@prometheus-ai/agent 0.5.4 → 0.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1145) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/cli.js +25110 -0
  3. package/dist/types/async/index.d.ts +0 -1
  4. package/dist/types/async/job-manager.d.ts +33 -0
  5. package/dist/types/autolearn/controller.d.ts +25 -0
  6. package/dist/types/autolearn/managed-skills.d.ts +45 -0
  7. package/dist/types/autoresearch/state.d.ts +1 -1
  8. package/dist/types/autoresearch/tools/init-experiment.d.ts +1 -1
  9. package/dist/types/autoresearch/tools/log-experiment.d.ts +1 -1
  10. package/dist/types/autoresearch/tools/run-experiment.d.ts +1 -1
  11. package/dist/types/autoresearch/tools/update-notes.d.ts +1 -1
  12. package/dist/types/autoresearch/types.d.ts +1 -1
  13. package/dist/types/capability/context-file.d.ts +0 -13
  14. package/dist/types/capability/mcp.d.ts +1 -0
  15. package/dist/types/capability/rule-buckets.d.ts +1 -1
  16. package/dist/types/capability/rule.d.ts +6 -1
  17. package/dist/types/capability/types.d.ts +0 -4
  18. package/dist/types/cli/args.d.ts +23 -3
  19. package/dist/types/cli/bench-cli.d.ts +78 -0
  20. package/dist/types/cli/claude-trace-cli.d.ts +7 -0
  21. package/dist/types/cli/dry-balance-cli.d.ts +16 -2
  22. package/dist/types/cli/gallery-cli.d.ts +43 -0
  23. package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
  24. package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
  25. package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
  26. package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
  27. package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
  28. package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
  29. package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
  30. package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
  31. package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
  32. package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
  33. package/dist/types/cli/gallery-fixtures/types.d.ts +55 -0
  34. package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
  35. package/dist/types/cli/gallery-screenshot.d.ts +35 -0
  36. package/dist/types/cli/grievances-cli.d.ts +1 -1
  37. package/dist/types/cli/list-models.d.ts +6 -14
  38. package/dist/types/cli/models-cli.d.ts +49 -0
  39. package/dist/types/cli/session-picker.d.ts +1 -1
  40. package/dist/types/cli/setup-cli.d.ts +1 -1
  41. package/dist/types/cli/setup-model-picker.d.ts +14 -0
  42. package/dist/types/cli/startup-cwd.d.ts +2 -0
  43. package/dist/types/cli/update-cli.d.ts +13 -40
  44. package/dist/types/cli/usage-cli.d.ts +81 -0
  45. package/dist/types/cli-commands.d.ts +12 -0
  46. package/dist/types/collab/crypto.d.ts +7 -0
  47. package/dist/types/collab/guest.d.ts +37 -0
  48. package/dist/types/collab/host.d.ts +29 -0
  49. package/dist/types/collab/protocol.d.ts +119 -0
  50. package/dist/types/collab/relay-client.d.ts +22 -0
  51. package/dist/types/commands/bench.d.ts +29 -0
  52. package/dist/types/commands/gallery.d.ts +47 -0
  53. package/dist/types/commands/install.d.ts +1 -1
  54. package/dist/types/commands/join.d.ts +12 -0
  55. package/dist/types/commands/launch.d.ts +8 -4
  56. package/dist/types/commands/models.d.ts +33 -0
  57. package/dist/types/commands/read.d.ts +1 -1
  58. package/dist/types/commands/say.d.ts +24 -0
  59. package/dist/types/commands/token.d.ts +25 -0
  60. package/dist/types/commands/usage.d.ts +34 -0
  61. package/dist/types/commit/agentic/tools/analyze-file.d.ts +1 -1
  62. package/dist/types/commit/agentic/tools/git-file-diff.d.ts +1 -1
  63. package/dist/types/commit/agentic/tools/git-hunk.d.ts +1 -1
  64. package/dist/types/commit/agentic/tools/git-overview.d.ts +1 -1
  65. package/dist/types/commit/agentic/tools/propose-changelog.d.ts +1 -1
  66. package/dist/types/commit/agentic/tools/propose-commit.d.ts +1 -1
  67. package/dist/types/commit/agentic/tools/recent-commits.d.ts +1 -1
  68. package/dist/types/commit/agentic/tools/schemas.d.ts +1 -1
  69. package/dist/types/commit/agentic/tools/split-commit.d.ts +1 -1
  70. package/dist/types/commit/analysis/conventional.d.ts +2 -2
  71. package/dist/types/commit/analysis/summary.d.ts +2 -2
  72. package/dist/types/commit/changelog/generate.d.ts +3 -3
  73. package/dist/types/commit/changelog/index.d.ts +2 -2
  74. package/dist/types/commit/map-reduce/index.d.ts +3 -3
  75. package/dist/types/commit/map-reduce/map-phase.d.ts +2 -2
  76. package/dist/types/commit/map-reduce/reduce-phase.d.ts +2 -2
  77. package/dist/types/commit/model-selection.d.ts +10 -4
  78. package/dist/types/commit/shared-llm.d.ts +1 -1
  79. package/dist/types/config/api-key-resolver.d.ts +43 -0
  80. package/dist/types/config/append-only-context-mode.d.ts +2 -1
  81. package/dist/types/config/keybindings.d.ts +12 -7
  82. package/dist/types/config/model-discovery.d.ts +57 -0
  83. package/dist/types/config/model-equivalence.d.ts +1 -1
  84. package/dist/types/config/model-registry.d.ts +86 -222
  85. package/dist/types/config/model-resolver.d.ts +43 -12
  86. package/dist/types/config/model-roles.d.ts +29 -0
  87. package/dist/types/config/models-config-schema.d.ts +536 -43
  88. package/dist/types/config/models-config.d.ts +391 -0
  89. package/dist/types/config/settings-schema.d.ts +1202 -324
  90. package/dist/types/config/settings.d.ts +15 -3
  91. package/dist/types/dap/config.d.ts +14 -1
  92. package/dist/types/dap/types.d.ts +10 -0
  93. package/dist/types/debug/log-viewer.d.ts +1 -1
  94. package/dist/types/debug/raw-sse.d.ts +1 -1
  95. package/dist/types/debug/report-bundle.d.ts +3 -0
  96. package/dist/types/debug/terminal-info.d.ts +0 -1
  97. package/dist/types/discovery/at-imports.d.ts +15 -0
  98. package/dist/types/discovery/prometheus-extension-roots.d.ts +7 -7
  99. package/dist/types/edit/diff.d.ts +3 -2
  100. package/dist/types/edit/file-snapshot-store.d.ts +18 -0
  101. package/dist/types/edit/hashline/noop-loop-guard.d.ts +72 -0
  102. package/dist/types/edit/hashline/params.d.ts +1 -1
  103. package/dist/types/edit/index.d.ts +0 -1
  104. package/dist/types/edit/modes/apply-patch.d.ts +1 -1
  105. package/dist/types/edit/modes/patch.d.ts +1 -1
  106. package/dist/types/edit/modes/replace.d.ts +1 -1
  107. package/dist/types/edit/renderer.d.ts +1 -0
  108. package/dist/types/eval/__tests__/completion-bridge.test.d.ts +1 -0
  109. package/dist/types/eval/__tests__/helpers-local-roots.test.d.ts +1 -0
  110. package/dist/types/eval/__tests__/js-context-manager.test.d.ts +1 -0
  111. package/dist/types/eval/backend.d.ts +7 -2
  112. package/dist/types/eval/bridge-timeout.d.ts +1 -1
  113. package/dist/types/eval/completion-bridge.d.ts +25 -0
  114. package/dist/types/eval/idle-timeout.d.ts +1 -5
  115. package/dist/types/eval/js/context-manager.d.ts +1 -0
  116. package/dist/types/eval/js/executor.d.ts +2 -0
  117. package/dist/types/eval/js/index.d.ts +1 -1
  118. package/dist/types/eval/js/shared/helpers.d.ts +7 -1
  119. package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -6
  120. package/dist/types/eval/js/shared/runtime.d.ts +6 -1
  121. package/dist/types/eval/js/worker-protocol.d.ts +6 -0
  122. package/dist/types/eval/py/__tests__/prelude.test.d.ts +1 -0
  123. package/dist/types/eval/py/executor.d.ts +12 -0
  124. package/dist/types/eval/py/index.d.ts +1 -1
  125. package/dist/types/eval/py/kernel.d.ts +6 -1
  126. package/dist/types/eval/py/runtime.d.ts +9 -0
  127. package/dist/types/exa/index.d.ts +1 -19
  128. package/dist/types/exa/mcp-client.d.ts +10 -3
  129. package/dist/types/exa/types.d.ts +0 -83
  130. package/dist/types/exec/bash-executor.d.ts +7 -0
  131. package/dist/types/export/custom-share.d.ts +1 -2
  132. package/dist/types/export/html/index.d.ts +39 -0
  133. package/dist/types/export/html/template-js.d.ts +2 -0
  134. package/dist/types/export/share.d.ts +61 -0
  135. package/dist/types/export/ttsr.d.ts +14 -0
  136. package/dist/types/extensibility/custom-commands/types.d.ts +9 -4
  137. package/dist/types/extensibility/custom-tools/loader.d.ts +30 -4
  138. package/dist/types/extensibility/custom-tools/types.d.ts +16 -8
  139. package/dist/types/extensibility/extensions/index.d.ts +1 -1
  140. package/dist/types/extensibility/extensions/loader.d.ts +20 -1
  141. package/dist/types/extensibility/extensions/model-api.d.ts +17 -0
  142. package/dist/types/extensibility/extensions/runner.d.ts +5 -2
  143. package/dist/types/extensibility/extensions/types.d.ts +72 -11
  144. package/dist/types/extensibility/hooks/index.d.ts +2 -1
  145. package/dist/types/extensibility/hooks/loader.d.ts +1 -1
  146. package/dist/types/extensibility/hooks/types.d.ts +11 -5
  147. package/dist/types/extensibility/{legacy-pi-ai-shim.d.ts → legacy-package-ai-shim.d.ts} +2 -2
  148. package/dist/types/extensibility/plugins/{legacy-pi-compat.d.ts → legacy-package-compat.d.ts} +20 -3
  149. package/dist/types/extensibility/plugins/loader.d.ts +11 -0
  150. package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
  151. package/dist/types/extensibility/plugins/types.d.ts +2 -2
  152. package/dist/types/extensibility/shared-events.d.ts +3 -3
  153. package/dist/types/extensibility/skills.d.ts +10 -0
  154. package/dist/types/extensibility/slash-commands.d.ts +1 -11
  155. package/dist/types/goals/guided-setup.d.ts +18 -0
  156. package/dist/types/goals/state.d.ts +1 -1
  157. package/dist/types/goals/tools/goal-tool.d.ts +1 -1
  158. package/dist/types/hindsight/mental-models.d.ts +17 -8
  159. package/dist/types/hindsight/transcript.d.ts +1 -1
  160. package/dist/types/index.d.ts +5 -0
  161. package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
  162. package/dist/types/internal-urls/history-protocol.d.ts +14 -0
  163. package/dist/types/internal-urls/index.d.ts +1 -0
  164. package/dist/types/internal-urls/local-protocol.d.ts +14 -2
  165. package/dist/types/internal-urls/types.d.ts +1 -1
  166. package/dist/types/irc/bus.d.ts +79 -0
  167. package/dist/types/lib/xai-http.d.ts +1 -1
  168. package/dist/types/lsp/client.d.ts +10 -0
  169. package/dist/types/lsp/config.d.ts +2 -2
  170. package/dist/types/lsp/edits.d.ts +9 -0
  171. package/dist/types/lsp/format-options.d.ts +32 -0
  172. package/dist/types/lsp/index.d.ts +2 -7
  173. package/dist/types/lsp/types.d.ts +13 -1
  174. package/dist/types/lsp/utils.d.ts +6 -2
  175. package/dist/types/main.d.ts +23 -8
  176. package/dist/types/mcp/json-rpc.d.ts +5 -0
  177. package/dist/types/mcp/manager.d.ts +8 -0
  178. package/dist/types/mcp/oauth-discovery.d.ts +6 -1
  179. package/dist/types/mcp/oauth-flow.d.ts +13 -3
  180. package/dist/types/mcp/startup-events.d.ts +11 -0
  181. package/dist/types/mcp/tool-bridge.d.ts +2 -0
  182. package/dist/types/mcp/transports/stdio.d.ts +13 -0
  183. package/dist/types/mcp/types.d.ts +2 -0
  184. package/dist/types/memories/index.d.ts +7 -15
  185. package/dist/types/memories/storage.d.ts +0 -10
  186. package/dist/types/memory-backend/index.d.ts +3 -1
  187. package/dist/types/memory-backend/local-backend.d.ts +4 -3
  188. package/dist/types/memory-backend/resolve.d.ts +2 -2
  189. package/dist/types/memory-backend/runtime.d.ts +4 -0
  190. package/dist/types/memory-backend/types.d.ts +67 -2
  191. package/dist/types/mnemopi/config.d.ts +31 -1
  192. package/dist/types/mnemopi/state.d.ts +40 -2
  193. package/dist/types/modes/acp/acp-agent.d.ts +1 -2
  194. package/dist/types/modes/components/agent-dashboard.d.ts +17 -1
  195. package/dist/types/modes/components/agent-hub.d.ts +82 -0
  196. package/dist/types/modes/components/assistant-message.d.ts +5 -12
  197. package/dist/types/modes/components/bash-execution.d.ts +1 -1
  198. package/dist/types/modes/components/chat-block.d.ts +64 -0
  199. package/dist/types/modes/components/collab-prompt-message.d.ts +10 -0
  200. package/dist/types/modes/components/compaction-summary-message.d.ts +25 -5
  201. package/dist/types/modes/components/copy-selector.d.ts +1 -1
  202. package/dist/types/modes/components/custom-editor.d.ts +49 -2
  203. package/dist/types/modes/components/custom-editor.test.d.ts +1 -0
  204. package/dist/types/modes/components/dynamic-border.d.ts +1 -1
  205. package/dist/types/modes/components/extensions/extension-dashboard.d.ts +1 -1
  206. package/dist/types/modes/components/extensions/extension-list.d.ts +1 -1
  207. package/dist/types/modes/components/extensions/inspector-panel.d.ts +1 -1
  208. package/dist/types/modes/components/footer.d.ts +1 -1
  209. package/dist/types/modes/components/hook-editor.d.ts +5 -0
  210. package/dist/types/modes/components/hook-input.d.ts +4 -0
  211. package/dist/types/modes/components/hook-selector.d.ts +5 -7
  212. package/dist/types/modes/components/index.d.ts +1 -0
  213. package/dist/types/modes/components/late-diagnostics-message.d.ts +20 -0
  214. package/dist/types/modes/components/logout-account-selector.d.ts +8 -0
  215. package/dist/types/modes/components/mcp-add-wizard.d.ts +2 -1
  216. package/dist/types/modes/components/model-selector.d.ts +1 -1
  217. package/dist/types/modes/components/oauth-selector.d.ts +10 -1
  218. package/dist/types/modes/components/overlay-box.d.ts +17 -0
  219. package/dist/types/modes/components/plan-review-overlay.d.ts +61 -0
  220. package/dist/types/modes/components/plan-toc.d.ts +41 -0
  221. package/dist/types/modes/components/read-tool-group.d.ts +8 -0
  222. package/dist/types/modes/components/reset-usage-selector.d.ts +12 -0
  223. package/dist/types/modes/components/segment-track.d.ts +11 -6
  224. package/dist/types/modes/components/session-selector.d.ts +18 -9
  225. package/dist/types/modes/components/settings-defs.d.ts +9 -2
  226. package/dist/types/modes/components/settings-selector.d.ts +17 -4
  227. package/dist/types/modes/components/snapcompact-shape-preview.d.ts +31 -0
  228. package/dist/types/modes/components/status-line/component.d.ts +61 -0
  229. package/dist/types/modes/components/status-line/index.d.ts +1 -0
  230. package/dist/types/modes/components/status-line/types.d.ts +47 -3
  231. package/dist/types/modes/components/tiny-title-download-progress.d.ts +1 -1
  232. package/dist/types/modes/components/tool-execution.d.ts +49 -2
  233. package/dist/types/modes/components/transcript-container.d.ts +76 -26
  234. package/dist/types/modes/components/tree-selector.d.ts +2 -2
  235. package/dist/types/modes/components/ttsr-notification.d.ts +5 -1
  236. package/dist/types/modes/components/usage-row.d.ts +3 -0
  237. package/dist/types/modes/components/user-message-selector.d.ts +1 -1
  238. package/dist/types/modes/components/user-message.d.ts +2 -1
  239. package/dist/types/modes/components/visual-truncate.d.ts +1 -1
  240. package/dist/types/modes/components/welcome.d.ts +12 -2
  241. package/dist/types/modes/controllers/command-controller.d.ts +3 -2
  242. package/dist/types/modes/controllers/event-controller.d.ts +7 -1
  243. package/dist/types/modes/controllers/extension-ui-controller.d.ts +0 -1
  244. package/dist/types/modes/controllers/input-controller.d.ts +25 -3
  245. package/dist/types/modes/controllers/mcp-command-controller.d.ts +8 -0
  246. package/dist/types/modes/controllers/selector-controller.d.ts +5 -2
  247. package/dist/types/modes/controllers/session-focus-controller.d.ts +31 -0
  248. package/dist/types/modes/controllers/streaming-reveal.d.ts +22 -0
  249. package/dist/types/modes/controllers/tan-command-controller.d.ts +6 -0
  250. package/dist/types/modes/controllers/tool-args-reveal.d.ts +43 -0
  251. package/dist/types/modes/gradient-highlight.d.ts +9 -4
  252. package/dist/types/modes/image-references.d.ts +14 -3
  253. package/dist/types/modes/index.d.ts +8 -7
  254. package/dist/types/modes/interactive-mode.d.ts +92 -16
  255. package/dist/types/modes/magic-keywords.d.ts +14 -2
  256. package/dist/types/modes/markdown-prose.d.ts +1 -1
  257. package/dist/types/modes/oauth-manual-input.d.ts +7 -0
  258. package/dist/types/modes/rpc/rpc-client.d.ts +48 -2
  259. package/dist/types/modes/rpc/rpc-mode.d.ts +67 -2
  260. package/dist/types/modes/rpc/rpc-subagents.d.ts +24 -0
  261. package/dist/types/modes/rpc/rpc-types.d.ts +113 -1
  262. package/dist/types/modes/runtime-init.d.ts +4 -0
  263. package/dist/types/modes/session-observer-registry.d.ts +9 -0
  264. package/dist/types/modes/setup-version.d.ts +11 -0
  265. package/dist/types/modes/setup-wizard/index.d.ts +7 -2
  266. package/dist/types/modes/setup-wizard/lazy.d.ts +2 -0
  267. package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +4 -1
  268. package/dist/types/modes/setup-wizard/scenes/types.d.ts +11 -2
  269. package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +6 -2
  270. package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +1 -1
  271. package/dist/types/modes/theme/theme.d.ts +42 -7
  272. package/dist/types/modes/types.d.ts +62 -13
  273. package/dist/types/modes/utils/context-usage.d.ts +6 -1
  274. package/dist/types/modes/utils/copy-targets.d.ts +21 -1
  275. package/dist/types/modes/utils/ui-helpers.d.ts +4 -4
  276. package/dist/types/modes/workflow.d.ts +3 -3
  277. package/dist/types/plan-mode/approved-plan.d.ts +27 -8
  278. package/dist/types/plan-mode/plan-protection.d.ts +4 -4
  279. package/dist/types/registry/agent-lifecycle.d.ts +51 -0
  280. package/dist/types/registry/agent-registry.d.ts +33 -5
  281. package/dist/types/sdk.d.ts +46 -4
  282. package/dist/types/secrets/index.d.ts +1 -1
  283. package/dist/types/secrets/obfuscator.d.ts +9 -3
  284. package/dist/types/session/agent-session.d.ts +136 -66
  285. package/dist/types/session/agent-storage.d.ts +2 -1
  286. package/dist/types/session/auth-broker-config.d.ts +4 -0
  287. package/dist/types/session/auth-storage.d.ts +1 -1
  288. package/dist/types/session/codex-auto-reset.d.ts +111 -0
  289. package/dist/types/session/indexed-session-storage.d.ts +3 -3
  290. package/dist/types/session/messages.d.ts +26 -15
  291. package/dist/types/session/session-context.d.ts +39 -0
  292. package/dist/types/session/session-entries.d.ts +159 -0
  293. package/dist/types/session/session-history-format.d.ts +12 -0
  294. package/dist/types/session/session-listing.d.ts +69 -0
  295. package/dist/types/session/session-loader.d.ts +16 -0
  296. package/dist/types/session/session-manager.d.ts +107 -440
  297. package/dist/types/session/session-migrations.d.ts +12 -0
  298. package/dist/types/session/session-paths.d.ts +25 -0
  299. package/dist/types/session/session-persistence.d.ts +8 -0
  300. package/dist/types/session/session-storage.d.ts +11 -7
  301. package/dist/types/session/snapcompact-inline.d.ts +145 -0
  302. package/dist/types/session/snapcompact-savings-journal.d.ts +46 -0
  303. package/dist/types/session/streaming-output.d.ts +46 -0
  304. package/dist/types/session/tool-choice-queue.d.ts +6 -6
  305. package/dist/types/session/yield-queue.d.ts +10 -1
  306. package/dist/types/slash-commands/acp-builtins.d.ts +16 -0
  307. package/dist/types/slash-commands/available-commands.d.ts +34 -0
  308. package/dist/types/slash-commands/builtin-registry.d.ts +10 -0
  309. package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +14 -0
  310. package/dist/types/slash-commands/helpers/logout.d.ts +15 -0
  311. package/dist/types/slash-commands/helpers/reset-usage.d.ts +27 -0
  312. package/dist/types/slash-commands/helpers/stats-dashboard.d.ts +13 -0
  313. package/dist/types/slash-commands/types.d.ts +5 -9
  314. package/dist/types/ssh/connection-manager.d.ts +8 -0
  315. package/dist/types/stt/asr-client.d.ts +90 -0
  316. package/dist/types/stt/asr-protocol.d.ts +97 -0
  317. package/dist/types/stt/asr-worker.d.ts +2 -0
  318. package/dist/types/stt/downloader.d.ts +38 -0
  319. package/dist/types/stt/endpointer.d.ts +59 -0
  320. package/dist/types/stt/index.d.ts +5 -1
  321. package/dist/types/stt/models.d.ts +120 -0
  322. package/dist/types/stt/recorder.d.ts +17 -0
  323. package/dist/types/stt/stt-controller.d.ts +6 -0
  324. package/dist/types/stt/transcriber.d.ts +5 -7
  325. package/dist/types/stt/wav.d.ts +29 -0
  326. package/dist/types/system-prompt.d.ts +9 -1
  327. package/dist/types/task/commands.d.ts +1 -1
  328. package/dist/types/task/discovery.d.ts +1 -2
  329. package/dist/types/task/executor.d.ts +61 -2
  330. package/dist/types/task/index.d.ts +37 -6
  331. package/dist/types/task/output-manager.d.ts +0 -7
  332. package/dist/types/task/parallel.d.ts +2 -2
  333. package/dist/types/task/prometheus-command.d.ts +2 -2
  334. package/dist/types/task/render.d.ts +20 -7
  335. package/dist/types/task/repair-args.d.ts +8 -7
  336. package/dist/types/task/types.d.ts +109 -52
  337. package/dist/types/task/worktree.d.ts +2 -0
  338. package/dist/types/telemetry-export.d.ts +2 -2
  339. package/dist/types/thinking.d.ts +4 -0
  340. package/dist/types/tiny/models.d.ts +1 -1
  341. package/dist/types/tiny/title-client.d.ts +12 -1
  342. package/dist/types/tiny/title-protocol.d.ts +1 -0
  343. package/dist/types/tools/archive-reader.d.ts +5 -0
  344. package/dist/types/tools/ask.d.ts +6 -1
  345. package/dist/types/tools/ast-edit.d.ts +4 -1
  346. package/dist/types/tools/ast-grep.d.ts +4 -1
  347. package/dist/types/tools/bash.d.ts +5 -2
  348. package/dist/types/tools/browser/attach.d.ts +4 -4
  349. package/dist/types/tools/browser/cmux/cmux-tab.d.ts +202 -0
  350. package/dist/types/tools/browser/cmux/rpc.d.ts +70 -0
  351. package/dist/types/tools/browser/cmux/socket-client.d.ts +19 -0
  352. package/dist/types/tools/browser/registry.d.ts +17 -3
  353. package/dist/types/tools/browser/render.d.ts +2 -0
  354. package/dist/types/tools/browser/tab-protocol.d.ts +2 -0
  355. package/dist/types/tools/browser/tab-supervisor.d.ts +16 -4
  356. package/dist/types/tools/browser/tab-worker.d.ts +18 -1
  357. package/dist/types/tools/browser.d.ts +3 -1
  358. package/dist/types/tools/checkpoint.d.ts +1 -1
  359. package/dist/types/tools/conflict-detect.d.ts +16 -0
  360. package/dist/types/tools/debug.d.ts +1 -1
  361. package/dist/types/tools/eval-render.d.ts +1 -8
  362. package/dist/types/tools/eval.d.ts +9 -1
  363. package/dist/types/tools/fetch.d.ts +17 -8
  364. package/dist/types/tools/find.d.ts +1 -8
  365. package/dist/types/tools/gh-cache-invalidation.d.ts +6 -0
  366. package/dist/types/tools/gh.d.ts +4 -1
  367. package/dist/types/tools/github-cache.d.ts +19 -0
  368. package/dist/types/tools/grouped-file-output.d.ts +46 -12
  369. package/dist/types/tools/image-gen.d.ts +1 -1
  370. package/dist/types/tools/index.d.ts +89 -8
  371. package/dist/types/tools/inspect-image.d.ts +1 -1
  372. package/dist/types/tools/irc.d.ts +79 -39
  373. package/dist/types/tools/job.d.ts +8 -2
  374. package/dist/types/tools/learn.d.ts +51 -0
  375. package/dist/types/tools/manage-skill.d.ts +40 -0
  376. package/dist/types/tools/memory-edit.d.ts +2 -2
  377. package/dist/types/tools/memory-recall.d.ts +1 -1
  378. package/dist/types/tools/memory-reflect.d.ts +1 -1
  379. package/dist/types/tools/memory-render.d.ts +4 -1
  380. package/dist/types/tools/memory-retain.d.ts +1 -1
  381. package/dist/types/tools/path-utils.d.ts +17 -5
  382. package/dist/types/tools/plan-mode-guard.d.ts +18 -9
  383. package/dist/types/tools/read.d.ts +3 -2
  384. package/dist/types/tools/render-mermaid.d.ts +1 -1
  385. package/dist/types/tools/render-utils.d.ts +47 -27
  386. package/dist/types/tools/renderers.d.ts +10 -2
  387. package/dist/types/tools/report-tool-issue.d.ts +6 -1
  388. package/dist/types/tools/resolve.d.ts +1 -1
  389. package/dist/types/tools/review.d.ts +1 -1
  390. package/dist/types/tools/search-tool-bm25.d.ts +1 -1
  391. package/dist/types/tools/search.d.ts +7 -3
  392. package/dist/types/tools/sqlite-reader.d.ts +4 -0
  393. package/dist/types/tools/ssh.d.ts +2 -1
  394. package/dist/types/tools/todo.d.ts +7 -15
  395. package/dist/types/tools/tool-result.d.ts +2 -0
  396. package/dist/types/tools/tool-timeouts.d.ts +1 -1
  397. package/dist/types/tools/tts.d.ts +26 -1
  398. package/dist/types/tools/write.d.ts +6 -3
  399. package/dist/types/tools/yield.d.ts +8 -0
  400. package/dist/types/tts/downloader.d.ts +20 -0
  401. package/dist/types/tts/index.d.ts +8 -0
  402. package/dist/types/tts/models.d.ts +82 -0
  403. package/dist/types/tts/player.d.ts +32 -0
  404. package/dist/types/tts/runtime.d.ts +6 -0
  405. package/dist/types/tts/streaming-player.d.ts +41 -0
  406. package/dist/types/tts/tts-client.d.ts +93 -0
  407. package/dist/types/tts/tts-protocol.d.ts +95 -0
  408. package/dist/types/tts/tts-worker.d.ts +2 -0
  409. package/dist/types/tts/vocalizer.d.ts +41 -0
  410. package/dist/types/tts/wav.d.ts +8 -0
  411. package/dist/types/tui/code-cell.d.ts +0 -2
  412. package/dist/types/tui/hyperlink.d.ts +13 -7
  413. package/dist/types/tui/output-block.d.ts +16 -22
  414. package/dist/types/tui/status-line.d.ts +3 -0
  415. package/dist/types/utils/block-context.d.ts +35 -0
  416. package/dist/types/utils/changelog.d.ts +8 -0
  417. package/dist/types/utils/clipboard.d.ts +4 -3
  418. package/dist/types/utils/enhanced-paste.d.ts +20 -0
  419. package/dist/types/utils/file-mentions.d.ts +7 -0
  420. package/dist/types/utils/git.d.ts +22 -3
  421. package/dist/types/utils/image-loading.d.ts +30 -1
  422. package/dist/types/utils/session-color.d.ts +15 -3
  423. package/dist/types/utils/thinking-display.d.ts +17 -0
  424. package/dist/types/utils/title-generator.d.ts +3 -2
  425. package/dist/types/utils/tool-choice.d.ts +8 -0
  426. package/dist/types/utils/tools-manager.d.ts +2 -1
  427. package/dist/types/web/kagi.d.ts +2 -2
  428. package/dist/types/web/parallel.d.ts +3 -0
  429. package/dist/types/web/scrapers/github.d.ts +22 -0
  430. package/dist/types/web/scrapers/readthedocs.d.ts +3 -0
  431. package/dist/types/web/scrapers/types.d.ts +12 -0
  432. package/dist/types/web/search/index.d.ts +1 -1
  433. package/dist/types/web/search/providers/anthropic.d.ts +2 -1
  434. package/dist/types/web/search/providers/base.d.ts +2 -1
  435. package/dist/types/web/search/providers/brave.d.ts +2 -1
  436. package/dist/types/web/search/providers/codex.d.ts +2 -1
  437. package/dist/types/web/search/providers/exa.d.ts +2 -1
  438. package/dist/types/web/search/providers/gemini.d.ts +10 -6
  439. package/dist/types/web/search/providers/jina.d.ts +7 -2
  440. package/dist/types/web/search/providers/kagi.d.ts +7 -2
  441. package/dist/types/web/search/providers/kimi.d.ts +7 -2
  442. package/dist/types/web/search/providers/parallel.d.ts +2 -1
  443. package/dist/types/web/search/providers/perplexity.d.ts +10 -2
  444. package/dist/types/web/search/providers/searxng.d.ts +2 -1
  445. package/dist/types/web/search/providers/synthetic.d.ts +7 -3
  446. package/dist/types/web/search/providers/tavily.d.ts +2 -1
  447. package/dist/types/web/search/providers/zai.d.ts +2 -1
  448. package/dist/types/web/search/types.d.ts +1 -1
  449. package/examples/extensions/api-demo.ts +2 -2
  450. package/package.json +41 -15
  451. package/scripts/bench-guard.ts +71 -0
  452. package/scripts/build-binary.ts +24 -25
  453. package/scripts/bundle-dist.ts +97 -0
  454. package/scripts/generate-share-viewer.ts +34 -0
  455. package/scripts/prometheus +42 -0
  456. package/scripts/prometheus.ts +20 -0
  457. package/src/async/index.ts +0 -1
  458. package/src/async/job-manager.ts +106 -3
  459. package/src/auto-thinking/classifier.ts +2 -1
  460. package/src/autolearn/controller.ts +139 -0
  461. package/src/autolearn/managed-skills.ts +257 -0
  462. package/src/autoresearch/dashboard.ts +1 -1
  463. package/src/autoresearch/prompt-setup.md +6 -6
  464. package/src/autoresearch/prompt.md +6 -6
  465. package/src/autoresearch/state.ts +1 -1
  466. package/src/autoresearch/storage.ts +2 -1
  467. package/src/autoresearch/tools/init-experiment.ts +1 -1
  468. package/src/autoresearch/tools/log-experiment.ts +1 -1
  469. package/src/autoresearch/tools/run-experiment.ts +1 -1
  470. package/src/autoresearch/tools/update-notes.ts +1 -1
  471. package/src/autoresearch/types.ts +1 -1
  472. package/src/capability/context-file.ts +0 -14
  473. package/src/capability/fs.ts +10 -0
  474. package/src/capability/index.ts +1 -6
  475. package/src/capability/mcp.ts +1 -0
  476. package/src/capability/rule-buckets.ts +4 -2
  477. package/src/capability/rule.ts +10 -1
  478. package/src/capability/types.ts +0 -4
  479. package/src/cli/args.ts +66 -13
  480. package/src/cli/auth-broker-cli.ts +6 -7
  481. package/src/cli/auth-gateway-cli.ts +8 -9
  482. package/src/cli/bench-cli.ts +437 -0
  483. package/src/cli/claude-trace-cli.ts +28 -50
  484. package/src/cli/completion-gen.ts +28 -28
  485. package/src/cli/dry-balance-cli.ts +56 -23
  486. package/src/cli/gallery-cli.ts +231 -0
  487. package/src/cli/gallery-fixtures/agentic.ts +407 -0
  488. package/src/cli/gallery-fixtures/codeintel.ts +187 -0
  489. package/src/cli/gallery-fixtures/edit.ts +194 -0
  490. package/src/cli/gallery-fixtures/fs.ts +220 -0
  491. package/src/cli/gallery-fixtures/index.ts +40 -0
  492. package/src/cli/gallery-fixtures/interaction.ts +49 -0
  493. package/src/cli/gallery-fixtures/memory.ts +81 -0
  494. package/src/cli/gallery-fixtures/misc.ts +250 -0
  495. package/src/cli/gallery-fixtures/search.ts +213 -0
  496. package/src/cli/gallery-fixtures/shell.ts +167 -0
  497. package/src/cli/gallery-fixtures/types.ts +57 -0
  498. package/src/cli/gallery-fixtures/web.ts +158 -0
  499. package/src/cli/gallery-screenshot.ts +279 -0
  500. package/src/cli/grievances-cli.ts +1 -1
  501. package/src/cli/list-models.ts +16 -174
  502. package/src/cli/models-cli.ts +429 -0
  503. package/src/cli/session-picker.ts +2 -1
  504. package/src/cli/setup-cli.ts +148 -47
  505. package/src/cli/setup-model-picker.ts +43 -0
  506. package/src/cli/startup-cwd.ts +68 -0
  507. package/src/cli/update-cli.ts +144 -272
  508. package/src/cli/usage-cli.ts +774 -0
  509. package/src/cli-commands.ts +36 -0
  510. package/src/cli.ts +141 -32
  511. package/src/collab/crypto.ts +63 -0
  512. package/src/collab/guest.ts +451 -0
  513. package/src/collab/host.ts +565 -0
  514. package/src/collab/protocol.ts +241 -0
  515. package/src/collab/relay-client.ts +216 -0
  516. package/src/commands/bench.ts +42 -0
  517. package/src/commands/complete.ts +1 -1
  518. package/src/commands/gallery.ts +52 -0
  519. package/src/commands/install.ts +1 -1
  520. package/src/commands/join.ts +39 -0
  521. package/src/commands/launch.ts +8 -4
  522. package/src/commands/models.ts +61 -0
  523. package/src/commands/read.ts +6 -3
  524. package/src/commands/say.ts +102 -0
  525. package/src/commands/setup.ts +1 -1
  526. package/src/commands/token.ts +89 -0
  527. package/src/commands/usage.ts +43 -0
  528. package/src/commit/agentic/agent.ts +2 -1
  529. package/src/commit/agentic/tools/analyze-file.ts +42 -20
  530. package/src/commit/agentic/tools/git-file-diff.ts +1 -1
  531. package/src/commit/agentic/tools/git-hunk.ts +1 -1
  532. package/src/commit/agentic/tools/git-overview.ts +1 -1
  533. package/src/commit/agentic/tools/propose-changelog.ts +1 -1
  534. package/src/commit/agentic/tools/propose-commit.ts +1 -1
  535. package/src/commit/agentic/tools/recent-commits.ts +1 -1
  536. package/src/commit/agentic/tools/schemas.ts +1 -1
  537. package/src/commit/agentic/tools/split-commit.ts +9 -2
  538. package/src/commit/analysis/conventional.ts +2 -2
  539. package/src/commit/analysis/summary.ts +3 -3
  540. package/src/commit/changelog/generate.ts +3 -3
  541. package/src/commit/changelog/index.ts +2 -2
  542. package/src/commit/map-reduce/index.ts +3 -3
  543. package/src/commit/map-reduce/map-phase.ts +2 -2
  544. package/src/commit/map-reduce/reduce-phase.ts +2 -2
  545. package/src/commit/model-selection.ts +35 -12
  546. package/src/commit/pipeline.ts +4 -4
  547. package/src/commit/shared-llm.ts +1 -1
  548. package/src/config/api-key-resolver.ts +67 -0
  549. package/src/config/append-only-context-mode.ts +6 -12
  550. package/src/config/keybindings.ts +9 -4
  551. package/src/config/mcp-schema.json +4 -0
  552. package/src/config/model-discovery.ts +574 -0
  553. package/src/config/model-equivalence.ts +5 -4
  554. package/src/config/model-registry.ts +659 -1093
  555. package/src/config/model-resolver.ts +374 -174
  556. package/src/config/model-roles.ts +88 -0
  557. package/src/config/models-config-schema.ts +61 -9
  558. package/src/config/models-config.ts +130 -0
  559. package/src/config/settings-schema.ts +1441 -387
  560. package/src/config/settings.ts +261 -69
  561. package/src/dap/client.ts +138 -53
  562. package/src/dap/config.ts +41 -2
  563. package/src/dap/defaults.json +1 -0
  564. package/src/dap/session.ts +263 -161
  565. package/src/dap/types.ts +10 -0
  566. package/src/debug/index.ts +50 -60
  567. package/src/debug/log-viewer.ts +1 -1
  568. package/src/debug/protocol-probe.ts +1 -1
  569. package/src/debug/raw-sse-buffer.ts +7 -4
  570. package/src/debug/raw-sse.ts +1 -1
  571. package/src/debug/report-bundle.ts +9 -0
  572. package/src/debug/terminal-info.ts +0 -3
  573. package/src/discovery/agents-md.ts +25 -21
  574. package/src/discovery/agents.ts +9 -15
  575. package/src/discovery/at-imports.ts +273 -0
  576. package/src/discovery/builtin-rules/index.ts +4 -0
  577. package/src/discovery/builtin-rules/ts-no-test-timers.md +55 -0
  578. package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +75 -0
  579. package/src/discovery/builtin.ts +45 -23
  580. package/src/discovery/claude-plugins.ts +44 -5
  581. package/src/discovery/helpers.ts +50 -9
  582. package/src/discovery/prometheus-extension-roots.ts +10 -10
  583. package/src/discovery/prometheus-plugins.ts +10 -10
  584. package/src/edit/diff.ts +191 -4
  585. package/src/edit/file-snapshot-store.ts +34 -1
  586. package/src/edit/hashline/block-resolver.ts +20 -1
  587. package/src/edit/hashline/diff.ts +123 -2
  588. package/src/edit/hashline/execute.ts +60 -4
  589. package/src/edit/hashline/filesystem.ts +2 -1
  590. package/src/edit/hashline/noop-loop-guard.ts +99 -0
  591. package/src/edit/hashline/params.ts +1 -1
  592. package/src/edit/index.ts +47 -18
  593. package/src/edit/modes/apply-patch.ts +1 -1
  594. package/src/edit/modes/patch.ts +59 -3
  595. package/src/edit/modes/replace.ts +58 -24
  596. package/src/edit/notebook.ts +22 -2
  597. package/src/edit/renderer.ts +315 -151
  598. package/src/eval/__tests__/agent-bridge.test.ts +105 -39
  599. package/src/eval/__tests__/budget-bridge.test.ts +1 -1
  600. package/src/eval/__tests__/completion-bridge.test.ts +412 -0
  601. package/src/eval/__tests__/helpers-local-roots.test.ts +58 -0
  602. package/src/eval/__tests__/js-context-manager.test.ts +241 -0
  603. package/src/eval/__tests__/llm-bridge.test.ts +6 -4
  604. package/src/eval/__tests__/shared-executors.test.ts +34 -92
  605. package/src/eval/agent-bridge.ts +39 -23
  606. package/src/eval/backend.ts +15 -2
  607. package/src/eval/bridge-timeout.ts +1 -1
  608. package/src/eval/completion-bridge.ts +203 -0
  609. package/src/eval/idle-timeout.ts +3 -10
  610. package/src/eval/js/context-manager.ts +108 -31
  611. package/src/eval/js/executor.ts +9 -2
  612. package/src/eval/js/index.ts +7 -3
  613. package/src/eval/js/shared/helpers.ts +59 -13
  614. package/src/eval/js/shared/local-module-loader.ts +2 -2
  615. package/src/eval/js/shared/prelude.txt +167 -30
  616. package/src/eval/js/shared/rewrite-imports.ts +58 -34
  617. package/src/eval/js/shared/runtime.ts +24 -16
  618. package/src/eval/js/tool-bridge.ts +4 -0
  619. package/src/eval/js/worker-core.ts +1 -0
  620. package/src/eval/js/worker-entry.ts +6 -0
  621. package/src/eval/js/worker-protocol.ts +6 -0
  622. package/src/eval/llm-bridge.ts +2 -1
  623. package/src/eval/py/__tests__/prelude.test.ts +19 -0
  624. package/src/eval/py/executor.ts +70 -26
  625. package/src/eval/py/index.ts +13 -4
  626. package/src/eval/py/kernel.ts +48 -9
  627. package/src/eval/py/prelude.py +73 -24
  628. package/src/eval/py/runner.py +133 -28
  629. package/src/eval/py/runtime.ts +38 -1
  630. package/src/exa/index.ts +1 -26
  631. package/src/exa/mcp-client.ts +10 -10
  632. package/src/exa/types.ts +0 -97
  633. package/src/exec/bash-executor.ts +104 -7
  634. package/src/export/custom-share.ts +1 -1
  635. package/src/export/html/index.ts +119 -17
  636. package/src/export/html/share-loader.js +102 -0
  637. package/src/export/html/template-js.ts +6 -0
  638. package/src/export/html/template.css +745 -459
  639. package/src/export/html/template.css.d.ts +2 -0
  640. package/src/export/html/template.html +6 -3
  641. package/src/export/html/template.js +277 -891
  642. package/src/export/html/tool-views.generated.d.ts +2 -0
  643. package/src/export/html/tool-views.generated.js +38 -0
  644. package/src/export/share.ts +269 -0
  645. package/src/export/ttsr.ts +122 -1
  646. package/src/extensibility/custom-commands/loader.ts +7 -4
  647. package/src/extensibility/custom-commands/types.ts +9 -4
  648. package/src/extensibility/custom-tools/loader.ts +51 -23
  649. package/src/extensibility/custom-tools/types.ts +16 -8
  650. package/src/extensibility/extensions/get-commands-handler.ts +2 -1
  651. package/src/extensibility/extensions/index.ts +1 -0
  652. package/src/extensibility/extensions/loader.ts +70 -20
  653. package/src/extensibility/extensions/model-api.ts +41 -0
  654. package/src/extensibility/extensions/runner.ts +12 -2
  655. package/src/extensibility/extensions/types.ts +83 -11
  656. package/src/extensibility/extensions/wrapper.ts +41 -5
  657. package/src/extensibility/hooks/index.ts +2 -1
  658. package/src/extensibility/hooks/loader.ts +6 -3
  659. package/src/extensibility/hooks/types.ts +11 -5
  660. package/src/extensibility/{legacy-pi-ai-shim.ts → legacy-package-ai-shim.ts} +2 -2
  661. package/src/extensibility/plugins/doctor.ts +1 -2
  662. package/src/extensibility/plugins/installer.ts +2 -2
  663. package/src/extensibility/plugins/{legacy-pi-compat.ts → legacy-package-compat.ts} +165 -77
  664. package/src/extensibility/plugins/loader.ts +34 -23
  665. package/src/extensibility/plugins/manager.ts +226 -95
  666. package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
  667. package/src/extensibility/plugins/types.ts +3 -3
  668. package/src/extensibility/shared-events.ts +3 -3
  669. package/src/extensibility/skills.ts +113 -9
  670. package/src/extensibility/slash-commands.ts +1 -97
  671. package/src/goals/guided-setup.ts +133 -0
  672. package/src/goals/state.ts +1 -1
  673. package/src/goals/tools/goal-tool.ts +38 -28
  674. package/src/hindsight/bank.ts +17 -2
  675. package/src/hindsight/client.ts +27 -2
  676. package/src/hindsight/mental-models.ts +59 -12
  677. package/src/hindsight/state.ts +12 -3
  678. package/src/hindsight/transcript.ts +1 -1
  679. package/src/index.ts +5 -0
  680. package/src/internal-urls/artifact-protocol.ts +11 -2
  681. package/src/internal-urls/docs-index.generated.ts +9 -7
  682. package/src/internal-urls/history-protocol.ts +113 -0
  683. package/src/internal-urls/index.ts +1 -0
  684. package/src/internal-urls/issue-pr-protocol.ts +22 -9
  685. package/src/internal-urls/local-protocol.ts +42 -7
  686. package/src/internal-urls/memory-protocol.ts +4 -31
  687. package/src/internal-urls/router.ts +3 -1
  688. package/src/internal-urls/types.ts +1 -1
  689. package/src/irc/bus.ts +303 -0
  690. package/src/lib/xai-http.ts +3 -3
  691. package/src/lsp/client.ts +245 -104
  692. package/src/lsp/clients/biome-client.ts +101 -39
  693. package/src/lsp/clients/lsp-linter-client.ts +2 -10
  694. package/src/lsp/config.ts +15 -5
  695. package/src/lsp/defaults.json +6 -0
  696. package/src/lsp/edits.ts +143 -95
  697. package/src/lsp/format-options.ts +119 -0
  698. package/src/lsp/index.ts +233 -93
  699. package/src/lsp/render.ts +11 -35
  700. package/src/lsp/types.ts +13 -1
  701. package/src/lsp/utils.ts +31 -12
  702. package/src/main.ts +396 -216
  703. package/src/mcp/config-writer.ts +7 -3
  704. package/src/mcp/json-rpc.ts +35 -5
  705. package/src/mcp/manager.ts +31 -16
  706. package/src/mcp/oauth-discovery.ts +34 -4
  707. package/src/mcp/oauth-flow.ts +61 -8
  708. package/src/mcp/render.ts +7 -1
  709. package/src/mcp/startup-events.ts +21 -0
  710. package/src/mcp/tool-bridge.ts +2 -0
  711. package/src/mcp/transports/stdio.ts +224 -4
  712. package/src/mcp/types.ts +2 -0
  713. package/src/memories/index.ts +174 -1128
  714. package/src/memories/storage.ts +2 -41
  715. package/src/memory-backend/index.ts +14 -1
  716. package/src/memory-backend/local-backend.ts +18 -3
  717. package/src/memory-backend/off-backend.ts +9 -0
  718. package/src/memory-backend/resolve.ts +4 -6
  719. package/src/memory-backend/runtime.ts +66 -0
  720. package/src/memory-backend/types.ts +82 -2
  721. package/src/mnemopi/backend.ts +220 -28
  722. package/src/mnemopi/config.ts +138 -33
  723. package/src/mnemopi/state.ts +91 -11
  724. package/src/modes/acp/acp-agent.ts +149 -142
  725. package/src/modes/acp/acp-event-mapper.ts +5 -1
  726. package/src/modes/components/agent-dashboard.ts +17 -11
  727. package/src/modes/components/agent-hub.ts +1346 -0
  728. package/src/modes/components/assistant-message.ts +190 -80
  729. package/src/modes/components/bash-execution.ts +1 -1
  730. package/src/modes/components/btw-panel.ts +5 -1
  731. package/src/modes/components/chat-block.ts +111 -0
  732. package/src/modes/components/collab-prompt-message.ts +30 -0
  733. package/src/modes/components/compaction-summary-message.ts +168 -33
  734. package/src/modes/components/copy-selector.ts +2 -45
  735. package/src/modes/components/custom-editor.test.ts +96 -0
  736. package/src/modes/components/custom-editor.ts +405 -118
  737. package/src/modes/components/custom-message.ts +1 -3
  738. package/src/modes/components/diff.ts +13 -2
  739. package/src/modes/components/dynamic-border.ts +12 -3
  740. package/src/modes/components/execution-shared.ts +1 -2
  741. package/src/modes/components/extensions/extension-dashboard.ts +8 -5
  742. package/src/modes/components/extensions/extension-list.ts +1 -1
  743. package/src/modes/components/extensions/inspector-panel.ts +7 -3
  744. package/src/modes/components/extensions/state-manager.ts +36 -41
  745. package/src/modes/components/footer.ts +4 -2
  746. package/src/modes/components/history-search.ts +1 -1
  747. package/src/modes/components/hook-editor.ts +8 -0
  748. package/src/modes/components/hook-input.ts +8 -0
  749. package/src/modes/components/hook-message.ts +1 -3
  750. package/src/modes/components/hook-selector.ts +6 -7
  751. package/src/modes/components/index.ts +1 -0
  752. package/src/modes/components/late-diagnostics-message.ts +60 -0
  753. package/src/modes/components/login-dialog.ts +1 -1
  754. package/src/modes/components/logout-account-selector.ts +130 -0
  755. package/src/modes/components/mcp-add-wizard.ts +14 -1
  756. package/src/modes/components/model-selector.ts +177 -75
  757. package/src/modes/components/oauth-selector.ts +102 -16
  758. package/src/modes/components/overlay-box.ts +108 -0
  759. package/src/modes/components/plan-review-overlay.ts +845 -0
  760. package/src/modes/components/plan-toc.ts +138 -0
  761. package/src/modes/components/plugin-settings.ts +22 -5
  762. package/src/modes/components/read-tool-group.ts +442 -39
  763. package/src/modes/components/reset-usage-selector.ts +161 -0
  764. package/src/modes/components/segment-track.ts +44 -7
  765. package/src/modes/components/session-selector.ts +97 -37
  766. package/src/modes/components/settings-defs.ts +28 -6
  767. package/src/modes/components/settings-selector.ts +541 -93
  768. package/src/modes/components/skill-message.ts +0 -1
  769. package/src/modes/components/snapcompact-shape-preview-doc.md +11 -0
  770. package/src/modes/components/snapcompact-shape-preview.ts +193 -0
  771. package/src/modes/components/{status-line.ts → status-line/component.ts} +205 -168
  772. package/src/modes/components/status-line/index.ts +1 -0
  773. package/src/modes/components/status-line/presets.ts +3 -3
  774. package/src/modes/components/status-line/segments.ts +26 -7
  775. package/src/modes/components/status-line/types.ts +40 -9
  776. package/src/modes/components/tiny-title-download-progress.ts +1 -1
  777. package/src/modes/components/tips.txt +7 -3
  778. package/src/modes/components/todo-reminder.ts +0 -2
  779. package/src/modes/components/tool-execution.ts +236 -103
  780. package/src/modes/components/transcript-container.ts +724 -99
  781. package/src/modes/components/tree-selector.ts +19 -4
  782. package/src/modes/components/ttsr-notification.ts +72 -30
  783. package/src/modes/components/usage-row.ts +18 -0
  784. package/src/modes/components/user-message-selector.ts +1 -1
  785. package/src/modes/components/user-message.ts +28 -12
  786. package/src/modes/components/visual-truncate.ts +1 -1
  787. package/src/modes/components/welcome.ts +80 -22
  788. package/src/modes/controllers/command-controller-shared.ts +7 -6
  789. package/src/modes/controllers/command-controller.ts +210 -180
  790. package/src/modes/controllers/event-controller.ts +352 -142
  791. package/src/modes/controllers/extension-ui-controller.ts +167 -208
  792. package/src/modes/controllers/input-controller.ts +778 -162
  793. package/src/modes/controllers/mcp-command-controller.ts +232 -80
  794. package/src/modes/controllers/selector-controller.ts +284 -145
  795. package/src/modes/controllers/session-focus-controller.ts +112 -0
  796. package/src/modes/controllers/ssh-command-controller.ts +2 -2
  797. package/src/modes/controllers/streaming-reveal.ts +295 -0
  798. package/src/modes/controllers/tan-command-controller.ts +173 -0
  799. package/src/modes/controllers/tool-args-reveal.ts +174 -0
  800. package/src/modes/gradient-highlight.ts +21 -9
  801. package/src/modes/image-references.ts +33 -7
  802. package/src/modes/index.ts +8 -25
  803. package/src/modes/interactive-mode.ts +840 -186
  804. package/src/modes/magic-keywords.ts +28 -6
  805. package/src/modes/markdown-prose.ts +1 -1
  806. package/src/modes/oauth-manual-input.ts +30 -3
  807. package/src/modes/rpc/rpc-client.ts +186 -3
  808. package/src/modes/rpc/rpc-mode.ts +318 -24
  809. package/src/modes/rpc/rpc-subagents.ts +265 -0
  810. package/src/modes/rpc/rpc-types.ts +111 -2
  811. package/src/modes/runtime-init.ts +28 -3
  812. package/src/modes/session-observer-registry.ts +72 -3
  813. package/src/modes/setup-version.ts +11 -0
  814. package/src/modes/setup-wizard/index.ts +16 -4
  815. package/src/modes/setup-wizard/lazy.ts +16 -0
  816. package/src/modes/setup-wizard/scenes/glyph.ts +25 -7
  817. package/src/modes/setup-wizard/scenes/providers.ts +45 -12
  818. package/src/modes/setup-wizard/scenes/sign-in.ts +14 -13
  819. package/src/modes/setup-wizard/scenes/splash.ts +1 -1
  820. package/src/modes/setup-wizard/scenes/theme.ts +29 -2
  821. package/src/modes/setup-wizard/scenes/types.ts +11 -2
  822. package/src/modes/setup-wizard/scenes/web-search.ts +26 -9
  823. package/src/modes/setup-wizard/wizard-overlay.ts +40 -3
  824. package/src/modes/shared.ts +2 -0
  825. package/src/modes/theme/defaults/dark-poimandres.json +1 -1
  826. package/src/modes/theme/defaults/light-poimandres.json +1 -1
  827. package/src/modes/theme/shimmer.ts +20 -9
  828. package/src/modes/theme/theme-schema.json +1 -1
  829. package/src/modes/theme/theme.ts +342 -82
  830. package/src/modes/types.ts +60 -18
  831. package/src/modes/utils/context-usage.ts +88 -8
  832. package/src/modes/utils/copy-targets.ts +133 -27
  833. package/src/modes/utils/hotkeys-markdown.ts +3 -2
  834. package/src/modes/utils/ui-helpers.ts +191 -110
  835. package/src/modes/workflow.ts +10 -10
  836. package/src/plan-mode/approved-plan.ts +66 -43
  837. package/src/plan-mode/plan-protection.ts +4 -4
  838. package/src/priority.json +5 -1
  839. package/src/prompts/agents/designer.md +1 -1
  840. package/src/prompts/agents/explore.md +3 -3
  841. package/src/prompts/agents/librarian.md +2 -3
  842. package/src/prompts/agents/oracle.md +2 -2
  843. package/src/prompts/agents/plan.md +6 -6
  844. package/src/prompts/agents/reviewer.md +1 -1
  845. package/src/prompts/agents/task.md +6 -5
  846. package/src/prompts/bench.md +12 -0
  847. package/src/prompts/ci-green-request.md +5 -7
  848. package/src/prompts/goals/goal-budget-limit.md +2 -2
  849. package/src/prompts/goals/goal-continuation.md +4 -4
  850. package/src/prompts/goals/goal-mode-active.md +1 -1
  851. package/src/prompts/goals/guided-goal-interview.md +8 -0
  852. package/src/prompts/goals/guided-goal-system.md +12 -0
  853. package/src/prompts/memories/consolidation.md +2 -7
  854. package/src/prompts/memories/consolidation_system.md +4 -0
  855. package/src/prompts/memories/identity_review.md +2 -2
  856. package/src/prompts/memories/read-path.md +11 -10
  857. package/src/prompts/memories/stage_one_system.md +2 -2
  858. package/src/prompts/review-custom-request.md +1 -1
  859. package/src/prompts/system/agent-creation-architect.md +2 -2
  860. package/src/prompts/system/auto-continue.md +1 -1
  861. package/src/prompts/system/autolearn-guidance-learn.md +1 -0
  862. package/src/prompts/system/autolearn-guidance.md +7 -0
  863. package/src/prompts/system/autolearn-nudge.md +3 -0
  864. package/src/prompts/system/background-tan-dispatch.md +8 -0
  865. package/src/prompts/system/btw-user.md +2 -2
  866. package/src/prompts/system/commit-message-system.md +13 -1
  867. package/src/prompts/system/custom-system-prompt.md +1 -1
  868. package/src/prompts/system/eager-task.md +7 -0
  869. package/src/prompts/system/eager-todo.md +11 -6
  870. package/src/prompts/system/empty-stop-retry.md +4 -6
  871. package/src/prompts/system/irc-autoreply.md +6 -0
  872. package/src/prompts/system/irc-incoming.md +3 -4
  873. package/src/prompts/system/manual-continue.md +7 -0
  874. package/src/prompts/system/omfg-user.md +3 -4
  875. package/src/prompts/system/orchestrate-notice.md +10 -10
  876. package/src/prompts/system/personalities/default.md +26 -0
  877. package/src/prompts/system/personalities/friendly.md +17 -0
  878. package/src/prompts/system/personalities/pragmatic.md +15 -0
  879. package/src/prompts/system/plan-mode-active.md +70 -77
  880. package/src/prompts/system/plan-mode-approved.md +1 -1
  881. package/src/prompts/system/plan-mode-subagent.md +4 -5
  882. package/src/prompts/system/plan-mode-tool-decision-reminder.md +1 -1
  883. package/src/prompts/system/project-prompt.md +2 -2
  884. package/src/prompts/system/snapcompact-context-frames-note.md +1 -0
  885. package/src/prompts/system/snapcompact-context-stub.md +1 -0
  886. package/src/prompts/system/snapcompact-system-frames-note.md +1 -0
  887. package/src/prompts/system/snapcompact-system-stub.md +1 -0
  888. package/src/prompts/system/snapcompact-toolresult-note.md +1 -0
  889. package/src/prompts/system/subagent-system-prompt.md +7 -8
  890. package/src/prompts/system/system-prompt.md +28 -57
  891. package/src/prompts/system/tiny-title-system.md +1 -1
  892. package/src/prompts/system/title-marker-instruction.md +1 -0
  893. package/src/prompts/system/title-system-marker.md +16 -0
  894. package/src/prompts/system/title-system.md +16 -3
  895. package/src/prompts/system/ttsr-tool-reminder.md +1 -1
  896. package/src/prompts/system/workflow-notice.md +4 -4
  897. package/src/prompts/tools/ast-edit.md +1 -1
  898. package/src/prompts/tools/ast-grep.md +2 -2
  899. package/src/prompts/tools/bash.md +16 -8
  900. package/src/prompts/tools/browser.md +33 -43
  901. package/src/prompts/tools/debug.md +1 -1
  902. package/src/prompts/tools/eval.md +31 -51
  903. package/src/prompts/tools/find.md +0 -1
  904. package/src/prompts/tools/github.md +8 -7
  905. package/src/prompts/tools/goal.md +1 -1
  906. package/src/prompts/tools/image-gen.md +1 -1
  907. package/src/prompts/tools/inspect-image-system.md +1 -1
  908. package/src/prompts/tools/irc.md +39 -31
  909. package/src/prompts/tools/job.md +2 -1
  910. package/src/prompts/tools/learn.md +7 -0
  911. package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
  912. package/src/prompts/tools/lsp.md +2 -2
  913. package/src/prompts/tools/manage-skill.md +9 -0
  914. package/src/prompts/tools/memory-edit.md +1 -1
  915. package/src/prompts/tools/patch.md +2 -2
  916. package/src/prompts/tools/read.md +31 -39
  917. package/src/prompts/tools/recall.md +1 -1
  918. package/src/prompts/tools/reflect.md +1 -1
  919. package/src/prompts/tools/render-mermaid.md +2 -2
  920. package/src/prompts/tools/replace.md +4 -10
  921. package/src/prompts/tools/rewind.md +2 -2
  922. package/src/prompts/tools/search-tool-bm25.md +1 -9
  923. package/src/prompts/tools/search.md +0 -1
  924. package/src/prompts/tools/ssh.md +0 -4
  925. package/src/prompts/tools/task-summary.md +5 -16
  926. package/src/prompts/tools/task.md +47 -31
  927. package/src/prompts/tools/todo.md +6 -3
  928. package/src/registry/agent-lifecycle.ts +218 -0
  929. package/src/registry/agent-registry.ts +46 -5
  930. package/src/sdk.ts +692 -219
  931. package/src/secrets/index.ts +8 -1
  932. package/src/secrets/obfuscator.ts +40 -19
  933. package/src/session/agent-session.ts +1577 -806
  934. package/src/session/agent-storage.ts +18 -9
  935. package/src/session/auth-broker-config.ts +30 -1
  936. package/src/session/auth-storage.ts +6 -0
  937. package/src/session/codex-auto-reset.ts +202 -0
  938. package/src/session/history-storage.ts +3 -2
  939. package/src/session/indexed-session-storage.ts +7 -10
  940. package/src/session/messages.ts +59 -95
  941. package/src/session/session-context.ts +352 -0
  942. package/src/session/session-dump-format.ts +12 -3
  943. package/src/session/session-entries.ts +194 -0
  944. package/src/session/session-history-format.ts +246 -0
  945. package/src/session/session-listing.ts +588 -0
  946. package/src/session/session-loader.ts +106 -0
  947. package/src/session/session-manager.ts +1003 -2920
  948. package/src/session/session-migrations.ts +78 -0
  949. package/src/session/session-paths.ts +193 -0
  950. package/src/session/session-persistence.ts +131 -0
  951. package/src/session/session-storage.ts +91 -30
  952. package/src/session/snapcompact-inline.ts +542 -0
  953. package/src/session/snapcompact-savings-journal.ts +113 -0
  954. package/src/session/streaming-output.ts +248 -11
  955. package/src/session/tool-choice-queue.ts +23 -11
  956. package/src/session/yield-queue.ts +20 -2
  957. package/src/slash-commands/acp-builtins.ts +25 -1
  958. package/src/slash-commands/available-commands.ts +105 -0
  959. package/src/slash-commands/builtin-registry.ts +575 -49
  960. package/src/slash-commands/helpers/active-oauth-account.ts +44 -0
  961. package/src/slash-commands/helpers/context-report.ts +28 -1
  962. package/src/slash-commands/helpers/logout.ts +88 -0
  963. package/src/slash-commands/helpers/reset-usage.ts +66 -0
  964. package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
  965. package/src/slash-commands/helpers/usage-report.ts +38 -3
  966. package/src/slash-commands/types.ts +5 -9
  967. package/src/ssh/connection-manager.ts +27 -0
  968. package/src/ssh/ssh-executor.ts +60 -4
  969. package/src/stt/asr-client.ts +520 -0
  970. package/src/stt/asr-protocol.ts +65 -0
  971. package/src/stt/asr-worker.ts +790 -0
  972. package/src/stt/downloader.ts +107 -47
  973. package/src/stt/endpointer.ts +259 -0
  974. package/src/stt/index.ts +5 -1
  975. package/src/stt/models.ts +150 -0
  976. package/src/stt/recorder.ts +254 -67
  977. package/src/stt/stt-controller.ts +201 -22
  978. package/src/stt/transcriber.ts +37 -68
  979. package/src/stt/wav.ts +173 -0
  980. package/src/system-prompt.ts +52 -10
  981. package/src/task/agents.ts +3 -4
  982. package/src/task/commands.ts +3 -2
  983. package/src/task/discovery.ts +17 -24
  984. package/src/task/executor.ts +1054 -529
  985. package/src/task/index.ts +862 -757
  986. package/src/task/output-manager.ts +0 -11
  987. package/src/task/parallel.ts +3 -3
  988. package/src/task/prometheus-command.ts +2 -2
  989. package/src/task/render.ts +529 -182
  990. package/src/task/repair-args.ts +21 -9
  991. package/src/task/types.ts +144 -66
  992. package/src/task/worktree.ts +64 -56
  993. package/src/telemetry-export.ts +27 -9
  994. package/src/thinking.ts +9 -7
  995. package/src/tiny/models.ts +2 -2
  996. package/src/tiny/text.ts +5 -1
  997. package/src/tiny/title-client.ts +72 -20
  998. package/src/tiny/title-protocol.ts +1 -1
  999. package/src/tiny/worker.ts +23 -99
  1000. package/src/tool-discovery/tool-index.ts +2 -0
  1001. package/src/tools/archive-reader.ts +94 -2
  1002. package/src/tools/ask.ts +234 -177
  1003. package/src/tools/ast-edit.ts +136 -80
  1004. package/src/tools/ast-grep.ts +41 -45
  1005. package/src/tools/auto-generated-guard.ts +20 -3
  1006. package/src/tools/bash-interactive.ts +28 -8
  1007. package/src/tools/bash.ts +198 -35
  1008. package/src/tools/browser/attach.ts +26 -7
  1009. package/src/tools/browser/cmux/cmux-tab.ts +1264 -0
  1010. package/src/tools/browser/cmux/rpc.ts +156 -0
  1011. package/src/tools/browser/cmux/socket-client.ts +309 -0
  1012. package/src/tools/browser/launch.ts +11 -2
  1013. package/src/tools/browser/readable.ts +19 -2
  1014. package/src/tools/browser/registry.ts +52 -5
  1015. package/src/tools/browser/render.ts +13 -5
  1016. package/src/tools/browser/tab-protocol.ts +2 -0
  1017. package/src/tools/browser/tab-supervisor.ts +256 -34
  1018. package/src/tools/browser/tab-worker.ts +259 -91
  1019. package/src/tools/browser.ts +44 -2
  1020. package/src/tools/checkpoint.ts +1 -1
  1021. package/src/tools/conflict-detect.ts +50 -4
  1022. package/src/tools/debug.ts +27 -12
  1023. package/src/tools/eval-render.ts +32 -35
  1024. package/src/tools/eval.ts +26 -12
  1025. package/src/tools/fetch.ts +450 -99
  1026. package/src/tools/find.ts +182 -142
  1027. package/src/tools/gh-cache-invalidation.ts +255 -0
  1028. package/src/tools/gh-renderer.ts +104 -51
  1029. package/src/tools/gh.ts +232 -37
  1030. package/src/tools/github-cache.ts +97 -7
  1031. package/src/tools/grouped-file-output.ts +159 -52
  1032. package/src/tools/image-gen.ts +237 -132
  1033. package/src/tools/index.ts +147 -26
  1034. package/src/tools/inspect-image-renderer.ts +74 -45
  1035. package/src/tools/inspect-image.ts +12 -6
  1036. package/src/tools/irc.ts +626 -173
  1037. package/src/tools/job.ts +106 -29
  1038. package/src/tools/learn.ts +144 -0
  1039. package/src/tools/manage-skill.ts +104 -0
  1040. package/src/tools/memory-edit.ts +4 -4
  1041. package/src/tools/memory-recall.ts +7 -9
  1042. package/src/tools/memory-reflect.ts +5 -9
  1043. package/src/tools/memory-render.ts +23 -6
  1044. package/src/tools/memory-retain.ts +4 -4
  1045. package/src/tools/path-utils.ts +102 -48
  1046. package/src/tools/plan-mode-guard.ts +101 -40
  1047. package/src/tools/read.ts +475 -120
  1048. package/src/tools/render-mermaid.ts +1 -1
  1049. package/src/tools/render-utils.ts +132 -76
  1050. package/src/tools/renderers.ts +12 -1
  1051. package/src/tools/report-tool-issue.ts +14 -6
  1052. package/src/tools/resolve.ts +20 -3
  1053. package/src/tools/review.ts +2 -2
  1054. package/src/tools/search-tool-bm25.ts +37 -24
  1055. package/src/tools/search.ts +233 -115
  1056. package/src/tools/sqlite-reader.ts +26 -17
  1057. package/src/tools/ssh.ts +20 -14
  1058. package/src/tools/todo.ts +197 -191
  1059. package/src/tools/tool-result.ts +8 -0
  1060. package/src/tools/tool-timeouts.ts +1 -1
  1061. package/src/tools/tts.ts +205 -74
  1062. package/src/tools/write.ts +291 -155
  1063. package/src/tools/yield.ts +10 -1
  1064. package/src/tts/downloader.ts +64 -0
  1065. package/src/tts/index.ts +8 -0
  1066. package/src/tts/models.ts +137 -0
  1067. package/src/tts/player.ts +137 -0
  1068. package/src/tts/runtime.ts +21 -0
  1069. package/src/tts/streaming-player.ts +266 -0
  1070. package/src/tts/tts-client.ts +647 -0
  1071. package/src/tts/tts-protocol.ts +60 -0
  1072. package/src/tts/tts-worker.ts +505 -0
  1073. package/src/tts/vocalizer.ts +162 -0
  1074. package/src/tts/wav.ts +58 -0
  1075. package/src/tui/code-cell.ts +2 -7
  1076. package/src/tui/hyperlink.ts +40 -26
  1077. package/src/tui/output-block.ts +60 -108
  1078. package/src/tui/status-line.ts +5 -1
  1079. package/src/utils/block-context.ts +312 -0
  1080. package/src/utils/changelog.ts +27 -1
  1081. package/src/utils/clipboard.ts +91 -22
  1082. package/src/utils/commit-message-generator.ts +8 -3
  1083. package/src/utils/enhanced-paste.ts +230 -0
  1084. package/src/utils/file-mentions.ts +3 -1
  1085. package/src/utils/git.ts +315 -15
  1086. package/src/utils/image-loading.ts +65 -4
  1087. package/src/utils/session-color.ts +83 -9
  1088. package/src/utils/thinking-display.ts +37 -0
  1089. package/src/utils/title-generator.ts +73 -10
  1090. package/src/utils/tool-choice.ts +16 -0
  1091. package/src/utils/tools-manager.ts +19 -1
  1092. package/src/web/kagi.ts +28 -26
  1093. package/src/web/parallel.ts +7 -3
  1094. package/src/web/scrapers/arxiv.ts +1 -1
  1095. package/src/web/scrapers/github.ts +351 -3
  1096. package/src/web/scrapers/go-pkg.ts +1 -1
  1097. package/src/web/scrapers/iacr.ts +1 -1
  1098. package/src/web/scrapers/readthedocs.ts +1 -1
  1099. package/src/web/scrapers/twitter.ts +2 -1
  1100. package/src/web/scrapers/types.ts +87 -8
  1101. package/src/web/scrapers/wikipedia.ts +1 -1
  1102. package/src/web/scrapers/youtube.ts +9 -3
  1103. package/src/web/search/index.ts +15 -2
  1104. package/src/web/search/providers/anthropic.ts +62 -21
  1105. package/src/web/search/providers/base.ts +2 -1
  1106. package/src/web/search/providers/brave.ts +5 -2
  1107. package/src/web/search/providers/codex.ts +87 -51
  1108. package/src/web/search/providers/exa.ts +101 -10
  1109. package/src/web/search/providers/gemini.ts +49 -24
  1110. package/src/web/search/providers/jina.ts +15 -5
  1111. package/src/web/search/providers/kagi.ts +9 -2
  1112. package/src/web/search/providers/kimi.ts +45 -20
  1113. package/src/web/search/providers/parallel.ts +39 -24
  1114. package/src/web/search/providers/perplexity.ts +226 -63
  1115. package/src/web/search/providers/searxng.ts +19 -3
  1116. package/src/web/search/providers/synthetic.ts +16 -11
  1117. package/src/web/search/providers/tavily.ts +12 -9
  1118. package/src/web/search/providers/zai.ts +22 -9
  1119. package/src/web/search/render.ts +59 -64
  1120. package/src/web/search/types.ts +5 -1
  1121. package/dist/types/discovery/context-files.d.ts +0 -17
  1122. package/dist/types/exa/factory.d.ts +0 -13
  1123. package/dist/types/exa/render.d.ts +0 -19
  1124. package/dist/types/exa/researcher.d.ts +0 -9
  1125. package/dist/types/exa/search.d.ts +0 -9
  1126. package/dist/types/exa/websets.d.ts +0 -9
  1127. package/dist/types/export/html/template.generated.d.ts +0 -1
  1128. package/dist/types/modes/components/session-observer-overlay.d.ts +0 -11
  1129. package/dist/types/modes/components/status-line.d.ts +0 -77
  1130. package/dist/types/slash-commands/headless-plan.d.ts +0 -3
  1131. package/dist/types/stt/setup.d.ts +0 -18
  1132. package/scripts/generate-template.ts +0 -33
  1133. package/src/discovery/context-files.ts +0 -49
  1134. package/src/exa/factory.ts +0 -60
  1135. package/src/exa/render.ts +0 -244
  1136. package/src/exa/researcher.ts +0 -36
  1137. package/src/exa/search.ts +0 -47
  1138. package/src/exa/websets.ts +0 -248
  1139. package/src/export/html/template.generated.ts +0 -2
  1140. package/src/modes/components/session-observer-overlay.ts +0 -852
  1141. package/src/slash-commands/headless-plan.ts +0 -142
  1142. package/src/stt/setup.ts +0 -52
  1143. package/src/stt/transcribe.py +0 -70
  1144. /package/dist/types/extensibility/{legacy-pi-coding-agent-shim.d.ts → legacy-package-agent-shim.d.ts} +0 -0
  1145. /package/src/extensibility/{legacy-pi-coding-agent-shim.ts → legacy-package-agent-shim.ts} +0 -0
@@ -2,6 +2,7 @@
2
2
  * Interactive mode for the coding agent.
3
3
  * Handles TUI rendering and user interaction, delegating business logic to AgentSession.
4
4
  */
5
+
5
6
  import * as fs from "node:fs/promises";
6
7
  import * as path from "node:path";
7
8
  import {
@@ -12,15 +13,16 @@ import {
12
13
  ThinkingLevel,
13
14
  } from "@prometheus-ai/agent-core";
14
15
  import type { CompactionOutcome } from "@prometheus-ai/agent-core/compaction";
15
- import {
16
- type AssistantMessage,
17
- type ImageContent,
18
- type Message,
19
- type Model,
20
- modelsAreEqual,
21
- type UsageReport,
22
- } from "@prometheus-ai/ai";
23
- import type { Component, EditorTheme, SlashCommand } from "@prometheus-ai/tui";
16
+ import type { AssistantMessage, ImageContent, Message, Model, UsageReport } from "@prometheus-ai/ai";
17
+ import { modelsAreEqual } from "@prometheus-ai/catalog/models";
18
+ import type {
19
+ Component,
20
+ EditorTheme,
21
+ LoaderMessageColorFn,
22
+ NativeScrollbackLiveRegion,
23
+ OverlayHandle,
24
+ SlashCommand,
25
+ } from "@prometheus-ai/tui";
24
26
  import {
25
27
  Container,
26
28
  clearRenderCache,
@@ -48,9 +50,10 @@ import {
48
50
  } from "@prometheus-ai/utils";
49
51
  import chalk from "chalk";
50
52
  import { reset as resetCapabilities } from "../capability";
53
+ import type { CollabGuestLink } from "../collab/guest";
54
+ import type { CollabHost } from "../collab/host";
51
55
  import { KeybindingsManager } from "../config/keybindings";
52
- import { MODEL_ROLES, type ModelRole } from "../config/model-registry";
53
- import { isSettingsInitialized, Settings, settings } from "../config/settings";
56
+ import { isSettingsInitialized, onStatusLineSessionAccentChanged, Settings, settings } from "../config/settings";
54
57
  import { clearClaudePluginRootsCache } from "../discovery/helpers";
55
58
  import type {
56
59
  ContextUsage,
@@ -61,14 +64,17 @@ import type {
61
64
  ExtensionWidgetOptions,
62
65
  } from "../extensibility/extensions";
63
66
  import type { CompactOptions } from "../extensibility/extensions/types";
64
- import { BUILTIN_SLASH_COMMANDS, loadSlashCommands } from "../extensibility/slash-commands";
67
+ import { loadSlashCommands } from "../extensibility/slash-commands";
68
+ import { type GuidedGoalMessage, runGuidedGoalTurn } from "../goals/guided-setup";
65
69
  import type { Goal, GoalModeState } from "../goals/state";
66
70
  import { resolveLocalUrlToPath } from "../internal-urls";
67
71
  import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "../lsp/startup-events";
72
+ import type { MCPManager } from "../mcp";
73
+ import { formatMCPConnectingMessage, isMcpConnectingEvent, MCP_CONNECTING_EVENT_CHANNEL } from "../mcp/startup-events";
68
74
  import {
69
75
  humanizePlanTitle,
70
76
  type PlanApprovalDetails,
71
- renameApprovedPlanFile,
77
+ resolveApprovedPlan,
72
78
  resolvePlanTitle,
73
79
  } from "../plan-mode/approved-plan";
74
80
  import planModeApprovedPrompt from "../prompts/system/plan-mode-approved.md" with { type: "text" };
@@ -77,23 +83,30 @@ import planModeCompactInstructionsPrompt from "../prompts/system/plan-mode-compa
77
83
  };
78
84
  import type { AgentSession, AgentSessionEvent, ResolvedRoleModel } from "../session/agent-session";
79
85
  import { HistoryStorage } from "../session/history-storage";
80
- import type { SessionContext, SessionManager } from "../session/session-manager";
81
- import { getRecentSessions } from "../session/session-manager";
86
+ import type { SessionContext } from "../session/session-context";
87
+ import { getRecentSessions } from "../session/session-listing";
88
+ import type { SessionManager } from "../session/session-manager";
82
89
  import type { ShakeMode } from "../session/shake-types";
90
+ import { BUILTIN_SLASH_COMMAND_RESERVED_NAMES, BUILTIN_SLASH_COMMANDS } from "../slash-commands/builtin-registry";
83
91
  import { formatDuration } from "../slash-commands/helpers/format";
84
92
  import { STTController, type SttState } from "../stt";
93
+ import { discoverTitleSystemPromptFile, resolvePromptInput } from "../system-prompt";
94
+ import { formatTaskId } from "../task/render";
85
95
  import type { LspStartupServerInfo } from "../tools";
86
96
  import { normalizeLocalScheme } from "../tools/path-utils";
97
+ import { replaceTabs, TRUNCATE_LENGTHS, truncateToWidth } from "../tools/render-utils";
87
98
  import { setAutoQaConsentHandler } from "../tools/report-tool-issue";
88
99
  import { type ResolveToolDetails, runResolveInvocation } from "../tools/resolve";
89
100
  import { formatPhaseDisplayName, selectStickyTodoWindow, todoMatchesAnyDescription } from "../tools/todo";
90
101
  import { ToolError } from "../tools/tool-errors";
102
+ import { vocalizer } from "../tts/vocalizer";
91
103
  import type { EventBus } from "../utils/event-bus";
92
104
  import { getEditorCommand, openInEditor } from "../utils/external-editor";
93
105
  import { getSessionAccentAnsi, getSessionAccentHex } from "../utils/session-color";
94
106
  import { popTerminalTitle, pushTerminalTitle, setSessionTerminalTitle } from "../utils/title-generator";
95
107
  import type { AssistantMessageComponent } from "./components/assistant-message";
96
108
  import type { BashExecutionComponent } from "./components/bash-execution";
109
+ import { ChatBlock, type ChatBlockHost } from "./components/chat-block";
97
110
  import { CustomEditor } from "./components/custom-editor";
98
111
  import { DynamicBorder } from "./components/dynamic-border";
99
112
  import { ErrorBannerComponent } from "./components/error-banner";
@@ -101,6 +114,7 @@ import type { EvalExecutionComponent } from "./components/eval-execution";
101
114
  import type { HookEditorComponent } from "./components/hook-editor";
102
115
  import type { HookInputComponent } from "./components/hook-input";
103
116
  import type { HookSelectorComponent, HookSelectorSlider } from "./components/hook-selector";
117
+ import { PlanReviewOverlay } from "./components/plan-review-overlay";
104
118
  import { StatusLineComponent } from "./components/status-line";
105
119
  import type { ToolExecutionHandle } from "./components/tool-execution";
106
120
  import { TranscriptContainer } from "./components/transcript-container";
@@ -113,7 +127,9 @@ import { InputController } from "./controllers/input-controller";
113
127
  import { MCPCommandController } from "./controllers/mcp-command-controller";
114
128
  import { OmfgController } from "./controllers/omfg-controller";
115
129
  import { SelectorController } from "./controllers/selector-controller";
130
+ import { SessionFocusController } from "./controllers/session-focus-controller";
116
131
  import { SSHCommandController } from "./controllers/ssh-command-controller";
132
+ import { TanCommandController } from "./controllers/tan-command-controller";
117
133
  import { TodoCommandController } from "./controllers/todo-command-controller";
118
134
  import {
119
135
  consumeLoopLimitIteration,
@@ -125,9 +141,11 @@ import {
125
141
  parseLoopLimitArgs,
126
142
  } from "./loop-limit";
127
143
  import { OAuthManualInputManager } from "./oauth-manual-input";
144
+ import type { ObservableSession } from "./session-observer-registry";
128
145
  import { SessionObserverRegistry } from "./session-observer-registry";
146
+ import { runProviderSetupWizard } from "./setup-wizard/lazy";
129
147
  import { interruptHint } from "./shared";
130
- import { type ShimmerPalette, shimmerSegments, shimmerText } from "./theme/shimmer";
148
+ import { type ShimmerPalette, shimmerEnabled, shimmerSegments, shimmerText } from "./theme/shimmer";
131
149
  import type { Theme } from "./theme/theme";
132
150
  import {
133
151
  getEditorTheme,
@@ -159,6 +177,12 @@ interface WorkingMessageAccent {
159
177
  dim: string;
160
178
  }
161
179
 
180
+ interface WorkingMessageAccentCacheKey {
181
+ sessionName: string | undefined;
182
+ accentSurfaceLuminance: number | undefined;
183
+ sessionAccentEnabled: boolean;
184
+ }
185
+
162
186
  function renderWorkingMessage(message: string, accent?: WorkingMessageAccent): string {
163
187
  const palette = accent
164
188
  ? ({
@@ -191,6 +215,25 @@ const EDITOR_MAX_HEIGHT_MIN = 6;
191
215
  const EDITOR_MAX_HEIGHT_MAX = 18;
192
216
  const EDITOR_RESERVED_ROWS = 12;
193
217
  const EDITOR_FALLBACK_ROWS = 24;
218
+ const EDITOR_MIN_CHROME_ROWS = 4; // rows reserved for transcript + status on small terms
219
+ const EDITOR_MIN_RENDERED_ROWS = 3; // bordered editor floor: top+bottom border + 1 content row
220
+
221
+ /**
222
+ * Editor max-height cap for a terminal of `terminalRows` rows.
223
+ *
224
+ * Roomy terminals get the comfortable [6, 18] band. Small terminals shrink the
225
+ * cap so the editor leaves at least EDITOR_MIN_CHROME_ROWS rows for the
226
+ * transcript + status line. The editor is bordered, so it never renders fewer
227
+ * than EDITOR_MIN_RENDERED_ROWS rows; once the terminal is too small for both
228
+ * (terminalRows < EDITOR_MIN_RENDERED_ROWS + EDITOR_MIN_CHROME_ROWS) the cap is
229
+ * pinned to that floor — returning a smaller number would not shrink the editor
230
+ * any further, it would only misreport the rows it actually occupies.
231
+ */
232
+ export function computeEditorMaxHeight(terminalRows: number): number {
233
+ const rows = Number.isFinite(terminalRows) && terminalRows > 0 ? terminalRows : EDITOR_FALLBACK_ROWS;
234
+ const comfortable = Math.max(EDITOR_MAX_HEIGHT_MIN, Math.min(EDITOR_MAX_HEIGHT_MAX, rows - EDITOR_RESERVED_ROWS));
235
+ return Math.max(EDITOR_MIN_RENDERED_ROWS, Math.min(comfortable, rows - EDITOR_MIN_CHROME_ROWS));
236
+ }
194
237
 
195
238
  const HUD_NOTE_SUP_DIGITS: Record<string, string> = {
196
239
  "0": "\u2070",
@@ -250,6 +293,63 @@ export interface InteractiveModeOptions {
250
293
  initialMessages?: string[];
251
294
  }
252
295
 
296
+ /**
297
+ * Hosts the working loader and transient status rows. While anything is
298
+ * mounted, every row is live: report a seam at 0 so the engine never commits
299
+ * a still-animating loader to native scrollback (stale `Working…` rows would
300
+ * otherwise pile up above the live one). The transcript's own seam, when
301
+ * present, sits higher and wins (topmost-seam merge in TUI.render).
302
+ */
303
+ class StatusContainer extends Container implements NativeScrollbackLiveRegion {
304
+ getNativeScrollbackLiveRegionStart(): number | undefined {
305
+ return this.children.length > 0 ? 0 : undefined;
306
+ }
307
+ }
308
+
309
+ /** How long the ctrl+p model-role cycle chip track lingers above the editor
310
+ * before it auto-clears, mirroring the todo HUD's auto-clear timer. */
311
+ const MODEL_CYCLE_TRACK_CLEAR_MS = 4000;
312
+
313
+ /**
314
+ * Build the anchored subagent HUD block: a bold accent "Subagents" header plus
315
+ * one hooked row per running agent in the same `Id: description` shape the
316
+ * inline task rows use (muted task preview when no description was given).
317
+ * Only detached background spawns are listed: a sync task call blocks the
318
+ * parent turn and its inline tool block already renders progress live, and
319
+ * eval `agent()` spawns are rendered by their own eval cell tree.
320
+ * Returns an empty array when nothing is running so the container can clear.
321
+ */
322
+ export function renderSubagentHudLines(sessions: ObservableSession[], columns: number): string[] {
323
+ const running = sessions.filter(
324
+ session => session.kind === "subagent" && session.status === "active" && session.detached === true,
325
+ );
326
+ if (running.length === 0) return [];
327
+
328
+ const indent = " ";
329
+ const hook = theme.tree.hook;
330
+ const dot = theme.styledSymbol("status.done", "accent");
331
+ const lines = ["", indent + theme.bold(theme.fg("accent", "Subagents"))];
332
+ running.forEach((session, index) => {
333
+ const prefix = `${indent}${index === 0 ? hook : " "} `;
334
+ const displayId = formatTaskId(session.id);
335
+ let line = `${prefix}${dot} ${theme.fg("accent", theme.bold(displayId))}`;
336
+ const description = session.description?.trim() || session.progress?.description?.trim();
337
+ if (description) {
338
+ const budget = Math.max(TRUNCATE_LENGTHS.SHORT, columns - visibleWidth(prefix) - visibleWidth(displayId) - 6);
339
+ line += `${theme.fg("accent", ":")} ${theme.fg("accent", truncateToWidth(replaceTabs(description), budget))}`;
340
+ } else {
341
+ // No spawn description: fall back to a muted task preview, same as
342
+ // the inline task rows when a row has no label.
343
+ const taskPreview = session.progress?.task?.trim();
344
+ if (taskPreview) {
345
+ line += ` ${theme.fg("muted", truncateToWidth(replaceTabs(taskPreview), TRUNCATE_LENGTHS.SHORT))}`;
346
+ }
347
+ }
348
+ lines.push(line);
349
+ });
350
+ return lines;
351
+ }
352
+
253
353
  export class InteractiveMode implements InteractiveModeContext {
254
354
  session: AgentSession;
255
355
  sessionManager: SessionManager;
@@ -257,15 +357,18 @@ export class InteractiveMode implements InteractiveModeContext {
257
357
  keybindings: KeybindingsManager;
258
358
  agent: Agent;
259
359
  historyStorage?: HistoryStorage;
360
+ titleSystemPrompt?: string;
260
361
 
261
362
  ui: TUI;
262
363
  chatContainer: TranscriptContainer;
263
364
  pendingMessagesContainer: Container;
264
365
  statusContainer: Container;
265
366
  todoContainer: Container;
367
+ subagentContainer: Container;
266
368
  btwContainer: Container;
267
369
  omfgContainer: Container;
268
370
  errorBannerContainer: Container;
371
+ modelCycleContainer: Container;
269
372
  editor: CustomEditor;
270
373
  editorContainer: Container;
271
374
  hookWidgetContainerAbove: Container;
@@ -273,7 +376,6 @@ export class InteractiveMode implements InteractiveModeContext {
273
376
  statusLine: StatusLineComponent;
274
377
 
275
378
  isInitialized = false;
276
- isBackgrounded = false;
277
379
  isBashMode = false;
278
380
  toolOutputExpanded = false;
279
381
  todoExpanded = false;
@@ -287,6 +389,7 @@ export class InteractiveMode implements InteractiveModeContext {
287
389
  loopLimit: LoopLimitRuntime | undefined = undefined;
288
390
  #loopAutoSubmitTimer: NodeJS.Timeout | undefined;
289
391
  #todoAutoClearTimer: NodeJS.Timeout | undefined;
392
+ #modelCycleClearTimer: NodeJS.Timeout | undefined;
290
393
  todoPhases: TodoPhase[] = [];
291
394
  hideThinkingBlock = false;
292
395
  pendingImages: ImageContent[] = [];
@@ -304,11 +407,12 @@ export class InteractiveMode implements InteractiveModeContext {
304
407
  autoCompactionLoader: Loader | undefined = undefined;
305
408
  retryLoader: Loader | undefined = undefined;
306
409
  #pendingWorkingMessage: string | undefined;
410
+ #workingMessageAccentCacheKey?: WorkingMessageAccentCacheKey;
411
+ #workingMessageAccentCacheValue?: WorkingMessageAccent;
412
+ #workingMessageAccentCacheHasValue = false;
307
413
  get #defaultWorkingMessage(): string {
308
414
  return `Working…${interruptHint()}`;
309
415
  }
310
- autoCompactionEscapeHandler?: () => void;
311
- retryEscapeHandler?: () => void;
312
416
  unsubscribe?: () => void;
313
417
  onInputCallback?: (input: SubmittedUserInput) => void;
314
418
  optimisticUserMessageSignature: string | undefined = undefined;
@@ -317,6 +421,7 @@ export class InteractiveMode implements InteractiveModeContext {
317
421
  #pendingSubmissionDispose: (() => void) | undefined;
318
422
  lastSigintTime = 0;
319
423
  lastEscapeTime = 0;
424
+ lastLeftTapTime = 0;
320
425
  shutdownRequested = false;
321
426
  #isShuttingDown = false;
322
427
  hookSelector: HookSelectorComponent | undefined = undefined;
@@ -327,6 +432,8 @@ export class InteractiveMode implements InteractiveModeContext {
327
432
  fileSlashCommands: Set<string> = new Set();
328
433
  skillCommands: Map<string, string> = new Map();
329
434
  oauthManualInput: OAuthManualInputManager = new OAuthManualInputManager();
435
+ collabHost?: CollabHost;
436
+ collabGuest?: CollabGuestLink;
330
437
 
331
438
  #pendingSlashCommands: SlashCommand[] = [];
332
439
  #cleanupUnsubscribe?: () => void;
@@ -341,19 +448,57 @@ export class InteractiveMode implements InteractiveModeContext {
341
448
  #planModePreviousModelState: { model: Model; thinkingLevel?: ThinkingLevel } | undefined;
342
449
  #pendingModelSwitch: { model: Model; thinkingLevel?: ThinkingLevel } | undefined;
343
450
  #planModeHasEntered = false;
344
- #planReviewContainer: Container | undefined;
451
+ #planReviewOverlay: PlanReviewOverlay | undefined;
452
+ #planReviewOverlayHandle: OverlayHandle | undefined;
345
453
  readonly lspServers: LspStartupServerInfo[] | undefined = undefined;
346
- mcpManager?: import("../mcp").MCPManager;
454
+ mcpManager?: MCPManager;
347
455
  readonly #toolUiContextSetter: (uiContext: ExtensionUIContext, hasUI: boolean) => void;
348
456
 
349
457
  readonly #btwController: BtwController;
458
+ readonly #tanCommandController: TanCommandController;
350
459
  readonly #omfgController: OmfgController;
351
460
  readonly #commandController: CommandController;
352
461
  readonly #todoCommandController: TodoCommandController;
353
462
  readonly #eventController: EventController;
463
+ get eventController(): EventController {
464
+ return this.#eventController;
465
+ }
466
+ get eventBus(): EventBus | undefined {
467
+ return this.#eventBus;
468
+ }
354
469
  readonly #extensionUiController: ExtensionUiController;
355
470
  readonly #inputController: InputController;
356
471
  readonly #selectorController: SelectorController;
472
+ readonly #focusController: SessionFocusController;
473
+ get viewSession(): AgentSession {
474
+ return this.#focusController.target ?? this.session;
475
+ }
476
+ get focusedAgentId(): string | undefined {
477
+ return this.#focusController.focusedAgentId;
478
+ }
479
+ focusAgentSession(id: string): Promise<void> {
480
+ return this.#focusController.focusAgent(id);
481
+ }
482
+ focusParentSession(): Promise<void> {
483
+ return this.#focusController.focusParent();
484
+ }
485
+ unfocusSession(): Promise<void> {
486
+ return this.#focusController.unfocus();
487
+ }
488
+ clearTransientSessionUi(): void {
489
+ if (this.loadingAnimation) {
490
+ this.loadingAnimation.stop();
491
+ this.loadingAnimation = undefined;
492
+ }
493
+ this.statusContainer.clear();
494
+ this.pendingMessagesContainer.clear();
495
+ this.#cancelModelCycleClearTimer();
496
+ this.modelCycleContainer.clear();
497
+ this.compactionQueuedMessages = [];
498
+ this.streamingComponent = undefined;
499
+ this.streamingMessage = undefined;
500
+ this.pendingTools.clear();
501
+ }
357
502
  readonly #uiHelpers: UiHelpers;
358
503
  #sttController: STTController | undefined;
359
504
  #voiceAnimationInterval: NodeJS.Timeout | undefined;
@@ -365,6 +510,7 @@ export class InteractiveMode implements InteractiveModeContext {
365
510
  #eventBus?: EventBus;
366
511
  #eventBusUnsubscribers: Array<() => void> = [];
367
512
  #welcomeComponent?: WelcomeComponent;
513
+ readonly #chatHost: ChatBlockHost = { requestRender: () => this.ui.requestRender() };
368
514
 
369
515
  constructor(
370
516
  session: AgentSession,
@@ -372,8 +518,9 @@ export class InteractiveMode implements InteractiveModeContext {
372
518
  changelogMarkdown: string | undefined = undefined,
373
519
  setToolUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void = () => {},
374
520
  lspServers: LspStartupServerInfo[] | undefined = undefined,
375
- mcpManager?: import("../mcp").MCPManager,
521
+ mcpManager?: MCPManager,
376
522
  eventBus?: EventBus,
523
+ titleSystemPrompt?: string,
377
524
  ) {
378
525
  this.session = session;
379
526
  this.sessionManager = session.sessionManager;
@@ -386,16 +533,25 @@ export class InteractiveMode implements InteractiveModeContext {
386
533
  this.lspServers = lspServers;
387
534
  this.mcpManager = mcpManager;
388
535
  this.#eventBus = eventBus;
536
+ this.titleSystemPrompt = titleSystemPrompt;
389
537
  if (eventBus) {
390
538
  this.#eventBusUnsubscribers.push(
391
539
  eventBus.on(LSP_STARTUP_EVENT_CHANNEL, data => {
392
540
  this.#handleLspStartupEvent(data as LspStartupEvent);
393
541
  }),
394
542
  );
543
+ this.#eventBusUnsubscribers.push(
544
+ eventBus.on(MCP_CONNECTING_EVENT_CHANNEL, data => {
545
+ if (!isMcpConnectingEvent(data)) {
546
+ logger.warn("Ignoring malformed mcp:connecting event", { data });
547
+ return;
548
+ }
549
+ this.showStatus(formatMCPConnectingMessage(data.serverNames));
550
+ }),
551
+ );
395
552
  }
396
553
 
397
554
  this.ui = new TUI(new ProcessTerminal(), settings.get("showHardwareCursor"));
398
- this.ui.setClearOnShrink(settings.get("clearOnShrink"));
399
555
  this.ui.setMaxInlineImages(settings.get("tui.maxInlineImages"));
400
556
  // OSC 66 text-sizing is Kitty-only; resolve the setting against the terminal's
401
557
  // capability (`TERMINAL.textSizing` defaults on for Kitty) so it stays off
@@ -403,11 +559,13 @@ export class InteractiveMode implements InteractiveModeContext {
403
559
  setTerminalTextSizing(settings.get("tui.textSizing") && TERMINAL.textSizing);
404
560
  this.chatContainer = new TranscriptContainer();
405
561
  this.pendingMessagesContainer = new Container();
406
- this.statusContainer = new Container();
562
+ this.statusContainer = new StatusContainer();
407
563
  this.todoContainer = new Container();
564
+ this.subagentContainer = new Container();
408
565
  this.btwContainer = new Container();
409
566
  this.omfgContainer = new Container();
410
567
  this.errorBannerContainer = new Container();
568
+ this.modelCycleContainer = new Container();
411
569
  this.editor = new CustomEditor(getEditorTheme());
412
570
  this.editor.setUseTerminalCursor(this.ui.getShowHardwareCursor());
413
571
  this.editor.setAutocompleteMaxVisible(settings.get("autocompleteMaxVisible"));
@@ -415,8 +573,9 @@ export class InteractiveMode implements InteractiveModeContext {
415
573
  this.ui.requestRender(true);
416
574
  };
417
575
  this.editor.onAutocompleteUpdate = () => {
418
- this.ui.requestRender(false, { allowUnknownViewportMutation: true });
576
+ this.ui.requestRender();
419
577
  };
578
+ this.editor.setShimmerRepaintHandler(() => this.ui.requestComponentRender(this.editor));
420
579
  this.#syncEditorMaxHeight();
421
580
  this.#resizeHandler = () => {
422
581
  this.#syncEditorMaxHeight();
@@ -440,9 +599,8 @@ export class InteractiveMode implements InteractiveModeContext {
440
599
 
441
600
  this.hideThinkingBlock = settings.get("hideThinkingBlock");
442
601
 
443
- const builtinCommandNames = new Set(BUILTIN_SLASH_COMMANDS.map(c => c.name));
444
602
  const hookCommands: SlashCommand[] = (
445
- this.session.extensionRunner?.getRegisteredCommands(builtinCommandNames) ?? []
603
+ this.session.extensionRunner?.getRegisteredCommands(BUILTIN_SLASH_COMMAND_RESERVED_NAMES) ?? []
446
604
  ).map(cmd => ({
447
605
  name: cmd.name,
448
606
  description: cmd.description ?? "(hook command)",
@@ -470,19 +628,25 @@ export class InteractiveMode implements InteractiveModeContext {
470
628
 
471
629
  this.#uiHelpers = new UiHelpers(this);
472
630
  this.#btwController = new BtwController(this);
631
+ this.#tanCommandController = new TanCommandController(this);
473
632
  this.#omfgController = new OmfgController(this);
474
633
  this.#extensionUiController = new ExtensionUiController(this);
475
634
  this.#eventController = new EventController(this);
476
635
  this.#commandController = new CommandController(this);
477
636
  this.#todoCommandController = new TodoCommandController(this);
478
637
  this.#selectorController = new SelectorController(this);
638
+ this.#focusController = new SessionFocusController(this);
479
639
  this.#inputController = new InputController(this);
480
640
  this.#observerRegistry = new SessionObserverRegistry();
481
641
  }
482
642
 
483
643
  playWelcomeIntro(): void {
484
- this.#welcomeComponent?.playIntro(() => this.ui.requestRender());
644
+ const welcome = this.#welcomeComponent;
645
+ // Component-scoped: the intro only mutates the welcome box's own rows,
646
+ // so a resumed long transcript is not re-walked per animation frame.
647
+ welcome?.playIntro(() => this.ui.requestComponentRender(welcome));
485
648
  }
649
+
486
650
  async init(options: InteractiveModeInitOptions = {}): Promise<void> {
487
651
  if (this.isInitialized) return;
488
652
 
@@ -567,9 +731,11 @@ export class InteractiveMode implements InteractiveModeContext {
567
731
  this.ui.addChild(this.pendingMessagesContainer);
568
732
  this.ui.addChild(this.statusContainer);
569
733
  this.ui.addChild(this.todoContainer);
734
+ this.ui.addChild(this.subagentContainer);
570
735
  this.ui.addChild(this.btwContainer);
571
736
  this.ui.addChild(this.omfgContainer);
572
737
  this.ui.addChild(this.errorBannerContainer);
738
+ this.ui.addChild(this.modelCycleContainer);
573
739
  this.ui.addChild(this.statusLine); // Only renders hook statuses (main status in editor border)
574
740
  this.ui.addChild(this.hookWidgetContainerAbove);
575
741
  this.ui.addChild(this.editorContainer);
@@ -593,14 +759,16 @@ export class InteractiveMode implements InteractiveModeContext {
593
759
  this.#reconcileTodosWithSubagents();
594
760
  this.#syncTodoAutoClearTimer();
595
761
  this.#renderTodoList();
762
+ this.#renderSubagentList();
596
763
  this.ui.requestRender();
597
764
  });
598
765
 
599
766
  // Load initial todos
600
767
  await this.#loadTodoList();
601
768
 
602
- // Start the UI
603
- this.ui.start();
769
+ // Start the UI. Cold `prometheus` launch opts into clearing on the first paint so
770
+ // the initial welcome frame does not append over the previous run's scrollback.
771
+ this.ui.start({ clearScrollback: options.clearInitialTerminalHistory === true });
604
772
  pushTerminalTitle();
605
773
  setSessionTerminalTitle(this.sessionManager.getSessionName(), this.sessionManager.getCwd());
606
774
  this.updateEditorBorderColor();
@@ -636,9 +804,17 @@ export class InteractiveMode implements InteractiveModeContext {
636
804
  this.session.subscribe(event => {
637
805
  void this.#handleGoalSessionEvent(event);
638
806
  }),
807
+ this.sessionManager.onSessionNameChanged(() => {
808
+ this.#handleSessionAccentInputsChanged();
809
+ }),
810
+ onStatusLineSessionAccentChanged(() => {
811
+ this.#syncStatusLineSettings();
812
+ this.#handleSessionAccentInputsChanged();
813
+ }),
639
814
  );
640
815
  // Set up theme file watcher
641
816
  onThemeChange(() => {
817
+ this.#clearWorkingMessageAccentCache();
642
818
  clearRenderCache();
643
819
  this.ui.invalidate();
644
820
  this.updateEditorBorderColor();
@@ -662,6 +838,13 @@ export class InteractiveMode implements InteractiveModeContext {
662
838
  this.updateEditorTopBorder();
663
839
  }
664
840
 
841
+ /** Reload the title-generation system prompt override for the provided working directory. */
842
+ async refreshTitleSystemPrompt(cwd?: string): Promise<void> {
843
+ const basePath = cwd ?? this.sessionManager.getCwd();
844
+ const titleSystemPromptSource = discoverTitleSystemPromptFile(basePath);
845
+ this.titleSystemPrompt = await resolvePromptInput(titleSystemPromptSource, "title system prompt");
846
+ }
847
+
665
848
  /** Reload slash commands and autocomplete for the provided working directory. */
666
849
  async refreshSlashCommandState(cwd?: string): Promise<void> {
667
850
  const basePath = cwd ?? this.sessionManager.getCwd();
@@ -671,8 +854,30 @@ export class InteractiveMode implements InteractiveModeContext {
671
854
  name: cmd.name,
672
855
  description: cmd.description,
673
856
  }));
857
+ // Surface discovered prompt templates in the picker. AgentSession.prompt() expands
858
+ // `expandSlashCommand` before `expandPromptTemplate`, and builtin command
859
+ // execution resolves aliases before template expansion. Mirror that command
860
+ // resolution order by skipping templates whose names already appear in any
861
+ // builtin/hook/custom/skill/file command token.
862
+ const reservedNames = new Set<string>();
863
+ for (const command of this.#pendingSlashCommands) {
864
+ reservedNames.add(command.name);
865
+ for (const alias of command.aliases ?? []) reservedNames.add(alias);
866
+ }
867
+ for (const command of fileSlashCommands) {
868
+ reservedNames.add(command.name);
869
+ for (const alias of command.aliases ?? []) reservedNames.add(alias);
870
+ }
871
+ const promptTemplateCommands: SlashCommand[] = this.session.promptTemplates
872
+ .filter(template => !reservedNames.has(template.name))
873
+ .map(template => ({
874
+ name: template.name,
875
+ // `PromptTemplate.description` from `loadTemplatesFromDir` already includes the
876
+ // source suffix (e.g. "Review code (project)"), so pass it through verbatim.
877
+ description: template.description,
878
+ }));
674
879
  const autocompleteProvider = this.#inputController.createAutocompleteProvider(
675
- [...this.#pendingSlashCommands, ...fileSlashCommands],
880
+ [...this.#pendingSlashCommands, ...fileSlashCommands, ...promptTemplateCommands],
676
881
  basePath,
677
882
  );
678
883
  this.editor.setAutocompleteProvider(autocompleteProvider);
@@ -696,6 +901,7 @@ export class InteractiveMode implements InteractiveModeContext {
696
901
  // Re-warm plugin roots, capabilities, slash commands, and the ssh tool so
697
902
  // the next prompt sees everything scoped to the new project directory.
698
903
  clearClaudePluginRootsCache();
904
+ await this.refreshTitleSystemPrompt(newCwd);
699
905
  resetCapabilities();
700
906
  await this.refreshSlashCommandState(newCwd);
701
907
  await this.session.refreshSshTool({ activateIfAvailable: true });
@@ -765,6 +971,14 @@ export class InteractiveMode implements InteractiveModeContext {
765
971
  this.#goalContinuationTimer = undefined;
766
972
  if (!this.onInputCallback) return;
767
973
  if (!this.goalModeEnabled || this.goalModePaused) return;
974
+ // The 800ms timer can outlive the idle window that scheduled it: a
975
+ // `/goal set` taken via the streaming branch (or any extension/hook
976
+ // path that starts a turn while we wait) leaves the agent busy. Firing
977
+ // the continuation now would route through `submitInteractiveInput` →
978
+ // `promptCustomMessage` with no `streamingBehavior` and resurface
979
+ // `AgentBusyError`. Drop this tick; `#handleGoalSessionEvent` reschedules
980
+ // on the next `agent_end`.
981
+ if (this.#isAutoSubmitBlocked()) return;
768
982
  if (this.#pendingSubmittedInput) return;
769
983
  if (this.editor.getText().trim().length > 0) return;
770
984
  if ((this.pendingImages?.length ?? 0) > 0) return;
@@ -788,7 +1002,7 @@ export class InteractiveMode implements InteractiveModeContext {
788
1002
  }
789
1003
  }
790
1004
 
791
- #isLoopAutoSubmitBlocked(): boolean {
1005
+ #isAutoSubmitBlocked(): boolean {
792
1006
  return this.session.isStreaming || this.session.isCompacting || this.session.hasPostPromptWork;
793
1007
  }
794
1008
 
@@ -798,7 +1012,7 @@ export class InteractiveMode implements InteractiveModeContext {
798
1012
  this.disableLoopMode("Loop time limit reached. Loop mode disabled.");
799
1013
  return;
800
1014
  }
801
- if (this.#isLoopAutoSubmitBlocked()) {
1015
+ if (this.#isAutoSubmitBlocked()) {
802
1016
  this.#deferLoopAutoSubmit(() => this.#submitLoopPromptWhenReady(prompt));
803
1017
  return;
804
1018
  }
@@ -807,7 +1021,7 @@ export class InteractiveMode implements InteractiveModeContext {
807
1021
 
808
1022
  async #runLoopIteration(action: "prompt" | "compact" | "reset", prompt: string): Promise<void> {
809
1023
  if (!this.loopModeEnabled || this.loopPrompt !== prompt || !this.onInputCallback) return;
810
- if (this.#isLoopAutoSubmitBlocked()) {
1024
+ if (this.#isAutoSubmitBlocked()) {
811
1025
  this.#deferLoopAutoSubmit(() => {
812
1026
  void this.#runLoopIteration(action, prompt);
813
1027
  });
@@ -935,13 +1149,6 @@ export class InteractiveMode implements InteractiveModeContext {
935
1149
  }
936
1150
  this.editor.setText("");
937
1151
  this.editor.imageLinks = undefined;
938
- // Reconciliation checkpoint: only retire frozen block snapshots after TUI
939
- // proves the native viewport is at the tail and replays scrollback safely.
940
- // Unknown host viewports stay frozen; thawing them would expose live rows
941
- // over stale native history and can yank or duplicate when ED3 is unsafe.
942
- if (this.ui.refreshNativeScrollbackIfDirty()) {
943
- this.chatContainer.thaw();
944
- }
945
1152
  this.ensureLoadingAnimation();
946
1153
  this.ui.requestRender();
947
1154
  return submission;
@@ -963,9 +1170,7 @@ export class InteractiveMode implements InteractiveModeContext {
963
1170
  this.#goalContinuationTurnInFlight = false;
964
1171
  }
965
1172
  if (this.loadingAnimation) {
966
- this.loadingAnimation.stop();
967
- this.loadingAnimation = undefined;
968
- this.statusContainer.clear();
1173
+ this.#stopLoadingAnimation(true);
969
1174
  }
970
1175
  if (!submission.customType) {
971
1176
  this.pendingImages = submission.images ? [...submission.images] : [];
@@ -1003,24 +1208,38 @@ export class InteractiveMode implements InteractiveModeContext {
1003
1208
  pendingSubmissionDispose?.();
1004
1209
  this.#pendingWorkingMessage = undefined;
1005
1210
  if (this.loadingAnimation) {
1006
- this.loadingAnimation.stop();
1007
- this.loadingAnimation = undefined;
1008
- this.statusContainer.clear();
1211
+ this.#stopLoadingAnimation(true);
1009
1212
  }
1010
1213
  }
1011
1214
  }
1012
1215
 
1013
1216
  #computeEditorMaxHeight(): number {
1014
- const rows = this.ui.terminal.rows;
1015
- const terminalRows = Number.isFinite(rows) && rows > 0 ? rows : EDITOR_FALLBACK_ROWS;
1016
- const maxHeight = terminalRows - EDITOR_RESERVED_ROWS;
1017
- return Math.max(EDITOR_MAX_HEIGHT_MIN, Math.min(EDITOR_MAX_HEIGHT_MAX, maxHeight));
1217
+ return computeEditorMaxHeight(this.ui.terminal.rows);
1018
1218
  }
1019
1219
 
1020
1220
  #syncEditorMaxHeight(): void {
1021
1221
  this.editor.setMaxHeight(this.#computeEditorMaxHeight());
1022
1222
  }
1023
1223
 
1224
+ #syncStatusLineSettings(): void {
1225
+ this.statusLine.updateSettings({
1226
+ preset: settings.get("statusLine.preset"),
1227
+ leftSegments: settings.get("statusLine.leftSegments"),
1228
+ rightSegments: settings.get("statusLine.rightSegments"),
1229
+ separator: settings.get("statusLine.separator"),
1230
+ showHookStatus: settings.get("statusLine.showHookStatus"),
1231
+ sessionAccent: settings.get("statusLine.sessionAccent"),
1232
+ transparent: settings.get("statusLine.transparent"),
1233
+ segmentOptions: settings.get("statusLine.segmentOptions"),
1234
+ });
1235
+ }
1236
+
1237
+ #handleSessionAccentInputsChanged(): void {
1238
+ this.#clearWorkingMessageAccentCache();
1239
+ this.statusLine.invalidate();
1240
+ this.updateEditorBorderColor();
1241
+ }
1242
+
1024
1243
  updateEditorBorderColor(): void {
1025
1244
  if (this.isBashMode) {
1026
1245
  this.editor.borderColor = theme.getBashModeBorderColor();
@@ -1029,7 +1248,9 @@ export class InteractiveMode implements InteractiveModeContext {
1029
1248
  } else {
1030
1249
  const accentEnabled = !isSettingsInitialized() || settings.get("statusLine.sessionAccent") !== false;
1031
1250
  const sessionName = accentEnabled ? this.sessionManager.getSessionName() : undefined;
1032
- const hex = sessionName ? getSessionAccentHex(sessionName, theme.accentSurfaceLuminance) : undefined;
1251
+ const hex = sessionName
1252
+ ? getSessionAccentHex(sessionName, theme.getMajorThemeColorHexes(), theme.accentSurfaceLuminance)
1253
+ : undefined;
1033
1254
  const ansi = getSessionAccentAnsi(hex);
1034
1255
  if (ansi) {
1035
1256
  this.editor.borderColor = (str: string) => `${ansi}${str}\x1b[39m`;
@@ -1038,6 +1259,12 @@ export class InteractiveMode implements InteractiveModeContext {
1038
1259
  this.editor.borderColor = theme.getThinkingBorderColor(level);
1039
1260
  }
1040
1261
  }
1262
+ if (this.focusedAgentId) {
1263
+ // Focused subagent view: faint the outline so the borrowed session is
1264
+ // visually distinct from the main one.
1265
+ const base = this.editor.borderColor;
1266
+ this.editor.borderColor = (str: string) => `\x1b[2m${base(str)}\x1b[22m`;
1267
+ }
1041
1268
  this.updateEditorTopBorder();
1042
1269
  this.ui.requestRender();
1043
1270
  }
@@ -1050,8 +1277,34 @@ export class InteractiveMode implements InteractiveModeContext {
1050
1277
 
1051
1278
  rebuildChatFromMessages(): void {
1052
1279
  this.chatContainer.clear();
1053
- const context = this.session.buildDisplaySessionContext();
1280
+ // Full-history transcript: compactions render as inline dividers instead
1281
+ // of restarting the visible conversation (the LLM context still resets).
1282
+ const context = this.viewSession.buildTranscriptSessionContext();
1054
1283
  this.renderSessionContext(context);
1284
+ // During the pre-streaming window — after `startPendingSubmission` has
1285
+ // optimistically rendered the user's message but before the user
1286
+ // `message_start` event lands it in `session` entries — any rebuild
1287
+ // (e.g. Ctrl+T toggleThinkingBlockVisibility, theme selector) would
1288
+ // otherwise erase the user's just-submitted message until the first
1289
+ // assistant token arrived (#2372). Once `message_start` fires the
1290
+ // signature is cleared by `EventController`, so this replay is a no-op
1291
+ // post-streaming and cannot duplicate.
1292
+ this.#replayOptimisticUserMessage();
1293
+ }
1294
+
1295
+ #replayOptimisticUserMessage(): void {
1296
+ if (!this.optimisticUserMessageSignature) return;
1297
+ const submission = this.#pendingSubmittedInput;
1298
+ if (!submission || submission.cancelled || submission.customType) return;
1299
+ this.addMessageToChat(
1300
+ {
1301
+ role: "user",
1302
+ content: [{ type: "text", text: submission.text }, ...(submission.images ?? [])],
1303
+ attribution: "user",
1304
+ timestamp: Date.now(),
1305
+ },
1306
+ { imageLinks: submission.imageLinks },
1307
+ );
1055
1308
  }
1056
1309
 
1057
1310
  #formatTodoLine(todo: TodoItem, prefix: string, matched: boolean): string {
@@ -1161,6 +1414,41 @@ export class InteractiveMode implements InteractiveModeContext {
1161
1414
  this.#todoAutoClearTimer.unref?.();
1162
1415
  }
1163
1416
 
1417
+ /**
1418
+ * Render the ctrl+p model-role cycle chip track into its own anchored
1419
+ * container (just above the editor), mirroring the todo HUD: the container is
1420
+ * cleared and rebuilt in place on every cycle, so rapid presses or concurrent
1421
+ * chat activity can never stack duplicate tracks into the scrollback.
1422
+ */
1423
+ showModelCycleTrack(track: string): void {
1424
+ this.#renderModelCycleTrack(track);
1425
+ this.#syncModelCycleClearTimer();
1426
+ this.ui.requestRender();
1427
+ }
1428
+
1429
+ #renderModelCycleTrack(track: string | null): void {
1430
+ this.modelCycleContainer.clear();
1431
+ if (!track) return;
1432
+ this.modelCycleContainer.addChild(new Spacer(1));
1433
+ this.modelCycleContainer.addChild(new Text(track, 1, 0));
1434
+ }
1435
+
1436
+ #cancelModelCycleClearTimer(): void {
1437
+ if (!this.#modelCycleClearTimer) return;
1438
+ clearTimeout(this.#modelCycleClearTimer);
1439
+ this.#modelCycleClearTimer = undefined;
1440
+ }
1441
+
1442
+ #syncModelCycleClearTimer(): void {
1443
+ this.#cancelModelCycleClearTimer();
1444
+ this.#modelCycleClearTimer = setTimeout(() => {
1445
+ this.#modelCycleClearTimer = undefined;
1446
+ this.#renderModelCycleTrack(null);
1447
+ this.ui.requestRender();
1448
+ }, MODEL_CYCLE_TRACK_CLEAR_MS);
1449
+ this.#modelCycleClearTimer.unref?.();
1450
+ }
1451
+
1164
1452
  #getActivePhase(phases: TodoPhase[]): TodoPhase | undefined {
1165
1453
  const nonEmpty = phases.filter(phase => phase.tasks.length > 0);
1166
1454
  const active = nonEmpty.find(phase =>
@@ -1214,6 +1502,19 @@ export class InteractiveMode implements InteractiveModeContext {
1214
1502
  this.todoContainer.addChild(new Text(lines.join("\n"), 1, 0));
1215
1503
  }
1216
1504
 
1505
+ /**
1506
+ * Anchored HUD of in-flight subagents, mirroring the Todos block above the
1507
+ * editor. Driven entirely by observer-registry change events, so rows appear
1508
+ * on spawn and the whole block clears itself once the last subagent leaves
1509
+ * the "active" state.
1510
+ */
1511
+ #renderSubagentList(): void {
1512
+ this.subagentContainer.clear();
1513
+ const lines = renderSubagentHudLines(this.#observerRegistry.getSessions(), this.ui.terminal.columns);
1514
+ if (lines.length === 0) return;
1515
+ this.subagentContainer.addChild(new Text(lines.join("\n"), 1, 0));
1516
+ }
1517
+
1217
1518
  async #loadTodoList(): Promise<void> {
1218
1519
  this.todoPhases = this.session.getTodoPhases();
1219
1520
  this.#syncTodoAutoClearTimer();
@@ -1522,22 +1823,15 @@ export class InteractiveMode implements InteractiveModeContext {
1522
1823
  if (!state?.enabled) {
1523
1824
  throw new ToolError("Plan mode is not active.");
1524
1825
  }
1525
- const planFilePath = state.planFilePath;
1526
- const planContent = await this.#readPlanFile(planFilePath);
1527
- if (planContent === null) {
1528
- throw new ToolError(
1529
- `Plan file not found at ${planFilePath}. Write the finalized plan to ${planFilePath} before requesting approval.`,
1530
- );
1531
- }
1532
- const normalized = resolvePlanTitle({
1826
+ const { planFilePath, title } = await resolveApprovedPlan({
1533
1827
  suppliedTitle: extra?.title,
1534
- planContent,
1535
- planFilePath,
1828
+ statePlanFilePath: state.planFilePath,
1829
+ readPlan: url => this.#readPlanFile(url),
1830
+ listPlanFiles: () => this.#listLocalPlanFiles(),
1536
1831
  });
1537
1832
  const details: PlanApprovalDetails = {
1538
1833
  planFilePath,
1539
- finalPlanFilePath: `local://${normalized.fileName}`,
1540
- title: normalized.title,
1834
+ title,
1541
1835
  planExists: true,
1542
1836
  };
1543
1837
  return {
@@ -1548,7 +1842,40 @@ export class InteractiveMode implements InteractiveModeContext {
1548
1842
  });
1549
1843
  }
1550
1844
 
1551
- async #exitPlanMode(options?: { silent?: boolean; paused?: boolean }): Promise<void> {
1845
+ async #restorePlanPreviousModel(prev: { model: Model; thinkingLevel?: ThinkingLevel }): Promise<void> {
1846
+ if (modelsAreEqual(this.session.model, prev.model)) {
1847
+ // Same model — only thinking level may differ. Avoid setModelTemporary()
1848
+ // which would reset provider-side sessions and break continuity.
1849
+ this.session.setThinkingLevel(prev.thinkingLevel);
1850
+ } else if (this.session.isStreaming) {
1851
+ this.#pendingModelSwitch = { model: prev.model, thinkingLevel: prev.thinkingLevel };
1852
+ } else {
1853
+ await this.session.setModelTemporary(prev.model, prev.thinkingLevel);
1854
+ }
1855
+ }
1856
+
1857
+ /**
1858
+ * Idempotent post-compaction model transition for the plan-approval compact
1859
+ * path. The deferred pre-plan state is consumed on first application, so a
1860
+ * second call (the before-flush hook vs. the short-circuit fallback) is a
1861
+ * no-op. "failed" intentionally stays on the plan model — the context is
1862
+ * intact and we dispatch best-effort.
1863
+ */
1864
+ async #applyDeferredPlanModelTransition(
1865
+ outcome: CompactionOutcome | undefined,
1866
+ executionModel: ResolvedRoleModel | undefined,
1867
+ ): Promise<void> {
1868
+ const deferredPrev = this.#planModePreviousModelState;
1869
+ if (deferredPrev === undefined || outcome === "failed") return;
1870
+ this.#planModePreviousModelState = undefined;
1871
+ if (executionModel) {
1872
+ await this.#applyPlanExecutionModel(executionModel);
1873
+ } else {
1874
+ await this.#restorePlanPreviousModel(deferredPrev);
1875
+ }
1876
+ }
1877
+
1878
+ async #exitPlanMode(options?: { silent?: boolean; paused?: boolean; deferModelRestore?: boolean }): Promise<void> {
1552
1879
  if (!this.planModeEnabled) {
1553
1880
  return;
1554
1881
  }
@@ -1558,23 +1885,18 @@ export class InteractiveMode implements InteractiveModeContext {
1558
1885
  await this.session.setActiveToolsByName(previousTools);
1559
1886
  }
1560
1887
  if (this.#planModePreviousModelState) {
1561
- const prev = this.#planModePreviousModelState;
1562
- if (modelsAreEqual(this.session.model, prev.model)) {
1563
- // Same model — only thinking level may differ. Avoid setModelTemporary()
1564
- // which would reset provider-side sessions (openai-responses/Codex) and
1565
- // break conversation continuity.
1566
- this.session.setThinkingLevel(prev.thinkingLevel);
1567
- } else if (this.session.isStreaming) {
1568
- this.#pendingModelSwitch = { model: prev.model, thinkingLevel: prev.thinkingLevel };
1569
- } else {
1570
- await this.session.setModelTemporary(prev.model, prev.thinkingLevel);
1888
+ if (!options?.deferModelRestore) {
1889
+ await this.#restorePlanPreviousModel(this.#planModePreviousModelState);
1571
1890
  }
1572
1891
  // If #applyPlanModeModel queued a deferred switch to the plan-role model
1573
1892
  // (because the session was streaming on entry), drop it now: we are
1574
1893
  // leaving plan mode, so flushing it on the next agent_end would land the
1575
1894
  // session on the plan-role model after the user has exited plan mode
1576
- // (issue #816). Only clear when the pending target matches the plan-role
1577
- // model leave any unrelated user-queued switch intact.
1895
+ // (issue #816). This runs even when deferModelRestore is set
1896
+ // (compact-approval path): otherwise the stale plan switch survives and
1897
+ // flushPendingModelSwitch() later clobbers the restored/execution model.
1898
+ // Only clear when the pending target matches the plan-role model — leave
1899
+ // any unrelated user-queued switch intact.
1578
1900
  const pending = this.#pendingModelSwitch;
1579
1901
  if (pending) {
1580
1902
  const planResolution = this.session.resolveRoleModelWithThinking("plan");
@@ -1589,7 +1911,7 @@ export class InteractiveMode implements InteractiveModeContext {
1589
1911
  this.planModePaused = options?.paused ?? false;
1590
1912
  this.planModePlanFilePath = undefined;
1591
1913
  this.#planModePreviousTools = undefined;
1592
- this.#planModePreviousModelState = undefined;
1914
+ if (!options?.deferModelRestore) this.#planModePreviousModelState = undefined;
1593
1915
  this.#updatePlanModeStatus();
1594
1916
  const paused = options?.paused ?? false;
1595
1917
  this.sessionManager.appendModeChange(paused ? "plan_paused" : "none");
@@ -1677,22 +1999,97 @@ export class InteractiveMode implements InteractiveModeContext {
1677
1999
  }
1678
2000
  }
1679
2001
 
1680
- #renderPlanPreview(planContent: string, options?: { append?: boolean }): void {
1681
- const existingContainer = this.#planReviewContainer;
1682
- const replaceExisting = options?.append !== true && existingContainer !== undefined;
1683
- const planReviewContainer = replaceExisting ? existingContainer : new Container();
1684
- planReviewContainer.clear();
1685
- planReviewContainer.addChild(new Spacer(1));
1686
- planReviewContainer.addChild(new DynamicBorder());
1687
- planReviewContainer.addChild(new Text(theme.bold(theme.fg("accent", "Plan Review")), 1, 1));
1688
- planReviewContainer.addChild(new Spacer(1));
1689
- planReviewContainer.addChild(new Markdown(planContent, 1, 1, getMarkdownTheme()));
1690
- planReviewContainer.addChild(new DynamicBorder());
1691
- if (!replaceExisting) {
1692
- this.chatContainer.addChild(planReviewContainer);
2002
+ async #hasPlanModeDraftContent(planFilePath: string): Promise<boolean> {
2003
+ const candidates = new Set<string>([planFilePath, ...(await this.#listLocalPlanFiles())]);
2004
+ for (const candidate of candidates) {
2005
+ const content = await this.#readPlanFile(candidate);
2006
+ if (content !== null && content.trim().length > 0) return true;
2007
+ }
2008
+ return false;
2009
+ }
2010
+
2011
+ /** `local://` URLs of plan files in the session-local root, newest first.
2012
+ * A fallback for `resolveApprovedPlan` when the agent dropped `extra.title`,
2013
+ * so the plan it wrote is still found by scanning recent `*-plan.md` files. */
2014
+ async #listLocalPlanFiles(): Promise<string[]> {
2015
+ const localRoot = this.#resolvePlanFilePath("local://");
2016
+ try {
2017
+ const entries = await fs.readdir(localRoot, { withFileTypes: true });
2018
+ const plans = await Promise.all(
2019
+ entries
2020
+ .filter(entry => entry.isFile() && /plan\.md$/i.test(entry.name))
2021
+ .map(async name => {
2022
+ const stat = await fs.stat(path.join(localRoot, name.name)).catch(() => null);
2023
+ return { url: `local://${name.name}`, mtime: stat?.mtimeMs ?? 0 };
2024
+ }),
2025
+ );
2026
+ return plans.sort((a, b) => b.mtime - a.mtime).map(plan => plan.url);
2027
+ } catch {
2028
+ return [];
1693
2029
  }
1694
- this.#planReviewContainer = planReviewContainer;
2030
+ }
2031
+
2032
+ showPlanReview(
2033
+ planContent: string,
2034
+ title: string,
2035
+ options: string[],
2036
+ dialogOptions?: {
2037
+ helpText?: string;
2038
+ disabledIndices?: number[];
2039
+ onExternalEditor?: () => void;
2040
+ onPlanEdited?: (content: string) => void;
2041
+ onFeedbackChange?: (feedback: string) => void;
2042
+ initialIndex?: number;
2043
+ },
2044
+ extra?: { slider?: HookSelectorSlider },
2045
+ ): Promise<string | undefined> {
2046
+ this.#hidePlanReview();
2047
+ const { promise, resolve } = Promise.withResolvers<string | undefined>();
2048
+ let settled = false;
2049
+ const finish = (choice: string | undefined): void => {
2050
+ if (settled) return;
2051
+ settled = true;
2052
+ this.#hidePlanReview();
2053
+ this.ui.requestRender();
2054
+ resolve(choice);
2055
+ };
2056
+ const overlay = new PlanReviewOverlay(
2057
+ planContent,
2058
+ {
2059
+ promptTitle: title,
2060
+ options,
2061
+ disabledIndices: dialogOptions?.disabledIndices,
2062
+ helpText: dialogOptions?.helpText,
2063
+ initialIndex: dialogOptions?.initialIndex,
2064
+ slider: extra?.slider,
2065
+ externalEditorLabel: this.keybindings.getDisplayString("app.editor.external") || undefined,
2066
+ },
2067
+ {
2068
+ onPick: choice => finish(choice),
2069
+ onCancel: () => finish(undefined),
2070
+ onExternalEditor: dialogOptions?.onExternalEditor,
2071
+ onAnnotationExternalEditor: (draft, commit) => this.#openPlanAnnotationInExternalEditor(draft, commit),
2072
+ onPlanEdited: dialogOptions?.onPlanEdited,
2073
+ onFeedbackChange: dialogOptions?.onFeedbackChange,
2074
+ },
2075
+ );
2076
+ this.#planReviewOverlay = overlay;
2077
+ this.#planReviewOverlayHandle = this.ui.showOverlay(overlay, {
2078
+ anchor: "bottom-center",
2079
+ width: "100%",
2080
+ maxHeight: "100%",
2081
+ margin: 0,
2082
+ fullscreen: true,
2083
+ });
2084
+ this.ui.setFocus(overlay);
1695
2085
  this.ui.requestRender();
2086
+ return promise;
2087
+ }
2088
+
2089
+ #hidePlanReview(): void {
2090
+ this.#planReviewOverlayHandle?.hide();
2091
+ this.#planReviewOverlayHandle = undefined;
2092
+ this.#planReviewOverlay = undefined;
1696
2093
  }
1697
2094
 
1698
2095
  #getEditorTerminalPath(): string | null {
@@ -1714,14 +2111,6 @@ export class InteractiveMode implements InteractiveModeContext {
1714
2111
  }
1715
2112
  }
1716
2113
 
1717
- #getPlanReviewHelpText(): string {
1718
- const externalEditorKey = this.keybindings.getDisplayString("app.editor.external");
1719
- if (!externalEditorKey) {
1720
- return "up/down navigate enter select esc cancel";
1721
- }
1722
- return `up/down navigate enter select ${externalEditorKey.toLowerCase()} open in editor esc cancel`;
1723
- }
1724
-
1725
2114
  #getPlanApprovalContextUsage(): ContextUsage | undefined {
1726
2115
  const executionModel = this.#planModePreviousModelState?.model ?? this.session.model;
1727
2116
  const contextWindow = executionModel?.contextWindow;
@@ -1780,7 +2169,7 @@ export class InteractiveMode implements InteractiveModeContext {
1780
2169
  });
1781
2170
  if (result !== null) {
1782
2171
  await Bun.write(resolvedPath, result);
1783
- this.#renderPlanPreview(result);
2172
+ this.#planReviewOverlay?.setPlanContent(result);
1784
2173
  this.showStatus("Plan updated in external editor.");
1785
2174
  }
1786
2175
  } catch (error) {
@@ -1794,6 +2183,37 @@ export class InteractiveMode implements InteractiveModeContext {
1794
2183
  }
1795
2184
  }
1796
2185
 
2186
+ async #openPlanAnnotationInExternalEditor(draft: string, commit: (text: string | null) => void): Promise<void> {
2187
+ const editorCmd = getEditorCommand();
2188
+ if (!editorCmd) {
2189
+ this.showWarning("No editor configured. Set $VISUAL or $EDITOR environment variable.");
2190
+ return;
2191
+ }
2192
+
2193
+ let ttyHandle: fs.FileHandle | null = null;
2194
+ try {
2195
+ ttyHandle = await this.#openEditorTerminalHandle();
2196
+ this.ui.stop();
2197
+
2198
+ const stdio: [number | "inherit", number | "inherit", number | "inherit"] = ttyHandle
2199
+ ? [ttyHandle.fd, ttyHandle.fd, ttyHandle.fd]
2200
+ : ["inherit", "inherit", "inherit"];
2201
+
2202
+ const result = await openInEditor(editorCmd, draft, { extension: ".md", stdio });
2203
+ if (result !== null) {
2204
+ commit(result);
2205
+ }
2206
+ } catch (error) {
2207
+ this.showWarning(`Failed to open external editor: ${error instanceof Error ? error.message : String(error)}`);
2208
+ } finally {
2209
+ if (ttyHandle) {
2210
+ await ttyHandle.close();
2211
+ }
2212
+ this.ui.start();
2213
+ this.ui.requestRender(true);
2214
+ }
2215
+ }
2216
+
1797
2217
  async #applyPlanExecutionModel(entry: ResolvedRoleModel | undefined): Promise<void> {
1798
2218
  if (!entry) return;
1799
2219
  try {
@@ -1812,19 +2232,12 @@ export class InteractiveMode implements InteractiveModeContext {
1812
2232
  planContent: string,
1813
2233
  options: {
1814
2234
  planFilePath: string;
1815
- finalPlanFilePath: string;
1816
2235
  title: string;
1817
2236
  preserveContext?: boolean;
1818
2237
  compactBeforeExecute?: boolean;
1819
2238
  executionModel?: ResolvedRoleModel;
1820
2239
  },
1821
2240
  ): Promise<void> {
1822
- await renameApprovedPlanFile({
1823
- planFilePath: options.planFilePath,
1824
- finalPlanFilePath: options.finalPlanFilePath,
1825
- getArtifactsDir: () => this.sessionManager.getArtifactsDir(),
1826
- getSessionId: () => this.sessionManager.getSessionId(),
1827
- });
1828
2241
  const previousTools = this.#planModePreviousTools ?? this.session.getActiveToolNames();
1829
2242
 
1830
2243
  // Mark the pending abort caused by the plan-mode → compaction transition as
@@ -1838,13 +2251,17 @@ export class InteractiveMode implements InteractiveModeContext {
1838
2251
  }
1839
2252
  let compactOutcome: CompactionOutcome | undefined;
1840
2253
  try {
1841
- await this.#exitPlanMode({ silent: true, paused: false });
2254
+ await this.#exitPlanMode({
2255
+ silent: true,
2256
+ paused: false,
2257
+ deferModelRestore: options.compactBeforeExecute === true,
2258
+ });
1842
2259
 
1843
2260
  if (!options.preserveContext) {
1844
2261
  await this.handleClearCommand();
1845
2262
  // The new session has a fresh local:// root — persist the approved plan there
1846
- // so `local://<title>.md` resolves correctly in the execution session.
1847
- const newLocalPath = resolveLocalUrlToPath(options.finalPlanFilePath, {
2263
+ // so `local://<slug>-plan.md` resolves correctly in the execution session.
2264
+ const newLocalPath = resolveLocalUrlToPath(options.planFilePath, {
1848
2265
  getArtifactsDir: () => this.sessionManager.getArtifactsDir(),
1849
2266
  getSessionId: () => this.sessionManager.getSessionId(),
1850
2267
  });
@@ -1858,7 +2275,7 @@ export class InteractiveMode implements InteractiveModeContext {
1858
2275
  // Cancellation skips the synthetic-prompt dispatch (operator's explicit
1859
2276
  // abort is honored); failure proceeds best-effort — approval intent stands.
1860
2277
  const compactionPrompt = prompt.render(planModeCompactInstructionsPrompt, {
1861
- planFilePath: options.finalPlanFilePath,
2278
+ planFilePath: options.planFilePath,
1862
2279
  });
1863
2280
  // Pin the plan reference path BEFORE compaction so any user messages
1864
2281
  // queued during the compaction await (which `handleCompactCommand`
@@ -1866,8 +2283,10 @@ export class InteractiveMode implements InteractiveModeContext {
1866
2283
  // approved plan in `#buildPlanReferenceMessage`. Reassignment after
1867
2284
  // the try/finally is idempotent and kept for the !compactBeforeExecute
1868
2285
  // branch.
1869
- this.session.setPlanReferencePath(options.finalPlanFilePath);
1870
- compactOutcome = await this.handleCompactCommand(compactionPrompt);
2286
+ this.session.setPlanReferencePath(options.planFilePath);
2287
+ compactOutcome = await this.handleCompactCommand(compactionPrompt, outcome =>
2288
+ this.#applyDeferredPlanModelTransition(outcome, options.executionModel),
2289
+ );
1871
2290
  }
1872
2291
  } finally {
1873
2292
  // Unconditional clear. Idempotent: a no-op when the flag was never set
@@ -1882,24 +2301,35 @@ export class InteractiveMode implements InteractiveModeContext {
1882
2301
  if (previousTools.length > 0) {
1883
2302
  await this.session.setActiveToolsByName(previousTools);
1884
2303
  }
1885
- this.session.setPlanReferencePath(options.finalPlanFilePath);
2304
+ this.session.setPlanReferencePath(options.planFilePath);
2305
+
2306
+ // Resolve the deferred plan-approval model transition. On the compact path
2307
+ // the before-flush hook passed to handleCompactCommand already ran this (so
2308
+ // any input queued during compaction executed on the post-compaction
2309
+ // model); the re-run here is idempotent and covers the short-circuit where
2310
+ // compaction never executed. It runs for "cancelled" too — the operator
2311
+ // aborted only the compaction, not the approval — so the next turn no longer
2312
+ // lands on the plan model. "failed" stays on the plan model (context
2313
+ // intact) and dispatches best-effort.
2314
+ if (options.compactBeforeExecute) {
2315
+ await this.#applyDeferredPlanModelTransition(compactOutcome, options.executionModel);
2316
+ } else {
2317
+ await this.#applyPlanExecutionModel(options.executionModel);
2318
+ }
1886
2319
 
1887
2320
  if (compactOutcome === "cancelled") {
1888
2321
  // Explicit abort: honor it. `executeCompaction` already surfaced
1889
- // `showError("Compaction cancelled")` to the operator; we add the
1890
- // deferred-dispatch warning and exit. `markPlanReferenceSent` is
1891
- // intentionally skipped here: `#planReferenceSent` stays false, so
1892
- // `AgentSession.#buildPlanReferenceMessage` will inject the plan
1893
- // reference on the operator's next `prompt()` call. If we marked it
1894
- // sent here, the executor's first turn would have no plan context.
2322
+ // `showError("Compaction cancelled")`; we add the deferred-dispatch
2323
+ // warning and exit without dispatching the synthetic plan-approved
2324
+ // prompt. `markPlanReferenceSent` stays unset so
2325
+ // `AgentSession.#buildPlanReferenceMessage` injects the plan reference
2326
+ // on the operator's next `prompt()` call.
1895
2327
  this.showWarning(
1896
2328
  "Plan approved, but compaction was cancelled — execution not dispatched. Submit a turn to continue.",
1897
2329
  );
1898
2330
  return;
1899
2331
  }
1900
2332
 
1901
- await this.#applyPlanExecutionModel(options.executionModel);
1902
-
1903
2333
  // Approved plans land in a fresh (or compacted) session whose first user-visible
1904
2334
  // turn is the synthetic plan-approved prompt — that path bypasses the
1905
2335
  // input-controller's title generation. Seed an auto-name from the plan title
@@ -1919,9 +2349,18 @@ export class InteractiveMode implements InteractiveModeContext {
1919
2349
  this.session.markPlanReferenceSent();
1920
2350
  const planModePrompt = prompt.render(planModeApprovedPrompt, {
1921
2351
  planContent,
1922
- finalPlanFilePath: options.finalPlanFilePath,
2352
+ planFilePath: options.planFilePath,
1923
2353
  contextPreserved: options.preserveContext === true,
1924
2354
  });
2355
+ // The executor's first turn must start on an idle session. The agent may still
2356
+ // be streaming the post-`resolve` continuation (Agent.#emit is fire-and-forget)
2357
+ // or a turn kicked off by the compaction/clear above; prompt() would then throw
2358
+ // AgentBusyError ("Failed to finalize approved plan"). Abort the now-irrelevant
2359
+ // in-flight turn first — abort() bumps the prompt generation and cancels pending
2360
+ // continuations, so nothing re-streams in the synchronous gap before prompt().
2361
+ if (this.session.isStreaming) {
2362
+ await this.session.abort();
2363
+ }
1925
2364
  await this.session.prompt(planModePrompt, { synthetic: true });
1926
2365
  }
1927
2366
 
@@ -1931,14 +2370,30 @@ export class InteractiveMode implements InteractiveModeContext {
1931
2370
  return;
1932
2371
  }
1933
2372
  if (this.planModeEnabled) {
1934
- const confirmed = await this.showHookConfirm(
1935
- "Exit plan mode?",
1936
- "This exits plan mode without approving a plan.",
1937
- );
1938
- if (!confirmed) return;
2373
+ const planFilePath = this.planModePlanFilePath ?? (await this.#getPlanFilePath());
2374
+ if (await this.#hasPlanModeDraftContent(planFilePath)) {
2375
+ const confirmed = await this.showHookConfirm(
2376
+ "Exit plan mode?",
2377
+ "This exits plan mode without approving a plan.",
2378
+ );
2379
+ if (!confirmed) return;
2380
+ }
1939
2381
  await this.#exitPlanMode({ paused: true });
1940
2382
  return;
1941
2383
  }
2384
+ if (this.planModePaused && !initialPrompt) {
2385
+ // No-arg third toggle: paused → off. Tools, model, and plan state were
2386
+ // already restored by the prior #exitPlanMode({ paused: true }); only the
2387
+ // paused flag, the reentry marker, and the session mode entry remain.
2388
+ // Prompted /plan invocations fall through to #enterPlanMode below so the
2389
+ // supplied prompt is still submitted as the first plan-mode turn.
2390
+ this.planModePaused = false;
2391
+ this.#planModeHasEntered = false;
2392
+ this.#updatePlanModeStatus();
2393
+ this.sessionManager.appendModeChange("none");
2394
+ this.showStatus("Plan mode disabled.");
2395
+ return;
2396
+ }
1942
2397
  if (!this.session.settings.get("plan.enabled")) {
1943
2398
  this.showWarning("Plan mode is disabled. Enable it in settings (plan.enabled).");
1944
2399
  return;
@@ -2020,6 +2475,70 @@ export class InteractiveMode implements InteractiveModeContext {
2020
2475
  this.showError(error instanceof Error ? error.message : String(error));
2021
2476
  }
2022
2477
  }
2478
+ async handleGuidedGoalCommand(rest?: string): Promise<void> {
2479
+ try {
2480
+ if (this.planModeEnabled || this.planModePaused) {
2481
+ this.showWarning("Exit plan mode first.");
2482
+ return;
2483
+ }
2484
+ if (!this.session.settings.get("goal.enabled")) {
2485
+ this.showWarning("Goal mode is disabled. Enable it in settings (goal.enabled).");
2486
+ return;
2487
+ }
2488
+ if (this.goalModeEnabled) {
2489
+ this.showStatus("Goal mode is already active. Use /goal to manage it, or /goal drop to start over.");
2490
+ return;
2491
+ }
2492
+ if (this.#getPausedGoalState()) {
2493
+ this.showWarning("Resume the current goal first, or drop it before setting a new objective.");
2494
+ return;
2495
+ }
2496
+
2497
+ const initial = rest?.trim()
2498
+ ? rest.trim()
2499
+ : (await this.showHookEditor("Guided goal", undefined, undefined, { promptStyle: true }))?.trim();
2500
+ if (!initial) return;
2501
+
2502
+ const messages: GuidedGoalMessage[] = [{ role: "user", content: initial }];
2503
+ let latestDraftObjective: string | undefined;
2504
+ for (let turn = 0; turn < 6; turn++) {
2505
+ const result = await runGuidedGoalTurn(this.session, { messages });
2506
+ if (result.objective?.trim()) latestDraftObjective = result.objective.trim();
2507
+ if (result.kind === "question") {
2508
+ messages.push({ role: "assistant", content: result.question });
2509
+ const answer = (
2510
+ await this.showHookEditor(result.question, undefined, undefined, { promptStyle: true })
2511
+ )?.trim();
2512
+ if (!answer) return;
2513
+ messages.push({ role: "user", content: answer });
2514
+ continue;
2515
+ }
2516
+
2517
+ const finalObjective = (
2518
+ await this.showHookEditor("Review guided goal", result.objective, undefined, { promptStyle: true })
2519
+ )?.trim();
2520
+ if (!finalObjective) return;
2521
+ await this.#startGoalFromObjective(finalObjective);
2522
+ return;
2523
+ }
2524
+
2525
+ // Hit the turn cap without an explicit `ready`. Rather than discard the whole interview,
2526
+ // salvage the latest non-empty model objective draft seen on any earlier turn. A final
2527
+ // question turn may omit `objective`; that must not erase a usable draft.
2528
+ if (latestDraftObjective) {
2529
+ const finalObjective = (
2530
+ await this.showHookEditor("Review guided goal", latestDraftObjective, undefined, { promptStyle: true })
2531
+ )?.trim();
2532
+ if (finalObjective) {
2533
+ await this.#startGoalFromObjective(finalObjective);
2534
+ return;
2535
+ }
2536
+ }
2537
+ this.showWarning("Guided goal setup needs more detail. Run /guided-goal again with a narrower objective.");
2538
+ } catch (error) {
2539
+ this.showError(error instanceof Error ? error.message : String(error));
2540
+ }
2541
+ }
2023
2542
 
2024
2543
  async #dispatchGoalSubcommand(sub: GoalSubcommand, rest: string): Promise<void> {
2025
2544
  switch (sub) {
@@ -2153,7 +2672,7 @@ export class InteractiveMode implements InteractiveModeContext {
2153
2672
  async #startGoalFromObjective(objective: string): Promise<void> {
2154
2673
  await this.#enterGoalMode({ objective, silent: true });
2155
2674
  this.#resetGoalContinuationSuppression();
2156
- if (this.onInputCallback) {
2675
+ if (!this.session.isStreaming && this.onInputCallback) {
2157
2676
  this.onInputCallback(this.startPendingSubmission({ text: objective }));
2158
2677
  }
2159
2678
  }
@@ -2168,7 +2687,7 @@ export class InteractiveMode implements InteractiveModeContext {
2168
2687
  if (this.session.isStreaming) {
2169
2688
  await this.session.sendGoalModeContext({ deliverAs: "steer" });
2170
2689
  }
2171
- if (this.onInputCallback) {
2690
+ if (!this.session.isStreaming && this.onInputCallback) {
2172
2691
  this.onInputCallback(this.startPendingSubmission({ text: objective }));
2173
2692
  }
2174
2693
  }
@@ -2189,6 +2708,33 @@ export class InteractiveMode implements InteractiveModeContext {
2189
2708
  await this.#startGoalFromObjective(objective);
2190
2709
  }
2191
2710
 
2711
+ /** Manually (re-)open the plan-review overlay — bound to `/plan-review`. Lets
2712
+ * the operator pull the review back up after dismissing it, or review a plan
2713
+ * the agent wrote without calling `resolve`. There is no fixed plan filename:
2714
+ * `getPlanReferencePath()` is empty until a plan is actually approved (and does
2715
+ * not survive a restart), so this drives off the newest `local://<slug>-plan.md`
2716
+ * the agent wrote — the files persist in the session artifacts dir, so the scan
2717
+ * works before any review and across restarts. */
2718
+ async openPlanReview(): Promise<void> {
2719
+ if (!this.planModeEnabled) {
2720
+ this.showWarning("Plan mode is not active.");
2721
+ return;
2722
+ }
2723
+ const noPlan = "No plan to review yet — write one to a local://<slug>-plan.md file first.";
2724
+ const [planFilePath] = await this.#listLocalPlanFiles();
2725
+ if (!planFilePath) {
2726
+ this.showWarning(noPlan);
2727
+ return;
2728
+ }
2729
+ const planContent = await this.#readPlanFile(planFilePath);
2730
+ if (planContent === null) {
2731
+ this.showWarning(noPlan);
2732
+ return;
2733
+ }
2734
+ const { title } = resolvePlanTitle({ planContent, planFilePath });
2735
+ await this.handlePlanApproval({ planFilePath, title, planExists: true });
2736
+ }
2737
+
2192
2738
  async handlePlanApproval(details: PlanApprovalDetails): Promise<void> {
2193
2739
  if (!this.planModeEnabled) {
2194
2740
  this.showWarning("Plan mode is not active.");
@@ -2209,7 +2755,6 @@ export class InteractiveMode implements InteractiveModeContext {
2209
2755
  return;
2210
2756
  }
2211
2757
 
2212
- this.#renderPlanPreview(planContent, { append: true });
2213
2758
  const contextUsage = this.#getPlanApprovalContextUsage();
2214
2759
  const keepContextLabel = this.#formatKeepContextLabel(contextUsage);
2215
2760
  const keepContextDisabled = this.#isKeepContextDisabled(contextUsage);
@@ -2231,7 +2776,6 @@ export class InteractiveMode implements InteractiveModeContext {
2231
2776
  index: startTierIndex,
2232
2777
  segments: cycle.models.map(entry => ({
2233
2778
  label: entry.role,
2234
- color: MODEL_ROLES[entry.role as ModelRole]?.color,
2235
2779
  detail: entry.model.name || entry.model.id,
2236
2780
  })),
2237
2781
  onChange: index => {
@@ -2239,33 +2783,52 @@ export class InteractiveMode implements InteractiveModeContext {
2239
2783
  },
2240
2784
  }
2241
2785
  : undefined;
2242
- const helpText = slider ? `${this.#getPlanReviewHelpText()} ◂/▸ model` : this.#getPlanReviewHelpText();
2243
-
2244
- const choice = await this.showHookSelector(
2786
+ // The overlay now owns the dynamic, focus-aware help line; the caller only
2787
+ // supplies the trailing cancel hint.
2788
+ const helpText = "esc cancel";
2789
+ // In-overlay edits (section deletes/undo) and section annotations. Deletes
2790
+ // update `editedContent` (and mirror to disk); annotations build `feedback`
2791
+ // that the Refine branch re-prompts the model with.
2792
+ let editedContent: string | undefined;
2793
+ let feedback = "";
2794
+
2795
+ const choice = await this.showPlanReview(
2796
+ planContent,
2245
2797
  "Plan mode - next step",
2246
2798
  ["Approve and execute", "Approve and compact context", keepContextLabel, "Refine plan"],
2247
2799
  {
2248
2800
  helpText,
2249
2801
  onExternalEditor: () => void this.#openPlanInExternalEditor(planFilePath),
2802
+ onPlanEdited: content => {
2803
+ editedContent = content;
2804
+ void Bun.write(this.#resolvePlanFilePath(planFilePath), content);
2805
+ },
2806
+ onFeedbackChange: value => {
2807
+ feedback = value;
2808
+ },
2250
2809
  disabledIndices: keepContextDisabled ? [PLAN_KEEP_CONTEXT_OPTION_INDEX] : undefined,
2251
2810
  },
2252
2811
  { slider },
2253
2812
  );
2254
2813
 
2255
2814
  if (choice === "Approve and execute" || choice === "Approve and compact context" || choice === keepContextLabel) {
2256
- const finalPlanFilePath = details.finalPlanFilePath || planFilePath;
2257
2815
  try {
2258
- const latestPlanContent = await this.#readPlanFile(planFilePath);
2816
+ // Prefer in-overlay edits (already in memory) over a disk re-read; the
2817
+ // `onPlanEdited` write is fire-and-forget, so reading the file here could
2818
+ // race ahead of it.
2819
+ const latestPlanContent = editedContent ?? (await this.#readPlanFile(planFilePath));
2259
2820
  if (!latestPlanContent) {
2260
2821
  this.showError(`Plan file not found at ${planFilePath}`);
2261
2822
  return;
2262
2823
  }
2263
2824
  // Capture the operator's tier choice and hand it to #approvePlan, which
2264
- // applies it AFTER #exitPlanMode. #exitPlanMode restores
2825
+ // applies it AFTER #exitPlanMode. #exitPlanMode normally restores
2265
2826
  // #planModePreviousModelState (the model from before plan mode), so
2266
2827
  // applying the slider choice any earlier would be silently reverted —
2267
2828
  // the bug that made "continue with slow" keep executing on the default
2268
- // model. Deferred application also survives newSession()/compaction.
2829
+ // model. For compact-context approval, the plan model is kept through
2830
+ // compaction, then a successful compaction transitions to the slider model
2831
+ // (or restores the pre-plan model when no slider choice was made).
2269
2832
  // `cycle.currentIndex` is exactly that restored model, so any chosen tier
2270
2833
  // differing from it needs an explicit executionModel — this also covers
2271
2834
  // leaving the slider on its `default` anchor while planning ran elsewhere.
@@ -2273,7 +2836,6 @@ export class InteractiveMode implements InteractiveModeContext {
2273
2836
  cycle && selectedTierIndex !== cycle.currentIndex ? cycle.models[selectedTierIndex] : undefined;
2274
2837
  await this.#approvePlan(latestPlanContent, {
2275
2838
  planFilePath,
2276
- finalPlanFilePath,
2277
2839
  title: details.title,
2278
2840
  preserveContext: choice !== "Approve and execute",
2279
2841
  compactBeforeExecute: choice === "Approve and compact context",
@@ -2286,6 +2848,16 @@ export class InteractiveMode implements InteractiveModeContext {
2286
2848
  }
2287
2849
  return;
2288
2850
  }
2851
+
2852
+ if (choice === "Refine plan") {
2853
+ // Section annotations entered in the overlay become a refinement prompt
2854
+ // re-submitted to the model. With no annotations, fall back to today's
2855
+ // behavior: close the overlay and let the operator type their own.
2856
+ if (feedback.trim() && this.onInputCallback) {
2857
+ this.onInputCallback(this.startPendingSubmission({ text: feedback }));
2858
+ }
2859
+ return;
2860
+ }
2289
2861
  }
2290
2862
 
2291
2863
  /**
@@ -2346,8 +2918,7 @@ export class InteractiveMode implements InteractiveModeContext {
2346
2918
 
2347
2919
  stop(): void {
2348
2920
  if (this.loadingAnimation) {
2349
- this.loadingAnimation.stop();
2350
- this.loadingAnimation = undefined;
2921
+ this.#stopLoadingAnimation(false);
2351
2922
  }
2352
2923
  this.#cleanupMicAnimation();
2353
2924
  this.#cancelTodoAutoClearTimer();
@@ -2402,6 +2973,7 @@ export class InteractiveMode implements InteractiveModeContext {
2402
2973
  }
2403
2974
  this.#btwController.dispose();
2404
2975
  this.#omfgController.dispose();
2976
+ this.#focusController.dispose();
2405
2977
 
2406
2978
  // Emit shutdown event to hooks
2407
2979
  await this.session.dispose();
@@ -2439,9 +3011,6 @@ export class InteractiveMode implements InteractiveModeContext {
2439
3011
  initializeHookRunner(uiContext: ExtensionUIContext, hasUI: boolean): void {
2440
3012
  this.#extensionUiController.initializeHookRunner(uiContext, hasUI);
2441
3013
  }
2442
- createBackgroundUiContext(): ExtensionUIContext {
2443
- return this.#extensionUiController.createBackgroundUiContext();
2444
- }
2445
3014
 
2446
3015
  setEditorComponent(
2447
3016
  factory: ((tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager) => CustomEditor) | undefined,
@@ -2458,8 +3027,9 @@ export class InteractiveMode implements InteractiveModeContext {
2458
3027
  this.ui.requestRender(true);
2459
3028
  };
2460
3029
  nextEditor.onAutocompleteUpdate = () => {
2461
- this.ui.requestRender(false, { allowUnknownViewportMutation: true });
3030
+ this.ui.requestRender();
2462
3031
  };
3032
+ nextEditor.setShimmerRepaintHandler(() => this.ui.requestComponentRender(this.editor));
2463
3033
  nextEditor.setMaxHeight(this.#computeEditorMaxHeight());
2464
3034
  if (this.historyStorage) {
2465
3035
  nextEditor.setHistoryStorage(this.historyStorage);
@@ -2483,12 +3053,26 @@ export class InteractiveMode implements InteractiveModeContext {
2483
3053
  this.ui.requestRender();
2484
3054
  }
2485
3055
 
2486
- // Event handling
2487
- async handleBackgroundEvent(event: AgentSessionEvent): Promise<void> {
2488
- await this.#eventController.handleBackgroundEvent(event);
3056
+ // UI helpers
3057
+ present(content: Component | readonly Component[]): void {
3058
+ if (Array.isArray(content)) {
3059
+ for (const item of content) this.#mountChatChild(item);
3060
+ } else {
3061
+ this.#mountChatChild(content as Component);
3062
+ }
3063
+ this.ui.requestRender();
3064
+ }
3065
+
3066
+ #mountChatChild(item: Component): void {
3067
+ this.chatContainer.addChild(item);
3068
+ if (item instanceof ChatBlock) item.mount(this.#chatHost);
3069
+ }
3070
+
3071
+ resetTranscript(): void {
3072
+ this.chatContainer.dispose();
3073
+ this.chatContainer.clear();
2489
3074
  }
2490
3075
 
2491
- // UI helpers
2492
3076
  showStatus(message: string, options?: { dim?: boolean }): void {
2493
3077
  this.#uiHelpers.showStatus(message, options);
2494
3078
  }
@@ -2500,15 +3084,12 @@ export class InteractiveMode implements InteractiveModeContext {
2500
3084
  this.#pendingSubmissionDispose = undefined;
2501
3085
  this.#pendingWorkingMessage = undefined;
2502
3086
  if (this.loadingAnimation) {
2503
- this.loadingAnimation.stop();
2504
- this.loadingAnimation = undefined;
2505
- this.statusContainer.clear();
3087
+ this.#stopLoadingAnimation(true);
2506
3088
  }
2507
3089
  this.#uiHelpers.showError(message);
2508
3090
  }
2509
3091
 
2510
3092
  showPinnedError(message: string): void {
2511
- if (this.isBackgrounded) return;
2512
3093
  this.errorBannerContainer.clear();
2513
3094
  this.errorBannerContainer.addChild(new ErrorBannerComponent(message));
2514
3095
  this.ui.requestRender();
@@ -2566,26 +3147,76 @@ export class InteractiveMode implements InteractiveModeContext {
2566
3147
  this.ui.requestRender();
2567
3148
  }
2568
3149
 
3150
+ #clearWorkingMessageAccentCache(): void {
3151
+ this.#workingMessageAccentCacheKey = undefined;
3152
+ this.#workingMessageAccentCacheValue = undefined;
3153
+ this.#workingMessageAccentCacheHasValue = false;
3154
+ }
3155
+
3156
+ #buildWorkingMessageAccentCacheKey(): WorkingMessageAccentCacheKey {
3157
+ const sessionAccentEnabled = !isSettingsInitialized() || settings.get("statusLine.sessionAccent") !== false;
3158
+ return {
3159
+ sessionAccentEnabled,
3160
+ sessionName: sessionAccentEnabled ? this.sessionManager.getSessionName() : undefined,
3161
+ accentSurfaceLuminance: theme.accentSurfaceLuminance,
3162
+ };
3163
+ }
3164
+
3165
+ #workingMessageAccentCacheKeyEquals(a: WorkingMessageAccentCacheKey, b: WorkingMessageAccentCacheKey): boolean {
3166
+ return (
3167
+ a.sessionName === b.sessionName &&
3168
+ a.accentSurfaceLuminance === b.accentSurfaceLuminance &&
3169
+ a.sessionAccentEnabled === b.sessionAccentEnabled
3170
+ );
3171
+ }
3172
+
3173
+ #cacheWorkingMessageAccent(
3174
+ key: WorkingMessageAccentCacheKey,
3175
+ value: WorkingMessageAccent | undefined,
3176
+ ): WorkingMessageAccent | undefined {
3177
+ this.#workingMessageAccentCacheKey = key;
3178
+ this.#workingMessageAccentCacheValue = value;
3179
+ this.#workingMessageAccentCacheHasValue = true;
3180
+ return value;
3181
+ }
3182
+
2569
3183
  #getWorkingMessageAccent(): WorkingMessageAccent | undefined {
2570
- const accentEnabled = !isSettingsInitialized() || settings.get("statusLine.sessionAccent") !== false;
2571
- const sessionName = accentEnabled ? this.sessionManager.getSessionName() : undefined;
2572
- if (!sessionName) return undefined;
2573
- const hex = getSessionAccentHex(sessionName, theme.accentSurfaceLuminance);
3184
+ const key = this.#buildWorkingMessageAccentCacheKey();
3185
+ if (
3186
+ this.#workingMessageAccentCacheHasValue &&
3187
+ this.#workingMessageAccentCacheKey &&
3188
+ this.#workingMessageAccentCacheKeyEquals(key, this.#workingMessageAccentCacheKey)
3189
+ ) {
3190
+ return this.#workingMessageAccentCacheValue;
3191
+ }
3192
+ if (!key.sessionAccentEnabled || !key.sessionName) {
3193
+ return this.#cacheWorkingMessageAccent(key, undefined);
3194
+ }
3195
+ const hex = getSessionAccentHex(key.sessionName, theme.getMajorThemeColorHexes(), key.accentSurfaceLuminance);
2574
3196
  const main = getSessionAccentAnsi(hex);
2575
3197
  const dim = getSessionAccentAnsi(adjustHsv(hex, { s: 0.55, v: 0.65 }));
2576
- return main && dim ? { main, dim } : undefined;
3198
+ return this.#cacheWorkingMessageAccent(key, main && dim ? { main, dim } : undefined);
2577
3199
  }
2578
3200
 
2579
3201
  ensureLoadingAnimation(): void {
2580
3202
  if (!this.loadingAnimation) {
3203
+ this.#clearWorkingMessageAccentCache();
2581
3204
  this.statusContainer.clear();
3205
+ const messageColorFn = ((message: string) =>
3206
+ renderWorkingMessage(message, this.#getWorkingMessageAccent())) as LoaderMessageColorFn & {
3207
+ animated?: true;
3208
+ };
3209
+ // Shimmer drives the 30fps redraw; when it is disabled the working
3210
+ // message is static, so leave `animated` unset and let the loader use
3211
+ // the spinner-only ~12.5fps cadence instead of repainting a frozen line.
3212
+ if (shimmerEnabled()) messageColorFn.animated = true;
2582
3213
  this.loadingAnimation = new Loader(
2583
3214
  this.ui,
2584
3215
  spinner => {
2585
3216
  const accent = this.#getWorkingMessageAccent();
2586
3217
  return accent ? `${accent.main}${spinner}\x1b[39m` : theme.fg("accent", spinner);
2587
3218
  },
2588
- message => renderWorkingMessage(message, this.#getWorkingMessageAccent()),
3219
+ messageColorFn,
2589
3220
  this.#defaultWorkingMessage,
2590
3221
  getSymbolTheme().spinnerFrames,
2591
3222
  );
@@ -2595,6 +3226,16 @@ export class InteractiveMode implements InteractiveModeContext {
2595
3226
  this.applyPendingWorkingMessage();
2596
3227
  }
2597
3228
 
3229
+ #stopLoadingAnimation(clearStatusContainer: boolean): void {
3230
+ if (!this.loadingAnimation) return;
3231
+ this.loadingAnimation.stop();
3232
+ this.loadingAnimation = undefined;
3233
+ this.#clearWorkingMessageAccentCache();
3234
+ if (clearStatusContainer) {
3235
+ this.statusContainer.clear();
3236
+ }
3237
+ }
3238
+
2598
3239
  setWorkingMessage(message?: string): void {
2599
3240
  if (message === undefined) {
2600
3241
  this.#pendingWorkingMessage = undefined;
@@ -2634,8 +3275,8 @@ export class InteractiveMode implements InteractiveModeContext {
2634
3275
  this.#uiHelpers.updatePendingMessagesDisplay();
2635
3276
  }
2636
3277
 
2637
- queueCompactionMessage(text: string, mode: "steer" | "followUp"): void {
2638
- this.#uiHelpers.queueCompactionMessage(text, mode);
3278
+ queueCompactionMessage(text: string, mode: "steer" | "followUp", images?: ImageContent[]): void {
3279
+ this.#uiHelpers.queueCompactionMessage(text, mode, images);
2639
3280
  }
2640
3281
 
2641
3282
  flushCompactionQueue(options?: { willRetry?: boolean }): Promise<void> {
@@ -2664,11 +3305,8 @@ export class InteractiveMode implements InteractiveModeContext {
2664
3305
  this.#uiHelpers.renderSessionContext(sessionContext, options);
2665
3306
  }
2666
3307
 
2667
- renderInitialMessages(
2668
- prebuiltContext?: SessionContext,
2669
- options?: { preserveExistingChat?: boolean; clearTerminalHistory?: boolean },
2670
- ): void {
2671
- this.#uiHelpers.renderInitialMessages(prebuiltContext, options);
3308
+ renderInitialMessages(options?: { preserveExistingChat?: boolean; clearTerminalHistory?: boolean }): void {
3309
+ this.#uiHelpers.renderInitialMessages(options);
2672
3310
  }
2673
3311
 
2674
3312
  getUserMessageText(message: Message): string {
@@ -2737,7 +3375,7 @@ export class InteractiveMode implements InteractiveModeContext {
2737
3375
  this.#omfgController.dispose();
2738
3376
  this.#extensionUiController.clearExtensionTerminalInputListeners();
2739
3377
  this.clearPinnedError();
2740
- this.#planReviewContainer = undefined;
3378
+ this.#hidePlanReview();
2741
3379
  }
2742
3380
 
2743
3381
  handleClearCommand(): Promise<void> {
@@ -2745,6 +3383,10 @@ export class InteractiveMode implements InteractiveModeContext {
2745
3383
  return this.#commandController.handleClearCommand();
2746
3384
  }
2747
3385
 
3386
+ handleFreshCommand(): Promise<void> {
3387
+ return this.#commandController.handleFreshCommand();
3388
+ }
3389
+
2748
3390
  handleDropCommand(): Promise<void> {
2749
3391
  this.#prepareSessionSwitch();
2750
3392
  return this.#commandController.handleDropCommand();
@@ -2779,7 +3421,11 @@ export class InteractiveMode implements InteractiveModeContext {
2779
3421
  await this.#sttController.toggle(this.editor, {
2780
3422
  showWarning: (msg: string) => this.showWarning(msg),
2781
3423
  showStatus: (msg: string) => this.showStatus(msg),
3424
+ requestRender: () => this.ui.requestRender(),
2782
3425
  onStateChange: (state: SttState) => {
3426
+ // Duck assistant speech while the user is talking (push-to-talk); restore after.
3427
+ if (state === "recording") vocalizer.duck();
3428
+ else vocalizer.unduck();
2783
3429
  if (state === "recording") {
2784
3430
  this.#voicePreviousShowHardwareCursor = this.ui.getShowHardwareCursor();
2785
3431
  this.#voicePreviousUseTerminalCursor = this.editor.getUseTerminalCursor();
@@ -2816,7 +3462,9 @@ export class InteractiveMode implements InteractiveModeContext {
2816
3462
  this.#voiceAnimationInterval = setInterval(() => {
2817
3463
  this.#voiceHue = (this.#voiceHue + 8) % 360;
2818
3464
  this.#updateMicIcon();
2819
- this.ui.requestRender();
3465
+ // Component-scoped: the hue sweep only recolors the editor's cursor
3466
+ // glyph, so the transcript subtree is reused per animation frame.
3467
+ this.ui.requestComponentRender(this.editor);
2820
3468
  }, 60);
2821
3469
  }
2822
3470
 
@@ -2844,17 +3492,12 @@ export class InteractiveMode implements InteractiveModeContext {
2844
3492
  }
2845
3493
  }
2846
3494
 
2847
- showDebugSelector(): void {
2848
- this.#selectorController.showDebugSelector();
3495
+ async showDebugSelector(): Promise<void> {
3496
+ await this.#selectorController.showDebugSelector();
2849
3497
  }
2850
3498
 
2851
- showSessionObserver(): void {
2852
- const sessions = this.#observerRegistry.getSessions();
2853
- if (sessions.length <= 1) {
2854
- this.showStatus("No active subagent sessions");
2855
- return;
2856
- }
2857
- this.#selectorController.showSessionObserver(this.#observerRegistry);
3499
+ showAgentHub(options?: { requireContent?: boolean }): void {
3500
+ this.#selectorController.showAgentHub(this.#observerRegistry, options);
2858
3501
  }
2859
3502
 
2860
3503
  resetObserverRegistry(): void {
@@ -2880,8 +3523,11 @@ export class InteractiveMode implements InteractiveModeContext {
2880
3523
  await controller.handle(text);
2881
3524
  }
2882
3525
 
2883
- handleCompactCommand(customInstructions?: string): Promise<CompactionOutcome> {
2884
- return this.#commandController.handleCompactCommand(customInstructions);
3526
+ handleCompactCommand(
3527
+ customInstructions?: string,
3528
+ beforeFlush?: (outcome: CompactionOutcome) => void | Promise<void>,
3529
+ ): Promise<CompactionOutcome> {
3530
+ return this.#commandController.handleCompactCommand(customInstructions, beforeFlush);
2885
3531
  }
2886
3532
 
2887
3533
  handleHandoffCommand(customInstructions?: string): Promise<void> {
@@ -2959,6 +3605,14 @@ export class InteractiveMode implements InteractiveModeContext {
2959
3605
  return this.#selectorController.showOAuthSelector(mode, providerId);
2960
3606
  }
2961
3607
 
3608
+ showResetUsageSelector(): Promise<void> {
3609
+ return this.#selectorController.showResetUsageSelector();
3610
+ }
3611
+
3612
+ showProviderSetup(): Promise<void> {
3613
+ return runProviderSetupWizard(this);
3614
+ }
3615
+
2962
3616
  showHookConfirm(title: string, message: string): Promise<boolean> {
2963
3617
  return this.#extensionUiController.showHookConfirm(title, message);
2964
3618
  }
@@ -2980,10 +3634,6 @@ export class InteractiveMode implements InteractiveModeContext {
2980
3634
  this.#inputController.handleDequeue();
2981
3635
  }
2982
3636
 
2983
- handleBackgroundCommand(): void {
2984
- this.#inputController.handleBackgroundCommand();
2985
- }
2986
-
2987
3637
  handleImagePaste(): Promise<boolean> {
2988
3638
  return this.#inputController.handleImagePaste();
2989
3639
  }
@@ -2992,6 +3642,10 @@ export class InteractiveMode implements InteractiveModeContext {
2992
3642
  return this.#btwController.start(question);
2993
3643
  }
2994
3644
 
3645
+ handleTanCommand(work: string): Promise<void> {
3646
+ return this.#tanCommandController.start(work);
3647
+ }
3648
+
2995
3649
  hasActiveBtw(): boolean {
2996
3650
  return this.#btwController.hasActiveRequest();
2997
3651
  }