@wahack/pi-coding-agent 15.11.0

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