From a61ad113e1057a34fc979f96ce18b8a07712ed1c Mon Sep 17 00:00:00 2001 From: Rachel Date: Thu, 5 Mar 2026 12:02:21 +0300 Subject: [PATCH] refactor: cache getVersion() and add JSDoc to display utilities getVersion() was reading package.json from disk on every call even though the version cannot change at runtime. Cache the result after the first read. Also add JSDoc comments to all previously undocumented exported functions for better IDE support and maintainability. Co-Authored-By: Claude Opus 4.6 --- src/utils/display.js | 46 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/utils/display.js b/src/utils/display.js index dd1c9a8..37f0458 100644 --- a/src/utils/display.js +++ b/src/utils/display.js @@ -11,6 +11,12 @@ import { PROVIDERS } from "../providers/models.js"; export { p }; +/** + * Return the first non-internal IPv4 address found on this machine. + * Falls back to "localhost" when no external interface is available. + * + * @returns {string} Local IPv4 address or "localhost" + */ function getLocalIp() { const nets = networkInterfaces(); for (const iface of Object.values(nets)) { @@ -23,10 +29,20 @@ function getLocalIp() { const __dirname = dirname(fileURLToPath(import.meta.url)); +/** + * Read the application version from package.json. + * The result is cached after the first call since the version + * cannot change while the process is running. + * + * @returns {string} Semantic version string or "unknown" on read failure + */ +let _cachedVersion = null; function getVersion() { + if (_cachedVersion) return _cachedVersion; try { const pkg = JSON.parse(readFileSync(join(__dirname, "../../package.json"), "utf-8")); - return pkg.version; + _cachedVersion = pkg.version; + return _cachedVersion; } catch { return "unknown"; } @@ -55,10 +71,19 @@ const LOGO = ` // Green terminal gradient const monoGradient = gradient(["#00ff41", "#00cc33", "#009926", "#006619"]); +/** Print the KernelBot ASCII logo with a green terminal gradient. */ export function showLogo() { console.log(monoGradient.multiline(LOGO)); } +/** + * Run a startup health-check with a spinner. + * Displays a success or failure indicator once the check resolves. + * + * @param {string} label - Description shown next to the spinner + * @param {() => Promise} checkFn - Async function that throws on failure + * @returns {Promise} true if the check passed, false otherwise + */ export async function showStartupCheck(label, checkFn) { const spinner = ora({ text: label, color: "cyan" }).start(); try { @@ -71,6 +96,7 @@ export async function showStartupCheck(label, checkFn) { } } +/** Display a boxed "KernelBot is live" banner. */ export function showStartupComplete() { console.log( boxen(chalk.green.bold("KernelBot is live"), { @@ -82,6 +108,10 @@ export function showStartupComplete() { ); } +/** + * Display a green success box. + * @param {string} msg - Message to display + */ export function showSuccess(msg) { console.log( boxen(chalk.green(msg), { @@ -92,6 +122,10 @@ export function showSuccess(msg) { ); } +/** + * Display a red error box. + * @param {string} msg - Message to display + */ export function showError(msg) { console.log( boxen(chalk.red(msg), { @@ -102,6 +136,11 @@ export function showError(msg) { ); } +/** + * Create a cyan ora spinner (not yet started). + * @param {string} text - Spinner label + * @returns {import('ora').Ora} + */ export function createSpinner(text) { return ora({ text, color: "cyan" }); } @@ -201,6 +240,11 @@ export function showWelcomeScreen(config, characterManager) { ); } +/** + * Display the character selection gallery with all available characters. + * @param {object[]} characters - Array of character profiles + * @param {string|null} [activeId] - ID of the currently active character + */ export function showCharacterGallery(characters, activeId = null) { console.log(""); console.log(