@caupulican/pi-adaptative 0.80.27 → 0.80.29
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 +15 -1
- package/dist/core/agent-session.d.ts +5 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +47 -5
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/context-gc.d.ts +62 -0
- package/dist/core/context-gc.d.ts.map +1 -0
- package/dist/core/context-gc.js +332 -0
- package/dist/core/context-gc.js.map +1 -0
- package/dist/core/extensions/builtin.d.ts +3 -1
- package/dist/core/extensions/builtin.d.ts.map +1 -1
- package/dist/core/extensions/builtin.js +41 -1
- package/dist/core/extensions/builtin.js.map +1 -1
- package/dist/core/settings-manager.d.ts +26 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +31 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/bash.d.ts +5 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +59 -21
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +33 -12
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +250 -104
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js +49 -9
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/docs/settings.md +30 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG3D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAY5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAKtF,OAAO,EAAoD,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAExG,QAAA,MAAM,UAAU;;;EAGd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B;;;;;;OAMG;IACH,IAAI,EAAE,CACL,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;QACR,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;KACxB,KACG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CA4D1F;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;AAO5E,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,aAAa,CAAC;CAC1B;AAKD,KAAK,eAAe,GAAG;IACtB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;CACrC,CAAC;AAuPF,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CAmNjF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG","sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess, readdir as fsReaddir, readFile as fsReadFile, stat as fsStat } from \"node:fs/promises\";\nimport { relative as relativePath, resolve as resolvePath } from \"node:path\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport { Container, Text, truncateToWidth } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { classifyGitCommand, executeFilteredGit } from \"./git-filter.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { getTextOutput, invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\n/**\n * Create bash operations using pi's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want pi's\n * standard local shell behavior while wrapping or rewriting commands.\n */\nexport function createLocalBashOperations(options?: { shellPath?: string }): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst { shell, args } = getShellConfig(options?.shellPath);\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute bash commands.`);\n\t\t\t}\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\n\t\t\tconst child = spawn(shell, [...args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeout !== undefined && timeout > 0) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeout * 1000);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn { exitCode };\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nfunction resolveSpawnContext(command: string, cwd: string, spawnHook?: BashSpawnHook): BashSpawnContext {\n\tconst baseContext: BashSpawnContext = { command, cwd, env: { ...getShellEnv() } };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\ntype BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction formatBashCall(args: { command?: string; timeout?: number } | undefined): string {\n\tconst command = str(args?.command);\n\tconst timeout = args?.timeout as number | undefined;\n\tconst timeoutSuffix = timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tconst commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\treturn theme.fg(\"toolTitle\", theme.bold(`$ ${commandDisplay}`)) + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tlet output = getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines;\n\t\t\t\t\t\tstate.cachedSkipped = preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint =\n\t\t\t\t\t\t\ttheme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) +\n\t\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\tif (startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nasync function tryOptimizeCommand(\n\tcommand: string,\n\tcwd: string,\n): Promise<{ optimized: boolean; output?: string; exitCode?: number }> {\n\tif (process.env.PI_TOOL_OPTIMIZER_DISABLED === \"1\") {\n\t\treturn { optimized: false };\n\t}\n\n\tconst trimmed = command.trim();\n\tif (!trimmed) {\n\t\treturn { optimized: false };\n\t}\n\n\t// Reject if there are shell operators or pipes/redirects\n\tconst shellOperators = [\"|\", \">\", \"<\", \"&\", \";\", \"\\n\", \"\\r\", \"$\", \"`\", \"(\", \")\", \"*\", \"?\", \"[\", \"]\"];\n\tif (shellOperators.some((op) => trimmed.includes(op))) {\n\t\treturn { optimized: false };\n\t}\n\n\t// Simple tokenizer split by whitespace\n\tconst args = trimmed.split(/\\s+/);\n\tif (args.length === 0) {\n\t\treturn { optimized: false };\n\t}\n\n\tconst cmd = args[0];\n\tconst unquote = (s: string) => {\n\t\tif ((s.startsWith('\"') && s.endsWith('\"')) || (s.startsWith(\"'\") && s.endsWith(\"'\"))) {\n\t\t\treturn s.slice(1, -1);\n\t\t}\n\t\treturn s;\n\t};\n\n\tconst resolveToCwd = (p: string, base: string) => {\n\t\tconst clean = unquote(p);\n\t\tif (clean.startsWith(\"/\")) return clean;\n\t\treturn resolvePath(base, clean);\n\t};\n\n\ttry {\n\t\tif (cmd === \"cat\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\treturn { optimized: true, output: content, exitCode: 0 };\n\t\t\t}\n\t\t} else if (cmd === \"head\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst lines = content.split(\"\\n\").slice(0, 10).join(\"\\n\");\n\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t} else if (args.length === 4 && args[1] === \"-n\" && !args[3].startsWith(\"-\")) {\n\t\t\t\tconst count = parseInt(args[2], 10);\n\t\t\t\tif (!Number.isNaN(count) && count >= 0) {\n\t\t\t\t\tconst filePath = resolveToCwd(args[3], cwd);\n\t\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\t\tconst lines = content.split(\"\\n\").slice(0, count).join(\"\\n\");\n\t\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (cmd === \"tail\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst allLines = content.split(\"\\n\");\n\t\t\t\tconst lines = allLines.slice(Math.max(0, allLines.length - 10)).join(\"\\n\");\n\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t} else if (args.length === 4 && args[1] === \"-n\" && !args[3].startsWith(\"-\")) {\n\t\t\t\tconst count = parseInt(args[2], 10);\n\t\t\t\tif (!Number.isNaN(count) && count >= 0) {\n\t\t\t\t\tconst filePath = resolveToCwd(args[3], cwd);\n\t\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\t\tconst allLines = content.split(\"\\n\");\n\t\t\t\t\tconst lines = allLines.slice(Math.max(0, allLines.length - count)).join(\"\\n\");\n\t\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (cmd === \"ls\") {\n\t\t\tif (args.length === 1 || (args.length === 2 && !args[1].startsWith(\"-\"))) {\n\t\t\t\tconst targetDir = args.length === 2 ? resolveToCwd(args[1], cwd) : cwd;\n\t\t\t\tconst entries = await fsReaddir(targetDir);\n\t\t\t\tentries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\t\t\t\tconst results: string[] = [];\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst entryStat = await fsStat(resolvePath(targetDir, entry));\n\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t} catch {}\n\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t}\n\t\t\t\treturn { optimized: true, output: results.join(\"\\n\"), exitCode: 0 };\n\t\t\t}\n\t\t} else if (cmd === \"grep\" || cmd === \"rg\") {\n\t\t\tif (args.length === 3 && !args[1].startsWith(\"-\") && !args[2].startsWith(\"-\")) {\n\t\t\t\tconst patternStr = unquote(args[1]);\n\t\t\t\tconst filePath = resolveToCwd(args[2], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst lines = content.split(\"\\n\");\n\t\t\t\tconst matches: string[] = [];\n\t\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\t\tif (lines[i].includes(patternStr)) {\n\t\t\t\t\t\tmatches.push(lines[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { optimized: true, output: matches.join(\"\\n\"), exitCode: matches.length > 0 ? 0 : 1 };\n\t\t\t}\n\t\t} else if (cmd === \"find\") {\n\t\t\tif (args.length === 1 || (args.length === 2 && !args[1].startsWith(\"-\"))) {\n\t\t\t\tconst searchPath = args.length === 2 ? resolveToCwd(args[1], cwd) : cwd;\n\t\t\t\tconst walk = async (dir: string): Promise<string[]> => {\n\t\t\t\t\tlet results: string[] = [];\n\t\t\t\t\tconst entries = await fsReaddir(dir);\n\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\tconst full = resolvePath(dir, entry);\n\t\t\t\t\t\tconst entryStat = await fsStat(full);\n\t\t\t\t\t\tif (entryStat.isDirectory()) {\n\t\t\t\t\t\t\tresults.push(full);\n\t\t\t\t\t\t\tresults = results.concat(await walk(full));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresults.push(full);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn results;\n\t\t\t\t};\n\t\t\t\tconst all = (await walk(searchPath)).map((p) => relativePath(searchPath, p).replace(/\\\\/g, \"/\"));\n\t\t\t\treturn { optimized: true, output: all.join(\"\\n\"), exitCode: 0 };\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn { optimized: false };\n\t}\n\n\treturn { optimized: false };\n}\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst spawnHook = options?.spawnHook;\n\tconst canOptimizeCommand = !options?.operations && !options?.shellPath && !commandPrefix && !spawnHook;\n\tconst canFilterCommand = canOptimizeCommand;\n\treturn {\n\t\tname: \"bash\",\n\t\tlabel: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\t\tparameters: bashSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ command, timeout }: { command: string; timeout?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\tonUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook);\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: \"pi-bash\" });\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: snapshot.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\treturn snapshot;\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tif (canFilterCommand) {\n\t\t\t\t\tconst classification = classifyGitCommand(command, spawnContext.env);\n\t\t\t\t\tif (classification.eligible && classification.subcommand) {\n\t\t\t\t\t\tconst res = await executeFilteredGit(\n\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\tclassification.subcommand,\n\t\t\t\t\t\t\tclassification.globalOptions || [],\n\t\t\t\t\t\t\tclassification.subcommandArgs || [],\n\t\t\t\t\t\t\t{ signal, timeout },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (res.exitCode !== -100) {\n\t\t\t\t\t\t\toutput.append(res.rawBytes ?? Buffer.from(res.rawOut, \"utf-8\"));\n\t\t\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\t\t\tif (res.exitCode !== 0) {\n\t\t\t\t\t\t\t\tconst { text: rawOutputText } = formatOutput(snapshot);\n\t\t\t\t\t\t\t\tthrow new Error(appendStatus(rawOutputText, `Command exited with code ${res.exitCode}`));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst details = snapshot.truncation.truncated\n\t\t\t\t\t\t\t\t? { truncation: snapshot.truncation, fullOutputPath: snapshot.fullOutputPath }\n\t\t\t\t\t\t\t\t: snapshot.fullOutputPath\n\t\t\t\t\t\t\t\t\t? { fullOutputPath: snapshot.fullOutputPath }\n\t\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\t\treturn { content: [{ type: \"text\", text: res.output }], details };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (canOptimizeCommand) {\n\t\t\t\t\tconst optResult = await tryOptimizeCommand(command, cwd);\n\t\t\t\t\tif (optResult.optimized) {\n\t\t\t\t\t\toutput.append(Buffer.from(optResult.output ?? \"\", \"utf-8\"));\n\t\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\t\t\tif (optResult.exitCode !== 0 && optResult.exitCode !== undefined) {\n\t\t\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${optResult.exitCode}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new Error(appendStatus(text, \"Command aborted\"));\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new Error(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`));\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${exitCode}`));\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBashCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\treturn wrapToolDefinition(createBashToolDefinition(cwd, options));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG3D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAY5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAKtF,OAAO,EAAoD,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAExG,QAAA,MAAM,UAAU;;;EAGd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;KACrB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B;;;;;;OAMG;IACH,IAAI,EAAE,CACL,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;QACR,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;KACxB,KACG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CA4D1F;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;AAO5E,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,aAAa,CAAC;CAC1B;AAMD,KAAK,eAAe,GAAG;IACtB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;CACrC,CAAC;AA0PF,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CAmPjF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG","sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess, readdir as fsReaddir, readFile as fsReadFile, stat as fsStat } from \"node:fs/promises\";\nimport { relative as relativePath, resolve as resolvePath } from \"node:path\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport { Container, Text, truncateToWidth } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { classifyGitCommand, executeFilteredGit } from \"./git-filter.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { getTextOutput, invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\tfullOutputError?: string;\n\tpreview?: {\n\t\tcontent: string;\n\t\tskippedLines: number;\n\t};\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\n/**\n * Create bash operations using pi's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want pi's\n * standard local shell behavior while wrapping or rewriting commands.\n */\nexport function createLocalBashOperations(options?: { shellPath?: string }): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst { shell, args } = getShellConfig(options?.shellPath);\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute bash commands.`);\n\t\t\t}\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\n\t\t\tconst child = spawn(shell, [...args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeout !== undefined && timeout > 0) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeout * 1000);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn { exitCode };\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nfunction resolveSpawnContext(command: string, cwd: string, spawnHook?: BashSpawnHook): BashSpawnContext {\n\tconst baseContext: BashSpawnContext = { command, cwd, env: { ...getShellEnv() } };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_PREVIEW_BYTES = 8 * 1024;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\ntype BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction formatBashCall(args: { command?: string; timeout?: number } | undefined): string {\n\tconst command = str(args?.command);\n\tconst timeout = args?.timeout as number | undefined;\n\tconst timeoutSuffix = timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tconst commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\treturn theme.fg(\"toolTitle\", theme.bold(`$ ${commandDisplay}`)) + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tconst renderPreview = !options.expanded ? result.details?.preview : undefined;\n\tlet output = (renderPreview ? renderPreview.content : getTextOutput(result as any, showImages)).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tconst fullOutputError = result.details?.fullOutputError;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tif (options.expanded) {\n\t\t\tconst styledOutput = output\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t\t.join(\"\\n\");\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(output, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines.map((line) => theme.fg(\"toolOutput\", line));\n\t\t\t\t\t\tstate.cachedSkipped = (result.details?.preview?.skippedLines ?? 0) + preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint =\n\t\t\t\t\t\t\ttheme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) +\n\t\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath || fullOutputError) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t} else if (fullOutputError) {\n\t\t\twarnings.push(`Full output unavailable: ${fullOutputError}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\tif (startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nasync function tryOptimizeCommand(\n\tcommand: string,\n\tcwd: string,\n): Promise<{ optimized: boolean; output?: string; exitCode?: number }> {\n\tif (process.env.PI_TOOL_OPTIMIZER_DISABLED === \"1\") {\n\t\treturn { optimized: false };\n\t}\n\n\tconst trimmed = command.trim();\n\tif (!trimmed) {\n\t\treturn { optimized: false };\n\t}\n\n\t// Reject if there are shell operators or pipes/redirects\n\tconst shellOperators = [\"|\", \">\", \"<\", \"&\", \";\", \"\\n\", \"\\r\", \"$\", \"`\", \"(\", \")\", \"*\", \"?\", \"[\", \"]\"];\n\tif (shellOperators.some((op) => trimmed.includes(op))) {\n\t\treturn { optimized: false };\n\t}\n\n\t// Simple tokenizer split by whitespace\n\tconst args = trimmed.split(/\\s+/);\n\tif (args.length === 0) {\n\t\treturn { optimized: false };\n\t}\n\n\tconst cmd = args[0];\n\tconst unquote = (s: string) => {\n\t\tif ((s.startsWith('\"') && s.endsWith('\"')) || (s.startsWith(\"'\") && s.endsWith(\"'\"))) {\n\t\t\treturn s.slice(1, -1);\n\t\t}\n\t\treturn s;\n\t};\n\n\tconst resolveToCwd = (p: string, base: string) => {\n\t\tconst clean = unquote(p);\n\t\tif (clean.startsWith(\"/\")) return clean;\n\t\treturn resolvePath(base, clean);\n\t};\n\n\ttry {\n\t\tif (cmd === \"cat\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\treturn { optimized: true, output: content, exitCode: 0 };\n\t\t\t}\n\t\t} else if (cmd === \"head\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst lines = content.split(\"\\n\").slice(0, 10).join(\"\\n\");\n\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t} else if (args.length === 4 && args[1] === \"-n\" && !args[3].startsWith(\"-\")) {\n\t\t\t\tconst count = parseInt(args[2], 10);\n\t\t\t\tif (!Number.isNaN(count) && count >= 0) {\n\t\t\t\t\tconst filePath = resolveToCwd(args[3], cwd);\n\t\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\t\tconst lines = content.split(\"\\n\").slice(0, count).join(\"\\n\");\n\t\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (cmd === \"tail\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst allLines = content.split(\"\\n\");\n\t\t\t\tconst lines = allLines.slice(Math.max(0, allLines.length - 10)).join(\"\\n\");\n\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t} else if (args.length === 4 && args[1] === \"-n\" && !args[3].startsWith(\"-\")) {\n\t\t\t\tconst count = parseInt(args[2], 10);\n\t\t\t\tif (!Number.isNaN(count) && count >= 0) {\n\t\t\t\t\tconst filePath = resolveToCwd(args[3], cwd);\n\t\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\t\tconst allLines = content.split(\"\\n\");\n\t\t\t\t\tconst lines = allLines.slice(Math.max(0, allLines.length - count)).join(\"\\n\");\n\t\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (cmd === \"ls\") {\n\t\t\tif (args.length === 1 || (args.length === 2 && !args[1].startsWith(\"-\"))) {\n\t\t\t\tconst targetDir = args.length === 2 ? resolveToCwd(args[1], cwd) : cwd;\n\t\t\t\tconst entries = await fsReaddir(targetDir);\n\t\t\t\tentries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\t\t\t\tconst results: string[] = [];\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst entryStat = await fsStat(resolvePath(targetDir, entry));\n\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t} catch {}\n\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t}\n\t\t\t\treturn { optimized: true, output: results.join(\"\\n\"), exitCode: 0 };\n\t\t\t}\n\t\t} else if (cmd === \"grep\" || cmd === \"rg\") {\n\t\t\tif (args.length === 3 && !args[1].startsWith(\"-\") && !args[2].startsWith(\"-\")) {\n\t\t\t\tconst patternStr = unquote(args[1]);\n\t\t\t\tconst filePath = resolveToCwd(args[2], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst lines = content.split(\"\\n\");\n\t\t\t\tconst matches: string[] = [];\n\t\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\t\tif (lines[i].includes(patternStr)) {\n\t\t\t\t\t\tmatches.push(lines[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { optimized: true, output: matches.join(\"\\n\"), exitCode: matches.length > 0 ? 0 : 1 };\n\t\t\t}\n\t\t} else if (cmd === \"find\") {\n\t\t\tif (args.length === 1 || (args.length === 2 && !args[1].startsWith(\"-\"))) {\n\t\t\t\tconst searchPath = args.length === 2 ? resolveToCwd(args[1], cwd) : cwd;\n\t\t\t\tconst walk = async (dir: string): Promise<string[]> => {\n\t\t\t\t\tlet results: string[] = [];\n\t\t\t\t\tconst entries = await fsReaddir(dir);\n\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\tconst full = resolvePath(dir, entry);\n\t\t\t\t\t\tconst entryStat = await fsStat(full);\n\t\t\t\t\t\tif (entryStat.isDirectory()) {\n\t\t\t\t\t\t\tresults.push(full);\n\t\t\t\t\t\t\tresults = results.concat(await walk(full));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresults.push(full);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn results;\n\t\t\t\t};\n\t\t\t\tconst all = (await walk(searchPath)).map((p) => relativePath(searchPath, p).replace(/\\\\/g, \"/\"));\n\t\t\t\treturn { optimized: true, output: all.join(\"\\n\"), exitCode: 0 };\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn { optimized: false };\n\t}\n\n\treturn { optimized: false };\n}\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst spawnHook = options?.spawnHook;\n\tconst canOptimizeCommand = !options?.operations && !options?.shellPath && !commandPrefix && !spawnHook;\n\tconst canFilterCommand = canOptimizeCommand;\n\treturn {\n\t\tname: \"bash\",\n\t\tlabel: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\t\tparameters: bashSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ command, timeout }: { command: string; timeout?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\tonUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook);\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: \"pi-bash\" });\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.previewSnapshot(BASH_PREVIEW_LINES, BASH_PREVIEW_BYTES, {\n\t\t\t\t\tpersistIfFullTruncated: true,\n\t\t\t\t});\n\t\t\t\tconst preview = {\n\t\t\t\t\tcontent: snapshot.content,\n\t\t\t\t\tskippedLines: Math.max(0, snapshot.truncation.totalLines - snapshot.truncation.outputLines),\n\t\t\t\t};\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: preview.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t\tfullOutputError: snapshot.fullOutputError,\n\t\t\t\t\t\tpreview,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\treturn output.snapshot({ persistIfTruncated: true });\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tconst preview = output.preview(BASH_PREVIEW_LINES, BASH_PREVIEW_BYTES);\n\t\t\t\tconst fullOutputNotice = snapshot.fullOutputPath\n\t\t\t\t\t? `Full output: ${snapshot.fullOutputPath}`\n\t\t\t\t\t: snapshot.fullOutputError\n\t\t\t\t\t\t? `Full output unavailable: ${snapshot.fullOutputError}`\n\t\t\t\t\t\t: \"Full output unavailable\";\n\t\t\t\tif (truncation.truncated || preview.skippedLines > 0) {\n\t\t\t\t\tdetails = { preview };\n\t\t\t\t}\n\t\t\t\tif (snapshot.fullOutputPath || snapshot.fullOutputError) {\n\t\t\t\t\tdetails = {\n\t\t\t\t\t\t...(details ?? {}),\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t\tfullOutputError: snapshot.fullOutputError,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = {\n\t\t\t\t\t\t...(details ?? {}),\n\t\t\t\t\t\ttruncation,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t\tfullOutputError: snapshot.fullOutputError,\n\t\t\t\t\t};\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). ${fullOutputNotice}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. ${fullOutputNotice}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). ${fullOutputNotice}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tif (canFilterCommand) {\n\t\t\t\t\tconst classification = classifyGitCommand(command, spawnContext.env);\n\t\t\t\t\tif (classification.eligible && classification.subcommand) {\n\t\t\t\t\t\tconst res = await executeFilteredGit(\n\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\tclassification.subcommand,\n\t\t\t\t\t\t\tclassification.globalOptions || [],\n\t\t\t\t\t\t\tclassification.subcommandArgs || [],\n\t\t\t\t\t\t\t{ signal, timeout },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (res.exitCode !== -100) {\n\t\t\t\t\t\t\toutput.append(res.rawBytes ?? Buffer.from(res.rawOut, \"utf-8\"));\n\t\t\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\t\t\tif (res.exitCode !== 0) {\n\t\t\t\t\t\t\t\tconst { text: rawOutputText } = formatOutput(snapshot);\n\t\t\t\t\t\t\t\tthrow new Error(appendStatus(rawOutputText, `Command exited with code ${res.exitCode}`));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst details = snapshot.truncation.truncated\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\ttruncation: snapshot.truncation,\n\t\t\t\t\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t\t\t\t\t\tfullOutputError: snapshot.fullOutputError,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: snapshot.fullOutputPath || snapshot.fullOutputError\n\t\t\t\t\t\t\t\t\t? { fullOutputPath: snapshot.fullOutputPath, fullOutputError: snapshot.fullOutputError }\n\t\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\t\treturn { content: [{ type: \"text\", text: res.output }], details };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (canOptimizeCommand) {\n\t\t\t\t\tconst optResult = await tryOptimizeCommand(command, cwd);\n\t\t\t\t\tif (optResult.optimized) {\n\t\t\t\t\t\toutput.append(Buffer.from(optResult.output ?? \"\", \"utf-8\"));\n\t\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\t\t\tif (optResult.exitCode !== 0 && optResult.exitCode !== undefined) {\n\t\t\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${optResult.exitCode}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new Error(appendStatus(text, \"Command aborted\"));\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new Error(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`));\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${exitCode}`));\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t\tawait output.closeTempFile();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBashCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\treturn wrapToolDefinition(createBashToolDefinition(cwd, options));\n}\n"]}
|
package/dist/core/tools/bash.js
CHANGED
|
@@ -98,6 +98,7 @@ function resolveSpawnContext(command, cwd, spawnHook) {
|
|
|
98
98
|
return spawnHook ? spawnHook(baseContext) : baseContext;
|
|
99
99
|
}
|
|
100
100
|
const BASH_PREVIEW_LINES = 5;
|
|
101
|
+
const BASH_PREVIEW_BYTES = 8 * 1024;
|
|
101
102
|
const BASH_UPDATE_THROTTLE_MS = 100;
|
|
102
103
|
class BashResultRenderComponent extends Container {
|
|
103
104
|
state = {
|
|
@@ -119,9 +120,11 @@ function formatBashCall(args) {
|
|
|
119
120
|
function rebuildBashResultRenderComponent(component, result, options, showImages, startedAt, endedAt) {
|
|
120
121
|
const state = component.state;
|
|
121
122
|
component.clear();
|
|
122
|
-
|
|
123
|
+
const renderPreview = !options.expanded ? result.details?.preview : undefined;
|
|
124
|
+
let output = (renderPreview ? renderPreview.content : getTextOutput(result, showImages)).trim();
|
|
123
125
|
const truncation = result.details?.truncation;
|
|
124
126
|
const fullOutputPath = result.details?.fullOutputPath;
|
|
127
|
+
const fullOutputError = result.details?.fullOutputError;
|
|
125
128
|
if (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith("]")) {
|
|
126
129
|
const footerStart = output.lastIndexOf("\n\n[");
|
|
127
130
|
if (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {
|
|
@@ -129,20 +132,20 @@ function rebuildBashResultRenderComponent(component, result, options, showImages
|
|
|
129
132
|
}
|
|
130
133
|
}
|
|
131
134
|
if (output) {
|
|
132
|
-
const styledOutput = output
|
|
133
|
-
.split("\n")
|
|
134
|
-
.map((line) => theme.fg("toolOutput", line))
|
|
135
|
-
.join("\n");
|
|
136
135
|
if (options.expanded) {
|
|
136
|
+
const styledOutput = output
|
|
137
|
+
.split("\n")
|
|
138
|
+
.map((line) => theme.fg("toolOutput", line))
|
|
139
|
+
.join("\n");
|
|
137
140
|
component.addChild(new Text(`\n${styledOutput}`, 0, 0));
|
|
138
141
|
}
|
|
139
142
|
else {
|
|
140
143
|
component.addChild({
|
|
141
144
|
render: (width) => {
|
|
142
145
|
if (state.cachedLines === undefined || state.cachedWidth !== width) {
|
|
143
|
-
const preview = truncateToVisualLines(
|
|
144
|
-
state.cachedLines = preview.visualLines;
|
|
145
|
-
state.cachedSkipped = preview.skippedCount;
|
|
146
|
+
const preview = truncateToVisualLines(output, BASH_PREVIEW_LINES, width);
|
|
147
|
+
state.cachedLines = preview.visualLines.map((line) => theme.fg("toolOutput", line));
|
|
148
|
+
state.cachedSkipped = (result.details?.preview?.skippedLines ?? 0) + preview.skippedCount;
|
|
146
149
|
state.cachedWidth = width;
|
|
147
150
|
}
|
|
148
151
|
if (state.cachedSkipped && state.cachedSkipped > 0) {
|
|
@@ -160,11 +163,14 @@ function rebuildBashResultRenderComponent(component, result, options, showImages
|
|
|
160
163
|
});
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
|
-
if (truncation?.truncated || fullOutputPath) {
|
|
166
|
+
if (truncation?.truncated || fullOutputPath || fullOutputError) {
|
|
164
167
|
const warnings = [];
|
|
165
168
|
if (fullOutputPath) {
|
|
166
169
|
warnings.push(`Full output: ${fullOutputPath}`);
|
|
167
170
|
}
|
|
171
|
+
else if (fullOutputError) {
|
|
172
|
+
warnings.push(`Full output unavailable: ${fullOutputError}`);
|
|
173
|
+
}
|
|
168
174
|
if (truncation?.truncated) {
|
|
169
175
|
if (truncation.truncatedBy === "lines") {
|
|
170
176
|
warnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);
|
|
@@ -343,12 +349,20 @@ export function createBashToolDefinition(cwd, options) {
|
|
|
343
349
|
return;
|
|
344
350
|
updateDirty = false;
|
|
345
351
|
lastUpdateAt = Date.now();
|
|
346
|
-
const snapshot = output.
|
|
352
|
+
const snapshot = output.previewSnapshot(BASH_PREVIEW_LINES, BASH_PREVIEW_BYTES, {
|
|
353
|
+
persistIfFullTruncated: true,
|
|
354
|
+
});
|
|
355
|
+
const preview = {
|
|
356
|
+
content: snapshot.content,
|
|
357
|
+
skippedLines: Math.max(0, snapshot.truncation.totalLines - snapshot.truncation.outputLines),
|
|
358
|
+
};
|
|
347
359
|
onUpdate({
|
|
348
|
-
content: [{ type: "text", text:
|
|
360
|
+
content: [{ type: "text", text: preview.content || "" }],
|
|
349
361
|
details: {
|
|
350
362
|
truncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,
|
|
351
363
|
fullOutputPath: snapshot.fullOutputPath,
|
|
364
|
+
fullOutputError: snapshot.fullOutputError,
|
|
365
|
+
preview,
|
|
352
366
|
},
|
|
353
367
|
});
|
|
354
368
|
};
|
|
@@ -384,27 +398,46 @@ export function createBashToolDefinition(cwd, options) {
|
|
|
384
398
|
output.finish();
|
|
385
399
|
clearUpdateTimer();
|
|
386
400
|
emitOutputUpdate();
|
|
387
|
-
|
|
388
|
-
await output.closeTempFile();
|
|
389
|
-
return snapshot;
|
|
401
|
+
return output.snapshot({ persistIfTruncated: true });
|
|
390
402
|
};
|
|
391
403
|
const formatOutput = (snapshot, emptyText = "(no output)") => {
|
|
392
404
|
const truncation = snapshot.truncation;
|
|
393
405
|
let text = snapshot.content || emptyText;
|
|
394
406
|
let details;
|
|
407
|
+
const preview = output.preview(BASH_PREVIEW_LINES, BASH_PREVIEW_BYTES);
|
|
408
|
+
const fullOutputNotice = snapshot.fullOutputPath
|
|
409
|
+
? `Full output: ${snapshot.fullOutputPath}`
|
|
410
|
+
: snapshot.fullOutputError
|
|
411
|
+
? `Full output unavailable: ${snapshot.fullOutputError}`
|
|
412
|
+
: "Full output unavailable";
|
|
413
|
+
if (truncation.truncated || preview.skippedLines > 0) {
|
|
414
|
+
details = { preview };
|
|
415
|
+
}
|
|
416
|
+
if (snapshot.fullOutputPath || snapshot.fullOutputError) {
|
|
417
|
+
details = {
|
|
418
|
+
...(details ?? {}),
|
|
419
|
+
fullOutputPath: snapshot.fullOutputPath,
|
|
420
|
+
fullOutputError: snapshot.fullOutputError,
|
|
421
|
+
};
|
|
422
|
+
}
|
|
395
423
|
if (truncation.truncated) {
|
|
396
|
-
details = {
|
|
424
|
+
details = {
|
|
425
|
+
...(details ?? {}),
|
|
426
|
+
truncation,
|
|
427
|
+
fullOutputPath: snapshot.fullOutputPath,
|
|
428
|
+
fullOutputError: snapshot.fullOutputError,
|
|
429
|
+
};
|
|
397
430
|
const startLine = truncation.totalLines - truncation.outputLines + 1;
|
|
398
431
|
const endLine = truncation.totalLines;
|
|
399
432
|
if (truncation.lastLinePartial) {
|
|
400
433
|
const lastLineSize = formatSize(output.getLastLineBytes());
|
|
401
|
-
text += `\n\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}).
|
|
434
|
+
text += `\n\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). ${fullOutputNotice}]`;
|
|
402
435
|
}
|
|
403
436
|
else if (truncation.truncatedBy === "lines") {
|
|
404
|
-
text += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}.
|
|
437
|
+
text += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. ${fullOutputNotice}]`;
|
|
405
438
|
}
|
|
406
439
|
else {
|
|
407
|
-
text += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit).
|
|
440
|
+
text += `\n\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). ${fullOutputNotice}]`;
|
|
408
441
|
}
|
|
409
442
|
}
|
|
410
443
|
return { text, details };
|
|
@@ -423,9 +456,13 @@ export function createBashToolDefinition(cwd, options) {
|
|
|
423
456
|
throw new Error(appendStatus(rawOutputText, `Command exited with code ${res.exitCode}`));
|
|
424
457
|
}
|
|
425
458
|
const details = snapshot.truncation.truncated
|
|
426
|
-
? {
|
|
427
|
-
|
|
428
|
-
|
|
459
|
+
? {
|
|
460
|
+
truncation: snapshot.truncation,
|
|
461
|
+
fullOutputPath: snapshot.fullOutputPath,
|
|
462
|
+
fullOutputError: snapshot.fullOutputError,
|
|
463
|
+
}
|
|
464
|
+
: snapshot.fullOutputPath || snapshot.fullOutputError
|
|
465
|
+
? { fullOutputPath: snapshot.fullOutputPath, fullOutputError: snapshot.fullOutputError }
|
|
429
466
|
: undefined;
|
|
430
467
|
return { content: [{ type: "text", text: res.output }], details };
|
|
431
468
|
}
|
|
@@ -474,6 +511,7 @@ export function createBashToolDefinition(cwd, options) {
|
|
|
474
511
|
}
|
|
475
512
|
finally {
|
|
476
513
|
clearUpdateTimer();
|
|
514
|
+
await output.closeTempFile();
|
|
477
515
|
}
|
|
478
516
|
},
|
|
479
517
|
renderCall(args, _theme, context) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess, readdir as fsReaddir, readFile as fsReadFile, stat as fsStat } from \"node:fs/promises\";\nimport { relative as relativePath, resolve as resolvePath } from \"node:path\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport { Container, Text, truncateToWidth } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { classifyGitCommand, executeFilteredGit } from \"./git-filter.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { getTextOutput, invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\n/**\n * Create bash operations using pi's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want pi's\n * standard local shell behavior while wrapping or rewriting commands.\n */\nexport function createLocalBashOperations(options?: { shellPath?: string }): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst { shell, args } = getShellConfig(options?.shellPath);\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute bash commands.`);\n\t\t\t}\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\n\t\t\tconst child = spawn(shell, [...args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeout !== undefined && timeout > 0) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeout * 1000);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn { exitCode };\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nfunction resolveSpawnContext(command: string, cwd: string, spawnHook?: BashSpawnHook): BashSpawnContext {\n\tconst baseContext: BashSpawnContext = { command, cwd, env: { ...getShellEnv() } };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\ntype BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction formatBashCall(args: { command?: string; timeout?: number } | undefined): string {\n\tconst command = str(args?.command);\n\tconst timeout = args?.timeout as number | undefined;\n\tconst timeoutSuffix = timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tconst commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\treturn theme.fg(\"toolTitle\", theme.bold(`$ ${commandDisplay}`)) + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tlet output = getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(styledOutput, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines;\n\t\t\t\t\t\tstate.cachedSkipped = preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint =\n\t\t\t\t\t\t\ttheme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) +\n\t\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\tif (startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nasync function tryOptimizeCommand(\n\tcommand: string,\n\tcwd: string,\n): Promise<{ optimized: boolean; output?: string; exitCode?: number }> {\n\tif (process.env.PI_TOOL_OPTIMIZER_DISABLED === \"1\") {\n\t\treturn { optimized: false };\n\t}\n\n\tconst trimmed = command.trim();\n\tif (!trimmed) {\n\t\treturn { optimized: false };\n\t}\n\n\t// Reject if there are shell operators or pipes/redirects\n\tconst shellOperators = [\"|\", \">\", \"<\", \"&\", \";\", \"\\n\", \"\\r\", \"$\", \"`\", \"(\", \")\", \"*\", \"?\", \"[\", \"]\"];\n\tif (shellOperators.some((op) => trimmed.includes(op))) {\n\t\treturn { optimized: false };\n\t}\n\n\t// Simple tokenizer split by whitespace\n\tconst args = trimmed.split(/\\s+/);\n\tif (args.length === 0) {\n\t\treturn { optimized: false };\n\t}\n\n\tconst cmd = args[0];\n\tconst unquote = (s: string) => {\n\t\tif ((s.startsWith('\"') && s.endsWith('\"')) || (s.startsWith(\"'\") && s.endsWith(\"'\"))) {\n\t\t\treturn s.slice(1, -1);\n\t\t}\n\t\treturn s;\n\t};\n\n\tconst resolveToCwd = (p: string, base: string) => {\n\t\tconst clean = unquote(p);\n\t\tif (clean.startsWith(\"/\")) return clean;\n\t\treturn resolvePath(base, clean);\n\t};\n\n\ttry {\n\t\tif (cmd === \"cat\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\treturn { optimized: true, output: content, exitCode: 0 };\n\t\t\t}\n\t\t} else if (cmd === \"head\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst lines = content.split(\"\\n\").slice(0, 10).join(\"\\n\");\n\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t} else if (args.length === 4 && args[1] === \"-n\" && !args[3].startsWith(\"-\")) {\n\t\t\t\tconst count = parseInt(args[2], 10);\n\t\t\t\tif (!Number.isNaN(count) && count >= 0) {\n\t\t\t\t\tconst filePath = resolveToCwd(args[3], cwd);\n\t\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\t\tconst lines = content.split(\"\\n\").slice(0, count).join(\"\\n\");\n\t\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (cmd === \"tail\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst allLines = content.split(\"\\n\");\n\t\t\t\tconst lines = allLines.slice(Math.max(0, allLines.length - 10)).join(\"\\n\");\n\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t} else if (args.length === 4 && args[1] === \"-n\" && !args[3].startsWith(\"-\")) {\n\t\t\t\tconst count = parseInt(args[2], 10);\n\t\t\t\tif (!Number.isNaN(count) && count >= 0) {\n\t\t\t\t\tconst filePath = resolveToCwd(args[3], cwd);\n\t\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\t\tconst allLines = content.split(\"\\n\");\n\t\t\t\t\tconst lines = allLines.slice(Math.max(0, allLines.length - count)).join(\"\\n\");\n\t\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (cmd === \"ls\") {\n\t\t\tif (args.length === 1 || (args.length === 2 && !args[1].startsWith(\"-\"))) {\n\t\t\t\tconst targetDir = args.length === 2 ? resolveToCwd(args[1], cwd) : cwd;\n\t\t\t\tconst entries = await fsReaddir(targetDir);\n\t\t\t\tentries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\t\t\t\tconst results: string[] = [];\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst entryStat = await fsStat(resolvePath(targetDir, entry));\n\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t} catch {}\n\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t}\n\t\t\t\treturn { optimized: true, output: results.join(\"\\n\"), exitCode: 0 };\n\t\t\t}\n\t\t} else if (cmd === \"grep\" || cmd === \"rg\") {\n\t\t\tif (args.length === 3 && !args[1].startsWith(\"-\") && !args[2].startsWith(\"-\")) {\n\t\t\t\tconst patternStr = unquote(args[1]);\n\t\t\t\tconst filePath = resolveToCwd(args[2], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst lines = content.split(\"\\n\");\n\t\t\t\tconst matches: string[] = [];\n\t\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\t\tif (lines[i].includes(patternStr)) {\n\t\t\t\t\t\tmatches.push(lines[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { optimized: true, output: matches.join(\"\\n\"), exitCode: matches.length > 0 ? 0 : 1 };\n\t\t\t}\n\t\t} else if (cmd === \"find\") {\n\t\t\tif (args.length === 1 || (args.length === 2 && !args[1].startsWith(\"-\"))) {\n\t\t\t\tconst searchPath = args.length === 2 ? resolveToCwd(args[1], cwd) : cwd;\n\t\t\t\tconst walk = async (dir: string): Promise<string[]> => {\n\t\t\t\t\tlet results: string[] = [];\n\t\t\t\t\tconst entries = await fsReaddir(dir);\n\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\tconst full = resolvePath(dir, entry);\n\t\t\t\t\t\tconst entryStat = await fsStat(full);\n\t\t\t\t\t\tif (entryStat.isDirectory()) {\n\t\t\t\t\t\t\tresults.push(full);\n\t\t\t\t\t\t\tresults = results.concat(await walk(full));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresults.push(full);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn results;\n\t\t\t\t};\n\t\t\t\tconst all = (await walk(searchPath)).map((p) => relativePath(searchPath, p).replace(/\\\\/g, \"/\"));\n\t\t\t\treturn { optimized: true, output: all.join(\"\\n\"), exitCode: 0 };\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn { optimized: false };\n\t}\n\n\treturn { optimized: false };\n}\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst spawnHook = options?.spawnHook;\n\tconst canOptimizeCommand = !options?.operations && !options?.shellPath && !commandPrefix && !spawnHook;\n\tconst canFilterCommand = canOptimizeCommand;\n\treturn {\n\t\tname: \"bash\",\n\t\tlabel: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\t\tparameters: bashSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ command, timeout }: { command: string; timeout?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\tonUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook);\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: \"pi-bash\" });\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: snapshot.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\tconst snapshot = output.snapshot({ persistIfTruncated: true });\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\treturn snapshot;\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tif (canFilterCommand) {\n\t\t\t\t\tconst classification = classifyGitCommand(command, spawnContext.env);\n\t\t\t\t\tif (classification.eligible && classification.subcommand) {\n\t\t\t\t\t\tconst res = await executeFilteredGit(\n\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\tclassification.subcommand,\n\t\t\t\t\t\t\tclassification.globalOptions || [],\n\t\t\t\t\t\t\tclassification.subcommandArgs || [],\n\t\t\t\t\t\t\t{ signal, timeout },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (res.exitCode !== -100) {\n\t\t\t\t\t\t\toutput.append(res.rawBytes ?? Buffer.from(res.rawOut, \"utf-8\"));\n\t\t\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\t\t\tif (res.exitCode !== 0) {\n\t\t\t\t\t\t\t\tconst { text: rawOutputText } = formatOutput(snapshot);\n\t\t\t\t\t\t\t\tthrow new Error(appendStatus(rawOutputText, `Command exited with code ${res.exitCode}`));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst details = snapshot.truncation.truncated\n\t\t\t\t\t\t\t\t? { truncation: snapshot.truncation, fullOutputPath: snapshot.fullOutputPath }\n\t\t\t\t\t\t\t\t: snapshot.fullOutputPath\n\t\t\t\t\t\t\t\t\t? { fullOutputPath: snapshot.fullOutputPath }\n\t\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\t\treturn { content: [{ type: \"text\", text: res.output }], details };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (canOptimizeCommand) {\n\t\t\t\t\tconst optResult = await tryOptimizeCommand(command, cwd);\n\t\t\t\t\tif (optResult.optimized) {\n\t\t\t\t\t\toutput.append(Buffer.from(optResult.output ?? \"\", \"utf-8\"));\n\t\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\t\t\tif (optResult.exitCode !== 0 && optResult.exitCode !== undefined) {\n\t\t\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${optResult.exitCode}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new Error(appendStatus(text, \"Command aborted\"));\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new Error(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`));\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${exitCode}`));\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBashCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\treturn wrapToolDefinition(createBashToolDefinition(cwd, options));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess, readdir as fsReaddir, readFile as fsReadFile, stat as fsStat } from \"node:fs/promises\";\nimport { relative as relativePath, resolve as resolvePath } from \"node:path\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport { Container, Text, truncateToWidth } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { truncateToVisualLines } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport { theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { classifyGitCommand, executeFilteredGit } from \"./git-filter.ts\";\nimport { OutputAccumulator } from \"./output-accumulator.ts\";\nimport { getTextOutput, invalidArgText, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult } from \"./truncate.ts\";\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\tfullOutputError?: string;\n\tpreview?: {\n\t\tcontent: string;\n\t\tskippedLines: number;\n\t};\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to exit code (null if killed)\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\n/**\n * Create bash operations using pi's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want pi's\n * standard local shell behavior while wrapping or rewriting commands.\n */\nexport function createLocalBashOperations(options?: { shellPath?: string }): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst { shell, args } = getShellConfig(options?.shellPath);\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute bash commands.`);\n\t\t\t}\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\n\t\t\tconst child = spawn(shell, [...args, command], {\n\t\t\t\tcwd,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeout !== undefined && timeout > 0) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeout * 1000);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\treturn { exitCode };\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nfunction resolveSpawnContext(command: string, cwd: string, spawnHook?: BashSpawnHook): BashSpawnContext {\n\tconst baseContext: BashSpawnContext = { command, cwd, env: { ...getShellEnv() } };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n}\n\nconst BASH_PREVIEW_LINES = 5;\nconst BASH_PREVIEW_BYTES = 8 * 1024;\nconst BASH_UPDATE_THROTTLE_MS = 100;\n\ntype BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\ntype BashResultRenderState = {\n\tcachedWidth: number | undefined;\n\tcachedLines: string[] | undefined;\n\tcachedSkipped: number | undefined;\n};\n\nclass BashResultRenderComponent extends Container {\n\tstate: BashResultRenderState = {\n\t\tcachedWidth: undefined,\n\t\tcachedLines: undefined,\n\t\tcachedSkipped: undefined,\n\t};\n}\n\nfunction formatDuration(ms: number): string {\n\treturn `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction formatBashCall(args: { command?: string; timeout?: number } | undefined): string {\n\tconst command = str(args?.command);\n\tconst timeout = args?.timeout as number | undefined;\n\tconst timeoutSuffix = timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n\tconst commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg(\"toolOutput\", \"...\");\n\treturn theme.fg(\"toolTitle\", theme.bold(`$ ${commandDisplay}`)) + timeoutSuffix;\n}\n\nfunction rebuildBashResultRenderComponent(\n\tcomponent: BashResultRenderComponent,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n): void {\n\tconst state = component.state;\n\tcomponent.clear();\n\n\tconst renderPreview = !options.expanded ? result.details?.preview : undefined;\n\tlet output = (renderPreview ? renderPreview.content : getTextOutput(result as any, showImages)).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tconst fullOutputError = result.details?.fullOutputError;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tif (options.expanded) {\n\t\t\tconst styledOutput = output\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t\t.join(\"\\n\");\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild({\n\t\t\t\trender: (width: number) => {\n\t\t\t\t\tif (state.cachedLines === undefined || state.cachedWidth !== width) {\n\t\t\t\t\t\tconst preview = truncateToVisualLines(output, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\tstate.cachedLines = preview.visualLines.map((line) => theme.fg(\"toolOutput\", line));\n\t\t\t\t\t\tstate.cachedSkipped = (result.details?.preview?.skippedLines ?? 0) + preview.skippedCount;\n\t\t\t\t\t\tstate.cachedWidth = width;\n\t\t\t\t\t}\n\t\t\t\t\tif (state.cachedSkipped && state.cachedSkipped > 0) {\n\t\t\t\t\t\tconst hint =\n\t\t\t\t\t\t\ttheme.fg(\"muted\", `... (${state.cachedSkipped} earlier lines,`) +\n\t\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t\t\t\t\treturn [\"\", truncateToWidth(hint, width, \"...\"), ...(state.cachedLines ?? [])];\n\t\t\t\t\t}\n\t\t\t\t\treturn [\"\", ...(state.cachedLines ?? [])];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => {\n\t\t\t\t\tstate.cachedWidth = undefined;\n\t\t\t\t\tstate.cachedLines = undefined;\n\t\t\t\t\tstate.cachedSkipped = undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath || fullOutputError) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t} else if (fullOutputError) {\n\t\t\twarnings.push(`Full output unavailable: ${fullOutputError}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\tif (startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\nasync function tryOptimizeCommand(\n\tcommand: string,\n\tcwd: string,\n): Promise<{ optimized: boolean; output?: string; exitCode?: number }> {\n\tif (process.env.PI_TOOL_OPTIMIZER_DISABLED === \"1\") {\n\t\treturn { optimized: false };\n\t}\n\n\tconst trimmed = command.trim();\n\tif (!trimmed) {\n\t\treturn { optimized: false };\n\t}\n\n\t// Reject if there are shell operators or pipes/redirects\n\tconst shellOperators = [\"|\", \">\", \"<\", \"&\", \";\", \"\\n\", \"\\r\", \"$\", \"`\", \"(\", \")\", \"*\", \"?\", \"[\", \"]\"];\n\tif (shellOperators.some((op) => trimmed.includes(op))) {\n\t\treturn { optimized: false };\n\t}\n\n\t// Simple tokenizer split by whitespace\n\tconst args = trimmed.split(/\\s+/);\n\tif (args.length === 0) {\n\t\treturn { optimized: false };\n\t}\n\n\tconst cmd = args[0];\n\tconst unquote = (s: string) => {\n\t\tif ((s.startsWith('\"') && s.endsWith('\"')) || (s.startsWith(\"'\") && s.endsWith(\"'\"))) {\n\t\t\treturn s.slice(1, -1);\n\t\t}\n\t\treturn s;\n\t};\n\n\tconst resolveToCwd = (p: string, base: string) => {\n\t\tconst clean = unquote(p);\n\t\tif (clean.startsWith(\"/\")) return clean;\n\t\treturn resolvePath(base, clean);\n\t};\n\n\ttry {\n\t\tif (cmd === \"cat\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\treturn { optimized: true, output: content, exitCode: 0 };\n\t\t\t}\n\t\t} else if (cmd === \"head\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst lines = content.split(\"\\n\").slice(0, 10).join(\"\\n\");\n\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t} else if (args.length === 4 && args[1] === \"-n\" && !args[3].startsWith(\"-\")) {\n\t\t\t\tconst count = parseInt(args[2], 10);\n\t\t\t\tif (!Number.isNaN(count) && count >= 0) {\n\t\t\t\t\tconst filePath = resolveToCwd(args[3], cwd);\n\t\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\t\tconst lines = content.split(\"\\n\").slice(0, count).join(\"\\n\");\n\t\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (cmd === \"tail\") {\n\t\t\tif (args.length === 2 && !args[1].startsWith(\"-\")) {\n\t\t\t\tconst filePath = resolveToCwd(args[1], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst allLines = content.split(\"\\n\");\n\t\t\t\tconst lines = allLines.slice(Math.max(0, allLines.length - 10)).join(\"\\n\");\n\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t} else if (args.length === 4 && args[1] === \"-n\" && !args[3].startsWith(\"-\")) {\n\t\t\t\tconst count = parseInt(args[2], 10);\n\t\t\t\tif (!Number.isNaN(count) && count >= 0) {\n\t\t\t\t\tconst filePath = resolveToCwd(args[3], cwd);\n\t\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\t\tconst allLines = content.split(\"\\n\");\n\t\t\t\t\tconst lines = allLines.slice(Math.max(0, allLines.length - count)).join(\"\\n\");\n\t\t\t\t\treturn { optimized: true, output: lines, exitCode: 0 };\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (cmd === \"ls\") {\n\t\t\tif (args.length === 1 || (args.length === 2 && !args[1].startsWith(\"-\"))) {\n\t\t\t\tconst targetDir = args.length === 2 ? resolveToCwd(args[1], cwd) : cwd;\n\t\t\t\tconst entries = await fsReaddir(targetDir);\n\t\t\t\tentries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));\n\t\t\t\tconst results: string[] = [];\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tlet suffix = \"\";\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst entryStat = await fsStat(resolvePath(targetDir, entry));\n\t\t\t\t\t\tif (entryStat.isDirectory()) suffix = \"/\";\n\t\t\t\t\t} catch {}\n\t\t\t\t\tresults.push(entry + suffix);\n\t\t\t\t}\n\t\t\t\treturn { optimized: true, output: results.join(\"\\n\"), exitCode: 0 };\n\t\t\t}\n\t\t} else if (cmd === \"grep\" || cmd === \"rg\") {\n\t\t\tif (args.length === 3 && !args[1].startsWith(\"-\") && !args[2].startsWith(\"-\")) {\n\t\t\t\tconst patternStr = unquote(args[1]);\n\t\t\t\tconst filePath = resolveToCwd(args[2], cwd);\n\t\t\t\tconst content = await fsReadFile(filePath, \"utf-8\");\n\t\t\t\tconst lines = content.split(\"\\n\");\n\t\t\t\tconst matches: string[] = [];\n\t\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\t\tif (lines[i].includes(patternStr)) {\n\t\t\t\t\t\tmatches.push(lines[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { optimized: true, output: matches.join(\"\\n\"), exitCode: matches.length > 0 ? 0 : 1 };\n\t\t\t}\n\t\t} else if (cmd === \"find\") {\n\t\t\tif (args.length === 1 || (args.length === 2 && !args[1].startsWith(\"-\"))) {\n\t\t\t\tconst searchPath = args.length === 2 ? resolveToCwd(args[1], cwd) : cwd;\n\t\t\t\tconst walk = async (dir: string): Promise<string[]> => {\n\t\t\t\t\tlet results: string[] = [];\n\t\t\t\t\tconst entries = await fsReaddir(dir);\n\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\tconst full = resolvePath(dir, entry);\n\t\t\t\t\t\tconst entryStat = await fsStat(full);\n\t\t\t\t\t\tif (entryStat.isDirectory()) {\n\t\t\t\t\t\t\tresults.push(full);\n\t\t\t\t\t\t\tresults = results.concat(await walk(full));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresults.push(full);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn results;\n\t\t\t\t};\n\t\t\t\tconst all = (await walk(searchPath)).map((p) => relativePath(searchPath, p).replace(/\\\\/g, \"/\"));\n\t\t\t\treturn { optimized: true, output: all.join(\"\\n\"), exitCode: 0 };\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn { optimized: false };\n\t}\n\n\treturn { optimized: false };\n}\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });\n\tconst commandPrefix = options?.commandPrefix;\n\tconst spawnHook = options?.spawnHook;\n\tconst canOptimizeCommand = !options?.operations && !options?.shellPath && !commandPrefix && !spawnHook;\n\tconst canFilterCommand = canOptimizeCommand;\n\treturn {\n\t\tname: \"bash\",\n\t\tlabel: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tpromptSnippet: \"Execute bash commands (ls, grep, find, etc.)\",\n\t\tparameters: bashSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ command, timeout }: { command: string; timeout?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\tonUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\tconst spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook);\n\t\t\tconst output = new OutputAccumulator({ tempFilePrefix: \"pi-bash\" });\n\t\t\tlet updateTimer: NodeJS.Timeout | undefined;\n\t\t\tlet updateDirty = false;\n\t\t\tlet lastUpdateAt = 0;\n\n\t\t\tconst emitOutputUpdate = () => {\n\t\t\t\tif (!onUpdate || !updateDirty) return;\n\t\t\t\tupdateDirty = false;\n\t\t\t\tlastUpdateAt = Date.now();\n\t\t\t\tconst snapshot = output.previewSnapshot(BASH_PREVIEW_LINES, BASH_PREVIEW_BYTES, {\n\t\t\t\t\tpersistIfFullTruncated: true,\n\t\t\t\t});\n\t\t\t\tconst preview = {\n\t\t\t\t\tcontent: snapshot.content,\n\t\t\t\t\tskippedLines: Math.max(0, snapshot.truncation.totalLines - snapshot.truncation.outputLines),\n\t\t\t\t};\n\t\t\t\tonUpdate({\n\t\t\t\t\tcontent: [{ type: \"text\", text: preview.content || \"\" }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t\tfullOutputError: snapshot.fullOutputError,\n\t\t\t\t\t\tpreview,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tconst clearUpdateTimer = () => {\n\t\t\t\tif (updateTimer) {\n\t\t\t\t\tclearTimeout(updateTimer);\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst scheduleOutputUpdate = () => {\n\t\t\t\tif (!onUpdate) return;\n\t\t\t\tupdateDirty = true;\n\t\t\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearUpdateTimer();\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\t\tupdateTimer = undefined;\n\t\t\t\t\temitOutputUpdate();\n\t\t\t\t}, delay);\n\t\t\t};\n\n\t\t\tif (onUpdate) {\n\t\t\t\tonUpdate({ content: [], details: undefined });\n\t\t\t}\n\n\t\t\tconst handleData = (data: Buffer) => {\n\t\t\t\toutput.append(data);\n\t\t\t\tscheduleOutputUpdate();\n\t\t\t};\n\n\t\t\tconst finishOutput = async () => {\n\t\t\t\toutput.finish();\n\t\t\t\tclearUpdateTimer();\n\t\t\t\temitOutputUpdate();\n\t\t\t\treturn output.snapshot({ persistIfTruncated: true });\n\t\t\t};\n\n\t\t\tconst formatOutput = (snapshot: Awaited<ReturnType<typeof finishOutput>>, emptyText = \"(no output)\") => {\n\t\t\t\tconst truncation = snapshot.truncation;\n\t\t\t\tlet text = snapshot.content || emptyText;\n\t\t\t\tlet details: BashToolDetails | undefined;\n\t\t\t\tconst preview = output.preview(BASH_PREVIEW_LINES, BASH_PREVIEW_BYTES);\n\t\t\t\tconst fullOutputNotice = snapshot.fullOutputPath\n\t\t\t\t\t? `Full output: ${snapshot.fullOutputPath}`\n\t\t\t\t\t: snapshot.fullOutputError\n\t\t\t\t\t\t? `Full output unavailable: ${snapshot.fullOutputError}`\n\t\t\t\t\t\t: \"Full output unavailable\";\n\t\t\t\tif (truncation.truncated || preview.skippedLines > 0) {\n\t\t\t\t\tdetails = { preview };\n\t\t\t\t}\n\t\t\t\tif (snapshot.fullOutputPath || snapshot.fullOutputError) {\n\t\t\t\t\tdetails = {\n\t\t\t\t\t\t...(details ?? {}),\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t\tfullOutputError: snapshot.fullOutputError,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\tdetails = {\n\t\t\t\t\t\t...(details ?? {}),\n\t\t\t\t\t\ttruncation,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t\tfullOutputError: snapshot.fullOutputError,\n\t\t\t\t\t};\n\t\t\t\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\t\t\t\tconst endLine = truncation.totalLines;\n\t\t\t\t\tif (truncation.lastLinePartial) {\n\t\t\t\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\t\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). ${fullOutputNotice}]`;\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. ${fullOutputNotice}]`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). ${fullOutputNotice}]`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { text, details };\n\t\t\t};\n\n\t\t\tconst appendStatus = (text: string, status: string) => `${text ? `${text}\\n\\n` : \"\"}${status}`;\n\n\t\t\ttry {\n\t\t\t\tif (canFilterCommand) {\n\t\t\t\t\tconst classification = classifyGitCommand(command, spawnContext.env);\n\t\t\t\t\tif (classification.eligible && classification.subcommand) {\n\t\t\t\t\t\tconst res = await executeFilteredGit(\n\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\tclassification.subcommand,\n\t\t\t\t\t\t\tclassification.globalOptions || [],\n\t\t\t\t\t\t\tclassification.subcommandArgs || [],\n\t\t\t\t\t\t\t{ signal, timeout },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (res.exitCode !== -100) {\n\t\t\t\t\t\t\toutput.append(res.rawBytes ?? Buffer.from(res.rawOut, \"utf-8\"));\n\t\t\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\t\t\tif (res.exitCode !== 0) {\n\t\t\t\t\t\t\t\tconst { text: rawOutputText } = formatOutput(snapshot);\n\t\t\t\t\t\t\t\tthrow new Error(appendStatus(rawOutputText, `Command exited with code ${res.exitCode}`));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst details = snapshot.truncation.truncated\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\ttruncation: snapshot.truncation,\n\t\t\t\t\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t\t\t\t\t\tfullOutputError: snapshot.fullOutputError,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: snapshot.fullOutputPath || snapshot.fullOutputError\n\t\t\t\t\t\t\t\t\t? { fullOutputPath: snapshot.fullOutputPath, fullOutputError: snapshot.fullOutputError }\n\t\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\t\treturn { content: [{ type: \"text\", text: res.output }], details };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (canOptimizeCommand) {\n\t\t\t\t\tconst optResult = await tryOptimizeCommand(command, cwd);\n\t\t\t\t\tif (optResult.optimized) {\n\t\t\t\t\t\toutput.append(Buffer.from(optResult.output ?? \"\", \"utf-8\"));\n\t\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\t\t\tif (optResult.exitCode !== 0 && optResult.exitCode !== undefined) {\n\t\t\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${optResult.exitCode}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet exitCode: number | null;\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await ops.exec(spawnContext.command, spawnContext.cwd, {\n\t\t\t\t\t\tonData: handleData,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tenv: spawnContext.env,\n\t\t\t\t\t});\n\t\t\t\t\texitCode = result.exitCode;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\t\tconst { text } = formatOutput(snapshot, \"\");\n\t\t\t\t\tif (err instanceof Error && err.message === \"aborted\") {\n\t\t\t\t\t\tthrow new Error(appendStatus(text, \"Command aborted\"));\n\t\t\t\t\t}\n\t\t\t\t\tif (err instanceof Error && err.message.startsWith(\"timeout:\")) {\n\t\t\t\t\t\tconst timeoutSecs = err.message.split(\":\")[1];\n\t\t\t\t\t\tthrow new Error(appendStatus(text, `Command timed out after ${timeoutSecs} seconds`));\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tconst snapshot = await finishOutput();\n\t\t\t\tconst { text: outputText, details } = formatOutput(snapshot);\n\t\t\t\tif (exitCode !== 0 && exitCode !== null) {\n\t\t\t\t\tthrow new Error(appendStatus(outputText, `Command exited with code ${exitCode}`));\n\t\t\t\t}\n\t\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t\t} finally {\n\t\t\t\tclearUpdateTimer();\n\t\t\t\tawait output.closeTempFile();\n\t\t\t}\n\t\t},\n\t\trenderCall(args, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (context.executionStarted && state.startedAt === undefined) {\n\t\t\t\tstate.startedAt = Date.now();\n\t\t\t\tstate.endedAt = undefined;\n\t\t\t}\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBashCall(args));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst state = context.state;\n\t\t\tif (state.startedAt !== undefined && options.isPartial && !state.interval) {\n\t\t\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t}\n\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\tstate.endedAt ??= Date.now();\n\t\t\t\tif (state.interval) {\n\t\t\t\t\tclearInterval(state.interval);\n\t\t\t\t\tstate.interval = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashResultRenderComponent | undefined) ?? new BashResultRenderComponent();\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\tstate.startedAt,\n\t\t\t\tstate.endedAt,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\treturn wrapToolDefinition(createBashToolDefinition(cwd, options));\n}\n"]}
|