@tryhamster/gerbil 1.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +253 -0
- package/bin/cli.js +2 -0
- package/dist/auto-update-BbNHbSU1.mjs +3 -0
- package/dist/browser/index.d.mts +262 -0
- package/dist/browser/index.d.mts.map +1 -0
- package/dist/browser/index.mjs +755 -0
- package/dist/browser/index.mjs.map +1 -0
- package/dist/chrome-backend-C5Un08O4.mjs +771 -0
- package/dist/chrome-backend-C5Un08O4.mjs.map +1 -0
- package/dist/chrome-backend-CtwPENIW.mjs +3 -0
- package/dist/chunk-Ct1HF2bE.mjs +7 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +7078 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/frameworks/express.d.mts +22 -0
- package/dist/frameworks/express.d.mts.map +1 -0
- package/dist/frameworks/express.mjs +123 -0
- package/dist/frameworks/express.mjs.map +1 -0
- package/dist/frameworks/fastify.d.mts +11 -0
- package/dist/frameworks/fastify.d.mts.map +1 -0
- package/dist/frameworks/fastify.mjs +73 -0
- package/dist/frameworks/fastify.mjs.map +1 -0
- package/dist/frameworks/hono.d.mts +14 -0
- package/dist/frameworks/hono.d.mts.map +1 -0
- package/dist/frameworks/hono.mjs +82 -0
- package/dist/frameworks/hono.mjs.map +1 -0
- package/dist/frameworks/next.d.mts +31 -0
- package/dist/frameworks/next.d.mts.map +1 -0
- package/dist/frameworks/next.mjs +116 -0
- package/dist/frameworks/next.mjs.map +1 -0
- package/dist/frameworks/react.d.mts +56 -0
- package/dist/frameworks/react.d.mts.map +1 -0
- package/dist/frameworks/react.mjs +172 -0
- package/dist/frameworks/react.mjs.map +1 -0
- package/dist/frameworks/trpc.d.mts +12 -0
- package/dist/frameworks/trpc.d.mts.map +1 -0
- package/dist/frameworks/trpc.mjs +80 -0
- package/dist/frameworks/trpc.mjs.map +1 -0
- package/dist/gerbil-BfnsFWRE.mjs +644 -0
- package/dist/gerbil-BfnsFWRE.mjs.map +1 -0
- package/dist/gerbil-BjW-z7Fq.mjs +5 -0
- package/dist/gerbil-DZ1k3ChC.d.mts +138 -0
- package/dist/gerbil-DZ1k3ChC.d.mts.map +1 -0
- package/dist/index.d.mts +223 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +13 -0
- package/dist/index.mjs.map +1 -0
- package/dist/integrations/ai-sdk.d.mts +78 -0
- package/dist/integrations/ai-sdk.d.mts.map +1 -0
- package/dist/integrations/ai-sdk.mjs +199 -0
- package/dist/integrations/ai-sdk.mjs.map +1 -0
- package/dist/integrations/langchain.d.mts +41 -0
- package/dist/integrations/langchain.d.mts.map +1 -0
- package/dist/integrations/langchain.mjs +93 -0
- package/dist/integrations/langchain.mjs.map +1 -0
- package/dist/integrations/llamaindex.d.mts +45 -0
- package/dist/integrations/llamaindex.d.mts.map +1 -0
- package/dist/integrations/llamaindex.mjs +86 -0
- package/dist/integrations/llamaindex.mjs.map +1 -0
- package/dist/integrations/mcp-client.d.mts +206 -0
- package/dist/integrations/mcp-client.d.mts.map +1 -0
- package/dist/integrations/mcp-client.mjs +507 -0
- package/dist/integrations/mcp-client.mjs.map +1 -0
- package/dist/integrations/mcp.d.mts +177 -0
- package/dist/integrations/mcp.d.mts.map +1 -0
- package/dist/integrations/mcp.mjs +8 -0
- package/dist/mcp-R8kRLIKb.mjs +348 -0
- package/dist/mcp-R8kRLIKb.mjs.map +1 -0
- package/dist/models-DKULvhOr.mjs +136 -0
- package/dist/models-DKULvhOr.mjs.map +1 -0
- package/dist/models-De2-_GmQ.d.mts +22 -0
- package/dist/models-De2-_GmQ.d.mts.map +1 -0
- package/dist/one-liner-BUQR0nqq.mjs +98 -0
- package/dist/one-liner-BUQR0nqq.mjs.map +1 -0
- package/dist/skills/index.d.mts +390 -0
- package/dist/skills/index.d.mts.map +1 -0
- package/dist/skills/index.mjs +7 -0
- package/dist/skills-D3CEpgDc.mjs +630 -0
- package/dist/skills-D3CEpgDc.mjs.map +1 -0
- package/dist/tools-BsiEE6f2.mjs +567 -0
- package/dist/tools-BsiEE6f2.mjs.map +1 -0
- package/dist/types-BS1N92Jt.d.mts +183 -0
- package/dist/types-BS1N92Jt.d.mts.map +1 -0
- package/dist/utils-7vXqtq2Q.mjs +63 -0
- package/dist/utils-7vXqtq2Q.mjs.map +1 -0
- package/docs/ai-sdk.md +80 -0
- package/docs/architecture/README.md +84 -0
- package/docs/architecture/caching.md +227 -0
- package/docs/architecture/inference.md +176 -0
- package/docs/architecture/overview.md +179 -0
- package/docs/architecture/streaming.md +261 -0
- package/docs/architecture/webgpu.md +213 -0
- package/docs/browser.md +328 -0
- package/docs/cli.md +155 -0
- package/docs/frameworks.md +90 -0
- package/docs/mcp-client.md +224 -0
- package/docs/mcp.md +109 -0
- package/docs/memory.md +229 -0
- package/docs/repl.md +473 -0
- package/docs/skills.md +261 -0
- package/docs/tools.md +304 -0
- package/package.json +207 -0
package/dist/cli.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":["models: CachedModelInfo[]","devices: Record<string, { avgTokPerSec: number; runs: number }>","bests","converted: BenchmarkResult[]","newResult: BenchmarkResult","elements: React.ReactNode[]","codeBlockContent: string[]","parts: React.ReactNode[]","exec","copyToClipboard","cmd: string","LANG_EXTENSIONS: Record<string, string>","cmd: string","STEPS","input","info: HFModelDetails","files: { path: string; size?: number }[]","models: HFModel[]","e: any","path","fs","modes: SortMode[]","filters: SizeFilter[]","SKILL_DETAILS: Record<\n string,\n {\n emoji: string;\n what: string;\n example: string;\n cliExample?: string;\n inputHint: string;\n }\n>","parsedInput: Record<string, unknown>","allTools: ToolInfo[]","toolPath: string | undefined","params: any","ctx: ViewContext","col","sigintTimer: NodeJS.Timeout | null","skills.commit","skills.summarize","skills.explain","skills.review","Gerbil","opts","fs","path","os","models: {\n name: string;\n size: number;\n mtime: Date;\n path: string;\n }[]","results: {\n tokPerSec: number;\n firstToken: number;\n tokens: number;\n }[]","checkForUpdate","CURRENT_VERSION","installUpdate"],"sources":["../package.json","../src/cli/repl/auto-update.ts","../src/cli/repl/utils.ts","../src/cli/repl/views/BenchmarkView.tsx","../src/cli/repl/views/ChatView.tsx","../src/cli/repl/views/CodeView.tsx","../src/cli/repl/views/CreateSkillView.tsx","../src/cli/repl/views/CreateToolView.tsx","../src/cli/repl/views/FrameworksView.tsx","../src/cli/repl/views/InfoView.tsx","../src/cli/repl/views/LoadingView.tsx","../src/cli/repl/views/ModelView.tsx","../src/cli/repl/views/ServeView.tsx","../src/cli/repl/views/SkillsView.tsx","../src/cli/repl/views/ToolsView.tsx","../src/cli/repl/App.tsx","../src/cli/repl/index.tsx","../src/cli/index.ts"],"sourcesContent":["{\n \"name\": \"@tryhamster/gerbil\",\n \"version\": \"1.0.0-rc.0\",\n \"description\": \"Local LLM inference for Node.js. GPU-accelerated. Zero config. Works standalone or with Vercel AI SDK.\",\n \"type\": \"module\",\n \"main\": \"dist/index.mjs\",\n \"types\": \"dist/index.d.mts\",\n \"bin\": {\n \"gerbil\": \"./bin/cli.js\"\n },\n \"exports\": {\n \".\": {\n \"import\": \"./dist/index.mjs\",\n \"types\": \"./dist/index.d.mts\"\n },\n \"./skills\": {\n \"import\": \"./dist/skills/index.mjs\",\n \"types\": \"./dist/skills/index.d.mts\"\n },\n \"./ai\": {\n \"import\": \"./dist/integrations/ai-sdk.mjs\",\n \"types\": \"./dist/integrations/ai-sdk.d.mts\"\n },\n \"./react\": {\n \"import\": \"./dist/frameworks/react.mjs\",\n \"types\": \"./dist/frameworks/react.d.mts\"\n },\n \"./next\": {\n \"import\": \"./dist/frameworks/next.mjs\",\n \"types\": \"./dist/frameworks/next.d.mts\"\n },\n \"./express\": {\n \"import\": \"./dist/frameworks/express.mjs\",\n \"types\": \"./dist/frameworks/express.d.mts\"\n },\n \"./fastify\": {\n \"import\": \"./dist/frameworks/fastify.mjs\",\n \"types\": \"./dist/frameworks/fastify.d.mts\"\n },\n \"./hono\": {\n \"import\": \"./dist/frameworks/hono.mjs\",\n \"types\": \"./dist/frameworks/hono.d.mts\"\n },\n \"./trpc\": {\n \"import\": \"./dist/frameworks/trpc.mjs\",\n \"types\": \"./dist/frameworks/trpc.d.mts\"\n },\n \"./langchain\": {\n \"import\": \"./dist/integrations/langchain.mjs\",\n \"types\": \"./dist/integrations/langchain.d.mts\"\n },\n \"./llamaindex\": {\n \"import\": \"./dist/integrations/llamaindex.mjs\",\n \"types\": \"./dist/integrations/llamaindex.d.mts\"\n },\n \"./mcp\": {\n \"import\": \"./dist/integrations/mcp.mjs\",\n \"types\": \"./dist/integrations/mcp.d.mts\"\n },\n \"./mcp-client\": {\n \"import\": \"./dist/integrations/mcp-client.mjs\",\n \"types\": \"./dist/integrations/mcp-client.d.mts\"\n },\n \"./browser\": {\n \"import\": \"./dist/browser/index.mjs\",\n \"types\": \"./dist/browser/index.d.mts\"\n }\n },\n \"scripts\": {\n \"build\": \"tsdown\",\n \"dev\": \"tsx src/cli/index.ts\",\n \"typecheck\": \"tsc --noEmit\",\n \"check\": \"ultracite check\",\n \"fix\": \"ultracite fix\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"prepublishOnly\": \"pnpm build\",\n \"changeset\": \"changeset\",\n \"release\": \"changeset publish\",\n \"prepare\": \"lefthook install\"\n },\n \"dependencies\": {\n \"@huggingface/hub\": \"^2.7.1\",\n \"@huggingface/transformers\": \"^3.8.0\",\n \"chalk\": \"^5.3.0\",\n \"cli-progress\": \"^3.12.0\",\n \"commander\": \"^12.1.0\",\n \"onnxruntime-web\": \"^1.21.0-dev.20250114-228dd16893\",\n \"ora\": \"^8.0.1\",\n \"puppeteer-core\": \"^24.31.0\",\n \"webgpu\": \"^0.3.8\",\n \"zod\": \"^3.23.0\"\n },\n \"peerDependencies\": {\n \"@ai-sdk/provider\": \">=2.0.0\",\n \"@modelcontextprotocol/sdk\": \">=0.5.0\",\n \"@trpc/server\": \">=10.0.0\",\n \"ai\": \">=5.0.0\",\n \"express\": \">=4.0.0\",\n \"fastify\": \">=4.0.0\",\n \"hono\": \">=4.0.0\",\n \"langchain\": \">=0.1.0\",\n \"llamaindex\": \">=0.1.0\",\n \"next\": \">=14.0.0\",\n \"react\": \">=18.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"@ai-sdk/provider\": {\n \"optional\": true\n },\n \"@modelcontextprotocol/sdk\": {\n \"optional\": true\n },\n \"@trpc/server\": {\n \"optional\": true\n },\n \"ai\": {\n \"optional\": true\n },\n \"express\": {\n \"optional\": true\n },\n \"fastify\": {\n \"optional\": true\n },\n \"hono\": {\n \"optional\": true\n },\n \"langchain\": {\n \"optional\": true\n },\n \"llamaindex\": {\n \"optional\": true\n },\n \"next\": {\n \"optional\": true\n },\n \"react\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"@ai-sdk/provider\": \"^2.0.0\",\n \"@biomejs/biome\": \"^2.3.8\",\n \"@changesets/changelog-github\": \"^0.5.1\",\n \"@changesets/cli\": \"^2.28.1\",\n \"@types/cli-progress\": \"^3.11.6\",\n \"@types/express\": \"^4.17.21\",\n \"@types/ink-big-text\": \"^1.2.4\",\n \"@types/node\": \"^20.14.0\",\n \"@types/react\": \"^19.0.0\",\n \"ai\": \"^5.0.0\",\n \"express\": \"^4.19.0\",\n \"ink\": \"^6.5.1\",\n \"ink-big-text\": \"^2.0.0\",\n \"ink-gradient\": \"^3.0.0\",\n \"ink-select-input\": \"^6.2.0\",\n \"ink-spinner\": \"^5.0.0\",\n \"ink-text-input\": \"^6.0.0\",\n \"lefthook\": \"^2.0.5\",\n \"react\": \"^19.0.0\",\n \"tsdown\": \"^0.17.0-beta.3\",\n \"tsx\": \"^4.15.0\",\n \"typescript\": \"^5.4.5\",\n \"ultracite\": \"6.3.8\",\n \"vitest\": \"^1.6.0\"\n },\n \"engines\": {\n \"node\": \">=18.0.0\"\n },\n \"keywords\": [\n \"llm\",\n \"local\",\n \"gpu\",\n \"webgpu\",\n \"inference\",\n \"ai-sdk\",\n \"transformers\",\n \"qwen\",\n \"thinking\",\n \"mcp\",\n \"langchain\",\n \"nextjs\",\n \"express\",\n \"cli\"\n ],\n \"license\": \"MIT\",\n \"author\": \"Hamster <hello@tryhamster.com>\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/gethamster/gerbil.git\"\n },\n \"homepage\": \"https://github.com/gethamster/gerbil#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/gethamster/gerbil/issues\"\n },\n \"files\": [\n \"dist\",\n \"bin\",\n \"docs\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import { exec } from \"child_process\";\nimport { promisify } from \"util\";\n\nconst execAsync = promisify(exec);\n\nconst CURRENT_VERSION = \"1.0.0\";\nconst PACKAGE_NAME = \"@tryhamster/gerbil\";\n\nexport type UpdateCheckResult = {\n updateAvailable: boolean;\n currentVersion: string;\n latestVersion?: string;\n error?: string;\n};\n\nexport type UpdateInstallResult = {\n success: boolean;\n version?: string;\n error?: string;\n};\n\n/**\n * Check if an update is available (non-blocking, no install)\n */\nexport async function checkForUpdate(): Promise<UpdateCheckResult> {\n try {\n // Check latest version from npm\n const { stdout } = await execAsync(`npm view ${PACKAGE_NAME} version`, {\n timeout: 5000,\n });\n const latestVersion = stdout.trim();\n\n // Compare versions\n if (compareVersions(latestVersion, CURRENT_VERSION) > 0) {\n return {\n updateAvailable: true,\n currentVersion: CURRENT_VERSION,\n latestVersion,\n };\n }\n\n return {\n updateAvailable: false,\n currentVersion: CURRENT_VERSION,\n latestVersion,\n };\n } catch (error) {\n // Silent fail - network issues, npm not available, etc.\n return {\n updateAvailable: false,\n currentVersion: CURRENT_VERSION,\n error: `Update check failed: ${error}`,\n };\n }\n}\n\n/**\n * Install the latest version\n */\nexport async function installUpdate(): Promise<UpdateInstallResult> {\n try {\n const { stdout } = await execAsync(`npm install -g ${PACKAGE_NAME}@latest`, {\n timeout: 60_000, // 60s for download + install\n });\n\n // Try to extract version from output\n const versionMatch = stdout.match(/\\+ @tryhamster\\/gerbil@([\\d.]+)/);\n const version = versionMatch ? versionMatch[1] : undefined;\n\n return {\n success: true,\n version,\n };\n } catch (error) {\n return {\n success: false,\n error: `Failed to install update: ${error}`,\n };\n }\n}\n\n/**\n * Compare two semver versions\n * Returns: 1 if a > b, -1 if a < b, 0 if equal\n */\nexport function compareVersions(a: string, b: string): number {\n const aParts = a.split(\".\").map(Number);\n const bParts = b.split(\".\").map(Number);\n\n for (let i = 0; i < 3; i++) {\n const aPart = aParts[i] || 0;\n const bPart = bParts[i] || 0;\n if (aPart > bPart) {\n return 1;\n }\n if (aPart < bPart) {\n return -1;\n }\n }\n return 0;\n}\n\nexport { CURRENT_VERSION };\n","/**\n * Shared utilities for the REPL\n */\n\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport { getChromeCachedModels, refreshCachedModelSizes } from \"../../core/chrome-backend.js\";\n\n/**\n * Format bytes to human readable string\n */\nexport function formatBytes(bytes: number): string {\n if (!bytes || bytes === 0) {\n return \"\";\n }\n if (bytes >= 1e9) {\n return `${(bytes / 1e9).toFixed(1)}GB`;\n }\n if (bytes >= 1e6) {\n return `${(bytes / 1e6).toFixed(0)}MB`;\n }\n if (bytes >= 1e3) {\n return `${(bytes / 1e3).toFixed(0)}KB`;\n }\n return `${bytes}B`;\n}\n\n/**\n * Format time ago string\n */\nexport function formatTimeAgo(date: Date): string {\n const seconds = Math.floor((Date.now() - date.getTime()) / 1000);\n if (seconds < 60) {\n return \"just now\";\n }\n if (seconds < 3600) {\n return `${Math.floor(seconds / 60)}m ago`;\n }\n if (seconds < 86_400) {\n return `${Math.floor(seconds / 3600)}h ago`;\n }\n if (seconds < 604_800) {\n return `${Math.floor(seconds / 86_400)}d ago`;\n }\n return `${Math.floor(seconds / 604_800)}w ago`;\n}\n\n/**\n * Format download count\n */\nexport function formatDownloads(n: number): string {\n if (n >= 1_000_000) {\n return `${(n / 1_000_000).toFixed(1)}M dl`;\n }\n if (n >= 1000) {\n return `${(n / 1000).toFixed(1)}K dl`;\n }\n return `${n} dl`;\n}\n\n/**\n * Get Gerbil models directory (local project models)\n */\nexport function getGerbilModelsDir(): string {\n return path.join(process.cwd(), \".gerbil\", \"models\");\n}\n\n/**\n * Get transformers.js cache directory (downloaded HF models)\n */\nexport function getTransformersCacheDir(): string {\n const nodeModulesCache = path.join(\n process.cwd(),\n \"node_modules\",\n \"@huggingface\",\n \"transformers\",\n \".cache\",\n );\n if (fs.existsSync(nodeModulesCache)) {\n return nodeModulesCache;\n }\n return (\n process.env.HF_HOME ||\n process.env.TRANSFORMERS_CACHE ||\n path.join(os.homedir(), \".cache\", \"huggingface\", \"hub\")\n );\n}\n\n/**\n * Get all cache directories that might contain models\n */\nexport function getAllCacheDirs(): string[] {\n return [getGerbilModelsDir(), getTransformersCacheDir()].filter((dir) => fs.existsSync(dir));\n}\n\n/**\n * Check if a model is cached locally (checks gerbil, transformers, and Chrome cache)\n */\nexport function isModelCached(hfId: string): boolean {\n const [org, model] = hfId.split(\"/\");\n if (!(org && model)) {\n return false;\n }\n\n // Check Chrome IndexedDB cache first (tracked in JSON file)\n try {\n const chromeCached = getChromeCachedModels();\n if (chromeCached.some((m) => m.modelId === hfId)) {\n return true;\n }\n } catch {\n // Chrome cache tracking not available\n }\n\n // Check filesystem cache locations\n const cacheDirs = [getGerbilModelsDir(), getTransformersCacheDir()];\n\n for (const cacheDir of cacheDirs) {\n const possiblePaths = [\n path.join(cacheDir, org, model),\n path.join(cacheDir, hfId.replace(\"/\", \"--\")),\n path.join(cacheDir, `models--${org}--${model}`),\n ];\n\n for (const p of possiblePaths) {\n try {\n if (fs.existsSync(p)) {\n const stat = fs.statSync(p);\n if (stat.isDirectory()) {\n const files = fs.readdirSync(p, { recursive: true });\n const hasOnnxModel = files.some((f: any) => {\n const fname = String(f).toLowerCase();\n return (\n fname.endsWith(\".onnx\") ||\n fname.endsWith(\"model.safetensors\") ||\n fname.includes(\"decoder_model\") ||\n fname.includes(\"encoder_model\")\n );\n });\n if (hasOnnxModel) {\n return true;\n }\n }\n }\n } catch {}\n }\n }\n\n return false;\n}\n\n/** Detailed model info from cache */\nexport type CachedModelInfo = {\n name: string;\n modelSize: string; // ONNX model files only\n totalSize: string; // All files (including shaders, config, etc.)\n lastUsed: string;\n location: string;\n};\n\n/**\n * Scan a single cache directory for models\n */\nfunction scanCacheDir(cacheDir: string, models: CachedModelInfo[]): number {\n let totalBytes = 0;\n\n try {\n if (!fs.existsSync(cacheDir)) {\n return 0;\n }\n\n const entries = fs.readdirSync(cacheDir);\n for (const entry of entries) {\n const entryPath = path.join(cacheDir, entry);\n const entryStat = fs.statSync(entryPath);\n\n if (!entryStat.isDirectory()) {\n continue;\n }\n\n let modelName = entry;\n if (entry.startsWith(\"models--\")) {\n modelName = entry.replace(\"models--\", \"\").replace(\"--\", \"/\");\n }\n\n const subEntries = fs.readdirSync(entryPath);\n for (const subEntry of subEntries) {\n const subPath = path.join(entryPath, subEntry);\n try {\n const subStat = fs.statSync(subPath);\n if (subStat.isDirectory()) {\n const fullModelName = `${entry}/${subEntry}`;\n let totalSize = 0;\n let modelFileSize = 0;\n try {\n const files = fs.readdirSync(subPath, { recursive: true });\n for (const file of files) {\n try {\n const filePath = path.join(subPath, String(file));\n const fileStat = fs.statSync(filePath);\n if (fileStat.isFile()) {\n totalSize += fileStat.size;\n const fname = String(file).toLowerCase();\n if (fname.endsWith(\".onnx\") || fname.endsWith(\".safetensors\")) {\n modelFileSize += fileStat.size;\n }\n }\n } catch {}\n }\n } catch {\n totalSize = subStat.size;\n }\n\n if (totalSize > 0) {\n totalBytes += totalSize;\n const lastUsed = formatTimeAgo(subStat.mtime);\n models.push({\n name: fullModelName,\n modelSize: formatBytes(modelFileSize || totalSize),\n totalSize: formatBytes(totalSize),\n lastUsed,\n location: cacheDir,\n });\n }\n }\n } catch {}\n }\n\n const hasModelFiles = subEntries.some((f) => f.endsWith(\".onnx\") || f.endsWith(\".json\"));\n if (hasModelFiles) {\n let totalSize = 0;\n let modelFileSize = 0;\n try {\n const files = fs.readdirSync(entryPath, { recursive: true });\n for (const file of files) {\n try {\n const filePath = path.join(entryPath, String(file));\n const fileStat = fs.statSync(filePath);\n if (fileStat.isFile()) {\n totalSize += fileStat.size;\n const fname = String(file).toLowerCase();\n if (fname.endsWith(\".onnx\") || fname.endsWith(\".safetensors\")) {\n modelFileSize += fileStat.size;\n }\n }\n } catch {}\n }\n } catch {\n totalSize = entryStat.size;\n }\n\n totalBytes += totalSize;\n const lastUsed = formatTimeAgo(entryStat.mtime);\n models.push({\n name: modelName,\n modelSize: formatBytes(modelFileSize || totalSize),\n totalSize: formatBytes(totalSize),\n lastUsed,\n location: cacheDir,\n });\n }\n }\n } catch {}\n\n return totalBytes;\n}\n\n/**\n * Get cache info from all cache locations\n */\nexport function getCacheInfo(): {\n locations: string[];\n totalSize: string;\n models: CachedModelInfo[];\n} {\n const gerbilDir = getGerbilModelsDir();\n const transformersDir = getTransformersCacheDir();\n const models: CachedModelInfo[] = [];\n\n let totalBytes = 0;\n totalBytes += scanCacheDir(gerbilDir, models);\n totalBytes += scanCacheDir(transformersDir, models);\n\n // Add Chrome-cached models (stored in IndexedDB, tracked in JSON)\n let hasMissingSizes = false;\n try {\n const chromeCached = getChromeCachedModels();\n for (const entry of chromeCached) {\n // Check if already in list from filesystem scan\n const exists = models.some(\n (m) =>\n m.name === entry.modelId ||\n m.name.replace(\"--\", \"/\") === entry.modelId ||\n entry.modelId.replace(\"/\", \"--\") === m.name,\n );\n\n if (!exists) {\n const lastUsed = entry.lastUsed ? formatTimeAgo(new Date(entry.lastUsed)) : \"unknown\";\n if (!entry.sizeBytes) {\n hasMissingSizes = true;\n }\n models.push({\n name: entry.modelId,\n modelSize: entry.sizeBytes ? formatBytes(entry.sizeBytes) : \"~\",\n totalSize: entry.sizeBytes ? formatBytes(entry.sizeBytes) : \"~\",\n lastUsed,\n location: \"Chrome IndexedDB\",\n });\n if (entry.sizeBytes) {\n totalBytes += entry.sizeBytes;\n }\n }\n }\n\n // Trigger background refresh for missing sizes\n if (hasMissingSizes) {\n refreshCachedModelSizes().catch(() => {});\n }\n } catch {\n // Chrome cache tracking not available\n }\n\n // Get active locations that have models\n const activeLocations = [...new Set(models.map((m) => m.location))];\n\n return {\n locations: activeLocations.length > 0 ? activeLocations : [gerbilDir, transformersDir],\n totalSize: formatBytes(totalBytes),\n models: models.sort((a, b) => a.name.localeCompare(b.name)),\n };\n}\n\n/**\n * Get system memory info\n */\nexport function getMemoryInfo(): {\n total: string;\n used: string;\n free: string;\n percentUsed: number;\n} {\n const totalMem = os.totalmem();\n const freeMem = os.freemem();\n const usedMem = totalMem - freeMem;\n const percentUsed = Math.round((usedMem / totalMem) * 100);\n\n return {\n total: formatBytes(totalMem),\n used: formatBytes(usedMem),\n free: formatBytes(freeMem),\n percentUsed,\n };\n}\n\n/**\n * OSC 8 hyperlink helper (clickable links in terminal)\n */\nexport function hyperlink(url: string, text: string): string {\n return `\\x1b]8;;${url}\\x07${text}\\x1b]8;;\\x07`;\n}\n\n/**\n * Clean AI response - remove think tags and trim\n */\nexport function cleanResponse(text: string): string {\n return text\n .replace(/<think>[\\s\\S]*?<\\/think>/g, \"\")\n .replace(/<\\/?think>/g, \"\")\n .trim();\n}\n\n/**\n * Preset models with known performance\n */\nexport const PRESET_MODELS = [\n {\n id: \"qwen3-0.6b\",\n name: \"Qwen3 0.6B\",\n size: \"~400MB\",\n speed: \"fastest\",\n hfId: \"onnx-community/Qwen3-0.6B-ONNX\",\n },\n {\n id: \"qwen2.5-0.5b\",\n name: \"Qwen2.5 0.5B\",\n size: \"~350MB\",\n speed: \"fast\",\n hfId: \"onnx-community/Qwen2.5-0.5B-Instruct\",\n },\n {\n id: \"qwen2.5-coder-0.5b\",\n name: \"Qwen2.5 Coder\",\n size: \"~400MB\",\n speed: \"fast\",\n hfId: \"onnx-community/Qwen2.5-Coder-0.5B-Instruct\",\n },\n {\n id: \"smollm2-360m\",\n name: \"SmolLM2 360M\",\n size: \"~250MB\",\n speed: \"fastest\",\n hfId: \"HuggingFaceTB/SmolLM2-360M-Instruct\",\n },\n {\n id: \"smollm2-135m\",\n name: \"SmolLM2 135M\",\n size: \"~100MB\",\n speed: \"fastest\",\n hfId: \"HuggingFaceTB/SmolLM2-135M-Instruct\",\n },\n {\n id: \"phi-3-mini\",\n name: \"Phi-3 Mini\",\n size: \"~2.1GB\",\n speed: \"medium\",\n hfId: \"microsoft/Phi-3-mini-4k-instruct-onnx\",\n },\n];\n\n/**\n * Session stats interface\n */\nexport type SessionStats = {\n prompts: number;\n tokensIn: number;\n tokensOut: number;\n totalTimeMs: number;\n startTime: number;\n benchResults: { model: string; tokPerSec: number }[];\n /** Last message tok/s */\n lastTokPerSec: number;\n /** Average tok/s across all messages */\n avgTokPerSec: number;\n};\n\n// ============================================\n// Benchmark Persistence\n// ============================================\n\nexport type StoredBenchmark = {\n timestamp: string;\n model: string;\n device: \"webgpu\" | \"cpu\" | \"wasm\";\n tokensPerSec: number;\n firstTokenMs: number;\n totalTokens: number;\n totalMs: number;\n};\n\nconst BENCHMARKS_FILE = path.join(os.homedir(), \".gerbil\", \"benchmarks.json\");\n\n/**\n * Get all stored benchmarks\n */\nexport function getStoredBenchmarks(): StoredBenchmark[] {\n try {\n if (!fs.existsSync(BENCHMARKS_FILE)) {\n return [];\n }\n const data = JSON.parse(fs.readFileSync(BENCHMARKS_FILE, \"utf-8\"));\n return data.benchmarks || [];\n } catch {\n return [];\n }\n}\n\n/**\n * Save a benchmark result\n */\nexport function saveBenchmark(result: {\n model: string;\n device: \"webgpu\" | \"cpu\" | \"wasm\";\n tokensPerSec: number;\n firstTokenMs: number;\n totalTokens: number;\n totalMs: number;\n}): void {\n try {\n const dir = path.dirname(BENCHMARKS_FILE);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n const benchmarks = getStoredBenchmarks();\n benchmarks.push({\n ...result,\n timestamp: new Date().toISOString(),\n });\n\n // Keep last 1000 benchmarks\n const trimmed = benchmarks.slice(-1000);\n fs.writeFileSync(BENCHMARKS_FILE, JSON.stringify({ benchmarks: trimmed }, null, 2));\n } catch {\n // Ignore save errors\n }\n}\n\n/**\n * Get average benchmark stats for a model\n */\n/**\n * Normalize model ID for matching (extract core name)\n * e.g., \"HuggingFaceTB/SmolLM2-135M-Instruct\" -> \"smollm2-135m\"\n * \"onnx-community/Qwen3-0.6B-ONNX\" -> \"qwen3-0.6b\"\n * \"qwen3-0.6b\" -> \"qwen3-0.6b\"\n */\nfunction normalizeModelId(id: string): string {\n // Get the last part after /\n const name = id.split(\"/\").pop() || id;\n // Remove common suffixes and convert to lowercase\n return name\n .toLowerCase()\n .replace(/-instruct$/i, \"\")\n .replace(/-onnx$/i, \"\")\n .replace(/-chat$/i, \"\")\n .replace(/-it$/i, \"\");\n}\n\nexport function getModelBenchmarkStats(modelId: string): {\n avgTokPerSec: number;\n avgFirstToken: number;\n runs: number;\n devices: Record<string, { avgTokPerSec: number; runs: number }>;\n} | null {\n const benchmarks = getStoredBenchmarks();\n const normalizedId = normalizeModelId(modelId);\n\n const modelBenchmarks = benchmarks.filter((b) => {\n const normalizedBench = normalizeModelId(b.model);\n return (\n normalizedBench === normalizedId ||\n normalizedBench.includes(normalizedId) ||\n normalizedId.includes(normalizedBench)\n );\n });\n\n if (modelBenchmarks.length === 0) {\n return null;\n }\n\n const avgTokPerSec = Math.round(\n modelBenchmarks.reduce((a, b) => a + b.tokensPerSec, 0) / modelBenchmarks.length,\n );\n const avgFirstToken = Math.round(\n modelBenchmarks.reduce((a, b) => a + b.firstTokenMs, 0) / modelBenchmarks.length,\n );\n\n // Group by device\n const devices: Record<string, { avgTokPerSec: number; runs: number }> = {};\n for (const b of modelBenchmarks) {\n if (!devices[b.device]) {\n devices[b.device] = { avgTokPerSec: 0, runs: 0 };\n }\n devices[b.device].runs++;\n }\n for (const device of Object.keys(devices)) {\n const deviceBenchmarks = modelBenchmarks.filter((b) => b.device === device);\n devices[device].avgTokPerSec = Math.round(\n deviceBenchmarks.reduce((a, b) => a + b.tokensPerSec, 0) / deviceBenchmarks.length,\n );\n }\n\n return { avgTokPerSec, avgFirstToken, runs: modelBenchmarks.length, devices };\n}\n","import { Box, Text, useInput } from \"ink\";\nimport Spinner from \"ink-spinner\";\nimport type React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport type { Gerbil } from \"../../../core/gerbil.js\";\nimport { getStoredBenchmarks, type StoredBenchmark, saveBenchmark } from \"../utils.js\";\n\nexport type BenchmarkResult = {\n model: string;\n device: \"webgpu\" | \"cpu\" | \"wasm\";\n tokensPerSec: number;\n firstTokenMs: number;\n totalTokens: number;\n totalMs: number;\n};\n\nexport type BenchmarkStats = {\n runCount: number;\n lastResult?: BenchmarkResult;\n averages: Array<{\n model: string;\n device: string;\n avgTokPerSec: number;\n avgFirstToken: number;\n runs: number;\n }>;\n bests?: {\n fastestRun: BenchmarkResult;\n fastestFirstToken: BenchmarkResult;\n bestOverall: {\n model: string;\n device: string;\n avgTokPerSec: number;\n avgFirstToken: number;\n score: number;\n } | null;\n };\n};\n\ntype BenchmarkViewProps = {\n gerbil: Gerbil;\n model: string;\n disabled?: boolean;\n onResult?: (tokPerSec: number) => void;\n onSwitchModel?: () => void;\n onSwitchDevice?: (device: \"webgpu\" | \"cpu\") => void;\n onStatusChange?: (status: \"idle\" | \"running\" | \"done\", stats: BenchmarkStats) => void;\n benchmarkResults: BenchmarkResult[];\n setBenchmarkResults: React.Dispatch<React.SetStateAction<BenchmarkResult[]>>;\n benchmarkModels: string[];\n setBenchmarkModels: React.Dispatch<React.SetStateAction<string[]>>;\n};\n\nexport function BenchmarkView({\n gerbil,\n model,\n disabled = false,\n onResult,\n onSwitchModel,\n onSwitchDevice,\n onStatusChange,\n benchmarkResults,\n setBenchmarkResults,\n benchmarkModels,\n setBenchmarkModels,\n}: BenchmarkViewProps) {\n const [status, setStatus] = useState<\"idle\" | \"running\" | \"done\">(\"idle\");\n const [currentRun, setCurrentRun] = useState(benchmarkResults.length);\n const [showHistory, setShowHistory] = useState(false);\n const [historyData, setHistoryData] = useState<StoredBenchmark[]>([]);\n\n // Notify parent of status changes with full stats\n const updateStatus = (\n newStatus: \"idle\" | \"running\" | \"done\",\n result?: BenchmarkResult,\n allResults?: BenchmarkResult[],\n ) => {\n setStatus(newStatus);\n\n const results = allResults || benchmarkResults;\n\n // Calculate averages\n const resultKeys = [...new Set(results.map((r) => `${r.model}|${r.device}`))];\n const averages = resultKeys.map((key) => {\n const [m, d] = key.split(\"|\");\n const filtered = results.filter((r) => r.model === m && r.device === d);\n return {\n model: m,\n device: d,\n avgTokPerSec: Math.round(\n filtered.reduce((a, r) => a + r.tokensPerSec, 0) / filtered.length,\n ),\n avgFirstToken: Math.round(\n filtered.reduce((a, r) => a + r.firstTokenMs, 0) / filtered.length,\n ),\n runs: filtered.length,\n };\n });\n\n // Calculate bests\n const bests =\n results.length > 0\n ? (() => {\n const fastestRun = results.reduce((best, r) =>\n r.tokensPerSec > best.tokensPerSec ? r : best,\n );\n const fastestFirstToken = results.reduce((best, r) =>\n r.firstTokenMs < best.firstTokenMs ? r : best,\n );\n\n // Best overall: score = tok/s / (1 + firstTokenMs/100)\n const overallScores = averages.map((s) => ({\n ...s,\n score: s.avgTokPerSec / (1 + s.avgFirstToken / 100),\n }));\n const bestOverall =\n overallScores.length > 0\n ? overallScores.reduce((best, s) => (s.score > best.score ? s : best))\n : null;\n\n return { fastestRun, fastestFirstToken, bestOverall };\n })()\n : undefined;\n\n onStatusChange?.(newStatus, {\n runCount: currentRun + (newStatus === \"done\" ? 1 : 0),\n lastResult: result,\n averages,\n bests,\n });\n };\n\n useEffect(() => {\n if (!benchmarkModels.includes(model)) {\n setBenchmarkModels((prev) => [...prev.slice(-2), model]);\n }\n }, [model, benchmarkModels, setBenchmarkModels]);\n\n const currentDevice = gerbil.getDeviceMode();\n\n useInput((input, key) => {\n // Block all actions while disabled (one-liner generating) or running\n const blocked = disabled || status === \"running\";\n\n if (key.return && !blocked) {\n runBenchmark();\n }\n if ((input === \"r\" || input === \"R\") && !blocked) {\n setBenchmarkResults([]);\n setCurrentRun(0);\n setBenchmarkModels([model]);\n }\n if ((input === \"m\" || input === \"M\") && !blocked) {\n onSwitchModel?.();\n }\n // Toggle device mode with 'd'\n if ((input === \"d\" || input === \"D\") && !blocked) {\n const newDevice = currentDevice === \"webgpu\" ? \"cpu\" : \"webgpu\";\n onSwitchDevice?.(newDevice);\n }\n // Toggle history with 'h'\n if ((input === \"h\" || input === \"H\") && !blocked) {\n if (!showHistory) {\n // Load history when opening\n const stored = getStoredBenchmarks();\n setHistoryData(stored);\n }\n setShowHistory(!showHistory);\n }\n // Load history into current session with 'l'\n if ((input === \"l\" || input === \"L\") && !blocked && showHistory) {\n const stored = getStoredBenchmarks();\n const converted: BenchmarkResult[] = stored.map((s) => ({\n model: s.model,\n device: s.device,\n tokensPerSec: s.tokensPerSec,\n firstTokenMs: s.firstTokenMs,\n totalTokens: s.totalTokens,\n totalMs: s.totalMs,\n }));\n setBenchmarkResults(converted);\n setCurrentRun(converted.length);\n // Collect unique models\n const models = [...new Set(converted.map((r) => r.model))];\n setBenchmarkModels(models.length > 0 ? models.slice(-3) : [model]);\n setShowHistory(false);\n }\n });\n\n const runBenchmark = async () => {\n updateStatus(\"running\");\n const prompts = [\n \"Write a haiku about programming.\",\n \"Explain recursion in one sentence.\",\n \"List 3 benefits of TypeScript.\",\n ];\n const prompt = prompts[currentRun % prompts.length];\n\n // Use generate() to get actual token counts from the result\n // This gives us real tokensGenerated and tokensPerSecond from transformers.js\n const startTime = Date.now();\n let firstTokenTime = 0;\n let gotFirstToken = false;\n\n const result = await gerbil.generate(prompt, {\n maxTokens: 100,\n onToken: () => {\n if (!gotFirstToken) {\n firstTokenTime = Date.now() - startTime;\n gotFirstToken = true;\n }\n },\n });\n\n const device = gerbil.getDeviceMode();\n const newResult: BenchmarkResult = {\n model,\n device,\n // Use actual metrics from generation result\n tokensPerSec: Math.round(result.tokensPerSecond),\n firstTokenMs: firstTokenTime || Math.round(result.totalTime * 0.1), // fallback estimate\n totalTokens: result.tokensGenerated,\n totalMs: Math.round(result.totalTime),\n };\n\n // Persist benchmark to ~/.gerbil/benchmarks.json\n saveBenchmark(newResult);\n\n const updatedResults = [...benchmarkResults, newResult];\n setBenchmarkResults(updatedResults);\n setCurrentRun((prev) => prev + 1);\n updateStatus(\"done\", newResult, updatedResults);\n onResult?.(newResult.tokensPerSec);\n };\n\n const currentResults = benchmarkResults.filter(\n (r) => r.model === model && r.device === currentDevice,\n );\n\n // Group results by model+device combination\n const resultKeys = [...new Set(benchmarkResults.map((r) => `${r.model}|${r.device}`))];\n const modelStats = resultKeys\n .map((key) => {\n const [m, d] = key.split(\"|\");\n const results = benchmarkResults.filter((r) => r.model === m && r.device === d);\n if (results.length === 0) {\n return null;\n }\n return {\n model: m,\n device: d as \"webgpu\" | \"cpu\" | \"wasm\",\n runs: results.length,\n avgTokPerSec: Math.round(results.reduce((a, r) => a + r.tokensPerSec, 0) / results.length),\n avgFirstToken: Math.round(results.reduce((a, r) => a + r.firstTokenMs, 0) / results.length),\n };\n })\n .filter(Boolean) as {\n model: string;\n device: string;\n runs: number;\n avgTokPerSec: number;\n avgFirstToken: number;\n }[];\n\n const bestTokPerSec =\n modelStats.length > 0 ? Math.max(...modelStats.map((s) => s.avgTokPerSec)) : 0;\n\n // Calculate \"bests\" across all runs\n // Best overall: score = tok/s / (1 + firstTokenMs/100) - rewards speed, penalizes slow first token\n const bests =\n benchmarkResults.length > 0\n ? (() => {\n const fastestRun = benchmarkResults.reduce((best, r) =>\n r.tokensPerSec > best.tokensPerSec ? r : best,\n );\n const fastestFirstToken = benchmarkResults.reduce((best, r) =>\n r.firstTokenMs < best.firstTokenMs ? r : best,\n );\n\n // Calculate overall score for each model+device combo using averages\n const overallScores = modelStats.map((s) => ({\n ...s,\n // Score: tok/s weighted against first token penalty\n // Higher tok/s is better, lower first token is better\n score: s.avgTokPerSec / (1 + s.avgFirstToken / 100),\n }));\n const bestOverall =\n overallScores.length > 0\n ? overallScores.reduce((best, s) => (s.score > best.score ? s : best))\n : null;\n\n return { fastestRun, fastestFirstToken, bestOverall };\n })()\n : null;\n\n const deviceColor =\n currentDevice === \"webgpu\" ? \"green\" : currentDevice === \"cpu\" ? \"yellow\" : \"gray\";\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Box>\n <Text bold>Benchmark: </Text>\n <Text bold color=\"cyan\">\n {model}\n </Text>\n <Text> on </Text>\n <Text bold color={deviceColor}>\n {currentDevice.toUpperCase()}\n </Text>\n {modelStats.length > 1 && <Text dimColor> (comparing {modelStats.length} configs)</Text>}\n </Box>\n <Text dimColor>Run multiple times for accurate averages</Text>\n\n {currentResults.length > 0 && (\n <Box flexDirection=\"column\" marginY={1}>\n <Text bold color=\"cyan\">\n Results for {model} on {currentDevice.toUpperCase()} ({currentResults.length} runs):\n </Text>\n <Box flexDirection=\"column\" marginTop={1}>\n {currentResults.slice(-6).map((r, i) => (\n <Text dimColor={i < currentResults.length - 1} key={i}>\n Run {i + 1}: <Text color=\"cyan\">{r.tokensPerSec}</Text> tok/s,{\" \"}\n <Text color=\"yellow\">{r.firstTokenMs}ms</Text> first token, {r.totalTokens} tokens\n </Text>\n ))}\n </Box>\n </Box>\n )}\n\n <Box flexDirection=\"row\" marginY={1}>\n {modelStats.length > 0 && (\n <Box\n borderColor=\"green\"\n borderStyle=\"single\"\n flexDirection=\"column\"\n marginRight={1}\n paddingX={1}\n >\n <Text bold color=\"green\">\n {modelStats.length > 1 ? \"Comparison:\" : \"Averages:\"}\n </Text>\n {modelStats.map((s) => {\n const isCurrent = s.model === model && s.device === currentDevice;\n const dColor =\n s.device === \"webgpu\" ? \"green\" : s.device === \"cpu\" ? \"yellow\" : \"gray\";\n return (\n <Box key={`${s.model}-${s.device}`}>\n <Text>\n {isCurrent ? \">\" : \" \"} {s.model}\n </Text>\n <Text color={dColor}> [{s.device}]</Text>\n <Text>: </Text>\n <Text\n bold\n color={\n s.avgTokPerSec === bestTokPerSec && modelStats.length > 1 ? \"green\" : \"cyan\"\n }\n >\n {s.avgTokPerSec} tok/s\n </Text>\n <Text>, </Text>\n <Text color=\"yellow\">{s.avgFirstToken}ms</Text>\n <Text dimColor> ({s.runs} runs)</Text>\n {s.avgTokPerSec === bestTokPerSec && modelStats.length > 1 && (\n <Text color=\"green\"> *fastest*</Text>\n )}\n </Box>\n );\n })}\n </Box>\n )}\n\n {bests && benchmarkResults.length >= 2 && (\n <Box borderColor=\"magenta\" borderStyle=\"single\" flexDirection=\"column\" paddingX={1}>\n <Text bold color=\"magenta\">\n Records:\n </Text>\n <Text>\n <Text color=\"cyan\">» Speed:</Text>{\" \"}\n <Text bold color=\"green\">\n {bests.fastestRun.tokensPerSec}\n </Text>{\" \"}\n tok/s\n <Text dimColor>\n {\" \"}\n ({bests.fastestRun.model} on {bests.fastestRun.device})\n </Text>\n </Text>\n <Text>\n <Text color=\"cyan\">» First:</Text>{\" \"}\n <Text bold color=\"yellow\">\n {bests.fastestFirstToken.firstTokenMs}\n </Text>\n ms\n <Text dimColor>\n {\" \"}\n ({bests.fastestFirstToken.model} on {bests.fastestFirstToken.device})\n </Text>\n </Text>\n {bests.bestOverall && (\n <Text>\n <Text color=\"cyan\">» Best:</Text>{\" \"}\n <Text bold color=\"magenta\">\n {bests.bestOverall.model}\n </Text>\n <Text dimColor>\n {\" \"}\n on {bests.bestOverall.device} ({bests.bestOverall.avgTokPerSec} tok/s,{\" \"}\n {bests.bestOverall.avgFirstToken}ms)\n </Text>\n </Text>\n )}\n </Box>\n )}\n </Box>\n\n {status === \"running\" && (\n <Box marginY={1}>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" /> Running benchmark #{currentRun + 1}...\n </Text>\n </Box>\n )}\n\n {showHistory && (\n <Box\n borderColor=\"gray\"\n borderStyle=\"single\"\n flexDirection=\"column\"\n marginY={1}\n paddingX={1}\n >\n <Text bold color=\"gray\">\n Benchmark History ({historyData.length} runs)\n </Text>\n {historyData.length === 0 ? (\n <Text dimColor>No saved benchmarks found in ~/.gerbil/benchmarks.json</Text>\n ) : (\n <>\n <Box flexDirection=\"column\" marginY={1}>\n {historyData\n .slice(-10)\n .reverse()\n .map((b, i) => (\n <Text dimColor key={i}>\n <Text color=\"cyan\">{b.tokensPerSec}</Text> tok/s,{\" \"}\n <Text color=\"yellow\">{b.firstTokenMs}</Text>ms first\n <Text dimColor>\n {\" \"}\n - {b.model} [{b.device}] {new Date(b.timestamp).toLocaleDateString()}\n </Text>\n </Text>\n ))}\n {historyData.length > 10 && (\n <Text dimColor>... and {historyData.length - 10} more</Text>\n )}\n </Box>\n <Text dimColor>\n Press <Text color=\"yellow\">l</Text> to load all history into session |{\" \"}\n <Text color=\"yellow\">h</Text> to close\n </Text>\n </>\n )}\n </Box>\n )}\n\n <Box marginTop={1}>\n <Text dimColor>\n <Text color=\"yellow\">Enter</Text> run | <Text color=\"yellow\">d</Text> switch{\" \"}\n {currentDevice === \"webgpu\" ? \"CPU\" : \"GPU\"} | <Text color=\"yellow\">m</Text> model |{\" \"}\n <Text color=\"yellow\">h</Text> history | <Text color=\"yellow\">r</Text> reset |{\" \"}\n <Text color=\"gray\">Esc</Text> back\n </Text>\n </Box>\n </Box>\n );\n}\n","import fs from \"fs\";\nimport { Box, Text, useInput } from \"ink\";\nimport SelectInput from \"ink-select-input\";\nimport Spinner from \"ink-spinner\";\nimport TextInput from \"ink-text-input\";\nimport path from \"path\";\nimport type React from \"react\";\nimport { useEffect, useState } from \"react\";\nimport type { Gerbil } from \"../../../core/gerbil.js\";\nimport {\n executeToolCall,\n formatToolsForPrompt,\n getToolDefinitions,\n parseToolCall,\n} from \"../../../core/tools.js\";\n\ntype Message = {\n role: \"user\" | \"assistant\" | \"thinking\" | \"system\";\n content: string;\n};\n\ntype ChatViewProps = {\n gerbil: Gerbil;\n thinkingMode: boolean;\n agentMode: boolean;\n onCreateTool?: () => void;\n onGenerationComplete?: (stats: { tokensOut: number; timeMs: number; tokPerSec: number }) => void;\n /** Last generation tok/s */\n lastTokPerSec?: number;\n /** Average tok/s across session */\n avgTokPerSec?: number;\n};\n\n// Chat modes with system prompts\nconst CHAT_MODES = {\n assistant: {\n name: \"Assistant\",\n symbol: \">\",\n description: \"Helpful and concise\",\n system: `You are Gerbil, a helpful AI assistant running locally. Be concise and direct.\n- Answer questions clearly without unnecessary preamble\n- If you don't know something, say so\n- Use markdown formatting when helpful\n- Keep responses focused and actionable`,\n },\n coder: {\n name: \"Coder\",\n symbol: \"$\",\n description: \"Code-focused, minimal talk\",\n system: `You are Gerbil, a local coding assistant. Be extremely concise.\n- Output code first, explanations only if asked\n- Use proper syntax highlighting hints\n- Prefer working examples over theory\n- When fixing bugs, show the fix directly\n- No pleasantries, just solutions`,\n },\n teacher: {\n name: \"Teacher\",\n symbol: \"?\",\n description: \"Explains concepts clearly\",\n system: `You are Gerbil, a patient teacher who explains concepts clearly.\n- Break down complex topics into simple parts\n- Use analogies and examples\n- Check understanding with questions\n- Build from fundamentals\n- Encourage curiosity`,\n },\n creative: {\n name: \"Creative\",\n symbol: \"*\",\n description: \"Expressive and imaginative\",\n system: `You are Gerbil, a creative collaborator with an expressive style.\n- Embrace unconventional ideas\n- Use vivid language and metaphors\n- Explore possibilities freely\n- Be playful when appropriate\n- Think outside the box`,\n },\n minimal: {\n name: \"Minimal\",\n symbol: \".\",\n description: \"Ultra-short responses\",\n system: \"You are Gerbil. Respond in as few words as possible. No fluff. Direct answers only.\",\n },\n};\n\ntype ChatMode = keyof typeof CHAT_MODES;\n\n// Rough token estimation (4 chars per token average)\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n// Strip all think tags from content\nfunction stripThinkTags(content: string): string {\n return content\n .replace(/<think>[\\s\\S]*?<\\/think>/g, \"\")\n .replace(/<\\/?think>/g, \"\")\n .trim();\n}\n\n// Simple terminal markdown renderer\nfunction renderMarkdown(content: string): React.ReactNode[] {\n const lines = content.split(\"\\n\");\n const elements: React.ReactNode[] = [];\n let inCodeBlock = false;\n let codeBlockContent: string[] = [];\n let codeBlockLang = \"\";\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Code blocks\n if (line.startsWith(\"```\")) {\n if (inCodeBlock) {\n // End code block\n elements.push(\n <Box\n borderColor=\"gray\"\n borderStyle=\"single\"\n flexDirection=\"column\"\n key={`code-${i}`}\n marginY={1}\n paddingX={1}\n >\n {codeBlockLang && <Text dimColor>{codeBlockLang}</Text>}\n <Text color=\"green\">{codeBlockContent.join(\"\\n\")}</Text>\n </Box>,\n );\n codeBlockContent = [];\n codeBlockLang = \"\";\n inCodeBlock = false;\n } else {\n inCodeBlock = true;\n codeBlockLang = line.slice(3).trim();\n }\n continue;\n }\n\n if (inCodeBlock) {\n codeBlockContent.push(line);\n continue;\n }\n\n // Headers\n if (line.startsWith(\"### \")) {\n elements.push(\n <Text bold color=\"cyan\" key={i}>\n {line.slice(4)}\n </Text>,\n );\n continue;\n }\n if (line.startsWith(\"## \")) {\n elements.push(\n <Text bold color=\"yellow\" key={i}>\n {line.slice(3)}\n </Text>,\n );\n continue;\n }\n if (line.startsWith(\"# \")) {\n elements.push(\n <Text bold color=\"magenta\" key={i}>\n {line.slice(2)}\n </Text>,\n );\n continue;\n }\n\n // Bullet points\n if (line.match(/^[-*]\\s/)) {\n const bulletContent = line.slice(2);\n elements.push(\n <Text key={i}>\n <Text color=\"cyan\"> * </Text>\n {renderInlineMarkdown(bulletContent)}\n </Text>,\n );\n continue;\n }\n\n // Numbered lists\n const numMatch = line.match(/^(\\d+)\\.\\s(.*)$/);\n if (numMatch) {\n elements.push(\n <Text key={i}>\n <Text color=\"cyan\"> {numMatch[1]}. </Text>\n {renderInlineMarkdown(numMatch[2])}\n </Text>,\n );\n continue;\n }\n\n // Regular text with inline formatting\n elements.push(<Text key={i}>{renderInlineMarkdown(line)}</Text>);\n }\n\n return elements;\n}\n\n// Render inline markdown (bold, italic, code, links)\nfunction renderInlineMarkdown(text: string): React.ReactNode {\n // Split by inline code, bold, and italic markers\n const parts: React.ReactNode[] = [];\n let remaining = text;\n let key = 0;\n\n while (remaining.length > 0) {\n // Inline code `code`\n const codeMatch = remaining.match(/^(.*?)`([^`]+)`(.*)$/);\n if (codeMatch) {\n if (codeMatch[1]) {\n parts.push(<Text key={key++}>{codeMatch[1]}</Text>);\n }\n parts.push(\n <Text backgroundColor=\"black\" color=\"green\" key={key++}>\n {\" \"}\n {codeMatch[2]}{\" \"}\n </Text>,\n );\n remaining = codeMatch[3];\n continue;\n }\n\n // Bold **text**\n const boldMatch = remaining.match(/^(.*?)\\*\\*([^*]+)\\*\\*(.*)$/);\n if (boldMatch) {\n if (boldMatch[1]) {\n parts.push(<Text key={key++}>{boldMatch[1]}</Text>);\n }\n parts.push(\n <Text bold key={key++}>\n {boldMatch[2]}\n </Text>,\n );\n remaining = boldMatch[3];\n continue;\n }\n\n // Italic *text*\n const italicMatch = remaining.match(/^(.*?)\\*([^*]+)\\*(.*)$/);\n if (italicMatch) {\n if (italicMatch[1]) {\n parts.push(<Text key={key++}>{italicMatch[1]}</Text>);\n }\n parts.push(\n <Text italic key={key++}>\n {italicMatch[2]}\n </Text>,\n );\n remaining = italicMatch[3];\n continue;\n }\n\n // No more formatting found\n parts.push(<Text key={key++}>{remaining}</Text>);\n break;\n }\n\n return <>{parts}</>;\n}\n\n// Parse streaming content to separate thinking from response\nfunction parseStreamContent(\n content: string,\n showThinking: boolean,\n): { thinking: string; response: string; isThinking: boolean } {\n if (!showThinking) {\n return { thinking: \"\", response: stripThinkTags(content), isThinking: false };\n }\n\n // Check for opening <think> tag (may be incomplete during streaming)\n const thinkStart = content.indexOf(\"<think>\");\n const thinkEnd = content.indexOf(\"</think>\");\n\n // Currently inside a think block (has opening but no closing)\n if (thinkStart !== -1 && thinkEnd === -1) {\n const thinking = content.slice(thinkStart + 7);\n const response = content.slice(0, thinkStart).trim();\n return { thinking, response, isThinking: true };\n }\n\n // Has complete think block\n if (thinkStart !== -1 && thinkEnd !== -1 && thinkEnd > thinkStart) {\n const thinking = content.slice(thinkStart + 7, thinkEnd).trim();\n const response = stripThinkTags(content);\n return { thinking, response, isThinking: false };\n }\n\n // No think tags at all - strip any partial/malformed tags just in case\n return { thinking: \"\", response: stripThinkTags(content), isThinking: false };\n}\n\nfunction StreamingResponse({\n content,\n symbol,\n showThinking,\n}: {\n content: string;\n symbol: string;\n showThinking: boolean;\n}) {\n const { thinking, response, isThinking } = parseStreamContent(content, showThinking);\n\n return (\n <Box flexDirection=\"column\" marginBottom={1} paddingX={1}>\n {showThinking && thinking && (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text color=\"gray\" dimColor italic>\n {\"<think>\"}\n </Text>\n <Text dimColor italic>\n {stripThinkTags(thinking)}\n {isThinking && <Spinner type=\"dots\" />}\n </Text>\n </Box>\n )}\n {response && (\n <Box>\n <Text bold color=\"cyan\">\n {symbol}{\" \"}\n </Text>\n <Text bold color=\"white\">\n {response}\n </Text>\n {!isThinking && (\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n )}\n </Box>\n )}\n {!(thinking || response) && (\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n )}\n </Box>\n );\n}\n\n// Build conversation history for context\nfunction buildConversationContext(messages: Message[], mode: ChatMode): string {\n const systemPrompt = CHAT_MODES[mode].system;\n let context = `<|im_start|>system\\n${systemPrompt}<|im_end|>\\n`;\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n context += `<|im_start|>user\\n${msg.content}<|im_end|>\\n`;\n } else if (msg.role === \"assistant\") {\n context += `<|im_start|>assistant\\n${msg.content}<|im_end|>\\n`;\n }\n // Skip thinking and system messages for context\n }\n\n return context;\n}\n\nexport function ChatView({\n gerbil,\n thinkingMode,\n agentMode,\n onCreateTool,\n onGenerationComplete,\n lastTokPerSec,\n avgTokPerSec,\n}: ChatViewProps) {\n const [messages, setMessages] = useState<Message[]>([]);\n const [input, setInput] = useState(\"\");\n const [generating, setGenerating] = useState(false);\n const [streamedContent, setStreamedContent] = useState(\"\");\n const [mode, setMode] = useState<ChatMode>(\"assistant\");\n const [showModeSelector, setShowModeSelector] = useState(false);\n const [summarizing, setSummarizing] = useState(false);\n\n // Command history\n const [history, setHistory] = useState<string[]>([]);\n const [historyIndex, setHistoryIndex] = useState(-1);\n const [savedInput, setSavedInput] = useState(\"\");\n\n // Track previous mode values to detect changes\n const [prevThinkingMode, setPrevThinkingMode] = useState(thinkingMode);\n const [prevAgentMode, setPrevAgentMode] = useState(agentMode);\n\n // Show feedback when modes change\n useEffect(() => {\n if (thinkingMode !== prevThinkingMode) {\n setPrevThinkingMode(thinkingMode);\n setMessages((m) => [\n ...m,\n {\n role: \"system\",\n content: thinkingMode ? \"🧠 Thinking mode enabled\" : \"🧠 Thinking mode disabled\",\n },\n ]);\n }\n }, [thinkingMode, prevThinkingMode]);\n\n useEffect(() => {\n if (agentMode !== prevAgentMode) {\n setPrevAgentMode(agentMode);\n setMessages((m) => [\n ...m,\n {\n role: \"system\",\n content: agentMode ? \"🔧 Agent mode enabled (tools available)\" : \"🔧 Agent mode disabled\",\n },\n ]);\n }\n }, [agentMode, prevAgentMode]);\n\n const modes = Object.keys(CHAT_MODES) as ChatMode[];\n\n // Get model info for context limits\n const modelInfo = gerbil.getModelInfo();\n const maxContext = modelInfo?.contextLength || 32_768;\n\n // Calculate current context usage\n const contextText = buildConversationContext(messages, mode);\n const currentTokens = estimateTokens(contextText);\n const contextPercent = Math.round((currentTokens / maxContext) * 100);\n\n // Handle Tab for mode selector, Up/Down for history, and Cmd shortcuts\n useInput((char, key) => {\n if (key.tab && !generating) {\n setShowModeSelector((s) => !s);\n }\n\n // Cmd+C to copy chat\n if (char === \"c\" && key.meta) {\n copyChat();\n }\n\n // Cmd+S to save chat\n if (char === \"s\" && key.meta) {\n saveChat();\n }\n\n // Navigate history with Up/Down arrows\n if (!(generating || showModeSelector)) {\n if (key.upArrow && history.length > 0) {\n if (historyIndex === -1) {\n // Save current input before browsing history\n setSavedInput(input);\n setHistoryIndex(history.length - 1);\n setInput(history.at(-1) ?? \"\");\n } else if (historyIndex > 0) {\n setHistoryIndex(historyIndex - 1);\n setInput(history[historyIndex - 1]);\n }\n }\n if (key.downArrow && historyIndex !== -1) {\n if (historyIndex < history.length - 1) {\n setHistoryIndex(historyIndex + 1);\n setInput(history[historyIndex + 1]);\n } else {\n // Return to saved input\n setHistoryIndex(-1);\n setInput(savedInput);\n }\n }\n }\n });\n\n // Summarize conversation and reset context\n const summarizeConversation = async () => {\n if (messages.length < 4) {\n setMessages((m) => [...m, { role: \"system\", content: \"Not enough messages to summarize.\" }]);\n return;\n }\n\n setSummarizing(true);\n setMessages((m) => [...m, { role: \"system\", content: \"Summarizing conversation...\" }]);\n\n try {\n const conversationText = messages\n .filter((m) => m.role === \"user\" || m.role === \"assistant\")\n .map((m) => `${m.role === \"user\" ? \"User\" : \"Assistant\"}: ${m.content}`)\n .join(\"\\n\");\n\n let summary = \"\";\n for await (const chunk of gerbil.stream(\n `Summarize this conversation in 2-3 sentences, capturing the key topics and conclusions:\\n\\n${conversationText}`,\n { maxTokens: 200, system: \"You are a summarizer. Be concise.\" },\n )) {\n summary += chunk;\n }\n\n summary = stripThinkTags(summary);\n\n // Reset messages with just the summary\n setMessages([\n { role: \"system\", content: `Previous conversation summary: ${summary}` },\n { role: \"system\", content: \"Context compressed. Continuing from summary above.\" },\n ]);\n } catch (e) {\n setMessages((m) => [...m, { role: \"system\", content: `Error summarizing: ${e}` }]);\n }\n\n setSummarizing(false);\n };\n\n // Format chat as text\n const formatChatContent = () => {\n let content = `# Gerbil Chat - ${new Date().toLocaleString()}\\n\\n`;\n content += `**Mode:** ${CHAT_MODES[mode].name}\\n`;\n content += `**Model:** ${modelInfo?.id || \"unknown\"}\\n\\n`;\n content += \"---\\n\\n\";\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n content += `**You:** ${msg.content}\\n\\n`;\n } else if (msg.role === \"assistant\") {\n content += `**Gerbil:** ${msg.content}\\n\\n`;\n } else if (msg.role === \"system\") {\n content += `*${msg.content}*\\n\\n`;\n }\n }\n return content;\n };\n\n // Copy chat to clipboard\n const copyChat = () => {\n const content = formatChatContent();\n const { exec } = require(\"child_process\");\n const platform = process.platform;\n\n const cmd =\n platform === \"darwin\"\n ? \"pbcopy\"\n : platform === \"win32\"\n ? \"clip\"\n : \"xclip -selection clipboard\";\n const proc = exec(cmd, (err: any) => {\n if (err) {\n setMessages((m) => [...m, { role: \"system\", content: `Copy failed: ${err}` }]);\n } else {\n setMessages((m) => [...m, { role: \"system\", content: \"Chat copied to clipboard\" }]);\n }\n });\n proc.stdin?.write(content);\n proc.stdin?.end();\n };\n\n // Save chat to file\n const saveChat = (filename?: string) => {\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\").slice(0, 19);\n const fname = filename || `gerbil-chat-${timestamp}.md`;\n const fpath = path.join(process.cwd(), fname);\n\n const content = formatChatContent();\n\n try {\n fs.writeFileSync(fpath, content);\n setMessages((m) => [...m, { role: \"system\", content: `Chat saved to ${fname}` }]);\n } catch (e) {\n setMessages((m) => [...m, { role: \"system\", content: `Error saving: ${e}` }]);\n }\n };\n\n const handleSubmit = async (value: string) => {\n if (!value.trim() || generating || summarizing) {\n return;\n }\n\n // Handle slash commands\n if (value.startsWith(\"/\")) {\n const parts = value.slice(1).split(\" \");\n const cmd = parts[0].toLowerCase().trim();\n const arg = parts.slice(1).join(\" \");\n\n if (cmd === \"clear\" || cmd === \"new\") {\n setMessages([]);\n setInput(\"\");\n return;\n }\n if (cmd === \"mode\") {\n setShowModeSelector(true);\n setInput(\"\");\n return;\n }\n if (cmd === \"summarize\" || cmd === \"compress\") {\n setInput(\"\");\n await summarizeConversation();\n return;\n }\n if (cmd === \"reset-cache\" || cmd === \"reset\") {\n setInput(\"\");\n try {\n await gerbil.clearCache();\n const mem = await gerbil.getMemoryUsage();\n const memInfo = mem ? ` (was ${mem.usedGB.toFixed(1)}GB)` : \"\";\n setMessages((m) => [\n ...m,\n { role: \"system\", content: `🧹 Cache cleared${memInfo}. Conversation context reset.` },\n ]);\n } catch (err) {\n setMessages((m) => [\n ...m,\n { role: \"system\", content: `❌ Failed to clear cache: ${err}` },\n ]);\n }\n return;\n }\n if (cmd === \"memory\" || cmd === \"mem\") {\n setInput(\"\");\n try {\n const mem = await gerbil.getMemoryUsage();\n if (mem) {\n setMessages((m) => [\n ...m,\n {\n role: \"system\",\n content: `💾 Memory: ${mem.usedGB.toFixed(1)}GB / ${mem.totalGB.toFixed(1)}GB (${mem.usedPercent.toFixed(1)}%)`,\n },\n ]);\n } else {\n setMessages((m) => [\n ...m,\n { role: \"system\", content: \"Memory monitoring not available (CPU mode)\" },\n ]);\n }\n } catch (err) {\n setMessages((m) => [\n ...m,\n { role: \"system\", content: `❌ Failed to get memory: ${err}` },\n ]);\n }\n return;\n }\n if (cmd === \"save\") {\n setInput(\"\");\n saveChat(arg || undefined);\n return;\n }\n if (cmd === \"help\") {\n setMessages((m) => [\n ...m,\n {\n role: \"system\",\n content: `Commands:\n /new, /clear - Start new chat\n /docs <topic> - Search Gerbil docs (tools, skills, ai-sdk, next, etc.)\n /summarize - Compress conversation\n /reset-cache - Clear KV cache (frees memory)\n /memory - Show memory usage\n /mode - Change chat mode\n\nShortcuts:\n ⌘C - Copy chat to clipboard\n ⌘S - Save chat to file \n ^T - Toggle thinking mode\n ^A - Toggle agent mode\n Tab - Mode selector`,\n },\n ]);\n setInput(\"\");\n return;\n }\n\n // /docs command - direct docs search\n if (cmd === \"docs\" && arg) {\n setInput(\"\");\n setGenerating(true);\n try {\n const result = await executeToolCall(\"gerbil_docs\", { query: arg });\n setMessages((m) => [\n ...m,\n {\n role: \"system\",\n content: `📄 docs(${arg}):\\n${result.slice(0, 600)}${result.length > 600 ? \"...\" : \"\"}`,\n },\n ]);\n } catch (e) {\n setMessages((m) => [...m, { role: \"system\", content: `Error: ${e}` }]);\n }\n setGenerating(false);\n return;\n }\n }\n\n const userMessage = value.trim();\n setInput(\"\");\n\n // Add to history (avoid duplicates)\n if (history.at(-1) !== userMessage) {\n setHistory((h) => [...h.slice(-50), userMessage]); // Keep last 50\n }\n setHistoryIndex(-1);\n setSavedInput(\"\");\n\n setMessages((m) => [...m, { role: \"user\", content: userMessage }]);\n setGenerating(true);\n setStreamedContent(\"\");\n\n try {\n let fullResponse = \"\";\n const currentMode = CHAT_MODES[mode];\n const startTime = performance.now();\n let tokenCount = 0;\n\n // Build system prompt - replace with agent prompt if agent mode is enabled\n let systemPrompt = currentMode.system;\n\n if (agentMode) {\n const tools = getToolDefinitions();\n // Agent mode uses its own prompt entirely (not combined with mode)\n systemPrompt = formatToolsForPrompt(tools);\n }\n\n for await (const chunk of gerbil.stream(userMessage, {\n thinking: thinkingMode,\n maxTokens: 500,\n system: systemPrompt,\n })) {\n fullResponse += chunk;\n tokenCount++;\n setStreamedContent(fullResponse);\n }\n\n // Calculate and report tok/s\n const endTime = performance.now();\n const timeMs = endTime - startTime;\n const tokPerSec = timeMs > 0 ? (tokenCount / timeMs) * 1000 : 0;\n onGenerationComplete?.({ tokensOut: tokenCount, timeMs, tokPerSec });\n\n let response = stripThinkTags(fullResponse);\n\n // Check for tool calls in agent mode\n if (agentMode) {\n const toolCall = parseToolCall(response);\n if (toolCall) {\n // Show that we're calling a tool\n setMessages((m) => [\n ...m,\n {\n role: \"system\",\n content: `🔧 Calling: ${toolCall.tool}(${JSON.stringify(toolCall.params)})`,\n },\n ]);\n setStreamedContent(\"\");\n\n // Execute the tool\n const toolResult = await executeToolCall(toolCall.tool, toolCall.params);\n\n // Add tool result (truncate if too long)\n const truncatedResult =\n toolResult.length > 500 ? `${toolResult.slice(0, 500)}\\n... (truncated)` : toolResult;\n setMessages((m) => [...m, { role: \"system\", content: `📄 Result:\\n${truncatedResult}` }]);\n\n // Generate follow-up response with tool result\n let followUp = \"\";\n for await (const chunk of gerbil.stream(\n `Here's documentation:\\n${toolResult}\\n\\nSummarize this for the user who asked: \"${userMessage}\"`,\n { maxTokens: 300, system: \"You are helpful. Summarize the documentation briefly.\" },\n )) {\n followUp += chunk;\n setStreamedContent(followUp);\n }\n response = stripThinkTags(followUp);\n\n // If follow-up is empty, just show the tool worked\n if (!response.trim()) {\n response = \"See the documentation above.\";\n }\n }\n }\n\n const thinkMatch = fullResponse.match(/<think>([\\s\\S]*?)<\\/think>/);\n let thinking = \"\";\n\n if (thinkMatch && thinkingMode) {\n // Extract content and strip any remaining tags\n thinking = stripThinkTags(thinkMatch[1]).trim();\n }\n\n setMessages((m) => {\n const newMessages = [...m];\n if (thinking && thinkingMode) {\n newMessages.push({ role: \"thinking\", content: thinking });\n }\n newMessages.push({ role: \"assistant\", content: response });\n return newMessages;\n });\n } catch (error) {\n setMessages((m) => [...m, { role: \"assistant\", content: `Error: ${error}` }]);\n } finally {\n setGenerating(false);\n setStreamedContent(\"\");\n }\n };\n\n const modeItems = modes.map((key) => ({\n key,\n label: `[${CHAT_MODES[key].symbol}] ${CHAT_MODES[key].name}`,\n value: key,\n }));\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n {/* Mode selector popup */}\n {showModeSelector && (\n <Box\n borderColor=\"cyan\"\n borderStyle=\"round\"\n flexDirection=\"column\"\n marginX={1}\n paddingX={2}\n paddingY={1}\n >\n <Text bold color=\"cyan\">\n Select Mode\n </Text>\n <Box marginY={1}>\n <SelectInput\n initialIndex={modes.indexOf(mode)}\n itemComponent={({ isSelected, label }) => {\n const modeKey = modeItems.find((m) => m.label === label)?.value as ChatMode;\n const modeInfo = modeKey ? CHAT_MODES[modeKey] : null;\n return (\n <Box>\n <Text bold={isSelected} color={isSelected ? \"cyan\" : \"white\"}>\n {isSelected ? \"> \" : \" \"}\n {label}\n </Text>\n {isSelected && modeInfo && <Text dimColor> - {modeInfo.description}</Text>}\n </Box>\n );\n }}\n items={modeItems}\n onSelect={(item) => {\n setMode(item.value as ChatMode);\n setShowModeSelector(false);\n }}\n />\n </Box>\n <Text dimColor>Tab to close</Text>\n </Box>\n )}\n\n {/* Header with mode and context info */}\n {!showModeSelector && (\n <Box justifyContent=\"space-between\" paddingX={1}>\n <Text color=\"gray\">\n [{CHAT_MODES[mode].symbol}] {CHAT_MODES[mode].name}\n {agentMode && <Text color=\"cyan\"> +tools</Text>}\n <Text dimColor> | tab mode | </Text>\n <Text color=\"magenta\">^T</Text>\n <Text dimColor>hinking | </Text>\n <Text color=\"green\">^A</Text>\n <Text dimColor>gent | /help</Text>\n </Text>\n <Box>\n {lastTokPerSec !== undefined && lastTokPerSec > 0 && (\n <>\n <Text color=\"yellow\">{lastTokPerSec.toFixed(1)}</Text>\n <Text dimColor> tok/s</Text>\n {avgTokPerSec !== undefined && avgTokPerSec > 0 && (\n <>\n <Text dimColor> (avg </Text>\n <Text color=\"cyan\">{avgTokPerSec.toFixed(1)}</Text>\n <Text dimColor>)</Text>\n </>\n )}\n <Text dimColor> </Text>\n </>\n )}\n <Text color={contextPercent > 80 ? \"red\" : contextPercent > 50 ? \"yellow\" : \"green\"}>\n {currentTokens.toLocaleString()}/{maxContext.toLocaleString()} tokens (\n {contextPercent}%)\n </Text>\n </Box>\n </Box>\n )}\n\n {/* Messages */}\n <Box flexDirection=\"column\" flexGrow={1} overflowY=\"hidden\">\n {messages.length === 0 && !generating && (\n <Box padding={1}>\n <Text color=\"gray\">Start a conversation. Type a message and press Enter.</Text>\n </Box>\n )}\n\n {messages.map((msg, i) => (\n <Box key={i} marginBottom={1} paddingX={1}>\n {msg.role === \"user\" && (\n <Box>\n <Text bold color=\"cyan\">\n You:{\" \"}\n </Text>\n <Text>{msg.content}</Text>\n </Box>\n )}\n {msg.role === \"thinking\" && (\n <Box flexDirection=\"column\">\n <Text color=\"gray\" dimColor italic>\n {\"<think>\"}\n </Text>\n <Text dimColor italic>\n {msg.content}\n </Text>\n </Box>\n )}\n {msg.role === \"assistant\" && (\n <Box>\n <Text bold color=\"cyan\">\n {CHAT_MODES[mode].symbol}{\" \"}\n </Text>\n <Box flexDirection=\"column\" flexGrow={1}>\n {renderMarkdown(msg.content)}\n </Box>\n </Box>\n )}\n {msg.role === \"system\" &&\n (msg.content.startsWith(\"🔧 Calling\") ? (\n <Text color=\"cyan\" dimColor>\n ◆{\" \"}\n {msg.content\n .replace(\"🔧 Calling: \", \"\")\n .replace(\"gerbil_docs\", \"docs\")\n .replace(\"run_skill\", \"skill\")}\n </Text>\n ) : msg.content.startsWith(\"📄\") ? (\n <Box borderColor=\"gray\" borderStyle=\"single\" marginBottom={1} paddingX={1}>\n <Text color=\"gray\">\n {msg.content.replace(\"📄 Result:\\n\", \"\").slice(0, 300)}\n {msg.content.replace(\"📄 Result:\\n\", \"\").length > 300 ? \"...\" : \"\"}\n </Text>\n </Box>\n ) : msg.content.startsWith(\"🧠\") ? (\n <Text color=\"magenta\" dimColor>\n ◆ {msg.content}\n </Text>\n ) : msg.content.startsWith(\"🔧 Agent\") ? (\n <Text color=\"green\" dimColor>\n ◆ {msg.content}\n </Text>\n ) : (\n <Text color=\"yellow\" dimColor>\n {msg.content}\n </Text>\n ))}\n </Box>\n ))}\n\n {/* Streaming response */}\n {generating && streamedContent && (\n <StreamingResponse\n content={streamedContent}\n showThinking={thinkingMode}\n symbol={CHAT_MODES[mode].symbol}\n />\n )}\n\n {generating && !streamedContent && (\n <Box paddingX={1}>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text color=\"gray\"> Thinking...</Text>\n </Box>\n )}\n\n {summarizing && (\n <Box paddingX={1}>\n <Text color=\"yellow\">\n <Spinner type=\"dots\" />\n </Text>\n <Text color=\"gray\"> Summarizing...</Text>\n </Box>\n )}\n </Box>\n\n {/* Context warning */}\n {contextPercent > 80 && (\n <Box paddingX={1}>\n <Text color=\"red\">Context {contextPercent}% full. Use /summarize to compress.</Text>\n </Box>\n )}\n\n {/* Input */}\n <Box\n borderColor={generating || summarizing ? \"gray\" : \"cyan\"}\n borderStyle=\"single\"\n paddingX={1}\n >\n <Text color=\"cyan\">> </Text>\n <TextInput\n onChange={setInput}\n onSubmit={handleSubmit}\n placeholder={\n generating ? \"generating...\" : summarizing ? \"summarizing...\" : \"type a message...\"\n }\n value={input}\n />\n </Box>\n </Box>\n );\n}\n","import { exec } from \"child_process\";\nimport fs from \"fs\";\nimport { Box, Text, useInput } from \"ink\";\nimport Spinner from \"ink-spinner\";\nimport TextInput from \"ink-text-input\";\nimport os from \"os\";\nimport path from \"path\";\nimport { useState } from \"react\";\nimport type { Gerbil } from \"../../../core/gerbil.js\";\n\n// Copy to clipboard utility\nfunction copyToClipboard(text: string): Promise<boolean> {\n return new Promise((resolve) => {\n const platform = os.platform();\n let cmd: string;\n\n if (platform === \"darwin\") {\n cmd = \"pbcopy\";\n } else if (platform === \"linux\") {\n cmd = \"xclip -selection clipboard\";\n } else if (platform === \"win32\") {\n cmd = \"clip\";\n } else {\n resolve(false);\n return;\n }\n\n const proc = exec(cmd, (err) => {\n resolve(!err);\n });\n proc.stdin?.write(text);\n proc.stdin?.end();\n });\n}\n\n// File extension map for languages\nconst LANG_EXTENSIONS: Record<string, string> = {\n typescript: \"ts\",\n javascript: \"js\",\n python: \"py\",\n rust: \"rs\",\n go: \"go\",\n java: \"java\",\n cpp: \"cpp\",\n c: \"c\",\n ruby: \"rb\",\n php: \"php\",\n swift: \"swift\",\n kotlin: \"kt\",\n sql: \"sql\",\n bash: \"sh\",\n shell: \"sh\",\n html: \"html\",\n css: \"css\",\n json: \"json\",\n yaml: \"yaml\",\n markdown: \"md\",\n};\n\ntype CodeViewProps = {\n gerbil: Gerbil;\n};\n\ntype Phase = \"input\" | \"generating\" | \"result\";\n\nexport function CodeView({ gerbil }: CodeViewProps) {\n const [phase, setPhase] = useState<Phase>(\"input\");\n const [prompt, setPrompt] = useState(\"\");\n const [code, setCode] = useState(\"\");\n const [language, setLanguage] = useState(\"typescript\");\n const [error, setError] = useState<string | null>(null);\n const [saveStatus, setSaveStatus] = useState<string | null>(null);\n const [copyStatus, setCopyStatus] = useState<string | null>(null);\n\n const handleSave = async () => {\n if (!code || phase !== \"result\" || error) {\n return;\n }\n\n // Generate filename from prompt (sanitized)\n const baseName =\n prompt\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 30) || \"generated\";\n\n const ext = LANG_EXTENSIONS[language] || \"txt\";\n const fileName = `${baseName}.${ext}`;\n const filePath = path.join(process.cwd(), fileName);\n\n try {\n fs.writeFileSync(filePath, code, \"utf-8\");\n setSaveStatus(`Saved to ${fileName}`);\n setTimeout(() => setSaveStatus(null), 3000);\n } catch (err) {\n setSaveStatus(`Error: ${err}`);\n setTimeout(() => setSaveStatus(null), 3000);\n }\n };\n\n const handleCopy = async () => {\n if (!code || phase !== \"result\" || error) {\n return;\n }\n\n const success = await copyToClipboard(code);\n setCopyStatus(success ? \"Copied to clipboard!\" : \"Failed to copy\");\n setTimeout(() => setCopyStatus(null), 2000);\n };\n\n const handleSubmit = async (value: string) => {\n if (!value.trim()) {\n return;\n }\n\n setPrompt(value);\n setPhase(\"generating\");\n setError(null);\n\n try {\n const result = await gerbil.generate(value, {\n maxTokens: 1000,\n temperature: 0.3,\n system: `You are an expert programmer. Generate clean, working code.\nWhen asked to generate code:\n1. Output ONLY the code, no explanations before or after\n2. Use proper formatting and comments within the code\n3. Make the code complete and runnable\n4. Detect the appropriate language from the request`,\n });\n\n // Try to detect language and clean up code\n let generatedCode = result.text;\n\n // Extract language from code fence if present\n const langMatch = generatedCode.match(/```(\\w+)\\n/);\n if (langMatch) {\n setLanguage(langMatch[1]);\n }\n\n // Remove code fences and think tags\n generatedCode = generatedCode\n .replace(/<think>[\\s\\S]*?<\\/think>/g, \"\") // Remove think blocks\n .replace(/```\\w*\\n?/g, \"\")\n .replace(/```\\n?/g, \"\")\n .trim();\n\n setCode(generatedCode);\n setPhase(\"result\");\n } catch (err) {\n setError(String(err));\n setPhase(\"result\");\n }\n };\n\n const handleReset = () => {\n setPhase(\"input\");\n setPrompt(\"\");\n setCode(\"\");\n setError(null);\n };\n\n useInput((input, key) => {\n if (key.escape && phase === \"result\") {\n handleReset();\n }\n\n // Save and copy shortcuts when code is generated\n if (phase === \"result\" && !error) {\n if (input === \"s\" || input === \"S\") {\n handleSave();\n }\n if (input === \"c\" || input === \"C\") {\n handleCopy();\n }\n }\n });\n\n if (phase === \"input\") {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Box marginBottom={1}>\n <Text bold>💻 Generate Code</Text>\n </Box>\n <Box marginBottom={1}>\n <Text color=\"gray\">Describe what code you want to generate:</Text>\n </Box>\n <Box borderColor=\"cyan\" borderStyle=\"single\" paddingX={1}>\n <Text color=\"cyan\">❯ </Text>\n <TextInput\n onChange={setPrompt}\n onSubmit={handleSubmit}\n placeholder=\"e.g., A function that calculates fibonacci numbers\"\n value={prompt}\n />\n </Box>\n <Box marginTop={1}>\n <Text color=\"gray\" dimColor>\n Examples:\n </Text>\n </Box>\n <Text color=\"gray\" dimColor>\n • A React hook for debouncing\n </Text>\n <Text color=\"gray\" dimColor>\n • Python script to parse CSV files\n </Text>\n <Text color=\"gray\" dimColor>\n • SQL query to find duplicate records\n </Text>\n </Box>\n );\n }\n\n if (phase === \"generating\") {\n return (\n <Box padding={1}>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text> Generating code...</Text>\n </Box>\n );\n }\n\n // Result phase\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Box marginBottom={1}>\n <Text bold color={error ? \"red\" : \"green\"}>\n {error ? \"[x] Error\" : \"[done] Generated Code\"}\n </Text>\n {!error && <Text color=\"gray\"> -- {language}</Text>}\n </Box>\n\n {!error && (\n <Box marginBottom={1}>\n <Text color=\"gray\" dimColor>\n Prompt: {prompt}\n </Text>\n </Box>\n )}\n\n <Box\n borderColor={error ? \"red\" : \"cyan\"}\n borderStyle=\"single\"\n flexDirection=\"column\"\n padding={1}\n >\n <Text color={error ? \"red\" : \"white\"} wrap=\"wrap\">\n {error || code}\n </Text>\n </Box>\n\n {/* Status messages */}\n {saveStatus && (\n <Box marginTop={1}>\n <Text color={saveStatus.startsWith(\"Error\") ? \"red\" : \"green\"}>{saveStatus}</Text>\n </Box>\n )}\n {copyStatus && (\n <Box marginTop={1}>\n <Text color={copyStatus.includes(\"Failed\") ? \"red\" : \"green\"}>{copyStatus}</Text>\n </Box>\n )}\n\n <Box marginTop={1}>\n {error ? (\n <Text dimColor>Esc to try again</Text>\n ) : (\n <Text dimColor>\n <Text color=\"yellow\">s</Text> save to file | <Text color=\"yellow\">c</Text> copy to\n clipboard | <Text color=\"gray\">Esc</Text> generate more\n </Text>\n )}\n </Box>\n </Box>\n );\n}\n","import { exec } from \"child_process\";\nimport fs from \"fs\";\nimport { Box, Text, useInput } from \"ink\";\nimport Spinner from \"ink-spinner\";\nimport TextInput from \"ink-text-input\";\nimport os from \"os\";\nimport path from \"path\";\nimport { useState } from \"react\";\nimport type { Gerbil } from \"../../../core/gerbil.js\";\n\n// Copy to clipboard utility\nfunction copyToClipboard(text: string): Promise<boolean> {\n return new Promise((resolve) => {\n const platform = os.platform();\n let cmd: string;\n\n if (platform === \"darwin\") {\n cmd = \"pbcopy\";\n } else if (platform === \"linux\") {\n cmd = \"xclip -selection clipboard\";\n } else if (platform === \"win32\") {\n cmd = \"clip\";\n } else {\n resolve(false);\n return;\n }\n\n const proc = exec(cmd, (err) => {\n resolve(!err);\n });\n proc.stdin?.write(text);\n proc.stdin?.end();\n });\n}\n\ntype CreateSkillViewProps = {\n gerbil: Gerbil;\n onDone: () => void;\n};\n\ntype Step = \"name\" | \"description\" | \"behavior\" | \"generating\" | \"done\";\n\ntype SkillDraft = {\n name: string;\n description: string;\n behavior: string;\n};\n\n// Step definitions for visual progress\nconst STEPS = [\n { key: \"name\", num: 1, title: \"Name\", hint: \"Give your skill a unique identifier\" },\n { key: \"description\", num: 2, title: \"Purpose\", hint: \"What does this skill do?\" },\n { key: \"behavior\", num: 3, title: \"Logic\", hint: \"How should it work?\" },\n] as const;\n\nexport function CreateSkillView({ gerbil, onDone }: CreateSkillViewProps) {\n const [step, setStep] = useState<Step>(\"name\");\n const [draft, setDraft] = useState<SkillDraft>({\n name: \"\",\n description: \"\",\n behavior: \"\",\n });\n const [input, setInput] = useState(\"\");\n const [generatedCode, setGeneratedCode] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [saveStatus, setSaveStatus] = useState<string | null>(null);\n const [copyStatus, setCopyStatus] = useState<string | null>(null);\n\n const currentStepNum =\n step === \"name\" ? 1 : step === \"description\" ? 2 : step === \"behavior\" ? 3 : 4;\n\n const handleSubmit = async (value: string) => {\n if (!value.trim()) {\n return;\n }\n\n if (step === \"name\") {\n // Validate kebab-case\n const kebabCase = value\n .toLowerCase()\n .replace(/\\s+/g, \"-\")\n .replace(/[^a-z0-9-]/g, \"\");\n setDraft((d) => ({ ...d, name: kebabCase }));\n setInput(\"\");\n setStep(\"description\");\n } else if (step === \"description\") {\n setDraft((d) => ({ ...d, description: value }));\n setInput(\"\");\n setStep(\"behavior\");\n } else if (step === \"behavior\") {\n setDraft((d) => ({ ...d, behavior: value }));\n setInput(\"\");\n setStep(\"generating\");\n await generateSkill({ ...draft, behavior: value });\n }\n };\n\n // Render the step progress indicator\n const renderProgress = () => (\n <Box flexDirection=\"column\" marginBottom={1}>\n {/* Progress bar */}\n <Box marginBottom={1}>\n {STEPS.map((s, i) => {\n const isComplete = currentStepNum > s.num;\n const isCurrent = step === s.key;\n const _isPending = currentStepNum < s.num;\n\n return (\n <Box key={s.key}>\n {/* Step circle */}\n <Text bold={isCurrent} color={isComplete ? \"green\" : isCurrent ? \"cyan\" : \"gray\"}>\n {isComplete ? \"[x]\" : isCurrent ? \"[>]\" : \"[ ]\"}\n </Text>\n <Text bold={isCurrent} color={isComplete ? \"green\" : isCurrent ? \"cyan\" : \"gray\"}>\n {\" \"}\n {s.title}\n </Text>\n {/* Connector line */}\n {i < STEPS.length - 1 && <Text color={isComplete ? \"green\" : \"gray\"}> --- </Text>}\n </Box>\n );\n })}\n </Box>\n\n {/* Step details summary */}\n {(draft.name || draft.description) && (\n <Box\n borderColor=\"gray\"\n borderStyle=\"single\"\n flexDirection=\"column\"\n marginBottom={1}\n paddingX={1}\n >\n {draft.name && (\n <Text>\n <Text dimColor>Name: </Text>\n <Text color=\"white\">{draft.name}</Text>\n </Text>\n )}\n {draft.description && (\n <Text>\n <Text dimColor>Purpose: </Text>\n <Text color=\"white\">{draft.description}</Text>\n </Text>\n )}\n </Box>\n )}\n </Box>\n );\n\n const generateSkill = async (skillDraft: SkillDraft) => {\n try {\n const prompt = `Generate a Gerbil skill file for:\nName: ${skillDraft.name}\nDescription: ${skillDraft.description}\nBehavior: ${skillDraft.behavior}\n\nGenerate TypeScript code that:\n1. Imports { defineSkill } from \"gerbil/skills\" and { z } from \"zod\"\n2. Defines an input schema with Zod\n3. Exports a skill using defineSkill()\n4. Implements the run function that uses gerbil.generate() or gerbil.json()\n\nOnly output the code, no explanations. The file should be complete and runnable.`;\n\n const result = await gerbil.generate(prompt, {\n maxTokens: 800,\n temperature: 0.3,\n system: \"You are an expert TypeScript developer. Generate clean, working code.\",\n });\n\n // Clean up the code - remove code fences and think tags\n let code = result.text;\n code = code\n .replace(/<think>[\\s\\S]*?<\\/think>/g, \"\") // Remove think blocks\n .replace(/```typescript\\n?/g, \"\")\n .replace(/```\\n?/g, \"\")\n .trim();\n\n setGeneratedCode(code);\n setStep(\"done\");\n } catch (err) {\n setError(String(err));\n setStep(\"done\");\n }\n };\n\n const handleSave = async () => {\n if (!generatedCode || step !== \"done\") {\n return;\n }\n\n // Save to .gerbil/skills/ directory in cwd\n const gerbilDir = path.join(process.cwd(), \".gerbil\");\n const skillsDir = path.join(gerbilDir, \"skills\");\n const filePath = path.join(skillsDir, `${draft.name}.skill.ts`);\n\n try {\n // Create .gerbil/skills directory if it doesn't exist\n if (!fs.existsSync(skillsDir)) {\n fs.mkdirSync(skillsDir, { recursive: true });\n }\n\n fs.writeFileSync(filePath, generatedCode, \"utf-8\");\n setSaveStatus(`Saved to .gerbil/skills/${draft.name}.skill.ts`);\n\n // Clear status after 3 seconds\n setTimeout(() => setSaveStatus(null), 3000);\n } catch (err) {\n setSaveStatus(`Error: ${err}`);\n setTimeout(() => setSaveStatus(null), 3000);\n }\n };\n\n const handleCopy = async () => {\n if (!generatedCode || step !== \"done\") {\n return;\n }\n\n const success = await copyToClipboard(generatedCode);\n setCopyStatus(success ? \"Copied to clipboard!\" : \"Failed to copy\");\n setTimeout(() => setCopyStatus(null), 2000);\n };\n\n useInput((input, key) => {\n if (key.escape) {\n onDone();\n }\n\n // Save and copy shortcuts when skill is generated\n if (step === \"done\" && !error) {\n if (input === \"s\" || input === \"S\") {\n handleSave();\n }\n if (input === \"c\" || input === \"C\") {\n handleCopy();\n }\n }\n });\n\n const renderCurrentInput = () => {\n const currentStep = STEPS.find((s) => s.key === step);\n if (!currentStep) {\n return null;\n }\n\n const placeholders: Record<string, string> = {\n name: \"sentiment-analyzer, code-reviewer, email-writer...\",\n description: \"Analyzes text sentiment, Reviews code for issues...\",\n behavior:\n \"Input: text string. Output: { sentiment, confidence }. Use gerbil.json() for structured output...\",\n };\n\n const helpText: Record<string, string> = {\n name: \"Use lowercase letters, numbers, and hyphens only\",\n description: \"A clear, one-line description of what the skill does\",\n behavior: \"Describe inputs, outputs, and logic. Be specific about data types and structure.\",\n };\n\n return (\n <Box flexDirection=\"column\">\n <Text bold color=\"cyan\">\n {currentStep.hint}\n </Text>\n <Box marginBottom={1}>\n <Text dimColor>{helpText[step]}</Text>\n </Box>\n <Box borderColor=\"cyan\" borderStyle=\"single\" paddingX={1}>\n <Text color=\"cyan\">> </Text>\n <TextInput\n onChange={setInput}\n onSubmit={handleSubmit}\n placeholder={placeholders[step]}\n value={input}\n />\n </Box>\n </Box>\n );\n };\n\n // Generating state\n if (step === \"generating\") {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text bold color=\"cyan\">\n \\ Create New Skill\n </Text>\n <Box marginY={1}>{renderProgress()}</Box>\n <Box>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text> Generating skill code with AI...</Text>\n </Box>\n <Box marginTop={1}>\n <Text dimColor>This may take a few seconds</Text>\n </Box>\n </Box>\n );\n }\n\n // Done state\n if (step === \"done\") {\n if (error) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text bold color=\"cyan\">\n \\ Create New Skill\n </Text>\n <Box marginY={1}>\n <Text bold color=\"red\">\n Error generating skill\n </Text>\n </Box>\n <Text color=\"red\">{error}</Text>\n <Box marginTop={1}>\n <Text dimColor>Esc go back</Text>\n </Box>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text bold color=\"cyan\">\n \\ Create New Skill\n </Text>\n <Box marginY={1}>\n <Text bold color=\"green\">\n [done] Skill Generated: {draft.name}\n </Text>\n </Box>\n <Box marginBottom={1}>\n <Text dimColor>\n Save this code as: <Text color=\"white\">.gerbil/skills/{draft.name}.skill.ts</Text>\n </Text>\n </Box>\n <Box borderColor=\"green\" borderStyle=\"single\" flexDirection=\"column\" padding={1}>\n <Text color=\"white\" wrap=\"wrap\">\n {generatedCode}\n </Text>\n </Box>\n\n {/* Status messages */}\n {saveStatus && (\n <Box marginTop={1}>\n <Text color={saveStatus.startsWith(\"Error\") ? \"red\" : \"green\"}>{saveStatus}</Text>\n </Box>\n )}\n {copyStatus && (\n <Box marginTop={1}>\n <Text color={copyStatus.includes(\"Failed\") ? \"red\" : \"green\"}>{copyStatus}</Text>\n </Box>\n )}\n\n <Box marginTop={1}>\n <Text dimColor>\n <Text color=\"yellow\">s</Text> save to .gerbil/skills/ | <Text color=\"yellow\">c</Text>{\" \"}\n copy to clipboard | <Text color=\"gray\">Esc</Text> go back\n </Text>\n </Box>\n </Box>\n );\n }\n\n // Input steps (name, description, behavior)\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text bold color=\"cyan\">\n \\ Create New Skill\n </Text>\n <Box marginY={1}>{renderProgress()}</Box>\n {renderCurrentInput()}\n <Box marginTop={1}>\n <Text dimColor>Enter continue | Esc cancel</Text>\n </Box>\n </Box>\n );\n}\n","import fs from \"fs\";\nimport { Box, Text, useInput } from \"ink\";\nimport Spinner from \"ink-spinner\";\nimport TextInput from \"ink-text-input\";\nimport path from \"path\";\nimport { useState } from \"react\";\nimport type { Gerbil } from \"../../../core/gerbil.js\";\n\ntype CreateToolViewProps = {\n gerbil: Gerbil;\n onDone: () => void;\n};\n\ntype Step = \"name\" | \"description\" | \"params\" | \"execute\" | \"generating\" | \"done\";\n\ntype ToolDraft = {\n name: string;\n description: string;\n params: string;\n execute: string;\n};\n\nconst STEPS = [\n { key: \"name\", num: 1, title: \"Name\", hint: \"Tool name (e.g., get_weather)\" },\n { key: \"description\", num: 2, title: \"Description\", hint: \"What does this tool do?\" },\n { key: \"params\", num: 3, title: \"Parameters\", hint: \"What inputs does it need?\" },\n { key: \"execute\", num: 4, title: \"Logic\", hint: \"What should it return?\" },\n] as const;\n\n// Template for tool files - simple format, no imports needed\nfunction buildToolCode(draft: ToolDraft, executeBody: string): string {\n return `// Gerbil Tool: ${draft.name}\n// No imports needed - just export a config object\n\nexport default {\n name: \"${draft.name}\",\n description: \"${draft.description}\",\n execute: async (params) => {\n${executeBody}\n },\n};\n`;\n}\n\nexport function CreateToolView({ gerbil, onDone }: CreateToolViewProps) {\n const [step, setStep] = useState<Step>(\"name\");\n const [draft, setDraft] = useState<ToolDraft>({\n name: \"\",\n description: \"\",\n params: \"\",\n execute: \"\",\n });\n const [input, setInput] = useState(\"\");\n const [generatedCode, setGeneratedCode] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [saveStatus, setSaveStatus] = useState<string | null>(null);\n\n const currentStepNum =\n step === \"name\"\n ? 1\n : step === \"description\"\n ? 2\n : step === \"params\"\n ? 3\n : step === \"execute\"\n ? 4\n : 5;\n\n useInput((char, key) => {\n if (key.escape && step === \"done\") {\n onDone();\n }\n if ((char === \"s\" || char === \"S\") && step === \"done\" && !error) {\n saveToFile();\n }\n });\n\n const handleSubmit = async (value: string) => {\n if (step === \"name\") {\n if (!value.trim()) {\n return; // Name is required\n }\n const snakeCase = value\n .toLowerCase()\n .replace(/\\s+/g, \"_\")\n .replace(/[^a-z0-9_]/g, \"\");\n setDraft((d) => ({ ...d, name: snakeCase }));\n setInput(\"\");\n setStep(\"description\");\n } else if (step === \"description\") {\n if (!value.trim()) {\n return; // Description is required\n }\n setDraft((d) => ({ ...d, description: value }));\n setInput(\"\");\n setStep(\"params\");\n } else if (step === \"params\") {\n // Params are optional - can press enter to skip\n setDraft((d) => ({ ...d, params: value.trim() || \"(none)\" }));\n setInput(\"\");\n setStep(\"execute\");\n } else if (step === \"execute\") {\n if (!value.trim()) {\n return; // Logic is required\n }\n setDraft((d) => ({ ...d, execute: value }));\n setInput(\"\");\n setStep(\"generating\");\n await generateTool({ ...draft, execute: value });\n }\n };\n\n const cleanCode = (text: string): string => {\n return text\n .replace(/<think>[\\s\\S]*?<\\/think>/g, \"\") // Remove think blocks\n .replace(/<\\/?think>/g, \"\") // Remove unclosed think tags\n .replace(/^```[\\w]*\\n?/gm, \"\") // Remove code fence starts\n .replace(/```$/gm, \"\") // Remove code fence ends\n .replace(/\\*\\*/g, \"\") // Remove markdown bold **\n .replace(/`([^`]+)`/g, \"$1\") // Remove inline code backticks\n .trim();\n };\n\n const generateTool = async (finalDraft: ToolDraft) => {\n try {\n // Generate just the execute function body\n const hasParams = finalDraft.params !== \"(none)\";\n const executePrompt = `Write a simple function body for: ${finalDraft.execute}\n${hasParams ? `params has: ${finalDraft.params}` : \"\"}\nUse params?.fieldName with defaults. Return a string.\n\nExample:\n const value = params?.name || \"default\";\n return \\`Result: \\${value}\\`;`;\n\n let executeBody = \"\";\n for await (const chunk of gerbil.stream(executePrompt, {\n maxTokens: 200,\n system: \"Output only function body code. No markdown. No backticks. Must return a string.\",\n })) {\n executeBody += chunk;\n }\n executeBody = cleanCode(executeBody);\n\n // Ensure proper indentation\n if (!executeBody.startsWith(\" \")) {\n executeBody = executeBody\n .split(\"\\n\")\n .map((line) => ` ${line.trim()}`)\n .join(\"\\n\");\n }\n\n // Build final code from template\n const code = buildToolCode(finalDraft, executeBody);\n setGeneratedCode(code);\n setStep(\"done\");\n } catch (e) {\n setError(`${e}`);\n setStep(\"done\");\n }\n };\n\n const saveToFile = () => {\n try {\n const toolsDir = path.join(process.cwd(), \".gerbil\", \"tools\");\n if (!fs.existsSync(toolsDir)) {\n fs.mkdirSync(toolsDir, { recursive: true });\n }\n const filePath = path.join(toolsDir, `${draft.name}.tool.ts`);\n fs.writeFileSync(filePath, generatedCode);\n setSaveStatus(`Saved to .gerbil/tools/${draft.name}.tool.ts`);\n } catch (e) {\n setSaveStatus(`Error: ${e}`);\n }\n };\n\n const renderProgress = () => (\n <Box marginBottom={1}>\n {STEPS.map((s, i) => {\n const isComplete = currentStepNum > s.num;\n const isCurrent = step === s.key;\n return (\n <Box key={s.key} marginRight={1}>\n <Text color={isComplete ? \"green\" : isCurrent ? \"cyan\" : \"gray\"}>\n {isComplete ? \"[✓]\" : isCurrent ? \"[>]\" : \"[ ]\"} {s.title}\n </Text>\n {i < STEPS.length - 1 && <Text dimColor> --- </Text>}\n </Box>\n );\n })}\n </Box>\n );\n\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n {renderProgress()}\n\n {/* Current draft */}\n <Box\n borderColor=\"gray\"\n borderStyle=\"round\"\n flexDirection=\"column\"\n marginBottom={1}\n paddingX={1}\n >\n <Text>\n <Text color=\"cyan\">Name:</Text> {draft.name || \"...\"}\n </Text>\n <Text>\n <Text color=\"cyan\">Description:</Text> {draft.description || \"...\"}\n </Text>\n <Text>\n <Text color=\"cyan\">Parameters:</Text> {draft.params || \"...\"}\n </Text>\n <Text>\n <Text color=\"cyan\">Logic:</Text> {draft.execute || \"...\"}\n </Text>\n </Box>\n\n {/* Step content */}\n {step === \"name\" && (\n <Box flexDirection=\"column\">\n <Text bold color=\"cyan\">\n Tool Name\n </Text>\n <Text dimColor>Use snake_case (e.g., get_weather, search_docs)</Text>\n <Box marginTop={1}>\n <Text color=\"cyan\">> </Text>\n <TextInput\n onChange={setInput}\n onSubmit={handleSubmit}\n placeholder=\"my_tool\"\n value={input}\n />\n </Box>\n </Box>\n )}\n\n {step === \"description\" && (\n <Box flexDirection=\"column\">\n <Text bold color=\"cyan\">\n Description\n </Text>\n <Text dimColor>What does this tool do? (one sentence)</Text>\n <Box marginTop={1}>\n <Text color=\"cyan\">> </Text>\n <TextInput\n onChange={setInput}\n onSubmit={handleSubmit}\n placeholder=\"Gets the current weather for a city\"\n value={input}\n />\n </Box>\n </Box>\n )}\n\n {step === \"params\" && (\n <Box flexDirection=\"column\">\n <Text bold color=\"cyan\">\n Parameters\n </Text>\n <Text dimColor>What inputs does this tool need? (press Enter to skip)</Text>\n <Box marginTop={1}>\n <Text color=\"cyan\">> </Text>\n <TextInput\n onChange={setInput}\n onSubmit={handleSubmit}\n placeholder=\"theme as a string (optional)\"\n value={input}\n />\n </Box>\n </Box>\n )}\n\n {step === \"execute\" && (\n <Box flexDirection=\"column\">\n <Text bold color=\"cyan\">\n Logic\n </Text>\n <Text dimColor>What should this tool do and return?</Text>\n <Box marginTop={1}>\n <Text color=\"cyan\">> </Text>\n <TextInput\n onChange={setInput}\n onSubmit={handleSubmit}\n placeholder=\"fetch weather from API and return temperature\"\n value={input}\n />\n </Box>\n </Box>\n )}\n\n {step === \"generating\" && (\n <Box flexDirection=\"column\">\n <Box>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text> Generating execute function...</Text>\n </Box>\n <Text dimColor>Using template with your inputs</Text>\n </Box>\n )}\n\n {step === \"done\" && (\n <Box flexDirection=\"column\">\n {error ? (\n <Text color=\"red\">Error: {error}</Text>\n ) : (\n <>\n <Text bold color=\"green\">\n ✓ Tool Generated\n </Text>\n <Box\n borderColor=\"green\"\n borderStyle=\"single\"\n flexDirection=\"column\"\n marginY={1}\n paddingX={1}\n >\n <Text color=\"gray\">\n {generatedCode.slice(0, 500)}\n {generatedCode.length > 500 ? \"...\" : \"\"}\n </Text>\n </Box>\n\n <Box>\n <Text dimColor>Press </Text>\n <Text color=\"yellow\">s</Text>\n <Text dimColor> to save to .gerbil/tools/ | </Text>\n <Text color=\"gray\">Esc</Text>\n <Text dimColor> to go back</Text>\n </Box>\n\n {saveStatus && (\n <Box marginTop={1}>\n <Text color={saveStatus.startsWith(\"Error\") ? \"red\" : \"green\"}>{saveStatus}</Text>\n </Box>\n )}\n </>\n )}\n </Box>\n )}\n </Box>\n );\n}\n","import { Box, Text, useInput } from \"ink\";\nimport { useState } from \"react\";\nimport { hyperlink } from \"../utils.js\";\n\nconst FRAMEWORKS = [\n {\n name: \"React Hooks\",\n id: \"browser\",\n description:\n \"useChat for conversations, useCompletion for one-off. Runs in browser with WebGPU.\",\n install: \"npm install @tryhamster/gerbil\",\n code: `import { useChat, useCompletion } from \"@tryhamster/gerbil/browser\";\n\n// useChat - Full chat with message history\nfunction Chat() {\n const { messages, input, setInput, handleSubmit, isLoading, isGenerating, stop } = useChat({\n model: \"qwen3-0.6b\",\n thinking: true,\n });\n if (isLoading) return <div>Loading...</div>;\n return (\n <form onSubmit={handleSubmit}>\n {messages.map(m => <div key={m.id}>{m.role}: {m.content}</div>)}\n <input value={input} onChange={e => setInput(e.target.value)} />\n {isGenerating && <button type=\"button\" onClick={stop}>Stop</button>}\n </form>\n );\n}\n\n// useCompletion - One-off generation\nfunction Generator() {\n const { complete, completion, isLoading, isGenerating } = useCompletion();\n if (isLoading) return <div>Loading...</div>;\n return <button onClick={() => complete(\"Write a haiku\")}>{completion || \"Generate\"}</button>;\n}`,\n },\n {\n name: \"AI SDK v5 (Vercel)\",\n id: \"ai-sdk\",\n description: \"The official AI SDK integration. Fully compatible with LanguageModelV2.\",\n install: \"npm install gerbil ai @ai-sdk/provider\",\n code: `import { generateText, streamText } from \"ai\";\nimport { gerbil } from \"gerbil/ai\";\n\n// Simple generation\nconst { text } = await generateText({\n model: gerbil(\"qwen3-0.6b\"),\n prompt: \"Explain quantum computing\",\n});\n\n// Streaming\nconst { textStream } = streamText({\n model: gerbil(\"qwen3-0.6b\"),\n system: \"You are a helpful assistant.\",\n messages: [{ role: \"user\", content: \"Hello!\" }],\n});\n\nfor await (const chunk of textStream) {\n process.stdout.write(chunk);\n}`,\n },\n {\n name: \"Next.js App Router\",\n id: \"nextjs\",\n description: \"Ready-to-use API route handler for Next.js 13+ with streaming support.\",\n install: \"npm install gerbil\",\n code: `// app/api/chat/route.ts\nimport { gerbil } from \"gerbil/next\";\n\n// Creates a streaming chat endpoint\nexport const POST = gerbil.handler({ \n model: \"qwen3-0.6b\",\n system: \"You are a helpful coding assistant.\"\n});\n\n// Client usage with AI SDK UI:\n// import { useChat } from \"@ai-sdk/react\";\n// const { messages, input, handleSubmit } = useChat();`,\n },\n {\n name: \"Express.js\",\n id: \"express\",\n description: \"Express middleware with /generate and /stream endpoints.\",\n install: \"npm install gerbil express\",\n code: `import express from \"express\";\nimport { gerbil } from \"gerbil/express\";\n\nconst app = express();\napp.use(express.json());\n\n// Mount Gerbil routes\napp.use(\"/api/ai\", gerbil({\n model: \"qwen3-0.6b\",\n maxTokens: 500,\n})());\n\n// Endpoints:\n// POST /api/ai/generate { prompt, options }\n// POST /api/ai/stream { prompt, options } (SSE)\n// GET /api/ai/info\n\napp.listen(3000);`,\n },\n {\n name: \"Hono\",\n id: \"hono\",\n description: \"Lightweight Hono integration for edge and serverless.\",\n install: \"npm install gerbil hono\",\n code: `import { Hono } from \"hono\";\nimport { gerbil } from \"gerbil/hono\";\n\nconst app = new Hono();\n\n// Mount Gerbil routes\napp.route(\"/ai\", await gerbil({\n model: \"qwen3-0.6b\"\n})());\n\n// Works with Cloudflare Workers, Deno, Bun\nexport default app;`,\n },\n {\n name: \"LangChain\",\n id: \"langchain\",\n description: \"LangChain LLM wrapper for chains, agents, and RAG.\",\n install: \"npm install gerbil langchain\",\n code: `import { GerbilLLM } from \"gerbil/langchain\";\nimport { PromptTemplate } from \"langchain/prompts\";\nimport { LLMChain } from \"langchain/chains\";\n\nconst llm = new GerbilLLM({ \n model: \"qwen3-0.6b\",\n temperature: 0.7,\n});\n\n// Use in chains\nconst prompt = PromptTemplate.fromTemplate(\n \"Summarize: {text}\"\n);\nconst chain = new LLMChain({ llm, prompt });\nconst result = await chain.call({ text: \"...\" });`,\n },\n {\n name: \"MCP Server\",\n id: \"mcp\",\n description: \"Model Context Protocol server for Claude Desktop and Cursor.\",\n install: \"npm install gerbil\",\n code: `// Start MCP server from CLI:\n// npx gerbil serve --mcp --model qwen3-0.6b\n\n// Claude Desktop config (~/.claude/settings.json):\n{\n \"mcpServers\": {\n \"gerbil\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"gerbil\", \"serve\", \"--mcp\"]\n }\n }\n}\n\n// Cursor config (.cursor/settings.json):\n{\n \"mcpServers\": {\n \"gerbil\": {\n \"command\": \"npx\", \n \"args\": [\"-y\", \"gerbil\", \"serve\", \"--mcp\"]\n }\n }\n}`,\n },\n {\n name: \"Standalone\",\n id: \"standalone\",\n description: \"Direct Gerbil usage without any framework.\",\n install: \"npm install gerbil\",\n code: `import { Gerbil } from \"gerbil\";\n\nconst g = new Gerbil();\nawait g.loadModel(\"qwen3-0.6b\", {\n onProgress: (p) => console.log(p.status)\n});\n\n// Generate text\nconst result = await g.generate(\"Hello!\", {\n maxTokens: 100,\n temperature: 0.7,\n});\nconsole.log(result.text);\n\n// Stream\nfor await (const chunk of g.stream(\"Tell me a story\")) {\n process.stdout.write(chunk);\n}\n\n// JSON output\nconst data = await g.json(\"List 3 colors\", {\n schema: z.object({ colors: z.array(z.string()) })\n});`,\n },\n];\n\nexport function FrameworksView() {\n const [selected, setSelected] = useState(0);\n\n useInput((_input, key) => {\n if (key.upArrow) {\n setSelected((s) => Math.max(0, s - 1));\n }\n if (key.downArrow) {\n setSelected((s) => Math.min(FRAMEWORKS.length - 1, s + 1));\n }\n });\n\n const framework = FRAMEWORKS[selected];\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text bold>Framework Integrations</Text>\n <Text dimColor>Select a framework to see setup instructions and code examples</Text>\n\n <Box flexDirection=\"row\" marginY={1}>\n <Box flexDirection=\"column\" marginRight={2} minWidth={22}>\n {FRAMEWORKS.map((f, i) => (\n <Text bold={i === selected} color={i === selected ? \"cyan\" : \"gray\"} key={f.id}>\n {i === selected ? \"> \" : \" \"}\n {f.name}\n </Text>\n ))}\n </Box>\n\n <Box\n borderColor={selected === 0 ? \"cyan\" : \"gray\"}\n borderStyle=\"single\"\n flexDirection=\"column\"\n flexGrow={1}\n paddingX={1}\n >\n <Text bold color=\"cyan\">\n {framework.name}\n </Text>\n <Text dimColor>{framework.description}</Text>\n\n <Box marginTop={1}>\n <Text color=\"yellow\">$ </Text>\n <Text color=\"white\">{framework.install}</Text>\n </Box>\n\n <Box flexDirection=\"column\" marginTop={1}>\n <Text dimColor>Example:</Text>\n <Text color=\"green\">{framework.code}</Text>\n </Box>\n </Box>\n </Box>\n\n <Box marginTop={1}>\n <Text dimColor>\n <Text color=\"yellow\">Up/Down</Text> select | See{\" \"}\n {hyperlink(\"https://github.com/gethamster/gerbil/tree/main/docs\", \"docs\")} for detailed\n guides | <Text color=\"gray\">Esc</Text> back\n </Text>\n </Box>\n </Box>\n );\n}\n","import { Box, Text, useInput } from \"ink\";\nimport os from \"os\";\nimport type { Gerbil } from \"../../../core/gerbil.js\";\nimport { getCacheInfo, getMemoryInfo, hyperlink, type SessionStats } from \"../utils.js\";\n\ntype InfoViewProps = {\n gerbil: Gerbil;\n model: string;\n modelFamily: string;\n stats: SessionStats;\n onGoToCache?: () => void;\n};\n\nfunction getDeviceLabel(deviceMode: \"webgpu\" | \"cpu\" | \"wasm\"): string {\n const platform = os.platform();\n const arch = os.arch();\n\n if (deviceMode === \"webgpu\") {\n if (platform === \"darwin\" && arch === \"arm64\") {\n return \"WebGPU (Chrome → Metal)\";\n }\n if (platform === \"linux\") {\n return \"WebGPU (Chrome → Vulkan)\";\n }\n if (platform === \"win32\") {\n return \"WebGPU (Chrome → D3D12)\";\n }\n return \"WebGPU (Chrome)\";\n }\n\n if (platform === \"darwin\" && arch === \"arm64\") {\n return `Apple Silicon (${deviceMode.toUpperCase()})`;\n }\n if (platform === \"darwin\" && arch === \"x64\") {\n return `Intel Mac (${deviceMode.toUpperCase()})`;\n }\n\n return deviceMode.toUpperCase();\n}\n\nexport function InfoView({ gerbil, model, modelFamily, stats, onGoToCache }: InfoViewProps) {\n const deviceMode = gerbil.getDeviceMode();\n const dtype = gerbil.getDtype();\n const chromeStatus = gerbil.getChromeStatus();\n const deviceLabel = getDeviceLabel(deviceMode);\n\n const cacheInfo = getCacheInfo();\n const memInfo = getMemoryInfo();\n\n useInput((input) => {\n if (input === \"c\" || input === \"C\") {\n onGoToCache?.();\n }\n });\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text bold>System Information</Text>\n\n <Box borderColor=\"gray\" borderStyle=\"single\" flexDirection=\"column\" marginY={1} paddingX={1}>\n <Text bold color=\"cyan\">\n Model\n </Text>\n <Text>\n Current:{\" \"}\n <Text bold color=\"cyan\">\n {model}\n </Text>\n </Text>\n <Text>\n Family: <Text color=\"gray\">{modelFamily}</Text>\n </Text>\n <Text>\n Device: <Text color={deviceMode === \"webgpu\" ? \"green\" : \"yellow\"}>{deviceLabel}</Text>\n </Text>\n <Text>\n Dtype: <Text color={dtype === \"q4f16\" ? \"green\" : \"gray\"}>{dtype}</Text>\n </Text>\n </Box>\n\n <Box flexDirection=\"row\" marginBottom={1}>\n <Box\n borderColor=\"gray\"\n borderStyle=\"single\"\n flexDirection=\"column\"\n marginRight={1}\n minWidth={30}\n paddingX={1}\n >\n <Text bold color=\"cyan\">\n Memory\n </Text>\n <Text>\n Total: <Text color=\"gray\">{memInfo.total}</Text>\n </Text>\n <Text>\n Used:{\" \"}\n <Text color={memInfo.percentUsed > 80 ? \"red\" : \"yellow\"}>\n {memInfo.used} ({memInfo.percentUsed}%)\n </Text>\n </Text>\n <Text>\n Free: <Text color=\"green\">{memInfo.free}</Text>\n </Text>\n </Box>\n\n <Box\n borderColor=\"gray\"\n borderStyle=\"single\"\n flexDirection=\"column\"\n marginRight={1}\n minWidth={30}\n paddingX={1}\n >\n <Text bold color=\"cyan\">\n Session Stats\n </Text>\n <Text>\n Prompts: <Text color=\"gray\">{stats.prompts}</Text>\n </Text>\n <Text>\n Tokens In: <Text color=\"gray\">{stats.tokensIn}</Text>\n </Text>\n <Text>\n Tokens Out: <Text color=\"gray\">{stats.tokensOut}</Text>\n </Text>\n <Text>\n Total Time: <Text color=\"gray\">{Math.round(stats.totalTimeMs / 1000)}s</Text>\n </Text>\n {stats.lastTokPerSec > 0 && (\n <Text>\n Last tok/s: <Text color=\"yellow\">{stats.lastTokPerSec.toFixed(1)}</Text>\n </Text>\n )}\n {stats.avgTokPerSec > 0 && (\n <Text>\n Avg tok/s: <Text color=\"cyan\">{stats.avgTokPerSec.toFixed(1)}</Text>\n </Text>\n )}\n {stats.benchResults.length > 0 && (\n <Text>\n Best Bench:{\" \"}\n <Text color=\"green\">\n {Math.max(...stats.benchResults.map((b) => b.tokPerSec))} tok/s\n </Text>\n </Text>\n )}\n </Box>\n\n {chromeStatus && (\n <Box\n borderColor=\"green\"\n borderStyle=\"single\"\n flexDirection=\"column\"\n minWidth={38}\n paddingX={1}\n >\n <Text bold color=\"green\">\n WebGPU Backend\n </Text>\n <Text>\n Status: <Text color=\"green\">● Running</Text>\n </Text>\n <Text>\n PID:{\" \"}\n <Text color={chromeStatus.pid ? \"gray\" : \"yellow\"}>\n {chromeStatus.pid ?? \"connected (no PID)\"}\n </Text>\n </Text>\n <Text>\n Port: <Text color=\"gray\">{chromeStatus.port}</Text>\n </Text>\n <Text>\n Model:{\" \"}\n <Text color=\"gray\">\n {chromeStatus.modelId.length > 28\n ? `...${chromeStatus.modelId.slice(-25)}`\n : chromeStatus.modelId}\n </Text>\n </Text>\n </Box>\n )}\n </Box>\n\n <Box borderColor=\"gray\" borderStyle=\"single\" flexDirection=\"column\" paddingX={1}>\n <Text bold color=\"cyan\">\n Cache\n </Text>\n <Text>\n Location:{\" \"}\n <Text dimColor>\n {(cacheInfo.locations[0] || \"\").length > 50\n ? `...${(cacheInfo.locations[0] || \"\").slice(-47)}`\n : cacheInfo.locations[0] || \"none\"}\n </Text>\n </Text>\n <Text>\n Total Size: <Text color=\"yellow\">{cacheInfo.totalSize || \"empty\"}</Text>\n </Text>\n <Text>\n Models: <Text color=\"gray\">{cacheInfo.models.length}</Text>\n </Text>\n <Text dimColor>\n Press <Text color=\"cyan\">c</Text> to manage cached models\n </Text>\n </Box>\n\n <Box flexDirection=\"column\" marginTop={1}>\n <Text dimColor>\n Runtime: <Text color=\"gray\">Node.js {process.version}</Text> | Gerbil:{\" \"}\n <Text color=\"gray\">0.1.x</Text> |\n {hyperlink(\"https://github.com/gethamster/gerbil\", \"GitHub\")}\n </Text>\n </Box>\n\n <Box marginTop={1}>\n <Text dimColor>\n <Text color=\"cyan\">c</Text> cache | <Text color=\"gray\">Esc</Text> back\n </Text>\n </Box>\n </Box>\n );\n}\n","import { Box, Text } from \"ink\";\nimport Spinner from \"ink-spinner\";\n\ntype LoadingViewProps = {\n message: string;\n};\n\nexport function LoadingView({ message }: LoadingViewProps) {\n return (\n <Box\n alignItems=\"center\"\n flexDirection=\"column\"\n height=\"100%\"\n justifyContent=\"center\"\n padding={2}\n >\n <Box marginBottom={1}>\n <Text bold color=\"cyan\">\n 🐹 Gerbil\n </Text>\n </Box>\n <Box>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text> {message}</Text>\n </Box>\n </Box>\n );\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Box, Text, useInput } from \"ink\";\nimport Spinner from \"ink-spinner\";\nimport TextInput from \"ink-text-input\";\nimport { useEffect, useRef, useState } from \"react\";\nimport {\n type CachedModelInfo,\n formatBytes,\n getCacheInfo,\n getModelBenchmarkStats,\n isModelCached,\n PRESET_MODELS,\n} from \"../utils.js\";\n\ntype HFModel = {\n id: string;\n downloads: number;\n likes: number;\n createdAt?: string;\n // These are fetched separately via individual model API\n sizeBytes?: number;\n params?: number;\n loading?: boolean;\n};\n\ntype HFApiModel = {\n id: string;\n modelId: string;\n downloads: number;\n likes: number;\n createdAt?: string;\n pipeline_tag?: string;\n library_name?: string;\n tags?: string[];\n};\n\ntype HFModelDetails = {\n siblings?: { rfilename: string; size?: number }[];\n safetensors?: { parameters?: Record<string, number>; total?: number };\n usedStorage?: number;\n};\n\n// Extract param count from model name (e.g., \"Qwen3-0.6B\" -> 0.6B, \"llama-7b\" -> 7B)\nfunction extractParamsFromName(modelId: string): number | null {\n // Match patterns like: 0.6B, 7B, 1.7B, 70B, 360M, etc.\n const match = modelId.match(/[-_](\\d+(?:\\.\\d+)?)(B|M|K)(?:[-_]|$)/i);\n if (match) {\n const num = Number.parseFloat(match[1]);\n const unit = match[2].toUpperCase();\n if (unit === \"B\") {\n return num * 1e9;\n }\n if (unit === \"M\") {\n return num * 1e6;\n }\n if (unit === \"K\") {\n return num * 1e3;\n }\n }\n return null;\n}\n\nfunction formatParams(params: number | undefined, modelId?: string): string {\n // Try the provided params first\n if (params && params > 0) {\n if (params >= 1e9) {\n return `${(params / 1e9).toFixed(1)}B`;\n }\n if (params >= 1e6) {\n return `${Math.round(params / 1e6)}M`;\n }\n if (params >= 1e3) {\n return `${Math.round(params / 1e3)}K`;\n }\n return `${params}`;\n }\n\n // Fallback: try to extract from model name\n if (modelId) {\n const extracted = extractParamsFromName(modelId);\n if (extracted) {\n if (extracted >= 1e9) {\n return `${(extracted / 1e9).toFixed(1)}B`;\n }\n if (extracted >= 1e6) {\n return `${Math.round(extracted / 1e6)}M`;\n }\n if (extracted >= 1e3) {\n return `${Math.round(extracted / 1e3)}K`;\n }\n }\n }\n\n return \"-\";\n}\n\nfunction formatDownloads(n: number): string {\n if (n >= 1e6) {\n return `${(n / 1e6).toFixed(1)}M`;\n }\n if (n >= 1e3) {\n return `${(n / 1e3).toFixed(1)}K`;\n }\n return `${n}`;\n}\n\nfunction formatDate(dateStr: string | undefined): string {\n if (!dateStr) {\n return \"-\";\n }\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) {\n return \"today\";\n }\n if (diffDays === 1) {\n return \"1d ago\";\n }\n if (diffDays < 7) {\n return `${diffDays}d ago`;\n }\n if (diffDays < 30) {\n return `${Math.floor(diffDays / 7)}w ago`;\n }\n if (diffDays < 365) {\n return `${Math.floor(diffDays / 30)}mo ago`;\n }\n return `${Math.floor(diffDays / 365)}y ago`;\n}\n\ntype ModelViewProps = {\n currentModel: string;\n onSelect: (model: string) => void;\n onDownloadOnly?: (model: string, hfId: string) => Promise<boolean>;\n onTabChange?: (tab: \"preset\" | \"cached\" | \"huggingface\") => void;\n onSearchChange?: (query: string) => void;\n};\n\n// Secondary sort applied on top of downloads (primary sort)\ntype SortMode = \"none\" | \"likes\" | \"updatedAt\";\ntype SizeFilter = \"all\" | \"small\" | \"medium\" | \"large\";\n\nconst PAGE_SIZE = 15;\n\nexport function ModelView({\n currentModel,\n onSelect,\n onDownloadOnly,\n onTabChange,\n onSearchChange,\n}: ModelViewProps) {\n const [tab, setTab] = useState<\"preset\" | \"cached\" | \"huggingface\">(\"preset\");\n const [selected, setSelected] = useState(\n PRESET_MODELS.findIndex((m) => m.id === currentModel) || 0,\n );\n const [hfModels, setHfModels] = useState<HFModel[]>([]);\n const [hfSelected, setHfSelected] = useState(0);\n const [hfLoading, setHfLoading] = useState(false);\n const [hfSearchInput, setHfSearchInput] = useState(\"\");\n const [hfSearchFocused, setHfSearchFocused] = useState(false);\n const [hfError, setHfError] = useState(\"\");\n const [hfHasMore, setHfHasMore] = useState(true);\n const [sortMode, setSortMode] = useState<SortMode>(\"none\");\n const [sizeFilter, setSizeFilter] = useState<SizeFilter>(\"all\");\n const [cachedModels, setCachedModels] = useState<Set<string>>(new Set());\n const [localModels, setLocalModels] = useState<CachedModelInfo[]>([]);\n const [localSelected, setLocalSelected] = useState(0);\n const [deleteConfirm, setDeleteConfirm] = useState<string | null>(null);\n\n // Track which models we've fetched details for\n const fetchedDetailsRef = useRef<Set<string>>(new Set());\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const refreshCachedModels = () => {\n const cached = new Set<string>();\n for (const model of PRESET_MODELS) {\n if (isModelCached(model.hfId)) {\n cached.add(model.id);\n }\n }\n setCachedModels(cached);\n const cacheInfo = getCacheInfo();\n setLocalModels(cacheInfo.models);\n };\n\n useEffect(() => {\n refreshCachedModels();\n }, [refreshCachedModels]);\n\n // Fetch model details (size, params) for a single model using raw API\n const fetchModelDetails = async (\n modelId: string,\n ): Promise<{ sizeBytes: number; params: number } | null> => {\n try {\n // First get model info for params\n const res = await fetch(`https://huggingface.co/api/models/${modelId}`);\n if (!res.ok) {\n return null;\n }\n const info: HFModelDetails = await res.json();\n\n // Try to get params from safetensors info\n let params = 0;\n if (info.safetensors?.parameters) {\n const p = info.safetensors.parameters;\n params = p.BF16 || p.F16 || p.F32 || info.safetensors.total || 0;\n }\n\n // Try to get actual ONNX file size from tree API (more accurate)\n let sizeBytes = 0;\n try {\n const treeRes = await fetch(`https://huggingface.co/api/models/${modelId}/tree/main/onnx`);\n if (treeRes.ok) {\n const files: { path: string; size?: number }[] = await treeRes.json();\n // Prefer q4f16 > q4 > fp16 > any .onnx file\n const q4f16 = files.find((f) => f.path.includes(\"q4f16\") && f.path.endsWith(\".onnx\"));\n const q4 = files.find(\n (f) => f.path.includes(\"q4\") && !f.path.includes(\"f16\") && f.path.endsWith(\".onnx\"),\n );\n const fp16 = files.find((f) => f.path.includes(\"fp16\") && f.path.endsWith(\".onnx\"));\n const anyOnnx = files.find(\n (f) => f.path.endsWith(\".onnx\") && !f.path.includes(\"quantized\"),\n );\n\n const bestFile = q4f16 || q4 || fp16 || anyOnnx;\n if (bestFile?.size) {\n sizeBytes = bestFile.size;\n }\n }\n } catch {\n // Fallback to usedStorage if tree API fails\n }\n\n // Fallback to usedStorage if we couldn't get ONNX size\n if (!sizeBytes) {\n sizeBytes = info.usedStorage || 0;\n }\n\n return { sizeBytes, params };\n } catch {\n return null;\n }\n };\n\n // Fetch all model details in parallel after getting the list\n const fetchAllModelDetails = async (models: HFModel[]) => {\n // Fetch all details in parallel (batch of 5 at a time to avoid rate limiting)\n const batchSize = 5;\n const updatedModels = [...models];\n\n for (let i = 0; i < models.length; i += batchSize) {\n const batch = models.slice(i, i + batchSize);\n const results = await Promise.all(batch.map((m) => fetchModelDetails(m.id)));\n\n results.forEach((result, idx) => {\n const modelIdx = i + idx;\n if (result && updatedModels[modelIdx]) {\n updatedModels[modelIdx] = {\n ...updatedModels[modelIdx],\n sizeBytes: result.sizeBytes,\n params: result.params,\n loading: false,\n };\n } else if (updatedModels[modelIdx]) {\n updatedModels[modelIdx] = { ...updatedModels[modelIdx], loading: false };\n }\n });\n\n // Update state after each batch so user sees progress\n setHfModels([...updatedModels]);\n }\n };\n\n const fetchHFModels = async (query?: string, append = false, sort: SortMode = sortMode) => {\n if (hfLoading) {\n return;\n }\n\n // Cancel any pending request\n abortControllerRef.current?.abort();\n abortControllerRef.current = new AbortController();\n\n setHfLoading(true);\n setHfError(\"\");\n\n try {\n const offset = append ? hfModels.length : 0;\n\n // Build URL with query params - fetch extra for preloading\n // Note: HF API's library=onnx filter isn't reliable, so we use filter=onnx and search\n // Always sort by downloads first (primary), secondary sort applied client-side\n const params = new URLSearchParams({\n filter: \"onnx\",\n sort: \"downloads\",\n direction: \"-1\",\n limit: String(PAGE_SIZE * 2), // Fetch double for preloading next page\n });\n\n // Handle compound search (comma-separated terms like \"qwen3, onnx\")\n // Combine all terms with spaces for the search API\n if (query) {\n const searchTerms = query\n .split(\",\")\n .map((t) => t.trim())\n .filter(Boolean);\n // Always include \"onnx\" in search to help filter results\n if (!searchTerms.some((t) => t.toLowerCase().includes(\"onnx\"))) {\n searchTerms.push(\"onnx\");\n }\n params.set(\"search\", searchTerms.join(\" \"));\n } else {\n // Default search includes onnx\n params.set(\"search\", \"onnx\");\n }\n\n if (offset > 0) {\n params.set(\"skip\", String(offset));\n }\n\n const res = await fetch(`https://huggingface.co/api/models?${params}`, {\n signal: abortControllerRef.current.signal,\n });\n\n if (!res.ok) {\n throw new Error(\"API error\");\n }\n const data: HFApiModel[] = await res.json();\n\n // Apply secondary sort on top of downloads (primary sort from API)\n const sortedData = [...data];\n if (sort === \"likes\") {\n // Sort by likes within download tiers\n sortedData.sort((a, b) => (b.likes || 0) - (a.likes || 0));\n } else if (sort === \"updatedAt\") {\n // Sort by recency within download tiers\n sortedData.sort((a, b) => {\n const aDate = a.createdAt ? new Date(a.createdAt).getTime() : 0;\n const bDate = b.createdAt ? new Date(b.createdAt).getTime() : 0;\n return bDate - aDate;\n });\n }\n\n // Then boost models with q4f16/q4 quantization or from onnx-community\n sortedData.sort((a, b) => {\n const aHasQuant =\n a.id.includes(\"q4f16\") || a.id.includes(\"q4\") || a.id.startsWith(\"onnx-community/\");\n const bHasQuant =\n b.id.includes(\"q4f16\") || b.id.includes(\"q4\") || b.id.startsWith(\"onnx-community/\");\n if (aHasQuant && !bHasQuant) {\n return -1;\n }\n if (!aHasQuant && bHasQuant) {\n return 1;\n }\n return 0; // Keep original order for equal priority\n });\n\n const models: HFModel[] = sortedData.map((m) => ({\n id: m.id,\n downloads: m.downloads || 0,\n likes: m.likes || 0,\n createdAt: m.createdAt,\n loading: true,\n }));\n\n setHfHasMore(models.length >= PAGE_SIZE);\n\n if (append) {\n const newModels = [...hfModels, ...models];\n setHfModels(newModels);\n // Fetch details for new models in background\n fetchAllModelDetails(models);\n } else {\n fetchedDetailsRef.current.clear();\n setHfModels(models);\n setHfSelected(0);\n // Fetch all details immediately\n fetchAllModelDetails(models);\n }\n } catch (e: any) {\n if (e.name !== \"AbortError\") {\n setHfError(\"Failed to fetch models. Check your connection.\");\n if (!append) {\n setHfModels([]);\n }\n }\n }\n setHfLoading(false);\n };\n\n useEffect(() => {\n if (tab === \"huggingface\" && hfModels.length === 0 && !hfLoading) {\n fetchHFModels();\n }\n }, [tab, fetchHFModels, hfLoading, hfModels.length]);\n\n const loadMoreModels = () => {\n if (!hfLoading && hfHasMore) {\n fetchHFModels(hfSearchInput || undefined, true);\n }\n };\n\n // Filter models by size (only works for models with fetched params)\n const getFilteredModels = () => {\n if (sizeFilter === \"all\") {\n return hfModels;\n }\n return hfModels.filter((m) => {\n if (!m.params) {\n return true; // Show models without params info\n }\n if (sizeFilter === \"small\") {\n return m.params < 500e6;\n }\n if (sizeFilter === \"medium\") {\n return m.params >= 500e6 && m.params < 3e9;\n }\n if (sizeFilter === \"large\") {\n return m.params >= 3e9;\n }\n return true;\n });\n };\n\n const filteredModels = getFilteredModels();\n\n const deleteModel = (model: CachedModelInfo) => {\n try {\n const possiblePaths = [\n path.join(model.location, model.name),\n path.join(model.location, model.name.replace(\"/\", \"--\")),\n path.join(model.location, `models--${model.name.replace(\"/\", \"--\")}`),\n ];\n\n for (const p of possiblePaths) {\n if (fs.existsSync(p)) {\n fs.rmSync(p, { recursive: true, force: true });\n break;\n }\n }\n\n refreshCachedModels();\n setDeleteConfirm(null);\n\n if (localSelected >= localModels.length - 1) {\n setLocalSelected(Math.max(0, localModels.length - 2));\n }\n } catch {\n setDeleteConfirm(null);\n refreshCachedModels();\n }\n };\n\n useInput((input, key) => {\n if (deleteConfirm !== null) {\n if (input === \"y\" || input === \"Y\") {\n const model = localModels.find((m) => m.name === deleteConfirm);\n if (model) {\n deleteModel(model);\n }\n } else {\n setDeleteConfirm(null);\n }\n return;\n }\n\n if (tab === \"huggingface\" && hfSearchFocused) {\n if (key.escape) {\n setHfSearchFocused(false);\n return;\n }\n return;\n }\n\n if (key.tab) {\n const newTab = tab === \"preset\" ? \"cached\" : tab === \"cached\" ? \"huggingface\" : \"preset\";\n setTab(newTab);\n setHfSearchFocused(false);\n onTabChange?.(newTab);\n return;\n }\n\n if (tab === \"preset\") {\n if (key.upArrow) {\n setSelected((s) => Math.max(0, s - 1));\n }\n if (key.downArrow) {\n setSelected((s) => Math.min(PRESET_MODELS.length - 1, s + 1));\n }\n if (key.return) {\n onSelect(PRESET_MODELS[selected].id);\n }\n if (input === \"d\" || input === \"D\") {\n const model = PRESET_MODELS[selected];\n if (!cachedModels.has(model.id)) {\n onDownloadOnly?.(model.id, model.hfId).then((success) => {\n if (success) {\n refreshCachedModels();\n }\n });\n }\n }\n } else if (tab === \"cached\") {\n if (key.upArrow) {\n setLocalSelected((s) => Math.max(0, s - 1));\n }\n if (key.downArrow) {\n setLocalSelected((s) => Math.min(localModels.length - 1, s + 1));\n }\n if (key.return && localModels.length > 0) {\n const model = localModels[localSelected];\n const hfId = model.name.includes(\"/\") ? model.name : model.name.replace(\"--\", \"/\");\n onSelect(hfId);\n }\n if ((input === \"x\" || input === \"X\") && localModels.length > 0) {\n const model = localModels[localSelected];\n setDeleteConfirm(model.name);\n }\n } else {\n if (input === \"s\" || input === \"S\") {\n setHfSearchFocused(true);\n return;\n }\n if (input === \"o\" || input === \"O\") {\n // Cycle through secondary sort options (downloads is always primary)\n const modes: SortMode[] = [\"none\", \"likes\", \"updatedAt\"];\n const idx = modes.indexOf(sortMode);\n const newSort = modes[(idx + 1) % modes.length];\n setSortMode(newSort);\n fetchedDetailsRef.current.clear();\n fetchHFModels(hfSearchInput || undefined, false, newSort);\n return;\n }\n if (input === \"f\" || input === \"F\") {\n const filters: SizeFilter[] = [\"all\", \"small\", \"medium\", \"large\"];\n const idx = filters.indexOf(sizeFilter);\n setSizeFilter(filters[(idx + 1) % filters.length]);\n setHfSelected(0);\n return;\n }\n if (key.upArrow) {\n setHfSelected((s) => Math.max(0, s - 1));\n }\n if (key.downArrow) {\n const newSelected = Math.min(filteredModels.length - 1, hfSelected + 1);\n setHfSelected(newSelected);\n if (newSelected >= filteredModels.length - 3 && hfHasMore && !hfLoading) {\n loadMoreModels();\n }\n }\n if (input === \"n\" || input === \"N\") {\n loadMoreModels();\n }\n if (key.return && filteredModels.length > 0) {\n const selectedModel = filteredModels[hfSelected];\n // Only allow Enter if model is cached\n if (isModelCached(selectedModel.id)) {\n onSelect(selectedModel.id);\n }\n }\n if ((input === \"d\" || input === \"D\") && filteredModels.length > 0) {\n const model = filteredModels[hfSelected];\n onDownloadOnly?.(model.id, model.id).then((success) => {\n if (success) {\n refreshCachedModels();\n }\n });\n }\n }\n });\n\n const handleSearch = (value: string) => {\n setHfSearchInput(value);\n };\n\n const handleSearchSubmit = () => {\n setHfHasMore(true);\n fetchedDetailsRef.current.clear();\n fetchHFModels(hfSearchInput || undefined, false);\n setHfSearchFocused(false);\n onSearchChange?.(hfSearchInput);\n };\n\n // Helper to render colored shortcuts\n const renderHelpText = () => {\n if (deleteConfirm !== null) {\n return (\n <Text dimColor>\n Press <Text color=\"red\">y</Text> to confirm delete, any other key to cancel\n </Text>\n );\n }\n if (tab === \"cached\") {\n return (\n <Text dimColor>\n <Text color=\"gray\">↑↓</Text> select | <Text color=\"yellow\">Enter</Text> use |{\" \"}\n <Text color=\"red\">x</Text> delete | <Text color=\"cyan\">Tab</Text> switch |{\" \"}\n <Text color=\"gray\">Esc</Text> back\n </Text>\n );\n }\n if (tab === \"huggingface\") {\n if (hfSearchFocused) {\n return (\n <Text dimColor>\n Type to search | <Text color=\"yellow\">Enter</Text> submit |{\" \"}\n <Text color=\"gray\">Esc</Text> cancel\n </Text>\n );\n }\n const selectedModel = filteredModels[hfSelected];\n const isCached = selectedModel ? isModelCached(selectedModel.id) : false;\n return (\n <Text dimColor>\n <Text color=\"gray\">↑↓</Text> nav |{\" \"}\n {isCached ? (\n <>\n <Text color=\"yellow\">Enter</Text> use |{\" \"}\n </>\n ) : null}\n <Text color=\"cyan\">s</Text> search | <Text color=\"cyan\">o</Text> sort |{\" \"}\n <Text color=\"cyan\">f</Text> filter | <Text color=\"cyan\">n</Text> more |{\" \"}\n <Text color=\"green\">d</Text> download | <Text color=\"cyan\">Tab</Text> |{\" \"}\n <Text color=\"gray\">Esc</Text>\n </Text>\n );\n }\n return (\n <Text dimColor>\n <Text color=\"gray\">↑↓</Text> select | <Text color=\"yellow\">Enter</Text> use |{\" \"}\n <Text color=\"green\">d</Text> download | <Text color=\"cyan\">Tab</Text> switch |{\" \"}\n <Text color=\"gray\">Esc</Text> back\n </Text>\n );\n };\n\n const getSortLabel = () => {\n switch (sortMode) {\n case \"none\":\n return \"downloads\";\n case \"updatedAt\":\n return \"recent\";\n case \"likes\":\n return \"likes\";\n }\n };\n\n const getFilterLabel = () => {\n switch (sizeFilter) {\n case \"small\":\n return \"<500M\";\n case \"medium\":\n return \"500M-3B\";\n case \"large\":\n return \"3B+\";\n default:\n return \"all\";\n }\n };\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Box marginBottom={1}>\n <Text bold={tab === \"preset\"} color={tab === \"preset\" ? \"cyan\" : \"gray\"}>\n [Recommended]\n </Text>\n <Text color=\"gray\"> </Text>\n <Text bold={tab === \"cached\"} color={tab === \"cached\" ? \"green\" : \"gray\"}>\n [Cached]\n </Text>\n <Text color=\"gray\"> </Text>\n <Text bold={tab === \"huggingface\"} color={tab === \"huggingface\" ? \"cyan\" : \"gray\"}>\n [HuggingFace]\n </Text>\n <Text dimColor> (Tab to switch)</Text>\n </Box>\n\n {tab === \"preset\" ? (\n <>\n <Text dimColor>Tested models with known performance</Text>\n <Box flexDirection=\"column\" marginY={1}>\n {PRESET_MODELS.map((model, i) => {\n const isCached = cachedModels.has(model.id) || isModelCached(model.hfId);\n const benchStats = getModelBenchmarkStats(model.hfId);\n return (\n <Box key={model.id}>\n <Text color={isCached ? \"green\" : \"gray\"}>{isCached ? \"●\" : \"○\"} </Text>\n <Text color={i === selected ? \"cyan\" : \"white\"}>\n {i === selected ? \"> \" : \" \"}\n {model.name.padEnd(15)}\n </Text>\n <Text dimColor>{model.size.padEnd(10)}</Text>\n <Text\n color={\n model.speed === \"fastest\"\n ? \"green\"\n : model.speed === \"fast\"\n ? \"yellow\"\n : \"gray\"\n }\n >\n {model.speed.padEnd(8)}\n </Text>\n {benchStats && <Text dimColor> {benchStats.avgTokPerSec} tok/s avg</Text>}\n {model.id === currentModel && <Text color=\"cyan\"> [current]</Text>}\n </Box>\n );\n })}\n </Box>\n {cachedModels.size > 0 && (\n <Text color=\"green\" dimColor>\n {cachedModels.size} model{cachedModels.size > 1 ? \"s\" : \"\"} cached locally\n </Text>\n )}\n </>\n ) : tab === \"cached\" ? (\n <>\n <Text dimColor>All locally downloaded models</Text>\n <Box flexDirection=\"column\" marginY={1}>\n {localModels.length === 0 ? (\n <Text color=\"gray\">\n No cached models found. Download from Recommended or HuggingFace.\n </Text>\n ) : (\n localModels.map((model, i) => {\n const isCurrent =\n currentModel === model.name || currentModel === model.name.replace(\"--\", \"/\");\n const isPendingDelete = deleteConfirm === model.name;\n const sizeDisplay =\n model.modelSize !== model.totalSize\n ? `${model.modelSize} (${model.totalSize})`\n : model.modelSize;\n const benchStats = getModelBenchmarkStats(model.name);\n return (\n <Box key={model.name}>\n <Text color={isPendingDelete ? \"red\" : \"green\"}>\n {isPendingDelete ? \"✕\" : \"●\"}{\" \"}\n </Text>\n <Text color={isPendingDelete ? \"red\" : i === localSelected ? \"cyan\" : \"white\"}>\n {i === localSelected ? \"> \" : \" \"}\n {model.name.length > 40\n ? `${model.name.slice(0, 37)}...`\n : model.name.padEnd(40)}\n </Text>\n <Text color=\"yellow\">{sizeDisplay.padStart(18)}</Text>\n {benchStats ? (\n <Text color=\"cyan\">{` ${benchStats.avgTokPerSec}`.padStart(5)} tok/s</Text>\n ) : (\n <Text dimColor>{\"\".padStart(12)}</Text>\n )}\n <Text dimColor> {model.lastUsed}</Text>\n {isCurrent && <Text color=\"cyan\"> [current]</Text>}\n {isPendingDelete && <Text color=\"red\"> DELETE? (y/n)</Text>}\n </Box>\n );\n })\n )}\n </Box>\n {localModels.length > 0 && !deleteConfirm && (\n <Text color=\"green\" dimColor>\n {localModels.length} model{localModels.length > 1 ? \"s\" : \"\"} cached\n </Text>\n )}\n {deleteConfirm && (\n <Text color=\"red\">⚠ This will permanently delete the model from disk</Text>\n )}\n </>\n ) : (\n <>\n <Box alignItems=\"center\" flexDirection=\"row\" marginBottom={1}>\n <Text color=\"gray\">Search:</Text>\n <Box\n borderColor={hfSearchFocused ? \"cyan\" : \"gray\"}\n borderStyle=\"single\"\n marginLeft={1}\n paddingX={1}\n width={30}\n >\n {hfSearchFocused ? (\n <TextInput\n focus={true}\n onChange={handleSearch}\n onSubmit={handleSearchSubmit}\n placeholder=\"qwen, llama, whisper...\"\n value={hfSearchInput}\n />\n ) : (\n <Text color=\"gray\">{hfSearchInput || \"'s' to search\"}</Text>\n )}\n </Box>\n <Box marginLeft={2}>\n <Text color=\"gray\">Sort: </Text>\n <Text color=\"yellow\">{getSortLabel()}</Text>\n <Text dimColor> (o)</Text>\n </Box>\n <Box marginLeft={2}>\n <Text color=\"gray\">Size: </Text>\n <Text color={sizeFilter !== \"all\" ? \"yellow\" : \"gray\"}>{getFilterLabel()}</Text>\n <Text dimColor> (f)</Text>\n </Box>\n </Box>\n\n {hfLoading && hfModels.length === 0 && (\n <Box>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />{\" \"}\n </Text>\n <Text dimColor>Fetching ONNX models...</Text>\n </Box>\n )}\n\n {hfError && <Text color=\"red\">{hfError}</Text>}\n\n {filteredModels.length > 0 && (\n <Box flexDirection=\"column\" marginY={1}>\n <Box>\n <Text dimColor>{\" \"}</Text>\n <Text bold dimColor>\n {\"Model\".padEnd(48)}\n </Text>\n <Text bold dimColor>\n {\"Params\".padStart(8)}\n </Text>\n <Text bold dimColor>\n {\"Size\".padStart(10)}\n </Text>\n <Text bold dimColor>\n {\"Updated\".padStart(10)}\n </Text>\n <Text bold dimColor>\n {\"Downloads\".padStart(12)}\n </Text>\n </Box>\n {filteredModels.map((model, i) => {\n const isCached = isModelCached(model.id);\n return (\n <Box key={`${model.id}-${i}`}>\n <Text color={isCached ? \"green\" : \"gray\"}>{isCached ? \"●\" : \"○\"} </Text>\n <Text color={i === hfSelected ? \"cyan\" : \"white\"}>\n {i === hfSelected ? \"> \" : \" \"}\n {model.id.length > 46 ? `${model.id.slice(0, 43)}...` : model.id.padEnd(46)}\n </Text>\n <Text color=\"yellow\">{formatParams(model.params, model.id).padStart(8)}</Text>\n <Text color=\"magenta\">\n {(model.sizeBytes ? formatBytes(model.sizeBytes) : \"-\").padStart(10)}\n </Text>\n <Text dimColor>{formatDate(model.createdAt).padStart(10)}</Text>\n <Text color=\"gray\">{formatDownloads(model.downloads).padStart(12)}</Text>\n {model.id === currentModel && <Text color=\"cyan\"> [cur]</Text>}\n </Box>\n );\n })}\n {hfLoading && (\n <Box>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />{\" \"}\n </Text>\n <Text dimColor>Loading more...</Text>\n </Box>\n )}\n {!hfLoading && hfHasMore && (\n <Text dimColor> 'n' for more ({filteredModels.length} shown)</Text>\n )}\n {!hfHasMore && <Text dimColor> End of results ({filteredModels.length} total)</Text>}\n </Box>\n )}\n\n {!hfLoading && filteredModels.length === 0 && hfModels.length > 0 && (\n <Text dimColor>No models match size filter. Press 'f' to change.</Text>\n )}\n\n {!hfLoading && hfModels.length === 0 && !hfError && (\n <Text dimColor>Loading ONNX models...</Text>\n )}\n </>\n )}\n\n <Box marginTop={1}>{renderHelpText()}</Box>\n </Box>\n );\n}\n","import { exec } from \"child_process\";\nimport http from \"http\";\nimport { Box, Text, useInput } from \"ink\";\nimport Spinner from \"ink-spinner\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { Gerbil } from \"../../../core/gerbil.js\";\n\ntype ServeViewProps = {\n gerbil: Gerbil;\n model: string;\n};\n\nexport function ServeView({ gerbil, model }: ServeViewProps) {\n const [mode, setMode] = useState<\"http\" | \"mcp\">(\"http\");\n const [port, setPort] = useState(3000);\n const [serverStatus, setServerStatus] = useState<\"idle\" | \"starting\" | \"running\" | \"error\">(\n \"idle\",\n );\n const [logs, setLogs] = useState<string[]>([]);\n const [copied, setCopied] = useState(false);\n const [requestCount, setRequestCount] = useState(0);\n const serverRef = useRef<http.Server | null>(null);\n\n // Cleanup on unmount\n useEffect(\n () => () => {\n if (serverRef.current) {\n serverRef.current.close();\n serverRef.current = null;\n }\n },\n [],\n );\n\n useInput((input, key) => {\n if (key.tab) {\n setMode((m) => (m === \"http\" ? \"mcp\" : \"http\"));\n }\n if (key.return && serverStatus === \"idle\" && mode === \"http\") {\n startServer();\n }\n if ((input === \"s\" || input === \"S\") && serverStatus === \"running\") {\n stopServer();\n }\n if (key.upArrow && serverStatus === \"idle\" && mode === \"http\") {\n setPort((p) => Math.min(65_535, p + 1));\n }\n if (key.downArrow && serverStatus === \"idle\" && mode === \"http\") {\n setPort((p) => Math.max(1024, p - 1));\n }\n if ((input === \"c\" || input === \"C\") && mode === \"mcp\") {\n copyMcpConfig();\n }\n });\n\n const addLog = (msg: string) => {\n setLogs((prev) => [...prev.slice(-8), `${new Date().toLocaleTimeString()} ${msg}`]);\n };\n\n const startServer = () => {\n setServerStatus(\"starting\");\n setLogs([]);\n setRequestCount(0);\n\n const server = http.createServer(async (req, res) => {\n // CORS headers\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n const url = req.url || \"/\";\n\n if (req.method === \"POST\" && url === \"/generate\") {\n let body = \"\";\n req.on(\"data\", (chunk) => (body += chunk));\n req.on(\"end\", async () => {\n try {\n const { prompt, ...opts } = JSON.parse(body);\n addLog(`POST /generate: \"${prompt.slice(0, 30)}...\"`);\n setRequestCount((c) => c + 1);\n\n const result = await gerbil.generate(prompt, opts);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n } catch (e) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(e) }));\n }\n });\n } else if (req.method === \"POST\" && url === \"/json\") {\n let body = \"\";\n req.on(\"data\", (chunk) => (body += chunk));\n req.on(\"end\", async () => {\n try {\n const { prompt, schema, ...opts } = JSON.parse(body);\n addLog(`POST /json: \"${prompt.slice(0, 30)}...\"`);\n setRequestCount((c) => c + 1);\n\n // Simple JSON generation without Zod validation in HTTP API\n const result = await gerbil.generate(`${prompt}\\n\\nRespond with valid JSON only.`, {\n ...opts,\n temperature: opts.temperature ?? 0.3,\n });\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(result.text);\n } catch (e) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(e) }));\n }\n });\n } else if (req.method === \"GET\" && url === \"/info\") {\n addLog(\"GET /info\");\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(gerbil.getInfo()));\n } else if (req.method === \"GET\" && url === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ status: \"ok\", model }));\n } else {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: \"Not found\",\n endpoints: [\"POST /generate\", \"POST /json\", \"GET /info\", \"GET /health\"],\n }),\n );\n }\n });\n\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n addLog(`Port ${port} in use, trying ${port + 1}...`);\n setPort((p) => p + 1);\n setTimeout(() => startServer(), 100);\n } else {\n addLog(`Error: ${err.message}`);\n setServerStatus(\"error\");\n }\n });\n\n server.listen(port, () => {\n addLog(`Server listening on http://localhost:${port}`);\n setServerStatus(\"running\");\n });\n\n serverRef.current = server;\n };\n\n const stopServer = () => {\n if (serverRef.current) {\n serverRef.current.close(() => {\n addLog(\"Server stopped\");\n });\n serverRef.current = null;\n setServerStatus(\"idle\");\n }\n };\n\n const copyMcpConfig = () => {\n const config = JSON.stringify(\n {\n mcpServers: {\n gerbil: {\n command: \"npx\",\n args: [\"-y\", \"@tryhamster/gerbil\", \"serve\", \"--mcp\"],\n },\n },\n },\n null,\n 2,\n );\n\n const platform = process.platform;\n const cmd =\n platform === \"darwin\"\n ? \"pbcopy\"\n : platform === \"win32\"\n ? \"clip\"\n : \"xclip -selection clipboard\";\n const proc = exec(cmd);\n proc.stdin?.write(config);\n proc.stdin?.end();\n\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text bold>Server Mode</Text>\n <Text dimColor>Expose Gerbil as an API server or MCP server</Text>\n\n <Box marginY={1}>\n <Text bold={mode === \"http\"} color={mode === \"http\" ? \"cyan\" : \"gray\"}>\n [HTTP API]\n </Text>\n <Text color=\"gray\"> </Text>\n <Text bold={mode === \"mcp\"} color={mode === \"mcp\" ? \"cyan\" : \"gray\"}>\n [MCP Server]\n </Text>\n <Text dimColor> (Tab to switch)</Text>\n </Box>\n\n <Box borderColor=\"gray\" borderStyle=\"single\" flexDirection=\"column\" paddingX={1}>\n <Text bold color=\"cyan\">\n {mode === \"http\" ? \"HTTP REST API\" : \"Model Context Protocol\"}\n </Text>\n <Text>\n Model: <Text color=\"cyan\">{model}</Text>\n </Text>\n\n {mode === \"http\" ? (\n <>\n <Text>\n Port: <Text color=\"yellow\">{port}</Text> <Text dimColor>(Up/Down to change)</Text>\n </Text>\n <Text dimColor>Endpoints: /generate, /json, /info, /health</Text>\n </>\n ) : (\n <>\n <Text dimColor>For Claude Desktop and Cursor AI integration</Text>\n <Text dimColor>Tools: generate, stream, json, embed, plus all skills</Text>\n </>\n )}\n </Box>\n\n {mode === \"http\" && serverStatus !== \"idle\" && (\n <Box flexDirection=\"column\" marginY={1}>\n <Box>\n {serverStatus === \"starting\" && (\n <Text color=\"yellow\">\n <Spinner type=\"dots\" /> Starting server...\n </Text>\n )}\n {serverStatus === \"running\" && (\n <Text color=\"green\">\n ● Running on http://localhost:{port} ({requestCount} requests)\n </Text>\n )}\n {serverStatus === \"error\" && <Text color=\"red\">✗ Server error</Text>}\n </Box>\n\n {logs.length > 0 && (\n <Box\n borderColor=\"gray\"\n borderStyle=\"single\"\n flexDirection=\"column\"\n marginTop={1}\n paddingX={1}\n >\n {logs.slice(-5).map((log, i) => (\n <Text dimColor key={i}>\n {log}\n </Text>\n ))}\n </Box>\n )}\n </Box>\n )}\n\n {mode === \"http\" && serverStatus === \"running\" && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text dimColor>Test with:</Text>\n <Text color=\"green\">curl -X POST http://localhost:{port}/generate \\</Text>\n <Text color=\"green\"> -H \"Content-Type: application/json\" \\</Text>\n <Text color=\"green\"> -d '{`{\"prompt\": \"Hello!\"}`}'</Text>\n </Box>\n )}\n\n {mode === \"mcp\" && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box marginBottom={1}>\n <Text color=\"yellow\">⚠ </Text>\n <Text>MCP servers use stdio - run from terminal, not REPL</Text>\n </Box>\n\n <Text dimColor>Terminal command:</Text>\n <Text color=\"cyan\">npx @tryhamster/gerbil serve --mcp</Text>\n\n <Box marginTop={1}>\n <Text dimColor>Add to MCP config (e.g. .cursor/mcp.json):</Text>\n </Box>\n <Text color=\"green\">{`{\n \"mcpServers\": {\n \"gerbil\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@tryhamster/gerbil\", \"serve\", \"--mcp\"]\n }\n }\n}`}</Text>\n\n {copied && (\n <Box marginTop={1}>\n <Text color=\"green\">✓ Config copied to clipboard!</Text>\n </Box>\n )}\n </Box>\n )}\n\n <Box marginTop={1}>\n <Text dimColor>\n {mode === \"mcp\" ? (\n <>\n <Text color=\"yellow\">c</Text> copy config | <Text color=\"yellow\">Tab</Text> HTTP mode\n | <Text color=\"gray\">Esc</Text> back\n </>\n ) : serverStatus === \"idle\" ? (\n <>\n <Text color=\"yellow\">Enter</Text> start | <Text color=\"yellow\">Tab</Text> MCP mode |{\" \"}\n <Text color=\"gray\">Esc</Text> back\n </>\n ) : (\n <>\n <Text color=\"yellow\">s</Text> stop | <Text color=\"gray\">Esc</Text> back\n </>\n )}\n </Text>\n </Box>\n </Box>\n );\n}\n","import { Box, Text, useInput } from \"ink\";\nimport Spinner from \"ink-spinner\";\nimport TextInput from \"ink-text-input\";\nimport { useEffect, useState } from \"react\";\nimport type { Gerbil } from \"../../../core/gerbil.js\";\nimport { getSkillInfo, listSkills, loadProjectSkills, useSkill } from \"../../../skills/index.js\";\nimport { type CachedModelInfo, getCacheInfo } from \"../utils.js\";\n\ntype SkillsViewProps = {\n gerbil: Gerbil;\n onCreateNew?: () => void;\n onSwitchModel?: (modelId: string) => void;\n};\n\ntype Phase = \"select\" | \"input\" | \"running\" | \"result\" | \"model-select\";\n\n// Detailed skill information with examples\nconst SKILL_DETAILS: Record<\n string,\n {\n emoji: string;\n what: string;\n example: string;\n cliExample?: string;\n inputHint: string;\n }\n> = {\n commit: {\n emoji: \"->\",\n what: \"Generate git commit messages from staged changes\",\n example: \"feat(auth): add OAuth2 login flow\",\n cliExample: \"gerbil commit --type conventional\",\n inputHint: \"Leave empty to use staged changes, or paste a diff\",\n },\n summarize: {\n emoji: \"=\",\n what: \"Condense documents, articles, or code into key points\",\n example: \"• Key insight 1\\\\n• Key insight 2\\\\n• Conclusion\",\n cliExample: \"gerbil summarize README.md --format bullets\",\n inputHint: \"Paste text, article, or document to summarize\",\n },\n explain: {\n emoji: \"?\",\n what: \"Break down code or concepts for any skill level\",\n example: \"This function uses recursion to...\",\n cliExample: \"gerbil explain src/utils.ts --level beginner\",\n inputHint: \"Paste code or describe a concept to explain\",\n },\n review: {\n emoji: \"!\",\n what: \"Find bugs, suggest improvements, check security\",\n example: \"⚠️ Line 5: potential null reference\\\\n✓ Good use of...\",\n cliExample: \"gerbil review src/api.ts --focus security,performance\",\n inputHint: \"Paste code to get a detailed review\",\n },\n extract: {\n emoji: \"<>\",\n what: \"Pull structured data from messy text (names, dates, etc)\",\n example: '{ \"name\": \"John\", \"email\": \"john@...\" }',\n cliExample: 'echo \"John Doe, john@email.com\" | gerbil extract',\n inputHint: \"Paste unstructured text to extract data from\",\n },\n title: {\n emoji: \"#\",\n what: \"Generate catchy titles, headlines, or subject lines\",\n example: \"10 Tips for Better Code Reviews\",\n cliExample: \"cat article.md | gerbil title --style seo\",\n inputHint: \"Paste content to generate a title for\",\n },\n test: {\n emoji: \"T\",\n what: \"Auto-generate unit tests for functions and classes\",\n example: \"describe('add', () => { it('adds numbers'... })\",\n cliExample: \"gerbil test src/utils.ts --framework vitest\",\n inputHint: \"Paste a function or class to generate tests for\",\n },\n translate: {\n emoji: \"~\",\n what: \"Translate text to any language while preserving tone\",\n example: \"Hola mundo (Spanish)\",\n cliExample: 'gerbil translate \"Hello world\" --to spanish',\n inputHint: 'Type: \"your text\" to [language]',\n },\n};\n\nexport function SkillsView({ gerbil, onCreateNew, onSwitchModel }: SkillsViewProps) {\n const [phase, setPhase] = useState<Phase>(\"select\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [selectedSkill, setSelectedSkill] = useState<string | null>(null);\n const [inputValue, setInputValue] = useState(\"\");\n const [result, setResult] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [skillsLoaded, setSkillsLoaded] = useState(false);\n const [cachedModels, setCachedModels] = useState<CachedModelInfo[]>([]);\n const [modelSelectIndex, setModelSelectIndex] = useState(0);\n const [currentModel, setCurrentModel] = useState<string>(\n gerbil.getModelInfo()?.id || \"qwen3-0.6b\",\n );\n\n // Load project skills from .gerbil/skills/ on mount\n useEffect(() => {\n if (!skillsLoaded) {\n loadProjectSkills()\n .then(() => {\n setSkillsLoaded(true);\n })\n .catch(() => {\n setSkillsLoaded(true);\n });\n }\n // Load cached models\n const cacheInfo = getCacheInfo();\n setCachedModels(cacheInfo.models);\n }, [skillsLoaded]);\n\n const skills = listSkills();\n\n // Create skill list with \"Create new\" at the end\n const allItems = [\n ...skills.map((name) => {\n const info = getSkillInfo(name);\n const details = SKILL_DETAILS[name];\n return {\n name,\n description: info?.description || \"\",\n builtin: info?.builtin,\n emoji: details?.emoji || \"*\",\n what: details?.what || info?.description || \"\",\n example: details?.example || \"\",\n cliExample: details?.cliExample || \"\",\n inputHint: details?.inputHint || \"Enter input...\",\n };\n }),\n {\n name: \"__create__\",\n description: \"Build a custom AI skill with the wizard\",\n builtin: false,\n emoji: \"+\",\n what: \"Create your own skill using AI-assisted code generation\",\n example: \"sentiment-analyzer, email-writer, data-formatter...\",\n cliExample: \"\",\n inputHint: \"\",\n },\n ];\n\n useInput((input, key) => {\n if (phase === \"model-select\") {\n if (key.upArrow) {\n setModelSelectIndex((i) => Math.max(0, i - 1));\n }\n if (key.downArrow) {\n setModelSelectIndex((i) => Math.min(cachedModels.length - 1, i + 1));\n }\n if (key.return && cachedModels.length > 0) {\n const model = cachedModels[modelSelectIndex];\n const modelId = model.name.includes(\"/\") ? model.name : model.name.replace(\"--\", \"/\");\n setCurrentModel(modelId);\n onSwitchModel?.(modelId);\n setPhase(\"select\");\n }\n if (key.escape) {\n setPhase(\"select\");\n }\n return;\n }\n\n if (phase === \"select\") {\n if (key.upArrow) {\n setSelectedIndex((i) => Math.max(0, i - 1));\n }\n if (key.downArrow) {\n setSelectedIndex((i) => Math.min(allItems.length - 1, i + 1));\n }\n if (key.return) {\n const item = allItems[selectedIndex];\n if (item.name === \"__create__\") {\n onCreateNew?.();\n } else {\n setSelectedSkill(item.name);\n setPhase(\"input\");\n }\n }\n // C to create new skill\n if (input === \"c\" || input === \"C\") {\n onCreateNew?.();\n }\n // M to select model\n if ((input === \"m\" || input === \"M\") && cachedModels.length > 0) {\n setPhase(\"model-select\");\n }\n }\n if (key.escape && (phase === \"result\" || phase === \"input\")) {\n handleReset();\n }\n });\n\n const handleRunSkill = async (input: string) => {\n if (!selectedSkill) {\n return;\n }\n\n setPhase(\"running\");\n setError(null);\n\n try {\n const skill = useSkill(selectedSkill);\n\n // Parse input as JSON or use as content/text\n let parsedInput: Record<string, unknown>;\n try {\n parsedInput = JSON.parse(input);\n } catch {\n // Smart input parsing based on skill type\n if (selectedSkill === \"commit\") {\n parsedInput = { diff: input, type: \"conventional\" };\n } else if (selectedSkill === \"translate\") {\n const toMatch = input.match(/(.+?)\\s+to\\s+(\\w+)$/i);\n if (toMatch) {\n parsedInput = { text: toMatch[1].trim(), to: toMatch[2].trim() };\n } else {\n parsedInput = { text: input, to: \"spanish\" };\n }\n } else if (selectedSkill === \"summarize\") {\n parsedInput = { content: input, format: \"bullet\" };\n } else if (selectedSkill === \"explain\") {\n parsedInput = { code: input, level: \"beginner\" };\n } else if (selectedSkill === \"review\") {\n parsedInput = { code: input };\n } else if (selectedSkill === \"test\") {\n parsedInput = { code: input, framework: \"jest\" };\n } else {\n parsedInput = { content: input, text: input, code: input };\n }\n }\n\n const output = await skill.run(parsedInput, gerbil);\n\n // Clean up think tags from output\n let cleanOutput = typeof output === \"string\" ? output : JSON.stringify(output, null, 2);\n cleanOutput = cleanOutput.replace(/<think>[\\s\\S]*?<\\/think>/g, \"\").trim();\n\n setResult(cleanOutput);\n setPhase(\"result\");\n } catch (err) {\n setError(String(err));\n setPhase(\"result\");\n }\n };\n\n const handleReset = () => {\n setPhase(\"select\");\n setSelectedSkill(null);\n setInputValue(\"\");\n setResult(null);\n setError(null);\n };\n\n // Selection phase\n if (phase === \"select\") {\n const currentItem = allItems[selectedIndex];\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n {/* Header explanation */}\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text bold color=\"cyan\">\n What are Skills?\n </Text>\n <Text dimColor>\n Skills are pre-built AI tasks that solve specific problems. Each skill has optimized\n prompts and structured outputs.\n </Text>\n <Box marginTop={1}>\n <Text dimColor>\n <Text color=\"yellow\">CLI Usage:</Text> gerbil {\"<skill>\"} [input] [--options]\n </Text>\n </Box>\n <Text dimColor>\n Examples: <Text color=\"gray\">gerbil commit</Text> ·{\" \"}\n <Text color=\"gray\">gerbil summarize README.md</Text> ·{\" \"}\n <Text color=\"gray\">gerbil explain src/utils.ts</Text>\n </Text>\n </Box>\n\n {/* Skill list */}\n <Box flexDirection=\"row\">\n {/* Left: Skill list */}\n <Box flexDirection=\"column\" marginRight={2} minWidth={28}>\n <Box marginBottom={1}>\n <Text bold>Available Skills:</Text>\n </Box>\n {allItems.map((item, i) => {\n const isSelected = i === selectedIndex;\n const isCreate = item.name === \"__create__\";\n return (\n <Box key={item.name}>\n <Text\n bold={isSelected}\n color={isSelected ? (isCreate ? \"green\" : \"cyan\") : \"gray\"}\n >\n {isSelected ? \"> \" : \" \"}[{item.emoji}]{\" \"}\n {isCreate ? \"Create new...\" : item.name}\n </Text>\n </Box>\n );\n })}\n </Box>\n\n {/* Right: Selected skill details */}\n <Box\n borderColor={currentItem.name === \"__create__\" ? \"green\" : \"cyan\"}\n borderStyle=\"single\"\n flexDirection=\"column\"\n flexGrow={1}\n paddingX={2}\n paddingY={1}\n >\n <Text bold color={currentItem.name === \"__create__\" ? \"green\" : \"cyan\"}>\n {currentItem.name === \"__create__\" ? \"Create New Skill\" : currentItem.name}\n </Text>\n\n {currentItem.builtin && <Text dimColor>[built-in]</Text>}\n\n <Box marginTop={1}>\n <Text wrap=\"wrap\">{currentItem.what}</Text>\n </Box>\n\n {currentItem.example && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text dimColor>Output example:</Text>\n <Text color=\"green\">{currentItem.example}</Text>\n </Box>\n )}\n\n {currentItem.cliExample && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text dimColor>CLI usage:</Text>\n <Text color=\"yellow\">{currentItem.cliExample}</Text>\n </Box>\n )}\n\n {currentItem.name !== \"__create__\" && (\n <Box marginTop={1}>\n <Text dimColor>Press Enter to run this skill</Text>\n </Box>\n )}\n </Box>\n </Box>\n\n <Box flexDirection=\"column\" marginTop={1}>\n <Box>\n <Text dimColor>Model: </Text>\n <Text color=\"cyan\">{currentModel}</Text>\n {cachedModels.length > 0 && <Text dimColor> (press </Text>}\n {cachedModels.length > 0 && <Text color=\"yellow\">m</Text>}\n {cachedModels.length > 0 && <Text dimColor> to change)</Text>}\n </Box>\n <Box marginTop={1}>\n <Text dimColor>\n <Text color=\"yellow\">Up/Down</Text> navigate | <Text color=\"yellow\">Enter</Text>{\" \"}\n select | <Text color=\"yellow\">m</Text> model | <Text color=\"gray\">Esc</Text> back\n </Text>\n </Box>\n </Box>\n </Box>\n );\n }\n\n // Model selection phase\n if (phase === \"model-select\") {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text bold color=\"cyan\">\n Select Model for Skills\n </Text>\n <Box marginBottom={1}>\n <Text dimColor>Choose a cached model to run skills with</Text>\n </Box>\n\n <Box flexDirection=\"column\" marginY={1}>\n {cachedModels.length === 0 ? (\n <Text color=\"gray\">No cached models found. Download models from Model view.</Text>\n ) : (\n cachedModels.map((model, i) => {\n const isSelected = i === modelSelectIndex;\n const isCurrent =\n model.name === currentModel || model.name.replace(\"--\", \"/\") === currentModel;\n return (\n <Box key={model.name}>\n <Text\n bold={isSelected}\n color={isSelected ? \"cyan\" : isCurrent ? \"green\" : \"gray\"}\n >\n {isSelected ? \"> \" : \" \"}\n {model.name.length > 50 ? `${model.name.slice(0, 47)}...` : model.name}\n </Text>\n <Text color=\"yellow\"> {model.modelSize}</Text>\n {isCurrent && <Text color=\"green\"> [current]</Text>}\n </Box>\n );\n })\n )}\n </Box>\n\n <Box marginTop={1}>\n <Text dimColor>\n <Text color=\"yellow\">Up/Down</Text> navigate | <Text color=\"yellow\">Enter</Text> select\n | <Text color=\"gray\">Esc</Text> cancel\n </Text>\n </Box>\n </Box>\n );\n }\n\n // Input phase\n if (phase === \"input\") {\n const info = getSkillInfo(selectedSkill!);\n const details = SKILL_DETAILS[selectedSkill!];\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text bold color=\"cyan\">\n [{details?.emoji || \"*\"}] {selectedSkill}\n </Text>\n </Box>\n <Text dimColor>{details?.what || info?.description}</Text>\n </Box>\n\n {details?.example && (\n <Box marginBottom={1}>\n <Text dimColor>Example: </Text>\n <Text color=\"green\">{details.example}</Text>\n </Box>\n )}\n\n <Box marginBottom={1}>\n <Text color=\"white\">{details?.inputHint || \"Enter input:\"}</Text>\n </Box>\n\n <Box borderColor=\"cyan\" borderStyle=\"single\" paddingX={1}>\n <Text color=\"cyan\">> </Text>\n <TextInput\n onChange={setInputValue}\n onSubmit={handleRunSkill}\n placeholder=\"Type here...\"\n value={inputValue}\n />\n </Box>\n\n <Box marginTop={1}>\n <Text dimColor>\n <Text color=\"yellow\">Enter</Text> run | <Text color=\"gray\">Esc</Text> cancel\n </Text>\n </Box>\n </Box>\n );\n }\n\n // Running phase\n if (phase === \"running\") {\n const details = SKILL_DETAILS[selectedSkill!];\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Box marginBottom={1}>\n <Text bold color=\"cyan\">\n [{details?.emoji || \"*\"}] {selectedSkill}\n </Text>\n </Box>\n <Box>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />{\" \"}\n </Text>\n <Text>Processing...</Text>\n </Box>\n <Box marginTop={1}>\n <Text dimColor>This may take a few seconds</Text>\n </Box>\n </Box>\n );\n }\n\n // Result phase\n const _details = SKILL_DETAILS[selectedSkill!];\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Box marginBottom={1}>\n <Text bold color={error ? \"red\" : \"green\"}>\n {error ? \"[x] Error\" : \"[done]\"} {selectedSkill}\n </Text>\n </Box>\n\n <Box\n borderColor={error ? \"red\" : \"green\"}\n borderStyle=\"single\"\n flexDirection=\"column\"\n padding={1}\n >\n <Text color={error ? \"red\" : \"white\"} wrap=\"wrap\">\n {error || result}\n </Text>\n </Box>\n\n <Box marginTop={1}>\n <Text dimColor>\n <Text color=\"gray\">Esc</Text> back to skills\n </Text>\n </Box>\n </Box>\n );\n}\n","import { exec } from \"child_process\";\nimport fs from \"fs\";\nimport { Box, Text, useInput } from \"ink\";\nimport Spinner from \"ink-spinner\";\nimport TextInput from \"ink-text-input\";\nimport path from \"path\";\nimport { useEffect, useState } from \"react\";\nimport { getTool, getToolDefinitions, loadProjectTools } from \"../../../core/tools.js\";\n\ntype ToolsViewProps = {\n onCreateTool: () => void;\n};\n\ntype ToolInfo = {\n name: string;\n description: string;\n source: \"builtin\" | \"project\" | \"error\";\n path?: string;\n error?: string;\n parameters?: object;\n};\n\ntype ExecuteState = \"idle\" | \"input\" | \"running\" | \"done\";\n\nexport function ToolsView({ onCreateTool }: ToolsViewProps) {\n const [tools, setTools] = useState<ToolInfo[]>([]);\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [expandedTool, setExpandedTool] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n\n // Execution state\n const [executeState, setExecuteState] = useState<ExecuteState>(\"idle\");\n const [executeInput, setExecuteInput] = useState(\"\");\n const [executeResult, setExecuteResult] = useState<string | null>(null);\n const [executeError, setExecuteError] = useState<string | null>(null);\n\n useEffect(() => {\n const loadAllTools = async () => {\n const allTools: ToolInfo[] = [];\n\n // First load project tools from .gerbil/tools/\n const projectResults = await loadProjectTools();\n\n // Add failed tools to list with error status\n for (const result of projectResults) {\n if (!result.loaded) {\n allTools.push({\n name: result.name,\n description: result.error || \"Failed to load\",\n source: \"error\",\n path: result.path,\n error: result.error,\n });\n }\n }\n\n // Then get all successfully registered tool definitions\n const defs = getToolDefinitions();\n const toolsDir = path.join(process.cwd(), \".gerbil\", \"tools\");\n\n for (const t of defs) {\n const isBuiltin = t.name.startsWith(\"gerbil_\");\n let toolPath: string | undefined;\n\n if (!isBuiltin) {\n // Check if tool file exists\n const tsPath = path.join(toolsDir, `${t.name}.tool.ts`);\n const jsPath = path.join(toolsDir, `${t.name}.tool.js`);\n if (fs.existsSync(tsPath)) {\n toolPath = tsPath;\n } else if (fs.existsSync(jsPath)) {\n toolPath = jsPath;\n }\n }\n\n allTools.push({\n name: t.name,\n description: t.description,\n source: isBuiltin ? \"builtin\" : \"project\",\n path: toolPath,\n parameters: t.parameters ? {} : undefined,\n });\n }\n\n setTools(allTools);\n setLoading(false);\n };\n\n loadAllTools();\n }, []);\n\n const selectedTool = selectedIndex > 0 ? tools[selectedIndex - 1] : null;\n\n const executeTool = async (toolName: string, inputStr: string) => {\n setExecuteState(\"running\");\n setExecuteError(null);\n setExecuteResult(null);\n\n try {\n const tool = getTool(toolName);\n if (!tool) {\n throw new Error(`Tool \"${toolName}\" not found`);\n }\n\n // Simple param handling:\n // - If JSON object, use as-is\n // - Otherwise, set all common param names to the input value\n let params: any = {};\n const trimmed = inputStr.trim();\n\n if (trimmed) {\n if (trimmed.startsWith(\"{\")) {\n params = JSON.parse(trimmed);\n } else {\n // Set multiple common param names so the tool gets the value\n params = {\n query: trimmed,\n input: trimmed,\n text: trimmed,\n theme: trimmed,\n content: trimmed,\n value: trimmed,\n };\n }\n }\n\n const result = await tool(params);\n setExecuteResult(result);\n setExecuteState(\"done\");\n } catch (e) {\n setExecuteError(e instanceof Error ? e.message : String(e));\n setExecuteState(\"done\");\n }\n };\n\n const handleExecuteSubmit = (value: string) => {\n if (selectedTool && selectedTool.source !== \"error\") {\n executeTool(selectedTool.name, value);\n }\n };\n\n useInput((char, key) => {\n // Handle escape to exit execute mode\n if (key.escape && executeState !== \"idle\") {\n setExecuteState(\"idle\");\n setExecuteInput(\"\");\n setExecuteResult(null);\n setExecuteError(null);\n return;\n }\n\n // Don't process other keys during input/running\n if (executeState === \"input\" || executeState === \"running\") {\n return;\n }\n\n // Clear result on any key when done\n if (executeState === \"done\") {\n setExecuteState(\"idle\");\n setExecuteResult(null);\n setExecuteError(null);\n return;\n }\n\n if (key.upArrow && selectedIndex > 0) {\n setSelectedIndex(selectedIndex - 1);\n setExpandedTool(null);\n }\n if (key.downArrow && selectedIndex < tools.length) {\n setSelectedIndex(selectedIndex + 1);\n setExpandedTool(null);\n }\n if (key.return) {\n if (selectedIndex === 0) {\n onCreateTool();\n } else if (selectedTool) {\n // Toggle expanded view\n setExpandedTool(expandedTool === selectedTool.name ? null : selectedTool.name);\n }\n }\n if (char === \"c\" || char === \"C\") {\n onCreateTool();\n }\n // Open in editor (works for both project and error tools)\n if ((char === \"o\" || char === \"O\") && selectedTool?.path) {\n exec(`code \"${selectedTool.path}\"`);\n }\n // Execute tool\n if ((char === \"x\" || char === \"X\") && selectedTool && selectedTool.source !== \"error\") {\n setExecuteInput(\"\");\n setExecuteState(\"input\");\n }\n });\n\n if (loading) {\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <Text dimColor>Loading tools...</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <Box marginBottom={1}>\n <Text bold color=\"magenta\">\n Tools\n </Text>\n <Text dimColor> — {tools.length} registered</Text>\n </Box>\n\n {/* Create new option */}\n <Box marginBottom={1}>\n <Text color={selectedIndex === 0 ? \"cyan\" : \"gray\"}>\n {selectedIndex === 0 ? \"> \" : \" \"}\n <Text bold color=\"green\">\n + Create new tool\n </Text>\n </Text>\n </Box>\n\n {/* Tool list */}\n <Box flexDirection=\"column\">\n {tools.length === 0 ? (\n <Text dimColor>No tools registered yet</Text>\n ) : (\n tools.map((tool, i) => {\n const isSelected = selectedIndex === i + 1;\n const isExpanded = expandedTool === tool.name;\n\n return (\n <Box flexDirection=\"column\" key={tool.name}>\n <Box>\n <Text color={isSelected ? \"cyan\" : \"white\"}>\n {isSelected ? \"> \" : \" \"}\n <Text\n bold\n color={isSelected ? \"cyan\" : tool.source === \"error\" ? \"red\" : \"white\"}\n >\n {tool.name}\n </Text>\n </Text>\n <Text\n color={tool.source === \"error\" ? \"red\" : undefined}\n dimColor={tool.source !== \"error\"}\n >\n {\" \"}\n — {tool.description.slice(0, 40)}\n {tool.description.length > 40 ? \"...\" : \"\"}\n </Text>\n <Text\n color={\n tool.source === \"builtin\"\n ? \"yellow\"\n : tool.source === \"error\"\n ? \"red\"\n : \"green\"\n }\n dimColor={tool.source !== \"error\"}\n >\n {\" \"}\n [{tool.source}]\n </Text>\n </Box>\n\n {/* Expanded details */}\n {isExpanded && (\n <Box\n borderColor={tool.source === \"error\" ? \"red\" : \"cyan\"}\n borderStyle=\"single\"\n flexDirection=\"column\"\n marginLeft={4}\n marginY={1}\n paddingX={1}\n >\n {tool.source === \"error\" ? (\n <>\n <Text>\n <Text color=\"red\">Error:</Text> {tool.error}\n </Text>\n <Text>\n <Text color=\"gray\">File:</Text> {tool.path}\n </Text>\n <Text dimColor>Press 'o' to open and fix in editor</Text>\n </>\n ) : (\n <>\n <Text>\n <Text color=\"gray\">Description:</Text> {tool.description}\n </Text>\n <Text>\n <Text color=\"gray\">Source:</Text>{\" \"}\n {tool.source === \"builtin\"\n ? \"Built-in (src/core/tools.ts)\"\n : tool.path || \".gerbil/tools/\"}\n </Text>\n {tool.source === \"project\" && tool.path && (\n <Text dimColor>Press 'o' to open in editor</Text>\n )}\n </>\n )}\n </Box>\n )}\n </Box>\n );\n })\n )}\n </Box>\n\n {/* Execute UI */}\n {executeState === \"input\" && selectedTool && (\n <Box\n borderColor=\"yellow\"\n borderStyle=\"round\"\n flexDirection=\"column\"\n marginY={1}\n paddingX={1}\n >\n <Text bold color=\"yellow\">\n Execute: {selectedTool.name}\n </Text>\n <Text dimColor>Enter params (JSON or single value, empty for none):</Text>\n <Box marginTop={1}>\n <Text color=\"yellow\">> </Text>\n <TextInput\n onChange={setExecuteInput}\n onSubmit={handleExecuteSubmit}\n placeholder='{\"param\": \"value\"} or just: value'\n value={executeInput}\n />\n </Box>\n </Box>\n )}\n\n {executeState === \"running\" && (\n <Box marginY={1} paddingX={1}>\n <Text color=\"yellow\">\n <Spinner type=\"dots\" />\n </Text>\n <Text> Running {selectedTool?.name}...</Text>\n </Box>\n )}\n\n {executeState === \"done\" && (\n <Box\n borderColor={executeError ? \"red\" : \"green\"}\n borderStyle=\"round\"\n flexDirection=\"column\"\n marginY={1}\n paddingX={1}\n >\n <Text bold color={executeError ? \"red\" : \"green\"}>\n {executeError ? \"✗ Error\" : \"✓ Result\"}\n </Text>\n <Text color={executeError ? \"red\" : \"white\"}>\n {executeError || executeResult || \"(no output)\"}\n </Text>\n <Text dimColor>Press any key to dismiss</Text>\n </Box>\n )}\n\n <Box marginTop={1}>\n <Text dimColor>\n <Text color=\"yellow\">x</Text> execute |<Text color=\"green\">c</Text> create |\n <Text color=\"cyan\">Enter</Text> expand |<Text color=\"gray\">↑↓</Text> navigate |\n <Text color=\"gray\">Esc</Text> back\n </Text>\n </Box>\n </Box>\n );\n}\n","import { exec } from \"child_process\";\nimport { Box, Text, useApp, useInput } from \"ink\";\nimport type React from \"react\";\nimport { useEffect, useEffectEvent, useRef, useState } from \"react\";\nimport { Gerbil } from \"../../core/gerbil.js\";\nimport { setToolContext } from \"../../core/tools.js\";\nimport {\n CURRENT_VERSION,\n checkForUpdate,\n installUpdate,\n type UpdateCheckResult,\n} from \"./auto-update.js\";\nimport { cleanResponse, getCacheInfo, hyperlink, type SessionStats } from \"./utils.js\";\nimport { type BenchmarkResult, type BenchmarkStats, BenchmarkView } from \"./views/BenchmarkView.js\";\nimport { ChatView } from \"./views/ChatView.js\";\nimport { CodeView } from \"./views/CodeView.js\";\nimport { CreateSkillView } from \"./views/CreateSkillView.js\";\nimport { CreateToolView } from \"./views/CreateToolView.js\";\nimport { FrameworksView } from \"./views/FrameworksView.js\";\nimport { InfoView } from \"./views/InfoView.js\";\nimport { LoadingView } from \"./views/LoadingView.js\";\nimport { ModelView } from \"./views/ModelView.js\";\nimport { ServeView } from \"./views/ServeView.js\";\nimport { SkillsView } from \"./views/SkillsView\";\nimport { ToolsView } from \"./views/ToolsView.js\";\n\nexport type View =\n | \"menu\"\n | \"chat\"\n | \"tools\"\n | \"skills\"\n | \"create-skill\"\n | \"create-tool\"\n | \"code\"\n | \"model\"\n | \"frameworks\"\n | \"benchmark\"\n | \"info\"\n | \"serve\";\n\nexport type AppState = {\n view: View;\n gerbil: Gerbil | null;\n model: string;\n loading: boolean;\n loadingMessage: string;\n thinkingMode: boolean;\n agentMode: boolean;\n downloadStatus: string;\n deviceMode: \"webgpu\" | \"cpu\";\n};\n\nconst MENU_ITEMS = [\n {\n key: \"1\",\n view: \"chat\" as View,\n label: \"Chat\",\n desc: \"Talk with Gerbil\",\n color: \"cyan\",\n },\n {\n key: \"2\",\n view: \"skills\" as View,\n label: \"Skills\",\n desc: \"Run AI skills\",\n color: \"yellow\",\n },\n {\n key: \"3\",\n view: \"tools\" as View,\n label: \"Tools\",\n desc: \"Manage tools\",\n color: \"magenta\",\n },\n {\n key: \"4\",\n view: \"model\" as View,\n label: \"Model\",\n desc: \"Change model\",\n color: \"blue\",\n },\n {\n key: \"5\",\n view: \"frameworks\" as View,\n label: \"Integrate\",\n desc: \"Framework setup\",\n color: \"cyan\",\n },\n {\n key: \"6\",\n view: \"benchmark\" as View,\n label: \"Benchmark\",\n desc: \"Speed tests\",\n color: \"red\",\n },\n {\n key: \"7\",\n view: \"info\" as View,\n label: \"Info\",\n desc: \"System info\",\n color: \"white\",\n },\n {\n key: \"8\",\n view: \"serve\" as View,\n label: \"Serve\",\n desc: \"Start server\",\n color: \"green\",\n },\n];\n\nfunction openBrowser(url: string) {\n const cmd =\n process.platform === \"darwin\"\n ? `open \"${url}\"`\n : process.platform === \"win32\"\n ? `start \"${url}\"`\n : `xdg-open \"${url}\"`;\n exec(cmd);\n}\n\nconst WELCOME_PROMPT =\n \"You are Gerbil, a helpful AI assistant. Write a warm, friendly greeting in 1 short sentence (under 12 words). Be natural and welcoming. No markdown, no emojis, no XML tags, no asterisks, no quotes, no punctuation at the end.\";\n\n// Context-aware view prompts - can include dynamic state\ntype ViewContext = {\n model?: string;\n deviceMode?: \"cpu\" | \"webgpu\";\n thinkingMode?: boolean;\n agentMode?: boolean;\n cachedModelsCount?: number;\n modelTab?: \"preset\" | \"cached\" | \"huggingface\";\n hfSearchQuery?: string;\n benchmarkStatus?: \"idle\" | \"running\" | \"done\";\n benchmarkStats?: BenchmarkStats;\n};\n\nfunction getViewPrompt(view: View, ctx: ViewContext = {}): string {\n // System instruction to prevent conversational responses\n const system =\n \"Complete the sentence. Do NOT start with 'Sure', 'I', 'Here', 'Of course', or any greeting. Just continue the sentence naturally. Max 20 words.\";\n\n switch (view) {\n case \"chat\":\n return `${system} \"Ready to chat about...\"`;\n case \"skills\":\n return `${system} \"Skills let you...\"`;\n case \"model\": {\n if (ctx.modelTab === \"preset\") {\n return `${system} \"These tested models...\"`;\n }\n if (ctx.modelTab === \"cached\") {\n const count = ctx.cachedModelsCount || 0;\n return `${system} \"${\n count > 0 ? `Your ${count} downloaded models` : \"Downloaded models\"\n }...\"`;\n }\n // HuggingFace tab - mention search if active\n if (ctx.hfSearchQuery) {\n return `${system} \"Searching '${ctx.hfSearchQuery}' to find...\"`;\n }\n return `${system} \"Search HuggingFace to...\"`;\n }\n case \"create-skill\":\n return `${system} \"Create a skill to...\"`;\n case \"code\":\n return `${system} \"Describe what code you need and...\"`;\n case \"benchmark\": {\n const stats = ctx.benchmarkStats;\n if (!stats || stats.runCount === 0) {\n return `${system} \"Run a benchmark to...\"`;\n }\n\n const last = stats.lastResult;\n const bests = stats.bests;\n const avgs = stats.averages;\n\n // Build a rich context for the AI\n let context = `Benchmark results: ${stats.runCount} total runs. `;\n\n if (last) {\n context += `Last run: ${last.tokensPerSec} tok/s, ${last.firstTokenMs}ms first token on ${last.device}. `;\n }\n\n if (bests) {\n context += `Records: fastest ${bests.fastestRun.tokensPerSec} tok/s (${bests.fastestRun.model}/${bests.fastestRun.device}), quickest first token ${bests.fastestFirstToken.firstTokenMs}ms. `;\n }\n\n if (avgs.length > 0) {\n const avgStrs = avgs.map(\n (a) => `${a.model} on ${a.device}: avg ${a.avgTokPerSec} tok/s over ${a.runs} runs`,\n );\n context += `Averages: ${avgStrs.join(\"; \")}. `;\n }\n\n // Compare last to best\n if (last && bests && last.tokensPerSec === bests.fastestRun.tokensPerSec) {\n context += \"This last run set a NEW RECORD! \";\n } else if (last && bests) {\n const diff = bests.fastestRun.tokensPerSec - last.tokensPerSec;\n if (diff > 0) {\n context += `Last run was ${diff} tok/s below the record. `;\n }\n }\n\n return `Based on this benchmark data, give an encouraging and insightful comment. Be specific about the numbers. ${context} Output ONLY the comment, 1-2 sentences. No greetings.`;\n }\n case \"info\":\n return `${system} \"System info shows...\"`;\n case \"serve\":\n return `${system} \"Start a server to...\"`;\n case \"frameworks\":\n return `${system} \"Add Gerbil to your app with...\"`;\n default:\n return \"\";\n }\n}\n\n// Keep static version for backwards compatibility\nconst _VIEW_PROMPTS: Record<View, string> = {\n menu: \"\",\n chat: getViewPrompt(\"chat\"),\n skills: getViewPrompt(\"skills\"),\n tools: \"\",\n \"create-skill\": getViewPrompt(\"create-skill\"),\n \"create-tool\": \"\",\n code: getViewPrompt(\"code\"),\n model: \"\",\n frameworks: \"\",\n benchmark: \"\",\n info: \"\",\n serve: \"\",\n};\n\nexport type DeviceMode = \"cpu\" | \"webgpu\";\n\nexport type AppProps = {\n /** Initial view to show after loading (default: \"menu\") */\n initialView?: View;\n /** Force a specific device mode (cpu or webgpu) */\n forcedDevice?: DeviceMode;\n};\n\nexport function App({ initialView = \"menu\", forcedDevice }: AppProps = {}) {\n const { exit } = useApp();\n const gerbilRef = useRef<Gerbil | null>(null); // Ref for cleanup\n // Determine initial device mode\n const initialDevice = forcedDevice ?? (process.env.GERBIL_CPU === \"1\" ? \"cpu\" : \"webgpu\");\n\n const [state, setState] = useState<AppState>({\n view: \"menu\", // Always start at menu during loading\n gerbil: null,\n model: \"qwen3-0.6b\",\n loading: true,\n loadingMessage: \"Loading model...\",\n thinkingMode: false,\n agentMode: true, // On by default - using proper Qwen tool format\n downloadStatus: \"\",\n deviceMode: initialDevice,\n });\n const [pendingView, setPendingView] = useState<View | null>(\n initialView !== \"menu\" ? initialView : null,\n );\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [prevSelectedIndex, setPrevSelectedIndex] = useState(0);\n const [selectionPulse, setSelectionPulse] = useState(false);\n const [viewTransition, setViewTransition] = useState<\"in\" | \"out\" | null>(null);\n const [welcomeMessage, setWelcomeMessage] = useState(\"\");\n const [viewTip, setViewTip] = useState(\"\");\n const [generatingTip, setGeneratingTip] = useState(false);\n const generatingTipRef = useRef(false); // Ref to check without causing re-renders\n const [ctrlCPressed, setCtrlCPressed] = useState(false);\n const [modelTab, setModelTab] = useState<\"preset\" | \"cached\" | \"huggingface\">(\"preset\");\n const [hfSearchQuery, setHfSearchQuery] = useState(\"\");\n const [benchmarkStatus, setBenchmarkStatus] = useState<\"idle\" | \"running\" | \"done\">(\"idle\");\n const [benchmarkStatsState, setBenchmarkStatsState] = useState<BenchmarkStats | undefined>();\n\n // Konami code easter egg\n const [konamiSequence, setKonamiSequence] = useState<string[]>([]);\n const [konamiActivated, setKonamiActivated] = useState(false);\n const [konamiMessage, setKonamiMessage] = useState(\"\");\n const KONAMI_CODE = [\"up\", \"up\", \"down\", \"down\", \"left\", \"right\", \"left\", \"right\", \"b\", \"a\"];\n\n const [sessionStats, setSessionStats] = useState<SessionStats>({\n prompts: 0,\n tokensIn: 0,\n tokensOut: 0,\n totalTimeMs: 0,\n startTime: Date.now(),\n benchResults: [],\n lastTokPerSec: 0,\n avgTokPerSec: 0,\n });\n\n // Benchmark comparison state (persists across model switches)\n const [benchmarkResults, setBenchmarkResults] = useState<BenchmarkResult[]>([]);\n const [benchmarkModels, setBenchmarkModels] = useState<string[]>([]);\n const [returnToBenchmark, setReturnToBenchmark] = useState(false);\n\n // Update state\n const [updateCheck, setUpdateCheck] = useState<UpdateCheckResult | null>(null);\n const [isUpdating, setIsUpdating] = useState(false);\n const [updateSuccess, setUpdateSuccess] = useState(false);\n\n // Animation: pulse effect when selection changes\n useEffect(() => {\n if (selectedIndex !== prevSelectedIndex) {\n setPrevSelectedIndex(selectedIndex);\n setSelectionPulse(true);\n const timer = setTimeout(() => setSelectionPulse(false), 150);\n return () => clearTimeout(timer);\n }\n }, [selectedIndex, prevSelectedIndex]);\n\n // Animation: view transition\n const transitionToView = (newView: View) => {\n setViewTransition(\"out\");\n setTimeout(() => {\n setState((s) => ({ ...s, view: newView }));\n setViewTransition(\"in\");\n setTimeout(() => setViewTransition(null), 200);\n }, 100);\n };\n\n // Generate welcome message\n const generateWelcome = useEffectEvent(async (g: Gerbil) => {\n try {\n setWelcomeMessage(\"\");\n for await (const chunk of g.stream(WELCOME_PROMPT, { maxTokens: 20 })) {\n setWelcomeMessage((m) => m + chunk);\n }\n } catch {\n // Ignore welcome generation errors\n setWelcomeMessage(\"Ready to help!\");\n }\n });\n\n // Load model on start\n useEffect(() => {\n let mounted = true; // Guard against strict mode double-render\n\n const loadModel = async () => {\n const g = new Gerbil();\n try {\n // Use the device mode from state (set from CLI flag or env var)\n const device = state.deviceMode;\n\n await g.loadModel(state.model, {\n device,\n onProgress: (p) => {\n if (!mounted) {\n return;\n }\n if (p.status?.includes(\"Unable to determine content-length\")) {\n return;\n }\n setState((s) => ({\n ...s,\n loadingMessage: p.file ? `${p.file} ${p.progress || 0}%` : p.status,\n }));\n },\n });\n\n if (!mounted) {\n // Component unmounted during load - clean up\n g.dispose();\n return;\n }\n\n const modelInfo = g.getModelInfo();\n const supportsThinking = modelInfo?.supportsThinking ?? false;\n\n // Set tool context so tools can use gerbil.generate()\n setToolContext({\n generate: async (prompt: string) => {\n const result = await g.generate(prompt, { maxTokens: 200 });\n return result.text;\n },\n });\n\n gerbilRef.current = g; // Store in ref for cleanup\n setState((s) => ({\n ...s,\n gerbil: g,\n loading: false,\n thinkingMode: supportsThinking,\n // If we have a pending view, go directly there\n view: pendingView || \"menu\",\n }));\n\n // Clear pending view\n if (pendingView) {\n setPendingView(null);\n }\n\n // Generate welcome in background\n // For WebGPU, add a delay to let Chrome GPU stabilize\n const isWebGPU = g.getDeviceMode() === \"webgpu\";\n if (isWebGPU) {\n setTimeout(() => generateWelcome(g).catch(() => {}), 1500);\n } else {\n generateWelcome(g).catch(() => {});\n }\n } catch (error) {\n if (!mounted) {\n return;\n }\n setState((s) => ({\n ...s,\n loading: false,\n loadingMessage: `Error: ${error}`,\n }));\n }\n };\n loadModel();\n\n return () => {\n mounted = false;\n // Only dispose if we actually have a gerbil instance\n if (gerbilRef.current) {\n gerbilRef.current.dispose().catch(() => {});\n gerbilRef.current = null;\n }\n };\n }, [pendingView, state.deviceMode, state.model]);\n\n // Check for updates on mount (non-blocking)\n useEffect(() => {\n const performUpdateCheck = async () => {\n const result = await checkForUpdate();\n if (result.updateAvailable) {\n setUpdateCheck(result);\n }\n };\n\n // Run in background, don't block\n performUpdateCheck().catch(() => {\n // Silent fail - don't interrupt user experience\n });\n }, []);\n\n // Handle update installation\n const handleUpdate = async () => {\n setIsUpdating(true);\n const result = await installUpdate();\n setIsUpdating(false);\n\n if (result.success) {\n setUpdateSuccess(true);\n setUpdateCheck(null);\n // Clear success message after 10s\n setTimeout(() => setUpdateSuccess(false), 10_000);\n } else {\n // Show error briefly\n setUpdateCheck({\n ...updateCheck!,\n error: result.error,\n });\n setTimeout(() => {\n if (updateCheck) {\n setUpdateCheck({ ...updateCheck, error: undefined });\n }\n }, 5000);\n }\n };\n\n // Generate view tip when changing views - with context awareness\n useEffect(() => {\n if (!state.gerbil || state.view === \"menu\") {\n return;\n }\n\n // Skip regenerating tip while benchmark is running - this would cause concurrent\n // generation which crashes transformers.js (tensor disposed error)\n if (state.view === \"benchmark\" && benchmarkStatus === \"running\") {\n return;\n }\n\n // Get cached models count for model view\n const cacheInfo = state.view === \"model\" ? getCacheInfo() : null;\n\n // Build context for the prompt\n const ctx: ViewContext = {\n model: state.model,\n deviceMode: state.deviceMode,\n thinkingMode: state.thinkingMode,\n agentMode: state.agentMode,\n modelTab: state.view === \"model\" ? modelTab : undefined,\n hfSearchQuery:\n state.view === \"model\" && modelTab === \"huggingface\" ? hfSearchQuery : undefined,\n cachedModelsCount: cacheInfo?.models.length,\n benchmarkStatus: state.view === \"benchmark\" ? benchmarkStatus : undefined,\n benchmarkStats: state.view === \"benchmark\" ? benchmarkStatsState : undefined,\n };\n\n // Get context-aware prompt\n const prompt = getViewPrompt(state.view, ctx);\n if (!prompt) {\n return;\n }\n\n // Use a ref to track if we should abort (view changed during generation)\n let cancelled = false;\n\n const generateTip = async () => {\n // Don't start if already generating - prevents concurrent generation crash\n if (generatingTipRef.current) {\n return;\n }\n\n setViewTip(\"\");\n setGeneratingTip(true);\n generatingTipRef.current = true;\n try {\n for await (const chunk of state.gerbil!.stream(prompt, {\n maxTokens: 50,\n })) {\n if (cancelled) {\n break;\n }\n setViewTip((t) => t + chunk);\n }\n } catch {\n // Ignore tip generation errors (including interrupts)\n }\n generatingTipRef.current = false;\n if (!cancelled) {\n setGeneratingTip(false);\n }\n };\n generateTip();\n\n // Cleanup: mark as cancelled if effect re-runs before completion\n return () => {\n cancelled = true;\n };\n }, [\n state.view,\n state.gerbil,\n state.model,\n state.deviceMode,\n state.thinkingMode,\n state.agentMode,\n modelTab,\n hfSearchQuery,\n benchmarkStatus,\n benchmarkStatsState,\n ]);\n\n // Reset Ctrl+C warning after a delay\n useEffect(() => {\n if (ctrlCPressed) {\n const timer = setTimeout(() => setCtrlCPressed(false), 3000);\n return () => clearTimeout(timer);\n }\n }, [ctrlCPressed]);\n\n // Reload with a specific device mode (for menu 'm' key and benchmark)\n const handleDeviceSwitch = async (newDevice: \"webgpu\" | \"cpu\") => {\n if (newDevice === state.deviceMode) {\n return;\n }\n\n setState((s) => ({\n ...s,\n deviceMode: newDevice,\n loading: true,\n loadingMessage: `Switching to ${newDevice.toUpperCase()}...`,\n }));\n\n // Dispose old gerbil\n gerbilRef.current?.dispose();\n gerbilRef.current = null;\n\n const g = new Gerbil();\n try {\n await g.loadModel(state.model, {\n device: newDevice,\n onProgress: (p) => {\n if (p.status?.includes(\"Unable to determine content-length\")) {\n return;\n }\n setState((s) => ({\n ...s,\n loadingMessage: p.file ? `${p.file} ${p.progress || 0}%` : p.status,\n }));\n },\n });\n const modelInfo = g.getModelInfo();\n const supportsThinking = modelInfo?.supportsThinking ?? false;\n\n setToolContext({\n generate: async (prompt: string) => {\n const result = await g.generate(prompt, { maxTokens: 200 });\n return result.text;\n },\n });\n\n gerbilRef.current = g;\n setState((s) => ({\n ...s,\n gerbil: g,\n loading: false,\n thinkingMode: supportsThinking,\n }));\n } catch (error) {\n setState((s) => ({\n ...s,\n loading: false,\n loadingMessage: `Error: ${error}`,\n }));\n }\n };\n\n // Global key handlers\n useInput((input, key) => {\n // Ctrl+C handling\n if (key.ctrl && input === \"c\") {\n if (ctrlCPressed) {\n // Exit immediately - cleanup happens in useEffect unmount\n exit();\n } else {\n setCtrlCPressed(true);\n }\n return;\n }\n\n if (ctrlCPressed) {\n setCtrlCPressed(false);\n }\n\n // Konami code detection (only on menu)\n if (state.view === \"menu\" && !konamiActivated) {\n let keyPressed = \"\";\n if (key.upArrow) {\n keyPressed = \"up\";\n } else if (key.downArrow) {\n keyPressed = \"down\";\n } else if (key.leftArrow) {\n keyPressed = \"left\";\n } else if (key.rightArrow) {\n keyPressed = \"right\";\n } else if (input === \"b\" || input === \"B\") {\n keyPressed = \"b\";\n } else if (input === \"a\" || input === \"A\") {\n keyPressed = \"a\";\n }\n\n if (keyPressed) {\n const newSequence = [...konamiSequence, keyPressed].slice(-10);\n setKonamiSequence(newSequence);\n\n if (newSequence.length === 10 && newSequence.every((k, i) => k === KONAMI_CODE[i])) {\n setKonamiActivated(true);\n setKonamiSequence([]);\n\n if (state.gerbil) {\n setKonamiMessage(\"*~* KONAMI CODE ACTIVATED *~*\");\n state.gerbil\n .generate(\n \"You just discovered a secret easter egg! Generate a single fun, quirky one-liner message (max 15 words) celebrating the user's achievement. Be playful and geeky. No quotes.\",\n { maxTokens: 50, temperature: 0.9 },\n )\n .then((result) => {\n const msg = result.text.replace(/<\\/?think>/g, \"\").trim();\n setKonamiMessage(`*~* ${msg} *~*`);\n setTimeout(() => {\n setKonamiActivated(false);\n setKonamiMessage(\"\");\n }, 5000);\n })\n .catch(() => {\n setKonamiMessage(\"*~* +30 LIVES! Just kidding, this is an LLM. *~*\");\n setTimeout(() => {\n setKonamiActivated(false);\n setKonamiMessage(\"\");\n }, 5000);\n });\n }\n }\n }\n }\n\n // Q to quit from menu\n if ((input === \"q\" || input === \"Q\") && state.view === \"menu\") {\n // Exit immediately - cleanup happens in useEffect unmount\n exit();\n return;\n }\n\n // Ctrl+Q to quit from anywhere\n if (input === \"q\" && key.ctrl) {\n // Exit immediately - cleanup happens in useEffect unmount\n exit();\n return;\n }\n\n // U to update (when update available)\n if ((input === \"u\" || input === \"U\") && updateCheck && !isUpdating) {\n handleUpdate();\n return;\n }\n\n // Menu navigation (grid: row 0 has 4 items, row 1 has 4 items)\n const ROW1_SIZE = 4;\n\n if (state.view === \"menu\") {\n if (key.leftArrow) {\n setSelectedIndex((i) => {\n if (i === 0) {\n return ROW1_SIZE - 1;\n }\n if (i === ROW1_SIZE) {\n return MENU_ITEMS.length - 1;\n }\n return i - 1;\n });\n }\n if (key.rightArrow) {\n setSelectedIndex((i) => {\n if (i === ROW1_SIZE - 1) {\n return 0;\n }\n if (i === MENU_ITEMS.length - 1) {\n return ROW1_SIZE;\n }\n return i + 1;\n });\n }\n if (key.upArrow) {\n setSelectedIndex((i) => {\n if (i < ROW1_SIZE) {\n const col = i;\n return Math.min(ROW1_SIZE + col, MENU_ITEMS.length - 1);\n }\n const col = i - ROW1_SIZE;\n return Math.min(col, ROW1_SIZE - 1);\n });\n }\n if (key.downArrow) {\n setSelectedIndex((i) => {\n if (i < ROW1_SIZE) {\n return Math.min(ROW1_SIZE + i, MENU_ITEMS.length - 1);\n }\n const col = i - ROW1_SIZE;\n return Math.min(col, ROW1_SIZE - 1);\n });\n }\n if (key.return) {\n transitionToView(MENU_ITEMS[selectedIndex].view);\n }\n // Number keys for quick select (0-9)\n if (/^[0-9]$/.test(input)) {\n const item = MENU_ITEMS.find((m) => m.key === input);\n if (item) {\n const idx = MENU_ITEMS.indexOf(item);\n setSelectedIndex(idx);\n transitionToView(item.view);\n }\n }\n // D for docs\n if (input === \"d\" || input === \"D\") {\n openBrowser(\"https://github.com/gethamster/gerbil#readme\");\n }\n // G for github\n if (input === \"g\" || input === \"G\") {\n openBrowser(\"https://github.com/gethamster/gerbil\");\n }\n } else {\n // Escape goes back to menu\n if (key.escape) {\n transitionToView(\"menu\");\n }\n }\n\n // Ctrl+T to toggle thinking mode (anywhere)\n if (input === \"t\" && key.ctrl) {\n const modelInfo = state.gerbil?.getModelInfo();\n if (modelInfo?.supportsThinking) {\n setState((s) => ({ ...s, thinkingMode: !s.thinkingMode }));\n }\n } else if ((input === \"t\" || input === \"T\") && state.view === \"menu\") {\n const modelInfo = state.gerbil?.getModelInfo();\n if (modelInfo?.supportsThinking) {\n setState((s) => ({ ...s, thinkingMode: !s.thinkingMode }));\n }\n }\n\n // Ctrl+A to toggle agent mode (anywhere)\n if (input === \"a\" && key.ctrl) {\n setState((s) => ({ ...s, agentMode: !s.agentMode }));\n } else if ((input === \"a\" || input === \"A\") && state.view === \"menu\") {\n setState((s) => ({ ...s, agentMode: !s.agentMode }));\n }\n\n // M to toggle device mode (menu only)\n if ((input === \"m\" || input === \"M\") && state.view === \"menu\" && !state.loading) {\n const newDevice = state.deviceMode === \"webgpu\" ? \"cpu\" : \"webgpu\";\n handleDeviceSwitch(newDevice);\n }\n });\n\n if (state.loading) {\n return <LoadingView message={state.loadingMessage} />;\n }\n\n // Menu view\n if (state.view === \"menu\") {\n return (\n <Box flexDirection=\"column\" paddingX={2} paddingY={1}>\n <Box alignItems=\"center\" flexDirection=\"column\">\n <Text bold color=\"cyan\">\n 🐹 Gerbil\n </Text>\n <Text dimColor>Local LLM inference for Node.js</Text>\n <Text dimColor>by {hyperlink(\"https://tryhamster.com\", \"tryhamster.com\")}</Text>\n </Box>\n\n {welcomeMessage && (\n <Box alignItems=\"center\" justifyContent=\"center\" marginY={1}>\n <Text color=\"gray\" italic>\n {cleanResponse(welcomeMessage)}\n </Text>\n </Box>\n )}\n\n <Box justifyContent=\"center\">\n <Text dimColor>model: </Text>\n <Text color=\"white\">{state.model}</Text>\n <Text dimColor> · </Text>\n <Text bold color={state.gerbil?.getDeviceMode() === \"webgpu\" ? \"green\" : \"yellow\"}>\n {state.gerbil?.getDeviceMode()?.toUpperCase() || \"CPU\"}\n </Text>\n {state.gerbil?.getModelInfo()?.supportsThinking && (\n <>\n <Text dimColor> · thinking: </Text>\n <Text bold={state.thinkingMode} color={state.thinkingMode ? \"magenta\" : \"gray\"}>\n {state.thinkingMode ? \"on\" : \"off\"}\n </Text>\n </>\n )}\n <Text dimColor> · agent: </Text>\n <Text bold={state.agentMode} color={state.agentMode ? \"green\" : \"gray\"}>\n {state.agentMode ? \"on\" : \"off\"}\n </Text>\n </Box>\n\n {konamiActivated && konamiMessage && (\n <Box justifyContent=\"center\" marginY={1}>\n <Text backgroundColor=\"black\" bold color=\"magenta\">\n {konamiMessage}\n </Text>\n </Box>\n )}\n\n <Box alignItems=\"center\" flexDirection=\"column\" marginY={1}>\n <Box justifyContent=\"center\">\n {MENU_ITEMS.slice(0, 4).map((item, idx) => (\n <MenuCard\n isTopRow={true}\n item={item}\n key={item.key}\n pulse={selectionPulse && idx === selectedIndex}\n selected={idx === selectedIndex}\n />\n ))}\n </Box>\n <Box justifyContent=\"center\">\n {MENU_ITEMS.slice(4).map((item, idx) => (\n <MenuCard\n isTopRow={false}\n item={item}\n key={item.key}\n pulse={selectionPulse && idx + 4 === selectedIndex}\n selected={idx + 4 === selectedIndex}\n />\n ))}\n </Box>\n </Box>\n\n <Box justifyContent=\"center\">\n <Text dimColor>arrows · enter · </Text>\n <Text color=\"yellow\">1-8</Text>\n {state.gerbil?.getModelInfo()?.supportsThinking && (\n <>\n <Text dimColor> · </Text>\n <Text color=\"magenta\">t</Text>\n <Text dimColor>hink</Text>\n </>\n )}\n <Text dimColor> · </Text>\n <Text color=\"green\">a</Text>\n <Text dimColor>gent · </Text>\n <Text color=\"cyan\">m</Text>\n <Text dimColor>ode · </Text>\n <Text color=\"blue\">d</Text>\n <Text dimColor>ocs · </Text>\n <Text color=\"blue\">g</Text>\n <Text dimColor>ithub · </Text>\n <Text color=\"red\">q</Text>\n <Text dimColor>uit</Text>\n </Box>\n\n {ctrlCPressed && (\n <Box justifyContent=\"center\" marginTop={1}>\n <Text color=\"yellow\">Press Ctrl+C again to quit</Text>\n </Box>\n )}\n </Box>\n );\n }\n\n // Handle model switching\n const handleModelSelect = async (model: string, deviceOverride?: \"webgpu\" | \"cpu\") => {\n const returnView = returnToBenchmark ? \"benchmark\" : \"menu\";\n const newDevice = deviceOverride ?? state.deviceMode;\n setState((s) => ({\n ...s,\n model,\n deviceMode: newDevice,\n view: returnView,\n loading: true,\n loadingMessage: \"Switching model...\",\n }));\n setReturnToBenchmark(false);\n\n // Dispose old gerbil using ref\n gerbilRef.current?.dispose();\n gerbilRef.current = null;\n\n const g = new Gerbil();\n try {\n await g.loadModel(model, {\n device: newDevice,\n onProgress: (p) => {\n if (p.status?.includes(\"Unable to determine content-length\")) {\n return;\n }\n setState((s) => ({\n ...s,\n loadingMessage: p.file ? `${p.file} ${p.progress || 0}%` : p.status,\n }));\n },\n });\n const modelInfo = g.getModelInfo();\n const supportsThinking = modelInfo?.supportsThinking ?? false;\n\n // Update tool context for new model\n setToolContext({\n generate: async (prompt: string) => {\n const result = await g.generate(prompt, { maxTokens: 200 });\n return result.text;\n },\n });\n\n gerbilRef.current = g; // Update ref\n setState((s) => ({\n ...s,\n gerbil: g,\n loading: false,\n thinkingMode: supportsThinking,\n }));\n generateWelcome(g);\n } catch (error) {\n setState((s) => ({\n ...s,\n loading: false,\n loadingMessage: `Error: ${error}`,\n }));\n }\n };\n\n const handleDownloadOnly = async (modelId: string, _hfId: string): Promise<boolean> => {\n setState((s) => ({ ...s, downloadStatus: `Downloading ${modelId}...` }));\n const tempGerbil = new Gerbil();\n try {\n await tempGerbil.loadModel(modelId, {\n onProgress: (p) => {\n if (p.status?.includes(\"Unable to determine content-length\")) {\n return;\n }\n setState((s) => ({\n ...s,\n downloadStatus: p.file ? `${p.file} ${p.progress || 0}%` : p.status || \"\",\n }));\n },\n });\n tempGerbil.dispose();\n setState((s) => ({\n ...s,\n downloadStatus: `[done] Downloaded ${modelId}`,\n }));\n setTimeout(() => setState((s) => ({ ...s, downloadStatus: \"\" })), 2500);\n return true; // Success\n } catch (error) {\n setState((s) => ({ ...s, downloadStatus: `[error] ${error}` }));\n setTimeout(() => setState((s) => ({ ...s, downloadStatus: \"\" })), 3000);\n return false; // Failed\n }\n };\n\n // Active view with minimal header\n return (\n <Box flexDirection=\"column\" height=\"100%\">\n <Box\n borderBottom={false}\n borderColor=\"gray\"\n borderLeft={false}\n borderRight={false}\n borderStyle=\"single\"\n paddingX={1}\n >\n <Text bold color=\"cyan\">\n gerbil\n </Text>\n <Text color=\"gray\"> </Text>\n <Text dimColor>{CURRENT_VERSION}</Text>\n <Text color=\"gray\"> / </Text>\n <Text color=\"white\">\n {MENU_ITEMS.find((m) => m.view === state.view)?.label || state.view}\n </Text>\n {state.thinkingMode && (\n <>\n <Text color=\"gray\"> / </Text>\n <Text color=\"magenta\">thinking</Text>\n </>\n )}\n {state.agentMode && (\n <>\n <Text color=\"gray\"> / </Text>\n <Text color=\"green\">agent</Text>\n </>\n )}\n {state.downloadStatus && (\n <>\n <Text color=\"gray\"> | </Text>\n <Text color=\"yellow\">{state.downloadStatus}</Text>\n </>\n )}\n {isUpdating && (\n <>\n <Text color=\"gray\"> | </Text>\n <Text color=\"yellow\">⬇ Updating...</Text>\n </>\n )}\n {updateSuccess && (\n <>\n <Text color=\"gray\"> | </Text>\n <Text color=\"green\">✅ Updated! Restart to use v{updateCheck?.latestVersion}</Text>\n </>\n )}\n {updateCheck && !isUpdating && !updateSuccess && (\n <>\n <Text color=\"gray\"> | </Text>\n <Text color=\"cyan\">Update v{updateCheck.latestVersion} → Press </Text>\n <Text bold color=\"cyan\">\n u\n </Text>\n <Text color=\"cyan\"> to update</Text>\n </>\n )}\n <Text color=\"gray\"> | </Text>\n <Text dimColor>esc back | ^C quit</Text>\n {ctrlCPressed && <Text color=\"yellow\"> (again to quit)</Text>}\n </Box>\n\n {viewTip && (\n <Box paddingX={2} paddingY={1}>\n <Text dimColor italic>\n {generatingTip ? `${cleanResponse(viewTip)}▋` : cleanResponse(viewTip)}\n </Text>\n </Box>\n )}\n\n <Box flexDirection=\"column\" flexGrow={1}>\n <ViewTransition transition={viewTransition}>\n {state.view === \"chat\" && state.gerbil && (\n <ChatView\n agentMode={state.agentMode}\n avgTokPerSec={sessionStats.avgTokPerSec}\n gerbil={state.gerbil}\n lastTokPerSec={sessionStats.lastTokPerSec}\n onCreateTool={() => transitionToView(\"create-tool\")}\n onGenerationComplete={(stats) => {\n setSessionStats((s) => {\n const newPrompts = s.prompts + 1;\n const newTotalTokens = s.tokensOut + stats.tokensOut;\n const newTotalTime = s.totalTimeMs + stats.timeMs;\n return {\n ...s,\n prompts: newPrompts,\n tokensOut: newTotalTokens,\n totalTimeMs: newTotalTime,\n lastTokPerSec: stats.tokPerSec,\n avgTokPerSec: newTotalTime > 0 ? (newTotalTokens / newTotalTime) * 1000 : 0,\n };\n });\n }}\n thinkingMode={state.thinkingMode}\n />\n )}\n {state.view === \"skills\" && state.gerbil && (\n <SkillsView\n gerbil={state.gerbil}\n onCreateNew={() => transitionToView(\"create-skill\")}\n onSwitchModel={async (modelId) => {\n // Switch to the selected model\n setState((s) => ({\n ...s,\n loading: true,\n loadingMessage: `Loading ${modelId}...`,\n }));\n try {\n await state.gerbil!.loadModel(modelId);\n setState((s) => ({ ...s, model: modelId, loading: false }));\n } catch (_err) {\n setState((s) => ({ ...s, loading: false }));\n }\n }}\n />\n )}\n {state.view === \"create-skill\" && state.gerbil && (\n <CreateSkillView gerbil={state.gerbil} onDone={() => transitionToView(\"menu\")} />\n )}\n {state.view === \"tools\" && (\n <ToolsView onCreateTool={() => transitionToView(\"create-tool\")} />\n )}\n {state.view === \"create-tool\" && state.gerbil && (\n <CreateToolView gerbil={state.gerbil} onDone={() => transitionToView(\"tools\")} />\n )}\n {state.view === \"code\" && state.gerbil && <CodeView gerbil={state.gerbil} />}\n {state.view === \"model\" && (\n <ModelView\n currentModel={state.model}\n onDownloadOnly={handleDownloadOnly}\n onSearchChange={setHfSearchQuery}\n onSelect={handleModelSelect}\n onTabChange={setModelTab}\n />\n )}\n {state.view === \"frameworks\" && <FrameworksView />}\n {state.view === \"benchmark\" && state.gerbil && (\n <BenchmarkView\n benchmarkModels={benchmarkModels}\n benchmarkResults={benchmarkResults}\n disabled={generatingTip}\n gerbil={state.gerbil}\n model={state.model}\n onResult={(tokPerSec) => {\n setSessionStats((s) => ({\n ...s,\n benchResults: [...s.benchResults, { model: state.model, tokPerSec }],\n }));\n }}\n onStatusChange={(status, stats) => {\n setBenchmarkStatus(status);\n setBenchmarkStatsState(stats);\n }}\n onSwitchDevice={handleDeviceSwitch}\n onSwitchModel={() => {\n setReturnToBenchmark(true);\n transitionToView(\"model\");\n }}\n setBenchmarkModels={setBenchmarkModels}\n setBenchmarkResults={setBenchmarkResults}\n />\n )}\n {state.view === \"info\" && state.gerbil && (\n <InfoView\n gerbil={state.gerbil}\n model={state.model}\n modelFamily={state.gerbil.getModelInfo()?.family || \"other\"}\n onGoToCache={() => {\n // Go to Model view with Cached tab selected\n transitionToView(\"model\");\n // ModelView will need to handle starting on cached tab\n }}\n stats={sessionStats}\n />\n )}\n {state.view === \"serve\" && state.gerbil && (\n <ServeView gerbil={state.gerbil} model={state.model} />\n )}\n </ViewTransition>\n </Box>\n </Box>\n );\n}\n\nfunction ViewTransition({\n transition,\n children,\n}: {\n transition: \"in\" | \"out\" | null;\n children: React.ReactNode;\n}) {\n if (transition === \"out\") {\n return (\n <Box alignItems=\"center\" flexDirection=\"column\" height={3} justifyContent=\"center\">\n <Text dimColor>...</Text>\n </Box>\n );\n }\n return <>{children}</>;\n}\n\nfunction MenuCard({\n item,\n selected,\n pulse,\n}: {\n item: (typeof MENU_ITEMS)[0];\n selected: boolean;\n pulse: boolean;\n isTopRow?: boolean;\n}) {\n const borderStyle = selected ? (pulse ? \"round\" : \"double\") : \"single\";\n const pointer = selected ? (pulse ? \">\" : \"*\") : \" \";\n\n return (\n <Box\n alignItems=\"center\"\n borderColor={selected ? (item.color as any) : \"gray\"}\n borderStyle={borderStyle}\n flexDirection=\"column\"\n justifyContent=\"center\"\n paddingX={1}\n paddingY={1}\n width={20}\n >\n <Box justifyContent=\"center\">\n <Text bold={selected} color={selected ? (item.color as any) : \"gray\"}>\n {pointer}[{item.key}]\n </Text>\n <Text\n bold={selected}\n color={selected ? (item.color as any) : \"white\"}\n inverse={pulse && selected}\n >\n {\" \"}\n {item.label}\n </Text>\n </Box>\n <Text color={selected ? (item.color as any) : undefined} dimColor={!selected}>\n {item.desc}\n </Text>\n </Box>\n );\n}\n","import { render } from \"ink\";\nimport { App, type View } from \"./App.js\";\n\nexport type DeviceMode = \"cpu\" | \"webgpu\";\n\nexport type ReplOptions = {\n /** Initial view to show (default: \"menu\") */\n initialView?: View;\n /** Force a specific device mode (cpu or webgpu) */\n forcedDevice?: DeviceMode;\n};\n\nexport async function startRepl(options?: ReplOptions) {\n // Track SIGINT count for force-exit on repeated signals\n let sigintCount = 0;\n let sigintTimer: NodeJS.Timeout | null = null;\n\n const handleSignal = () => {\n sigintCount++;\n\n // Reset count after 2 seconds\n if (sigintTimer) {\n clearTimeout(sigintTimer);\n }\n sigintTimer = setTimeout(() => {\n sigintCount = 0;\n }, 2000);\n\n if (sigintCount >= 2) {\n // Force exit on second SIGINT (user really wants out)\n process.exit(0);\n }\n // First SIGINT is handled by ink's useInput - don't exit yet\n };\n\n process.on(\"SIGINT\", handleSignal);\n process.on(\"SIGTERM\", () => process.exit(0));\n\n try {\n const { waitUntilExit } = render(\n <App forcedDevice={options?.forcedDevice} initialView={options?.initialView} />,\n );\n await waitUntilExit();\n // Clean exit after ink finishes\n process.exit(0);\n } finally {\n process.off(\"SIGINT\", handleSignal);\n if (sigintTimer) {\n clearTimeout(sigintTimer);\n }\n }\n}\n","#!/usr/bin/env node\n\n/**\n * Gerbil CLI\n *\n * @example\n * ```bash\n * gerbil \"Write a haiku\"\n * gerbil generate \"Hello world\" --thinking\n * gerbil commit\n * gerbil chat\n * gerbil serve --mcp\n * gerbil models\n * gerbil info\n * ```\n */\n\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport ora from \"ora\";\nimport { version } from \"../../package.json\" with { type: \"json\" };\nimport { Gerbil } from \"../core/gerbil.js\";\nimport { BUILTIN_MODELS } from \"../core/models.js\";\nimport { startMCPServer } from \"../integrations/mcp.js\";\nimport * as skills from \"../skills/index.js\";\nimport { startRepl } from \"./repl/index.js\";\n\nconst program = new Command();\n\nprogram.name(\"gerbil\").description(\"🐹 Local LLM inference for Node.js\").version(version);\n\n// ============================================\n// Default command: generate\n// ============================================\n\nprogram\n .argument(\"[prompt...]\", \"Prompt to generate from (opens REPL if empty)\")\n .option(\"-m, --model <id>\", \"Model to use\", \"qwen3-0.6b\")\n .option(\"-n, --max-tokens <n>\", \"Max tokens\", \"256\")\n .option(\"-t, --temperature <t>\", \"Temperature\", \"0.7\")\n .option(\"-s, --system <text>\", \"System prompt\")\n .option(\"--thinking\", \"Enable thinking mode\")\n .option(\"--stream\", \"Stream output\")\n .option(\"--json\", \"Output as JSON\")\n .action(async (promptParts, opts) => {\n // If no prompt provided, launch REPL\n if (promptParts.length === 0) {\n await startRepl({});\n return;\n }\n\n const prompt = promptParts.join(\" \");\n await runGenerate(prompt, opts);\n });\n\n// ============================================\n// Generate command\n// ============================================\n\nprogram\n .command(\"generate <prompt...>\")\n .alias(\"g\")\n .description(\"Generate text\")\n .option(\"-m, --model <id>\", \"Model to use\", \"qwen3-0.6b\")\n .option(\"-n, --max-tokens <n>\", \"Max tokens\", \"256\")\n .option(\"-t, --temperature <t>\", \"Temperature\", \"0.7\")\n .option(\"-s, --system <text>\", \"System prompt\")\n .option(\"--thinking\", \"Enable thinking mode\")\n .option(\"--stream\", \"Stream output\")\n .option(\"--json\", \"Output as JSON\")\n .action(async (promptParts, opts) => {\n const prompt = promptParts.join(\" \");\n await runGenerate(prompt, opts);\n });\n\nasync function runGenerate(prompt: string, opts: any) {\n const g = new Gerbil();\n const spinner = ora(`Loading ${chalk.cyan(opts.model)}...`).start();\n\n try {\n await g.loadModel(opts.model, {\n onProgress: (p) => {\n spinner.text = p.progress ? `${p.status} (${p.progress}%)` : p.status;\n },\n });\n spinner.succeed(\"Model loaded\");\n\n if (opts.thinking) {\n console.log(chalk.magenta(\"\\n💭 Thinking mode enabled\\n\"));\n }\n\n if (opts.stream) {\n process.stdout.write(chalk.green(\"Response: \"));\n for await (const chunk of g.stream(prompt, {\n maxTokens: Number.parseInt(opts.maxTokens, 10),\n temperature: Number.parseFloat(opts.temperature),\n system: opts.system,\n thinking: opts.thinking,\n })) {\n process.stdout.write(chunk);\n }\n console.log();\n } else {\n const genSpinner = ora(\"Generating...\").start();\n const result = await g.generate(prompt, {\n maxTokens: Number.parseInt(opts.maxTokens, 10),\n temperature: Number.parseFloat(opts.temperature),\n system: opts.system,\n thinking: opts.thinking,\n });\n genSpinner.stop();\n\n if (opts.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.thinking) {\n console.log(chalk.cyan(\"\\n💭 Thinking:\"), result.thinking, \"\\n\");\n }\n console.log(chalk.green(\"Response:\"), result.text);\n console.log(\n chalk.dim(\n `\\n(${result.tokensPerSecond.toFixed(1)} tok/s, ${result.totalTime.toFixed(0)}ms)`,\n ),\n );\n }\n }\n\n await g.dispose();\n } catch (e) {\n spinner.fail(\"Error\");\n console.error(chalk.red(String(e)));\n process.exit(1);\n }\n}\n\n// ============================================\n// REPL command (TUI)\n// ============================================\n\nprogram\n .command(\"repl\")\n .alias(\"r\")\n .description(\"Interactive TUI with chat, skills, and more\")\n .option(\"--cpu\", \"Force CPU inference mode\")\n .option(\"--gpu\", \"Force GPU/WebGPU inference mode\")\n .action(async (opts) => {\n const forcedDevice = opts.cpu ? \"cpu\" : opts.gpu ? \"webgpu\" : undefined;\n await startRepl({ forcedDevice });\n });\n\n// ============================================\n// Chat command (opens REPL in chat view)\n// ============================================\n\nprogram\n .command(\"chat\")\n .alias(\"c\")\n .description(\"Interactive chat (opens REPL chat view)\")\n .option(\"--cpu\", \"Force CPU inference mode\")\n .option(\"--gpu\", \"Force GPU/WebGPU inference mode\")\n .action(async (opts) => {\n const forcedDevice = opts.cpu ? \"cpu\" : opts.gpu ? \"webgpu\" : undefined;\n await startRepl({ initialView: \"chat\", forcedDevice });\n });\n\n// ============================================\n// REPL View Shortcuts (no args = open view)\n// ============================================\n\nprogram\n .command(\"skills\")\n .description(\"Open REPL skills view\")\n .option(\"--cpu\", \"Force CPU inference mode\")\n .option(\"--gpu\", \"Force GPU/WebGPU inference mode\")\n .action(async (opts) => {\n const forcedDevice = opts.cpu ? \"cpu\" : opts.gpu ? \"webgpu\" : undefined;\n await startRepl({ initialView: \"skills\", forcedDevice });\n });\n\nprogram\n .command(\"tools\")\n .description(\"Open REPL tools view\")\n .option(\"--cpu\", \"Force CPU inference mode\")\n .option(\"--gpu\", \"Force GPU/WebGPU inference mode\")\n .action(async (opts) => {\n const forcedDevice = opts.cpu ? \"cpu\" : opts.gpu ? \"webgpu\" : undefined;\n await startRepl({ initialView: \"tools\", forcedDevice });\n });\n\nprogram\n .command(\"model\")\n .description(\"Open REPL model view\")\n .option(\"--cpu\", \"Force CPU inference mode\")\n .option(\"--gpu\", \"Force GPU/WebGPU inference mode\")\n .action(async (opts) => {\n const forcedDevice = opts.cpu ? \"cpu\" : opts.gpu ? \"webgpu\" : undefined;\n await startRepl({ initialView: \"model\", forcedDevice });\n });\n\nprogram\n .command(\"integrate\")\n .description(\"Open REPL framework integration view\")\n .option(\"--cpu\", \"Force CPU inference mode\")\n .option(\"--gpu\", \"Force GPU/WebGPU inference mode\")\n .action(async (opts) => {\n const forcedDevice = opts.cpu ? \"cpu\" : opts.gpu ? \"webgpu\" : undefined;\n await startRepl({ initialView: \"frameworks\", forcedDevice });\n });\n\nprogram\n .command(\"benchmark\")\n .description(\"Open REPL benchmark view\")\n .option(\"--cpu\", \"Force CPU inference mode\")\n .option(\"--gpu\", \"Force GPU/WebGPU inference mode\")\n .action(async (opts) => {\n const forcedDevice = opts.cpu ? \"cpu\" : opts.gpu ? \"webgpu\" : undefined;\n await startRepl({ initialView: \"benchmark\", forcedDevice });\n });\n\n// ============================================\n// Commit command\n// ============================================\n\nprogram\n .command(\"commit\")\n .description(\"Generate commit message from staged changes\")\n .option(\"--type <type>\", \"Commit style: conventional, simple, detailed\", \"conventional\")\n .option(\"--write\", \"Write message to .git/COMMIT_EDITMSG\")\n .action(async (opts) => {\n const spinner = ora(\"Generating commit message...\").start();\n\n try {\n const message = await skills.commit({ type: opts.type });\n spinner.stop();\n\n console.log(chalk.green(\"Commit message:\"), message);\n\n if (opts.write) {\n const fs = await import(\"fs\");\n fs.writeFileSync(\".git/COMMIT_EDITMSG\", message);\n console.log(chalk.dim(\"\\nWritten to .git/COMMIT_EDITMSG\"));\n }\n } catch (e) {\n spinner.fail(\"Error\");\n console.error(chalk.red(String(e)));\n process.exit(1);\n }\n });\n\n// ============================================\n// Summarize command\n// ============================================\n\nprogram\n .command(\"summarize <file>\")\n .description(\"Summarize a file\")\n .option(\"-l, --length <length>\", \"Length: short, medium, long\", \"medium\")\n .option(\"-f, --format <format>\", \"Format: paragraph, bullets\", \"paragraph\")\n .action(async (file, opts) => {\n const fs = await import(\"fs\");\n const content = fs.readFileSync(file, \"utf-8\");\n\n const spinner = ora(\"Summarizing...\").start();\n\n try {\n const summary = await skills.summarize({\n content,\n length: opts.length,\n format: opts.format,\n });\n spinner.stop();\n\n console.log(chalk.green(\"Summary:\"), summary);\n } catch (e) {\n spinner.fail(\"Error\");\n console.error(chalk.red(String(e)));\n process.exit(1);\n }\n });\n\n// ============================================\n// Explain command\n// ============================================\n\nprogram\n .command(\"explain <file>\")\n .description(\"Explain code\")\n .option(\"-l, --level <level>\", \"Level: beginner, intermediate, expert\", \"intermediate\")\n .action(async (file, opts) => {\n const fs = await import(\"fs\");\n const content = fs.readFileSync(file, \"utf-8\");\n\n const spinner = ora(\"Explaining...\").start();\n\n try {\n const explanation = await skills.explain({ content, level: opts.level });\n spinner.stop();\n\n console.log(chalk.green(\"Explanation:\"), explanation);\n } catch (e) {\n spinner.fail(\"Error\");\n console.error(chalk.red(String(e)));\n process.exit(1);\n }\n });\n\n// ============================================\n// Review command\n// ============================================\n\nprogram\n .command(\"review <file>\")\n .description(\"Review code\")\n .option(\"-f, --focus <areas>\", \"Focus areas (comma-separated)\", \"all\")\n .action(async (file, opts) => {\n const fs = await import(\"fs\");\n const content = fs.readFileSync(file, \"utf-8\");\n\n const spinner = ora(\"Reviewing...\").start();\n\n try {\n const focus = opts.focus === \"all\" ? [\"all\"] : opts.focus.split(\",\");\n const reviewResult = await skills.review({\n code: content,\n focus: focus as any,\n });\n spinner.stop();\n\n console.log(chalk.green(\"Review:\"), reviewResult);\n } catch (e) {\n spinner.fail(\"Error\");\n console.error(chalk.red(String(e)));\n process.exit(1);\n }\n });\n\n// ============================================\n// Serve command\n// ============================================\n\nprogram\n .command(\"serve\")\n .description(\"Start Gerbil server (use --mcp or --http for CLI, otherwise opens REPL)\")\n .option(\"-m, --model <id>\", \"Model to use\", \"qwen3-0.6b\")\n .option(\"-p, --port <port>\", \"HTTP port\", \"3000\")\n .option(\"--mcp\", \"Start MCP server (stdio)\")\n .option(\"--http\", \"Start HTTP server (CLI mode)\")\n .option(\"--cpu\", \"Force CPU inference mode\")\n .option(\"--gpu\", \"Force GPU/WebGPU inference mode\")\n .action(async (opts) => {\n // If no specific server flag, open REPL serve view\n if (!(opts.mcp || opts.http)) {\n const forcedDevice = opts.cpu ? \"cpu\" : opts.gpu ? \"webgpu\" : undefined;\n await startRepl({ initialView: \"serve\", forcedDevice });\n return;\n }\n if (opts.mcp) {\n await startMCPServer({ model: opts.model });\n } else {\n // HTTP server\n const { Gerbil } = await import(\"../core/gerbil.js\");\n const g = new Gerbil();\n\n console.log(chalk.cyan(\"🐹 Gerbil HTTP Server\"));\n console.log(chalk.dim(` Model: ${opts.model}`));\n\n const spinner = ora(\"Loading model...\").start();\n await g.loadModel(opts.model);\n spinner.succeed(\"Model loaded\");\n\n // Simple HTTP server\n const http = await import(\"http\");\n\n const server = http.createServer(async (req, res) => {\n if (req.method === \"POST\" && req.url === \"/generate\") {\n let body = \"\";\n req.on(\"data\", (chunk) => (body += chunk));\n req.on(\"end\", async () => {\n try {\n const { prompt, ...opts } = JSON.parse(body);\n const result = await g.generate(prompt, opts);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n } catch (e) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: String(e) }));\n }\n });\n } else if (req.method === \"GET\" && req.url === \"/info\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(g.getInfo()));\n } else {\n res.writeHead(404);\n res.end(\"Not found\");\n }\n });\n\n server.listen(Number.parseInt(opts.port, 10), () => {\n // Plain text for child process detection\n console.log(`[gerbil] Server started on port ${opts.port}`);\n console.log(chalk.green(` Listening on http://localhost:${opts.port}`));\n console.log(chalk.dim(\" POST /generate - Generate text\"));\n console.log(chalk.dim(\" GET /info - Server info\"));\n });\n }\n });\n\n// ============================================\n// Models command\n// ============================================\n\nprogram\n .command(\"models\")\n .description(\"List available models\")\n .option(\"--search <query>\", \"Search models\")\n .action(async (opts) => {\n console.log(chalk.bold(\"\\n🐹 Available Models:\\n\"));\n\n let models = Object.values(BUILTIN_MODELS);\n\n if (opts.search) {\n const q = opts.search.toLowerCase();\n models = models.filter(\n (m) => m.id.toLowerCase().includes(q) || m.description.toLowerCase().includes(q),\n );\n }\n\n for (const m of models) {\n console.log(` ${chalk.cyan(m.id)}`);\n console.log(` ${chalk.dim(m.description)}`);\n console.log(\n ` ${chalk.dim(`Size: ${m.size} | Context: ${m.contextLength.toLocaleString()}`)}`,\n );\n if (m.supportsThinking) {\n console.log(` ${chalk.magenta(\"✓ Thinking mode\")}`);\n }\n console.log();\n }\n\n console.log(chalk.dim(\" Use any HuggingFace model with: gerbil -m hf:org/model\\n\"));\n });\n\n// ============================================\n// Info command\n// ============================================\n\nprogram\n .command(\"info\")\n .description(\"Show system and model info (use --cli for text output, otherwise opens REPL)\")\n .option(\"-m, --model <id>\", \"Model to load and show info for\", \"qwen3-0.6b\")\n .option(\"--cli\", \"Output text info instead of opening REPL\")\n .option(\"--cpu\", \"Force CPU inference mode\")\n .option(\"--gpu\", \"Force GPU/WebGPU inference mode\")\n .action(async (opts) => {\n // If no --cli flag, open REPL info view\n if (!opts.cli) {\n const forcedDevice = opts.cpu ? \"cpu\" : opts.gpu ? \"webgpu\" : undefined;\n await startRepl({ initialView: \"info\", forcedDevice });\n return;\n }\n\n console.log(chalk.bold(\"\\n🐹 Gerbil v0.1.0\\n\"));\n\n const g = new Gerbil();\n const spinner = ora(`Loading ${chalk.cyan(opts.model)}...`).start();\n\n try {\n await g.loadModel(opts.model, {\n onProgress: (p) => {\n spinner.text = p.progress ? `${p.status} (${p.progress}%)` : p.status;\n },\n });\n spinner.stop();\n\n const info = g.getInfo();\n\n console.log(chalk.yellow(\"LOADED MODEL\"));\n console.log(` Name: ${chalk.white(info.model?.id || opts.model)}`);\n console.log(` Size: ${chalk.white(info.model?.size || \"unknown\")}`);\n console.log(\n ` Context: ${chalk.white((info.model?.contextLength || 0).toLocaleString())} tokens`,\n );\n console.log(\n ` Thinking: ${\n info.model?.supportsThinking ? chalk.green(\"supported\") : chalk.dim(\"no\")\n }`,\n );\n console.log();\n\n console.log(chalk.yellow(\"DEVICE\"));\n console.log(` Platform: ${chalk.white(`${process.platform} ${process.arch}`)}`);\n console.log(` Node: ${chalk.white(process.version)}`);\n console.log(` Backend: ${chalk.white(\"WebGPU/WASM\")}`);\n console.log(` Status: ${chalk.green(\"✓ Ready\")}`);\n console.log();\n\n await g.dispose();\n } catch (e) {\n spinner.fail(\"Error loading model\");\n console.error(chalk.red(String(e)));\n\n // Still show basic info\n console.log(chalk.yellow(\"\\nSYSTEM\"));\n console.log(` Platform: ${chalk.white(`${process.platform} ${process.arch}`)}`);\n console.log(` Node: ${chalk.white(process.version)}`);\n console.log();\n }\n });\n\n// ============================================\n// Cache command\n// ============================================\n\nprogram\n .command(\"cache\")\n .description(\"Show or manage model cache\")\n .option(\"--clean\", \"Remove all cached models\")\n .option(\"--older-than <days>\", \"Remove models older than N days\")\n .action(async (opts) => {\n const fs = await import(\"fs\");\n const path = await import(\"path\");\n const os = await import(\"os\");\n\n // Check transformers.js cache first (where Gerbil actually stores models)\n const nodeModulesCache = path.join(\n process.cwd(),\n \"node_modules\",\n \"@huggingface\",\n \"transformers\",\n \".cache\",\n );\n const cacheDir = fs.existsSync(nodeModulesCache)\n ? nodeModulesCache\n : process.env.HF_HOME ||\n process.env.TRANSFORMERS_CACHE ||\n path.join(os.homedir(), \".cache\", \"huggingface\", \"hub\");\n\n console.log(chalk.bold(\"\\n🐹 Gerbil Cache\\n\"));\n console.log(chalk.yellow(\"LOCATION\"));\n console.log(` ${chalk.white(cacheDir)}\\n`);\n\n try {\n if (!fs.existsSync(cacheDir)) {\n console.log(chalk.dim(\" No cache directory found.\\n\"));\n return;\n }\n\n const entries = fs.readdirSync(cacheDir);\n const models: {\n name: string;\n size: number;\n mtime: Date;\n path: string;\n }[] = [];\n\n // Helper to get folder size\n const getSize = (dir: string): number => {\n let total = 0;\n try {\n const items = fs.readdirSync(dir);\n for (const item of items) {\n const itemPath = path.join(dir, item);\n const itemStat = fs.statSync(itemPath);\n if (itemStat.isDirectory()) {\n total += getSize(itemPath);\n } else {\n total += itemStat.size;\n }\n }\n } catch {}\n return total;\n };\n\n for (const entry of entries) {\n const entryPath = path.join(cacheDir, entry);\n try {\n const entryStat = fs.statSync(entryPath);\n if (!entryStat.isDirectory()) {\n continue;\n }\n\n // Handle HuggingFace hub format (models--org--model)\n if (entry.startsWith(\"models--\")) {\n const modelName = entry.replace(\"models--\", \"\").replace(\"--\", \"/\");\n const size = getSize(entryPath);\n models.push({\n name: modelName,\n size,\n mtime: entryStat.mtime,\n path: entryPath,\n });\n } else {\n // Handle transformers.js format (org/model directories)\n const subEntries = fs.readdirSync(entryPath);\n for (const subEntry of subEntries) {\n const subPath = path.join(entryPath, subEntry);\n try {\n const subStat = fs.statSync(subPath);\n if (subStat.isDirectory()) {\n const modelName = `${entry}/${subEntry}`;\n const size = getSize(subPath);\n if (size > 0) {\n models.push({\n name: modelName,\n size,\n mtime: subStat.mtime,\n path: subPath,\n });\n }\n }\n } catch {}\n }\n }\n } catch {}\n }\n\n if (models.length === 0) {\n console.log(chalk.dim(\" No models cached.\\n\"));\n return;\n }\n\n // Handle clean options\n if (opts.clean || opts.olderThan) {\n const daysThreshold = opts.olderThan ? Number.parseInt(opts.olderThan, 10) : 0;\n const cutoffDate = new Date(Date.now() - daysThreshold * 24 * 60 * 60 * 1000);\n\n let removed = 0;\n let removedSize = 0;\n\n for (const model of models) {\n if (opts.clean || model.mtime < cutoffDate) {\n try {\n fs.rmSync(model.path, { recursive: true, force: true });\n removed++;\n removedSize += model.size;\n console.log(chalk.red(` Removed: ${model.name} (${formatSize(model.size)})`));\n } catch (_e) {\n console.log(chalk.red(` Failed to remove: ${model.name}`));\n }\n }\n }\n\n if (removed > 0) {\n console.log(\n chalk.green(`\\n Cleaned ${removed} model(s), freed ${formatSize(removedSize)}\\n`),\n );\n } else {\n console.log(chalk.dim(\"\\n No models to clean.\\n\"));\n }\n return;\n }\n\n // Display cache contents\n console.log(chalk.yellow(\"CACHED MODELS\"));\n let totalSize = 0;\n\n for (const model of models.sort((a, b) => b.mtime.getTime() - a.mtime.getTime())) {\n const timeAgo = formatTimeAgo(model.mtime);\n const sizeStr = formatSize(model.size).padStart(8);\n console.log(\n ` ${chalk.white(model.name.padEnd(40))} ${chalk.dim(sizeStr)} ${chalk.dim(timeAgo)}`,\n );\n totalSize += model.size;\n }\n\n console.log(chalk.dim(` ${\"─\".repeat(60)}`));\n console.log(\n ` ${chalk.white(\"Total:\".padEnd(40))} ${chalk.white(formatSize(totalSize).padStart(8))}`,\n );\n console.log();\n } catch (e) {\n console.error(chalk.red(` Error reading cache: ${e}`));\n }\n });\n\n// Import shared utilities from repl/utils\nimport { formatBytes, formatTimeAgo } from \"./repl/utils.js\";\n\n// Alias for CLI usage\nconst formatSize = formatBytes;\n\n// ============================================\n// Bench command\n// ============================================\n\nprogram\n .command(\"bench\")\n .description(\"Benchmark model performance\")\n .option(\"-m, --model <id>\", \"Model to benchmark\", \"qwen3-0.6b\")\n .option(\"-n, --runs <n>\", \"Number of runs\", \"3\")\n .action(async (opts) => {\n const g = new Gerbil();\n const spinner = ora(`Loading ${chalk.cyan(opts.model)}...`).start();\n\n try {\n await g.loadModel(opts.model, {\n onProgress: (p) => {\n spinner.text = p.progress ? `${p.status} (${p.progress}%)` : p.status;\n },\n });\n spinner.succeed(\"Model loaded\");\n\n console.log(chalk.bold(`\\nBenchmarking ${chalk.cyan(opts.model)}...\\n`));\n\n const runs = Number.parseInt(opts.runs, 10);\n const results: {\n tokPerSec: number;\n firstToken: number;\n tokens: number;\n }[] = [];\n const prompts = [\n \"Write a haiku about programming.\",\n \"Explain recursion briefly.\",\n \"List 3 benefits of TypeScript.\",\n ];\n\n for (let i = 0; i < runs; i++) {\n const prompt = prompts[i % prompts.length];\n const runSpinner = ora(`Run ${i + 1}/${runs}...`).start();\n\n const startTime = Date.now();\n let firstTokenTime = 0;\n let tokenCount = 0;\n\n for await (const _chunk of g.stream(prompt, { maxTokens: 100 })) {\n if (tokenCount === 0) {\n firstTokenTime = Date.now() - startTime;\n }\n tokenCount++;\n }\n\n const totalTime = Date.now() - startTime;\n const tokPerSec = Math.round((tokenCount / totalTime) * 1000);\n\n results.push({\n tokPerSec,\n firstToken: firstTokenTime,\n tokens: tokenCount,\n });\n runSpinner.succeed(\n `Run ${i + 1}: ${chalk.cyan(tokPerSec)} tok/s, ${chalk.yellow(\n `${firstTokenTime}ms`,\n )} first token`,\n );\n }\n\n // Calculate averages\n const avgTokPerSec = Math.round(\n results.reduce((a, r) => a + r.tokPerSec, 0) / results.length,\n );\n const avgFirstToken = Math.round(\n results.reduce((a, r) => a + r.firstToken, 0) / results.length,\n );\n\n console.log(chalk.bold(`\\n${chalk.green(\"RESULTS\")}`));\n console.log(` Avg tokens/sec: ${chalk.cyan(avgTokPerSec)}`);\n console.log(` Avg first token: ${chalk.yellow(`${avgFirstToken}ms`)}`);\n console.log();\n\n await g.dispose();\n } catch (e) {\n spinner.fail(\"Error\");\n console.error(chalk.red(String(e)));\n process.exit(1);\n }\n });\n\n// ============================================\n// Update command\n// ============================================\n\nprogram\n .command(\"update\")\n .description(\"Update Gerbil to the latest version\")\n .action(async () => {\n const { checkForUpdate, installUpdate, CURRENT_VERSION } = await import(\n \"./repl/auto-update.js\"\n );\n\n const spinner = ora(\"Checking for updates...\").start();\n\n try {\n const check = await checkForUpdate();\n\n if (!check.updateAvailable) {\n spinner.succeed(chalk.green(`Already on latest version (v${CURRENT_VERSION})`));\n return;\n }\n\n spinner.info(chalk.cyan(`Update available: v${CURRENT_VERSION} → v${check.latestVersion}`));\n\n const updateSpinner = ora(`Installing v${check.latestVersion}...`).start();\n const result = await installUpdate();\n\n if (result.success) {\n updateSpinner.succeed(\n chalk.green(`✅ Updated to v${result.version || check.latestVersion}`),\n );\n console.log(\n chalk.dim(\"\\n Restart your terminal or run 'gerbil' to use the new version.\\n\"),\n );\n } else {\n updateSpinner.fail(chalk.red(\"Update failed\"));\n console.error(chalk.red(` ${result.error}`));\n process.exit(1);\n }\n } catch (e) {\n spinner.fail(\"Update check failed\");\n console.error(chalk.red(` ${e}`));\n process.exit(1);\n }\n });\n\n// ============================================\n// Parse and run\n// ============================================\n\n// Check for updates after command completes (non-blocking)\nconst originalParse = program.parse.bind(program);\nprogram.parse = (...args) => {\n const result = originalParse(...args);\n\n // Check for updates in background (don't block)\n checkForUpdateCLI().catch(() => {\n // Silent fail\n });\n\n return result;\n};\n\nasync function checkForUpdateCLI() {\n const { checkForUpdate, CURRENT_VERSION } = await import(\"./repl/auto-update.js\");\n const check = await checkForUpdate();\n\n if (check.updateAvailable) {\n console.log(chalk.cyan(`\\n💡 Update available: v${CURRENT_VERSION} → v${check.latestVersion}`));\n console.log(chalk.dim(` Run '${chalk.white(\"gerbil update\")}' to install\\n`));\n }\n}\n\nprogram.parse();\n"],"mappings":"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"}
|