@astralyn/pi 0.85.1 → 0.85.3
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 +43 -0
- package/dist/bundle/chunks/anthropic-messages-IHRRITCV.js +6 -0
- package/dist/bundle/chunks/anthropic.js +75 -0
- package/dist/bundle/chunks/azure-openai-responses-QXBIDYXO.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +78 -0
- package/dist/bundle/chunks/chunk-37ATLPRE.js +2 -0
- package/dist/bundle/chunks/chunk-4L3WN2XY.js +2 -0
- package/dist/bundle/chunks/chunk-5B3S5DVL.js +4 -0
- package/dist/bundle/chunks/chunk-5FDOJRDS.js +2 -0
- package/dist/bundle/chunks/chunk-6CYCI3EJ.js +12 -0
- package/dist/bundle/chunks/chunk-7LO5Z4WE.js +2 -0
- package/dist/bundle/chunks/chunk-APKJ4JGA.js +2 -0
- package/dist/bundle/chunks/chunk-EDBLK2JQ.js +2 -0
- package/dist/bundle/chunks/chunk-FEZ5RM2B.js +2 -0
- package/dist/bundle/chunks/chunk-JEIV47WR.js +2 -0
- package/dist/bundle/chunks/chunk-JSJPY26N.js +2 -0
- package/dist/bundle/chunks/chunk-KI6LC764.js +42 -0
- package/dist/bundle/chunks/chunk-LB4P77SH.js +1688 -0
- package/dist/bundle/chunks/chunk-NUHFSC37.js +25 -0
- package/dist/bundle/chunks/chunk-O36ZMA3U.js +2 -0
- package/dist/bundle/chunks/chunk-OWESLY5T.js +11 -0
- package/dist/bundle/chunks/chunk-RRBI7OUG.js +50 -0
- package/dist/bundle/chunks/chunk-S2DJQQI2.js +2 -0
- package/dist/bundle/chunks/chunk-UP6RLTHQ.js +2 -0
- package/dist/bundle/chunks/chunk-UUSTLCVC.js +2 -0
- package/dist/bundle/chunks/chunk-WWBSZG5V.js +2 -0
- package/dist/bundle/chunks/chunk-YZJWMPUI.js +2 -0
- package/dist/bundle/chunks/github-copilot.js +2 -0
- package/dist/bundle/chunks/google-generative-ai-NBOR3IQR.js +2 -0
- package/dist/bundle/chunks/google-vertex-VTHX3SUB.js +2 -0
- package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +13 -0
- package/dist/bundle/chunks/image-resize-worker.js +2 -0
- package/dist/bundle/chunks/kimi-coding.js +2 -0
- package/dist/bundle/chunks/mistral-conversations-NO4ANAA5.js +5 -0
- package/dist/bundle/chunks/multipart-parser-SQ6GDJL7.js +3 -0
- package/dist/bundle/chunks/node-7L5OTM6S.js +2 -0
- package/dist/bundle/chunks/node-G4XOIDPH.js +16 -0
- package/dist/bundle/chunks/openai-codex-responses-5S3T3HMA.js +10 -0
- package/dist/bundle/chunks/openai-codex.js +75 -0
- package/dist/bundle/chunks/openai-completions-CXRRTRWE.js +7 -0
- package/dist/bundle/chunks/openai-responses-CV3MH6VP.js +2 -0
- package/dist/bundle/chunks/openrouter-images-6XDE2CEW.js +2 -0
- package/dist/bundle/chunks/openrouter.js +75 -0
- package/dist/bundle/chunks/pi-messages-PE6B42TG.js +8 -0
- package/dist/bundle/chunks/radius.js +75 -0
- package/dist/bundle/chunks/src-UK77SYZE.js +4 -0
- package/dist/bundle/chunks/xai.js +2 -0
- package/dist/bundle/cli.js +3 -0
- package/dist/bundle/index.js +2 -0
- package/dist/bundle/rpc-entry.js +3 -0
- package/dist/cli.js +5 -2469
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -6
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/background/history.d.ts.map +1 -1
- package/dist/core/background/history.js +6 -0
- package/dist/core/background/history.js.map +1 -1
- package/dist/core/background/presentation.d.ts.map +1 -1
- package/dist/core/background/presentation.js +41 -4
- package/dist/core/background/presentation.js.map +1 -1
- package/dist/core/background/service.d.ts +2 -2
- package/dist/core/background/service.d.ts.map +1 -1
- package/dist/core/background/service.js +38 -15
- package/dist/core/background/service.js.map +1 -1
- package/dist/core/background/types.d.ts +9 -0
- package/dist/core/background/types.d.ts.map +1 -1
- package/dist/core/background/types.js +4 -0
- package/dist/core/background/types.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +5 -12
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +11 -19
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/settings.d.ts +27 -0
- package/dist/core/compaction/settings.d.ts.map +1 -0
- package/dist/core/compaction/settings.js +40 -0
- package/dist/core/compaction/settings.js.map +1 -0
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +0 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +0 -6
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +0 -11
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/keybindings.d.ts +15 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +12 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-config.d.ts +32 -10
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +38 -1
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +4 -0
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/settings-manager.d.ts +4 -7
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +7 -6
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/bash.d.ts +3 -9
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +3 -8
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/shell-execution.d.ts.map +1 -1
- package/dist/core/tools/shell-execution.js +3 -1
- package/dist/core/tools/shell-execution.js.map +1 -1
- package/dist/extensions/background/manager.d.ts +8 -5
- package/dist/extensions/background/manager.d.ts.map +1 -1
- package/dist/extensions/background/manager.js +115 -39
- package/dist/extensions/background/manager.js.map +1 -1
- package/dist/extensions/background/task-view.d.ts +5 -0
- package/dist/extensions/background/task-view.d.ts.map +1 -1
- package/dist/extensions/background/task-view.js +4 -0
- package/dist/extensions/background/task-view.js.map +1 -1
- package/dist/extensions/btw/controller.d.ts +1 -1
- package/dist/extensions/btw/controller.d.ts.map +1 -1
- package/dist/extensions/btw/controller.js +4 -4
- package/dist/extensions/btw/controller.js.map +1 -1
- package/dist/extensions/btw/index.js +3 -3
- package/dist/extensions/btw/index.js.map +1 -1
- package/dist/extensions/index.js +2 -2
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/provider/catalog.d.ts +57 -0
- package/dist/extensions/provider/catalog.d.ts.map +1 -0
- package/dist/extensions/provider/catalog.js +181 -0
- package/dist/extensions/provider/catalog.js.map +1 -0
- package/dist/extensions/provider/compat-fields.d.ts +25 -0
- package/dist/extensions/provider/compat-fields.d.ts.map +1 -0
- package/dist/extensions/provider/compat-fields.js +148 -0
- package/dist/extensions/provider/compat-fields.js.map +1 -0
- package/dist/extensions/provider/configuration.d.ts +8 -0
- package/dist/extensions/provider/configuration.d.ts.map +1 -0
- package/dist/extensions/provider/configuration.js +21 -0
- package/dist/extensions/provider/configuration.js.map +1 -0
- package/dist/extensions/provider/connection.d.ts +14 -0
- package/dist/extensions/provider/connection.d.ts.map +1 -0
- package/dist/extensions/provider/connection.js +86 -0
- package/dist/extensions/provider/connection.js.map +1 -0
- package/dist/extensions/provider/constants.d.ts +38 -0
- package/dist/extensions/provider/constants.d.ts.map +1 -0
- package/dist/extensions/provider/constants.js +75 -0
- package/dist/extensions/provider/constants.js.map +1 -0
- package/dist/extensions/provider/index.d.ts +4 -0
- package/dist/extensions/provider/index.d.ts.map +1 -0
- package/dist/extensions/provider/index.js +65 -0
- package/dist/extensions/provider/index.js.map +1 -0
- package/dist/extensions/provider/probe.d.ts +34 -0
- package/dist/extensions/provider/probe.d.ts.map +1 -0
- package/dist/extensions/provider/probe.js +178 -0
- package/dist/extensions/provider/probe.js.map +1 -0
- package/dist/extensions/provider/refresh.d.ts +30 -0
- package/dist/extensions/provider/refresh.d.ts.map +1 -0
- package/dist/extensions/provider/refresh.js +66 -0
- package/dist/extensions/provider/refresh.js.map +1 -0
- package/dist/extensions/provider/store.d.ts +131 -0
- package/dist/extensions/provider/store.d.ts.map +1 -0
- package/dist/extensions/provider/store.js +503 -0
- package/dist/extensions/provider/store.js.map +1 -0
- package/dist/extensions/provider/ui/app.d.ts +25 -0
- package/dist/extensions/provider/ui/app.d.ts.map +1 -0
- package/dist/extensions/provider/ui/app.js +153 -0
- package/dist/extensions/provider/ui/app.js.map +1 -0
- package/dist/extensions/provider/ui/builtin-data.d.ts +53 -0
- package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -0
- package/dist/extensions/provider/ui/builtin-data.js +315 -0
- package/dist/extensions/provider/ui/builtin-data.js.map +1 -0
- package/dist/extensions/provider/ui/compat.d.ts +57 -0
- package/dist/extensions/provider/ui/compat.d.ts.map +1 -0
- package/dist/extensions/provider/ui/compat.js +427 -0
- package/dist/extensions/provider/ui/compat.js.map +1 -0
- package/dist/extensions/provider/ui/dialogs.d.ts +30 -0
- package/dist/extensions/provider/ui/dialogs.d.ts.map +1 -0
- package/dist/extensions/provider/ui/dialogs.js +89 -0
- package/dist/extensions/provider/ui/dialogs.js.map +1 -0
- package/dist/extensions/provider/ui/dictionary.d.ts +29 -0
- package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -0
- package/dist/extensions/provider/ui/dictionary.js +385 -0
- package/dist/extensions/provider/ui/dictionary.js.map +1 -0
- package/dist/extensions/provider/ui/editor.d.ts +91 -0
- package/dist/extensions/provider/ui/editor.d.ts.map +1 -0
- package/dist/extensions/provider/ui/editor.js +667 -0
- package/dist/extensions/provider/ui/editor.js.map +1 -0
- package/dist/extensions/provider/ui/fetch-models.d.ts +39 -0
- package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -0
- package/dist/extensions/provider/ui/fetch-models.js +320 -0
- package/dist/extensions/provider/ui/fetch-models.js.map +1 -0
- package/dist/extensions/provider/ui/model-fields.d.ts +43 -0
- package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -0
- package/dist/extensions/provider/ui/model-fields.js +441 -0
- package/dist/extensions/provider/ui/model-fields.js.map +1 -0
- package/dist/extensions/provider/ui/model-options.d.ts +93 -0
- package/dist/extensions/provider/ui/model-options.d.ts.map +1 -0
- package/dist/extensions/provider/ui/model-options.js +529 -0
- package/dist/extensions/provider/ui/model-options.js.map +1 -0
- package/dist/extensions/provider/ui/pane.d.ts +81 -0
- package/dist/extensions/provider/ui/pane.d.ts.map +1 -0
- package/dist/extensions/provider/ui/pane.js +3 -0
- package/dist/extensions/provider/ui/pane.js.map +1 -0
- package/dist/extensions/provider/ui/provider-fields.d.ts +60 -0
- package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -0
- package/dist/extensions/provider/ui/provider-fields.js +326 -0
- package/dist/extensions/provider/ui/provider-fields.js.map +1 -0
- package/dist/extensions/provider/ui/provider-list.d.ts +34 -0
- package/dist/extensions/provider/ui/provider-list.d.ts.map +1 -0
- package/dist/extensions/provider/ui/provider-list.js +162 -0
- package/dist/extensions/provider/ui/provider-list.js.map +1 -0
- package/dist/extensions/provider/ui/session.d.ts +20 -0
- package/dist/extensions/provider/ui/session.d.ts.map +1 -0
- package/dist/extensions/provider/ui/session.js +52 -0
- package/dist/extensions/provider/ui/session.js.map +1 -0
- package/dist/extensions/provider/ui/thinking-map.d.ts +20 -0
- package/dist/extensions/provider/ui/thinking-map.d.ts.map +1 -0
- package/dist/extensions/provider/ui/thinking-map.js +166 -0
- package/dist/extensions/provider/ui/thinking-map.js.map +1 -0
- package/dist/extensions/provider/ui/value-row.d.ts +88 -0
- package/dist/extensions/provider/ui/value-row.d.ts.map +1 -0
- package/dist/extensions/provider/ui/value-row.js +158 -0
- package/dist/extensions/provider/ui/value-row.js.map +1 -0
- package/dist/extensions/statusline/index.js +2 -2
- package/dist/extensions/statusline/index.js.map +1 -1
- package/dist/extensions/subagent/index.d.ts.map +1 -1
- package/dist/extensions/subagent/index.js +4 -2
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/subagent/resolve.d.ts +5 -0
- package/dist/extensions/subagent/resolve.d.ts.map +1 -1
- package/dist/extensions/subagent/resolve.js +15 -7
- package/dist/extensions/subagent/resolve.js.map +1 -1
- package/dist/extensions/subagent/schema.d.ts +2 -0
- package/dist/extensions/subagent/schema.d.ts.map +1 -1
- package/dist/extensions/subagent/schema.js +1 -0
- package/dist/extensions/subagent/schema.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +10 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +20 -2
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +6 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/rpc-entry.js +10 -2469
- package/docs/bundled/README.md +1 -1
- package/docs/bundled/extensions/background.md +5 -5
- package/docs/bundled/extensions/provider.md +117 -0
- package/docs/bundled/extensions/statusline.md +1 -1
- package/docs/bundled/extensions/subagent.md +7 -3
- package/docs/compaction.md +16 -6
- package/docs/development.md +1 -1
- package/docs/docs.json +2 -2
- package/docs/extensions.md +0 -13
- package/docs/keybindings.md +3 -0
- package/docs/settings.md +11 -7
- package/npm-shrinkwrap.json +4 -4
- package/package.json +6 -5
- package/dist/extensions/router/constants.d.ts +0 -23
- package/dist/extensions/router/constants.d.ts.map +0 -1
- package/dist/extensions/router/constants.js +0 -30
- package/dist/extensions/router/constants.js.map +0 -1
- package/dist/extensions/router/dialog-host.d.ts +0 -60
- package/dist/extensions/router/dialog-host.d.ts.map +0 -1
- package/dist/extensions/router/dialog-host.js +0 -196
- package/dist/extensions/router/dialog-host.js.map +0 -1
- package/dist/extensions/router/dialog.d.ts +0 -45
- package/dist/extensions/router/dialog.d.ts.map +0 -1
- package/dist/extensions/router/dialog.js +0 -378
- package/dist/extensions/router/dialog.js.map +0 -1
- package/dist/extensions/router/identity.d.ts +0 -15
- package/dist/extensions/router/identity.d.ts.map +0 -1
- package/dist/extensions/router/identity.js +0 -173
- package/dist/extensions/router/identity.js.map +0 -1
- package/dist/extensions/router/index.d.ts +0 -15
- package/dist/extensions/router/index.d.ts.map +0 -1
- package/dist/extensions/router/index.js +0 -70
- package/dist/extensions/router/index.js.map +0 -1
- package/dist/extensions/router/presets.d.ts +0 -51
- package/dist/extensions/router/presets.d.ts.map +0 -1
- package/dist/extensions/router/presets.js +0 -108
- package/dist/extensions/router/presets.js.map +0 -1
- package/dist/extensions/router/probe.d.ts +0 -26
- package/dist/extensions/router/probe.d.ts.map +0 -1
- package/dist/extensions/router/probe.js +0 -216
- package/dist/extensions/router/probe.js.map +0 -1
- package/dist/extensions/router/register.d.ts +0 -12
- package/dist/extensions/router/register.d.ts.map +0 -1
- package/dist/extensions/router/register.js +0 -90
- package/dist/extensions/router/register.js.map +0 -1
- package/dist/extensions/router/state.d.ts +0 -20
- package/dist/extensions/router/state.d.ts.map +0 -1
- package/dist/extensions/router/state.js +0 -169
- package/dist/extensions/router/state.js.map +0 -1
- package/dist/extensions/router/store.d.ts +0 -12
- package/dist/extensions/router/store.d.ts.map +0 -1
- package/dist/extensions/router/store.js +0 -266
- package/dist/extensions/router/store.js.map +0 -1
- package/dist/extensions/router/stream.d.ts +0 -12
- package/dist/extensions/router/stream.d.ts.map +0 -1
- package/dist/extensions/router/stream.js +0 -233
- package/dist/extensions/router/stream.js.map +0 -1
- package/dist/extensions/router/transport.d.ts +0 -9
- package/dist/extensions/router/transport.d.ts.map +0 -1
- package/dist/extensions/router/transport.js +0 -81
- package/dist/extensions/router/transport.js.map +0 -1
- package/dist/extensions/router/types.d.ts +0 -39
- package/dist/extensions/router/types.d.ts.map +0 -1
- package/dist/extensions/router/types.js +0 -2
- package/dist/extensions/router/types.js.map +0 -1
- package/dist/extensions/router/ui.d.ts +0 -26
- package/dist/extensions/router/ui.d.ts.map +0 -1
- package/dist/extensions/router/ui.js +0 -897
- package/dist/extensions/router/ui.js.map +0 -1
- package/dist/image-resize-worker.js +0 -2
- package/docs/bundled/extensions/router.md +0 -197
|
@@ -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 } from \"node:fs/promises\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\trewriteCmdNulRedirects,\n\ttype ShellConfig,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport { type BackgroundCompletion, BackgroundExecutionError } from \"../background/types.ts\";\nimport { getExperimentalToolSampling } from \"../experimental.ts\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport { createShellRenderers } from \"./renderers/bash.ts\";\nimport { type ManagedShellExecution, runShellCommand } from \"./shell-execution.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult } from \"./truncate.ts\";\n\nexport { MAX_BACKGROUND_OUTPUT_BYTES } from \"./shell-execution.ts\";\n\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nexport const MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\n\n/**\n * The one timeout rule, shared by this tool and the background extension so a\n * rejected timeout reads the same wherever it is caught.\n */\nexport function resolveTimeoutMs(timeout: number | undefined): number | undefined {\n\tif (timeout === undefined) return undefined;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\n\tconst timeoutMs = timeout * 1000;\n\tif (timeoutMs > MAX_TIMEOUT_MS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n\treturn timeoutMs;\n}\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Shell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"true returns a managed task ID immediately and runs the command in the background; omit or false to block until exit\",\n\t\t}),\n\t),\n});\n\nexport const bashToolSystemPromptContribution = {\n\tsnippet: \"Execute bash commands, foreground or background\",\n\tguidelines: [\"You can inspect PI_* environment variables for current model and session details.\"],\n} as const;\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\t/** Settled handoff snapshot, not a command completion or exit code. */\n\tbackground?: { kind: \"background\"; taskId: 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\t * Error contract: reject with `new Error(\"aborted\")` when aborted via `signal`,\n\t * and `new Error(\"timeout:<seconds>\")` on timeout expiry — callers (including\n\t * the background extension) classify outcomes from these exact markers.\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/** Shared process execution used by the built-in shell tools. */\nexport function createLocalShellOperations(\n\tshellName: string,\n\tresolveShellConfig: () => ShellConfig,\n\tnormalizeCommand: (command: string) => string = (command) => command,\n): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst timeoutMs = resolveTimeoutMs(timeout);\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\t\t\tconst shellConfig = resolveShellConfig();\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 ${shellName} commands.`);\n\t\t\t}\n\n\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst normalizedCommand = normalizeCommand(command);\n\t\t\tconst child = spawn(\n\t\t\t\tshellConfig.shell,\n\t\t\t\tcommandFromStdin ? shellConfig.args : [...shellConfig.args, normalizedCommand],\n\t\t\t\t{\n\t\t\t\t\tcwd,\n\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\twindowsHide: true,\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(normalizedCommand);\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 (timeoutMs !== undefined) {\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}, timeoutMs);\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\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 normalizeLocalBashCommand(command: string, platform: NodeJS.Platform = process.platform): string {\n\treturn platform === \"win32\" ? rewriteCmdNulRedirects(command) : command;\n}\n\nexport function createLocalBashOperations(options?: { shellPath?: string }): BashOperations {\n\treturn createLocalShellOperations(\"bash\", () => getShellConfig(options?.shellPath), normalizeLocalBashCommand);\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nexport function resolveSpawnContext(\n\tcommand: string,\n\tcwd: string,\n\tspawnHook: BashSpawnHook | undefined,\n\texposeSessionEnvironment: boolean,\n\tctx: ExtensionContext | undefined,\n): BashSpawnContext {\n\tconst env = { ...getShellEnv() };\n\tdelete env.PI_SESSION_ID;\n\tdelete env.PI_SESSION_FILE;\n\tdelete env.PI_PROVIDER;\n\tdelete env.PI_MODEL;\n\tdelete env.PI_REASONING_LEVEL;\n\tif (exposeSessionEnvironment && ctx) {\n\t\tconst model = ctx.model;\n\t\tenv.PI_SESSION_ID = ctx.sessionManager.getSessionId();\n\t\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\t\tif (sessionFile) env.PI_SESSION_FILE = sessionFile;\n\t\tif (model) {\n\t\t\tenv.PI_PROVIDER = model.provider;\n\t\t\tenv.PI_MODEL = model.id;\n\t\t}\n\t\tif (ctx.thinkingLevel) env.PI_REASONING_LEVEL = ctx.thinkingLevel;\n\t}\n\tconst baseContext: BashSpawnContext = { command, cwd, env };\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/** Expose current Pi session metadata as PI_* environment variables. Default: true */\n\texposeSessionEnvironment?: boolean;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n}\n\nexport type BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\nexport interface ShellToolConfig {\n\tname: string;\n\tlabel: string;\n\tshellName: string;\n\tprompt: string;\n\tpromptSnippet: string;\n\tpromptGuidelines?: readonly string[];\n\ttempFilePrefix: string;\n}\n\n/** Translate terminal shell failures to the native foreground tool contract once. */\nfunction shellToolResult(completion: BackgroundCompletion<BashToolDetails | undefined>, managed: boolean) {\n\tconst status = completion.status;\n\tif (status === \"failed\" || status === \"timeout\" || status === \"cancelled\") {\n\t\tconst text = completion.result.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\\n\");\n\t\tconst message = completion.error ? text || completion.error : `${text ? `${text}\\n\\n` : \"\"}Command ${status}`;\n\t\tthrow managed ? new BackgroundExecutionError(message, status) : new Error(message);\n\t}\n\treturn completion.result;\n}\n\nexport function createShellToolDefinition(\n\tcwd: string,\n\tconfig: ShellToolConfig,\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 exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\treturn {\n\t\tname: config.name,\n\t\tlabel: config.label,\n\t\tdescription: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr, truncated to the last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first); the full output is saved to a temp file. Optionally provide a timeout in seconds (no default). Choose the mode per call: foreground (default) blocks until the command exits — use it when your next step needs the output; background: true returns immediately with a task ID — use it for long-running work (builds, servers, watchers, big test suites) or when you have independent work to continue. A handoff is not completion: the result arrives later as an automatic completion notification; meanwhile use bg read to inspect output, bg wait to block until it settles, bg kill to stop it. Background output is limited to 20 MiB; an expired bg wait window never stops the command.`,\n\t\tpromptSnippet: config.promptSnippet,\n\t\tpromptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,\n\t\tparameters: bashSchema,\n\t\tconstrainedSampling: getExperimentalToolSampling(),\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{ command, timeout, background }: BashToolInput,\n\t\t\tparentSignal?: AbortSignal,\n\t\t\toriginalUpdate?,\n\t\t\tctx?: ExtensionContext,\n\t\t) {\n\t\t\tconst host = ctx?.background;\n\t\t\tif (host?.closed) throw new Error(\"Background service is closed\");\n\t\t\tconst run = async (\n\t\t\t\tmanaged?: ManagedShellExecution,\n\t\t\t): Promise<BackgroundCompletion<BashToolDetails | undefined>> => {\n\t\t\t\tconst signal = managed?.control.signal ?? parentSignal;\n\t\t\t\ttry {\n\t\t\t\t\tif (managed) {\n\t\t\t\t\t\tif (signal?.aborted) throw new Error(\"Command aborted\");\n\t\t\t\t\t\tresolveTimeoutMs(timeout);\n\t\t\t\t\t}\n\t\t\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\t\t\tconst spawnContext = resolveSpawnContext(\n\t\t\t\t\t\tresolvedCommand,\n\t\t\t\t\t\tctx?.cwd || cwd,\n\t\t\t\t\t\tspawnHook,\n\t\t\t\t\t\texposeSessionEnvironment,\n\t\t\t\t\t\tctx,\n\t\t\t\t\t);\n\t\t\t\t\treturn await runShellCommand({\n\t\t\t\t\t\toperations: ops,\n\t\t\t\t\t\tshellName: config.shellName,\n\t\t\t\t\t\tcontext: spawnContext,\n\t\t\t\t\t\ttempFilePrefix: config.tempFilePrefix,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tonUpdate: originalUpdate,\n\t\t\t\t\t\tmanaged,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Setup and cleanup exceptions carry an explicit terminal status.\n\t\t\t\t\tif (!managed) throw error;\n\t\t\t\t\tthrow new BackgroundExecutionError(\n\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t\t\tmanaged.control.signal.aborted ? \"cancelled\" : \"failed\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (!host || (!host.enabled && !background)) {\n\t\t\t\tif (background)\n\t\t\t\t\tthrow new Error(\"Background execution is not available in this host. No command was started.\");\n\t\t\t\treturn shellToolResult(await run(), false);\n\t\t\t}\n\t\t\tconst outcome = await host.execute<BashToolDetails | undefined>({\n\t\t\t\tkind: \"bash\",\n\t\t\t\ttitle: `${config.label}: ${command}`,\n\t\t\t\ttoolCallId,\n\t\t\t\tcommand,\n\t\t\t\tcwd: ctx?.cwd || cwd,\n\t\t\t\tbackground,\n\t\t\t\tsignal: parentSignal,\n\t\t\t\tonUpdate: originalUpdate,\n\t\t\t\trun: (control) => run({ host, control }),\n\t\t\t});\n\t\t\tif (outcome.kind === \"result\") return shellToolResult(outcome, true);\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `Command handed to background. Task ID: ${outcome.task.id}. Status: ${outcome.task.status}. Its completion will be delivered automatically; use bg read to inspect output, bg wait to block until it settles, or bg kill to stop it.${outcome.task.outputPath ? `\\nFull output: ${outcome.task.outputPath}` : \"\"}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: {\n\t\t\t\t\tbackground: { kind: \"background\", taskId: outcome.task.id },\n\t\t\t\t\tfullOutputPath: outcome.task.outputPath,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t...createShellRenderers(config),\n\t};\n}\n\nconst bashToolConfig: ShellToolConfig = {\n\tname: \"bash\",\n\tlabel: \"bash\",\n\tshellName: \"bash\",\n\tprompt: \"$\",\n\tpromptSnippet: bashToolSystemPromptContribution.snippet,\n\tpromptGuidelines: bashToolSystemPromptContribution.guidelines,\n\ttempFilePrefix: \"pi-bash\",\n};\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\treturn createShellToolDefinition(cwd, bashToolConfig, options);\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\tconst definition = createBashToolDefinition(cwd, options);\n\tconst tool = wrapToolDefinition(definition);\n\tObject.assign(tool, {\n\t\tpromptSnippet: definition.promptSnippet,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t});\n\treturn tool;\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 } from \"node:fs/promises\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellConfig,\n\tgetShellEnv,\n\tkillProcessTree,\n\trewriteCmdNulRedirects,\n\ttype ShellConfig,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport { type BackgroundCompletion, BackgroundExecutionError } from \"../background/types.ts\";\nimport { getExperimentalToolSampling } from \"../experimental.ts\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport { createShellRenderers } from \"./renderers/bash.ts\";\nimport { type ManagedShellExecution, runShellCommand } from \"./shell-execution.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult } from \"./truncate.ts\";\n\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\n\nfunction resolveTimeoutMs(timeout: number | undefined): number | undefined {\n\tif (timeout === undefined) return undefined;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\n\tconst timeoutMs = timeout * 1000;\n\tif (timeoutMs > MAX_TIMEOUT_MS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n\treturn timeoutMs;\n}\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Shell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"true returns a managed task ID immediately and runs the command in the background; omit or false to block until exit\",\n\t\t}),\n\t),\n});\n\nexport const bashToolSystemPromptContribution = {\n\tsnippet: \"Execute bash commands, foreground or background\",\n\tguidelines: [\"You can inspect PI_* environment variables for current model and session details.\"],\n} as const;\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\t/** Settled handoff snapshot, not a command completion or exit code. */\n\tbackground?: { kind: \"background\"; taskId: 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\t * Error contract: reject with `new Error(\"aborted\")` when aborted via `signal`,\n\t * and `new Error(\"timeout:<seconds>\")` on timeout expiry. The shared shell\n\t * execution pipeline classifies outcomes from these exact markers.\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/** Shared process execution used by the built-in shell tools. */\nexport function createLocalShellOperations(\n\tshellName: string,\n\tresolveShellConfig: () => ShellConfig,\n\tnormalizeCommand: (command: string) => string = (command) => command,\n): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst timeoutMs = resolveTimeoutMs(timeout);\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\t\t\tconst shellConfig = resolveShellConfig();\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 ${shellName} commands.`);\n\t\t\t}\n\n\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst normalizedCommand = normalizeCommand(command);\n\t\t\tconst child = spawn(\n\t\t\t\tshellConfig.shell,\n\t\t\t\tcommandFromStdin ? shellConfig.args : [...shellConfig.args, normalizedCommand],\n\t\t\t\t{\n\t\t\t\t\tcwd,\n\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\twindowsHide: true,\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(normalizedCommand);\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 (timeoutMs !== undefined) {\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}, timeoutMs);\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\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 normalizeLocalBashCommand(command: string, platform: NodeJS.Platform = process.platform): string {\n\treturn platform === \"win32\" ? rewriteCmdNulRedirects(command) : command;\n}\n\nexport function createLocalBashOperations(options?: { shellPath?: string }): BashOperations {\n\treturn createLocalShellOperations(\"bash\", () => getShellConfig(options?.shellPath), normalizeLocalBashCommand);\n}\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nexport function resolveSpawnContext(\n\tcommand: string,\n\tcwd: string,\n\tspawnHook: BashSpawnHook | undefined,\n\texposeSessionEnvironment: boolean,\n\tctx: ExtensionContext | undefined,\n): BashSpawnContext {\n\tconst env = { ...getShellEnv() };\n\tdelete env.PI_SESSION_ID;\n\tdelete env.PI_SESSION_FILE;\n\tdelete env.PI_PROVIDER;\n\tdelete env.PI_MODEL;\n\tdelete env.PI_REASONING_LEVEL;\n\tif (exposeSessionEnvironment && ctx) {\n\t\tconst model = ctx.model;\n\t\tenv.PI_SESSION_ID = ctx.sessionManager.getSessionId();\n\t\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\t\tif (sessionFile) env.PI_SESSION_FILE = sessionFile;\n\t\tif (model) {\n\t\t\tenv.PI_PROVIDER = model.provider;\n\t\t\tenv.PI_MODEL = model.id;\n\t\t}\n\t\tif (ctx.thinkingLevel) env.PI_REASONING_LEVEL = ctx.thinkingLevel;\n\t}\n\tconst baseContext: BashSpawnContext = { command, cwd, env };\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/** Expose current Pi session metadata as PI_* environment variables. Default: true */\n\texposeSessionEnvironment?: boolean;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n}\n\nexport type BashRenderState = {\n\tstartedAt: number | undefined;\n\tendedAt: number | undefined;\n\tinterval: NodeJS.Timeout | undefined;\n};\n\nexport interface ShellToolConfig {\n\tname: string;\n\tlabel: string;\n\tshellName: string;\n\tprompt: string;\n\tpromptSnippet: string;\n\tpromptGuidelines?: readonly string[];\n\ttempFilePrefix: string;\n}\n\n/** Translate terminal shell failures to the native foreground tool contract once. */\nfunction shellToolResult(completion: BackgroundCompletion<BashToolDetails | undefined>, managed: boolean) {\n\tconst status = completion.status;\n\tif (status === \"failed\" || status === \"timeout\" || status === \"cancelled\") {\n\t\tconst text = completion.result.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\\n\");\n\t\tconst message = completion.error ? text || completion.error : `${text ? `${text}\\n\\n` : \"\"}Command ${status}`;\n\t\tthrow managed ? new BackgroundExecutionError(message, status) : new Error(message);\n\t}\n\treturn completion.result;\n}\n\nexport function createShellToolDefinition(\n\tcwd: string,\n\tconfig: ShellToolConfig,\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 exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\treturn {\n\t\tname: config.name,\n\t\tlabel: config.label,\n\t\tdescription: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr, truncated to the last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first); the full output is saved to a temp file. Optionally provide a timeout in seconds (no default). Choose the mode per call: foreground (default) blocks until the command exits — use it when your next step needs the output; background: true returns immediately with a task ID — use it for long-running work (builds, servers, watchers, big test suites) or when you have independent work to continue. A handoff is not completion: the result arrives later as an automatic completion notification; meanwhile use bg read to inspect output, bg wait to block until it settles, bg kill to stop it. Background output is limited to 20 MiB; an expired bg wait window never stops the command.`,\n\t\tpromptSnippet: config.promptSnippet,\n\t\tpromptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,\n\t\tparameters: bashSchema,\n\t\tconstrainedSampling: getExperimentalToolSampling(),\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{ command, timeout, background }: BashToolInput,\n\t\t\tparentSignal?: AbortSignal,\n\t\t\toriginalUpdate?,\n\t\t\tctx?: ExtensionContext,\n\t\t) {\n\t\t\tconst host = ctx?.background;\n\t\t\tif (host?.closed) throw new Error(\"Background service is closed\");\n\t\t\tconst run = async (\n\t\t\t\tmanaged?: ManagedShellExecution,\n\t\t\t): Promise<BackgroundCompletion<BashToolDetails | undefined>> => {\n\t\t\t\tconst signal = managed?.control.signal ?? parentSignal;\n\t\t\t\ttry {\n\t\t\t\t\tif (managed) {\n\t\t\t\t\t\tif (signal?.aborted) throw new Error(\"Command aborted\");\n\t\t\t\t\t\tresolveTimeoutMs(timeout);\n\t\t\t\t\t}\n\t\t\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\t\t\tconst spawnContext = resolveSpawnContext(\n\t\t\t\t\t\tresolvedCommand,\n\t\t\t\t\t\tctx?.cwd || cwd,\n\t\t\t\t\t\tspawnHook,\n\t\t\t\t\t\texposeSessionEnvironment,\n\t\t\t\t\t\tctx,\n\t\t\t\t\t);\n\t\t\t\t\treturn await runShellCommand({\n\t\t\t\t\t\toperations: ops,\n\t\t\t\t\t\tshellName: config.shellName,\n\t\t\t\t\t\tcontext: spawnContext,\n\t\t\t\t\t\ttempFilePrefix: config.tempFilePrefix,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tonUpdate: originalUpdate,\n\t\t\t\t\t\tmanaged,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Setup and cleanup exceptions carry an explicit terminal status.\n\t\t\t\t\tif (!managed) throw error;\n\t\t\t\t\tthrow new BackgroundExecutionError(\n\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t\t\tmanaged.control.signal.aborted ? \"cancelled\" : \"failed\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (!host || (!host.enabled && !background)) {\n\t\t\t\tif (background)\n\t\t\t\t\tthrow new Error(\"Background execution is not available in this host. No command was started.\");\n\t\t\t\treturn shellToolResult(await run(), false);\n\t\t\t}\n\t\t\tconst outcome = await host.execute<BashToolDetails | undefined>({\n\t\t\t\tkind: \"bash\",\n\t\t\t\ttitle: `${config.label}: ${command}`,\n\t\t\t\ttoolCallId,\n\t\t\t\tcommand,\n\t\t\t\tcwd: ctx?.cwd || cwd,\n\t\t\t\tbackground,\n\t\t\t\tsignal: parentSignal,\n\t\t\t\tonUpdate: originalUpdate,\n\t\t\t\trun: (control) => run({ host, control }),\n\t\t\t});\n\t\t\tif (outcome.kind === \"result\") return shellToolResult(outcome, true);\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `Command handed to background. Task ID: ${outcome.task.id}. Status: ${outcome.task.status}. Completion arrives automatically as a notification — do not poll or immediately wait on it; continue with other work or hand back to the user. Use bg read to inspect output, bg wait only when your next step is blocked on the result (prefer foreground next time in that case), or bg kill to stop it.${outcome.task.outputPath ? `\\nFull output: ${outcome.task.outputPath}` : \"\"}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: {\n\t\t\t\t\tbackground: { kind: \"background\", taskId: outcome.task.id },\n\t\t\t\t\tfullOutputPath: outcome.task.outputPath,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t...createShellRenderers(config),\n\t};\n}\n\nconst bashToolConfig: ShellToolConfig = {\n\tname: \"bash\",\n\tlabel: \"bash\",\n\tshellName: \"bash\",\n\tprompt: \"$\",\n\tpromptSnippet: bashToolSystemPromptContribution.snippet,\n\tpromptGuidelines: bashToolSystemPromptContribution.guidelines,\n\ttempFilePrefix: \"pi-bash\",\n};\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\treturn createShellToolDefinition(cwd, bashToolConfig, options);\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {\n\tconst definition = createBashToolDefinition(cwd, options);\n\tconst tool = wrapToolDefinition(definition);\n\tObject.assign(tool, {\n\t\tpromptSnippet: definition.promptSnippet,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t});\n\treturn tool;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-execution.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-execution.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AACzG,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAKnF,eAAO,MAAM,2BAA2B,QAAmB,CAAC;AAE5D,MAAM,WAAW,qBAAqB;IACrC,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,iBAAiB,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;CACxD;AAED,UAAU,qBAAqB;IAC9B,UAAU,EAAE,cAAc,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,CAAC,eAAe,GAAG,SAAS,CAAC,KAAK,IAAI,CAAC;IAC1E,OAAO,CAAC,EAAE,qBAAqB,CAAC;CAChC;AAwCD,6EAA6E;AAC7E,wBAAsB,eAAe,CACpC,OAAO,EAAE,qBAAqB,GAC5B,OAAO,CAAC,oBAAoB,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"shell-execution.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-execution.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AACzG,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAKnF,eAAO,MAAM,2BAA2B,QAAmB,CAAC;AAE5D,MAAM,WAAW,qBAAqB;IACrC,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,iBAAiB,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;CACxD;AAED,UAAU,qBAAqB;IAC9B,UAAU,EAAE,cAAc,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,CAAC,eAAe,GAAG,SAAS,CAAC,KAAK,IAAI,CAAC;IAC1E,OAAO,CAAC,EAAE,qBAAqB,CAAC;CAChC;AAwCD,6EAA6E;AAC7E,wBAAsB,eAAe,CACpC,OAAO,EAAE,qBAAqB,GAC5B,OAAO,CAAC,oBAAoB,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC,CA4J5D"}
|
|
@@ -156,6 +156,7 @@ export async function runShellCommand(options) {
|
|
|
156
156
|
}
|
|
157
157
|
publish();
|
|
158
158
|
let failure;
|
|
159
|
+
let exitCode;
|
|
159
160
|
try {
|
|
160
161
|
if (signal?.aborted)
|
|
161
162
|
throw new Error("aborted");
|
|
@@ -166,7 +167,7 @@ export async function runShellCommand(options) {
|
|
|
166
167
|
env: context.env,
|
|
167
168
|
});
|
|
168
169
|
managed?.control.accept();
|
|
169
|
-
|
|
170
|
+
({ exitCode } = await execution);
|
|
170
171
|
if (exitCode === null && managed) {
|
|
171
172
|
failure = { status: "failed", error: "Command terminated without an exit code" };
|
|
172
173
|
}
|
|
@@ -194,6 +195,7 @@ export async function runShellCommand(options) {
|
|
|
194
195
|
return {
|
|
195
196
|
status: failure?.status,
|
|
196
197
|
error: failure?.error,
|
|
198
|
+
...(exitCode !== undefined ? { exitCode } : {}),
|
|
197
199
|
result: {
|
|
198
200
|
content: [{ type: "text", text: failure ? `${text ? `${text}\n\n` : ""}${failure.error}` : text }],
|
|
199
201
|
details,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-execution.js","sourceRoot":"","sources":["../../../src/core/tools/shell-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGpD,OAAO,EAAE,iBAAiB,EAAuB,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEzD,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAuB5D,4FAA4F;AAC5F,SAAS,YAAY,CAAC,KAAc;IACnC,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;IACpH,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;QACjE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,2BAA2B,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;IACvG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;AAC7G,CAAC;AAED,SAAS,YAAY,CACpB,MAAyB,EACzB,QAAwB,EACxB,OAAgB,EAChB,SAAiB;IAEjB,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;IACvC,IAAI,IAAI,GAAG,QAAQ,CAAC,OAAO,IAAI,SAAS,CAAC;IACzC,IAAI,OAAO,GAAgC,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7G,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;QAC1B,OAAO,GAAG,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC;QAClE,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,GAAG,UAAU,CAAC,WAAW,GAAG,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC;QACtC,IAAI,UAAU,CAAC,eAAe,EAAE,CAAC;YAChC,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;YAC3D,IAAI,IAAI,qBAAqB,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,YAAY,OAAO,aAAa,YAAY,mBAAmB,QAAQ,CAAC,cAAc,GAAG,CAAC;QAC1J,CAAC;aAAM,IAAI,UAAU,CAAC,WAAW,KAAK,OAAO,EAAE,CAAC;YAC/C,IAAI,IAAI,sBAAsB,SAAS,IAAI,OAAO,OAAO,UAAU,CAAC,UAAU,kBAAkB,QAAQ,CAAC,cAAc,GAAG,CAAC;QAC5H,CAAC;aAAM,CAAC;YACP,IAAI,IAAI,sBAAsB,SAAS,IAAI,OAAO,OAAO,UAAU,CAAC,UAAU,KAAK,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,yBAAyB,QAAQ,CAAC,cAAc,GAAG,CAAC;QACvK,CAAC;IACF,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC1B,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,OAA8B;IAE9B,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9G,IAAI,WAA8B,CAAC;IACnC,IAAI,eAAe,GAAG,IAAI,CAAC;IAC3B,IAAI,WAAqC,CAAC;IAC1C,IAAI,WAAuC,CAAC;IAC5C,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,MAAM,UAAU,GAAG,CAAC,KAAc,EAAE,EAAE;QACrC,IAAI,WAAW;YAAE,OAAO;QACxB,WAAW,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC;YACJ,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACR,uDAAuD;QACxD,CAAC;IACF,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,aAAa,EAAE,GAAG,2BAA2B,EAAE,CAAC;YACpG,UAAU,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAC9E,CAAC;IACF,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,GAAG,EAAE,CACrB,MAAM,CAAC,QAAQ,CAAC;QACf,kBAAkB,EAAE,IAAI;QACxB,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS;KACxE,CAAC,CAAC;IACJ,MAAM,OAAO,GAAG,CAAC,QAAyB,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAiD;YAC5D,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;YACnE,OAAO,EAAE,QAAQ;gBAChB,CAAC,CAAC;oBACA,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;oBAC3E,cAAc,EAAE,QAAQ,CAAC,cAAc;iBACvC;gBACF,CAAC,CAAC,SAAS;SACZ,CAAC;QACF,IAAI,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE;gBAC/B,IAAI,EAAE,YAAY,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,OAAO;gBAC5E,KAAK,EAAE;oBACN,IAAI,EAAE,OAAO,CAAC,SAAS;oBACvB,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,SAAS,IAAI,KAAK,EAAE;iBAC7F;aACD,CAAC,CAAC;QACJ,CAAC;;YAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAC5D,WAAW,GAAG,KAAK,CAAC;QACpB,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1B,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrB,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,WAAW;YAAE,YAAY,CAAC,WAAW,CAAC,CAAC;QAC3C,WAAW,GAAG,SAAS,CAAC;IACzB,CAAC,CAAC;IACF,MAAM,oBAAoB,GAAG,GAAG,EAAE;QACjC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,OAAO;QAC1C,WAAW,GAAG,IAAI,CAAC;QACnB,MAAM,KAAK,GAAG,uBAAuB,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC,CAAC;QACpE,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YAChB,gBAAgB,EAAE,CAAC;YACnB,gBAAgB,EAAE,CAAC;QACpB,CAAC;aAAM,CAAC;YACP,WAAW,KAAK,UAAU,CAAC,GAAG,EAAE;gBAC/B,WAAW,GAAG,SAAS,CAAC;gBACxB,gBAAgB,EAAE,CAAC;YACpB,CAAC,EAAE,KAAK,CAAC,CAAC;QACX,CAAC;IACF,CAAC,CAAC;IACF,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;QACnC,IAAI,CAAC,eAAe,IAAI,WAAW;YAAE,OAAO;QAC5C,IAAI,CAAC;YACJ,IACC,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,YAAY;gBACtC,MAAM,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,2BAA2B,EACjE,CAAC;gBACF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,2BAA2B,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;gBACpF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;gBAC3C,UAAU,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;YAC9E,CAAC;;gBAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3B,oBAAoB,EAAE,CAAC;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO;gBAAE,MAAM,KAAK,CAAC;YAC1B,UAAU,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACF,CAAC,CAAC;IAEF,IAAI,CAAC;QACJ,IAAI,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,cAAe,CAAC;YAC/C,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;gBAC1B,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;gBAC7B,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAA4B,EAAE,EAAE;oBACzD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;wBAAE,MAAM,KAAK,CAAC;gBAC1C,CAAC,CAAC,CAAC;YACJ,CAAC,CAAC;YACF,IAAI,CAAC;gBACJ,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC9C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,MAAM,OAAO,EAAE,CAAC;gBAChB,MAAM,KAAK,CAAC;YACb,CAAC;YACD,mFAAmF;YACnF,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,EAAE,CAAC;QACV,IAAI,OAAiC,CAAC;QACtC,IAAI,CAAC;YACJ,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;YAChD,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE;gBAC/D,MAAM,EAAE,UAAU;gBAClB,MAAM;gBACN,OAAO;gBACP,GAAG,EAAE,OAAO,CAAC,GAAG;aAChB,CAAC,CAAC;YACH,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YAC1B,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,SAAS,CAAC;YACrC,IAAI,QAAQ,KAAK,IAAI,IAAI,OAAO,EAAE,CAAC;gBAClC,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,yCAAyC,EAAE,CAAC;YAClF,CAAC;iBAAM,IAAI,QAAQ,KAAK,CAAC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBAChD,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,4BAA4B,QAAQ,EAAE,EAAE,CAAC;YAC/E,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,eAAe,GAAG,KAAK,CAAC;QACxB,MAAM,CAAC,MAAM,EAAE,CAAC;QAChB,gBAAgB,EAAE,CAAC;QACnB,IAAI,OAAO;YAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;;YAC5B,gBAAgB,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;QAC7B,4EAA4E;QAC5E,sEAAsE;QACtE,IAAI,WAAW;YAAE,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QAC7F,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAC/F,OAAO;YACN,MAAM,EAAE,OAAO,EAAE,MAAM;YACvB,KAAK,EAAE,OAAO,EAAE,KAAK;YACrB,MAAM,EAAE;gBACP,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAClG,OAAO;aACP;SACD,CAAC;IACH,CAAC;YAAS,CAAC;QACV,eAAe,GAAG,KAAK,CAAC;QACxB,WAAW,EAAE,EAAE,CAAC;QAChB,gBAAgB,EAAE,CAAC;QACnB,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;IAC9B,CAAC;AACF,CAAC","sourcesContent":["import { unlink } from \"node:fs/promises\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport { boundText } from \"../background/output.ts\";\nimport type { BackgroundCompletion, BackgroundContext, BackgroundControl } from \"../background/types.ts\";\nimport type { BashOperations, BashSpawnContext, BashToolDetails } from \"./bash.ts\";\nimport { OutputAccumulator, type OutputSnapshot } from \"./output-accumulator.ts\";\nimport { BASH_UPDATE_THROTTLE_MS } from \"./renderers/bash.ts\";\nimport { formatSize, truncateTail } from \"./truncate.ts\";\n\nexport const MAX_BACKGROUND_OUTPUT_BYTES = 20 * 1024 * 1024;\n\nexport interface ManagedShellExecution {\n\thost: BackgroundContext;\n\tcontrol: BackgroundControl<BashToolDetails | undefined>;\n}\n\ninterface ShellExecutionOptions {\n\toperations: BashOperations;\n\tshellName: string;\n\tcontext: BashSpawnContext;\n\ttempFilePrefix: string;\n\ttimeout?: number;\n\tsignal?: AbortSignal;\n\tonUpdate?: (result: AgentToolResult<BashToolDetails | undefined>) => void;\n\tmanaged?: ManagedShellExecution;\n}\n\ninterface ShellFailure {\n\tstatus: \"failed\" | \"cancelled\" | \"timeout\";\n\terror: string;\n}\n\n/** Interpret the documented BashOperations error markers once, before formatting output. */\nfunction shellFailure(error: unknown): ShellFailure {\n\tif (error instanceof Error && error.message === \"aborted\") return { status: \"cancelled\", error: \"Command aborted\" };\n\tif (error instanceof Error && error.message.startsWith(\"timeout:\"))\n\t\treturn { status: \"timeout\", error: `Command timed out after ${error.message.split(\":\")[1]} seconds` };\n\treturn { status: \"failed\", error: boundText(error instanceof Error ? error.message : String(error), 4096) };\n}\n\nfunction formatOutput(\n\toutput: OutputAccumulator,\n\tsnapshot: OutputSnapshot,\n\tmanaged: boolean,\n\temptyText: string,\n): { text: string; details: BashToolDetails | undefined } {\n\tconst truncation = snapshot.truncation;\n\tlet text = snapshot.content || emptyText;\n\tlet details: BashToolDetails | undefined = managed ? { fullOutputPath: snapshot.fullOutputPath } : undefined;\n\tif (truncation.truncated) {\n\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\tconst endLine = truncation.totalLines;\n\t\tif (truncation.lastLinePartial) {\n\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(truncation.maxBytes)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t}\n\t}\n\treturn { text, details };\n}\n\n/** One process and one output owner across foreground/background handoff. */\nexport async function runShellCommand(\n\toptions: ShellExecutionOptions,\n): Promise<BackgroundCompletion<BashToolDetails | undefined>> {\n\tconst { operations, context, managed, signal, timeout } = options;\n\tconst output = new OutputAccumulator({ tempFilePrefix: options.tempFilePrefix, persistFromStart: !!managed });\n\tlet outputError: Error | undefined;\n\tlet acceptingOutput = true;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet updateTimer: NodeJS.Timeout | undefined;\n\tlet updateDirty = false;\n\tlet lastUpdateAt = 0;\n\n\tconst failOutput = (error: unknown) => {\n\t\tif (outputError) return;\n\t\toutputError = error instanceof Error ? error : new Error(String(error));\n\t\ttry {\n\t\t\tif (managed) managed.host.kill(managed.control.id);\n\t\t} catch {\n\t\t\t// Late data must not throw through a process observer.\n\t\t}\n\t};\n\tconst checkOutputLimit = () => {\n\t\tif (managed?.control.mode === \"background\" && output.getTotalBytes() > MAX_BACKGROUND_OUTPUT_BYTES) {\n\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t}\n\t};\n\tconst snapshot = () =>\n\t\toutput.snapshot({\n\t\t\tpersistIfTruncated: true,\n\t\t\tmaxBytes: managed?.control.mode === \"background\" ? 40 * 1024 : undefined,\n\t\t});\n\tconst publish = (snapshot?: OutputSnapshot) => {\n\t\tconst result: AgentToolResult<BashToolDetails | undefined> = {\n\t\t\tcontent: snapshot ? [{ type: \"text\", text: snapshot.content }] : [],\n\t\t\tdetails: snapshot\n\t\t\t\t? {\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: undefined,\n\t\t};\n\t\tif (managed) {\n\t\t\tmanaged.control.publish(result, {\n\t\t\t\ttext: truncateTail(snapshot?.content ?? \"\", { maxBytes: 16 * 1024 }).content,\n\t\t\t\tshell: {\n\t\t\t\t\tname: options.shellName,\n\t\t\t\t\toutput: { text: snapshot?.content ?? \"\", truncated: snapshot?.truncation.truncated ?? false },\n\t\t\t\t},\n\t\t\t});\n\t\t} else options.onUpdate?.(result);\n\t};\n\tconst emitOutputUpdate = () => {\n\t\tif ((!managed && !options.onUpdate) || !updateDirty) return;\n\t\tupdateDirty = false;\n\t\tlastUpdateAt = Date.now();\n\t\tpublish(snapshot());\n\t};\n\tconst clearUpdateTimer = () => {\n\t\tif (updateTimer) clearTimeout(updateTimer);\n\t\tupdateTimer = undefined;\n\t};\n\tconst scheduleOutputUpdate = () => {\n\t\tif (!managed && !options.onUpdate) return;\n\t\tupdateDirty = true;\n\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\tif (delay <= 0) {\n\t\t\tclearUpdateTimer();\n\t\t\temitOutputUpdate();\n\t\t} else {\n\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\tupdateTimer = undefined;\n\t\t\t\temitOutputUpdate();\n\t\t\t}, delay);\n\t\t}\n\t};\n\tconst handleData = (data: Buffer) => {\n\t\tif (!acceptingOutput || outputError) return;\n\t\ttry {\n\t\t\tif (\n\t\t\t\tmanaged?.control.mode === \"background\" &&\n\t\t\t\toutput.getTotalBytes() + data.length > MAX_BACKGROUND_OUTPUT_BYTES\n\t\t\t) {\n\t\t\t\tconst remaining = Math.max(0, MAX_BACKGROUND_OUTPUT_BYTES - output.getTotalBytes());\n\t\t\t\toutput.append(data.subarray(0, remaining));\n\t\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t\t} else output.append(data);\n\t\t\tscheduleOutputUpdate();\n\t\t} catch (error) {\n\t\t\tif (!managed) throw error;\n\t\t\tfailOutput(error);\n\t\t}\n\t};\n\n\ttry {\n\t\tif (managed) {\n\t\t\tconst path = output.snapshot().fullOutputPath!;\n\t\t\tconst cleanup = async () => {\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\tawait unlink(path).catch((error: NodeJS.ErrnoException) => {\n\t\t\t\t\tif (error.code !== \"ENOENT\") throw error;\n\t\t\t\t});\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tmanaged.control.setOutputPath(path, cleanup);\n\t\t\t} catch (error) {\n\t\t\t\tawait cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\t// Detach must check a silent foreground log too, preserving bytes already written.\n\t\t\tunsubscribe = managed.host.subscribe(checkOutputLimit);\n\t\t}\n\t\tpublish();\n\t\tlet failure: ShellFailure | undefined;\n\t\ttry {\n\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\t\t\tconst execution = operations.exec(context.command, context.cwd, {\n\t\t\t\tonData: handleData,\n\t\t\t\tsignal,\n\t\t\t\ttimeout,\n\t\t\t\tenv: context.env,\n\t\t\t});\n\t\t\tmanaged?.control.accept();\n\t\t\tconst { exitCode } = await execution;\n\t\t\tif (exitCode === null && managed) {\n\t\t\t\tfailure = { status: \"failed\", error: \"Command terminated without an exit code\" };\n\t\t\t} else if (exitCode !== 0 && exitCode !== null) {\n\t\t\t\tfailure = { status: \"failed\", error: `Command exited with code ${exitCode}` };\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfailure = shellFailure(error);\n\t\t}\n\t\tacceptingOutput = false;\n\t\toutput.finish();\n\t\tclearUpdateTimer();\n\t\tif (managed) publish(snapshot());\n\t\telse emitOutputUpdate();\n\t\tconst final = snapshot();\n\t\tawait output.closeTempFile();\n\t\t// Final progress/cleanup can re-enter handoff. Classify policy cancellation\n\t\t// after those callbacks, independently of the process's abort marker.\n\t\tif (outputError) failure = { status: \"failed\", error: boundText(outputError.message, 4096) };\n\t\tconst { text, details } = formatOutput(output, final, !!managed, failure ? \"\" : \"(no output)\");\n\t\treturn {\n\t\t\tstatus: failure?.status,\n\t\t\terror: failure?.error,\n\t\t\tresult: {\n\t\t\t\tcontent: [{ type: \"text\", text: failure ? `${text ? `${text}\\n\\n` : \"\"}${failure.error}` : text }],\n\t\t\t\tdetails,\n\t\t\t},\n\t\t};\n\t} finally {\n\t\tacceptingOutput = false;\n\t\tunsubscribe?.();\n\t\tclearUpdateTimer();\n\t\tawait output.closeTempFile();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"shell-execution.js","sourceRoot":"","sources":["../../../src/core/tools/shell-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import { unlink } from \"node:fs/promises\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport { boundText } from \"../background/output.ts\";\nimport type { BackgroundCompletion, BackgroundContext, BackgroundControl } from \"../background/types.ts\";\nimport type { BashOperations, BashSpawnContext, BashToolDetails } from \"./bash.ts\";\nimport { OutputAccumulator, type OutputSnapshot } from \"./output-accumulator.ts\";\nimport { BASH_UPDATE_THROTTLE_MS } from \"./renderers/bash.ts\";\nimport { formatSize, truncateTail } from \"./truncate.ts\";\n\nexport const MAX_BACKGROUND_OUTPUT_BYTES = 20 * 1024 * 1024;\n\nexport interface ManagedShellExecution {\n\thost: BackgroundContext;\n\tcontrol: BackgroundControl<BashToolDetails | undefined>;\n}\n\ninterface ShellExecutionOptions {\n\toperations: BashOperations;\n\tshellName: string;\n\tcontext: BashSpawnContext;\n\ttempFilePrefix: string;\n\ttimeout?: number;\n\tsignal?: AbortSignal;\n\tonUpdate?: (result: AgentToolResult<BashToolDetails | undefined>) => void;\n\tmanaged?: ManagedShellExecution;\n}\n\ninterface ShellFailure {\n\tstatus: \"failed\" | \"cancelled\" | \"timeout\";\n\terror: string;\n}\n\n/** Interpret the documented BashOperations error markers once, before formatting output. */\nfunction shellFailure(error: unknown): ShellFailure {\n\tif (error instanceof Error && error.message === \"aborted\") return { status: \"cancelled\", error: \"Command aborted\" };\n\tif (error instanceof Error && error.message.startsWith(\"timeout:\"))\n\t\treturn { status: \"timeout\", error: `Command timed out after ${error.message.split(\":\")[1]} seconds` };\n\treturn { status: \"failed\", error: boundText(error instanceof Error ? error.message : String(error), 4096) };\n}\n\nfunction formatOutput(\n\toutput: OutputAccumulator,\n\tsnapshot: OutputSnapshot,\n\tmanaged: boolean,\n\temptyText: string,\n): { text: string; details: BashToolDetails | undefined } {\n\tconst truncation = snapshot.truncation;\n\tlet text = snapshot.content || emptyText;\n\tlet details: BashToolDetails | undefined = managed ? { fullOutputPath: snapshot.fullOutputPath } : undefined;\n\tif (truncation.truncated) {\n\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\tconst endLine = truncation.totalLines;\n\t\tif (truncation.lastLinePartial) {\n\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(truncation.maxBytes)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t}\n\t}\n\treturn { text, details };\n}\n\n/** One process and one output owner across foreground/background handoff. */\nexport async function runShellCommand(\n\toptions: ShellExecutionOptions,\n): Promise<BackgroundCompletion<BashToolDetails | undefined>> {\n\tconst { operations, context, managed, signal, timeout } = options;\n\tconst output = new OutputAccumulator({ tempFilePrefix: options.tempFilePrefix, persistFromStart: !!managed });\n\tlet outputError: Error | undefined;\n\tlet acceptingOutput = true;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet updateTimer: NodeJS.Timeout | undefined;\n\tlet updateDirty = false;\n\tlet lastUpdateAt = 0;\n\n\tconst failOutput = (error: unknown) => {\n\t\tif (outputError) return;\n\t\toutputError = error instanceof Error ? error : new Error(String(error));\n\t\ttry {\n\t\t\tif (managed) managed.host.kill(managed.control.id);\n\t\t} catch {\n\t\t\t// Late data must not throw through a process observer.\n\t\t}\n\t};\n\tconst checkOutputLimit = () => {\n\t\tif (managed?.control.mode === \"background\" && output.getTotalBytes() > MAX_BACKGROUND_OUTPUT_BYTES) {\n\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t}\n\t};\n\tconst snapshot = () =>\n\t\toutput.snapshot({\n\t\t\tpersistIfTruncated: true,\n\t\t\tmaxBytes: managed?.control.mode === \"background\" ? 40 * 1024 : undefined,\n\t\t});\n\tconst publish = (snapshot?: OutputSnapshot) => {\n\t\tconst result: AgentToolResult<BashToolDetails | undefined> = {\n\t\t\tcontent: snapshot ? [{ type: \"text\", text: snapshot.content }] : [],\n\t\t\tdetails: snapshot\n\t\t\t\t? {\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: undefined,\n\t\t};\n\t\tif (managed) {\n\t\t\tmanaged.control.publish(result, {\n\t\t\t\ttext: truncateTail(snapshot?.content ?? \"\", { maxBytes: 16 * 1024 }).content,\n\t\t\t\tshell: {\n\t\t\t\t\tname: options.shellName,\n\t\t\t\t\toutput: { text: snapshot?.content ?? \"\", truncated: snapshot?.truncation.truncated ?? false },\n\t\t\t\t},\n\t\t\t});\n\t\t} else options.onUpdate?.(result);\n\t};\n\tconst emitOutputUpdate = () => {\n\t\tif ((!managed && !options.onUpdate) || !updateDirty) return;\n\t\tupdateDirty = false;\n\t\tlastUpdateAt = Date.now();\n\t\tpublish(snapshot());\n\t};\n\tconst clearUpdateTimer = () => {\n\t\tif (updateTimer) clearTimeout(updateTimer);\n\t\tupdateTimer = undefined;\n\t};\n\tconst scheduleOutputUpdate = () => {\n\t\tif (!managed && !options.onUpdate) return;\n\t\tupdateDirty = true;\n\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\tif (delay <= 0) {\n\t\t\tclearUpdateTimer();\n\t\t\temitOutputUpdate();\n\t\t} else {\n\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\tupdateTimer = undefined;\n\t\t\t\temitOutputUpdate();\n\t\t\t}, delay);\n\t\t}\n\t};\n\tconst handleData = (data: Buffer) => {\n\t\tif (!acceptingOutput || outputError) return;\n\t\ttry {\n\t\t\tif (\n\t\t\t\tmanaged?.control.mode === \"background\" &&\n\t\t\t\toutput.getTotalBytes() + data.length > MAX_BACKGROUND_OUTPUT_BYTES\n\t\t\t) {\n\t\t\t\tconst remaining = Math.max(0, MAX_BACKGROUND_OUTPUT_BYTES - output.getTotalBytes());\n\t\t\t\toutput.append(data.subarray(0, remaining));\n\t\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t\t} else output.append(data);\n\t\t\tscheduleOutputUpdate();\n\t\t} catch (error) {\n\t\t\tif (!managed) throw error;\n\t\t\tfailOutput(error);\n\t\t}\n\t};\n\n\ttry {\n\t\tif (managed) {\n\t\t\tconst path = output.snapshot().fullOutputPath!;\n\t\t\tconst cleanup = async () => {\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\tawait unlink(path).catch((error: NodeJS.ErrnoException) => {\n\t\t\t\t\tif (error.code !== \"ENOENT\") throw error;\n\t\t\t\t});\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tmanaged.control.setOutputPath(path, cleanup);\n\t\t\t} catch (error) {\n\t\t\t\tawait cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\t// Detach must check a silent foreground log too, preserving bytes already written.\n\t\t\tunsubscribe = managed.host.subscribe(checkOutputLimit);\n\t\t}\n\t\tpublish();\n\t\tlet failure: ShellFailure | undefined;\n\t\tlet exitCode: number | null | undefined;\n\t\ttry {\n\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\t\t\tconst execution = operations.exec(context.command, context.cwd, {\n\t\t\t\tonData: handleData,\n\t\t\t\tsignal,\n\t\t\t\ttimeout,\n\t\t\t\tenv: context.env,\n\t\t\t});\n\t\t\tmanaged?.control.accept();\n\t\t\t({ exitCode } = await execution);\n\t\t\tif (exitCode === null && managed) {\n\t\t\t\tfailure = { status: \"failed\", error: \"Command terminated without an exit code\" };\n\t\t\t} else if (exitCode !== 0 && exitCode !== null) {\n\t\t\t\tfailure = { status: \"failed\", error: `Command exited with code ${exitCode}` };\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfailure = shellFailure(error);\n\t\t}\n\t\tacceptingOutput = false;\n\t\toutput.finish();\n\t\tclearUpdateTimer();\n\t\tif (managed) publish(snapshot());\n\t\telse emitOutputUpdate();\n\t\tconst final = snapshot();\n\t\tawait output.closeTempFile();\n\t\t// Final progress/cleanup can re-enter handoff. Classify policy cancellation\n\t\t// after those callbacks, independently of the process's abort marker.\n\t\tif (outputError) failure = { status: \"failed\", error: boundText(outputError.message, 4096) };\n\t\tconst { text, details } = formatOutput(output, final, !!managed, failure ? \"\" : \"(no output)\");\n\t\treturn {\n\t\t\tstatus: failure?.status,\n\t\t\terror: failure?.error,\n\t\t\t...(exitCode !== undefined ? { exitCode } : {}),\n\t\t\tresult: {\n\t\t\t\tcontent: [{ type: \"text\", text: failure ? `${text ? `${text}\\n\\n` : \"\"}${failure.error}` : text }],\n\t\t\t\tdetails,\n\t\t\t},\n\t\t};\n\t} finally {\n\t\tacceptingOutput = false;\n\t\tunsubscribe?.();\n\t\tclearUpdateTimer();\n\t\tawait output.closeTempFile();\n\t}\n}\n"]}
|
|
@@ -23,22 +23,22 @@ export declare class BackgroundTasksMenu implements Component, Focusable {
|
|
|
23
23
|
private rows;
|
|
24
24
|
private runningCount;
|
|
25
25
|
private finishedCount;
|
|
26
|
+
private completedCount;
|
|
27
|
+
private failedCount;
|
|
26
28
|
private hiddenFinished;
|
|
27
29
|
private selected?;
|
|
28
30
|
private pinned?;
|
|
29
31
|
private releasePin?;
|
|
30
32
|
private unsubscribe;
|
|
31
|
-
private
|
|
33
|
+
private pollTimer;
|
|
34
|
+
private animationTimer;
|
|
32
35
|
private disposed;
|
|
33
36
|
private focus;
|
|
34
37
|
private pendingKill?;
|
|
38
|
+
private pendingKillTimer?;
|
|
35
39
|
private readonly positions;
|
|
36
40
|
private readonly renderCache;
|
|
37
41
|
private width;
|
|
38
|
-
private text;
|
|
39
|
-
private readKey?;
|
|
40
|
-
private readError?;
|
|
41
|
-
private finalRead;
|
|
42
42
|
private busy;
|
|
43
43
|
private feedback?;
|
|
44
44
|
private lastFrame;
|
|
@@ -46,6 +46,7 @@ export declare class BackgroundTasksMenu implements Component, Focusable {
|
|
|
46
46
|
private queueTick;
|
|
47
47
|
invalidate(): void;
|
|
48
48
|
dispose(): void;
|
|
49
|
+
private clearPendingKill;
|
|
49
50
|
private current;
|
|
50
51
|
private wide;
|
|
51
52
|
/** Fullscreen overlay: body fills the terminal minus the frame (rule, title, rule, hints, rule). */
|
|
@@ -68,6 +69,8 @@ export declare class BackgroundTasksMenu implements Component, Focusable {
|
|
|
68
69
|
private scrollPreview;
|
|
69
70
|
private listRowLine;
|
|
70
71
|
private emptyLine;
|
|
72
|
+
/** Tiny-terminal fallback: the frame stays, the layout steps aside. */
|
|
73
|
+
private renderTooSmall;
|
|
71
74
|
private centered;
|
|
72
75
|
private dividerLine;
|
|
73
76
|
render(width: number): string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/extensions/background/manager.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,KAAK,SAAS,EACd,KAAK,SAAS,EAMd,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,KAAK,iBAAiB,
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/extensions/background/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
/** Inline observer: selecting or closing a view never changes execution ownership. */
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { Markdown, stripTerminalSequences, truncateToWidth, visibleWidth, wrapTextWithAnsi, } from "@earendil-works/pi-tui";
|
|
4
|
-
import { isBackgroundTerminal, } from "../../core/background/types.js";
|
|
4
|
+
import { isBackgroundTerminal, isForegroundShellTask, } from "../../core/background/types.js";
|
|
5
5
|
import { DynamicBorder } from "../../modes/interactive/components/dynamic-border.js";
|
|
6
6
|
import { keyLabel } from "../../modes/interactive/components/keybinding-hints.js";
|
|
7
|
-
import { statusMarker } from "../../modes/interactive/components/status-marker.js";
|
|
7
|
+
import { STATUS_SPINNER_INTERVAL_MS, statusMarker } from "../../modes/interactive/components/status-marker.js";
|
|
8
8
|
import { getMarkdownTheme, highlightCode } from "../../modes/interactive/theme/theme.js";
|
|
9
9
|
import { sanitizeBinaryOutput } from "../../utils/shell.js";
|
|
10
|
-
import { runtimeLabel, taskLabel } from "./task-view.js";
|
|
10
|
+
import { exitSuffix, runtimeLabel, taskLabel, workerLabel } from "./task-view.js";
|
|
11
11
|
import { firstCommandLine, formatAge } from "./text.js";
|
|
12
12
|
const WIDE_MIN_WIDTH = 100;
|
|
13
13
|
const LIST_MIN_WIDTH = 28;
|
|
14
14
|
const LIST_MAX_WIDTH = 44;
|
|
15
15
|
const NARROW_LIST_MAX_ROWS = 7;
|
|
16
|
+
/** Below this the two-pane layout is unreadable; show a resize notice instead. */
|
|
17
|
+
const MIN_RENDER_WIDTH = 60;
|
|
18
|
+
const MIN_RENDER_HEIGHT = 12;
|
|
19
|
+
/** A pending kill confirmation auto-cancels instead of capturing input forever. */
|
|
20
|
+
const KILL_CONFIRM_TIMEOUT_MS = 5000;
|
|
16
21
|
const DETAIL_LABEL_WIDTH = 10;
|
|
17
22
|
const DETAIL_MAX_ROWS = 9;
|
|
18
23
|
const COMMAND_MAX_ROWS = 3;
|
|
@@ -69,13 +74,13 @@ export class BackgroundTasksMenu {
|
|
|
69
74
|
this.rows = [];
|
|
70
75
|
this.runningCount = 0;
|
|
71
76
|
this.finishedCount = 0;
|
|
77
|
+
this.completedCount = 0;
|
|
78
|
+
this.failedCount = 0;
|
|
72
79
|
this.hiddenFinished = 0;
|
|
73
80
|
this.disposed = false;
|
|
74
81
|
this.focus = "list";
|
|
75
82
|
this.positions = new Map();
|
|
76
83
|
this.renderCache = new Map();
|
|
77
|
-
this.text = "";
|
|
78
|
-
this.finalRead = false;
|
|
79
84
|
this.busy = false;
|
|
80
85
|
this.lastFrame = "";
|
|
81
86
|
this.options = options;
|
|
@@ -83,10 +88,10 @@ export class BackgroundTasksMenu {
|
|
|
83
88
|
this.sync();
|
|
84
89
|
this.unsubscribe = options.host.subscribe(() => {
|
|
85
90
|
this.sync();
|
|
86
|
-
// Coalesce high-frequency progress;
|
|
91
|
+
// Coalesce high-frequency progress; polling reads only visible output.
|
|
87
92
|
});
|
|
88
|
-
this.
|
|
89
|
-
this.
|
|
93
|
+
this.pollTimer = setInterval(() => this.queueTick(), options.pollIntervalMs ?? 1000);
|
|
94
|
+
this.pollTimer.unref?.();
|
|
90
95
|
this.queueTick();
|
|
91
96
|
}
|
|
92
97
|
queueTick() {
|
|
@@ -102,9 +107,20 @@ export class BackgroundTasksMenu {
|
|
|
102
107
|
if (this.disposed)
|
|
103
108
|
return;
|
|
104
109
|
this.disposed = true;
|
|
105
|
-
clearInterval(this.
|
|
110
|
+
clearInterval(this.pollTimer);
|
|
111
|
+
clearInterval(this.animationTimer);
|
|
112
|
+
this.animationTimer = undefined;
|
|
113
|
+
this.clearPendingKill();
|
|
106
114
|
this.unsubscribe();
|
|
107
115
|
this.releasePin?.();
|
|
116
|
+
this.positions.clear();
|
|
117
|
+
}
|
|
118
|
+
clearPendingKill() {
|
|
119
|
+
this.pendingKill = undefined;
|
|
120
|
+
if (this.pendingKillTimer) {
|
|
121
|
+
clearTimeout(this.pendingKillTimer);
|
|
122
|
+
this.pendingKillTimer = undefined;
|
|
123
|
+
}
|
|
108
124
|
}
|
|
109
125
|
current() {
|
|
110
126
|
return this.rows.find((row) => row.key === this.selected);
|
|
@@ -123,16 +139,17 @@ export class BackgroundTasksMenu {
|
|
|
123
139
|
const running = tasks
|
|
124
140
|
.filter((task) => !isBackgroundTerminal(task.status))
|
|
125
141
|
.sort((a, b) => b.startedAt - a.startedAt);
|
|
126
|
-
// Finished
|
|
127
|
-
//
|
|
128
|
-
// row never disappears mid-watch when its execution settles.
|
|
142
|
+
// Finished includes every subagent group and background shell. Foreground
|
|
143
|
+
// shells deliver inline, except the selected row stays until selection moves.
|
|
129
144
|
const selectedTask = this.selected?.split("/")[0];
|
|
130
145
|
const settled = tasks
|
|
131
146
|
.filter((task) => isBackgroundTerminal(task.status))
|
|
132
147
|
.sort((a, b) => (b.endedAt ?? b.startedAt) - (a.endedAt ?? a.startedAt));
|
|
133
|
-
const finished = settled.filter((task) => task
|
|
148
|
+
const finished = settled.filter((task) => !isForegroundShellTask(task) || task.id === selectedTask);
|
|
134
149
|
this.runningCount = running.length;
|
|
135
150
|
this.finishedCount = finished.length;
|
|
151
|
+
this.completedCount = finished.filter((task) => task.status === "completed").length;
|
|
152
|
+
this.failedCount = this.finishedCount - this.completedCount;
|
|
136
153
|
this.hiddenFinished = settled.length - finished.length;
|
|
137
154
|
this.rows = [...running, ...finished].flatMap((task) => [
|
|
138
155
|
{ key: task.id, task },
|
|
@@ -154,6 +171,17 @@ export class BackgroundTasksMenu {
|
|
|
154
171
|
this.releasePin = release;
|
|
155
172
|
previous?.();
|
|
156
173
|
}
|
|
174
|
+
// Spinner frames must advance independently of output polling and pending reads.
|
|
175
|
+
if (this.rows.some((row) => (row.worker?.status ?? row.task.status) === "running")) {
|
|
176
|
+
if (!this.animationTimer) {
|
|
177
|
+
this.animationTimer = setInterval(() => this.options.tui.requestRender(), STATUS_SPINNER_INTERVAL_MS);
|
|
178
|
+
this.animationTimer.unref?.();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
clearInterval(this.animationTimer);
|
|
183
|
+
this.animationTimer = undefined;
|
|
184
|
+
}
|
|
157
185
|
}
|
|
158
186
|
async tick() {
|
|
159
187
|
if (this.disposed)
|
|
@@ -171,23 +199,34 @@ export class BackgroundTasksMenu {
|
|
|
171
199
|
}
|
|
172
200
|
async refresh() {
|
|
173
201
|
const row = this.current();
|
|
174
|
-
if (!row || row.worker || row.task.kind !== "bash" || this.busy
|
|
202
|
+
if (!row || row.worker || row.task.kind !== "bash" || this.busy)
|
|
203
|
+
return;
|
|
204
|
+
const position = this.position();
|
|
205
|
+
// Keep the bounded output with its row's scroll anchor while browsing.
|
|
206
|
+
// A new tail can otherwise move even lines that are still inside the read window.
|
|
207
|
+
if (position.output && (!position.follow || position.output.settled))
|
|
175
208
|
return;
|
|
176
209
|
this.busy = true;
|
|
177
210
|
try {
|
|
178
211
|
const slice = await this.options.host.read(row.task.id, { mode: "tail", bytes: 128 * 1024 });
|
|
179
212
|
if (this.disposed || this.selected !== row.key)
|
|
180
213
|
return;
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
214
|
+
// A read started while following may settle after the user scrolls up.
|
|
215
|
+
if (!position.follow && position.output)
|
|
216
|
+
return;
|
|
217
|
+
position.output = {
|
|
218
|
+
text: clean(slice.text).split("\n").slice(-2000).join("\n"),
|
|
219
|
+
readError: slice.readError ? clean(slice.readError).slice(0, 4096) : undefined,
|
|
220
|
+
settled: isBackgroundTerminal(slice.task.status),
|
|
221
|
+
};
|
|
185
222
|
}
|
|
186
223
|
catch (error) {
|
|
187
|
-
if (!this.disposed && this.selected === row.key) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
224
|
+
if (!this.disposed && this.selected === row.key && (position.follow || !position.output)) {
|
|
225
|
+
position.output = {
|
|
226
|
+
text: "",
|
|
227
|
+
readError: `Cannot read output: ${clean(String(error)).slice(0, 1000)}`,
|
|
228
|
+
settled: false,
|
|
229
|
+
};
|
|
191
230
|
}
|
|
192
231
|
}
|
|
193
232
|
finally {
|
|
@@ -202,7 +241,7 @@ export class BackgroundTasksMenu {
|
|
|
202
241
|
if (this.pendingKill) {
|
|
203
242
|
// The one raw-key exception: a pending y/N confirmation captures the next input.
|
|
204
243
|
const id = this.pendingKill;
|
|
205
|
-
this.
|
|
244
|
+
this.clearPendingKill();
|
|
206
245
|
if (data === "y" || data === "Y") {
|
|
207
246
|
try {
|
|
208
247
|
this.feedback = this.options.host.kill(id)
|
|
@@ -227,8 +266,17 @@ export class BackgroundTasksMenu {
|
|
|
227
266
|
}
|
|
228
267
|
else if (kb.matches(data, "app.backgroundTasks.kill")) {
|
|
229
268
|
const row = this.current();
|
|
230
|
-
if (row)
|
|
269
|
+
if (row) {
|
|
270
|
+
this.clearPendingKill();
|
|
231
271
|
this.pendingKill = row.task.id;
|
|
272
|
+
this.pendingKillTimer = setTimeout(() => {
|
|
273
|
+
this.pendingKill = undefined;
|
|
274
|
+
this.pendingKillTimer = undefined;
|
|
275
|
+
if (!this.disposed)
|
|
276
|
+
this.options.tui.requestRender();
|
|
277
|
+
}, KILL_CONFIRM_TIMEOUT_MS);
|
|
278
|
+
this.pendingKillTimer.unref?.();
|
|
279
|
+
}
|
|
232
280
|
}
|
|
233
281
|
else if (kb.matches(data, "app.backgroundTasks.focusList")) {
|
|
234
282
|
this.focus = "list";
|
|
@@ -252,10 +300,6 @@ export class BackgroundTasksMenu {
|
|
|
252
300
|
? Math.max(0, Math.min(this.rows.length - 1, index + delta))
|
|
253
301
|
: (index + delta + this.rows.length) % this.rows.length;
|
|
254
302
|
this.selected = this.rows[next]?.key;
|
|
255
|
-
this.text = "";
|
|
256
|
-
this.readKey = undefined;
|
|
257
|
-
this.readError = undefined;
|
|
258
|
-
this.finalRead = false;
|
|
259
303
|
this.sync();
|
|
260
304
|
this.queueTick();
|
|
261
305
|
}
|
|
@@ -325,7 +369,9 @@ export class BackgroundTasksMenu {
|
|
|
325
369
|
const glyph = theme.fg(marker.color, marker.glyph);
|
|
326
370
|
const time = isBackgroundTerminal(task.status) && task.endedAt ? formatAge(task.endedAt, now) : runtimeLabel(task, now);
|
|
327
371
|
const field = (label, values) => values.map((value, index) => `${theme.fg("dim", padEnd(index === 0 ? label : "", DETAIL_LABEL_WIDTH))}${value}`);
|
|
328
|
-
const status = worker
|
|
372
|
+
const status = worker
|
|
373
|
+
? `${glyph} ${worker.status}`
|
|
374
|
+
: `${glyph} ${task.status} · ${task.mode} · ${time}${exitSuffix(task.exitCode, " · ")}`;
|
|
329
375
|
if (compact) {
|
|
330
376
|
const second = worker
|
|
331
377
|
? field("Worker", [truncateToWidth(clean(worker.label), valueWidth, "…")])
|
|
@@ -346,12 +392,13 @@ export class BackgroundTasksMenu {
|
|
|
346
392
|
...field("Usage", wrap(worker.usage ?? "—")),
|
|
347
393
|
];
|
|
348
394
|
}
|
|
395
|
+
const readError = this.positions.get(row.key)?.output?.readError;
|
|
349
396
|
const lines = [
|
|
350
397
|
...field("Status", [status]),
|
|
351
398
|
...field("Task", [truncateToWidth(task.id, valueWidth, "…")]),
|
|
352
399
|
...field("Error", [
|
|
353
400
|
task.error ? `Task error: ${oneLine(task.error)}` : "",
|
|
354
|
-
|
|
401
|
+
readError ? `Output read error: ${oneLine(readError)}` : "",
|
|
355
402
|
]
|
|
356
403
|
.filter(Boolean)
|
|
357
404
|
.flatMap((error) => wrapTextWithAnsi(theme.fg("error", error), Math.max(1, valueWidth)))
|
|
@@ -420,7 +467,7 @@ export class BackgroundTasksMenu {
|
|
|
420
467
|
.map((line) => theme.fg("toolOutput", line))
|
|
421
468
|
: [theme.fg("muted", "No workers.")];
|
|
422
469
|
}
|
|
423
|
-
const text = this.
|
|
470
|
+
const text = this.positions.get(row.key)?.output?.text ?? task.projection?.text ?? "Loading…";
|
|
424
471
|
return clean(text)
|
|
425
472
|
.split("\n")
|
|
426
473
|
.map((line) => theme.fg("toolOutput", line));
|
|
@@ -487,12 +534,15 @@ export class BackgroundTasksMenu {
|
|
|
487
534
|
scrollPreview(delta) {
|
|
488
535
|
const { start, max, entries } = this.layout();
|
|
489
536
|
const position = this.position();
|
|
537
|
+
const wasFollowing = position.follow;
|
|
490
538
|
position.scroll = Math.min(max, Math.max(0, start + delta));
|
|
491
539
|
const entry = entries[position.scroll];
|
|
492
540
|
position.anchor = entry ? { line: entry.line, column: entry.column } : undefined;
|
|
493
541
|
// Only an explicit downward movement resumes shell following, never resize/update.
|
|
494
542
|
position.follow =
|
|
495
543
|
delta > 0 && position.scroll === max && this.current()?.task.kind === "bash" && !this.current()?.worker;
|
|
544
|
+
if (position.follow && !wasFollowing)
|
|
545
|
+
this.queueTick();
|
|
496
546
|
}
|
|
497
547
|
listRowLine(row, width) {
|
|
498
548
|
const { theme } = this.options;
|
|
@@ -503,18 +553,22 @@ export class BackgroundTasksMenu {
|
|
|
503
553
|
const cursor = selected ? theme.fg(this.focus === "list" ? "accent" : "muted", "→ ") : " ";
|
|
504
554
|
const indent = row.worker ? " " : "";
|
|
505
555
|
const terminal = isBackgroundTerminal(row.task.status);
|
|
506
|
-
//
|
|
507
|
-
// background panel is self-explanatory; settled ones leave the list.
|
|
556
|
+
// Foreground mode stays explicit, including completed subagent groups.
|
|
508
557
|
let time = "";
|
|
509
558
|
if (!row.worker) {
|
|
510
559
|
time = terminal ? formatAge(row.task.endedAt ?? row.task.startedAt, now) : runtimeLabel(row.task, now);
|
|
511
|
-
|
|
560
|
+
const workers = row.task.projection?.workers;
|
|
561
|
+
if (workers && workers.length > 0) {
|
|
562
|
+
const settledCount = workers.filter((w) => w.status !== "queued" && w.status !== "running").length;
|
|
563
|
+
time = `${settledCount}/${workers.length} · ${time}`;
|
|
564
|
+
}
|
|
565
|
+
if (row.task.mode === "foreground")
|
|
512
566
|
time = `fg · ${time}`;
|
|
513
567
|
}
|
|
514
568
|
const timeWidth = time ? visibleWidth(time) + 1 : 0;
|
|
515
569
|
const labelWidth = Math.max(1, width - 2 - indent.length - visibleWidth(glyph) - 1 - timeWidth);
|
|
516
570
|
const labelColor = selected && this.focus === "list" ? "accent" : "text";
|
|
517
|
-
const label = theme.fg(labelColor, truncateToWidth(clean(row.worker ? row.worker
|
|
571
|
+
const label = theme.fg(labelColor, truncateToWidth(clean(row.worker ? workerLabel(row.worker) : taskLabel({ command: row.task.command ?? row.task.title })), labelWidth, "…"));
|
|
518
572
|
let line = `${cursor}${indent}${glyph} ${label}`;
|
|
519
573
|
if (time)
|
|
520
574
|
line += " ".repeat(Math.max(1, width - visibleWidth(line) - visibleWidth(time))) + theme.fg("dim", time);
|
|
@@ -523,6 +577,17 @@ export class BackgroundTasksMenu {
|
|
|
523
577
|
emptyLine(width) {
|
|
524
578
|
return this.centered(width, "No background tasks.");
|
|
525
579
|
}
|
|
580
|
+
/** Tiny-terminal fallback: the frame stays, the layout steps aside. */
|
|
581
|
+
renderTooSmall(width, rows) {
|
|
582
|
+
const { theme, keybindings } = this.options;
|
|
583
|
+
const rule = () => new DynamicBorder((text) => theme.fg("border", text)).render(width)[0] ?? "";
|
|
584
|
+
const message = `Terminal too small for /bg — resize to at least ${MIN_RENDER_WIDTH}×${MIN_RENDER_HEIGHT}.`;
|
|
585
|
+
const bodyHeight = Math.max(1, rows - 4);
|
|
586
|
+
const body = Array.from({ length: bodyHeight }, () => pad("", width));
|
|
587
|
+
body[Math.floor(bodyHeight / 2)] = this.centered(width, message);
|
|
588
|
+
const closeHint = pad(theme.fg("dim", `${keyLabel("tui.select.cancel", { keybindings })} close`), width);
|
|
589
|
+
return [rule(), ...body, rule(), closeHint, rule()];
|
|
590
|
+
}
|
|
526
591
|
centered(width, message) {
|
|
527
592
|
const leftPad = Math.max(0, Math.floor((width - visibleWidth(message)) / 2));
|
|
528
593
|
return pad(this.options.theme.fg("muted", `${" ".repeat(leftPad)}${message}`), width);
|
|
@@ -544,6 +609,10 @@ export class BackgroundTasksMenu {
|
|
|
544
609
|
render(width) {
|
|
545
610
|
if (width < 1)
|
|
546
611
|
return [];
|
|
612
|
+
const terminalRows = this.options.tui.terminal.rows;
|
|
613
|
+
if (width < MIN_RENDER_WIDTH || terminalRows < MIN_RENDER_HEIGHT) {
|
|
614
|
+
return this.renderTooSmall(width, terminalRows);
|
|
615
|
+
}
|
|
547
616
|
const wasWide = this.wide();
|
|
548
617
|
this.width = width;
|
|
549
618
|
if (!wasWide && this.wide())
|
|
@@ -552,10 +621,17 @@ export class BackgroundTasksMenu {
|
|
|
552
621
|
const layout = this.layout();
|
|
553
622
|
const rule = () => new DynamicBorder((text) => theme.fg("border", text)).render(width)[0] ?? "";
|
|
554
623
|
const title = theme.fg("accent", theme.bold("Background tasks"));
|
|
555
|
-
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
|
|
624
|
+
// Only non-zero segments show: a quiet header means nothing needs attention.
|
|
625
|
+
const segments = [];
|
|
626
|
+
if (this.runningCount > 0)
|
|
627
|
+
segments.push(theme.fg("accent", `${this.runningCount} running`));
|
|
628
|
+
if (this.completedCount > 0)
|
|
629
|
+
segments.push(theme.fg("muted", `${this.completedCount} completed`));
|
|
630
|
+
if (this.failedCount > 0)
|
|
631
|
+
segments.push(theme.fg("error", `${this.failedCount} failed`));
|
|
632
|
+
if (this.hiddenFinished > 0)
|
|
633
|
+
segments.push(theme.fg("muted", `${this.hiddenFinished} foreground shell${this.hiddenFinished === 1 ? "" : "s"} hidden`));
|
|
634
|
+
const stats = segments.join(theme.fg("muted", " · "));
|
|
559
635
|
const gap = width - visibleWidth(title) - visibleWidth(stats);
|
|
560
636
|
const titleLine = pad(stats && gap >= 1 ? `${title}${" ".repeat(gap)}${stats}` : title, width);
|
|
561
637
|
const hint = (id) => keyLabel(id, { keybindings });
|