agent-termo 1.0.3 → 1.0.4

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/dist/cli.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/cli.ts", "../src/llm/client.ts", "../src/llm/models.ts", "../src/llm/tools.ts", "../src/tools/index.ts", "../src/utils/config.ts", "../src/diff/index.ts", "../src/memory/index.ts", "../src/agents/index.ts", "../src/ui/index.ts", "../src/ui/screen.ts", "../src/main.ts"],
4
- "sourcesContent": ["#!/usr/bin/env node\r\n// =============================================================================\r\n// CLI Entry Point \u2014 Agent-Termo\r\n// =============================================================================\r\n\r\nimport { Command } from 'commander';\r\nimport { runRepl } from './main.js';\r\nimport { saveNimApiKey } from './utils/config.js';\r\n\r\nconst program = new Command();\r\n\r\nasync function promptForApiKey(): Promise<string> {\r\n const input = process.stdin;\r\n const output = process.stdout;\r\n\r\n if (!input.isTTY || typeof input.setRawMode !== 'function') {\r\n throw new Error(\r\n 'NVIDIA NIM API key is missing. Run Agent-Termo in an interactive terminal or set NIM_API_KEY before starting.',\r\n );\r\n }\r\n\r\n console.log('An NVIDIA NIM API key is required to start Agent-Termo.');\r\n console.log('Get your key at https://build.nvidia.com/');\r\n output.write('Enter your API key (input hidden): ');\r\n\r\n return new Promise((resolve, reject) => {\r\n let apiKey = '';\r\n let previousWasCarriageReturn = false;\r\n\r\n const restoreTerminal = () => {\r\n input.off('data', onData);\r\n input.setRawMode(false);\r\n input.pause();\r\n output.write('\\n');\r\n };\r\n\r\n const onData = (data: Buffer) => {\r\n for (const char of data.toString('utf-8')) {\r\n if (char === '\\n' && previousWasCarriageReturn) {\r\n previousWasCarriageReturn = false;\r\n continue;\r\n }\r\n previousWasCarriageReturn = char === '\\r';\r\n\r\n if (char === '\\u0003' || char === '\\u0004') {\r\n restoreTerminal();\r\n reject(new Error('API key setup cancelled.'));\r\n return;\r\n }\r\n\r\n if (char === '\\r' || char === '\\n') {\r\n if (!apiKey.trim()) {\r\n output.write('\\nAn API key is required. Enter your API key: ');\r\n continue;\r\n }\r\n\r\n restoreTerminal();\r\n resolve(apiKey.trim());\r\n return;\r\n }\r\n\r\n if (char === '\\u007f' || char === '\\b') {\r\n apiKey = apiKey.slice(0, -1);\r\n } else if (char >= ' ') {\r\n apiKey += char;\r\n }\r\n }\r\n };\r\n\r\n input.setRawMode(true);\r\n input.resume();\r\n input.on('data', onData);\r\n });\r\n}\r\n\r\nasync function startAgent(\r\n project: string,\r\n options: { apiKey?: string; model?: string; debug?: boolean },\r\n): Promise<void> {\r\n // Apply CLI overrides to env before main initializes.\r\n if (options.apiKey) process.env.NIM_API_KEY = options.apiKey;\r\n if (options.model) process.env.NIM_MODEL = options.model;\r\n if (options.debug) process.env.LOG_LEVEL = 'debug';\r\n\r\n if (!process.env.NIM_API_KEY?.trim()) {\r\n const apiKey = await promptForApiKey();\r\n saveNimApiKey(apiKey);\r\n process.env.NIM_API_KEY = apiKey;\r\n console.log('API key saved. Agent-Termo will remember it for future sessions.');\r\n }\r\n\r\n console.log(`Starting Agent-Termo in: ${project}`);\r\n await runRepl(project);\r\n}\r\n\r\nprogram\r\n .name('agent-termo')\r\n .description('Terminal AI coding agent with Nvidia NIM APIs')\r\n .version('1.0.2')\r\n .argument('[project]', 'Project directory to operate in', process.cwd())\r\n .option('-k, --api-key <key>', 'Nvidia NIM API key')\r\n .option('-m, --model <model>', 'Model name to use')\r\n .option('--debug', 'Enable debug logging')\r\n .action(async (project: string, options: { apiKey?: string; model?: string; debug?: boolean }) => {\r\n await startAgent(project, options);\r\n });\r\n\r\nprogram\r\n .command('init')\r\n .description('Initialize Agent-Termo in a project directory')\r\n .argument('[dir]', 'Directory to initialize', '.')\r\n .action(async (dir: string) => {\r\n const { mkdirSync, writeFileSync, existsSync } = await import('node:fs');\r\n const { resolve } = await import('node:path');\r\n\r\n const dirsToCreate = [resolve(dir, 'docs'), resolve(dir, '.claude', 'agents'), resolve(dir, 'src')];\r\n for (const d of dirsToCreate) {\r\n mkdirSync(d, { recursive: true });\r\n }\r\n\r\n // Create stub docs\r\n const memoryPath = resolve(dir, 'docs', 'MEMORY.md');\r\n if (!existsSync(memoryPath)) {\r\n writeFileSync(memoryPath, '# Project Memory\\n\\n## Project Context\\n(Add project context here)\\n', 'utf-8');\r\n }\r\n\r\n const timelinePath = resolve(dir, 'docs', 'TIMELINE.md');\r\n if (!existsSync(timelinePath)) {\r\n writeFileSync(\r\n timelinePath,\r\n '# Project Timeline\\n\\n## Initialization\\n- [date] Agent-Termo initialized\\n',\r\n 'utf-8',\r\n );\r\n }\r\n\r\n console.log(`\\n\u2713 Initialized Agent-Termo in ${resolve(dir)}`);\r\n console.log(' Created: docs/MEMORY.md, docs/TIMELINE.md');\r\n console.log(' Agent-Termo will ask for your NVIDIA NIM API key the first time you launch it.');\r\n });\r\n\r\nasync function main() {\r\n // Run REPL mode directly when no command or options are supplied.\r\n const args = process.argv.slice(2);\r\n if (args.length === 0) {\r\n await startAgent(process.cwd(), {});\r\n return;\r\n }\r\n\r\n await program.parseAsync(process.argv);\r\n}\r\n\r\nmain().catch((err) => {\r\n console.error(`\\nFatal error: ${err instanceof Error ? err.message : err}`);\r\n process.exit(1);\r\n});\r\n", "// =============================================================================\r\n// Nvidia NIM LLM Client \u2014 Stepfun + OpenAI-compatible models\r\n// =============================================================================\r\n\r\nimport OpenAI from 'openai';\r\nimport type { ToolCall, ConversationMessage, ToolDef } from '../types/index.js';\r\nimport { mergeModels, type ModelInfo } from './models.js';\r\n\r\ntype NIMTool = OpenAI.Chat.ChatCompletionTool;\r\n\r\nexport class NimClient {\r\n private client: OpenAI;\r\n private model: string;\r\n\r\n constructor(_projectRoot?: string) {\r\n const apiKey = process.env.NIM_API_KEY ?? '';\r\n const baseUrl = process.env.NIM_BASE_URL ?? 'https://integrate.api.nvidia.com/v1';\r\n this.model = process.env.NIM_MODEL ?? 'stepfun-ai/step-3.7-flash';\r\n const timeout = parseInt(process.env.LLM_TIMEOUT ?? '120000', 10);\r\n\r\n this.client = new OpenAI({\r\n apiKey,\r\n baseURL: baseUrl,\r\n timeout,\r\n defaultHeaders: { 'User-Agent': 'agent-termo/1.0' },\r\n });\r\n }\r\n\r\n buildToolDefs(toolSchemas: ToolDef[]): NIMTool[] {\r\n return toolSchemas.map((t) => ({\r\n type: 'function' as const,\r\n function: {\r\n name: t.name,\r\n description: t.description,\r\n parameters: t.parameters as unknown as NIMTool['function']['parameters'],\r\n },\r\n })) as NIMTool[];\r\n }\r\n\r\n getModel(): string {\r\n return this.model;\r\n }\r\n\r\n setModel(model: string): void {\r\n this.model = model;\r\n }\r\n\r\n /**\r\n * Fetch the models this API key can use. Never throws: on failure the curated\r\n * list is returned with `live: false` and the reason in `error`.\r\n */\r\n async listModels(): Promise<{ models: ModelInfo[]; live: boolean; error?: string }> {\r\n try {\r\n const page = await this.client.models.list({ timeout: 10_000 });\r\n const ids = page.data.map((m) => m.id);\r\n if (ids.length === 0) throw new Error('empty model list');\r\n return { models: mergeModels(ids), live: true };\r\n } catch (err) {\r\n return {\r\n models: mergeModels(null),\r\n live: false,\r\n error: err instanceof Error ? err.message : String(err),\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Streaming chat completion.\r\n * Handles Stepfun's quirks: filters \"null\" reasoning chunks, strips reasoning field.\r\n * Yields { content, toolCalls } at the end with clean text.\r\n */\r\n async *streamComplete(\r\n messages: ConversationMessage[],\r\n tools?: NIMTool[],\r\n onChunk?: (text: string) => void,\r\n ): AsyncGenerator<{ content: string; toolCalls: ToolCall[] }, void, unknown> {\r\n const rawChunks: string[] = [];\r\n const toolCallMap: Map<number, { id: string; name: string; arguments: string }> = new Map();\r\n\r\n const stream = await this.client.chat.completions.create({\r\n model: this.model,\r\n messages: messages.map((m) => {\r\n if (m.role === 'tool') {\r\n return {\r\n role: 'tool' as const,\r\n content: m.content,\r\n tool_call_id: m.id,\r\n };\r\n }\r\n return {\r\n role: m.role as 'system' | 'user' | 'assistant',\r\n content: m.content,\r\n };\r\n }),\r\n tools: tools,\r\n temperature: 0.3,\r\n max_tokens: 8192,\r\n stream: true,\r\n });\r\n\r\n for await (const chunk of stream) {\r\n const delta = chunk.choices[0]?.delta;\r\n\r\n if (!delta) continue;\r\n\r\n // Text delta \u2014 filter out \"null\" chunks (Stepfun's reasoning output)\r\n const rawContent = delta.content ?? '';\r\n // Check: if it's the literal string \"null\", it's reasoning noise \u2014 skip it\r\n const isNoise = rawContent === 'null' || rawContent === 'undefined';\r\n if (!isNoise && rawContent) {\r\n rawChunks.push(rawContent);\r\n onChunk?.(rawContent);\r\n }\r\n\r\n // Tool call deltas (accumulate across chunks via index)\r\n if (delta.tool_calls) {\r\n for (const tc of delta.tool_calls) {\r\n const idx = tc.index ?? 0;\r\n const prev = toolCallMap.get(idx);\r\n if (!prev) {\r\n toolCallMap.set(idx, {\r\n id: tc.id ?? crypto.randomUUID(),\r\n name: tc.function?.name ?? '',\r\n arguments: tc.function?.arguments ?? '',\r\n });\r\n } else {\r\n prev.arguments += tc.function?.arguments ?? '';\r\n if (tc.id && !prev.id) prev.id = tc.id;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // For streaming: content is accumulated in rawChunks (null chunks already filtered)\r\n // For non-streaming (complete() method): reasoning stripping happens in that method\r\n const finalContent = rawChunks.join('');\r\n\r\n // Extract tool calls\r\n const toolCalls: ToolCall[] = Array.from(toolCallMap.values()).map((tc) => {\r\n let args: Record<string, unknown> = {};\r\n try {\r\n args = JSON.parse(tc.arguments);\r\n } catch {\r\n args = { _raw: tc.arguments };\r\n }\r\n return { id: tc.id, name: tc.name, arguments: args };\r\n });\r\n\r\n yield { content: finalContent, toolCalls };\r\n }\r\n\r\n /**\r\n * Non-streaming completion \u2014 for when streaming fails or for retries.\r\n */\r\n async complete(\r\n messages: ConversationMessage[],\r\n tools?: NIMTool[],\r\n ): Promise<{ content: string; toolCalls: ToolCall[] }> {\r\n const response = await this.client.chat.completions.create({\r\n model: this.model,\r\n messages: messages.map((m) => {\r\n if (m.role === 'tool') {\r\n return { role: 'tool' as const, content: m.content, tool_call_id: m.id };\r\n }\r\n return { role: m.role as 'system' | 'user' | 'assistant', content: m.content };\r\n }),\r\n tools: tools,\r\n temperature: 0.3,\r\n max_tokens: 8192,\r\n stream: false,\r\n });\r\n\r\n const msg = response.choices[0]?.message;\r\n // Strip reasoning noise\r\n let content =\r\n msg?.content?.replace(\r\n /\\[ Reasoning[^\\]]*\\][^\\[]*\\[\\/ Reasoning\\][^\\n]*/gi,\r\n '',\r\n ).trim() ?? '';\r\n\r\n const toolCalls: ToolCall[] = (msg?.tool_calls ?? []).map((tc) => {\r\n let args: Record<string, unknown> = {};\r\n try {\r\n args = JSON.parse(tc.function.arguments ?? '{}');\r\n } catch {\r\n args = { _raw: tc.function.arguments };\r\n }\r\n return { id: tc.id, name: tc.function.name, arguments: args };\r\n });\r\n\r\n // If no tool calls but content looks like a tool call request, parse it\r\n if (toolCalls.length === 0 && content.includes('\"tool_calls\"')) {\r\n try {\r\n const parsed = JSON.parse(content);\r\n if (parsed.tool_calls?.length) {\r\n toolCalls.push(...parsed.tool_calls.map((tc: { id?: string; name?: string; function?: { name?: string; arguments?: unknown } }) => ({\r\n id: tc.id ?? crypto.randomUUID(),\r\n name: tc.function?.name ?? tc.name ?? '',\r\n arguments: typeof tc.function?.arguments === 'string'\r\n ? JSON.parse(tc.function.arguments)\r\n : tc.function?.arguments ?? {},\r\n })));\r\n // Remove JSON from content\r\n const jsonStart = content.indexOf('{\"tool_calls\"');\r\n if (jsonStart !== -1) content = content.slice(0, jsonStart).trim();\r\n }\r\n } catch {\r\n // Not valid JSON \u2014 leave as-is\r\n }\r\n }\r\n\r\n return { content, toolCalls };\r\n }\r\n}\r\n\r\nexport { type ToolDef } from '../types/index.js';", "// =============================================================================\r\n// NVIDIA NIM model catalogue \u2014 curated suggestions + live /v1/models merge\r\n// =============================================================================\r\n\r\nexport interface ModelInfo {\r\n id: string;\r\n note?: string;\r\n}\r\n\r\n/**\r\n * Hand-picked chat/coding models worth surfacing first. This list is only a\r\n * starting point: when the live catalogue is reachable, entries NIM no longer\r\n * serves are dropped, and everything else NIM returns is still selectable.\r\n */\r\nexport const CURATED_MODELS: ModelInfo[] = [\r\n { id: 'stepfun-ai/step-3.7-flash', note: 'default' },\r\n { id: 'meta/llama-3.1-8b-instruct', note: 'fast, low cost' },\r\n { id: 'meta/llama-3.1-70b-instruct', note: 'balanced' },\r\n { id: 'meta/llama-3.3-70b-instruct', note: 'balanced' },\r\n { id: 'meta/llama-3.1-405b-instruct', note: 'highest quality Llama' },\r\n { id: 'nvidia/llama-3.1-nemotron-70b-instruct', note: 'NVIDIA tuned' },\r\n { id: 'qwen/qwen2.5-coder-32b-instruct', note: 'coding' },\r\n { id: 'deepseek-ai/deepseek-r1', note: 'reasoning' },\r\n { id: 'moonshotai/kimi-k2-instruct', note: 'agentic / tool use' },\r\n { id: 'openai/gpt-oss-120b', note: 'open-weight GPT' },\r\n];\r\n\r\n// NIM serves embedding, vision, speech and other non-chat models from the same\r\n// endpoint. Hide the obvious ones so the picker stays about chat models.\r\nconst NON_CHAT =\r\n /embed|rerank|retriev|reward|guard|safety|parse|clip|vila|neva|fuyu|kosmos|paligemma|deplot|riva|asr|tts|whisper|diffusion|sdxl|flux|cosmos|segment|bge-|e5-|gliner|pii|streampetr|ocdrnet|bevformer/i;\r\n\r\nexport function isChatModel(id: string): boolean {\r\n return !NON_CHAT.test(id);\r\n}\r\n\r\n/**\r\n * Build the picker list.\r\n * - live === null: the catalogue could not be fetched, so offer the curated list.\r\n * - otherwise: curated entries that NIM serves first, then the rest of the live\r\n * chat models alphabetically.\r\n */\r\nexport function mergeModels(live: string[] | null): ModelInfo[] {\r\n if (!live) return [...CURATED_MODELS];\r\n\r\n const liveSet = new Set(live);\r\n const curated = CURATED_MODELS.filter((m) => liveSet.has(m.id));\r\n const curatedIds = new Set(curated.map((m) => m.id));\r\n const rest = live\r\n .filter((id) => !curatedIds.has(id) && isChatModel(id))\r\n .sort((a, b) => a.localeCompare(b))\r\n .map((id): ModelInfo => ({ id }));\r\n\r\n return [...curated, ...rest];\r\n}\r\n", "// =============================================================================\r\n// Tool Definitions (OpenAI function calling schema)\r\n// These are matched to the actual tools implemented in src/tools/\r\n// =============================================================================\r\n\r\nimport type { ToolDef } from '../types/index.js';\r\n\r\nexport const TOOL_DEFINITIONS: ToolDef[] = [\r\n // \u2500\u2500 File Operations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n {\r\n name: 'file:read',\r\n description: 'Read the complete contents of a file. Use for examining existing code, config, or documentation.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n path: {\r\n type: 'string',\r\n description: 'File path (absolute or relative to project root)',\r\n },\r\n limit: {\r\n type: 'number',\r\n description: 'Maximum number of lines to read (0 = all)',\r\n default: 0,\r\n },\r\n offset: {\r\n type: 'number',\r\n description: 'Line offset to start reading from (0 = start)',\r\n default: 0,\r\n },\r\n },\r\n required: ['path'],\r\n },\r\n },\r\n {\r\n name: 'file:write',\r\n description: 'Write or overwrite a complete file. Use this to create new files or replace existing ones entirely.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n path: {\r\n type: 'string',\r\n description: 'File path to write (relative to project root)',\r\n },\r\n content: {\r\n type: 'string',\r\n description: 'Complete file content to write',\r\n },\r\n },\r\n required: ['path', 'content'],\r\n },\r\n },\r\n {\r\n name: 'file:edit',\r\n description: 'Edit an existing file by replacing an exact section. The old_string must appear verbatim in the file.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n path: {\r\n type: 'string',\r\n description: 'File to edit',\r\n },\r\n old_string: {\r\n type: 'string',\r\n description: 'Exact text to find and replace (must be unique in file)',\r\n },\r\n new_string: {\r\n type: 'string',\r\n description: 'Replacement text',\r\n },\r\n },\r\n required: ['path', 'old_string', 'new_string'],\r\n },\r\n },\r\n {\r\n name: 'file:glob',\r\n description: 'Find all files matching a glob pattern. Use to discover project structure.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n pattern: {\r\n type: 'string',\r\n description: 'Glob pattern (e.g. \"src/**/*.ts\", \"**/*.json\")',\r\n },\r\n cwd: {\r\n type: 'string',\r\n description: 'Root directory to search in (defaults to project root)',\r\n },\r\n },\r\n required: ['pattern'],\r\n },\r\n },\r\n {\r\n name: 'grep',\r\n description: 'Search for text or regex patterns inside files. Use to find function definitions, imports, etc.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n pattern: {\r\n type: 'string',\r\n description: 'Text or regex pattern to search for',\r\n },\r\n path: {\r\n type: 'string',\r\n description: 'File or directory to search in',\r\n },\r\n glob: {\r\n type: 'string',\r\n description: 'Only search files matching this glob pattern',\r\n },\r\n case_sensitive: {\r\n type: 'boolean',\r\n description: 'Case sensitive search (default true)',\r\n default: true,\r\n },\r\n },\r\n required: ['pattern', 'path'],\r\n },\r\n },\r\n // \u2500\u2500 Bash \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n {\r\n name: 'bash:execute',\r\n description: 'Execute a shell command and return its stdout/stderr output. Destructive commands (rm, dd) require user confirmation.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n command: {\r\n type: 'string',\r\n description: 'Shell command to execute',\r\n },\r\n cwd: {\r\n type: 'string',\r\n description: 'Working directory (defaults to project root)',\r\n },\r\n timeout: {\r\n type: 'number',\r\n description: 'Timeout in milliseconds (default 300000)',\r\n default: 300000,\r\n },\r\n },\r\n required: ['command'],\r\n },\r\n },\r\n // \u2500\u2500 Git \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n {\r\n name: 'git:status',\r\n description: 'Show the git working tree status (modified, staged, untracked files).',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n cwd: {\r\n type: 'string',\r\n description: 'Repository root (default: project root)',\r\n },\r\n },\r\n },\r\n },\r\n {\r\n name: 'git:commit',\r\n description: 'Stage and commit all changes with a conventional commit message.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n message: {\r\n type: 'string',\r\n description: 'Conventional commit message (e.g. \"feat: add login page\")',\r\n },\r\n cwd: {\r\n type: 'string',\r\n description: 'Repository root (default: project root)',\r\n },\r\n },\r\n required: ['message'],\r\n },\r\n },\r\n {\r\n name: 'git:push',\r\n description: 'Push the current branch to the remote repository.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n cwd: {\r\n type: 'string',\r\n description: 'Repository root (default: project root)',\r\n },\r\n },\r\n },\r\n },\r\n {\r\n name: 'git:log',\r\n description: 'Show recent git commit history.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n cwd: {\r\n type: 'string',\r\n description: 'Repository root (default: project root)',\r\n },\r\n limit: {\r\n type: 'number',\r\n description: 'Number of commits to show (default: 20)',\r\n default: 20,\r\n },\r\n },\r\n },\r\n },\r\n];", "// =============================================================================\r\n// Agent-Termo Tool Executor \u2014 routes tool calls to implementations\r\n// =============================================================================\r\n\r\nimport { readFile as readFileAsync, writeFile as writeFileAsync } from 'node:fs/promises';\r\nimport { resolve, isAbsolute, relative } from 'node:path';\r\nimport { exec as execAsync } from 'node:child_process';\r\nimport { promisify } from 'node:util';\r\nimport { default as globAsync } from 'glob';\r\nimport { simpleGit } from 'simple-git';\r\nimport { statSync, existsSync, mkdirSync } from 'node:fs';\r\nimport { getConfig } from '../utils/config.js';\r\nimport { computeDiff } from '../diff/index.js';\r\nimport type { ToolResult, ProposedFileChange } from '../types/index.js';\r\n\r\nconst exec = promisify(execAsync);\r\nconst globPromise = promisify(globAsync);\r\n\r\n// \u2500\u2500 Tool map \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst TOOL_MAP: Record<string, (...args: any[]) => Promise<ToolResult>> = {\r\n\t'file:read': toolFileRead,\r\n\t'file:write': toolFileWrite,\r\n\t'file:edit': toolFileEdit,\r\n\t'file:glob': toolFileGlob,\r\n\t'grep': toolGrep,\r\n\t'bash:execute': toolBash,\r\n\t'git:status': toolGitStatus,\r\n\t'git:commit': toolGitCommit,\r\n\t'git:push': toolGitPush,\r\n\t'git:log': toolGitLog,\r\n};\r\n\r\n// \u2500\u2500 Re-exported tool definitions for OpenAI schema \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\nexport const TOOL_DEFS = TOOL_MAP;\r\n\r\n// \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nexport async function executeTool(\r\n\tname: string,\r\n\targs: Record<string, unknown>,\r\n\tprojectRoot: string,\r\n): Promise<ToolResult> {\r\n\tconst start = Date.now();\r\n\tconst id = crypto.randomUUID();\r\n\r\n\ttry {\r\n\t\tconst fn = TOOL_MAP[name];\r\n\t\tif (!fn) {\r\n\t\t\treturn { id, name, success: false, error: 'Unknown tool: ' + name, durationMs: Date.now() - start };\r\n\t\t}\r\n\t\treturn await fn(args, projectRoot);\r\n\t} catch (err) {\r\n\t\treturn {\r\n\t\t\tid,\r\n\t\t\tname,\r\n\t\t\tsuccess: false,\r\n\t\t\terror: String(err instanceof Error ? err.message : err),\r\n\t\t\tdurationMs: Date.now() - start,\r\n\t\t};\r\n\t}\r\n}\r\n\r\n// \u2500\u2500 Path helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nfunction toProjectPath(path: string, projectRoot: string): string {\r\n\tif (isAbsolute(path)) return path;\r\n\treturn resolve(projectRoot, path);\r\n}\r\n\r\nfunction withinProject(path: string, projectRoot: string): boolean {\r\n\ttry {\r\n\t\tconst resolved = toProjectPath(path, projectRoot);\r\n\t\tconst rel = relative(projectRoot, resolved);\r\n\t\treturn !rel.startsWith('..') && !isAbsolute(rel);\r\n\t} catch {\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\n// \u2500\u2500 Propose a file change (returns ProposedFileChange without writing) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nfunction proposeFileChange(\r\n\tpath: string,\r\n\tproposedContent: string,\r\n\tprojectRoot: string,\r\n\tchangeType: 'write' | 'edit',\r\n\toldContent?: string,\r\n): { change: ProposedFileChange; result: ToolResult } {\r\n\tconst fullPath = toProjectPath(path, projectRoot);\r\n\tconst originalContent = oldContent ?? '';\r\n\tconst isNewFile = !existsSync(fullPath);\r\n\tconst isDeletion = proposedContent === '' && changeType === 'write';\r\n\r\n\tconst baseContent = isNewFile ? '' : originalContent;\r\n\tconst diff = computeDiff(baseContent, proposedContent);\r\n\r\n\tconst change: ProposedFileChange = {\r\n\t\tpath,\r\n\t\toriginalContent,\r\n\t\tproposedContent,\r\n\t\tdiff: { ...diff, file: path },\r\n\t\tisNewFile,\r\n\t\tisDeletion,\r\n\t};\r\n\r\n\tconst lineCount = proposedContent.split('\\n').length;\r\n\tconst summary = isDeletion\r\n\t\t? `Delete ${path} (${lineCount} lines removed)`\r\n\t\t: isNewFile\r\n\t\t\t? `Create ${path} (${lineCount} lines)`\r\n\t\t\t: `${changeType === 'edit' ? 'Edit' : 'Overwrite'} ${path} (${lineCount} lines, +${diff.additions}/-${diff.deletions})`;\r\n\r\n\tconst result: ToolResult = {\r\n\t\tid: '',\r\n\t\tname: `${changeType}:${path}`,\r\n\t\tsuccess: true,\r\n\t\toutput: JSON.stringify({\r\n\t\t\tmessage: summary,\r\n\t\t\tneedsApproval: true,\r\n\t\t\tproposedChange: change,\r\n\t\t}),\r\n\t\tdurationMs: 0,\r\n\t};\r\n\r\n\treturn { change, result };\r\n}\r\n\r\n// \u2500\u2500 Apply an approved change to disk \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nexport async function applyFileChange(change: ProposedFileChange, projectRoot: string): Promise<ToolResult> {\r\n\tconst start = Date.now();\r\n\tconst fullPath = toProjectPath(change.path, projectRoot);\r\n\r\n\ttry {\r\n\t\tif (change.isDeletion) {\r\n\t\t\tif (existsSync(fullPath)) {\r\n\t\t\t\tawait writeFileAsync(fullPath, '');\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst dir = resolve(fullPath, '..');\r\n\t\t\tif (!existsSync(dir)) {\r\n\t\t\t\tmkdirSync(dir, { recursive: true });\r\n\t\t\t}\r\n\t\t\tawait writeFileAsync(fullPath, change.proposedContent, 'utf-8');\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tid: '',\r\n\t\t\tname: 'file:write',\r\n\t\t\tsuccess: true,\r\n\t\t\toutput: `Applied: ${change.path}`,\r\n\t\t\tdurationMs: Date.now() - start,\r\n\t\t};\r\n\t} catch (err) {\r\n\t\treturn {\r\n\t\t\tid: '',\r\n\t\t\tname: 'file:write',\r\n\t\t\tsuccess: false,\r\n\t\t\terror: 'Cannot apply ' + change.path + ': ' + (err instanceof Error ? err.message : String(err)),\r\n\t\t\tdurationMs: Date.now() - start,\r\n\t\t};\r\n\t}\r\n}\r\n\r\n// \u2500\u2500 File Tools \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nasync function toolFileRead(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst path = String(args.path ?? '');\r\n\tif (!path) return { id: '', name: 'file:read', success: false, error: 'path is required', durationMs: 0 };\r\n\tif (!withinProject(path, projectRoot)) {\r\n\t\treturn { id: '', name: 'file:read', success: false, error: 'Access denied: ' + path, durationMs: 0 };\r\n\t}\r\n\r\n\tconst fullPath = toProjectPath(path, projectRoot);\r\n\tconst limit = Number(args.limit ?? 0);\r\n\tconst offset = Number(args.offset ?? 0);\r\n\r\n\ttry {\r\n\t\tconst statResult = statSync(fullPath);\r\n\t\tif (statResult.isDirectory()) {\r\n\t\t\treturn { id: '', name: 'file:read', success: false, error: 'Path \"' + path + '\" is a directory', durationMs: 0 };\r\n\t\t}\r\n\r\n\t\tconst content = await readFileAsync(fullPath, 'utf-8');\r\n\t\tconst lines = content.split('\\n');\r\n\t\tconst sliced = lines.slice(offset, limit > 0 ? offset + limit : undefined);\r\n\t\tconst summary = limit > 0 ? '[Showing lines ' + (offset + 1) + '-' + (offset + sliced.length) + ' of ' + lines.length + ']' : '';\r\n\t\treturn { id: '', name: 'file:read', success: true, output: (summary ? summary + '\\n' : '') + sliced.join('\\n'), durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'file:read', success: false, error: 'Cannot read ' + path + ': ' + (err instanceof Error ? err.message : String(err)), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolFileWrite(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst path = String(args.path ?? '');\r\n\tconst content = String(args.content ?? '');\r\n\tif (!path) return { id: '', name: 'file:write', success: false, error: 'path is required', durationMs: 0 };\r\n\tif (!withinProject(path, projectRoot)) {\r\n\t\treturn { id: '', name: 'file:write', success: false, error: 'Access denied: ' + path, durationMs: 0 };\r\n\t}\r\n\r\n\tconst { result } = proposeFileChange(path, content, projectRoot, 'write');\r\n\treturn result;\r\n}\r\n\r\nasync function toolFileEdit(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst path = String(args.path ?? '');\r\n\tconst oldString = String(args.old_string ?? '');\r\n\tconst newString = String(args.new_string ?? '');\r\n\tif (!path || !oldString) return { id: '', name: 'file:edit', success: false, error: 'path and old_string are required', durationMs: 0 };\r\n\tif (!withinProject(path, projectRoot)) {\r\n\t\treturn { id: '', name: 'file:edit', success: false, error: 'Access denied: ' + path, durationMs: 0 };\r\n\t}\r\n\r\n\tconst fullPath = toProjectPath(path, projectRoot);\r\n\r\n\ttry {\r\n\t\tconst existingContent = existsSync(fullPath) ? await readFileAsync(fullPath, 'utf-8') : '';\r\n\t\tif (!existingContent.includes(oldString)) {\r\n\t\t\treturn { id: '', name: 'file:edit', success: false, error: 'old_string not found in ' + path + '. Check whitespace.', durationMs: 0 };\r\n\t\t}\r\n\t\tconst newContent = existingContent.replace(oldString, newString);\r\n\t\tconst { result } = proposeFileChange(path, newContent, projectRoot, 'edit', existingContent);\r\n\t\treturn result;\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'file:edit', success: false, error: 'Cannot edit ' + path + ': ' + (err instanceof Error ? err.message : String(err)), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolFileGlob(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst globPattern = String(args.pattern ?? '');\r\n\tif (!globPattern) return { id: '', name: 'file:glob', success: false, error: 'pattern is required', durationMs: 0 };\r\n\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\tif (!withinProject(cwd, projectRoot)) {\r\n\t\treturn { id: '', name: 'file:glob', success: false, error: 'Access denied', durationMs: 0 };\r\n\t}\r\n\r\n\ttry {\r\n\t\tconst files = await globPromise(globPattern, { cwd, absolute: false });\r\n\t\treturn { id: '', name: 'file:glob', success: true, output: files.length > 0 ? files.join('\\n') : '(no files matched)', durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'file:glob', success: false, error: 'glob error: ' + (err instanceof Error ? err.message : String(err)), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolGrep(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst pattern = String(args.pattern ?? '');\r\n\tconst path = args.path ? String(args.path) : '.';\r\n\tconst caseSensitive = args.case_sensitive !== false;\r\n\r\n\tif (!pattern || !path) return { id: '', name: 'grep', success: false, error: 'pattern and path are required', durationMs: 0 };\r\n\r\n\tif (isAbsolute(path) && !withinProject(path, projectRoot)) {\r\n\t\treturn { id: '', name: 'grep', success: false, error: 'Access denied', durationMs: 0 };\r\n\t}\r\n\tconst fullPath = isAbsolute(path) ? path : resolve(projectRoot, path);\r\n\tconst flags = caseSensitive ? '' : '-i';\r\n\tconst includeFlag = args.glob ? ['--include=' + String(args.glob)] : [];\r\n\r\n\ttry {\r\n\t\tconst cmd = ['grep', flags, '-rn', '--color=never', pattern, fullPath, ...includeFlag].join(' ');\r\n\t\tconst { stdout, stderr } = await exec(cmd, { timeout: 30000 } as { timeout: number });\r\n\t\tconst results = (stdout || stderr).trim();\r\n\t\treturn { id: '', name: 'grep', success: true, output: results || '(no matches found)', durationMs: 0 };\r\n\t} catch (err: unknown) {\r\n\t\tconst errorObj = err as { code?: string | number; message?: string; stdout?: string; stderr?: string };\r\n\t\tif (errorObj.code === 1) return { id: '', name: 'grep', success: true, output: '(no matches found)', durationMs: 0 };\r\n\t\treturn { id: '', name: 'grep', success: false, error: 'grep error: ' + (err instanceof Error ? err.message : String(err)), durationMs: 0 };\r\n\t}\r\n}\r\n\r\n// \u2500\u2500 Bash \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst DANGEROUS_PATTERNS = [\r\n\t/rm\\s+-rf\\s+['\"]?\\//i,\r\n\t/dd\\s+if=/i,\r\n\t/>\\s*\\/dev\\/sda/i,\r\n\t/mkfs\\./i,\r\n\t/:\\s*\\(\\)\\s*\\{\\s*:\\|:&?\\s*\\};?\\s*:/i,\r\n];\r\n\r\nasync function toolBash(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst command = String(args.command ?? '');\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\tconst timeout = Number(args.timeout ?? getConfig(projectRoot).bashTimeout);\r\n\r\n\tif (!command) return { id: '', name: 'bash:execute', success: false, error: 'command is required', durationMs: 0 };\r\n\r\n\tfor (const pattern of DANGEROUS_PATTERNS) {\r\n\t\tif (pattern.test(command)) {\r\n\t\t\treturn { id: '', name: 'bash:execute', success: false, error: 'Dangerous command blocked: ' + command.slice(0, 50), durationMs: 0 };\r\n\t\t}\r\n\t}\r\n\r\n\ttry {\r\n\t\tconst { stdout, stderr } = await exec(command, { cwd, timeout } as { cwd: string; timeout: number });\r\n\t\tconst output = [stdout, stderr].filter(Boolean).join('\\n');\r\n\t\treturn { id: '', name: 'bash:execute', success: true, output: output || '(no output)', durationMs: 0 };\r\n\t} catch (err: unknown) {\r\n\t\tconst errorObj = err as { message?: string; stdout?: string; stderr?: string };\r\n\t\tconst combined = [errorObj.stdout, errorObj.stderr].filter(Boolean).join('\\n');\r\n\t\treturn { id: '', name: 'bash:execute', success: false, error: combined.slice(0, 500) || errorObj.message, durationMs: 0 };\r\n\t}\r\n}\r\n\r\n// \u2500\u2500 Git Tools \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nasync function toolGitStatus(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\ttry {\r\n\t\tconst git = simpleGit(cwd);\r\n\t\tconst status = await git.status();\r\n\t\tconst tracking = status.tracking;\r\n\t\tconst lines = [\r\n\t\t\t'Current branch: ' + (status.current ?? 'unknown'),\r\n\t\t\ttracking ? 'tracking: ' + tracking : '',\r\n\t\t\t'',\r\n\t\t\t'Modified: ' + (status.modified.length > 0 ? status.modified.join(', ') : '(none)'),\r\n\t\t\t'Created: ' + (status.created.length > 0 ? status.created.join(', ') : '(none)'),\r\n\t\t\t'Deleted: ' + (status.deleted.length > 0 ? status.deleted.join(', ') : '(none)'),\r\n\t\t\t'',\r\n\t\t\t'Not staged: ' + (status.not_added.length > 0 ? status.not_added.join(', ') : '(none)'),\r\n\t\t\t'',\r\n\t\t\t'Untracked: ' + (status.files.length > 0 ? status.files.join(', ') : '(none)'),\r\n\t\t].filter(Boolean).join('\\n');\r\n\t\treturn { id: '', name: 'git:status', success: true, output: lines, durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'git:status', success: false, error: err instanceof Error ? err.message : String(err), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolGitCommit(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst message = String(args.message ?? '');\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\tif (!message) return { id: '', name: 'git:commit', success: false, error: 'message is required', durationMs: 0 };\r\n\ttry {\r\n\t\tconst git = simpleGit(cwd);\r\n\t\tawait git.add('.');\r\n\t\tconst result = await git.commit(message);\r\n\t\treturn { id: '', name: 'git:commit', success: true, output: 'Committed ' + result.commit + ' \u2014 ' + message, durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'git:commit', success: false, error: err instanceof Error ? err.message : String(err), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolGitPush(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\ttry {\r\n\t\tconst git = simpleGit(cwd);\r\n\t\tawait git.push();\r\n\t\treturn { id: '', name: 'git:push', success: true, output: 'Pushed to remote.', durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'git:push', success: false, error: err instanceof Error ? err.message : String(err), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolGitLog(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\tconst limit = Number(args.limit ?? 20);\r\n\ttry {\r\n\t\tconst git = simpleGit(cwd);\r\n\t\tconst log = await git.log({ maxCount: limit });\r\n\t\tconst lines = log.all\r\n\t\t\t.map((c: { hash: string; date: string; message: string; author_name: string }) => c.hash.slice(0, 7) + ' | ' + c.date.slice(0, 10) + ' | ' + c.message + ' (' + c.author_name + ')')\r\n\t\t\t.join('\\n');\r\n\t\treturn { id: '', name: 'git:log', success: true, output: lines, durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'git:log', success: false, error: err instanceof Error ? err.message : String(err), durationMs: 0 };\r\n\t}\r\n}\r\n", "// =============================================================================\r\n// Config Management\r\n// =============================================================================\r\n\r\nimport { chmodSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\r\nimport { resolve, dirname } from 'node:path';\r\nimport { fileURLToPath } from 'node:url';\r\nimport type { AppConfig } from '../types/index.js';\r\n\r\n// Find project root reliably (works even when cwd != project dir)\r\nfunction getProjectRoot(): string {\r\n // Try import.meta.url first (ESM)\r\n try {\r\n const thisFile = fileURLToPath(import.meta.url);\r\n return dirname(dirname(thisFile)); // src/utils/ \u2192 src/ \u2192 project root\r\n } catch {\r\n // Fall back to process.cwd()\r\n return process.cwd();\r\n }\r\n}\r\n\r\n// Load .env files at startup\r\nfunction loadEnvFile(envPath: string): void {\r\n try {\r\n const content = readFileSync(envPath, 'utf-8');\r\n for (const line of content.split('\\n')) {\r\n const trimmed = line.trim();\r\n if (!trimmed || trimmed.startsWith('#')) continue;\r\n const eqIdx = trimmed.indexOf('=');\r\n if (eqIdx === -1 || eqIdx === trimmed.length - 1) continue;\r\n const key = trimmed.slice(0, eqIdx).trim();\r\n const value = trimmed.slice(eqIdx + 1).trim().replace(/^[\"']|[\"']$/g, '');\r\n if (!process.env[key]) process.env[key] = value;\r\n }\r\n } catch {\r\n // file not found \u2014 continue silently\r\n }\r\n}\r\n\r\n// Load .env from project root and current directory\r\nconst PROJECT_ROOT = getProjectRoot();\r\nloadEnvFile(resolve(PROJECT_ROOT, '.env'));\r\nloadEnvFile(resolve('.env')); // also try cwd\r\n\r\nexport { PROJECT_ROOT };\r\n\r\nexport function getAgentTermoDir(): string {\r\n const envDir = process.env.AGENT_TERMO_DIR;\r\n if (envDir) {\r\n return resolve(process.env.HOME || process.env.USERPROFILE || '.', envDir);\r\n }\r\n return resolve(process.env.HOME || process.env.USERPROFILE || '.', '.agent-termo');\r\n}\r\n\r\nfunction readStoredConfig(): Record<string, unknown> {\r\n try {\r\n const existing: unknown = JSON.parse(\r\n readFileSync(resolve(getAgentTermoDir(), 'config.json'), 'utf-8'),\r\n );\r\n if (existing && typeof existing === 'object' && !Array.isArray(existing)) {\r\n return existing as Record<string, unknown>;\r\n }\r\n } catch {\r\n // No saved user configuration yet.\r\n }\r\n return {};\r\n}\r\n\r\nfunction updateStoredConfig(patch: Record<string, unknown>): void {\r\n const configDir = getAgentTermoDir();\r\n const configPath = resolve(configDir, 'config.json');\r\n const storedConfig = { ...readStoredConfig(), ...patch };\r\n\r\n mkdirSync(configDir, { recursive: true, mode: 0o700 });\r\n writeFileSync(configPath, `${JSON.stringify(storedConfig, null, 2)}\\n`, {\r\n encoding: 'utf-8',\r\n mode: 0o600,\r\n });\r\n\r\n // Restrict permissions even when updating an existing file on Unix.\r\n if (process.platform !== 'win32') chmodSync(configPath, 0o600);\r\n}\r\n\r\nfunction loadStoredNimApiKey(): void {\r\n if (process.env.NIM_API_KEY) return;\r\n\r\n const { nimApiKey } = readStoredConfig();\r\n if (typeof nimApiKey === 'string' && nimApiKey.trim()) {\r\n process.env.NIM_API_KEY = nimApiKey;\r\n }\r\n}\r\n\r\n/**\r\n * A model picked with /model is saved and wins over NIM_MODEL from .env, so\r\n * the choice survives restarts. The --model CLI flag still overrides it.\r\n */\r\nfunction loadStoredNimModel(): void {\r\n const { nimModel } = readStoredConfig();\r\n if (typeof nimModel === 'string' && nimModel.trim()) {\r\n process.env.NIM_MODEL = nimModel;\r\n }\r\n}\r\n\r\nexport function saveNimApiKey(apiKey: string): void {\r\n updateStoredConfig({ nimApiKey: apiKey });\r\n}\r\n\r\nexport function saveNimModel(model: string): void {\r\n updateStoredConfig({ nimModel: model });\r\n}\r\n\r\nloadStoredNimApiKey();\r\nloadStoredNimModel();\r\n\r\nexport function getConfig(projectRoot: string): AppConfig {\r\n loadEnvFile(resolve(projectRoot, '.env'));\r\n\r\n return {\r\n nimApiKey: process.env.NIM_API_KEY ?? '',\r\n nimBaseUrl: process.env.NIM_BASE_URL ?? 'https://integrate.api.nvidia.com/v1',\r\n nimModel: process.env.NIM_MODEL ?? 'stepfun-ai/step-3.7-flash',\r\n agentTermoDir: process.env.AGENT_TERMO_DIR ?? '.claude',\r\n logLevel: (process.env.LOG_LEVEL as AppConfig['logLevel']) || 'info',\r\n confirmDestructive: process.env.CONFIRM_DESTRUCTIVE !== 'false',\r\n allowedCommands: (\r\n process.env.ALLOWED_COMMANDS ?? 'git,npm,node,pnpm,yarn,tsx,tsc,npx'\r\n ).split(','),\r\n llmTimeout: parseInt(process.env.LLM_TIMEOUT ?? '120000', 10),\r\n bashTimeout: parseInt(process.env.BASH_TIMEOUT ?? '300000', 10),\r\n };\r\n}\r\n\r\nexport function resolveProjectRoot(cwd?: string): string {\r\n return cwd || PROJECT_ROOT;\r\n}\r\n", "// =============================================================================\r\n// Diff Engine \u2014 line-level diff computation for file change review\r\n// =============================================================================\r\n// Uses LCS (Longest Common Subsequence) to compute minimal line-level diffs.\r\n\r\nimport type { DiffLine, DiffResult } from '../types/index.js';\r\n\r\n// \u2500\u2500 LCS-based Diff Algorithm \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nexport function computeDiff(original: string, proposed: string): DiffResult {\r\n\tconst originalLines = original.split('\\n');\r\n\tconst proposedLines = proposed.split('\\n');\r\n\r\n\tif (originalLines.length === 1 && originalLines[0] === '') {\r\n\t\tconst lines: DiffLine[] = proposedLines.map((content, i) => ({\r\n\t\t\ttype: 'add',\r\n\t\t\tlineNumber: i + 1,\r\n\t\t\tcontent,\r\n\t\t}));\r\n\t\treturn { file: '', lines, additions: proposedLines.length, deletions: 0 };\r\n\t}\r\n\r\n\tif (original === proposed) {\r\n\t\treturn { file: '', lines: [], additions: 0, deletions: 0 };\r\n\t}\r\n\r\n\tconst m = originalLines.length;\r\n\tconst n = proposedLines.length;\r\n\tconst stride = n + 1;\r\n\tconst table = new Int32Array((m + 1) * (n + 1));\r\n\r\n\tconst get = (i: number, j: number): number => table[i * stride + j]!;\r\n\tconst set = (i: number, j: number, val: number) => { table[i * stride + j] = val; };\r\n\r\n\tfor (let i = 1; i <= m; i++) {\r\n\t\tfor (let j = 1; j <= n; j++) {\r\n\t\t\tif (originalLines[i - 1] === proposedLines[j - 1]) {\r\n\t\t\t\tset(i, j, get(i - 1, j - 1) + 1);\r\n\t\t\t} else {\r\n\t\t\t\tset(i, j, Math.max(get(i - 1, j), get(i, j - 1)));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tconst ops = backtrackLCS(get, originalLines, proposedLines);\r\n\tconst diffLines = opsToDiffLines(ops);\r\n\r\n\tlet additions = 0;\r\n\tlet deletions = 0;\r\n\tfor (const line of diffLines) {\r\n\t\tif (line.type === 'add') additions++;\r\n\t\tif (line.type === 'remove') deletions++;\r\n\t}\r\n\r\n\treturn { file: '', lines: diffLines, additions, deletions };\r\n}\r\n\r\ninterface DiffOp {\r\n\ttype: 'same' | 'add' | 'remove';\r\n\toriginalIndex: number;\r\n\tproposedIndex: number;\r\n\toriginalLine?: string;\r\n\tproposedLine?: string;\r\n}\r\n\r\nfunction backtrackLCS(\r\n\tget: (i: number, j: number) => number,\r\n\ta: string[],\r\n\tb: string[],\r\n): DiffOp[] {\r\n\tconst ops: DiffOp[] = [];\r\n\tconst m = a.length;\r\n\tconst n = b.length;\r\n\tlet i = m;\r\n\tlet j = n;\r\n\r\n\twhile (i > 0 || j > 0) {\r\n\t\tif (i > 0 && j > 0 && a[i - 1] === b[j - 1]) {\r\n\t\t\tops.unshift({\r\n\t\t\t\ttype: 'same',\r\n\t\t\t\toriginalIndex: i,\r\n\t\t\t\tproposedIndex: j,\r\n\t\t\t\toriginalLine: a[i - 1],\r\n\t\t\t\tproposedLine: b[j - 1],\r\n\t\t\t});\r\n\t\t\ti--;\r\n\t\t\tj--;\r\n\t\t} else if (j > 0 && (i === 0 || get(i, j - 1) >= get(i - 1, j))) {\r\n\t\t\tops.unshift({\r\n\t\t\t\ttype: 'add',\r\n\t\t\t\tproposedIndex: j,\r\n\t\t\t\toriginalIndex: i,\r\n\t\t\t\tproposedLine: b[j - 1],\r\n\t\t\t});\r\n\t\t\tj--;\r\n\t\t} else {\r\n\t\t\tops.unshift({\r\n\t\t\t\ttype: 'remove',\r\n\t\t\t\toriginalIndex: i,\r\n\t\t\t\tproposedIndex: j,\r\n\t\t\t\toriginalLine: a[i - 1],\r\n\t\t\t});\r\n\t\t\ti--;\r\n\t\t}\r\n\t}\r\n\r\n\treturn ops;\r\n}\r\n\r\nfunction opsToDiffLines(ops: DiffOp[]): DiffLine[] {\r\n\tconst lines: DiffLine[] = [];\r\n\tlet originalLineNum = 0;\r\n\tlet proposedLineNum = 0;\r\n\r\n\tfor (const op of ops) {\r\n\t\tswitch (op.type) {\r\n\t\t\tcase 'same': {\r\n\t\t\t\toriginalLineNum++;\r\n\t\t\t\tproposedLineNum++;\r\n\t\t\t\tlines.push({\r\n\t\t\t\t\ttype: 'context',\r\n\t\t\t\t\tlineNumber: originalLineNum,\r\n\t\t\t\t\tcontent: op.originalLine ?? '',\r\n\t\t\t\t});\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tcase 'remove': {\r\n\t\t\t\toriginalLineNum++;\r\n\t\t\t\tlines.push({\r\n\t\t\t\t\ttype: 'remove',\r\n\t\t\t\t\tlineNumber: originalLineNum,\r\n\t\t\t\t\tcontent: op.originalLine ?? '',\r\n\t\t\t\t});\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tcase 'add': {\r\n\t\t\t\tproposedLineNum++;\r\n\t\t\t\tlines.push({\r\n\t\t\t\t\ttype: 'add',\r\n\t\t\t\t\tlineNumber: proposedLineNum,\r\n\t\t\t\t\tcontent: op.proposedLine ?? '',\r\n\t\t\t\t});\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn lines;\r\n}\r\n\r\n// \u2500\u2500 Context Extraction for large files \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nexport interface DiffOptions {\r\n\tcontextLines?: number;\r\n\tmaxLines?: number;\r\n}\r\n\r\nexport function applyDiffContext(diff: DiffResult, options: DiffOptions = {}): DiffResult {\r\n\tconst { contextLines = 3, maxLines = 0 } = options;\r\n\r\n\tif (contextLines <= 0 && maxLines <= 0) {\r\n\t\treturn diff;\r\n\t}\r\n\r\n\t// Identify contiguous change regions\r\n\tconst changeRegions: { start: number; end: number }[] = [];\r\n\tlet inChange = false;\r\n\tlet regionStart = 0;\r\n\r\n\tfor (let i = 0; i < diff.lines.length; i++) {\r\n\t\tconst line = diff.lines[i]!;\r\n\t\tif (line.type === 'add' || line.type === 'remove') {\r\n\t\t\tif (!inChange) {\r\n\t\t\t\tregionStart = i;\r\n\t\t\t\tinChange = true;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (inChange) {\r\n\t\t\t\tchangeRegions.push({ start: regionStart, end: i - 1 });\r\n\t\t\t\tinChange = false;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tif (inChange) {\r\n\t\tchangeRegions.push({ start: regionStart, end: diff.lines.length - 1 });\r\n\t}\r\n\r\n\t// Build merged ranges \u2014 use parallel arrays to avoid tuple strict-null issues\r\n\t// All accesses use ! because arrays are never sparse at these indices\r\n\tconst mergeStarts: number[] = [];\r\n\tconst mergeEnds: number[] = [];\r\n\r\n\tfor (const region of changeRegions) {\r\n\t\tconst start = Math.max(0, region.start - contextLines);\r\n\t\tconst end = Math.min(diff.lines.length - 1, region.end + contextLines);\r\n\r\n\t\tconst lastIdx = mergeStarts.length - 1;\r\n\t\tif (mergeStarts.length > 0 && start <= mergeEnds[lastIdx]! + 1) {\r\n\t\t\tmergeEnds[lastIdx] = Math.max(mergeEnds[lastIdx]!, end);\r\n\t\t} else {\r\n\t\t\tmergeStarts.push(start);\r\n\t\t\tmergeEnds.push(end);\r\n\t\t}\r\n\t}\r\n\r\n\t// Build filtered diff lines with ellipsis between non-adjacent ranges\r\n\tconst filteredLines: DiffLine[] = [];\r\n\r\n\tfor (let r = 0; r < mergeStarts.length; r++) {\r\n\t\tconst rangeStart = mergeStarts[r]!;\r\n\t\tconst rangeEnd = mergeEnds[r]!;\r\n\t\tconst prevEnd = r > 0 ? mergeEnds[r - 1]! : -1;\r\n\r\n\t\tif (r > 0 && rangeStart > prevEnd + 1) {\r\n\t\t\tconst omitted = rangeStart - prevEnd - 1;\r\n\t\t\tfilteredLines.push({\r\n\t\t\t\ttype: 'context',\r\n\t\t\t\tlineNumber: 0,\r\n\t\t\t\tcontent: '... ' + omitted + ' unchanged lines omitted ...',\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tfor (let i = rangeStart; i <= rangeEnd; i++) {\r\n\t\t\tconst line = diff.lines[i]!;\r\n\t\t\tfilteredLines.push(line);\r\n\t\t}\r\n\t}\r\n\r\n\tlet finalLines = filteredLines;\r\n\tif (maxLines > 0 && finalLines.length > maxLines) {\r\n\t\tconst halfMax = Math.floor(maxLines / 2);\r\n\t\tfinalLines = [\r\n\t\t\t...finalLines.slice(0, halfMax),\r\n\t\t\t{\r\n\t\t\t\ttype: 'context',\r\n\t\t\t\tlineNumber: 0,\r\n\t\t\t\tcontent: '... ' + (finalLines.length - maxLines) + ' more lines ...',\r\n\t\t\t},\r\n\t\t\t...finalLines.slice(finalLines.length - halfMax),\r\n\t\t];\r\n\t}\r\n\r\n\tlet additions = 0;\r\n\tlet deletions = 0;\r\n\tfor (const line of finalLines) {\r\n\t\tif (line.type === 'add') additions++;\r\n\t\tif (line.type === 'remove') deletions++;\r\n\t}\r\n\r\n\treturn { ...diff, lines: finalLines, additions, deletions };\r\n}\r\n\r\nexport function isNoOpDiff(diff: DiffResult): boolean {\r\n\treturn diff.lines.length === 0 && diff.additions === 0 && diff.deletions === 0;\r\n}\r\n", "// =============================================================================\r\n// Memory & Timeline Runtime\r\n// =============================================================================\r\n\r\nimport { readFileSync as readFile, appendFileSync as appendFile, writeFileSync as writeFile, existsSync, mkdirSync } from 'node:fs';\r\nimport { resolve } from 'node:path';\r\n\r\n// \u2500\u2500 Agent-Termo Home Memory \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nfunction ensureAgentTermoDir(): string {\r\n const dir = resolve(process.env.HOME || process.env.USERPROFILE || '.', '.agent-termo');\r\n try {\r\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\r\n } catch {\r\n // non-fatal; callers will handle missing file\r\n }\r\n return dir;\r\n}\r\n\r\nconst AGENT_TERMO_MEMORY_PATH = resolve(ensureAgentTermoDir(), 'memory.md');\r\n\r\nexport function loadAgentTermoMemory(): string {\r\n if (!existsSync(AGENT_TERMO_MEMORY_PATH)) return '';\r\n try {\r\n return readFile(AGENT_TERMO_MEMORY_PATH, 'utf-8');\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nexport function appendToAgentTermoMemory(entry: string): void {\r\n const timestamp = new Date().toISOString().split('T')[0];\r\n const content = '\\n\\n## ' + timestamp + '\\n\\n' + entry;\r\n try {\r\n appendFile(AGENT_TERMO_MEMORY_PATH, content, 'utf-8');\r\n } catch {\r\n // ignore persistence failure\r\n }\r\n}\r\n\r\nconst AGENT_TERMO_TIMELINE_PATH = resolve(ensureAgentTermoDir(), 'timeline.md');\r\n\r\nexport function loadAgentTermoTimeline(): string {\r\n if (!existsSync(AGENT_TERMO_TIMELINE_PATH)) return '';\r\n try {\r\n return readFile(AGENT_TERMO_TIMELINE_PATH, 'utf-8');\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nexport function logAgentTermoTimeline(message: string): void {\r\n const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 16);\r\n const entry = '\\n- [' + timestamp + '] ' + message;\r\n try {\r\n appendFile(AGENT_TERMO_TIMELINE_PATH, entry, 'utf-8');\r\n } catch {\r\n // ignore persistence failure\r\n }\r\n}\r\n\r\n// \u2500\u2500 Project Memory & Timeline Runtime \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nexport async function loadMemory(projectRoot: string): Promise<string> {\r\n const path = resolve(projectRoot, 'docs', 'MEMORY.md');\r\n if (!existsSync(path)) return '';\r\n try {\r\n return readFile(path, 'utf-8');\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nexport async function appendToMemory(projectRoot: string, entry: string): Promise<void> {\r\n const path = resolve(projectRoot, 'docs', 'MEMORY.md');\r\n const timestamp = new Date().toISOString().split('T')[0];\r\n appendFile(path, '\\n\\n## ' + timestamp + '\\n\\n' + entry, 'utf-8');\r\n}\r\n\r\n// \u2500\u2500 Timeline System \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst TIMELINE_TEMPLATE = '# Project Timeline\\n\\nThis document tracks the complete chronological history of the project.\\n\\n---\\n\\n';\r\n\r\nexport async function loadTimeline(projectRoot: string): Promise<string> {\r\n const path = resolve(projectRoot, 'docs', 'TIMELINE.md');\r\n if (!existsSync(path)) {\r\n try {\r\n writeFile(path, TIMELINE_TEMPLATE, 'utf-8');\r\n } catch {\r\n // ignore\r\n }\r\n return '';\r\n }\r\n try {\r\n return readFile(path, 'utf-8');\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nexport async function appendToTimeline(\r\n projectRoot: string,\r\n agent: string,\r\n phase: string,\r\n actions: string[],\r\n notes: string[] = [],\r\n): Promise<void> {\r\n const path = resolve(projectRoot, 'docs', 'TIMELINE.md');\r\n const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 16);\r\n\r\n const entry =\r\n '\\n\\n---\\n\\n## [' +\r\n timestamp +\r\n '] - ' +\r\n agent +\r\n '\\n\\n### Phase/Activity\\n' +\r\n phase +\r\n '\\n\\n### Actions Taken\\n' +\r\n actions.map((a) => '- ' + a).join('\\n') +\r\n '\\n\\n### Notes\\n' +\r\n (notes.length > 0 ? notes.map((n) => '- ' + n).join('\\n') : '- (none)');\r\n\r\n appendFile(path, entry, 'utf-8');\r\n}\r\n\r\nexport async function logToTimeline(projectRoot: string, message: string): Promise<void> {\r\n const path = resolve(projectRoot, 'docs', 'TIMELINE.md');\r\n const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 16);\r\n appendFile(path, '\\n- [' + timestamp + '] ' + message, 'utf-8');\r\n}\r\n", "// =============================================================================\r\n// Agent Loader + System Prompt Builder\r\n// =============================================================================\r\n\r\nimport { readdirSync, readFileSync } from 'node:fs';\r\nimport { resolve } from 'node:path';\r\nimport type { Agent } from '../types/index.js';\r\n\r\nfunction parseAgentMeta(content: string): { description: string; tools: string[] } {\r\n const descMatch = content.match(/^description:\\s*(.+)$/m);\r\n const toolsMatch = content.match(/^tools:\\s*\\[(.+)\\]/m);\r\n const toolsStr = toolsMatch?.[1] ?? '';\r\n const tools = toolsStr\r\n ? toolsStr.split(',').map((t) => t.trim().replace(/^[\"']|[\"']$/g, ''))\r\n : ['file:read', 'file:write', 'file:edit', 'file:glob', 'grep', 'bash:execute', 'git:status', 'git:commit', 'git:push', 'git:log'];\r\n return { description: descMatch?.[1]?.trim() ?? '', tools };\r\n}\r\n\r\nexport function loadAgentPrompt(agentName: string, agentDir: string): string | null {\r\n const candidate = resolve(agentDir, 'agents', agentName + '.md');\r\n try {\r\n const content = readFileSync(candidate, 'utf-8');\r\n const withoutFrontmatter = content.replace(/^---[\\s\\S]+?---\\n/, '');\r\n return withoutFrontmatter.trim();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function loadAllAgents(agentDir: string): Agent[] {\r\n const agentsDir = resolve(agentDir, 'agents');\r\n try {\r\n const files = readdirSync(agentsDir).filter((f) => f.endsWith('.md'));\r\n const agents: Agent[] = files.map((file) => {\r\n const agentId = file.replace(/\\.md$/, '');\r\n const content = readFileSync(resolve(agentsDir, file), 'utf-8');\r\n const meta = parseAgentMeta(content);\r\n const withoutFrontmatter = content.replace(/^---[\\s\\S]+?---\\n/, '').trim();\r\n return { name: agentId, description: meta.description, systemPrompt: withoutFrontmatter, tools: meta.tools };\r\n });\r\n return agents.sort((a, b) => a.name.localeCompare(b.name));\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n// =============================================================================\r\n// Agent System Prompt Builder\r\n// =============================================================================\r\n\r\nconst SYSTEM_BASE = `You are Agent-Termo, a helpful AI assistant in a terminal.\r\n\r\nRESPONSE RULES (follow these strictly):\r\n- Be concise and direct. 1-3 sentences for simple questions.\r\n- Never output verbose chain-of-thought or reasoning \u2014 just the answer.\r\n- For coding tasks: briefly explain what you did, show key code.\r\n- Never write \"null\" or placeholders in your response.\r\n- When using function calls, respond with the function only \u2014 no preamble.\r\n\r\nCONVERSATION MODE (default):\r\nJust chat. Say things like \"I'm doing well!\" or \"2+2 is 4.\" \u2014 no tools needed.\r\n\r\nTOOL MODE (when asked to code/build/fix files):\r\nUse these functions (JSON tool_calls format):\r\n{\"tool_calls\":[{\"id\":\"call_1\",\"name\":\"function_name\",\"arguments\":{\"key\":\"value\"}}]}\r\n\r\nAvailable functions:\r\n- file:read(path) \u2192 read a file\r\n- file:write(path, content) \u2192 overwrite a file completely\r\n- file:edit(path, old_string, new_string) \u2192 edit a specific line section\r\n- file:glob(pattern) \u2192 list files matching a glob (e.g. \"src/**/*.ts\")\r\n- grep(pattern, path, glob?) \u2192 search for text in files\r\n- bash:execute(command) \u2192 run a shell command\r\n- git:status() / git:commit(message) / git:push() \u2192 version control\r\n\r\nWhen done, say \"Done: <brief summary>.\"\r\n\r\nAVAILABLE FILES:\r\n- docs/MEMORY.md \u2014 project context\r\n- docs/TIMELINE.md \u2014 recent activity log`;\r\n\r\nexport function buildSystemPrompt(memory: string, timeline: string, _agentDir: string): string {\r\n let prompt = SYSTEM_BASE;\r\n\r\n if (memory) {\r\n prompt += '\\n\\n## Project Memory\\n' + memory;\r\n }\r\n\r\n if (timeline) {\r\n prompt += '\\n\\n## Recent Timeline (last entries)\\n' + timeline.slice(-1500);\r\n }\r\n\r\n return prompt;\r\n}", "// =============================================================================\r\n// Terminal UI \u2014 chalk-based styling, markdown output, diff viewer\r\n// Layout (pinned input box, scroll region) and keyboard input live in screen.ts\r\n// =============================================================================\r\n\r\nimport Chalk from 'chalk';\r\nimport type { ProposedFileChange } from '../types/index.js';\r\nimport { loadAgentTermoMemory, loadAgentTermoTimeline } from '../memory/index.js';\r\nimport {\r\n\tclipText,\r\n\tlistenKeys,\r\n\tresetScreen,\r\n\tsetCommands,\r\n\tterminalWidth,\r\n\ttype CommandInfo,\r\n} from './screen.js';\r\n\r\nexport {\r\n\tcreateInput,\r\n\tinitScreen,\r\n\tpick,\r\n\tsetScreenStatus,\r\n\ttype InputController,\r\n\ttype PickItem,\r\n} from './screen.js';\r\n\r\nconst c: typeof Chalk = Chalk as unknown as typeof Chalk;\r\nconst out = process.stdout;\r\n\r\nexport const COMMANDS: CommandInfo[] = [\r\n\t{ name: '/help', description: 'show all commands' },\r\n\t{ name: '/clear', description: 'clear conversation & screen' },\r\n\t{ name: '/memory', description: 'view Agent-Termo memory' },\r\n\t{ name: '/timeline', description: 'view recent activity' },\r\n\t{ name: '/model', description: 'switch NVIDIA NIM model (or /model <id>)' },\r\n\t{ name: '/agents', description: 'list all agents' },\r\n\t{ name: '/history', description: 'show message count' },\r\n\t{ name: '/exit', description: 'quit' },\r\n];\r\nsetCommands(COMMANDS);\r\n\r\n// eslint-disable-next-line no-control-regex\r\nconst ANSI_RE = /\\x1b\\[[0-9;?]*[A-Za-z]/g;\r\nconst visibleLength = (s: string): number => s.replace(ANSI_RE, '').length;\r\nconst rule = (): string => c.dim('\u2500'.repeat(Math.max(10, Math.min(terminalWidth() - 2, 100))));\r\n\r\n// =============================================================================\r\n// WELCOME BANNER\r\n// =============================================================================\r\n\r\nexport function printWelcome(projectRoot: string, model: string): void {\r\n\tconst width = Math.max(40, Math.min(terminalWidth() - 2, 64));\r\n\tconst inner = width - 2;\r\n\tconst room = inner - 2;\r\n\tconst row = (content: string): string =>\r\n\t\t' ' + c.magenta('\u2502') + ' ' + content + ' '.repeat(Math.max(0, room - visibleLength(content))) + ' ' + c.magenta('\u2502');\r\n\tconst field = (label: string, value: string): string =>\r\n\t\tc.dim(label.padEnd(7)) + c.cyan(clipText(value, room - 7));\r\n\r\n\tout.write('\\n');\r\n\tout.write(' ' + c.magenta('\u256D' + '\u2500'.repeat(inner) + '\u256E') + '\\n');\r\n\tout.write(row(c.magenta.bold('\u273B Agent-Termo')) + '\\n');\r\n\tout.write(row(c.dim(clipText('AI coding agent for your terminal', room))) + '\\n');\r\n\tout.write(row('') + '\\n');\r\n\tout.write(row(field('model', model)) + '\\n');\r\n\tout.write(row(field('cwd', projectRoot)) + '\\n');\r\n\tout.write(' ' + c.magenta('\u2570' + '\u2500'.repeat(inner) + '\u256F') + '\\n');\r\n\tout.write('\\n');\r\n\tout.write(\r\n\t\tc.dim(' ') + c.cyan('/help') + c.dim(' commands \u00B7 ') + c.cyan('/model') + c.dim(' switch NIM model \u00B7 ') +\r\n\t\t\tc.cyan('Tab') + c.dim(' completes') + '\\n\\n',\r\n\t);\r\n}\r\n\r\n// =============================================================================\r\n// MARKDOWN OUTPUT \u2014 line-buffered so streamed replies render as they arrive\r\n// =============================================================================\r\n\r\nfunction inline(text: string): string {\r\n\treturn text\r\n\t\t.split(/(`[^`]+`)/)\r\n\t\t.map((seg) =>\r\n\t\t\tseg.length > 1 && seg.startsWith('`') && seg.endsWith('`')\r\n\t\t\t\t? c.cyan(seg.slice(1, -1))\r\n\t\t\t\t: seg.replace(/\\*\\*(.+?)\\*\\*/g, (_m, g: string) => c.bold(g)),\r\n\t\t)\r\n\t\t.join('');\r\n}\r\n\r\nexport class MarkdownPrinter {\r\n\tprivate pending = '';\r\n\tprivate inCode = false;\r\n\tprivate first = true;\r\n\tprivate lastBlank = false;\r\n\r\n\t/** `beforeFirstOutput` runs once, just before the first line is printed (stop the spinner there). */\r\n\tconstructor(private readonly beforeFirstOutput?: () => void) {}\r\n\r\n\tpush(text: string): void {\r\n\t\tthis.pending += text;\r\n\t\tlet nl = this.pending.indexOf('\\n');\r\n\t\twhile (nl !== -1) {\r\n\t\t\tconst line = this.pending.slice(0, nl).replace(/\\r$/, '');\r\n\t\t\tthis.pending = this.pending.slice(nl + 1);\r\n\t\t\tthis.emit(line);\r\n\t\t\tnl = this.pending.indexOf('\\n');\r\n\t\t}\r\n\t}\r\n\r\n\tend(): void {\r\n\t\tif (this.pending) this.emit(this.pending.replace(/\\r$/, ''));\r\n\t\tthis.pending = '';\r\n\t}\r\n\r\n\tget printed(): boolean {\r\n\t\treturn !this.first;\r\n\t}\r\n\r\n\tprivate emit(line: string): void {\r\n\t\tconst blank = line.trim() === '';\r\n\t\tif (!this.inCode && blank && (this.first || this.lastBlank)) return;\r\n\t\tthis.lastBlank = blank && !this.inCode;\r\n\r\n\t\tif (this.first) {\r\n\t\t\tthis.beforeFirstOutput?.();\r\n\t\t\tout.write('\\n');\r\n\t\t}\r\n\t\tconst prefix = this.first ? c.magenta('\u25CF ') : ' ';\r\n\t\tthis.first = false;\r\n\t\t// Blank prose lines stay empty (no trailing indent); code keeps its gutter.\r\n\t\tout.write(blank && !this.inCode ? '\\n' : prefix + this.render(line) + '\\n');\r\n\t}\r\n\r\n\tprivate render(line: string): string {\r\n\t\tconst fence = /^\\s*```\\s*([\\w+-]*)/.exec(line);\r\n\t\tif (fence) {\r\n\t\t\tthis.inCode = !this.inCode;\r\n\t\t\treturn this.inCode ? c.dim('\u250C\u2500 ' + (fence[1] || 'code')) : c.dim('\u2514\u2500');\r\n\t\t}\r\n\t\tif (this.inCode) return c.dim('\u2502 ') + c.cyan(line.replace(/\\t/g, ' '));\r\n\r\n\t\tconst heading = /^#{1,6}\\s+(.*)$/.exec(line);\r\n\t\tif (heading) return c.bold.magenta(inline(heading[1] ?? ''));\r\n\t\tif (/^\\s*([-*_])\\1{2,}\\s*$/.test(line)) return c.dim('\u2500'.repeat(Math.min(40, terminalWidth() - 4)));\r\n\r\n\t\tconst bullet = /^(\\s*)[-*+]\\s+(.*)$/.exec(line);\r\n\t\tif (bullet) return (bullet[1] ?? '') + c.magenta('\u2022') + ' ' + inline(bullet[2] ?? '');\r\n\r\n\t\tconst numbered = /^(\\s*)(\\d+)[.)]\\s+(.*)$/.exec(line);\r\n\t\tif (numbered) return (numbered[1] ?? '') + c.magenta(numbered[2] + '.') + ' ' + inline(numbered[3] ?? '');\r\n\r\n\t\tconst quote = /^>\\s?(.*)$/.exec(line);\r\n\t\tif (quote) return c.dim('\u258E ') + c.italic(inline(quote[1] ?? ''));\r\n\r\n\t\treturn inline(line);\r\n\t}\r\n}\r\n\r\n// =============================================================================\r\n// MESSAGE DISPLAY\r\n// =============================================================================\r\n\r\nexport function printUserMessage(text: string): void {\r\n\tconst lines = text.split('\\n');\r\n\tout.write('\\n' + c.green.bold('\u276F ') + c.bold(lines[0] ?? '') + '\\n');\r\n\tfor (const l of lines.slice(1)) out.write(' ' + c.bold(l) + '\\n');\r\n}\r\n\r\nexport function printAssistantMessage(content: string): void {\r\n\tconst md = new MarkdownPrinter();\r\n\tmd.push(content);\r\n\tmd.end();\r\n}\r\n\r\n// =============================================================================\r\n// TOOL CALL DISPLAY\r\n// =============================================================================\r\n\r\nexport function printToolCall(toolName: string, args: Record<string, unknown>): void {\r\n\tconst summary = Object.entries(args)\r\n\t\t.map(([k, v]) => {\r\n\t\t\tconst raw = typeof v === 'string' ? v : JSON.stringify(v);\r\n\t\t\treturn k + '=' + clipText(String(raw ?? '').replace(/\\s+/g, ' '), 40);\r\n\t\t})\r\n\t\t.join(', ');\r\n\tconst room = terminalWidth() - toolName.length - 6;\r\n\tout.write('\\n' + c.blue('\u25CF ') + c.bold(toolName) + c.dim('(' + clipText(summary, room) + ')') + '\\n');\r\n}\r\n\r\nexport function printToolResult(\r\n\ttoolName: string,\r\n\tresult: { success: boolean; output?: string; error?: string },\r\n\tparsedOutput?: { needsApproval?: boolean; proposedChange?: ProposedFileChange },\r\n): void {\r\n\t// A proposed file change is shown as a diff, then the accept/reject prompt.\r\n\tif (parsedOutput?.needsApproval && parsedOutput.proposedChange) {\r\n\t\tprintDiffViewer(parsedOutput.proposedChange);\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst room = terminalWidth() - 8;\r\n\tif (result.success) {\r\n\t\t// One line of output is shown as-is; longer output (file contents, command\r\n\t\t// logs) is summarised, since the full text goes to the model.\r\n\t\tconst lines = (result.output ?? '').split('\\n').filter((l) => l.trim() !== '');\r\n\t\tconst summary = lines.length > 1 ? `${lines.length} lines` : clipText((lines[0] ?? '').trim() || 'done', room);\r\n\t\tout.write(c.dim(' \u23BF ') + c.green('\u2713 ') + summary + '\\n');\r\n\t} else {\r\n\t\tconst message = (result.error ?? 'unknown error').split('\\n')[0] ?? 'unknown error';\r\n\t\tout.write(c.dim(' \u23BF ') + c.red('\u2717 ' + clipText(`${toolName}: ${message}`, room)) + '\\n');\r\n\t}\r\n}\r\n\r\n// =============================================================================\r\n// DIFF VIEWER\r\n// =============================================================================\r\n\r\nexport function printDiffViewer(change: ProposedFileChange): void {\r\n\tconst diff = change.diff;\r\n\tconst room = Math.max(20, terminalWidth() - 14);\r\n\r\n\tconst label = change.isDeletion\r\n\t\t? c.red('DELETE')\r\n\t\t: change.isNewFile\r\n\t\t\t? c.green('NEW')\r\n\t\t\t: c.blue('MODIFY');\r\n\r\n\tout.write('\\n ' + c.bold.cyan(diff.file) + ' ' + label + ' ' + c.green('+' + diff.additions) + ' ' + c.red('-' + diff.deletions) + '\\n');\r\n\tout.write(' ' + c.dim('\u2500'.repeat(Math.max(10, Math.min(terminalWidth() - 4, 100)))) + '\\n');\r\n\r\n\tfor (const line of diff.lines) {\r\n\t\tconst prefix = line.type === 'add' ? '+' : line.type === 'remove' ? '-' : ' ';\r\n\t\tconst color = line.type === 'add' ? c.green : line.type === 'remove' ? c.red : c.dim;\r\n\t\tconst num = line.lineNumber > 0 ? String(line.lineNumber).padStart(4) : ' ';\r\n\t\tconst text = clipText(line.content.replace(/\\t/g, ' '), room);\r\n\t\tout.write(' ' + color(prefix + num + ' \u2502 ' + text) + '\\n');\r\n\t}\r\n\tout.write('\\n');\r\n}\r\n\r\n// =============================================================================\r\n// ACCEPT / REJECT PROMPT\r\n// =============================================================================\r\n\r\nexport function promptAcceptReject(message: string = 'Accept this change?'): Promise<'accept' | 'reject'> {\r\n\tout.write(\r\n\t\t'\\n' + c.yellow('? ') + c.bold(message) + c.dim(' [') + c.green('Y') + c.dim('/') + c.red('n') + c.dim('] '),\r\n\t);\r\n\r\n\treturn new Promise((resolve) => {\r\n\t\tlet done = false;\r\n\t\tlet stop: () => void = () => undefined;\r\n\r\n\t\tconst answer = (accepted: boolean | 'cancelled'): void => {\r\n\t\t\tdone = true;\r\n\t\t\tstop();\r\n\t\t\tout.write(\r\n\t\t\t\taccepted === true ? c.green('yes') + '\\n' : accepted === false ? c.red('no') + '\\n' : c.red('cancelled') + '\\n',\r\n\t\t\t);\r\n\t\t\tresolve(accepted === true ? 'accept' : 'reject');\r\n\t\t};\r\n\r\n\t\tstop = listenKeys((key) => {\r\n\t\t\tif (done) return;\r\n\t\t\tconst first = key.text?.[0]?.toLowerCase();\r\n\t\t\tif (key.name === 'enter' || first === 'y') answer(true);\r\n\t\t\telse if (key.name === 'escape' || first === 'n') answer(false);\r\n\t\t\telse if (key.name === 'ctrl+c') answer('cancelled');\r\n\t\t});\r\n\t});\r\n}\r\n\r\n// =============================================================================\r\n// STATUS MESSAGES\r\n// =============================================================================\r\n\r\nexport function printError(message: string, hint?: string): void {\r\n\tout.write('\\n' + c.red('\u2717 ' + message) + '\\n');\r\n\tif (hint) out.write(c.dim(' Hint: ' + hint) + '\\n');\r\n}\r\n\r\nexport function printSuccess(message: string): void {\r\n\tout.write(c.green('\u2713 ' + message) + '\\n');\r\n}\r\n\r\nexport function printInfo(message: string): void {\r\n\tout.write(c.blue('\u2139 ') + message + '\\n');\r\n}\r\n\r\n// =============================================================================\r\n// AGENT-TERMO MEMORY + TIMELINE DISPLAY\r\n// =============================================================================\r\n\r\nexport async function printMemoryFile(): Promise<void> {\r\n\tconst mem = loadAgentTermoMemory();\r\n\tif (!mem) {\r\n\t\tprintInfo('Agent-Termo memory is empty. (Normal for new sessions.)');\r\n\t\treturn;\r\n\t}\r\n\tout.write('\\n' + c.bold('Agent-Termo memory') + '\\n' + rule() + '\\n' + mem + '\\n' + rule() + '\\n\\n');\r\n}\r\n\r\nexport async function printTimelineFile(): Promise<void> {\r\n\tconst tl = loadAgentTermoTimeline();\r\n\tif (!tl || tl.trim().length === 0) {\r\n\t\tprintInfo('Timeline is empty.');\r\n\t\treturn;\r\n\t}\r\n\tconst lines = tl.split('\\n');\r\n\tconst recentCount = Math.min(40, lines.length);\r\n\tout.write('\\n' + c.bold('Agent-Termo timeline') + c.dim(' (recent entries)') + '\\n' + rule() + '\\n');\r\n\tout.write(lines.slice(-recentCount).join('\\n') + '\\n' + rule() + '\\n');\r\n\tif (lines.length > recentCount) {\r\n\t\tout.write(c.dim('\u2026 ' + (lines.length - recentCount) + ' earlier entries hidden') + '\\n');\r\n\t}\r\n\tout.write('\\n');\r\n}\r\n\r\n// =============================================================================\r\n// HELP + AGENTS DISPLAY\r\n// =============================================================================\r\n\r\nexport function printHelp(): void {\r\n\tout.write('\\n' + c.bold('Commands') + '\\n' + rule() + '\\n');\r\n\tfor (const cmd of COMMANDS) {\r\n\t\tout.write(' ' + c.cyan(cmd.name.padEnd(11)) + c.dim(cmd.description) + '\\n');\r\n\t}\r\n\tout.write('\\n' + c.bold('Keys') + '\\n' + rule() + '\\n');\r\n\tconst keys: Array<[string, string]> = [\r\n\t\t['\u2191 / \u2193', 'input history'],\r\n\t\t['Tab', 'complete a /command'],\r\n\t\t['Ctrl+A / Ctrl+E', 'start / end of line'],\r\n\t\t['Ctrl+W / Ctrl+U', 'delete word / to line start'],\r\n\t\t['Ctrl+C', 'clear the line, or quit when empty'],\r\n\t];\r\n\tfor (const [k, d] of keys) out.write(' ' + c.cyan(k.padEnd(17)) + c.dim(d) + '\\n');\r\n\tout.write('\\n');\r\n}\r\n\r\nexport function printAgentsList(agents: Array<{ name: string; description: string }>): void {\r\n\tout.write('\\n' + c.bold('Available agents') + '\\n' + rule() + '\\n');\r\n\tconst room = Math.max(10, terminalWidth() - 34);\r\n\tfor (const a of agents) {\r\n\t\tout.write(' ' + c.cyan(a.name.padEnd(30)) + c.dim(clipText(a.description.replace(/\\s+/g, ' '), room)) + '\\n');\r\n\t}\r\n\tout.write('\\n');\r\n}\r\n\r\n// =============================================================================\r\n// SPINNER\r\n// =============================================================================\r\n\r\nconst FRAMES = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F'];\r\nlet spinnerTimer: ReturnType<typeof setInterval> | null = null;\r\n\r\nexport function startSpinner(message: string): void {\r\n\tstopSpinner();\r\n\tif (!out.isTTY) {\r\n\t\tout.write(c.dim(message + '\u2026') + '\\n');\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst startedAt = Date.now();\r\n\tlet frame = 0;\r\n\tconst label = clipText(message, Math.max(10, terminalWidth() - 14));\r\n\tconst render = (): void => {\r\n\t\tconst secs = Math.floor((Date.now() - startedAt) / 1000);\r\n\t\tout.write('\\r\\x1b[2K' + c.magenta(FRAMES[frame++ % FRAMES.length] ?? '\u280B') + ' ' + c.dim(`${label}\u2026 ${secs}s`));\r\n\t};\r\n\r\n\tout.write('\\x1b[?25l');\r\n\trender();\r\n\tspinnerTimer = setInterval(render, 80);\r\n}\r\n\r\n/** Stops the spinner and clears its line. The argument is kept for older call sites and is ignored. */\r\nexport function stopSpinner(_success?: boolean): void {\r\n\tif (!spinnerTimer) return;\r\n\tclearInterval(spinnerTimer);\r\n\tspinnerTimer = null;\r\n\tout.write('\\r\\x1b[2K\\x1b[?25h');\r\n}\r\n\r\nexport function clearScreen(): void {\r\n\tresetScreen();\r\n}\r\n", "// =============================================================================\r\n// Screen layout + raw keyboard input\r\n//\r\n// Claude Code-style layout: output scrolls in a region at the top of the\r\n// terminal while a bordered input box and a status line stay pinned to the\r\n// bottom. Implemented with a DECSTBM scroll region, so every console.log /\r\n// process.stdout.write elsewhere in the app lands in the scrolling region.\r\n// =============================================================================\r\n\r\nimport Chalk from 'chalk';\r\nimport { createInterface } from 'node:readline';\r\n\r\nconst c: typeof Chalk = Chalk as unknown as typeof Chalk;\r\nconst out = process.stdout;\r\n\r\nconst CSI = '\\x1b[';\r\nconst SAVE = '\\x1b7'; // DECSC \u2014 save cursor\r\nconst RESTORE = '\\x1b8'; // DECRC \u2014 restore cursor\r\n\r\n/** Rows pinned to the bottom: top border, input row, bottom border, status row. */\r\nconst CHROME_ROWS = 4;\r\nconst MIN_ROWS = 12;\r\nconst MIN_COLS = 40;\r\nconst PLACEHOLDER = 'Ask anything\u2026 or type / for commands';\r\n\r\nexport interface CommandInfo {\r\n\tname: string;\r\n\tdescription: string;\r\n}\r\n\r\nconst S = {\r\n\tactive: false,\r\n\tediting: false,\r\n\t/** False when the output position saved at the start of editing is stale (resize). */\r\n\tsavedValid: true,\r\n\trows: 0,\r\n\tmodel: '',\r\n\tproject: '',\r\n\tcommands: [] as CommandInfo[],\r\n\tbuffer: '',\r\n\tcursor: 0,\r\n\toffset: 0,\r\n};\r\n\r\nexport function setCommands(commands: CommandInfo[]): void {\r\n\tS.commands = commands;\r\n}\r\n\r\nfunction dims(): { rows: number; cols: number } {\r\n\treturn { rows: out.rows || 24, cols: out.columns || 80 };\r\n}\r\n\r\nexport function terminalWidth(): number {\r\n\treturn out.columns || 80;\r\n}\r\n\r\nexport function clipText(text: string, max: number): string {\r\n\tif (max <= 0) return '';\r\n\treturn text.length <= max ? text : text.slice(0, Math.max(0, max - 1)) + '\u2026';\r\n}\r\n\r\nfunction shortPath(p: string): string {\r\n\tconst home = process.env.HOME || process.env.USERPROFILE || '';\r\n\treturn home && p.startsWith(home) ? '~' + p.slice(home.length) : p;\r\n}\r\n\r\nexport function layoutSupported(): boolean {\r\n\treturn Boolean(\r\n\t\tout.isTTY && process.stdin.isTTY && (out.rows ?? 0) >= MIN_ROWS && (out.columns ?? 0) >= MIN_COLS,\r\n\t);\r\n}\r\n\r\n// =============================================================================\r\n// Bottom chrome (input box + status line)\r\n// =============================================================================\r\n\r\nfunction statusLine(max: number): string {\r\n\t// While typing a slash command, the status line shows matching commands.\r\n\tif (S.editing && S.buffer.startsWith('/') && !S.buffer.includes(' ')) {\r\n\t\tconst typed = S.buffer.toLowerCase();\r\n\t\tconst hits = S.commands.filter((cmd) => cmd.name.startsWith(typed));\r\n\t\tconst only = hits[0];\r\n\t\tif (hits.length === 1 && only) {\r\n\t\t\treturn ' ' + c.cyan(only.name) + c.dim(clipText(' \u2014 ' + only.description, max - only.name.length - 1));\r\n\t\t}\r\n\t\tif (hits.length > 1) {\r\n\t\t\treturn c.cyan(clipText(' ' + hits.map((h) => h.name).join(' '), max));\r\n\t\t}\r\n\t}\r\n\r\n\tconst hint = '/help \u00B7 /model \u00B7 ctrl+c to exit';\r\n\tconst modelPart = clipText(' ' + S.model, max);\r\n\tconst roomWithHint = max - modelPart.length - hint.length - 2;\r\n\tconst showHint = roomWithHint >= 15;\r\n\tconst projPart = clipText(\r\n\t\t' \u00B7 ' + shortPath(S.project),\r\n\t\tshowHint ? roomWithHint : Math.max(0, max - modelPart.length),\r\n\t);\r\n\tconst gap = Math.max(1, max - modelPart.length - projPart.length - hint.length);\r\n\treturn c.cyan(modelPart) + c.dim(projPart + (showHint ? ' '.repeat(gap) + hint : ''));\r\n}\r\n\r\nfunction chromeString(): string {\r\n\tconst { rows, cols } = dims();\r\n\tconst width = Math.max(1, cols - 6); // '\u2502 \u276F ' + text + ' \u2502'\r\n\r\n\t// Keep the cursor inside the visible window of the input line.\r\n\tS.offset = Math.min(S.offset, Math.max(0, S.buffer.length - width + 1));\r\n\tif (S.cursor < S.offset) S.offset = S.cursor;\r\n\tif (S.cursor > S.offset + width - 1) S.offset = S.cursor - width + 1;\r\n\r\n\tconst edge = S.editing ? c.magenta : c.dim;\r\n\tconst body = S.buffer\r\n\t\t? S.buffer.slice(S.offset, S.offset + width).padEnd(width)\r\n\t\t: c.dim(clipText(PLACEHOLDER, width).padEnd(width));\r\n\r\n\tconst top = rows - 3;\r\n\tconst line = (row: number, text: string): string => `${CSI}${row};1H${CSI}2K${text}`;\r\n\treturn [\r\n\t\tline(top, edge('\u256D' + '\u2500'.repeat(cols - 2) + '\u256E')),\r\n\t\tline(top + 1, edge('\u2502') + ' ' + c.magenta.bold('\u276F') + ' ' + body + ' ' + edge('\u2502')),\r\n\t\tline(top + 2, edge('\u2570' + '\u2500'.repeat(cols - 2) + '\u256F')),\r\n\t\tline(rows, statusLine(cols - 1)),\r\n\t].join('');\r\n}\r\n\r\nfunction inputCursor(): string {\r\n\tconst { rows } = dims();\r\n\treturn `${CSI}${rows - 2};${5 + S.cursor - S.offset}H`;\r\n}\r\n\r\nfunction paint(): void {\r\n\tif (!S.active) return;\r\n\tif (S.editing) {\r\n\t\t// The saved slot holds the output position while editing: don't touch it.\r\n\t\tout.write(CSI + '?25l' + chromeString() + inputCursor() + CSI + '?25h');\r\n\t} else {\r\n\t\tout.write(SAVE + chromeString() + RESTORE);\r\n\t}\r\n}\r\n\r\nfunction regionBottom(): number {\r\n\treturn Math.max(1, dims().rows - CHROME_ROWS);\r\n}\r\n\r\nfunction applyRegion(): void {\r\n\tout.write(`${CSI}1;${regionBottom()}r`); // also homes the cursor\r\n}\r\n\r\nfunction onResize(): void {\r\n\tconst { rows } = dims();\r\n\tif (rows === S.rows) {\r\n\t\tpaint();\r\n\t\treturn;\r\n\t}\r\n\t// Height changed: old chrome rows are stale, so start from a clean screen.\r\n\tS.rows = rows;\r\n\tS.savedValid = false;\r\n\tout.write(`${CSI}2J${CSI}H`);\r\n\tapplyRegion();\r\n\tout.write(chromeString() + `${CSI}${regionBottom()};1H`);\r\n\tif (S.editing) paint();\r\n}\r\n\r\n// =============================================================================\r\n// Screen lifecycle\r\n// =============================================================================\r\n\r\nexport function initScreen(info: { model: string; project: string }): void {\r\n\tS.model = info.model;\r\n\tS.project = info.project;\r\n\tif (S.active || !layoutSupported()) return;\r\n\r\n\tS.active = true;\r\n\tS.rows = dims().rows;\r\n\tout.write(`${CSI}2J${CSI}H`);\r\n\tapplyRegion();\r\n\tout.write(chromeString() + `${CSI}1;1H`);\r\n\tout.on('resize', onResize);\r\n\tprocess.on('exit', teardownScreen);\r\n}\r\n\r\nexport function setScreenStatus(info: { model?: string; project?: string }): void {\r\n\tif (info.model !== undefined) S.model = info.model;\r\n\tif (info.project !== undefined) S.project = info.project;\r\n\tpaint();\r\n}\r\n\r\n/** Clear everything and start output again from the top (used by /clear). */\r\nexport function resetScreen(): void {\r\n\tout.write(`${CSI}2J${CSI}H`);\r\n\tif (!S.active) return;\r\n\tapplyRegion();\r\n\tout.write(chromeString() + `${CSI}1;1H`);\r\n}\r\n\r\nexport function teardownScreen(): void {\r\n\tif (!S.active) return;\r\n\tS.active = false;\r\n\r\n\tconst { rows } = dims();\r\n\tconst first = Math.max(1, rows - CHROME_ROWS + 1);\r\n\tlet wipe = '';\r\n\tfor (let r = first; r <= rows; r++) wipe += `${CSI}${r};1H${CSI}2K`;\r\n\r\n\t// Leave the shell prompt right after the last output line.\r\n\tconst head = S.editing ? '' : SAVE;\r\n\tconst back = S.editing && !S.savedValid ? `${CSI}${first};1H` : RESTORE;\r\n\tout.write(head + CSI + 'r' + wipe + back + CSI + '?25h' + CSI + '?2004l');\r\n}\r\n\r\n// =============================================================================\r\n// Key parsing\r\n// =============================================================================\r\n\r\nexport interface Key {\r\n\tname: string;\r\n\ttext?: string;\r\n}\r\n\r\n// eslint-disable-next-line no-control-regex\r\nconst TOKEN_RE = /\\x1b\\[200~|\\x1b\\[201~|\\x1b\\[[0-9;?]*[ -/]*[@-~]|\\x1bO[A-Za-z]|\\x1b[\\s\\S]|[\\s\\S]/gu;\r\n\r\nconst NAMED: Record<string, string> = {\r\n\t'\\r': 'enter',\r\n\t'\\n': 'enter',\r\n\t'\\x03': 'ctrl+c',\r\n\t'\\x04': 'ctrl+d',\r\n\t'\\x7f': 'backspace',\r\n\t'\\b': 'backspace',\r\n\t'\\t': 'tab',\r\n\t'\\x1b': 'escape',\r\n\t'\\x01': 'home',\r\n\t'\\x05': 'end',\r\n\t'\\x15': 'ctrl+u',\r\n\t'\\x0b': 'ctrl+k',\r\n\t'\\x17': 'ctrl+w',\r\n\t'\\x0c': 'ctrl+l',\r\n\t'\\x1b[A': 'up',\r\n\t'\\x1bOA': 'up',\r\n\t'\\x1b[B': 'down',\r\n\t'\\x1bOB': 'down',\r\n\t'\\x1b[C': 'right',\r\n\t'\\x1bOC': 'right',\r\n\t'\\x1b[D': 'left',\r\n\t'\\x1bOD': 'left',\r\n\t'\\x1b[H': 'home',\r\n\t'\\x1bOH': 'home',\r\n\t'\\x1b[1~': 'home',\r\n\t'\\x1b[F': 'end',\r\n\t'\\x1bOF': 'end',\r\n\t'\\x1b[4~': 'end',\r\n\t'\\x1b[3~': 'delete',\r\n\t'\\x1b[5~': 'pageup',\r\n\t'\\x1b[6~': 'pagedown',\r\n\t'\\x1b[1;5D': 'word-left',\r\n\t'\\x1b[1;3D': 'word-left',\r\n\t'\\x1bb': 'word-left',\r\n\t'\\x1b[1;5C': 'word-right',\r\n\t'\\x1b[1;3C': 'word-right',\r\n\t'\\x1bf': 'word-right',\r\n\t'\\x1b\\x7f': 'ctrl+w',\r\n};\r\n\r\n/**\r\n * Split a stdin chunk into keys. Consecutive printable characters are merged\r\n * into one `text` key, and bracketed pastes arrive as a single `paste` key.\r\n * `state.paste` carries an unfinished paste across chunks.\r\n */\r\nexport function parseKeys(chunk: string, state: { paste: string | null }): Key[] {\r\n\tconst keys: Key[] = [];\r\n\tlet run = '';\r\n\tconst flush = (): void => {\r\n\t\tif (run) keys.push({ name: 'text', text: run });\r\n\t\trun = '';\r\n\t};\r\n\r\n\tfor (const tok of chunk.match(TOKEN_RE) ?? []) {\r\n\t\tif (tok === '\\x1b[200~') {\r\n\t\t\tflush();\r\n\t\t\tstate.paste = '';\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tif (tok === '\\x1b[201~') {\r\n\t\t\tflush();\r\n\t\t\tif (state.paste !== null) keys.push({ name: 'paste', text: state.paste });\r\n\t\t\tstate.paste = null;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tif (state.paste !== null) {\r\n\t\t\tstate.paste += tok;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst named = NAMED[tok];\r\n\t\tif (named) {\r\n\t\t\tflush();\r\n\t\t\tkeys.push({ name: named });\r\n\t\t} else if ((tok.codePointAt(0) ?? 0) >= 0x20 && !tok.startsWith('\\x1b') && tok !== '\\x7f') {\r\n\t\t\trun += tok;\r\n\t\t} else {\r\n\t\t\tflush();\r\n\t\t\tkeys.push({ name: 'unknown' });\r\n\t\t}\r\n\t}\r\n\tflush();\r\n\treturn keys;\r\n}\r\n\r\n/**\r\n * Put stdin in raw mode and call `handler` for every key until the returned\r\n * function is called, which restores the terminal.\r\n */\r\nexport function listenKeys(handler: (key: Key) => void): () => void {\r\n\tconst stdin = process.stdin;\r\n\tconst state = { paste: null as string | null };\r\n\tconst onData = (chunk: string | Buffer): void => {\r\n\t\tfor (const key of parseKeys(chunk.toString(), state)) handler(key);\r\n\t};\r\n\r\n\tstdin.setRawMode?.(true);\r\n\tstdin.resume();\r\n\tstdin.setEncoding('utf8');\r\n\tif (out.isTTY) out.write(`${CSI}?2004h`); // bracketed paste\r\n\tstdin.on('data', onData);\r\n\r\n\treturn () => {\r\n\t\tstdin.off('data', onData);\r\n\t\tif (out.isTTY) out.write(`${CSI}?2004l`);\r\n\t\tstdin.setRawMode?.(false);\r\n\t\tstdin.pause();\r\n\t};\r\n}\r\n\r\n// =============================================================================\r\n// Line editor\r\n// =============================================================================\r\n\r\nfunction wordLeft(s: string, from: number): number {\r\n\tlet i = from;\r\n\twhile (i > 0 && s[i - 1] === ' ') i--;\r\n\twhile (i > 0 && s[i - 1] !== ' ') i--;\r\n\treturn i;\r\n}\r\n\r\nfunction wordRight(s: string, from: number): number {\r\n\tlet i = from;\r\n\twhile (i < s.length && s[i] === ' ') i++;\r\n\twhile (i < s.length && s[i] !== ' ') i++;\r\n\treturn i;\r\n}\r\n\r\n/** Pasted text is kept on one line: newlines become spaces, controls are dropped. */\r\nfunction sanitizePaste(text: string): string {\r\n\treturn [...text.replace(/\\r\\n|\\r|\\n/g, ' ').replace(/\\t/g, ' ')]\r\n\t\t.filter((ch) => (ch.codePointAt(0) ?? 0) >= 0x20 && ch !== '\\x7f')\r\n\t\t.join('');\r\n}\r\n\r\nfunction completeCommand(): void {\r\n\tif (!S.buffer.startsWith('/') || S.buffer.includes(' ')) return;\r\n\tconst typed = S.buffer.toLowerCase();\r\n\tconst names = S.commands.map((cmd) => cmd.name).filter((n) => n.startsWith(typed));\r\n\tconst first = names[0];\r\n\tif (!first) return;\r\n\r\n\tlet prefix = first;\r\n\tfor (const n of names) while (!n.startsWith(prefix)) prefix = prefix.slice(0, -1);\r\n\tS.buffer = prefix;\r\n\tS.cursor = prefix.length;\r\n}\r\n\r\n/** Cooked-mode fallback for non-TTY stdin and terminals too small for the layout. */\r\nfunction plainQuestion(): Promise<string> {\r\n\treturn new Promise((resolve) => {\r\n\t\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\r\n\t\trl.once('close', () => resolve('/exit'));\r\n\t\trl.question('> ', (answer) => {\r\n\t\t\trl.removeAllListeners('close');\r\n\t\t\trl.close();\r\n\t\t\tresolve(answer.trim());\r\n\t\t});\r\n\t});\r\n}\r\n\r\nexport interface InputController {\r\n\tquestion: (prompt?: string) => Promise<string>;\r\n\tclose: () => void;\r\n\tshowPrompt: () => void;\r\n}\r\n\r\nexport function createInput(): InputController {\r\n\tconst history: string[] = [];\r\n\tlet stop: (() => void) | null = null;\r\n\r\n\treturn {\r\n\t\tquestion(): Promise<string> {\r\n\t\t\tif (!S.active) return plainQuestion();\r\n\r\n\t\t\treturn new Promise<string>((resolve) => {\r\n\t\t\t\tlet histIdx = -1;\r\n\t\t\t\tlet draft = '';\r\n\t\t\t\tlet done = false;\r\n\r\n\t\t\t\tS.editing = true;\r\n\t\t\t\tS.savedValid = true;\r\n\t\t\t\tS.buffer = '';\r\n\t\t\t\tS.cursor = 0;\r\n\t\t\t\tS.offset = 0;\r\n\t\t\t\tout.write(SAVE); // remember where output continues\r\n\t\t\t\tpaint();\r\n\r\n\t\t\t\t// Return the cursor to the scrolling region and go idle.\r\n\t\t\t\tconst leave = (): void => {\r\n\t\t\t\t\tdone = true;\r\n\t\t\t\t\tstop?.();\r\n\t\t\t\t\tstop = null;\r\n\t\t\t\t\tS.editing = false;\r\n\t\t\t\t\tS.buffer = '';\r\n\t\t\t\t\tS.cursor = 0;\r\n\t\t\t\t\tS.offset = 0;\r\n\t\t\t\t\tout.write(S.savedValid ? RESTORE : `${CSI}${regionBottom()};1H`);\r\n\t\t\t\t\tpaint();\r\n\t\t\t\t};\r\n\r\n\t\t\t\tconst quit = (): void => {\r\n\t\t\t\t\tleave();\r\n\t\t\t\t\tprocess.emit('SIGINT'); // lets the REPL print its session summary\r\n\t\t\t\t\tprocess.exit(0);\r\n\t\t\t\t};\r\n\r\n\t\t\t\tconst set = (text: string, cursor: number): void => {\r\n\t\t\t\t\tS.buffer = text;\r\n\t\t\t\t\tS.cursor = cursor;\r\n\t\t\t\t\tpaint();\r\n\t\t\t\t};\r\n\r\n\t\t\t\tstop = listenKeys((key) => {\r\n\t\t\t\t\tif (done) return;\r\n\t\t\t\t\tconst { buffer, cursor } = S;\r\n\r\n\t\t\t\t\tswitch (key.name) {\r\n\t\t\t\t\t\tcase 'enter': {\r\n\t\t\t\t\t\t\tconst line = buffer.trim();\r\n\t\t\t\t\t\t\tif (line && history[0] !== line) history.unshift(line);\r\n\t\t\t\t\t\t\tif (history.length > 100) history.pop();\r\n\t\t\t\t\t\t\tleave();\r\n\t\t\t\t\t\t\tresolve(line);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcase 'ctrl+c':\r\n\t\t\t\t\t\t\tif (buffer) {\r\n\t\t\t\t\t\t\t\thistIdx = -1;\r\n\t\t\t\t\t\t\t\tset('', 0);\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tquit();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'ctrl+d':\r\n\t\t\t\t\t\t\tif (!buffer) quit();\r\n\t\t\t\t\t\t\telse set(buffer.slice(0, cursor) + buffer.slice(cursor + 1), cursor);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'backspace':\r\n\t\t\t\t\t\t\tif (cursor > 0) set(buffer.slice(0, cursor - 1) + buffer.slice(cursor), cursor - 1);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'delete':\r\n\t\t\t\t\t\t\tset(buffer.slice(0, cursor) + buffer.slice(cursor + 1), cursor);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'left':\r\n\t\t\t\t\t\t\tset(buffer, Math.max(0, cursor - 1));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'right':\r\n\t\t\t\t\t\t\tset(buffer, Math.min(buffer.length, cursor + 1));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'home':\r\n\t\t\t\t\t\t\tset(buffer, 0);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'end':\r\n\t\t\t\t\t\t\tset(buffer, buffer.length);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'word-left':\r\n\t\t\t\t\t\t\tset(buffer, wordLeft(buffer, cursor));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'word-right':\r\n\t\t\t\t\t\t\tset(buffer, wordRight(buffer, cursor));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'ctrl+u':\r\n\t\t\t\t\t\t\tset(buffer.slice(cursor), 0);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'ctrl+k':\r\n\t\t\t\t\t\t\tset(buffer.slice(0, cursor), cursor);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'ctrl+w': {\r\n\t\t\t\t\t\t\tconst j = wordLeft(buffer, cursor);\r\n\t\t\t\t\t\t\tset(buffer.slice(0, j) + buffer.slice(cursor), j);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcase 'ctrl+l':\r\n\t\t\t\t\t\t\tpaint();\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'tab':\r\n\t\t\t\t\t\t\tcompleteCommand();\r\n\t\t\t\t\t\t\tpaint();\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'up':\r\n\t\t\t\t\t\t\tif (histIdx < history.length - 1) {\r\n\t\t\t\t\t\t\t\tif (histIdx === -1) draft = buffer;\r\n\t\t\t\t\t\t\t\thistIdx++;\r\n\t\t\t\t\t\t\t\tconst entry = history[histIdx] ?? '';\r\n\t\t\t\t\t\t\t\tset(entry, entry.length);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'down':\r\n\t\t\t\t\t\t\tif (histIdx >= 0) {\r\n\t\t\t\t\t\t\t\thistIdx--;\r\n\t\t\t\t\t\t\t\tconst entry = histIdx === -1 ? draft : (history[histIdx] ?? '');\r\n\t\t\t\t\t\t\t\tset(entry, entry.length);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'text':\r\n\t\t\t\t\t\tcase 'paste': {\r\n\t\t\t\t\t\t\tconst text = key.name === 'paste' ? sanitizePaste(key.text ?? '') : (key.text ?? '');\r\n\t\t\t\t\t\t\tif (text) set(buffer.slice(0, cursor) + text + buffer.slice(cursor), cursor + text.length);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tdefault:\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t},\r\n\r\n\t\tclose(): void {\r\n\t\t\tstop?.();\r\n\t\t\tstop = null;\r\n\t\t},\r\n\r\n\t\tshowPrompt(): void {\r\n\t\t\tpaint();\r\n\t\t},\r\n\t};\r\n}\r\n\r\n// =============================================================================\r\n// Picker (arrow keys + type-to-filter), rendered in the scrolling region\r\n// =============================================================================\r\n\r\nexport interface PickItem {\r\n\tvalue: string;\r\n\tlabel: string;\r\n\thint?: string;\r\n}\r\n\r\n/**\r\n * Let the user choose one item. Resolves with its value, or null when cancelled\r\n * (or when there is no interactive terminal). With `allowCustom`, a typed value\r\n * that matches nothing can be chosen as-is.\r\n */\r\nexport function pick(opts: {\r\n\ttitle: string;\r\n\titems: PickItem[];\r\n\tcurrent?: string;\r\n\tallowCustom?: boolean;\r\n}): Promise<string | null> {\r\n\tif (!process.stdin.isTTY || !out.isTTY) return Promise.resolve(null);\r\n\r\n\tconst { rows, cols } = dims();\r\n\tconst visible = Math.max(3, Math.min(10, rows - (S.active ? CHROME_ROWS : 0) - 5));\r\n\tconst height = visible + 3; // title, search, items, footer\r\n\tconst max = cols - 1;\r\n\r\n\tlet filter = '';\r\n\tlet top = 0;\r\n\tlet sel = Math.max(0, opts.items.findIndex((it) => it.value === opts.current));\r\n\r\n\tconst matches = (): PickItem[] => {\r\n\t\tconst words = filter.toLowerCase().split(/\\s+/).filter(Boolean);\r\n\t\tconst list = opts.items.filter((it) => {\r\n\t\t\tconst hay = (it.label + ' ' + (it.hint ?? '')).toLowerCase();\r\n\t\t\treturn words.every((w) => hay.includes(w));\r\n\t\t});\r\n\t\t// Custom IDs look like \"org/name\". The entry goes last, so Enter picks the\r\n\t\t// best filtered match and the custom ID is first only when nothing matches.\r\n\t\tconst typed = filter.trim();\r\n\t\tif (opts.allowCustom && typed.includes('/') && !opts.items.some((it) => it.value === typed)) {\r\n\t\t\tlist.push({ value: typed, label: typed, hint: 'use as typed' });\r\n\t\t}\r\n\t\treturn list;\r\n\t};\r\n\r\n\tconst frame = (): string[] => {\r\n\t\tconst list = matches();\r\n\t\tsel = Math.min(sel, Math.max(0, list.length - 1));\r\n\t\tif (sel < top) top = sel;\r\n\t\tif (sel >= top + visible) top = sel - visible + 1;\r\n\r\n\t\tconst lines: string[] = [\r\n\t\t\tc.bold(clipText(opts.title, max - 16)) + c.dim(` ${list.length} of ${opts.items.length}`),\r\n\t\t\tc.dim(' search \u203A ') + clipText(filter, max - 14) + c.dim('\u258F'),\r\n\t\t];\r\n\t\tfor (let i = 0; i < visible; i++) {\r\n\t\t\tconst it = list[top + i];\r\n\t\t\tif (!it) {\r\n\t\t\t\tlines.push(i === 0 && list.length === 0 ? c.dim(' no matches') : '');\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst isSel = top + i === sel;\r\n\t\t\tconst isCur = it.value === opts.current;\r\n\t\t\tconst label = clipText(it.label, max - 6);\r\n\t\t\tconst room = max - 3 - label.length - (isCur ? 2 : 0) - 2;\r\n\t\t\tconst hint = it.hint && room > 8 ? ' ' + clipText(it.hint, room) : '';\r\n\t\t\tlines.push(\r\n\t\t\t\t(isSel ? c.magenta(' \u203A ') : ' ') +\r\n\t\t\t\t\t(isSel ? c.magenta.bold(label) : label) +\r\n\t\t\t\t\t(isCur ? c.green(' \u2713') : '') +\r\n\t\t\t\t\tc.dim(hint),\r\n\t\t\t);\r\n\t\t}\r\n\t\tlines.push(c.dim(clipText(' \u2191\u2193 move \u00B7 enter select \u00B7 esc cancel \u00B7 type to filter', max)));\r\n\t\treturn lines;\r\n\t};\r\n\r\n\tconst draw = (first: boolean): void => {\r\n\t\tconst body = frame()\r\n\t\t\t.map((l) => `${CSI}2K${l}\\n`)\r\n\t\t\t.join('');\r\n\t\tout.write((first ? '' : `${CSI}${height}A\\r`) + body);\r\n\t};\r\n\r\n\treturn new Promise<string | null>((resolve) => {\r\n\t\tlet done = false;\r\n\t\tlet stop: () => void = () => undefined;\r\n\r\n\t\tconst end = (value: string | null): void => {\r\n\t\t\tdone = true;\r\n\t\t\tstop();\r\n\t\t\t// Remove the picker lines from the scrolling region.\r\n\t\t\tout.write(`${CSI}${height}A\\r${CSI}${height}M${CSI}?25h`);\r\n\t\t\tresolve(value);\r\n\t\t};\r\n\r\n\t\tout.write(CSI + '?25l');\r\n\t\tdraw(true);\r\n\r\n\t\tstop = listenKeys((key) => {\r\n\t\t\tif (done) return;\r\n\t\t\tconst list = matches();\r\n\t\t\tconst resetFilter = (): void => {\r\n\t\t\t\tsel = 0;\r\n\t\t\t\ttop = 0;\r\n\t\t\t};\r\n\r\n\t\t\tswitch (key.name) {\r\n\t\t\t\tcase 'up':\r\n\t\t\t\t\tsel = Math.max(0, sel - 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'down':\r\n\t\t\t\t\tsel = Math.min(Math.max(0, list.length - 1), sel + 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'pageup':\r\n\t\t\t\t\tsel = Math.max(0, sel - visible);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'pagedown':\r\n\t\t\t\t\tsel = Math.min(Math.max(0, list.length - 1), sel + visible);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'home':\r\n\t\t\t\t\tsel = 0;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'end':\r\n\t\t\t\t\tsel = Math.max(0, list.length - 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'backspace':\r\n\t\t\t\t\tfilter = filter.slice(0, -1);\r\n\t\t\t\t\tresetFilter();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'ctrl+u':\r\n\t\t\t\t\tfilter = '';\r\n\t\t\t\t\tresetFilter();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'text':\r\n\t\t\t\tcase 'paste':\r\n\t\t\t\t\tfilter += sanitizePaste(key.text ?? '');\r\n\t\t\t\t\tresetFilter();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'enter':\r\n\t\t\t\t\tend(list[sel]?.value ?? null);\r\n\t\t\t\t\treturn;\r\n\t\t\t\tcase 'escape':\r\n\t\t\t\tcase 'ctrl+c':\r\n\t\t\t\t\tend(null);\r\n\t\t\t\t\treturn;\r\n\t\t\t\tdefault:\r\n\t\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tdraw(false);\r\n\t\t});\r\n\t});\r\n}\r\n", "// =============================================================================\r\n// Agent-Termo \u2014 Main REPL entry point\r\n// =============================================================================\r\n\r\nimport { NimClient } from './llm/client.js';\r\nimport { TOOL_DEFINITIONS } from './llm/tools.js';\r\nimport { executeTool, applyFileChange } from './tools/index.js';\r\nimport { loadMemory, logToTimeline, logAgentTermoTimeline } from './memory/index.js';\r\nimport { loadAllAgents } from './agents/index.js';\r\nimport { buildSystemPrompt } from './agents/index.js';\r\nimport { resolveProjectRoot, saveNimModel } from './utils/config.js';\r\nimport {\r\n\tMarkdownPrinter,\r\n\tprintWelcome,\r\n\tprintUserMessage,\r\n\tprintAssistantMessage,\r\n\tprintToolCall,\r\n\tprintToolResult,\r\n\tprintError,\r\n\tprintSuccess,\r\n\tprintInfo,\r\n\tprintHelp,\r\n\tprintAgentsList,\r\n\tprintMemoryFile,\r\n\tprintTimelineFile,\r\n\tstartSpinner,\r\n\tstopSpinner,\r\n\tclearScreen,\r\n\tcreateInput,\r\n\tinitScreen,\r\n\tpick,\r\n\tsetScreenStatus,\r\n\tpromptAcceptReject,\r\n} from './ui/index.js';\r\nimport type { ConversationMessage, ToolCall, ProposedFileChange } from './types/index.js';\r\n\r\nconst TOOL_KEYWORDS = [\r\n\t'build', 'create', 'write', 'edit', 'modify', 'file', 'code', 'function', 'class',\r\n\t'component', 'debug', 'fix', 'git', 'commit', 'push', 'install', 'npm', 'run',\r\n\t'bash', 'shell', 'command', 'read', 'grep', 'check', 'show', 'implement',\r\n\t'configure', 'setup', 'src', 'package', 'app', 'project', 'api', 'deploy',\r\n\t'test', 'compile', 'typescript', 'javascript', 'python', 'node', 'add', 'delete',\r\n];\r\n\r\n/**\r\n * Tool-capable models to try when the active model rejects the `tools` parameter.\r\n * Ordered by preference; first one that accepts tool calls wins.\r\n */\r\nconst TOOL_MODELS = [\r\n\t'qwen/qwen2.5-coder-32b-instruct',\r\n\t'moonshotai/kimi-k2-instruct',\r\n\t'meta/llama-3.1-405b-instruct',\r\n];\r\n\r\nfunction mightNeedTools(message: string): boolean {\r\n\tconst lower = message.toLowerCase();\r\n\treturn TOOL_KEYWORDS.some((w) => lower.includes(w));\r\n}\r\n\r\nfunction dedup(arr: ToolCall[]): ToolCall[] {\r\n\tconst seen = new Set<string>();\r\n\treturn arr.filter((tc) => {\r\n\t\tif (seen.has(tc.id)) return false;\r\n\t\tseen.add(tc.id);\r\n\t\treturn true;\r\n\t});\r\n}\r\n\r\n/**\r\n * Try each tool-capable model in TOOL_MODELS order until one accepts the\r\n * `tools` parameter. Restores the original model in a finally block.\r\n * Returns the first successful result, or null if all models fail.\r\n */\r\nasync function tryToolModels(\r\n\tconversation: ConversationMessage[],\r\n\tnimClient: NimClient,\r\n\toriginalModel: string,\r\n): Promise<{ content: string; toolCalls: ToolCall[] } | null> {\r\n\tfor (const toolModel of TOOL_MODELS) {\r\n\t\tif (toolModel === originalModel) continue;\r\n\t\ttry {\r\n\t\t\tnimClient.setModel(toolModel);\r\n\t\t\tconst tools = nimClient.buildToolDefs(TOOL_DEFINITIONS);\r\n\t\t\tconst result = await nimClient.complete(conversation, tools);\r\n\t\t\treturn result;\r\n\t\t} catch {\r\n\t\t\t// Try the next model\r\n\t\t}\r\n\t}\r\n\tnimClient.setModel(originalModel);\r\n\treturn null;\r\n}\r\n\r\n/**\r\n * Get a plain-text assistant response without tool calling: stream first, fall\r\n * back to a single non-streaming completion. Appends the assistant message to\r\n * the conversation and prints it. Never throws: if both the stream and the\r\n * retry fail, an LLM error is printed and no message is appended.\r\n */\r\nasync function replyWithText(\r\n\tconversation: ConversationMessage[],\r\n\tnimClient: NimClient,\r\n): Promise<void> {\r\n\tstartSpinner('Thinking');\r\n\tconst md = new MarkdownPrinter(() => stopSpinner());\r\n\ttry {\r\n\t\tconst gen = nimClient.streamComplete(conversation, undefined, (text: string) => md.push(text));\r\n\t\t// The generator streams everything, then yields once at the end; the\r\n\t\t// chunks have already been rendered through the callback.\r\n\t\tawait gen.next();\r\n\t\tmd.end();\r\n\t\tstopSpinner();\r\n\t\treturn;\r\n\t} catch {\r\n\t\tmd.end();\r\n\t\tstopSpinner();\r\n\t}\r\n\r\n\tstartSpinner('Retrying');\r\n\ttry {\r\n\t\tconst result = await nimClient.complete(conversation, undefined);\r\n\t\tstopSpinner();\r\n\t\tconst cleanText = (result.content ?? '').trim();\r\n\t\tif (cleanText) {\r\n\t\t\tconversation.push({\r\n\t\t\t\tid: crypto.randomUUID(),\r\n\t\t\t\trole: 'assistant',\r\n\t\t\t\tcontent: cleanText,\r\n\t\t\t\ttimestamp: new Date(),\r\n\t\t\t});\r\n\t\t\tprintAssistantMessage(cleanText);\r\n\t\t}\r\n\t} catch (err) {\r\n\t\tstopSpinner();\r\n\t\tprintError('LLM error: ' + (err instanceof Error ? err.message : String(err)));\r\n\t}\r\n}\r\n\r\nfunction extractProposedChange(toolName: string, resultOutput: string): ProposedFileChange | undefined {\r\n\tconst isFileTool = toolName === 'file:write' || toolName === 'file:edit';\r\n\tif (!isFileTool) return undefined;\r\n\ttry {\r\n\t\tconst parsed = JSON.parse(resultOutput);\r\n\t\tif (parsed?.needsApproval && parsed?.proposedChange) {\r\n\t\t\treturn parsed.proposedChange as ProposedFileChange;\r\n\t\t}\r\n\t} catch {\r\n\t\t// Not JSON \u2014 tool returned a simple string\r\n\t}\r\n\treturn undefined;\r\n}\r\n\r\ninterface InputController {\r\n\tclose(): void;\r\n\tshowPrompt(): void;\r\n}\r\n\r\n/**\r\n * Open a VS Code diff window for the proposed change.\r\n * Writes original + proposed content to temp files and launches `code --diff`.\r\n */\r\nasync function openVsCodeDiff(change: ProposedFileChange): Promise<void> {\r\n\ttry {\r\n\t\tconst { exec } = await import('node:child_process');\r\n\t\tconst { promisify } = await import('node:util');\r\n\t\tconst { mkdtemp, writeFile } = await import('node:fs/promises');\r\n\t\tconst { basename } = await import('node:path');\r\n\t\tconst { tmpdir } = await import('node:os');\r\n\r\n\t\tconst execAsync = promisify(exec);\r\n\r\n\t\tconst originalPath = change.path;\r\n\t\tconst tmpDir = await mkdtemp(tmpdir() + '/agent-termo-diff-');\r\n\t\tconst tmpFile = tmpDir + '/' + basename(originalPath);\r\n\r\n\t\tawait writeFile(tmpFile, change.proposedContent, 'utf-8');\r\n\r\n\t\t// Write original content to a temp file for diff display\r\n\t\tif (!change.isNewFile && change.originalContent.length > 0) {\r\n\t\t\tconst originalTmp = tmpDir + '/original-' + basename(originalPath);\r\n\t\t\tawait writeFile(originalTmp, change.originalContent, 'utf-8');\r\n\t\t\texecAsync(`code --diff \"${originalTmp}\" \"${tmpFile}\" --wait`).catch(() => {\r\n\t\t\t\t// VS Code not available or user closed \u2014 continue silently\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\t// New file: just open the proposed file\r\n\t\t\texecAsync(`code \"${tmpFile}\" --wait`).catch(() => {\r\n\t\t\t\t// Silently fall back\r\n\t\t\t});\r\n\t\t}\r\n\t} catch {\r\n\t\t// Silently fall back to terminal diff view\r\n\t}\r\n}\r\n\r\nasync function executeToolWithReview(\r\n\ttoolName: string,\r\n\targs: Record<string, unknown>,\r\n\tprojectRoot: string,\r\n\tinput: InputController,\r\n): Promise<{ toolResult: { success: boolean; output?: string; error?: string }; change?: ProposedFileChange; applied: boolean }> {\r\n\tprintToolCall(toolName, args);\r\n\tstartSpinner('Running ' + toolName);\r\n\tconst toolResult = await executeTool(toolName, args, projectRoot);\r\n\tstopSpinner(toolResult.success);\r\n\r\n\tconst proposedChange = extractProposedChange(toolName, toolResult.output ?? '');\r\n\r\n\tif (proposedChange) {\r\n\t\t// Pause REPL input to prevent stale listeners from interfering with promptAcceptReject\r\n\t\tinput.close();\r\n\r\n\t\t// Show terminal diff viewer\r\n\t\tprintToolResult(toolName, { success: toolResult.success, output: toolResult.output, error: toolResult.error }, { needsApproval: true, proposedChange });\r\n\r\n\t\t// Also open VS Code diff window (non-blocking, fire-and-forget)\r\n\t\topenVsCodeDiff(proposedChange);\r\n\r\n\t\tconst decision = await promptAcceptReject('Accept this change?');\r\n\r\n\t\t// Restore input for next REPL iteration\r\n\t\tinput.showPrompt();\r\n\r\n\t\tif (decision === 'accept') {\r\n\t\t\tstartSpinner('Writing to disk');\r\n\t\t\tconst applyResult = await applyFileChange(proposedChange, projectRoot);\r\n\t\t\tstopSpinner(applyResult.success);\r\n\t\t\tif (applyResult.success) {\r\n\t\t\t\tprintSuccess(applyResult.output ?? 'Change applied');\r\n\t\t\t\treturn { toolResult: applyResult, change: proposedChange, applied: true };\r\n\t\t\t} else {\r\n\t\t\t\tprintError(applyResult.error ?? 'Failed to apply change');\r\n\t\t\t\treturn { toolResult: applyResult, change: proposedChange, applied: false };\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tprintInfo('Change rejected \u2014 file was not modified');\r\n\t\t\treturn { toolResult, change: proposedChange, applied: false };\r\n\t\t}\r\n\t}\r\n\r\n\tprintToolResult(toolName, toolResult);\r\n\treturn { toolResult, applied: false };\r\n}\r\n\r\n/**\r\n * Run the tool-call loop: execute tools, feed results back to the LLM,\r\n * and repeat until the LLM stops issuing tool calls.\r\n */\r\nasync function runToolLoop(\r\n\tconversation: ConversationMessage[],\r\n\tprojectRoot: string,\r\n\tinitialToolCalls: ToolCall[],\r\n\tinput: InputController,\r\n\tnimClient: NimClient,\r\n): Promise<string> {\r\n\tlet toolCalls = initialToolCalls;\r\n\tlet finalText = '';\r\n\r\n\t// Continue looping while the LLM keeps issuing tool calls\r\n\twhile (toolCalls.length > 0) {\r\n\t\t// Execute all tool calls from this turn\r\n\t\tfor (const tc of toolCalls) {\r\n\t\t\tconst execution = await executeToolWithReview(tc.name, tc.arguments, projectRoot, input);\r\n\r\n\t\t\tconst toolResult = execution.toolResult;\r\n\t\t\tconst statusText = toolResult.success ? 'OK' : ('ERR: ' + (toolResult.error ? toolResult.error.slice(0, 80) : 'unknown error'));\r\n\t\t\tconst changeNote = execution.change ? (execution.applied ? ' (applied)' : ' (rejected)') : '';\r\n\r\n\t\t\tconversation.push({\r\n\t\t\t\tid: crypto.randomUUID(),\r\n\t\t\t\trole: 'tool',\r\n\t\t\t\tcontent: (toolResult.success ? 'Result: ' : 'Error: ') + (toolResult.success ? (toolResult.output ?? '') : toolResult.error) + changeNote,\r\n\t\t\t\ttimestamp: new Date(),\r\n\t\t\t});\r\n\r\n\t\t\tlogToTimeline(projectRoot, 'Tool: ' + tc.name + ' -- ' + statusText + changeNote);\r\n\t\t\tlogAgentTermoTimeline('Tool: ' + tc.name + ' -- ' + statusText + changeNote);\r\n\t\t}\r\n\r\n\t\t// Send conversation (including tool results) back to the LLM\r\n\t\t// The LLM will either produce text or more tool calls\r\n\t\tstartSpinner('Working');\r\n\t\tlet result: { content: string; toolCalls: ToolCall[] } | null;\r\n\t\ttry {\r\n\t\t\tconst tools = nimClient.buildToolDefs(TOOL_DEFINITIONS);\r\n\t\t\tresult = await nimClient.complete(conversation, tools);\r\n\t\t} catch {\r\n\t\t\t// Model doesn't support native tool calling \u2014 try tool-capable\r\n\t\t\t// models in order, then restore the original model.\r\n\t\t\tconst originalModel = nimClient.getModel();\r\n\t\t\ttry {\r\n\t\t\t\tresult = await tryToolModels(conversation, nimClient, originalModel);\r\n\t\t\t} finally {\r\n\t\t\t\tnimClient.setModel(originalModel);\r\n\t\t\t}\r\n\t\t\tif (!result) {\r\n\t\t\t\tstopSpinner();\r\n\t\t\t\tprintError('LLM error: no tool-capable model available');\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\tstopSpinner();\r\n\r\n\t\tfinalText = result.content;\r\n\t\ttoolCalls = dedup(result.toolCalls);\r\n\r\n\t\t// If the LLM produced text alongside tool calls, save it\r\n\t\tif (finalText && finalText.trim() && finalText.trim() !== 'null') {\r\n\t\t\tconversation.push({\r\n\t\t\t\tid: crypto.randomUUID(),\r\n\t\t\t\trole: 'assistant',\r\n\t\t\t\tcontent: finalText.trim(),\r\n\t\t\t\ttimestamp: new Date(),\r\n\t\t\t});\r\n\t\t\t// Narration that comes with more tool calls is shown now; the\r\n\t\t\t// final answer (no tool calls) is printed by the caller.\r\n\t\t\tif (toolCalls.length > 0) printAssistantMessage(finalText.trim());\r\n\t\t}\r\n\t}\r\n\r\n\treturn finalText;\r\n}\r\n\r\n/**\r\n * /model \u2014 pick from the live NVIDIA NIM catalogue (falls back to a built-in list)\r\n * /model <model-id> \u2014 switch directly, e.g. /model meta/llama-3.3-70b-instruct\r\n */\r\nasync function handleModelCommand(arg: string, nimClient: NimClient, projectRoot: string): Promise<void> {\r\n\tlet selected: string | null = arg || null;\r\n\r\n\tif (!selected) {\r\n\t\tstartSpinner('Fetching NVIDIA NIM models');\r\n\t\tconst { models, live, error } = await nimClient.listModels();\r\n\t\tstopSpinner();\r\n\t\tif (!live) {\r\n\t\t\tprintInfo('Could not fetch the live model list (' + (error ?? 'unknown error') + '). Showing built-in suggestions; you can type any model ID.');\r\n\t\t}\r\n\r\n\t\tselected = await pick({\r\n\t\t\ttitle: 'Select a model',\r\n\t\t\titems: models.map((m) => ({ value: m.id, label: m.id, hint: m.note })),\r\n\t\t\tcurrent: nimClient.getModel(),\r\n\t\t\tallowCustom: true,\r\n\t\t});\r\n\t\tif (!selected) {\r\n\t\t\tprintInfo('Model unchanged: ' + nimClient.getModel());\r\n\t\t\treturn;\r\n\t\t}\r\n\t}\r\n\r\n\tif (selected === nimClient.getModel()) {\r\n\t\tprintInfo('Already using ' + selected);\r\n\t\treturn;\r\n\t}\r\n\r\n\tnimClient.setModel(selected);\r\n\tsetScreenStatus({ model: selected });\r\n\tlogAgentTermoTimeline('Model switched to ' + selected);\r\n\tlogToTimeline(projectRoot, 'Model switched to ' + selected);\r\n\r\n\ttry {\r\n\t\tsaveNimModel(selected);\r\n\t\tprintSuccess('Model set to ' + selected + ' (saved as your default)');\r\n\t} catch {\r\n\t\tprintSuccess('Model set to ' + selected + ' for this session');\r\n\t\tprintInfo('Could not save it as your default.');\r\n\t}\r\n}\r\n\r\nexport async function runRepl(projectRoot?: string): Promise<void> {\r\n\tprojectRoot = resolveProjectRoot(projectRoot);\r\n\r\n\tconst memory = await loadMemory(projectRoot);\r\n\tconst nimClient = new NimClient(projectRoot);\r\n\tconst systemPrompt = buildSystemPrompt(memory, '', projectRoot);\r\n\r\n\tconst session = { id: crypto.randomUUID(), projectRoot, startedAt: new Date() };\r\n\r\n\tconst conversation: ConversationMessage[] = [\r\n\t\t{\r\n\t\t\tid: crypto.randomUUID(),\r\n\t\t\trole: 'system',\r\n\t\t\tcontent: systemPrompt,\r\n\t\t\ttimestamp: new Date(),\r\n\t\t},\r\n\t];\r\n\r\n\tinitScreen({ model: nimClient.getModel(), project: projectRoot });\r\n\tprintWelcome(projectRoot, nimClient.getModel());\r\n\tlogAgentTermoTimeline('Agent-Termo session started. Model: ' + nimClient.getModel());\r\n\tlogToTimeline(projectRoot, 'Agent-Termo session started. Model: ' + nimClient.getModel());\r\n\tlogAgentTermoTimeline('Commands: /help /clear /memory /timeline /model /agents /history');\r\n\tlogToTimeline(projectRoot, 'Commands: /help /clear /memory /timeline /model /agents /history');\r\n\r\n\tconst input = createInput();\r\n\r\n\tconst cleanup = () => {\r\n\t\tinput.close();\r\n\t\tprocess.stdout.write('\\n');\r\n\t\tconsole.log(\r\n\t\t\t'Session complete. ' +\r\n\t\t\tMath.round((Date.now() - session.startedAt.getTime()) / 60000) +\r\n\t\t\t' minutes.',\r\n\t\t);\r\n\t\tprocess.exit(0);\r\n\t};\r\n\tprocess.on('SIGINT', cleanup);\r\n\r\n\tmainLoop: while (true) {\r\n\t\ttry {\r\n\t\t\tconst userInput = await input.question('');\r\n\t\t\tif (!userInput) continue;\r\n\t\t\tif (userInput === 'exit' || userInput === 'quit') {\r\n\t\t\t\tcleanup();\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tif (userInput.startsWith('/')) {\r\n\t\t\t\tconst cmd = userInput.toLowerCase().trim();\r\n\t\t\t\tprintUserMessage(userInput);\r\n\r\n\t\t\t\tif (cmd === '/help' || cmd === '/') {\r\n\t\t\t\t\tprintHelp();\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/clear' || cmd === '/cls') {\r\n\t\t\t\t\tconversation.length = 1;\r\n\t\t\t\t\tclearScreen();\r\n\t\t\t\t\tprintWelcome(projectRoot, nimClient.getModel());\r\n\t\t\t\t\tprintSuccess('Conversation cleared.');\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/memory') {\r\n\t\t\t\t\tawait printMemoryFile();\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/timeline' || cmd === '/tl') {\r\n\t\t\t\t\tawait printTimelineFile();\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/model' || cmd.startsWith('/model ')) {\r\n\t\t\t\t\t// Take the argument from the original text: model IDs are case-sensitive.\r\n\t\t\t\t\tawait handleModelCommand(userInput.trim().slice('/model'.length).trim(), nimClient, projectRoot);\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/agents') {\r\n\t\t\t\t\tconst agents = loadAllAgents(process.env.AGENT_TERMO_DIR || '.claude');\r\n\t\t\t\t\tprintAgentsList(agents);\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/history' || cmd === '/hist') {\r\n\t\t\t\t\tprintInfo('Conversation (excluding system): ' + (conversation.length - 1) + ' messages');\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/exit' || cmd === '/quit') {\r\n\t\t\t\t\tcleanup();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tprintError('Unknown command: ' + cmd, 'Type /help for available commands.');\r\n\t\t\t\tcontinue mainLoop;\r\n\t\t\t}\r\n\r\n\t\t\tconst userMsg: ConversationMessage = {\r\n\t\t\t\tid: crypto.randomUUID(),\r\n\t\t\t\trole: 'user',\r\n\t\t\t\tcontent: userInput,\r\n\t\t\t\ttimestamp: new Date(),\r\n\t\t\t};\r\n\t\t\tconversation.push(userMsg);\r\n\t\t\tprintUserMessage(userInput);\r\n\r\n\t\t\tconst useTools = mightNeedTools(userInput);\r\n\t\t\tconst tools = useTools ? nimClient.buildToolDefs(TOOL_DEFINITIONS) : undefined;\r\n\r\n\t\t\tif (useTools) {\r\n\t\t\t\tstartSpinner('Working');\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst result = await nimClient.complete(conversation, tools);\r\n\t\t\t\t\tconst fullText = result.content;\r\n\t\t\t\t\tlet toolCalls = dedup(result.toolCalls);\r\n\t\t\t\t\tstopSpinner();\r\n\r\n\t\t\t\t\tif (toolCalls.length === 0) {\r\n\t\t\t\t\t\t// No tool calls \u2014 just display the text response\r\n\t\t\t\t\t\tconst cleanText = (fullText ?? '').trim().replace(/^null$/, '').trim();\r\n\t\t\t\t\t\tif (cleanText) {\r\n\t\t\t\t\t\t\tconversation.push({\r\n\t\t\t\t\t\t\t\tid: crypto.randomUUID(),\r\n\t\t\t\t\t\t\t\trole: 'assistant',\r\n\t\t\t\t\t\t\t\tcontent: cleanText,\r\n\t\t\t\t\t\t\t\ttimestamp: new Date(),\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\tprintAssistantMessage(cleanText);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// Show any narration that came with the first tool calls\r\n\t\t\t\t\t\tconst narration = (fullText ?? '').trim().replace(/^null$/, '').trim();\r\n\t\t\t\t\t\tif (narration) printAssistantMessage(narration);\r\n\r\n\t\t\t\t\t\t// Run the tool-call loop: execute tools, feed results back, repeat\r\n\t\t\t\t\t\tconst finalText = await runToolLoop(conversation, projectRoot, toolCalls, input, nimClient);\r\n\t\t\t\t\t\tif (finalText && finalText.trim() && finalText.trim() !== 'null') {\r\n\t\t\t\t\t\t\tprintAssistantMessage(finalText.trim());\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (err) {\r\n\t\t\t\t\tstopSpinner();\r\n\t\t\t\t\t// Tool calling failed (e.g. HTTP 400 because the model does not\r\n\t\t\t\t\t// support the `tools` parameter). Try tool-capable models in order,\r\n\t\t\t\t\t// execute the tools, then restore the original model.\r\n\t\t\t\t\tconst originalModel = nimClient.getModel();\r\n\t\t\t\t\tlet toolResult: { content: string; toolCalls: ToolCall[] } | null = null;\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\ttoolResult = await tryToolModels(conversation, nimClient, originalModel);\r\n\t\t\t\t\t} finally {\r\n\t\t\t\t\t\tnimClient.setModel(originalModel);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (!toolResult) {\r\n\t\t\t\t\t\tconversation.pop();\r\n\t\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tconst fullText = toolResult.content;\r\n\t\t\t\t\tlet toolCalls = dedup(toolResult.toolCalls);\r\n\t\t\t\t\tif (fullText && fullText.trim() && fullText.trim() !== 'null') {\r\n\t\t\t\t\t\tconversation.push({\r\n\t\t\t\t\t\t\tid: crypto.randomUUID(),\r\n\t\t\t\t\t\t\trole: 'assistant',\r\n\t\t\t\t\t\t\tcontent: fullText.trim(),\r\n\t\t\t\t\t\t\ttimestamp: new Date(),\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (toolCalls.length > 0) {\r\n\t\t\t\t\t\tconst narration = fullText.trim().replace(/^null$/, '').trim();\r\n\t\t\t\t\t\tif (narration) printAssistantMessage(narration);\r\n\t\t\t\t\t\tconst finalText = await runToolLoop(conversation, projectRoot, toolCalls, input, nimClient);\r\n\t\t\t\t\t\tif (finalText && finalText.trim() && finalText.trim() !== 'null') {\r\n\t\t\t\t\t\t\tprintAssistantMessage(finalText.trim());\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else if (fullText && fullText.trim()) {\r\n\t\t\t\t\t\tprintAssistantMessage(fullText.trim());\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tawait replyWithText(conversation, nimClient);\r\n\t\t\t}\r\n\r\n\t\t\tif (conversation.length > 42) {\r\n\t\t\t\tconversation.splice(1, conversation.length - 42);\r\n\t\t\t}\r\n\t\t} catch (err) {\r\n\t\t\tstopSpinner();\r\n\t\t\tprintError('Session error: ' + (err instanceof Error ? err.message : String(err)));\r\n\t\t}\r\n\t}\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": ["Command", "OpenAI", "CURATED_MODELS", "NON_CHAT", "isChatModel", "id", "mergeModels", "live", "liveSet", "curated", "m", "curatedIds", "rest", "a", "b", "NimClient", "_projectRoot", "apiKey", "baseUrl", "timeout", "OpenAI", "toolSchemas", "t", "model", "ids", "m", "mergeModels", "err", "messages", "tools", "onChunk", "rawChunks", "toolCallMap", "stream", "chunk", "delta", "rawContent", "tc", "idx", "prev", "finalContent", "toolCalls", "args", "msg", "content", "parsed", "jsonStart", "TOOL_DEFINITIONS", "readFileAsync", "writeFileAsync", "resolve", "isAbsolute", "relative", "execAsync", "promisify", "globAsync", "simpleGit", "statSync", "existsSync", "mkdirSync", "chmodSync", "mkdirSync", "readFileSync", "writeFileSync", "resolve", "dirname", "fileURLToPath", "getProjectRoot", "thisFile", "loadEnvFile", "envPath", "content", "line", "trimmed", "eqIdx", "key", "value", "PROJECT_ROOT", "getAgentTermoDir", "envDir", "resolve", "readStoredConfig", "existing", "readFileSync", "updateStoredConfig", "patch", "configDir", "configPath", "storedConfig", "mkdirSync", "writeFileSync", "chmodSync", "loadStoredNimApiKey", "nimApiKey", "loadStoredNimModel", "nimModel", "saveNimApiKey", "apiKey", "saveNimModel", "model", "getConfig", "projectRoot", "loadEnvFile", "resolveProjectRoot", "cwd", "PROJECT_ROOT", "computeDiff", "original", "proposed", "originalLines", "proposedLines", "content", "i", "m", "n", "stride", "table", "get", "j", "set", "val", "ops", "backtrackLCS", "diffLines", "opsToDiffLines", "additions", "deletions", "line", "a", "b", "lines", "originalLineNum", "proposedLineNum", "op", "exec", "promisify", "execAsync", "globPromise", "globAsync", "TOOL_MAP", "toolFileRead", "toolFileWrite", "toolFileEdit", "toolFileGlob", "toolGrep", "toolBash", "toolGitStatus", "toolGitCommit", "toolGitPush", "toolGitLog", "executeTool", "name", "args", "projectRoot", "start", "id", "fn", "TOOL_MAP", "err", "toProjectPath", "path", "isAbsolute", "resolve", "withinProject", "resolved", "rel", "relative", "proposeFileChange", "proposedContent", "changeType", "oldContent", "fullPath", "originalContent", "isNewFile", "existsSync", "isDeletion", "diff", "computeDiff", "change", "lineCount", "summary", "result", "applyFileChange", "writeFileAsync", "dir", "mkdirSync", "toolFileRead", "limit", "offset", "statSync", "lines", "readFileAsync", "sliced", "toolFileWrite", "content", "toolFileEdit", "oldString", "newString", "existingContent", "newContent", "toolFileGlob", "globPattern", "cwd", "files", "globPromise", "toolGrep", "pattern", "caseSensitive", "flags", "includeFlag", "cmd", "stdout", "stderr", "exec", "DANGEROUS_PATTERNS", "toolBash", "command", "timeout", "getConfig", "errorObj", "toolGitStatus", "status", "simpleGit", "tracking", "toolGitCommit", "message", "git", "toolGitPush", "toolGitLog", "readFile", "appendFile", "writeFile", "existsSync", "mkdirSync", "resolve", "ensureAgentTermoDir", "dir", "AGENT_TERMO_MEMORY_PATH", "loadAgentTermoMemory", "AGENT_TERMO_TIMELINE_PATH", "resolve", "ensureAgentTermoDir", "loadAgentTermoTimeline", "existsSync", "readFile", "logAgentTermoTimeline", "message", "entry", "appendFile", "loadMemory", "projectRoot", "path", "logToTimeline", "projectRoot", "message", "path", "resolve", "timestamp", "appendFile", "readdirSync", "readFileSync", "resolve", "parseAgentMeta", "content", "descMatch", "toolsStr", "tools", "t", "loadAllAgents", "agentDir", "agentsDir", "resolve", "readdirSync", "f", "file", "agentId", "content", "readFileSync", "meta", "parseAgentMeta", "withoutFrontmatter", "a", "b", "SYSTEM_BASE", "buildSystemPrompt", "memory", "timeline", "_agentDir", "prompt", "Chalk", "Chalk", "createInterface", "c", "out", "CSI", "SAVE", "RESTORE", "CHROME_ROWS", "MIN_ROWS", "MIN_COLS", "PLACEHOLDER", "S", "setCommands", "commands", "dims", "terminalWidth", "clipText", "text", "max", "shortPath", "p", "home", "layoutSupported", "statusLine", "typed", "hits", "cmd", "only", "h", "hint", "modelPart", "roomWithHint", "showHint", "projPart", "gap", "chromeString", "rows", "cols", "width", "edge", "body", "top", "line", "row", "inputCursor", "paint", "regionBottom", "applyRegion", "onResize", "initScreen", "info", "teardownScreen", "setScreenStatus", "resetScreen", "first", "wipe", "r", "head", "back", "TOKEN_RE", "NAMED", "parseKeys", "chunk", "state", "keys", "run", "flush", "tok", "named", "listenKeys", "handler", "stdin", "onData", "key", "wordLeft", "s", "from", "i", "wordRight", "sanitizePaste", "ch", "completeCommand", "names", "n", "prefix", "plainQuestion", "resolve", "rl", "answer", "createInput", "history", "stop", "histIdx", "draft", "done", "leave", "quit", "set", "cursor", "buffer", "j", "entry", "pick", "opts", "visible", "height", "filter", "sel", "it", "matches", "words", "list", "hay", "w", "frame", "lines", "isSel", "isCur", "label", "room", "draw", "l", "end", "value", "resetFilter", "c", "Chalk", "out", "COMMANDS", "setCommands", "ANSI_RE", "visibleLength", "s", "rule", "terminalWidth", "printWelcome", "projectRoot", "model", "inner", "room", "row", "content", "field", "label", "value", "clipText", "inline", "text", "seg", "_m", "g", "MarkdownPrinter", "beforeFirstOutput", "nl", "line", "blank", "prefix", "fence", "heading", "bullet", "numbered", "quote", "printUserMessage", "lines", "l", "printAssistantMessage", "md", "printToolCall", "toolName", "args", "summary", "k", "v", "raw", "printToolResult", "result", "parsedOutput", "printDiffViewer", "message", "change", "diff", "color", "num", "promptAcceptReject", "resolve", "done", "stop", "answer", "accepted", "listenKeys", "key", "first", "printError", "hint", "printSuccess", "printInfo", "printMemoryFile", "mem", "loadAgentTermoMemory", "printTimelineFile", "tl", "loadAgentTermoTimeline", "recentCount", "printHelp", "cmd", "keys", "d", "printAgentsList", "agents", "a", "FRAMES", "spinnerTimer", "startSpinner", "stopSpinner", "startedAt", "frame", "render", "secs", "_success", "clearScreen", "resetScreen", "TOOL_KEYWORDS", "TOOL_MODELS", "mightNeedTools", "message", "lower", "w", "dedup", "arr", "seen", "tc", "tryToolModels", "conversation", "nimClient", "originalModel", "toolModel", "tools", "TOOL_DEFINITIONS", "replyWithText", "startSpinner", "md", "MarkdownPrinter", "stopSpinner", "text", "result", "cleanText", "printAssistantMessage", "err", "printError", "extractProposedChange", "toolName", "resultOutput", "parsed", "openVsCodeDiff", "change", "exec", "promisify", "mkdtemp", "writeFile", "basename", "tmpdir", "execAsync", "originalPath", "tmpDir", "tmpFile", "originalTmp", "executeToolWithReview", "args", "projectRoot", "input", "printToolCall", "toolResult", "executeTool", "proposedChange", "printToolResult", "decision", "promptAcceptReject", "applyResult", "applyFileChange", "printSuccess", "printInfo", "runToolLoop", "initialToolCalls", "toolCalls", "finalText", "execution", "statusText", "changeNote", "logToTimeline", "logAgentTermoTimeline", "handleModelCommand", "arg", "selected", "models", "live", "error", "pick", "m", "setScreenStatus", "saveNimModel", "runRepl", "resolveProjectRoot", "memory", "loadMemory", "NimClient", "systemPrompt", "buildSystemPrompt", "session", "initScreen", "printWelcome", "createInput", "cleanup", "mainLoop", "userInput", "cmd", "printUserMessage", "printHelp", "clearScreen", "printMemoryFile", "printTimelineFile", "agents", "loadAllAgents", "printAgentsList", "userMsg", "useTools", "fullText", "narration", "program", "Command", "promptForApiKey", "input", "output", "resolve", "reject", "apiKey", "previousWasCarriageReturn", "restoreTerminal", "onData", "data", "char", "startAgent", "project", "options", "saveNimApiKey", "runRepl", "dir", "mkdirSync", "writeFileSync", "existsSync", "dirsToCreate", "d", "memoryPath", "timelinePath", "main", "err"]
4
+ "sourcesContent": ["#!/usr/bin/env node\r\n// =============================================================================\r\n// CLI Entry Point \u2014 Agent-Termo\r\n// =============================================================================\r\n\r\nimport { Command } from 'commander';\r\nimport { runRepl } from './main.js';\r\nimport { saveNimApiKey } from './utils/config.js';\r\n\r\nconst program = new Command();\r\n\r\nasync function promptForApiKey(): Promise<string> {\r\n const input = process.stdin;\r\n const output = process.stdout;\r\n\r\n if (!input.isTTY || typeof input.setRawMode !== 'function') {\r\n throw new Error(\r\n 'NVIDIA NIM API key is missing. Run Agent-Termo in an interactive terminal or set NIM_API_KEY before starting.',\r\n );\r\n }\r\n\r\n console.log('An NVIDIA NIM API key is required to start Agent-Termo.');\r\n console.log('Get your key at https://build.nvidia.com/');\r\n output.write('Enter your API key (input hidden): ');\r\n\r\n return new Promise((resolve, reject) => {\r\n let apiKey = '';\r\n let previousWasCarriageReturn = false;\r\n\r\n const restoreTerminal = () => {\r\n input.off('data', onData);\r\n input.setRawMode(false);\r\n input.pause();\r\n output.write('\\n');\r\n };\r\n\r\n const onData = (data: Buffer) => {\r\n for (const char of data.toString('utf-8')) {\r\n if (char === '\\n' && previousWasCarriageReturn) {\r\n previousWasCarriageReturn = false;\r\n continue;\r\n }\r\n previousWasCarriageReturn = char === '\\r';\r\n\r\n if (char === '\\u0003' || char === '\\u0004') {\r\n restoreTerminal();\r\n reject(new Error('API key setup cancelled.'));\r\n return;\r\n }\r\n\r\n if (char === '\\r' || char === '\\n') {\r\n if (!apiKey.trim()) {\r\n output.write('\\nAn API key is required. Enter your API key: ');\r\n continue;\r\n }\r\n\r\n restoreTerminal();\r\n resolve(apiKey.trim());\r\n return;\r\n }\r\n\r\n if (char === '\\u007f' || char === '\\b') {\r\n apiKey = apiKey.slice(0, -1);\r\n } else if (char >= ' ') {\r\n apiKey += char;\r\n }\r\n }\r\n };\r\n\r\n input.setRawMode(true);\r\n input.resume();\r\n input.on('data', onData);\r\n });\r\n}\r\n\r\nasync function startAgent(\r\n project: string,\r\n options: { apiKey?: string; model?: string; debug?: boolean },\r\n): Promise<void> {\r\n // Apply CLI overrides to env before main initializes.\r\n if (options.apiKey) process.env.NIM_API_KEY = options.apiKey;\r\n if (options.model) process.env.NIM_MODEL = options.model;\r\n if (options.debug) process.env.LOG_LEVEL = 'debug';\r\n\r\n if (!process.env.NIM_API_KEY?.trim()) {\r\n const apiKey = await promptForApiKey();\r\n saveNimApiKey(apiKey);\r\n process.env.NIM_API_KEY = apiKey;\r\n console.log('API key saved. Agent-Termo will remember it for future sessions.');\r\n }\r\n\r\n console.log(`Starting Agent-Termo in: ${project}`);\r\n await runRepl(project);\r\n}\r\n\r\nprogram\r\n .name('agent-termo')\r\n .description('Terminal AI coding agent with Nvidia NIM APIs')\r\n .version('1.0.3')\r\n .argument('[project]', 'Project directory to operate in', process.cwd())\r\n .option('-k, --api-key <key>', 'Nvidia NIM API key')\r\n .option('-m, --model <model>', 'Model name to use')\r\n .option('--debug', 'Enable debug logging')\r\n .action(async (project: string, options: { apiKey?: string; model?: string; debug?: boolean }) => {\r\n await startAgent(project, options);\r\n });\r\n\r\nprogram\r\n .command('init')\r\n .description('Initialize Agent-Termo in a project directory')\r\n .argument('[dir]', 'Directory to initialize', '.')\r\n .action(async (dir: string) => {\r\n const { mkdirSync, writeFileSync, existsSync } = await import('node:fs');\r\n const { resolve } = await import('node:path');\r\n\r\n const dirsToCreate = [resolve(dir, 'docs'), resolve(dir, '.claude', 'agents'), resolve(dir, 'src')];\r\n for (const d of dirsToCreate) {\r\n mkdirSync(d, { recursive: true });\r\n }\r\n\r\n // Create stub docs\r\n const memoryPath = resolve(dir, 'docs', 'MEMORY.md');\r\n if (!existsSync(memoryPath)) {\r\n writeFileSync(memoryPath, '# Project Memory\\n\\n## Project Context\\n(Add project context here)\\n', 'utf-8');\r\n }\r\n\r\n const timelinePath = resolve(dir, 'docs', 'TIMELINE.md');\r\n if (!existsSync(timelinePath)) {\r\n writeFileSync(\r\n timelinePath,\r\n '# Project Timeline\\n\\n## Initialization\\n- [date] Agent-Termo initialized\\n',\r\n 'utf-8',\r\n );\r\n }\r\n\r\n console.log(`\\n\u2713 Initialized Agent-Termo in ${resolve(dir)}`);\r\n console.log(' Created: docs/MEMORY.md, docs/TIMELINE.md');\r\n console.log(' Agent-Termo will ask for your NVIDIA NIM API key the first time you launch it.');\r\n });\r\n\r\nasync function main() {\r\n // Run REPL mode directly when no command or options are supplied.\r\n const args = process.argv.slice(2);\r\n if (args.length === 0) {\r\n await startAgent(process.cwd(), {});\r\n return;\r\n }\r\n\r\n await program.parseAsync(process.argv);\r\n}\r\n\r\nmain().catch((err) => {\r\n console.error(`\\nFatal error: ${err instanceof Error ? err.message : err}`);\r\n process.exit(1);\r\n});\r\n", "// =============================================================================\r\n// Nvidia NIM LLM Client \u2014 Stepfun + OpenAI-compatible models\r\n// =============================================================================\r\n\r\nimport OpenAI from 'openai';\r\nimport type { ToolCall, ConversationMessage, ToolDef } from '../types/index.js';\r\nimport { mergeModels, type ModelInfo } from './models.js';\r\n\r\ntype NIMTool = OpenAI.Chat.ChatCompletionTool;\r\n\r\nconst TOOL_NAME_ALIASES: Record<string, string> = {\r\n\t'file:read': 'file_read',\r\n\t'file:write': 'file_write',\r\n\t'file:edit': 'file_edit',\r\n\t'file:delete': 'file_delete',\r\n\t'file:glob': 'file_glob',\r\n\t'bash:execute': 'bash_execute',\r\n\t'git:status': 'git_status',\r\n\t'git:commit': 'git_commit',\r\n\t'git:push': 'git_push',\r\n\t'git:log': 'git_log',\r\n};\r\n\r\nexport function toWireToolName(name: string): string {\r\n\treturn TOOL_NAME_ALIASES[name] ?? name.replace(/:/g, '_');\r\n}\r\n\r\nexport function fromWireToolName(name: string): string {\r\n\treturn Object.entries(TOOL_NAME_ALIASES).find(([, wireName]) => wireName === name)?.[0] ?? name;\r\n}\r\n\r\nexport class NimClient {\r\n private client: OpenAI;\r\n private model: string;\r\n\r\n constructor(_projectRoot?: string) {\r\n const apiKey = process.env.NIM_API_KEY ?? '';\r\n const baseUrl = process.env.NIM_BASE_URL ?? 'https://integrate.api.nvidia.com/v1';\r\n this.model = process.env.NIM_MODEL ?? 'stepfun-ai/step-3.7-flash';\r\n const timeout = parseInt(process.env.LLM_TIMEOUT ?? '120000', 10);\r\n\r\n this.client = new OpenAI({\r\n apiKey,\r\n baseURL: baseUrl,\r\n timeout,\r\n defaultHeaders: { 'User-Agent': 'agent-termo/1.0' },\r\n });\r\n }\r\n\r\n buildToolDefs(toolSchemas: ToolDef[]): NIMTool[] {\r\n return toolSchemas.map((t) => ({\r\n type: 'function' as const,\r\n function: {\r\n\t\t\tname: toWireToolName(t.name),\r\n description: t.description,\r\n parameters: t.parameters as unknown as NIMTool['function']['parameters'],\r\n },\r\n })) as NIMTool[];\r\n }\r\n\r\n getModel(): string {\r\n return this.model;\r\n }\r\n\r\n setModel(model: string): void {\r\n this.model = model;\r\n }\r\n\r\n /**\r\n * Fetch the models this API key can use. Never throws: on failure the curated\r\n * list is returned with `live: false` and the reason in `error`.\r\n */\r\n async listModels(): Promise<{ models: ModelInfo[]; live: boolean; error?: string }> {\r\n try {\r\n const page = await this.client.models.list({ timeout: 10_000 });\r\n const ids = page.data.map((m) => m.id);\r\n if (ids.length === 0) throw new Error('empty model list');\r\n return { models: mergeModels(ids), live: true };\r\n } catch (err) {\r\n return {\r\n models: mergeModels(null),\r\n live: false,\r\n error: err instanceof Error ? err.message : String(err),\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Streaming chat completion.\r\n * Handles Stepfun's quirks: filters \"null\" reasoning chunks, strips reasoning field.\r\n * Yields { content, toolCalls } at the end with clean text.\r\n */\r\n\tasync *streamComplete(\r\n messages: ConversationMessage[],\r\n tools?: NIMTool[],\r\n onChunk?: (text: string) => void,\r\n ): AsyncGenerator<{ content: string; toolCalls: ToolCall[] }, void, unknown> {\r\n const rawChunks: string[] = [];\r\n const toolCallMap: Map<number, { id: string; name: string; arguments: string }> = new Map();\r\n\r\n const stream = await this.client.chat.completions.create({\r\n model: this.model,\r\n\t\tmessages: messages.map((m) => {\r\n\t\t\tif (m.role === 'tool') {\r\n\t\t\t\treturn {\r\n\t\t\t\t\trole: 'tool' as const,\r\n\t\t\t\t\tcontent: m.content,\r\n\t\t\t\t\ttool_call_id: m.id,\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\tif (m.role === 'assistant' && m.toolCalls?.length) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\trole: 'assistant' as const,\r\n\t\t\t\t\tcontent: m.content || null,\r\n\t\t\t\t\ttool_calls: m.toolCalls.map((tc) => ({\r\n\t\t\t\t\t\tid: tc.id,\r\n\t\t\t\t\t\ttype: 'function' as const,\r\n\t\t\t\t\t\tfunction: { name: toWireToolName(tc.name), arguments: JSON.stringify(tc.arguments) },\r\n\t\t\t\t\t})),\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\treturn {\r\n role: m.role as 'system' | 'user' | 'assistant',\r\n content: m.content,\r\n };\r\n }),\r\n tools: tools,\r\n temperature: 0.3,\r\n max_tokens: 8192,\r\n stream: true,\r\n });\r\n\r\n for await (const chunk of stream) {\r\n const delta = chunk.choices[0]?.delta;\r\n\r\n if (!delta) continue;\r\n\r\n // Text delta \u2014 filter out \"null\" chunks (Stepfun's reasoning output)\r\n const rawContent = delta.content ?? '';\r\n // Check: if it's the literal string \"null\", it's reasoning noise \u2014 skip it\r\n const isNoise = rawContent === 'null' || rawContent === 'undefined';\r\n if (!isNoise && rawContent) {\r\n rawChunks.push(rawContent);\r\n onChunk?.(rawContent);\r\n }\r\n\r\n // Tool call deltas (accumulate across chunks via index)\r\n if (delta.tool_calls) {\r\n for (const tc of delta.tool_calls) {\r\n const idx = tc.index ?? 0;\r\n const prev = toolCallMap.get(idx);\r\n if (!prev) {\r\n toolCallMap.set(idx, {\r\n id: tc.id ?? crypto.randomUUID(),\r\n name: tc.function?.name ?? '',\r\n arguments: tc.function?.arguments ?? '',\r\n });\r\n } else {\r\n prev.arguments += tc.function?.arguments ?? '';\r\n if (tc.id && !prev.id) prev.id = tc.id;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // For streaming: content is accumulated in rawChunks (null chunks already filtered)\r\n // For non-streaming (complete() method): reasoning stripping happens in that method\r\n const finalContent = rawChunks.join('');\r\n\r\n // Extract tool calls\r\n const toolCalls: ToolCall[] = Array.from(toolCallMap.values()).map((tc) => {\r\n let args: Record<string, unknown> = {};\r\n try {\r\n args = JSON.parse(tc.arguments);\r\n } catch {\r\n args = { _raw: tc.arguments };\r\n }\r\n\t\t\treturn { id: tc.id, name: fromWireToolName(tc.name), arguments: args };\r\n });\r\n\r\n yield { content: finalContent, toolCalls };\r\n }\r\n\r\n /**\r\n * Non-streaming completion \u2014 for when streaming fails or for retries.\r\n */\r\n async complete(\r\n messages: ConversationMessage[],\r\n tools?: NIMTool[],\r\n ): Promise<{ content: string; toolCalls: ToolCall[] }> {\r\n const response = await this.client.chat.completions.create({\r\n model: this.model,\r\n\t\tmessages: messages.map((m) => {\r\n\t\t\tif (m.role === 'tool') {\r\n\t\t\t\treturn { role: 'tool' as const, content: m.content, tool_call_id: m.id };\r\n\t\t\t}\r\n\t\t\tif (m.role === 'assistant' && m.toolCalls?.length) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\trole: 'assistant' as const,\r\n\t\t\t\t\tcontent: m.content || null,\r\n\t\t\t\t\ttool_calls: m.toolCalls.map((tc) => ({\r\n\t\t\t\t\t\tid: tc.id,\r\n\t\t\t\t\t\ttype: 'function' as const,\r\n\t\t\t\t\t\tfunction: { name: toWireToolName(tc.name), arguments: JSON.stringify(tc.arguments) },\r\n\t\t\t\t\t})),\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\treturn { role: m.role as 'system' | 'user' | 'assistant', content: m.content };\r\n }),\r\n tools: tools,\r\n temperature: 0.3,\r\n max_tokens: 8192,\r\n stream: false,\r\n });\r\n\r\n const msg = response.choices[0]?.message;\r\n // Strip reasoning noise\r\n let content =\r\n msg?.content?.replace(\r\n /\\[ Reasoning[^\\]]*\\][^\\[]*\\[\\/ Reasoning\\][^\\n]*/gi,\r\n '',\r\n ).trim() ?? '';\r\n\r\n const toolCalls: ToolCall[] = (msg?.tool_calls ?? []).map((tc) => {\r\n let args: Record<string, unknown> = {};\r\n try {\r\n args = JSON.parse(tc.function.arguments ?? '{}');\r\n } catch {\r\n args = { _raw: tc.function.arguments };\r\n }\r\n\t\t\treturn { id: tc.id, name: fromWireToolName(tc.function.name), arguments: args };\r\n });\r\n\r\n // If no tool calls but content looks like a tool call request, parse it\r\n if (toolCalls.length === 0 && content.includes('\"tool_calls\"')) {\r\n try {\r\n const parsed = JSON.parse(content);\r\n if (parsed.tool_calls?.length) {\r\n toolCalls.push(...parsed.tool_calls.map((tc: { id?: string; name?: string; function?: { name?: string; arguments?: unknown } }) => ({\r\n id: tc.id ?? crypto.randomUUID(),\r\n\t\t\t\tname: fromWireToolName(tc.function?.name ?? tc.name ?? ''),\r\n arguments: typeof tc.function?.arguments === 'string'\r\n ? JSON.parse(tc.function.arguments)\r\n : tc.function?.arguments ?? {},\r\n })));\r\n // Remove JSON from content\r\n const jsonStart = content.indexOf('{\"tool_calls\"');\r\n if (jsonStart !== -1) content = content.slice(0, jsonStart).trim();\r\n }\r\n } catch {\r\n // Not valid JSON \u2014 leave as-is\r\n }\r\n }\r\n\r\n return { content, toolCalls };\r\n }\r\n}\r\n\r\nexport { type ToolDef } from '../types/index.js';\r\n", "// =============================================================================\r\n// NVIDIA NIM model catalogue \u2014 curated suggestions + live /v1/models merge\r\n// =============================================================================\r\n\r\nexport interface ModelInfo {\r\n id: string;\r\n note?: string;\r\n}\r\n\r\n/**\r\n * Hand-picked chat/coding models worth surfacing first. This list is only a\r\n * starting point: when the live catalogue is reachable, entries NIM no longer\r\n * serves are dropped, and everything else NIM returns is still selectable.\r\n */\r\nexport const CURATED_MODELS: ModelInfo[] = [\r\n { id: 'stepfun-ai/step-3.7-flash', note: 'default' },\r\n { id: 'meta/llama-3.1-8b-instruct', note: 'fast, low cost' },\r\n { id: 'meta/llama-3.1-70b-instruct', note: 'balanced' },\r\n { id: 'meta/llama-3.3-70b-instruct', note: 'balanced' },\r\n { id: 'meta/llama-3.1-405b-instruct', note: 'highest quality Llama' },\r\n { id: 'nvidia/llama-3.1-nemotron-70b-instruct', note: 'NVIDIA tuned' },\r\n { id: 'qwen/qwen2.5-coder-32b-instruct', note: 'coding' },\r\n { id: 'deepseek-ai/deepseek-r1', note: 'reasoning' },\r\n { id: 'moonshotai/kimi-k2-instruct', note: 'agentic / tool use' },\r\n { id: 'openai/gpt-oss-120b', note: 'open-weight GPT' },\r\n];\r\n\r\n// NIM serves embedding, vision, speech and other non-chat models from the same\r\n// endpoint. Hide the obvious ones so the picker stays about chat models.\r\nconst NON_CHAT =\r\n /embed|rerank|retriev|reward|guard|safety|parse|clip|vila|neva|fuyu|kosmos|paligemma|deplot|riva|asr|tts|whisper|diffusion|sdxl|flux|cosmos|segment|bge-|e5-|gliner|pii|streampetr|ocdrnet|bevformer/i;\r\n\r\nexport function isChatModel(id: string): boolean {\r\n return !NON_CHAT.test(id);\r\n}\r\n\r\n/**\r\n * Build the picker list.\r\n * - live === null: the catalogue could not be fetched, so offer the curated list.\r\n * - otherwise: curated entries that NIM serves first, then the rest of the live\r\n * chat models alphabetically.\r\n */\r\nexport function mergeModels(live: string[] | null): ModelInfo[] {\r\n if (!live) return [...CURATED_MODELS];\r\n\r\n const liveSet = new Set(live);\r\n const curated = CURATED_MODELS.filter((m) => liveSet.has(m.id));\r\n const curatedIds = new Set(curated.map((m) => m.id));\r\n const rest = live\r\n .filter((id) => !curatedIds.has(id) && isChatModel(id))\r\n .sort((a, b) => a.localeCompare(b))\r\n .map((id): ModelInfo => ({ id }));\r\n\r\n return [...curated, ...rest];\r\n}\r\n", "// =============================================================================\r\n// Tool Definitions (OpenAI function calling schema)\r\n// These are matched to the actual tools implemented in src/tools/\r\n// =============================================================================\r\n\r\nimport type { ToolDef } from '../types/index.js';\r\n\r\nexport const TOOL_DEFINITIONS: ToolDef[] = [\r\n // \u2500\u2500 File Operations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n {\r\n name: 'file:read',\r\n description: 'Read the complete contents of a file. Use for examining existing code, config, or documentation.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n path: {\r\n type: 'string',\r\n description: 'File path (absolute or relative to project root)',\r\n },\r\n limit: {\r\n type: 'number',\r\n description: 'Maximum number of lines to read (0 = all)',\r\n default: 0,\r\n },\r\n offset: {\r\n type: 'number',\r\n description: 'Line offset to start reading from (0 = start)',\r\n default: 0,\r\n },\r\n },\r\n required: ['path'],\r\n },\r\n },\r\n {\r\n name: 'file:write',\r\n description: 'Write or overwrite a complete file. Use this to create new files or replace existing ones entirely.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n path: {\r\n type: 'string',\r\n description: 'File path to write (relative to project root)',\r\n },\r\n content: {\r\n type: 'string',\r\n description: 'Complete file content to write',\r\n },\r\n },\r\n required: ['path', 'content'],\r\n },\r\n },\r\n {\r\n name: 'file:edit',\r\n description: 'Edit an existing file by replacing an exact section. The old_string must appear verbatim in the file.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n path: {\r\n type: 'string',\r\n description: 'File to edit',\r\n },\r\n old_string: {\r\n type: 'string',\r\n description: 'Exact text to find and replace (must be unique in file)',\r\n },\r\n new_string: {\r\n type: 'string',\r\n description: 'Replacement text',\r\n },\r\n\t\t\t},\r\n\t\t\trequired: ['path', 'old_string', 'new_string'],\r\n\t\t},\r\n\t},\r\n\t{\r\n\t\tname: 'file:delete',\r\n\t\tdescription: 'Delete a file from the project. Use only when the user explicitly asks to remove it.',\r\n\t\tparameters: {\r\n\t\t\ttype: 'object',\r\n\t\t\tproperties: {\r\n\t\t\t\tpath: {\r\n\t\t\t\t\ttype: 'string',\r\n\t\t\t\t\tdescription: 'File path to delete (relative to project root)',\r\n\t\t\t\t},\r\n\t\t\t},\r\n\t\t\trequired: ['path'],\r\n\t\t},\r\n\t},\r\n\t{\r\n\t\tname: 'file:glob',\r\n description: 'Find all files matching a glob pattern. Use to discover project structure.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n pattern: {\r\n type: 'string',\r\n description: 'Glob pattern (e.g. \"src/**/*.ts\", \"**/*.json\")',\r\n },\r\n cwd: {\r\n type: 'string',\r\n description: 'Root directory to search in (defaults to project root)',\r\n },\r\n },\r\n required: ['pattern'],\r\n },\r\n },\r\n {\r\n name: 'grep',\r\n description: 'Search for text or regex patterns inside files. Use to find function definitions, imports, etc.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n pattern: {\r\n type: 'string',\r\n description: 'Text or regex pattern to search for',\r\n },\r\n path: {\r\n type: 'string',\r\n description: 'File or directory to search in',\r\n },\r\n glob: {\r\n type: 'string',\r\n description: 'Only search files matching this glob pattern',\r\n },\r\n case_sensitive: {\r\n type: 'boolean',\r\n description: 'Case sensitive search (default true)',\r\n default: true,\r\n },\r\n },\r\n required: ['pattern', 'path'],\r\n },\r\n },\r\n // \u2500\u2500 Bash \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n {\r\n name: 'bash:execute',\r\n description: 'Execute a shell command and return its stdout/stderr output. Destructive commands (rm, dd) require user confirmation.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n command: {\r\n type: 'string',\r\n description: 'Shell command to execute',\r\n },\r\n cwd: {\r\n type: 'string',\r\n description: 'Working directory (defaults to project root)',\r\n },\r\n timeout: {\r\n type: 'number',\r\n description: 'Timeout in milliseconds (default 300000)',\r\n default: 300000,\r\n },\r\n },\r\n required: ['command'],\r\n },\r\n },\r\n // \u2500\u2500 Git \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n {\r\n name: 'git:status',\r\n description: 'Show the git working tree status (modified, staged, untracked files).',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n cwd: {\r\n type: 'string',\r\n description: 'Repository root (default: project root)',\r\n },\r\n },\r\n },\r\n },\r\n {\r\n name: 'git:commit',\r\n description: 'Stage and commit all changes with a conventional commit message.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n message: {\r\n type: 'string',\r\n description: 'Conventional commit message (e.g. \"feat: add login page\")',\r\n },\r\n cwd: {\r\n type: 'string',\r\n description: 'Repository root (default: project root)',\r\n },\r\n },\r\n required: ['message'],\r\n },\r\n },\r\n {\r\n name: 'git:push',\r\n description: 'Push the current branch to the remote repository.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n cwd: {\r\n type: 'string',\r\n description: 'Repository root (default: project root)',\r\n },\r\n },\r\n },\r\n },\r\n {\r\n name: 'git:log',\r\n description: 'Show recent git commit history.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n cwd: {\r\n type: 'string',\r\n description: 'Repository root (default: project root)',\r\n },\r\n limit: {\r\n type: 'number',\r\n description: 'Number of commits to show (default: 20)',\r\n default: 20,\r\n },\r\n },\r\n },\r\n },\r\n];\r\n", "// =============================================================================\r\n// Agent-Termo Tool Executor \u2014 routes tool calls to implementations\r\n// =============================================================================\r\n\r\nimport { readFile as readFileAsync, writeFile as writeFileAsync, unlink as unlinkAsync } from 'node:fs/promises';\r\nimport { resolve, isAbsolute, relative } from 'node:path';\r\nimport { exec as execAsync } from 'node:child_process';\r\nimport { promisify } from 'node:util';\r\nimport { default as globAsync } from 'glob';\r\nimport { simpleGit } from 'simple-git';\r\nimport { statSync, existsSync, mkdirSync } from 'node:fs';\r\nimport { getConfig } from '../utils/config.js';\r\nimport { computeDiff } from '../diff/index.js';\r\nimport type { ToolResult, ProposedFileChange } from '../types/index.js';\r\n\r\nconst exec = promisify(execAsync);\r\nconst globPromise = promisify(globAsync);\r\n\r\n// \u2500\u2500 Tool map \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst TOOL_MAP: Record<string, (...args: any[]) => Promise<ToolResult>> = {\r\n\t'file:read': toolFileRead,\r\n\t'file:write': toolFileWrite,\r\n\t'file:edit': toolFileEdit,\r\n\t'file:delete': toolFileDelete,\r\n\t'file:glob': toolFileGlob,\r\n\t'grep': toolGrep,\r\n\t'bash:execute': toolBash,\r\n\t'git:status': toolGitStatus,\r\n\t'git:commit': toolGitCommit,\r\n\t'git:push': toolGitPush,\r\n\t'git:log': toolGitLog,\r\n};\r\n\r\n// \u2500\u2500 Re-exported tool definitions for OpenAI schema \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\nexport const TOOL_DEFS = TOOL_MAP;\r\n\r\n// \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nexport async function executeTool(\r\n\tname: string,\r\n\targs: Record<string, unknown>,\r\n\tprojectRoot: string,\r\n): Promise<ToolResult> {\r\n\tconst start = Date.now();\r\n\tconst id = crypto.randomUUID();\r\n\r\n\ttry {\r\n\t\tconst fn = TOOL_MAP[name];\r\n\t\tif (!fn) {\r\n\t\t\treturn { id, name, success: false, error: 'Unknown tool: ' + name, durationMs: Date.now() - start };\r\n\t\t}\r\n\t\treturn await fn(args, projectRoot);\r\n\t} catch (err) {\r\n\t\treturn {\r\n\t\t\tid,\r\n\t\t\tname,\r\n\t\t\tsuccess: false,\r\n\t\t\terror: String(err instanceof Error ? err.message : err),\r\n\t\t\tdurationMs: Date.now() - start,\r\n\t\t};\r\n\t}\r\n}\r\n\r\n// \u2500\u2500 Path helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nfunction toProjectPath(path: string, projectRoot: string): string {\r\n\tif (isAbsolute(path)) return path;\r\n\treturn resolve(projectRoot, path);\r\n}\r\n\r\nfunction withinProject(path: string, projectRoot: string): boolean {\r\n\ttry {\r\n\t\tconst resolved = toProjectPath(path, projectRoot);\r\n\t\tconst rel = relative(projectRoot, resolved);\r\n\t\treturn !rel.startsWith('..') && !isAbsolute(rel);\r\n\t} catch {\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\n// \u2500\u2500 Propose a file change (returns ProposedFileChange without writing) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nfunction proposeFileChange(\r\n\tpath: string,\r\n\tproposedContent: string,\r\n\tprojectRoot: string,\r\n\tchangeType: 'write' | 'edit',\r\n\toldContent?: string,\r\n): { change: ProposedFileChange; result: ToolResult } {\r\n\tconst fullPath = toProjectPath(path, projectRoot);\r\n\tconst originalContent = oldContent ?? '';\r\n\tconst isNewFile = !existsSync(fullPath);\r\n\tconst isDeletion = proposedContent === '' && changeType === 'write';\r\n\r\n\tconst baseContent = isNewFile ? '' : originalContent;\r\n\tconst diff = computeDiff(baseContent, proposedContent);\r\n\r\n\tconst change: ProposedFileChange = {\r\n\t\tpath,\r\n\t\toriginalContent,\r\n\t\tproposedContent,\r\n\t\tdiff: { ...diff, file: path },\r\n\t\tisNewFile,\r\n\t\tisDeletion,\r\n\t};\r\n\r\n\tconst lineCount = proposedContent.split('\\n').length;\r\n\tconst summary = isDeletion\r\n\t\t? `Delete ${path} (${lineCount} lines removed)`\r\n\t\t: isNewFile\r\n\t\t\t? `Create ${path} (${lineCount} lines)`\r\n\t\t\t: `${changeType === 'edit' ? 'Edit' : 'Overwrite'} ${path} (${lineCount} lines, +${diff.additions}/-${diff.deletions})`;\r\n\r\n\tconst result: ToolResult = {\r\n\t\tid: '',\r\n\t\tname: `${changeType}:${path}`,\r\n\t\tsuccess: true,\r\n\t\toutput: JSON.stringify({\r\n\t\t\tmessage: summary,\r\n\t\t\tneedsApproval: true,\r\n\t\t\tproposedChange: change,\r\n\t\t}),\r\n\t\tdurationMs: 0,\r\n\t};\r\n\r\n\treturn { change, result };\r\n}\r\n\r\n// \u2500\u2500 Apply an approved change to disk \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nexport async function applyFileChange(change: ProposedFileChange, projectRoot: string): Promise<ToolResult> {\r\n\tconst start = Date.now();\r\n\tconst fullPath = toProjectPath(change.path, projectRoot);\r\n\r\n\ttry {\r\n\t\tif (change.isDeletion) {\r\n\t\t\tif (existsSync(fullPath)) {\r\n\t\t\t\t\tawait unlinkAsync(fullPath);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst dir = resolve(fullPath, '..');\r\n\t\t\tif (!existsSync(dir)) {\r\n\t\t\t\tmkdirSync(dir, { recursive: true });\r\n\t\t\t}\r\n\t\t\tawait writeFileAsync(fullPath, change.proposedContent, 'utf-8');\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tid: '',\r\n\t\t\tname: 'file:write',\r\n\t\t\tsuccess: true,\r\n\t\t\toutput: `Applied: ${change.path}`,\r\n\t\t\tdurationMs: Date.now() - start,\r\n\t\t};\r\n\t} catch (err) {\r\n\t\treturn {\r\n\t\t\tid: '',\r\n\t\t\tname: 'file:write',\r\n\t\t\tsuccess: false,\r\n\t\t\terror: 'Cannot apply ' + change.path + ': ' + (err instanceof Error ? err.message : String(err)),\r\n\t\t\tdurationMs: Date.now() - start,\r\n\t\t};\r\n\t}\r\n}\r\n\r\n// \u2500\u2500 File Tools \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nasync function toolFileRead(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst path = String(args.path ?? '');\r\n\tif (!path) return { id: '', name: 'file:read', success: false, error: 'path is required', durationMs: 0 };\r\n\tif (!withinProject(path, projectRoot)) {\r\n\t\treturn { id: '', name: 'file:read', success: false, error: 'Access denied: ' + path, durationMs: 0 };\r\n\t}\r\n\r\n\tconst fullPath = toProjectPath(path, projectRoot);\r\n\tconst limit = Number(args.limit ?? 0);\r\n\tconst offset = Number(args.offset ?? 0);\r\n\r\n\ttry {\r\n\t\tconst statResult = statSync(fullPath);\r\n\t\tif (statResult.isDirectory()) {\r\n\t\t\treturn { id: '', name: 'file:read', success: false, error: 'Path \"' + path + '\" is a directory', durationMs: 0 };\r\n\t\t}\r\n\r\n\t\tconst content = await readFileAsync(fullPath, 'utf-8');\r\n\t\tconst lines = content.split('\\n');\r\n\t\tconst sliced = lines.slice(offset, limit > 0 ? offset + limit : undefined);\r\n\t\tconst summary = limit > 0 ? '[Showing lines ' + (offset + 1) + '-' + (offset + sliced.length) + ' of ' + lines.length + ']' : '';\r\n\t\treturn { id: '', name: 'file:read', success: true, output: (summary ? summary + '\\n' : '') + sliced.join('\\n'), durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'file:read', success: false, error: 'Cannot read ' + path + ': ' + (err instanceof Error ? err.message : String(err)), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolFileWrite(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst path = String(args.path ?? '');\r\n\tconst content = String(args.content ?? '');\r\n\tif (!path) return { id: '', name: 'file:write', success: false, error: 'path is required', durationMs: 0 };\r\n\tif (!withinProject(path, projectRoot)) {\r\n\t\treturn { id: '', name: 'file:write', success: false, error: 'Access denied: ' + path, durationMs: 0 };\r\n\t}\r\n\r\n\tconst { result } = proposeFileChange(path, content, projectRoot, 'write');\r\n\treturn result;\r\n}\r\n\r\nasync function toolFileEdit(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst path = String(args.path ?? '');\r\n\tconst oldString = String(args.old_string ?? '');\r\n\tconst newString = String(args.new_string ?? '');\r\n\tif (!path || !oldString) return { id: '', name: 'file:edit', success: false, error: 'path and old_string are required', durationMs: 0 };\r\n\tif (!withinProject(path, projectRoot)) {\r\n\t\treturn { id: '', name: 'file:edit', success: false, error: 'Access denied: ' + path, durationMs: 0 };\r\n\t}\r\n\r\n\tconst fullPath = toProjectPath(path, projectRoot);\r\n\r\n\ttry {\r\n\t\tconst existingContent = existsSync(fullPath) ? await readFileAsync(fullPath, 'utf-8') : '';\r\n\t\tif (!existingContent.includes(oldString)) {\r\n\t\t\treturn { id: '', name: 'file:edit', success: false, error: 'old_string not found in ' + path + '. Check whitespace.', durationMs: 0 };\r\n\t\t}\r\n\t\tconst newContent = existingContent.replace(oldString, newString);\r\n\t\tconst { result } = proposeFileChange(path, newContent, projectRoot, 'edit', existingContent);\r\n\t\treturn result;\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'file:edit', success: false, error: 'Cannot edit ' + path + ': ' + (err instanceof Error ? err.message : String(err)), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolFileDelete(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst path = String(args.path ?? '');\r\n\tif (!path) return { id: '', name: 'file:delete', success: false, error: 'path is required', durationMs: 0 };\r\n\tif (!withinProject(path, projectRoot)) {\r\n\t\treturn { id: '', name: 'file:delete', success: false, error: 'Access denied: ' + path, durationMs: 0 };\r\n\t}\r\n\r\n\tconst fullPath = toProjectPath(path, projectRoot);\r\n\ttry {\r\n\t\tif (!existsSync(fullPath)) {\r\n\t\t\treturn { id: '', name: 'file:delete', success: false, error: 'File not found: ' + path, durationMs: 0 };\r\n\t\t}\r\n\t\tconst existingContent = await readFileAsync(fullPath, 'utf-8');\r\n\t\treturn proposeFileChange(path, '', projectRoot, 'write', existingContent).result;\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'file:delete', success: false, error: 'Cannot delete ' + path + ': ' + (err instanceof Error ? err.message : String(err)), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolFileGlob(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst globPattern = String(args.pattern ?? '');\r\n\tif (!globPattern) return { id: '', name: 'file:glob', success: false, error: 'pattern is required', durationMs: 0 };\r\n\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\tif (!withinProject(cwd, projectRoot)) {\r\n\t\treturn { id: '', name: 'file:glob', success: false, error: 'Access denied', durationMs: 0 };\r\n\t}\r\n\r\n\ttry {\r\n\t\tconst files = await globPromise(globPattern, { cwd, absolute: false });\r\n\t\treturn { id: '', name: 'file:glob', success: true, output: files.length > 0 ? files.join('\\n') : '(no files matched)', durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'file:glob', success: false, error: 'glob error: ' + (err instanceof Error ? err.message : String(err)), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolGrep(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst pattern = String(args.pattern ?? '');\r\n\tconst path = args.path ? String(args.path) : '.';\r\n\tconst caseSensitive = args.case_sensitive !== false;\r\n\r\n\tif (!pattern || !path) return { id: '', name: 'grep', success: false, error: 'pattern and path are required', durationMs: 0 };\r\n\r\n\tif (isAbsolute(path) && !withinProject(path, projectRoot)) {\r\n\t\treturn { id: '', name: 'grep', success: false, error: 'Access denied', durationMs: 0 };\r\n\t}\r\n\tconst fullPath = isAbsolute(path) ? path : resolve(projectRoot, path);\r\n\tconst flags = caseSensitive ? '' : '-i';\r\n\tconst includeFlag = args.glob ? ['--include=' + String(args.glob)] : [];\r\n\r\n\ttry {\r\n\t\tconst cmd = ['grep', flags, '-rn', '--color=never', pattern, fullPath, ...includeFlag].join(' ');\r\n\t\tconst { stdout, stderr } = await exec(cmd, { timeout: 30000 } as { timeout: number });\r\n\t\tconst results = (stdout || stderr).trim();\r\n\t\treturn { id: '', name: 'grep', success: true, output: results || '(no matches found)', durationMs: 0 };\r\n\t} catch (err: unknown) {\r\n\t\tconst errorObj = err as { code?: string | number; message?: string; stdout?: string; stderr?: string };\r\n\t\tif (errorObj.code === 1) return { id: '', name: 'grep', success: true, output: '(no matches found)', durationMs: 0 };\r\n\t\treturn { id: '', name: 'grep', success: false, error: 'grep error: ' + (err instanceof Error ? err.message : String(err)), durationMs: 0 };\r\n\t}\r\n}\r\n\r\n// \u2500\u2500 Bash \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst DANGEROUS_PATTERNS = [\r\n\t/rm\\s+-rf\\s+['\"]?\\//i,\r\n\t/dd\\s+if=/i,\r\n\t/>\\s*\\/dev\\/sda/i,\r\n\t/mkfs\\./i,\r\n\t/:\\s*\\(\\)\\s*\\{\\s*:\\|:&?\\s*\\};?\\s*:/i,\r\n];\r\n\r\nasync function toolBash(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst command = String(args.command ?? '');\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\tconst timeout = Number(args.timeout ?? getConfig(projectRoot).bashTimeout);\r\n\r\n\tif (!command) return { id: '', name: 'bash:execute', success: false, error: 'command is required', durationMs: 0 };\r\n\r\n\tfor (const pattern of DANGEROUS_PATTERNS) {\r\n\t\tif (pattern.test(command)) {\r\n\t\t\treturn { id: '', name: 'bash:execute', success: false, error: 'Dangerous command blocked: ' + command.slice(0, 50), durationMs: 0 };\r\n\t\t}\r\n\t}\r\n\r\n\ttry {\r\n\t\tconst { stdout, stderr } = await exec(command, { cwd, timeout } as { cwd: string; timeout: number });\r\n\t\tconst output = [stdout, stderr].filter(Boolean).join('\\n');\r\n\t\treturn { id: '', name: 'bash:execute', success: true, output: output || '(no output)', durationMs: 0 };\r\n\t} catch (err: unknown) {\r\n\t\tconst errorObj = err as { message?: string; stdout?: string; stderr?: string };\r\n\t\tconst combined = [errorObj.stdout, errorObj.stderr].filter(Boolean).join('\\n');\r\n\t\treturn { id: '', name: 'bash:execute', success: false, error: combined.slice(0, 500) || errorObj.message, durationMs: 0 };\r\n\t}\r\n}\r\n\r\n// \u2500\u2500 Git Tools \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nasync function toolGitStatus(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\ttry {\r\n\t\tconst git = simpleGit(cwd);\r\n\t\tconst status = await git.status();\r\n\t\tconst tracking = status.tracking;\r\n\t\tconst lines = [\r\n\t\t\t'Current branch: ' + (status.current ?? 'unknown'),\r\n\t\t\ttracking ? 'tracking: ' + tracking : '',\r\n\t\t\t'',\r\n\t\t\t'Modified: ' + (status.modified.length > 0 ? status.modified.join(', ') : '(none)'),\r\n\t\t\t'Created: ' + (status.created.length > 0 ? status.created.join(', ') : '(none)'),\r\n\t\t\t'Deleted: ' + (status.deleted.length > 0 ? status.deleted.join(', ') : '(none)'),\r\n\t\t\t'',\r\n\t\t\t'Not staged: ' + (status.not_added.length > 0 ? status.not_added.join(', ') : '(none)'),\r\n\t\t\t'',\r\n\t\t\t'Untracked: ' + (status.files.length > 0 ? status.files.join(', ') : '(none)'),\r\n\t\t].filter(Boolean).join('\\n');\r\n\t\treturn { id: '', name: 'git:status', success: true, output: lines, durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'git:status', success: false, error: err instanceof Error ? err.message : String(err), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolGitCommit(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst message = String(args.message ?? '');\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\tif (!message) return { id: '', name: 'git:commit', success: false, error: 'message is required', durationMs: 0 };\r\n\ttry {\r\n\t\tconst git = simpleGit(cwd);\r\n\t\tawait git.add('.');\r\n\t\tconst result = await git.commit(message);\r\n\t\treturn { id: '', name: 'git:commit', success: true, output: 'Committed ' + result.commit + ' \u2014 ' + message, durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'git:commit', success: false, error: err instanceof Error ? err.message : String(err), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolGitPush(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\ttry {\r\n\t\tconst git = simpleGit(cwd);\r\n\t\tawait git.push();\r\n\t\treturn { id: '', name: 'git:push', success: true, output: 'Pushed to remote.', durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'git:push', success: false, error: err instanceof Error ? err.message : String(err), durationMs: 0 };\r\n\t}\r\n}\r\n\r\nasync function toolGitLog(args: Record<string, unknown>, projectRoot: string): Promise<ToolResult> {\r\n\tconst cwd = args.cwd ? String(args.cwd) : projectRoot;\r\n\tconst limit = Number(args.limit ?? 20);\r\n\ttry {\r\n\t\tconst git = simpleGit(cwd);\r\n\t\tconst log = await git.log({ maxCount: limit });\r\n\t\tconst lines = log.all\r\n\t\t\t.map((c: { hash: string; date: string; message: string; author_name: string }) => c.hash.slice(0, 7) + ' | ' + c.date.slice(0, 10) + ' | ' + c.message + ' (' + c.author_name + ')')\r\n\t\t\t.join('\\n');\r\n\t\treturn { id: '', name: 'git:log', success: true, output: lines, durationMs: 0 };\r\n\t} catch (err) {\r\n\t\treturn { id: '', name: 'git:log', success: false, error: err instanceof Error ? err.message : String(err), durationMs: 0 };\r\n\t}\r\n}\r\n", "// =============================================================================\r\n// Config Management\r\n// =============================================================================\r\n\r\nimport { chmodSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\r\nimport { resolve, dirname } from 'node:path';\r\nimport { fileURLToPath } from 'node:url';\r\nimport type { AppConfig } from '../types/index.js';\r\n\r\n// Find project root reliably (works even when cwd != project dir)\r\nfunction getProjectRoot(): string {\r\n // Try import.meta.url first (ESM)\r\n try {\r\n const thisFile = fileURLToPath(import.meta.url);\r\n return dirname(dirname(thisFile)); // src/utils/ \u2192 src/ \u2192 project root\r\n } catch {\r\n // Fall back to process.cwd()\r\n return process.cwd();\r\n }\r\n}\r\n\r\n// Load .env files at startup\r\nfunction loadEnvFile(envPath: string): void {\r\n try {\r\n const content = readFileSync(envPath, 'utf-8');\r\n for (const line of content.split('\\n')) {\r\n const trimmed = line.trim();\r\n if (!trimmed || trimmed.startsWith('#')) continue;\r\n const eqIdx = trimmed.indexOf('=');\r\n if (eqIdx === -1 || eqIdx === trimmed.length - 1) continue;\r\n const key = trimmed.slice(0, eqIdx).trim();\r\n const value = trimmed.slice(eqIdx + 1).trim().replace(/^[\"']|[\"']$/g, '');\r\n if (!process.env[key]) process.env[key] = value;\r\n }\r\n } catch {\r\n // file not found \u2014 continue silently\r\n }\r\n}\r\n\r\n// Load .env from project root and current directory\r\nconst PROJECT_ROOT = getProjectRoot();\r\nloadEnvFile(resolve(PROJECT_ROOT, '.env'));\r\nloadEnvFile(resolve('.env')); // also try cwd\r\n\r\nexport { PROJECT_ROOT };\r\n\r\nexport function getAgentTermoDir(): string {\r\n const envDir = process.env.AGENT_TERMO_DIR;\r\n if (envDir) {\r\n return resolve(process.env.HOME || process.env.USERPROFILE || '.', envDir);\r\n }\r\n return resolve(process.env.HOME || process.env.USERPROFILE || '.', '.agent-termo');\r\n}\r\n\r\nfunction readStoredConfig(): Record<string, unknown> {\r\n try {\r\n const existing: unknown = JSON.parse(\r\n readFileSync(resolve(getAgentTermoDir(), 'config.json'), 'utf-8'),\r\n );\r\n if (existing && typeof existing === 'object' && !Array.isArray(existing)) {\r\n return existing as Record<string, unknown>;\r\n }\r\n } catch {\r\n // No saved user configuration yet.\r\n }\r\n return {};\r\n}\r\n\r\nfunction updateStoredConfig(patch: Record<string, unknown>): void {\r\n const configDir = getAgentTermoDir();\r\n const configPath = resolve(configDir, 'config.json');\r\n const storedConfig = { ...readStoredConfig(), ...patch };\r\n\r\n mkdirSync(configDir, { recursive: true, mode: 0o700 });\r\n writeFileSync(configPath, `${JSON.stringify(storedConfig, null, 2)}\\n`, {\r\n encoding: 'utf-8',\r\n mode: 0o600,\r\n });\r\n\r\n // Restrict permissions even when updating an existing file on Unix.\r\n if (process.platform !== 'win32') chmodSync(configPath, 0o600);\r\n}\r\n\r\nfunction loadStoredNimApiKey(): void {\r\n if (process.env.NIM_API_KEY) return;\r\n\r\n const { nimApiKey } = readStoredConfig();\r\n if (typeof nimApiKey === 'string' && nimApiKey.trim()) {\r\n process.env.NIM_API_KEY = nimApiKey;\r\n }\r\n}\r\n\r\n/**\r\n * A model picked with /model is saved and wins over NIM_MODEL from .env, so\r\n * the choice survives restarts. The --model CLI flag still overrides it.\r\n */\r\nfunction loadStoredNimModel(): void {\r\n const { nimModel } = readStoredConfig();\r\n if (typeof nimModel === 'string' && nimModel.trim()) {\r\n process.env.NIM_MODEL = nimModel;\r\n }\r\n}\r\n\r\nexport function saveNimApiKey(apiKey: string): void {\r\n updateStoredConfig({ nimApiKey: apiKey });\r\n}\r\n\r\nexport function saveNimModel(model: string): void {\r\n updateStoredConfig({ nimModel: model });\r\n}\r\n\r\nloadStoredNimApiKey();\r\nloadStoredNimModel();\r\n\r\nexport function getConfig(projectRoot: string): AppConfig {\r\n loadEnvFile(resolve(projectRoot, '.env'));\r\n\r\n return {\r\n nimApiKey: process.env.NIM_API_KEY ?? '',\r\n nimBaseUrl: process.env.NIM_BASE_URL ?? 'https://integrate.api.nvidia.com/v1',\r\n nimModel: process.env.NIM_MODEL ?? 'stepfun-ai/step-3.7-flash',\r\n agentTermoDir: process.env.AGENT_TERMO_DIR ?? '.claude',\r\n logLevel: (process.env.LOG_LEVEL as AppConfig['logLevel']) || 'info',\r\n confirmDestructive: process.env.CONFIRM_DESTRUCTIVE !== 'false',\r\n allowedCommands: (\r\n process.env.ALLOWED_COMMANDS ?? 'git,npm,node,pnpm,yarn,tsx,tsc,npx'\r\n ).split(','),\r\n llmTimeout: parseInt(process.env.LLM_TIMEOUT ?? '120000', 10),\r\n bashTimeout: parseInt(process.env.BASH_TIMEOUT ?? '300000', 10),\r\n };\r\n}\r\n\r\nexport function resolveProjectRoot(cwd?: string): string {\r\n return cwd || PROJECT_ROOT;\r\n}\r\n", "// =============================================================================\r\n// Diff Engine \u2014 line-level diff computation for file change review\r\n// =============================================================================\r\n// Uses LCS (Longest Common Subsequence) to compute minimal line-level diffs.\r\n\r\nimport type { DiffLine, DiffResult } from '../types/index.js';\r\n\r\n// \u2500\u2500 LCS-based Diff Algorithm \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nexport function computeDiff(original: string, proposed: string): DiffResult {\r\n\tconst originalLines = original.split('\\n');\r\n\tconst proposedLines = proposed.split('\\n');\r\n\r\n\tif (originalLines.length === 1 && originalLines[0] === '') {\r\n\t\tconst lines: DiffLine[] = proposedLines.map((content, i) => ({\r\n\t\t\ttype: 'add',\r\n\t\t\tlineNumber: i + 1,\r\n\t\t\tcontent,\r\n\t\t}));\r\n\t\treturn { file: '', lines, additions: proposedLines.length, deletions: 0 };\r\n\t}\r\n\r\n\tif (original === proposed) {\r\n\t\treturn { file: '', lines: [], additions: 0, deletions: 0 };\r\n\t}\r\n\r\n\tconst m = originalLines.length;\r\n\tconst n = proposedLines.length;\r\n\tconst stride = n + 1;\r\n\tconst table = new Int32Array((m + 1) * (n + 1));\r\n\r\n\tconst get = (i: number, j: number): number => table[i * stride + j]!;\r\n\tconst set = (i: number, j: number, val: number) => { table[i * stride + j] = val; };\r\n\r\n\tfor (let i = 1; i <= m; i++) {\r\n\t\tfor (let j = 1; j <= n; j++) {\r\n\t\t\tif (originalLines[i - 1] === proposedLines[j - 1]) {\r\n\t\t\t\tset(i, j, get(i - 1, j - 1) + 1);\r\n\t\t\t} else {\r\n\t\t\t\tset(i, j, Math.max(get(i - 1, j), get(i, j - 1)));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tconst ops = backtrackLCS(get, originalLines, proposedLines);\r\n\tconst diffLines = opsToDiffLines(ops);\r\n\r\n\tlet additions = 0;\r\n\tlet deletions = 0;\r\n\tfor (const line of diffLines) {\r\n\t\tif (line.type === 'add') additions++;\r\n\t\tif (line.type === 'remove') deletions++;\r\n\t}\r\n\r\n\treturn { file: '', lines: diffLines, additions, deletions };\r\n}\r\n\r\ninterface DiffOp {\r\n\ttype: 'same' | 'add' | 'remove';\r\n\toriginalIndex: number;\r\n\tproposedIndex: number;\r\n\toriginalLine?: string;\r\n\tproposedLine?: string;\r\n}\r\n\r\nfunction backtrackLCS(\r\n\tget: (i: number, j: number) => number,\r\n\ta: string[],\r\n\tb: string[],\r\n): DiffOp[] {\r\n\tconst ops: DiffOp[] = [];\r\n\tconst m = a.length;\r\n\tconst n = b.length;\r\n\tlet i = m;\r\n\tlet j = n;\r\n\r\n\twhile (i > 0 || j > 0) {\r\n\t\tif (i > 0 && j > 0 && a[i - 1] === b[j - 1]) {\r\n\t\t\tops.unshift({\r\n\t\t\t\ttype: 'same',\r\n\t\t\t\toriginalIndex: i,\r\n\t\t\t\tproposedIndex: j,\r\n\t\t\t\toriginalLine: a[i - 1],\r\n\t\t\t\tproposedLine: b[j - 1],\r\n\t\t\t});\r\n\t\t\ti--;\r\n\t\t\tj--;\r\n\t\t} else if (j > 0 && (i === 0 || get(i, j - 1) >= get(i - 1, j))) {\r\n\t\t\tops.unshift({\r\n\t\t\t\ttype: 'add',\r\n\t\t\t\tproposedIndex: j,\r\n\t\t\t\toriginalIndex: i,\r\n\t\t\t\tproposedLine: b[j - 1],\r\n\t\t\t});\r\n\t\t\tj--;\r\n\t\t} else {\r\n\t\t\tops.unshift({\r\n\t\t\t\ttype: 'remove',\r\n\t\t\t\toriginalIndex: i,\r\n\t\t\t\tproposedIndex: j,\r\n\t\t\t\toriginalLine: a[i - 1],\r\n\t\t\t});\r\n\t\t\ti--;\r\n\t\t}\r\n\t}\r\n\r\n\treturn ops;\r\n}\r\n\r\nfunction opsToDiffLines(ops: DiffOp[]): DiffLine[] {\r\n\tconst lines: DiffLine[] = [];\r\n\tlet originalLineNum = 0;\r\n\tlet proposedLineNum = 0;\r\n\r\n\tfor (const op of ops) {\r\n\t\tswitch (op.type) {\r\n\t\t\tcase 'same': {\r\n\t\t\t\toriginalLineNum++;\r\n\t\t\t\tproposedLineNum++;\r\n\t\t\t\tlines.push({\r\n\t\t\t\t\ttype: 'context',\r\n\t\t\t\t\tlineNumber: originalLineNum,\r\n\t\t\t\t\tcontent: op.originalLine ?? '',\r\n\t\t\t\t});\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tcase 'remove': {\r\n\t\t\t\toriginalLineNum++;\r\n\t\t\t\tlines.push({\r\n\t\t\t\t\ttype: 'remove',\r\n\t\t\t\t\tlineNumber: originalLineNum,\r\n\t\t\t\t\tcontent: op.originalLine ?? '',\r\n\t\t\t\t});\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tcase 'add': {\r\n\t\t\t\tproposedLineNum++;\r\n\t\t\t\tlines.push({\r\n\t\t\t\t\ttype: 'add',\r\n\t\t\t\t\tlineNumber: proposedLineNum,\r\n\t\t\t\t\tcontent: op.proposedLine ?? '',\r\n\t\t\t\t});\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn lines;\r\n}\r\n\r\n// \u2500\u2500 Context Extraction for large files \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nexport interface DiffOptions {\r\n\tcontextLines?: number;\r\n\tmaxLines?: number;\r\n}\r\n\r\nexport function applyDiffContext(diff: DiffResult, options: DiffOptions = {}): DiffResult {\r\n\tconst { contextLines = 3, maxLines = 0 } = options;\r\n\r\n\tif (contextLines <= 0 && maxLines <= 0) {\r\n\t\treturn diff;\r\n\t}\r\n\r\n\t// Identify contiguous change regions\r\n\tconst changeRegions: { start: number; end: number }[] = [];\r\n\tlet inChange = false;\r\n\tlet regionStart = 0;\r\n\r\n\tfor (let i = 0; i < diff.lines.length; i++) {\r\n\t\tconst line = diff.lines[i]!;\r\n\t\tif (line.type === 'add' || line.type === 'remove') {\r\n\t\t\tif (!inChange) {\r\n\t\t\t\tregionStart = i;\r\n\t\t\t\tinChange = true;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (inChange) {\r\n\t\t\t\tchangeRegions.push({ start: regionStart, end: i - 1 });\r\n\t\t\t\tinChange = false;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tif (inChange) {\r\n\t\tchangeRegions.push({ start: regionStart, end: diff.lines.length - 1 });\r\n\t}\r\n\r\n\t// Build merged ranges \u2014 use parallel arrays to avoid tuple strict-null issues\r\n\t// All accesses use ! because arrays are never sparse at these indices\r\n\tconst mergeStarts: number[] = [];\r\n\tconst mergeEnds: number[] = [];\r\n\r\n\tfor (const region of changeRegions) {\r\n\t\tconst start = Math.max(0, region.start - contextLines);\r\n\t\tconst end = Math.min(diff.lines.length - 1, region.end + contextLines);\r\n\r\n\t\tconst lastIdx = mergeStarts.length - 1;\r\n\t\tif (mergeStarts.length > 0 && start <= mergeEnds[lastIdx]! + 1) {\r\n\t\t\tmergeEnds[lastIdx] = Math.max(mergeEnds[lastIdx]!, end);\r\n\t\t} else {\r\n\t\t\tmergeStarts.push(start);\r\n\t\t\tmergeEnds.push(end);\r\n\t\t}\r\n\t}\r\n\r\n\t// Build filtered diff lines with ellipsis between non-adjacent ranges\r\n\tconst filteredLines: DiffLine[] = [];\r\n\r\n\tfor (let r = 0; r < mergeStarts.length; r++) {\r\n\t\tconst rangeStart = mergeStarts[r]!;\r\n\t\tconst rangeEnd = mergeEnds[r]!;\r\n\t\tconst prevEnd = r > 0 ? mergeEnds[r - 1]! : -1;\r\n\r\n\t\tif (r > 0 && rangeStart > prevEnd + 1) {\r\n\t\t\tconst omitted = rangeStart - prevEnd - 1;\r\n\t\t\tfilteredLines.push({\r\n\t\t\t\ttype: 'context',\r\n\t\t\t\tlineNumber: 0,\r\n\t\t\t\tcontent: '... ' + omitted + ' unchanged lines omitted ...',\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tfor (let i = rangeStart; i <= rangeEnd; i++) {\r\n\t\t\tconst line = diff.lines[i]!;\r\n\t\t\tfilteredLines.push(line);\r\n\t\t}\r\n\t}\r\n\r\n\tlet finalLines = filteredLines;\r\n\tif (maxLines > 0 && finalLines.length > maxLines) {\r\n\t\tconst halfMax = Math.floor(maxLines / 2);\r\n\t\tfinalLines = [\r\n\t\t\t...finalLines.slice(0, halfMax),\r\n\t\t\t{\r\n\t\t\t\ttype: 'context',\r\n\t\t\t\tlineNumber: 0,\r\n\t\t\t\tcontent: '... ' + (finalLines.length - maxLines) + ' more lines ...',\r\n\t\t\t},\r\n\t\t\t...finalLines.slice(finalLines.length - halfMax),\r\n\t\t];\r\n\t}\r\n\r\n\tlet additions = 0;\r\n\tlet deletions = 0;\r\n\tfor (const line of finalLines) {\r\n\t\tif (line.type === 'add') additions++;\r\n\t\tif (line.type === 'remove') deletions++;\r\n\t}\r\n\r\n\treturn { ...diff, lines: finalLines, additions, deletions };\r\n}\r\n\r\nexport function isNoOpDiff(diff: DiffResult): boolean {\r\n\treturn diff.lines.length === 0 && diff.additions === 0 && diff.deletions === 0;\r\n}\r\n", "// =============================================================================\r\n// Memory & Timeline Runtime\r\n// =============================================================================\r\n\r\nimport { readFileSync as readFile, appendFileSync as appendFile, writeFileSync as writeFile, existsSync, mkdirSync } from 'node:fs';\r\nimport { resolve } from 'node:path';\r\n\r\n// \u2500\u2500 Agent-Termo Home Memory \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nfunction ensureAgentTermoDir(): string {\r\n const dir = resolve(process.env.HOME || process.env.USERPROFILE || '.', '.agent-termo');\r\n try {\r\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\r\n } catch {\r\n // non-fatal; callers will handle missing file\r\n }\r\n return dir;\r\n}\r\n\r\nconst AGENT_TERMO_MEMORY_PATH = resolve(ensureAgentTermoDir(), 'memory.md');\r\n\r\nexport function loadAgentTermoMemory(): string {\r\n if (!existsSync(AGENT_TERMO_MEMORY_PATH)) return '';\r\n try {\r\n return readFile(AGENT_TERMO_MEMORY_PATH, 'utf-8');\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nexport function appendToAgentTermoMemory(entry: string): void {\r\n const timestamp = new Date().toISOString().split('T')[0];\r\n const content = '\\n\\n## ' + timestamp + '\\n\\n' + entry;\r\n try {\r\n appendFile(AGENT_TERMO_MEMORY_PATH, content, 'utf-8');\r\n } catch {\r\n // ignore persistence failure\r\n }\r\n}\r\n\r\nconst AGENT_TERMO_TIMELINE_PATH = resolve(ensureAgentTermoDir(), 'timeline.md');\r\n\r\nexport function loadAgentTermoTimeline(): string {\r\n if (!existsSync(AGENT_TERMO_TIMELINE_PATH)) return '';\r\n try {\r\n return readFile(AGENT_TERMO_TIMELINE_PATH, 'utf-8');\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nexport function logAgentTermoTimeline(message: string): void {\r\n const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 16);\r\n const entry = '\\n- [' + timestamp + '] ' + message;\r\n try {\r\n appendFile(AGENT_TERMO_TIMELINE_PATH, entry, 'utf-8');\r\n } catch {\r\n // ignore persistence failure\r\n }\r\n}\r\n\r\n// \u2500\u2500 Project Memory & Timeline Runtime \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nexport async function loadMemory(projectRoot: string): Promise<string> {\r\n const path = resolve(projectRoot, 'docs', 'MEMORY.md');\r\n if (!existsSync(path)) return '';\r\n try {\r\n return readFile(path, 'utf-8');\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nexport async function appendToMemory(projectRoot: string, entry: string): Promise<void> {\r\n let path: string;\r\n try {\r\n path = ensureProjectDocs(projectRoot).memoryPath;\r\n } catch {\r\n return;\r\n }\r\n const timestamp = new Date().toISOString().split('T')[0];\r\n try {\r\n appendFile(path, '\\n\\n## ' + timestamp + '\\n\\n' + entry, 'utf-8');\r\n } catch {\r\n // Project memory persistence must not crash the agent.\r\n }\r\n}\r\n\r\n// \u2500\u2500 Timeline System \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst TIMELINE_TEMPLATE = '# Project Timeline\\n\\nThis document tracks the complete chronological history of the project.\\n\\n---\\n\\n';\r\nconst MEMORY_TEMPLATE = '# Project Memory\\n\\n## Project Context\\n(Add project context here)\\n';\r\n\r\nfunction ensureProjectDocs(projectRoot: string): { memoryPath: string; timelinePath: string } {\r\n const docsDir = resolve(projectRoot, 'docs');\r\n const memoryPath = resolve(docsDir, 'MEMORY.md');\r\n const timelinePath = resolve(docsDir, 'TIMELINE.md');\r\n\r\n mkdirSync(docsDir, { recursive: true });\r\n if (!existsSync(memoryPath)) writeFile(memoryPath, MEMORY_TEMPLATE, 'utf-8');\r\n if (!existsSync(timelinePath)) writeFile(timelinePath, TIMELINE_TEMPLATE, 'utf-8');\r\n return { memoryPath, timelinePath };\r\n}\r\n\r\nexport async function loadTimeline(projectRoot: string): Promise<string> {\r\n let path: string;\r\n try {\r\n path = ensureProjectDocs(projectRoot).timelinePath;\r\n } catch {\r\n return '';\r\n }\r\n try {\r\n return readFile(path, 'utf-8');\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nexport async function appendToTimeline(\r\n projectRoot: string,\r\n agent: string,\r\n phase: string,\r\n actions: string[],\r\n notes: string[] = [],\r\n): Promise<void> {\r\n let path: string;\r\n try {\r\n path = ensureProjectDocs(projectRoot).timelinePath;\r\n } catch {\r\n return;\r\n }\r\n const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 16);\r\n\r\n const entry =\r\n '\\n\\n---\\n\\n## [' +\r\n timestamp +\r\n '] - ' +\r\n agent +\r\n '\\n\\n### Phase/Activity\\n' +\r\n phase +\r\n '\\n\\n### Actions Taken\\n' +\r\n actions.map((a) => '- ' + a).join('\\n') +\r\n '\\n\\n### Notes\\n' +\r\n (notes.length > 0 ? notes.map((n) => '- ' + n).join('\\n') : '- (none)');\r\n\r\n try {\r\n appendFile(path, entry, 'utf-8');\r\n } catch {\r\n // Project logging must never prevent the agent from starting.\r\n }\r\n}\r\n\r\nexport async function logToTimeline(projectRoot: string, message: string): Promise<void> {\r\n let path: string;\r\n try {\r\n path = ensureProjectDocs(projectRoot).timelinePath;\r\n } catch {\r\n return;\r\n }\r\n const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 16);\r\n try {\r\n appendFile(path, '\\n- [' + timestamp + '] ' + message, 'utf-8');\r\n } catch {\r\n // Project logging must never prevent the agent from starting.\r\n }\r\n}\r\n", "// =============================================================================\r\n// Agent Loader + System Prompt Builder\r\n// =============================================================================\r\n\r\nimport { readdirSync, readFileSync } from 'node:fs';\r\nimport { resolve } from 'node:path';\r\nimport type { Agent } from '../types/index.js';\r\n\r\nfunction parseAgentMeta(content: string): { description: string; tools: string[] } {\r\n const descMatch = content.match(/^description:\\s*(.+)$/m);\r\n const toolsMatch = content.match(/^tools:\\s*\\[(.+)\\]/m);\r\n const toolsStr = toolsMatch?.[1] ?? '';\r\n const tools = toolsStr\r\n ? toolsStr.split(',').map((t) => t.trim().replace(/^[\"']|[\"']$/g, ''))\r\n : ['file:read', 'file:write', 'file:edit', 'file:delete', 'file:glob', 'grep', 'bash:execute', 'git:status', 'git:commit', 'git:push', 'git:log'];\r\n return { description: descMatch?.[1]?.trim() ?? '', tools };\r\n}\r\n\r\nexport function loadAgentPrompt(agentName: string, agentDir: string): string | null {\r\n const candidate = resolve(agentDir, 'agents', agentName + '.md');\r\n try {\r\n const content = readFileSync(candidate, 'utf-8');\r\n const withoutFrontmatter = content.replace(/^---[\\s\\S]+?---\\n/, '');\r\n return withoutFrontmatter.trim();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function loadAllAgents(agentDir: string): Agent[] {\r\n const agentsDir = resolve(agentDir, 'agents');\r\n try {\r\n const files = readdirSync(agentsDir).filter((f) => f.endsWith('.md'));\r\n const agents: Agent[] = files.map((file) => {\r\n const agentId = file.replace(/\\.md$/, '');\r\n const content = readFileSync(resolve(agentsDir, file), 'utf-8');\r\n const meta = parseAgentMeta(content);\r\n const withoutFrontmatter = content.replace(/^---[\\s\\S]+?---\\n/, '').trim();\r\n return { name: agentId, description: meta.description, systemPrompt: withoutFrontmatter, tools: meta.tools };\r\n });\r\n return agents.sort((a, b) => a.name.localeCompare(b.name));\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n// =============================================================================\r\n// Agent System Prompt Builder\r\n// =============================================================================\r\n\r\nconst SYSTEM_BASE = `You are Agent-Termo, a helpful AI assistant in a terminal.\r\n\r\nRESPONSE RULES (follow these strictly):\r\n- Be concise and direct. 1-3 sentences for simple questions.\r\n- Never output verbose chain-of-thought or reasoning \u2014 just the answer.\r\n- For coding tasks: briefly explain what you did, show key code.\r\n- Never write \"null\" or placeholders in your response.\r\n- When using function calls, respond with the function only \u2014 no preamble.\r\n\r\nCONVERSATION MODE (default):\r\nJust chat. Say things like \"I'm doing well!\" or \"2+2 is 4.\" \u2014 no tools needed.\r\n\r\nTOOL MODE (when asked to code/build/fix files):\r\nUse these functions (JSON tool_calls format):\r\n{\"tool_calls\":[{\"id\":\"call_1\",\"name\":\"function_name\",\"arguments\":{\"key\":\"value\"}}]}\r\n\r\nAvailable functions:\r\n- file:read(path) \u2192 read a file\r\n- file:write(path, content) \u2192 overwrite a file completely\r\n- file:edit(path, old_string, new_string) \u2192 edit a specific line section\r\n- file:delete(path) \u2192 delete a file after explicit user instruction\r\n- file:glob(pattern) \u2192 list files matching a glob (e.g. \"src/**/*.ts\")\r\n- grep(pattern, path, glob?) \u2192 search for text in files\r\n- bash:execute(command) \u2192 run a shell command\r\n- git:status() / git:commit(message) / git:push() \u2192 version control\r\n\r\nWhen done, say \"Done: <brief summary>.\"\r\n\r\nAVAILABLE FILES:\r\n- docs/MEMORY.md \u2014 project context\r\n- docs/TIMELINE.md \u2014 recent activity log`;\r\n\r\nexport function buildSystemPrompt(memory: string, timeline: string, _agentDir: string): string {\r\n let prompt = SYSTEM_BASE;\r\n\r\n if (memory) {\r\n prompt += '\\n\\n## Project Memory\\n' + memory;\r\n }\r\n\r\n if (timeline) {\r\n prompt += '\\n\\n## Recent Timeline (last entries)\\n' + timeline.slice(-1500);\r\n }\r\n\r\n return prompt;\r\n}\r\n", "// =============================================================================\r\n// Terminal UI \u2014 chalk-based styling, markdown output, diff viewer\r\n// Layout (pinned input box, scroll region) and keyboard input live in screen.ts\r\n// =============================================================================\r\n\r\nimport Chalk from 'chalk';\r\nimport type { ProposedFileChange } from '../types/index.js';\r\nimport { loadAgentTermoMemory, loadAgentTermoTimeline } from '../memory/index.js';\r\nimport {\r\n\tclipText,\r\n\tlistenKeys,\r\n\tresetScreen,\r\n\tsetCommands,\r\n\tterminalWidth,\r\n\ttype CommandInfo,\r\n} from './screen.js';\r\n\r\nexport {\r\n\tcreateInput,\r\n\tinitScreen,\r\n\tpick,\r\n\tsetScreenStatus,\r\n\ttype InputController,\r\n\ttype PickItem,\r\n} from './screen.js';\r\n\r\nconst c: typeof Chalk = Chalk as unknown as typeof Chalk;\r\nconst out = process.stdout;\r\n\r\nexport const COMMANDS: CommandInfo[] = [\r\n\t{ name: '/help', description: 'show all commands' },\r\n\t{ name: '/clear', description: 'clear conversation & screen' },\r\n\t{ name: '/memory', description: 'view Agent-Termo memory' },\r\n\t{ name: '/timeline', description: 'view recent activity' },\r\n\t{ name: '/model', description: 'switch NVIDIA NIM model (or /model <id>)' },\r\n\t{ name: '/agents', description: 'list all agents' },\r\n\t{ name: '/history', description: 'show message count' },\r\n\t{ name: '/exit', description: 'quit' },\r\n];\r\nsetCommands(COMMANDS);\r\n\r\n// eslint-disable-next-line no-control-regex\r\nconst ANSI_RE = /\\x1b\\[[0-9;?]*[A-Za-z]/g;\r\nconst visibleLength = (s: string): number => s.replace(ANSI_RE, '').length;\r\nconst rule = (): string => c.dim('\u2500'.repeat(Math.max(10, Math.min(terminalWidth() - 2, 100))));\r\n\r\n// =============================================================================\r\n// WELCOME BANNER\r\n// =============================================================================\r\n\r\nexport function printWelcome(projectRoot: string, model: string): void {\r\n\tconst width = Math.max(40, Math.min(terminalWidth() - 2, 64));\r\n\tconst inner = width - 2;\r\n\tconst room = inner - 2;\r\n\tconst row = (content: string): string =>\r\n\t\t' ' + c.magenta('\u2502') + ' ' + content + ' '.repeat(Math.max(0, room - visibleLength(content))) + ' ' + c.magenta('\u2502');\r\n\tconst field = (label: string, value: string): string =>\r\n\t\tc.dim(label.padEnd(7)) + c.cyan(clipText(value, room - 7));\r\n\r\n\tout.write('\\n');\r\n\tout.write(' ' + c.magenta('\u256D' + '\u2500'.repeat(inner) + '\u256E') + '\\n');\r\n\tout.write(row(c.magenta.bold('\u273B Agent-Termo')) + '\\n');\r\n\tout.write(row(c.dim(clipText('AI coding agent for your terminal', room))) + '\\n');\r\n\tout.write(row('') + '\\n');\r\n\tout.write(row(field('model', model)) + '\\n');\r\n\tout.write(row(field('cwd', projectRoot)) + '\\n');\r\n\tout.write(' ' + c.magenta('\u2570' + '\u2500'.repeat(inner) + '\u256F') + '\\n');\r\n\tout.write('\\n');\r\n\tout.write(\r\n\t\tc.dim(' ') + c.cyan('/help') + c.dim(' commands \u00B7 ') + c.cyan('/model') + c.dim(' switch NIM model \u00B7 ') +\r\n\t\t\tc.cyan('Tab') + c.dim(' completes') + '\\n\\n',\r\n\t);\r\n}\r\n\r\n// =============================================================================\r\n// MARKDOWN OUTPUT \u2014 line-buffered so streamed replies render as they arrive\r\n// =============================================================================\r\n\r\nfunction inline(text: string): string {\r\n\treturn text\r\n\t\t.split(/(`[^`]+`)/)\r\n\t\t.map((seg) =>\r\n\t\t\tseg.length > 1 && seg.startsWith('`') && seg.endsWith('`')\r\n\t\t\t\t? c.cyan(seg.slice(1, -1))\r\n\t\t\t\t: seg.replace(/\\*\\*(.+?)\\*\\*/g, (_m, g: string) => c.bold(g)),\r\n\t\t)\r\n\t\t.join('');\r\n}\r\n\r\nexport class MarkdownPrinter {\r\n\tprivate pending = '';\r\n\tprivate inCode = false;\r\n\tprivate first = true;\r\n\tprivate lastBlank = false;\r\n\r\n\t/** `beforeFirstOutput` runs once, just before the first line is printed (stop the spinner there). */\r\n\tconstructor(private readonly beforeFirstOutput?: () => void) {}\r\n\r\n\tpush(text: string): void {\r\n\t\tthis.pending += text;\r\n\t\tlet nl = this.pending.indexOf('\\n');\r\n\t\twhile (nl !== -1) {\r\n\t\t\tconst line = this.pending.slice(0, nl).replace(/\\r$/, '');\r\n\t\t\tthis.pending = this.pending.slice(nl + 1);\r\n\t\t\tthis.emit(line);\r\n\t\t\tnl = this.pending.indexOf('\\n');\r\n\t\t}\r\n\t}\r\n\r\n\tend(): void {\r\n\t\tif (this.pending) this.emit(this.pending.replace(/\\r$/, ''));\r\n\t\tthis.pending = '';\r\n\t}\r\n\r\n\tget printed(): boolean {\r\n\t\treturn !this.first;\r\n\t}\r\n\r\n\tprivate emit(line: string): void {\r\n\t\tconst blank = line.trim() === '';\r\n\t\tif (!this.inCode && blank && (this.first || this.lastBlank)) return;\r\n\t\tthis.lastBlank = blank && !this.inCode;\r\n\r\n\t\tif (this.first) {\r\n\t\t\tthis.beforeFirstOutput?.();\r\n\t\t\tout.write('\\n');\r\n\t\t}\r\n\t\tconst prefix = this.first ? c.magenta('\u25CF ') : ' ';\r\n\t\tthis.first = false;\r\n\t\t// Blank prose lines stay empty (no trailing indent); code keeps its gutter.\r\n\t\tout.write(blank && !this.inCode ? '\\n' : prefix + this.render(line) + '\\n');\r\n\t}\r\n\r\n\tprivate render(line: string): string {\r\n\t\tconst fence = /^\\s*```\\s*([\\w+-]*)/.exec(line);\r\n\t\tif (fence) {\r\n\t\t\tthis.inCode = !this.inCode;\r\n\t\t\treturn this.inCode ? c.dim('\u250C\u2500 ' + (fence[1] || 'code')) : c.dim('\u2514\u2500');\r\n\t\t}\r\n\t\tif (this.inCode) return c.dim('\u2502 ') + c.cyan(line.replace(/\\t/g, ' '));\r\n\r\n\t\tconst heading = /^#{1,6}\\s+(.*)$/.exec(line);\r\n\t\tif (heading) return c.bold.magenta(inline(heading[1] ?? ''));\r\n\t\tif (/^\\s*([-*_])\\1{2,}\\s*$/.test(line)) return c.dim('\u2500'.repeat(Math.min(40, terminalWidth() - 4)));\r\n\r\n\t\tconst bullet = /^(\\s*)[-*+]\\s+(.*)$/.exec(line);\r\n\t\tif (bullet) return (bullet[1] ?? '') + c.magenta('\u2022') + ' ' + inline(bullet[2] ?? '');\r\n\r\n\t\tconst numbered = /^(\\s*)(\\d+)[.)]\\s+(.*)$/.exec(line);\r\n\t\tif (numbered) return (numbered[1] ?? '') + c.magenta(numbered[2] + '.') + ' ' + inline(numbered[3] ?? '');\r\n\r\n\t\tconst quote = /^>\\s?(.*)$/.exec(line);\r\n\t\tif (quote) return c.dim('\u258E ') + c.italic(inline(quote[1] ?? ''));\r\n\r\n\t\treturn inline(line);\r\n\t}\r\n}\r\n\r\n// =============================================================================\r\n// MESSAGE DISPLAY\r\n// =============================================================================\r\n\r\nexport function printUserMessage(text: string): void {\r\n\tconst lines = text.split('\\n');\r\n\tout.write('\\n' + c.green.bold('\u276F ') + c.bold(lines[0] ?? '') + '\\n');\r\n\tfor (const l of lines.slice(1)) out.write(' ' + c.bold(l) + '\\n');\r\n}\r\n\r\nexport function printAssistantMessage(content: string): void {\r\n\tconst md = new MarkdownPrinter();\r\n\tmd.push(content);\r\n\tmd.end();\r\n}\r\n\r\n// =============================================================================\r\n// TOOL CALL DISPLAY\r\n// =============================================================================\r\n\r\nexport function printToolCall(toolName: string, args: Record<string, unknown>): void {\r\n\tconst summary = Object.entries(args)\r\n\t\t.map(([k, v]) => {\r\n\t\t\tconst raw = typeof v === 'string' ? v : JSON.stringify(v);\r\n\t\t\treturn k + '=' + clipText(String(raw ?? '').replace(/\\s+/g, ' '), 40);\r\n\t\t})\r\n\t\t.join(', ');\r\n\tconst room = terminalWidth() - toolName.length - 6;\r\n\tout.write('\\n' + c.blue('\u25CF ') + c.bold(toolName) + c.dim('(' + clipText(summary, room) + ')') + '\\n');\r\n}\r\n\r\nexport function printToolResult(\r\n\ttoolName: string,\r\n\tresult: { success: boolean; output?: string; error?: string },\r\n\tparsedOutput?: { needsApproval?: boolean; proposedChange?: ProposedFileChange },\r\n): void {\r\n\t// A proposed file change is shown as a diff, then the accept/reject prompt.\r\n\tif (parsedOutput?.needsApproval && parsedOutput.proposedChange) {\r\n\t\tprintDiffViewer(parsedOutput.proposedChange);\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst room = terminalWidth() - 8;\r\n\tif (result.success) {\r\n\t\t// One line of output is shown as-is; longer output (file contents, command\r\n\t\t// logs) is summarised, since the full text goes to the model.\r\n\t\tconst lines = (result.output ?? '').split('\\n').filter((l) => l.trim() !== '');\r\n\t\tconst summary = lines.length > 1 ? `${lines.length} lines` : clipText((lines[0] ?? '').trim() || 'done', room);\r\n\t\tout.write(c.dim(' \u23BF ') + c.green('\u2713 ') + summary + '\\n');\r\n\t} else {\r\n\t\tconst message = (result.error ?? 'unknown error').split('\\n')[0] ?? 'unknown error';\r\n\t\tout.write(c.dim(' \u23BF ') + c.red('\u2717 ' + clipText(`${toolName}: ${message}`, room)) + '\\n');\r\n\t}\r\n}\r\n\r\n// =============================================================================\r\n// DIFF VIEWER\r\n// =============================================================================\r\n\r\nexport function printDiffViewer(change: ProposedFileChange): void {\r\n\tconst diff = change.diff;\r\n\tconst room = Math.max(20, terminalWidth() - 14);\r\n\r\n\tconst label = change.isDeletion\r\n\t\t? c.red('DELETE')\r\n\t\t: change.isNewFile\r\n\t\t\t? c.green('NEW')\r\n\t\t\t: c.blue('MODIFY');\r\n\r\n\tout.write('\\n ' + c.bold.cyan(diff.file) + ' ' + label + ' ' + c.green('+' + diff.additions) + ' ' + c.red('-' + diff.deletions) + '\\n');\r\n\tout.write(' ' + c.dim('\u2500'.repeat(Math.max(10, Math.min(terminalWidth() - 4, 100)))) + '\\n');\r\n\r\n\tfor (const line of diff.lines) {\r\n\t\tconst prefix = line.type === 'add' ? '+' : line.type === 'remove' ? '-' : ' ';\r\n\t\tconst color = line.type === 'add' ? c.green : line.type === 'remove' ? c.red : c.dim;\r\n\t\tconst num = line.lineNumber > 0 ? String(line.lineNumber).padStart(4) : ' ';\r\n\t\tconst text = clipText(line.content.replace(/\\t/g, ' '), room);\r\n\t\tout.write(' ' + color(prefix + num + ' \u2502 ' + text) + '\\n');\r\n\t}\r\n\tout.write('\\n');\r\n}\r\n\r\n// =============================================================================\r\n// ACCEPT / REJECT PROMPT\r\n// =============================================================================\r\n\r\nexport function promptAcceptReject(message: string = 'Accept this change?'): Promise<'accept' | 'reject'> {\r\n\tout.write(\r\n\t\t'\\n' + c.yellow('? ') + c.bold(message) + c.dim(' [') + c.green('Y') + c.dim('/') + c.red('n') + c.dim('] '),\r\n\t);\r\n\r\n\treturn new Promise((resolve) => {\r\n\t\tlet done = false;\r\n\t\tlet stop: () => void = () => undefined;\r\n\r\n\t\tconst answer = (accepted: boolean | 'cancelled'): void => {\r\n\t\t\tdone = true;\r\n\t\t\tstop();\r\n\t\t\tout.write(\r\n\t\t\t\taccepted === true ? c.green('yes') + '\\n' : accepted === false ? c.red('no') + '\\n' : c.red('cancelled') + '\\n',\r\n\t\t\t);\r\n\t\t\tresolve(accepted === true ? 'accept' : 'reject');\r\n\t\t};\r\n\r\n\t\tstop = listenKeys((key) => {\r\n\t\t\tif (done) return;\r\n\t\t\tconst first = key.text?.[0]?.toLowerCase();\r\n\t\t\tif (key.name === 'enter' || first === 'y') answer(true);\r\n\t\t\telse if (key.name === 'escape' || first === 'n') answer(false);\r\n\t\t\telse if (key.name === 'ctrl+c') answer('cancelled');\r\n\t\t});\r\n\t});\r\n}\r\n\r\n// =============================================================================\r\n// STATUS MESSAGES\r\n// =============================================================================\r\n\r\nexport function printError(message: string, hint?: string): void {\r\n\tout.write('\\n' + c.red('\u2717 ' + message) + '\\n');\r\n\tif (hint) out.write(c.dim(' Hint: ' + hint) + '\\n');\r\n}\r\n\r\nexport function printSuccess(message: string): void {\r\n\tout.write(c.green('\u2713 ' + message) + '\\n');\r\n}\r\n\r\nexport function printInfo(message: string): void {\r\n\tout.write(c.blue('\u2139 ') + message + '\\n');\r\n}\r\n\r\n// =============================================================================\r\n// AGENT-TERMO MEMORY + TIMELINE DISPLAY\r\n// =============================================================================\r\n\r\nexport async function printMemoryFile(): Promise<void> {\r\n\tconst mem = loadAgentTermoMemory();\r\n\tif (!mem) {\r\n\t\tprintInfo('Agent-Termo memory is empty. (Normal for new sessions.)');\r\n\t\treturn;\r\n\t}\r\n\tout.write('\\n' + c.bold('Agent-Termo memory') + '\\n' + rule() + '\\n' + mem + '\\n' + rule() + '\\n\\n');\r\n}\r\n\r\nexport async function printTimelineFile(): Promise<void> {\r\n\tconst tl = loadAgentTermoTimeline();\r\n\tif (!tl || tl.trim().length === 0) {\r\n\t\tprintInfo('Timeline is empty.');\r\n\t\treturn;\r\n\t}\r\n\tconst lines = tl.split('\\n');\r\n\tconst recentCount = Math.min(40, lines.length);\r\n\tout.write('\\n' + c.bold('Agent-Termo timeline') + c.dim(' (recent entries)') + '\\n' + rule() + '\\n');\r\n\tout.write(lines.slice(-recentCount).join('\\n') + '\\n' + rule() + '\\n');\r\n\tif (lines.length > recentCount) {\r\n\t\tout.write(c.dim('\u2026 ' + (lines.length - recentCount) + ' earlier entries hidden') + '\\n');\r\n\t}\r\n\tout.write('\\n');\r\n}\r\n\r\n// =============================================================================\r\n// HELP + AGENTS DISPLAY\r\n// =============================================================================\r\n\r\nexport function printHelp(): void {\r\n\tout.write('\\n' + c.bold('Commands') + '\\n' + rule() + '\\n');\r\n\tfor (const cmd of COMMANDS) {\r\n\t\tout.write(' ' + c.cyan(cmd.name.padEnd(11)) + c.dim(cmd.description) + '\\n');\r\n\t}\r\n\tout.write('\\n' + c.bold('Keys') + '\\n' + rule() + '\\n');\r\n\tconst keys: Array<[string, string]> = [\r\n\t\t['\u2191 / \u2193', 'input history'],\r\n\t\t['Tab', 'complete a /command'],\r\n\t\t['Ctrl+A / Ctrl+E', 'start / end of line'],\r\n\t\t['Ctrl+W / Ctrl+U', 'delete word / to line start'],\r\n\t\t['Ctrl+C', 'clear the line, or quit when empty'],\r\n\t];\r\n\tfor (const [k, d] of keys) out.write(' ' + c.cyan(k.padEnd(17)) + c.dim(d) + '\\n');\r\n\tout.write('\\n');\r\n}\r\n\r\nexport function printAgentsList(agents: Array<{ name: string; description: string }>): void {\r\n\tout.write('\\n' + c.bold('Available agents') + '\\n' + rule() + '\\n');\r\n\tconst room = Math.max(10, terminalWidth() - 34);\r\n\tfor (const a of agents) {\r\n\t\tout.write(' ' + c.cyan(a.name.padEnd(30)) + c.dim(clipText(a.description.replace(/\\s+/g, ' '), room)) + '\\n');\r\n\t}\r\n\tout.write('\\n');\r\n}\r\n\r\n// =============================================================================\r\n// SPINNER\r\n// =============================================================================\r\n\r\nconst FRAMES = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F'];\r\nlet spinnerTimer: ReturnType<typeof setInterval> | null = null;\r\n\r\nexport function startSpinner(message: string): void {\r\n\tstopSpinner();\r\n\tif (!out.isTTY) {\r\n\t\tout.write(c.dim(message + '\u2026') + '\\n');\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst startedAt = Date.now();\r\n\tlet frame = 0;\r\n\tconst label = clipText(message, Math.max(10, terminalWidth() - 14));\r\n\tconst render = (): void => {\r\n\t\tconst secs = Math.floor((Date.now() - startedAt) / 1000);\r\n\t\tout.write('\\r\\x1b[2K' + c.magenta(FRAMES[frame++ % FRAMES.length] ?? '\u280B') + ' ' + c.dim(`${label}\u2026 ${secs}s`));\r\n\t};\r\n\r\n\tout.write('\\x1b[?25l');\r\n\trender();\r\n\tspinnerTimer = setInterval(render, 80);\r\n}\r\n\r\n/** Stops the spinner and clears its line. The argument is kept for older call sites and is ignored. */\r\nexport function stopSpinner(_success?: boolean): void {\r\n\tif (!spinnerTimer) return;\r\n\tclearInterval(spinnerTimer);\r\n\tspinnerTimer = null;\r\n\tout.write('\\r\\x1b[2K\\x1b[?25h');\r\n}\r\n\r\nexport function clearScreen(): void {\r\n\tresetScreen();\r\n}\r\n", "// =============================================================================\r\n// Screen layout + raw keyboard input\r\n//\r\n// Claude Code-style layout: output scrolls in a region at the top of the\r\n// terminal while a bordered input box and a status line stay pinned to the\r\n// bottom. Implemented with a DECSTBM scroll region, so every console.log /\r\n// process.stdout.write elsewhere in the app lands in the scrolling region.\r\n// =============================================================================\r\n\r\nimport Chalk from 'chalk';\r\nimport { createInterface } from 'node:readline';\r\n\r\nconst c: typeof Chalk = Chalk as unknown as typeof Chalk;\r\nconst out = process.stdout;\r\n\r\nconst CSI = '\\x1b[';\r\nconst SAVE = '\\x1b7'; // DECSC \u2014 save cursor\r\nconst RESTORE = '\\x1b8'; // DECRC \u2014 restore cursor\r\n\r\n/** Rows pinned to the bottom: top border, input row, bottom border, status row. */\r\nconst CHROME_ROWS = 4;\r\nconst MIN_ROWS = 12;\r\nconst MIN_COLS = 40;\r\nconst PLACEHOLDER = 'Ask anything\u2026 or type / for commands';\r\n\r\nexport interface CommandInfo {\r\n\tname: string;\r\n\tdescription: string;\r\n}\r\n\r\nconst S = {\r\n\tactive: false,\r\n\tediting: false,\r\n\t/** False when the output position saved at the start of editing is stale (resize). */\r\n\tsavedValid: true,\r\n\trows: 0,\r\n\tmodel: '',\r\n\tproject: '',\r\n\tcommands: [] as CommandInfo[],\r\n\tbuffer: '',\r\n\tcursor: 0,\r\n\toffset: 0,\r\n};\r\n\r\nexport function setCommands(commands: CommandInfo[]): void {\r\n\tS.commands = commands;\r\n}\r\n\r\nfunction dims(): { rows: number; cols: number } {\r\n\treturn { rows: out.rows || 24, cols: out.columns || 80 };\r\n}\r\n\r\nexport function terminalWidth(): number {\r\n\treturn out.columns || 80;\r\n}\r\n\r\nexport function clipText(text: string, max: number): string {\r\n\tif (max <= 0) return '';\r\n\treturn text.length <= max ? text : text.slice(0, Math.max(0, max - 1)) + '\u2026';\r\n}\r\n\r\nfunction shortPath(p: string): string {\r\n\tconst home = process.env.HOME || process.env.USERPROFILE || '';\r\n\treturn home && p.startsWith(home) ? '~' + p.slice(home.length) : p;\r\n}\r\n\r\nexport function layoutSupported(): boolean {\r\n\treturn Boolean(\r\n\t\tout.isTTY && process.stdin.isTTY && (out.rows ?? 0) >= MIN_ROWS && (out.columns ?? 0) >= MIN_COLS,\r\n\t);\r\n}\r\n\r\n// =============================================================================\r\n// Bottom chrome (input box + status line)\r\n// =============================================================================\r\n\r\nfunction statusLine(max: number): string {\r\n\t// While typing a slash command, the status line shows matching commands.\r\n\tif (S.editing && S.buffer.startsWith('/') && !S.buffer.includes(' ')) {\r\n\t\tconst typed = S.buffer.toLowerCase();\r\n\t\tconst hits = S.commands.filter((cmd) => cmd.name.startsWith(typed));\r\n\t\tconst only = hits[0];\r\n\t\tif (hits.length === 1 && only) {\r\n\t\t\treturn ' ' + c.cyan(only.name) + c.dim(clipText(' \u2014 ' + only.description, max - only.name.length - 1));\r\n\t\t}\r\n\t\tif (hits.length > 1) {\r\n\t\t\treturn c.cyan(clipText(' ' + hits.map((h) => h.name).join(' '), max));\r\n\t\t}\r\n\t}\r\n\r\n\tconst hint = '/help \u00B7 /model \u00B7 ctrl+c to exit';\r\n\tconst modelPart = clipText(' ' + S.model, max);\r\n\tconst roomWithHint = max - modelPart.length - hint.length - 2;\r\n\tconst showHint = roomWithHint >= 15;\r\n\tconst projPart = clipText(\r\n\t\t' \u00B7 ' + shortPath(S.project),\r\n\t\tshowHint ? roomWithHint : Math.max(0, max - modelPart.length),\r\n\t);\r\n\tconst gap = Math.max(1, max - modelPart.length - projPart.length - hint.length);\r\n\treturn c.cyan(modelPart) + c.dim(projPart + (showHint ? ' '.repeat(gap) + hint : ''));\r\n}\r\n\r\nfunction chromeString(): string {\r\n\tconst { rows, cols } = dims();\r\n\tconst width = Math.max(1, cols - 6); // '\u2502 \u276F ' + text + ' \u2502'\r\n\r\n\t// Keep the cursor inside the visible window of the input line.\r\n\tS.offset = Math.min(S.offset, Math.max(0, S.buffer.length - width + 1));\r\n\tif (S.cursor < S.offset) S.offset = S.cursor;\r\n\tif (S.cursor > S.offset + width - 1) S.offset = S.cursor - width + 1;\r\n\r\n\tconst edge = S.editing ? c.magenta : c.dim;\r\n\tconst body = S.buffer\r\n\t\t? S.buffer.slice(S.offset, S.offset + width).padEnd(width)\r\n\t\t: c.dim(clipText(PLACEHOLDER, width).padEnd(width));\r\n\r\n\tconst top = rows - 3;\r\n\tconst line = (row: number, text: string): string => `${CSI}${row};1H${CSI}2K${text}`;\r\n\treturn [\r\n\t\tline(top, edge('\u256D' + '\u2500'.repeat(cols - 2) + '\u256E')),\r\n\t\tline(top + 1, edge('\u2502') + ' ' + c.magenta.bold('\u276F') + ' ' + body + ' ' + edge('\u2502')),\r\n\t\tline(top + 2, edge('\u2570' + '\u2500'.repeat(cols - 2) + '\u256F')),\r\n\t\tline(rows, statusLine(cols - 1)),\r\n\t].join('');\r\n}\r\n\r\nfunction inputCursor(): string {\r\n\tconst { rows } = dims();\r\n\treturn `${CSI}${rows - 2};${5 + S.cursor - S.offset}H`;\r\n}\r\n\r\nfunction paint(): void {\r\n\tif (!S.active) return;\r\n\tif (S.editing) {\r\n\t\t// The saved slot holds the output position while editing: don't touch it.\r\n\t\tout.write(CSI + '?25l' + chromeString() + inputCursor() + CSI + '?25h');\r\n\t} else {\r\n\t\tout.write(SAVE + chromeString() + RESTORE);\r\n\t}\r\n}\r\n\r\nfunction regionBottom(): number {\r\n\treturn Math.max(1, dims().rows - CHROME_ROWS);\r\n}\r\n\r\nfunction applyRegion(): void {\r\n\tout.write(`${CSI}1;${regionBottom()}r`); // also homes the cursor\r\n}\r\n\r\nfunction onResize(): void {\r\n\tconst { rows } = dims();\r\n\tif (rows === S.rows) {\r\n\t\tpaint();\r\n\t\treturn;\r\n\t}\r\n\t// Height changed: old chrome rows are stale, so start from a clean screen.\r\n\tS.rows = rows;\r\n\tS.savedValid = false;\r\n\tout.write(`${CSI}2J${CSI}H`);\r\n\tapplyRegion();\r\n\tout.write(chromeString() + `${CSI}${regionBottom()};1H`);\r\n\tif (S.editing) paint();\r\n}\r\n\r\n// =============================================================================\r\n// Screen lifecycle\r\n// =============================================================================\r\n\r\nexport function initScreen(info: { model: string; project: string }): void {\r\n\tS.model = info.model;\r\n\tS.project = info.project;\r\n\tif (S.active || !layoutSupported()) return;\r\n\r\n\tS.active = true;\r\n\tS.rows = dims().rows;\r\n\tout.write(`${CSI}2J${CSI}H`);\r\n\tapplyRegion();\r\n\tout.write(chromeString() + `${CSI}1;1H`);\r\n\tout.on('resize', onResize);\r\n\tprocess.on('exit', teardownScreen);\r\n}\r\n\r\nexport function setScreenStatus(info: { model?: string; project?: string }): void {\r\n\tif (info.model !== undefined) S.model = info.model;\r\n\tif (info.project !== undefined) S.project = info.project;\r\n\tpaint();\r\n}\r\n\r\n/** Clear everything and start output again from the top (used by /clear). */\r\nexport function resetScreen(): void {\r\n\tout.write(`${CSI}2J${CSI}H`);\r\n\tif (!S.active) return;\r\n\tapplyRegion();\r\n\tout.write(chromeString() + `${CSI}1;1H`);\r\n}\r\n\r\nexport function teardownScreen(): void {\r\n\tif (!S.active) return;\r\n\tS.active = false;\r\n\r\n\tconst { rows } = dims();\r\n\tconst first = Math.max(1, rows - CHROME_ROWS + 1);\r\n\tlet wipe = '';\r\n\tfor (let r = first; r <= rows; r++) wipe += `${CSI}${r};1H${CSI}2K`;\r\n\r\n\t// Leave the shell prompt right after the last output line.\r\n\tconst head = S.editing ? '' : SAVE;\r\n\tconst back = S.editing && !S.savedValid ? `${CSI}${first};1H` : RESTORE;\r\n\tout.write(head + CSI + 'r' + wipe + back + CSI + '?25h' + CSI + '?2004l');\r\n}\r\n\r\n// =============================================================================\r\n// Key parsing\r\n// =============================================================================\r\n\r\nexport interface Key {\r\n\tname: string;\r\n\ttext?: string;\r\n}\r\n\r\n// eslint-disable-next-line no-control-regex\r\nconst TOKEN_RE = /\\x1b\\[200~|\\x1b\\[201~|\\x1b\\[[0-9;?]*[ -/]*[@-~]|\\x1bO[A-Za-z]|\\x1b[\\s\\S]|[\\s\\S]/gu;\r\n\r\nconst NAMED: Record<string, string> = {\r\n\t'\\r': 'enter',\r\n\t'\\n': 'enter',\r\n\t'\\x03': 'ctrl+c',\r\n\t'\\x04': 'ctrl+d',\r\n\t'\\x7f': 'backspace',\r\n\t'\\b': 'backspace',\r\n\t'\\t': 'tab',\r\n\t'\\x1b': 'escape',\r\n\t'\\x01': 'home',\r\n\t'\\x05': 'end',\r\n\t'\\x15': 'ctrl+u',\r\n\t'\\x0b': 'ctrl+k',\r\n\t'\\x17': 'ctrl+w',\r\n\t'\\x0c': 'ctrl+l',\r\n\t'\\x1b[A': 'up',\r\n\t'\\x1bOA': 'up',\r\n\t'\\x1b[B': 'down',\r\n\t'\\x1bOB': 'down',\r\n\t'\\x1b[C': 'right',\r\n\t'\\x1bOC': 'right',\r\n\t'\\x1b[D': 'left',\r\n\t'\\x1bOD': 'left',\r\n\t'\\x1b[H': 'home',\r\n\t'\\x1bOH': 'home',\r\n\t'\\x1b[1~': 'home',\r\n\t'\\x1b[F': 'end',\r\n\t'\\x1bOF': 'end',\r\n\t'\\x1b[4~': 'end',\r\n\t'\\x1b[3~': 'delete',\r\n\t'\\x1b[5~': 'pageup',\r\n\t'\\x1b[6~': 'pagedown',\r\n\t'\\x1b[1;5D': 'word-left',\r\n\t'\\x1b[1;3D': 'word-left',\r\n\t'\\x1bb': 'word-left',\r\n\t'\\x1b[1;5C': 'word-right',\r\n\t'\\x1b[1;3C': 'word-right',\r\n\t'\\x1bf': 'word-right',\r\n\t'\\x1b\\x7f': 'ctrl+w',\r\n};\r\n\r\n/**\r\n * Split a stdin chunk into keys. Consecutive printable characters are merged\r\n * into one `text` key, and bracketed pastes arrive as a single `paste` key.\r\n * `state.paste` carries an unfinished paste across chunks.\r\n */\r\nexport function parseKeys(chunk: string, state: { paste: string | null }): Key[] {\r\n\tconst keys: Key[] = [];\r\n\tlet run = '';\r\n\tconst flush = (): void => {\r\n\t\tif (run) keys.push({ name: 'text', text: run });\r\n\t\trun = '';\r\n\t};\r\n\r\n\tfor (const tok of chunk.match(TOKEN_RE) ?? []) {\r\n\t\tif (tok === '\\x1b[200~') {\r\n\t\t\tflush();\r\n\t\t\tstate.paste = '';\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tif (tok === '\\x1b[201~') {\r\n\t\t\tflush();\r\n\t\t\tif (state.paste !== null) keys.push({ name: 'paste', text: state.paste });\r\n\t\t\tstate.paste = null;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tif (state.paste !== null) {\r\n\t\t\tstate.paste += tok;\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst named = NAMED[tok];\r\n\t\tif (named) {\r\n\t\t\tflush();\r\n\t\t\tkeys.push({ name: named });\r\n\t\t} else if ((tok.codePointAt(0) ?? 0) >= 0x20 && !tok.startsWith('\\x1b') && tok !== '\\x7f') {\r\n\t\t\trun += tok;\r\n\t\t} else {\r\n\t\t\tflush();\r\n\t\t\tkeys.push({ name: 'unknown' });\r\n\t\t}\r\n\t}\r\n\tflush();\r\n\treturn keys;\r\n}\r\n\r\n/**\r\n * Put stdin in raw mode and call `handler` for every key until the returned\r\n * function is called, which restores the terminal.\r\n */\r\nexport function listenKeys(handler: (key: Key) => void): () => void {\r\n\tconst stdin = process.stdin;\r\n\tconst state = { paste: null as string | null };\r\n\tconst onData = (chunk: string | Buffer): void => {\r\n\t\tfor (const key of parseKeys(chunk.toString(), state)) handler(key);\r\n\t};\r\n\r\n\tstdin.setRawMode?.(true);\r\n\tstdin.resume();\r\n\tstdin.setEncoding('utf8');\r\n\tif (out.isTTY) out.write(`${CSI}?2004h`); // bracketed paste\r\n\tstdin.on('data', onData);\r\n\r\n\treturn () => {\r\n\t\tstdin.off('data', onData);\r\n\t\tif (out.isTTY) out.write(`${CSI}?2004l`);\r\n\t\tstdin.setRawMode?.(false);\r\n\t\tstdin.pause();\r\n\t};\r\n}\r\n\r\n// =============================================================================\r\n// Line editor\r\n// =============================================================================\r\n\r\nfunction wordLeft(s: string, from: number): number {\r\n\tlet i = from;\r\n\twhile (i > 0 && s[i - 1] === ' ') i--;\r\n\twhile (i > 0 && s[i - 1] !== ' ') i--;\r\n\treturn i;\r\n}\r\n\r\nfunction wordRight(s: string, from: number): number {\r\n\tlet i = from;\r\n\twhile (i < s.length && s[i] === ' ') i++;\r\n\twhile (i < s.length && s[i] !== ' ') i++;\r\n\treturn i;\r\n}\r\n\r\n/** Pasted text is kept on one line: newlines become spaces, controls are dropped. */\r\nfunction sanitizePaste(text: string): string {\r\n\treturn [...text.replace(/\\r\\n|\\r|\\n/g, ' ').replace(/\\t/g, ' ')]\r\n\t\t.filter((ch) => (ch.codePointAt(0) ?? 0) >= 0x20 && ch !== '\\x7f')\r\n\t\t.join('');\r\n}\r\n\r\nfunction completeCommand(): void {\r\n\tif (!S.buffer.startsWith('/') || S.buffer.includes(' ')) return;\r\n\tconst typed = S.buffer.toLowerCase();\r\n\tconst names = S.commands.map((cmd) => cmd.name).filter((n) => n.startsWith(typed));\r\n\tconst first = names[0];\r\n\tif (!first) return;\r\n\r\n\tlet prefix = first;\r\n\tfor (const n of names) while (!n.startsWith(prefix)) prefix = prefix.slice(0, -1);\r\n\tS.buffer = prefix;\r\n\tS.cursor = prefix.length;\r\n}\r\n\r\n/** Cooked-mode fallback for non-TTY stdin and terminals too small for the layout. */\r\nfunction plainQuestion(): Promise<string> {\r\n\treturn new Promise((resolve) => {\r\n\t\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\r\n\t\trl.once('close', () => resolve('/exit'));\r\n\t\trl.question('> ', (answer) => {\r\n\t\t\trl.removeAllListeners('close');\r\n\t\t\trl.close();\r\n\t\t\tresolve(answer.trim());\r\n\t\t});\r\n\t});\r\n}\r\n\r\nexport interface InputController {\r\n\tquestion: (prompt?: string) => Promise<string>;\r\n\tclose: () => void;\r\n\tshowPrompt: () => void;\r\n}\r\n\r\nexport function createInput(): InputController {\r\n\tconst history: string[] = [];\r\n\tlet stop: (() => void) | null = null;\r\n\r\n\treturn {\r\n\t\tquestion(): Promise<string> {\r\n\t\t\tif (!S.active) return plainQuestion();\r\n\r\n\t\t\treturn new Promise<string>((resolve) => {\r\n\t\t\t\tlet histIdx = -1;\r\n\t\t\t\tlet draft = '';\r\n\t\t\t\tlet done = false;\r\n\r\n\t\t\t\tS.editing = true;\r\n\t\t\t\tS.savedValid = true;\r\n\t\t\t\tS.buffer = '';\r\n\t\t\t\tS.cursor = 0;\r\n\t\t\t\tS.offset = 0;\r\n\t\t\t\tout.write(SAVE); // remember where output continues\r\n\t\t\t\tpaint();\r\n\r\n\t\t\t\t// Return the cursor to the scrolling region and go idle.\r\n\t\t\t\tconst leave = (): void => {\r\n\t\t\t\t\tdone = true;\r\n\t\t\t\t\tstop?.();\r\n\t\t\t\t\tstop = null;\r\n\t\t\t\t\tS.editing = false;\r\n\t\t\t\t\tS.buffer = '';\r\n\t\t\t\t\tS.cursor = 0;\r\n\t\t\t\t\tS.offset = 0;\r\n\t\t\t\t\tout.write(S.savedValid ? RESTORE : `${CSI}${regionBottom()};1H`);\r\n\t\t\t\t\tpaint();\r\n\t\t\t\t};\r\n\r\n\t\t\t\tconst quit = (): void => {\r\n\t\t\t\t\tleave();\r\n\t\t\t\t\tprocess.emit('SIGINT'); // lets the REPL print its session summary\r\n\t\t\t\t\tprocess.exit(0);\r\n\t\t\t\t};\r\n\r\n\t\t\t\tconst set = (text: string, cursor: number): void => {\r\n\t\t\t\t\tS.buffer = text;\r\n\t\t\t\t\tS.cursor = cursor;\r\n\t\t\t\t\tpaint();\r\n\t\t\t\t};\r\n\r\n\t\t\t\tstop = listenKeys((key) => {\r\n\t\t\t\t\tif (done) return;\r\n\t\t\t\t\tconst { buffer, cursor } = S;\r\n\r\n\t\t\t\t\tswitch (key.name) {\r\n\t\t\t\t\t\tcase 'enter': {\r\n\t\t\t\t\t\t\tconst line = buffer.trim();\r\n\t\t\t\t\t\t\tif (line && history[0] !== line) history.unshift(line);\r\n\t\t\t\t\t\t\tif (history.length > 100) history.pop();\r\n\t\t\t\t\t\t\tleave();\r\n\t\t\t\t\t\t\tresolve(line);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcase 'ctrl+c':\r\n\t\t\t\t\t\t\tif (buffer) {\r\n\t\t\t\t\t\t\t\thistIdx = -1;\r\n\t\t\t\t\t\t\t\tset('', 0);\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tquit();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'ctrl+d':\r\n\t\t\t\t\t\t\tif (!buffer) quit();\r\n\t\t\t\t\t\t\telse set(buffer.slice(0, cursor) + buffer.slice(cursor + 1), cursor);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'backspace':\r\n\t\t\t\t\t\t\tif (cursor > 0) set(buffer.slice(0, cursor - 1) + buffer.slice(cursor), cursor - 1);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'delete':\r\n\t\t\t\t\t\t\tset(buffer.slice(0, cursor) + buffer.slice(cursor + 1), cursor);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'left':\r\n\t\t\t\t\t\t\tset(buffer, Math.max(0, cursor - 1));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'right':\r\n\t\t\t\t\t\t\tset(buffer, Math.min(buffer.length, cursor + 1));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'home':\r\n\t\t\t\t\t\t\tset(buffer, 0);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'end':\r\n\t\t\t\t\t\t\tset(buffer, buffer.length);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'word-left':\r\n\t\t\t\t\t\t\tset(buffer, wordLeft(buffer, cursor));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'word-right':\r\n\t\t\t\t\t\t\tset(buffer, wordRight(buffer, cursor));\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'ctrl+u':\r\n\t\t\t\t\t\t\tset(buffer.slice(cursor), 0);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'ctrl+k':\r\n\t\t\t\t\t\t\tset(buffer.slice(0, cursor), cursor);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'ctrl+w': {\r\n\t\t\t\t\t\t\tconst j = wordLeft(buffer, cursor);\r\n\t\t\t\t\t\t\tset(buffer.slice(0, j) + buffer.slice(cursor), j);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcase 'ctrl+l':\r\n\t\t\t\t\t\t\tpaint();\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'tab':\r\n\t\t\t\t\t\t\tcompleteCommand();\r\n\t\t\t\t\t\t\tpaint();\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'up':\r\n\t\t\t\t\t\t\tif (histIdx < history.length - 1) {\r\n\t\t\t\t\t\t\t\tif (histIdx === -1) draft = buffer;\r\n\t\t\t\t\t\t\t\thistIdx++;\r\n\t\t\t\t\t\t\t\tconst entry = history[histIdx] ?? '';\r\n\t\t\t\t\t\t\t\tset(entry, entry.length);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'down':\r\n\t\t\t\t\t\t\tif (histIdx >= 0) {\r\n\t\t\t\t\t\t\t\thistIdx--;\r\n\t\t\t\t\t\t\t\tconst entry = histIdx === -1 ? draft : (history[histIdx] ?? '');\r\n\t\t\t\t\t\t\t\tset(entry, entry.length);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\tcase 'text':\r\n\t\t\t\t\t\tcase 'paste': {\r\n\t\t\t\t\t\t\tconst text = key.name === 'paste' ? sanitizePaste(key.text ?? '') : (key.text ?? '');\r\n\t\t\t\t\t\t\tif (text) set(buffer.slice(0, cursor) + text + buffer.slice(cursor), cursor + text.length);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tdefault:\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t},\r\n\r\n\t\tclose(): void {\r\n\t\t\tstop?.();\r\n\t\t\tstop = null;\r\n\t\t},\r\n\r\n\t\tshowPrompt(): void {\r\n\t\t\tpaint();\r\n\t\t},\r\n\t};\r\n}\r\n\r\n// =============================================================================\r\n// Picker (arrow keys + type-to-filter), rendered in the scrolling region\r\n// =============================================================================\r\n\r\nexport interface PickItem {\r\n\tvalue: string;\r\n\tlabel: string;\r\n\thint?: string;\r\n}\r\n\r\n/**\r\n * Let the user choose one item. Resolves with its value, or null when cancelled\r\n * (or when there is no interactive terminal). With `allowCustom`, a typed value\r\n * that matches nothing can be chosen as-is.\r\n */\r\nexport function pick(opts: {\r\n\ttitle: string;\r\n\titems: PickItem[];\r\n\tcurrent?: string;\r\n\tallowCustom?: boolean;\r\n}): Promise<string | null> {\r\n\tif (!process.stdin.isTTY || !out.isTTY) return Promise.resolve(null);\r\n\r\n\tconst { rows, cols } = dims();\r\n\tconst visible = Math.max(3, Math.min(10, rows - (S.active ? CHROME_ROWS : 0) - 5));\r\n\tconst height = visible + 3; // title, search, items, footer\r\n\tconst max = cols - 1;\r\n\r\n\tlet filter = '';\r\n\tlet top = 0;\r\n\tlet sel = Math.max(0, opts.items.findIndex((it) => it.value === opts.current));\r\n\r\n\tconst matches = (): PickItem[] => {\r\n\t\tconst words = filter.toLowerCase().split(/\\s+/).filter(Boolean);\r\n\t\tconst list = opts.items.filter((it) => {\r\n\t\t\tconst hay = (it.label + ' ' + (it.hint ?? '')).toLowerCase();\r\n\t\t\treturn words.every((w) => hay.includes(w));\r\n\t\t});\r\n\t\t// Custom IDs look like \"org/name\". The entry goes last, so Enter picks the\r\n\t\t// best filtered match and the custom ID is first only when nothing matches.\r\n\t\tconst typed = filter.trim();\r\n\t\tif (opts.allowCustom && typed.includes('/') && !opts.items.some((it) => it.value === typed)) {\r\n\t\t\tlist.push({ value: typed, label: typed, hint: 'use as typed' });\r\n\t\t}\r\n\t\treturn list;\r\n\t};\r\n\r\n\tconst frame = (): string[] => {\r\n\t\tconst list = matches();\r\n\t\tsel = Math.min(sel, Math.max(0, list.length - 1));\r\n\t\tif (sel < top) top = sel;\r\n\t\tif (sel >= top + visible) top = sel - visible + 1;\r\n\r\n\t\tconst lines: string[] = [\r\n\t\t\tc.bold(clipText(opts.title, max - 16)) + c.dim(` ${list.length} of ${opts.items.length}`),\r\n\t\t\tc.dim(' search \u203A ') + clipText(filter, max - 14) + c.dim('\u258F'),\r\n\t\t];\r\n\t\tfor (let i = 0; i < visible; i++) {\r\n\t\t\tconst it = list[top + i];\r\n\t\t\tif (!it) {\r\n\t\t\t\tlines.push(i === 0 && list.length === 0 ? c.dim(' no matches') : '');\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst isSel = top + i === sel;\r\n\t\t\tconst isCur = it.value === opts.current;\r\n\t\t\tconst label = clipText(it.label, max - 6);\r\n\t\t\tconst room = max - 3 - label.length - (isCur ? 2 : 0) - 2;\r\n\t\t\tconst hint = it.hint && room > 8 ? ' ' + clipText(it.hint, room) : '';\r\n\t\t\tlines.push(\r\n\t\t\t\t(isSel ? c.magenta(' \u203A ') : ' ') +\r\n\t\t\t\t\t(isSel ? c.magenta.bold(label) : label) +\r\n\t\t\t\t\t(isCur ? c.green(' \u2713') : '') +\r\n\t\t\t\t\tc.dim(hint),\r\n\t\t\t);\r\n\t\t}\r\n\t\tlines.push(c.dim(clipText(' \u2191\u2193 move \u00B7 enter select \u00B7 esc cancel \u00B7 type to filter', max)));\r\n\t\treturn lines;\r\n\t};\r\n\r\n\tconst draw = (first: boolean): void => {\r\n\t\tconst body = frame()\r\n\t\t\t.map((l) => `${CSI}2K${l}\\n`)\r\n\t\t\t.join('');\r\n\t\tout.write((first ? '' : `${CSI}${height}A\\r`) + body);\r\n\t};\r\n\r\n\treturn new Promise<string | null>((resolve) => {\r\n\t\tlet done = false;\r\n\t\tlet stop: () => void = () => undefined;\r\n\r\n\t\tconst end = (value: string | null): void => {\r\n\t\t\tdone = true;\r\n\t\t\tstop();\r\n\t\t\t// Remove the picker lines from the scrolling region.\r\n\t\t\tout.write(`${CSI}${height}A\\r${CSI}${height}M${CSI}?25h`);\r\n\t\t\tresolve(value);\r\n\t\t};\r\n\r\n\t\tout.write(CSI + '?25l');\r\n\t\tdraw(true);\r\n\r\n\t\tstop = listenKeys((key) => {\r\n\t\t\tif (done) return;\r\n\t\t\tconst list = matches();\r\n\t\t\tconst resetFilter = (): void => {\r\n\t\t\t\tsel = 0;\r\n\t\t\t\ttop = 0;\r\n\t\t\t};\r\n\r\n\t\t\tswitch (key.name) {\r\n\t\t\t\tcase 'up':\r\n\t\t\t\t\tsel = Math.max(0, sel - 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'down':\r\n\t\t\t\t\tsel = Math.min(Math.max(0, list.length - 1), sel + 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'pageup':\r\n\t\t\t\t\tsel = Math.max(0, sel - visible);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'pagedown':\r\n\t\t\t\t\tsel = Math.min(Math.max(0, list.length - 1), sel + visible);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'home':\r\n\t\t\t\t\tsel = 0;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'end':\r\n\t\t\t\t\tsel = Math.max(0, list.length - 1);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'backspace':\r\n\t\t\t\t\tfilter = filter.slice(0, -1);\r\n\t\t\t\t\tresetFilter();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'ctrl+u':\r\n\t\t\t\t\tfilter = '';\r\n\t\t\t\t\tresetFilter();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'text':\r\n\t\t\t\tcase 'paste':\r\n\t\t\t\t\tfilter += sanitizePaste(key.text ?? '');\r\n\t\t\t\t\tresetFilter();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'enter':\r\n\t\t\t\t\tend(list[sel]?.value ?? null);\r\n\t\t\t\t\treturn;\r\n\t\t\t\tcase 'escape':\r\n\t\t\t\tcase 'ctrl+c':\r\n\t\t\t\t\tend(null);\r\n\t\t\t\t\treturn;\r\n\t\t\t\tdefault:\r\n\t\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tdraw(false);\r\n\t\t});\r\n\t});\r\n}\r\n", "// =============================================================================\r\n// Agent-Termo \u2014 Main REPL entry point\r\n// =============================================================================\r\n\r\nimport { NimClient, fromWireToolName } from './llm/client.js';\r\nimport { TOOL_DEFINITIONS } from './llm/tools.js';\r\nimport { executeTool, applyFileChange } from './tools/index.js';\r\nimport { loadMemory, logToTimeline, logAgentTermoTimeline } from './memory/index.js';\r\nimport { loadAllAgents } from './agents/index.js';\r\nimport { buildSystemPrompt } from './agents/index.js';\r\nimport { resolveProjectRoot, saveNimModel } from './utils/config.js';\r\nimport {\r\n\tMarkdownPrinter,\r\n\tprintWelcome,\r\n\tprintUserMessage,\r\n\tprintAssistantMessage,\r\n\tprintToolCall,\r\n\tprintToolResult,\r\n\tprintError,\r\n\tprintSuccess,\r\n\tprintInfo,\r\n\tprintHelp,\r\n\tprintAgentsList,\r\n\tprintMemoryFile,\r\n\tprintTimelineFile,\r\n\tstartSpinner,\r\n\tstopSpinner,\r\n\tclearScreen,\r\n\tcreateInput,\r\n\tinitScreen,\r\n\tpick,\r\n\tsetScreenStatus,\r\n\tpromptAcceptReject,\r\n} from './ui/index.js';\r\nimport type { ConversationMessage, ToolCall, ProposedFileChange } from './types/index.js';\r\n\r\nconst TOOL_KEYWORDS = [\r\n\t'build', 'create', 'write', 'edit', 'modify', 'file', 'code', 'function', 'class',\r\n\t'component', 'debug', 'fix', 'git', 'commit', 'push', 'install', 'npm', 'run',\r\n\t'bash', 'shell', 'command', 'read', 'grep', 'check', 'show', 'implement',\r\n\t'configure', 'setup', 'src', 'package', 'app', 'project', 'api', 'deploy',\r\n\t'test', 'compile', 'typescript', 'javascript', 'python', 'node', 'add', 'delete',\r\n];\r\n\r\nfunction mightNeedTools(message: string): boolean {\r\n\tconst lower = message.toLowerCase();\r\n\treturn TOOL_KEYWORDS.some((w) => lower.includes(w));\r\n}\r\n\r\nfunction dedup(arr: ToolCall[]): ToolCall[] {\r\n\tconst seen = new Set<string>();\r\n\treturn arr.filter((tc) => {\r\n\t\tif (seen.has(tc.id)) return false;\r\n\t\tseen.add(tc.id);\r\n\t\treturn true;\r\n\t});\r\n}\r\n\r\n/**\r\n * Get a plain-text assistant response without tool calling: stream first, fall\r\n * back to a single non-streaming completion. Appends the assistant message to\r\n * the conversation and prints it. Never throws: if both the stream and the\r\n * retry fail, an LLM error is printed and no message is appended.\r\n */\r\nasync function replyWithText(\r\n\tconversation: ConversationMessage[],\r\n\tnimClient: NimClient,\r\n): Promise<void> {\r\n\tstartSpinner('Thinking');\r\n\tconst md = new MarkdownPrinter(() => stopSpinner());\r\n\ttry {\r\n\t\tconst gen = nimClient.streamComplete(conversation, undefined, (text: string) => md.push(text));\r\n\t\t// The generator streams everything, then yields once at the end; the\r\n\t\t// chunks have already been rendered through the callback.\r\n\t\tawait gen.next();\r\n\t\tmd.end();\r\n\t\tstopSpinner();\r\n\t\treturn;\r\n\t} catch {\r\n\t\tmd.end();\r\n\t\tstopSpinner();\r\n\t}\r\n\r\n\tstartSpinner('Retrying');\r\n\ttry {\r\n\t\tconst result = await nimClient.complete(conversation, undefined);\r\n\t\tstopSpinner();\r\n\t\tconst cleanText = (result.content ?? '').trim();\r\n\t\tif (cleanText) {\r\n\t\t\tconversation.push({\r\n\t\t\t\tid: crypto.randomUUID(),\r\n\t\t\t\trole: 'assistant',\r\n\t\t\t\tcontent: cleanText,\r\n\t\t\t\ttimestamp: new Date(),\r\n\t\t\t});\r\n\t\t\tprintAssistantMessage(cleanText);\r\n\t\t}\r\n\t} catch (err) {\r\n\t\tstopSpinner();\r\n\t\tprintError('LLM error: ' + (err instanceof Error ? err.message : String(err)));\r\n\t}\r\n}\r\n\r\n/**\r\n * Parse JSON tool calls that a non-tool-calling model may emit as plain text,\r\n * e.g. {\"tool_calls\":[{\"id\":\"call_1\",\"name\":\"file:write\",\"arguments\":{...}}]}.\r\n * Returns an empty array when nothing parseable is found.\r\n */\r\nfunction parseToolCallsFromText(text: string): ToolCall[] {\r\n\tlet cleaned = (text ?? '').trim();\r\n\tcleaned = cleaned.replace(/^```(?:json)?\\s*/i, '').replace(/```\\s*$/i, '').trim();\r\n\r\n\tlet obj: { tool_calls?: unknown };\r\n\ttry {\r\n\t\tobj = JSON.parse(cleaned);\r\n\t} catch {\r\n\t\tconst start = cleaned.indexOf('{');\r\n\t\tconst end = cleaned.lastIndexOf('}');\r\n\t\tif (start === -1 || end === -1 || end <= start) return [];\r\n\t\ttry {\r\n\t\t\tobj = JSON.parse(cleaned.slice(start, end + 1));\r\n\t\t} catch {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t}\r\n\r\n\tconst rawCalls = Array.isArray(obj.tool_calls) ? obj.tool_calls : [];\r\n\treturn rawCalls.map((tc: { id?: string; name?: string; function?: { name?: string; arguments?: unknown } }) => ({\r\n\t\tid: tc.id ?? crypto.randomUUID(),\r\n\t\tname: fromWireToolName(tc.name ?? (tc.function?.name ?? '')),\r\n\t\targuments:\r\n\t\t\ttypeof tc.function?.arguments === 'string'\r\n\t\t\t\t? (() => { try { return JSON.parse(tc.function.arguments as string); } catch { return { _raw: tc.function.arguments }; } })()\r\n\t\t\t\t: (tc.function?.arguments ?? {}),\r\n\t}));\r\n}\r\n\r\nfunction extractProposedChange(toolName: string, resultOutput: string): ProposedFileChange | undefined {\r\n\tconst isFileTool = toolName === 'file:write' || toolName === 'file:edit' || toolName === 'file:delete';\r\n\tif (!isFileTool) return undefined;\r\n\ttry {\r\n\t\tconst parsed = JSON.parse(resultOutput);\r\n\t\tif (parsed?.needsApproval && parsed?.proposedChange) {\r\n\t\t\treturn parsed.proposedChange as ProposedFileChange;\r\n\t\t}\r\n\t} catch {\r\n\t\t// Not JSON \u2014 tool returned a simple string\r\n\t}\r\n\treturn undefined;\r\n}\r\n\r\ninterface InputController {\r\n\tclose(): void;\r\n\tshowPrompt(): void;\r\n}\r\n\r\n/**\r\n * Open a VS Code diff window for the proposed change.\r\n * Writes original + proposed content to temp files and launches `code --diff`.\r\n */\r\nasync function openVsCodeDiff(change: ProposedFileChange): Promise<void> {\r\n\ttry {\r\n\t\tconst { exec } = await import('node:child_process');\r\n\t\tconst { promisify } = await import('node:util');\r\n\t\tconst { mkdtemp, writeFile } = await import('node:fs/promises');\r\n\t\tconst { basename } = await import('node:path');\r\n\t\tconst { tmpdir } = await import('node:os');\r\n\r\n\t\tconst execAsync = promisify(exec);\r\n\r\n\t\tconst originalPath = change.path;\r\n\t\tconst tmpDir = await mkdtemp(tmpdir() + '/agent-termo-diff-');\r\n\t\tconst tmpFile = tmpDir + '/' + basename(originalPath);\r\n\r\n\t\tawait writeFile(tmpFile, change.proposedContent, 'utf-8');\r\n\r\n\t\t// Write original content to a temp file for diff display\r\n\t\tif (!change.isNewFile && change.originalContent.length > 0) {\r\n\t\t\tconst originalTmp = tmpDir + '/original-' + basename(originalPath);\r\n\t\t\tawait writeFile(originalTmp, change.originalContent, 'utf-8');\r\n\t\t\texecAsync(`code --diff \"${originalTmp}\" \"${tmpFile}\" --wait`).catch(() => {\r\n\t\t\t\t// VS Code not available or user closed \u2014 continue silently\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\t// New file: just open the proposed file\r\n\t\t\texecAsync(`code \"${tmpFile}\" --wait`).catch(() => {\r\n\t\t\t\t// Silently fall back\r\n\t\t\t});\r\n\t\t}\r\n\t} catch {\r\n\t\t// Silently fall back to terminal diff view\r\n\t}\r\n}\r\n\r\nasync function executeToolWithReview(\r\n\ttoolName: string,\r\n\targs: Record<string, unknown>,\r\n\tprojectRoot: string,\r\n\tinput: InputController,\r\n): Promise<{ toolResult: { success: boolean; output?: string; error?: string }; change?: ProposedFileChange; applied: boolean }> {\r\n\tprintToolCall(toolName, args);\r\n\tstartSpinner('Running ' + toolName);\r\n\tconst toolResult = await executeTool(toolName, args, projectRoot);\r\n\tstopSpinner(toolResult.success);\r\n\r\n\tconst proposedChange = extractProposedChange(toolName, toolResult.output ?? '');\r\n\r\n\tif (proposedChange) {\r\n\t\t// Pause REPL input to prevent stale listeners from interfering with promptAcceptReject\r\n\t\tinput.close();\r\n\r\n\t\t// Show terminal diff viewer\r\n\t\tprintToolResult(toolName, { success: toolResult.success, output: toolResult.output, error: toolResult.error }, { needsApproval: true, proposedChange });\r\n\r\n\t\t// Also open VS Code diff window (non-blocking, fire-and-forget)\r\n\t\topenVsCodeDiff(proposedChange);\r\n\r\n\t\tconst decision = await promptAcceptReject('Accept this change?');\r\n\r\n\t\t// Restore input for next REPL iteration\r\n\t\tinput.showPrompt();\r\n\r\n\t\tif (decision === 'accept') {\r\n\t\t\tstartSpinner('Writing to disk');\r\n\t\t\tconst applyResult = await applyFileChange(proposedChange, projectRoot);\r\n\t\t\tstopSpinner(applyResult.success);\r\n\t\t\tif (applyResult.success) {\r\n\t\t\t\tprintSuccess(applyResult.output ?? 'Change applied');\r\n\t\t\t\treturn { toolResult: applyResult, change: proposedChange, applied: true };\r\n\t\t\t} else {\r\n\t\t\t\tprintError(applyResult.error ?? 'Failed to apply change');\r\n\t\t\t\treturn { toolResult: applyResult, change: proposedChange, applied: false };\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tprintInfo('Change rejected \u2014 file was not modified');\r\n\t\t\treturn { toolResult, change: proposedChange, applied: false };\r\n\t\t}\r\n\t}\r\n\r\n\tprintToolResult(toolName, toolResult);\r\n\treturn { toolResult, applied: false };\r\n}\r\n\r\n/**\r\n * Run the tool-call loop: execute tools, feed results back to the LLM,\r\n * and repeat until the LLM stops issuing tool calls.\r\n */\r\nasync function runToolLoop(\r\n\tconversation: ConversationMessage[],\r\n\tprojectRoot: string,\r\n\tinitialToolCalls: ToolCall[],\r\n\tinput: InputController,\r\n\tnimClient: NimClient,\r\n): Promise<string> {\r\n\tlet toolCalls = initialToolCalls;\r\n\tlet finalText = '';\r\n\r\n\t// Continue looping while the LLM keeps issuing tool calls\r\n\twhile (toolCalls.length > 0) {\r\n\t\t// OpenAI-compatible APIs require the assistant tool-call message directly\r\n\t\t// before the corresponding tool results. Without this message, the next\r\n\t\t// request is rejected and file operations appear not to work.\r\n\t\tconversation.push({\r\n\t\t\tid: crypto.randomUUID(),\r\n\t\t\trole: 'assistant',\r\n\t\t\tcontent: finalText || '',\r\n\t\t\ttoolCalls,\r\n\t\t\ttimestamp: new Date(),\r\n\t\t});\r\n\r\n\t\t// Execute all tool calls from this turn\r\n\t\tfor (const tc of toolCalls) {\r\n\t\t\tconst execution = await executeToolWithReview(tc.name, tc.arguments, projectRoot, input);\r\n\r\n\t\t\tconst toolResult = execution.toolResult;\r\n\t\t\tconst statusText = toolResult.success ? 'OK' : ('ERR: ' + (toolResult.error ? toolResult.error.slice(0, 80) : 'unknown error'));\r\n\t\t\tconst changeNote = execution.change ? (execution.applied ? ' (applied)' : ' (rejected)') : '';\r\n\r\n\t\t\t\tconversation.push({\r\n\t\t\t\t\tid: tc.id,\r\n\t\t\t\t\trole: 'tool',\r\n\t\t\t\tcontent: (toolResult.success ? 'Result: ' : 'Error: ') + (toolResult.success ? (toolResult.output ?? '') : toolResult.error) + changeNote,\r\n\t\t\t\ttimestamp: new Date(),\r\n\t\t\t});\r\n\r\n\t\t\tlogToTimeline(projectRoot, 'Tool: ' + tc.name + ' -- ' + statusText + changeNote);\r\n\t\t\tlogAgentTermoTimeline('Tool: ' + tc.name + ' -- ' + statusText + changeNote);\r\n\t\t}\r\n\r\n\t\t// Send conversation (including tool results) back to the LLM\r\n\t\t// The LLM will either produce text or more tool calls\r\n\t\tstartSpinner('Working');\r\n\t\tlet result: { content: string; toolCalls: ToolCall[] };\r\n\t\ttry {\r\n\t\t\tconst tools = nimClient.buildToolDefs(TOOL_DEFINITIONS);\r\n\t\t\tresult = await nimClient.complete(conversation, tools);\r\n\t\t} catch {\r\n\t\t\t// Model doesn't support native tool calling \u2014 fall back to plain text\r\n\t\t\t// and parse any JSON tool calls emitted in the content.\r\n\t\t\ttry {\r\n\t\t\t\tconst fallback = await nimClient.complete(conversation, undefined);\r\n\t\t\t\tresult = {\r\n\t\t\t\t\tcontent: fallback.content,\r\n\t\t\t\t\ttoolCalls: parseToolCallsFromText(fallback.content),\r\n\t\t\t\t};\r\n\t\t\t} catch (err2) {\r\n\t\t\t\tstopSpinner();\r\n\t\t\t\tprintError('LLM error: ' + (err2 instanceof Error ? err2.message : String(err2)));\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\tstopSpinner();\r\n\r\n\t\tfinalText = result.content;\r\n\t\ttoolCalls = dedup(result.toolCalls);\r\n\r\n\t\t// If the LLM produced text alongside tool calls, save it\r\n\t\tif (finalText && finalText.trim() && finalText.trim() !== 'null') {\r\n\t\t\t\tif (toolCalls.length === 0) {\r\n\t\t\t\t\tconversation.push({\r\n\t\t\t\t\t\tid: crypto.randomUUID(),\r\n\t\t\t\t\t\trole: 'assistant',\r\n\t\t\t\t\t\tcontent: finalText.trim(),\r\n\t\t\t\t\t\ttimestamp: new Date(),\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t// Narration that comes with more tool calls is shown now; the\r\n\t\t\t// final answer (no tool calls) is printed by the caller.\r\n\t\t\tif (toolCalls.length > 0) printAssistantMessage(finalText.trim());\r\n\t\t}\r\n\t}\r\n\r\n\treturn finalText;\r\n}\r\n\r\n/**\r\n * /model \u2014 pick from the live NVIDIA NIM catalogue (falls back to a built-in list)\r\n * /model <model-id> \u2014 switch directly, e.g. /model meta/llama-3.3-70b-instruct\r\n */\r\nasync function handleModelCommand(arg: string, nimClient: NimClient, projectRoot: string): Promise<void> {\r\n\tlet selected: string | null = arg || null;\r\n\r\n\tif (!selected) {\r\n\t\tstartSpinner('Fetching NVIDIA NIM models');\r\n\t\tconst { models, live, error } = await nimClient.listModels();\r\n\t\tstopSpinner();\r\n\t\tif (!live) {\r\n\t\t\tprintInfo('Could not fetch the live model list (' + (error ?? 'unknown error') + '). Showing built-in suggestions; you can type any model ID.');\r\n\t\t}\r\n\r\n\t\tselected = await pick({\r\n\t\t\ttitle: 'Select a model',\r\n\t\t\titems: models.map((m) => ({ value: m.id, label: m.id, hint: m.note })),\r\n\t\t\tcurrent: nimClient.getModel(),\r\n\t\t\tallowCustom: true,\r\n\t\t});\r\n\t\tif (!selected) {\r\n\t\t\tprintInfo('Model unchanged: ' + nimClient.getModel());\r\n\t\t\treturn;\r\n\t\t}\r\n\t}\r\n\r\n\tif (selected === nimClient.getModel()) {\r\n\t\tprintInfo('Already using ' + selected);\r\n\t\treturn;\r\n\t}\r\n\r\n\tnimClient.setModel(selected);\r\n\tsetScreenStatus({ model: selected });\r\n\tlogAgentTermoTimeline('Model switched to ' + selected);\r\n\tlogToTimeline(projectRoot, 'Model switched to ' + selected);\r\n\r\n\ttry {\r\n\t\tsaveNimModel(selected);\r\n\t\tprintSuccess('Model set to ' + selected + ' (saved as your default)');\r\n\t} catch {\r\n\t\tprintSuccess('Model set to ' + selected + ' for this session');\r\n\t\tprintInfo('Could not save it as your default.');\r\n\t}\r\n}\r\n\r\nexport async function runRepl(projectRoot?: string): Promise<void> {\r\n\tprojectRoot = resolveProjectRoot(projectRoot);\r\n\r\n\tconst memory = await loadMemory(projectRoot);\r\n\tconst nimClient = new NimClient(projectRoot);\r\n\tconst systemPrompt = buildSystemPrompt(memory, '', projectRoot);\r\n\r\n\tconst session = { id: crypto.randomUUID(), projectRoot, startedAt: new Date() };\r\n\r\n\tconst conversation: ConversationMessage[] = [\r\n\t\t{\r\n\t\t\tid: crypto.randomUUID(),\r\n\t\t\trole: 'system',\r\n\t\t\tcontent: systemPrompt,\r\n\t\t\ttimestamp: new Date(),\r\n\t\t},\r\n\t];\r\n\r\n\tinitScreen({ model: nimClient.getModel(), project: projectRoot });\r\n\tprintWelcome(projectRoot, nimClient.getModel());\r\n\tlogAgentTermoTimeline('Agent-Termo session started. Model: ' + nimClient.getModel());\r\n\tlogToTimeline(projectRoot, 'Agent-Termo session started. Model: ' + nimClient.getModel());\r\n\tlogAgentTermoTimeline('Commands: /help /clear /memory /timeline /model /agents /history');\r\n\tlogToTimeline(projectRoot, 'Commands: /help /clear /memory /timeline /model /agents /history');\r\n\r\n\tconst input = createInput();\r\n\r\n\tconst cleanup = () => {\r\n\t\tinput.close();\r\n\t\tprocess.stdout.write('\\n');\r\n\t\tconsole.log(\r\n\t\t\t'Session complete. ' +\r\n\t\t\tMath.round((Date.now() - session.startedAt.getTime()) / 60000) +\r\n\t\t\t' minutes.',\r\n\t\t);\r\n\t\tprocess.exit(0);\r\n\t};\r\n\tprocess.on('SIGINT', cleanup);\r\n\r\n\tmainLoop: while (true) {\r\n\t\ttry {\r\n\t\t\tconst userInput = await input.question('');\r\n\t\t\tif (!userInput) continue;\r\n\t\t\tif (userInput === 'exit' || userInput === 'quit') {\r\n\t\t\t\tcleanup();\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\tif (userInput.startsWith('/')) {\r\n\t\t\t\tconst cmd = userInput.toLowerCase().trim();\r\n\t\t\t\tprintUserMessage(userInput);\r\n\r\n\t\t\t\tif (cmd === '/help' || cmd === '/') {\r\n\t\t\t\t\tprintHelp();\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/clear' || cmd === '/cls') {\r\n\t\t\t\t\tconversation.length = 1;\r\n\t\t\t\t\tclearScreen();\r\n\t\t\t\t\tprintWelcome(projectRoot, nimClient.getModel());\r\n\t\t\t\t\tprintSuccess('Conversation cleared.');\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/memory') {\r\n\t\t\t\t\tawait printMemoryFile();\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/timeline' || cmd === '/tl') {\r\n\t\t\t\t\tawait printTimelineFile();\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/model' || cmd.startsWith('/model ')) {\r\n\t\t\t\t\t// Take the argument from the original text: model IDs are case-sensitive.\r\n\t\t\t\t\tawait handleModelCommand(userInput.trim().slice('/model'.length).trim(), nimClient, projectRoot);\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/agents') {\r\n\t\t\t\t\tconst agents = loadAllAgents(process.env.AGENT_TERMO_DIR || '.claude');\r\n\t\t\t\t\tprintAgentsList(agents);\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/history' || cmd === '/hist') {\r\n\t\t\t\t\tprintInfo('Conversation (excluding system): ' + (conversation.length - 1) + ' messages');\r\n\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t}\r\n\t\t\t\tif (cmd === '/exit' || cmd === '/quit') {\r\n\t\t\t\t\tcleanup();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tprintError('Unknown command: ' + cmd, 'Type /help for available commands.');\r\n\t\t\t\tcontinue mainLoop;\r\n\t\t\t}\r\n\r\n\t\t\tconst userMsg: ConversationMessage = {\r\n\t\t\t\tid: crypto.randomUUID(),\r\n\t\t\t\trole: 'user',\r\n\t\t\t\tcontent: userInput,\r\n\t\t\t\ttimestamp: new Date(),\r\n\t\t\t};\r\n\t\t\tconversation.push(userMsg);\r\n\t\t\tprintUserMessage(userInput);\r\n\r\n\t\t\tconst useTools = mightNeedTools(userInput);\r\n\t\t\tconst tools = useTools ? nimClient.buildToolDefs(TOOL_DEFINITIONS) : undefined;\r\n\r\n\t\t\tif (useTools) {\r\n\t\t\t\tstartSpinner('Working');\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst result = await nimClient.complete(conversation, tools);\r\n\t\t\t\t\tconst fullText = result.content;\r\n\t\t\t\t\tlet toolCalls = dedup(result.toolCalls);\r\n\t\t\t\t\tstopSpinner();\r\n\r\n\t\t\t\t\tif (toolCalls.length === 0) {\r\n\t\t\t\t\t\t// No tool calls \u2014 just display the text response\r\n\t\t\t\t\t\tconst cleanText = (fullText ?? '').trim().replace(/^null$/, '').trim();\r\n\t\t\t\t\t\tif (cleanText) {\r\n\t\t\t\t\t\t\tconversation.push({\r\n\t\t\t\t\t\t\t\tid: crypto.randomUUID(),\r\n\t\t\t\t\t\t\t\trole: 'assistant',\r\n\t\t\t\t\t\t\t\tcontent: cleanText,\r\n\t\t\t\t\t\t\t\ttimestamp: new Date(),\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\tprintAssistantMessage(cleanText);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// Show any narration that came with the first tool calls\r\n\t\t\t\t\t\tconst narration = (fullText ?? '').trim().replace(/^null$/, '').trim();\r\n\t\t\t\t\t\tif (narration) printAssistantMessage(narration);\r\n\r\n\t\t\t\t\t\t// Run the tool-call loop: execute tools, feed results back, repeat\r\n\t\t\t\t\t\tconst finalText = await runToolLoop(conversation, projectRoot, toolCalls, input, nimClient);\r\n\t\t\t\t\t\tif (finalText && finalText.trim() && finalText.trim() !== 'null') {\r\n\t\t\t\t\t\t\tprintAssistantMessage(finalText.trim());\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (err) {\r\n\t\t\t\t\tstopSpinner();\r\n\t\t\t\t\t// Tool calling failed (e.g. HTTP 400 because the model does not\r\n\t\t\t\t\t// support the `tools` parameter). Retry without tools and parse\r\n\t\t\t\t\t// any JSON tool calls the model may have emitted as plain text.\r\n\t\t\t\t\tprintInfo('Tool calls not supported by this model \u2014 retrying without tools.');\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tconst fallback = await nimClient.complete(conversation, undefined);\r\n\t\t\t\t\t\tconst toolCalls = dedup(\r\n\t\t\t\t\t\t\tfallback.toolCalls.length > 0 ? fallback.toolCalls : parseToolCallsFromText(fallback.content),\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t\tif (toolCalls.length > 0) {\r\n\t\t\t\t\t\t\tconst narration = (fallback.content ?? '').trim().replace(/^null$/, '').trim();\r\n\t\t\t\t\t\t\tif (narration && !narration.includes('\"tool_calls\"')) printAssistantMessage(narration);\r\n\t\t\t\t\t\t\tconst finalText = await runToolLoop(conversation, projectRoot, toolCalls, input, nimClient);\r\n\t\t\t\t\t\t\tif (finalText && finalText.trim() && finalText.trim() !== 'null') {\r\n\t\t\t\t\t\t\t\tprintAssistantMessage(finalText.trim());\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tconst cleanText = (fallback.content ?? '').trim().replace(/^null$/, '').trim();\r\n\t\t\t\t\t\t\tif (cleanText) {\r\n\t\t\t\t\t\t\t\tconversation.push({ id: crypto.randomUUID(), role: 'assistant', content: cleanText, timestamp: new Date() });\r\n\t\t\t\t\t\t\t\tprintAssistantMessage(cleanText);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t} catch (err2) {\r\n\t\t\t\t\t\tprintError('LLM error: ' + (err2 instanceof Error ? err2.message : String(err2)));\r\n\t\t\t\t\t\tconversation.pop();\r\n\t\t\t\t\t\tcontinue mainLoop;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tawait replyWithText(conversation, nimClient);\r\n\t\t\t}\r\n\r\n\t\t\tif (conversation.length > 42) {\r\n\t\t\t\tconversation.splice(1, conversation.length - 42);\r\n\t\t\t}\r\n\t\t} catch (err) {\r\n\t\t\tstopSpinner();\r\n\t\t\tprintError('Session error: ' + (err instanceof Error ? err.message : String(err)));\r\n\t\t}\r\n\t}\r\n}\r\n"],
5
+ "mappings": "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M,GAA8B,CAEzC,CACE,KAAM,YACN,YAAa,mGACb,WAAY,CACV,KAAM,SACN,WAAY,CACV,KAAM,CACJ,KAAM,SACN,YAAa,kDACf,EACA,MAAO,CACL,KAAM,SACN,YAAa,4CACb,QAAS,CACX,EACA,OAAQ,CACN,KAAM,SACN,YAAa,gDACb,QAAS,CACX,CACF,EACA,SAAU,CAAC,MAAM,CACnB,CACF,EACA,CACE,KAAM,aACN,YAAa,sGACb,WAAY,CACV,KAAM,SACN,WAAY,CACV,KAAM,CACJ,KAAM,SACN,YAAa,+CACf,EACA,QAAS,CACP,KAAM,SACN,YAAa,gCACf,CACF,EACA,SAAU,CAAC,OAAQ,SAAS,CAC9B,CACF,EACA,CACE,KAAM,YACN,YAAa,wGACb,WAAY,CACV,KAAM,SACN,WAAY,CACV,KAAM,CACJ,KAAM,SACN,YAAa,cACf,EACA,WAAY,CACV,KAAM,SACN,YAAa,yDACf,EACA,WAAY,CACV,KAAM,SACN,YAAa,kBACf,CACL,EACA,SAAU,CAAC,OAAQ,aAAc,YAAY,CAC9C,CACD,EACA,CACC,KAAM,cACN,YAAa,uFACb,WAAY,CACX,KAAM,SACN,WAAY,CACX,KAAM,CACL,KAAM,SACN,YAAa,gDACd,CACD,EACA,SAAU,CAAC,MAAM,CAClB,CACD,EACA,CACC,KAAM,YACJ,YAAa,6EACb,WAAY,CACV,KAAM,SACN,WAAY,CACV,QAAS,CACP,KAAM,SACN,YAAa,gDACf,EACA,IAAK,CACH,KAAM,SACN,YAAa,wDACf,CACF,EACA,SAAU,CAAC,SAAS,CACtB,CACF,EACA,CACE,KAAM,OACN,YAAa,kGACb,WAAY,CACV,KAAM,SACN,WAAY,CACV,QAAS,CACP,KAAM,SACN,YAAa,qCACf,EACA,KAAM,CACJ,KAAM,SACN,YAAa,gCACf,EACA,KAAM,CACJ,KAAM,SACN,YAAa,8CACf,EACA,eAAgB,CACd,KAAM,UACN,YAAa,uCACb,QAAS,EACX,CACF,EACA,SAAU,CAAC,UAAW,MAAM,CAC9B,CACF,EAEA,CACE,KAAM,eACN,YAAa,wHACb,WAAY,CACV,KAAM,SAC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",
6
+ "names": ["Command", "OpenAI", "CURATED_MODELS", "NON_CHAT", "isChatModel", "id", "mergeModels", "live", "liveSet", "curated", "m", "curatedIds", "rest", "a", "b", "TOOL_NAME_ALIASES", "toWireToolName", "name", "fromWireToolName", "wireName", "NimClient", "_projectRoot", "apiKey", "baseUrl", "timeout", "OpenAI", "toolSchemas", "t", "model", "ids", "m", "mergeModels", "err", "messages", "tools", "onChunk", "rawChunks", "toolCallMap", "stream", "tc", "chunk", "delta", "rawContent", "idx", "prev", "finalContent", "toolCalls", "args", "msg", "content", "parsed", "jsonStart", "TOOL_DEFINITIONS", "readFileAsync", "writeFileAsync", "unlinkAsync", "resolve", "isAbsolute", "relative", "execAsync", "promisify", "globAsync", "simpleGit", "statSync", "existsSync", "mkdirSync", "chmodSync", "mkdirSync", "readFileSync", "writeFileSync", "resolve", "dirname", "fileURLToPath", "getProjectRoot", "thisFile", "loadEnvFile", "envPath", "content", "line", "trimmed", "eqIdx", "key", "value", "PROJECT_ROOT", "getAgentTermoDir", "envDir", "resolve", "readStoredConfig", "existing", "readFileSync", "updateStoredConfig", "patch", "configDir", "configPath", "storedConfig", "mkdirSync", "writeFileSync", "chmodSync", "loadStoredNimApiKey", "nimApiKey", "loadStoredNimModel", "nimModel", "saveNimApiKey", "apiKey", "saveNimModel", "model", "getConfig", "projectRoot", "loadEnvFile", "resolveProjectRoot", "cwd", "PROJECT_ROOT", "computeDiff", "original", "proposed", "originalLines", "proposedLines", "content", "i", "m", "n", "stride", "table", "get", "j", "set", "val", "ops", "backtrackLCS", "diffLines", "opsToDiffLines", "additions", "deletions", "line", "a", "b", "lines", "originalLineNum", "proposedLineNum", "op", "exec", "promisify", "execAsync", "globPromise", "globAsync", "TOOL_MAP", "toolFileRead", "toolFileWrite", "toolFileEdit", "toolFileDelete", "toolFileGlob", "toolGrep", "toolBash", "toolGitStatus", "toolGitCommit", "toolGitPush", "toolGitLog", "executeTool", "name", "args", "projectRoot", "start", "id", "fn", "TOOL_MAP", "err", "toProjectPath", "path", "isAbsolute", "resolve", "withinProject", "resolved", "rel", "relative", "proposeFileChange", "proposedContent", "changeType", "oldContent", "fullPath", "originalContent", "isNewFile", "existsSync", "isDeletion", "diff", "computeDiff", "change", "lineCount", "summary", "result", "applyFileChange", "unlinkAsync", "dir", "mkdirSync", "writeFileAsync", "toolFileRead", "limit", "offset", "statSync", "lines", "readFileAsync", "sliced", "toolFileWrite", "content", "toolFileEdit", "oldString", "newString", "existingContent", "newContent", "toolFileDelete", "toolFileGlob", "globPattern", "cwd", "files", "globPromise", "toolGrep", "pattern", "caseSensitive", "flags", "includeFlag", "cmd", "stdout", "stderr", "exec", "DANGEROUS_PATTERNS", "toolBash", "command", "timeout", "getConfig", "errorObj", "toolGitStatus", "status", "simpleGit", "tracking", "toolGitCommit", "message", "git", "toolGitPush", "toolGitLog", "readFile", "appendFile", "writeFile", "existsSync", "mkdirSync", "resolve", "ensureAgentTermoDir", "dir", "AGENT_TERMO_MEMORY_PATH", "loadAgentTermoMemory", "AGENT_TERMO_TIMELINE_PATH", "resolve", "ensureAgentTermoDir", "loadAgentTermoTimeline", "existsSync", "readFile", "logAgentTermoTimeline", "message", "entry", "appendFile", "loadMemory", "projectRoot", "path", "TIMELINE_TEMPLATE", "MEMORY_TEMPLATE", "ensureProjectDocs", "projectRoot", "docsDir", "resolve", "memoryPath", "timelinePath", "mkdirSync", "existsSync", "writeFile", "logToTimeline", "projectRoot", "message", "path", "ensureProjectDocs", "timestamp", "appendFile", "readdirSync", "readFileSync", "resolve", "parseAgentMeta", "content", "descMatch", "toolsStr", "tools", "t", "loadAllAgents", "agentDir", "agentsDir", "resolve", "readdirSync", "f", "file", "agentId", "content", "readFileSync", "meta", "parseAgentMeta", "withoutFrontmatter", "a", "b", "SYSTEM_BASE", "buildSystemPrompt", "memory", "timeline", "_agentDir", "prompt", "Chalk", "Chalk", "createInterface", "c", "out", "CSI", "SAVE", "RESTORE", "CHROME_ROWS", "MIN_ROWS", "MIN_COLS", "PLACEHOLDER", "S", "setCommands", "commands", "dims", "terminalWidth", "clipText", "text", "max", "shortPath", "p", "home", "layoutSupported", "statusLine", "typed", "hits", "cmd", "only", "h", "hint", "modelPart", "roomWithHint", "showHint", "projPart", "gap", "chromeString", "rows", "cols", "width", "edge", "body", "top", "line", "row", "inputCursor", "paint", "regionBottom", "applyRegion", "onResize", "initScreen", "info", "teardownScreen", "setScreenStatus", "resetScreen", "first", "wipe", "r", "head", "back", "TOKEN_RE", "NAMED", "parseKeys", "chunk", "state", "keys", "run", "flush", "tok", "named", "listenKeys", "handler", "stdin", "onData", "key", "wordLeft", "s", "from", "i", "wordRight", "sanitizePaste", "ch", "completeCommand", "names", "n", "prefix", "plainQuestion", "resolve", "rl", "answer", "createInput", "history", "stop", "histIdx", "draft", "done", "leave", "quit", "set", "cursor", "buffer", "j", "entry", "pick", "opts", "visible", "height", "filter", "sel", "it", "matches", "words", "list", "hay", "w", "frame", "lines", "isSel", "isCur", "label", "room", "draw", "l", "end", "value", "resetFilter", "c", "Chalk", "out", "COMMANDS", "setCommands", "ANSI_RE", "visibleLength", "s", "rule", "terminalWidth", "printWelcome", "projectRoot", "model", "inner", "room", "row", "content", "field", "label", "value", "clipText", "inline", "text", "seg", "_m", "g", "MarkdownPrinter", "beforeFirstOutput", "nl", "line", "blank", "prefix", "fence", "heading", "bullet", "numbered", "quote", "printUserMessage", "lines", "l", "printAssistantMessage", "md", "printToolCall", "toolName", "args", "summary", "k", "v", "raw", "printToolResult", "result", "parsedOutput", "printDiffViewer", "message", "change", "diff", "color", "num", "promptAcceptReject", "resolve", "done", "stop", "answer", "accepted", "listenKeys", "key", "first", "printError", "hint", "printSuccess", "printInfo", "printMemoryFile", "mem", "loadAgentTermoMemory", "printTimelineFile", "tl", "loadAgentTermoTimeline", "recentCount", "printHelp", "cmd", "keys", "d", "printAgentsList", "agents", "a", "FRAMES", "spinnerTimer", "startSpinner", "stopSpinner", "startedAt", "frame", "render", "secs", "_success", "clearScreen", "resetScreen", "TOOL_KEYWORDS", "mightNeedTools", "message", "lower", "w", "dedup", "arr", "seen", "tc", "replyWithText", "conversation", "nimClient", "startSpinner", "md", "MarkdownPrinter", "stopSpinner", "text", "result", "cleanText", "printAssistantMessage", "err", "printError", "parseToolCallsFromText", "cleaned", "obj", "start", "end", "fromWireToolName", "extractProposedChange", "toolName", "resultOutput", "parsed", "openVsCodeDiff", "change", "exec", "promisify", "mkdtemp", "writeFile", "basename", "tmpdir", "execAsync", "originalPath", "tmpDir", "tmpFile", "originalTmp", "executeToolWithReview", "args", "projectRoot", "input", "printToolCall", "toolResult", "executeTool", "proposedChange", "printToolResult", "decision", "promptAcceptReject", "applyResult", "applyFileChange", "printSuccess", "printInfo", "runToolLoop", "initialToolCalls", "toolCalls", "finalText", "execution", "statusText", "changeNote", "logToTimeline", "logAgentTermoTimeline", "tools", "TOOL_DEFINITIONS", "fallback", "err2", "handleModelCommand", "arg", "selected", "models", "live", "error", "pick", "m", "setScreenStatus", "saveNimModel", "runRepl", "resolveProjectRoot", "memory", "loadMemory", "NimClient", "systemPrompt", "buildSystemPrompt", "session", "initScreen", "printWelcome", "createInput", "cleanup", "mainLoop", "userInput", "cmd", "printUserMessage", "printHelp", "clearScreen", "printMemoryFile", "printTimelineFile", "agents", "loadAllAgents", "printAgentsList", "userMsg", "useTools", "fullText", "narration", "program", "Command", "promptForApiKey", "input", "output", "resolve", "reject", "apiKey", "previousWasCarriageReturn", "restoreTerminal", "onData", "data", "char", "startAgent", "project", "options", "saveNimApiKey", "runRepl", "dir", "mkdirSync", "writeFileSync", "existsSync", "dirsToCreate", "d", "memoryPath", "timelinePath", "main", "err"]
7
7
  }