@wahack/pi-coding-agent 15.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10031 -0
- package/README.md +36 -0
- package/examples/README.md +21 -0
- package/examples/custom-tools/README.md +104 -0
- package/examples/custom-tools/hello/index.ts +20 -0
- package/examples/extensions/README.md +142 -0
- package/examples/extensions/api-demo.ts +79 -0
- package/examples/extensions/chalk-logger.ts +25 -0
- package/examples/extensions/hello.ts +31 -0
- package/examples/extensions/pirate.ts +43 -0
- package/examples/extensions/plan-mode.ts +549 -0
- package/examples/extensions/reload-runtime.ts +38 -0
- package/examples/extensions/thinking-note.ts +13 -0
- package/examples/extensions/tools.ts +145 -0
- package/examples/extensions/with-deps/index.ts +36 -0
- package/examples/extensions/with-deps/package-lock.json +31 -0
- package/examples/extensions/with-deps/package.json +17 -0
- package/examples/hooks/README.md +56 -0
- package/examples/hooks/auto-commit-on-exit.ts +48 -0
- package/examples/hooks/confirm-destructive.ts +58 -0
- package/examples/hooks/custom-compaction.ts +115 -0
- package/examples/hooks/dirty-repo-guard.ts +51 -0
- package/examples/hooks/file-trigger.ts +40 -0
- package/examples/hooks/git-checkpoint.ts +52 -0
- package/examples/hooks/handoff.ts +149 -0
- package/examples/hooks/permission-gate.ts +33 -0
- package/examples/hooks/protected-paths.ts +29 -0
- package/examples/hooks/qna.ts +118 -0
- package/examples/hooks/status-line.ts +39 -0
- package/examples/sdk/01-minimal.ts +21 -0
- package/examples/sdk/02-custom-model.ts +49 -0
- package/examples/sdk/03-custom-prompt.ts +46 -0
- package/examples/sdk/04-skills.ts +43 -0
- package/examples/sdk/06-extensions.ts +82 -0
- package/examples/sdk/06-hooks.ts +61 -0
- package/examples/sdk/07-context-files.ts +35 -0
- package/examples/sdk/08-prompt-templates.ts +41 -0
- package/examples/sdk/08-slash-commands.ts +46 -0
- package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
- package/examples/sdk/11-sessions.ts +47 -0
- package/examples/sdk/12-redis-sessions.ts +54 -0
- package/examples/sdk/13-sql-sessions.ts +61 -0
- package/examples/sdk/README.md +172 -0
- package/package.json +554 -0
- package/scripts/build-binary.ts +100 -0
- package/scripts/bundle-dist.ts +90 -0
- package/scripts/format-prompts.ts +68 -0
- package/scripts/generate-docs-index.ts +40 -0
- package/scripts/generate-template.ts +33 -0
- package/scripts/omp +42 -0
- package/scripts/omp.ts +19 -0
- package/src/async/index.ts +1 -0
- package/src/async/job-manager.ts +625 -0
- package/src/auto-thinking/classifier.ts +185 -0
- package/src/autoresearch/command-resume.md +14 -0
- package/src/autoresearch/dashboard.ts +436 -0
- package/src/autoresearch/git.ts +319 -0
- package/src/autoresearch/helpers.ts +218 -0
- package/src/autoresearch/index.ts +536 -0
- package/src/autoresearch/prompt-setup.md +43 -0
- package/src/autoresearch/prompt.md +103 -0
- package/src/autoresearch/resume-message.md +10 -0
- package/src/autoresearch/state.ts +273 -0
- package/src/autoresearch/storage.ts +699 -0
- package/src/autoresearch/tools/init-experiment.ts +272 -0
- package/src/autoresearch/tools/log-experiment.ts +524 -0
- package/src/autoresearch/tools/run-experiment.ts +407 -0
- package/src/autoresearch/tools/update-notes.ts +109 -0
- package/src/autoresearch/types.ts +168 -0
- package/src/bun-imports.d.ts +28 -0
- package/src/capability/context-file.ts +44 -0
- package/src/capability/extension-module.ts +34 -0
- package/src/capability/extension.ts +47 -0
- package/src/capability/fs.ts +117 -0
- package/src/capability/hook.ts +40 -0
- package/src/capability/index.ts +436 -0
- package/src/capability/instruction.ts +37 -0
- package/src/capability/mcp.ts +74 -0
- package/src/capability/prompt.ts +35 -0
- package/src/capability/rule-buckets.ts +66 -0
- package/src/capability/rule.ts +261 -0
- package/src/capability/settings.ts +34 -0
- package/src/capability/skill.ts +63 -0
- package/src/capability/slash-command.ts +40 -0
- package/src/capability/ssh.ts +41 -0
- package/src/capability/system-prompt.ts +34 -0
- package/src/capability/tool.ts +38 -0
- package/src/capability/types.ts +168 -0
- package/src/cli/agents-cli.ts +138 -0
- package/src/cli/args.ts +340 -0
- package/src/cli/auth-broker-cli.ts +895 -0
- package/src/cli/auth-gateway-cli.ts +611 -0
- package/src/cli/classify-install-target.ts +76 -0
- package/src/cli/claude-trace-cli.ts +795 -0
- package/src/cli/commands/init-xdg.ts +27 -0
- package/src/cli/completion-gen.ts +550 -0
- package/src/cli/config-cli.ts +418 -0
- package/src/cli/dry-balance-cli.ts +856 -0
- package/src/cli/extension-flags.ts +48 -0
- package/src/cli/file-processor.ts +133 -0
- package/src/cli/gallery-cli.ts +230 -0
- package/src/cli/gallery-fixtures/agentic.ts +407 -0
- package/src/cli/gallery-fixtures/codeintel.ts +187 -0
- package/src/cli/gallery-fixtures/edit.ts +194 -0
- package/src/cli/gallery-fixtures/fs.ts +220 -0
- package/src/cli/gallery-fixtures/index.ts +40 -0
- package/src/cli/gallery-fixtures/interaction.ts +49 -0
- package/src/cli/gallery-fixtures/memory.ts +81 -0
- package/src/cli/gallery-fixtures/misc.ts +250 -0
- package/src/cli/gallery-fixtures/search.ts +213 -0
- package/src/cli/gallery-fixtures/shell.ts +167 -0
- package/src/cli/gallery-fixtures/types.ts +57 -0
- package/src/cli/gallery-fixtures/web.ts +158 -0
- package/src/cli/gallery-screenshot.ts +279 -0
- package/src/cli/grep-cli.ts +160 -0
- package/src/cli/grievances-cli.ts +256 -0
- package/src/cli/initial-message.ts +58 -0
- package/src/cli/list-models.ts +194 -0
- package/src/cli/plugin-cli.ts +996 -0
- package/src/cli/read-cli.ts +57 -0
- package/src/cli/session-picker.ts +79 -0
- package/src/cli/setup-cli.ts +231 -0
- package/src/cli/shell-cli.ts +176 -0
- package/src/cli/ssh-cli.ts +179 -0
- package/src/cli/startup-cwd.ts +68 -0
- package/src/cli/stats-cli.ts +238 -0
- package/src/cli/tiny-models-cli.ts +127 -0
- package/src/cli/update-cli.ts +611 -0
- package/src/cli/usage-cli.ts +603 -0
- package/src/cli/web-search-cli.ts +132 -0
- package/src/cli/worktree-cli.ts +291 -0
- package/src/cli-commands.ts +79 -0
- package/src/cli.ts +200 -0
- package/src/commands/acp.ts +24 -0
- package/src/commands/agents.ts +57 -0
- package/src/commands/auth-broker.ts +99 -0
- package/src/commands/auth-gateway.ts +69 -0
- package/src/commands/commit.ts +46 -0
- package/src/commands/complete.ts +66 -0
- package/src/commands/completions.ts +60 -0
- package/src/commands/config.ts +51 -0
- package/src/commands/dry-balance.ts +43 -0
- package/src/commands/gallery.ts +52 -0
- package/src/commands/grep.ts +48 -0
- package/src/commands/grievances.ts +51 -0
- package/src/commands/install.ts +107 -0
- package/src/commands/launch.ts +169 -0
- package/src/commands/plugin.ts +78 -0
- package/src/commands/read.ts +38 -0
- package/src/commands/setup.ts +67 -0
- package/src/commands/shell.ts +29 -0
- package/src/commands/ssh.ts +60 -0
- package/src/commands/stats.ts +29 -0
- package/src/commands/tiny-models.ts +36 -0
- package/src/commands/update.ts +21 -0
- package/src/commands/usage.ts +35 -0
- package/src/commands/web-search.ts +42 -0
- package/src/commands/worktree.ts +56 -0
- package/src/commit/agentic/agent.ts +317 -0
- package/src/commit/agentic/fallback.ts +96 -0
- package/src/commit/agentic/index.ts +355 -0
- package/src/commit/agentic/prompts/analyze-file.md +22 -0
- package/src/commit/agentic/prompts/session-user.md +25 -0
- package/src/commit/agentic/prompts/split-confirm.md +1 -0
- package/src/commit/agentic/prompts/system.md +38 -0
- package/src/commit/agentic/state.ts +60 -0
- package/src/commit/agentic/tools/analyze-file.ts +146 -0
- package/src/commit/agentic/tools/git-file-diff.ts +191 -0
- package/src/commit/agentic/tools/git-hunk.ts +50 -0
- package/src/commit/agentic/tools/git-overview.ts +81 -0
- package/src/commit/agentic/tools/index.ts +54 -0
- package/src/commit/agentic/tools/propose-changelog.ts +144 -0
- package/src/commit/agentic/tools/propose-commit.ts +109 -0
- package/src/commit/agentic/tools/recent-commits.ts +81 -0
- package/src/commit/agentic/tools/schemas.ts +23 -0
- package/src/commit/agentic/tools/split-commit.ts +245 -0
- package/src/commit/agentic/topo-sort.ts +44 -0
- package/src/commit/agentic/trivial.ts +51 -0
- package/src/commit/agentic/validation.ts +183 -0
- package/src/commit/analysis/conventional.ts +64 -0
- package/src/commit/analysis/index.ts +4 -0
- package/src/commit/analysis/scope.ts +242 -0
- package/src/commit/analysis/summary.ts +105 -0
- package/src/commit/analysis/validation.ts +66 -0
- package/src/commit/changelog/detect.ts +40 -0
- package/src/commit/changelog/generate.ts +97 -0
- package/src/commit/changelog/index.ts +234 -0
- package/src/commit/changelog/parse.ts +44 -0
- package/src/commit/cli.ts +85 -0
- package/src/commit/git/diff.ts +148 -0
- package/src/commit/index.ts +5 -0
- package/src/commit/map-reduce/index.ts +69 -0
- package/src/commit/map-reduce/map-phase.ts +193 -0
- package/src/commit/map-reduce/reduce-phase.ts +49 -0
- package/src/commit/map-reduce/utils.ts +9 -0
- package/src/commit/message.ts +11 -0
- package/src/commit/model-selection.ts +92 -0
- package/src/commit/pipeline.ts +243 -0
- package/src/commit/prompts/analysis-system.md +148 -0
- package/src/commit/prompts/analysis-user.md +38 -0
- package/src/commit/prompts/changelog-system.md +50 -0
- package/src/commit/prompts/changelog-user.md +18 -0
- package/src/commit/prompts/file-observer-system.md +24 -0
- package/src/commit/prompts/file-observer-user.md +8 -0
- package/src/commit/prompts/reduce-system.md +50 -0
- package/src/commit/prompts/reduce-user.md +17 -0
- package/src/commit/prompts/summary-retry.md +3 -0
- package/src/commit/prompts/summary-system.md +38 -0
- package/src/commit/prompts/summary-user.md +13 -0
- package/src/commit/prompts/types-description.md +2 -0
- package/src/commit/shared-llm.ts +77 -0
- package/src/commit/types.ts +118 -0
- package/src/commit/utils/exclusions.ts +42 -0
- package/src/commit/utils.ts +58 -0
- package/src/config/api-key-resolver.ts +60 -0
- package/src/config/append-only-context-mode.ts +31 -0
- package/src/config/config-file.ts +317 -0
- package/src/config/file-lock.ts +164 -0
- package/src/config/keybindings.ts +628 -0
- package/src/config/mcp-schema.json +230 -0
- package/src/config/model-discovery.ts +554 -0
- package/src/config/model-registry.ts +2090 -0
- package/src/config/model-resolver.ts +1502 -0
- package/src/config/model-roles.ts +74 -0
- package/src/config/models-config-schema.ts +226 -0
- package/src/config/models-config.ts +129 -0
- package/src/config/prompt-templates.ts +185 -0
- package/src/config/resolve-config-value.ts +94 -0
- package/src/config/settings-schema.ts +3530 -0
- package/src/config/settings.ts +1178 -0
- package/src/config.ts +242 -0
- package/src/cursor.ts +340 -0
- package/src/dap/client.ts +760 -0
- package/src/dap/config.ts +189 -0
- package/src/dap/defaults.json +212 -0
- package/src/dap/index.ts +4 -0
- package/src/dap/session.ts +1441 -0
- package/src/dap/types.ts +610 -0
- package/src/debug/index.ts +515 -0
- package/src/debug/log-formatting.ts +58 -0
- package/src/debug/log-viewer.ts +908 -0
- package/src/debug/profiler.ts +162 -0
- package/src/debug/protocol-probe.ts +267 -0
- package/src/debug/raw-sse-buffer.ts +273 -0
- package/src/debug/raw-sse.ts +292 -0
- package/src/debug/report-bundle.ts +374 -0
- package/src/debug/system-info.ts +111 -0
- package/src/debug/terminal-info.ts +124 -0
- package/src/discovery/agents-md.ts +67 -0
- package/src/discovery/agents.ts +230 -0
- package/src/discovery/at-imports.ts +273 -0
- package/src/discovery/builtin-defaults.ts +39 -0
- package/src/discovery/builtin-rules/index.ts +54 -0
- package/src/discovery/builtin-rules/rs-box-leak.md +48 -0
- package/src/discovery/builtin-rules/rs-future-prelude.md +23 -0
- package/src/discovery/builtin-rules/rs-lazylock.md +51 -0
- package/src/discovery/builtin-rules/rs-match-ergonomics.md +67 -0
- package/src/discovery/builtin-rules/rs-parking-lot.md +44 -0
- package/src/discovery/builtin-rules/rs-result-type.md +19 -0
- package/src/discovery/builtin-rules/ts-bare-catch.md +38 -0
- package/src/discovery/builtin-rules/ts-import-type.md +42 -0
- package/src/discovery/builtin-rules/ts-no-any.md +56 -0
- package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +44 -0
- package/src/discovery/builtin-rules/ts-no-dynamic-import.md +39 -0
- package/src/discovery/builtin-rules/ts-no-return-type.md +45 -0
- package/src/discovery/builtin-rules/ts-no-test-timers.md +55 -0
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +51 -0
- package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +65 -0
- package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +75 -0
- package/src/discovery/builtin-rules/ts-set-map.md +28 -0
- package/src/discovery/builtin.ts +906 -0
- package/src/discovery/claude-plugins.ts +386 -0
- package/src/discovery/claude.ts +584 -0
- package/src/discovery/cline.ts +83 -0
- package/src/discovery/codex.ts +522 -0
- package/src/discovery/cursor.ts +220 -0
- package/src/discovery/gemini.ts +383 -0
- package/src/discovery/github.ts +154 -0
- package/src/discovery/helpers.ts +1016 -0
- package/src/discovery/index.ts +81 -0
- package/src/discovery/mcp-json.ts +171 -0
- package/src/discovery/omp-extension-roots.ts +190 -0
- package/src/discovery/omp-plugins.ts +383 -0
- package/src/discovery/opencode.ts +398 -0
- package/src/discovery/plugin-dir-roots.ts +28 -0
- package/src/discovery/ssh.ts +153 -0
- package/src/discovery/substitute-plugin-root.ts +29 -0
- package/src/discovery/vscode.ts +105 -0
- package/src/discovery/windsurf.ts +147 -0
- package/src/edit/apply-patch/index.ts +87 -0
- package/src/edit/apply-patch/parser.ts +174 -0
- package/src/edit/diff.ts +999 -0
- package/src/edit/file-snapshot-store.ts +91 -0
- package/src/edit/hashline/block-resolver.ts +33 -0
- package/src/edit/hashline/diff.ts +290 -0
- package/src/edit/hashline/execute.ts +242 -0
- package/src/edit/hashline/filesystem.ts +130 -0
- package/src/edit/hashline/index.ts +5 -0
- package/src/edit/hashline/noop-loop-guard.ts +99 -0
- package/src/edit/hashline/params.ts +18 -0
- package/src/edit/index.ts +571 -0
- package/src/edit/modes/apply-patch.lark +19 -0
- package/src/edit/modes/apply-patch.ts +53 -0
- package/src/edit/modes/patch.ts +1891 -0
- package/src/edit/modes/replace.ts +1137 -0
- package/src/edit/normalize.ts +345 -0
- package/src/edit/notebook.ts +242 -0
- package/src/edit/read-file.ts +25 -0
- package/src/edit/renderer.ts +769 -0
- package/src/edit/streaming.ts +517 -0
- package/src/eval/__tests__/agent-bridge.test.ts +708 -0
- package/src/eval/__tests__/bridge-timeout.test.ts +64 -0
- package/src/eval/__tests__/budget-bridge.test.ts +69 -0
- package/src/eval/__tests__/completion-bridge.test.ts +412 -0
- package/src/eval/__tests__/helpers-local-roots.test.ts +58 -0
- package/src/eval/__tests__/idle-timeout.test.ts +80 -0
- package/src/eval/__tests__/js-context-manager.test.ts +241 -0
- package/src/eval/__tests__/kernel-spawn.test.ts +103 -0
- package/src/eval/agent-bridge.ts +319 -0
- package/src/eval/backend.ts +71 -0
- package/src/eval/bridge-timeout.ts +44 -0
- package/src/eval/budget-bridge.ts +48 -0
- package/src/eval/completion-bridge.ts +207 -0
- package/src/eval/concurrency-bridge.ts +34 -0
- package/src/eval/idle-timeout.ts +91 -0
- package/src/eval/index.ts +4 -0
- package/src/eval/js/context-manager.ts +502 -0
- package/src/eval/js/executor.ts +173 -0
- package/src/eval/js/index.ts +51 -0
- package/src/eval/js/shared/helpers.ts +283 -0
- package/src/eval/js/shared/indirect-eval.ts +30 -0
- package/src/eval/js/shared/local-module-loader.ts +342 -0
- package/src/eval/js/shared/prelude.ts +2 -0
- package/src/eval/js/shared/prelude.txt +246 -0
- package/src/eval/js/shared/rewrite-imports.ts +532 -0
- package/src/eval/js/shared/runtime.ts +352 -0
- package/src/eval/js/shared/types.ts +18 -0
- package/src/eval/js/tool-bridge.ts +162 -0
- package/src/eval/js/worker-core.ts +132 -0
- package/src/eval/js/worker-entry.ts +30 -0
- package/src/eval/js/worker-protocol.ts +47 -0
- package/src/eval/py/__tests__/prelude.test.ts +19 -0
- package/src/eval/py/display.ts +71 -0
- package/src/eval/py/executor.ts +742 -0
- package/src/eval/py/index.ts +68 -0
- package/src/eval/py/kernel.ts +748 -0
- package/src/eval/py/prelude.py +658 -0
- package/src/eval/py/prelude.ts +3 -0
- package/src/eval/py/runner.py +1133 -0
- package/src/eval/py/runtime.ts +276 -0
- package/src/eval/py/spawn-options.ts +126 -0
- package/src/eval/py/tool-bridge.ts +182 -0
- package/src/eval/session-id.ts +8 -0
- package/src/eval/types.ts +48 -0
- package/src/exa/index.ts +2 -0
- package/src/exa/mcp-client.ts +370 -0
- package/src/exa/types.ts +69 -0
- package/src/exec/bash-executor.ts +419 -0
- package/src/exec/exec.ts +53 -0
- package/src/exec/non-interactive-env.ts +48 -0
- package/src/export/custom-share.ts +65 -0
- package/src/export/html/index.ts +164 -0
- package/src/export/html/template.css +1051 -0
- package/src/export/html/template.generated.ts +2 -0
- package/src/export/html/template.html +46 -0
- package/src/export/html/template.js +2271 -0
- package/src/export/html/template.macro.ts +25 -0
- package/src/export/html/vendor/highlight.min.js +1213 -0
- package/src/export/html/vendor/marked.min.js +6 -0
- package/src/export/ttsr.ts +583 -0
- package/src/extensibility/custom-commands/bundled/ci-green/index.ts +54 -0
- package/src/extensibility/custom-commands/bundled/review/index.ts +489 -0
- package/src/extensibility/custom-commands/index.ts +2 -0
- package/src/extensibility/custom-commands/loader.ts +238 -0
- package/src/extensibility/custom-commands/types.ts +113 -0
- package/src/extensibility/custom-tools/index.ts +7 -0
- package/src/extensibility/custom-tools/loader.ts +269 -0
- package/src/extensibility/custom-tools/types.ts +270 -0
- package/src/extensibility/custom-tools/wrapper.ts +47 -0
- package/src/extensibility/extensions/compact-handler.ts +40 -0
- package/src/extensibility/extensions/get-commands-handler.ts +78 -0
- package/src/extensibility/extensions/index.ts +16 -0
- package/src/extensibility/extensions/loader.ts +572 -0
- package/src/extensibility/extensions/runner.ts +922 -0
- package/src/extensibility/extensions/types.ts +1322 -0
- package/src/extensibility/extensions/wrapper.ts +223 -0
- package/src/extensibility/hooks/index.ts +5 -0
- package/src/extensibility/hooks/loader.ts +257 -0
- package/src/extensibility/hooks/runner.ts +425 -0
- package/src/extensibility/hooks/tool-wrapper.ts +107 -0
- package/src/extensibility/hooks/types.ts +606 -0
- package/src/extensibility/legacy-pi-ai-shim.ts +24 -0
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +15 -0
- package/src/extensibility/plugins/doctor.ts +65 -0
- package/src/extensibility/plugins/git-url.ts +367 -0
- package/src/extensibility/plugins/index.ts +9 -0
- package/src/extensibility/plugins/installer.ts +192 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +682 -0
- package/src/extensibility/plugins/loader.ts +313 -0
- package/src/extensibility/plugins/manager.ts +827 -0
- package/src/extensibility/plugins/marketplace/cache.ts +136 -0
- package/src/extensibility/plugins/marketplace/fetcher.ts +317 -0
- package/src/extensibility/plugins/marketplace/index.ts +6 -0
- package/src/extensibility/plugins/marketplace/manager.ts +770 -0
- package/src/extensibility/plugins/marketplace/registry.ts +196 -0
- package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
- package/src/extensibility/plugins/marketplace/types.ts +191 -0
- package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
- package/src/extensibility/plugins/parser.ts +105 -0
- package/src/extensibility/plugins/types.ts +194 -0
- package/src/extensibility/shared-events.ts +343 -0
- package/src/extensibility/skills.ts +312 -0
- package/src/extensibility/slash-commands.ts +227 -0
- package/src/extensibility/tool-proxy.ts +25 -0
- package/src/extensibility/typebox.ts +418 -0
- package/src/extensibility/utils.ts +44 -0
- package/src/goals/index.ts +3 -0
- package/src/goals/runtime.ts +528 -0
- package/src/goals/state.ts +37 -0
- package/src/goals/tools/goal-tool.ts +251 -0
- package/src/hindsight/backend.ts +354 -0
- package/src/hindsight/bank.ts +156 -0
- package/src/hindsight/client.ts +598 -0
- package/src/hindsight/config.ts +175 -0
- package/src/hindsight/content.ts +210 -0
- package/src/hindsight/index.ts +8 -0
- package/src/hindsight/mental-models.ts +429 -0
- package/src/hindsight/seeds.json +32 -0
- package/src/hindsight/state.ts +488 -0
- package/src/hindsight/transcript.ts +71 -0
- package/src/index.ts +59 -0
- package/src/internal-urls/agent-protocol.ts +146 -0
- package/src/internal-urls/artifact-protocol.ts +107 -0
- package/src/internal-urls/docs-index.generated.ts +106 -0
- package/src/internal-urls/history-protocol.ts +113 -0
- package/src/internal-urls/index.ts +25 -0
- package/src/internal-urls/issue-pr-protocol.ts +584 -0
- package/src/internal-urls/json-query.ts +126 -0
- package/src/internal-urls/local-protocol.ts +287 -0
- package/src/internal-urls/mcp-protocol.ts +151 -0
- package/src/internal-urls/memory-protocol.ts +169 -0
- package/src/internal-urls/omp-protocol.ts +93 -0
- package/src/internal-urls/parse.ts +72 -0
- package/src/internal-urls/registry-helpers.ts +25 -0
- package/src/internal-urls/router.ts +105 -0
- package/src/internal-urls/rule-protocol.ts +45 -0
- package/src/internal-urls/skill-protocol.ts +96 -0
- package/src/internal-urls/types.ts +152 -0
- package/src/internal-urls/vault-protocol.ts +936 -0
- package/src/irc/bus.ts +292 -0
- package/src/lib/xai-http.ts +124 -0
- package/src/lsp/client.ts +1193 -0
- package/src/lsp/clients/biome-client.ts +264 -0
- package/src/lsp/clients/index.ts +50 -0
- package/src/lsp/clients/lsp-linter-client.ts +93 -0
- package/src/lsp/clients/swiftlint-client.ts +120 -0
- package/src/lsp/config.ts +502 -0
- package/src/lsp/defaults.json +493 -0
- package/src/lsp/diagnostics-ledger.ts +51 -0
- package/src/lsp/edits.ts +267 -0
- package/src/lsp/index.ts +2477 -0
- package/src/lsp/lspmux.ts +233 -0
- package/src/lsp/render.ts +694 -0
- package/src/lsp/startup-events.ts +13 -0
- package/src/lsp/types.ts +455 -0
- package/src/lsp/utils.ts +718 -0
- package/src/main.ts +1325 -0
- package/src/mcp/client.ts +484 -0
- package/src/mcp/config-writer.ts +225 -0
- package/src/mcp/config.ts +365 -0
- package/src/mcp/index.ts +29 -0
- package/src/mcp/json-rpc.ts +122 -0
- package/src/mcp/loader.ts +124 -0
- package/src/mcp/manager.ts +1275 -0
- package/src/mcp/oauth-discovery.ts +442 -0
- package/src/mcp/oauth-flow.ts +442 -0
- package/src/mcp/render.ts +132 -0
- package/src/mcp/smithery-auth.ts +104 -0
- package/src/mcp/smithery-connect.ts +145 -0
- package/src/mcp/smithery-registry.ts +477 -0
- package/src/mcp/timeout.ts +59 -0
- package/src/mcp/tool-bridge.ts +426 -0
- package/src/mcp/tool-cache.ts +117 -0
- package/src/mcp/transports/http.ts +519 -0
- package/src/mcp/transports/index.ts +6 -0
- package/src/mcp/transports/stdio.ts +528 -0
- package/src/mcp/types.ts +423 -0
- package/src/memories/index.ts +1150 -0
- package/src/memories/storage.ts +577 -0
- package/src/memory-backend/index.ts +18 -0
- package/src/memory-backend/local-backend.ts +39 -0
- package/src/memory-backend/off-backend.ts +25 -0
- package/src/memory-backend/resolve.ts +25 -0
- package/src/memory-backend/runtime.ts +66 -0
- package/src/memory-backend/types.ts +166 -0
- package/src/mnemopi/backend.ts +547 -0
- package/src/mnemopi/config.ts +160 -0
- package/src/mnemopi/index.ts +3 -0
- package/src/mnemopi/state.ts +584 -0
- package/src/modes/acp/acp-agent.ts +2407 -0
- package/src/modes/acp/acp-client-bridge.ts +154 -0
- package/src/modes/acp/acp-event-mapper.ts +929 -0
- package/src/modes/acp/acp-mode.ts +23 -0
- package/src/modes/acp/index.ts +2 -0
- package/src/modes/acp/terminal-auth.ts +37 -0
- package/src/modes/components/agent-dashboard.ts +1206 -0
- package/src/modes/components/agent-hub.ts +1071 -0
- package/src/modes/components/assistant-message.ts +307 -0
- package/src/modes/components/bash-execution.ts +220 -0
- package/src/modes/components/bordered-loader.ts +41 -0
- package/src/modes/components/branch-summary-message.ts +45 -0
- package/src/modes/components/btw-panel.ts +104 -0
- package/src/modes/components/chat-block.ts +111 -0
- package/src/modes/components/compaction-summary-message.ts +87 -0
- package/src/modes/components/copy-selector.ts +206 -0
- package/src/modes/components/countdown-timer.ts +75 -0
- package/src/modes/components/custom-editor.ts +398 -0
- package/src/modes/components/custom-message.ts +63 -0
- package/src/modes/components/diff.ts +277 -0
- package/src/modes/components/dynamic-border.ts +34 -0
- package/src/modes/components/error-banner.ts +33 -0
- package/src/modes/components/eval-execution.ts +158 -0
- package/src/modes/components/execution-shared.ts +101 -0
- package/src/modes/components/extensions/extension-dashboard.ts +399 -0
- package/src/modes/components/extensions/extension-list.ts +502 -0
- package/src/modes/components/extensions/index.ts +9 -0
- package/src/modes/components/extensions/inspector-panel.ts +317 -0
- package/src/modes/components/extensions/state-manager.ts +627 -0
- package/src/modes/components/extensions/types.ts +186 -0
- package/src/modes/components/footer.ts +274 -0
- package/src/modes/components/history-search.ts +280 -0
- package/src/modes/components/hook-editor.ts +167 -0
- package/src/modes/components/hook-input.ts +87 -0
- package/src/modes/components/hook-message.ts +66 -0
- package/src/modes/components/hook-selector.ts +660 -0
- package/src/modes/components/index.ts +38 -0
- package/src/modes/components/keybinding-hints.ts +65 -0
- package/src/modes/components/late-diagnostics-message.ts +60 -0
- package/src/modes/components/login-dialog.ts +164 -0
- package/src/modes/components/mcp-add-wizard.ts +1340 -0
- package/src/modes/components/message-frame.ts +88 -0
- package/src/modes/components/model-selector.ts +1271 -0
- package/src/modes/components/oauth-selector.ts +368 -0
- package/src/modes/components/omfg-panel.ts +141 -0
- package/src/modes/components/overlay-box.ts +108 -0
- package/src/modes/components/plan-review-overlay.ts +820 -0
- package/src/modes/components/plan-toc.ts +138 -0
- package/src/modes/components/plugin-selector.ts +95 -0
- package/src/modes/components/plugin-settings.ts +722 -0
- package/src/modes/components/queue-mode-selector.ts +56 -0
- package/src/modes/components/read-tool-group.ts +670 -0
- package/src/modes/components/segment-track.ts +52 -0
- package/src/modes/components/session-selector.ts +625 -0
- package/src/modes/components/settings-defs.ts +189 -0
- package/src/modes/components/settings-selector.ts +651 -0
- package/src/modes/components/show-images-selector.ts +45 -0
- package/src/modes/components/skill-message.ts +89 -0
- package/src/modes/components/status-line/component.ts +869 -0
- package/src/modes/components/status-line/context-thresholds.ts +79 -0
- package/src/modes/components/status-line/git-utils.ts +42 -0
- package/src/modes/components/status-line/index.ts +5 -0
- package/src/modes/components/status-line/presets.ts +106 -0
- package/src/modes/components/status-line/segments.ts +584 -0
- package/src/modes/components/status-line/separators.ts +55 -0
- package/src/modes/components/status-line/token-rate.ts +66 -0
- package/src/modes/components/status-line/types.ts +108 -0
- package/src/modes/components/theme-selector.ts +63 -0
- package/src/modes/components/thinking-selector.ts +52 -0
- package/src/modes/components/tiny-title-download-progress.ts +90 -0
- package/src/modes/components/tips.txt +19 -0
- package/src/modes/components/todo-reminder.ts +38 -0
- package/src/modes/components/tool-execution.ts +1024 -0
- package/src/modes/components/transcript-container.ts +608 -0
- package/src/modes/components/tree-selector.ts +978 -0
- package/src/modes/components/ttsr-notification.ts +122 -0
- package/src/modes/components/user-message-selector.ts +227 -0
- package/src/modes/components/user-message.ts +66 -0
- package/src/modes/components/visual-truncate.ts +63 -0
- package/src/modes/components/welcome.ts +493 -0
- package/src/modes/controllers/btw-controller.ts +105 -0
- package/src/modes/controllers/command-controller-shared.ts +109 -0
- package/src/modes/controllers/command-controller.ts +1566 -0
- package/src/modes/controllers/event-controller.ts +1054 -0
- package/src/modes/controllers/extension-ui-controller.ts +886 -0
- package/src/modes/controllers/input-controller.ts +1073 -0
- package/src/modes/controllers/mcp-command-controller.ts +2017 -0
- package/src/modes/controllers/omfg-controller.ts +283 -0
- package/src/modes/controllers/omfg-rule.ts +647 -0
- package/src/modes/controllers/selector-controller.ts +1108 -0
- package/src/modes/controllers/ssh-command-controller.ts +384 -0
- package/src/modes/controllers/streaming-reveal.ts +279 -0
- package/src/modes/controllers/tan-command-controller.ts +173 -0
- package/src/modes/controllers/todo-command-controller.ts +485 -0
- package/src/modes/data/emojis.json +1 -0
- package/src/modes/emoji-autocomplete.ts +285 -0
- package/src/modes/gradient-highlight.ts +87 -0
- package/src/modes/image-references.ts +117 -0
- package/src/modes/index.ts +17 -0
- package/src/modes/interactive-mode.ts +3370 -0
- package/src/modes/internal-url-autocomplete.ts +143 -0
- package/src/modes/loop-limit.ts +140 -0
- package/src/modes/magic-keywords.ts +20 -0
- package/src/modes/markdown-prose.ts +247 -0
- package/src/modes/oauth-manual-input.ts +69 -0
- package/src/modes/orchestrate.ts +42 -0
- package/src/modes/print-mode.ts +126 -0
- package/src/modes/prompt-action-autocomplete.ts +260 -0
- package/src/modes/rpc/host-tools.ts +186 -0
- package/src/modes/rpc/host-uris.ts +235 -0
- package/src/modes/rpc/rpc-client.ts +963 -0
- package/src/modes/rpc/rpc-mode.ts +947 -0
- package/src/modes/rpc/rpc-subagents.ts +265 -0
- package/src/modes/rpc/rpc-types.ts +458 -0
- package/src/modes/runtime-init.ts +116 -0
- package/src/modes/session-observer-registry.ts +146 -0
- package/src/modes/setup-version.ts +11 -0
- package/src/modes/setup-wizard/index.ts +99 -0
- package/src/modes/setup-wizard/lazy.ts +16 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +96 -0
- package/src/modes/setup-wizard/scenes/outro.ts +35 -0
- package/src/modes/setup-wizard/scenes/providers.ts +69 -0
- package/src/modes/setup-wizard/scenes/sign-in.ts +205 -0
- package/src/modes/setup-wizard/scenes/splash.ts +201 -0
- package/src/modes/setup-wizard/scenes/theme.ts +299 -0
- package/src/modes/setup-wizard/scenes/types.ts +48 -0
- package/src/modes/setup-wizard/scenes/web-search.ts +129 -0
- package/src/modes/setup-wizard/wizard-overlay.ts +275 -0
- package/src/modes/shared.ts +47 -0
- package/src/modes/theme/dark.json +95 -0
- package/src/modes/theme/defaults/alabaster.json +93 -0
- package/src/modes/theme/defaults/amethyst.json +96 -0
- package/src/modes/theme/defaults/anthracite.json +93 -0
- package/src/modes/theme/defaults/basalt.json +91 -0
- package/src/modes/theme/defaults/birch.json +95 -0
- package/src/modes/theme/defaults/dark-abyss.json +91 -0
- package/src/modes/theme/defaults/dark-arctic.json +104 -0
- package/src/modes/theme/defaults/dark-aurora.json +95 -0
- package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
- package/src/modes/theme/defaults/dark-cavern.json +91 -0
- package/src/modes/theme/defaults/dark-copper.json +95 -0
- package/src/modes/theme/defaults/dark-cosmos.json +90 -0
- package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
- package/src/modes/theme/defaults/dark-dracula.json +98 -0
- package/src/modes/theme/defaults/dark-eclipse.json +91 -0
- package/src/modes/theme/defaults/dark-ember.json +95 -0
- package/src/modes/theme/defaults/dark-equinox.json +90 -0
- package/src/modes/theme/defaults/dark-forest.json +96 -0
- package/src/modes/theme/defaults/dark-github.json +105 -0
- package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
- package/src/modes/theme/defaults/dark-lavender.json +95 -0
- package/src/modes/theme/defaults/dark-lunar.json +89 -0
- package/src/modes/theme/defaults/dark-midnight.json +95 -0
- package/src/modes/theme/defaults/dark-monochrome.json +94 -0
- package/src/modes/theme/defaults/dark-monokai.json +98 -0
- package/src/modes/theme/defaults/dark-nebula.json +90 -0
- package/src/modes/theme/defaults/dark-nord.json +97 -0
- package/src/modes/theme/defaults/dark-ocean.json +101 -0
- package/src/modes/theme/defaults/dark-one.json +100 -0
- package/src/modes/theme/defaults/dark-poimandres.json +142 -0
- package/src/modes/theme/defaults/dark-rainforest.json +91 -0
- package/src/modes/theme/defaults/dark-reef.json +91 -0
- package/src/modes/theme/defaults/dark-retro.json +92 -0
- package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
- package/src/modes/theme/defaults/dark-sakura.json +95 -0
- package/src/modes/theme/defaults/dark-slate.json +95 -0
- package/src/modes/theme/defaults/dark-solarized.json +97 -0
- package/src/modes/theme/defaults/dark-solstice.json +90 -0
- package/src/modes/theme/defaults/dark-starfall.json +91 -0
- package/src/modes/theme/defaults/dark-sunset.json +99 -0
- package/src/modes/theme/defaults/dark-swamp.json +90 -0
- package/src/modes/theme/defaults/dark-synthwave.json +103 -0
- package/src/modes/theme/defaults/dark-taiga.json +91 -0
- package/src/modes/theme/defaults/dark-terminal.json +95 -0
- package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
- package/src/modes/theme/defaults/dark-tundra.json +91 -0
- package/src/modes/theme/defaults/dark-twilight.json +91 -0
- package/src/modes/theme/defaults/dark-volcanic.json +91 -0
- package/src/modes/theme/defaults/graphite.json +92 -0
- package/src/modes/theme/defaults/index.ts +199 -0
- package/src/modes/theme/defaults/light-arctic.json +107 -0
- package/src/modes/theme/defaults/light-aurora-day.json +91 -0
- package/src/modes/theme/defaults/light-canyon.json +91 -0
- package/src/modes/theme/defaults/light-catppuccin.json +106 -0
- package/src/modes/theme/defaults/light-cirrus.json +90 -0
- package/src/modes/theme/defaults/light-coral.json +95 -0
- package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
- package/src/modes/theme/defaults/light-dawn.json +90 -0
- package/src/modes/theme/defaults/light-dunes.json +91 -0
- package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
- package/src/modes/theme/defaults/light-forest.json +100 -0
- package/src/modes/theme/defaults/light-frost.json +95 -0
- package/src/modes/theme/defaults/light-github.json +115 -0
- package/src/modes/theme/defaults/light-glacier.json +91 -0
- package/src/modes/theme/defaults/light-gruvbox.json +108 -0
- package/src/modes/theme/defaults/light-haze.json +90 -0
- package/src/modes/theme/defaults/light-honeycomb.json +95 -0
- package/src/modes/theme/defaults/light-lagoon.json +91 -0
- package/src/modes/theme/defaults/light-lavender.json +95 -0
- package/src/modes/theme/defaults/light-meadow.json +91 -0
- package/src/modes/theme/defaults/light-mint.json +95 -0
- package/src/modes/theme/defaults/light-monochrome.json +101 -0
- package/src/modes/theme/defaults/light-ocean.json +99 -0
- package/src/modes/theme/defaults/light-one.json +99 -0
- package/src/modes/theme/defaults/light-opal.json +91 -0
- package/src/modes/theme/defaults/light-orchard.json +91 -0
- package/src/modes/theme/defaults/light-paper.json +95 -0
- package/src/modes/theme/defaults/light-poimandres.json +142 -0
- package/src/modes/theme/defaults/light-prism.json +90 -0
- package/src/modes/theme/defaults/light-retro.json +98 -0
- package/src/modes/theme/defaults/light-sand.json +95 -0
- package/src/modes/theme/defaults/light-savanna.json +91 -0
- package/src/modes/theme/defaults/light-solarized.json +102 -0
- package/src/modes/theme/defaults/light-soleil.json +90 -0
- package/src/modes/theme/defaults/light-sunset.json +99 -0
- package/src/modes/theme/defaults/light-synthwave.json +98 -0
- package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
- package/src/modes/theme/defaults/light-wetland.json +91 -0
- package/src/modes/theme/defaults/light-zenith.json +89 -0
- package/src/modes/theme/defaults/limestone.json +94 -0
- package/src/modes/theme/defaults/mahogany.json +97 -0
- package/src/modes/theme/defaults/marble.json +93 -0
- package/src/modes/theme/defaults/obsidian.json +91 -0
- package/src/modes/theme/defaults/onyx.json +91 -0
- package/src/modes/theme/defaults/pearl.json +93 -0
- package/src/modes/theme/defaults/porcelain.json +91 -0
- package/src/modes/theme/defaults/quartz.json +96 -0
- package/src/modes/theme/defaults/sandstone.json +95 -0
- package/src/modes/theme/defaults/titanium.json +90 -0
- package/src/modes/theme/light.json +93 -0
- package/src/modes/theme/mermaid-cache.ts +29 -0
- package/src/modes/theme/shimmer.ts +235 -0
- package/src/modes/theme/theme-schema.json +459 -0
- package/src/modes/theme/theme.ts +2676 -0
- package/src/modes/turn-budget.ts +31 -0
- package/src/modes/types.ts +359 -0
- package/src/modes/ultrathink.ts +41 -0
- package/src/modes/utils/context-usage.ts +339 -0
- package/src/modes/utils/copy-targets.ts +360 -0
- package/src/modes/utils/hotkeys-markdown.ts +61 -0
- package/src/modes/utils/keybinding-matchers.ts +51 -0
- package/src/modes/utils/tools-markdown.ts +27 -0
- package/src/modes/utils/ui-helpers.ts +801 -0
- package/src/modes/workflow.ts +42 -0
- package/src/plan-mode/approved-plan.ts +186 -0
- package/src/plan-mode/plan-handoff.ts +37 -0
- package/src/plan-mode/plan-protection.ts +31 -0
- package/src/plan-mode/state.ts +6 -0
- package/src/priority.json +41 -0
- package/src/prompts/agents/designer.md +66 -0
- package/src/prompts/agents/explore.md +58 -0
- package/src/prompts/agents/frontmatter.md +11 -0
- package/src/prompts/agents/init.md +33 -0
- package/src/prompts/agents/librarian.md +119 -0
- package/src/prompts/agents/oracle.md +55 -0
- package/src/prompts/agents/plan.md +48 -0
- package/src/prompts/agents/reviewer.md +140 -0
- package/src/prompts/agents/task.md +16 -0
- package/src/prompts/ci-green-request.md +36 -0
- package/src/prompts/dry-balance-bench.md +8 -0
- package/src/prompts/goals/goal-budget-limit.md +16 -0
- package/src/prompts/goals/goal-continuation.md +28 -0
- package/src/prompts/goals/goal-mode-active.md +23 -0
- package/src/prompts/memories/consolidation.md +30 -0
- package/src/prompts/memories/read-path.md +11 -0
- package/src/prompts/memories/stage_one_input.md +6 -0
- package/src/prompts/memories/stage_one_system.md +21 -0
- package/src/prompts/review-custom-request.md +22 -0
- package/src/prompts/review-headless-request.md +16 -0
- package/src/prompts/review-request.md +69 -0
- package/src/prompts/steering/user-interjection.md +10 -0
- package/src/prompts/system/agent-creation-architect.md +50 -0
- package/src/prompts/system/agent-creation-user.md +6 -0
- package/src/prompts/system/auto-continue.md +1 -0
- package/src/prompts/system/auto-thinking-difficulty-local.md +14 -0
- package/src/prompts/system/auto-thinking-difficulty.md +12 -0
- package/src/prompts/system/background-tan-dispatch.md +8 -0
- package/src/prompts/system/btw-user.md +8 -0
- package/src/prompts/system/commit-message-system.md +14 -0
- package/src/prompts/system/custom-system-prompt.md +64 -0
- package/src/prompts/system/eager-todo.md +13 -0
- package/src/prompts/system/empty-stop-retry.md +6 -0
- package/src/prompts/system/irc-incoming.md +7 -0
- package/src/prompts/system/manual-continue.md +7 -0
- package/src/prompts/system/memory-consolidation-system.md +8 -0
- package/src/prompts/system/memory-extraction-system.md +26 -0
- package/src/prompts/system/omfg-user.md +50 -0
- package/src/prompts/system/orchestrate-notice.md +40 -0
- package/src/prompts/system/plan-mode-active.md +109 -0
- package/src/prompts/system/plan-mode-approved.md +25 -0
- package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
- package/src/prompts/system/plan-mode-reference.md +11 -0
- package/src/prompts/system/plan-mode-subagent.md +33 -0
- package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
- package/src/prompts/system/project-prompt.md +52 -0
- package/src/prompts/system/subagent-system-prompt.md +64 -0
- package/src/prompts/system/subagent-user-prompt.md +3 -0
- package/src/prompts/system/subagent-yield-reminder.md +12 -0
- package/src/prompts/system/system-prompt.md +258 -0
- package/src/prompts/system/tiny-title-system.md +8 -0
- package/src/prompts/system/title-system.md +16 -0
- package/src/prompts/system/ttsr-interrupt.md +7 -0
- package/src/prompts/system/ttsr-tool-reminder.md +5 -0
- package/src/prompts/system/ultrathink-notice.md +3 -0
- package/src/prompts/system/web-search.md +25 -0
- package/src/prompts/system/workflow-notice.md +70 -0
- package/src/prompts/tools/apply-patch.md +65 -0
- package/src/prompts/tools/ask.md +30 -0
- package/src/prompts/tools/ast-edit.md +39 -0
- package/src/prompts/tools/ast-grep.md +42 -0
- package/src/prompts/tools/async-result.md +8 -0
- package/src/prompts/tools/bash.md +46 -0
- package/src/prompts/tools/browser.md +73 -0
- package/src/prompts/tools/checkpoint.md +16 -0
- package/src/prompts/tools/debug.md +34 -0
- package/src/prompts/tools/eval.md +92 -0
- package/src/prompts/tools/find.md +36 -0
- package/src/prompts/tools/github.md +21 -0
- package/src/prompts/tools/goal.md +18 -0
- package/src/prompts/tools/image-gen.md +7 -0
- package/src/prompts/tools/inspect-image-system.md +20 -0
- package/src/prompts/tools/inspect-image.md +32 -0
- package/src/prompts/tools/irc.md +59 -0
- package/src/prompts/tools/job.md +19 -0
- package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
- package/src/prompts/tools/lsp.md +42 -0
- package/src/prompts/tools/memory-edit.md +8 -0
- package/src/prompts/tools/patch.md +70 -0
- package/src/prompts/tools/read.md +84 -0
- package/src/prompts/tools/recall.md +5 -0
- package/src/prompts/tools/reflect.md +5 -0
- package/src/prompts/tools/render-mermaid.md +9 -0
- package/src/prompts/tools/replace.md +30 -0
- package/src/prompts/tools/resolve.md +9 -0
- package/src/prompts/tools/retain.md +6 -0
- package/src/prompts/tools/rewind.md +13 -0
- package/src/prompts/tools/search-tool-bm25.md +32 -0
- package/src/prompts/tools/search.md +24 -0
- package/src/prompts/tools/ssh.md +31 -0
- package/src/prompts/tools/task-summary.md +17 -0
- package/src/prompts/tools/task.md +88 -0
- package/src/prompts/tools/todo.md +62 -0
- package/src/prompts/tools/web-search.md +10 -0
- package/src/prompts/tools/write.md +14 -0
- package/src/registry/agent-lifecycle.ts +218 -0
- package/src/registry/agent-registry.ts +151 -0
- package/src/sdk.ts +2558 -0
- package/src/secrets/index.ts +123 -0
- package/src/secrets/obfuscator.ts +298 -0
- package/src/secrets/regex.ts +21 -0
- package/src/session/agent-session.ts +10121 -0
- package/src/session/agent-storage.ts +455 -0
- package/src/session/artifacts.ts +135 -0
- package/src/session/auth-broker-config.ts +131 -0
- package/src/session/auth-storage.ts +29 -0
- package/src/session/blob-store.ts +255 -0
- package/src/session/client-bridge.ts +85 -0
- package/src/session/history-storage.ts +348 -0
- package/src/session/indexed-session-storage.ts +430 -0
- package/src/session/messages.ts +541 -0
- package/src/session/redis-session-storage.ts +170 -0
- package/src/session/session-dump-format.ts +209 -0
- package/src/session/session-history-format.ts +246 -0
- package/src/session/session-manager.ts +3676 -0
- package/src/session/session-storage.ts +529 -0
- package/src/session/shake-types.ts +43 -0
- package/src/session/sql-session-storage.ts +314 -0
- package/src/session/streaming-output.ts +1330 -0
- package/src/session/tool-choice-queue.ts +213 -0
- package/src/session/yield-queue.ts +173 -0
- package/src/slash-commands/acp-builtins.ts +70 -0
- package/src/slash-commands/builtin-registry.ts +1798 -0
- package/src/slash-commands/helpers/context-report.ts +39 -0
- package/src/slash-commands/helpers/format.ts +46 -0
- package/src/slash-commands/helpers/marketplace-manager.ts +25 -0
- package/src/slash-commands/helpers/mcp.ts +532 -0
- package/src/slash-commands/helpers/parse.ts +85 -0
- package/src/slash-commands/helpers/ssh.ts +195 -0
- package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
- package/src/slash-commands/helpers/todo.ts +279 -0
- package/src/slash-commands/helpers/usage-report.ts +95 -0
- package/src/slash-commands/marketplace-install-parser.ts +99 -0
- package/src/slash-commands/types.ts +135 -0
- package/src/ssh/config-writer.ts +183 -0
- package/src/ssh/connection-manager.ts +509 -0
- package/src/ssh/ssh-executor.ts +189 -0
- package/src/ssh/sshfs-mount.ts +140 -0
- package/src/ssh/utils.ts +8 -0
- package/src/stt/downloader.ts +71 -0
- package/src/stt/index.ts +3 -0
- package/src/stt/recorder.ts +351 -0
- package/src/stt/setup.ts +52 -0
- package/src/stt/stt-controller.ts +160 -0
- package/src/stt/transcribe.py +70 -0
- package/src/stt/transcriber.ts +91 -0
- package/src/stubs/natives/index.ts +814 -0
- package/src/stubs/natives/package.json +7 -0
- package/src/stubs/tui/index.ts +282 -0
- package/src/stubs/tui/package.json +7 -0
- package/src/system-prompt.ts +611 -0
- package/src/task/agents.ts +167 -0
- package/src/task/commands.ts +132 -0
- package/src/task/discovery.ts +122 -0
- package/src/task/executor.ts +2133 -0
- package/src/task/index.ts +1419 -0
- package/src/task/name-generator.ts +1577 -0
- package/src/task/omp-command.ts +26 -0
- package/src/task/output-manager.ts +88 -0
- package/src/task/parallel.ts +116 -0
- package/src/task/render.ts +1381 -0
- package/src/task/repair-args.ts +129 -0
- package/src/task/subprocess-tool-registry.ts +88 -0
- package/src/task/types.ts +336 -0
- package/src/task/worktree.ts +514 -0
- package/src/telemetry-export.ts +144 -0
- package/src/thinking.ts +167 -0
- package/src/tiny/compiled-runtime.ts +179 -0
- package/src/tiny/device.ts +111 -0
- package/src/tiny/dtype.ts +101 -0
- package/src/tiny/models.ts +242 -0
- package/src/tiny/text.ts +165 -0
- package/src/tiny/title-client.ts +543 -0
- package/src/tiny/title-protocol.ts +56 -0
- package/src/tiny/worker.ts +568 -0
- package/src/tool-discovery/mode.ts +24 -0
- package/src/tool-discovery/tool-index.ts +256 -0
- package/src/tools/approval.ts +189 -0
- package/src/tools/archive-reader.ts +721 -0
- package/src/tools/ask.ts +928 -0
- package/src/tools/ast-edit.ts +642 -0
- package/src/tools/ast-grep.ts +452 -0
- package/src/tools/auto-generated-guard.ts +322 -0
- package/src/tools/bash-command-fixup.ts +37 -0
- package/src/tools/bash-interactive.ts +408 -0
- package/src/tools/bash-interceptor.ts +67 -0
- package/src/tools/bash-pty-selection.ts +14 -0
- package/src/tools/bash-skill-urls.ts +248 -0
- package/src/tools/bash.ts +1386 -0
- package/src/tools/browser/attach.ts +175 -0
- package/src/tools/browser/launch.ts +660 -0
- package/src/tools/browser/readable.ts +112 -0
- package/src/tools/browser/registry.ts +197 -0
- package/src/tools/browser/render.ts +216 -0
- package/src/tools/browser/tab-protocol.ts +105 -0
- package/src/tools/browser/tab-supervisor.ts +628 -0
- package/src/tools/browser/tab-worker-entry.ts +21 -0
- package/src/tools/browser/tab-worker.ts +1226 -0
- package/src/tools/browser.ts +343 -0
- package/src/tools/checkpoint.ts +136 -0
- package/src/tools/conflict-detect.ts +718 -0
- package/src/tools/context.ts +39 -0
- package/src/tools/debug.ts +1067 -0
- package/src/tools/eval-backends.ts +27 -0
- package/src/tools/eval-render.ts +752 -0
- package/src/tools/eval.ts +577 -0
- package/src/tools/fetch.ts +1926 -0
- package/src/tools/file-recorder.ts +35 -0
- package/src/tools/find.ts +609 -0
- package/src/tools/fs-cache-invalidation.ts +28 -0
- package/src/tools/gh-cache-invalidation.ts +255 -0
- package/src/tools/gh-format.ts +12 -0
- package/src/tools/gh-renderer.ts +481 -0
- package/src/tools/gh.ts +3720 -0
- package/src/tools/github-cache.ts +637 -0
- package/src/tools/grouped-file-output.ts +210 -0
- package/src/tools/image-gen.ts +1517 -0
- package/src/tools/index.ts +599 -0
- package/src/tools/inspect-image-renderer.ts +132 -0
- package/src/tools/inspect-image.ts +174 -0
- package/src/tools/irc.ts +723 -0
- package/src/tools/job.ts +557 -0
- package/src/tools/json-tree.ts +243 -0
- package/src/tools/jtd-to-json-schema.ts +219 -0
- package/src/tools/jtd-to-typescript.ts +136 -0
- package/src/tools/jtd-utils.ts +102 -0
- package/src/tools/list-limit.ts +40 -0
- package/src/tools/match-line-format.ts +20 -0
- package/src/tools/memory-edit.ts +59 -0
- package/src/tools/memory-recall.ts +100 -0
- package/src/tools/memory-reflect.ts +88 -0
- package/src/tools/memory-render.ts +202 -0
- package/src/tools/memory-retain.ts +91 -0
- package/src/tools/output-meta.ts +754 -0
- package/src/tools/output-schema-validator.ts +132 -0
- package/src/tools/path-utils.ts +1054 -0
- package/src/tools/plan-mode-guard.ts +108 -0
- package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
- package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
- package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
- package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
- package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
- package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
- package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
- package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
- package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
- package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
- package/src/tools/puppeteer/10_stealth_plugins.txt +206 -0
- package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
- package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
- package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
- package/src/tools/read.ts +2929 -0
- package/src/tools/render-mermaid.ts +69 -0
- package/src/tools/render-utils.ts +838 -0
- package/src/tools/renderers.ts +77 -0
- package/src/tools/report-tool-issue.ts +534 -0
- package/src/tools/resolve.ts +276 -0
- package/src/tools/review.ts +253 -0
- package/src/tools/search-tool-bm25.ts +351 -0
- package/src/tools/search.ts +1580 -0
- package/src/tools/sqlite-reader.ts +828 -0
- package/src/tools/ssh.ts +349 -0
- package/src/tools/todo.ts +982 -0
- package/src/tools/tool-errors.ts +62 -0
- package/src/tools/tool-result.ts +94 -0
- package/src/tools/tool-timeouts.ts +30 -0
- package/src/tools/tts.ts +133 -0
- package/src/tools/write.ts +1217 -0
- package/src/tools/yield.ts +269 -0
- package/src/tui/code-cell.ts +216 -0
- package/src/tui/file-list.ts +55 -0
- package/src/tui/hyperlink.ts +175 -0
- package/src/tui/index.ts +12 -0
- package/src/tui/output-block.ts +240 -0
- package/src/tui/status-line.ts +54 -0
- package/src/tui/tree-list.ts +84 -0
- package/src/tui/types.ts +15 -0
- package/src/tui/utils.ts +103 -0
- package/src/utils/block-context.ts +312 -0
- package/src/utils/changelog.ts +132 -0
- package/src/utils/clipboard.ts +193 -0
- package/src/utils/command-args.ts +76 -0
- package/src/utils/commit-message-generator.ts +151 -0
- package/src/utils/edit-mode.ts +41 -0
- package/src/utils/enhanced-paste.ts +230 -0
- package/src/utils/event-bus.ts +33 -0
- package/src/utils/external-editor.ts +65 -0
- package/src/utils/file-display-mode.ts +45 -0
- package/src/utils/file-mentions.ts +281 -0
- package/src/utils/git.ts +1833 -0
- package/src/utils/image-loading.ts +132 -0
- package/src/utils/image-resize.ts +309 -0
- package/src/utils/jj.ts +248 -0
- package/src/utils/lang-from-path.ts +239 -0
- package/src/utils/markit.ts +89 -0
- package/src/utils/open.ts +55 -0
- package/src/utils/session-color.ts +68 -0
- package/src/utils/shell-snapshot.ts +187 -0
- package/src/utils/sixel.ts +69 -0
- package/src/utils/title-generator.ts +373 -0
- package/src/utils/tool-choice.ts +33 -0
- package/src/utils/tools-manager.ts +363 -0
- package/src/web/kagi.ts +305 -0
- package/src/web/parallel.ts +353 -0
- package/src/web/scrapers/artifacthub.ts +207 -0
- package/src/web/scrapers/arxiv.ts +83 -0
- package/src/web/scrapers/aur.ts +162 -0
- package/src/web/scrapers/biorxiv.ts +133 -0
- package/src/web/scrapers/bluesky.ts +262 -0
- package/src/web/scrapers/brew.ts +172 -0
- package/src/web/scrapers/cheatsh.ts +68 -0
- package/src/web/scrapers/chocolatey.ts +196 -0
- package/src/web/scrapers/choosealicense.ts +95 -0
- package/src/web/scrapers/cisa-kev.ts +87 -0
- package/src/web/scrapers/clojars.ts +154 -0
- package/src/web/scrapers/coingecko.ts +177 -0
- package/src/web/scrapers/crates-io.ts +97 -0
- package/src/web/scrapers/crossref.ts +136 -0
- package/src/web/scrapers/devto.ts +147 -0
- package/src/web/scrapers/discogs.ts +306 -0
- package/src/web/scrapers/discourse.ts +197 -0
- package/src/web/scrapers/dockerhub.ts +138 -0
- package/src/web/scrapers/docs-rs.ts +653 -0
- package/src/web/scrapers/fdroid.ts +134 -0
- package/src/web/scrapers/firefox-addons.ts +191 -0
- package/src/web/scrapers/flathub.ts +223 -0
- package/src/web/scrapers/github-gist.ts +58 -0
- package/src/web/scrapers/github.ts +704 -0
- package/src/web/scrapers/gitlab.ts +401 -0
- package/src/web/scrapers/go-pkg.ts +266 -0
- package/src/web/scrapers/hackage.ts +140 -0
- package/src/web/scrapers/hackernews.ts +189 -0
- package/src/web/scrapers/hex.ts +105 -0
- package/src/web/scrapers/huggingface.ts +321 -0
- package/src/web/scrapers/iacr.ts +89 -0
- package/src/web/scrapers/index.ts +252 -0
- package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
- package/src/web/scrapers/lemmy.ts +203 -0
- package/src/web/scrapers/lobsters.ts +175 -0
- package/src/web/scrapers/mastodon.ts +292 -0
- package/src/web/scrapers/maven.ts +138 -0
- package/src/web/scrapers/mdn.ts +173 -0
- package/src/web/scrapers/metacpan.ts +222 -0
- package/src/web/scrapers/musicbrainz.ts +250 -0
- package/src/web/scrapers/npm.ts +98 -0
- package/src/web/scrapers/nuget.ts +183 -0
- package/src/web/scrapers/nvd.ts +222 -0
- package/src/web/scrapers/ollama.ts +239 -0
- package/src/web/scrapers/open-vsx.ts +106 -0
- package/src/web/scrapers/opencorporates.ts +292 -0
- package/src/web/scrapers/openlibrary.ts +336 -0
- package/src/web/scrapers/orcid.ts +286 -0
- package/src/web/scrapers/osv.ts +176 -0
- package/src/web/scrapers/packagist.ts +160 -0
- package/src/web/scrapers/pub-dev.ts +143 -0
- package/src/web/scrapers/pubmed.ts +211 -0
- package/src/web/scrapers/pypi.ts +112 -0
- package/src/web/scrapers/rawg.ts +110 -0
- package/src/web/scrapers/readthedocs.ts +120 -0
- package/src/web/scrapers/reddit.ts +95 -0
- package/src/web/scrapers/repology.ts +251 -0
- package/src/web/scrapers/rfc.ts +201 -0
- package/src/web/scrapers/rubygems.ts +103 -0
- package/src/web/scrapers/searchcode.ts +189 -0
- package/src/web/scrapers/sec-edgar.ts +261 -0
- package/src/web/scrapers/semantic-scholar.ts +171 -0
- package/src/web/scrapers/snapcraft.ts +187 -0
- package/src/web/scrapers/sourcegraph.ts +336 -0
- package/src/web/scrapers/spdx.ts +108 -0
- package/src/web/scrapers/spotify.ts +198 -0
- package/src/web/scrapers/stackoverflow.ts +120 -0
- package/src/web/scrapers/terraform.ts +277 -0
- package/src/web/scrapers/tldr.ts +47 -0
- package/src/web/scrapers/twitter.ts +94 -0
- package/src/web/scrapers/types.ts +397 -0
- package/src/web/scrapers/utils.ts +109 -0
- package/src/web/scrapers/vimeo.ts +133 -0
- package/src/web/scrapers/vscode-marketplace.ts +187 -0
- package/src/web/scrapers/w3c.ts +156 -0
- package/src/web/scrapers/wikidata.ts +344 -0
- package/src/web/scrapers/wikipedia.ts +84 -0
- package/src/web/scrapers/youtube.ts +325 -0
- package/src/web/search/index.ts +292 -0
- package/src/web/search/provider.ts +157 -0
- package/src/web/search/providers/anthropic.ts +318 -0
- package/src/web/search/providers/base.ts +89 -0
- package/src/web/search/providers/brave.ts +152 -0
- package/src/web/search/providers/codex.ts +591 -0
- package/src/web/search/providers/exa.ts +400 -0
- package/src/web/search/providers/gemini.ts +460 -0
- package/src/web/search/providers/jina.ts +111 -0
- package/src/web/search/providers/kagi.ts +86 -0
- package/src/web/search/providers/kimi.ts +196 -0
- package/src/web/search/providers/parallel.ts +225 -0
- package/src/web/search/providers/perplexity.ts +730 -0
- package/src/web/search/providers/searxng.ts +313 -0
- package/src/web/search/providers/synthetic.ts +114 -0
- package/src/web/search/providers/tavily.ts +176 -0
- package/src/web/search/providers/utils.ts +128 -0
- package/src/web/search/providers/zai.ts +333 -0
- package/src/web/search/render.ts +262 -0
- package/src/web/search/types.ts +482 -0
- package/src/web/search/utils.ts +17 -0
- package/src/workspace-tree.ts +286 -0
|
@@ -0,0 +1,1419 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task tool - Delegate tasks to specialized agents.
|
|
3
|
+
*
|
|
4
|
+
* Discovers agent definitions from:
|
|
5
|
+
* - Bundled agents (shipped with omp-coding-agent)
|
|
6
|
+
* - ~/.omp/agent/agents/*.md (user-level)
|
|
7
|
+
* - .omp/agents/*.md (project-level)
|
|
8
|
+
*
|
|
9
|
+
* Supports:
|
|
10
|
+
* - Single agent spawn per call (parallelism = parallel task calls)
|
|
11
|
+
* - Batch spawning + shared context per call when `task.batch` is enabled
|
|
12
|
+
* - Non-blocking execution via the session's AsyncJobManager
|
|
13
|
+
* - Progress tracking via JSON events
|
|
14
|
+
* - Session artifacts for debugging
|
|
15
|
+
*/
|
|
16
|
+
import * as fs from "node:fs/promises";
|
|
17
|
+
import * as os from "node:os";
|
|
18
|
+
import path from "node:path";
|
|
19
|
+
import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
20
|
+
import type { Usage } from "@oh-my-pi/pi-ai";
|
|
21
|
+
import { $env, logger, prompt, Snowflake } from "@oh-my-pi/pi-utils";
|
|
22
|
+
import type { ToolSession } from "..";
|
|
23
|
+
import { resolveAgentModelPatterns } from "../config/model-resolver";
|
|
24
|
+
import { MCPManager } from "../mcp/manager";
|
|
25
|
+
import type { Theme } from "../modes/theme/theme";
|
|
26
|
+
import planModeSubagentPrompt from "../prompts/system/plan-mode-subagent.md" with { type: "text" };
|
|
27
|
+
import subagentUserPromptTemplate from "../prompts/system/subagent-user-prompt.md" with { type: "text" };
|
|
28
|
+
import taskDescriptionTemplate from "../prompts/tools/task.md" with { type: "text" };
|
|
29
|
+
import taskSummaryTemplate from "../prompts/tools/task-summary.md" with { type: "text" };
|
|
30
|
+
import { truncateForPrompt } from "../tools/approval";
|
|
31
|
+
import { isIrcEnabled } from "../tools/irc";
|
|
32
|
+
import { formatBytes, formatDuration } from "../tools/render-utils";
|
|
33
|
+
import {
|
|
34
|
+
type AgentDefinition,
|
|
35
|
+
type AgentProgress,
|
|
36
|
+
getTaskSchema,
|
|
37
|
+
type SingleResult,
|
|
38
|
+
type TaskItem,
|
|
39
|
+
type TaskParams,
|
|
40
|
+
type TaskToolDetails,
|
|
41
|
+
type TaskToolSchemaInstance,
|
|
42
|
+
} from "./types";
|
|
43
|
+
// Import review tools for side effects (registers subagent tool handlers)
|
|
44
|
+
import "../tools/review";
|
|
45
|
+
import type { AsyncJobManager } from "../async";
|
|
46
|
+
import type { LocalProtocolOptions } from "../internal-urls";
|
|
47
|
+
import { loadOverallPlanReference } from "../plan-mode/plan-handoff";
|
|
48
|
+
import { AgentRegistry } from "../registry/agent-registry";
|
|
49
|
+
import { generateCommitMessage } from "../utils/commit-message-generator";
|
|
50
|
+
import * as git from "../utils/git";
|
|
51
|
+
import { type DiscoveryResult, discoverAgents, getAgent } from "./discovery";
|
|
52
|
+
import { runSubprocess } from "./executor";
|
|
53
|
+
import { generateTaskName } from "./name-generator";
|
|
54
|
+
import { AgentOutputManager } from "./output-manager";
|
|
55
|
+
import { mapWithConcurrencyLimit, Semaphore } from "./parallel";
|
|
56
|
+
import { renderResult, renderCall as renderTaskCall } from "./render";
|
|
57
|
+
import { repairTaskParams } from "./repair-args";
|
|
58
|
+
import {
|
|
59
|
+
applyNestedPatches,
|
|
60
|
+
captureBaseline,
|
|
61
|
+
captureDeltaPatch,
|
|
62
|
+
cleanupIsolation,
|
|
63
|
+
cleanupTaskBranches,
|
|
64
|
+
commitToBranch,
|
|
65
|
+
ensureIsolation,
|
|
66
|
+
getRepoRoot,
|
|
67
|
+
type IsolationHandle,
|
|
68
|
+
mergeTaskBranches,
|
|
69
|
+
parseIsolationMode,
|
|
70
|
+
type WorktreeBaseline,
|
|
71
|
+
} from "./worktree";
|
|
72
|
+
|
|
73
|
+
function renderSubagentUserPrompt(assignment: string): string {
|
|
74
|
+
return prompt.render(subagentUserPromptTemplate, {
|
|
75
|
+
assignment: assignment.trim(),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function createUsageTotals(): Usage {
|
|
80
|
+
return {
|
|
81
|
+
input: 0,
|
|
82
|
+
output: 0,
|
|
83
|
+
cacheRead: 0,
|
|
84
|
+
cacheWrite: 0,
|
|
85
|
+
totalTokens: 0,
|
|
86
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function addUsageTotals(target: Usage, usage: Partial<Usage>): void {
|
|
91
|
+
const input = usage.input ?? 0;
|
|
92
|
+
const output = usage.output ?? 0;
|
|
93
|
+
const cacheRead = usage.cacheRead ?? 0;
|
|
94
|
+
const cacheWrite = usage.cacheWrite ?? 0;
|
|
95
|
+
const totalTokens = usage.totalTokens ?? input + output + cacheRead + cacheWrite;
|
|
96
|
+
const cost =
|
|
97
|
+
usage.cost ??
|
|
98
|
+
({
|
|
99
|
+
input: 0,
|
|
100
|
+
output: 0,
|
|
101
|
+
cacheRead: 0,
|
|
102
|
+
cacheWrite: 0,
|
|
103
|
+
total: 0,
|
|
104
|
+
} satisfies Usage["cost"]);
|
|
105
|
+
|
|
106
|
+
target.input += input;
|
|
107
|
+
target.output += output;
|
|
108
|
+
target.cacheRead += cacheRead;
|
|
109
|
+
target.cacheWrite += cacheWrite;
|
|
110
|
+
target.totalTokens += totalTokens;
|
|
111
|
+
target.cost.input += cost.input;
|
|
112
|
+
target.cost.output += cost.output;
|
|
113
|
+
target.cost.cacheRead += cost.cacheRead;
|
|
114
|
+
target.cost.cacheWrite += cost.cacheWrite;
|
|
115
|
+
target.cost.total += cost.total;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Re-export types and utilities
|
|
119
|
+
export { loadBundledAgents as BUNDLED_AGENTS } from "./agents";
|
|
120
|
+
export { discoverCommands, expandCommand, getCommand } from "./commands";
|
|
121
|
+
export { discoverAgents, getAgent } from "./discovery";
|
|
122
|
+
export { AgentOutputManager } from "./output-manager";
|
|
123
|
+
export type {
|
|
124
|
+
AgentDefinition,
|
|
125
|
+
AgentProgress,
|
|
126
|
+
SingleResult,
|
|
127
|
+
SubagentEventPayload,
|
|
128
|
+
SubagentLifecyclePayload,
|
|
129
|
+
SubagentProgressPayload,
|
|
130
|
+
TaskParams,
|
|
131
|
+
TaskToolDetails,
|
|
132
|
+
} from "./types";
|
|
133
|
+
export {
|
|
134
|
+
TASK_SUBAGENT_EVENT_CHANNEL,
|
|
135
|
+
TASK_SUBAGENT_LIFECYCLE_CHANNEL,
|
|
136
|
+
TASK_SUBAGENT_PROGRESS_CHANNEL,
|
|
137
|
+
taskSchema,
|
|
138
|
+
} from "./types";
|
|
139
|
+
|
|
140
|
+
// Built-in tools whose approval tier is "read" (see tool classes' `approval`).
|
|
141
|
+
// An agent is read-only iff its declared tools are a non-empty subset of this set.
|
|
142
|
+
// Fail-safe: any unknown tool makes the agent not read-only.
|
|
143
|
+
export const READ_ONLY_TOOL_NAMES: ReadonlySet<string> = new Set([
|
|
144
|
+
"read",
|
|
145
|
+
"search",
|
|
146
|
+
"find",
|
|
147
|
+
"web_search",
|
|
148
|
+
"ast_grep",
|
|
149
|
+
"yield",
|
|
150
|
+
"irc",
|
|
151
|
+
"ask",
|
|
152
|
+
"job",
|
|
153
|
+
"todo",
|
|
154
|
+
"recall",
|
|
155
|
+
"reflect",
|
|
156
|
+
"retain",
|
|
157
|
+
"memory_edit",
|
|
158
|
+
"render_mermaid",
|
|
159
|
+
"inspect_image",
|
|
160
|
+
"checkpoint",
|
|
161
|
+
"rewind",
|
|
162
|
+
"resolve",
|
|
163
|
+
"report_finding",
|
|
164
|
+
"search_tool_bm25",
|
|
165
|
+
]);
|
|
166
|
+
|
|
167
|
+
const PLAN_MODE_AGENT_TOOL_ALLOWLIST: ReadonlySet<string> = new Set(["ast_grep", "report_finding"]);
|
|
168
|
+
|
|
169
|
+
export function isReadOnlyAgent(agent: AgentDefinition): boolean {
|
|
170
|
+
return !!agent.tools?.length && agent.tools.every(tool => READ_ONLY_TOOL_NAMES.has(tool));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Preview text for a child result. Falls back to "(no output)" — annotated
|
|
175
|
+
* with the request count when the child actually did work, so the parent can
|
|
176
|
+
* tell a no-op child from one that burned requests before being cancelled.
|
|
177
|
+
*/
|
|
178
|
+
export function formatResultOutputFallback(result: Pick<SingleResult, "output" | "stderr" | "requests">): string {
|
|
179
|
+
const base = result.output.trim() || result.stderr.trim();
|
|
180
|
+
if (base) return base;
|
|
181
|
+
return result.requests > 0 ? `(no output) after ${result.requests} req` : "(no output)";
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Render the tool description from a cached agent list and current settings.
|
|
186
|
+
*/
|
|
187
|
+
function renderDescription(
|
|
188
|
+
agents: AgentDefinition[],
|
|
189
|
+
maxConcurrency: number,
|
|
190
|
+
isolationEnabled: boolean,
|
|
191
|
+
disabledAgents: string[],
|
|
192
|
+
batchEnabled: boolean,
|
|
193
|
+
ircEnabled: boolean,
|
|
194
|
+
parentSpawns: string,
|
|
195
|
+
): string {
|
|
196
|
+
const spawningDisabled = parentSpawns === "";
|
|
197
|
+
let filteredAgents = disabledAgents.length > 0 ? agents.filter(a => !disabledAgents.includes(a.name)) : agents;
|
|
198
|
+
if (spawningDisabled) {
|
|
199
|
+
filteredAgents = [];
|
|
200
|
+
} else if (parentSpawns !== "*") {
|
|
201
|
+
const allowed = new Set(
|
|
202
|
+
parentSpawns
|
|
203
|
+
.split(",")
|
|
204
|
+
.map(s => s.trim())
|
|
205
|
+
.filter(Boolean),
|
|
206
|
+
);
|
|
207
|
+
filteredAgents = filteredAgents.filter(a => allowed.has(a.name));
|
|
208
|
+
}
|
|
209
|
+
const renderedAgents = filteredAgents.map(agent => ({
|
|
210
|
+
name: agent.name,
|
|
211
|
+
description: agent.description,
|
|
212
|
+
readOnly: isReadOnlyAgent(agent),
|
|
213
|
+
}));
|
|
214
|
+
return prompt.render(taskDescriptionTemplate, {
|
|
215
|
+
agents: renderedAgents,
|
|
216
|
+
spawningDisabled,
|
|
217
|
+
MAX_CONCURRENCY: maxConcurrency,
|
|
218
|
+
isolationEnabled,
|
|
219
|
+
batchEnabled,
|
|
220
|
+
ircEnabled,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function createTaskModeError(text: string): AgentToolResult<TaskToolDetails> {
|
|
225
|
+
return {
|
|
226
|
+
content: [{ type: "text", text }],
|
|
227
|
+
details: { projectAgentsDir: null, results: [], totalDurationMs: 0 },
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Reject fields the current configuration does not accept. `schema` is never
|
|
233
|
+
* accepted (structured output comes from the agent definition's `output`
|
|
234
|
+
* frontmatter, the inherited session schema, or an eval-workflow
|
|
235
|
+
* `agent(..., schema)` call); `tasks`/`context` require `task.batch`.
|
|
236
|
+
*/
|
|
237
|
+
function validateShapeParams(batchEnabled: boolean, params: TaskParams): string | undefined {
|
|
238
|
+
if ((params as Record<string, unknown>).schema !== undefined) {
|
|
239
|
+
return "The task tool does not accept `schema`. Rely on the selected agent definition's `output` schema or the inherited session schema; workflows needing ad-hoc structured output use eval `agent(prompt, schema)`.";
|
|
240
|
+
}
|
|
241
|
+
if (!batchEnabled) {
|
|
242
|
+
const disallowed = (["tasks", "context"] as const).filter(field => params[field] !== undefined);
|
|
243
|
+
if (disallowed.length > 0) {
|
|
244
|
+
return `task.batch is disabled, so the task tool does not accept ${disallowed.map(f => `\`${f}\``).join(" or ")}. Spawn one agent per call with \`assignment\`, or enable the task.batch setting.`;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return undefined;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Validate the spawn parameter contract against the wire shapes. `agent` is
|
|
252
|
+
* always required. With `task.batch` the model-facing shape is
|
|
253
|
+
* `{ agent, context, tasks[] }` — `tasks` non-empty with per-item assignments
|
|
254
|
+
* and unique ids, `context` non-empty, no top-level `assignment` alongside.
|
|
255
|
+
* The flat `{ agent, ...item }` form stays accepted at runtime under either
|
|
256
|
+
* setting (internal callers, stale transcripts). Returns a problem
|
|
257
|
+
* description, or undefined when valid.
|
|
258
|
+
*/
|
|
259
|
+
function validateSpawnParams(params: TaskParams, batchEnabled: boolean): string | undefined {
|
|
260
|
+
const agent = typeof params.agent === "string" ? params.agent.trim() : "";
|
|
261
|
+
if (!agent) {
|
|
262
|
+
return "Missing `agent`. Provide an agent type to spawn.";
|
|
263
|
+
}
|
|
264
|
+
const hasAssignment = typeof params.assignment === "string" && params.assignment.trim() !== "";
|
|
265
|
+
const tasks = params.tasks;
|
|
266
|
+
if (batchEnabled && tasks !== undefined) {
|
|
267
|
+
if (!Array.isArray(tasks) || tasks.length === 0) {
|
|
268
|
+
return "Missing `tasks`. Provide at least one task item ({ id?, description?, assignment }).";
|
|
269
|
+
}
|
|
270
|
+
if (hasAssignment) {
|
|
271
|
+
return "Top-level `assignment` is not part of the batch shape. Put the work in `tasks[]` items.";
|
|
272
|
+
}
|
|
273
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
274
|
+
const item = tasks[i];
|
|
275
|
+
if (!item || typeof item.assignment !== "string" || item.assignment.trim() === "") {
|
|
276
|
+
return `Task ${i + 1}${item?.id ? ` (\`${item.id}\`)` : ""} is missing \`assignment\`. Every task needs complete, self-contained instructions.`;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const seen = new Map<string, string>();
|
|
280
|
+
for (const item of tasks) {
|
|
281
|
+
const id = item.id?.trim();
|
|
282
|
+
if (!id) continue;
|
|
283
|
+
const key = id.toLowerCase();
|
|
284
|
+
const existing = seen.get(key);
|
|
285
|
+
if (existing !== undefined) {
|
|
286
|
+
return `Duplicate task id ${existing === id ? `\`${id}\`` : `\`${existing}\` / \`${id}\``}. Provided ids must be unique within a call (case-insensitive).`;
|
|
287
|
+
}
|
|
288
|
+
seen.set(key, id);
|
|
289
|
+
}
|
|
290
|
+
if (typeof params.context !== "string" || params.context.trim() === "") {
|
|
291
|
+
return "Missing `context`. Provide the shared background for this batch — goal, constraints, and any contract the tasks share.";
|
|
292
|
+
}
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
if (!hasAssignment) {
|
|
296
|
+
return batchEnabled
|
|
297
|
+
? "Missing `tasks`. Provide a `tasks` array (one subagent per item) with a shared `context`."
|
|
298
|
+
: "Missing `assignment`. Provide complete, self-contained instructions for the agent.";
|
|
299
|
+
}
|
|
300
|
+
return undefined;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Normalize a validated call into its spawn list: the `tasks[]` batch when
|
|
305
|
+
* provided, otherwise the single top-level spawn.
|
|
306
|
+
*/
|
|
307
|
+
function resolveSpawnItems(params: TaskParams): TaskItem[] {
|
|
308
|
+
if (Array.isArray(params.tasks) && params.tasks.length > 0) {
|
|
309
|
+
return params.tasks;
|
|
310
|
+
}
|
|
311
|
+
return [{ id: params.id, description: params.description, assignment: params.assignment }];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Per-spawn params handed to the executor path: top-level call fields with the
|
|
316
|
+
* item's identity substituted in. `tasks` never leaks into a spawn; the shared
|
|
317
|
+
* `context` rides along unchanged. Keys are only materialized when present —
|
|
318
|
+
* `#runSpawn` distinguishes an absent `isolated` from an explicit one. The
|
|
319
|
+
* item's `isolated` (batch form) wins over the top-level flag (flat form).
|
|
320
|
+
*/
|
|
321
|
+
function spawnParamsFor(params: TaskParams, item: TaskItem): TaskParams {
|
|
322
|
+
const spawn: TaskParams = { agent: params.agent };
|
|
323
|
+
if (item.id !== undefined) spawn.id = item.id;
|
|
324
|
+
if (item.description !== undefined) spawn.description = item.description;
|
|
325
|
+
if (item.assignment !== undefined) spawn.assignment = item.assignment;
|
|
326
|
+
if (params.context !== undefined) spawn.context = params.context;
|
|
327
|
+
if (item.isolated !== undefined) {
|
|
328
|
+
spawn.isolated = item.isolated;
|
|
329
|
+
} else if ("isolated" in params) {
|
|
330
|
+
spawn.isolated = params.isolated;
|
|
331
|
+
}
|
|
332
|
+
return spawn;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** Sentinel for async jobs whose subagent finished with a failing result; progress is already updated. */
|
|
336
|
+
class TaskJobError extends Error {}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Process-level memo for create-time agent discovery, keyed by resolved cwd.
|
|
340
|
+
*
|
|
341
|
+
* `TaskTool.create` runs for every (sub)agent session in this process and the
|
|
342
|
+
* walk-up + plugin-registry scan in `discoverAgents` is identical for a given
|
|
343
|
+
* cwd, so repeat creations reuse the first scan. Execution-time discovery
|
|
344
|
+
* (`#runSpawn`) intentionally stays fresh. The memo also tracks the live
|
|
345
|
+
* `discoverAgents` binding: test spies swap that binding, which invalidates
|
|
346
|
+
* the memo automatically.
|
|
347
|
+
*/
|
|
348
|
+
const discoveryMemo = new Map<string, Promise<DiscoveryResult>>();
|
|
349
|
+
let discoveryMemoFn: typeof discoverAgents | undefined;
|
|
350
|
+
|
|
351
|
+
function discoverAgentsForCreate(cwd: string): Promise<DiscoveryResult> {
|
|
352
|
+
const fn = discoverAgents;
|
|
353
|
+
if (discoveryMemoFn !== fn) {
|
|
354
|
+
discoveryMemoFn = fn;
|
|
355
|
+
discoveryMemo.clear();
|
|
356
|
+
}
|
|
357
|
+
const key = path.resolve(cwd);
|
|
358
|
+
let pending = discoveryMemo.get(key);
|
|
359
|
+
if (!pending) {
|
|
360
|
+
pending = fn(cwd);
|
|
361
|
+
discoveryMemo.set(key, pending);
|
|
362
|
+
pending.catch(() => {
|
|
363
|
+
if (discoveryMemo.get(key) === pending) discoveryMemo.delete(key);
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
return pending;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
370
|
+
// Tool Class
|
|
371
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Task tool - Delegate tasks to specialized agents.
|
|
375
|
+
*
|
|
376
|
+
* Each call spawns one subagent — or, with `task.batch`, one per `tasks[]`
|
|
377
|
+
* item. Spawning is non-blocking: the call registers AsyncJobManager jobs and
|
|
378
|
+
* returns immediately; each result is delivered when that agent yields.
|
|
379
|
+
*/
|
|
380
|
+
export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetails, Theme> {
|
|
381
|
+
readonly name = "task";
|
|
382
|
+
readonly approval = "exec" as const;
|
|
383
|
+
readonly formatApprovalDetails = (args: unknown): string[] => {
|
|
384
|
+
const params = args as Partial<TaskParams>;
|
|
385
|
+
const lines: string[] = [];
|
|
386
|
+
if (typeof params.agent === "string") {
|
|
387
|
+
lines.push(`Agent: ${truncateForPrompt(params.agent)}`);
|
|
388
|
+
}
|
|
389
|
+
if (typeof params.id === "string" && params.id.trim()) {
|
|
390
|
+
lines.push(`Task: ${truncateForPrompt(params.id)}`);
|
|
391
|
+
}
|
|
392
|
+
if (typeof params.assignment === "string") {
|
|
393
|
+
lines.push(`Assignment:\n${truncateForPrompt(params.assignment)}`);
|
|
394
|
+
}
|
|
395
|
+
if (typeof params.context === "string" && params.context.trim()) {
|
|
396
|
+
lines.push(`Context:\n${truncateForPrompt(params.context)}`);
|
|
397
|
+
}
|
|
398
|
+
const tasks = Array.isArray(params.tasks) ? params.tasks : [];
|
|
399
|
+
const firstTask = tasks[0];
|
|
400
|
+
if (firstTask) {
|
|
401
|
+
if (typeof firstTask.id === "string" && firstTask.id.trim()) {
|
|
402
|
+
lines.push(`Task: ${truncateForPrompt(firstTask.id)}`);
|
|
403
|
+
}
|
|
404
|
+
if (typeof firstTask.assignment === "string") {
|
|
405
|
+
lines.push(`Assignment:\n${truncateForPrompt(firstTask.assignment)}`);
|
|
406
|
+
}
|
|
407
|
+
if (tasks.length > 1) {
|
|
408
|
+
lines.push(`+${tasks.length - 1} more task${tasks.length === 2 ? "" : "s"}`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return lines;
|
|
412
|
+
};
|
|
413
|
+
readonly label = "Task";
|
|
414
|
+
readonly summary = "Spawn a subagent to complete a task in the background";
|
|
415
|
+
readonly strict = true;
|
|
416
|
+
readonly loadMode = "discoverable";
|
|
417
|
+
readonly renderResult = renderResult;
|
|
418
|
+
// Suppress the streaming call preview once a (partial or final) result exists
|
|
419
|
+
// so the task renders as ONE block that transitions in place — not a pending
|
|
420
|
+
// call frame stacked above the result frame. Mirrors `taskToolRenderer`.
|
|
421
|
+
readonly mergeCallAndResult = true;
|
|
422
|
+
readonly #discoveredAgents: AgentDefinition[];
|
|
423
|
+
readonly #blockedAgent: string | undefined;
|
|
424
|
+
/**
|
|
425
|
+
* One semaphore per TaskTool instance (i.e. per session): bounds concurrent
|
|
426
|
+
* subagents across parallel `task` calls within the session. Sized from
|
|
427
|
+
* `task.maxConcurrency` at first use; later setting changes do not resize it.
|
|
428
|
+
*/
|
|
429
|
+
#spawnSemaphore: Semaphore | undefined;
|
|
430
|
+
|
|
431
|
+
get parameters(): TaskToolSchemaInstance {
|
|
432
|
+
const isolationEnabled = this.session.settings.get("task.isolation.mode") !== "none";
|
|
433
|
+
return getTaskSchema({ isolationEnabled, batchEnabled: this.#isBatchEnabled() });
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
renderCall(args: unknown, options: Parameters<typeof renderTaskCall>[1], theme: Theme) {
|
|
437
|
+
return renderTaskCall(repairTaskParams(args as TaskParams), options, theme);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/** Dynamic description that reflects current disabled-agent settings */
|
|
441
|
+
get description(): string {
|
|
442
|
+
const disabledAgents = this.session.settings.get("task.disabledAgents") as string[];
|
|
443
|
+
const maxConcurrency = this.session.settings.get("task.maxConcurrency");
|
|
444
|
+
const isolationMode = this.session.settings.get("task.isolation.mode");
|
|
445
|
+
return renderDescription(
|
|
446
|
+
this.#discoveredAgents,
|
|
447
|
+
maxConcurrency,
|
|
448
|
+
isolationMode !== "none",
|
|
449
|
+
disabledAgents,
|
|
450
|
+
this.#isBatchEnabled(),
|
|
451
|
+
isIrcEnabled(this.session.settings, this.session.taskDepth ?? 0),
|
|
452
|
+
this.session.getSessionSpawns() ?? "*",
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
private constructor(
|
|
456
|
+
private readonly session: ToolSession,
|
|
457
|
+
discoveredAgents: AgentDefinition[],
|
|
458
|
+
) {
|
|
459
|
+
this.#blockedAgent = $env.PI_BLOCKED_AGENT;
|
|
460
|
+
this.#discoveredAgents = discoveredAgents;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
#isBatchEnabled(): boolean {
|
|
464
|
+
return this.session.settings.get("task.batch");
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
#getSpawnSemaphore(): Semaphore {
|
|
468
|
+
this.#spawnSemaphore ??= new Semaphore(this.session.settings.get("task.maxConcurrency"));
|
|
469
|
+
return this.#spawnSemaphore;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Create a TaskTool instance with async agent discovery.
|
|
474
|
+
*/
|
|
475
|
+
static async create(session: ToolSession): Promise<TaskTool> {
|
|
476
|
+
const { agents } = await discoverAgentsForCreate(session.cwd);
|
|
477
|
+
return new TaskTool(session, agents);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
async execute(
|
|
481
|
+
toolCallId: string,
|
|
482
|
+
rawParams: unknown,
|
|
483
|
+
signal?: AbortSignal,
|
|
484
|
+
onUpdate?: AgentToolUpdateCallback<TaskToolDetails>,
|
|
485
|
+
): Promise<AgentToolResult<TaskToolDetails>> {
|
|
486
|
+
const params = repairTaskParams(rawParams as TaskParams);
|
|
487
|
+
const batchEnabled = this.#isBatchEnabled();
|
|
488
|
+
const validationError = validateShapeParams(batchEnabled, params) ?? validateSpawnParams(params, batchEnabled);
|
|
489
|
+
if (validationError) {
|
|
490
|
+
return createTaskModeError(validationError);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const spawnItems = resolveSpawnItems(params);
|
|
494
|
+
const selectedAgent = this.#discoveredAgents.find(agent => agent.name === params.agent);
|
|
495
|
+
const manager = this.session.asyncJobManager;
|
|
496
|
+
if (!manager || selectedAgent?.blocking === true) {
|
|
497
|
+
// Sync fallback: orphaned host that never wired a job manager, or an
|
|
498
|
+
// agent definition that declares `blocking: true`. The session-scoped
|
|
499
|
+
// semaphore still bounds fan-out across parallel task calls.
|
|
500
|
+
if (!manager) {
|
|
501
|
+
logger.warn("task: no AsyncJobManager registered; falling back to sync execution");
|
|
502
|
+
}
|
|
503
|
+
return this.#executeSyncFanout(toolCallId, params, spawnItems, signal, onUpdate);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Resolve agent ids up front so the immediate result can name them.
|
|
507
|
+
const outputManager =
|
|
508
|
+
this.session.agentOutputManager ?? new AgentOutputManager(this.session.getArtifactsDir ?? (() => null));
|
|
509
|
+
const agentLabel = params.agent ?? "task";
|
|
510
|
+
const agentSource = selectedAgent?.source ?? "bundled";
|
|
511
|
+
const spawns: Array<{ agentId: string; item: TaskItem; progress: AgentProgress }> = [];
|
|
512
|
+
for (let index = 0; index < spawnItems.length; index++) {
|
|
513
|
+
const item = spawnItems[index];
|
|
514
|
+
const agentId = await outputManager.allocate(item.id?.trim() || generateTaskName());
|
|
515
|
+
const assignment = (item.assignment ?? "").trim();
|
|
516
|
+
spawns.push({
|
|
517
|
+
agentId,
|
|
518
|
+
item,
|
|
519
|
+
progress: {
|
|
520
|
+
index,
|
|
521
|
+
id: agentId,
|
|
522
|
+
agent: agentLabel,
|
|
523
|
+
agentSource,
|
|
524
|
+
status: "pending",
|
|
525
|
+
task: renderSubagentUserPrompt(assignment),
|
|
526
|
+
assignment,
|
|
527
|
+
description: item.description,
|
|
528
|
+
recentTools: [],
|
|
529
|
+
recentOutput: [],
|
|
530
|
+
toolCount: 0,
|
|
531
|
+
requests: 0,
|
|
532
|
+
tokens: 0,
|
|
533
|
+
cost: 0,
|
|
534
|
+
durationMs: 0,
|
|
535
|
+
},
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// Aggregate async state for the one tool call: every spawn's job reports
|
|
540
|
+
// into the shared progress snapshot; the call stays "running" until all
|
|
541
|
+
// jobs settle, then turns "failed" if any spawn failed. The single-spawn
|
|
542
|
+
// case passes the job's own suggestion through (pre-batch behavior).
|
|
543
|
+
const single = spawns.length === 1;
|
|
544
|
+
let settledCount = 0;
|
|
545
|
+
let failedCount = 0;
|
|
546
|
+
let primaryJobId = spawns[0].agentId;
|
|
547
|
+
const buildAsyncDetails = (state: "running" | "completed" | "failed", jobId: string): TaskToolDetails => ({
|
|
548
|
+
projectAgentsDir: null,
|
|
549
|
+
results: [],
|
|
550
|
+
totalDurationMs: 0,
|
|
551
|
+
progress: spawns.map(spawn => ({ ...spawn.progress })),
|
|
552
|
+
async: {
|
|
553
|
+
state: single ? state : settledCount < spawns.length ? "running" : failedCount > 0 ? "failed" : "completed",
|
|
554
|
+
jobId: single ? jobId : primaryJobId,
|
|
555
|
+
type: "task",
|
|
556
|
+
},
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
const ircEnabled = isIrcEnabled(this.session.settings, this.session.taskDepth ?? 0);
|
|
560
|
+
const started: Array<{ agentId: string; jobId: string; description?: string }> = [];
|
|
561
|
+
const failedSchedules: string[] = [];
|
|
562
|
+
for (const spawn of spawns) {
|
|
563
|
+
try {
|
|
564
|
+
const jobId = this.#registerSpawnJob({
|
|
565
|
+
manager,
|
|
566
|
+
toolCallId,
|
|
567
|
+
spawnParams: spawnParamsFor(params, spawn.item),
|
|
568
|
+
agentId: spawn.agentId,
|
|
569
|
+
progress: spawn.progress,
|
|
570
|
+
ircEnabled,
|
|
571
|
+
buildDetails: buildAsyncDetails,
|
|
572
|
+
onUpdate,
|
|
573
|
+
onSettled: failed => {
|
|
574
|
+
settledCount += 1;
|
|
575
|
+
if (failed) failedCount += 1;
|
|
576
|
+
},
|
|
577
|
+
});
|
|
578
|
+
if (started.length === 0) primaryJobId = jobId;
|
|
579
|
+
started.push({ agentId: spawn.agentId, jobId, description: spawn.item.description });
|
|
580
|
+
} catch (error) {
|
|
581
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
582
|
+
failedSchedules.push(`${spawn.agentId}: ${message}`);
|
|
583
|
+
spawn.progress.status = "failed";
|
|
584
|
+
settledCount += 1;
|
|
585
|
+
failedCount += 1;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (started.length === 0) {
|
|
590
|
+
return {
|
|
591
|
+
content: [
|
|
592
|
+
{
|
|
593
|
+
type: "text",
|
|
594
|
+
text: `Failed to start background task job${single ? "" : "s"}: ${failedSchedules.join("; ")}`,
|
|
595
|
+
},
|
|
596
|
+
],
|
|
597
|
+
details: { projectAgentsDir: null, results: [], totalDurationMs: 0 },
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (single) {
|
|
602
|
+
const { agentId, jobId, description } = started[0];
|
|
603
|
+
const coordinationHint = ircEnabled
|
|
604
|
+
? `DM \`${agentId}\` via \`irc\` to coordinate while it runs; use \`job\` only to inspect (\`list\`), wait (\`poll\`), or cancel a stuck task.`
|
|
605
|
+
: `Use \`job\` to inspect (\`list\`), wait (\`poll\`), or cancel a stuck task.`;
|
|
606
|
+
const descriptionSuffix = description ? ` — ${description}` : "";
|
|
607
|
+
onUpdate?.({
|
|
608
|
+
content: [{ type: "text", text: `Spawned agent \`${agentId}\`...` }],
|
|
609
|
+
details: buildAsyncDetails("running", jobId),
|
|
610
|
+
});
|
|
611
|
+
return {
|
|
612
|
+
content: [
|
|
613
|
+
{
|
|
614
|
+
type: "text",
|
|
615
|
+
text: `Spawned agent \`${agentId}\` (job \`${jobId}\`)${descriptionSuffix}. The result will be delivered when it yields. ${coordinationHint}`,
|
|
616
|
+
},
|
|
617
|
+
],
|
|
618
|
+
details: buildAsyncDetails("running", jobId),
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
const coordinationHint = ircEnabled
|
|
623
|
+
? `DM these ids via \`irc\` to coordinate while they run; use \`job\` only to inspect (\`list\`), wait (\`poll\`), or cancel a stuck task.`
|
|
624
|
+
: `Use \`job\` to inspect (\`list\`), wait (\`poll\`), or cancel a stuck task by id.`;
|
|
625
|
+
const scheduleFailureSummary =
|
|
626
|
+
failedSchedules.length > 0
|
|
627
|
+
? ` Failed to schedule ${failedSchedules.length} spawn${failedSchedules.length === 1 ? "" : "s"}: ${failedSchedules.join("; ")}.`
|
|
628
|
+
: "";
|
|
629
|
+
const startedListing = started
|
|
630
|
+
.map(({ agentId, jobId, description }) => {
|
|
631
|
+
const prefix = `- \`${agentId}\` (job \`${jobId}\`)`;
|
|
632
|
+
return description ? `${prefix} — ${description}` : prefix;
|
|
633
|
+
})
|
|
634
|
+
.join("\n");
|
|
635
|
+
onUpdate?.({
|
|
636
|
+
content: [{ type: "text", text: `Spawned ${started.length} agents...` }],
|
|
637
|
+
details: buildAsyncDetails("running", primaryJobId),
|
|
638
|
+
});
|
|
639
|
+
return {
|
|
640
|
+
content: [
|
|
641
|
+
{
|
|
642
|
+
type: "text",
|
|
643
|
+
text: `Spawned ${started.length} background agents using ${agentLabel}.${scheduleFailureSummary} Each result will be delivered when that agent yields.\n${startedListing}\n${coordinationHint}`,
|
|
644
|
+
},
|
|
645
|
+
],
|
|
646
|
+
details: buildAsyncDetails("running", primaryJobId),
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Register one background job that runs a single spawn to completion and
|
|
652
|
+
* delivers its yield text. The job body mirrors the sync path; `buildDetails`
|
|
653
|
+
* supplies the (possibly batch-shared) progress snapshot and `onSettled`
|
|
654
|
+
* feeds the caller's aggregate counters.
|
|
655
|
+
*/
|
|
656
|
+
#registerSpawnJob(options: {
|
|
657
|
+
manager: AsyncJobManager;
|
|
658
|
+
toolCallId: string;
|
|
659
|
+
spawnParams: TaskParams;
|
|
660
|
+
agentId: string;
|
|
661
|
+
progress: AgentProgress;
|
|
662
|
+
ircEnabled: boolean;
|
|
663
|
+
buildDetails: (state: "running" | "completed" | "failed", jobId: string) => TaskToolDetails;
|
|
664
|
+
onUpdate?: AgentToolUpdateCallback<TaskToolDetails>;
|
|
665
|
+
onSettled?: (failed: boolean) => void;
|
|
666
|
+
}): string {
|
|
667
|
+
const { manager, toolCallId, spawnParams, agentId, progress, ircEnabled, buildDetails, onUpdate, onSettled } =
|
|
668
|
+
options;
|
|
669
|
+
const buildFollowUpHint = (aborted: boolean): string => {
|
|
670
|
+
if (aborted) {
|
|
671
|
+
return `\n\n${agentId} was aborted — transcript at history://${agentId}`;
|
|
672
|
+
}
|
|
673
|
+
const followUp = ircEnabled ? "message it via `irc` to follow up; " : "";
|
|
674
|
+
return `\n\n${agentId} is now idle — ${followUp}transcript at history://${agentId}`;
|
|
675
|
+
};
|
|
676
|
+
return manager.register(
|
|
677
|
+
"task",
|
|
678
|
+
agentId,
|
|
679
|
+
async ({ jobId: ownJobId, signal: runSignal, reportProgress, markRunning }) => {
|
|
680
|
+
const startedAt = Date.now();
|
|
681
|
+
const semaphore = this.#getSpawnSemaphore();
|
|
682
|
+
await semaphore.acquire();
|
|
683
|
+
if (runSignal.aborted) {
|
|
684
|
+
semaphore.release();
|
|
685
|
+
progress.status = "aborted";
|
|
686
|
+
onSettled?.(true);
|
|
687
|
+
throw new Error("Aborted before execution");
|
|
688
|
+
}
|
|
689
|
+
markRunning();
|
|
690
|
+
progress.status = "running";
|
|
691
|
+
await reportProgress(
|
|
692
|
+
`Running background task ${agentId}...`,
|
|
693
|
+
buildDetails("running", ownJobId) as unknown as Record<string, unknown>,
|
|
694
|
+
);
|
|
695
|
+
try {
|
|
696
|
+
const result = await this.#executeSync(toolCallId, spawnParams, runSignal, undefined, agentId);
|
|
697
|
+
const finalText = result.content.find(part => part.type === "text")?.text ?? "(no output)";
|
|
698
|
+
const singleResult = result.details?.results[0];
|
|
699
|
+
// A missing result means the sync path failed at the tool level
|
|
700
|
+
// (results: []) — treat it as a failure, not success.
|
|
701
|
+
const resultFailed = !singleResult || (singleResult.aborted ?? false) || singleResult.exitCode !== 0;
|
|
702
|
+
progress.status = singleResult?.aborted ? "aborted" : resultFailed ? "failed" : "completed";
|
|
703
|
+
progress.durationMs = singleResult?.durationMs ?? Math.max(0, Date.now() - startedAt);
|
|
704
|
+
progress.tokens = singleResult?.tokens ?? 0;
|
|
705
|
+
progress.requests = singleResult?.requests ?? 0;
|
|
706
|
+
progress.contextTokens = singleResult?.contextTokens;
|
|
707
|
+
progress.contextWindow = singleResult?.contextWindow;
|
|
708
|
+
progress.cost = singleResult?.usage?.cost.total ?? 0;
|
|
709
|
+
progress.extractedToolData = singleResult?.extractedToolData;
|
|
710
|
+
progress.retryFailure = singleResult?.retryFailure;
|
|
711
|
+
progress.retryState = undefined;
|
|
712
|
+
onSettled?.(resultFailed);
|
|
713
|
+
const statusText = resultFailed
|
|
714
|
+
? `Background task ${agentId} failed.`
|
|
715
|
+
: `Background task ${agentId} complete.`;
|
|
716
|
+
await reportProgress(
|
|
717
|
+
statusText,
|
|
718
|
+
buildDetails(resultFailed ? "failed" : "completed", ownJobId) as unknown as Record<string, unknown>,
|
|
719
|
+
);
|
|
720
|
+
onUpdate?.({
|
|
721
|
+
content: [{ type: "text", text: statusText }],
|
|
722
|
+
details: buildDetails(resultFailed ? "failed" : "completed", ownJobId),
|
|
723
|
+
});
|
|
724
|
+
const deliveryText = `${finalText}${buildFollowUpHint(singleResult?.aborted === true)}`;
|
|
725
|
+
if (resultFailed) {
|
|
726
|
+
// Mark the job itself failed; the failed agent stays interrogable.
|
|
727
|
+
throw new TaskJobError(deliveryText);
|
|
728
|
+
}
|
|
729
|
+
return deliveryText;
|
|
730
|
+
} catch (error) {
|
|
731
|
+
if (error instanceof TaskJobError) {
|
|
732
|
+
throw error;
|
|
733
|
+
}
|
|
734
|
+
progress.status = "failed";
|
|
735
|
+
progress.durationMs = Math.max(0, Date.now() - startedAt);
|
|
736
|
+
onSettled?.(true);
|
|
737
|
+
const statusText = `Background task ${agentId} failed.`;
|
|
738
|
+
await reportProgress(statusText, buildDetails("failed", ownJobId) as unknown as Record<string, unknown>);
|
|
739
|
+
onUpdate?.({
|
|
740
|
+
content: [{ type: "text", text: statusText }],
|
|
741
|
+
details: buildDetails("failed", ownJobId),
|
|
742
|
+
});
|
|
743
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
744
|
+
const hint = AgentRegistry.global().get(agentId) ? buildFollowUpHint(false) : "";
|
|
745
|
+
throw new TaskJobError(`${message}${hint}`);
|
|
746
|
+
} finally {
|
|
747
|
+
semaphore.release();
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
id: agentId,
|
|
752
|
+
queued: true,
|
|
753
|
+
ownerId: this.session.getAgentId?.() ?? undefined,
|
|
754
|
+
onProgress: (text, details) => {
|
|
755
|
+
const progressDetails = (details as TaskToolDetails | undefined) ?? buildDetails("running", agentId);
|
|
756
|
+
onUpdate?.({ content: [{ type: "text", text }], details: progressDetails });
|
|
757
|
+
},
|
|
758
|
+
},
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Sync fallback fan-out (no job manager, or a `blocking: true` agent): run
|
|
764
|
+
* every spawn to completion inline and merge the per-spawn payloads into a
|
|
765
|
+
* single tool result. The session-scoped semaphore still bounds concurrency
|
|
766
|
+
* across parallel task calls.
|
|
767
|
+
*/
|
|
768
|
+
async #executeSyncFanout(
|
|
769
|
+
toolCallId: string,
|
|
770
|
+
params: TaskParams,
|
|
771
|
+
spawnItems: TaskItem[],
|
|
772
|
+
signal?: AbortSignal,
|
|
773
|
+
onUpdate?: AgentToolUpdateCallback<TaskToolDetails>,
|
|
774
|
+
): Promise<AgentToolResult<TaskToolDetails>> {
|
|
775
|
+
const semaphore = this.#getSpawnSemaphore();
|
|
776
|
+
if (spawnItems.length === 1) {
|
|
777
|
+
await semaphore.acquire();
|
|
778
|
+
try {
|
|
779
|
+
return await this.#executeSync(toolCallId, spawnParamsFor(params, spawnItems[0]), signal, onUpdate);
|
|
780
|
+
} finally {
|
|
781
|
+
semaphore.release();
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
const startTime = Date.now();
|
|
786
|
+
const latestProgress = new Map<number, AgentProgress>();
|
|
787
|
+
const emitCombined = () => {
|
|
788
|
+
onUpdate?.({
|
|
789
|
+
content: [{ type: "text", text: `Running ${spawnItems.length} agents...` }],
|
|
790
|
+
details: {
|
|
791
|
+
projectAgentsDir: null,
|
|
792
|
+
results: [],
|
|
793
|
+
totalDurationMs: Date.now() - startTime,
|
|
794
|
+
progress: Array.from(latestProgress.entries())
|
|
795
|
+
.sort((a, b) => a[0] - b[0])
|
|
796
|
+
.map(([, progress]) => progress),
|
|
797
|
+
},
|
|
798
|
+
});
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
const { results: payloads } = await mapWithConcurrencyLimit(
|
|
802
|
+
spawnItems,
|
|
803
|
+
spawnItems.length,
|
|
804
|
+
async (item, index, workerSignal) => {
|
|
805
|
+
await semaphore.acquire();
|
|
806
|
+
try {
|
|
807
|
+
const itemOnUpdate: AgentToolUpdateCallback<TaskToolDetails> | undefined = onUpdate
|
|
808
|
+
? update => {
|
|
809
|
+
const progress = update.details?.progress?.[0];
|
|
810
|
+
if (progress) {
|
|
811
|
+
latestProgress.set(index, { ...progress, index });
|
|
812
|
+
emitCombined();
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
: undefined;
|
|
816
|
+
return await this.#executeSync(toolCallId, spawnParamsFor(params, item), workerSignal, itemOnUpdate);
|
|
817
|
+
} finally {
|
|
818
|
+
semaphore.release();
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
signal,
|
|
822
|
+
);
|
|
823
|
+
|
|
824
|
+
const results: SingleResult[] = [];
|
|
825
|
+
const contentParts: string[] = [];
|
|
826
|
+
const outputPaths: string[] = [];
|
|
827
|
+
const usageTotals = createUsageTotals();
|
|
828
|
+
let hasUsage = false;
|
|
829
|
+
let projectAgentsDir: string | null = null;
|
|
830
|
+
for (let index = 0; index < spawnItems.length; index++) {
|
|
831
|
+
const payload = payloads[index];
|
|
832
|
+
if (!payload) {
|
|
833
|
+
contentParts.push(`Task ${spawnItems[index].id?.trim() || `#${index + 1}`}: cancelled before start.`);
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
projectAgentsDir ??= payload.details?.projectAgentsDir ?? null;
|
|
837
|
+
const text = payload.content.find(part => part.type === "text")?.text;
|
|
838
|
+
if (text) contentParts.push(text);
|
|
839
|
+
for (const result of payload.details?.results ?? []) {
|
|
840
|
+
results.push({ ...result, index });
|
|
841
|
+
if (result.usage) {
|
|
842
|
+
addUsageTotals(usageTotals, result.usage);
|
|
843
|
+
hasUsage = true;
|
|
844
|
+
}
|
|
845
|
+
if (result.outputPath) outputPaths.push(result.outputPath);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
return {
|
|
850
|
+
content: [{ type: "text", text: contentParts.join("\n\n") }],
|
|
851
|
+
details: {
|
|
852
|
+
projectAgentsDir,
|
|
853
|
+
results,
|
|
854
|
+
totalDurationMs: Date.now() - startTime,
|
|
855
|
+
usage: hasUsage ? usageTotals : undefined,
|
|
856
|
+
outputPaths: outputPaths.length > 0 ? outputPaths : undefined,
|
|
857
|
+
},
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* Synchronous execution of one spawn. Used as the body of every
|
|
863
|
+
* async job and directly by the sync fallback (no job manager / blocking
|
|
864
|
+
* agent) and by in-process callers that need the result inline (e.g. the
|
|
865
|
+
* commit flow's analyze_files tool).
|
|
866
|
+
*/
|
|
867
|
+
async #executeSync(
|
|
868
|
+
toolCallId: string,
|
|
869
|
+
params: TaskParams,
|
|
870
|
+
signal?: AbortSignal,
|
|
871
|
+
onUpdate?: AgentToolUpdateCallback<TaskToolDetails>,
|
|
872
|
+
preAllocatedId?: string,
|
|
873
|
+
): Promise<AgentToolResult<TaskToolDetails>> {
|
|
874
|
+
return this.#runSpawn(toolCallId, params, signal, onUpdate, preAllocatedId);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/** Spawn a fresh subagent and run it to completion. */
|
|
878
|
+
async #runSpawn(
|
|
879
|
+
toolCallId: string,
|
|
880
|
+
params: TaskParams,
|
|
881
|
+
signal?: AbortSignal,
|
|
882
|
+
onUpdate?: AgentToolUpdateCallback<TaskToolDetails>,
|
|
883
|
+
preAllocatedId?: string,
|
|
884
|
+
): Promise<AgentToolResult<TaskToolDetails>> {
|
|
885
|
+
const startTime = Date.now();
|
|
886
|
+
const { agents, projectAgentsDir } = await discoverAgents(this.session.cwd);
|
|
887
|
+
const agentName = params.agent ?? "";
|
|
888
|
+
const sharedContext = this.#isBatchEnabled() ? params.context?.trim() || undefined : undefined;
|
|
889
|
+
const assignment = (params.assignment ?? "").trim();
|
|
890
|
+
const isolationMode = this.session.settings.get("task.isolation.mode");
|
|
891
|
+
const isolationRequested = "isolated" in params ? params.isolated === true : false;
|
|
892
|
+
const isIsolated = isolationMode !== "none" && isolationRequested;
|
|
893
|
+
const mergeMode = this.session.settings.get("task.isolation.merge");
|
|
894
|
+
const commitStyle = this.session.settings.get("task.isolation.commits");
|
|
895
|
+
const taskDepth = this.session.taskDepth ?? 0;
|
|
896
|
+
const subagentLspEnabled = (this.session.enableLsp ?? true) && this.session.settings.get("task.enableLsp");
|
|
897
|
+
|
|
898
|
+
if (isolationMode === "none" && "isolated" in params) {
|
|
899
|
+
return {
|
|
900
|
+
content: [{ type: "text", text: "Task isolation is disabled." }],
|
|
901
|
+
details: { projectAgentsDir, results: [], totalDurationMs: 0 },
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Validate agent exists
|
|
906
|
+
const agent = getAgent(agents, agentName);
|
|
907
|
+
if (!agent) {
|
|
908
|
+
const available = agents.map(a => a.name).join(", ") || "none";
|
|
909
|
+
return {
|
|
910
|
+
content: [{ type: "text", text: `Unknown agent "${agentName}". Available: ${available}` }],
|
|
911
|
+
details: { projectAgentsDir, results: [], totalDurationMs: 0 },
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
// Check if agent is disabled in settings
|
|
916
|
+
const disabledAgents = this.session.settings.get("task.disabledAgents") as string[];
|
|
917
|
+
if (disabledAgents.length > 0 && disabledAgents.includes(agentName)) {
|
|
918
|
+
const enabled = agents.filter(a => !disabledAgents.includes(a.name)).map(a => a.name);
|
|
919
|
+
return {
|
|
920
|
+
content: [
|
|
921
|
+
{
|
|
922
|
+
type: "text",
|
|
923
|
+
text: `Agent "${agentName}" is disabled in settings. Enable it via /agents, or use a different agent type.${enabled.length > 0 ? ` Available: ${enabled.join(", ")}` : ""}`,
|
|
924
|
+
},
|
|
925
|
+
],
|
|
926
|
+
details: { projectAgentsDir, results: [], totalDurationMs: 0 },
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
const planModeState = this.session.getPlanModeState?.();
|
|
931
|
+
const planModeBaseTools = ["read", "search", "find", "lsp", "web_search"];
|
|
932
|
+
const planModeTools = [
|
|
933
|
+
...planModeBaseTools,
|
|
934
|
+
...(agent.tools ?? []).filter(
|
|
935
|
+
tool => PLAN_MODE_AGENT_TOOL_ALLOWLIST.has(tool) && !planModeBaseTools.includes(tool),
|
|
936
|
+
),
|
|
937
|
+
];
|
|
938
|
+
const effectiveAgent: typeof agent = planModeState?.enabled
|
|
939
|
+
? {
|
|
940
|
+
...agent,
|
|
941
|
+
systemPrompt: `${planModeSubagentPrompt}\n\n${agent.systemPrompt}`,
|
|
942
|
+
tools: planModeTools,
|
|
943
|
+
spawns: undefined,
|
|
944
|
+
}
|
|
945
|
+
: agent;
|
|
946
|
+
|
|
947
|
+
// Apply per-agent model override from settings (highest priority)
|
|
948
|
+
const agentModelOverrides = this.session.settings.get("task.agentModelOverrides");
|
|
949
|
+
const settingsModelOverride = agentModelOverrides[agentName];
|
|
950
|
+
const parentActiveModelPattern = this.session.getActiveModelString?.();
|
|
951
|
+
const modelOverride = resolveAgentModelPatterns({
|
|
952
|
+
settingsOverride: settingsModelOverride,
|
|
953
|
+
agentModel: effectiveAgent.model,
|
|
954
|
+
settings: this.session.settings,
|
|
955
|
+
activeModelPattern: parentActiveModelPattern,
|
|
956
|
+
fallbackModelPattern: this.session.getModelString?.(),
|
|
957
|
+
});
|
|
958
|
+
const thinkingLevelOverride = effectiveAgent.thinkingLevel;
|
|
959
|
+
|
|
960
|
+
// Output schema priority: agent frontmatter > inherited parent session.
|
|
961
|
+
// The task call itself never carries a schema; workflows needing ad-hoc
|
|
962
|
+
// structured output go through eval agent(prompt, schema).
|
|
963
|
+
const effectiveOutputSchema = effectiveAgent.output ?? this.session.outputSchema;
|
|
964
|
+
|
|
965
|
+
let repoRoot: string | null = null;
|
|
966
|
+
let baseline: WorktreeBaseline | null = null;
|
|
967
|
+
if (isIsolated) {
|
|
968
|
+
try {
|
|
969
|
+
repoRoot = await getRepoRoot(this.session.cwd);
|
|
970
|
+
baseline = await captureBaseline(repoRoot);
|
|
971
|
+
} catch (err) {
|
|
972
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
973
|
+
return {
|
|
974
|
+
content: [{ type: "text", text: `Isolated task execution requires a git repository. ${message}` }],
|
|
975
|
+
details: { projectAgentsDir, results: [], totalDurationMs: Date.now() - startTime },
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
const preferredIsolationBackend = parseIsolationMode(isolationMode);
|
|
981
|
+
|
|
982
|
+
// Derive artifacts directory
|
|
983
|
+
const sessionFile = this.session.getSessionFile();
|
|
984
|
+
const artifactsDir = sessionFile ? sessionFile.slice(0, -6) : null;
|
|
985
|
+
const tempArtifactsDir = artifactsDir ? null : path.join(os.tmpdir(), `omp-task-${Snowflake.next()}`);
|
|
986
|
+
const effectiveArtifactsDir = artifactsDir || tempArtifactsDir!;
|
|
987
|
+
|
|
988
|
+
const localProtocolOptions: LocalProtocolOptions = this.session.localProtocolOptions ?? {
|
|
989
|
+
getArtifactsDir: this.session.getArtifactsDir ?? (() => null),
|
|
990
|
+
getSessionId: this.session.getSessionId ?? (() => null),
|
|
991
|
+
};
|
|
992
|
+
|
|
993
|
+
// Subagents adopt the parent's ArtifactManager so artifact IDs are unique
|
|
994
|
+
// across the whole tree and outputs land flat in the parent's dir.
|
|
995
|
+
const parentArtifactManager = this.session.getArtifactManager?.() ?? undefined;
|
|
996
|
+
|
|
997
|
+
// When the session is executing an approved plan, hand the overall plan to
|
|
998
|
+
// every subagent so they share the main agent's plan context. Skipped in
|
|
999
|
+
// plan mode (read-only exploration uses planModeSubagentPrompt instead) and
|
|
1000
|
+
// when no plan file exists at the session's reference path.
|
|
1001
|
+
const planReference = planModeState?.enabled
|
|
1002
|
+
? undefined
|
|
1003
|
+
: await loadOverallPlanReference(
|
|
1004
|
+
this.session.getPlanReferencePath?.() ?? "local://PLAN.md",
|
|
1005
|
+
localProtocolOptions,
|
|
1006
|
+
);
|
|
1007
|
+
|
|
1008
|
+
try {
|
|
1009
|
+
// Check self-recursion prevention
|
|
1010
|
+
if (this.#blockedAgent && agentName === this.#blockedAgent) {
|
|
1011
|
+
return {
|
|
1012
|
+
content: [
|
|
1013
|
+
{
|
|
1014
|
+
type: "text",
|
|
1015
|
+
text: `Cannot spawn ${this.#blockedAgent} agent from within itself (recursion prevention). Use a different agent type.`,
|
|
1016
|
+
},
|
|
1017
|
+
],
|
|
1018
|
+
details: { projectAgentsDir, results: [], totalDurationMs: Date.now() - startTime },
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// Check spawn restrictions from parent
|
|
1023
|
+
const parentSpawns = this.session.getSessionSpawns() ?? "*";
|
|
1024
|
+
const allowedSpawns = parentSpawns.split(",").map(s => s.trim());
|
|
1025
|
+
const isSpawnAllowed = (): boolean => {
|
|
1026
|
+
if (parentSpawns === "") return false; // Empty = deny all
|
|
1027
|
+
if (parentSpawns === "*") return true; // Wildcard = allow all
|
|
1028
|
+
return allowedSpawns.includes(agentName);
|
|
1029
|
+
};
|
|
1030
|
+
|
|
1031
|
+
if (!isSpawnAllowed()) {
|
|
1032
|
+
const allowed = parentSpawns === "" ? "none (spawns disabled for this agent)" : parentSpawns;
|
|
1033
|
+
return {
|
|
1034
|
+
content: [{ type: "text", text: `Cannot spawn '${agentName}'. Allowed: ${allowed}` }],
|
|
1035
|
+
details: { projectAgentsDir, results: [], totalDurationMs: Date.now() - startTime },
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
await fs.mkdir(effectiveArtifactsDir, { recursive: true });
|
|
1040
|
+
|
|
1041
|
+
// Allocate a unique ID across the session to prevent artifact collisions
|
|
1042
|
+
let agentId: string;
|
|
1043
|
+
if (preAllocatedId) {
|
|
1044
|
+
agentId = preAllocatedId;
|
|
1045
|
+
} else {
|
|
1046
|
+
const outputManager =
|
|
1047
|
+
this.session.agentOutputManager ?? new AgentOutputManager(this.session.getArtifactsDir ?? (() => null));
|
|
1048
|
+
agentId = await outputManager.allocate(params.id?.trim() || generateTaskName());
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
const availableSkills = [...(this.session.skills ?? [])];
|
|
1052
|
+
// Resolve autoload skills from agent definition against available skills
|
|
1053
|
+
const resolvedAutoloadSkills =
|
|
1054
|
+
agent.autoloadSkills?.length && availableSkills.length > 0
|
|
1055
|
+
? agent.autoloadSkills
|
|
1056
|
+
.map(name => availableSkills.find(s => s.name === name))
|
|
1057
|
+
.filter((s): s is NonNullable<typeof s> => s !== undefined)
|
|
1058
|
+
: [];
|
|
1059
|
+
const contextFiles = this.session.contextFiles?.filter(
|
|
1060
|
+
file => path.basename(file.path).toLowerCase() !== "agents.md",
|
|
1061
|
+
);
|
|
1062
|
+
const promptTemplates = this.session.promptTemplates;
|
|
1063
|
+
const parentEvalSessionId = this.session.getEvalSessionId?.() ?? undefined;
|
|
1064
|
+
const mcpManager = this.session.mcpManager ?? MCPManager.instance();
|
|
1065
|
+
|
|
1066
|
+
// Progress tracking for the single agent
|
|
1067
|
+
let latestProgress: AgentProgress = {
|
|
1068
|
+
index: 0,
|
|
1069
|
+
id: agentId,
|
|
1070
|
+
agent: agentName,
|
|
1071
|
+
agentSource: agent.source,
|
|
1072
|
+
status: "pending",
|
|
1073
|
+
task: renderSubagentUserPrompt(assignment),
|
|
1074
|
+
assignment,
|
|
1075
|
+
recentTools: [],
|
|
1076
|
+
recentOutput: [],
|
|
1077
|
+
toolCount: 0,
|
|
1078
|
+
requests: 0,
|
|
1079
|
+
tokens: 0,
|
|
1080
|
+
cost: 0,
|
|
1081
|
+
durationMs: 0,
|
|
1082
|
+
modelOverride,
|
|
1083
|
+
description: params.description,
|
|
1084
|
+
};
|
|
1085
|
+
const emitProgress = () => {
|
|
1086
|
+
onUpdate?.({
|
|
1087
|
+
content: [{ type: "text", text: `Running agent ${agentId}...` }],
|
|
1088
|
+
details: {
|
|
1089
|
+
projectAgentsDir,
|
|
1090
|
+
results: [],
|
|
1091
|
+
totalDurationMs: Date.now() - startTime,
|
|
1092
|
+
progress: [latestProgress],
|
|
1093
|
+
},
|
|
1094
|
+
});
|
|
1095
|
+
};
|
|
1096
|
+
emitProgress();
|
|
1097
|
+
|
|
1098
|
+
const buildCommitMessageFn = () =>
|
|
1099
|
+
commitStyle === "ai" && this.session.modelRegistry
|
|
1100
|
+
? async (diff: string) => {
|
|
1101
|
+
return generateCommitMessage(
|
|
1102
|
+
diff,
|
|
1103
|
+
this.session.modelRegistry!,
|
|
1104
|
+
this.session.settings,
|
|
1105
|
+
this.session.getSessionId?.() ?? undefined,
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
: undefined;
|
|
1109
|
+
|
|
1110
|
+
const sharedRunOptions = {
|
|
1111
|
+
cwd: this.session.cwd,
|
|
1112
|
+
agent: effectiveAgent,
|
|
1113
|
+
task: renderSubagentUserPrompt(assignment),
|
|
1114
|
+
assignment,
|
|
1115
|
+
context: sharedContext,
|
|
1116
|
+
planReference,
|
|
1117
|
+
description: params.description,
|
|
1118
|
+
index: 0,
|
|
1119
|
+
parentToolCallId: toolCallId,
|
|
1120
|
+
id: agentId,
|
|
1121
|
+
taskDepth,
|
|
1122
|
+
modelOverride,
|
|
1123
|
+
parentActiveModelPattern,
|
|
1124
|
+
thinkingLevel: thinkingLevelOverride,
|
|
1125
|
+
outputSchema: effectiveOutputSchema,
|
|
1126
|
+
sessionFile,
|
|
1127
|
+
persistArtifacts: !!artifactsDir,
|
|
1128
|
+
artifactsDir: effectiveArtifactsDir,
|
|
1129
|
+
enableLsp: subagentLspEnabled,
|
|
1130
|
+
signal,
|
|
1131
|
+
eventBus: this.session.eventBus,
|
|
1132
|
+
onProgress: (progress: AgentProgress) => {
|
|
1133
|
+
// Shallow snapshot; recentTools is mutated in place by the
|
|
1134
|
+
// executor, the rest is reassigned or immutable. A deep clone
|
|
1135
|
+
// here cost O(extractedToolData) per progress event.
|
|
1136
|
+
latestProgress = { ...progress, recentTools: progress.recentTools.slice() };
|
|
1137
|
+
emitProgress();
|
|
1138
|
+
},
|
|
1139
|
+
authStorage: this.session.authStorage,
|
|
1140
|
+
modelRegistry: this.session.modelRegistry,
|
|
1141
|
+
settings: this.session.settings,
|
|
1142
|
+
mcpManager,
|
|
1143
|
+
contextFiles,
|
|
1144
|
+
skills: availableSkills,
|
|
1145
|
+
autoloadSkills: resolvedAutoloadSkills,
|
|
1146
|
+
workspaceTree: this.session.workspaceTree,
|
|
1147
|
+
promptTemplates,
|
|
1148
|
+
rules: this.session.rules,
|
|
1149
|
+
preloadedExtensionPaths: this.session.extensionPaths,
|
|
1150
|
+
preloadedCustomToolPaths: this.session.customToolPaths,
|
|
1151
|
+
localProtocolOptions,
|
|
1152
|
+
parentArtifactManager,
|
|
1153
|
+
parentHindsightSessionState: this.session.getHindsightSessionState?.(),
|
|
1154
|
+
parentMnemopiSessionState: this.session.getMnemopiSessionState?.(),
|
|
1155
|
+
parentTelemetry: this.session.getTelemetry?.(),
|
|
1156
|
+
parentEvalSessionId,
|
|
1157
|
+
};
|
|
1158
|
+
|
|
1159
|
+
const runTask = async (): Promise<SingleResult> => {
|
|
1160
|
+
if (!isIsolated) {
|
|
1161
|
+
return runSubprocess(sharedRunOptions);
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
const taskStart = Date.now();
|
|
1165
|
+
let isolationHandle: IsolationHandle | undefined;
|
|
1166
|
+
try {
|
|
1167
|
+
if (!repoRoot || !baseline) {
|
|
1168
|
+
throw new Error("Isolated task execution not initialized.");
|
|
1169
|
+
}
|
|
1170
|
+
const taskBaseline = structuredClone(baseline);
|
|
1171
|
+
|
|
1172
|
+
isolationHandle = await ensureIsolation(repoRoot, agentId, preferredIsolationBackend);
|
|
1173
|
+
const isolationDir = isolationHandle.mergedDir;
|
|
1174
|
+
|
|
1175
|
+
// Isolated runs re-discover extensions/custom tools inside the
|
|
1176
|
+
// worktree instead of reusing the parent's source paths.
|
|
1177
|
+
const result = await runSubprocess({
|
|
1178
|
+
...sharedRunOptions,
|
|
1179
|
+
worktree: isolationDir,
|
|
1180
|
+
preloadedExtensionPaths: undefined,
|
|
1181
|
+
preloadedCustomToolPaths: undefined,
|
|
1182
|
+
});
|
|
1183
|
+
if (mergeMode === "branch" && result.exitCode === 0) {
|
|
1184
|
+
try {
|
|
1185
|
+
const commitResult = await commitToBranch(
|
|
1186
|
+
isolationDir,
|
|
1187
|
+
taskBaseline,
|
|
1188
|
+
agentId,
|
|
1189
|
+
params.description,
|
|
1190
|
+
buildCommitMessageFn(),
|
|
1191
|
+
);
|
|
1192
|
+
return {
|
|
1193
|
+
...result,
|
|
1194
|
+
branchName: commitResult?.branchName,
|
|
1195
|
+
nestedPatches: commitResult?.nestedPatches,
|
|
1196
|
+
};
|
|
1197
|
+
} catch (mergeErr) {
|
|
1198
|
+
// Agent succeeded but branch commit failed — clean up stale branch
|
|
1199
|
+
const branchName = `omp/task/${agentId}`;
|
|
1200
|
+
await git.branch.tryDelete(repoRoot, branchName);
|
|
1201
|
+
const msg = mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
|
|
1202
|
+
return { ...result, error: `Merge failed: ${msg}` };
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
if (result.exitCode === 0) {
|
|
1206
|
+
try {
|
|
1207
|
+
const delta = await captureDeltaPatch(isolationDir, taskBaseline);
|
|
1208
|
+
const patchPath = path.join(effectiveArtifactsDir, `${agentId}.patch`);
|
|
1209
|
+
await Bun.write(patchPath, delta.rootPatch);
|
|
1210
|
+
return {
|
|
1211
|
+
...result,
|
|
1212
|
+
patchPath,
|
|
1213
|
+
nestedPatches: delta.nestedPatches,
|
|
1214
|
+
};
|
|
1215
|
+
} catch (patchErr) {
|
|
1216
|
+
const msg = patchErr instanceof Error ? patchErr.message : String(patchErr);
|
|
1217
|
+
return { ...result, error: `Patch capture failed: ${msg}` };
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
return result;
|
|
1221
|
+
} catch (err) {
|
|
1222
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1223
|
+
return {
|
|
1224
|
+
index: 0,
|
|
1225
|
+
id: agentId,
|
|
1226
|
+
agent: agent.name,
|
|
1227
|
+
agentSource: agent.source,
|
|
1228
|
+
task: renderSubagentUserPrompt(assignment),
|
|
1229
|
+
assignment,
|
|
1230
|
+
description: params.description,
|
|
1231
|
+
exitCode: 1,
|
|
1232
|
+
output: "",
|
|
1233
|
+
stderr: message,
|
|
1234
|
+
truncated: false,
|
|
1235
|
+
durationMs: Date.now() - taskStart,
|
|
1236
|
+
tokens: 0,
|
|
1237
|
+
requests: 0,
|
|
1238
|
+
modelOverride,
|
|
1239
|
+
error: message,
|
|
1240
|
+
};
|
|
1241
|
+
} finally {
|
|
1242
|
+
if (isolationHandle) {
|
|
1243
|
+
await cleanupIsolation(isolationHandle);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
|
|
1248
|
+
const result = await runTask();
|
|
1249
|
+
|
|
1250
|
+
let mergeSummary = "";
|
|
1251
|
+
let changesApplied: boolean | null = null;
|
|
1252
|
+
let hadAnyChanges = false;
|
|
1253
|
+
let mergedBranchForNestedPatches = false;
|
|
1254
|
+
if (isIsolated && repoRoot) {
|
|
1255
|
+
try {
|
|
1256
|
+
if (mergeMode === "branch") {
|
|
1257
|
+
if (!result.branchName || result.exitCode !== 0 || result.aborted) {
|
|
1258
|
+
changesApplied = true;
|
|
1259
|
+
mergeSummary = "\n\nNo changes to apply.";
|
|
1260
|
+
} else {
|
|
1261
|
+
const mergeResult = await mergeTaskBranches(repoRoot, [
|
|
1262
|
+
{ branchName: result.branchName, taskId: result.id, description: result.description },
|
|
1263
|
+
]);
|
|
1264
|
+
mergedBranchForNestedPatches = mergeResult.merged.includes(result.branchName);
|
|
1265
|
+
changesApplied = mergeResult.failed.length === 0;
|
|
1266
|
+
hadAnyChanges = changesApplied && mergeResult.merged.length > 0;
|
|
1267
|
+
|
|
1268
|
+
if (changesApplied) {
|
|
1269
|
+
mergeSummary = hadAnyChanges
|
|
1270
|
+
? `\n\nMerged branch: ${result.branchName}`
|
|
1271
|
+
: "\n\nNo changes to apply.";
|
|
1272
|
+
} else {
|
|
1273
|
+
const conflictPart = mergeResult.conflict ? `\nConflict: ${mergeResult.conflict}` : "";
|
|
1274
|
+
mergeSummary = `\n\n<system-notification>Branch merge failed: ${result.branchName}.${conflictPart}\nThe unmerged branch remains for manual resolution.</system-notification>`;
|
|
1275
|
+
}
|
|
1276
|
+
if (mergeResult.stashConflict) {
|
|
1277
|
+
mergeSummary += `\n\n<system-notification>${mergeResult.stashConflict}</system-notification>`;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// Clean up the merged branch (keep failed ones for manual resolution)
|
|
1281
|
+
if (changesApplied) {
|
|
1282
|
+
await cleanupTaskBranches(repoRoot, [result.branchName]);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
} else {
|
|
1286
|
+
// Patch mode: apply the patch from a successful run. A failed or
|
|
1287
|
+
// aborted run has nothing to apply and must not block the result.
|
|
1288
|
+
const succeeded = result.exitCode === 0 && !result.error && !result.aborted;
|
|
1289
|
+
if (!succeeded) {
|
|
1290
|
+
changesApplied = true;
|
|
1291
|
+
hadAnyChanges = false;
|
|
1292
|
+
} else if (!result.patchPath) {
|
|
1293
|
+
changesApplied = false;
|
|
1294
|
+
hadAnyChanges = false;
|
|
1295
|
+
} else {
|
|
1296
|
+
const patchText = await Bun.file(result.patchPath).text();
|
|
1297
|
+
if (!patchText.trim()) {
|
|
1298
|
+
changesApplied = true;
|
|
1299
|
+
hadAnyChanges = false;
|
|
1300
|
+
} else {
|
|
1301
|
+
const normalized = patchText.endsWith("\n") ? patchText : `${patchText}\n`;
|
|
1302
|
+
changesApplied = await git.patch.canApplyText(repoRoot, normalized);
|
|
1303
|
+
if (changesApplied) {
|
|
1304
|
+
try {
|
|
1305
|
+
await git.patch.applyText(repoRoot, normalized);
|
|
1306
|
+
hadAnyChanges = true;
|
|
1307
|
+
} catch {
|
|
1308
|
+
changesApplied = false;
|
|
1309
|
+
hadAnyChanges = false;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
if (changesApplied) {
|
|
1316
|
+
mergeSummary = hadAnyChanges ? "\n\nApplied patches: yes" : "\n\nNo changes to apply.";
|
|
1317
|
+
} else {
|
|
1318
|
+
const notification =
|
|
1319
|
+
"<system-notification>Patches were not applied and must be handled manually.</system-notification>";
|
|
1320
|
+
const patchList = result.patchPath ? `\n\nPatch artifact:\n- ${result.patchPath}` : "";
|
|
1321
|
+
mergeSummary = `\n\n${notification}${patchList}`;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
} catch (mergeErr) {
|
|
1325
|
+
const msg = mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
|
|
1326
|
+
changesApplied = false;
|
|
1327
|
+
hadAnyChanges = false;
|
|
1328
|
+
mergeSummary = `\n\n<system-notification>Merge phase failed: ${msg}\nTask outputs are preserved but changes were not applied.</system-notification>`;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
// Apply nested repo patches (separate from parent git)
|
|
1333
|
+
if (isIsolated && repoRoot && (mergeMode === "branch" || changesApplied !== false)) {
|
|
1334
|
+
const nestedPatches = result.nestedPatches ?? [];
|
|
1335
|
+
const eligible =
|
|
1336
|
+
nestedPatches.length > 0 &&
|
|
1337
|
+
result.exitCode === 0 &&
|
|
1338
|
+
!result.aborted &&
|
|
1339
|
+
(mergeMode !== "branch" || mergedBranchForNestedPatches);
|
|
1340
|
+
if (eligible) {
|
|
1341
|
+
try {
|
|
1342
|
+
await applyNestedPatches(repoRoot, nestedPatches, buildCommitMessageFn());
|
|
1343
|
+
} catch {
|
|
1344
|
+
// Nested patch failures are non-fatal to the parent merge
|
|
1345
|
+
mergeSummary +=
|
|
1346
|
+
"\n\n<system-notification>Some nested repository patches failed to apply.</system-notification>";
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
// Cleanup temp directory if used
|
|
1352
|
+
const shouldCleanupTempArtifacts =
|
|
1353
|
+
tempArtifactsDir && (!isIsolated || changesApplied === true || changesApplied === null);
|
|
1354
|
+
if (shouldCleanupTempArtifacts) {
|
|
1355
|
+
await fs.rm(tempArtifactsDir, { recursive: true, force: true });
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
return this.#buildResultPayload(result, projectAgentsDir, Date.now() - startTime, mergeSummary);
|
|
1359
|
+
} catch (err) {
|
|
1360
|
+
return {
|
|
1361
|
+
content: [{ type: "text", text: `Task execution failed: ${err}` }],
|
|
1362
|
+
details: { projectAgentsDir, results: [], totalDurationMs: Date.now() - startTime },
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
/** Build the tool result (summary text + details) for a settled run. */
|
|
1368
|
+
#buildResultPayload(
|
|
1369
|
+
result: SingleResult,
|
|
1370
|
+
projectAgentsDir: string | null,
|
|
1371
|
+
totalDurationMs: number,
|
|
1372
|
+
mergeSummary: string,
|
|
1373
|
+
): AgentToolResult<TaskToolDetails> {
|
|
1374
|
+
const status = result.aborted
|
|
1375
|
+
? "cancelled"
|
|
1376
|
+
: result.exitCode === 0 && result.error
|
|
1377
|
+
? "merge failed"
|
|
1378
|
+
: result.exitCode === 0
|
|
1379
|
+
? "completed"
|
|
1380
|
+
: `failed (exit ${result.exitCode})`;
|
|
1381
|
+
const output = formatResultOutputFallback(result);
|
|
1382
|
+
const outputCharCount = result.outputMeta?.charCount ?? output.length;
|
|
1383
|
+
const fullOutputThreshold = 5000;
|
|
1384
|
+
let preview = output;
|
|
1385
|
+
let truncated = false;
|
|
1386
|
+
if (outputCharCount > fullOutputThreshold) {
|
|
1387
|
+
const slice = output.slice(0, fullOutputThreshold);
|
|
1388
|
+
const lastNewline = slice.lastIndexOf("\n");
|
|
1389
|
+
preview = lastNewline >= 0 ? slice.slice(0, lastNewline) : slice;
|
|
1390
|
+
truncated = true;
|
|
1391
|
+
}
|
|
1392
|
+
const summary = prompt.render(taskSummaryTemplate, {
|
|
1393
|
+
agentName: result.agent,
|
|
1394
|
+
id: result.id,
|
|
1395
|
+
status,
|
|
1396
|
+
duration: formatDuration(totalDurationMs),
|
|
1397
|
+
preview,
|
|
1398
|
+
truncated,
|
|
1399
|
+
meta: result.outputMeta
|
|
1400
|
+
? {
|
|
1401
|
+
lineCount: result.outputMeta.lineCount,
|
|
1402
|
+
charSize: formatBytes(result.outputMeta.charCount),
|
|
1403
|
+
}
|
|
1404
|
+
: undefined,
|
|
1405
|
+
mergeSummary,
|
|
1406
|
+
});
|
|
1407
|
+
|
|
1408
|
+
return {
|
|
1409
|
+
content: [{ type: "text", text: summary }],
|
|
1410
|
+
details: {
|
|
1411
|
+
projectAgentsDir,
|
|
1412
|
+
results: [result],
|
|
1413
|
+
totalDurationMs,
|
|
1414
|
+
usage: result.usage,
|
|
1415
|
+
outputPaths: result.outputPath ? [result.outputPath] : undefined,
|
|
1416
|
+
},
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
}
|