@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,1381 @@
1
+ /**
2
+ * TUI rendering for task tool.
3
+ *
4
+ * Provides renderCall and renderResult functions for displaying
5
+ * task execution in the terminal UI.
6
+ */
7
+ import path from "node:path";
8
+ import type { Component } from './stubs/tui/index.ts';
9
+ import { Container, Markdown, Text } from './stubs/tui/index.ts';
10
+ import { formatNumber } from "@oh-my-pi/pi-utils";
11
+ import { settings } from "../config/settings";
12
+ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
13
+ import { formatContextUsage } from "../modes/components/status-line/context-thresholds";
14
+ import { shimmerEnabled, shimmerText } from "../modes/theme/shimmer";
15
+ import { getMarkdownTheme, type Theme } from "../modes/theme/theme";
16
+ import {
17
+ formatBadge,
18
+ formatDuration,
19
+ formatMoreItems,
20
+ formatStatusIcon,
21
+ replaceTabs,
22
+ type ToolUIStatus,
23
+ truncateToWidth,
24
+ } from "../tools/render-utils";
25
+ import {
26
+ type FindingPriority,
27
+ getPriorityInfo,
28
+ PRIORITY_LABELS,
29
+ parseReportFindingDetails,
30
+ type ReportFindingDetails,
31
+ type SubmitReviewDetails,
32
+ } from "../tools/review";
33
+ import { framedBlock, renderStatusLine } from "../tui";
34
+ import { repairDoubleEncodedJsonString } from "./repair-args";
35
+ import { subprocessToolRegistry } from "./subprocess-tool-registry";
36
+ import type { AgentProgress, SingleResult, TaskItem, TaskParams, TaskToolDetails } from "./types";
37
+
38
+ /**
39
+ * Get status icon for agent state.
40
+ * For running status, uses animated spinner if spinnerFrame is provided.
41
+ * Maps AgentProgress status to styled icon format.
42
+ */
43
+ function getStatusIcon(status: AgentProgress["status"], theme: Theme, spinnerFrame?: number): string {
44
+ switch (status) {
45
+ case "pending":
46
+ return formatStatusIcon("pending", theme);
47
+ case "running":
48
+ return formatStatusIcon("running", theme, spinnerFrame);
49
+ case "completed":
50
+ return formatStatusIcon("success", theme);
51
+ case "failed":
52
+ return formatStatusIcon("error", theme);
53
+ case "aborted":
54
+ return formatStatusIcon("aborted", theme);
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Append tool-count, context, and cost stats to a status line string.
60
+ */
61
+ function appendAgentStats(
62
+ line: string,
63
+ opts: {
64
+ toolCount?: number;
65
+ requests?: number;
66
+ tokens: number;
67
+ contextTokens?: number;
68
+ contextWindow?: number;
69
+ cost: number;
70
+ resolvedModel?: string;
71
+ showResolvedModelBadge?: boolean;
72
+ },
73
+ theme: Theme,
74
+ ): string {
75
+ if (opts.toolCount) {
76
+ line += `${theme.sep.dot}${theme.fg("dim", `${formatNumber(opts.toolCount)} ${theme.icon.extensionTool}`)}`;
77
+ }
78
+ if (opts.requests) {
79
+ line += `${theme.sep.dot}${theme.fg("dim", `${formatNumber(opts.requests)} req`)}`;
80
+ }
81
+ // Current per-turn context — match the status line's `<pct>%/<window>` gauge (e.g. `5.1%/1M`).
82
+ if (opts.contextTokens && opts.contextTokens > 0) {
83
+ const ctx =
84
+ opts.contextWindow && opts.contextWindow > 0
85
+ ? formatContextUsage((opts.contextTokens / opts.contextWindow) * 100, opts.contextWindow)
86
+ : `${formatNumber(opts.contextTokens)}`;
87
+ line += `${theme.sep.dot}${theme.fg("dim", ctx)}`;
88
+ }
89
+ if (opts.cost > 0) {
90
+ line += `${theme.sep.dot}${theme.fg("statusLineCost", `$${opts.cost.toFixed(2)}`)}`;
91
+ }
92
+ if (opts.resolvedModel && opts.showResolvedModelBadge) {
93
+ line += `${theme.sep.dot}${theme.fg("dim", truncateToWidth(replaceTabs(opts.resolvedModel), 30))}`;
94
+ }
95
+ return line;
96
+ }
97
+
98
+ function formatFindingSummary(findings: ReportFindingDetails[], theme: Theme): string {
99
+ if (findings.length === 0) return theme.fg("dim", "Findings: none");
100
+
101
+ const counts: { [P in FindingPriority]?: number } = {};
102
+ for (const finding of findings) {
103
+ counts[finding.priority] = (counts[finding.priority] ?? 0) + 1;
104
+ }
105
+
106
+ const parts: string[] = [];
107
+ for (const label of PRIORITY_LABELS) {
108
+ const { symbol, color } = getPriorityInfo(label);
109
+ const count = counts[label] ?? 0;
110
+ const text = theme.fg(color, `${label}:${count}`);
111
+ parts.push(theme.styledSymbol(symbol, color) ? `${theme.styledSymbol(symbol, color)} ${text}` : text);
112
+ }
113
+
114
+ return `${theme.fg("dim", "Findings:")} ${parts.join(theme.sep.dot)}`;
115
+ }
116
+
117
+ function normalizeReportFindings(value: unknown): ReportFindingDetails[] {
118
+ if (!Array.isArray(value)) return [];
119
+ const findings: ReportFindingDetails[] = [];
120
+ for (const item of value) {
121
+ const finding = parseReportFindingDetails(item);
122
+ if (finding) findings.push(finding);
123
+ }
124
+ return findings;
125
+ }
126
+
127
+ /**
128
+ * Normalize the `yield` slot of `extractedToolData` into an array of
129
+ * yield-detail records. The subprocess executor always populates this slot as
130
+ * `unknown[]` (see `executor.ts` `extractData` handler), but the renderer
131
+ * MUST also tolerate a stray single object — optional chaining short-circuits
132
+ * on `null`/`undefined` only, so calling `.map` on a plain object would throw
133
+ * `TypeError: completeData?.map is not a function` and crash the TUI.
134
+ * A single object is wrapped as a 1-element array so the review verdict still
135
+ * renders; non-object primitives drop out.
136
+ */
137
+ function normalizeYieldData(value: unknown): Array<{ data: unknown }> {
138
+ if (Array.isArray(value)) {
139
+ return value.filter((item): item is { data: unknown } => item !== null && typeof item === "object");
140
+ }
141
+ if (value !== null && typeof value === "object") {
142
+ return [value as { data: unknown }];
143
+ }
144
+ return [];
145
+ }
146
+
147
+ function formatJsonScalar(value: unknown, _theme: Theme): string {
148
+ if (value === null) return "null";
149
+ if (typeof value === "string") {
150
+ const trimmed = truncateToWidth(value, 70);
151
+ return `"${trimmed}"`;
152
+ }
153
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
154
+ return "";
155
+ }
156
+
157
+ function formatTaskId(id: string): string {
158
+ // Ids are name-based (e.g. "Anna", "Anna-2"); a "." separates nesting levels
159
+ // (e.g. "Anna.Bob"). Render the hierarchy with a ">" breadcrumb.
160
+ const segments = id.split(".");
161
+ return segments.length < 2 ? id : segments.join(">");
162
+ }
163
+
164
+ const MISSING_YIELD_WARNING_PREFIX = "SYSTEM WARNING: Subagent exited without calling yield tool";
165
+
166
+ function extractMissingYieldWarning(output: string): { warning?: string; rest: string } {
167
+ const lines = output.split("\n");
168
+ const firstLine = lines[0]?.trim() ?? "";
169
+ if (!firstLine.startsWith(MISSING_YIELD_WARNING_PREFIX)) {
170
+ return { rest: output };
171
+ }
172
+ const rest = lines
173
+ .slice(1)
174
+ .join("\n")
175
+ .replace(/^\s*\n+/, "");
176
+ return { warning: firstLine, rest };
177
+ }
178
+
179
+ function buildTreePrefix(ancestors: boolean[], theme: Theme): string {
180
+ return ancestors.map(hasNext => (hasNext ? `${theme.tree.vertical} ` : " ")).join("");
181
+ }
182
+
183
+ function renderJsonTreeLines(
184
+ value: unknown,
185
+ theme: Theme,
186
+ maxDepth: number,
187
+ maxLines: number,
188
+ ): { lines: string[]; truncated: boolean } {
189
+ const lines: string[] = [];
190
+ let truncated = false;
191
+
192
+ const iconObject = theme.styledSymbol("icon.folder", "muted");
193
+ const iconArray = theme.styledSymbol("icon.package", "muted");
194
+ const iconScalar = theme.styledSymbol("icon.file", "muted");
195
+
196
+ const pushLine = (line: string) => {
197
+ if (lines.length >= maxLines) {
198
+ truncated = true;
199
+ return false;
200
+ }
201
+ lines.push(line);
202
+ return true;
203
+ };
204
+
205
+ const renderNode = (val: unknown, key: string | undefined, ancestors: boolean[], isLast: boolean, depth: number) => {
206
+ if (lines.length >= maxLines) {
207
+ truncated = true;
208
+ return;
209
+ }
210
+
211
+ const connector = isLast ? theme.tree.last : theme.tree.branch;
212
+ const prefix = `${buildTreePrefix(ancestors, theme)}${theme.fg("dim", connector)} `;
213
+ const scalar = formatJsonScalar(val, theme);
214
+
215
+ if (scalar) {
216
+ const label = key ? theme.fg("muted", key) : theme.fg("muted", "value");
217
+ pushLine(`${prefix}${iconScalar} ${label}: ${theme.fg("dim", scalar)}`);
218
+ return;
219
+ }
220
+
221
+ if (Array.isArray(val)) {
222
+ const header = key ? theme.fg("muted", key) : theme.fg("muted", "array");
223
+ pushLine(`${prefix}${iconArray} ${header}`);
224
+ if (val.length === 0) {
225
+ pushLine(
226
+ `${buildTreePrefix([...ancestors, !isLast], theme)}${theme.fg("dim", theme.tree.last)} ${theme.fg(
227
+ "dim",
228
+ "[]",
229
+ )}`,
230
+ );
231
+ return;
232
+ }
233
+ if (depth >= maxDepth) {
234
+ pushLine(
235
+ `${buildTreePrefix([...ancestors, !isLast], theme)}${theme.fg("dim", theme.tree.last)} ${theme.fg(
236
+ "dim",
237
+ "…",
238
+ )}`,
239
+ );
240
+ return;
241
+ }
242
+ const nextAncestors = [...ancestors, !isLast];
243
+ for (let i = 0; i < val.length; i++) {
244
+ renderNode(val[i], `[${i}]`, nextAncestors, i === val.length - 1, depth + 1);
245
+ if (lines.length >= maxLines) {
246
+ truncated = true;
247
+ return;
248
+ }
249
+ }
250
+ return;
251
+ }
252
+
253
+ if (val && typeof val === "object") {
254
+ const header = key ? theme.fg("muted", key) : theme.fg("muted", "object");
255
+ pushLine(`${prefix}${iconObject} ${header}`);
256
+ const entries = Object.entries(val as Record<string, unknown>);
257
+ if (entries.length === 0) {
258
+ pushLine(
259
+ `${buildTreePrefix([...ancestors, !isLast], theme)}${theme.fg("dim", theme.tree.last)} ${theme.fg(
260
+ "dim",
261
+ "{}",
262
+ )}`,
263
+ );
264
+ return;
265
+ }
266
+ if (depth >= maxDepth) {
267
+ pushLine(
268
+ `${buildTreePrefix([...ancestors, !isLast], theme)}${theme.fg("dim", theme.tree.last)} ${theme.fg(
269
+ "dim",
270
+ "…",
271
+ )}`,
272
+ );
273
+ return;
274
+ }
275
+ const nextAncestors = [...ancestors, !isLast];
276
+ for (let i = 0; i < entries.length; i++) {
277
+ const [childKey, child] = entries[i];
278
+ renderNode(child, childKey, nextAncestors, i === entries.length - 1, depth + 1);
279
+ if (lines.length >= maxLines) {
280
+ truncated = true;
281
+ return;
282
+ }
283
+ }
284
+ return;
285
+ }
286
+
287
+ const label = key ? theme.fg("muted", key) : theme.fg("muted", "value");
288
+ pushLine(`${prefix}${iconScalar} ${label}: ${theme.fg("dim", String(val))}`);
289
+ };
290
+
291
+ const renderRoot = (val: unknown) => {
292
+ if (Array.isArray(val)) {
293
+ for (let i = 0; i < val.length; i++) {
294
+ renderNode(val[i], `[${i}]`, [], i === val.length - 1, 1);
295
+ if (lines.length >= maxLines) {
296
+ truncated = true;
297
+ return;
298
+ }
299
+ }
300
+ return;
301
+ }
302
+ if (val && typeof val === "object") {
303
+ const entries = Object.entries(val as Record<string, unknown>);
304
+ for (let i = 0; i < entries.length; i++) {
305
+ const [childKey, child] = entries[i];
306
+ renderNode(child, childKey, [], i === entries.length - 1, 1);
307
+ if (lines.length >= maxLines) {
308
+ truncated = true;
309
+ return;
310
+ }
311
+ }
312
+ return;
313
+ }
314
+ renderNode(val, undefined, [], true, 0);
315
+ };
316
+
317
+ renderRoot(value);
318
+
319
+ return { lines, truncated };
320
+ }
321
+
322
+ function renderOutputSection(
323
+ output: string,
324
+ continuePrefix: string,
325
+ expanded: boolean,
326
+ theme: Theme,
327
+ maxCollapsed = 3,
328
+ maxExpanded = 10,
329
+ warning?: string,
330
+ ): string[] {
331
+ const lines: string[] = [];
332
+ const trimmedOutput = output.trimEnd();
333
+ if (!trimmedOutput && !warning) return lines;
334
+
335
+ if (warning) {
336
+ lines.push(`${continuePrefix}${theme.fg("dim", "Output")}`);
337
+ lines.push(
338
+ `${continuePrefix} ${theme.fg("warning", theme.status.warning)} ${theme.fg(
339
+ "dim",
340
+ truncateToWidth(warning, 80),
341
+ )}`,
342
+ );
343
+
344
+ if (!trimmedOutput) {
345
+ return lines;
346
+ }
347
+
348
+ if (trimmedOutput.startsWith("{") || trimmedOutput.startsWith("[")) {
349
+ try {
350
+ const parsed = JSON.parse(trimmedOutput);
351
+
352
+ if (!expanded) {
353
+ lines.push(`${continuePrefix} ${theme.fg("dim", formatOutputInline(parsed, theme))}`);
354
+ return lines;
355
+ }
356
+
357
+ const tree = renderJsonTreeLines(parsed, theme, expanded ? 6 : 2, expanded ? 24 : 6);
358
+ if (tree.lines.length > 0) {
359
+ for (const line of tree.lines) {
360
+ lines.push(`${continuePrefix} ${line}`);
361
+ }
362
+ if (tree.truncated) {
363
+ lines.push(`${continuePrefix} ${theme.fg("dim", "…")}`);
364
+ }
365
+ return lines;
366
+ }
367
+ } catch {
368
+ // Fall back to raw output
369
+ }
370
+ }
371
+
372
+ const outputLines = output.trimEnd().split("\n");
373
+ const previewCount = expanded ? maxExpanded : maxCollapsed;
374
+ for (const line of outputLines.slice(0, previewCount)) {
375
+ lines.push(`${continuePrefix} ${theme.fg("dim", truncateToWidth(replaceTabs(line), 70))}`);
376
+ }
377
+
378
+ if (outputLines.length > previewCount) {
379
+ lines.push(
380
+ `${continuePrefix} ${theme.fg("dim", formatMoreItems(outputLines.length - previewCount, "line"))}`,
381
+ );
382
+ }
383
+
384
+ return lines;
385
+ }
386
+
387
+ if (trimmedOutput.startsWith("{") || trimmedOutput.startsWith("[")) {
388
+ try {
389
+ const parsed = JSON.parse(trimmedOutput);
390
+
391
+ // Collapsed: inline format like Args
392
+ if (!expanded) {
393
+ lines.push(`${continuePrefix}${theme.fg("dim", formatOutputInline(parsed, theme))}`);
394
+ return lines;
395
+ }
396
+
397
+ // Expanded: tree format
398
+ lines.push(`${continuePrefix}${theme.fg("dim", "Output")}`);
399
+ const tree = renderJsonTreeLines(parsed, theme, expanded ? 6 : 2, expanded ? 24 : 6);
400
+ if (tree.lines.length > 0) {
401
+ for (const line of tree.lines) {
402
+ lines.push(`${continuePrefix} ${line}`);
403
+ }
404
+ if (tree.truncated) {
405
+ lines.push(`${continuePrefix} ${theme.fg("dim", "…")}`);
406
+ }
407
+ return lines;
408
+ }
409
+ } catch {
410
+ // Fall back to raw output
411
+ }
412
+ }
413
+
414
+ lines.push(`${continuePrefix}${theme.fg("dim", "Output")}`);
415
+
416
+ const outputLines = output.trimEnd().split("\n");
417
+ const previewCount = expanded ? maxExpanded : maxCollapsed;
418
+ for (const line of outputLines.slice(0, previewCount)) {
419
+ lines.push(`${continuePrefix} ${theme.fg("dim", truncateToWidth(replaceTabs(line), 70))}`);
420
+ }
421
+
422
+ if (outputLines.length > previewCount) {
423
+ lines.push(`${continuePrefix} ${theme.fg("dim", formatMoreItems(outputLines.length - previewCount, "line"))}`);
424
+ }
425
+
426
+ return lines;
427
+ }
428
+
429
+ function renderTaskSection(
430
+ task: string,
431
+ continuePrefix: string,
432
+ expanded: boolean,
433
+ theme: Theme,
434
+ maxExpanded = 20,
435
+ ): string[] {
436
+ const lines: string[] = [];
437
+ const trimmed = task.trim();
438
+ if (!expanded || !trimmed) return lines;
439
+
440
+ lines.push(`${continuePrefix}${theme.fg("dim", "Task")}`);
441
+ const taskLines = trimmed.split("\n");
442
+ for (const line of taskLines.slice(0, maxExpanded)) {
443
+ lines.push(`${continuePrefix} ${theme.fg("dim", truncateToWidth(replaceTabs(line), 70))}`);
444
+ }
445
+ if (taskLines.length > maxExpanded) {
446
+ lines.push(`${continuePrefix} ${theme.fg("dim", formatMoreItems(taskLines.length - maxExpanded, "line"))}`);
447
+ }
448
+
449
+ return lines;
450
+ }
451
+
452
+ function formatScalarInline(value: unknown, maxLen: number, _theme: Theme): string {
453
+ if (value === null) return "null";
454
+ if (value === undefined) return "undefined";
455
+ if (typeof value === "boolean") return String(value);
456
+ if (typeof value === "number") return String(value);
457
+ if (typeof value === "string") {
458
+ const firstLine = value.split("\n")[0].trim();
459
+ if (firstLine.length === 0) return `"" (${value.split("\n").length} lines)`;
460
+ const preview = truncateToWidth(firstLine, maxLen);
461
+ if (value.includes("\n")) return `"${preview}…" (${value.split("\n").length} lines)`;
462
+ return `"${preview}"`;
463
+ }
464
+ if (Array.isArray(value)) return `[${value.length} items]`;
465
+ if (typeof value === "object") {
466
+ const keys = Object.keys(value);
467
+ return `{${keys.length} keys}`;
468
+ }
469
+ return String(value);
470
+ }
471
+
472
+ function formatOutputInline(data: unknown, theme: Theme, maxWidth = 80): string {
473
+ if (data === null || data === undefined) return "Output: none";
474
+
475
+ // For scalars, show directly
476
+ if (typeof data !== "object") {
477
+ return `Output: ${formatScalarInline(data, 60, theme)}`;
478
+ }
479
+
480
+ // For arrays, show count and first element preview
481
+ if (Array.isArray(data)) {
482
+ if (data.length === 0) return "Output: []";
483
+ const preview = formatScalarInline(data[0], 40, theme);
484
+ return `Output: [${data.length} items] ${preview}${data.length > 1 ? "…" : ""}`;
485
+ }
486
+
487
+ // For objects, show key=value pairs inline
488
+ const entries = Object.entries(data as Record<string, unknown>);
489
+ if (entries.length === 0) return "Output: {}";
490
+
491
+ const pairs: string[] = [];
492
+ let totalLen = "Output: ".length;
493
+
494
+ for (const [key, value] of entries) {
495
+ const valueStr = formatScalarInline(value, 24, theme);
496
+ const pairStr = `${key}=${valueStr}`;
497
+ const addLen = pairs.length > 0 ? pairStr.length + 2 : pairStr.length; // +2 for ", "
498
+
499
+ if (totalLen + addLen > maxWidth && pairs.length > 0) {
500
+ pairs.push("…");
501
+ break;
502
+ }
503
+
504
+ pairs.push(pairStr);
505
+ totalLen += addLen;
506
+ }
507
+
508
+ return `Output: ${pairs.join(", ")}`;
509
+ }
510
+
511
+ /**
512
+ * Render the call preview lines for the single spawned agent. The
513
+ * args stream in token by token, so every field access is defensive.
514
+ */
515
+ function renderTaskCallLines(args: Partial<TaskParams> | undefined, theme: Theme): string[] {
516
+ if (!args) return [];
517
+ const bullet = theme.fg("dim", "•");
518
+ const lines: string[] = [];
519
+
520
+ const rawId = typeof args.id === "string" ? args.id.trim() : "";
521
+ const idLabel = rawId ? formatTaskId(rawId) : "";
522
+ const desc = typeof args.description === "string" ? args.description.trim() : "";
523
+ if (idLabel || desc) {
524
+ let line = `${bullet} ${theme.fg("accent", theme.bold(idLabel || "agent"))}`;
525
+ if (desc) {
526
+ line += `: ${theme.fg("muted", truncateToWidth(replaceTabs(desc), 64))}`;
527
+ }
528
+ lines.push(line);
529
+ }
530
+ lines.push(...renderTaskItemLines(args.tasks, theme));
531
+ return lines;
532
+ }
533
+
534
+ /**
535
+ * Render the per-item list (`id` + ui `description`) for a batch call's
536
+ * streaming preview. The args stream in token by token, so the array grows
537
+ * over time and trailing entries may be partially parsed — every field access
538
+ * is defensive.
539
+ */
540
+ function renderTaskItemLines(tasks: TaskItem[] | undefined, theme: Theme): string[] {
541
+ if (!Array.isArray(tasks) || tasks.length === 0) return [];
542
+
543
+ const bullet = theme.fg("dim", "•");
544
+ const cap = Math.min(tasks.length, 12);
545
+ const lines: string[] = [];
546
+ for (let i = 0; i < cap; i++) {
547
+ const task = tasks[i] as Partial<TaskItem> | undefined;
548
+ const rawId = typeof task?.id === "string" ? task.id.trim() : "";
549
+ const idLabel = rawId ? formatTaskId(rawId) : `#${i + 1}`;
550
+ let line = `${bullet} ${theme.fg("accent", theme.bold(idLabel))}`;
551
+ const desc = typeof task?.description === "string" ? task.description.trim() : "";
552
+ if (desc) {
553
+ line += `: ${theme.fg("muted", truncateToWidth(replaceTabs(desc), 64))}`;
554
+ }
555
+ if (task?.isolated === true) {
556
+ line += theme.fg("dim", " [isolated]");
557
+ }
558
+ lines.push(line);
559
+ }
560
+ if (cap < tasks.length) {
561
+ lines.push(`${bullet} ${theme.fg("dim", formatMoreItems(tasks.length - cap, "agent"))}`);
562
+ }
563
+ return lines;
564
+ }
565
+
566
+ /** One renderable frame section: optional label, body rows, leading divider. */
567
+ type TaskRenderSection = { label?: string; lines: readonly string[]; separator?: boolean };
568
+ type AssignmentSectionRenderer = (width: number) => TaskRenderSection;
569
+
570
+ // Default output-block layout is: left border + one-cell content inset + right
571
+ // border. Render markdown at that inner width so the output block does not need
572
+ // to rewrap already-rendered assignment lines.
573
+ const ASSIGNMENT_FRAME_INSET = 3;
574
+
575
+ /**
576
+ * Build the assignment section (the markdown brief handed to the subagent).
577
+ * Rendered in both the streaming call preview and the result frame so the
578
+ * brief stays visible for the whole task lifecycle — not just until the first
579
+ * progress snapshot replaces the call view.
580
+ */
581
+ function createAssignmentSectionRenderer(
582
+ args: Partial<TaskParams> | undefined,
583
+ theme: Theme,
584
+ ): AssignmentSectionRenderer | undefined {
585
+ // `renderResult` receives the raw tool args (unlike `renderCall`, which is
586
+ // fed through `repairTaskParams`), so undo any per-field double-encoding
587
+ // here too. The repair is idempotent on already-clean text.
588
+ const assignment = repairDoubleEncodedJsonString(typeof args?.assignment === "string" ? args.assignment : "").trim();
589
+ if (!assignment) return undefined;
590
+ return createMarkdownSectionRenderer(assignment, theme);
591
+ }
592
+
593
+ /**
594
+ * Build the shared-context section (the `# Goal / # Constraints` background a
595
+ * batch call hands every subagent). Rendered like the assignment brief so the
596
+ * shared background stays visible for the whole task lifecycle.
597
+ */
598
+ function createContextSectionRenderer(
599
+ args: Partial<TaskParams> | undefined,
600
+ theme: Theme,
601
+ ): AssignmentSectionRenderer | undefined {
602
+ const context = repairDoubleEncodedJsonString(typeof args?.context === "string" ? args.context : "").trim();
603
+ if (!context) return undefined;
604
+ return createMarkdownSectionRenderer(context, theme);
605
+ }
606
+
607
+ function createMarkdownSectionRenderer(text: string, theme: Theme): AssignmentSectionRenderer {
608
+ const markdown = new Markdown(text, 0, 0, getMarkdownTheme(), {
609
+ color: line => theme.fg("muted", line),
610
+ });
611
+ return width => ({ lines: markdown.render(Math.max(1, width - ASSIGNMENT_FRAME_INSET)) });
612
+ }
613
+
614
+ /**
615
+ * Render the tool call arguments.
616
+ */
617
+ export function renderCall(
618
+ args: TaskParams,
619
+ options: RenderResultOptions & { renderContext?: { hasResult?: boolean } },
620
+ theme: Theme,
621
+ ): Component {
622
+ const showIsolated = "isolated" in args && args.isolated === true;
623
+ const header = renderStatusLine({ icon: "pending", title: "Task", description: args.agent }, theme);
624
+ const assignmentSection = createAssignmentSectionRenderer(args, theme);
625
+ const contextSection = createContextSectionRenderer(args, theme);
626
+ return framedBlock(theme, width => {
627
+ const sections: Array<{ label?: string; lines: readonly string[]; separator?: boolean }> = [];
628
+
629
+ // The call preview only exists to surface the dispatched agent while the
630
+ // args stream in. Once a result snapshot exists, `renderResult` draws the
631
+ // same agent (and the assignment brief) itself, so showing it here would
632
+ // repeat what the result frame already shows.
633
+ if (!options.renderContext?.hasResult) {
634
+ sections.push({
635
+ separator: true,
636
+ lines: renderTaskCallLines(args, theme),
637
+ });
638
+ if (contextSection) sections.push(contextSection(width));
639
+ if (assignmentSection) sections.push(assignmentSection(width));
640
+ }
641
+
642
+ return {
643
+ header,
644
+ headerMeta: showIsolated ? "isolated" : undefined,
645
+ sections,
646
+ state: "pending",
647
+ borderColor: "borderMuted",
648
+ width,
649
+ };
650
+ });
651
+ }
652
+
653
+ /**
654
+ * Render streaming progress for a single agent.
655
+ */
656
+ function renderAgentProgress(
657
+ progress: AgentProgress,
658
+ prefix: string,
659
+ continuePrefix: string,
660
+ expanded: boolean,
661
+ theme: Theme,
662
+ spinnerFrame?: number,
663
+ ): string[] {
664
+ const lines: string[] = [];
665
+
666
+ const icon = getStatusIcon(progress.status, theme, spinnerFrame);
667
+ const iconColor =
668
+ progress.status === "completed"
669
+ ? "success"
670
+ : progress.status === "failed" || progress.status === "aborted"
671
+ ? "error"
672
+ : "accent";
673
+
674
+ // Main status line: id: description [status] · stats · ⟨agent⟩
675
+ const description = progress.description?.trim();
676
+ const displayId = formatTaskId(progress.id);
677
+ const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
678
+ const indent = prefix ? `${prefix} ` : "";
679
+ let statusLine: string;
680
+ if (progress.status === "running" || progress.status === "pending") {
681
+ // Live (or queued) agents shimmer their description so the row reads as
682
+ // in-flight even after the block freezes — the async spawn result keeps
683
+ // the agent on "pending" while the detached job runs.
684
+ const bullet =
685
+ progress.status === "running" ? theme.styledSymbol("status.done", "text") : theme.fg(iconColor, icon);
686
+ const name = theme.fg("accent", description ? theme.bold(displayId) : displayId);
687
+ statusLine = `${indent}${bullet} ${name}`;
688
+ if (description) {
689
+ const desc = shimmerEnabled() ? shimmerText(description, theme) : theme.fg("accent", description);
690
+ statusLine += `${theme.fg("accent", ":")} ${desc}`;
691
+ }
692
+ } else {
693
+ const glyph =
694
+ progress.status === "completed" ? theme.styledSymbol("status.done", "accent") : theme.fg(iconColor, icon);
695
+ statusLine = `${indent}${glyph} ${theme.fg("accent", titlePart)}`;
696
+ }
697
+
698
+ // Show retry-blocked badge so the parent immediately sees that a child
699
+ // is sleeping on a provider 429, not silently progressing. Wins over the
700
+ // generic running marker because "we're waiting on a quota window" is
701
+ // the operationally meaningful state.
702
+ if (progress.retryState && progress.status === "running") {
703
+ statusLine += ` ${formatBadge("retrying", "warning", theme)}`;
704
+ } else if (progress.retryFailure && (progress.status === "failed" || progress.status === "aborted")) {
705
+ statusLine += ` ${formatBadge("rate-limited", "error", theme)}`;
706
+ } else if (progress.status === "failed" || progress.status === "aborted") {
707
+ const statusLabel = progress.status === "failed" ? "failed" : "aborted";
708
+ statusLine += ` ${formatBadge(statusLabel, iconColor, theme)}`;
709
+ }
710
+
711
+ const showBadge = settings.get("task.showResolvedModelBadge");
712
+ if (progress.status === "running") {
713
+ if (!description) {
714
+ const taskPreview = truncateToWidth(progress.assignment ?? progress.task, 40);
715
+ statusLine += ` ${theme.fg("muted", taskPreview)}`;
716
+ }
717
+ statusLine = appendAgentStats(statusLine, { ...progress, showResolvedModelBadge: showBadge }, theme);
718
+ } else if (progress.status === "completed") {
719
+ statusLine = appendAgentStats(statusLine, { ...progress, showResolvedModelBadge: showBadge }, theme);
720
+ }
721
+
722
+ lines.push(statusLine);
723
+
724
+ lines.push(...renderTaskSection(progress.assignment ?? progress.task, continuePrefix, expanded, theme));
725
+
726
+ // Current tool (if running) or most recent completed tool
727
+ if (progress.status === "running") {
728
+ if (progress.currentTool) {
729
+ let toolLine = `${continuePrefix}${theme.tree.hook} ${theme.fg("muted", progress.currentTool)}`;
730
+ const toolDetail = progress.lastIntent ?? progress.currentToolArgs;
731
+ if (toolDetail) {
732
+ toolLine += `: ${theme.fg("dim", truncateToWidth(replaceTabs(toolDetail), 40))}`;
733
+ }
734
+ if (progress.currentToolStartMs) {
735
+ const elapsed = Date.now() - progress.currentToolStartMs;
736
+ if (elapsed > 5000) {
737
+ toolLine += `${theme.sep.dot}${theme.fg("warning", formatDuration(elapsed))}`;
738
+ }
739
+ }
740
+ lines.push(toolLine);
741
+ } else if (progress.recentTools.length > 0) {
742
+ // Show most recent completed tool when idle between tools
743
+ const recent = progress.recentTools[0];
744
+ let toolLine = `${continuePrefix}${theme.tree.hook} ${theme.fg("dim", recent.tool)}`;
745
+ const toolDetail = progress.lastIntent ?? recent.args;
746
+ if (toolDetail) {
747
+ toolLine += `: ${theme.fg("dim", truncateToWidth(replaceTabs(toolDetail), 40))}`;
748
+ }
749
+ lines.push(toolLine);
750
+ }
751
+ }
752
+
753
+ // Retry detail line: surface why the subagent is paused and roughly how
754
+ // long until the next attempt. Without this, the parent UI would just
755
+ // keep spinning while a child sleeps on a 3-hour provider rate-limit.
756
+ if (progress.retryState && progress.status === "running") {
757
+ const remainingMs = Math.max(0, progress.retryState.startedAtMs + progress.retryState.delayMs - Date.now());
758
+ const waitLabel = remainingMs > 0 ? `in ${formatDuration(remainingMs)}` : "now";
759
+ const summary =
760
+ `retrying ${progress.retryState.attempt}/${progress.retryState.maxAttempts} ${waitLabel}: ` +
761
+ truncateToWidth(replaceTabs(progress.retryState.errorMessage), 60);
762
+ lines.push(`${continuePrefix}${theme.tree.hook} ${theme.fg("warning", summary)}`);
763
+ } else if (progress.retryFailure && progress.status !== "running") {
764
+ const summary = `auto-retry gave up after ${progress.retryFailure.attempt} attempt${
765
+ progress.retryFailure.attempt === 1 ? "" : "s"
766
+ }: ${truncateToWidth(replaceTabs(progress.retryFailure.errorMessage), 80)}`;
767
+ lines.push(`${continuePrefix}${theme.tree.hook} ${theme.fg("error", summary)}`);
768
+ }
769
+
770
+ // Render extracted tool data inline (e.g., review findings)
771
+ if (progress.extractedToolData) {
772
+ // For completed tasks, check for review verdict from yield tool
773
+ if (progress.status === "completed") {
774
+ const completeData = normalizeYieldData(progress.extractedToolData.yield);
775
+ const reportFindingData = normalizeReportFindings(progress.extractedToolData.report_finding);
776
+ const reviewData = completeData
777
+ .map(c => c.data as SubmitReviewDetails)
778
+ .filter(d => d && typeof d === "object" && "overall_correctness" in d);
779
+ if (reviewData.length > 0) {
780
+ const summary = reviewData[reviewData.length - 1];
781
+ const findings = reportFindingData;
782
+ lines.push(...renderReviewResult(summary, findings, continuePrefix, expanded, theme));
783
+ return lines; // Review result handles its own rendering
784
+ }
785
+ }
786
+
787
+ for (const toolName in progress.extractedToolData) {
788
+ const dataArray = progress.extractedToolData[toolName];
789
+ // Handle report_finding with tree formatting
790
+ if (toolName === "report_finding") {
791
+ const findings = normalizeReportFindings(dataArray);
792
+ if (findings.length === 0) continue;
793
+ lines.push(`${continuePrefix}${formatFindingSummary(findings, theme)}`);
794
+ lines.push(...renderFindings(findings, continuePrefix, expanded, theme));
795
+ continue;
796
+ }
797
+
798
+ // Nested `task` data has its own dedicated tree renderer below that
799
+ // also merges in the in-flight snapshot — skip the generic inline
800
+ // path so we don't render twice.
801
+ if (toolName === "task") continue;
802
+
803
+ const handler = subprocessToolRegistry.getHandler(toolName);
804
+ if (handler?.renderInline) {
805
+ const displayCount = expanded ? (dataArray as unknown[]).length : 3;
806
+ const recentData = (dataArray as unknown[]).slice(-displayCount);
807
+ for (const data of recentData) {
808
+ const component = handler.renderInline(data, theme);
809
+ if (component instanceof Text) {
810
+ lines.push(`${continuePrefix}${component.getText()}`);
811
+ }
812
+ }
813
+ if ((dataArray as unknown[]).length > displayCount) {
814
+ lines.push(
815
+ `${continuePrefix}${theme.fg(
816
+ "dim",
817
+ formatMoreItems((dataArray as unknown[]).length - displayCount, "item"),
818
+ )}`,
819
+ );
820
+ }
821
+ }
822
+ }
823
+ }
824
+
825
+ // Nested `task` tree: completed sub-calls from `extractedToolData.task` plus
826
+ // the in-flight snapshot (if any). Surfacing this in the live view means
827
+ // the user sees deep-tree progress without waiting for this agent to finish
828
+ // its own turn.
829
+ const completedTaskCalls = (progress.extractedToolData?.task as TaskToolDetails[] | undefined) ?? [];
830
+ const inflight = progress.inflightTaskDetails;
831
+ if (completedTaskCalls.length > 0 || inflight) {
832
+ const snapshots = inflight ? [...completedTaskCalls, inflight] : completedTaskCalls;
833
+ const nestedLines = renderNestedTaskTree(snapshots, expanded, theme, spinnerFrame);
834
+ for (const line of nestedLines) {
835
+ lines.push(`${continuePrefix}${line}`);
836
+ }
837
+ }
838
+
839
+ // Expanded view: recent output and tools
840
+ if (expanded && progress.status === "running") {
841
+ const output = progress.recentOutput.join("\n");
842
+ lines.push(...renderOutputSection(output, continuePrefix, true, theme, 2, 6));
843
+ }
844
+
845
+ return lines;
846
+ }
847
+
848
+ /**
849
+ * Render review result with combined verdict + findings in tree structure.
850
+ */
851
+ function renderReviewResult(
852
+ summary: SubmitReviewDetails,
853
+ findings: ReportFindingDetails[],
854
+ continuePrefix: string,
855
+ expanded: boolean,
856
+ theme: Theme,
857
+ ): string[] {
858
+ const lines: string[] = [];
859
+
860
+ // Verdict line
861
+ const verdictColor = summary.overall_correctness === "correct" ? "success" : "error";
862
+ const isCorrect = summary.overall_correctness === "correct";
863
+ const verdictIcon = isCorrect
864
+ ? theme.styledSymbol("status.done", "accent")
865
+ : theme.fg(verdictColor, theme.status.error);
866
+ lines.push(
867
+ `${continuePrefix} Patch is ${theme.fg(verdictColor, summary.overall_correctness)} ${verdictIcon} ${theme.fg(
868
+ "dim",
869
+ `(${(summary.confidence * 100).toFixed(0)}% confidence)`,
870
+ )}`,
871
+ );
872
+
873
+ // Explanation preview (first ~80 chars when collapsed, full when expanded)
874
+ if (summary.explanation) {
875
+ if (expanded) {
876
+ lines.push(`${continuePrefix}${theme.fg("dim", "Summary")}`);
877
+ const explanationLines = summary.explanation.split("\n");
878
+ for (const line of explanationLines) {
879
+ lines.push(`${continuePrefix} ${theme.fg("dim", replaceTabs(line))}`);
880
+ }
881
+ } else {
882
+ // Preview: first sentence or ~100 chars (flatten tabs/newlines first)
883
+ const flat = replaceTabs(summary.explanation).replace(/[\r\n]+/g, " ");
884
+ const firstSentence = flat.split(/[.!?]/)[0].trim();
885
+ const preview = truncateToWidth(`${firstSentence}.`, 100);
886
+ lines.push(`${continuePrefix}${theme.fg("dim", preview)}`);
887
+ }
888
+ }
889
+
890
+ // Findings summary + list
891
+ lines.push(`${continuePrefix}${formatFindingSummary(findings, theme)}`);
892
+
893
+ if (findings.length > 0) {
894
+ lines.push(...renderFindings(findings, continuePrefix, expanded, theme));
895
+ }
896
+
897
+ return lines;
898
+ }
899
+
900
+ /**
901
+ * Render review findings list.
902
+ */
903
+ function renderFindings(
904
+ findings: ReportFindingDetails[],
905
+ continuePrefix: string,
906
+ expanded: boolean,
907
+ theme: Theme,
908
+ ): string[] {
909
+ const lines: string[] = [];
910
+
911
+ // Sort by priority (lower = more severe) when collapsed to show most important first
912
+ const sortedFindings = expanded
913
+ ? findings
914
+ : [...findings].sort((a, b) => getPriorityInfo(a.priority).ord - getPriorityInfo(b.priority).ord);
915
+ const displayCount = expanded ? sortedFindings.length : Math.min(3, sortedFindings.length);
916
+
917
+ for (let i = 0; i < displayCount; i++) {
918
+ const finding = sortedFindings[i];
919
+ const isLastFinding = i === displayCount - 1 && (expanded || sortedFindings.length <= 3);
920
+ const findingPrefix = isLastFinding ? theme.tree.last : theme.tree.branch;
921
+ const findingContinue = isLastFinding ? " " : `${theme.tree.vertical} `;
922
+
923
+ const { color } = getPriorityInfo(finding.priority);
924
+ const rawTitle = finding.title?.replace(/^\[P\d\]\s*/, "") ?? "Untitled";
925
+ const titleText = replaceTabs(rawTitle).replace(/[\r\n]+/g, " ");
926
+ const loc = `${path.basename(finding.file_path || "<unknown>")}:${finding.line_start}`;
927
+
928
+ lines.push(
929
+ `${continuePrefix}${findingPrefix} ${theme.fg(color, `[${finding.priority}]`)} ${titleText} ${theme.fg("dim", loc)}`,
930
+ );
931
+
932
+ // Show body when expanded
933
+ if (expanded && finding.body) {
934
+ // Wrap body text
935
+ const bodyLines = finding.body.split("\n");
936
+ for (const bodyLine of bodyLines) {
937
+ lines.push(`${continuePrefix}${findingContinue}${theme.fg("dim", replaceTabs(bodyLine))}`);
938
+ }
939
+ }
940
+ }
941
+
942
+ if (!expanded && findings.length > 3) {
943
+ lines.push(`${continuePrefix}${theme.fg("dim", formatMoreItems(findings.length - 3, "finding"))}`);
944
+ }
945
+
946
+ return lines;
947
+ }
948
+
949
+ /**
950
+ * Render final result for a single agent.
951
+ */
952
+ function renderAgentResult(
953
+ result: SingleResult,
954
+ prefix: string,
955
+ continuePrefix: string,
956
+ expanded: boolean,
957
+ theme: Theme,
958
+ ): string[] {
959
+ const lines: string[] = [];
960
+
961
+ const { warning: missingCompleteWarning, rest: outputWithoutWarning } = extractMissingYieldWarning(result.output);
962
+ const aborted = result.aborted ?? false;
963
+ const mergeFailed = !aborted && result.exitCode === 0 && !!result.error;
964
+ const success = !aborted && result.exitCode === 0 && !result.error;
965
+ const needsWarning = Boolean(missingCompleteWarning) && success;
966
+ const icon = aborted
967
+ ? theme.status.aborted
968
+ : needsWarning
969
+ ? theme.status.warning
970
+ : success
971
+ ? theme.styledSymbol("status.done", "accent")
972
+ : theme.status.error;
973
+ const iconColor = needsWarning ? "warning" : success ? "success" : mergeFailed ? "warning" : "error";
974
+ const statusText = aborted
975
+ ? "aborted"
976
+ : needsWarning
977
+ ? "warning"
978
+ : success
979
+ ? "done"
980
+ : mergeFailed
981
+ ? "merge failed"
982
+ : "failed";
983
+
984
+ // Main status line: id: description [status] · stats · ⟨agent⟩
985
+ const description = result.description?.trim();
986
+ const displayId = formatTaskId(result.id);
987
+ const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
988
+ let statusLine = `${prefix ? `${prefix} ` : ""}${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)} ${formatBadge(
989
+ statusText,
990
+ iconColor,
991
+ theme,
992
+ )}`;
993
+ const showBadge = settings.get("task.showResolvedModelBadge");
994
+ statusLine = appendAgentStats(
995
+ statusLine,
996
+ {
997
+ tokens: result.tokens,
998
+ requests: result.requests,
999
+ contextTokens: result.contextTokens,
1000
+ contextWindow: result.contextWindow,
1001
+ cost: result.usage?.cost.total ?? 0,
1002
+ resolvedModel: result.resolvedModel,
1003
+ showResolvedModelBadge: showBadge,
1004
+ },
1005
+ theme,
1006
+ );
1007
+ statusLine += `${theme.sep.dot}${theme.fg("dim", formatDuration(result.durationMs))}`;
1008
+
1009
+ if (result.truncated) {
1010
+ statusLine += ` ${theme.fg("warning", "[truncated]")}`;
1011
+ }
1012
+
1013
+ lines.push(statusLine);
1014
+
1015
+ lines.push(...renderTaskSection(result.assignment ?? result.task, continuePrefix, expanded, theme));
1016
+
1017
+ if (aborted && result.abortReason) {
1018
+ lines.push(
1019
+ `${continuePrefix}${theme.fg("error", theme.status.aborted)} ${theme.fg("dim", truncateToWidth(replaceTabs(result.abortReason), 80))}`,
1020
+ );
1021
+ }
1022
+ // Check for review result (yield with review schema + report_finding)
1023
+ // Check for review result (yield with review schema + report_finding).
1024
+ // `normalizeYieldData` guards against a stray non-array `yield` slot —
1025
+ // optional chaining on `.map` only short-circuits on null/undefined and
1026
+ // would otherwise crash the renderer with `TypeError: completeData?.map
1027
+ // is not a function` when the slot is a plain object (see issue #1987).
1028
+ const completeData = normalizeYieldData(result.extractedToolData?.yield);
1029
+ const reportFindingData = normalizeReportFindings(result.extractedToolData?.report_finding);
1030
+
1031
+ // Extract review verdict from yield tool's data field if it matches SubmitReviewDetails
1032
+ const reviewData = completeData
1033
+ .map(c => c.data as SubmitReviewDetails)
1034
+ .filter(d => d && typeof d === "object" && "overall_correctness" in d);
1035
+ const submitReviewData = reviewData.length > 0 ? reviewData : undefined;
1036
+
1037
+ if (submitReviewData) {
1038
+ // Use combined review renderer
1039
+ const summary = submitReviewData[submitReviewData.length - 1];
1040
+ const findings = reportFindingData;
1041
+ lines.push(...renderReviewResult(summary, findings, continuePrefix, expanded, theme));
1042
+ return lines;
1043
+ }
1044
+ if (reportFindingData.length > 0) {
1045
+ const hasCompleteData = completeData.length > 0;
1046
+ const message = hasCompleteData
1047
+ ? "Review verdict missing expected fields"
1048
+ : "Review incomplete (yield not called)";
1049
+ lines.push(`${continuePrefix}${theme.fg("warning", theme.status.warning)} ${theme.fg("dim", message)}`);
1050
+ lines.push(`${continuePrefix}${formatFindingSummary(reportFindingData, theme)}`);
1051
+ lines.push(...renderFindings(reportFindingData, continuePrefix, expanded, theme));
1052
+ return lines;
1053
+ }
1054
+
1055
+ // Check for extracted tool data with custom renderers (skip review tools)
1056
+ let hasCustomRendering = false;
1057
+ const deferredToolLines: string[] = [];
1058
+ if (result.extractedToolData) {
1059
+ for (const [toolName, dataArray] of Object.entries(result.extractedToolData)) {
1060
+ // Skip review tools - handled above
1061
+ if (toolName === "yield" || toolName === "report_finding") continue;
1062
+
1063
+ const handler = subprocessToolRegistry.getHandler(toolName);
1064
+ if (handler?.renderFinal && (dataArray as unknown[]).length > 0) {
1065
+ const isTaskTool = toolName === "task";
1066
+ const component = handler.renderFinal(dataArray as unknown[], theme, expanded);
1067
+ const target = isTaskTool ? deferredToolLines : lines;
1068
+ if (!isTaskTool) {
1069
+ hasCustomRendering = true;
1070
+ target.push(`${continuePrefix}${theme.fg("dim", `Tool: ${toolName}`)}`);
1071
+ }
1072
+ if (component instanceof Text) {
1073
+ // Prefix each line with continuePrefix
1074
+ const text = component.getText();
1075
+ for (const line of text.split("\n")) {
1076
+ target.push(`${continuePrefix}${line}`);
1077
+ }
1078
+ } else if (component instanceof Container) {
1079
+ // For containers, render each child
1080
+ for (const child of (component as Container).children) {
1081
+ if (child instanceof Text) {
1082
+ target.push(`${continuePrefix}${child.getText()}`);
1083
+ }
1084
+ }
1085
+ }
1086
+ }
1087
+ }
1088
+ }
1089
+
1090
+ if (hasCustomRendering && missingCompleteWarning) {
1091
+ lines.push(
1092
+ `${continuePrefix}${theme.fg("warning", theme.status.warning)} ${theme.fg(
1093
+ "dim",
1094
+ truncateToWidth(missingCompleteWarning, 80),
1095
+ )}`,
1096
+ );
1097
+ }
1098
+
1099
+ // Fallback to output preview if no custom rendering
1100
+ if (!hasCustomRendering) {
1101
+ lines.push(
1102
+ ...renderOutputSection(outputWithoutWarning, continuePrefix, expanded, theme, 3, 12, missingCompleteWarning),
1103
+ );
1104
+ }
1105
+
1106
+ if (deferredToolLines.length > 0) {
1107
+ lines.push(...deferredToolLines);
1108
+ }
1109
+
1110
+ if (result.patchPath && !aborted && result.exitCode === 0) {
1111
+ lines.push(`${continuePrefix}${theme.fg("dim", `Patch: ${result.patchPath}`)}`);
1112
+ } else if (result.branchName && !aborted && result.exitCode === 0) {
1113
+ lines.push(`${continuePrefix}${theme.fg("dim", `Branch: ${result.branchName}`)}`);
1114
+ }
1115
+
1116
+ // Error message
1117
+ if (result.error && (!success || mergeFailed) && (!aborted || result.error !== result.abortReason)) {
1118
+ lines.push(
1119
+ `${continuePrefix}${theme.fg(mergeFailed ? "warning" : "error", truncateToWidth(replaceTabs(result.error), 70))}`,
1120
+ );
1121
+ }
1122
+
1123
+ return lines;
1124
+ }
1125
+
1126
+ /**
1127
+ * Order live progress entries so finished agents render first — sorted by
1128
+ * runtime ascending, matching {@link orderResultsForDisplay} — while
1129
+ * unfinished (pending/running) ones stay pinned at the bottom in dispatch
1130
+ * order. Because a finished agent's runtime is fixed, finalization renders
1131
+ * the same order and rows never reshuffle.
1132
+ */
1133
+ function orderProgressForDisplay(progress: readonly AgentProgress[]): AgentProgress[] {
1134
+ const finished: AgentProgress[] = [];
1135
+ const unfinished: AgentProgress[] = [];
1136
+ for (const p of progress) {
1137
+ (p.status === "pending" || p.status === "running" ? unfinished : finished).push(p);
1138
+ }
1139
+ finished.sort((a, b) => a.durationMs - b.durationMs || a.index - b.index);
1140
+ return finished.concat(unfinished);
1141
+ }
1142
+
1143
+ /**
1144
+ * Order finalized results by runtime ascending (tie-break: dispatch index) so
1145
+ * the finalized list matches the live-progress order produced by
1146
+ * {@link orderProgressForDisplay}.
1147
+ */
1148
+ function orderResultsForDisplay(results: readonly SingleResult[]): SingleResult[] {
1149
+ return [...results].sort((a, b) => a.durationMs - b.durationMs || a.index - b.index);
1150
+ }
1151
+
1152
+ /**
1153
+ * Render the tool result.
1154
+ */
1155
+ export function renderResult(
1156
+ result: { content: Array<{ type: string; text?: string }>; details?: TaskToolDetails; isError?: boolean },
1157
+ options: RenderResultOptions,
1158
+ theme: Theme,
1159
+ args?: TaskParams,
1160
+ ): Component {
1161
+ const fallbackText = result.content.find(c => c.type === "text")?.text ?? "";
1162
+ const details = result.details;
1163
+ const agentLabel = args?.agent?.trim() || undefined;
1164
+ const assignmentSection = createAssignmentSectionRenderer(args, theme);
1165
+ const contextSection = createContextSectionRenderer(args, theme);
1166
+
1167
+ if (!details) {
1168
+ const text = result.content.find(c => c.type === "text")?.text || "";
1169
+ const errored = result.isError === true;
1170
+ const header = errored
1171
+ ? renderStatusLine({ icon: "error", title: "Task", description: agentLabel }, theme)
1172
+ : renderStatusLine(
1173
+ {
1174
+ iconOverride: theme.styledSymbol("status.done", "accent"),
1175
+ title: "Task",
1176
+ description: agentLabel,
1177
+ },
1178
+ theme,
1179
+ );
1180
+ return framedBlock(theme, width => ({
1181
+ header,
1182
+ sections: [
1183
+ ...(contextSection ? [contextSection(width)] : []),
1184
+ ...(assignmentSection ? [assignmentSection(width)] : []),
1185
+ ...(text ? [{ separator: true, lines: [theme.fg("dim", truncateToWidth(text, width))] }] : []),
1186
+ ],
1187
+ state: errored ? "error" : "success",
1188
+ borderColor: errored ? "error" : "borderMuted",
1189
+ width,
1190
+ }));
1191
+ }
1192
+
1193
+ const hasResults = Boolean(details.results && details.results.length > 0);
1194
+ const aborted = hasResults && details.results.some(r => r.aborted);
1195
+ const failed = hasResults && details.results.some(r => !r.aborted && r.exitCode !== 0);
1196
+ const mergeFailed = hasResults && details.results.some(r => !r.aborted && r.exitCode === 0 && Boolean(r.error));
1197
+ const isError = aborted || failed;
1198
+ const agentCount = hasResults ? details.results.length : (details.progress?.length ?? 0);
1199
+ const icon: ToolUIStatus = options.isPartial ? "running" : isError ? "error" : mergeFailed ? "warning" : "success";
1200
+ // Surface the dispatched agent type (e.g. `Reviewer`) alongside the count
1201
+ // so the header reads `Task 1 agent: Reviewer`.
1202
+ const countLabel = agentCount > 0 ? `${agentCount} ${agentCount === 1 ? "agent" : "agents"}` : undefined;
1203
+ const metaLabel = countLabel ? (agentLabel ? `${countLabel}: ${agentLabel}` : countLabel) : agentLabel;
1204
+ const header = renderStatusLine(
1205
+ {
1206
+ icon: icon === "success" ? undefined : icon,
1207
+ iconOverride: icon === "success" ? theme.styledSymbol("status.done", "accent") : undefined,
1208
+ title: "Task",
1209
+ meta: metaLabel ? [metaLabel] : undefined,
1210
+ },
1211
+ theme,
1212
+ );
1213
+
1214
+ return framedBlock(theme, width => {
1215
+ const { expanded, isPartial, spinnerFrame } = options;
1216
+ const lines: string[] = [];
1217
+
1218
+ const shouldRenderProgress =
1219
+ Boolean(details.progress && details.progress.length > 0) && (isPartial || details.results.length === 0);
1220
+ if (shouldRenderProgress && details.progress) {
1221
+ orderProgressForDisplay(details.progress).forEach(progress => {
1222
+ lines.push(...renderAgentProgress(progress, "", " ", expanded, theme, spinnerFrame));
1223
+ });
1224
+ } else if (details.results && details.results.length > 0) {
1225
+ orderResultsForDisplay(details.results).forEach(res => {
1226
+ lines.push(...renderAgentResult(res, "", " ", expanded, theme));
1227
+ });
1228
+
1229
+ const abortedCount = details.results.filter(r => r.aborted).length;
1230
+ const mergeFailedCount = details.results.filter(r => !r.aborted && r.exitCode === 0 && r.error).length;
1231
+ const successCount = details.results.filter(r => !r.aborted && r.exitCode === 0 && !r.error).length;
1232
+ const failCount = details.results.length - successCount - mergeFailedCount - abortedCount;
1233
+ const summaryParts: string[] = [];
1234
+ if (abortedCount > 0) summaryParts.push(theme.fg("error", `${abortedCount} aborted`));
1235
+ if (successCount > 0) summaryParts.push(theme.fg("success", `${successCount} succeeded`));
1236
+ if (mergeFailedCount > 0) summaryParts.push(theme.fg("warning", `${mergeFailedCount} merge failed`));
1237
+ if (failCount > 0) summaryParts.push(theme.fg("error", `${failCount} failed`));
1238
+ const totalRequests = details.results.reduce((sum, r) => sum + (r.requests ?? 0), 0);
1239
+ if (totalRequests > 0) summaryParts.push(theme.fg("dim", `${formatNumber(totalRequests)} req`));
1240
+ summaryParts.push(theme.fg("dim", formatDuration(details.totalDurationMs)));
1241
+ // Wrap the run summary in the theme's bracket glyphs (dim chrome, colored
1242
+ // counts) to match the bash tool's `[Wall: … | Exit: …]` footer.
1243
+ lines.push(
1244
+ theme.fg("dim", theme.format.bracketLeft) +
1245
+ summaryParts.join(theme.fg("dim", theme.sep.dot)) +
1246
+ theme.fg("dim", theme.format.bracketRight),
1247
+ );
1248
+ }
1249
+
1250
+ const state = isPartial ? "running" : isError ? "error" : mergeFailed ? "warning" : "success";
1251
+ const borderColor = isError ? "error" : "borderMuted";
1252
+
1253
+ if (lines.length === 0) {
1254
+ const text = fallbackText.trim() ? fallbackText : "No results";
1255
+ return {
1256
+ header,
1257
+ sections: [
1258
+ ...(contextSection ? [contextSection(width)] : []),
1259
+ ...(assignmentSection ? [assignmentSection(width)] : []),
1260
+ { separator: true, lines: [theme.fg("dim", truncateToWidth(text, width))] },
1261
+ ],
1262
+ state,
1263
+ borderColor,
1264
+ width,
1265
+ };
1266
+ }
1267
+
1268
+ if (fallbackText.trim()) {
1269
+ const summaryLines = fallbackText.split("\n");
1270
+ const markerIndex = summaryLines.findIndex(
1271
+ line =>
1272
+ line.includes("<system-notification>") ||
1273
+ line.startsWith("Applied patches:") ||
1274
+ line.startsWith("No changes to apply."),
1275
+ );
1276
+ if (markerIndex >= 0) {
1277
+ const extra = summaryLines.slice(markerIndex);
1278
+ for (const line of extra) {
1279
+ if (!line.trim()) continue;
1280
+ lines.push(theme.fg("dim", line));
1281
+ }
1282
+ }
1283
+ }
1284
+
1285
+ while (lines.length > 0 && lines[0].trim() === "") lines.shift();
1286
+ return {
1287
+ header,
1288
+ sections: [
1289
+ ...(contextSection ? [contextSection(width)] : []),
1290
+ ...(assignmentSection ? [assignmentSection(width)] : []),
1291
+ ...(lines.length > 0 ? [{ separator: true, lines }] : []),
1292
+ ],
1293
+ state,
1294
+ borderColor,
1295
+ width,
1296
+ };
1297
+ });
1298
+ }
1299
+
1300
+ function isTaskToolDetails(value: unknown): value is TaskToolDetails {
1301
+ return (
1302
+ Boolean(value) &&
1303
+ typeof value === "object" &&
1304
+ "results" in (value as TaskToolDetails) &&
1305
+ Array.isArray((value as TaskToolDetails).results)
1306
+ );
1307
+ }
1308
+
1309
+ // Nested subagent snapshots sit one or more levels below the frame border, so
1310
+ // they keep tree guides to convey depth (the parent prepends its own continue
1311
+ // prefix). Only the top-level agent list drops guides (the frame is its box).
1312
+ function nestedMarkers(isLast: boolean, theme: Theme): { prefix: string; continuePrefix: string } {
1313
+ return {
1314
+ prefix: isLast ? theme.fg("dim", theme.tree.last) : theme.fg("dim", theme.tree.branch),
1315
+ continuePrefix: isLast ? " " : `${theme.fg("dim", theme.tree.vertical)} `,
1316
+ };
1317
+ }
1318
+
1319
+ function renderNestedTaskResults(detailsList: TaskToolDetails[], expanded: boolean, theme: Theme): string[] {
1320
+ const lines: string[] = [];
1321
+ for (const details of detailsList) {
1322
+ if (!details.results || details.results.length === 0) continue;
1323
+ const ordered = orderResultsForDisplay(details.results);
1324
+ ordered.forEach((result, index) => {
1325
+ const { prefix, continuePrefix } = nestedMarkers(index === ordered.length - 1, theme);
1326
+ lines.push(...renderAgentResult(result, prefix, continuePrefix, expanded, theme));
1327
+ });
1328
+ }
1329
+ return lines;
1330
+ }
1331
+
1332
+ /**
1333
+ * Render a list of `TaskToolDetails` snapshots — completed (`results[]`) or
1334
+ * in-flight (`progress[]`) — as an interleaved tree. Used by the live progress
1335
+ * view to surface nested subagent activity while this agent is still running.
1336
+ */
1337
+ function renderNestedTaskTree(
1338
+ detailsList: TaskToolDetails[],
1339
+ expanded: boolean,
1340
+ theme: Theme,
1341
+ spinnerFrame?: number,
1342
+ ): string[] {
1343
+ const lines: string[] = [];
1344
+ for (const details of detailsList) {
1345
+ const hasResults = Boolean(details.results && details.results.length > 0);
1346
+ if (hasResults) {
1347
+ const ordered = orderResultsForDisplay(details.results);
1348
+ ordered.forEach((result, index) => {
1349
+ const { prefix, continuePrefix } = nestedMarkers(index === ordered.length - 1, theme);
1350
+ lines.push(...renderAgentResult(result, prefix, continuePrefix, expanded, theme));
1351
+ });
1352
+ continue;
1353
+ }
1354
+ const inflight = details.progress;
1355
+ if (inflight && inflight.length > 0) {
1356
+ const ordered = orderProgressForDisplay(inflight);
1357
+ ordered.forEach((prog, index) => {
1358
+ const { prefix, continuePrefix } = nestedMarkers(index === ordered.length - 1, theme);
1359
+ lines.push(...renderAgentProgress(prog, prefix, continuePrefix, expanded, theme, spinnerFrame));
1360
+ });
1361
+ }
1362
+ }
1363
+ return lines;
1364
+ }
1365
+
1366
+ subprocessToolRegistry.register<TaskToolDetails>("task", {
1367
+ extractData: event => {
1368
+ const details = event.result?.details;
1369
+ return isTaskToolDetails(details) ? details : undefined;
1370
+ },
1371
+ renderFinal: (allData, theme, expanded) => {
1372
+ const lines = renderNestedTaskResults(allData, expanded, theme);
1373
+ return new Text(lines.join("\n"), 0, 0);
1374
+ },
1375
+ });
1376
+
1377
+ export const taskToolRenderer = {
1378
+ renderCall,
1379
+ renderResult,
1380
+ mergeCallAndResult: true,
1381
+ };