@mariozechner/pi-coding-agent 0.22.3 → 0.22.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/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased]
3
+ ## [0.22.4] - 2025-12-17
4
+
5
+ ### Added
6
+
7
+ - `--list-models [search]` CLI flag to list available models with optional fuzzy search. Shows provider, model ID, context window, max output, thinking support, and image support. Only lists models with configured API keys. ([#203](https://github.com/badlogic/pi-mono/issues/203))
8
+
9
+ ### Fixed
10
+
11
+ - Fixed tool execution showing green (success) background while still running. Now correctly shows gray (pending) background until the tool completes.
12
+
13
+ ## [0.22.3] - 2025-12-16
4
14
 
5
15
  ### Added
6
16
 
@@ -24,6 +24,7 @@ export interface Args {
24
24
  print?: boolean;
25
25
  export?: string;
26
26
  noSkills?: boolean;
27
+ listModels?: string | true;
27
28
  messages: string[];
28
29
  fileArgs: string[];
29
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE3C,MAAM,WAAW,IAAI;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAID,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,aAAa,CAE1E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA+E9C;AAED,wBAAgB,SAAS,IAAI,IAAI,CAuFhC","sourcesContent":["/**\n * CLI argument parsing and help display\n */\n\nimport type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport chalk from \"chalk\";\nimport { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR } from \"../config.js\";\nimport { allTools, type ToolName } from \"../core/tools/index.js\";\n\nexport type Mode = \"text\" | \"json\" | \"rpc\";\n\nexport interface Args {\n\tprovider?: string;\n\tmodel?: string;\n\tapiKey?: string;\n\tsystemPrompt?: string;\n\tappendSystemPrompt?: string;\n\tthinking?: ThinkingLevel;\n\tcontinue?: boolean;\n\tresume?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n\tmode?: Mode;\n\tnoSession?: boolean;\n\tsession?: string;\n\tmodels?: string[];\n\ttools?: ToolName[];\n\thooks?: string[];\n\tprint?: boolean;\n\texport?: string;\n\tnoSkills?: boolean;\n\tmessages: string[];\n\tfileArgs: string[];\n}\n\nconst VALID_THINKING_LEVELS = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"] as const;\n\nexport function isValidThinkingLevel(level: string): level is ThinkingLevel {\n\treturn VALID_THINKING_LEVELS.includes(level as ThinkingLevel);\n}\n\nexport function parseArgs(args: string[]): Args {\n\tconst result: Args = {\n\t\tmessages: [],\n\t\tfileArgs: [],\n\t};\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i];\n\n\t\tif (arg === \"--help\" || arg === \"-h\") {\n\t\t\tresult.help = true;\n\t\t} else if (arg === \"--version\" || arg === \"-v\") {\n\t\t\tresult.version = true;\n\t\t} else if (arg === \"--mode\" && i + 1 < args.length) {\n\t\t\tconst mode = args[++i];\n\t\t\tif (mode === \"text\" || mode === \"json\" || mode === \"rpc\") {\n\t\t\t\tresult.mode = mode;\n\t\t\t}\n\t\t} else if (arg === \"--continue\" || arg === \"-c\") {\n\t\t\tresult.continue = true;\n\t\t} else if (arg === \"--resume\" || arg === \"-r\") {\n\t\t\tresult.resume = true;\n\t\t} else if (arg === \"--provider\" && i + 1 < args.length) {\n\t\t\tresult.provider = args[++i];\n\t\t} else if (arg === \"--model\" && i + 1 < args.length) {\n\t\t\tresult.model = args[++i];\n\t\t} else if (arg === \"--api-key\" && i + 1 < args.length) {\n\t\t\tresult.apiKey = args[++i];\n\t\t} else if (arg === \"--system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.systemPrompt = args[++i];\n\t\t} else if (arg === \"--append-system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.appendSystemPrompt = args[++i];\n\t\t} else if (arg === \"--no-session\") {\n\t\t\tresult.noSession = true;\n\t\t} else if (arg === \"--session\" && i + 1 < args.length) {\n\t\t\tresult.session = args[++i];\n\t\t} else if (arg === \"--models\" && i + 1 < args.length) {\n\t\t\tresult.models = args[++i].split(\",\").map((s) => s.trim());\n\t\t} else if (arg === \"--tools\" && i + 1 < args.length) {\n\t\t\tconst toolNames = args[++i].split(\",\").map((s) => s.trim());\n\t\t\tconst validTools: ToolName[] = [];\n\t\t\tfor (const name of toolNames) {\n\t\t\t\tif (name in allTools) {\n\t\t\t\t\tvalidTools.push(name as ToolName);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\tchalk.yellow(`Warning: Unknown tool \"${name}\". Valid tools: ${Object.keys(allTools).join(\", \")}`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult.tools = validTools;\n\t\t} else if (arg === \"--thinking\" && i + 1 < args.length) {\n\t\t\tconst level = args[++i];\n\t\t\tif (isValidThinkingLevel(level)) {\n\t\t\t\tresult.thinking = level;\n\t\t\t} else {\n\t\t\t\tconsole.error(\n\t\t\t\t\tchalk.yellow(\n\t\t\t\t\t\t`Warning: Invalid thinking level \"${level}\". Valid values: ${VALID_THINKING_LEVELS.join(\", \")}`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (arg === \"--print\" || arg === \"-p\") {\n\t\t\tresult.print = true;\n\t\t} else if (arg === \"--export\" && i + 1 < args.length) {\n\t\t\tresult.export = args[++i];\n\t\t} else if (arg === \"--hook\" && i + 1 < args.length) {\n\t\t\tresult.hooks = result.hooks ?? [];\n\t\t\tresult.hooks.push(args[++i]);\n\t\t} else if (arg === \"--no-skills\") {\n\t\t\tresult.noSkills = true;\n\t\t} else if (arg.startsWith(\"@\")) {\n\t\t\tresult.fileArgs.push(arg.slice(1)); // Remove @ prefix\n\t\t} else if (!arg.startsWith(\"-\")) {\n\t\t\tresult.messages.push(arg);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nexport function printHelp(): void {\n\tconsole.log(`${chalk.bold(APP_NAME)} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n ${APP_NAME} [options] [@files...] [messages...]\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <id> Model ID (default: gemini-2.5-flash)\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --append-system-prompt <text> Append text or file contents to the system prompt\n --mode <mode> Output mode: text (default), json, or rpc\n --print, -p Non-interactive mode: process prompt and exit\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path> Use specific session file\n --no-session Don't save session (ephemeral)\n --models <patterns> Comma-separated model patterns for quick cycling with Ctrl+P\n --tools <tools> Comma-separated list of tools to enable (default: read,bash,edit,write)\n Available: read, bash, edit, write, grep, find, ls\n --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh\n --hook <path> Load a hook file (can be used multiple times)\n --no-skills Disable skills discovery and loading\n --export <file> Export session file to HTML and exit\n --help, -h Show this help\n --version, -v Show version number\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode\n ${APP_NAME}\n\n # Interactive mode with initial prompt\n ${APP_NAME} \"List all .ts files in src/\"\n\n # Include files in initial message\n ${APP_NAME} @prompt.md @image.png \"What color is the sky?\"\n\n # Non-interactive mode (process and exit)\n ${APP_NAME} -p \"List all .ts files in src/\"\n\n # Multiple messages (interactive)\n ${APP_NAME} \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n ${APP_NAME} --continue \"What did we discuss?\"\n\n # Use different model\n ${APP_NAME} --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n # Limit model cycling to specific models\n ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o\n\n # Cycle models with fixed thinking levels\n ${APP_NAME} --models sonnet:high,haiku:low\n\n # Start with a specific thinking level\n ${APP_NAME} --thinking high \"Solve this complex problem\"\n\n # Read-only mode (no file modifications possible)\n ${APP_NAME} --tools read,grep,find,ls -p \"Review the code in src/\"\n\n # Export a session file to HTML\n ${APP_NAME} --export ~/${CONFIG_DIR_NAME}/agent/sessions/--path--/session.jsonl\n ${APP_NAME} --export session.jsonl output.html\n\n${chalk.bold(\"Environment Variables:\")}\n ANTHROPIC_API_KEY - Anthropic Claude API key\n ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth token (alternative to API key)\n OPENAI_API_KEY - OpenAI GPT API key\n GEMINI_API_KEY - Google Gemini API key\n GROQ_API_KEY - Groq API key\n CEREBRAS_API_KEY - Cerebras API key\n XAI_API_KEY - xAI Grok API key\n OPENROUTER_API_KEY - OpenRouter API key\n ZAI_API_KEY - ZAI API key\n ${ENV_AGENT_DIR.padEnd(23)} - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)\n\n${chalk.bold(\"Available Tools (default: read, bash, edit, write):\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n grep - Search file contents (read-only, off by default)\n find - Find files by glob pattern (read-only, off by default)\n ls - List directory contents (read-only, off by default)\n`);\n}\n"]}
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE3C,MAAM,WAAW,IAAI;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAID,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,aAAa,CAE1E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAsF9C;AAED,wBAAgB,SAAS,IAAI,IAAI,CAwFhC","sourcesContent":["/**\n * CLI argument parsing and help display\n */\n\nimport type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport chalk from \"chalk\";\nimport { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR } from \"../config.js\";\nimport { allTools, type ToolName } from \"../core/tools/index.js\";\n\nexport type Mode = \"text\" | \"json\" | \"rpc\";\n\nexport interface Args {\n\tprovider?: string;\n\tmodel?: string;\n\tapiKey?: string;\n\tsystemPrompt?: string;\n\tappendSystemPrompt?: string;\n\tthinking?: ThinkingLevel;\n\tcontinue?: boolean;\n\tresume?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n\tmode?: Mode;\n\tnoSession?: boolean;\n\tsession?: string;\n\tmodels?: string[];\n\ttools?: ToolName[];\n\thooks?: string[];\n\tprint?: boolean;\n\texport?: string;\n\tnoSkills?: boolean;\n\tlistModels?: string | true;\n\tmessages: string[];\n\tfileArgs: string[];\n}\n\nconst VALID_THINKING_LEVELS = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"] as const;\n\nexport function isValidThinkingLevel(level: string): level is ThinkingLevel {\n\treturn VALID_THINKING_LEVELS.includes(level as ThinkingLevel);\n}\n\nexport function parseArgs(args: string[]): Args {\n\tconst result: Args = {\n\t\tmessages: [],\n\t\tfileArgs: [],\n\t};\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i];\n\n\t\tif (arg === \"--help\" || arg === \"-h\") {\n\t\t\tresult.help = true;\n\t\t} else if (arg === \"--version\" || arg === \"-v\") {\n\t\t\tresult.version = true;\n\t\t} else if (arg === \"--mode\" && i + 1 < args.length) {\n\t\t\tconst mode = args[++i];\n\t\t\tif (mode === \"text\" || mode === \"json\" || mode === \"rpc\") {\n\t\t\t\tresult.mode = mode;\n\t\t\t}\n\t\t} else if (arg === \"--continue\" || arg === \"-c\") {\n\t\t\tresult.continue = true;\n\t\t} else if (arg === \"--resume\" || arg === \"-r\") {\n\t\t\tresult.resume = true;\n\t\t} else if (arg === \"--provider\" && i + 1 < args.length) {\n\t\t\tresult.provider = args[++i];\n\t\t} else if (arg === \"--model\" && i + 1 < args.length) {\n\t\t\tresult.model = args[++i];\n\t\t} else if (arg === \"--api-key\" && i + 1 < args.length) {\n\t\t\tresult.apiKey = args[++i];\n\t\t} else if (arg === \"--system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.systemPrompt = args[++i];\n\t\t} else if (arg === \"--append-system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.appendSystemPrompt = args[++i];\n\t\t} else if (arg === \"--no-session\") {\n\t\t\tresult.noSession = true;\n\t\t} else if (arg === \"--session\" && i + 1 < args.length) {\n\t\t\tresult.session = args[++i];\n\t\t} else if (arg === \"--models\" && i + 1 < args.length) {\n\t\t\tresult.models = args[++i].split(\",\").map((s) => s.trim());\n\t\t} else if (arg === \"--tools\" && i + 1 < args.length) {\n\t\t\tconst toolNames = args[++i].split(\",\").map((s) => s.trim());\n\t\t\tconst validTools: ToolName[] = [];\n\t\t\tfor (const name of toolNames) {\n\t\t\t\tif (name in allTools) {\n\t\t\t\t\tvalidTools.push(name as ToolName);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\tchalk.yellow(`Warning: Unknown tool \"${name}\". Valid tools: ${Object.keys(allTools).join(\", \")}`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult.tools = validTools;\n\t\t} else if (arg === \"--thinking\" && i + 1 < args.length) {\n\t\t\tconst level = args[++i];\n\t\t\tif (isValidThinkingLevel(level)) {\n\t\t\t\tresult.thinking = level;\n\t\t\t} else {\n\t\t\t\tconsole.error(\n\t\t\t\t\tchalk.yellow(\n\t\t\t\t\t\t`Warning: Invalid thinking level \"${level}\". Valid values: ${VALID_THINKING_LEVELS.join(\", \")}`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (arg === \"--print\" || arg === \"-p\") {\n\t\t\tresult.print = true;\n\t\t} else if (arg === \"--export\" && i + 1 < args.length) {\n\t\t\tresult.export = args[++i];\n\t\t} else if (arg === \"--hook\" && i + 1 < args.length) {\n\t\t\tresult.hooks = result.hooks ?? [];\n\t\t\tresult.hooks.push(args[++i]);\n\t\t} else if (arg === \"--no-skills\") {\n\t\t\tresult.noSkills = true;\n\t\t} else if (arg === \"--list-models\") {\n\t\t\t// Check if next arg is a search pattern (not a flag or file arg)\n\t\t\tif (i + 1 < args.length && !args[i + 1].startsWith(\"-\") && !args[i + 1].startsWith(\"@\")) {\n\t\t\t\tresult.listModels = args[++i];\n\t\t\t} else {\n\t\t\t\tresult.listModels = true;\n\t\t\t}\n\t\t} else if (arg.startsWith(\"@\")) {\n\t\t\tresult.fileArgs.push(arg.slice(1)); // Remove @ prefix\n\t\t} else if (!arg.startsWith(\"-\")) {\n\t\t\tresult.messages.push(arg);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nexport function printHelp(): void {\n\tconsole.log(`${chalk.bold(APP_NAME)} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n ${APP_NAME} [options] [@files...] [messages...]\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <id> Model ID (default: gemini-2.5-flash)\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --append-system-prompt <text> Append text or file contents to the system prompt\n --mode <mode> Output mode: text (default), json, or rpc\n --print, -p Non-interactive mode: process prompt and exit\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path> Use specific session file\n --no-session Don't save session (ephemeral)\n --models <patterns> Comma-separated model patterns for quick cycling with Ctrl+P\n --tools <tools> Comma-separated list of tools to enable (default: read,bash,edit,write)\n Available: read, bash, edit, write, grep, find, ls\n --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh\n --hook <path> Load a hook file (can be used multiple times)\n --no-skills Disable skills discovery and loading\n --export <file> Export session file to HTML and exit\n --list-models [search] List available models (with optional fuzzy search)\n --help, -h Show this help\n --version, -v Show version number\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode\n ${APP_NAME}\n\n # Interactive mode with initial prompt\n ${APP_NAME} \"List all .ts files in src/\"\n\n # Include files in initial message\n ${APP_NAME} @prompt.md @image.png \"What color is the sky?\"\n\n # Non-interactive mode (process and exit)\n ${APP_NAME} -p \"List all .ts files in src/\"\n\n # Multiple messages (interactive)\n ${APP_NAME} \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n ${APP_NAME} --continue \"What did we discuss?\"\n\n # Use different model\n ${APP_NAME} --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n # Limit model cycling to specific models\n ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o\n\n # Cycle models with fixed thinking levels\n ${APP_NAME} --models sonnet:high,haiku:low\n\n # Start with a specific thinking level\n ${APP_NAME} --thinking high \"Solve this complex problem\"\n\n # Read-only mode (no file modifications possible)\n ${APP_NAME} --tools read,grep,find,ls -p \"Review the code in src/\"\n\n # Export a session file to HTML\n ${APP_NAME} --export ~/${CONFIG_DIR_NAME}/agent/sessions/--path--/session.jsonl\n ${APP_NAME} --export session.jsonl output.html\n\n${chalk.bold(\"Environment Variables:\")}\n ANTHROPIC_API_KEY - Anthropic Claude API key\n ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth token (alternative to API key)\n OPENAI_API_KEY - OpenAI GPT API key\n GEMINI_API_KEY - Google Gemini API key\n GROQ_API_KEY - Groq API key\n CEREBRAS_API_KEY - Cerebras API key\n XAI_API_KEY - xAI Grok API key\n OPENROUTER_API_KEY - OpenRouter API key\n ZAI_API_KEY - ZAI API key\n ${ENV_AGENT_DIR.padEnd(23)} - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)\n\n${chalk.bold(\"Available Tools (default: read, bash, edit, write):\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n grep - Search file contents (read-only, off by default)\n find - Find files by glob pattern (read-only, off by default)\n ls - List directory contents (read-only, off by default)\n`);\n}\n"]}
package/dist/cli/args.js CHANGED
@@ -92,6 +92,15 @@ export function parseArgs(args) {
92
92
  else if (arg === "--no-skills") {
93
93
  result.noSkills = true;
94
94
  }
95
+ else if (arg === "--list-models") {
96
+ // Check if next arg is a search pattern (not a flag or file arg)
97
+ if (i + 1 < args.length && !args[i + 1].startsWith("-") && !args[i + 1].startsWith("@")) {
98
+ result.listModels = args[++i];
99
+ }
100
+ else {
101
+ result.listModels = true;
102
+ }
103
+ }
95
104
  else if (arg.startsWith("@")) {
96
105
  result.fileArgs.push(arg.slice(1)); // Remove @ prefix
97
106
  }
@@ -126,6 +135,7 @@ ${chalk.bold("Options:")}
126
135
  --hook <path> Load a hook file (can be used multiple times)
127
136
  --no-skills Disable skills discovery and loading
128
137
  --export <file> Export session file to HTML and exit
138
+ --list-models [search] List available models (with optional fuzzy search)
129
139
  --help, -h Show this help
130
140
  --version, -v Show version number
131
141
 
@@ -1 +1 @@
1
- {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CLI argument parsing and help display\n */\n\nimport type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport chalk from \"chalk\";\nimport { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR } from \"../config.js\";\nimport { allTools, type ToolName } from \"../core/tools/index.js\";\n\nexport type Mode = \"text\" | \"json\" | \"rpc\";\n\nexport interface Args {\n\tprovider?: string;\n\tmodel?: string;\n\tapiKey?: string;\n\tsystemPrompt?: string;\n\tappendSystemPrompt?: string;\n\tthinking?: ThinkingLevel;\n\tcontinue?: boolean;\n\tresume?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n\tmode?: Mode;\n\tnoSession?: boolean;\n\tsession?: string;\n\tmodels?: string[];\n\ttools?: ToolName[];\n\thooks?: string[];\n\tprint?: boolean;\n\texport?: string;\n\tnoSkills?: boolean;\n\tmessages: string[];\n\tfileArgs: string[];\n}\n\nconst VALID_THINKING_LEVELS = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"] as const;\n\nexport function isValidThinkingLevel(level: string): level is ThinkingLevel {\n\treturn VALID_THINKING_LEVELS.includes(level as ThinkingLevel);\n}\n\nexport function parseArgs(args: string[]): Args {\n\tconst result: Args = {\n\t\tmessages: [],\n\t\tfileArgs: [],\n\t};\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i];\n\n\t\tif (arg === \"--help\" || arg === \"-h\") {\n\t\t\tresult.help = true;\n\t\t} else if (arg === \"--version\" || arg === \"-v\") {\n\t\t\tresult.version = true;\n\t\t} else if (arg === \"--mode\" && i + 1 < args.length) {\n\t\t\tconst mode = args[++i];\n\t\t\tif (mode === \"text\" || mode === \"json\" || mode === \"rpc\") {\n\t\t\t\tresult.mode = mode;\n\t\t\t}\n\t\t} else if (arg === \"--continue\" || arg === \"-c\") {\n\t\t\tresult.continue = true;\n\t\t} else if (arg === \"--resume\" || arg === \"-r\") {\n\t\t\tresult.resume = true;\n\t\t} else if (arg === \"--provider\" && i + 1 < args.length) {\n\t\t\tresult.provider = args[++i];\n\t\t} else if (arg === \"--model\" && i + 1 < args.length) {\n\t\t\tresult.model = args[++i];\n\t\t} else if (arg === \"--api-key\" && i + 1 < args.length) {\n\t\t\tresult.apiKey = args[++i];\n\t\t} else if (arg === \"--system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.systemPrompt = args[++i];\n\t\t} else if (arg === \"--append-system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.appendSystemPrompt = args[++i];\n\t\t} else if (arg === \"--no-session\") {\n\t\t\tresult.noSession = true;\n\t\t} else if (arg === \"--session\" && i + 1 < args.length) {\n\t\t\tresult.session = args[++i];\n\t\t} else if (arg === \"--models\" && i + 1 < args.length) {\n\t\t\tresult.models = args[++i].split(\",\").map((s) => s.trim());\n\t\t} else if (arg === \"--tools\" && i + 1 < args.length) {\n\t\t\tconst toolNames = args[++i].split(\",\").map((s) => s.trim());\n\t\t\tconst validTools: ToolName[] = [];\n\t\t\tfor (const name of toolNames) {\n\t\t\t\tif (name in allTools) {\n\t\t\t\t\tvalidTools.push(name as ToolName);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\tchalk.yellow(`Warning: Unknown tool \"${name}\". Valid tools: ${Object.keys(allTools).join(\", \")}`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult.tools = validTools;\n\t\t} else if (arg === \"--thinking\" && i + 1 < args.length) {\n\t\t\tconst level = args[++i];\n\t\t\tif (isValidThinkingLevel(level)) {\n\t\t\t\tresult.thinking = level;\n\t\t\t} else {\n\t\t\t\tconsole.error(\n\t\t\t\t\tchalk.yellow(\n\t\t\t\t\t\t`Warning: Invalid thinking level \"${level}\". Valid values: ${VALID_THINKING_LEVELS.join(\", \")}`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (arg === \"--print\" || arg === \"-p\") {\n\t\t\tresult.print = true;\n\t\t} else if (arg === \"--export\" && i + 1 < args.length) {\n\t\t\tresult.export = args[++i];\n\t\t} else if (arg === \"--hook\" && i + 1 < args.length) {\n\t\t\tresult.hooks = result.hooks ?? [];\n\t\t\tresult.hooks.push(args[++i]);\n\t\t} else if (arg === \"--no-skills\") {\n\t\t\tresult.noSkills = true;\n\t\t} else if (arg.startsWith(\"@\")) {\n\t\t\tresult.fileArgs.push(arg.slice(1)); // Remove @ prefix\n\t\t} else if (!arg.startsWith(\"-\")) {\n\t\t\tresult.messages.push(arg);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nexport function printHelp(): void {\n\tconsole.log(`${chalk.bold(APP_NAME)} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n ${APP_NAME} [options] [@files...] [messages...]\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <id> Model ID (default: gemini-2.5-flash)\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --append-system-prompt <text> Append text or file contents to the system prompt\n --mode <mode> Output mode: text (default), json, or rpc\n --print, -p Non-interactive mode: process prompt and exit\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path> Use specific session file\n --no-session Don't save session (ephemeral)\n --models <patterns> Comma-separated model patterns for quick cycling with Ctrl+P\n --tools <tools> Comma-separated list of tools to enable (default: read,bash,edit,write)\n Available: read, bash, edit, write, grep, find, ls\n --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh\n --hook <path> Load a hook file (can be used multiple times)\n --no-skills Disable skills discovery and loading\n --export <file> Export session file to HTML and exit\n --help, -h Show this help\n --version, -v Show version number\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode\n ${APP_NAME}\n\n # Interactive mode with initial prompt\n ${APP_NAME} \"List all .ts files in src/\"\n\n # Include files in initial message\n ${APP_NAME} @prompt.md @image.png \"What color is the sky?\"\n\n # Non-interactive mode (process and exit)\n ${APP_NAME} -p \"List all .ts files in src/\"\n\n # Multiple messages (interactive)\n ${APP_NAME} \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n ${APP_NAME} --continue \"What did we discuss?\"\n\n # Use different model\n ${APP_NAME} --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n # Limit model cycling to specific models\n ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o\n\n # Cycle models with fixed thinking levels\n ${APP_NAME} --models sonnet:high,haiku:low\n\n # Start with a specific thinking level\n ${APP_NAME} --thinking high \"Solve this complex problem\"\n\n # Read-only mode (no file modifications possible)\n ${APP_NAME} --tools read,grep,find,ls -p \"Review the code in src/\"\n\n # Export a session file to HTML\n ${APP_NAME} --export ~/${CONFIG_DIR_NAME}/agent/sessions/--path--/session.jsonl\n ${APP_NAME} --export session.jsonl output.html\n\n${chalk.bold(\"Environment Variables:\")}\n ANTHROPIC_API_KEY - Anthropic Claude API key\n ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth token (alternative to API key)\n OPENAI_API_KEY - OpenAI GPT API key\n GEMINI_API_KEY - Google Gemini API key\n GROQ_API_KEY - Groq API key\n CEREBRAS_API_KEY - Cerebras API key\n XAI_API_KEY - xAI Grok API key\n OPENROUTER_API_KEY - OpenRouter API key\n ZAI_API_KEY - ZAI API key\n ${ENV_AGENT_DIR.padEnd(23)} - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)\n\n${chalk.bold(\"Available Tools (default: read, bash, edit, write):\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n grep - Search file contents (read-only, off by default)\n find - Find files by glob pattern (read-only, off by default)\n ls - List directory contents (read-only, off by default)\n`);\n}\n"]}
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CLI argument parsing and help display\n */\n\nimport type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport chalk from \"chalk\";\nimport { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR } from \"../config.js\";\nimport { allTools, type ToolName } from \"../core/tools/index.js\";\n\nexport type Mode = \"text\" | \"json\" | \"rpc\";\n\nexport interface Args {\n\tprovider?: string;\n\tmodel?: string;\n\tapiKey?: string;\n\tsystemPrompt?: string;\n\tappendSystemPrompt?: string;\n\tthinking?: ThinkingLevel;\n\tcontinue?: boolean;\n\tresume?: boolean;\n\thelp?: boolean;\n\tversion?: boolean;\n\tmode?: Mode;\n\tnoSession?: boolean;\n\tsession?: string;\n\tmodels?: string[];\n\ttools?: ToolName[];\n\thooks?: string[];\n\tprint?: boolean;\n\texport?: string;\n\tnoSkills?: boolean;\n\tlistModels?: string | true;\n\tmessages: string[];\n\tfileArgs: string[];\n}\n\nconst VALID_THINKING_LEVELS = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"] as const;\n\nexport function isValidThinkingLevel(level: string): level is ThinkingLevel {\n\treturn VALID_THINKING_LEVELS.includes(level as ThinkingLevel);\n}\n\nexport function parseArgs(args: string[]): Args {\n\tconst result: Args = {\n\t\tmessages: [],\n\t\tfileArgs: [],\n\t};\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i];\n\n\t\tif (arg === \"--help\" || arg === \"-h\") {\n\t\t\tresult.help = true;\n\t\t} else if (arg === \"--version\" || arg === \"-v\") {\n\t\t\tresult.version = true;\n\t\t} else if (arg === \"--mode\" && i + 1 < args.length) {\n\t\t\tconst mode = args[++i];\n\t\t\tif (mode === \"text\" || mode === \"json\" || mode === \"rpc\") {\n\t\t\t\tresult.mode = mode;\n\t\t\t}\n\t\t} else if (arg === \"--continue\" || arg === \"-c\") {\n\t\t\tresult.continue = true;\n\t\t} else if (arg === \"--resume\" || arg === \"-r\") {\n\t\t\tresult.resume = true;\n\t\t} else if (arg === \"--provider\" && i + 1 < args.length) {\n\t\t\tresult.provider = args[++i];\n\t\t} else if (arg === \"--model\" && i + 1 < args.length) {\n\t\t\tresult.model = args[++i];\n\t\t} else if (arg === \"--api-key\" && i + 1 < args.length) {\n\t\t\tresult.apiKey = args[++i];\n\t\t} else if (arg === \"--system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.systemPrompt = args[++i];\n\t\t} else if (arg === \"--append-system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.appendSystemPrompt = args[++i];\n\t\t} else if (arg === \"--no-session\") {\n\t\t\tresult.noSession = true;\n\t\t} else if (arg === \"--session\" && i + 1 < args.length) {\n\t\t\tresult.session = args[++i];\n\t\t} else if (arg === \"--models\" && i + 1 < args.length) {\n\t\t\tresult.models = args[++i].split(\",\").map((s) => s.trim());\n\t\t} else if (arg === \"--tools\" && i + 1 < args.length) {\n\t\t\tconst toolNames = args[++i].split(\",\").map((s) => s.trim());\n\t\t\tconst validTools: ToolName[] = [];\n\t\t\tfor (const name of toolNames) {\n\t\t\t\tif (name in allTools) {\n\t\t\t\t\tvalidTools.push(name as ToolName);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\tchalk.yellow(`Warning: Unknown tool \"${name}\". Valid tools: ${Object.keys(allTools).join(\", \")}`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult.tools = validTools;\n\t\t} else if (arg === \"--thinking\" && i + 1 < args.length) {\n\t\t\tconst level = args[++i];\n\t\t\tif (isValidThinkingLevel(level)) {\n\t\t\t\tresult.thinking = level;\n\t\t\t} else {\n\t\t\t\tconsole.error(\n\t\t\t\t\tchalk.yellow(\n\t\t\t\t\t\t`Warning: Invalid thinking level \"${level}\". Valid values: ${VALID_THINKING_LEVELS.join(\", \")}`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (arg === \"--print\" || arg === \"-p\") {\n\t\t\tresult.print = true;\n\t\t} else if (arg === \"--export\" && i + 1 < args.length) {\n\t\t\tresult.export = args[++i];\n\t\t} else if (arg === \"--hook\" && i + 1 < args.length) {\n\t\t\tresult.hooks = result.hooks ?? [];\n\t\t\tresult.hooks.push(args[++i]);\n\t\t} else if (arg === \"--no-skills\") {\n\t\t\tresult.noSkills = true;\n\t\t} else if (arg === \"--list-models\") {\n\t\t\t// Check if next arg is a search pattern (not a flag or file arg)\n\t\t\tif (i + 1 < args.length && !args[i + 1].startsWith(\"-\") && !args[i + 1].startsWith(\"@\")) {\n\t\t\t\tresult.listModels = args[++i];\n\t\t\t} else {\n\t\t\t\tresult.listModels = true;\n\t\t\t}\n\t\t} else if (arg.startsWith(\"@\")) {\n\t\t\tresult.fileArgs.push(arg.slice(1)); // Remove @ prefix\n\t\t} else if (!arg.startsWith(\"-\")) {\n\t\t\tresult.messages.push(arg);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nexport function printHelp(): void {\n\tconsole.log(`${chalk.bold(APP_NAME)} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n ${APP_NAME} [options] [@files...] [messages...]\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <id> Model ID (default: gemini-2.5-flash)\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --append-system-prompt <text> Append text or file contents to the system prompt\n --mode <mode> Output mode: text (default), json, or rpc\n --print, -p Non-interactive mode: process prompt and exit\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path> Use specific session file\n --no-session Don't save session (ephemeral)\n --models <patterns> Comma-separated model patterns for quick cycling with Ctrl+P\n --tools <tools> Comma-separated list of tools to enable (default: read,bash,edit,write)\n Available: read, bash, edit, write, grep, find, ls\n --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh\n --hook <path> Load a hook file (can be used multiple times)\n --no-skills Disable skills discovery and loading\n --export <file> Export session file to HTML and exit\n --list-models [search] List available models (with optional fuzzy search)\n --help, -h Show this help\n --version, -v Show version number\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode\n ${APP_NAME}\n\n # Interactive mode with initial prompt\n ${APP_NAME} \"List all .ts files in src/\"\n\n # Include files in initial message\n ${APP_NAME} @prompt.md @image.png \"What color is the sky?\"\n\n # Non-interactive mode (process and exit)\n ${APP_NAME} -p \"List all .ts files in src/\"\n\n # Multiple messages (interactive)\n ${APP_NAME} \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n ${APP_NAME} --continue \"What did we discuss?\"\n\n # Use different model\n ${APP_NAME} --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n # Limit model cycling to specific models\n ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o\n\n # Cycle models with fixed thinking levels\n ${APP_NAME} --models sonnet:high,haiku:low\n\n # Start with a specific thinking level\n ${APP_NAME} --thinking high \"Solve this complex problem\"\n\n # Read-only mode (no file modifications possible)\n ${APP_NAME} --tools read,grep,find,ls -p \"Review the code in src/\"\n\n # Export a session file to HTML\n ${APP_NAME} --export ~/${CONFIG_DIR_NAME}/agent/sessions/--path--/session.jsonl\n ${APP_NAME} --export session.jsonl output.html\n\n${chalk.bold(\"Environment Variables:\")}\n ANTHROPIC_API_KEY - Anthropic Claude API key\n ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth token (alternative to API key)\n OPENAI_API_KEY - OpenAI GPT API key\n GEMINI_API_KEY - Google Gemini API key\n GROQ_API_KEY - Groq API key\n CEREBRAS_API_KEY - Cerebras API key\n XAI_API_KEY - xAI Grok API key\n OPENROUTER_API_KEY - OpenRouter API key\n ZAI_API_KEY - ZAI API key\n ${ENV_AGENT_DIR.padEnd(23)} - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)\n\n${chalk.bold(\"Available Tools (default: read, bash, edit, write):\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n grep - Search file contents (read-only, off by default)\n find - Find files by glob pattern (read-only, off by default)\n ls - List directory contents (read-only, off by default)\n`);\n}\n"]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * List available models with optional fuzzy search
3
+ */
4
+ /**
5
+ * List available models, optionally filtered by search pattern
6
+ */
7
+ export declare function listModels(searchPattern?: string): Promise<void>;
8
+ //# sourceMappingURL=list-models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-models.d.ts","sourceRoot":"","sources":["../../src/cli/list-models.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqBH;;GAEG;AACH,wBAAsB,UAAU,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkFtE","sourcesContent":["/**\n * List available models with optional fuzzy search\n */\n\nimport type { Api, Model } from \"@mariozechner/pi-ai\";\nimport { getAvailableModels } from \"../core/model-config.js\";\nimport { fuzzyFilter } from \"../utils/fuzzy.js\";\n\n/**\n * Format a number as human-readable (e.g., 200000 -> \"200K\", 1000000 -> \"1M\")\n */\nfunction formatTokenCount(count: number): string {\n\tif (count >= 1_000_000) {\n\t\tconst millions = count / 1_000_000;\n\t\treturn millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`;\n\t}\n\tif (count >= 1_000) {\n\t\tconst thousands = count / 1_000;\n\t\treturn thousands % 1 === 0 ? `${thousands}K` : `${thousands.toFixed(1)}K`;\n\t}\n\treturn count.toString();\n}\n\n/**\n * List available models, optionally filtered by search pattern\n */\nexport async function listModels(searchPattern?: string): Promise<void> {\n\tconst { models, error } = await getAvailableModels();\n\n\tif (error) {\n\t\tconsole.error(error);\n\t\tprocess.exit(1);\n\t}\n\n\tif (models.length === 0) {\n\t\tconsole.log(\"No models available. Set API keys in environment variables.\");\n\t\treturn;\n\t}\n\n\t// Apply fuzzy filter if search pattern provided\n\tlet filteredModels: Model<Api>[] = models;\n\tif (searchPattern) {\n\t\tfilteredModels = fuzzyFilter(models, searchPattern, (m) => `${m.provider} ${m.id}`);\n\t}\n\n\tif (filteredModels.length === 0) {\n\t\tconsole.log(`No models matching \"${searchPattern}\"`);\n\t\treturn;\n\t}\n\n\t// Sort by provider, then by model id\n\tfilteredModels.sort((a, b) => {\n\t\tconst providerCmp = a.provider.localeCompare(b.provider);\n\t\tif (providerCmp !== 0) return providerCmp;\n\t\treturn a.id.localeCompare(b.id);\n\t});\n\n\t// Calculate column widths\n\tconst rows = filteredModels.map((m) => ({\n\t\tprovider: m.provider,\n\t\tmodel: m.id,\n\t\tcontext: formatTokenCount(m.contextWindow),\n\t\tmaxOut: formatTokenCount(m.maxTokens),\n\t\tthinking: m.reasoning ? \"yes\" : \"no\",\n\t\timages: m.input.includes(\"image\") ? \"yes\" : \"no\",\n\t}));\n\n\tconst headers = {\n\t\tprovider: \"provider\",\n\t\tmodel: \"model\",\n\t\tcontext: \"context\",\n\t\tmaxOut: \"max-out\",\n\t\tthinking: \"thinking\",\n\t\timages: \"images\",\n\t};\n\n\tconst widths = {\n\t\tprovider: Math.max(headers.provider.length, ...rows.map((r) => r.provider.length)),\n\t\tmodel: Math.max(headers.model.length, ...rows.map((r) => r.model.length)),\n\t\tcontext: Math.max(headers.context.length, ...rows.map((r) => r.context.length)),\n\t\tmaxOut: Math.max(headers.maxOut.length, ...rows.map((r) => r.maxOut.length)),\n\t\tthinking: Math.max(headers.thinking.length, ...rows.map((r) => r.thinking.length)),\n\t\timages: Math.max(headers.images.length, ...rows.map((r) => r.images.length)),\n\t};\n\n\t// Print header\n\tconst headerLine = [\n\t\theaders.provider.padEnd(widths.provider),\n\t\theaders.model.padEnd(widths.model),\n\t\theaders.context.padEnd(widths.context),\n\t\theaders.maxOut.padEnd(widths.maxOut),\n\t\theaders.thinking.padEnd(widths.thinking),\n\t\theaders.images.padEnd(widths.images),\n\t].join(\" \");\n\tconsole.log(headerLine);\n\n\t// Print rows\n\tfor (const row of rows) {\n\t\tconst line = [\n\t\t\trow.provider.padEnd(widths.provider),\n\t\t\trow.model.padEnd(widths.model),\n\t\t\trow.context.padEnd(widths.context),\n\t\t\trow.maxOut.padEnd(widths.maxOut),\n\t\t\trow.thinking.padEnd(widths.thinking),\n\t\t\trow.images.padEnd(widths.images),\n\t\t].join(\" \");\n\t\tconsole.log(line);\n\t}\n}\n"]}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * List available models with optional fuzzy search
3
+ */
4
+ import { getAvailableModels } from "../core/model-config.js";
5
+ import { fuzzyFilter } from "../utils/fuzzy.js";
6
+ /**
7
+ * Format a number as human-readable (e.g., 200000 -> "200K", 1000000 -> "1M")
8
+ */
9
+ function formatTokenCount(count) {
10
+ if (count >= 1_000_000) {
11
+ const millions = count / 1_000_000;
12
+ return millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`;
13
+ }
14
+ if (count >= 1_000) {
15
+ const thousands = count / 1_000;
16
+ return thousands % 1 === 0 ? `${thousands}K` : `${thousands.toFixed(1)}K`;
17
+ }
18
+ return count.toString();
19
+ }
20
+ /**
21
+ * List available models, optionally filtered by search pattern
22
+ */
23
+ export async function listModels(searchPattern) {
24
+ const { models, error } = await getAvailableModels();
25
+ if (error) {
26
+ console.error(error);
27
+ process.exit(1);
28
+ }
29
+ if (models.length === 0) {
30
+ console.log("No models available. Set API keys in environment variables.");
31
+ return;
32
+ }
33
+ // Apply fuzzy filter if search pattern provided
34
+ let filteredModels = models;
35
+ if (searchPattern) {
36
+ filteredModels = fuzzyFilter(models, searchPattern, (m) => `${m.provider} ${m.id}`);
37
+ }
38
+ if (filteredModels.length === 0) {
39
+ console.log(`No models matching "${searchPattern}"`);
40
+ return;
41
+ }
42
+ // Sort by provider, then by model id
43
+ filteredModels.sort((a, b) => {
44
+ const providerCmp = a.provider.localeCompare(b.provider);
45
+ if (providerCmp !== 0)
46
+ return providerCmp;
47
+ return a.id.localeCompare(b.id);
48
+ });
49
+ // Calculate column widths
50
+ const rows = filteredModels.map((m) => ({
51
+ provider: m.provider,
52
+ model: m.id,
53
+ context: formatTokenCount(m.contextWindow),
54
+ maxOut: formatTokenCount(m.maxTokens),
55
+ thinking: m.reasoning ? "yes" : "no",
56
+ images: m.input.includes("image") ? "yes" : "no",
57
+ }));
58
+ const headers = {
59
+ provider: "provider",
60
+ model: "model",
61
+ context: "context",
62
+ maxOut: "max-out",
63
+ thinking: "thinking",
64
+ images: "images",
65
+ };
66
+ const widths = {
67
+ provider: Math.max(headers.provider.length, ...rows.map((r) => r.provider.length)),
68
+ model: Math.max(headers.model.length, ...rows.map((r) => r.model.length)),
69
+ context: Math.max(headers.context.length, ...rows.map((r) => r.context.length)),
70
+ maxOut: Math.max(headers.maxOut.length, ...rows.map((r) => r.maxOut.length)),
71
+ thinking: Math.max(headers.thinking.length, ...rows.map((r) => r.thinking.length)),
72
+ images: Math.max(headers.images.length, ...rows.map((r) => r.images.length)),
73
+ };
74
+ // Print header
75
+ const headerLine = [
76
+ headers.provider.padEnd(widths.provider),
77
+ headers.model.padEnd(widths.model),
78
+ headers.context.padEnd(widths.context),
79
+ headers.maxOut.padEnd(widths.maxOut),
80
+ headers.thinking.padEnd(widths.thinking),
81
+ headers.images.padEnd(widths.images),
82
+ ].join(" ");
83
+ console.log(headerLine);
84
+ // Print rows
85
+ for (const row of rows) {
86
+ const line = [
87
+ row.provider.padEnd(widths.provider),
88
+ row.model.padEnd(widths.model),
89
+ row.context.padEnd(widths.context),
90
+ row.maxOut.padEnd(widths.maxOut),
91
+ row.thinking.padEnd(widths.thinking),
92
+ row.images.padEnd(widths.images),
93
+ ].join(" ");
94
+ console.log(line);
95
+ }
96
+ }
97
+ //# sourceMappingURL=list-models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-models.js","sourceRoot":"","sources":["../../src/cli/list-models.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * List available models with optional fuzzy search\n */\n\nimport type { Api, Model } from \"@mariozechner/pi-ai\";\nimport { getAvailableModels } from \"../core/model-config.js\";\nimport { fuzzyFilter } from \"../utils/fuzzy.js\";\n\n/**\n * Format a number as human-readable (e.g., 200000 -> \"200K\", 1000000 -> \"1M\")\n */\nfunction formatTokenCount(count: number): string {\n\tif (count >= 1_000_000) {\n\t\tconst millions = count / 1_000_000;\n\t\treturn millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`;\n\t}\n\tif (count >= 1_000) {\n\t\tconst thousands = count / 1_000;\n\t\treturn thousands % 1 === 0 ? `${thousands}K` : `${thousands.toFixed(1)}K`;\n\t}\n\treturn count.toString();\n}\n\n/**\n * List available models, optionally filtered by search pattern\n */\nexport async function listModels(searchPattern?: string): Promise<void> {\n\tconst { models, error } = await getAvailableModels();\n\n\tif (error) {\n\t\tconsole.error(error);\n\t\tprocess.exit(1);\n\t}\n\n\tif (models.length === 0) {\n\t\tconsole.log(\"No models available. Set API keys in environment variables.\");\n\t\treturn;\n\t}\n\n\t// Apply fuzzy filter if search pattern provided\n\tlet filteredModels: Model<Api>[] = models;\n\tif (searchPattern) {\n\t\tfilteredModels = fuzzyFilter(models, searchPattern, (m) => `${m.provider} ${m.id}`);\n\t}\n\n\tif (filteredModels.length === 0) {\n\t\tconsole.log(`No models matching \"${searchPattern}\"`);\n\t\treturn;\n\t}\n\n\t// Sort by provider, then by model id\n\tfilteredModels.sort((a, b) => {\n\t\tconst providerCmp = a.provider.localeCompare(b.provider);\n\t\tif (providerCmp !== 0) return providerCmp;\n\t\treturn a.id.localeCompare(b.id);\n\t});\n\n\t// Calculate column widths\n\tconst rows = filteredModels.map((m) => ({\n\t\tprovider: m.provider,\n\t\tmodel: m.id,\n\t\tcontext: formatTokenCount(m.contextWindow),\n\t\tmaxOut: formatTokenCount(m.maxTokens),\n\t\tthinking: m.reasoning ? \"yes\" : \"no\",\n\t\timages: m.input.includes(\"image\") ? \"yes\" : \"no\",\n\t}));\n\n\tconst headers = {\n\t\tprovider: \"provider\",\n\t\tmodel: \"model\",\n\t\tcontext: \"context\",\n\t\tmaxOut: \"max-out\",\n\t\tthinking: \"thinking\",\n\t\timages: \"images\",\n\t};\n\n\tconst widths = {\n\t\tprovider: Math.max(headers.provider.length, ...rows.map((r) => r.provider.length)),\n\t\tmodel: Math.max(headers.model.length, ...rows.map((r) => r.model.length)),\n\t\tcontext: Math.max(headers.context.length, ...rows.map((r) => r.context.length)),\n\t\tmaxOut: Math.max(headers.maxOut.length, ...rows.map((r) => r.maxOut.length)),\n\t\tthinking: Math.max(headers.thinking.length, ...rows.map((r) => r.thinking.length)),\n\t\timages: Math.max(headers.images.length, ...rows.map((r) => r.images.length)),\n\t};\n\n\t// Print header\n\tconst headerLine = [\n\t\theaders.provider.padEnd(widths.provider),\n\t\theaders.model.padEnd(widths.model),\n\t\theaders.context.padEnd(widths.context),\n\t\theaders.maxOut.padEnd(widths.maxOut),\n\t\theaders.thinking.padEnd(widths.thinking),\n\t\theaders.images.padEnd(widths.images),\n\t].join(\" \");\n\tconsole.log(headerLine);\n\n\t// Print rows\n\tfor (const row of rows) {\n\t\tconst line = [\n\t\t\trow.provider.padEnd(widths.provider),\n\t\t\trow.model.padEnd(widths.model),\n\t\t\trow.context.padEnd(widths.context),\n\t\t\trow.maxOut.padEnd(widths.maxOut),\n\t\t\trow.thinking.padEnd(widths.thinking),\n\t\t\trow.images.padEnd(widths.images),\n\t\t].join(\" \");\n\t\tconsole.log(line);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwIH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,iBAiRxC","sourcesContent":["/**\n * Main entry point for the coding agent\n */\n\nimport { Agent, type Attachment, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport chalk from \"chalk\";\nimport { type Args, parseArgs, printHelp } from \"./cli/args.js\";\nimport { processFileArguments } from \"./cli/file-processor.js\";\nimport { selectSession } from \"./cli/session-picker.js\";\nimport { getModelsPath, VERSION } from \"./config.js\";\nimport { AgentSession } from \"./core/agent-session.js\";\nimport { exportFromFile } from \"./core/export-html.js\";\nimport { discoverAndLoadHooks, HookRunner, wrapToolsWithHooks } from \"./core/hooks/index.js\";\nimport { messageTransformer } from \"./core/messages.js\";\nimport { findModel, getApiKeyForModel, getAvailableModels } from \"./core/model-config.js\";\nimport { resolveModelScope, restoreModelFromSession, type ScopedModel } from \"./core/model-resolver.js\";\nimport { SessionManager } from \"./core/session-manager.js\";\nimport { SettingsManager } from \"./core/settings-manager.js\";\nimport { loadSlashCommands } from \"./core/slash-commands.js\";\nimport { buildSystemPrompt } from \"./core/system-prompt.js\";\nimport { allTools, codingTools } from \"./core/tools/index.js\";\nimport { InteractiveMode, runPrintMode, runRpcMode } from \"./modes/index.js\";\nimport { initTheme, stopThemeWatcher } from \"./modes/interactive/theme/theme.js\";\nimport { getChangelogPath, getNewEntries, parseChangelog } from \"./utils/changelog.js\";\nimport { ensureTool } from \"./utils/tools-manager.js\";\n\n/** Check npm registry for new version (non-blocking) */\nasync function checkForNewVersion(currentVersion: string): Promise<string | null> {\n\ttry {\n\t\tconst response = await fetch(\"https://registry.npmjs.org/@mariozechner/pi-coding-agent/latest\");\n\t\tif (!response.ok) return null;\n\n\t\tconst data = (await response.json()) as { version?: string };\n\t\tconst latestVersion = data.version;\n\n\t\tif (latestVersion && latestVersion !== currentVersion) {\n\t\t\treturn latestVersion;\n\t\t}\n\n\t\treturn null;\n\t} catch {\n\t\t// Silently fail - don't disrupt the user experience\n\t\treturn null;\n\t}\n}\n\n/** Run interactive mode with TUI */\nasync function runInteractiveMode(\n\tsession: AgentSession,\n\tversion: string,\n\tchangelogMarkdown: string | null,\n\tmodelFallbackMessage: string | null,\n\tversionCheckPromise: Promise<string | null>,\n\tinitialMessages: string[],\n\tinitialMessage?: string,\n\tinitialAttachments?: Attachment[],\n\tfdPath: string | null = null,\n): Promise<void> {\n\tconst mode = new InteractiveMode(session, version, changelogMarkdown, fdPath);\n\n\t// Initialize TUI (subscribes to agent events internally)\n\tawait mode.init();\n\n\t// Handle version check result when it completes (don't block)\n\tversionCheckPromise.then((newVersion) => {\n\t\tif (newVersion) {\n\t\t\tmode.showNewVersionNotification(newVersion);\n\t\t}\n\t});\n\n\t// Render any existing messages (from --continue mode)\n\tmode.renderInitialMessages(session.state);\n\n\t// Show model fallback warning at the end of the chat if applicable\n\tif (modelFallbackMessage) {\n\t\tmode.showWarning(modelFallbackMessage);\n\t}\n\n\t// Process initial message with attachments if provided (from @file args)\n\tif (initialMessage) {\n\t\ttry {\n\t\t\tawait session.prompt(initialMessage, { attachments: initialAttachments });\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\t// Process remaining initial messages if provided (from CLI args)\n\tfor (const message of initialMessages) {\n\t\ttry {\n\t\t\tawait session.prompt(message);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\t// Interactive loop\n\twhile (true) {\n\t\tconst userInput = await mode.getUserInput();\n\n\t\t// Process the message\n\t\ttry {\n\t\t\tawait session.prompt(userInput);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n}\n\n/** Prepare initial message from @file arguments */\nfunction prepareInitialMessage(parsed: Args): {\n\tinitialMessage?: string;\n\tinitialAttachments?: Attachment[];\n} {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn {};\n\t}\n\n\tconst { textContent, imageAttachments } = processFileArguments(parsed.fileArgs);\n\n\t// Combine file content with first plain text message (if any)\n\tlet initialMessage: string;\n\tif (parsed.messages.length > 0) {\n\t\tinitialMessage = textContent + parsed.messages[0];\n\t\tparsed.messages.shift(); // Remove first message as it's been combined\n\t} else {\n\t\tinitialMessage = textContent;\n\t}\n\n\treturn {\n\t\tinitialMessage,\n\t\tinitialAttachments: imageAttachments.length > 0 ? imageAttachments : undefined,\n\t};\n}\n\nexport async function main(args: string[]) {\n\tconst parsed = parseArgs(args);\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\t// Handle --export flag: convert session file to HTML and exit\n\tif (parsed.export) {\n\t\ttry {\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tconst result = exportFromFile(parsed.export, outputPath);\n\t\t\tconsole.log(`Exported to: ${result}`);\n\t\t\treturn;\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// Validate: RPC mode doesn't support @file arguments\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\t// Process @file arguments\n\tconst { initialMessage, initialAttachments } = prepareInitialMessage(parsed);\n\n\t// Determine if we're in interactive mode (needed for theme watcher)\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\n\t// Initialize theme (before any TUI rendering)\n\tconst settingsManager = new SettingsManager();\n\tconst themeName = settingsManager.getTheme();\n\tinitTheme(themeName, isInteractive);\n\n\t// Setup session manager\n\tconst sessionManager = new SessionManager(parsed.continue && !parsed.resume, parsed.session);\n\n\tif (parsed.noSession) {\n\t\tsessionManager.disable();\n\t}\n\n\t// Handle --resume flag: show session selector\n\tif (parsed.resume) {\n\t\tconst selectedSession = await selectSession(sessionManager);\n\t\tif (!selectedSession) {\n\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\treturn;\n\t\t}\n\t\tsessionManager.setSessionFile(selectedSession);\n\t}\n\n\t// Resolve model scope early if provided\n\tlet scopedModels: ScopedModel[] = [];\n\tif (parsed.models && parsed.models.length > 0) {\n\t\tscopedModels = await resolveModelScope(parsed.models);\n\t}\n\n\t// Determine mode and output behavior\n\tconst mode = parsed.mode || \"text\";\n\tconst shouldPrintMessages = isInteractive;\n\n\t// Find initial model\n\tlet initialModel = await findInitialModelForSession(parsed, scopedModels, settingsManager);\n\tlet initialThinking: ThinkingLevel = \"off\";\n\n\t// Get thinking level from scoped models if applicable\n\tif (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\tinitialThinking = scopedModels[0].thinkingLevel;\n\t} else {\n\t\t// Try saved thinking level\n\t\tconst savedThinking = settingsManager.getDefaultThinkingLevel();\n\t\tif (savedThinking) {\n\t\t\tinitialThinking = savedThinking;\n\t\t}\n\t}\n\n\t// Non-interactive mode: fail early if no model available\n\tif (!isInteractive && !initialModel) {\n\t\tconsole.error(chalk.red(\"No models available.\"));\n\t\tconsole.error(chalk.yellow(\"\\nSet an API key environment variable:\"));\n\t\tconsole.error(\" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\");\n\t\tconsole.error(chalk.yellow(`\\nOr create ${getModelsPath()}`));\n\t\tprocess.exit(1);\n\t}\n\n\t// Non-interactive mode: validate API key exists\n\tif (!isInteractive && initialModel) {\n\t\tconst apiKey = parsed.apiKey || (await getApiKeyForModel(initialModel));\n\t\tif (!apiKey) {\n\t\t\tconsole.error(chalk.red(`No API key found for ${initialModel.provider}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// Build system prompt\n\tconst skillsEnabled = !parsed.noSkills && settingsManager.getSkillsEnabled();\n\tconst systemPrompt = buildSystemPrompt({\n\t\tcustomPrompt: parsed.systemPrompt,\n\t\tselectedTools: parsed.tools,\n\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\tskillsEnabled,\n\t});\n\n\t// Handle session restoration\n\tlet modelFallbackMessage: string | null = null;\n\n\tif (parsed.continue || parsed.resume || parsed.session) {\n\t\tconst savedModel = sessionManager.loadModel();\n\t\tif (savedModel) {\n\t\t\tconst result = await restoreModelFromSession(\n\t\t\t\tsavedModel.provider,\n\t\t\t\tsavedModel.modelId,\n\t\t\t\tinitialModel,\n\t\t\t\tshouldPrintMessages,\n\t\t\t);\n\n\t\t\tif (result.model) {\n\t\t\t\tinitialModel = result.model;\n\t\t\t}\n\t\t\tmodelFallbackMessage = result.fallbackMessage;\n\t\t}\n\n\t\t// Load and restore thinking level\n\t\tconst thinkingLevel = sessionManager.loadThinkingLevel() as ThinkingLevel;\n\t\tif (thinkingLevel) {\n\t\t\tinitialThinking = thinkingLevel;\n\t\t\tif (shouldPrintMessages) {\n\t\t\t\tconsole.log(chalk.dim(`Restored thinking level: ${thinkingLevel}`));\n\t\t\t}\n\t\t}\n\t}\n\n\t// CLI --thinking flag takes highest priority\n\tif (parsed.thinking) {\n\t\tinitialThinking = parsed.thinking;\n\t}\n\n\t// Determine which tools to use\n\tlet selectedTools = parsed.tools ? parsed.tools.map((name) => allTools[name]) : codingTools;\n\n\t// Discover and load hooks from:\n\t// 1. ~/.pi/agent/hooks/*.ts (global)\n\t// 2. cwd/.pi/hooks/*.ts (project-local)\n\t// 3. Explicit paths in settings.json\n\t// 4. CLI --hook flags\n\tlet hookRunner: HookRunner | null = null;\n\tconst cwd = process.cwd();\n\tconst configuredHookPaths = [...settingsManager.getHookPaths(), ...(parsed.hooks ?? [])];\n\tconst { hooks, errors } = await discoverAndLoadHooks(configuredHookPaths, cwd);\n\n\t// Report hook loading errors\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(chalk.red(`Failed to load hook \"${path}\": ${error}`));\n\t}\n\n\tif (hooks.length > 0) {\n\t\tconst timeout = settingsManager.getHookTimeout();\n\t\thookRunner = new HookRunner(hooks, cwd, timeout);\n\n\t\t// Wrap tools with hook callbacks\n\t\tselectedTools = wrapToolsWithHooks(selectedTools, hookRunner);\n\t}\n\n\t// Create agent\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel: initialModel as any, // Can be null in interactive mode\n\t\t\tthinkingLevel: initialThinking,\n\t\t\ttools: selectedTools,\n\t\t},\n\t\tmessageTransformer,\n\t\tqueueMode: settingsManager.getQueueMode(),\n\t\ttransport: new ProviderTransport({\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentModel = agent.state.model;\n\t\t\t\tif (!currentModel) {\n\t\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t\t}\n\n\t\t\t\tif (parsed.apiKey) {\n\t\t\t\t\treturn parsed.apiKey;\n\t\t\t\t}\n\n\t\t\t\tconst key = await getApiKeyForModel(currentModel);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`No API key found for provider \"${currentModel.provider}\". Please set the appropriate environment variable or update ${getModelsPath()}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\n\t// If initial thinking was requested but model doesn't support it, reset to off\n\tif (initialThinking !== \"off\" && initialModel && !initialModel.reasoning) {\n\t\tagent.setThinkingLevel(\"off\");\n\t}\n\n\t// Load previous messages if continuing, resuming, or using --session\n\tif (parsed.continue || parsed.resume || parsed.session) {\n\t\tconst messages = sessionManager.loadMessages();\n\t\tif (messages.length > 0) {\n\t\t\tagent.replaceMessages(messages);\n\t\t}\n\t}\n\n\t// Load file commands for slash command expansion\n\tconst fileCommands = loadSlashCommands();\n\n\t// Create session\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels,\n\t\tfileCommands,\n\t\thookRunner,\n\t});\n\n\t// Route to appropriate mode\n\tif (mode === \"rpc\") {\n\t\tawait runRpcMode(session);\n\t} else if (isInteractive) {\n\t\t// Check for new version in the background\n\t\tconst versionCheckPromise = checkForNewVersion(VERSION).catch(() => null);\n\n\t\t// Check if we should show changelog\n\t\tconst changelogMarkdown = getChangelogForDisplay(parsed, settingsManager);\n\n\t\t// Show model scope if provided\n\t\tif (scopedModels.length > 0) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel !== \"off\" ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\t// Ensure fd tool is available for file autocomplete\n\t\tconst fdPath = await ensureTool(\"fd\");\n\n\t\tawait runInteractiveMode(\n\t\t\tsession,\n\t\t\tVERSION,\n\t\t\tchangelogMarkdown,\n\t\t\tmodelFallbackMessage,\n\t\t\tversionCheckPromise,\n\t\t\tparsed.messages,\n\t\t\tinitialMessage,\n\t\t\tinitialAttachments,\n\t\t\tfdPath,\n\t\t);\n\t} else {\n\t\t// Non-interactive mode (--print flag or --mode flag)\n\t\tawait runPrintMode(session, mode, parsed.messages, initialMessage, initialAttachments);\n\t\t// Clean up and exit (file watchers keep process alive)\n\t\tstopThemeWatcher();\n\t\tprocess.exit(0);\n\t}\n}\n\n/** Find initial model based on CLI args, scoped models, settings, or available models */\nasync function findInitialModelForSession(parsed: Args, scopedModels: ScopedModel[], settingsManager: SettingsManager) {\n\t// 1. CLI args take priority\n\tif (parsed.provider && parsed.model) {\n\t\tconst { model, error } = findModel(parsed.provider, parsed.model);\n\t\tif (error) {\n\t\t\tconsole.error(chalk.red(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (!model) {\n\t\t\tconsole.error(chalk.red(`Model ${parsed.provider}/${parsed.model} not found`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\treturn model;\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\treturn scopedModels[0].model;\n\t}\n\n\t// 3. Try saved default from settings\n\tconst defaultProvider = settingsManager.getDefaultProvider();\n\tconst defaultModelId = settingsManager.getDefaultModel();\n\tif (defaultProvider && defaultModelId) {\n\t\tconst { model, error } = findModel(defaultProvider, defaultModelId);\n\t\tif (error) {\n\t\t\tconsole.error(chalk.red(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (model) {\n\t\t\treturn model;\n\t\t}\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst { models: availableModels, error } = await getAvailableModels();\n\n\tif (error) {\n\t\tconsole.error(chalk.red(error));\n\t\tprocess.exit(1);\n\t}\n\n\tif (availableModels.length > 0) {\n\t\treturn availableModels[0];\n\t}\n\n\treturn null;\n}\n\n/** Get changelog markdown to display (only for new sessions with updates) */\nfunction getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): string | null {\n\tif (parsed.continue || parsed.resume) {\n\t\treturn null;\n\t}\n\n\tconst lastVersion = settingsManager.getLastChangelogVersion();\n\tconst changelogPath = getChangelogPath();\n\tconst entries = parseChangelog(changelogPath);\n\n\tif (!lastVersion) {\n\t\t// First run - show all entries\n\t\tif (entries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn entries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t} else {\n\t\t// Check for new entries since last version\n\t\tconst newEntries = getNewEntries(entries, lastVersion);\n\t\tif (newEntries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn newEntries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t}\n\n\treturn null;\n}\n"]}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyIH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,iBAwRxC","sourcesContent":["/**\n * Main entry point for the coding agent\n */\n\nimport { Agent, type Attachment, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport chalk from \"chalk\";\nimport { type Args, parseArgs, printHelp } from \"./cli/args.js\";\nimport { processFileArguments } from \"./cli/file-processor.js\";\nimport { listModels } from \"./cli/list-models.js\";\nimport { selectSession } from \"./cli/session-picker.js\";\nimport { getModelsPath, VERSION } from \"./config.js\";\nimport { AgentSession } from \"./core/agent-session.js\";\nimport { exportFromFile } from \"./core/export-html.js\";\nimport { discoverAndLoadHooks, HookRunner, wrapToolsWithHooks } from \"./core/hooks/index.js\";\nimport { messageTransformer } from \"./core/messages.js\";\nimport { findModel, getApiKeyForModel, getAvailableModels } from \"./core/model-config.js\";\nimport { resolveModelScope, restoreModelFromSession, type ScopedModel } from \"./core/model-resolver.js\";\nimport { SessionManager } from \"./core/session-manager.js\";\nimport { SettingsManager } from \"./core/settings-manager.js\";\nimport { loadSlashCommands } from \"./core/slash-commands.js\";\nimport { buildSystemPrompt } from \"./core/system-prompt.js\";\nimport { allTools, codingTools } from \"./core/tools/index.js\";\nimport { InteractiveMode, runPrintMode, runRpcMode } from \"./modes/index.js\";\nimport { initTheme, stopThemeWatcher } from \"./modes/interactive/theme/theme.js\";\nimport { getChangelogPath, getNewEntries, parseChangelog } from \"./utils/changelog.js\";\nimport { ensureTool } from \"./utils/tools-manager.js\";\n\n/** Check npm registry for new version (non-blocking) */\nasync function checkForNewVersion(currentVersion: string): Promise<string | null> {\n\ttry {\n\t\tconst response = await fetch(\"https://registry.npmjs.org/@mariozechner/pi-coding-agent/latest\");\n\t\tif (!response.ok) return null;\n\n\t\tconst data = (await response.json()) as { version?: string };\n\t\tconst latestVersion = data.version;\n\n\t\tif (latestVersion && latestVersion !== currentVersion) {\n\t\t\treturn latestVersion;\n\t\t}\n\n\t\treturn null;\n\t} catch {\n\t\t// Silently fail - don't disrupt the user experience\n\t\treturn null;\n\t}\n}\n\n/** Run interactive mode with TUI */\nasync function runInteractiveMode(\n\tsession: AgentSession,\n\tversion: string,\n\tchangelogMarkdown: string | null,\n\tmodelFallbackMessage: string | null,\n\tversionCheckPromise: Promise<string | null>,\n\tinitialMessages: string[],\n\tinitialMessage?: string,\n\tinitialAttachments?: Attachment[],\n\tfdPath: string | null = null,\n): Promise<void> {\n\tconst mode = new InteractiveMode(session, version, changelogMarkdown, fdPath);\n\n\t// Initialize TUI (subscribes to agent events internally)\n\tawait mode.init();\n\n\t// Handle version check result when it completes (don't block)\n\tversionCheckPromise.then((newVersion) => {\n\t\tif (newVersion) {\n\t\t\tmode.showNewVersionNotification(newVersion);\n\t\t}\n\t});\n\n\t// Render any existing messages (from --continue mode)\n\tmode.renderInitialMessages(session.state);\n\n\t// Show model fallback warning at the end of the chat if applicable\n\tif (modelFallbackMessage) {\n\t\tmode.showWarning(modelFallbackMessage);\n\t}\n\n\t// Process initial message with attachments if provided (from @file args)\n\tif (initialMessage) {\n\t\ttry {\n\t\t\tawait session.prompt(initialMessage, { attachments: initialAttachments });\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\t// Process remaining initial messages if provided (from CLI args)\n\tfor (const message of initialMessages) {\n\t\ttry {\n\t\t\tawait session.prompt(message);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\t// Interactive loop\n\twhile (true) {\n\t\tconst userInput = await mode.getUserInput();\n\n\t\t// Process the message\n\t\ttry {\n\t\t\tawait session.prompt(userInput);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n}\n\n/** Prepare initial message from @file arguments */\nfunction prepareInitialMessage(parsed: Args): {\n\tinitialMessage?: string;\n\tinitialAttachments?: Attachment[];\n} {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn {};\n\t}\n\n\tconst { textContent, imageAttachments } = processFileArguments(parsed.fileArgs);\n\n\t// Combine file content with first plain text message (if any)\n\tlet initialMessage: string;\n\tif (parsed.messages.length > 0) {\n\t\tinitialMessage = textContent + parsed.messages[0];\n\t\tparsed.messages.shift(); // Remove first message as it's been combined\n\t} else {\n\t\tinitialMessage = textContent;\n\t}\n\n\treturn {\n\t\tinitialMessage,\n\t\tinitialAttachments: imageAttachments.length > 0 ? imageAttachments : undefined,\n\t};\n}\n\nexport async function main(args: string[]) {\n\tconst parsed = parseArgs(args);\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\t// Handle --list-models flag: list available models and exit\n\tif (parsed.listModels !== undefined) {\n\t\tconst searchPattern = typeof parsed.listModels === \"string\" ? parsed.listModels : undefined;\n\t\tawait listModels(searchPattern);\n\t\treturn;\n\t}\n\n\t// Handle --export flag: convert session file to HTML and exit\n\tif (parsed.export) {\n\t\ttry {\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tconst result = exportFromFile(parsed.export, outputPath);\n\t\t\tconsole.log(`Exported to: ${result}`);\n\t\t\treturn;\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// Validate: RPC mode doesn't support @file arguments\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\t// Process @file arguments\n\tconst { initialMessage, initialAttachments } = prepareInitialMessage(parsed);\n\n\t// Determine if we're in interactive mode (needed for theme watcher)\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\n\t// Initialize theme (before any TUI rendering)\n\tconst settingsManager = new SettingsManager();\n\tconst themeName = settingsManager.getTheme();\n\tinitTheme(themeName, isInteractive);\n\n\t// Setup session manager\n\tconst sessionManager = new SessionManager(parsed.continue && !parsed.resume, parsed.session);\n\n\tif (parsed.noSession) {\n\t\tsessionManager.disable();\n\t}\n\n\t// Handle --resume flag: show session selector\n\tif (parsed.resume) {\n\t\tconst selectedSession = await selectSession(sessionManager);\n\t\tif (!selectedSession) {\n\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\treturn;\n\t\t}\n\t\tsessionManager.setSessionFile(selectedSession);\n\t}\n\n\t// Resolve model scope early if provided\n\tlet scopedModels: ScopedModel[] = [];\n\tif (parsed.models && parsed.models.length > 0) {\n\t\tscopedModels = await resolveModelScope(parsed.models);\n\t}\n\n\t// Determine mode and output behavior\n\tconst mode = parsed.mode || \"text\";\n\tconst shouldPrintMessages = isInteractive;\n\n\t// Find initial model\n\tlet initialModel = await findInitialModelForSession(parsed, scopedModels, settingsManager);\n\tlet initialThinking: ThinkingLevel = \"off\";\n\n\t// Get thinking level from scoped models if applicable\n\tif (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\tinitialThinking = scopedModels[0].thinkingLevel;\n\t} else {\n\t\t// Try saved thinking level\n\t\tconst savedThinking = settingsManager.getDefaultThinkingLevel();\n\t\tif (savedThinking) {\n\t\t\tinitialThinking = savedThinking;\n\t\t}\n\t}\n\n\t// Non-interactive mode: fail early if no model available\n\tif (!isInteractive && !initialModel) {\n\t\tconsole.error(chalk.red(\"No models available.\"));\n\t\tconsole.error(chalk.yellow(\"\\nSet an API key environment variable:\"));\n\t\tconsole.error(\" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\");\n\t\tconsole.error(chalk.yellow(`\\nOr create ${getModelsPath()}`));\n\t\tprocess.exit(1);\n\t}\n\n\t// Non-interactive mode: validate API key exists\n\tif (!isInteractive && initialModel) {\n\t\tconst apiKey = parsed.apiKey || (await getApiKeyForModel(initialModel));\n\t\tif (!apiKey) {\n\t\t\tconsole.error(chalk.red(`No API key found for ${initialModel.provider}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// Build system prompt\n\tconst skillsEnabled = !parsed.noSkills && settingsManager.getSkillsEnabled();\n\tconst systemPrompt = buildSystemPrompt({\n\t\tcustomPrompt: parsed.systemPrompt,\n\t\tselectedTools: parsed.tools,\n\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\tskillsEnabled,\n\t});\n\n\t// Handle session restoration\n\tlet modelFallbackMessage: string | null = null;\n\n\tif (parsed.continue || parsed.resume || parsed.session) {\n\t\tconst savedModel = sessionManager.loadModel();\n\t\tif (savedModel) {\n\t\t\tconst result = await restoreModelFromSession(\n\t\t\t\tsavedModel.provider,\n\t\t\t\tsavedModel.modelId,\n\t\t\t\tinitialModel,\n\t\t\t\tshouldPrintMessages,\n\t\t\t);\n\n\t\t\tif (result.model) {\n\t\t\t\tinitialModel = result.model;\n\t\t\t}\n\t\t\tmodelFallbackMessage = result.fallbackMessage;\n\t\t}\n\n\t\t// Load and restore thinking level\n\t\tconst thinkingLevel = sessionManager.loadThinkingLevel() as ThinkingLevel;\n\t\tif (thinkingLevel) {\n\t\t\tinitialThinking = thinkingLevel;\n\t\t\tif (shouldPrintMessages) {\n\t\t\t\tconsole.log(chalk.dim(`Restored thinking level: ${thinkingLevel}`));\n\t\t\t}\n\t\t}\n\t}\n\n\t// CLI --thinking flag takes highest priority\n\tif (parsed.thinking) {\n\t\tinitialThinking = parsed.thinking;\n\t}\n\n\t// Determine which tools to use\n\tlet selectedTools = parsed.tools ? parsed.tools.map((name) => allTools[name]) : codingTools;\n\n\t// Discover and load hooks from:\n\t// 1. ~/.pi/agent/hooks/*.ts (global)\n\t// 2. cwd/.pi/hooks/*.ts (project-local)\n\t// 3. Explicit paths in settings.json\n\t// 4. CLI --hook flags\n\tlet hookRunner: HookRunner | null = null;\n\tconst cwd = process.cwd();\n\tconst configuredHookPaths = [...settingsManager.getHookPaths(), ...(parsed.hooks ?? [])];\n\tconst { hooks, errors } = await discoverAndLoadHooks(configuredHookPaths, cwd);\n\n\t// Report hook loading errors\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(chalk.red(`Failed to load hook \"${path}\": ${error}`));\n\t}\n\n\tif (hooks.length > 0) {\n\t\tconst timeout = settingsManager.getHookTimeout();\n\t\thookRunner = new HookRunner(hooks, cwd, timeout);\n\n\t\t// Wrap tools with hook callbacks\n\t\tselectedTools = wrapToolsWithHooks(selectedTools, hookRunner);\n\t}\n\n\t// Create agent\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel: initialModel as any, // Can be null in interactive mode\n\t\t\tthinkingLevel: initialThinking,\n\t\t\ttools: selectedTools,\n\t\t},\n\t\tmessageTransformer,\n\t\tqueueMode: settingsManager.getQueueMode(),\n\t\ttransport: new ProviderTransport({\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentModel = agent.state.model;\n\t\t\t\tif (!currentModel) {\n\t\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t\t}\n\n\t\t\t\tif (parsed.apiKey) {\n\t\t\t\t\treturn parsed.apiKey;\n\t\t\t\t}\n\n\t\t\t\tconst key = await getApiKeyForModel(currentModel);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`No API key found for provider \"${currentModel.provider}\". Please set the appropriate environment variable or update ${getModelsPath()}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\n\t// If initial thinking was requested but model doesn't support it, reset to off\n\tif (initialThinking !== \"off\" && initialModel && !initialModel.reasoning) {\n\t\tagent.setThinkingLevel(\"off\");\n\t}\n\n\t// Load previous messages if continuing, resuming, or using --session\n\tif (parsed.continue || parsed.resume || parsed.session) {\n\t\tconst messages = sessionManager.loadMessages();\n\t\tif (messages.length > 0) {\n\t\t\tagent.replaceMessages(messages);\n\t\t}\n\t}\n\n\t// Load file commands for slash command expansion\n\tconst fileCommands = loadSlashCommands();\n\n\t// Create session\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels,\n\t\tfileCommands,\n\t\thookRunner,\n\t});\n\n\t// Route to appropriate mode\n\tif (mode === \"rpc\") {\n\t\tawait runRpcMode(session);\n\t} else if (isInteractive) {\n\t\t// Check for new version in the background\n\t\tconst versionCheckPromise = checkForNewVersion(VERSION).catch(() => null);\n\n\t\t// Check if we should show changelog\n\t\tconst changelogMarkdown = getChangelogForDisplay(parsed, settingsManager);\n\n\t\t// Show model scope if provided\n\t\tif (scopedModels.length > 0) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel !== \"off\" ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\t// Ensure fd tool is available for file autocomplete\n\t\tconst fdPath = await ensureTool(\"fd\");\n\n\t\tawait runInteractiveMode(\n\t\t\tsession,\n\t\t\tVERSION,\n\t\t\tchangelogMarkdown,\n\t\t\tmodelFallbackMessage,\n\t\t\tversionCheckPromise,\n\t\t\tparsed.messages,\n\t\t\tinitialMessage,\n\t\t\tinitialAttachments,\n\t\t\tfdPath,\n\t\t);\n\t} else {\n\t\t// Non-interactive mode (--print flag or --mode flag)\n\t\tawait runPrintMode(session, mode, parsed.messages, initialMessage, initialAttachments);\n\t\t// Clean up and exit (file watchers keep process alive)\n\t\tstopThemeWatcher();\n\t\tprocess.exit(0);\n\t}\n}\n\n/** Find initial model based on CLI args, scoped models, settings, or available models */\nasync function findInitialModelForSession(parsed: Args, scopedModels: ScopedModel[], settingsManager: SettingsManager) {\n\t// 1. CLI args take priority\n\tif (parsed.provider && parsed.model) {\n\t\tconst { model, error } = findModel(parsed.provider, parsed.model);\n\t\tif (error) {\n\t\t\tconsole.error(chalk.red(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (!model) {\n\t\t\tconsole.error(chalk.red(`Model ${parsed.provider}/${parsed.model} not found`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\treturn model;\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\treturn scopedModels[0].model;\n\t}\n\n\t// 3. Try saved default from settings\n\tconst defaultProvider = settingsManager.getDefaultProvider();\n\tconst defaultModelId = settingsManager.getDefaultModel();\n\tif (defaultProvider && defaultModelId) {\n\t\tconst { model, error } = findModel(defaultProvider, defaultModelId);\n\t\tif (error) {\n\t\t\tconsole.error(chalk.red(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (model) {\n\t\t\treturn model;\n\t\t}\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst { models: availableModels, error } = await getAvailableModels();\n\n\tif (error) {\n\t\tconsole.error(chalk.red(error));\n\t\tprocess.exit(1);\n\t}\n\n\tif (availableModels.length > 0) {\n\t\treturn availableModels[0];\n\t}\n\n\treturn null;\n}\n\n/** Get changelog markdown to display (only for new sessions with updates) */\nfunction getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): string | null {\n\tif (parsed.continue || parsed.resume) {\n\t\treturn null;\n\t}\n\n\tconst lastVersion = settingsManager.getLastChangelogVersion();\n\tconst changelogPath = getChangelogPath();\n\tconst entries = parseChangelog(changelogPath);\n\n\tif (!lastVersion) {\n\t\t// First run - show all entries\n\t\tif (entries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn entries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t} else {\n\t\t// Check for new entries since last version\n\t\tconst newEntries = getNewEntries(entries, lastVersion);\n\t\tif (newEntries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn newEntries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t}\n\n\treturn null;\n}\n"]}
package/dist/main.js CHANGED
@@ -5,6 +5,7 @@ import { Agent, ProviderTransport } from "@mariozechner/pi-agent-core";
5
5
  import chalk from "chalk";
6
6
  import { parseArgs, printHelp } from "./cli/args.js";
7
7
  import { processFileArguments } from "./cli/file-processor.js";
8
+ import { listModels } from "./cli/list-models.js";
8
9
  import { selectSession } from "./cli/session-picker.js";
9
10
  import { getModelsPath, VERSION } from "./config.js";
10
11
  import { AgentSession } from "./core/agent-session.js";
@@ -120,6 +121,12 @@ export async function main(args) {
120
121
  printHelp();
121
122
  return;
122
123
  }
124
+ // Handle --list-models flag: list available models and exit
125
+ if (parsed.listModels !== undefined) {
126
+ const searchPattern = typeof parsed.listModels === "string" ? parsed.listModels : undefined;
127
+ await listModels(searchPattern);
128
+ return;
129
+ }
123
130
  // Handle --export flag: convert session file to HTML and exit
124
131
  if (parsed.export) {
125
132
  try {
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Main entry point for the coding agent\n */\n\nimport { Agent, type Attachment, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport chalk from \"chalk\";\nimport { type Args, parseArgs, printHelp } from \"./cli/args.js\";\nimport { processFileArguments } from \"./cli/file-processor.js\";\nimport { selectSession } from \"./cli/session-picker.js\";\nimport { getModelsPath, VERSION } from \"./config.js\";\nimport { AgentSession } from \"./core/agent-session.js\";\nimport { exportFromFile } from \"./core/export-html.js\";\nimport { discoverAndLoadHooks, HookRunner, wrapToolsWithHooks } from \"./core/hooks/index.js\";\nimport { messageTransformer } from \"./core/messages.js\";\nimport { findModel, getApiKeyForModel, getAvailableModels } from \"./core/model-config.js\";\nimport { resolveModelScope, restoreModelFromSession, type ScopedModel } from \"./core/model-resolver.js\";\nimport { SessionManager } from \"./core/session-manager.js\";\nimport { SettingsManager } from \"./core/settings-manager.js\";\nimport { loadSlashCommands } from \"./core/slash-commands.js\";\nimport { buildSystemPrompt } from \"./core/system-prompt.js\";\nimport { allTools, codingTools } from \"./core/tools/index.js\";\nimport { InteractiveMode, runPrintMode, runRpcMode } from \"./modes/index.js\";\nimport { initTheme, stopThemeWatcher } from \"./modes/interactive/theme/theme.js\";\nimport { getChangelogPath, getNewEntries, parseChangelog } from \"./utils/changelog.js\";\nimport { ensureTool } from \"./utils/tools-manager.js\";\n\n/** Check npm registry for new version (non-blocking) */\nasync function checkForNewVersion(currentVersion: string): Promise<string | null> {\n\ttry {\n\t\tconst response = await fetch(\"https://registry.npmjs.org/@mariozechner/pi-coding-agent/latest\");\n\t\tif (!response.ok) return null;\n\n\t\tconst data = (await response.json()) as { version?: string };\n\t\tconst latestVersion = data.version;\n\n\t\tif (latestVersion && latestVersion !== currentVersion) {\n\t\t\treturn latestVersion;\n\t\t}\n\n\t\treturn null;\n\t} catch {\n\t\t// Silently fail - don't disrupt the user experience\n\t\treturn null;\n\t}\n}\n\n/** Run interactive mode with TUI */\nasync function runInteractiveMode(\n\tsession: AgentSession,\n\tversion: string,\n\tchangelogMarkdown: string | null,\n\tmodelFallbackMessage: string | null,\n\tversionCheckPromise: Promise<string | null>,\n\tinitialMessages: string[],\n\tinitialMessage?: string,\n\tinitialAttachments?: Attachment[],\n\tfdPath: string | null = null,\n): Promise<void> {\n\tconst mode = new InteractiveMode(session, version, changelogMarkdown, fdPath);\n\n\t// Initialize TUI (subscribes to agent events internally)\n\tawait mode.init();\n\n\t// Handle version check result when it completes (don't block)\n\tversionCheckPromise.then((newVersion) => {\n\t\tif (newVersion) {\n\t\t\tmode.showNewVersionNotification(newVersion);\n\t\t}\n\t});\n\n\t// Render any existing messages (from --continue mode)\n\tmode.renderInitialMessages(session.state);\n\n\t// Show model fallback warning at the end of the chat if applicable\n\tif (modelFallbackMessage) {\n\t\tmode.showWarning(modelFallbackMessage);\n\t}\n\n\t// Process initial message with attachments if provided (from @file args)\n\tif (initialMessage) {\n\t\ttry {\n\t\t\tawait session.prompt(initialMessage, { attachments: initialAttachments });\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\t// Process remaining initial messages if provided (from CLI args)\n\tfor (const message of initialMessages) {\n\t\ttry {\n\t\t\tawait session.prompt(message);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\t// Interactive loop\n\twhile (true) {\n\t\tconst userInput = await mode.getUserInput();\n\n\t\t// Process the message\n\t\ttry {\n\t\t\tawait session.prompt(userInput);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n}\n\n/** Prepare initial message from @file arguments */\nfunction prepareInitialMessage(parsed: Args): {\n\tinitialMessage?: string;\n\tinitialAttachments?: Attachment[];\n} {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn {};\n\t}\n\n\tconst { textContent, imageAttachments } = processFileArguments(parsed.fileArgs);\n\n\t// Combine file content with first plain text message (if any)\n\tlet initialMessage: string;\n\tif (parsed.messages.length > 0) {\n\t\tinitialMessage = textContent + parsed.messages[0];\n\t\tparsed.messages.shift(); // Remove first message as it's been combined\n\t} else {\n\t\tinitialMessage = textContent;\n\t}\n\n\treturn {\n\t\tinitialMessage,\n\t\tinitialAttachments: imageAttachments.length > 0 ? imageAttachments : undefined,\n\t};\n}\n\nexport async function main(args: string[]) {\n\tconst parsed = parseArgs(args);\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\t// Handle --export flag: convert session file to HTML and exit\n\tif (parsed.export) {\n\t\ttry {\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tconst result = exportFromFile(parsed.export, outputPath);\n\t\t\tconsole.log(`Exported to: ${result}`);\n\t\t\treturn;\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// Validate: RPC mode doesn't support @file arguments\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\t// Process @file arguments\n\tconst { initialMessage, initialAttachments } = prepareInitialMessage(parsed);\n\n\t// Determine if we're in interactive mode (needed for theme watcher)\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\n\t// Initialize theme (before any TUI rendering)\n\tconst settingsManager = new SettingsManager();\n\tconst themeName = settingsManager.getTheme();\n\tinitTheme(themeName, isInteractive);\n\n\t// Setup session manager\n\tconst sessionManager = new SessionManager(parsed.continue && !parsed.resume, parsed.session);\n\n\tif (parsed.noSession) {\n\t\tsessionManager.disable();\n\t}\n\n\t// Handle --resume flag: show session selector\n\tif (parsed.resume) {\n\t\tconst selectedSession = await selectSession(sessionManager);\n\t\tif (!selectedSession) {\n\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\treturn;\n\t\t}\n\t\tsessionManager.setSessionFile(selectedSession);\n\t}\n\n\t// Resolve model scope early if provided\n\tlet scopedModels: ScopedModel[] = [];\n\tif (parsed.models && parsed.models.length > 0) {\n\t\tscopedModels = await resolveModelScope(parsed.models);\n\t}\n\n\t// Determine mode and output behavior\n\tconst mode = parsed.mode || \"text\";\n\tconst shouldPrintMessages = isInteractive;\n\n\t// Find initial model\n\tlet initialModel = await findInitialModelForSession(parsed, scopedModels, settingsManager);\n\tlet initialThinking: ThinkingLevel = \"off\";\n\n\t// Get thinking level from scoped models if applicable\n\tif (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\tinitialThinking = scopedModels[0].thinkingLevel;\n\t} else {\n\t\t// Try saved thinking level\n\t\tconst savedThinking = settingsManager.getDefaultThinkingLevel();\n\t\tif (savedThinking) {\n\t\t\tinitialThinking = savedThinking;\n\t\t}\n\t}\n\n\t// Non-interactive mode: fail early if no model available\n\tif (!isInteractive && !initialModel) {\n\t\tconsole.error(chalk.red(\"No models available.\"));\n\t\tconsole.error(chalk.yellow(\"\\nSet an API key environment variable:\"));\n\t\tconsole.error(\" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\");\n\t\tconsole.error(chalk.yellow(`\\nOr create ${getModelsPath()}`));\n\t\tprocess.exit(1);\n\t}\n\n\t// Non-interactive mode: validate API key exists\n\tif (!isInteractive && initialModel) {\n\t\tconst apiKey = parsed.apiKey || (await getApiKeyForModel(initialModel));\n\t\tif (!apiKey) {\n\t\t\tconsole.error(chalk.red(`No API key found for ${initialModel.provider}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// Build system prompt\n\tconst skillsEnabled = !parsed.noSkills && settingsManager.getSkillsEnabled();\n\tconst systemPrompt = buildSystemPrompt({\n\t\tcustomPrompt: parsed.systemPrompt,\n\t\tselectedTools: parsed.tools,\n\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\tskillsEnabled,\n\t});\n\n\t// Handle session restoration\n\tlet modelFallbackMessage: string | null = null;\n\n\tif (parsed.continue || parsed.resume || parsed.session) {\n\t\tconst savedModel = sessionManager.loadModel();\n\t\tif (savedModel) {\n\t\t\tconst result = await restoreModelFromSession(\n\t\t\t\tsavedModel.provider,\n\t\t\t\tsavedModel.modelId,\n\t\t\t\tinitialModel,\n\t\t\t\tshouldPrintMessages,\n\t\t\t);\n\n\t\t\tif (result.model) {\n\t\t\t\tinitialModel = result.model;\n\t\t\t}\n\t\t\tmodelFallbackMessage = result.fallbackMessage;\n\t\t}\n\n\t\t// Load and restore thinking level\n\t\tconst thinkingLevel = sessionManager.loadThinkingLevel() as ThinkingLevel;\n\t\tif (thinkingLevel) {\n\t\t\tinitialThinking = thinkingLevel;\n\t\t\tif (shouldPrintMessages) {\n\t\t\t\tconsole.log(chalk.dim(`Restored thinking level: ${thinkingLevel}`));\n\t\t\t}\n\t\t}\n\t}\n\n\t// CLI --thinking flag takes highest priority\n\tif (parsed.thinking) {\n\t\tinitialThinking = parsed.thinking;\n\t}\n\n\t// Determine which tools to use\n\tlet selectedTools = parsed.tools ? parsed.tools.map((name) => allTools[name]) : codingTools;\n\n\t// Discover and load hooks from:\n\t// 1. ~/.pi/agent/hooks/*.ts (global)\n\t// 2. cwd/.pi/hooks/*.ts (project-local)\n\t// 3. Explicit paths in settings.json\n\t// 4. CLI --hook flags\n\tlet hookRunner: HookRunner | null = null;\n\tconst cwd = process.cwd();\n\tconst configuredHookPaths = [...settingsManager.getHookPaths(), ...(parsed.hooks ?? [])];\n\tconst { hooks, errors } = await discoverAndLoadHooks(configuredHookPaths, cwd);\n\n\t// Report hook loading errors\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(chalk.red(`Failed to load hook \"${path}\": ${error}`));\n\t}\n\n\tif (hooks.length > 0) {\n\t\tconst timeout = settingsManager.getHookTimeout();\n\t\thookRunner = new HookRunner(hooks, cwd, timeout);\n\n\t\t// Wrap tools with hook callbacks\n\t\tselectedTools = wrapToolsWithHooks(selectedTools, hookRunner);\n\t}\n\n\t// Create agent\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel: initialModel as any, // Can be null in interactive mode\n\t\t\tthinkingLevel: initialThinking,\n\t\t\ttools: selectedTools,\n\t\t},\n\t\tmessageTransformer,\n\t\tqueueMode: settingsManager.getQueueMode(),\n\t\ttransport: new ProviderTransport({\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentModel = agent.state.model;\n\t\t\t\tif (!currentModel) {\n\t\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t\t}\n\n\t\t\t\tif (parsed.apiKey) {\n\t\t\t\t\treturn parsed.apiKey;\n\t\t\t\t}\n\n\t\t\t\tconst key = await getApiKeyForModel(currentModel);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`No API key found for provider \"${currentModel.provider}\". Please set the appropriate environment variable or update ${getModelsPath()}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\n\t// If initial thinking was requested but model doesn't support it, reset to off\n\tif (initialThinking !== \"off\" && initialModel && !initialModel.reasoning) {\n\t\tagent.setThinkingLevel(\"off\");\n\t}\n\n\t// Load previous messages if continuing, resuming, or using --session\n\tif (parsed.continue || parsed.resume || parsed.session) {\n\t\tconst messages = sessionManager.loadMessages();\n\t\tif (messages.length > 0) {\n\t\t\tagent.replaceMessages(messages);\n\t\t}\n\t}\n\n\t// Load file commands for slash command expansion\n\tconst fileCommands = loadSlashCommands();\n\n\t// Create session\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels,\n\t\tfileCommands,\n\t\thookRunner,\n\t});\n\n\t// Route to appropriate mode\n\tif (mode === \"rpc\") {\n\t\tawait runRpcMode(session);\n\t} else if (isInteractive) {\n\t\t// Check for new version in the background\n\t\tconst versionCheckPromise = checkForNewVersion(VERSION).catch(() => null);\n\n\t\t// Check if we should show changelog\n\t\tconst changelogMarkdown = getChangelogForDisplay(parsed, settingsManager);\n\n\t\t// Show model scope if provided\n\t\tif (scopedModels.length > 0) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel !== \"off\" ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\t// Ensure fd tool is available for file autocomplete\n\t\tconst fdPath = await ensureTool(\"fd\");\n\n\t\tawait runInteractiveMode(\n\t\t\tsession,\n\t\t\tVERSION,\n\t\t\tchangelogMarkdown,\n\t\t\tmodelFallbackMessage,\n\t\t\tversionCheckPromise,\n\t\t\tparsed.messages,\n\t\t\tinitialMessage,\n\t\t\tinitialAttachments,\n\t\t\tfdPath,\n\t\t);\n\t} else {\n\t\t// Non-interactive mode (--print flag or --mode flag)\n\t\tawait runPrintMode(session, mode, parsed.messages, initialMessage, initialAttachments);\n\t\t// Clean up and exit (file watchers keep process alive)\n\t\tstopThemeWatcher();\n\t\tprocess.exit(0);\n\t}\n}\n\n/** Find initial model based on CLI args, scoped models, settings, or available models */\nasync function findInitialModelForSession(parsed: Args, scopedModels: ScopedModel[], settingsManager: SettingsManager) {\n\t// 1. CLI args take priority\n\tif (parsed.provider && parsed.model) {\n\t\tconst { model, error } = findModel(parsed.provider, parsed.model);\n\t\tif (error) {\n\t\t\tconsole.error(chalk.red(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (!model) {\n\t\t\tconsole.error(chalk.red(`Model ${parsed.provider}/${parsed.model} not found`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\treturn model;\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\treturn scopedModels[0].model;\n\t}\n\n\t// 3. Try saved default from settings\n\tconst defaultProvider = settingsManager.getDefaultProvider();\n\tconst defaultModelId = settingsManager.getDefaultModel();\n\tif (defaultProvider && defaultModelId) {\n\t\tconst { model, error } = findModel(defaultProvider, defaultModelId);\n\t\tif (error) {\n\t\t\tconsole.error(chalk.red(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (model) {\n\t\t\treturn model;\n\t\t}\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst { models: availableModels, error } = await getAvailableModels();\n\n\tif (error) {\n\t\tconsole.error(chalk.red(error));\n\t\tprocess.exit(1);\n\t}\n\n\tif (availableModels.length > 0) {\n\t\treturn availableModels[0];\n\t}\n\n\treturn null;\n}\n\n/** Get changelog markdown to display (only for new sessions with updates) */\nfunction getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): string | null {\n\tif (parsed.continue || parsed.resume) {\n\t\treturn null;\n\t}\n\n\tconst lastVersion = settingsManager.getLastChangelogVersion();\n\tconst changelogPath = getChangelogPath();\n\tconst entries = parseChangelog(changelogPath);\n\n\tif (!lastVersion) {\n\t\t// First run - show all entries\n\t\tif (entries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn entries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t} else {\n\t\t// Check for new entries since last version\n\t\tconst newEntries = getNewEntries(entries, lastVersion);\n\t\tif (newEntries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn newEntries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t}\n\n\treturn null;\n}\n"]}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Main entry point for the coding agent\n */\n\nimport { Agent, type Attachment, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport chalk from \"chalk\";\nimport { type Args, parseArgs, printHelp } from \"./cli/args.js\";\nimport { processFileArguments } from \"./cli/file-processor.js\";\nimport { listModels } from \"./cli/list-models.js\";\nimport { selectSession } from \"./cli/session-picker.js\";\nimport { getModelsPath, VERSION } from \"./config.js\";\nimport { AgentSession } from \"./core/agent-session.js\";\nimport { exportFromFile } from \"./core/export-html.js\";\nimport { discoverAndLoadHooks, HookRunner, wrapToolsWithHooks } from \"./core/hooks/index.js\";\nimport { messageTransformer } from \"./core/messages.js\";\nimport { findModel, getApiKeyForModel, getAvailableModels } from \"./core/model-config.js\";\nimport { resolveModelScope, restoreModelFromSession, type ScopedModel } from \"./core/model-resolver.js\";\nimport { SessionManager } from \"./core/session-manager.js\";\nimport { SettingsManager } from \"./core/settings-manager.js\";\nimport { loadSlashCommands } from \"./core/slash-commands.js\";\nimport { buildSystemPrompt } from \"./core/system-prompt.js\";\nimport { allTools, codingTools } from \"./core/tools/index.js\";\nimport { InteractiveMode, runPrintMode, runRpcMode } from \"./modes/index.js\";\nimport { initTheme, stopThemeWatcher } from \"./modes/interactive/theme/theme.js\";\nimport { getChangelogPath, getNewEntries, parseChangelog } from \"./utils/changelog.js\";\nimport { ensureTool } from \"./utils/tools-manager.js\";\n\n/** Check npm registry for new version (non-blocking) */\nasync function checkForNewVersion(currentVersion: string): Promise<string | null> {\n\ttry {\n\t\tconst response = await fetch(\"https://registry.npmjs.org/@mariozechner/pi-coding-agent/latest\");\n\t\tif (!response.ok) return null;\n\n\t\tconst data = (await response.json()) as { version?: string };\n\t\tconst latestVersion = data.version;\n\n\t\tif (latestVersion && latestVersion !== currentVersion) {\n\t\t\treturn latestVersion;\n\t\t}\n\n\t\treturn null;\n\t} catch {\n\t\t// Silently fail - don't disrupt the user experience\n\t\treturn null;\n\t}\n}\n\n/** Run interactive mode with TUI */\nasync function runInteractiveMode(\n\tsession: AgentSession,\n\tversion: string,\n\tchangelogMarkdown: string | null,\n\tmodelFallbackMessage: string | null,\n\tversionCheckPromise: Promise<string | null>,\n\tinitialMessages: string[],\n\tinitialMessage?: string,\n\tinitialAttachments?: Attachment[],\n\tfdPath: string | null = null,\n): Promise<void> {\n\tconst mode = new InteractiveMode(session, version, changelogMarkdown, fdPath);\n\n\t// Initialize TUI (subscribes to agent events internally)\n\tawait mode.init();\n\n\t// Handle version check result when it completes (don't block)\n\tversionCheckPromise.then((newVersion) => {\n\t\tif (newVersion) {\n\t\t\tmode.showNewVersionNotification(newVersion);\n\t\t}\n\t});\n\n\t// Render any existing messages (from --continue mode)\n\tmode.renderInitialMessages(session.state);\n\n\t// Show model fallback warning at the end of the chat if applicable\n\tif (modelFallbackMessage) {\n\t\tmode.showWarning(modelFallbackMessage);\n\t}\n\n\t// Process initial message with attachments if provided (from @file args)\n\tif (initialMessage) {\n\t\ttry {\n\t\t\tawait session.prompt(initialMessage, { attachments: initialAttachments });\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\t// Process remaining initial messages if provided (from CLI args)\n\tfor (const message of initialMessages) {\n\t\ttry {\n\t\t\tawait session.prompt(message);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n\n\t// Interactive loop\n\twhile (true) {\n\t\tconst userInput = await mode.getUserInput();\n\n\t\t// Process the message\n\t\ttry {\n\t\t\tawait session.prompt(userInput);\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Unknown error occurred\";\n\t\t\tmode.showError(errorMessage);\n\t\t}\n\t}\n}\n\n/** Prepare initial message from @file arguments */\nfunction prepareInitialMessage(parsed: Args): {\n\tinitialMessage?: string;\n\tinitialAttachments?: Attachment[];\n} {\n\tif (parsed.fileArgs.length === 0) {\n\t\treturn {};\n\t}\n\n\tconst { textContent, imageAttachments } = processFileArguments(parsed.fileArgs);\n\n\t// Combine file content with first plain text message (if any)\n\tlet initialMessage: string;\n\tif (parsed.messages.length > 0) {\n\t\tinitialMessage = textContent + parsed.messages[0];\n\t\tparsed.messages.shift(); // Remove first message as it's been combined\n\t} else {\n\t\tinitialMessage = textContent;\n\t}\n\n\treturn {\n\t\tinitialMessage,\n\t\tinitialAttachments: imageAttachments.length > 0 ? imageAttachments : undefined,\n\t};\n}\n\nexport async function main(args: string[]) {\n\tconst parsed = parseArgs(args);\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\t// Handle --list-models flag: list available models and exit\n\tif (parsed.listModels !== undefined) {\n\t\tconst searchPattern = typeof parsed.listModels === \"string\" ? parsed.listModels : undefined;\n\t\tawait listModels(searchPattern);\n\t\treturn;\n\t}\n\n\t// Handle --export flag: convert session file to HTML and exit\n\tif (parsed.export) {\n\t\ttry {\n\t\t\tconst outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;\n\t\t\tconst result = exportFromFile(parsed.export, outputPath);\n\t\t\tconsole.log(`Exported to: ${result}`);\n\t\t\treturn;\n\t\t} catch (error: unknown) {\n\t\t\tconst message = error instanceof Error ? error.message : \"Failed to export session\";\n\t\t\tconsole.error(chalk.red(`Error: ${message}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// Validate: RPC mode doesn't support @file arguments\n\tif (parsed.mode === \"rpc\" && parsed.fileArgs.length > 0) {\n\t\tconsole.error(chalk.red(\"Error: @file arguments are not supported in RPC mode\"));\n\t\tprocess.exit(1);\n\t}\n\n\t// Process @file arguments\n\tconst { initialMessage, initialAttachments } = prepareInitialMessage(parsed);\n\n\t// Determine if we're in interactive mode (needed for theme watcher)\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\n\t// Initialize theme (before any TUI rendering)\n\tconst settingsManager = new SettingsManager();\n\tconst themeName = settingsManager.getTheme();\n\tinitTheme(themeName, isInteractive);\n\n\t// Setup session manager\n\tconst sessionManager = new SessionManager(parsed.continue && !parsed.resume, parsed.session);\n\n\tif (parsed.noSession) {\n\t\tsessionManager.disable();\n\t}\n\n\t// Handle --resume flag: show session selector\n\tif (parsed.resume) {\n\t\tconst selectedSession = await selectSession(sessionManager);\n\t\tif (!selectedSession) {\n\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\treturn;\n\t\t}\n\t\tsessionManager.setSessionFile(selectedSession);\n\t}\n\n\t// Resolve model scope early if provided\n\tlet scopedModels: ScopedModel[] = [];\n\tif (parsed.models && parsed.models.length > 0) {\n\t\tscopedModels = await resolveModelScope(parsed.models);\n\t}\n\n\t// Determine mode and output behavior\n\tconst mode = parsed.mode || \"text\";\n\tconst shouldPrintMessages = isInteractive;\n\n\t// Find initial model\n\tlet initialModel = await findInitialModelForSession(parsed, scopedModels, settingsManager);\n\tlet initialThinking: ThinkingLevel = \"off\";\n\n\t// Get thinking level from scoped models if applicable\n\tif (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\tinitialThinking = scopedModels[0].thinkingLevel;\n\t} else {\n\t\t// Try saved thinking level\n\t\tconst savedThinking = settingsManager.getDefaultThinkingLevel();\n\t\tif (savedThinking) {\n\t\t\tinitialThinking = savedThinking;\n\t\t}\n\t}\n\n\t// Non-interactive mode: fail early if no model available\n\tif (!isInteractive && !initialModel) {\n\t\tconsole.error(chalk.red(\"No models available.\"));\n\t\tconsole.error(chalk.yellow(\"\\nSet an API key environment variable:\"));\n\t\tconsole.error(\" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\");\n\t\tconsole.error(chalk.yellow(`\\nOr create ${getModelsPath()}`));\n\t\tprocess.exit(1);\n\t}\n\n\t// Non-interactive mode: validate API key exists\n\tif (!isInteractive && initialModel) {\n\t\tconst apiKey = parsed.apiKey || (await getApiKeyForModel(initialModel));\n\t\tif (!apiKey) {\n\t\t\tconsole.error(chalk.red(`No API key found for ${initialModel.provider}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\t// Build system prompt\n\tconst skillsEnabled = !parsed.noSkills && settingsManager.getSkillsEnabled();\n\tconst systemPrompt = buildSystemPrompt({\n\t\tcustomPrompt: parsed.systemPrompt,\n\t\tselectedTools: parsed.tools,\n\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\tskillsEnabled,\n\t});\n\n\t// Handle session restoration\n\tlet modelFallbackMessage: string | null = null;\n\n\tif (parsed.continue || parsed.resume || parsed.session) {\n\t\tconst savedModel = sessionManager.loadModel();\n\t\tif (savedModel) {\n\t\t\tconst result = await restoreModelFromSession(\n\t\t\t\tsavedModel.provider,\n\t\t\t\tsavedModel.modelId,\n\t\t\t\tinitialModel,\n\t\t\t\tshouldPrintMessages,\n\t\t\t);\n\n\t\t\tif (result.model) {\n\t\t\t\tinitialModel = result.model;\n\t\t\t}\n\t\t\tmodelFallbackMessage = result.fallbackMessage;\n\t\t}\n\n\t\t// Load and restore thinking level\n\t\tconst thinkingLevel = sessionManager.loadThinkingLevel() as ThinkingLevel;\n\t\tif (thinkingLevel) {\n\t\t\tinitialThinking = thinkingLevel;\n\t\t\tif (shouldPrintMessages) {\n\t\t\t\tconsole.log(chalk.dim(`Restored thinking level: ${thinkingLevel}`));\n\t\t\t}\n\t\t}\n\t}\n\n\t// CLI --thinking flag takes highest priority\n\tif (parsed.thinking) {\n\t\tinitialThinking = parsed.thinking;\n\t}\n\n\t// Determine which tools to use\n\tlet selectedTools = parsed.tools ? parsed.tools.map((name) => allTools[name]) : codingTools;\n\n\t// Discover and load hooks from:\n\t// 1. ~/.pi/agent/hooks/*.ts (global)\n\t// 2. cwd/.pi/hooks/*.ts (project-local)\n\t// 3. Explicit paths in settings.json\n\t// 4. CLI --hook flags\n\tlet hookRunner: HookRunner | null = null;\n\tconst cwd = process.cwd();\n\tconst configuredHookPaths = [...settingsManager.getHookPaths(), ...(parsed.hooks ?? [])];\n\tconst { hooks, errors } = await discoverAndLoadHooks(configuredHookPaths, cwd);\n\n\t// Report hook loading errors\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(chalk.red(`Failed to load hook \"${path}\": ${error}`));\n\t}\n\n\tif (hooks.length > 0) {\n\t\tconst timeout = settingsManager.getHookTimeout();\n\t\thookRunner = new HookRunner(hooks, cwd, timeout);\n\n\t\t// Wrap tools with hook callbacks\n\t\tselectedTools = wrapToolsWithHooks(selectedTools, hookRunner);\n\t}\n\n\t// Create agent\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel: initialModel as any, // Can be null in interactive mode\n\t\t\tthinkingLevel: initialThinking,\n\t\t\ttools: selectedTools,\n\t\t},\n\t\tmessageTransformer,\n\t\tqueueMode: settingsManager.getQueueMode(),\n\t\ttransport: new ProviderTransport({\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentModel = agent.state.model;\n\t\t\t\tif (!currentModel) {\n\t\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t\t}\n\n\t\t\t\tif (parsed.apiKey) {\n\t\t\t\t\treturn parsed.apiKey;\n\t\t\t\t}\n\n\t\t\t\tconst key = await getApiKeyForModel(currentModel);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`No API key found for provider \"${currentModel.provider}\". Please set the appropriate environment variable or update ${getModelsPath()}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\n\t// If initial thinking was requested but model doesn't support it, reset to off\n\tif (initialThinking !== \"off\" && initialModel && !initialModel.reasoning) {\n\t\tagent.setThinkingLevel(\"off\");\n\t}\n\n\t// Load previous messages if continuing, resuming, or using --session\n\tif (parsed.continue || parsed.resume || parsed.session) {\n\t\tconst messages = sessionManager.loadMessages();\n\t\tif (messages.length > 0) {\n\t\t\tagent.replaceMessages(messages);\n\t\t}\n\t}\n\n\t// Load file commands for slash command expansion\n\tconst fileCommands = loadSlashCommands();\n\n\t// Create session\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels,\n\t\tfileCommands,\n\t\thookRunner,\n\t});\n\n\t// Route to appropriate mode\n\tif (mode === \"rpc\") {\n\t\tawait runRpcMode(session);\n\t} else if (isInteractive) {\n\t\t// Check for new version in the background\n\t\tconst versionCheckPromise = checkForNewVersion(VERSION).catch(() => null);\n\n\t\t// Check if we should show changelog\n\t\tconst changelogMarkdown = getChangelogForDisplay(parsed, settingsManager);\n\n\t\t// Show model scope if provided\n\t\tif (scopedModels.length > 0) {\n\t\t\tconst modelList = scopedModels\n\t\t\t\t.map((sm) => {\n\t\t\t\t\tconst thinkingStr = sm.thinkingLevel !== \"off\" ? `:${sm.thinkingLevel}` : \"\";\n\t\t\t\t\treturn `${sm.model.id}${thinkingStr}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \");\n\t\t\tconsole.log(chalk.dim(`Model scope: ${modelList} ${chalk.gray(\"(Ctrl+P to cycle)\")}`));\n\t\t}\n\n\t\t// Ensure fd tool is available for file autocomplete\n\t\tconst fdPath = await ensureTool(\"fd\");\n\n\t\tawait runInteractiveMode(\n\t\t\tsession,\n\t\t\tVERSION,\n\t\t\tchangelogMarkdown,\n\t\t\tmodelFallbackMessage,\n\t\t\tversionCheckPromise,\n\t\t\tparsed.messages,\n\t\t\tinitialMessage,\n\t\t\tinitialAttachments,\n\t\t\tfdPath,\n\t\t);\n\t} else {\n\t\t// Non-interactive mode (--print flag or --mode flag)\n\t\tawait runPrintMode(session, mode, parsed.messages, initialMessage, initialAttachments);\n\t\t// Clean up and exit (file watchers keep process alive)\n\t\tstopThemeWatcher();\n\t\tprocess.exit(0);\n\t}\n}\n\n/** Find initial model based on CLI args, scoped models, settings, or available models */\nasync function findInitialModelForSession(parsed: Args, scopedModels: ScopedModel[], settingsManager: SettingsManager) {\n\t// 1. CLI args take priority\n\tif (parsed.provider && parsed.model) {\n\t\tconst { model, error } = findModel(parsed.provider, parsed.model);\n\t\tif (error) {\n\t\t\tconsole.error(chalk.red(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (!model) {\n\t\t\tconsole.error(chalk.red(`Model ${parsed.provider}/${parsed.model} not found`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\treturn model;\n\t}\n\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\n\tif (scopedModels.length > 0 && !parsed.continue && !parsed.resume) {\n\t\treturn scopedModels[0].model;\n\t}\n\n\t// 3. Try saved default from settings\n\tconst defaultProvider = settingsManager.getDefaultProvider();\n\tconst defaultModelId = settingsManager.getDefaultModel();\n\tif (defaultProvider && defaultModelId) {\n\t\tconst { model, error } = findModel(defaultProvider, defaultModelId);\n\t\tif (error) {\n\t\t\tconsole.error(chalk.red(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (model) {\n\t\t\treturn model;\n\t\t}\n\t}\n\n\t// 4. Try first available model with valid API key\n\tconst { models: availableModels, error } = await getAvailableModels();\n\n\tif (error) {\n\t\tconsole.error(chalk.red(error));\n\t\tprocess.exit(1);\n\t}\n\n\tif (availableModels.length > 0) {\n\t\treturn availableModels[0];\n\t}\n\n\treturn null;\n}\n\n/** Get changelog markdown to display (only for new sessions with updates) */\nfunction getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): string | null {\n\tif (parsed.continue || parsed.resume) {\n\t\treturn null;\n\t}\n\n\tconst lastVersion = settingsManager.getLastChangelogVersion();\n\tconst changelogPath = getChangelogPath();\n\tconst entries = parseChangelog(changelogPath);\n\n\tif (!lastVersion) {\n\t\t// First run - show all entries\n\t\tif (entries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn entries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t} else {\n\t\t// Check for new entries since last version\n\t\tconst newEntries = getNewEntries(entries, lastVersion);\n\t\tif (newEntries.length > 0) {\n\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\treturn newEntries.map((e) => e.content).join(\"\\n\\n\");\n\t\t}\n\t}\n\n\treturn null;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"AACA,OAAO,EACN,SAAS,EAOT,MAAM,sBAAsB,CAAC;AAuB9B,MAAM,WAAW,oBAAoB;IACpC,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,WAAW,CAAO;IAC1B,OAAO,CAAC,eAAe,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAC,CAIb;IAEF,YAAY,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,GAAE,oBAAyB,EAS1E;IAED,UAAU,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CAG1B;IAED,YAAY,CACX,MAAM,EAAE;QACP,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAClF,OAAO,CAAC,EAAE,GAAG,CAAC;QACd,OAAO,EAAE,OAAO,CAAC;KACjB,EACD,SAAS,UAAQ,GACf,IAAI,CAIN;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAGnC;IAED,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAGjC;IAED,OAAO,CAAC,aAAa;IAoCrB,OAAO,CAAC,aAAa;IA8BrB,OAAO,CAAC,mBAAmB;CAwS3B","sourcesContent":["import * as os from \"node:os\";\nimport {\n\tContainer,\n\tgetCapabilities,\n\tgetImageDimensions,\n\tImage,\n\timageFallback,\n\tSpacer,\n\tText,\n} from \"@mariozechner/pi-tui\";\nimport stripAnsi from \"strip-ansi\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from \"../../../core/tools/truncate.js\";\nimport { theme } from \"../theme/theme.js\";\n\n/**\n * Convert absolute path to tilde notation if it's in home directory\n */\nfunction shortenPath(path: string): string {\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn \"~\" + path.slice(home.length);\n\t}\n\treturn path;\n}\n\n/**\n * Replace tabs with spaces for consistent rendering\n */\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean; // default: true (only used if terminal supports images)\n}\n\n/**\n * Component that renders a tool call with its result (updateable)\n */\nexport class ToolExecutionComponent extends Container {\n\tprivate contentText: Text;\n\tprivate imageComponents: Image[] = [];\n\tprivate toolName: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate showImages: boolean;\n\tprivate isPartial = false;\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\n\tconstructor(toolName: string, args: any, options: ToolExecutionOptions = {}) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.args = args;\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.contentText = new Text(\"\", 1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\t\tthis.addChild(this.contentText);\n\t\tthis.updateDisplay();\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tconst bgFn = this.isPartial\n\t\t\t? (text: string) => theme.bg(\"toolPendingBg\", text)\n\t\t\t: this.result?.isError\n\t\t\t\t? (text: string) => theme.bg(\"toolErrorBg\", text)\n\t\t\t\t: (text: string) => theme.bg(\"toolSuccessBg\", text);\n\n\t\tthis.contentText.setCustomBgFn(bgFn);\n\t\tthis.contentText.setText(this.formatToolExecution());\n\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\t\t\tconst caps = getCapabilities();\n\n\t\t\tfor (const img of imageBlocks) {\n\t\t\t\t// Show inline image only if terminal supports it AND user setting allows it\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\tthis.addChild(new Spacer(1));\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timg.data,\n\t\t\t\t\t\timg.mimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: 60 },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getTextOutput(): string {\n\t\tif (!this.result) return \"\";\n\n\t\tconst textBlocks = this.result.content?.filter((c: any) => c.type === \"text\") || [];\n\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\n\t\tlet output = textBlocks\n\t\t\t.map((c: any) => {\n\t\t\t\tlet text = stripAnsi(c.text || \"\").replace(/\\r/g, \"\");\n\t\t\t\ttext = text.replace(/\\x1b./g, \"\");\n\t\t\t\ttext = text.replace(/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f-\\x9f]/g, \"\");\n\t\t\t\treturn text;\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\n\t\tconst caps = getCapabilities();\n\t\t// Show text fallback if terminal doesn't support images OR if user disabled inline images\n\t\tif (imageBlocks.length > 0 && (!caps.images || !this.showImages)) {\n\t\t\tconst imageIndicators = imageBlocks\n\t\t\t\t.map((img: any) => {\n\t\t\t\t\tconst dims = img.data ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\t\treturn imageFallback(img.mimeType, dims);\n\t\t\t\t})\n\t\t\t\t.join(\"\\n\");\n\t\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t\t}\n\n\t\treturn output;\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tlet text = \"\";\n\n\t\t// Format based on tool type\n\t\tif (this.toolName === \"bash\") {\n\t\t\tconst command = this.args?.command || \"\";\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(`$ ${command || theme.fg(\"toolOutput\", \"...\")}`));\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 5;\n\t\t\t\t\tconst skipped = Math.max(0, lines.length - maxLines);\n\t\t\t\t\tconst displayLines = lines.slice(-maxLines);\n\n\t\t\t\t\tif (skipped > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n\\n... (${skipped} earlier lines)`);\n\t\t\t\t\t}\n\t\t\t\t\ttext +=\n\t\t\t\t\t\t(skipped > 0 ? \"\\n\" : \"\\n\\n\") +\n\t\t\t\t\t\tdisplayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tconst fullOutputPath = this.result.details?.fullOutputPath;\n\t\t\t\tif (truncation?.truncated || fullOutputPath) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (fullOutputPath) {\n\t\t\t\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\twarnings.push(\n\t\t\t\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[${warnings.join(\". \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"read\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\tconst offset = this.args?.offset;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\t// Build path display with offset/limit suffix (in warning color if offset/limit used)\n\t\t\tlet pathDisplay = path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\t\t\tif (offset !== undefined || limit !== undefined) {\n\t\t\t\tconst startLine = offset ?? 1;\n\t\t\t\tconst endLine = limit !== undefined ? startLine + limit - 1 : \"\";\n\t\t\t\tpathDisplay += theme.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n\t\t\t}\n\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(\"read\")) + \" \" + pathDisplay;\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput();\n\t\t\t\tconst lines = output.split(\"\\n\");\n\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", replaceTabs(line))).join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[First line exceeds ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${truncation.maxLines ?? DEFAULT_MAX_LINES} line limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"write\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\tconst fileContent = this.args?.content || \"\";\n\t\t\tconst lines = fileContent ? fileContent.split(\"\\n\") : [];\n\t\t\tconst totalLines = lines.length;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"write\")) +\n\t\t\t\t\" \" +\n\t\t\t\t(path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\"));\n\t\t\tif (totalLines > 10) {\n\t\t\t\ttext += ` (${totalLines} lines)`;\n\t\t\t}\n\n\t\t\t// Show first 10 lines of content if available\n\t\t\tif (fileContent) {\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", replaceTabs(line))).join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"edit\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"edit\")) +\n\t\t\t\t\" \" +\n\t\t\t\t(path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\"));\n\n\t\t\tif (this.result) {\n\t\t\t\t// Show error message if it's an error\n\t\t\t\tif (this.result.isError) {\n\t\t\t\t\tconst errorText = this.getTextOutput();\n\t\t\t\t\tif (errorText) {\n\t\t\t\t\t\ttext += \"\\n\\n\" + theme.fg(\"error\", errorText);\n\t\t\t\t\t}\n\t\t\t\t} else if (this.result.details?.diff) {\n\t\t\t\t\t// Show diff if available\n\t\t\t\t\tconst diffLines = this.result.details.diff.split(\"\\n\");\n\t\t\t\t\tconst coloredLines = diffLines.map((line: string) => {\n\t\t\t\t\t\tif (line.startsWith(\"+\")) {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffAdded\", line);\n\t\t\t\t\t\t} else if (line.startsWith(\"-\")) {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffRemoved\", line);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffContext\", line);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\ttext += \"\\n\\n\" + coloredLines.join(\"\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"ls\") {\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(\"ls\")) + \" \" + theme.fg(\"accent\", path);\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst entryLimit = this.result.details?.entryLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (entryLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (entryLimit) {\n\t\t\t\t\t\twarnings.push(`${entryLimit} entries limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"find\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"find\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", pattern) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst resultLimit = this.result.details?.resultLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (resultLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (resultLimit) {\n\t\t\t\t\t\twarnings.push(`${resultLimit} results limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"grep\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst glob = this.args?.glob;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", `/${pattern}/`) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (glob) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (${glob})`);\n\t\t\t}\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 15;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst matchLimit = this.result.details?.matchLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tconst linesTruncated = this.result.details?.linesTruncated;\n\t\t\t\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (matchLimit) {\n\t\t\t\t\t\twarnings.push(`${matchLimit} matches limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\twarnings.push(\"some lines truncated\");\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Generic tool\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(this.toolName));\n\n\t\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\t\ttext += \"\\n\\n\" + content;\n\t\t\tconst output = this.getTextOutput();\n\t\t\tif (output) {\n\t\t\t\ttext += \"\\n\" + output;\n\t\t\t}\n\t\t}\n\n\t\treturn text;\n\t}\n}\n"]}
1
+ {"version":3,"file":"tool-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"AACA,OAAO,EACN,SAAS,EAOT,MAAM,sBAAsB,CAAC;AAuB9B,MAAM,WAAW,oBAAoB;IACpC,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,WAAW,CAAO;IAC1B,OAAO,CAAC,eAAe,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,MAAM,CAAC,CAIb;IAEF,YAAY,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,GAAE,oBAAyB,EAS1E;IAED,UAAU,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CAG1B;IAED,YAAY,CACX,MAAM,EAAE;QACP,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAClF,OAAO,CAAC,EAAE,GAAG,CAAC;QACd,OAAO,EAAE,OAAO,CAAC;KACjB,EACD,SAAS,UAAQ,GACf,IAAI,CAIN;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAGnC;IAED,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAGjC;IAED,OAAO,CAAC,aAAa;IAoCrB,OAAO,CAAC,aAAa;IA8BrB,OAAO,CAAC,mBAAmB;CAwS3B","sourcesContent":["import * as os from \"node:os\";\nimport {\n\tContainer,\n\tgetCapabilities,\n\tgetImageDimensions,\n\tImage,\n\timageFallback,\n\tSpacer,\n\tText,\n} from \"@mariozechner/pi-tui\";\nimport stripAnsi from \"strip-ansi\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from \"../../../core/tools/truncate.js\";\nimport { theme } from \"../theme/theme.js\";\n\n/**\n * Convert absolute path to tilde notation if it's in home directory\n */\nfunction shortenPath(path: string): string {\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn \"~\" + path.slice(home.length);\n\t}\n\treturn path;\n}\n\n/**\n * Replace tabs with spaces for consistent rendering\n */\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean; // default: true (only used if terminal supports images)\n}\n\n/**\n * Component that renders a tool call with its result (updateable)\n */\nexport class ToolExecutionComponent extends Container {\n\tprivate contentText: Text;\n\tprivate imageComponents: Image[] = [];\n\tprivate toolName: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate showImages: boolean;\n\tprivate isPartial = true;\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\n\tconstructor(toolName: string, args: any, options: ToolExecutionOptions = {}) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.args = args;\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.contentText = new Text(\"\", 1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\t\tthis.addChild(this.contentText);\n\t\tthis.updateDisplay();\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tconst bgFn = this.isPartial\n\t\t\t? (text: string) => theme.bg(\"toolPendingBg\", text)\n\t\t\t: this.result?.isError\n\t\t\t\t? (text: string) => theme.bg(\"toolErrorBg\", text)\n\t\t\t\t: (text: string) => theme.bg(\"toolSuccessBg\", text);\n\n\t\tthis.contentText.setCustomBgFn(bgFn);\n\t\tthis.contentText.setText(this.formatToolExecution());\n\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\t\t\tconst caps = getCapabilities();\n\n\t\t\tfor (const img of imageBlocks) {\n\t\t\t\t// Show inline image only if terminal supports it AND user setting allows it\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\tthis.addChild(new Spacer(1));\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timg.data,\n\t\t\t\t\t\timg.mimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: 60 },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getTextOutput(): string {\n\t\tif (!this.result) return \"\";\n\n\t\tconst textBlocks = this.result.content?.filter((c: any) => c.type === \"text\") || [];\n\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\n\t\tlet output = textBlocks\n\t\t\t.map((c: any) => {\n\t\t\t\tlet text = stripAnsi(c.text || \"\").replace(/\\r/g, \"\");\n\t\t\t\ttext = text.replace(/\\x1b./g, \"\");\n\t\t\t\ttext = text.replace(/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f-\\x9f]/g, \"\");\n\t\t\t\treturn text;\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\n\t\tconst caps = getCapabilities();\n\t\t// Show text fallback if terminal doesn't support images OR if user disabled inline images\n\t\tif (imageBlocks.length > 0 && (!caps.images || !this.showImages)) {\n\t\t\tconst imageIndicators = imageBlocks\n\t\t\t\t.map((img: any) => {\n\t\t\t\t\tconst dims = img.data ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\t\treturn imageFallback(img.mimeType, dims);\n\t\t\t\t})\n\t\t\t\t.join(\"\\n\");\n\t\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t\t}\n\n\t\treturn output;\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tlet text = \"\";\n\n\t\t// Format based on tool type\n\t\tif (this.toolName === \"bash\") {\n\t\t\tconst command = this.args?.command || \"\";\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(`$ ${command || theme.fg(\"toolOutput\", \"...\")}`));\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 5;\n\t\t\t\t\tconst skipped = Math.max(0, lines.length - maxLines);\n\t\t\t\t\tconst displayLines = lines.slice(-maxLines);\n\n\t\t\t\t\tif (skipped > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n\\n... (${skipped} earlier lines)`);\n\t\t\t\t\t}\n\t\t\t\t\ttext +=\n\t\t\t\t\t\t(skipped > 0 ? \"\\n\" : \"\\n\\n\") +\n\t\t\t\t\t\tdisplayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tconst fullOutputPath = this.result.details?.fullOutputPath;\n\t\t\t\tif (truncation?.truncated || fullOutputPath) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (fullOutputPath) {\n\t\t\t\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\twarnings.push(\n\t\t\t\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[${warnings.join(\". \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"read\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\tconst offset = this.args?.offset;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\t// Build path display with offset/limit suffix (in warning color if offset/limit used)\n\t\t\tlet pathDisplay = path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\t\t\tif (offset !== undefined || limit !== undefined) {\n\t\t\t\tconst startLine = offset ?? 1;\n\t\t\t\tconst endLine = limit !== undefined ? startLine + limit - 1 : \"\";\n\t\t\t\tpathDisplay += theme.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n\t\t\t}\n\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(\"read\")) + \" \" + pathDisplay;\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput();\n\t\t\t\tconst lines = output.split(\"\\n\");\n\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", replaceTabs(line))).join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[First line exceeds ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${truncation.maxLines ?? DEFAULT_MAX_LINES} line limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"write\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\tconst fileContent = this.args?.content || \"\";\n\t\t\tconst lines = fileContent ? fileContent.split(\"\\n\") : [];\n\t\t\tconst totalLines = lines.length;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"write\")) +\n\t\t\t\t\" \" +\n\t\t\t\t(path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\"));\n\t\t\tif (totalLines > 10) {\n\t\t\t\ttext += ` (${totalLines} lines)`;\n\t\t\t}\n\n\t\t\t// Show first 10 lines of content if available\n\t\t\tif (fileContent) {\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", replaceTabs(line))).join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"edit\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"edit\")) +\n\t\t\t\t\" \" +\n\t\t\t\t(path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\"));\n\n\t\t\tif (this.result) {\n\t\t\t\t// Show error message if it's an error\n\t\t\t\tif (this.result.isError) {\n\t\t\t\t\tconst errorText = this.getTextOutput();\n\t\t\t\t\tif (errorText) {\n\t\t\t\t\t\ttext += \"\\n\\n\" + theme.fg(\"error\", errorText);\n\t\t\t\t\t}\n\t\t\t\t} else if (this.result.details?.diff) {\n\t\t\t\t\t// Show diff if available\n\t\t\t\t\tconst diffLines = this.result.details.diff.split(\"\\n\");\n\t\t\t\t\tconst coloredLines = diffLines.map((line: string) => {\n\t\t\t\t\t\tif (line.startsWith(\"+\")) {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffAdded\", line);\n\t\t\t\t\t\t} else if (line.startsWith(\"-\")) {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffRemoved\", line);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffContext\", line);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\ttext += \"\\n\\n\" + coloredLines.join(\"\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"ls\") {\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(\"ls\")) + \" \" + theme.fg(\"accent\", path);\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst entryLimit = this.result.details?.entryLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (entryLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (entryLimit) {\n\t\t\t\t\t\twarnings.push(`${entryLimit} entries limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"find\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"find\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", pattern) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst resultLimit = this.result.details?.resultLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (resultLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (resultLimit) {\n\t\t\t\t\t\twarnings.push(`${resultLimit} results limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"grep\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst glob = this.args?.glob;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", `/${pattern}/`) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (glob) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (${glob})`);\n\t\t\t}\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 15;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst matchLimit = this.result.details?.matchLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tconst linesTruncated = this.result.details?.linesTruncated;\n\t\t\t\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (matchLimit) {\n\t\t\t\t\t\twarnings.push(`${matchLimit} matches limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\twarnings.push(\"some lines truncated\");\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Generic tool\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(this.toolName));\n\n\t\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\t\ttext += \"\\n\\n\" + content;\n\t\t\tconst output = this.getTextOutput();\n\t\t\tif (output) {\n\t\t\t\ttext += \"\\n\" + output;\n\t\t\t}\n\t\t}\n\n\t\treturn text;\n\t}\n}\n"]}
@@ -29,7 +29,7 @@ export class ToolExecutionComponent extends Container {
29
29
  args;
30
30
  expanded = false;
31
31
  showImages;
32
- isPartial = false;
32
+ isPartial = true;
33
33
  result;
34
34
  constructor(toolName, args, options = {}) {
35
35
  super();
@@ -1 +1 @@
1
- {"version":3,"file":"tool-execution.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport {\n\tContainer,\n\tgetCapabilities,\n\tgetImageDimensions,\n\tImage,\n\timageFallback,\n\tSpacer,\n\tText,\n} from \"@mariozechner/pi-tui\";\nimport stripAnsi from \"strip-ansi\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from \"../../../core/tools/truncate.js\";\nimport { theme } from \"../theme/theme.js\";\n\n/**\n * Convert absolute path to tilde notation if it's in home directory\n */\nfunction shortenPath(path: string): string {\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn \"~\" + path.slice(home.length);\n\t}\n\treturn path;\n}\n\n/**\n * Replace tabs with spaces for consistent rendering\n */\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean; // default: true (only used if terminal supports images)\n}\n\n/**\n * Component that renders a tool call with its result (updateable)\n */\nexport class ToolExecutionComponent extends Container {\n\tprivate contentText: Text;\n\tprivate imageComponents: Image[] = [];\n\tprivate toolName: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate showImages: boolean;\n\tprivate isPartial = false;\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\n\tconstructor(toolName: string, args: any, options: ToolExecutionOptions = {}) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.args = args;\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.contentText = new Text(\"\", 1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\t\tthis.addChild(this.contentText);\n\t\tthis.updateDisplay();\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tconst bgFn = this.isPartial\n\t\t\t? (text: string) => theme.bg(\"toolPendingBg\", text)\n\t\t\t: this.result?.isError\n\t\t\t\t? (text: string) => theme.bg(\"toolErrorBg\", text)\n\t\t\t\t: (text: string) => theme.bg(\"toolSuccessBg\", text);\n\n\t\tthis.contentText.setCustomBgFn(bgFn);\n\t\tthis.contentText.setText(this.formatToolExecution());\n\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\t\t\tconst caps = getCapabilities();\n\n\t\t\tfor (const img of imageBlocks) {\n\t\t\t\t// Show inline image only if terminal supports it AND user setting allows it\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\tthis.addChild(new Spacer(1));\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timg.data,\n\t\t\t\t\t\timg.mimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: 60 },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getTextOutput(): string {\n\t\tif (!this.result) return \"\";\n\n\t\tconst textBlocks = this.result.content?.filter((c: any) => c.type === \"text\") || [];\n\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\n\t\tlet output = textBlocks\n\t\t\t.map((c: any) => {\n\t\t\t\tlet text = stripAnsi(c.text || \"\").replace(/\\r/g, \"\");\n\t\t\t\ttext = text.replace(/\\x1b./g, \"\");\n\t\t\t\ttext = text.replace(/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f-\\x9f]/g, \"\");\n\t\t\t\treturn text;\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\n\t\tconst caps = getCapabilities();\n\t\t// Show text fallback if terminal doesn't support images OR if user disabled inline images\n\t\tif (imageBlocks.length > 0 && (!caps.images || !this.showImages)) {\n\t\t\tconst imageIndicators = imageBlocks\n\t\t\t\t.map((img: any) => {\n\t\t\t\t\tconst dims = img.data ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\t\treturn imageFallback(img.mimeType, dims);\n\t\t\t\t})\n\t\t\t\t.join(\"\\n\");\n\t\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t\t}\n\n\t\treturn output;\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tlet text = \"\";\n\n\t\t// Format based on tool type\n\t\tif (this.toolName === \"bash\") {\n\t\t\tconst command = this.args?.command || \"\";\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(`$ ${command || theme.fg(\"toolOutput\", \"...\")}`));\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 5;\n\t\t\t\t\tconst skipped = Math.max(0, lines.length - maxLines);\n\t\t\t\t\tconst displayLines = lines.slice(-maxLines);\n\n\t\t\t\t\tif (skipped > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n\\n... (${skipped} earlier lines)`);\n\t\t\t\t\t}\n\t\t\t\t\ttext +=\n\t\t\t\t\t\t(skipped > 0 ? \"\\n\" : \"\\n\\n\") +\n\t\t\t\t\t\tdisplayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tconst fullOutputPath = this.result.details?.fullOutputPath;\n\t\t\t\tif (truncation?.truncated || fullOutputPath) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (fullOutputPath) {\n\t\t\t\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\twarnings.push(\n\t\t\t\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[${warnings.join(\". \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"read\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\tconst offset = this.args?.offset;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\t// Build path display with offset/limit suffix (in warning color if offset/limit used)\n\t\t\tlet pathDisplay = path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\t\t\tif (offset !== undefined || limit !== undefined) {\n\t\t\t\tconst startLine = offset ?? 1;\n\t\t\t\tconst endLine = limit !== undefined ? startLine + limit - 1 : \"\";\n\t\t\t\tpathDisplay += theme.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n\t\t\t}\n\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(\"read\")) + \" \" + pathDisplay;\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput();\n\t\t\t\tconst lines = output.split(\"\\n\");\n\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", replaceTabs(line))).join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[First line exceeds ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${truncation.maxLines ?? DEFAULT_MAX_LINES} line limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"write\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\tconst fileContent = this.args?.content || \"\";\n\t\t\tconst lines = fileContent ? fileContent.split(\"\\n\") : [];\n\t\t\tconst totalLines = lines.length;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"write\")) +\n\t\t\t\t\" \" +\n\t\t\t\t(path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\"));\n\t\t\tif (totalLines > 10) {\n\t\t\t\ttext += ` (${totalLines} lines)`;\n\t\t\t}\n\n\t\t\t// Show first 10 lines of content if available\n\t\t\tif (fileContent) {\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", replaceTabs(line))).join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"edit\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"edit\")) +\n\t\t\t\t\" \" +\n\t\t\t\t(path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\"));\n\n\t\t\tif (this.result) {\n\t\t\t\t// Show error message if it's an error\n\t\t\t\tif (this.result.isError) {\n\t\t\t\t\tconst errorText = this.getTextOutput();\n\t\t\t\t\tif (errorText) {\n\t\t\t\t\t\ttext += \"\\n\\n\" + theme.fg(\"error\", errorText);\n\t\t\t\t\t}\n\t\t\t\t} else if (this.result.details?.diff) {\n\t\t\t\t\t// Show diff if available\n\t\t\t\t\tconst diffLines = this.result.details.diff.split(\"\\n\");\n\t\t\t\t\tconst coloredLines = diffLines.map((line: string) => {\n\t\t\t\t\t\tif (line.startsWith(\"+\")) {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffAdded\", line);\n\t\t\t\t\t\t} else if (line.startsWith(\"-\")) {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffRemoved\", line);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffContext\", line);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\ttext += \"\\n\\n\" + coloredLines.join(\"\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"ls\") {\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(\"ls\")) + \" \" + theme.fg(\"accent\", path);\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst entryLimit = this.result.details?.entryLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (entryLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (entryLimit) {\n\t\t\t\t\t\twarnings.push(`${entryLimit} entries limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"find\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"find\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", pattern) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst resultLimit = this.result.details?.resultLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (resultLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (resultLimit) {\n\t\t\t\t\t\twarnings.push(`${resultLimit} results limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"grep\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst glob = this.args?.glob;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", `/${pattern}/`) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (glob) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (${glob})`);\n\t\t\t}\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 15;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst matchLimit = this.result.details?.matchLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tconst linesTruncated = this.result.details?.linesTruncated;\n\t\t\t\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (matchLimit) {\n\t\t\t\t\t\twarnings.push(`${matchLimit} matches limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\twarnings.push(\"some lines truncated\");\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Generic tool\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(this.toolName));\n\n\t\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\t\ttext += \"\\n\\n\" + content;\n\t\t\tconst output = this.getTextOutput();\n\t\t\tif (output) {\n\t\t\t\ttext += \"\\n\" + output;\n\t\t\t}\n\t\t}\n\n\t\treturn text;\n\t}\n}\n"]}
1
+ {"version":3,"file":"tool-execution.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport {\n\tContainer,\n\tgetCapabilities,\n\tgetImageDimensions,\n\tImage,\n\timageFallback,\n\tSpacer,\n\tText,\n} from \"@mariozechner/pi-tui\";\nimport stripAnsi from \"strip-ansi\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from \"../../../core/tools/truncate.js\";\nimport { theme } from \"../theme/theme.js\";\n\n/**\n * Convert absolute path to tilde notation if it's in home directory\n */\nfunction shortenPath(path: string): string {\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn \"~\" + path.slice(home.length);\n\t}\n\treturn path;\n}\n\n/**\n * Replace tabs with spaces for consistent rendering\n */\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean; // default: true (only used if terminal supports images)\n}\n\n/**\n * Component that renders a tool call with its result (updateable)\n */\nexport class ToolExecutionComponent extends Container {\n\tprivate contentText: Text;\n\tprivate imageComponents: Image[] = [];\n\tprivate toolName: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate showImages: boolean;\n\tprivate isPartial = true;\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\n\tconstructor(toolName: string, args: any, options: ToolExecutionOptions = {}) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.args = args;\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.contentText = new Text(\"\", 1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\t\tthis.addChild(this.contentText);\n\t\tthis.updateDisplay();\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tconst bgFn = this.isPartial\n\t\t\t? (text: string) => theme.bg(\"toolPendingBg\", text)\n\t\t\t: this.result?.isError\n\t\t\t\t? (text: string) => theme.bg(\"toolErrorBg\", text)\n\t\t\t\t: (text: string) => theme.bg(\"toolSuccessBg\", text);\n\n\t\tthis.contentText.setCustomBgFn(bgFn);\n\t\tthis.contentText.setText(this.formatToolExecution());\n\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\t\t\tconst caps = getCapabilities();\n\n\t\t\tfor (const img of imageBlocks) {\n\t\t\t\t// Show inline image only if terminal supports it AND user setting allows it\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\tthis.addChild(new Spacer(1));\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timg.data,\n\t\t\t\t\t\timg.mimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: 60 },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getTextOutput(): string {\n\t\tif (!this.result) return \"\";\n\n\t\tconst textBlocks = this.result.content?.filter((c: any) => c.type === \"text\") || [];\n\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\n\t\tlet output = textBlocks\n\t\t\t.map((c: any) => {\n\t\t\t\tlet text = stripAnsi(c.text || \"\").replace(/\\r/g, \"\");\n\t\t\t\ttext = text.replace(/\\x1b./g, \"\");\n\t\t\t\ttext = text.replace(/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f-\\x9f]/g, \"\");\n\t\t\t\treturn text;\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\n\t\tconst caps = getCapabilities();\n\t\t// Show text fallback if terminal doesn't support images OR if user disabled inline images\n\t\tif (imageBlocks.length > 0 && (!caps.images || !this.showImages)) {\n\t\t\tconst imageIndicators = imageBlocks\n\t\t\t\t.map((img: any) => {\n\t\t\t\t\tconst dims = img.data ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\t\treturn imageFallback(img.mimeType, dims);\n\t\t\t\t})\n\t\t\t\t.join(\"\\n\");\n\t\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t\t}\n\n\t\treturn output;\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tlet text = \"\";\n\n\t\t// Format based on tool type\n\t\tif (this.toolName === \"bash\") {\n\t\t\tconst command = this.args?.command || \"\";\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(`$ ${command || theme.fg(\"toolOutput\", \"...\")}`));\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 5;\n\t\t\t\t\tconst skipped = Math.max(0, lines.length - maxLines);\n\t\t\t\t\tconst displayLines = lines.slice(-maxLines);\n\n\t\t\t\t\tif (skipped > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n\\n... (${skipped} earlier lines)`);\n\t\t\t\t\t}\n\t\t\t\t\ttext +=\n\t\t\t\t\t\t(skipped > 0 ? \"\\n\" : \"\\n\\n\") +\n\t\t\t\t\t\tdisplayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tconst fullOutputPath = this.result.details?.fullOutputPath;\n\t\t\t\tif (truncation?.truncated || fullOutputPath) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (fullOutputPath) {\n\t\t\t\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\twarnings.push(\n\t\t\t\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[${warnings.join(\". \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"read\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\tconst offset = this.args?.offset;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\t// Build path display with offset/limit suffix (in warning color if offset/limit used)\n\t\t\tlet pathDisplay = path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\t\t\tif (offset !== undefined || limit !== undefined) {\n\t\t\t\tconst startLine = offset ?? 1;\n\t\t\t\tconst endLine = limit !== undefined ? startLine + limit - 1 : \"\";\n\t\t\t\tpathDisplay += theme.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n\t\t\t}\n\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(\"read\")) + \" \" + pathDisplay;\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput();\n\t\t\t\tconst lines = output.split(\"\\n\");\n\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", replaceTabs(line))).join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[First line exceeds ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${truncation.maxLines ?? DEFAULT_MAX_LINES} line limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"write\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\tconst fileContent = this.args?.content || \"\";\n\t\t\tconst lines = fileContent ? fileContent.split(\"\\n\") : [];\n\t\t\tconst totalLines = lines.length;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"write\")) +\n\t\t\t\t\" \" +\n\t\t\t\t(path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\"));\n\t\t\tif (totalLines > 10) {\n\t\t\t\ttext += ` (${totalLines} lines)`;\n\t\t\t}\n\n\t\t\t// Show first 10 lines of content if available\n\t\t\tif (fileContent) {\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", replaceTabs(line))).join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"edit\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"edit\")) +\n\t\t\t\t\" \" +\n\t\t\t\t(path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\"));\n\n\t\t\tif (this.result) {\n\t\t\t\t// Show error message if it's an error\n\t\t\t\tif (this.result.isError) {\n\t\t\t\t\tconst errorText = this.getTextOutput();\n\t\t\t\t\tif (errorText) {\n\t\t\t\t\t\ttext += \"\\n\\n\" + theme.fg(\"error\", errorText);\n\t\t\t\t\t}\n\t\t\t\t} else if (this.result.details?.diff) {\n\t\t\t\t\t// Show diff if available\n\t\t\t\t\tconst diffLines = this.result.details.diff.split(\"\\n\");\n\t\t\t\t\tconst coloredLines = diffLines.map((line: string) => {\n\t\t\t\t\t\tif (line.startsWith(\"+\")) {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffAdded\", line);\n\t\t\t\t\t\t} else if (line.startsWith(\"-\")) {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffRemoved\", line);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn theme.fg(\"toolDiffContext\", line);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\ttext += \"\\n\\n\" + coloredLines.join(\"\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"ls\") {\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(\"ls\")) + \" \" + theme.fg(\"accent\", path);\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst entryLimit = this.result.details?.entryLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (entryLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (entryLimit) {\n\t\t\t\t\t\twarnings.push(`${entryLimit} entries limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"find\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"find\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", pattern) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst resultLimit = this.result.details?.resultLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (resultLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (resultLimit) {\n\t\t\t\t\t\twarnings.push(`${resultLimit} results limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"grep\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst glob = this.args?.glob;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", `/${pattern}/`) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (glob) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (${glob})`);\n\t\t\t}\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 15;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += \"\\n\\n\" + displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\");\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Show truncation warning at the bottom (outside collapsed area)\n\t\t\t\tconst matchLimit = this.result.details?.matchLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tconst linesTruncated = this.result.details?.linesTruncated;\n\t\t\t\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (matchLimit) {\n\t\t\t\t\t\twarnings.push(`${matchLimit} matches limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\twarnings.push(\"some lines truncated\");\n\t\t\t\t\t}\n\t\t\t\t\ttext += \"\\n\" + theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Generic tool\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(this.toolName));\n\n\t\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\t\ttext += \"\\n\\n\" + content;\n\t\t\tconst output = this.getTextOutput();\n\t\t\tif (output) {\n\t\t\t\ttext += \"\\n\" + output;\n\t\t\t}\n\t\t}\n\n\t\treturn text;\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mariozechner/pi-coding-agent",
3
- "version": "0.22.3",
3
+ "version": "0.22.4",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -39,9 +39,9 @@
39
39
  "prepublishOnly": "npm run clean && npm run build"
40
40
  },
41
41
  "dependencies": {
42
- "@mariozechner/pi-agent-core": "^0.22.3",
43
- "@mariozechner/pi-ai": "^0.22.3",
44
- "@mariozechner/pi-tui": "^0.22.3",
42
+ "@mariozechner/pi-agent-core": "^0.22.4",
43
+ "@mariozechner/pi-ai": "^0.22.4",
44
+ "@mariozechner/pi-tui": "^0.22.4",
45
45
  "chalk": "^5.5.0",
46
46
  "diff": "^8.0.2",
47
47
  "glob": "^11.0.3",