@prometheus-ai/agent 0.5.4 → 0.5.8

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.
Files changed (1145) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/cli.js +25110 -0
  3. package/dist/types/async/index.d.ts +0 -1
  4. package/dist/types/async/job-manager.d.ts +33 -0
  5. package/dist/types/autolearn/controller.d.ts +25 -0
  6. package/dist/types/autolearn/managed-skills.d.ts +45 -0
  7. package/dist/types/autoresearch/state.d.ts +1 -1
  8. package/dist/types/autoresearch/tools/init-experiment.d.ts +1 -1
  9. package/dist/types/autoresearch/tools/log-experiment.d.ts +1 -1
  10. package/dist/types/autoresearch/tools/run-experiment.d.ts +1 -1
  11. package/dist/types/autoresearch/tools/update-notes.d.ts +1 -1
  12. package/dist/types/autoresearch/types.d.ts +1 -1
  13. package/dist/types/capability/context-file.d.ts +0 -13
  14. package/dist/types/capability/mcp.d.ts +1 -0
  15. package/dist/types/capability/rule-buckets.d.ts +1 -1
  16. package/dist/types/capability/rule.d.ts +6 -1
  17. package/dist/types/capability/types.d.ts +0 -4
  18. package/dist/types/cli/args.d.ts +23 -3
  19. package/dist/types/cli/bench-cli.d.ts +78 -0
  20. package/dist/types/cli/claude-trace-cli.d.ts +7 -0
  21. package/dist/types/cli/dry-balance-cli.d.ts +16 -2
  22. package/dist/types/cli/gallery-cli.d.ts +43 -0
  23. package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
  24. package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
  25. package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
  26. package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
  27. package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
  28. package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
  29. package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
  30. package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
  31. package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
  32. package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
  33. package/dist/types/cli/gallery-fixtures/types.d.ts +55 -0
  34. package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
  35. package/dist/types/cli/gallery-screenshot.d.ts +35 -0
  36. package/dist/types/cli/grievances-cli.d.ts +1 -1
  37. package/dist/types/cli/list-models.d.ts +6 -14
  38. package/dist/types/cli/models-cli.d.ts +49 -0
  39. package/dist/types/cli/session-picker.d.ts +1 -1
  40. package/dist/types/cli/setup-cli.d.ts +1 -1
  41. package/dist/types/cli/setup-model-picker.d.ts +14 -0
  42. package/dist/types/cli/startup-cwd.d.ts +2 -0
  43. package/dist/types/cli/update-cli.d.ts +13 -40
  44. package/dist/types/cli/usage-cli.d.ts +81 -0
  45. package/dist/types/cli-commands.d.ts +12 -0
  46. package/dist/types/collab/crypto.d.ts +7 -0
  47. package/dist/types/collab/guest.d.ts +37 -0
  48. package/dist/types/collab/host.d.ts +29 -0
  49. package/dist/types/collab/protocol.d.ts +119 -0
  50. package/dist/types/collab/relay-client.d.ts +22 -0
  51. package/dist/types/commands/bench.d.ts +29 -0
  52. package/dist/types/commands/gallery.d.ts +47 -0
  53. package/dist/types/commands/install.d.ts +1 -1
  54. package/dist/types/commands/join.d.ts +12 -0
  55. package/dist/types/commands/launch.d.ts +8 -4
  56. package/dist/types/commands/models.d.ts +33 -0
  57. package/dist/types/commands/read.d.ts +1 -1
  58. package/dist/types/commands/say.d.ts +24 -0
  59. package/dist/types/commands/token.d.ts +25 -0
  60. package/dist/types/commands/usage.d.ts +34 -0
  61. package/dist/types/commit/agentic/tools/analyze-file.d.ts +1 -1
  62. package/dist/types/commit/agentic/tools/git-file-diff.d.ts +1 -1
  63. package/dist/types/commit/agentic/tools/git-hunk.d.ts +1 -1
  64. package/dist/types/commit/agentic/tools/git-overview.d.ts +1 -1
  65. package/dist/types/commit/agentic/tools/propose-changelog.d.ts +1 -1
  66. package/dist/types/commit/agentic/tools/propose-commit.d.ts +1 -1
  67. package/dist/types/commit/agentic/tools/recent-commits.d.ts +1 -1
  68. package/dist/types/commit/agentic/tools/schemas.d.ts +1 -1
  69. package/dist/types/commit/agentic/tools/split-commit.d.ts +1 -1
  70. package/dist/types/commit/analysis/conventional.d.ts +2 -2
  71. package/dist/types/commit/analysis/summary.d.ts +2 -2
  72. package/dist/types/commit/changelog/generate.d.ts +3 -3
  73. package/dist/types/commit/changelog/index.d.ts +2 -2
  74. package/dist/types/commit/map-reduce/index.d.ts +3 -3
  75. package/dist/types/commit/map-reduce/map-phase.d.ts +2 -2
  76. package/dist/types/commit/map-reduce/reduce-phase.d.ts +2 -2
  77. package/dist/types/commit/model-selection.d.ts +10 -4
  78. package/dist/types/commit/shared-llm.d.ts +1 -1
  79. package/dist/types/config/api-key-resolver.d.ts +43 -0
  80. package/dist/types/config/append-only-context-mode.d.ts +2 -1
  81. package/dist/types/config/keybindings.d.ts +12 -7
  82. package/dist/types/config/model-discovery.d.ts +57 -0
  83. package/dist/types/config/model-equivalence.d.ts +1 -1
  84. package/dist/types/config/model-registry.d.ts +86 -222
  85. package/dist/types/config/model-resolver.d.ts +43 -12
  86. package/dist/types/config/model-roles.d.ts +29 -0
  87. package/dist/types/config/models-config-schema.d.ts +536 -43
  88. package/dist/types/config/models-config.d.ts +391 -0
  89. package/dist/types/config/settings-schema.d.ts +1202 -324
  90. package/dist/types/config/settings.d.ts +15 -3
  91. package/dist/types/dap/config.d.ts +14 -1
  92. package/dist/types/dap/types.d.ts +10 -0
  93. package/dist/types/debug/log-viewer.d.ts +1 -1
  94. package/dist/types/debug/raw-sse.d.ts +1 -1
  95. package/dist/types/debug/report-bundle.d.ts +3 -0
  96. package/dist/types/debug/terminal-info.d.ts +0 -1
  97. package/dist/types/discovery/at-imports.d.ts +15 -0
  98. package/dist/types/discovery/prometheus-extension-roots.d.ts +7 -7
  99. package/dist/types/edit/diff.d.ts +3 -2
  100. package/dist/types/edit/file-snapshot-store.d.ts +18 -0
  101. package/dist/types/edit/hashline/noop-loop-guard.d.ts +72 -0
  102. package/dist/types/edit/hashline/params.d.ts +1 -1
  103. package/dist/types/edit/index.d.ts +0 -1
  104. package/dist/types/edit/modes/apply-patch.d.ts +1 -1
  105. package/dist/types/edit/modes/patch.d.ts +1 -1
  106. package/dist/types/edit/modes/replace.d.ts +1 -1
  107. package/dist/types/edit/renderer.d.ts +1 -0
  108. package/dist/types/eval/__tests__/completion-bridge.test.d.ts +1 -0
  109. package/dist/types/eval/__tests__/helpers-local-roots.test.d.ts +1 -0
  110. package/dist/types/eval/__tests__/js-context-manager.test.d.ts +1 -0
  111. package/dist/types/eval/backend.d.ts +7 -2
  112. package/dist/types/eval/bridge-timeout.d.ts +1 -1
  113. package/dist/types/eval/completion-bridge.d.ts +25 -0
  114. package/dist/types/eval/idle-timeout.d.ts +1 -5
  115. package/dist/types/eval/js/context-manager.d.ts +1 -0
  116. package/dist/types/eval/js/executor.d.ts +2 -0
  117. package/dist/types/eval/js/index.d.ts +1 -1
  118. package/dist/types/eval/js/shared/helpers.d.ts +7 -1
  119. package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -6
  120. package/dist/types/eval/js/shared/runtime.d.ts +6 -1
  121. package/dist/types/eval/js/worker-protocol.d.ts +6 -0
  122. package/dist/types/eval/py/__tests__/prelude.test.d.ts +1 -0
  123. package/dist/types/eval/py/executor.d.ts +12 -0
  124. package/dist/types/eval/py/index.d.ts +1 -1
  125. package/dist/types/eval/py/kernel.d.ts +6 -1
  126. package/dist/types/eval/py/runtime.d.ts +9 -0
  127. package/dist/types/exa/index.d.ts +1 -19
  128. package/dist/types/exa/mcp-client.d.ts +10 -3
  129. package/dist/types/exa/types.d.ts +0 -83
  130. package/dist/types/exec/bash-executor.d.ts +7 -0
  131. package/dist/types/export/custom-share.d.ts +1 -2
  132. package/dist/types/export/html/index.d.ts +39 -0
  133. package/dist/types/export/html/template-js.d.ts +2 -0
  134. package/dist/types/export/share.d.ts +61 -0
  135. package/dist/types/export/ttsr.d.ts +14 -0
  136. package/dist/types/extensibility/custom-commands/types.d.ts +9 -4
  137. package/dist/types/extensibility/custom-tools/loader.d.ts +30 -4
  138. package/dist/types/extensibility/custom-tools/types.d.ts +16 -8
  139. package/dist/types/extensibility/extensions/index.d.ts +1 -1
  140. package/dist/types/extensibility/extensions/loader.d.ts +20 -1
  141. package/dist/types/extensibility/extensions/model-api.d.ts +17 -0
  142. package/dist/types/extensibility/extensions/runner.d.ts +5 -2
  143. package/dist/types/extensibility/extensions/types.d.ts +72 -11
  144. package/dist/types/extensibility/hooks/index.d.ts +2 -1
  145. package/dist/types/extensibility/hooks/loader.d.ts +1 -1
  146. package/dist/types/extensibility/hooks/types.d.ts +11 -5
  147. package/dist/types/extensibility/{legacy-pi-ai-shim.d.ts → legacy-package-ai-shim.d.ts} +2 -2
  148. package/dist/types/extensibility/plugins/{legacy-pi-compat.d.ts → legacy-package-compat.d.ts} +20 -3
  149. package/dist/types/extensibility/plugins/loader.d.ts +11 -0
  150. package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
  151. package/dist/types/extensibility/plugins/types.d.ts +2 -2
  152. package/dist/types/extensibility/shared-events.d.ts +3 -3
  153. package/dist/types/extensibility/skills.d.ts +10 -0
  154. package/dist/types/extensibility/slash-commands.d.ts +1 -11
  155. package/dist/types/goals/guided-setup.d.ts +18 -0
  156. package/dist/types/goals/state.d.ts +1 -1
  157. package/dist/types/goals/tools/goal-tool.d.ts +1 -1
  158. package/dist/types/hindsight/mental-models.d.ts +17 -8
  159. package/dist/types/hindsight/transcript.d.ts +1 -1
  160. package/dist/types/index.d.ts +5 -0
  161. package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
  162. package/dist/types/internal-urls/history-protocol.d.ts +14 -0
  163. package/dist/types/internal-urls/index.d.ts +1 -0
  164. package/dist/types/internal-urls/local-protocol.d.ts +14 -2
  165. package/dist/types/internal-urls/types.d.ts +1 -1
  166. package/dist/types/irc/bus.d.ts +79 -0
  167. package/dist/types/lib/xai-http.d.ts +1 -1
  168. package/dist/types/lsp/client.d.ts +10 -0
  169. package/dist/types/lsp/config.d.ts +2 -2
  170. package/dist/types/lsp/edits.d.ts +9 -0
  171. package/dist/types/lsp/format-options.d.ts +32 -0
  172. package/dist/types/lsp/index.d.ts +2 -7
  173. package/dist/types/lsp/types.d.ts +13 -1
  174. package/dist/types/lsp/utils.d.ts +6 -2
  175. package/dist/types/main.d.ts +23 -8
  176. package/dist/types/mcp/json-rpc.d.ts +5 -0
  177. package/dist/types/mcp/manager.d.ts +8 -0
  178. package/dist/types/mcp/oauth-discovery.d.ts +6 -1
  179. package/dist/types/mcp/oauth-flow.d.ts +13 -3
  180. package/dist/types/mcp/startup-events.d.ts +11 -0
  181. package/dist/types/mcp/tool-bridge.d.ts +2 -0
  182. package/dist/types/mcp/transports/stdio.d.ts +13 -0
  183. package/dist/types/mcp/types.d.ts +2 -0
  184. package/dist/types/memories/index.d.ts +7 -15
  185. package/dist/types/memories/storage.d.ts +0 -10
  186. package/dist/types/memory-backend/index.d.ts +3 -1
  187. package/dist/types/memory-backend/local-backend.d.ts +4 -3
  188. package/dist/types/memory-backend/resolve.d.ts +2 -2
  189. package/dist/types/memory-backend/runtime.d.ts +4 -0
  190. package/dist/types/memory-backend/types.d.ts +67 -2
  191. package/dist/types/mnemopi/config.d.ts +31 -1
  192. package/dist/types/mnemopi/state.d.ts +40 -2
  193. package/dist/types/modes/acp/acp-agent.d.ts +1 -2
  194. package/dist/types/modes/components/agent-dashboard.d.ts +17 -1
  195. package/dist/types/modes/components/agent-hub.d.ts +82 -0
  196. package/dist/types/modes/components/assistant-message.d.ts +5 -12
  197. package/dist/types/modes/components/bash-execution.d.ts +1 -1
  198. package/dist/types/modes/components/chat-block.d.ts +64 -0
  199. package/dist/types/modes/components/collab-prompt-message.d.ts +10 -0
  200. package/dist/types/modes/components/compaction-summary-message.d.ts +25 -5
  201. package/dist/types/modes/components/copy-selector.d.ts +1 -1
  202. package/dist/types/modes/components/custom-editor.d.ts +49 -2
  203. package/dist/types/modes/components/custom-editor.test.d.ts +1 -0
  204. package/dist/types/modes/components/dynamic-border.d.ts +1 -1
  205. package/dist/types/modes/components/extensions/extension-dashboard.d.ts +1 -1
  206. package/dist/types/modes/components/extensions/extension-list.d.ts +1 -1
  207. package/dist/types/modes/components/extensions/inspector-panel.d.ts +1 -1
  208. package/dist/types/modes/components/footer.d.ts +1 -1
  209. package/dist/types/modes/components/hook-editor.d.ts +5 -0
  210. package/dist/types/modes/components/hook-input.d.ts +4 -0
  211. package/dist/types/modes/components/hook-selector.d.ts +5 -7
  212. package/dist/types/modes/components/index.d.ts +1 -0
  213. package/dist/types/modes/components/late-diagnostics-message.d.ts +20 -0
  214. package/dist/types/modes/components/logout-account-selector.d.ts +8 -0
  215. package/dist/types/modes/components/mcp-add-wizard.d.ts +2 -1
  216. package/dist/types/modes/components/model-selector.d.ts +1 -1
  217. package/dist/types/modes/components/oauth-selector.d.ts +10 -1
  218. package/dist/types/modes/components/overlay-box.d.ts +17 -0
  219. package/dist/types/modes/components/plan-review-overlay.d.ts +61 -0
  220. package/dist/types/modes/components/plan-toc.d.ts +41 -0
  221. package/dist/types/modes/components/read-tool-group.d.ts +8 -0
  222. package/dist/types/modes/components/reset-usage-selector.d.ts +12 -0
  223. package/dist/types/modes/components/segment-track.d.ts +11 -6
  224. package/dist/types/modes/components/session-selector.d.ts +18 -9
  225. package/dist/types/modes/components/settings-defs.d.ts +9 -2
  226. package/dist/types/modes/components/settings-selector.d.ts +17 -4
  227. package/dist/types/modes/components/snapcompact-shape-preview.d.ts +31 -0
  228. package/dist/types/modes/components/status-line/component.d.ts +61 -0
  229. package/dist/types/modes/components/status-line/index.d.ts +1 -0
  230. package/dist/types/modes/components/status-line/types.d.ts +47 -3
  231. package/dist/types/modes/components/tiny-title-download-progress.d.ts +1 -1
  232. package/dist/types/modes/components/tool-execution.d.ts +49 -2
  233. package/dist/types/modes/components/transcript-container.d.ts +76 -26
  234. package/dist/types/modes/components/tree-selector.d.ts +2 -2
  235. package/dist/types/modes/components/ttsr-notification.d.ts +5 -1
  236. package/dist/types/modes/components/usage-row.d.ts +3 -0
  237. package/dist/types/modes/components/user-message-selector.d.ts +1 -1
  238. package/dist/types/modes/components/user-message.d.ts +2 -1
  239. package/dist/types/modes/components/visual-truncate.d.ts +1 -1
  240. package/dist/types/modes/components/welcome.d.ts +12 -2
  241. package/dist/types/modes/controllers/command-controller.d.ts +3 -2
  242. package/dist/types/modes/controllers/event-controller.d.ts +7 -1
  243. package/dist/types/modes/controllers/extension-ui-controller.d.ts +0 -1
  244. package/dist/types/modes/controllers/input-controller.d.ts +25 -3
  245. package/dist/types/modes/controllers/mcp-command-controller.d.ts +8 -0
  246. package/dist/types/modes/controllers/selector-controller.d.ts +5 -2
  247. package/dist/types/modes/controllers/session-focus-controller.d.ts +31 -0
  248. package/dist/types/modes/controllers/streaming-reveal.d.ts +22 -0
  249. package/dist/types/modes/controllers/tan-command-controller.d.ts +6 -0
  250. package/dist/types/modes/controllers/tool-args-reveal.d.ts +43 -0
  251. package/dist/types/modes/gradient-highlight.d.ts +9 -4
  252. package/dist/types/modes/image-references.d.ts +14 -3
  253. package/dist/types/modes/index.d.ts +8 -7
  254. package/dist/types/modes/interactive-mode.d.ts +92 -16
  255. package/dist/types/modes/magic-keywords.d.ts +14 -2
  256. package/dist/types/modes/markdown-prose.d.ts +1 -1
  257. package/dist/types/modes/oauth-manual-input.d.ts +7 -0
  258. package/dist/types/modes/rpc/rpc-client.d.ts +48 -2
  259. package/dist/types/modes/rpc/rpc-mode.d.ts +67 -2
  260. package/dist/types/modes/rpc/rpc-subagents.d.ts +24 -0
  261. package/dist/types/modes/rpc/rpc-types.d.ts +113 -1
  262. package/dist/types/modes/runtime-init.d.ts +4 -0
  263. package/dist/types/modes/session-observer-registry.d.ts +9 -0
  264. package/dist/types/modes/setup-version.d.ts +11 -0
  265. package/dist/types/modes/setup-wizard/index.d.ts +7 -2
  266. package/dist/types/modes/setup-wizard/lazy.d.ts +2 -0
  267. package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +4 -1
  268. package/dist/types/modes/setup-wizard/scenes/types.d.ts +11 -2
  269. package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +6 -2
  270. package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +1 -1
  271. package/dist/types/modes/theme/theme.d.ts +42 -7
  272. package/dist/types/modes/types.d.ts +62 -13
  273. package/dist/types/modes/utils/context-usage.d.ts +6 -1
  274. package/dist/types/modes/utils/copy-targets.d.ts +21 -1
  275. package/dist/types/modes/utils/ui-helpers.d.ts +4 -4
  276. package/dist/types/modes/workflow.d.ts +3 -3
  277. package/dist/types/plan-mode/approved-plan.d.ts +27 -8
  278. package/dist/types/plan-mode/plan-protection.d.ts +4 -4
  279. package/dist/types/registry/agent-lifecycle.d.ts +51 -0
  280. package/dist/types/registry/agent-registry.d.ts +33 -5
  281. package/dist/types/sdk.d.ts +46 -4
  282. package/dist/types/secrets/index.d.ts +1 -1
  283. package/dist/types/secrets/obfuscator.d.ts +9 -3
  284. package/dist/types/session/agent-session.d.ts +136 -66
  285. package/dist/types/session/agent-storage.d.ts +2 -1
  286. package/dist/types/session/auth-broker-config.d.ts +4 -0
  287. package/dist/types/session/auth-storage.d.ts +1 -1
  288. package/dist/types/session/codex-auto-reset.d.ts +111 -0
  289. package/dist/types/session/indexed-session-storage.d.ts +3 -3
  290. package/dist/types/session/messages.d.ts +26 -15
  291. package/dist/types/session/session-context.d.ts +39 -0
  292. package/dist/types/session/session-entries.d.ts +159 -0
  293. package/dist/types/session/session-history-format.d.ts +12 -0
  294. package/dist/types/session/session-listing.d.ts +69 -0
  295. package/dist/types/session/session-loader.d.ts +16 -0
  296. package/dist/types/session/session-manager.d.ts +107 -440
  297. package/dist/types/session/session-migrations.d.ts +12 -0
  298. package/dist/types/session/session-paths.d.ts +25 -0
  299. package/dist/types/session/session-persistence.d.ts +8 -0
  300. package/dist/types/session/session-storage.d.ts +11 -7
  301. package/dist/types/session/snapcompact-inline.d.ts +145 -0
  302. package/dist/types/session/snapcompact-savings-journal.d.ts +46 -0
  303. package/dist/types/session/streaming-output.d.ts +46 -0
  304. package/dist/types/session/tool-choice-queue.d.ts +6 -6
  305. package/dist/types/session/yield-queue.d.ts +10 -1
  306. package/dist/types/slash-commands/acp-builtins.d.ts +16 -0
  307. package/dist/types/slash-commands/available-commands.d.ts +34 -0
  308. package/dist/types/slash-commands/builtin-registry.d.ts +10 -0
  309. package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +14 -0
  310. package/dist/types/slash-commands/helpers/logout.d.ts +15 -0
  311. package/dist/types/slash-commands/helpers/reset-usage.d.ts +27 -0
  312. package/dist/types/slash-commands/helpers/stats-dashboard.d.ts +13 -0
  313. package/dist/types/slash-commands/types.d.ts +5 -9
  314. package/dist/types/ssh/connection-manager.d.ts +8 -0
  315. package/dist/types/stt/asr-client.d.ts +90 -0
  316. package/dist/types/stt/asr-protocol.d.ts +97 -0
  317. package/dist/types/stt/asr-worker.d.ts +2 -0
  318. package/dist/types/stt/downloader.d.ts +38 -0
  319. package/dist/types/stt/endpointer.d.ts +59 -0
  320. package/dist/types/stt/index.d.ts +5 -1
  321. package/dist/types/stt/models.d.ts +120 -0
  322. package/dist/types/stt/recorder.d.ts +17 -0
  323. package/dist/types/stt/stt-controller.d.ts +6 -0
  324. package/dist/types/stt/transcriber.d.ts +5 -7
  325. package/dist/types/stt/wav.d.ts +29 -0
  326. package/dist/types/system-prompt.d.ts +9 -1
  327. package/dist/types/task/commands.d.ts +1 -1
  328. package/dist/types/task/discovery.d.ts +1 -2
  329. package/dist/types/task/executor.d.ts +61 -2
  330. package/dist/types/task/index.d.ts +37 -6
  331. package/dist/types/task/output-manager.d.ts +0 -7
  332. package/dist/types/task/parallel.d.ts +2 -2
  333. package/dist/types/task/prometheus-command.d.ts +2 -2
  334. package/dist/types/task/render.d.ts +20 -7
  335. package/dist/types/task/repair-args.d.ts +8 -7
  336. package/dist/types/task/types.d.ts +109 -52
  337. package/dist/types/task/worktree.d.ts +2 -0
  338. package/dist/types/telemetry-export.d.ts +2 -2
  339. package/dist/types/thinking.d.ts +4 -0
  340. package/dist/types/tiny/models.d.ts +1 -1
  341. package/dist/types/tiny/title-client.d.ts +12 -1
  342. package/dist/types/tiny/title-protocol.d.ts +1 -0
  343. package/dist/types/tools/archive-reader.d.ts +5 -0
  344. package/dist/types/tools/ask.d.ts +6 -1
  345. package/dist/types/tools/ast-edit.d.ts +4 -1
  346. package/dist/types/tools/ast-grep.d.ts +4 -1
  347. package/dist/types/tools/bash.d.ts +5 -2
  348. package/dist/types/tools/browser/attach.d.ts +4 -4
  349. package/dist/types/tools/browser/cmux/cmux-tab.d.ts +202 -0
  350. package/dist/types/tools/browser/cmux/rpc.d.ts +70 -0
  351. package/dist/types/tools/browser/cmux/socket-client.d.ts +19 -0
  352. package/dist/types/tools/browser/registry.d.ts +17 -3
  353. package/dist/types/tools/browser/render.d.ts +2 -0
  354. package/dist/types/tools/browser/tab-protocol.d.ts +2 -0
  355. package/dist/types/tools/browser/tab-supervisor.d.ts +16 -4
  356. package/dist/types/tools/browser/tab-worker.d.ts +18 -1
  357. package/dist/types/tools/browser.d.ts +3 -1
  358. package/dist/types/tools/checkpoint.d.ts +1 -1
  359. package/dist/types/tools/conflict-detect.d.ts +16 -0
  360. package/dist/types/tools/debug.d.ts +1 -1
  361. package/dist/types/tools/eval-render.d.ts +1 -8
  362. package/dist/types/tools/eval.d.ts +9 -1
  363. package/dist/types/tools/fetch.d.ts +17 -8
  364. package/dist/types/tools/find.d.ts +1 -8
  365. package/dist/types/tools/gh-cache-invalidation.d.ts +6 -0
  366. package/dist/types/tools/gh.d.ts +4 -1
  367. package/dist/types/tools/github-cache.d.ts +19 -0
  368. package/dist/types/tools/grouped-file-output.d.ts +46 -12
  369. package/dist/types/tools/image-gen.d.ts +1 -1
  370. package/dist/types/tools/index.d.ts +89 -8
  371. package/dist/types/tools/inspect-image.d.ts +1 -1
  372. package/dist/types/tools/irc.d.ts +79 -39
  373. package/dist/types/tools/job.d.ts +8 -2
  374. package/dist/types/tools/learn.d.ts +51 -0
  375. package/dist/types/tools/manage-skill.d.ts +40 -0
  376. package/dist/types/tools/memory-edit.d.ts +2 -2
  377. package/dist/types/tools/memory-recall.d.ts +1 -1
  378. package/dist/types/tools/memory-reflect.d.ts +1 -1
  379. package/dist/types/tools/memory-render.d.ts +4 -1
  380. package/dist/types/tools/memory-retain.d.ts +1 -1
  381. package/dist/types/tools/path-utils.d.ts +17 -5
  382. package/dist/types/tools/plan-mode-guard.d.ts +18 -9
  383. package/dist/types/tools/read.d.ts +3 -2
  384. package/dist/types/tools/render-mermaid.d.ts +1 -1
  385. package/dist/types/tools/render-utils.d.ts +47 -27
  386. package/dist/types/tools/renderers.d.ts +10 -2
  387. package/dist/types/tools/report-tool-issue.d.ts +6 -1
  388. package/dist/types/tools/resolve.d.ts +1 -1
  389. package/dist/types/tools/review.d.ts +1 -1
  390. package/dist/types/tools/search-tool-bm25.d.ts +1 -1
  391. package/dist/types/tools/search.d.ts +7 -3
  392. package/dist/types/tools/sqlite-reader.d.ts +4 -0
  393. package/dist/types/tools/ssh.d.ts +2 -1
  394. package/dist/types/tools/todo.d.ts +7 -15
  395. package/dist/types/tools/tool-result.d.ts +2 -0
  396. package/dist/types/tools/tool-timeouts.d.ts +1 -1
  397. package/dist/types/tools/tts.d.ts +26 -1
  398. package/dist/types/tools/write.d.ts +6 -3
  399. package/dist/types/tools/yield.d.ts +8 -0
  400. package/dist/types/tts/downloader.d.ts +20 -0
  401. package/dist/types/tts/index.d.ts +8 -0
  402. package/dist/types/tts/models.d.ts +82 -0
  403. package/dist/types/tts/player.d.ts +32 -0
  404. package/dist/types/tts/runtime.d.ts +6 -0
  405. package/dist/types/tts/streaming-player.d.ts +41 -0
  406. package/dist/types/tts/tts-client.d.ts +93 -0
  407. package/dist/types/tts/tts-protocol.d.ts +95 -0
  408. package/dist/types/tts/tts-worker.d.ts +2 -0
  409. package/dist/types/tts/vocalizer.d.ts +41 -0
  410. package/dist/types/tts/wav.d.ts +8 -0
  411. package/dist/types/tui/code-cell.d.ts +0 -2
  412. package/dist/types/tui/hyperlink.d.ts +13 -7
  413. package/dist/types/tui/output-block.d.ts +16 -22
  414. package/dist/types/tui/status-line.d.ts +3 -0
  415. package/dist/types/utils/block-context.d.ts +35 -0
  416. package/dist/types/utils/changelog.d.ts +8 -0
  417. package/dist/types/utils/clipboard.d.ts +4 -3
  418. package/dist/types/utils/enhanced-paste.d.ts +20 -0
  419. package/dist/types/utils/file-mentions.d.ts +7 -0
  420. package/dist/types/utils/git.d.ts +22 -3
  421. package/dist/types/utils/image-loading.d.ts +30 -1
  422. package/dist/types/utils/session-color.d.ts +15 -3
  423. package/dist/types/utils/thinking-display.d.ts +17 -0
  424. package/dist/types/utils/title-generator.d.ts +3 -2
  425. package/dist/types/utils/tool-choice.d.ts +8 -0
  426. package/dist/types/utils/tools-manager.d.ts +2 -1
  427. package/dist/types/web/kagi.d.ts +2 -2
  428. package/dist/types/web/parallel.d.ts +3 -0
  429. package/dist/types/web/scrapers/github.d.ts +22 -0
  430. package/dist/types/web/scrapers/readthedocs.d.ts +3 -0
  431. package/dist/types/web/scrapers/types.d.ts +12 -0
  432. package/dist/types/web/search/index.d.ts +1 -1
  433. package/dist/types/web/search/providers/anthropic.d.ts +2 -1
  434. package/dist/types/web/search/providers/base.d.ts +2 -1
  435. package/dist/types/web/search/providers/brave.d.ts +2 -1
  436. package/dist/types/web/search/providers/codex.d.ts +2 -1
  437. package/dist/types/web/search/providers/exa.d.ts +2 -1
  438. package/dist/types/web/search/providers/gemini.d.ts +10 -6
  439. package/dist/types/web/search/providers/jina.d.ts +7 -2
  440. package/dist/types/web/search/providers/kagi.d.ts +7 -2
  441. package/dist/types/web/search/providers/kimi.d.ts +7 -2
  442. package/dist/types/web/search/providers/parallel.d.ts +2 -1
  443. package/dist/types/web/search/providers/perplexity.d.ts +10 -2
  444. package/dist/types/web/search/providers/searxng.d.ts +2 -1
  445. package/dist/types/web/search/providers/synthetic.d.ts +7 -3
  446. package/dist/types/web/search/providers/tavily.d.ts +2 -1
  447. package/dist/types/web/search/providers/zai.d.ts +2 -1
  448. package/dist/types/web/search/types.d.ts +1 -1
  449. package/examples/extensions/api-demo.ts +2 -2
  450. package/package.json +41 -15
  451. package/scripts/bench-guard.ts +71 -0
  452. package/scripts/build-binary.ts +24 -25
  453. package/scripts/bundle-dist.ts +97 -0
  454. package/scripts/generate-share-viewer.ts +34 -0
  455. package/scripts/prometheus +42 -0
  456. package/scripts/prometheus.ts +20 -0
  457. package/src/async/index.ts +0 -1
  458. package/src/async/job-manager.ts +106 -3
  459. package/src/auto-thinking/classifier.ts +2 -1
  460. package/src/autolearn/controller.ts +139 -0
  461. package/src/autolearn/managed-skills.ts +257 -0
  462. package/src/autoresearch/dashboard.ts +1 -1
  463. package/src/autoresearch/prompt-setup.md +6 -6
  464. package/src/autoresearch/prompt.md +6 -6
  465. package/src/autoresearch/state.ts +1 -1
  466. package/src/autoresearch/storage.ts +2 -1
  467. package/src/autoresearch/tools/init-experiment.ts +1 -1
  468. package/src/autoresearch/tools/log-experiment.ts +1 -1
  469. package/src/autoresearch/tools/run-experiment.ts +1 -1
  470. package/src/autoresearch/tools/update-notes.ts +1 -1
  471. package/src/autoresearch/types.ts +1 -1
  472. package/src/capability/context-file.ts +0 -14
  473. package/src/capability/fs.ts +10 -0
  474. package/src/capability/index.ts +1 -6
  475. package/src/capability/mcp.ts +1 -0
  476. package/src/capability/rule-buckets.ts +4 -2
  477. package/src/capability/rule.ts +10 -1
  478. package/src/capability/types.ts +0 -4
  479. package/src/cli/args.ts +66 -13
  480. package/src/cli/auth-broker-cli.ts +6 -7
  481. package/src/cli/auth-gateway-cli.ts +8 -9
  482. package/src/cli/bench-cli.ts +437 -0
  483. package/src/cli/claude-trace-cli.ts +28 -50
  484. package/src/cli/completion-gen.ts +28 -28
  485. package/src/cli/dry-balance-cli.ts +56 -23
  486. package/src/cli/gallery-cli.ts +231 -0
  487. package/src/cli/gallery-fixtures/agentic.ts +407 -0
  488. package/src/cli/gallery-fixtures/codeintel.ts +187 -0
  489. package/src/cli/gallery-fixtures/edit.ts +194 -0
  490. package/src/cli/gallery-fixtures/fs.ts +220 -0
  491. package/src/cli/gallery-fixtures/index.ts +40 -0
  492. package/src/cli/gallery-fixtures/interaction.ts +49 -0
  493. package/src/cli/gallery-fixtures/memory.ts +81 -0
  494. package/src/cli/gallery-fixtures/misc.ts +250 -0
  495. package/src/cli/gallery-fixtures/search.ts +213 -0
  496. package/src/cli/gallery-fixtures/shell.ts +167 -0
  497. package/src/cli/gallery-fixtures/types.ts +57 -0
  498. package/src/cli/gallery-fixtures/web.ts +158 -0
  499. package/src/cli/gallery-screenshot.ts +279 -0
  500. package/src/cli/grievances-cli.ts +1 -1
  501. package/src/cli/list-models.ts +16 -174
  502. package/src/cli/models-cli.ts +429 -0
  503. package/src/cli/session-picker.ts +2 -1
  504. package/src/cli/setup-cli.ts +148 -47
  505. package/src/cli/setup-model-picker.ts +43 -0
  506. package/src/cli/startup-cwd.ts +68 -0
  507. package/src/cli/update-cli.ts +144 -272
  508. package/src/cli/usage-cli.ts +774 -0
  509. package/src/cli-commands.ts +36 -0
  510. package/src/cli.ts +141 -32
  511. package/src/collab/crypto.ts +63 -0
  512. package/src/collab/guest.ts +451 -0
  513. package/src/collab/host.ts +565 -0
  514. package/src/collab/protocol.ts +241 -0
  515. package/src/collab/relay-client.ts +216 -0
  516. package/src/commands/bench.ts +42 -0
  517. package/src/commands/complete.ts +1 -1
  518. package/src/commands/gallery.ts +52 -0
  519. package/src/commands/install.ts +1 -1
  520. package/src/commands/join.ts +39 -0
  521. package/src/commands/launch.ts +8 -4
  522. package/src/commands/models.ts +61 -0
  523. package/src/commands/read.ts +6 -3
  524. package/src/commands/say.ts +102 -0
  525. package/src/commands/setup.ts +1 -1
  526. package/src/commands/token.ts +89 -0
  527. package/src/commands/usage.ts +43 -0
  528. package/src/commit/agentic/agent.ts +2 -1
  529. package/src/commit/agentic/tools/analyze-file.ts +42 -20
  530. package/src/commit/agentic/tools/git-file-diff.ts +1 -1
  531. package/src/commit/agentic/tools/git-hunk.ts +1 -1
  532. package/src/commit/agentic/tools/git-overview.ts +1 -1
  533. package/src/commit/agentic/tools/propose-changelog.ts +1 -1
  534. package/src/commit/agentic/tools/propose-commit.ts +1 -1
  535. package/src/commit/agentic/tools/recent-commits.ts +1 -1
  536. package/src/commit/agentic/tools/schemas.ts +1 -1
  537. package/src/commit/agentic/tools/split-commit.ts +9 -2
  538. package/src/commit/analysis/conventional.ts +2 -2
  539. package/src/commit/analysis/summary.ts +3 -3
  540. package/src/commit/changelog/generate.ts +3 -3
  541. package/src/commit/changelog/index.ts +2 -2
  542. package/src/commit/map-reduce/index.ts +3 -3
  543. package/src/commit/map-reduce/map-phase.ts +2 -2
  544. package/src/commit/map-reduce/reduce-phase.ts +2 -2
  545. package/src/commit/model-selection.ts +35 -12
  546. package/src/commit/pipeline.ts +4 -4
  547. package/src/commit/shared-llm.ts +1 -1
  548. package/src/config/api-key-resolver.ts +67 -0
  549. package/src/config/append-only-context-mode.ts +6 -12
  550. package/src/config/keybindings.ts +9 -4
  551. package/src/config/mcp-schema.json +4 -0
  552. package/src/config/model-discovery.ts +574 -0
  553. package/src/config/model-equivalence.ts +5 -4
  554. package/src/config/model-registry.ts +659 -1093
  555. package/src/config/model-resolver.ts +374 -174
  556. package/src/config/model-roles.ts +88 -0
  557. package/src/config/models-config-schema.ts +61 -9
  558. package/src/config/models-config.ts +130 -0
  559. package/src/config/settings-schema.ts +1441 -387
  560. package/src/config/settings.ts +261 -69
  561. package/src/dap/client.ts +138 -53
  562. package/src/dap/config.ts +41 -2
  563. package/src/dap/defaults.json +1 -0
  564. package/src/dap/session.ts +263 -161
  565. package/src/dap/types.ts +10 -0
  566. package/src/debug/index.ts +50 -60
  567. package/src/debug/log-viewer.ts +1 -1
  568. package/src/debug/protocol-probe.ts +1 -1
  569. package/src/debug/raw-sse-buffer.ts +7 -4
  570. package/src/debug/raw-sse.ts +1 -1
  571. package/src/debug/report-bundle.ts +9 -0
  572. package/src/debug/terminal-info.ts +0 -3
  573. package/src/discovery/agents-md.ts +25 -21
  574. package/src/discovery/agents.ts +9 -15
  575. package/src/discovery/at-imports.ts +273 -0
  576. package/src/discovery/builtin-rules/index.ts +4 -0
  577. package/src/discovery/builtin-rules/ts-no-test-timers.md +55 -0
  578. package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +75 -0
  579. package/src/discovery/builtin.ts +45 -23
  580. package/src/discovery/claude-plugins.ts +44 -5
  581. package/src/discovery/helpers.ts +50 -9
  582. package/src/discovery/prometheus-extension-roots.ts +10 -10
  583. package/src/discovery/prometheus-plugins.ts +10 -10
  584. package/src/edit/diff.ts +191 -4
  585. package/src/edit/file-snapshot-store.ts +34 -1
  586. package/src/edit/hashline/block-resolver.ts +20 -1
  587. package/src/edit/hashline/diff.ts +123 -2
  588. package/src/edit/hashline/execute.ts +60 -4
  589. package/src/edit/hashline/filesystem.ts +2 -1
  590. package/src/edit/hashline/noop-loop-guard.ts +99 -0
  591. package/src/edit/hashline/params.ts +1 -1
  592. package/src/edit/index.ts +47 -18
  593. package/src/edit/modes/apply-patch.ts +1 -1
  594. package/src/edit/modes/patch.ts +59 -3
  595. package/src/edit/modes/replace.ts +58 -24
  596. package/src/edit/notebook.ts +22 -2
  597. package/src/edit/renderer.ts +315 -151
  598. package/src/eval/__tests__/agent-bridge.test.ts +105 -39
  599. package/src/eval/__tests__/budget-bridge.test.ts +1 -1
  600. package/src/eval/__tests__/completion-bridge.test.ts +412 -0
  601. package/src/eval/__tests__/helpers-local-roots.test.ts +58 -0
  602. package/src/eval/__tests__/js-context-manager.test.ts +241 -0
  603. package/src/eval/__tests__/llm-bridge.test.ts +6 -4
  604. package/src/eval/__tests__/shared-executors.test.ts +34 -92
  605. package/src/eval/agent-bridge.ts +39 -23
  606. package/src/eval/backend.ts +15 -2
  607. package/src/eval/bridge-timeout.ts +1 -1
  608. package/src/eval/completion-bridge.ts +203 -0
  609. package/src/eval/idle-timeout.ts +3 -10
  610. package/src/eval/js/context-manager.ts +108 -31
  611. package/src/eval/js/executor.ts +9 -2
  612. package/src/eval/js/index.ts +7 -3
  613. package/src/eval/js/shared/helpers.ts +59 -13
  614. package/src/eval/js/shared/local-module-loader.ts +2 -2
  615. package/src/eval/js/shared/prelude.txt +167 -30
  616. package/src/eval/js/shared/rewrite-imports.ts +58 -34
  617. package/src/eval/js/shared/runtime.ts +24 -16
  618. package/src/eval/js/tool-bridge.ts +4 -0
  619. package/src/eval/js/worker-core.ts +1 -0
  620. package/src/eval/js/worker-entry.ts +6 -0
  621. package/src/eval/js/worker-protocol.ts +6 -0
  622. package/src/eval/llm-bridge.ts +2 -1
  623. package/src/eval/py/__tests__/prelude.test.ts +19 -0
  624. package/src/eval/py/executor.ts +70 -26
  625. package/src/eval/py/index.ts +13 -4
  626. package/src/eval/py/kernel.ts +48 -9
  627. package/src/eval/py/prelude.py +73 -24
  628. package/src/eval/py/runner.py +133 -28
  629. package/src/eval/py/runtime.ts +38 -1
  630. package/src/exa/index.ts +1 -26
  631. package/src/exa/mcp-client.ts +10 -10
  632. package/src/exa/types.ts +0 -97
  633. package/src/exec/bash-executor.ts +104 -7
  634. package/src/export/custom-share.ts +1 -1
  635. package/src/export/html/index.ts +119 -17
  636. package/src/export/html/share-loader.js +102 -0
  637. package/src/export/html/template-js.ts +6 -0
  638. package/src/export/html/template.css +745 -459
  639. package/src/export/html/template.css.d.ts +2 -0
  640. package/src/export/html/template.html +6 -3
  641. package/src/export/html/template.js +277 -891
  642. package/src/export/html/tool-views.generated.d.ts +2 -0
  643. package/src/export/html/tool-views.generated.js +38 -0
  644. package/src/export/share.ts +269 -0
  645. package/src/export/ttsr.ts +122 -1
  646. package/src/extensibility/custom-commands/loader.ts +7 -4
  647. package/src/extensibility/custom-commands/types.ts +9 -4
  648. package/src/extensibility/custom-tools/loader.ts +51 -23
  649. package/src/extensibility/custom-tools/types.ts +16 -8
  650. package/src/extensibility/extensions/get-commands-handler.ts +2 -1
  651. package/src/extensibility/extensions/index.ts +1 -0
  652. package/src/extensibility/extensions/loader.ts +70 -20
  653. package/src/extensibility/extensions/model-api.ts +41 -0
  654. package/src/extensibility/extensions/runner.ts +12 -2
  655. package/src/extensibility/extensions/types.ts +83 -11
  656. package/src/extensibility/extensions/wrapper.ts +41 -5
  657. package/src/extensibility/hooks/index.ts +2 -1
  658. package/src/extensibility/hooks/loader.ts +6 -3
  659. package/src/extensibility/hooks/types.ts +11 -5
  660. package/src/extensibility/{legacy-pi-ai-shim.ts → legacy-package-ai-shim.ts} +2 -2
  661. package/src/extensibility/plugins/doctor.ts +1 -2
  662. package/src/extensibility/plugins/installer.ts +2 -2
  663. package/src/extensibility/plugins/{legacy-pi-compat.ts → legacy-package-compat.ts} +165 -77
  664. package/src/extensibility/plugins/loader.ts +34 -23
  665. package/src/extensibility/plugins/manager.ts +226 -95
  666. package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
  667. package/src/extensibility/plugins/types.ts +3 -3
  668. package/src/extensibility/shared-events.ts +3 -3
  669. package/src/extensibility/skills.ts +113 -9
  670. package/src/extensibility/slash-commands.ts +1 -97
  671. package/src/goals/guided-setup.ts +133 -0
  672. package/src/goals/state.ts +1 -1
  673. package/src/goals/tools/goal-tool.ts +38 -28
  674. package/src/hindsight/bank.ts +17 -2
  675. package/src/hindsight/client.ts +27 -2
  676. package/src/hindsight/mental-models.ts +59 -12
  677. package/src/hindsight/state.ts +12 -3
  678. package/src/hindsight/transcript.ts +1 -1
  679. package/src/index.ts +5 -0
  680. package/src/internal-urls/artifact-protocol.ts +11 -2
  681. package/src/internal-urls/docs-index.generated.ts +9 -7
  682. package/src/internal-urls/history-protocol.ts +113 -0
  683. package/src/internal-urls/index.ts +1 -0
  684. package/src/internal-urls/issue-pr-protocol.ts +22 -9
  685. package/src/internal-urls/local-protocol.ts +42 -7
  686. package/src/internal-urls/memory-protocol.ts +4 -31
  687. package/src/internal-urls/router.ts +3 -1
  688. package/src/internal-urls/types.ts +1 -1
  689. package/src/irc/bus.ts +303 -0
  690. package/src/lib/xai-http.ts +3 -3
  691. package/src/lsp/client.ts +245 -104
  692. package/src/lsp/clients/biome-client.ts +101 -39
  693. package/src/lsp/clients/lsp-linter-client.ts +2 -10
  694. package/src/lsp/config.ts +15 -5
  695. package/src/lsp/defaults.json +6 -0
  696. package/src/lsp/edits.ts +143 -95
  697. package/src/lsp/format-options.ts +119 -0
  698. package/src/lsp/index.ts +233 -93
  699. package/src/lsp/render.ts +11 -35
  700. package/src/lsp/types.ts +13 -1
  701. package/src/lsp/utils.ts +31 -12
  702. package/src/main.ts +396 -216
  703. package/src/mcp/config-writer.ts +7 -3
  704. package/src/mcp/json-rpc.ts +35 -5
  705. package/src/mcp/manager.ts +31 -16
  706. package/src/mcp/oauth-discovery.ts +34 -4
  707. package/src/mcp/oauth-flow.ts +61 -8
  708. package/src/mcp/render.ts +7 -1
  709. package/src/mcp/startup-events.ts +21 -0
  710. package/src/mcp/tool-bridge.ts +2 -0
  711. package/src/mcp/transports/stdio.ts +224 -4
  712. package/src/mcp/types.ts +2 -0
  713. package/src/memories/index.ts +174 -1128
  714. package/src/memories/storage.ts +2 -41
  715. package/src/memory-backend/index.ts +14 -1
  716. package/src/memory-backend/local-backend.ts +18 -3
  717. package/src/memory-backend/off-backend.ts +9 -0
  718. package/src/memory-backend/resolve.ts +4 -6
  719. package/src/memory-backend/runtime.ts +66 -0
  720. package/src/memory-backend/types.ts +82 -2
  721. package/src/mnemopi/backend.ts +220 -28
  722. package/src/mnemopi/config.ts +138 -33
  723. package/src/mnemopi/state.ts +91 -11
  724. package/src/modes/acp/acp-agent.ts +149 -142
  725. package/src/modes/acp/acp-event-mapper.ts +5 -1
  726. package/src/modes/components/agent-dashboard.ts +17 -11
  727. package/src/modes/components/agent-hub.ts +1346 -0
  728. package/src/modes/components/assistant-message.ts +190 -80
  729. package/src/modes/components/bash-execution.ts +1 -1
  730. package/src/modes/components/btw-panel.ts +5 -1
  731. package/src/modes/components/chat-block.ts +111 -0
  732. package/src/modes/components/collab-prompt-message.ts +30 -0
  733. package/src/modes/components/compaction-summary-message.ts +168 -33
  734. package/src/modes/components/copy-selector.ts +2 -45
  735. package/src/modes/components/custom-editor.test.ts +96 -0
  736. package/src/modes/components/custom-editor.ts +405 -118
  737. package/src/modes/components/custom-message.ts +1 -3
  738. package/src/modes/components/diff.ts +13 -2
  739. package/src/modes/components/dynamic-border.ts +12 -3
  740. package/src/modes/components/execution-shared.ts +1 -2
  741. package/src/modes/components/extensions/extension-dashboard.ts +8 -5
  742. package/src/modes/components/extensions/extension-list.ts +1 -1
  743. package/src/modes/components/extensions/inspector-panel.ts +7 -3
  744. package/src/modes/components/extensions/state-manager.ts +36 -41
  745. package/src/modes/components/footer.ts +4 -2
  746. package/src/modes/components/history-search.ts +1 -1
  747. package/src/modes/components/hook-editor.ts +8 -0
  748. package/src/modes/components/hook-input.ts +8 -0
  749. package/src/modes/components/hook-message.ts +1 -3
  750. package/src/modes/components/hook-selector.ts +6 -7
  751. package/src/modes/components/index.ts +1 -0
  752. package/src/modes/components/late-diagnostics-message.ts +60 -0
  753. package/src/modes/components/login-dialog.ts +1 -1
  754. package/src/modes/components/logout-account-selector.ts +130 -0
  755. package/src/modes/components/mcp-add-wizard.ts +14 -1
  756. package/src/modes/components/model-selector.ts +177 -75
  757. package/src/modes/components/oauth-selector.ts +102 -16
  758. package/src/modes/components/overlay-box.ts +108 -0
  759. package/src/modes/components/plan-review-overlay.ts +845 -0
  760. package/src/modes/components/plan-toc.ts +138 -0
  761. package/src/modes/components/plugin-settings.ts +22 -5
  762. package/src/modes/components/read-tool-group.ts +442 -39
  763. package/src/modes/components/reset-usage-selector.ts +161 -0
  764. package/src/modes/components/segment-track.ts +44 -7
  765. package/src/modes/components/session-selector.ts +97 -37
  766. package/src/modes/components/settings-defs.ts +28 -6
  767. package/src/modes/components/settings-selector.ts +541 -93
  768. package/src/modes/components/skill-message.ts +0 -1
  769. package/src/modes/components/snapcompact-shape-preview-doc.md +11 -0
  770. package/src/modes/components/snapcompact-shape-preview.ts +193 -0
  771. package/src/modes/components/{status-line.ts → status-line/component.ts} +205 -168
  772. package/src/modes/components/status-line/index.ts +1 -0
  773. package/src/modes/components/status-line/presets.ts +3 -3
  774. package/src/modes/components/status-line/segments.ts +26 -7
  775. package/src/modes/components/status-line/types.ts +40 -9
  776. package/src/modes/components/tiny-title-download-progress.ts +1 -1
  777. package/src/modes/components/tips.txt +7 -3
  778. package/src/modes/components/todo-reminder.ts +0 -2
  779. package/src/modes/components/tool-execution.ts +236 -103
  780. package/src/modes/components/transcript-container.ts +724 -99
  781. package/src/modes/components/tree-selector.ts +19 -4
  782. package/src/modes/components/ttsr-notification.ts +72 -30
  783. package/src/modes/components/usage-row.ts +18 -0
  784. package/src/modes/components/user-message-selector.ts +1 -1
  785. package/src/modes/components/user-message.ts +28 -12
  786. package/src/modes/components/visual-truncate.ts +1 -1
  787. package/src/modes/components/welcome.ts +80 -22
  788. package/src/modes/controllers/command-controller-shared.ts +7 -6
  789. package/src/modes/controllers/command-controller.ts +210 -180
  790. package/src/modes/controllers/event-controller.ts +352 -142
  791. package/src/modes/controllers/extension-ui-controller.ts +167 -208
  792. package/src/modes/controllers/input-controller.ts +778 -162
  793. package/src/modes/controllers/mcp-command-controller.ts +232 -80
  794. package/src/modes/controllers/selector-controller.ts +284 -145
  795. package/src/modes/controllers/session-focus-controller.ts +112 -0
  796. package/src/modes/controllers/ssh-command-controller.ts +2 -2
  797. package/src/modes/controllers/streaming-reveal.ts +295 -0
  798. package/src/modes/controllers/tan-command-controller.ts +173 -0
  799. package/src/modes/controllers/tool-args-reveal.ts +174 -0
  800. package/src/modes/gradient-highlight.ts +21 -9
  801. package/src/modes/image-references.ts +33 -7
  802. package/src/modes/index.ts +8 -25
  803. package/src/modes/interactive-mode.ts +840 -186
  804. package/src/modes/magic-keywords.ts +28 -6
  805. package/src/modes/markdown-prose.ts +1 -1
  806. package/src/modes/oauth-manual-input.ts +30 -3
  807. package/src/modes/rpc/rpc-client.ts +186 -3
  808. package/src/modes/rpc/rpc-mode.ts +318 -24
  809. package/src/modes/rpc/rpc-subagents.ts +265 -0
  810. package/src/modes/rpc/rpc-types.ts +111 -2
  811. package/src/modes/runtime-init.ts +28 -3
  812. package/src/modes/session-observer-registry.ts +72 -3
  813. package/src/modes/setup-version.ts +11 -0
  814. package/src/modes/setup-wizard/index.ts +16 -4
  815. package/src/modes/setup-wizard/lazy.ts +16 -0
  816. package/src/modes/setup-wizard/scenes/glyph.ts +25 -7
  817. package/src/modes/setup-wizard/scenes/providers.ts +45 -12
  818. package/src/modes/setup-wizard/scenes/sign-in.ts +14 -13
  819. package/src/modes/setup-wizard/scenes/splash.ts +1 -1
  820. package/src/modes/setup-wizard/scenes/theme.ts +29 -2
  821. package/src/modes/setup-wizard/scenes/types.ts +11 -2
  822. package/src/modes/setup-wizard/scenes/web-search.ts +26 -9
  823. package/src/modes/setup-wizard/wizard-overlay.ts +40 -3
  824. package/src/modes/shared.ts +2 -0
  825. package/src/modes/theme/defaults/dark-poimandres.json +1 -1
  826. package/src/modes/theme/defaults/light-poimandres.json +1 -1
  827. package/src/modes/theme/shimmer.ts +20 -9
  828. package/src/modes/theme/theme-schema.json +1 -1
  829. package/src/modes/theme/theme.ts +342 -82
  830. package/src/modes/types.ts +60 -18
  831. package/src/modes/utils/context-usage.ts +88 -8
  832. package/src/modes/utils/copy-targets.ts +133 -27
  833. package/src/modes/utils/hotkeys-markdown.ts +3 -2
  834. package/src/modes/utils/ui-helpers.ts +191 -110
  835. package/src/modes/workflow.ts +10 -10
  836. package/src/plan-mode/approved-plan.ts +66 -43
  837. package/src/plan-mode/plan-protection.ts +4 -4
  838. package/src/priority.json +5 -1
  839. package/src/prompts/agents/designer.md +1 -1
  840. package/src/prompts/agents/explore.md +3 -3
  841. package/src/prompts/agents/librarian.md +2 -3
  842. package/src/prompts/agents/oracle.md +2 -2
  843. package/src/prompts/agents/plan.md +6 -6
  844. package/src/prompts/agents/reviewer.md +1 -1
  845. package/src/prompts/agents/task.md +6 -5
  846. package/src/prompts/bench.md +12 -0
  847. package/src/prompts/ci-green-request.md +5 -7
  848. package/src/prompts/goals/goal-budget-limit.md +2 -2
  849. package/src/prompts/goals/goal-continuation.md +4 -4
  850. package/src/prompts/goals/goal-mode-active.md +1 -1
  851. package/src/prompts/goals/guided-goal-interview.md +8 -0
  852. package/src/prompts/goals/guided-goal-system.md +12 -0
  853. package/src/prompts/memories/consolidation.md +2 -7
  854. package/src/prompts/memories/consolidation_system.md +4 -0
  855. package/src/prompts/memories/identity_review.md +2 -2
  856. package/src/prompts/memories/read-path.md +11 -10
  857. package/src/prompts/memories/stage_one_system.md +2 -2
  858. package/src/prompts/review-custom-request.md +1 -1
  859. package/src/prompts/system/agent-creation-architect.md +2 -2
  860. package/src/prompts/system/auto-continue.md +1 -1
  861. package/src/prompts/system/autolearn-guidance-learn.md +1 -0
  862. package/src/prompts/system/autolearn-guidance.md +7 -0
  863. package/src/prompts/system/autolearn-nudge.md +3 -0
  864. package/src/prompts/system/background-tan-dispatch.md +8 -0
  865. package/src/prompts/system/btw-user.md +2 -2
  866. package/src/prompts/system/commit-message-system.md +13 -1
  867. package/src/prompts/system/custom-system-prompt.md +1 -1
  868. package/src/prompts/system/eager-task.md +7 -0
  869. package/src/prompts/system/eager-todo.md +11 -6
  870. package/src/prompts/system/empty-stop-retry.md +4 -6
  871. package/src/prompts/system/irc-autoreply.md +6 -0
  872. package/src/prompts/system/irc-incoming.md +3 -4
  873. package/src/prompts/system/manual-continue.md +7 -0
  874. package/src/prompts/system/omfg-user.md +3 -4
  875. package/src/prompts/system/orchestrate-notice.md +10 -10
  876. package/src/prompts/system/personalities/default.md +26 -0
  877. package/src/prompts/system/personalities/friendly.md +17 -0
  878. package/src/prompts/system/personalities/pragmatic.md +15 -0
  879. package/src/prompts/system/plan-mode-active.md +70 -77
  880. package/src/prompts/system/plan-mode-approved.md +1 -1
  881. package/src/prompts/system/plan-mode-subagent.md +4 -5
  882. package/src/prompts/system/plan-mode-tool-decision-reminder.md +1 -1
  883. package/src/prompts/system/project-prompt.md +2 -2
  884. package/src/prompts/system/snapcompact-context-frames-note.md +1 -0
  885. package/src/prompts/system/snapcompact-context-stub.md +1 -0
  886. package/src/prompts/system/snapcompact-system-frames-note.md +1 -0
  887. package/src/prompts/system/snapcompact-system-stub.md +1 -0
  888. package/src/prompts/system/snapcompact-toolresult-note.md +1 -0
  889. package/src/prompts/system/subagent-system-prompt.md +7 -8
  890. package/src/prompts/system/system-prompt.md +28 -57
  891. package/src/prompts/system/tiny-title-system.md +1 -1
  892. package/src/prompts/system/title-marker-instruction.md +1 -0
  893. package/src/prompts/system/title-system-marker.md +16 -0
  894. package/src/prompts/system/title-system.md +16 -3
  895. package/src/prompts/system/ttsr-tool-reminder.md +1 -1
  896. package/src/prompts/system/workflow-notice.md +4 -4
  897. package/src/prompts/tools/ast-edit.md +1 -1
  898. package/src/prompts/tools/ast-grep.md +2 -2
  899. package/src/prompts/tools/bash.md +16 -8
  900. package/src/prompts/tools/browser.md +33 -43
  901. package/src/prompts/tools/debug.md +1 -1
  902. package/src/prompts/tools/eval.md +31 -51
  903. package/src/prompts/tools/find.md +0 -1
  904. package/src/prompts/tools/github.md +8 -7
  905. package/src/prompts/tools/goal.md +1 -1
  906. package/src/prompts/tools/image-gen.md +1 -1
  907. package/src/prompts/tools/inspect-image-system.md +1 -1
  908. package/src/prompts/tools/irc.md +39 -31
  909. package/src/prompts/tools/job.md +2 -1
  910. package/src/prompts/tools/learn.md +7 -0
  911. package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
  912. package/src/prompts/tools/lsp.md +2 -2
  913. package/src/prompts/tools/manage-skill.md +9 -0
  914. package/src/prompts/tools/memory-edit.md +1 -1
  915. package/src/prompts/tools/patch.md +2 -2
  916. package/src/prompts/tools/read.md +31 -39
  917. package/src/prompts/tools/recall.md +1 -1
  918. package/src/prompts/tools/reflect.md +1 -1
  919. package/src/prompts/tools/render-mermaid.md +2 -2
  920. package/src/prompts/tools/replace.md +4 -10
  921. package/src/prompts/tools/rewind.md +2 -2
  922. package/src/prompts/tools/search-tool-bm25.md +1 -9
  923. package/src/prompts/tools/search.md +0 -1
  924. package/src/prompts/tools/ssh.md +0 -4
  925. package/src/prompts/tools/task-summary.md +5 -16
  926. package/src/prompts/tools/task.md +47 -31
  927. package/src/prompts/tools/todo.md +6 -3
  928. package/src/registry/agent-lifecycle.ts +218 -0
  929. package/src/registry/agent-registry.ts +46 -5
  930. package/src/sdk.ts +692 -219
  931. package/src/secrets/index.ts +8 -1
  932. package/src/secrets/obfuscator.ts +40 -19
  933. package/src/session/agent-session.ts +1577 -806
  934. package/src/session/agent-storage.ts +18 -9
  935. package/src/session/auth-broker-config.ts +30 -1
  936. package/src/session/auth-storage.ts +6 -0
  937. package/src/session/codex-auto-reset.ts +202 -0
  938. package/src/session/history-storage.ts +3 -2
  939. package/src/session/indexed-session-storage.ts +7 -10
  940. package/src/session/messages.ts +59 -95
  941. package/src/session/session-context.ts +352 -0
  942. package/src/session/session-dump-format.ts +12 -3
  943. package/src/session/session-entries.ts +194 -0
  944. package/src/session/session-history-format.ts +246 -0
  945. package/src/session/session-listing.ts +588 -0
  946. package/src/session/session-loader.ts +106 -0
  947. package/src/session/session-manager.ts +1003 -2920
  948. package/src/session/session-migrations.ts +78 -0
  949. package/src/session/session-paths.ts +193 -0
  950. package/src/session/session-persistence.ts +131 -0
  951. package/src/session/session-storage.ts +91 -30
  952. package/src/session/snapcompact-inline.ts +542 -0
  953. package/src/session/snapcompact-savings-journal.ts +113 -0
  954. package/src/session/streaming-output.ts +248 -11
  955. package/src/session/tool-choice-queue.ts +23 -11
  956. package/src/session/yield-queue.ts +20 -2
  957. package/src/slash-commands/acp-builtins.ts +25 -1
  958. package/src/slash-commands/available-commands.ts +105 -0
  959. package/src/slash-commands/builtin-registry.ts +575 -49
  960. package/src/slash-commands/helpers/active-oauth-account.ts +44 -0
  961. package/src/slash-commands/helpers/context-report.ts +28 -1
  962. package/src/slash-commands/helpers/logout.ts +88 -0
  963. package/src/slash-commands/helpers/reset-usage.ts +66 -0
  964. package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
  965. package/src/slash-commands/helpers/usage-report.ts +38 -3
  966. package/src/slash-commands/types.ts +5 -9
  967. package/src/ssh/connection-manager.ts +27 -0
  968. package/src/ssh/ssh-executor.ts +60 -4
  969. package/src/stt/asr-client.ts +520 -0
  970. package/src/stt/asr-protocol.ts +65 -0
  971. package/src/stt/asr-worker.ts +790 -0
  972. package/src/stt/downloader.ts +107 -47
  973. package/src/stt/endpointer.ts +259 -0
  974. package/src/stt/index.ts +5 -1
  975. package/src/stt/models.ts +150 -0
  976. package/src/stt/recorder.ts +254 -67
  977. package/src/stt/stt-controller.ts +201 -22
  978. package/src/stt/transcriber.ts +37 -68
  979. package/src/stt/wav.ts +173 -0
  980. package/src/system-prompt.ts +52 -10
  981. package/src/task/agents.ts +3 -4
  982. package/src/task/commands.ts +3 -2
  983. package/src/task/discovery.ts +17 -24
  984. package/src/task/executor.ts +1054 -529
  985. package/src/task/index.ts +862 -757
  986. package/src/task/output-manager.ts +0 -11
  987. package/src/task/parallel.ts +3 -3
  988. package/src/task/prometheus-command.ts +2 -2
  989. package/src/task/render.ts +529 -182
  990. package/src/task/repair-args.ts +21 -9
  991. package/src/task/types.ts +144 -66
  992. package/src/task/worktree.ts +64 -56
  993. package/src/telemetry-export.ts +27 -9
  994. package/src/thinking.ts +9 -7
  995. package/src/tiny/models.ts +2 -2
  996. package/src/tiny/text.ts +5 -1
  997. package/src/tiny/title-client.ts +72 -20
  998. package/src/tiny/title-protocol.ts +1 -1
  999. package/src/tiny/worker.ts +23 -99
  1000. package/src/tool-discovery/tool-index.ts +2 -0
  1001. package/src/tools/archive-reader.ts +94 -2
  1002. package/src/tools/ask.ts +234 -177
  1003. package/src/tools/ast-edit.ts +136 -80
  1004. package/src/tools/ast-grep.ts +41 -45
  1005. package/src/tools/auto-generated-guard.ts +20 -3
  1006. package/src/tools/bash-interactive.ts +28 -8
  1007. package/src/tools/bash.ts +198 -35
  1008. package/src/tools/browser/attach.ts +26 -7
  1009. package/src/tools/browser/cmux/cmux-tab.ts +1264 -0
  1010. package/src/tools/browser/cmux/rpc.ts +156 -0
  1011. package/src/tools/browser/cmux/socket-client.ts +309 -0
  1012. package/src/tools/browser/launch.ts +11 -2
  1013. package/src/tools/browser/readable.ts +19 -2
  1014. package/src/tools/browser/registry.ts +52 -5
  1015. package/src/tools/browser/render.ts +13 -5
  1016. package/src/tools/browser/tab-protocol.ts +2 -0
  1017. package/src/tools/browser/tab-supervisor.ts +256 -34
  1018. package/src/tools/browser/tab-worker.ts +259 -91
  1019. package/src/tools/browser.ts +44 -2
  1020. package/src/tools/checkpoint.ts +1 -1
  1021. package/src/tools/conflict-detect.ts +50 -4
  1022. package/src/tools/debug.ts +27 -12
  1023. package/src/tools/eval-render.ts +32 -35
  1024. package/src/tools/eval.ts +26 -12
  1025. package/src/tools/fetch.ts +450 -99
  1026. package/src/tools/find.ts +182 -142
  1027. package/src/tools/gh-cache-invalidation.ts +255 -0
  1028. package/src/tools/gh-renderer.ts +104 -51
  1029. package/src/tools/gh.ts +232 -37
  1030. package/src/tools/github-cache.ts +97 -7
  1031. package/src/tools/grouped-file-output.ts +159 -52
  1032. package/src/tools/image-gen.ts +237 -132
  1033. package/src/tools/index.ts +147 -26
  1034. package/src/tools/inspect-image-renderer.ts +74 -45
  1035. package/src/tools/inspect-image.ts +12 -6
  1036. package/src/tools/irc.ts +626 -173
  1037. package/src/tools/job.ts +106 -29
  1038. package/src/tools/learn.ts +144 -0
  1039. package/src/tools/manage-skill.ts +104 -0
  1040. package/src/tools/memory-edit.ts +4 -4
  1041. package/src/tools/memory-recall.ts +7 -9
  1042. package/src/tools/memory-reflect.ts +5 -9
  1043. package/src/tools/memory-render.ts +23 -6
  1044. package/src/tools/memory-retain.ts +4 -4
  1045. package/src/tools/path-utils.ts +102 -48
  1046. package/src/tools/plan-mode-guard.ts +101 -40
  1047. package/src/tools/read.ts +475 -120
  1048. package/src/tools/render-mermaid.ts +1 -1
  1049. package/src/tools/render-utils.ts +132 -76
  1050. package/src/tools/renderers.ts +12 -1
  1051. package/src/tools/report-tool-issue.ts +14 -6
  1052. package/src/tools/resolve.ts +20 -3
  1053. package/src/tools/review.ts +2 -2
  1054. package/src/tools/search-tool-bm25.ts +37 -24
  1055. package/src/tools/search.ts +233 -115
  1056. package/src/tools/sqlite-reader.ts +26 -17
  1057. package/src/tools/ssh.ts +20 -14
  1058. package/src/tools/todo.ts +197 -191
  1059. package/src/tools/tool-result.ts +8 -0
  1060. package/src/tools/tool-timeouts.ts +1 -1
  1061. package/src/tools/tts.ts +205 -74
  1062. package/src/tools/write.ts +291 -155
  1063. package/src/tools/yield.ts +10 -1
  1064. package/src/tts/downloader.ts +64 -0
  1065. package/src/tts/index.ts +8 -0
  1066. package/src/tts/models.ts +137 -0
  1067. package/src/tts/player.ts +137 -0
  1068. package/src/tts/runtime.ts +21 -0
  1069. package/src/tts/streaming-player.ts +266 -0
  1070. package/src/tts/tts-client.ts +647 -0
  1071. package/src/tts/tts-protocol.ts +60 -0
  1072. package/src/tts/tts-worker.ts +505 -0
  1073. package/src/tts/vocalizer.ts +162 -0
  1074. package/src/tts/wav.ts +58 -0
  1075. package/src/tui/code-cell.ts +2 -7
  1076. package/src/tui/hyperlink.ts +40 -26
  1077. package/src/tui/output-block.ts +60 -108
  1078. package/src/tui/status-line.ts +5 -1
  1079. package/src/utils/block-context.ts +312 -0
  1080. package/src/utils/changelog.ts +27 -1
  1081. package/src/utils/clipboard.ts +91 -22
  1082. package/src/utils/commit-message-generator.ts +8 -3
  1083. package/src/utils/enhanced-paste.ts +230 -0
  1084. package/src/utils/file-mentions.ts +3 -1
  1085. package/src/utils/git.ts +315 -15
  1086. package/src/utils/image-loading.ts +65 -4
  1087. package/src/utils/session-color.ts +83 -9
  1088. package/src/utils/thinking-display.ts +37 -0
  1089. package/src/utils/title-generator.ts +73 -10
  1090. package/src/utils/tool-choice.ts +16 -0
  1091. package/src/utils/tools-manager.ts +19 -1
  1092. package/src/web/kagi.ts +28 -26
  1093. package/src/web/parallel.ts +7 -3
  1094. package/src/web/scrapers/arxiv.ts +1 -1
  1095. package/src/web/scrapers/github.ts +351 -3
  1096. package/src/web/scrapers/go-pkg.ts +1 -1
  1097. package/src/web/scrapers/iacr.ts +1 -1
  1098. package/src/web/scrapers/readthedocs.ts +1 -1
  1099. package/src/web/scrapers/twitter.ts +2 -1
  1100. package/src/web/scrapers/types.ts +87 -8
  1101. package/src/web/scrapers/wikipedia.ts +1 -1
  1102. package/src/web/scrapers/youtube.ts +9 -3
  1103. package/src/web/search/index.ts +15 -2
  1104. package/src/web/search/providers/anthropic.ts +62 -21
  1105. package/src/web/search/providers/base.ts +2 -1
  1106. package/src/web/search/providers/brave.ts +5 -2
  1107. package/src/web/search/providers/codex.ts +87 -51
  1108. package/src/web/search/providers/exa.ts +101 -10
  1109. package/src/web/search/providers/gemini.ts +49 -24
  1110. package/src/web/search/providers/jina.ts +15 -5
  1111. package/src/web/search/providers/kagi.ts +9 -2
  1112. package/src/web/search/providers/kimi.ts +45 -20
  1113. package/src/web/search/providers/parallel.ts +39 -24
  1114. package/src/web/search/providers/perplexity.ts +226 -63
  1115. package/src/web/search/providers/searxng.ts +19 -3
  1116. package/src/web/search/providers/synthetic.ts +16 -11
  1117. package/src/web/search/providers/tavily.ts +12 -9
  1118. package/src/web/search/providers/zai.ts +22 -9
  1119. package/src/web/search/render.ts +59 -64
  1120. package/src/web/search/types.ts +5 -1
  1121. package/dist/types/discovery/context-files.d.ts +0 -17
  1122. package/dist/types/exa/factory.d.ts +0 -13
  1123. package/dist/types/exa/render.d.ts +0 -19
  1124. package/dist/types/exa/researcher.d.ts +0 -9
  1125. package/dist/types/exa/search.d.ts +0 -9
  1126. package/dist/types/exa/websets.d.ts +0 -9
  1127. package/dist/types/export/html/template.generated.d.ts +0 -1
  1128. package/dist/types/modes/components/session-observer-overlay.d.ts +0 -11
  1129. package/dist/types/modes/components/status-line.d.ts +0 -77
  1130. package/dist/types/slash-commands/headless-plan.d.ts +0 -3
  1131. package/dist/types/stt/setup.d.ts +0 -18
  1132. package/scripts/generate-template.ts +0 -33
  1133. package/src/discovery/context-files.ts +0 -49
  1134. package/src/exa/factory.ts +0 -60
  1135. package/src/exa/render.ts +0 -244
  1136. package/src/exa/researcher.ts +0 -36
  1137. package/src/exa/search.ts +0 -47
  1138. package/src/exa/websets.ts +0 -248
  1139. package/src/export/html/template.generated.ts +0 -2
  1140. package/src/modes/components/session-observer-overlay.ts +0 -852
  1141. package/src/slash-commands/headless-plan.ts +0 -142
  1142. package/src/stt/setup.ts +0 -52
  1143. package/src/stt/transcribe.py +0 -70
  1144. /package/dist/types/extensibility/{legacy-pi-coding-agent-shim.d.ts → legacy-package-agent-shim.d.ts} +0 -0
  1145. /package/src/extensibility/{legacy-pi-coding-agent-shim.ts → legacy-package-agent-shim.ts} +0 -0
package/src/task/index.ts CHANGED
@@ -7,11 +7,13 @@
7
7
  * - .prometheus/agents/*.md (project-level)
8
8
  *
9
9
  * Supports:
10
- * - Single agent execution
11
- * - Parallel execution with concurrency limits
10
+ * - Single agent spawn per call (parallelism = parallel task calls)
11
+ * - Batch spawning + shared context per call when `task.batch` is enabled
12
+ * - Background execution through AsyncJobManager when `async.enabled` is enabled
12
13
  * - Progress tracking via JSON events
13
14
  * - Session artifacts for debugging
14
15
  */
16
+
15
17
  import * as fs from "node:fs/promises";
16
18
  import * as os from "node:os";
17
19
  import path from "node:path";
@@ -27,29 +29,34 @@ import subagentUserPromptTemplate from "../prompts/system/subagent-user-prompt.m
27
29
  import taskDescriptionTemplate from "../prompts/tools/task.md" with { type: "text" };
28
30
  import taskSummaryTemplate from "../prompts/tools/task-summary.md" with { type: "text" };
29
31
  import { truncateForPrompt } from "../tools/approval";
32
+ import { isIrcEnabled } from "../tools/irc";
30
33
  import { formatBytes, formatDuration } from "../tools/render-utils";
31
34
  import {
32
35
  type AgentDefinition,
33
36
  type AgentProgress,
37
+ canSpawnAtDepth,
34
38
  getTaskSchema,
35
39
  type SingleResult,
40
+ type TaskItem,
36
41
  type TaskParams,
37
42
  type TaskToolDetails,
38
43
  type TaskToolSchemaInstance,
39
44
  } from "./types";
40
45
  // Import review tools for side effects (registers subagent tool handlers)
41
46
  import "../tools/review";
47
+ import type { AsyncJobManager } from "../async";
42
48
  import type { LocalProtocolOptions } from "../internal-urls";
43
49
  import { loadOverallPlanReference } from "../plan-mode/plan-handoff";
50
+ import { AgentRegistry } from "../registry/agent-registry";
44
51
  import { generateCommitMessage } from "../utils/commit-message-generator";
45
52
  import * as git from "../utils/git";
46
- import { discoverAgents, getAgent } from "./discovery";
53
+ import { type DiscoveryResult, discoverAgents, getAgent } from "./discovery";
47
54
  import { runSubprocess } from "./executor";
55
+ import { generateTaskName } from "./name-generator";
48
56
  import { AgentOutputManager } from "./output-manager";
49
57
  import { mapWithConcurrencyLimit, Semaphore } from "./parallel";
50
58
  import { renderResult, renderCall as renderTaskCall } from "./render";
51
59
  import { repairTaskParams } from "./repair-args";
52
- import { getTaskSimpleModeCapabilities, type TaskSimpleMode } from "./simple-mode";
53
60
  import {
54
61
  applyNestedPatches,
55
62
  captureBaseline,
@@ -65,12 +72,12 @@ import {
65
72
  type WorktreeBaseline,
66
73
  } from "./worktree";
67
74
 
68
- function renderSubagentUserPrompt(assignment: string, simpleMode: TaskSimpleMode): string {
75
+ function renderSubagentUserPrompt(assignment: string): string {
69
76
  return prompt.render(subagentUserPromptTemplate, {
70
77
  assignment: assignment.trim(),
71
- independentMode: simpleMode === "independent",
72
78
  });
73
79
  }
80
+
74
81
  function createUsageTotals(): Usage {
75
82
  return {
76
83
  input: 0,
@@ -119,6 +126,7 @@ export type {
119
126
  AgentDefinition,
120
127
  AgentProgress,
121
128
  SingleResult,
129
+ SubagentEventPayload,
122
130
  SubagentLifecyclePayload,
123
131
  SubagentProgressPayload,
124
132
  TaskParams,
@@ -158,10 +166,23 @@ export const READ_ONLY_TOOL_NAMES: ReadonlySet<string> = new Set([
158
166
  "search_tool_bm25",
159
167
  ]);
160
168
 
169
+ const PLAN_MODE_AGENT_TOOL_ALLOWLIST: ReadonlySet<string> = new Set(["ast_grep", "report_finding"]);
170
+
161
171
  export function isReadOnlyAgent(agent: AgentDefinition): boolean {
162
172
  return !!agent.tools?.length && agent.tools.every(tool => READ_ONLY_TOOL_NAMES.has(tool));
163
173
  }
164
174
 
175
+ /**
176
+ * Preview text for a child result. Falls back to "(no output)" — annotated
177
+ * with the request count when the child actually did work, so the parent can
178
+ * tell a no-op child from one that burned requests before being cancelled.
179
+ */
180
+ export function formatResultOutputFallback(result: Pick<SingleResult, "output" | "stderr" | "requests">): string {
181
+ const base = result.output.trim() || result.stderr.trim();
182
+ if (base) return base;
183
+ return result.requests > 0 ? `(no output) after ${result.requests} req` : "(no output)";
184
+ }
185
+
165
186
  /**
166
187
  * Render the tool description from a cached agent list and current settings.
167
188
  */
@@ -169,9 +190,9 @@ function renderDescription(
169
190
  agents: AgentDefinition[],
170
191
  maxConcurrency: number,
171
192
  isolationEnabled: boolean,
172
- asyncEnabled: boolean,
173
193
  disabledAgents: string[],
174
- simpleMode: TaskSimpleMode,
194
+ batchEnabled: boolean,
195
+ asyncEnabled: boolean,
175
196
  ircEnabled: boolean,
176
197
  parentSpawns: string,
177
198
  ): string {
@@ -193,19 +214,14 @@ function renderDescription(
193
214
  description: agent.description,
194
215
  readOnly: isReadOnlyAgent(agent),
195
216
  }));
196
- const { contextEnabled, customSchemaEnabled } = getTaskSimpleModeCapabilities(simpleMode);
197
217
  return prompt.render(taskDescriptionTemplate, {
198
218
  agents: renderedAgents,
199
219
  spawningDisabled,
200
220
  MAX_CONCURRENCY: maxConcurrency,
201
221
  isolationEnabled,
222
+ batchEnabled,
202
223
  asyncEnabled,
203
- contextEnabled,
204
- customSchemaEnabled,
205
224
  ircEnabled,
206
- defaultMode: simpleMode === "default",
207
- schemaFreeMode: simpleMode === "schema-free",
208
- independentMode: simpleMode === "independent",
209
225
  });
210
226
  }
211
227
 
@@ -216,28 +232,173 @@ function createTaskModeError(text: string): AgentToolResult<TaskToolDetails> {
216
232
  };
217
233
  }
218
234
 
219
- function validateTaskModeParams(simpleMode: TaskSimpleMode, params: TaskParams): string | undefined {
220
- const { contextEnabled, customSchemaEnabled } = getTaskSimpleModeCapabilities(simpleMode);
221
- const disallowedFields: string[] = [];
222
- if (!contextEnabled && params.context !== undefined) {
223
- disallowedFields.push("context");
235
+ /**
236
+ * Reject fields the current configuration does not accept. `schema` is never
237
+ * accepted (structured output comes from the agent definition's `output`
238
+ * frontmatter, the inherited session schema, or an eval-workflow
239
+ * `agent(..., schema)` call); `tasks`/`context` require `task.batch`.
240
+ */
241
+ function validateShapeParams(batchEnabled: boolean, params: TaskParams): string | undefined {
242
+ if ((params as Record<string, unknown>).schema !== undefined) {
243
+ 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)`.";
224
244
  }
225
- if (!customSchemaEnabled && params.schema !== undefined) {
226
- disallowedFields.push("schema");
245
+ if (!batchEnabled) {
246
+ const disallowed = (["tasks", "context"] as const).filter(field => params[field] !== undefined);
247
+ if (disallowed.length > 0) {
248
+ 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.`;
249
+ }
227
250
  }
228
- if (disallowedFields.length === 0) {
251
+ return undefined;
252
+ }
253
+
254
+ /**
255
+ * Validate the spawn parameter contract against the wire shapes. `agent` is
256
+ * always required. With `task.batch` the model-facing shape is
257
+ * `{ agent, context, tasks[] }` — `tasks` non-empty with per-item assignments
258
+ * and unique ids, `context` non-empty, no top-level `assignment` alongside.
259
+ * The flat `{ agent, ...item }` form stays accepted at runtime under either
260
+ * setting (internal callers, stale transcripts). Returns a problem
261
+ * description, or undefined when valid.
262
+ */
263
+ function validateSpawnParams(params: TaskParams, batchEnabled: boolean): string | undefined {
264
+ const agent = typeof params.agent === "string" ? params.agent.trim() : "";
265
+ if (!agent) {
266
+ return "Missing `agent`. Provide an agent type to spawn.";
267
+ }
268
+ const hasAssignment = typeof params.assignment === "string" && params.assignment.trim() !== "";
269
+ const tasks = params.tasks;
270
+ if (batchEnabled && tasks !== undefined) {
271
+ if (!Array.isArray(tasks) || tasks.length === 0) {
272
+ return "Missing `tasks`. Provide at least one task item ({ id?, description?, assignment }).";
273
+ }
274
+ if (hasAssignment) {
275
+ return "Top-level `assignment` is not part of the batch shape. Put the work in `tasks[]` items.";
276
+ }
277
+ for (let i = 0; i < tasks.length; i++) {
278
+ const item = tasks[i];
279
+ if (!item || typeof item.assignment !== "string" || item.assignment.trim() === "") {
280
+ return `Task ${i + 1}${item?.id ? ` (\`${item.id}\`)` : ""} is missing \`assignment\`. Every task needs complete, self-contained instructions.`;
281
+ }
282
+ }
283
+ const seen = new Map<string, string>();
284
+ for (const item of tasks) {
285
+ const id = item.id?.trim();
286
+ if (!id) continue;
287
+ const key = id.toLowerCase();
288
+ const existing = seen.get(key);
289
+ if (existing !== undefined) {
290
+ return `Duplicate task id ${existing === id ? `\`${id}\`` : `\`${existing}\` / \`${id}\``}. Provided ids must be unique within a call (case-insensitive).`;
291
+ }
292
+ seen.set(key, id);
293
+ }
294
+ if (typeof params.context !== "string" || params.context.trim() === "") {
295
+ return "Missing `context`. Provide the shared background for this batch — goal, constraints, and any contract the tasks share.";
296
+ }
229
297
  return undefined;
230
298
  }
299
+ if (!hasAssignment) {
300
+ return batchEnabled
301
+ ? "Missing `tasks`. Provide a `tasks` array (one subagent per item) with a shared `context`."
302
+ : "Missing `assignment`. Provide complete, self-contained instructions for the agent.";
303
+ }
304
+ return undefined;
305
+ }
231
306
 
232
- if (simpleMode === "schema-free") {
233
- return "task.simple is set to schema-free, so the task tool does not accept `schema`. Remove it and rely on the selected agent definition or inherited session schema.";
307
+ /**
308
+ * Normalize a validated call into its spawn list: the `tasks[]` batch when
309
+ * provided, otherwise the single top-level spawn.
310
+ */
311
+ function resolveSpawnItems(params: TaskParams): TaskItem[] {
312
+ if (Array.isArray(params.tasks) && params.tasks.length > 0) {
313
+ return params.tasks;
234
314
  }
315
+ return [{ id: params.id, description: params.description, role: params.role, assignment: params.assignment }];
316
+ }
235
317
 
236
- if (disallowedFields.length === 1) {
237
- return `task.simple is set to independent, so the task tool does not accept \`${disallowedFields[0]}\`. Put everything the subagent needs inside each task assignment.`;
318
+ /**
319
+ * Per-spawn params handed to the executor path: top-level call fields with the
320
+ * item's identity substituted in. `tasks` never leaks into a spawn; the shared
321
+ * `context` rides along unchanged. Keys are only materialized when present —
322
+ * `#runSpawn` distinguishes an absent `isolated` from an explicit one. The
323
+ * item's `isolated` (batch form) wins over the top-level flag (flat form).
324
+ */
325
+ function spawnParamsFor(params: TaskParams, item: TaskItem): TaskParams {
326
+ const spawn: TaskParams = { agent: params.agent };
327
+ if (item.id !== undefined) spawn.id = item.id;
328
+ if (item.description !== undefined) spawn.description = item.description;
329
+ if (item.role !== undefined) spawn.role = item.role;
330
+ if (item.assignment !== undefined) spawn.assignment = item.assignment;
331
+ if (params.context !== undefined) spawn.context = params.context;
332
+ if (item.isolated !== undefined) {
333
+ spawn.isolated = item.isolated;
334
+ } else if ("isolated" in params) {
335
+ spawn.isolated = params.isolated;
238
336
  }
337
+ return spawn;
338
+ }
339
+
340
+ /** Generic worker agents whose output sharpens with a tailored `role` rather than the bare type. */
341
+ const GENERIC_SPAWN_AGENTS: ReadonlySet<string> = new Set(["task", "quick_task"]);
239
342
 
240
- return "task.simple is set to independent, so the task tool does not accept `context` or `schema`. Put all required background and output expectations inside each task assignment or the selected agent definition.";
343
+ /**
344
+ * Advisory — never a rejection — nudging the spawner toward tailored
345
+ * specialists when it spawns generic role-less workers and still holds spawn
346
+ * capacity (DepthCapacity: it currently has the `task` tool). Fires when a
347
+ * generic `task`/`quick_task` spawn carries no `role`, or when one call clones
348
+ * the same agent ≥2× all without roles. Returns undefined when no nudge applies.
349
+ */
350
+ export function buildSpecializationAdvisory(
351
+ agentName: string | undefined,
352
+ items: TaskItem[],
353
+ depthCapacity: boolean,
354
+ ): string | undefined {
355
+ if (!depthCapacity) return undefined;
356
+ const rolelessCount = items.filter(item => !item.role?.trim()).length;
357
+ if (rolelessCount === 0) return undefined;
358
+ const generic = agentName !== undefined && GENERIC_SPAWN_AGENTS.has(agentName);
359
+ const cloned = items.length >= 2 && rolelessCount === items.length;
360
+ if (!generic && !cloned) return undefined;
361
+ const label = agentName ?? "task";
362
+ return (
363
+ `Tip: spawned ${rolelessCount} \`${label}\` worker${rolelessCount === 1 ? "" : "s"} without a \`role\`. ` +
364
+ `Tailored specialists outperform generic workers — give each spawn a \`role\` naming its expertise ` +
365
+ `(e.g. "Auth-flow security reviewer"). Depth budget remains, so decompose into named specialists ` +
366
+ `rather than cloning one generic worker.`
367
+ );
368
+ }
369
+
370
+ /** Sentinel for async jobs whose subagent finished with a failing result; progress is already updated. */
371
+ class TaskJobError extends Error {}
372
+
373
+ /**
374
+ * Process-level memo for create-time agent discovery, keyed by resolved cwd.
375
+ *
376
+ * `TaskTool.create` runs for every (sub)agent session in this process and the
377
+ * walk-up + plugin-registry scan in `discoverAgents` is identical for a given
378
+ * cwd, so repeat creations reuse the first scan. Execution-time discovery
379
+ * (`#runSpawn`) intentionally stays fresh. The memo also tracks the live
380
+ * `discoverAgents` binding: test spies swap that binding, which invalidates
381
+ * the memo automatically.
382
+ */
383
+ const discoveryMemo = new Map<string, Promise<DiscoveryResult>>();
384
+ let discoveryMemoFn: typeof discoverAgents | undefined;
385
+
386
+ function discoverAgentsForCreate(cwd: string): Promise<DiscoveryResult> {
387
+ const fn = discoverAgents;
388
+ if (discoveryMemoFn !== fn) {
389
+ discoveryMemoFn = fn;
390
+ discoveryMemo.clear();
391
+ }
392
+ const key = path.resolve(cwd);
393
+ let pending = discoveryMemo.get(key);
394
+ if (!pending) {
395
+ pending = fn(cwd);
396
+ discoveryMemo.set(key, pending);
397
+ pending.catch(() => {
398
+ if (discoveryMemo.get(key) === pending) discoveryMemo.delete(key);
399
+ });
400
+ }
401
+ return pending;
241
402
  }
242
403
 
243
404
  // ═══════════════════════════════════════════════════════════════════════════
@@ -247,8 +408,9 @@ function validateTaskModeParams(simpleMode: TaskSimpleMode, params: TaskParams):
247
408
  /**
248
409
  * Task tool - Delegate tasks to specialized agents.
249
410
  *
250
- * Requires async initialization to discover available agents.
251
- * Use `TaskTool.create(session)` to instantiate.
411
+ * Each call spawns one subagent or, with `task.batch`, one per `tasks[]`
412
+ * item. When `async.enabled` is on, spawns run as AsyncJobManager jobs; when
413
+ * disabled, the tool blocks until every spawn finishes.
252
414
  */
253
415
  export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetails, Theme> {
254
416
  readonly name = "task";
@@ -259,11 +421,30 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
259
421
  if (typeof params.agent === "string") {
260
422
  lines.push(`Agent: ${truncateForPrompt(params.agent)}`);
261
423
  }
424
+ if (typeof params.role === "string" && params.role.trim()) {
425
+ lines.push(`Role: ${truncateForPrompt(params.role)}`);
426
+ }
427
+ if (typeof params.id === "string" && params.id.trim()) {
428
+ lines.push(`Task: ${truncateForPrompt(params.id)}`);
429
+ }
430
+ if (typeof params.assignment === "string") {
431
+ lines.push(`Assignment:\n${truncateForPrompt(params.assignment)}`);
432
+ }
433
+ if (typeof params.context === "string" && params.context.trim()) {
434
+ lines.push(`Context:\n${truncateForPrompt(params.context)}`);
435
+ }
262
436
  const tasks = Array.isArray(params.tasks) ? params.tasks : [];
263
437
  const firstTask = tasks[0];
264
438
  if (firstTask) {
265
- lines.push(`Task: ${truncateForPrompt(firstTask.id)}`);
266
- lines.push(`Assignment:\n${truncateForPrompt(firstTask.assignment)}`);
439
+ if (typeof firstTask.id === "string" && firstTask.id.trim()) {
440
+ lines.push(`Task: ${truncateForPrompt(firstTask.id)}`);
441
+ }
442
+ if (typeof firstTask.role === "string" && firstTask.role.trim()) {
443
+ lines.push(`Role: ${truncateForPrompt(firstTask.role)}`);
444
+ }
445
+ if (typeof firstTask.assignment === "string") {
446
+ lines.push(`Assignment:\n${truncateForPrompt(firstTask.assignment)}`);
447
+ }
267
448
  if (tasks.length > 1) {
268
449
  lines.push(`+${tasks.length - 1} more task${tasks.length === 2 ? "" : "s"}`);
269
450
  }
@@ -271,16 +452,26 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
271
452
  return lines;
272
453
  };
273
454
  readonly label = "Task";
274
- readonly summary = "Spawn a subagent to complete a parallel task";
455
+ readonly summary = "Spawn subagents to complete delegated tasks";
275
456
  readonly strict = true;
276
457
  readonly loadMode = "discoverable";
277
458
  readonly renderResult = renderResult;
459
+ // Suppress the streaming call preview once a (partial or final) result exists
460
+ // so the task renders as ONE block that transitions in place — not a pending
461
+ // call frame stacked above the result frame. Mirrors `taskToolRenderer`.
462
+ readonly mergeCallAndResult = true;
278
463
  readonly #discoveredAgents: AgentDefinition[];
279
464
  readonly #blockedAgent: string | undefined;
465
+ /**
466
+ * One semaphore per TaskTool instance (i.e. per session): bounds concurrent
467
+ * subagents across parallel `task` calls within the session. Sized from
468
+ * `task.maxConcurrency` at first use; later setting changes do not resize it.
469
+ */
470
+ #spawnSemaphore: Semaphore | undefined;
280
471
 
281
472
  get parameters(): TaskToolSchemaInstance {
282
473
  const isolationEnabled = this.session.settings.get("task.isolation.mode") !== "none";
283
- return getTaskSchema({ isolationEnabled, simpleMode: this.#getTaskSimpleMode() });
474
+ return getTaskSchema({ isolationEnabled, batchEnabled: this.#isBatchEnabled() });
284
475
  }
285
476
 
286
477
  renderCall(args: unknown, options: Parameters<typeof renderTaskCall>[1], theme: Theme) {
@@ -296,10 +487,10 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
296
487
  this.#discoveredAgents,
297
488
  maxConcurrency,
298
489
  isolationMode !== "none",
299
- this.session.settings.get("async.enabled"),
300
490
  disabledAgents,
301
- this.#getTaskSimpleMode(),
302
- this.session.settings.get("irc.enabled") === true,
491
+ this.#isBatchEnabled(),
492
+ this.session.settings.get("async.enabled"),
493
+ isIrcEnabled(this.session.settings, this.session.taskDepth ?? 0),
303
494
  this.session.getSessionSpawns() ?? "*",
304
495
  );
305
496
  }
@@ -311,326 +502,488 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
311
502
  this.#discoveredAgents = discoveredAgents;
312
503
  }
313
504
 
314
- #getTaskSimpleMode(): TaskSimpleMode {
315
- return this.session.settings.get("task.simple");
505
+ #isBatchEnabled(): boolean {
506
+ return this.session.settings.get("task.batch");
507
+ }
508
+
509
+ #getSpawnSemaphore(): Semaphore {
510
+ this.#spawnSemaphore ??= new Semaphore(this.session.settings.get("task.maxConcurrency"));
511
+ return this.#spawnSemaphore;
316
512
  }
317
513
 
318
514
  /**
319
515
  * Create a TaskTool instance with async agent discovery.
320
516
  */
321
517
  static async create(session: ToolSession): Promise<TaskTool> {
322
- const { agents } = await discoverAgents(session.cwd);
518
+ const { agents } = await discoverAgentsForCreate(session.cwd);
323
519
  return new TaskTool(session, agents);
324
520
  }
325
521
 
326
522
  async execute(
327
- _toolCallId: string,
523
+ toolCallId: string,
328
524
  rawParams: unknown,
329
525
  signal?: AbortSignal,
330
526
  onUpdate?: AgentToolUpdateCallback<TaskToolDetails>,
331
527
  ): Promise<AgentToolResult<TaskToolDetails>> {
332
528
  const params = repairTaskParams(rawParams as TaskParams);
333
- const simpleMode = this.#getTaskSimpleMode();
334
- const validationError = validateTaskModeParams(simpleMode, params);
529
+ const batchEnabled = this.#isBatchEnabled();
530
+ const validationError = validateShapeParams(batchEnabled, params) ?? validateSpawnParams(params, batchEnabled);
335
531
  if (validationError) {
336
532
  return createTaskModeError(validationError);
337
533
  }
338
534
 
339
- const asyncEnabled = this.session.settings.get("async.enabled");
535
+ const spawnItems = resolveSpawnItems(params);
340
536
  const selectedAgent = this.#discoveredAgents.find(agent => agent.name === params.agent);
341
- if (!asyncEnabled || selectedAgent?.blocking === true) {
342
- return this.#executeSync(_toolCallId, params, signal, onUpdate);
343
- }
344
-
345
- const manager = this.session.asyncJobManager;
346
- if (!manager) {
347
- // Async was requested but no manager is registered (e.g. an
348
- // orphaned session whose host never wired one up). Falling back
349
- // to the sync path keeps the tool usable; only background/job-poll
350
- // semantics are lost.
351
- logger.warn("task: async.enabled but no AsyncJobManager registered; falling back to sync execution");
352
- return this.#executeSync(_toolCallId, params, signal, onUpdate);
353
- }
354
-
355
- const taskItems = params.tasks ?? [];
356
- if (taskItems.length === 0) {
357
- return this.#executeSync(_toolCallId, params, signal, onUpdate);
537
+ const asyncEnabled = this.session.settings.get("async.enabled");
538
+ const manager = asyncEnabled ? this.session.asyncJobManager : undefined;
539
+ const depthCapacity = canSpawnAtDepth(
540
+ this.session.settings.get("task.maxRecursionDepth") ?? 2,
541
+ this.session.taskDepth ?? 0,
542
+ );
543
+ const advisory = buildSpecializationAdvisory(params.agent, spawnItems, depthCapacity);
544
+ const withAdvisory = (result: AgentToolResult<TaskToolDetails>): AgentToolResult<TaskToolDetails> => {
545
+ if (!advisory) return result;
546
+ const textPart = result.content.find(part => part.type === "text");
547
+ if (textPart && typeof textPart.text === "string") {
548
+ textPart.text = `${textPart.text}\n\n${advisory}`;
549
+ } else {
550
+ result.content.push({ type: "text", text: advisory });
551
+ }
552
+ return result;
553
+ };
554
+ if (!asyncEnabled || !manager || selectedAgent?.blocking === true) {
555
+ // Sync fallback: async execution disabled, orphaned host that never
556
+ // wired a job manager, or an agent definition that declares
557
+ // `blocking: true`. The session-scoped semaphore still bounds fan-out
558
+ // across parallel task calls.
559
+ if (asyncEnabled && !manager) {
560
+ logger.warn("task: no AsyncJobManager registered; falling back to sync execution");
561
+ }
562
+ return withAdvisory(await this.#executeSyncFanout(toolCallId, params, spawnItems, signal, onUpdate));
358
563
  }
359
564
 
565
+ // Resolve agent ids up front so the immediate result can name them.
360
566
  const outputManager =
361
567
  this.session.agentOutputManager ?? new AgentOutputManager(this.session.getArtifactsDir ?? (() => null));
362
- const uniqueIds = await outputManager.allocateBatch(taskItems.map(t => t.id));
363
- const fallbackAgentSource =
364
- this.#discoveredAgents.find(agent => agent.name === params.agent)?.source ?? "bundled";
365
- const progressByTaskId = new Map<string, AgentProgress>();
366
- for (let index = 0; index < taskItems.length; index++) {
367
- const taskItem = taskItems[index];
368
- const assignment = taskItem.assignment.trim();
369
- progressByTaskId.set(taskItem.id, {
370
- index,
371
- id: taskItem.id,
372
- agent: params.agent,
373
- agentSource: fallbackAgentSource,
374
- status: "pending",
375
- task: renderSubagentUserPrompt(assignment, simpleMode),
376
- assignment,
377
- description: taskItem.description,
378
- recentTools: [],
379
- recentOutput: [],
380
- toolCount: 0,
381
- tokens: 0,
382
- cost: 0,
383
- durationMs: 0,
568
+ const agentLabel = params.agent ?? "task";
569
+ const agentSource = selectedAgent?.source ?? "bundled";
570
+ const spawns: Array<{ agentId: string; item: TaskItem; progress: AgentProgress }> = [];
571
+ for (let index = 0; index < spawnItems.length; index++) {
572
+ const item = spawnItems[index];
573
+ const agentId = await outputManager.allocate(item.id?.trim() || generateTaskName());
574
+ const assignment = (item.assignment ?? "").trim();
575
+ spawns.push({
576
+ agentId,
577
+ item,
578
+ progress: {
579
+ index,
580
+ id: agentId,
581
+ agent: agentLabel,
582
+ agentSource,
583
+ status: "pending",
584
+ task: renderSubagentUserPrompt(assignment),
585
+ assignment,
586
+ description: item.description,
587
+ recentTools: [],
588
+ recentOutput: [],
589
+ toolCount: 0,
590
+ requests: 0,
591
+ tokens: 0,
592
+ cost: 0,
593
+ durationMs: 0,
594
+ },
384
595
  });
385
596
  }
386
597
 
387
- const startedJobs: Array<{ jobId: string; taskId: string }> = [];
388
- const failedSchedules: string[] = [];
389
- let completedJobs = 0;
390
- let failedJobs = 0;
391
-
392
- const getProgressSnapshot = (): AgentProgress[] => {
393
- return Array.from(progressByTaskId.values())
394
- .sort((a, b) => a.index - b.index)
395
- .map(progress => structuredClone(progress));
396
- };
397
-
598
+ // Aggregate async state for the one tool call: every spawn's job reports
599
+ // into the shared progress snapshot; the call stays "running" until all
600
+ // jobs settle, then turns "failed" if any spawn failed. The single-spawn
601
+ // case passes the job's own suggestion through (pre-batch behavior).
602
+ const single = spawns.length === 1;
603
+ let settledCount = 0;
604
+ let failedCount = 0;
605
+ let primaryJobId = spawns[0].agentId;
398
606
  const buildAsyncDetails = (state: "running" | "completed" | "failed", jobId: string): TaskToolDetails => ({
399
607
  projectAgentsDir: null,
400
608
  results: [],
401
609
  totalDurationMs: 0,
402
- progress: getProgressSnapshot(),
403
- async: { state, jobId, type: "task" },
610
+ progress: spawns.map(spawn => ({ ...spawn.progress })),
611
+ async: {
612
+ state: single ? state : settledCount < spawns.length ? "running" : failedCount > 0 ? "failed" : "completed",
613
+ jobId: single ? jobId : primaryJobId,
614
+ type: "task",
615
+ },
404
616
  });
405
617
 
406
- const emitAsyncUpdate = (state: "running" | "completed" | "failed", text: string): void => {
407
- const primaryJobId = startedJobs[0]?.jobId ?? "task";
408
- onUpdate?.({
409
- content: [{ type: "text", text }],
410
- details: buildAsyncDetails(state, primaryJobId),
411
- });
412
- };
413
-
414
- const maxConcurrency = this.session.settings.get("task.maxConcurrency");
415
- const semaphore = new Semaphore(maxConcurrency);
416
-
417
- for (let i = 0; i < taskItems.length; i++) {
418
- const taskItem = taskItems[i];
419
- if (signal?.aborted) {
420
- failedSchedules.push(`${taskItem.id}: cancelled before scheduling`);
421
- const progress = progressByTaskId.get(taskItem.id);
422
- if (progress) {
423
- progress.status = "aborted";
424
- }
425
- continue;
426
- }
427
-
428
- const uniqueId = uniqueIds[i];
429
- const singleParams: TaskParams = { ...params, tasks: [taskItem] };
430
- const label = uniqueId;
618
+ const ircEnabled = isIrcEnabled(this.session.settings, this.session.taskDepth ?? 0);
619
+ const started: Array<{ agentId: string; jobId: string; description?: string }> = [];
620
+ const failedSchedules: string[] = [];
621
+ for (const spawn of spawns) {
431
622
  try {
432
- const jobId = manager.register(
433
- "task",
434
- label,
435
- async ({ signal: runSignal, reportProgress }) => {
436
- const startedAt = Date.now();
437
- const progress = progressByTaskId.get(taskItem.id);
438
- await semaphore.acquire();
439
- if (runSignal.aborted) {
440
- semaphore.release();
441
- if (progress) {
442
- progress.status = "aborted";
443
- }
444
- throw new Error("Aborted before execution");
445
- }
446
- if (progress) {
447
- progress.status = "running";
448
- }
449
- await reportProgress(
450
- `Running background task ${taskItem.id}...`,
451
- buildAsyncDetails("running", startedJobs[0]?.jobId ?? label) as unknown as Record<string, unknown>,
452
- );
453
- try {
454
- const result = await this.#executeSync(_toolCallId, singleParams, runSignal, undefined, [
455
- uniqueId,
456
- ]);
457
- const finalText = result.content.find(part => part.type === "text")?.text ?? "(no output)";
458
- const singleResult = result.details?.results[0];
459
- if (progress) {
460
- progress.status = singleResult?.aborted
461
- ? "aborted"
462
- : (singleResult?.exitCode ?? 0) === 0
463
- ? "completed"
464
- : "failed";
465
- progress.durationMs = singleResult?.durationMs ?? Math.max(0, Date.now() - startedAt);
466
- progress.tokens = singleResult?.tokens ?? 0;
467
- progress.contextTokens = singleResult?.contextTokens;
468
- progress.contextWindow = singleResult?.contextWindow;
469
- progress.cost = singleResult?.usage?.cost.total ?? 0;
470
- progress.extractedToolData = singleResult?.extractedToolData;
471
- progress.retryFailure = singleResult?.retryFailure;
472
- progress.retryState = undefined;
473
- }
474
- completedJobs += 1;
475
- if (singleResult && ((singleResult.aborted ?? false) || singleResult.exitCode !== 0)) {
476
- failedJobs += 1;
477
- }
478
- const remaining = taskItems.length - completedJobs;
479
- const isDone = remaining === 0;
480
- await reportProgress(
481
- isDone
482
- ? `Background task batch complete: ${completedJobs}/${taskItems.length} finished.`
483
- : `Background task batch progress: ${completedJobs}/${taskItems.length} finished (${remaining} running).`,
484
- buildAsyncDetails(
485
- isDone ? (failedJobs > 0 || failedSchedules.length > 0 ? "failed" : "completed") : "running",
486
- startedJobs[0]?.jobId ?? label,
487
- ) as unknown as Record<string, unknown>,
488
- );
489
- if (isDone) {
490
- emitAsyncUpdate(
491
- failedJobs > 0 || failedSchedules.length > 0 ? "failed" : "completed",
492
- `Background task batch complete: ${completedJobs}/${taskItems.length} finished.`,
493
- );
494
- }
495
- return finalText;
496
- } catch (error) {
497
- if (progress) {
498
- progress.status = "failed";
499
- progress.durationMs = Math.max(0, Date.now() - startedAt);
500
- }
501
- completedJobs += 1;
502
- failedJobs += 1;
503
- const remaining = taskItems.length - completedJobs;
504
- const isDone = remaining === 0;
505
- await reportProgress(
506
- isDone
507
- ? `Background task batch complete with failures: ${failedJobs} failed.`
508
- : `Background task batch progress: ${completedJobs}/${taskItems.length} finished (${remaining} running).`,
509
- buildAsyncDetails(
510
- isDone ? "failed" : "running",
511
- startedJobs[0]?.jobId ?? label,
512
- ) as unknown as Record<string, unknown>,
513
- );
514
- if (isDone) {
515
- emitAsyncUpdate(
516
- "failed",
517
- `Background task batch complete with failures: ${failedJobs} failed.`,
518
- );
519
- }
520
- throw error;
521
- } finally {
522
- semaphore.release();
523
- }
524
- },
525
- {
526
- id: label,
527
- ownerId: this.session.getAgentId?.() ?? undefined,
528
- onProgress: (text, details) => {
529
- const progressDetails =
530
- (details as TaskToolDetails | undefined) ??
531
- buildAsyncDetails("running", startedJobs[0]?.jobId ?? label);
532
- onUpdate?.({ content: [{ type: "text", text }], details: progressDetails });
533
- },
623
+ const jobId = this.#registerSpawnJob({
624
+ manager,
625
+ toolCallId,
626
+ spawnParams: spawnParamsFor(params, spawn.item),
627
+ agentId: spawn.agentId,
628
+ progress: spawn.progress,
629
+ ircEnabled,
630
+ buildDetails: buildAsyncDetails,
631
+ onUpdate,
632
+ onSettled: failed => {
633
+ settledCount += 1;
634
+ if (failed) failedCount += 1;
534
635
  },
535
- );
536
- startedJobs.push({ jobId, taskId: taskItem.id });
636
+ });
637
+ if (started.length === 0) primaryJobId = jobId;
638
+ started.push({ agentId: spawn.agentId, jobId, description: spawn.item.description });
537
639
  } catch (error) {
538
640
  const message = error instanceof Error ? error.message : String(error);
539
- failedSchedules.push(`${taskItem.id}: ${message}`);
540
- const progress = progressByTaskId.get(taskItem.id);
541
- if (progress) {
542
- progress.status = "failed";
543
- }
641
+ failedSchedules.push(`${spawn.agentId}: ${message}`);
642
+ spawn.progress.status = "failed";
643
+ settledCount += 1;
644
+ failedCount += 1;
544
645
  }
545
646
  }
546
647
 
547
- if (startedJobs.length === 0) {
548
- const failureText = `Failed to start background task jobs: ${failedSchedules.join("; ")}`;
648
+ if (started.length === 0) {
549
649
  return {
550
- content: [{ type: "text", text: failureText }],
650
+ content: [
651
+ {
652
+ type: "text",
653
+ text: `Failed to start background task job${single ? "" : "s"}: ${failedSchedules.join("; ")}`,
654
+ },
655
+ ],
551
656
  details: { projectAgentsDir: null, results: [], totalDurationMs: 0 },
552
657
  };
553
658
  }
554
659
 
555
- emitAsyncUpdate(
556
- "running",
557
- `Launching ${startedJobs.length} background ${startedJobs.length === 1 ? "task" : "tasks"}...`,
558
- );
660
+ if (single) {
661
+ const { agentId, jobId, description } = started[0];
662
+ const coordinationHint = ircEnabled
663
+ ? `DM \`${agentId}\` via \`irc\` to coordinate while it runs; use \`job\` only to inspect (\`list\`), wait (\`poll\`), or cancel a stuck task.`
664
+ : `Use \`job\` to inspect (\`list\`), wait (\`poll\`), or cancel a stuck task.`;
665
+ const descriptionSuffix = description ? ` — ${description}` : "";
666
+ onUpdate?.({
667
+ content: [{ type: "text", text: `Spawned agent \`${agentId}\`...` }],
668
+ details: buildAsyncDetails("running", jobId),
669
+ });
670
+ return withAdvisory({
671
+ content: [
672
+ {
673
+ type: "text",
674
+ text: `Spawned agent \`${agentId}\` (job \`${jobId}\`)${descriptionSuffix}. The result will be delivered when it yields. ${coordinationHint}`,
675
+ },
676
+ ],
677
+ details: buildAsyncDetails("running", jobId),
678
+ });
679
+ }
559
680
 
681
+ const coordinationHint = ircEnabled
682
+ ? `DM these ids via \`irc\` to coordinate while they run; use \`job\` only to inspect (\`list\`), wait (\`poll\`), or cancel a stuck task.`
683
+ : `Use \`job\` to inspect (\`list\`), wait (\`poll\`), or cancel a stuck task by id.`;
560
684
  const scheduleFailureSummary =
561
685
  failedSchedules.length > 0
562
- ? ` Failed to schedule ${failedSchedules.length} task${failedSchedules.length === 1 ? "" : "s"}.`
686
+ ? ` Failed to schedule ${failedSchedules.length} spawn${failedSchedules.length === 1 ? "" : "s"}: ${failedSchedules.join("; ")}.`
563
687
  : "";
564
-
565
- const ircEnabled = this.session.settings.get("irc.enabled") === true;
566
- const taskIdByItemId = new Map<string, string>();
567
- for (let i = 0; i < taskItems.length; i++) {
568
- taskIdByItemId.set(taskItems[i].id, uniqueIds[i]);
569
- }
570
- const startedListing = startedJobs
571
- .map(({ taskId, jobId }) => {
572
- const id = taskIdByItemId.get(taskId) ?? taskId;
573
- const desc = progressByTaskId.get(taskId)?.description;
574
- const prefix = `- \`${id}\` (job \`${jobId}\`)`;
575
- return desc ? `${prefix} — ${desc}` : prefix;
688
+ const startedListing = started
689
+ .map(({ agentId, jobId, description }) => {
690
+ const prefix = `- \`${agentId}\` (job \`${jobId}\`)`;
691
+ return description ? `${prefix} ${description}` : prefix;
576
692
  })
577
693
  .join("\n");
578
- const coordinationHint = ircEnabled
579
- ? ` DM these ids via \`irc\` to coordinate while they run; reach for \`job\` only to inspect (\`list\`), wait (\`poll\`), or cancel a stuck task.`
580
- : ` Use \`job\` to inspect (\`list\`), wait (\`poll\`), or cancel a stuck task by id.`;
581
-
582
- return {
694
+ onUpdate?.({
695
+ content: [{ type: "text", text: `Spawned ${started.length} agents...` }],
696
+ details: buildAsyncDetails("running", primaryJobId),
697
+ });
698
+ return withAdvisory({
583
699
  content: [
584
700
  {
585
701
  type: "text",
586
- text: `Started ${startedJobs.length} background task job${startedJobs.length === 1 ? "" : "s"} using ${params.agent}.${scheduleFailureSummary} Results will be delivered when complete.\n${startedListing}\n${coordinationHint}`,
702
+ text: `Spawned ${started.length} background agents using ${agentLabel}.${scheduleFailureSummary} Each result will be delivered when that agent yields.\n${startedListing}\n${coordinationHint}`,
587
703
  },
588
704
  ],
705
+ details: buildAsyncDetails("running", primaryJobId),
706
+ });
707
+ }
708
+
709
+ /**
710
+ * Register one background job that runs a single spawn to completion and
711
+ * delivers its yield text. The job body mirrors the sync path; `buildDetails`
712
+ * supplies the (possibly batch-shared) progress snapshot and `onSettled`
713
+ * feeds the caller's aggregate counters.
714
+ */
715
+ #registerSpawnJob(options: {
716
+ manager: AsyncJobManager;
717
+ toolCallId: string;
718
+ spawnParams: TaskParams;
719
+ agentId: string;
720
+ progress: AgentProgress;
721
+ ircEnabled: boolean;
722
+ buildDetails: (state: "running" | "completed" | "failed", jobId: string) => TaskToolDetails;
723
+ onUpdate?: AgentToolUpdateCallback<TaskToolDetails>;
724
+ onSettled?: (failed: boolean) => void;
725
+ }): string {
726
+ const { manager, toolCallId, spawnParams, agentId, progress, ircEnabled, buildDetails, onUpdate, onSettled } =
727
+ options;
728
+ const buildFollowUpHint = (aborted: boolean): string => {
729
+ if (aborted) {
730
+ return `\n\n${agentId} was aborted — transcript at history://${agentId}`;
731
+ }
732
+ const followUp = ircEnabled ? "message it via `irc` to follow up; " : "";
733
+ return `\n\n${agentId} is now idle — ${followUp}transcript at history://${agentId}`;
734
+ };
735
+ return manager.register(
736
+ "task",
737
+ agentId,
738
+ async ({ jobId: ownJobId, signal: runSignal, reportProgress, markRunning }) => {
739
+ const startedAt = Date.now();
740
+ const semaphore = this.#getSpawnSemaphore();
741
+ await semaphore.acquire();
742
+ if (runSignal.aborted) {
743
+ semaphore.release();
744
+ progress.status = "aborted";
745
+ onSettled?.(true);
746
+ throw new Error("Aborted before execution");
747
+ }
748
+ markRunning();
749
+ progress.status = "running";
750
+ await reportProgress(
751
+ `Running background task ${agentId}...`,
752
+ buildDetails("running", ownJobId) as unknown as Record<string, unknown>,
753
+ );
754
+ try {
755
+ const result = await this.#executeSync(
756
+ toolCallId,
757
+ spawnParams,
758
+ runSignal,
759
+ undefined,
760
+ agentId,
761
+ progress.index,
762
+ true,
763
+ );
764
+ const finalText = result.content.find(part => part.type === "text")?.text ?? "(no output)";
765
+ const singleResult = result.details?.results[0];
766
+ // A missing result means the sync path failed at the tool level
767
+ // (results: []) — treat it as a failure, not success.
768
+ const resultFailed = !singleResult || (singleResult.aborted ?? false) || singleResult.exitCode !== 0;
769
+ progress.status = singleResult?.aborted ? "aborted" : resultFailed ? "failed" : "completed";
770
+ progress.durationMs = singleResult?.durationMs ?? Math.max(0, Date.now() - startedAt);
771
+ progress.tokens = singleResult?.tokens ?? 0;
772
+ progress.requests = singleResult?.requests ?? 0;
773
+ progress.contextTokens = singleResult?.contextTokens;
774
+ progress.contextWindow = singleResult?.contextWindow;
775
+ progress.cost = singleResult?.usage?.cost.total ?? 0;
776
+ progress.extractedToolData = singleResult?.extractedToolData;
777
+ progress.retryFailure = singleResult?.retryFailure;
778
+ progress.retryState = undefined;
779
+ onSettled?.(resultFailed);
780
+ const statusText = resultFailed
781
+ ? `Background task ${agentId} failed.`
782
+ : `Background task ${agentId} complete.`;
783
+ await reportProgress(
784
+ statusText,
785
+ buildDetails(resultFailed ? "failed" : "completed", ownJobId) as unknown as Record<string, unknown>,
786
+ );
787
+ onUpdate?.({
788
+ content: [{ type: "text", text: statusText }],
789
+ details: buildDetails(resultFailed ? "failed" : "completed", ownJobId),
790
+ });
791
+ const deliveryText = `${finalText}${buildFollowUpHint(singleResult?.aborted === true)}`;
792
+ if (resultFailed) {
793
+ // Mark the job itself failed; the failed agent stays interrogable.
794
+ throw new TaskJobError(deliveryText);
795
+ }
796
+ return deliveryText;
797
+ } catch (error) {
798
+ if (error instanceof TaskJobError) {
799
+ throw error;
800
+ }
801
+ progress.status = "failed";
802
+ progress.durationMs = Math.max(0, Date.now() - startedAt);
803
+ onSettled?.(true);
804
+ const statusText = `Background task ${agentId} failed.`;
805
+ await reportProgress(statusText, buildDetails("failed", ownJobId) as unknown as Record<string, unknown>);
806
+ onUpdate?.({
807
+ content: [{ type: "text", text: statusText }],
808
+ details: buildDetails("failed", ownJobId),
809
+ });
810
+ const message = error instanceof Error ? error.message : String(error);
811
+ const hint = AgentRegistry.global().get(agentId) ? buildFollowUpHint(false) : "";
812
+ throw new TaskJobError(`${message}${hint}`);
813
+ } finally {
814
+ semaphore.release();
815
+ }
816
+ },
817
+ {
818
+ id: agentId,
819
+ queued: true,
820
+ ownerId: this.session.getAgentId?.() ?? undefined,
821
+ onProgress: (text, details) => {
822
+ const progressDetails = (details as TaskToolDetails | undefined) ?? buildDetails("running", agentId);
823
+ onUpdate?.({ content: [{ type: "text", text }], details: progressDetails });
824
+ },
825
+ },
826
+ );
827
+ }
828
+
829
+ /**
830
+ * Sync fallback fan-out (no job manager, or a `blocking: true` agent): run
831
+ * every spawn to completion inline and merge the per-spawn payloads into a
832
+ * single tool result. The session-scoped semaphore still bounds concurrency
833
+ * across parallel task calls.
834
+ */
835
+ async #executeSyncFanout(
836
+ toolCallId: string,
837
+ params: TaskParams,
838
+ spawnItems: TaskItem[],
839
+ signal?: AbortSignal,
840
+ onUpdate?: AgentToolUpdateCallback<TaskToolDetails>,
841
+ ): Promise<AgentToolResult<TaskToolDetails>> {
842
+ const semaphore = this.#getSpawnSemaphore();
843
+ if (spawnItems.length === 1) {
844
+ await semaphore.acquire();
845
+ try {
846
+ return await this.#executeSync(
847
+ toolCallId,
848
+ spawnParamsFor(params, spawnItems[0]),
849
+ signal,
850
+ onUpdate,
851
+ undefined,
852
+ 0,
853
+ );
854
+ } finally {
855
+ semaphore.release();
856
+ }
857
+ }
858
+
859
+ const startTime = Date.now();
860
+ const latestProgress = new Map<number, AgentProgress>();
861
+ const emitCombined = () => {
862
+ onUpdate?.({
863
+ content: [{ type: "text", text: `Running ${spawnItems.length} agents...` }],
864
+ details: {
865
+ projectAgentsDir: null,
866
+ results: [],
867
+ totalDurationMs: Date.now() - startTime,
868
+ progress: Array.from(latestProgress.entries())
869
+ .sort((a, b) => a[0] - b[0])
870
+ .map(([, progress]) => progress),
871
+ },
872
+ });
873
+ };
874
+
875
+ const { results: payloads } = await mapWithConcurrencyLimit(
876
+ spawnItems,
877
+ spawnItems.length,
878
+ async (item, index, workerSignal) => {
879
+ await semaphore.acquire();
880
+ try {
881
+ const itemOnUpdate: AgentToolUpdateCallback<TaskToolDetails> | undefined = onUpdate
882
+ ? update => {
883
+ const progress = update.details?.progress?.[0];
884
+ if (progress) {
885
+ latestProgress.set(index, { ...progress, index });
886
+ emitCombined();
887
+ }
888
+ }
889
+ : undefined;
890
+ return await this.#executeSync(
891
+ toolCallId,
892
+ spawnParamsFor(params, item),
893
+ workerSignal,
894
+ itemOnUpdate,
895
+ undefined,
896
+ index,
897
+ );
898
+ } finally {
899
+ semaphore.release();
900
+ }
901
+ },
902
+ signal,
903
+ );
904
+
905
+ const results: SingleResult[] = [];
906
+ const contentParts: string[] = [];
907
+ const outputPaths: string[] = [];
908
+ const usageTotals = createUsageTotals();
909
+ let hasUsage = false;
910
+ let projectAgentsDir: string | null = null;
911
+ for (let index = 0; index < spawnItems.length; index++) {
912
+ const payload = payloads[index];
913
+ if (!payload) {
914
+ contentParts.push(`Task ${spawnItems[index].id?.trim() || `#${index + 1}`}: cancelled before start.`);
915
+ continue;
916
+ }
917
+ projectAgentsDir ??= payload.details?.projectAgentsDir ?? null;
918
+ const text = payload.content.find(part => part.type === "text")?.text;
919
+ if (text) contentParts.push(text);
920
+ for (const result of payload.details?.results ?? []) {
921
+ results.push({ ...result, index });
922
+ if (result.usage) {
923
+ addUsageTotals(usageTotals, result.usage);
924
+ hasUsage = true;
925
+ }
926
+ if (result.outputPath) outputPaths.push(result.outputPath);
927
+ }
928
+ }
929
+
930
+ return {
931
+ content: [{ type: "text", text: contentParts.join("\n\n") }],
589
932
  details: {
590
- projectAgentsDir: null,
591
- results: [],
592
- totalDurationMs: 0,
593
- progress: getProgressSnapshot(),
594
- async: { state: "running", jobId: startedJobs[0].jobId, type: "task" },
933
+ projectAgentsDir,
934
+ results,
935
+ totalDurationMs: Date.now() - startTime,
936
+ usage: hasUsage ? usageTotals : undefined,
937
+ outputPaths: outputPaths.length > 0 ? outputPaths : undefined,
595
938
  },
596
939
  };
597
940
  }
598
941
 
942
+ /**
943
+ * Synchronous execution of one spawn. Used as the body of every
944
+ * async job and directly by the sync fallback (no job manager / blocking
945
+ * agent) and by in-process callers that need the result inline (e.g. the
946
+ * commit flow's analyze_files tool).
947
+ */
599
948
  async #executeSync(
600
- _toolCallId: string,
949
+ toolCallId: string,
601
950
  params: TaskParams,
602
951
  signal?: AbortSignal,
603
952
  onUpdate?: AgentToolUpdateCallback<TaskToolDetails>,
604
- preAllocatedIds?: string[],
953
+ preAllocatedId?: string,
954
+ spawnIndex = 0,
955
+ detached = false,
956
+ ): Promise<AgentToolResult<TaskToolDetails>> {
957
+ return this.#runSpawn(toolCallId, params, signal, onUpdate, preAllocatedId, spawnIndex, detached);
958
+ }
959
+
960
+ /** Spawn a fresh subagent and run it to completion. */
961
+ async #runSpawn(
962
+ toolCallId: string,
963
+ params: TaskParams,
964
+ signal?: AbortSignal,
965
+ onUpdate?: AgentToolUpdateCallback<TaskToolDetails>,
966
+ preAllocatedId?: string,
967
+ spawnIndex = 0,
968
+ detached = false,
605
969
  ): Promise<AgentToolResult<TaskToolDetails>> {
606
970
  const startTime = Date.now();
607
971
  const { agents, projectAgentsDir } = await discoverAgents(this.session.cwd);
608
- const { agent: agentName, context, schema: outputSchema } = params;
609
- const simpleMode = this.#getTaskSimpleMode();
610
- const { contextEnabled, customSchemaEnabled } = getTaskSimpleModeCapabilities(simpleMode);
611
- const sharedContext = contextEnabled ? context?.trim() : undefined;
972
+ const agentName = params.agent ?? "";
973
+ const sharedContext = this.#isBatchEnabled() ? params.context?.trim() || undefined : undefined;
974
+ const assignment = (params.assignment ?? "").trim();
612
975
  const isolationMode = this.session.settings.get("task.isolation.mode");
613
976
  const isolationRequested = "isolated" in params ? params.isolated === true : false;
614
977
  const isIsolated = isolationMode !== "none" && isolationRequested;
615
978
  const mergeMode = this.session.settings.get("task.isolation.merge");
616
979
  const commitStyle = this.session.settings.get("task.isolation.commits");
617
- const maxConcurrency = this.session.settings.get("task.maxConcurrency");
618
980
  const taskDepth = this.session.taskDepth ?? 0;
619
981
  const subagentLspEnabled = (this.session.enableLsp ?? true) && this.session.settings.get("task.enableLsp");
620
982
 
621
983
  if (isolationMode === "none" && "isolated" in params) {
622
984
  return {
623
- content: [
624
- {
625
- type: "text",
626
- text: "Task isolation is disabled.",
627
- },
628
- ],
629
- details: {
630
- projectAgentsDir,
631
- results: [],
632
- totalDurationMs: 0,
633
- },
985
+ content: [{ type: "text", text: "Task isolation is disabled." }],
986
+ details: { projectAgentsDir, results: [], totalDurationMs: 0 },
634
987
  };
635
988
  }
636
989
 
@@ -639,17 +992,8 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
639
992
  if (!agent) {
640
993
  const available = agents.map(a => a.name).join(", ") || "none";
641
994
  return {
642
- content: [
643
- {
644
- type: "text",
645
- text: `Unknown agent "${agentName}". Available: ${available}`,
646
- },
647
- ],
648
- details: {
649
- projectAgentsDir,
650
- results: [],
651
- totalDurationMs: 0,
652
- },
995
+ content: [{ type: "text", text: `Unknown agent "${agentName}". Available: ${available}` }],
996
+ details: { projectAgentsDir, results: [], totalDurationMs: 0 },
653
997
  };
654
998
  }
655
999
 
@@ -664,16 +1008,18 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
664
1008
  text: `Agent "${agentName}" is disabled in settings. Enable it via /agents, or use a different agent type.${enabled.length > 0 ? ` Available: ${enabled.join(", ")}` : ""}`,
665
1009
  },
666
1010
  ],
667
- details: {
668
- projectAgentsDir,
669
- results: [],
670
- totalDurationMs: 0,
671
- },
1011
+ details: { projectAgentsDir, results: [], totalDurationMs: 0 },
672
1012
  };
673
1013
  }
674
1014
 
675
1015
  const planModeState = this.session.getPlanModeState?.();
676
- const planModeTools = ["read", "search", "find", "lsp", "web_search"];
1016
+ const planModeBaseTools = ["read", "search", "find", "lsp", "web_search"];
1017
+ const planModeTools = [
1018
+ ...planModeBaseTools,
1019
+ ...(agent.tools ?? []).filter(
1020
+ tool => PLAN_MODE_AGENT_TOOL_ALLOWLIST.has(tool) && !planModeBaseTools.includes(tool),
1021
+ ),
1022
+ ];
677
1023
  const effectiveAgent: typeof agent = planModeState?.enabled
678
1024
  ? {
679
1025
  ...agent,
@@ -696,78 +1042,10 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
696
1042
  });
697
1043
  const thinkingLevelOverride = effectiveAgent.thinkingLevel;
698
1044
 
699
- // Output schema priority: task call > agent frontmatter > inherited parent session.
700
- // task.simple can disable the task-call override while leaving agent/session schemas intact.
701
- const effectiveOutputSchema = customSchemaEnabled
702
- ? (outputSchema ?? effectiveAgent.output ?? this.session.outputSchema)
703
- : (effectiveAgent.output ?? this.session.outputSchema);
704
-
705
- // Handle empty or missing tasks
706
- if (!params.tasks || params.tasks.length === 0) {
707
- return {
708
- content: [
709
- {
710
- type: "text",
711
- text: contextEnabled
712
- ? "No tasks provided. Use: { agent, context?, tasks: [{ id, description, assignment }, ...] }"
713
- : "No tasks provided. Use: { agent, tasks: [{ id, description, assignment }, ...] }",
714
- },
715
- ],
716
- details: {
717
- projectAgentsDir,
718
- results: [],
719
- totalDurationMs: 0,
720
- },
721
- };
722
- }
723
-
724
- const tasks = params.tasks;
725
- const missingTaskIndexes: number[] = [];
726
- const idIndexes = new Map<string, number[]>();
727
-
728
- for (let i = 0; i < tasks.length; i++) {
729
- const id = tasks[i]?.id;
730
- if (typeof id !== "string" || id.trim() === "") {
731
- missingTaskIndexes.push(i);
732
- continue;
733
- }
734
- const normalizedId = id.toLowerCase();
735
- const indexes = idIndexes.get(normalizedId);
736
- if (indexes) {
737
- indexes.push(i);
738
- } else {
739
- idIndexes.set(normalizedId, [i]);
740
- }
741
- }
742
-
743
- const duplicateIds: Array<{ id: string; indexes: number[] }> = [];
744
- for (const [normalizedId, indexes] of idIndexes.entries()) {
745
- if (indexes.length > 1) {
746
- duplicateIds.push({
747
- id: tasks[indexes[0]]?.id ?? normalizedId,
748
- indexes,
749
- });
750
- }
751
- }
752
-
753
- if (missingTaskIndexes.length > 0 || duplicateIds.length > 0) {
754
- const problems: string[] = [];
755
- if (missingTaskIndexes.length > 0) {
756
- problems.push(`Missing task ids at indexes: ${missingTaskIndexes.join(", ")}`);
757
- }
758
- if (duplicateIds.length > 0) {
759
- const details = duplicateIds.map(entry => `${entry.id} (indexes ${entry.indexes.join(", ")})`).join("; ");
760
- problems.push(`Duplicate task ids detected (case-insensitive): ${details}`);
761
- }
762
- return {
763
- content: [{ type: "text", text: `Invalid tasks: ${problems.join(". ")}` }],
764
- details: {
765
- projectAgentsDir,
766
- results: [],
767
- totalDurationMs: 0,
768
- },
769
- };
770
- }
1045
+ // Output schema priority: agent frontmatter > inherited parent session.
1046
+ // The task call itself never carries a schema; workflows needing ad-hoc
1047
+ // structured output go through eval agent(prompt, schema).
1048
+ const effectiveOutputSchema = effectiveAgent.output ?? this.session.outputSchema;
771
1049
 
772
1050
  let repoRoot: string | null = null;
773
1051
  let baseline: WorktreeBaseline | null = null;
@@ -778,17 +1056,8 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
778
1056
  } catch (err) {
779
1057
  const message = err instanceof Error ? err.message : String(err);
780
1058
  return {
781
- content: [
782
- {
783
- type: "text",
784
- text: `Isolated task execution requires a git repository. ${message}`,
785
- },
786
- ],
787
- details: {
788
- projectAgentsDir,
789
- results: [],
790
- totalDurationMs: Date.now() - startTime,
791
- },
1059
+ content: [{ type: "text", text: `Isolated task execution requires a git repository. ${message}` }],
1060
+ details: { projectAgentsDir, results: [], totalDurationMs: Date.now() - startTime },
792
1061
  };
793
1062
  }
794
1063
  }
@@ -821,23 +1090,6 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
821
1090
  localProtocolOptions,
822
1091
  );
823
1092
 
824
- // Initialize progress tracking
825
- const progressMap = new Map<number, AgentProgress>();
826
-
827
- // Update callback
828
- const emitProgress = () => {
829
- const progress = Array.from(progressMap.values()).sort((a, b) => a.index - b.index);
830
- onUpdate?.({
831
- content: [{ type: "text", text: `Running ${params.tasks.length} agents...` }],
832
- details: {
833
- projectAgentsDir,
834
- results: [],
835
- totalDurationMs: Date.now() - startTime,
836
- progress,
837
- },
838
- });
839
- };
840
-
841
1093
  try {
842
1094
  // Check self-recursion prevention
843
1095
  if (this.#blockedAgent && agentName === this.#blockedAgent) {
@@ -848,11 +1100,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
848
1100
  text: `Cannot spawn ${this.#blockedAgent} agent from within itself (recursion prevention). Use a different agent type.`,
849
1101
  },
850
1102
  ],
851
- details: {
852
- projectAgentsDir,
853
- results: [],
854
- totalDurationMs: Date.now() - startTime,
855
- },
1103
+ details: { projectAgentsDir, results: [], totalDurationMs: Date.now() - startTime },
856
1104
  };
857
1105
  }
858
1106
 
@@ -869,36 +1117,21 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
869
1117
  const allowed = parentSpawns === "" ? "none (spawns disabled for this agent)" : parentSpawns;
870
1118
  return {
871
1119
  content: [{ type: "text", text: `Cannot spawn '${agentName}'. Allowed: ${allowed}` }],
872
- details: {
873
- projectAgentsDir,
874
- results: [],
875
- totalDurationMs: Date.now() - startTime,
876
- },
1120
+ details: { projectAgentsDir, results: [], totalDurationMs: Date.now() - startTime },
877
1121
  };
878
1122
  }
879
1123
 
880
- // Write parent conversation context for subagents. When IRC is available,
881
- // subagents should ask live peers instead of reading a stale markdown dump.
882
1124
  await fs.mkdir(effectiveArtifactsDir, { recursive: true });
883
- const shouldWriteConversationContext = this.session.settings.get("irc.enabled") !== true;
884
- const compactContext = shouldWriteConversationContext ? this.session.getCompactContext?.() : undefined;
885
- let contextFilePath: string | undefined;
886
- if (compactContext) {
887
- contextFilePath = path.join(effectiveArtifactsDir, "context.md");
888
- await Bun.write(contextFilePath, compactContext);
889
- }
890
1125
 
891
- // Build full prompts with context prepended
892
- // Allocate unique IDs across the session to prevent artifact collisions
893
- let uniqueIds: string[];
894
- if (preAllocatedIds && preAllocatedIds.length === tasks.length) {
895
- uniqueIds = preAllocatedIds;
1126
+ // Allocate a unique ID across the session to prevent artifact collisions
1127
+ let agentId: string;
1128
+ if (preAllocatedId) {
1129
+ agentId = preAllocatedId;
896
1130
  } else {
897
1131
  const outputManager =
898
1132
  this.session.agentOutputManager ?? new AgentOutputManager(this.session.getArtifactsDir ?? (() => null));
899
- uniqueIds = await outputManager.allocateBatch(tasks.map(t => t.id));
1133
+ agentId = await outputManager.allocate(params.id?.trim() || generateTaskName());
900
1134
  }
901
- const tasksWithUniqueIds = tasks.map((t, i) => ({ ...t, id: uniqueIds[i] }));
902
1135
 
903
1136
  const availableSkills = [...(this.session.skills ?? [])];
904
1137
  // Resolve autoload skills from agent definition against available skills
@@ -915,76 +1148,104 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
915
1148
  const parentEvalSessionId = this.session.getEvalSessionId?.() ?? undefined;
916
1149
  const mcpManager = this.session.mcpManager ?? MCPManager.instance();
917
1150
 
918
- // Initialize progress for all tasks
919
- for (let i = 0; i < tasksWithUniqueIds.length; i++) {
920
- const taskItem = tasksWithUniqueIds[i];
921
- const assignment = taskItem.assignment.trim();
922
- progressMap.set(i, {
923
- index: i,
924
- id: taskItem.id,
925
- agent: agentName,
926
- agentSource: agent.source,
927
- status: "pending",
928
- task: renderSubagentUserPrompt(assignment, simpleMode),
929
- assignment,
930
- recentTools: [],
931
- recentOutput: [],
932
- toolCount: 0,
933
- tokens: 0,
934
- cost: 0,
935
- durationMs: 0,
936
- modelOverride,
937
- description: taskItem.description,
1151
+ // Progress tracking for the single agent
1152
+ let latestProgress: AgentProgress = {
1153
+ index: spawnIndex,
1154
+ id: agentId,
1155
+ agent: agentName,
1156
+ agentSource: agent.source,
1157
+ status: "pending",
1158
+ task: renderSubagentUserPrompt(assignment),
1159
+ assignment,
1160
+ recentTools: [],
1161
+ recentOutput: [],
1162
+ toolCount: 0,
1163
+ requests: 0,
1164
+ tokens: 0,
1165
+ cost: 0,
1166
+ durationMs: 0,
1167
+ modelOverride,
1168
+ description: params.description,
1169
+ };
1170
+ const emitProgress = () => {
1171
+ onUpdate?.({
1172
+ content: [{ type: "text", text: `Running agent ${agentId}...` }],
1173
+ details: {
1174
+ projectAgentsDir,
1175
+ results: [],
1176
+ totalDurationMs: Date.now() - startTime,
1177
+ progress: [latestProgress],
1178
+ },
938
1179
  });
939
- }
1180
+ };
940
1181
  emitProgress();
941
1182
 
942
- const runTask = async (task: (typeof tasksWithUniqueIds)[number], index: number) => {
1183
+ const buildCommitMessageFn = () =>
1184
+ commitStyle === "ai" && this.session.modelRegistry
1185
+ ? async (diff: string) => {
1186
+ return generateCommitMessage(
1187
+ diff,
1188
+ this.session.modelRegistry!,
1189
+ this.session.settings,
1190
+ this.session.getSessionId?.() ?? undefined,
1191
+ );
1192
+ }
1193
+ : undefined;
1194
+
1195
+ const sharedRunOptions = {
1196
+ cwd: this.session.cwd,
1197
+ agent: effectiveAgent,
1198
+ task: renderSubagentUserPrompt(assignment),
1199
+ assignment,
1200
+ context: sharedContext,
1201
+ planReference,
1202
+ description: params.description,
1203
+ role: params.role,
1204
+ index: spawnIndex,
1205
+ parentToolCallId: toolCallId,
1206
+ detached,
1207
+ id: agentId,
1208
+ taskDepth,
1209
+ modelOverride,
1210
+ parentActiveModelPattern,
1211
+ thinkingLevel: thinkingLevelOverride,
1212
+ outputSchema: effectiveOutputSchema,
1213
+ sessionFile,
1214
+ persistArtifacts: !!artifactsDir,
1215
+ artifactsDir: effectiveArtifactsDir,
1216
+ enableLsp: subagentLspEnabled,
1217
+ signal,
1218
+ eventBus: this.session.eventBus,
1219
+ onProgress: (progress: AgentProgress) => {
1220
+ // Shallow snapshot; recentTools is mutated in place by the
1221
+ // executor, the rest is reassigned or immutable. A deep clone
1222
+ // here cost O(extractedToolData) per progress event.
1223
+ latestProgress = { ...progress, recentTools: progress.recentTools.slice() };
1224
+ emitProgress();
1225
+ },
1226
+ authStorage: this.session.authStorage,
1227
+ modelRegistry: this.session.modelRegistry,
1228
+ settings: this.session.settings,
1229
+ mcpManager,
1230
+ contextFiles,
1231
+ skills: availableSkills,
1232
+ autoloadSkills: resolvedAutoloadSkills,
1233
+ workspaceTree: this.session.workspaceTree,
1234
+ promptTemplates,
1235
+ rules: this.session.rules,
1236
+ preloadedExtensionPaths: this.session.extensionPaths,
1237
+ preloadedCustomToolPaths: this.session.customToolPaths,
1238
+ localProtocolOptions,
1239
+ parentArtifactManager,
1240
+ parentHindsightSessionState: this.session.getHindsightSessionState?.(),
1241
+ parentMnemopiSessionState: this.session.getMnemopiSessionState?.(),
1242
+ parentTelemetry: this.session.getTelemetry?.(),
1243
+ parentEvalSessionId,
1244
+ };
1245
+
1246
+ const runTask = async (): Promise<SingleResult> => {
943
1247
  if (!isIsolated) {
944
- return runSubprocess({
945
- cwd: this.session.cwd,
946
- agent: effectiveAgent,
947
- task: renderSubagentUserPrompt(task.assignment, simpleMode),
948
- assignment: task.assignment.trim(),
949
- context: sharedContext,
950
- planReference,
951
- description: task.description,
952
- index,
953
- id: task.id,
954
- taskDepth,
955
- modelOverride,
956
- parentActiveModelPattern,
957
- thinkingLevel: thinkingLevelOverride,
958
- outputSchema: effectiveOutputSchema,
959
- sessionFile,
960
- persistArtifacts: !!artifactsDir,
961
- artifactsDir: effectiveArtifactsDir,
962
- contextFile: contextFilePath,
963
- enableLsp: subagentLspEnabled,
964
- signal,
965
- eventBus: this.session.eventBus,
966
- onProgress: progress => {
967
- progressMap.set(index, {
968
- ...structuredClone(progress),
969
- });
970
- emitProgress();
971
- },
972
- authStorage: this.session.authStorage,
973
- modelRegistry: this.session.modelRegistry,
974
- settings: this.session.settings,
975
- mcpManager,
976
- contextFiles,
977
- skills: availableSkills,
978
- autoloadSkills: resolvedAutoloadSkills,
979
- workspaceTree: this.session.workspaceTree,
980
- promptTemplates,
981
- localProtocolOptions,
982
- parentArtifactManager,
983
- parentHindsightSessionState: this.session.getHindsightSessionState?.(),
984
- parentMnemopiSessionState: this.session.getMnemopiSessionState?.(),
985
- parentTelemetry: this.session.getTelemetry?.(),
986
- parentEvalSessionId,
987
- });
1248
+ return runSubprocess(sharedRunOptions);
988
1249
  }
989
1250
 
990
1251
  const taskStart = Date.now();
@@ -995,73 +1256,25 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
995
1256
  }
996
1257
  const taskBaseline = structuredClone(baseline);
997
1258
 
998
- isolationHandle = await ensureIsolation(repoRoot, task.id, preferredIsolationBackend);
1259
+ isolationHandle = await ensureIsolation(repoRoot, agentId, preferredIsolationBackend);
999
1260
  const isolationDir = isolationHandle.mergedDir;
1000
1261
 
1262
+ // Isolated runs re-discover extensions/custom tools inside the
1263
+ // worktree instead of reusing the parent's source paths.
1001
1264
  const result = await runSubprocess({
1002
- cwd: this.session.cwd,
1265
+ ...sharedRunOptions,
1003
1266
  worktree: isolationDir,
1004
- agent: effectiveAgent,
1005
- task: renderSubagentUserPrompt(task.assignment, simpleMode),
1006
- assignment: task.assignment.trim(),
1007
- context: sharedContext,
1008
- planReference,
1009
- description: task.description,
1010
- index,
1011
- id: task.id,
1012
- taskDepth,
1013
- modelOverride,
1014
- parentActiveModelPattern,
1015
- thinkingLevel: thinkingLevelOverride,
1016
- outputSchema: effectiveOutputSchema,
1017
- sessionFile,
1018
- persistArtifacts: !!artifactsDir,
1019
- artifactsDir: effectiveArtifactsDir,
1020
- contextFile: contextFilePath,
1021
- enableLsp: subagentLspEnabled,
1022
- signal,
1023
- eventBus: this.session.eventBus,
1024
- onProgress: progress => {
1025
- progressMap.set(index, {
1026
- ...structuredClone(progress),
1027
- });
1028
- emitProgress();
1029
- },
1030
- authStorage: this.session.authStorage,
1031
- modelRegistry: this.session.modelRegistry,
1032
- settings: this.session.settings,
1033
- mcpManager,
1034
- contextFiles,
1035
- skills: availableSkills,
1036
- autoloadSkills: resolvedAutoloadSkills,
1037
- workspaceTree: this.session.workspaceTree,
1038
- promptTemplates,
1039
- localProtocolOptions,
1040
- parentArtifactManager,
1041
- parentHindsightSessionState: this.session.getHindsightSessionState?.(),
1042
- parentMnemopiSessionState: this.session.getMnemopiSessionState?.(),
1043
- parentTelemetry: this.session.getTelemetry?.(),
1044
- parentEvalSessionId,
1267
+ preloadedExtensionPaths: undefined,
1268
+ preloadedCustomToolPaths: undefined,
1045
1269
  });
1046
1270
  if (mergeMode === "branch" && result.exitCode === 0) {
1047
1271
  try {
1048
- const commitMsg =
1049
- commitStyle === "ai" && this.session.modelRegistry
1050
- ? async (diff: string) => {
1051
- return generateCommitMessage(
1052
- diff,
1053
- this.session.modelRegistry!,
1054
- this.session.settings,
1055
- this.session.getSessionId?.() ?? undefined,
1056
- );
1057
- }
1058
- : undefined;
1059
1272
  const commitResult = await commitToBranch(
1060
1273
  isolationDir,
1061
1274
  taskBaseline,
1062
- task.id,
1063
- task.description,
1064
- commitMsg,
1275
+ agentId,
1276
+ params.description,
1277
+ buildCommitMessageFn(),
1065
1278
  );
1066
1279
  return {
1067
1280
  ...result,
@@ -1070,7 +1283,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1070
1283
  };
1071
1284
  } catch (mergeErr) {
1072
1285
  // Agent succeeded but branch commit failed — clean up stale branch
1073
- const branchName = `prometheus/task/${task.id}`;
1286
+ const branchName = `prometheus/task/${agentId}`;
1074
1287
  await git.branch.tryDelete(repoRoot, branchName);
1075
1288
  const msg = mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
1076
1289
  return { ...result, error: `Merge failed: ${msg}` };
@@ -1079,7 +1292,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1079
1292
  if (result.exitCode === 0) {
1080
1293
  try {
1081
1294
  const delta = await captureDeltaPatch(isolationDir, taskBaseline);
1082
- const patchPath = path.join(effectiveArtifactsDir, `${task.id}.patch`);
1295
+ const patchPath = path.join(effectiveArtifactsDir, `${agentId}.patch`);
1083
1296
  await Bun.write(patchPath, delta.rootPatch);
1084
1297
  return {
1085
1298
  ...result,
@@ -1094,21 +1307,21 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1094
1307
  return result;
1095
1308
  } catch (err) {
1096
1309
  const message = err instanceof Error ? err.message : String(err);
1097
- const assignment = task.assignment.trim();
1098
1310
  return {
1099
- index,
1100
- id: task.id,
1311
+ index: spawnIndex,
1312
+ id: agentId,
1101
1313
  agent: agent.name,
1102
1314
  agentSource: agent.source,
1103
- task: renderSubagentUserPrompt(assignment, simpleMode),
1315
+ task: renderSubagentUserPrompt(assignment),
1104
1316
  assignment,
1105
- description: task.description,
1317
+ description: params.description,
1106
1318
  exitCode: 1,
1107
1319
  output: "",
1108
1320
  stderr: message,
1109
1321
  truncated: false,
1110
1322
  durationMs: Date.now() - taskStart,
1111
1323
  tokens: 0,
1324
+ requests: 0,
1112
1325
  modelOverride,
1113
1326
  error: message,
1114
1327
  };
@@ -1119,142 +1332,68 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1119
1332
  }
1120
1333
  };
1121
1334
 
1122
- // Execute in parallel with concurrency limit
1123
- const { results: partialResults, aborted } = await mapWithConcurrencyLimit(
1124
- tasksWithUniqueIds,
1125
- maxConcurrency,
1126
- runTask,
1127
- signal,
1128
- );
1129
-
1130
- // Fill in skipped tasks (undefined entries from abort) with placeholder results
1131
- const results: SingleResult[] = partialResults.map((result, index) => {
1132
- if (result !== undefined) {
1133
- return result;
1134
- }
1135
- const task = tasksWithUniqueIds[index];
1136
- const assignment = task.assignment.trim();
1137
- return {
1138
- index,
1139
- id: task.id,
1140
- agent: agentName,
1141
- agentSource: agent.source,
1142
- task: renderSubagentUserPrompt(assignment, simpleMode),
1143
- assignment,
1144
- description: task.description,
1145
- exitCode: 1,
1146
- output: "",
1147
- stderr: "Skipped (cancelled before start)",
1148
- truncated: false,
1149
- durationMs: 0,
1150
- tokens: 0,
1151
- modelOverride,
1152
- error: "Cancelled before start",
1153
- aborted: true,
1154
- abortReason: "Cancelled before start",
1155
- };
1156
- });
1157
-
1158
- // Aggregate usage from executor results (already accumulated incrementally)
1159
- const aggregatedUsage = createUsageTotals();
1160
- let hasAggregatedUsage = false;
1161
- for (const result of results) {
1162
- if (result.usage) {
1163
- addUsageTotals(aggregatedUsage, result.usage);
1164
- hasAggregatedUsage = true;
1165
- }
1166
- }
1167
-
1168
- // Collect output paths (artifacts already written by executor in real-time)
1169
- const outputPaths: string[] = [];
1170
- const patchPaths: string[] = [];
1171
- for (const result of results) {
1172
- if (result.outputPath) {
1173
- outputPaths.push(result.outputPath);
1174
- }
1175
- if (result.patchPath) {
1176
- patchPaths.push(result.patchPath);
1177
- }
1178
- }
1335
+ const result = await runTask();
1179
1336
 
1180
1337
  let mergeSummary = "";
1181
1338
  let changesApplied: boolean | null = null;
1182
1339
  let hadAnyChanges = false;
1183
- let mergedBranchesForNestedPatches: Set<string> | null = null;
1340
+ let mergedBranchForNestedPatches = false;
1184
1341
  if (isIsolated && repoRoot) {
1185
1342
  try {
1186
1343
  if (mergeMode === "branch") {
1187
- // Branch mode: merge task branches sequentially
1188
- const branchEntries = results
1189
- .filter(r => r.branchName && r.exitCode === 0 && !r.aborted)
1190
- .map(r => ({ branchName: r.branchName!, taskId: r.id, description: r.description }));
1191
-
1192
- if (branchEntries.length === 0) {
1344
+ if (!result.branchName || result.exitCode !== 0 || result.aborted) {
1193
1345
  changesApplied = true;
1194
- hadAnyChanges = false;
1195
1346
  mergeSummary = "\n\nNo changes to apply.";
1196
1347
  } else {
1197
- const mergeResult = await mergeTaskBranches(repoRoot, branchEntries);
1198
- mergedBranchesForNestedPatches = new Set(mergeResult.merged);
1348
+ const mergeResult = await mergeTaskBranches(repoRoot, [
1349
+ { branchName: result.branchName, taskId: result.id, description: result.description },
1350
+ ]);
1351
+ mergedBranchForNestedPatches = mergeResult.merged.includes(result.branchName);
1199
1352
  changesApplied = mergeResult.failed.length === 0;
1200
1353
  hadAnyChanges = changesApplied && mergeResult.merged.length > 0;
1201
1354
 
1202
1355
  if (changesApplied) {
1203
1356
  mergeSummary = hadAnyChanges
1204
- ? `\n\nMerged ${mergeResult.merged.length} branch${mergeResult.merged.length === 1 ? "" : "es"}: ${mergeResult.merged.join(", ")}`
1357
+ ? `\n\nMerged branch: ${result.branchName}`
1205
1358
  : "\n\nNo changes to apply.";
1206
1359
  } else {
1207
- const mergedPart =
1208
- mergeResult.merged.length > 0 ? `Merged: ${mergeResult.merged.join(", ")}.\n` : "";
1209
- const failedPart = `Failed: ${mergeResult.failed.join(", ")}.`;
1210
1360
  const conflictPart = mergeResult.conflict ? `\nConflict: ${mergeResult.conflict}` : "";
1211
- mergeSummary = `\n\n<system-notification>Branch merge failed. ${mergedPart}${failedPart}${conflictPart}\nUnmerged branches remain for manual resolution.</system-notification>`;
1361
+ mergeSummary = `\n\n<system-notification>Branch merge failed: ${result.branchName}.${conflictPart}\nThe unmerged branch remains for manual resolution.</system-notification>`;
1362
+ }
1363
+ if (mergeResult.stashConflict) {
1364
+ mergeSummary += `\n\n<system-notification>${mergeResult.stashConflict}</system-notification>`;
1212
1365
  }
1213
- }
1214
1366
 
1215
- // Clean up merged branches (keep failed ones for manual resolution)
1216
- const allBranches = branchEntries.map(b => b.branchName);
1217
- if (changesApplied) {
1218
- await cleanupTaskBranches(repoRoot, allBranches);
1367
+ // Clean up the merged branch (keep failed ones for manual resolution)
1368
+ if (changesApplied) {
1369
+ await cleanupTaskBranches(repoRoot, [result.branchName]);
1370
+ }
1219
1371
  }
1220
1372
  } else {
1221
- // Patch mode: combine and apply patches
1222
- const patchesInOrder = results.map(result => result.patchPath).filter(Boolean) as string[];
1223
- const missingPatch = results.some(result => !result.patchPath);
1224
- if (missingPatch) {
1373
+ // Patch mode: apply the patch from a successful run. A failed or
1374
+ // aborted run has nothing to apply and must not block the result.
1375
+ const succeeded = result.exitCode === 0 && !result.error && !result.aborted;
1376
+ if (!succeeded) {
1377
+ changesApplied = true;
1378
+ hadAnyChanges = false;
1379
+ } else if (!result.patchPath) {
1225
1380
  changesApplied = false;
1226
1381
  hadAnyChanges = false;
1227
1382
  } else {
1228
- const patchStats = await Promise.all(
1229
- patchesInOrder.map(async patchPath => ({
1230
- patchPath,
1231
- size: (await fs.stat(patchPath)).size,
1232
- })),
1233
- );
1234
- const nonEmptyPatches = patchStats.filter(patch => patch.size > 0).map(patch => patch.patchPath);
1235
- if (nonEmptyPatches.length === 0) {
1383
+ const patchText = await Bun.file(result.patchPath).text();
1384
+ if (!patchText.trim()) {
1236
1385
  changesApplied = true;
1237
1386
  hadAnyChanges = false;
1238
1387
  } else {
1239
- const patchTexts = await Promise.all(
1240
- nonEmptyPatches.map(async patchPath => Bun.file(patchPath).text()),
1241
- );
1242
- const combinedPatch = patchTexts
1243
- .map(text => (text.endsWith("\n") ? text : `${text}\n`))
1244
- .join("");
1245
- if (!combinedPatch.trim()) {
1246
- changesApplied = true;
1247
- hadAnyChanges = false;
1248
- } else {
1249
- changesApplied = await git.patch.canApplyText(repoRoot, combinedPatch);
1250
- if (changesApplied) {
1251
- try {
1252
- await git.patch.applyText(repoRoot, combinedPatch);
1253
- hadAnyChanges = true;
1254
- } catch {
1255
- changesApplied = false;
1256
- hadAnyChanges = false;
1257
- }
1388
+ const normalized = patchText.endsWith("\n") ? patchText : `${patchText}\n`;
1389
+ changesApplied = await git.patch.canApplyText(repoRoot, normalized);
1390
+ if (changesApplied) {
1391
+ try {
1392
+ await git.patch.applyText(repoRoot, normalized);
1393
+ hadAnyChanges = true;
1394
+ } catch {
1395
+ changesApplied = false;
1396
+ hadAnyChanges = false;
1258
1397
  }
1259
1398
  }
1260
1399
  }
@@ -1265,10 +1404,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1265
1404
  } else {
1266
1405
  const notification =
1267
1406
  "<system-notification>Patches were not applied and must be handled manually.</system-notification>";
1268
- const patchList =
1269
- patchPaths.length > 0
1270
- ? `\n\nPatch artifacts:\n${patchPaths.map(patch => `- ${patch}`).join("\n")}`
1271
- : "";
1407
+ const patchList = result.patchPath ? `\n\nPatch artifact:\n- ${result.patchPath}` : "";
1272
1408
  mergeSummary = `\n\n${notification}${patchList}`;
1273
1409
  }
1274
1410
  }
@@ -1282,34 +1418,15 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1282
1418
 
1283
1419
  // Apply nested repo patches (separate from parent git)
1284
1420
  if (isIsolated && repoRoot && (mergeMode === "branch" || changesApplied !== false)) {
1285
- const allNestedPatches = results
1286
- .filter(r => {
1287
- if (!r.nestedPatches || r.nestedPatches.length === 0 || r.exitCode !== 0 || r.aborted) {
1288
- return false;
1289
- }
1290
- if (mergeMode !== "branch") {
1291
- return true;
1292
- }
1293
- if (!r.branchName || !mergedBranchesForNestedPatches) {
1294
- return false;
1295
- }
1296
- return mergedBranchesForNestedPatches.has(r.branchName);
1297
- })
1298
- .flatMap(r => r.nestedPatches!);
1299
- if (allNestedPatches.length > 0) {
1421
+ const nestedPatches = result.nestedPatches ?? [];
1422
+ const eligible =
1423
+ nestedPatches.length > 0 &&
1424
+ result.exitCode === 0 &&
1425
+ !result.aborted &&
1426
+ (mergeMode !== "branch" || mergedBranchForNestedPatches);
1427
+ if (eligible) {
1300
1428
  try {
1301
- const commitMsg =
1302
- commitStyle === "ai" && this.session.modelRegistry
1303
- ? async (diff: string) => {
1304
- return generateCommitMessage(
1305
- diff,
1306
- this.session.modelRegistry!,
1307
- this.session.settings,
1308
- this.session.getSessionId?.() ?? undefined,
1309
- );
1310
- }
1311
- : undefined;
1312
- await applyNestedPatches(repoRoot, allNestedPatches, commitMsg);
1429
+ await applyNestedPatches(repoRoot, nestedPatches, buildCommitMessageFn());
1313
1430
  } catch {
1314
1431
  // Nested patch failures are non-fatal to the parent merge
1315
1432
  mergeSummary +=
@@ -1318,58 +1435,6 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1318
1435
  }
1319
1436
  }
1320
1437
 
1321
- // Build final output - match plugin format
1322
- const cancelledCount = results.filter(r => r.aborted).length;
1323
- const successCount = results.filter(r => r.exitCode === 0 && !r.error && !r.aborted).length;
1324
- const totalDuration = Date.now() - startTime;
1325
-
1326
- const summaries = results.map(r => {
1327
- const status = r.aborted
1328
- ? "cancelled"
1329
- : r.exitCode === 0 && r.error
1330
- ? "merge failed"
1331
- : r.exitCode === 0
1332
- ? "completed"
1333
- : `failed (exit ${r.exitCode})`;
1334
- const output = r.output.trim() || r.stderr.trim() || "(no output)";
1335
- const outputCharCount = r.outputMeta?.charCount ?? output.length;
1336
- const fullOutputThreshold = 5000;
1337
- let preview = output;
1338
- let truncated = false;
1339
- if (outputCharCount > fullOutputThreshold) {
1340
- const slice = output.slice(0, fullOutputThreshold);
1341
- const lastNewline = slice.lastIndexOf("\n");
1342
- preview = lastNewline >= 0 ? slice.slice(0, lastNewline) : slice;
1343
- truncated = true;
1344
- }
1345
- return {
1346
- agent: r.agent,
1347
- status,
1348
- id: r.id,
1349
- preview,
1350
- truncated,
1351
- meta: r.outputMeta
1352
- ? {
1353
- lineCount: r.outputMeta.lineCount,
1354
- charSize: formatBytes(r.outputMeta.charCount),
1355
- }
1356
- : undefined,
1357
- };
1358
- });
1359
-
1360
- const outputIds = results.filter(r => !r.aborted || r.output.trim()).map(r => `agent://${r.id}`);
1361
- const summary = prompt.render(taskSummaryTemplate, {
1362
- successCount,
1363
- totalCount: results.length,
1364
- cancelledCount,
1365
- hasCancelledNote: aborted && cancelledCount > 0,
1366
- duration: formatDuration(totalDuration),
1367
- summaries,
1368
- outputIds,
1369
- agentName,
1370
- mergeSummary,
1371
- });
1372
-
1373
1438
  // Cleanup temp directory if used
1374
1439
  const shouldCleanupTempArtifacts =
1375
1440
  tempArtifactsDir && (!isIsolated || changesApplied === true || changesApplied === null);
@@ -1377,25 +1442,65 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
1377
1442
  await fs.rm(tempArtifactsDir, { recursive: true, force: true });
1378
1443
  }
1379
1444
 
1380
- return {
1381
- content: [{ type: "text", text: summary }],
1382
- details: {
1383
- projectAgentsDir,
1384
- results: results,
1385
- totalDurationMs: totalDuration,
1386
- usage: hasAggregatedUsage ? aggregatedUsage : undefined,
1387
- outputPaths,
1388
- },
1389
- };
1445
+ return this.#buildResultPayload(result, projectAgentsDir, Date.now() - startTime, mergeSummary);
1390
1446
  } catch (err) {
1391
1447
  return {
1392
1448
  content: [{ type: "text", text: `Task execution failed: ${err}` }],
1393
- details: {
1394
- projectAgentsDir,
1395
- results: [],
1396
- totalDurationMs: Date.now() - startTime,
1397
- },
1449
+ details: { projectAgentsDir, results: [], totalDurationMs: Date.now() - startTime },
1398
1450
  };
1399
1451
  }
1400
1452
  }
1453
+
1454
+ /** Build the tool result (summary text + details) for a settled run. */
1455
+ #buildResultPayload(
1456
+ result: SingleResult,
1457
+ projectAgentsDir: string | null,
1458
+ totalDurationMs: number,
1459
+ mergeSummary: string,
1460
+ ): AgentToolResult<TaskToolDetails> {
1461
+ const status = result.aborted
1462
+ ? "cancelled"
1463
+ : result.exitCode === 0 && result.error
1464
+ ? "merge failed"
1465
+ : result.exitCode === 0
1466
+ ? "completed"
1467
+ : `failed (exit ${result.exitCode})`;
1468
+ const output = formatResultOutputFallback(result);
1469
+ const outputCharCount = result.outputMeta?.charCount ?? output.length;
1470
+ const fullOutputThreshold = 5000;
1471
+ let preview = output;
1472
+ let truncated = false;
1473
+ if (outputCharCount > fullOutputThreshold) {
1474
+ const slice = output.slice(0, fullOutputThreshold);
1475
+ const lastNewline = slice.lastIndexOf("\n");
1476
+ preview = lastNewline >= 0 ? slice.slice(0, lastNewline) : slice;
1477
+ truncated = true;
1478
+ }
1479
+ const summary = prompt.render(taskSummaryTemplate, {
1480
+ agentName: result.agent,
1481
+ id: result.id,
1482
+ status,
1483
+ duration: formatDuration(totalDurationMs),
1484
+ preview,
1485
+ truncated,
1486
+ meta: result.outputMeta
1487
+ ? {
1488
+ lineCount: result.outputMeta.lineCount,
1489
+ charSize: formatBytes(result.outputMeta.charCount),
1490
+ }
1491
+ : undefined,
1492
+ mergeSummary,
1493
+ });
1494
+
1495
+ return {
1496
+ content: [{ type: "text", text: summary }],
1497
+ details: {
1498
+ projectAgentsDir,
1499
+ results: [result],
1500
+ totalDurationMs,
1501
+ usage: result.usage,
1502
+ outputPaths: result.outputPath ? [result.outputPath] : undefined,
1503
+ },
1504
+ };
1505
+ }
1401
1506
  }