pi-agent-zh 17.1.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 (1519) hide show
  1. package/CHANGELOG.md +14459 -0
  2. package/README.md +35 -0
  3. package/dist/CHANGELOG-vt8ene9g.md +14459 -0
  4. package/dist/cli.js +22079 -0
  5. package/dist/template-dys3vk5b.js +1671 -0
  6. package/dist/template-f8wx9vfn.css +1355 -0
  7. package/dist/template-qat058wr.html +55 -0
  8. package/dist/tool-views.generated-jdfmzwmn.js +35 -0
  9. package/examples/README.md +21 -0
  10. package/examples/custom-tools/README.md +104 -0
  11. package/examples/custom-tools/hello/index.ts +20 -0
  12. package/examples/extensions/README.md +142 -0
  13. package/examples/extensions/api-demo.ts +79 -0
  14. package/examples/extensions/chalk-logger.ts +25 -0
  15. package/examples/extensions/hello.ts +31 -0
  16. package/examples/extensions/pirate.ts +43 -0
  17. package/examples/extensions/plan-mode.ts +549 -0
  18. package/examples/extensions/reload-runtime.ts +38 -0
  19. package/examples/extensions/thinking-note.ts +13 -0
  20. package/examples/extensions/tools.ts +145 -0
  21. package/examples/extensions/with-deps/index.ts +36 -0
  22. package/examples/extensions/with-deps/package-lock.json +31 -0
  23. package/examples/extensions/with-deps/package.json +17 -0
  24. package/examples/hooks/README.md +56 -0
  25. package/examples/hooks/auto-commit-on-exit.ts +48 -0
  26. package/examples/hooks/confirm-destructive.ts +58 -0
  27. package/examples/hooks/custom-compaction.ts +115 -0
  28. package/examples/hooks/dirty-repo-guard.ts +51 -0
  29. package/examples/hooks/file-trigger.ts +40 -0
  30. package/examples/hooks/git-checkpoint.ts +52 -0
  31. package/examples/hooks/handoff.ts +149 -0
  32. package/examples/hooks/permission-gate.ts +33 -0
  33. package/examples/hooks/protected-paths.ts +29 -0
  34. package/examples/hooks/qna.ts +118 -0
  35. package/examples/hooks/status-line.ts +39 -0
  36. package/examples/sdk/01-minimal.ts +21 -0
  37. package/examples/sdk/02-custom-model.ts +49 -0
  38. package/examples/sdk/03-custom-prompt.ts +46 -0
  39. package/examples/sdk/04-skills.ts +43 -0
  40. package/examples/sdk/06-extensions.ts +82 -0
  41. package/examples/sdk/06-hooks.ts +61 -0
  42. package/examples/sdk/07-context-files.ts +35 -0
  43. package/examples/sdk/08-prompt-templates.ts +41 -0
  44. package/examples/sdk/08-slash-commands.ts +46 -0
  45. package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
  46. package/examples/sdk/11-sessions.ts +47 -0
  47. package/examples/sdk/12-redis-sessions.ts +54 -0
  48. package/examples/sdk/13-sql-sessions.ts +61 -0
  49. package/examples/sdk/README.md +169 -0
  50. package/package.json +606 -0
  51. package/scripts/bench-guard.ts +71 -0
  52. package/scripts/bench-title-models.ts +332 -0
  53. package/scripts/build-binary.ts +117 -0
  54. package/scripts/bundle-dist.ts +133 -0
  55. package/scripts/compile-binary.ts +69 -0
  56. package/scripts/embed-mupdf-wasm.ts +67 -0
  57. package/scripts/format-prompts.ts +68 -0
  58. package/scripts/generate-aria-snapshot.ts +134 -0
  59. package/scripts/generate-docs-index.ts +58 -0
  60. package/scripts/generate-share-viewer.ts +34 -0
  61. package/scripts/legacy-pi-virtual-module.ts +195 -0
  62. package/scripts/measure-prompt-tokens.ts +63 -0
  63. package/scripts/omp +42 -0
  64. package/scripts/omp.ts +19 -0
  65. package/src/advisor/advise-tool.ts +216 -0
  66. package/src/advisor/config.ts +341 -0
  67. package/src/advisor/emission-guard.ts +172 -0
  68. package/src/advisor/index.ts +6 -0
  69. package/src/advisor/runtime.ts +1232 -0
  70. package/src/advisor/transcript-recorder.ts +159 -0
  71. package/src/advisor/watchdog.ts +135 -0
  72. package/src/async/index.ts +1 -0
  73. package/src/async/job-manager.ts +821 -0
  74. package/src/auto-thinking/classifier.ts +182 -0
  75. package/src/autolearn/controller.ts +152 -0
  76. package/src/autolearn/managed-skills.ts +255 -0
  77. package/src/autoresearch/command-resume.md +14 -0
  78. package/src/autoresearch/dashboard.ts +436 -0
  79. package/src/autoresearch/git.ts +331 -0
  80. package/src/autoresearch/helpers.ts +218 -0
  81. package/src/autoresearch/index.ts +541 -0
  82. package/src/autoresearch/prompt-setup.md +43 -0
  83. package/src/autoresearch/prompt.md +103 -0
  84. package/src/autoresearch/resume-message.md +10 -0
  85. package/src/autoresearch/state.ts +273 -0
  86. package/src/autoresearch/storage.ts +700 -0
  87. package/src/autoresearch/tools/init-experiment.ts +269 -0
  88. package/src/autoresearch/tools/log-experiment.ts +521 -0
  89. package/src/autoresearch/tools/run-experiment.ts +407 -0
  90. package/src/autoresearch/tools/update-notes.ts +109 -0
  91. package/src/autoresearch/types.ts +168 -0
  92. package/src/capability/context-file.ts +44 -0
  93. package/src/capability/extension-module.ts +34 -0
  94. package/src/capability/extension.ts +47 -0
  95. package/src/capability/fs.ts +117 -0
  96. package/src/capability/hook.ts +40 -0
  97. package/src/capability/index.ts +467 -0
  98. package/src/capability/instruction.ts +37 -0
  99. package/src/capability/mcp.ts +97 -0
  100. package/src/capability/prompt.ts +35 -0
  101. package/src/capability/rule-buckets.ts +66 -0
  102. package/src/capability/rule.ts +298 -0
  103. package/src/capability/settings.ts +34 -0
  104. package/src/capability/skill.ts +63 -0
  105. package/src/capability/slash-command.ts +40 -0
  106. package/src/capability/ssh.ts +41 -0
  107. package/src/capability/system-prompt.ts +34 -0
  108. package/src/capability/tool.ts +38 -0
  109. package/src/capability/types.ts +187 -0
  110. package/src/cleanse/agent.ts +226 -0
  111. package/src/cleanse/balance.ts +79 -0
  112. package/src/cleanse/checkers.ts +996 -0
  113. package/src/cleanse/index.ts +190 -0
  114. package/src/cleanse/loop.ts +51 -0
  115. package/src/cleanse/parsers.ts +726 -0
  116. package/src/cleanse/progress.ts +50 -0
  117. package/src/cleanse/prompts/assignment.md +47 -0
  118. package/src/cleanse/types.ts +72 -0
  119. package/src/cli/agents-cli.ts +138 -0
  120. package/src/cli/args.ts +420 -0
  121. package/src/cli/auth-broker-cli.ts +940 -0
  122. package/src/cli/auth-gateway-cli.ts +674 -0
  123. package/src/cli/bench-cli.ts +990 -0
  124. package/src/cli/classify-install-target.ts +76 -0
  125. package/src/cli/claude-trace-cli.ts +795 -0
  126. package/src/cli/commands/init-xdg.ts +27 -0
  127. package/src/cli/completion-gen.ts +550 -0
  128. package/src/cli/config-cli.ts +459 -0
  129. package/src/cli/dry-balance-cli.ts +864 -0
  130. package/src/cli/extension-flags.ts +48 -0
  131. package/src/cli/file-processor.ts +132 -0
  132. package/src/cli/flag-tables.ts +352 -0
  133. package/src/cli/gallery-cli.ts +272 -0
  134. package/src/cli/gallery-fixtures/agentic.ts +420 -0
  135. package/src/cli/gallery-fixtures/codeintel.ts +187 -0
  136. package/src/cli/gallery-fixtures/edit.ts +254 -0
  137. package/src/cli/gallery-fixtures/fs.ts +220 -0
  138. package/src/cli/gallery-fixtures/index.ts +40 -0
  139. package/src/cli/gallery-fixtures/interaction.ts +46 -0
  140. package/src/cli/gallery-fixtures/memory.ts +81 -0
  141. package/src/cli/gallery-fixtures/misc.ts +177 -0
  142. package/src/cli/gallery-fixtures/search.ts +135 -0
  143. package/src/cli/gallery-fixtures/shell.ts +241 -0
  144. package/src/cli/gallery-fixtures/types.ts +57 -0
  145. package/src/cli/gallery-fixtures/web.ts +158 -0
  146. package/src/cli/gallery-screenshot.ts +279 -0
  147. package/src/cli/gc-cli.ts +946 -0
  148. package/src/cli/grep-cli.ts +161 -0
  149. package/src/cli/grievances-cli.ts +256 -0
  150. package/src/cli/initial-message.ts +58 -0
  151. package/src/cli/models-cli.ts +388 -0
  152. package/src/cli/plugin-cli.ts +996 -0
  153. package/src/cli/profile-alias.ts +369 -0
  154. package/src/cli/profile-bootstrap.ts +233 -0
  155. package/src/cli/read-cli.ts +99 -0
  156. package/src/cli/session-picker.ts +93 -0
  157. package/src/cli/setup-cli.ts +320 -0
  158. package/src/cli/setup-model-picker.ts +43 -0
  159. package/src/cli/shell-cli.ts +176 -0
  160. package/src/cli/ssh-cli.ts +179 -0
  161. package/src/cli/startup-cwd.ts +58 -0
  162. package/src/cli/stats-cli.ts +229 -0
  163. package/src/cli/tiny-models-cli.ts +153 -0
  164. package/src/cli/ttsr-cli.ts +995 -0
  165. package/src/cli/update-cli.ts +1219 -0
  166. package/src/cli/usage-cli.ts +1084 -0
  167. package/src/cli/usage-error.ts +7 -0
  168. package/src/cli/web-search-cli.ts +144 -0
  169. package/src/cli/worktree-cli.ts +311 -0
  170. package/src/cli-commands.ts +166 -0
  171. package/src/cli.ts +407 -0
  172. package/src/collab/crypto.ts +63 -0
  173. package/src/collab/display-name.ts +13 -0
  174. package/src/collab/guest.ts +731 -0
  175. package/src/collab/host.ts +691 -0
  176. package/src/collab/protocol.ts +296 -0
  177. package/src/collab/relay-client.ts +282 -0
  178. package/src/collab/replication-shrink.ts +111 -0
  179. package/src/commands/acp.ts +33 -0
  180. package/src/commands/agents.ts +57 -0
  181. package/src/commands/auth-broker.ts +99 -0
  182. package/src/commands/auth-gateway.ts +69 -0
  183. package/src/commands/bench.ts +65 -0
  184. package/src/commands/cleanse.ts +45 -0
  185. package/src/commands/commit.ts +46 -0
  186. package/src/commands/complete.ts +66 -0
  187. package/src/commands/completions.ts +60 -0
  188. package/src/commands/config.ts +51 -0
  189. package/src/commands/dry-balance.ts +43 -0
  190. package/src/commands/gallery.ts +60 -0
  191. package/src/commands/gc.ts +46 -0
  192. package/src/commands/grep.ts +48 -0
  193. package/src/commands/grievances.ts +51 -0
  194. package/src/commands/install.ts +107 -0
  195. package/src/commands/join.ts +39 -0
  196. package/src/commands/launch.ts +212 -0
  197. package/src/commands/models.ts +60 -0
  198. package/src/commands/plugin.ts +78 -0
  199. package/src/commands/read.ts +38 -0
  200. package/src/commands/say.ts +145 -0
  201. package/src/commands/setup.ts +67 -0
  202. package/src/commands/shell.ts +29 -0
  203. package/src/commands/ssh.ts +60 -0
  204. package/src/commands/stats.ts +29 -0
  205. package/src/commands/tiny-models.ts +36 -0
  206. package/src/commands/token.ts +164 -0
  207. package/src/commands/ttsr.ts +125 -0
  208. package/src/commands/update.ts +33 -0
  209. package/src/commands/usage.ts +54 -0
  210. package/src/commands/web-search.ts +42 -0
  211. package/src/commands/worktree.ts +62 -0
  212. package/src/commit/agentic/agent.ts +322 -0
  213. package/src/commit/agentic/fallback.ts +96 -0
  214. package/src/commit/agentic/index.ts +382 -0
  215. package/src/commit/agentic/lock-files.ts +107 -0
  216. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  217. package/src/commit/agentic/prompts/session-user.md +25 -0
  218. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  219. package/src/commit/agentic/prompts/system.md +38 -0
  220. package/src/commit/agentic/state.ts +60 -0
  221. package/src/commit/agentic/tools/analyze-file.ts +148 -0
  222. package/src/commit/agentic/tools/git-file-diff.ts +191 -0
  223. package/src/commit/agentic/tools/git-hunk.ts +52 -0
  224. package/src/commit/agentic/tools/git-overview.ts +62 -0
  225. package/src/commit/agentic/tools/index.ts +54 -0
  226. package/src/commit/agentic/tools/propose-changelog.ts +147 -0
  227. package/src/commit/agentic/tools/propose-commit.ts +109 -0
  228. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  229. package/src/commit/agentic/tools/schemas.ts +11 -0
  230. package/src/commit/agentic/tools/split-commit.ts +241 -0
  231. package/src/commit/agentic/topo-sort.ts +44 -0
  232. package/src/commit/agentic/trivial.ts +51 -0
  233. package/src/commit/agentic/validation.ts +183 -0
  234. package/src/commit/analysis/conventional.ts +64 -0
  235. package/src/commit/analysis/index.ts +4 -0
  236. package/src/commit/analysis/scope.ts +242 -0
  237. package/src/commit/analysis/summary.ts +107 -0
  238. package/src/commit/analysis/validation.ts +66 -0
  239. package/src/commit/changelog/detect.ts +40 -0
  240. package/src/commit/changelog/generate.ts +101 -0
  241. package/src/commit/changelog/index.ts +234 -0
  242. package/src/commit/changelog/parse.ts +44 -0
  243. package/src/commit/cli.ts +85 -0
  244. package/src/commit/git/diff.ts +148 -0
  245. package/src/commit/index.ts +5 -0
  246. package/src/commit/map-reduce/index.ts +69 -0
  247. package/src/commit/map-reduce/map-phase.ts +193 -0
  248. package/src/commit/map-reduce/reduce-phase.ts +49 -0
  249. package/src/commit/map-reduce/utils.ts +9 -0
  250. package/src/commit/message.ts +11 -0
  251. package/src/commit/model-selection.ts +95 -0
  252. package/src/commit/pipeline.ts +243 -0
  253. package/src/commit/prompts/analysis-system.md +148 -0
  254. package/src/commit/prompts/analysis-user.md +38 -0
  255. package/src/commit/prompts/changelog-system.md +50 -0
  256. package/src/commit/prompts/changelog-user.md +18 -0
  257. package/src/commit/prompts/file-observer-system.md +24 -0
  258. package/src/commit/prompts/file-observer-user.md +8 -0
  259. package/src/commit/prompts/reduce-system.md +50 -0
  260. package/src/commit/prompts/reduce-user.md +17 -0
  261. package/src/commit/prompts/summary-retry.md +3 -0
  262. package/src/commit/prompts/summary-system.md +38 -0
  263. package/src/commit/prompts/summary-user.md +13 -0
  264. package/src/commit/prompts/types-description.md +2 -0
  265. package/src/commit/shared-llm.ts +70 -0
  266. package/src/commit/types.ts +118 -0
  267. package/src/commit/utils/exclusions.ts +42 -0
  268. package/src/commit/utils.ts +58 -0
  269. package/src/config/api-key-resolver.ts +81 -0
  270. package/src/config/append-only-context-mode.ts +76 -0
  271. package/src/config/config-file.ts +347 -0
  272. package/src/config/file-lock.ts +164 -0
  273. package/src/config/inline-tool-descriptors-mode.ts +26 -0
  274. package/src/config/keybindings.ts +688 -0
  275. package/src/config/mcp-schema.json +247 -0
  276. package/src/config/model-discovery.ts +999 -0
  277. package/src/config/model-registry.ts +2725 -0
  278. package/src/config/model-resolver.ts +2068 -0
  279. package/src/config/model-roles.ts +113 -0
  280. package/src/config/models-config-schema-bundle.ts +313 -0
  281. package/src/config/models-config-schema.ts +14 -0
  282. package/src/config/models-config.ts +130 -0
  283. package/src/config/prompt-templates.ts +205 -0
  284. package/src/config/provider-globals.ts +25 -0
  285. package/src/config/resolve-config-value.ts +94 -0
  286. package/src/config/service-tier.ts +141 -0
  287. package/src/config/settings-schema.ts +5751 -0
  288. package/src/config/settings.ts +2369 -0
  289. package/src/config.ts +242 -0
  290. package/src/cursor.ts +513 -0
  291. package/src/dap/client.ts +1043 -0
  292. package/src/dap/config.ts +480 -0
  293. package/src/dap/defaults.json +212 -0
  294. package/src/dap/index.ts +4 -0
  295. package/src/dap/session.ts +1841 -0
  296. package/src/dap/types.ts +611 -0
  297. package/src/debug/index.ts +584 -0
  298. package/src/debug/log-formatting.ts +58 -0
  299. package/src/debug/log-viewer.ts +966 -0
  300. package/src/debug/profiler.ts +168 -0
  301. package/src/debug/protocol-probe.ts +267 -0
  302. package/src/debug/raw-sse-buffer.ts +421 -0
  303. package/src/debug/raw-sse.ts +312 -0
  304. package/src/debug/remote-debugger.ts +151 -0
  305. package/src/debug/report-bundle.ts +411 -0
  306. package/src/debug/system-info.ts +111 -0
  307. package/src/debug/terminal-info.ts +124 -0
  308. package/src/discovery/agents-md.ts +67 -0
  309. package/src/discovery/agents.ts +230 -0
  310. package/src/discovery/at-imports.ts +273 -0
  311. package/src/discovery/builtin-defaults.ts +39 -0
  312. package/src/discovery/builtin-rules/go-add-cleanup.md +33 -0
  313. package/src/discovery/builtin-rules/go-bench-loop.md +36 -0
  314. package/src/discovery/builtin-rules/go-exp-promoted.md +40 -0
  315. package/src/discovery/builtin-rules/go-ioutil.md +37 -0
  316. package/src/discovery/builtin-rules/go-join-hostport.md +30 -0
  317. package/src/discovery/builtin-rules/go-new-expr.md +44 -0
  318. package/src/discovery/builtin-rules/go-rand-v2.md +41 -0
  319. package/src/discovery/builtin-rules/go-range-int.md +45 -0
  320. package/src/discovery/builtin-rules/index.ts +74 -0
  321. package/src/discovery/builtin-rules/rs-box-leak.md +49 -0
  322. package/src/discovery/builtin-rules/rs-future-prelude.md +24 -0
  323. package/src/discovery/builtin-rules/rs-lazylock.md +52 -0
  324. package/src/discovery/builtin-rules/rs-match-ergonomics.md +68 -0
  325. package/src/discovery/builtin-rules/rs-parking-lot.md +45 -0
  326. package/src/discovery/builtin-rules/rs-result-type.md +20 -0
  327. package/src/discovery/builtin-rules/ts-bare-catch.md +39 -0
  328. package/src/discovery/builtin-rules/ts-import-type.md +43 -0
  329. package/src/discovery/builtin-rules/ts-no-any.md +66 -0
  330. package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +45 -0
  331. package/src/discovery/builtin-rules/ts-no-dynamic-import.md +40 -0
  332. package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +55 -0
  333. package/src/discovery/builtin-rules/ts-no-local-is-record.md +48 -0
  334. package/src/discovery/builtin-rules/ts-no-return-type.md +45 -0
  335. package/src/discovery/builtin-rules/ts-no-test-timers.md +55 -0
  336. package/src/discovery/builtin-rules/ts-no-tiny-functions.md +51 -0
  337. package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +66 -0
  338. package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +75 -0
  339. package/src/discovery/builtin-rules/ts-set-map.md +28 -0
  340. package/src/discovery/builtin.ts +935 -0
  341. package/src/discovery/claude-plugins.ts +624 -0
  342. package/src/discovery/claude.ts +588 -0
  343. package/src/discovery/cline.ts +83 -0
  344. package/src/discovery/codex.ts +540 -0
  345. package/src/discovery/cursor.ts +220 -0
  346. package/src/discovery/gemini.ts +383 -0
  347. package/src/discovery/github.ts +337 -0
  348. package/src/discovery/helpers.ts +1159 -0
  349. package/src/discovery/index.ts +81 -0
  350. package/src/discovery/mcp-json.ts +172 -0
  351. package/src/discovery/omp-extension-roots.ts +213 -0
  352. package/src/discovery/omp-plugins.ts +387 -0
  353. package/src/discovery/opencode.ts +441 -0
  354. package/src/discovery/plugin-dir-roots.ts +28 -0
  355. package/src/discovery/ssh.ts +153 -0
  356. package/src/discovery/substitute-plugin-root.ts +77 -0
  357. package/src/discovery/vscode.ts +105 -0
  358. package/src/discovery/windsurf.ts +147 -0
  359. package/src/edit/apply-patch/index.ts +87 -0
  360. package/src/edit/apply-patch/parser.ts +174 -0
  361. package/src/edit/diff.ts +999 -0
  362. package/src/edit/file-snapshot-store.ts +148 -0
  363. package/src/edit/hashline/block-resolver.ts +33 -0
  364. package/src/edit/hashline/diff.ts +356 -0
  365. package/src/edit/hashline/execute.ts +280 -0
  366. package/src/edit/hashline/filesystem.ts +223 -0
  367. package/src/edit/hashline/index.ts +5 -0
  368. package/src/edit/hashline/noop-loop-guard.ts +99 -0
  369. package/src/edit/hashline/params.ts +12 -0
  370. package/src/edit/index.ts +676 -0
  371. package/src/edit/modes/apply-patch.lark +19 -0
  372. package/src/edit/modes/apply-patch.ts +53 -0
  373. package/src/edit/modes/patch.ts +1958 -0
  374. package/src/edit/modes/replace.ts +1137 -0
  375. package/src/edit/normalize.ts +345 -0
  376. package/src/edit/notebook.ts +242 -0
  377. package/src/edit/read-file.ts +25 -0
  378. package/src/edit/renderer.ts +998 -0
  379. package/src/edit/snapshot-details.ts +77 -0
  380. package/src/edit/streaming.ts +698 -0
  381. package/src/eval/agent-bridge.ts +224 -0
  382. package/src/eval/backend-helpers.ts +48 -0
  383. package/src/eval/backend.ts +71 -0
  384. package/src/eval/bridge-timeout.ts +62 -0
  385. package/src/eval/budget-bridge.ts +48 -0
  386. package/src/eval/completion-bridge.ts +211 -0
  387. package/src/eval/concurrency-bridge.ts +34 -0
  388. package/src/eval/executor-base.ts +504 -0
  389. package/src/eval/idle-timeout.ts +91 -0
  390. package/src/eval/index.ts +6 -0
  391. package/src/eval/jl/executor.ts +540 -0
  392. package/src/eval/jl/index.ts +54 -0
  393. package/src/eval/jl/kernel.ts +236 -0
  394. package/src/eval/jl/prelude.jl +736 -0
  395. package/src/eval/jl/prelude.ts +3 -0
  396. package/src/eval/jl/runner.jl +666 -0
  397. package/src/eval/jl/runtime.ts +118 -0
  398. package/src/eval/js/context-manager.ts +701 -0
  399. package/src/eval/js/executor.ts +175 -0
  400. package/src/eval/js/index.ts +40 -0
  401. package/src/eval/js/process-entry.ts +31 -0
  402. package/src/eval/js/shared/helpers.ts +170 -0
  403. package/src/eval/js/shared/indirect-eval.ts +30 -0
  404. package/src/eval/js/shared/local-module-loader.ts +364 -0
  405. package/src/eval/js/shared/prelude.ts +2 -0
  406. package/src/eval/js/shared/prelude.txt +294 -0
  407. package/src/eval/js/shared/rewrite-imports.ts +550 -0
  408. package/src/eval/js/shared/runtime.ts +590 -0
  409. package/src/eval/js/shared/types.ts +18 -0
  410. package/src/eval/js/tool-bridge.ts +163 -0
  411. package/src/eval/js/worker-core.ts +380 -0
  412. package/src/eval/js/worker-entry.ts +37 -0
  413. package/src/eval/js/worker-protocol.ts +47 -0
  414. package/src/eval/kernel-base.ts +569 -0
  415. package/src/eval/py/display.ts +71 -0
  416. package/src/eval/py/executor.ts +603 -0
  417. package/src/eval/py/index.ts +57 -0
  418. package/src/eval/py/kernel.ts +234 -0
  419. package/src/eval/py/prelude.py +672 -0
  420. package/src/eval/py/prelude.ts +3 -0
  421. package/src/eval/py/runner.py +1388 -0
  422. package/src/eval/py/runtime.ts +276 -0
  423. package/src/eval/py/spawn-options.ts +139 -0
  424. package/src/eval/py/tool-bridge.ts +181 -0
  425. package/src/eval/rb/executor.ts +504 -0
  426. package/src/eval/rb/index.ts +54 -0
  427. package/src/eval/rb/kernel.ts +231 -0
  428. package/src/eval/rb/prelude.rb +552 -0
  429. package/src/eval/rb/prelude.ts +3 -0
  430. package/src/eval/rb/runner.rb +581 -0
  431. package/src/eval/rb/runtime.ts +132 -0
  432. package/src/eval/runtime-env.ts +104 -0
  433. package/src/eval/session-id.ts +8 -0
  434. package/src/eval/types.ts +48 -0
  435. package/src/exa/index.ts +2 -0
  436. package/src/exa/mcp-client.ts +370 -0
  437. package/src/exa/types.ts +69 -0
  438. package/src/exec/bash-executor.ts +627 -0
  439. package/src/exec/direnv.ts +145 -0
  440. package/src/exec/exec.ts +53 -0
  441. package/src/exec/non-interactive-env.ts +118 -0
  442. package/src/export/custom-share.ts +65 -0
  443. package/src/export/html/args.ts +20 -0
  444. package/src/export/html/index.ts +313 -0
  445. package/src/export/html/share-loader.js +102 -0
  446. package/src/export/html/template.css +1355 -0
  447. package/src/export/html/template.html +55 -0
  448. package/src/export/html/template.js +1671 -0
  449. package/src/export/html/tool-views.generated.js +35 -0
  450. package/src/export/html/vendor/highlight.min.js +1213 -0
  451. package/src/export/html/vendor/marked.min.js +6 -0
  452. package/src/export/html/web-palette.ts +126 -0
  453. package/src/export/share.ts +682 -0
  454. package/src/export/ttsr.ts +590 -0
  455. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +54 -0
  456. package/src/extensibility/custom-commands/bundled/review/index.ts +698 -0
  457. package/src/extensibility/custom-commands/index.ts +2 -0
  458. package/src/extensibility/custom-commands/loader.ts +242 -0
  459. package/src/extensibility/custom-commands/types.ts +119 -0
  460. package/src/extensibility/custom-tools/index.ts +7 -0
  461. package/src/extensibility/custom-tools/loader.ts +301 -0
  462. package/src/extensibility/custom-tools/types.ts +286 -0
  463. package/src/extensibility/custom-tools/wrapper.ts +50 -0
  464. package/src/extensibility/extensions/compact-handler.ts +40 -0
  465. package/src/extensibility/extensions/get-commands-handler.ts +78 -0
  466. package/src/extensibility/extensions/index.ts +16 -0
  467. package/src/extensibility/extensions/load-errors.ts +13 -0
  468. package/src/extensibility/extensions/loader.ts +624 -0
  469. package/src/extensibility/extensions/managed-timers.ts +83 -0
  470. package/src/extensibility/extensions/model-api.ts +39 -0
  471. package/src/extensibility/extensions/runner.ts +1209 -0
  472. package/src/extensibility/extensions/types.ts +1526 -0
  473. package/src/extensibility/extensions/wrapper.ts +377 -0
  474. package/src/extensibility/hooks/index.ts +6 -0
  475. package/src/extensibility/hooks/loader.ts +244 -0
  476. package/src/extensibility/hooks/runner.ts +425 -0
  477. package/src/extensibility/hooks/tool-wrapper.ts +124 -0
  478. package/src/extensibility/hooks/types.ts +612 -0
  479. package/src/extensibility/legacy-pi-ai-shim.ts +140 -0
  480. package/src/extensibility/legacy-pi-coding-agent-shim.ts +1384 -0
  481. package/src/extensibility/legacy-pi-tui-shim.ts +43 -0
  482. package/src/extensibility/plugins/bun-git-cache.ts +91 -0
  483. package/src/extensibility/plugins/doctor.ts +65 -0
  484. package/src/extensibility/plugins/git-url.ts +367 -0
  485. package/src/extensibility/plugins/index.ts +9 -0
  486. package/src/extensibility/plugins/installer.ts +201 -0
  487. package/src/extensibility/plugins/legacy-pi-compat.ts +2532 -0
  488. package/src/extensibility/plugins/legacy-pi-virtual-modules.d.ts +4 -0
  489. package/src/extensibility/plugins/loader.ts +535 -0
  490. package/src/extensibility/plugins/manager.ts +1142 -0
  491. package/src/extensibility/plugins/marketplace/cache.ts +136 -0
  492. package/src/extensibility/plugins/marketplace/fetcher.ts +316 -0
  493. package/src/extensibility/plugins/marketplace/index.ts +6 -0
  494. package/src/extensibility/plugins/marketplace/manager.ts +926 -0
  495. package/src/extensibility/plugins/marketplace/registry.ts +196 -0
  496. package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
  497. package/src/extensibility/plugins/marketplace/types.ts +192 -0
  498. package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
  499. package/src/extensibility/plugins/parser.ts +107 -0
  500. package/src/extensibility/plugins/runtime-config.ts +9 -0
  501. package/src/extensibility/plugins/types.ts +194 -0
  502. package/src/extensibility/session-handler-types.ts +21 -0
  503. package/src/extensibility/shared-events.ts +401 -0
  504. package/src/extensibility/skills.ts +511 -0
  505. package/src/extensibility/slash-commands.ts +131 -0
  506. package/src/extensibility/tool-event-input.ts +80 -0
  507. package/src/extensibility/tool-proxy.ts +28 -0
  508. package/src/extensibility/typebox.ts +958 -0
  509. package/src/extensibility/utils.ts +184 -0
  510. package/src/goals/index.ts +3 -0
  511. package/src/goals/runtime.ts +521 -0
  512. package/src/goals/state.ts +37 -0
  513. package/src/goals/tools/goal-tool.ts +251 -0
  514. package/src/hindsight/backend.ts +354 -0
  515. package/src/hindsight/bank.ts +156 -0
  516. package/src/hindsight/client.ts +680 -0
  517. package/src/hindsight/config.ts +193 -0
  518. package/src/hindsight/content.ts +266 -0
  519. package/src/hindsight/index.ts +8 -0
  520. package/src/hindsight/mental-models.ts +429 -0
  521. package/src/hindsight/seeds.json +32 -0
  522. package/src/hindsight/state.ts +550 -0
  523. package/src/hindsight/transcript.ts +71 -0
  524. package/src/index.ts +66 -0
  525. package/src/internal-urls/agent-protocol.ts +180 -0
  526. package/src/internal-urls/artifact-protocol.ts +151 -0
  527. package/src/internal-urls/docs-index.ts +102 -0
  528. package/src/internal-urls/filesystem-resource.ts +34 -0
  529. package/src/internal-urls/history-protocol.ts +198 -0
  530. package/src/internal-urls/index.ts +27 -0
  531. package/src/internal-urls/issue-pr-protocol.ts +594 -0
  532. package/src/internal-urls/json-query.ts +126 -0
  533. package/src/internal-urls/local-protocol.ts +470 -0
  534. package/src/internal-urls/mcp-protocol.ts +165 -0
  535. package/src/internal-urls/memory-protocol.ts +347 -0
  536. package/src/internal-urls/omp-protocol.ts +94 -0
  537. package/src/internal-urls/parse.ts +103 -0
  538. package/src/internal-urls/registry-helpers.ts +132 -0
  539. package/src/internal-urls/router.ts +150 -0
  540. package/src/internal-urls/rule-protocol.ts +45 -0
  541. package/src/internal-urls/skill-protocol.ts +117 -0
  542. package/src/internal-urls/ssh-protocol.ts +368 -0
  543. package/src/internal-urls/types.ts +196 -0
  544. package/src/internal-urls/vault-protocol.ts +940 -0
  545. package/src/internal-urls/xd-protocol.ts +46 -0
  546. package/src/irc/bus.ts +380 -0
  547. package/src/jsonrpc/message-framing.ts +142 -0
  548. package/src/launch/broker.ts +1134 -0
  549. package/src/launch/client.ts +350 -0
  550. package/src/launch/paths.ts +17 -0
  551. package/src/launch/presence.ts +82 -0
  552. package/src/launch/protocol.ts +396 -0
  553. package/src/launch/spawn-options.ts +17 -0
  554. package/src/launch/terminal-output.ts +46 -0
  555. package/src/lib/xai-http.ts +150 -0
  556. package/src/live/attestation.ts +91 -0
  557. package/src/live/controller.ts +517 -0
  558. package/src/live/prompts/agent-final-message.md +3 -0
  559. package/src/live/prompts/live-instructions.md +23 -0
  560. package/src/live/protocol.ts +233 -0
  561. package/src/live/transport.ts +422 -0
  562. package/src/live/visualizer.ts +214 -0
  563. package/src/live/voices.ts +18 -0
  564. package/src/lsp/client.ts +1429 -0
  565. package/src/lsp/clients/biome-client.ts +263 -0
  566. package/src/lsp/clients/index.ts +50 -0
  567. package/src/lsp/clients/lsp-linter-client.ts +85 -0
  568. package/src/lsp/clients/swiftlint-client.ts +120 -0
  569. package/src/lsp/config.ts +549 -0
  570. package/src/lsp/defaults.json +499 -0
  571. package/src/lsp/deferred-diagnostics.ts +66 -0
  572. package/src/lsp/diagnostics-ledger.ts +51 -0
  573. package/src/lsp/edits.ts +288 -0
  574. package/src/lsp/format-options.ts +119 -0
  575. package/src/lsp/index.ts +2766 -0
  576. package/src/lsp/lspmux.ts +233 -0
  577. package/src/lsp/render.ts +668 -0
  578. package/src/lsp/startup-events.ts +13 -0
  579. package/src/lsp/types.ts +453 -0
  580. package/src/lsp/utils.ts +718 -0
  581. package/src/main.ts +1647 -0
  582. package/src/markit/NOTICE +32 -0
  583. package/src/markit/converters/docx.ts +56 -0
  584. package/src/markit/converters/epub.ts +136 -0
  585. package/src/markit/converters/mammoth.d.ts +24 -0
  586. package/src/markit/converters/pdf/columns.ts +103 -0
  587. package/src/markit/converters/pdf/extract.ts +598 -0
  588. package/src/markit/converters/pdf/grid.ts +780 -0
  589. package/src/markit/converters/pdf/headers.ts +106 -0
  590. package/src/markit/converters/pdf/index.ts +146 -0
  591. package/src/markit/converters/pdf/render.ts +501 -0
  592. package/src/markit/converters/pdf/types.ts +84 -0
  593. package/src/markit/converters/pptx.ts +325 -0
  594. package/src/markit/converters/xlsx.ts +173 -0
  595. package/src/markit/index.ts +2 -0
  596. package/src/markit/registry.ts +59 -0
  597. package/src/markit/types.ts +35 -0
  598. package/src/mcp/client.ts +511 -0
  599. package/src/mcp/config-writer.ts +377 -0
  600. package/src/mcp/config.ts +381 -0
  601. package/src/mcp/index.ts +29 -0
  602. package/src/mcp/json-rpc.ts +122 -0
  603. package/src/mcp/loader.ts +125 -0
  604. package/src/mcp/manager.ts +1419 -0
  605. package/src/mcp/oauth-credentials.ts +104 -0
  606. package/src/mcp/oauth-discovery.ts +587 -0
  607. package/src/mcp/oauth-flow.ts +820 -0
  608. package/src/mcp/render.ts +214 -0
  609. package/src/mcp/smithery-auth.ts +108 -0
  610. package/src/mcp/smithery-connect.ts +154 -0
  611. package/src/mcp/smithery-registry.ts +500 -0
  612. package/src/mcp/startup-events.ts +116 -0
  613. package/src/mcp/timeout.ts +59 -0
  614. package/src/mcp/tool-bridge.ts +691 -0
  615. package/src/mcp/tool-cache.ts +117 -0
  616. package/src/mcp/transports/http.ts +523 -0
  617. package/src/mcp/transports/index.ts +7 -0
  618. package/src/mcp/transports/sse.ts +377 -0
  619. package/src/mcp/transports/stdio.ts +903 -0
  620. package/src/mcp/types.ts +437 -0
  621. package/src/memories/index.ts +1434 -0
  622. package/src/memories/storage.ts +578 -0
  623. package/src/memory-backend/index.ts +18 -0
  624. package/src/memory-backend/local-backend.ts +47 -0
  625. package/src/memory-backend/off-backend.ts +25 -0
  626. package/src/memory-backend/resolve.ts +25 -0
  627. package/src/memory-backend/runtime.ts +66 -0
  628. package/src/memory-backend/tool-names.ts +2 -0
  629. package/src/memory-backend/types.ts +166 -0
  630. package/src/mnemopi/backend.ts +629 -0
  631. package/src/mnemopi/config.ts +267 -0
  632. package/src/mnemopi/embed-client.ts +246 -0
  633. package/src/mnemopi/embed-protocol.ts +35 -0
  634. package/src/mnemopi/embed-worker.ts +114 -0
  635. package/src/mnemopi/index.ts +3 -0
  636. package/src/mnemopi/state.ts +906 -0
  637. package/src/modes/acp/acp-agent.ts +2577 -0
  638. package/src/modes/acp/acp-client-bridge.ts +154 -0
  639. package/src/modes/acp/acp-event-mapper.ts +1084 -0
  640. package/src/modes/acp/acp-mode.ts +48 -0
  641. package/src/modes/acp/index.ts +2 -0
  642. package/src/modes/acp/terminal-auth.ts +37 -0
  643. package/src/modes/components/advisor-config.ts +635 -0
  644. package/src/modes/components/advisor-message.ts +109 -0
  645. package/src/modes/components/agent-dashboard.ts +1252 -0
  646. package/src/modes/components/agent-hub.ts +648 -0
  647. package/src/modes/components/agent-transcript-viewer.ts +649 -0
  648. package/src/modes/components/ask-dialog.ts +975 -0
  649. package/src/modes/components/assistant-message.ts +972 -0
  650. package/src/modes/components/background-tan-message.ts +36 -0
  651. package/src/modes/components/bash-execution.ts +233 -0
  652. package/src/modes/components/bordered-loader.ts +41 -0
  653. package/src/modes/components/btw-panel.ts +124 -0
  654. package/src/modes/components/cache-invalidation-marker.ts +110 -0
  655. package/src/modes/components/chat-block.ts +111 -0
  656. package/src/modes/components/chat-transcript-builder.ts +495 -0
  657. package/src/modes/components/collab-prompt-message.ts +32 -0
  658. package/src/modes/components/compaction-summary-message.ts +221 -0
  659. package/src/modes/components/copy-selector.ts +218 -0
  660. package/src/modes/components/countdown-timer.ts +75 -0
  661. package/src/modes/components/custom-editor.ts +1027 -0
  662. package/src/modes/components/custom-message.ts +70 -0
  663. package/src/modes/components/diff.ts +254 -0
  664. package/src/modes/components/dynamic-border.ts +37 -0
  665. package/src/modes/components/error-banner.ts +33 -0
  666. package/src/modes/components/eval-execution.ts +169 -0
  667. package/src/modes/components/execution-shared.ts +101 -0
  668. package/src/modes/components/extensions/extension-dashboard.ts +492 -0
  669. package/src/modes/components/extensions/extension-list.ts +507 -0
  670. package/src/modes/components/extensions/index.ts +9 -0
  671. package/src/modes/components/extensions/inspector-panel.ts +321 -0
  672. package/src/modes/components/extensions/state-manager.ts +648 -0
  673. package/src/modes/components/extensions/types.ts +186 -0
  674. package/src/modes/components/footer.ts +276 -0
  675. package/src/modes/components/history-search.ts +268 -0
  676. package/src/modes/components/hook-editor.ts +213 -0
  677. package/src/modes/components/hook-input.ts +87 -0
  678. package/src/modes/components/hook-message.ts +67 -0
  679. package/src/modes/components/hook-selector.ts +691 -0
  680. package/src/modes/components/index.ts +42 -0
  681. package/src/modes/components/keybinding-hints.ts +65 -0
  682. package/src/modes/components/late-diagnostics-message.ts +60 -0
  683. package/src/modes/components/login-dialog.ts +197 -0
  684. package/src/modes/components/logout-account-selector.ts +130 -0
  685. package/src/modes/components/mcp-add-wizard.ts +1413 -0
  686. package/src/modes/components/message-frame.ts +98 -0
  687. package/src/modes/components/model-browser.ts +872 -0
  688. package/src/modes/components/model-hub.ts +2011 -0
  689. package/src/modes/components/model-picker.ts +233 -0
  690. package/src/modes/components/move-overlay.ts +293 -0
  691. package/src/modes/components/oauth-selector.ts +474 -0
  692. package/src/modes/components/omfg-panel.ts +141 -0
  693. package/src/modes/components/overlay-box.ts +109 -0
  694. package/src/modes/components/pause-screen.ts +208 -0
  695. package/src/modes/components/plan-review-overlay.ts +1226 -0
  696. package/src/modes/components/plan-toc.ts +138 -0
  697. package/src/modes/components/plugin-selector.ts +100 -0
  698. package/src/modes/components/plugin-settings.ts +745 -0
  699. package/src/modes/components/queue-mode-selector.ts +61 -0
  700. package/src/modes/components/read-tool-group.ts +678 -0
  701. package/src/modes/components/reset-usage-selector.ts +161 -0
  702. package/src/modes/components/segment-track.ts +89 -0
  703. package/src/modes/components/select-list-mouse-routing.ts +35 -0
  704. package/src/modes/components/selector-helpers.ts +129 -0
  705. package/src/modes/components/session-account-selector.ts +62 -0
  706. package/src/modes/components/session-selector.ts +1019 -0
  707. package/src/modes/components/settings-defs.ts +267 -0
  708. package/src/modes/components/settings-selector.ts +1445 -0
  709. package/src/modes/components/show-images-selector.ts +50 -0
  710. package/src/modes/components/skill-message.ts +110 -0
  711. package/src/modes/components/snapcompact-shape-preview-doc.md +14 -0
  712. package/src/modes/components/snapcompact-shape-preview.ts +192 -0
  713. package/src/modes/components/status-line/component.ts +1516 -0
  714. package/src/modes/components/status-line/context-thresholds.ts +86 -0
  715. package/src/modes/components/status-line/git-utils.ts +42 -0
  716. package/src/modes/components/status-line/index.ts +5 -0
  717. package/src/modes/components/status-line/presets.ts +106 -0
  718. package/src/modes/components/status-line/segments.ts +710 -0
  719. package/src/modes/components/status-line/separators.ts +55 -0
  720. package/src/modes/components/status-line/types.ts +159 -0
  721. package/src/modes/components/theme-selector.ts +68 -0
  722. package/src/modes/components/thinking-selector.ts +57 -0
  723. package/src/modes/components/tiny-title-download-progress.ts +90 -0
  724. package/src/modes/components/tips.txt +26 -0
  725. package/src/modes/components/todo-reminder.ts +43 -0
  726. package/src/modes/components/tool-execution.ts +1356 -0
  727. package/src/modes/components/transcript-container.ts +527 -0
  728. package/src/modes/components/tree-selector.ts +1008 -0
  729. package/src/modes/components/ttsr-notification.ts +123 -0
  730. package/src/modes/components/usage-row.ts +47 -0
  731. package/src/modes/components/user-message-selector.ts +227 -0
  732. package/src/modes/components/user-message.ts +167 -0
  733. package/src/modes/components/visual-truncate.ts +63 -0
  734. package/src/modes/components/welcome.ts +578 -0
  735. package/src/modes/controllers/btw-controller.ts +198 -0
  736. package/src/modes/controllers/command-controller-shared.ts +109 -0
  737. package/src/modes/controllers/command-controller.ts +1993 -0
  738. package/src/modes/controllers/event-controller.ts +1781 -0
  739. package/src/modes/controllers/extension-ui-controller.ts +1242 -0
  740. package/src/modes/controllers/input-controller.ts +2004 -0
  741. package/src/modes/controllers/live-command-controller.ts +260 -0
  742. package/src/modes/controllers/mcp-command-controller.ts +2403 -0
  743. package/src/modes/controllers/omfg-controller.ts +287 -0
  744. package/src/modes/controllers/omfg-rule.ts +647 -0
  745. package/src/modes/controllers/selector-controller.ts +1968 -0
  746. package/src/modes/controllers/session-focus-controller.ts +117 -0
  747. package/src/modes/controllers/ssh-command-controller.ts +385 -0
  748. package/src/modes/controllers/streaming-reveal.ts +399 -0
  749. package/src/modes/controllers/tan-command-controller.ts +229 -0
  750. package/src/modes/controllers/todo-command-controller.ts +487 -0
  751. package/src/modes/controllers/tool-args-reveal.ts +591 -0
  752. package/src/modes/data/emojis.json +1 -0
  753. package/src/modes/emoji-autocomplete.ts +285 -0
  754. package/src/modes/github-ref-autocomplete.ts +75 -0
  755. package/src/modes/gradient-highlight.ts +99 -0
  756. package/src/modes/image-references.ts +137 -0
  757. package/src/modes/index.ts +10 -0
  758. package/src/modes/interactive-mode.ts +4957 -0
  759. package/src/modes/internal-url-autocomplete.ts +158 -0
  760. package/src/modes/loop-limit.ts +192 -0
  761. package/src/modes/magic-keyword-boundary.ts +23 -0
  762. package/src/modes/magic-keywords.ts +42 -0
  763. package/src/modes/markdown-prose.ts +247 -0
  764. package/src/modes/oauth-manual-input.ts +69 -0
  765. package/src/modes/orchestrate.ts +43 -0
  766. package/src/modes/print-mode.ts +265 -0
  767. package/src/modes/prompt-action-autocomplete.ts +322 -0
  768. package/src/modes/queue-input.ts +132 -0
  769. package/src/modes/rpc/host-tools.ts +204 -0
  770. package/src/modes/rpc/host-uris.ts +235 -0
  771. package/src/modes/rpc/rpc-client.ts +1195 -0
  772. package/src/modes/rpc/rpc-frame.ts +316 -0
  773. package/src/modes/rpc/rpc-input.ts +38 -0
  774. package/src/modes/rpc/rpc-messages.ts +127 -0
  775. package/src/modes/rpc/rpc-mode.ts +1504 -0
  776. package/src/modes/rpc/rpc-subagents.ts +265 -0
  777. package/src/modes/rpc/rpc-types.ts +533 -0
  778. package/src/modes/running-subagent-badge.ts +13 -0
  779. package/src/modes/runtime-init.ts +144 -0
  780. package/src/modes/session-observer-registry.ts +218 -0
  781. package/src/modes/session-teardown.ts +82 -0
  782. package/src/modes/setup-version.ts +11 -0
  783. package/src/modes/setup-wizard/index.ts +103 -0
  784. package/src/modes/setup-wizard/lazy.ts +16 -0
  785. package/src/modes/setup-wizard/scenes/glyph.ts +103 -0
  786. package/src/modes/setup-wizard/scenes/model.ts +132 -0
  787. package/src/modes/setup-wizard/scenes/outro.ts +35 -0
  788. package/src/modes/setup-wizard/scenes/providers.ts +105 -0
  789. package/src/modes/setup-wizard/scenes/sign-in.ts +312 -0
  790. package/src/modes/setup-wizard/scenes/splash.ts +201 -0
  791. package/src/modes/setup-wizard/scenes/theme.ts +330 -0
  792. package/src/modes/setup-wizard/scenes/types.ts +65 -0
  793. package/src/modes/setup-wizard/scenes/web-search.ts +153 -0
  794. package/src/modes/setup-wizard/startup-splash.ts +107 -0
  795. package/src/modes/setup-wizard/wizard-overlay.ts +335 -0
  796. package/src/modes/shared.ts +49 -0
  797. package/src/modes/skill-command.ts +91 -0
  798. package/src/modes/theme/dark.json +95 -0
  799. package/src/modes/theme/defaults/alabaster.json +93 -0
  800. package/src/modes/theme/defaults/amethyst.json +96 -0
  801. package/src/modes/theme/defaults/anthracite.json +93 -0
  802. package/src/modes/theme/defaults/basalt.json +91 -0
  803. package/src/modes/theme/defaults/birch.json +95 -0
  804. package/src/modes/theme/defaults/dark-abyss.json +91 -0
  805. package/src/modes/theme/defaults/dark-arctic.json +104 -0
  806. package/src/modes/theme/defaults/dark-aurora.json +95 -0
  807. package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
  808. package/src/modes/theme/defaults/dark-cavern.json +91 -0
  809. package/src/modes/theme/defaults/dark-copper.json +95 -0
  810. package/src/modes/theme/defaults/dark-cosmos.json +90 -0
  811. package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
  812. package/src/modes/theme/defaults/dark-dracula.json +98 -0
  813. package/src/modes/theme/defaults/dark-eclipse.json +91 -0
  814. package/src/modes/theme/defaults/dark-ember.json +95 -0
  815. package/src/modes/theme/defaults/dark-equinox.json +90 -0
  816. package/src/modes/theme/defaults/dark-forest.json +96 -0
  817. package/src/modes/theme/defaults/dark-github.json +105 -0
  818. package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
  819. package/src/modes/theme/defaults/dark-lavender.json +95 -0
  820. package/src/modes/theme/defaults/dark-lunar.json +89 -0
  821. package/src/modes/theme/defaults/dark-midnight.json +95 -0
  822. package/src/modes/theme/defaults/dark-monochrome.json +94 -0
  823. package/src/modes/theme/defaults/dark-monokai.json +98 -0
  824. package/src/modes/theme/defaults/dark-nebula.json +90 -0
  825. package/src/modes/theme/defaults/dark-nord.json +97 -0
  826. package/src/modes/theme/defaults/dark-ocean.json +101 -0
  827. package/src/modes/theme/defaults/dark-one.json +100 -0
  828. package/src/modes/theme/defaults/dark-poimandres.json +143 -0
  829. package/src/modes/theme/defaults/dark-rainforest.json +91 -0
  830. package/src/modes/theme/defaults/dark-reef.json +91 -0
  831. package/src/modes/theme/defaults/dark-retro.json +92 -0
  832. package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
  833. package/src/modes/theme/defaults/dark-sakura.json +95 -0
  834. package/src/modes/theme/defaults/dark-slate.json +95 -0
  835. package/src/modes/theme/defaults/dark-solarized.json +97 -0
  836. package/src/modes/theme/defaults/dark-solstice.json +90 -0
  837. package/src/modes/theme/defaults/dark-starfall.json +91 -0
  838. package/src/modes/theme/defaults/dark-sunset.json +99 -0
  839. package/src/modes/theme/defaults/dark-swamp.json +90 -0
  840. package/src/modes/theme/defaults/dark-synthwave.json +103 -0
  841. package/src/modes/theme/defaults/dark-taiga.json +91 -0
  842. package/src/modes/theme/defaults/dark-terminal.json +95 -0
  843. package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
  844. package/src/modes/theme/defaults/dark-tundra.json +91 -0
  845. package/src/modes/theme/defaults/dark-twilight.json +91 -0
  846. package/src/modes/theme/defaults/dark-volcanic.json +91 -0
  847. package/src/modes/theme/defaults/graphite.json +92 -0
  848. package/src/modes/theme/defaults/index.ts +199 -0
  849. package/src/modes/theme/defaults/light-arctic.json +107 -0
  850. package/src/modes/theme/defaults/light-aurora-day.json +91 -0
  851. package/src/modes/theme/defaults/light-canyon.json +91 -0
  852. package/src/modes/theme/defaults/light-catppuccin.json +106 -0
  853. package/src/modes/theme/defaults/light-cirrus.json +90 -0
  854. package/src/modes/theme/defaults/light-coral.json +95 -0
  855. package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
  856. package/src/modes/theme/defaults/light-dawn.json +90 -0
  857. package/src/modes/theme/defaults/light-dunes.json +91 -0
  858. package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
  859. package/src/modes/theme/defaults/light-forest.json +100 -0
  860. package/src/modes/theme/defaults/light-frost.json +95 -0
  861. package/src/modes/theme/defaults/light-github.json +115 -0
  862. package/src/modes/theme/defaults/light-glacier.json +91 -0
  863. package/src/modes/theme/defaults/light-gruvbox.json +108 -0
  864. package/src/modes/theme/defaults/light-haze.json +90 -0
  865. package/src/modes/theme/defaults/light-honeycomb.json +95 -0
  866. package/src/modes/theme/defaults/light-lagoon.json +91 -0
  867. package/src/modes/theme/defaults/light-lavender.json +95 -0
  868. package/src/modes/theme/defaults/light-meadow.json +91 -0
  869. package/src/modes/theme/defaults/light-mint.json +95 -0
  870. package/src/modes/theme/defaults/light-monochrome.json +101 -0
  871. package/src/modes/theme/defaults/light-ocean.json +99 -0
  872. package/src/modes/theme/defaults/light-one.json +99 -0
  873. package/src/modes/theme/defaults/light-opal.json +91 -0
  874. package/src/modes/theme/defaults/light-orchard.json +91 -0
  875. package/src/modes/theme/defaults/light-paper.json +95 -0
  876. package/src/modes/theme/defaults/light-poimandres.json +143 -0
  877. package/src/modes/theme/defaults/light-prism.json +90 -0
  878. package/src/modes/theme/defaults/light-retro.json +98 -0
  879. package/src/modes/theme/defaults/light-sand.json +95 -0
  880. package/src/modes/theme/defaults/light-savanna.json +91 -0
  881. package/src/modes/theme/defaults/light-solarized.json +102 -0
  882. package/src/modes/theme/defaults/light-soleil.json +90 -0
  883. package/src/modes/theme/defaults/light-sunset.json +99 -0
  884. package/src/modes/theme/defaults/light-synthwave.json +98 -0
  885. package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
  886. package/src/modes/theme/defaults/light-wetland.json +91 -0
  887. package/src/modes/theme/defaults/light-zenith.json +89 -0
  888. package/src/modes/theme/defaults/limestone.json +94 -0
  889. package/src/modes/theme/defaults/mahogany.json +97 -0
  890. package/src/modes/theme/defaults/marble.json +93 -0
  891. package/src/modes/theme/defaults/obsidian.json +91 -0
  892. package/src/modes/theme/defaults/onyx.json +91 -0
  893. package/src/modes/theme/defaults/pearl.json +93 -0
  894. package/src/modes/theme/defaults/porcelain.json +91 -0
  895. package/src/modes/theme/defaults/quartz.json +96 -0
  896. package/src/modes/theme/defaults/sandstone.json +95 -0
  897. package/src/modes/theme/defaults/titanium.json +90 -0
  898. package/src/modes/theme/light.json +93 -0
  899. package/src/modes/theme/mermaid-cache.ts +92 -0
  900. package/src/modes/theme/shimmer.ts +305 -0
  901. package/src/modes/theme/theme-schema.json +463 -0
  902. package/src/modes/theme/theme.ts +3019 -0
  903. package/src/modes/turn-budget.ts +31 -0
  904. package/src/modes/types.ts +479 -0
  905. package/src/modes/ultrathink.ts +42 -0
  906. package/src/modes/utils/context-usage.ts +518 -0
  907. package/src/modes/utils/copy-targets.ts +378 -0
  908. package/src/modes/utils/hotkeys-markdown.ts +63 -0
  909. package/src/modes/utils/interactive-context-helpers.ts +30 -0
  910. package/src/modes/utils/keybinding-matchers.ts +86 -0
  911. package/src/modes/utils/tools-markdown.ts +31 -0
  912. package/src/modes/utils/transcript-render-helpers.ts +253 -0
  913. package/src/modes/utils/ui-helpers.ts +963 -0
  914. package/src/modes/warp-events.ts +232 -0
  915. package/src/modes/workflow.ts +49 -0
  916. package/src/plan-mode/approved-plan.ts +194 -0
  917. package/src/plan-mode/model-transition.ts +51 -0
  918. package/src/plan-mode/plan-files.ts +40 -0
  919. package/src/plan-mode/plan-handoff.ts +37 -0
  920. package/src/plan-mode/plan-protection.ts +31 -0
  921. package/src/plan-mode/state.ts +6 -0
  922. package/src/priority.json +60 -0
  923. package/src/prompts/advisor/active-repo-watchdog.md +6 -0
  924. package/src/prompts/advisor/advise-tool.md +3 -0
  925. package/src/prompts/advisor/context-files.md +8 -0
  926. package/src/prompts/advisor/system.md +98 -0
  927. package/src/prompts/agents/designer.md +74 -0
  928. package/src/prompts/agents/frontmatter.md +12 -0
  929. package/src/prompts/agents/init.md +33 -0
  930. package/src/prompts/agents/librarian.md +119 -0
  931. package/src/prompts/agents/reviewer.md +139 -0
  932. package/src/prompts/agents/scout.md +58 -0
  933. package/src/prompts/agents/task.md +17 -0
  934. package/src/prompts/bench/cache-prefix-chunk.md +1 -0
  935. package/src/prompts/bench/cache-prefix.md +3 -0
  936. package/src/prompts/bench/cache-suffix.md +1 -0
  937. package/src/prompts/bench.md +6 -0
  938. package/src/prompts/ci-green-request.md +36 -0
  939. package/src/prompts/dry-balance-bench.md +8 -0
  940. package/src/prompts/goals/goal-budget-limit.md +16 -0
  941. package/src/prompts/goals/goal-continuation.md +28 -0
  942. package/src/prompts/goals/goal-mode-active.md +23 -0
  943. package/src/prompts/goals/goal-mode-context.md +4 -0
  944. package/src/prompts/goals/goal-todo-context.md +12 -0
  945. package/src/prompts/goals/guided-goal-interview.md +43 -0
  946. package/src/prompts/memories/consolidation.md +30 -0
  947. package/src/prompts/memories/consolidation_system.md +4 -0
  948. package/src/prompts/memories/read-path.md +17 -0
  949. package/src/prompts/memories/stage_one_input.md +6 -0
  950. package/src/prompts/memories/stage_one_system.md +21 -0
  951. package/src/prompts/review-custom-request.md +21 -0
  952. package/src/prompts/review-headless-request.md +16 -0
  953. package/src/prompts/review-request.md +68 -0
  954. package/src/prompts/skills/autoload.md +8 -0
  955. package/src/prompts/skills/user-invocation.md +11 -0
  956. package/src/prompts/steering/parent-irc.md +5 -0
  957. package/src/prompts/steering/user-interjection.md +6 -0
  958. package/src/prompts/system/active-repo-context.md +4 -0
  959. package/src/prompts/system/agent-creation-architect.md +50 -0
  960. package/src/prompts/system/agent-creation-user.md +6 -0
  961. package/src/prompts/system/auto-continue.md +1 -0
  962. package/src/prompts/system/auto-thinking-difficulty-local.md +14 -0
  963. package/src/prompts/system/auto-thinking-difficulty.md +12 -0
  964. package/src/prompts/system/autolearn-guidance-learn.md +1 -0
  965. package/src/prompts/system/autolearn-guidance.md +7 -0
  966. package/src/prompts/system/autolearn-nudge-autocontinue.md +5 -0
  967. package/src/prompts/system/background-tan-dispatch.md +8 -0
  968. package/src/prompts/system/btw-user.md +8 -0
  969. package/src/prompts/system/commit-message-system.md +14 -0
  970. package/src/prompts/system/computer-safety.md +14 -0
  971. package/src/prompts/system/custom-system-prompt.md +64 -0
  972. package/src/prompts/system/eager-task.md +7 -0
  973. package/src/prompts/system/eager-todo.md +18 -0
  974. package/src/prompts/system/empty-stop-retry.md +4 -0
  975. package/src/prompts/system/gemini-tool-call-reminder.md +9 -0
  976. package/src/prompts/system/interrupted-thinking.md +7 -0
  977. package/src/prompts/system/irc-autoreply.md +6 -0
  978. package/src/prompts/system/irc-incoming.md +9 -0
  979. package/src/prompts/system/manual-continue.md +7 -0
  980. package/src/prompts/system/mcp-xdev-guidance.md +11 -0
  981. package/src/prompts/system/memory-consolidation-system.md +8 -0
  982. package/src/prompts/system/memory-extraction-system.md +26 -0
  983. package/src/prompts/system/mid-run-todo-nudge.md +3 -0
  984. package/src/prompts/system/omfg-user.md +50 -0
  985. package/src/prompts/system/orchestrate-notice.md +40 -0
  986. package/src/prompts/system/personalities/default.md +18 -0
  987. package/src/prompts/system/personalities/friendly.md +17 -0
  988. package/src/prompts/system/personalities/pragmatic.md +15 -0
  989. package/src/prompts/system/plan-mode-active.md +125 -0
  990. package/src/prompts/system/plan-mode-approved.md +22 -0
  991. package/src/prompts/system/plan-mode-compact-instructions.md +17 -0
  992. package/src/prompts/system/plan-mode-reference.md +10 -0
  993. package/src/prompts/system/plan-mode-subagent.md +33 -0
  994. package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
  995. package/src/prompts/system/plan-yolo-handoff.md +5 -0
  996. package/src/prompts/system/prewalk-checklist.md +7 -0
  997. package/src/prompts/system/prewalk-continue.md +1 -0
  998. package/src/prompts/system/prewalk-plan.md +13 -0
  999. package/src/prompts/system/project-prompt.md +61 -0
  1000. package/src/prompts/system/recap-user.md +9 -0
  1001. package/src/prompts/system/resolve-device-reminder.md +3 -0
  1002. package/src/prompts/system/rewind-report.md +6 -0
  1003. package/src/prompts/system/side-channel-no-tools.md +3 -0
  1004. package/src/prompts/system/snapcompact-context-frames-note.md +1 -0
  1005. package/src/prompts/system/snapcompact-context-stub.md +1 -0
  1006. package/src/prompts/system/snapcompact-system-frames-note.md +1 -0
  1007. package/src/prompts/system/snapcompact-system-stub.md +1 -0
  1008. package/src/prompts/system/snapcompact-toolresult-note.md +1 -0
  1009. package/src/prompts/system/speech-rewrite.md +15 -0
  1010. package/src/prompts/system/subagent-async-pending.md +6 -0
  1011. package/src/prompts/system/subagent-system-prompt.md +73 -0
  1012. package/src/prompts/system/subagent-user-prompt.md +3 -0
  1013. package/src/prompts/system/subagent-yield-reminder.md +23 -0
  1014. package/src/prompts/system/system-prompt.md +283 -0
  1015. package/src/prompts/system/tan-context-switch.md +17 -0
  1016. package/src/prompts/system/task-label.md +23 -0
  1017. package/src/prompts/system/thinking-loop-redirect.md +10 -0
  1018. package/src/prompts/system/title-marker-instruction.md +1 -0
  1019. package/src/prompts/system/title-system.md +16 -0
  1020. package/src/prompts/system/tool-call-loop-redirect.md +8 -0
  1021. package/src/prompts/system/ttsr-interrupt.md +7 -0
  1022. package/src/prompts/system/ttsr-tool-reminder.md +5 -0
  1023. package/src/prompts/system/ultrathink-notice.md +3 -0
  1024. package/src/prompts/system/unexpected-stop-classifier.md +17 -0
  1025. package/src/prompts/system/unexpected-stop-retry.md +4 -0
  1026. package/src/prompts/system/vibe-mode-active.md +26 -0
  1027. package/src/prompts/system/web-search.md +25 -0
  1028. package/src/prompts/system/workflow-notice.md +112 -0
  1029. package/src/prompts/system/xdev-mount-notice.md +20 -0
  1030. package/src/prompts/tools/apply-patch.md +65 -0
  1031. package/src/prompts/tools/ask.md +22 -0
  1032. package/src/prompts/tools/ast-edit.md +11 -0
  1033. package/src/prompts/tools/ast-grep.md +19 -0
  1034. package/src/prompts/tools/async-result.md +8 -0
  1035. package/src/prompts/tools/bash.md +25 -0
  1036. package/src/prompts/tools/browser.md +28 -0
  1037. package/src/prompts/tools/checkpoint.md +15 -0
  1038. package/src/prompts/tools/computer.md +26 -0
  1039. package/src/prompts/tools/debug.md +3 -0
  1040. package/src/prompts/tools/eval.md +45 -0
  1041. package/src/prompts/tools/github.md +22 -0
  1042. package/src/prompts/tools/glob.md +15 -0
  1043. package/src/prompts/tools/goal.md +11 -0
  1044. package/src/prompts/tools/grep.md +12 -0
  1045. package/src/prompts/tools/hub.md +34 -0
  1046. package/src/prompts/tools/image-attachment-describe-system.md +8 -0
  1047. package/src/prompts/tools/image-attachment-describe.md +10 -0
  1048. package/src/prompts/tools/image-gen.md +7 -0
  1049. package/src/prompts/tools/inspect-image-system.md +20 -0
  1050. package/src/prompts/tools/inspect-image.md +22 -0
  1051. package/src/prompts/tools/learn.md +7 -0
  1052. package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
  1053. package/src/prompts/tools/lsp.md +19 -0
  1054. package/src/prompts/tools/manage-skill.md +9 -0
  1055. package/src/prompts/tools/memory-edit.md +12 -0
  1056. package/src/prompts/tools/patch.md +57 -0
  1057. package/src/prompts/tools/read.md +27 -0
  1058. package/src/prompts/tools/recall.md +7 -0
  1059. package/src/prompts/tools/reflect.md +5 -0
  1060. package/src/prompts/tools/replace.md +29 -0
  1061. package/src/prompts/tools/retain.md +6 -0
  1062. package/src/prompts/tools/rewind.md +14 -0
  1063. package/src/prompts/tools/task-async-contract.md +1 -0
  1064. package/src/prompts/tools/task-summary.md +20 -0
  1065. package/src/prompts/tools/task.md +83 -0
  1066. package/src/prompts/tools/todo.md +42 -0
  1067. package/src/prompts/tools/vibe-kill.md +3 -0
  1068. package/src/prompts/tools/vibe-list.md +3 -0
  1069. package/src/prompts/tools/vibe-send.md +9 -0
  1070. package/src/prompts/tools/vibe-spawn.md +10 -0
  1071. package/src/prompts/tools/vibe-turn-result.md +19 -0
  1072. package/src/prompts/tools/vibe-wait.md +8 -0
  1073. package/src/prompts/tools/web-search.md +8 -0
  1074. package/src/prompts/tools/write.md +14 -0
  1075. package/src/registry/agent-lifecycle.ts +455 -0
  1076. package/src/registry/agent-registry.ts +217 -0
  1077. package/src/registry/persisted-agents.ts +98 -0
  1078. package/src/sdk.ts +3553 -0
  1079. package/src/secrets/index.ts +246 -0
  1080. package/src/secrets/obfuscator.ts +2574 -0
  1081. package/src/secrets/regex.ts +21 -0
  1082. package/src/session/acp-permission-gate.ts +165 -0
  1083. package/src/session/agent-session-events.ts +66 -0
  1084. package/src/session/agent-session-types.ts +346 -0
  1085. package/src/session/agent-session.ts +8406 -0
  1086. package/src/session/agent-storage.ts +805 -0
  1087. package/src/session/artifacts.ts +154 -0
  1088. package/src/session/async-job-delivery.ts +82 -0
  1089. package/src/session/auth-broker-config.ts +92 -0
  1090. package/src/session/auth-storage.ts +25 -0
  1091. package/src/session/bash-runner.ts +326 -0
  1092. package/src/session/blob-store.ts +295 -0
  1093. package/src/session/checkpoint-entries.ts +81 -0
  1094. package/src/session/client-bridge.ts +85 -0
  1095. package/src/session/codex-auto-reset.ts +202 -0
  1096. package/src/session/compact-modes.ts +105 -0
  1097. package/src/session/eval-runner.ts +217 -0
  1098. package/src/session/exit-diagnostics.ts +310 -0
  1099. package/src/session/history-storage.ts +327 -0
  1100. package/src/session/indexed-session-storage.ts +544 -0
  1101. package/src/session/irc-bridge.ts +203 -0
  1102. package/src/session/messages.ts +1280 -0
  1103. package/src/session/model-controls.ts +750 -0
  1104. package/src/session/prewalk.ts +257 -0
  1105. package/src/session/provider-image-budget.ts +86 -0
  1106. package/src/session/queued-messages.ts +99 -0
  1107. package/src/session/redis-session-storage.ts +257 -0
  1108. package/src/session/retry-fallback-chains.ts +455 -0
  1109. package/src/session/role-models.ts +85 -0
  1110. package/src/session/session-advisors.ts +1754 -0
  1111. package/src/session/session-context.ts +554 -0
  1112. package/src/session/session-dump-format.ts +216 -0
  1113. package/src/session/session-entries.ts +260 -0
  1114. package/src/session/session-handoff.ts +308 -0
  1115. package/src/session/session-history-format.ts +459 -0
  1116. package/src/session/session-listing.ts +715 -0
  1117. package/src/session/session-loader.ts +280 -0
  1118. package/src/session/session-maintenance.ts +2983 -0
  1119. package/src/session/session-manager.ts +2557 -0
  1120. package/src/session/session-memory.ts +222 -0
  1121. package/src/session/session-metadata.ts +53 -0
  1122. package/src/session/session-migrations.ts +78 -0
  1123. package/src/session/session-paths.ts +222 -0
  1124. package/src/session/session-persistence.ts +293 -0
  1125. package/src/session/session-provider-boundary.ts +306 -0
  1126. package/src/session/session-stats.ts +293 -0
  1127. package/src/session/session-storage.ts +734 -0
  1128. package/src/session/session-title-slot.ts +141 -0
  1129. package/src/session/session-tools.ts +1226 -0
  1130. package/src/session/session-workspace.ts +53 -0
  1131. package/src/session/settings-stream-fn.ts +74 -0
  1132. package/src/session/shake-types.ts +43 -0
  1133. package/src/session/snapcompact-inline.ts +545 -0
  1134. package/src/session/snapcompact-savings-journal.ts +113 -0
  1135. package/src/session/sql-session-storage.ts +374 -0
  1136. package/src/session/stream-guards.ts +417 -0
  1137. package/src/session/streaming-output.ts +1459 -0
  1138. package/src/session/todo-tracker.ts +380 -0
  1139. package/src/session/tool-choice-queue.ts +305 -0
  1140. package/src/session/ttsr-coordinator.ts +496 -0
  1141. package/src/session/turn-persistence.ts +142 -0
  1142. package/src/session/turn-recovery.ts +1728 -0
  1143. package/src/session/unexpected-stop-classifier.ts +132 -0
  1144. package/src/session/yield-queue.ts +183 -0
  1145. package/src/slash-commands/acp-builtins.ts +70 -0
  1146. package/src/slash-commands/available-commands.ts +105 -0
  1147. package/src/slash-commands/builtin-registry.ts +2982 -0
  1148. package/src/slash-commands/helpers/active-oauth-account.ts +80 -0
  1149. package/src/slash-commands/helpers/collab-qrcode.ts +28 -0
  1150. package/src/slash-commands/helpers/context-report.ts +66 -0
  1151. package/src/slash-commands/helpers/format.ts +46 -0
  1152. package/src/slash-commands/helpers/logout.ts +108 -0
  1153. package/src/slash-commands/helpers/marketplace-manager.ts +25 -0
  1154. package/src/slash-commands/helpers/mcp.ts +533 -0
  1155. package/src/slash-commands/helpers/parse.ts +85 -0
  1156. package/src/slash-commands/helpers/reset-usage.ts +66 -0
  1157. package/src/slash-commands/helpers/session-pin.ts +44 -0
  1158. package/src/slash-commands/helpers/ssh.ts +196 -0
  1159. package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
  1160. package/src/slash-commands/helpers/todo.ts +285 -0
  1161. package/src/slash-commands/helpers/usage-report.ts +198 -0
  1162. package/src/slash-commands/marketplace-install-parser.ts +99 -0
  1163. package/src/slash-commands/types.ts +139 -0
  1164. package/src/ssh/config-writer.ts +183 -0
  1165. package/src/ssh/connection-manager.ts +667 -0
  1166. package/src/ssh/file-transfer.ts +214 -0
  1167. package/src/ssh/sshfs-mount.ts +163 -0
  1168. package/src/ssh/utils.ts +51 -0
  1169. package/src/startup-splash.ts +19 -0
  1170. package/src/stt/asr-client.ts +401 -0
  1171. package/src/stt/asr-protocol.ts +65 -0
  1172. package/src/stt/asr-worker.ts +603 -0
  1173. package/src/stt/downloader.ts +142 -0
  1174. package/src/stt/endpointer.ts +259 -0
  1175. package/src/stt/index.ts +6 -0
  1176. package/src/stt/models.ts +150 -0
  1177. package/src/stt/sherpa-runtime.ts +71 -0
  1178. package/src/stt/stt-controller.ts +320 -0
  1179. package/src/stt/submit-trigger.ts +74 -0
  1180. package/src/subprocess/worker-client.ts +463 -0
  1181. package/src/subprocess/worker-runtime.ts +494 -0
  1182. package/src/system-prompt.ts +894 -0
  1183. package/src/task/agents.ts +168 -0
  1184. package/src/task/commands.ts +132 -0
  1185. package/src/task/discovery.ts +145 -0
  1186. package/src/task/executor.ts +3129 -0
  1187. package/src/task/index.ts +1519 -0
  1188. package/src/task/isolation-ownership.ts +106 -0
  1189. package/src/task/isolation-runner.ts +413 -0
  1190. package/src/task/label.ts +40 -0
  1191. package/src/task/name-generator.ts +1577 -0
  1192. package/src/task/omp-command.ts +26 -0
  1193. package/src/task/output-manager.ts +115 -0
  1194. package/src/task/parallel.ts +221 -0
  1195. package/src/task/persisted-revive.ts +141 -0
  1196. package/src/task/prewalk.ts +6 -0
  1197. package/src/task/prompt-policy.ts +8 -0
  1198. package/src/task/provider-concurrency.ts +100 -0
  1199. package/src/task/render.ts +1814 -0
  1200. package/src/task/renderer.ts +14 -0
  1201. package/src/task/repair-args.ts +118 -0
  1202. package/src/task/spawn-policy.ts +58 -0
  1203. package/src/task/structured-subagent.ts +649 -0
  1204. package/src/task/subprocess-tool-registry.ts +88 -0
  1205. package/src/task/types.ts +551 -0
  1206. package/src/task/worktree.ts +967 -0
  1207. package/src/task/yield-assembly.ts +198 -0
  1208. package/src/telemetry-export.ts +500 -0
  1209. package/src/thinking.ts +364 -0
  1210. package/src/tiny/device.ts +111 -0
  1211. package/src/tiny/dtype.ts +101 -0
  1212. package/src/tiny/message-preproc.ts +155 -0
  1213. package/src/tiny/models.ts +268 -0
  1214. package/src/tiny/text.ts +278 -0
  1215. package/src/tiny/title-client.ts +460 -0
  1216. package/src/tiny/title-protocol.ts +56 -0
  1217. package/src/tiny/worker.ts +354 -0
  1218. package/src/tools/acp-bridge.ts +81 -0
  1219. package/src/tools/approval.ts +245 -0
  1220. package/src/tools/ask.ts +1459 -0
  1221. package/src/tools/ast-edit.ts +718 -0
  1222. package/src/tools/ast-grep.ts +520 -0
  1223. package/src/tools/auto-generated-guard.ts +335 -0
  1224. package/src/tools/bash-interactive.ts +435 -0
  1225. package/src/tools/bash-interceptor.ts +67 -0
  1226. package/src/tools/bash-pty-selection.ts +14 -0
  1227. package/src/tools/bash-skill-urls.ts +335 -0
  1228. package/src/tools/bash.ts +1762 -0
  1229. package/src/tools/browser/aria/aria-snapshot.bundle.txt +7 -0
  1230. package/src/tools/browser/aria/aria-snapshot.ts +131 -0
  1231. package/src/tools/browser/attach.ts +194 -0
  1232. package/src/tools/browser/cmux/cmux-tab.ts +1400 -0
  1233. package/src/tools/browser/cmux/rpc.ts +206 -0
  1234. package/src/tools/browser/cmux/socket-client.ts +445 -0
  1235. package/src/tools/browser/launch.ts +788 -0
  1236. package/src/tools/browser/readable.ts +112 -0
  1237. package/src/tools/browser/registry.ts +287 -0
  1238. package/src/tools/browser/render.ts +226 -0
  1239. package/src/tools/browser/run-cancellation.ts +131 -0
  1240. package/src/tools/browser/run-output.ts +76 -0
  1241. package/src/tools/browser/tab-protocol.ts +115 -0
  1242. package/src/tools/browser/tab-supervisor.ts +1040 -0
  1243. package/src/tools/browser/tab-worker-entry.ts +29 -0
  1244. package/src/tools/browser/tab-worker.ts +1842 -0
  1245. package/src/tools/browser.ts +457 -0
  1246. package/src/tools/builtin-names.ts +66 -0
  1247. package/src/tools/checkpoint.ts +150 -0
  1248. package/src/tools/computer/exposure.ts +38 -0
  1249. package/src/tools/computer/protocol.ts +28 -0
  1250. package/src/tools/computer/supervisor.ts +306 -0
  1251. package/src/tools/computer/worker-entry.ts +34 -0
  1252. package/src/tools/computer/worker.ts +131 -0
  1253. package/src/tools/computer-renderer.ts +108 -0
  1254. package/src/tools/computer.ts +516 -0
  1255. package/src/tools/conflict-detect.ts +815 -0
  1256. package/src/tools/context.ts +46 -0
  1257. package/src/tools/debug.ts +1121 -0
  1258. package/src/tools/default-renderer.ts +139 -0
  1259. package/src/tools/essential-tools.ts +46 -0
  1260. package/src/tools/eval-backends.ts +34 -0
  1261. package/src/tools/eval-format/index.ts +24 -0
  1262. package/src/tools/eval-format/javascript.ts +952 -0
  1263. package/src/tools/eval-format/julia.ts +446 -0
  1264. package/src/tools/eval-format/python.ts +544 -0
  1265. package/src/tools/eval-format/ruby.ts +380 -0
  1266. package/src/tools/eval-render.ts +784 -0
  1267. package/src/tools/eval.ts +774 -0
  1268. package/src/tools/fetch.ts +1889 -0
  1269. package/src/tools/file-recorder.ts +35 -0
  1270. package/src/tools/fs-cache-invalidation.ts +28 -0
  1271. package/src/tools/gh-cache-invalidation.ts +175 -0
  1272. package/src/tools/gh-format.ts +12 -0
  1273. package/src/tools/gh-renderer.ts +484 -0
  1274. package/src/tools/gh.ts +3959 -0
  1275. package/src/tools/github-cache.ts +663 -0
  1276. package/src/tools/glob.ts +682 -0
  1277. package/src/tools/grep.ts +1858 -0
  1278. package/src/tools/grouped-file-output.ts +210 -0
  1279. package/src/tools/hub/index.ts +579 -0
  1280. package/src/tools/hub/jobs.ts +714 -0
  1281. package/src/tools/hub/launch.ts +579 -0
  1282. package/src/tools/hub/messaging.ts +735 -0
  1283. package/src/tools/hub/types.ts +117 -0
  1284. package/src/tools/image-gen.ts +1689 -0
  1285. package/src/tools/image-providers.ts +50 -0
  1286. package/src/tools/index.ts +691 -0
  1287. package/src/tools/inspect-image-renderer.ts +133 -0
  1288. package/src/tools/inspect-image.ts +290 -0
  1289. package/src/tools/json-tree.ts +260 -0
  1290. package/src/tools/jtd-to-json-schema.ts +219 -0
  1291. package/src/tools/jtd-to-typescript.ts +136 -0
  1292. package/src/tools/jtd-utils.ts +102 -0
  1293. package/src/tools/learn.ts +141 -0
  1294. package/src/tools/list-limit.ts +40 -0
  1295. package/src/tools/manage-skill.ts +102 -0
  1296. package/src/tools/match-line-format.ts +20 -0
  1297. package/src/tools/memory-edit.ts +61 -0
  1298. package/src/tools/memory-recall.ts +102 -0
  1299. package/src/tools/memory-reflect.ts +88 -0
  1300. package/src/tools/memory-render.ts +211 -0
  1301. package/src/tools/memory-retain.ts +89 -0
  1302. package/src/tools/output-meta.ts +845 -0
  1303. package/src/tools/output-schema-validator.ts +307 -0
  1304. package/src/tools/path-utils.ts +1381 -0
  1305. package/src/tools/plan-mode-guard.ts +155 -0
  1306. package/src/tools/puppeteer/00_stealth_tampering.txt +44 -0
  1307. package/src/tools/puppeteer/01_stealth_activity.txt +80 -0
  1308. package/src/tools/puppeteer/02_stealth_hairline.txt +57 -0
  1309. package/src/tools/puppeteer/03_stealth_botd.txt +380 -0
  1310. package/src/tools/puppeteer/04_stealth_iframe.txt +174 -0
  1311. package/src/tools/puppeteer/05_stealth_webgl.txt +233 -0
  1312. package/src/tools/puppeteer/06_stealth_screen.txt +260 -0
  1313. package/src/tools/puppeteer/07_stealth_fonts.txt +99 -0
  1314. package/src/tools/puppeteer/08_stealth_audio.txt +63 -0
  1315. package/src/tools/puppeteer/09_stealth_locale.txt +51 -0
  1316. package/src/tools/puppeteer/10_stealth_plugins.txt +212 -0
  1317. package/src/tools/puppeteer/11_stealth_hardware.txt +59 -0
  1318. package/src/tools/puppeteer/12_stealth_codecs.txt +42 -0
  1319. package/src/tools/puppeteer/13_stealth_worker.txt +235 -0
  1320. package/src/tools/read.ts +3742 -0
  1321. package/src/tools/render-utils.ts +924 -0
  1322. package/src/tools/renderers.ts +133 -0
  1323. package/src/tools/report-tool-issue.ts +568 -0
  1324. package/src/tools/resolve.ts +423 -0
  1325. package/src/tools/review.ts +103 -0
  1326. package/src/tools/shell-tokenize.ts +83 -0
  1327. package/src/tools/sqlite-reader.ts +884 -0
  1328. package/src/tools/terminal-output.ts +141 -0
  1329. package/src/tools/todo.ts +1226 -0
  1330. package/src/tools/tool-errors.ts +62 -0
  1331. package/src/tools/tool-result.ts +102 -0
  1332. package/src/tools/tool-timeouts.ts +37 -0
  1333. package/src/tools/tts.ts +266 -0
  1334. package/src/tools/vibe.ts +607 -0
  1335. package/src/tools/write.ts +1640 -0
  1336. package/src/tools/xdev.ts +508 -0
  1337. package/src/tools/yield.ts +486 -0
  1338. package/src/tts/downloader.ts +64 -0
  1339. package/src/tts/index.ts +10 -0
  1340. package/src/tts/models.ts +137 -0
  1341. package/src/tts/runtime.ts +21 -0
  1342. package/src/tts/speakable.ts +392 -0
  1343. package/src/tts/speech-enhancer.ts +206 -0
  1344. package/src/tts/streaming-player.ts +120 -0
  1345. package/src/tts/tts-client.ts +475 -0
  1346. package/src/tts/tts-protocol.ts +69 -0
  1347. package/src/tts/tts-worker.ts +434 -0
  1348. package/src/tts/vocalizer.ts +419 -0
  1349. package/src/tts/wav.ts +58 -0
  1350. package/src/tui/code-cell.ts +268 -0
  1351. package/src/tui/file-list.ts +55 -0
  1352. package/src/tui/hyperlink.ts +178 -0
  1353. package/src/tui/index.ts +13 -0
  1354. package/src/tui/output-block.ts +268 -0
  1355. package/src/tui/status-line.ts +54 -0
  1356. package/src/tui/tree-list.ts +172 -0
  1357. package/src/tui/types.ts +15 -0
  1358. package/src/tui/utils.ts +103 -0
  1359. package/src/tui/width-aware-text.ts +58 -0
  1360. package/src/utils/active-repo-context.ts +143 -0
  1361. package/src/utils/block-context.ts +312 -0
  1362. package/src/utils/changelog.ts +232 -0
  1363. package/src/utils/clipboard.ts +327 -0
  1364. package/src/utils/command-args.ts +76 -0
  1365. package/src/utils/commit-message-generator.ts +148 -0
  1366. package/src/utils/cpuprofile.ts +235 -0
  1367. package/src/utils/edit-mode.ts +61 -0
  1368. package/src/utils/enhanced-paste.ts +230 -0
  1369. package/src/utils/event-bus.ts +33 -0
  1370. package/src/utils/external-editor.ts +78 -0
  1371. package/src/utils/fetch-timeout.ts +10 -0
  1372. package/src/utils/file-display-mode.ts +44 -0
  1373. package/src/utils/file-mentions.ts +293 -0
  1374. package/src/utils/git.ts +2425 -0
  1375. package/src/utils/image-loading.ts +231 -0
  1376. package/src/utils/image-resize.ts +420 -0
  1377. package/src/utils/image-vision-fallback.ts +196 -0
  1378. package/src/utils/inspect-image-mode.ts +39 -0
  1379. package/src/utils/ipc.ts +38 -0
  1380. package/src/utils/jj.ts +416 -0
  1381. package/src/utils/lang-from-path.ts +251 -0
  1382. package/src/utils/local-date.ts +7 -0
  1383. package/src/utils/mac-file-urls.applescript +37 -0
  1384. package/src/utils/markit-cache.ts +166 -0
  1385. package/src/utils/markit.ts +223 -0
  1386. package/src/utils/mupdf-wasm-embed.ts +12 -0
  1387. package/src/utils/open.ts +126 -0
  1388. package/src/utils/profile-tree.ts +111 -0
  1389. package/src/utils/prompt-path.ts +3 -0
  1390. package/src/utils/qrcode.ts +535 -0
  1391. package/src/utils/sample-profile.ts +437 -0
  1392. package/src/utils/session-color.ts +142 -0
  1393. package/src/utils/shell-snapshot-fn-env.sh +63 -0
  1394. package/src/utils/shell-snapshot.ts +316 -0
  1395. package/src/utils/sixel.ts +69 -0
  1396. package/src/utils/thinking-display.ts +163 -0
  1397. package/src/utils/title-generator.ts +597 -0
  1398. package/src/utils/token-rate.ts +72 -0
  1399. package/src/utils/tool-choice.ts +63 -0
  1400. package/src/utils/tools-manager.ts +411 -0
  1401. package/src/utils/turndown.ts +83 -0
  1402. package/src/utils/zip.ts +1106 -0
  1403. package/src/vibe/runtime.ts +1540 -0
  1404. package/src/vibe/state.ts +4 -0
  1405. package/src/web/kagi.ts +304 -0
  1406. package/src/web/parallel.ts +354 -0
  1407. package/src/web/scrapers/artifacthub.ts +207 -0
  1408. package/src/web/scrapers/arxiv.ts +83 -0
  1409. package/src/web/scrapers/aur.ts +162 -0
  1410. package/src/web/scrapers/biorxiv.ts +133 -0
  1411. package/src/web/scrapers/bluesky.ts +262 -0
  1412. package/src/web/scrapers/brew.ts +172 -0
  1413. package/src/web/scrapers/cheatsh.ts +68 -0
  1414. package/src/web/scrapers/chocolatey.ts +196 -0
  1415. package/src/web/scrapers/choosealicense.ts +95 -0
  1416. package/src/web/scrapers/cisa-kev.ts +87 -0
  1417. package/src/web/scrapers/clojars.ts +154 -0
  1418. package/src/web/scrapers/coingecko.ts +177 -0
  1419. package/src/web/scrapers/crates-io.ts +97 -0
  1420. package/src/web/scrapers/crossref.ts +136 -0
  1421. package/src/web/scrapers/devto.ts +147 -0
  1422. package/src/web/scrapers/discogs.ts +306 -0
  1423. package/src/web/scrapers/discourse.ts +197 -0
  1424. package/src/web/scrapers/dockerhub.ts +138 -0
  1425. package/src/web/scrapers/docs-rs.ts +663 -0
  1426. package/src/web/scrapers/fdroid.ts +134 -0
  1427. package/src/web/scrapers/firefox-addons.ts +191 -0
  1428. package/src/web/scrapers/flathub.ts +223 -0
  1429. package/src/web/scrapers/github-gist.ts +58 -0
  1430. package/src/web/scrapers/github.ts +800 -0
  1431. package/src/web/scrapers/gitlab.ts +401 -0
  1432. package/src/web/scrapers/go-pkg.ts +266 -0
  1433. package/src/web/scrapers/hackage.ts +140 -0
  1434. package/src/web/scrapers/hackernews.ts +189 -0
  1435. package/src/web/scrapers/hex.ts +105 -0
  1436. package/src/web/scrapers/huggingface.ts +321 -0
  1437. package/src/web/scrapers/iacr.ts +89 -0
  1438. package/src/web/scrapers/index.ts +252 -0
  1439. package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
  1440. package/src/web/scrapers/lemmy.ts +203 -0
  1441. package/src/web/scrapers/lobsters.ts +175 -0
  1442. package/src/web/scrapers/mastodon.ts +292 -0
  1443. package/src/web/scrapers/maven.ts +138 -0
  1444. package/src/web/scrapers/mdn.ts +173 -0
  1445. package/src/web/scrapers/metacpan.ts +222 -0
  1446. package/src/web/scrapers/musicbrainz.ts +250 -0
  1447. package/src/web/scrapers/npm.ts +98 -0
  1448. package/src/web/scrapers/nuget.ts +183 -0
  1449. package/src/web/scrapers/nvd.ts +222 -0
  1450. package/src/web/scrapers/ollama.ts +239 -0
  1451. package/src/web/scrapers/open-vsx.ts +106 -0
  1452. package/src/web/scrapers/opencorporates.ts +292 -0
  1453. package/src/web/scrapers/openlibrary.ts +336 -0
  1454. package/src/web/scrapers/orcid.ts +286 -0
  1455. package/src/web/scrapers/osv.ts +176 -0
  1456. package/src/web/scrapers/packagist.ts +160 -0
  1457. package/src/web/scrapers/pub-dev.ts +143 -0
  1458. package/src/web/scrapers/pubmed.ts +211 -0
  1459. package/src/web/scrapers/pypi.ts +112 -0
  1460. package/src/web/scrapers/rawg.ts +110 -0
  1461. package/src/web/scrapers/readthedocs.ts +120 -0
  1462. package/src/web/scrapers/reddit.ts +95 -0
  1463. package/src/web/scrapers/repology.ts +251 -0
  1464. package/src/web/scrapers/rfc.ts +201 -0
  1465. package/src/web/scrapers/rubygems.ts +103 -0
  1466. package/src/web/scrapers/searchcode.ts +189 -0
  1467. package/src/web/scrapers/sec-edgar.ts +261 -0
  1468. package/src/web/scrapers/semantic-scholar.ts +171 -0
  1469. package/src/web/scrapers/snapcraft.ts +187 -0
  1470. package/src/web/scrapers/sourcegraph.ts +336 -0
  1471. package/src/web/scrapers/spdx.ts +108 -0
  1472. package/src/web/scrapers/spotify.ts +198 -0
  1473. package/src/web/scrapers/stackoverflow.ts +120 -0
  1474. package/src/web/scrapers/terraform.ts +277 -0
  1475. package/src/web/scrapers/tldr.ts +47 -0
  1476. package/src/web/scrapers/twitter.ts +94 -0
  1477. package/src/web/scrapers/types.ts +354 -0
  1478. package/src/web/scrapers/utils.ts +109 -0
  1479. package/src/web/scrapers/vimeo.ts +133 -0
  1480. package/src/web/scrapers/vscode-marketplace.ts +187 -0
  1481. package/src/web/scrapers/w3c.ts +156 -0
  1482. package/src/web/scrapers/wikidata.ts +344 -0
  1483. package/src/web/scrapers/wikipedia.ts +84 -0
  1484. package/src/web/scrapers/youtube.ts +325 -0
  1485. package/src/web/search/index.ts +376 -0
  1486. package/src/web/search/provider.ts +272 -0
  1487. package/src/web/search/providers/anthropic.ts +401 -0
  1488. package/src/web/search/providers/base.ts +110 -0
  1489. package/src/web/search/providers/brave.ts +179 -0
  1490. package/src/web/search/providers/browser-headers.ts +109 -0
  1491. package/src/web/search/providers/browser-page.ts +123 -0
  1492. package/src/web/search/providers/codex.ts +749 -0
  1493. package/src/web/search/providers/duckduckgo.ts +213 -0
  1494. package/src/web/search/providers/ecosia.ts +182 -0
  1495. package/src/web/search/providers/exa.ts +511 -0
  1496. package/src/web/search/providers/firecrawl.ts +211 -0
  1497. package/src/web/search/providers/gemini.ts +628 -0
  1498. package/src/web/search/providers/google.ts +194 -0
  1499. package/src/web/search/providers/jina.ts +134 -0
  1500. package/src/web/search/providers/kagi.ts +95 -0
  1501. package/src/web/search/providers/kimi.ts +217 -0
  1502. package/src/web/search/providers/mojeek.ts +219 -0
  1503. package/src/web/search/providers/parallel.ts +182 -0
  1504. package/src/web/search/providers/perplexity-auth.ts +142 -0
  1505. package/src/web/search/providers/perplexity.ts +994 -0
  1506. package/src/web/search/providers/public.ts +199 -0
  1507. package/src/web/search/providers/searxng.ts +461 -0
  1508. package/src/web/search/providers/startpage.ts +219 -0
  1509. package/src/web/search/providers/synthetic.ts +120 -0
  1510. package/src/web/search/providers/tavily.ts +242 -0
  1511. package/src/web/search/providers/tinyfish.ts +164 -0
  1512. package/src/web/search/providers/utils.ts +128 -0
  1513. package/src/web/search/providers/xai.ts +372 -0
  1514. package/src/web/search/providers/zai.ts +437 -0
  1515. package/src/web/search/query.ts +850 -0
  1516. package/src/web/search/render.ts +262 -0
  1517. package/src/web/search/types.ts +507 -0
  1518. package/src/web/search/utils.ts +17 -0
  1519. package/src/workspace-tree.ts +326 -0
@@ -0,0 +1,1968 @@
1
+ import { type AgentToolResult, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
+ import { PASTE_CODE_LOGIN_PROVIDERS } from "@oh-my-pi/pi-ai";
3
+ import { getOAuthProviders } from "@oh-my-pi/pi-ai/oauth";
4
+ import type { OAuthProvider } from "@oh-my-pi/pi-ai/oauth/types";
5
+ import type { Component, OverlayHandle } from "@oh-my-pi/pi-tui";
6
+ import { Loader, Spacer, setTuiTight, Text } from "@oh-my-pi/pi-tui";
7
+ import { getAgentDbPath, getAgentDir, getProjectDir, normalizePathForComparison } from "@oh-my-pi/pi-utils";
8
+ import {
9
+ type AdvisorConfigScope,
10
+ discoverAdvisorConfigs,
11
+ loadWatchdogConfigFile,
12
+ resolveAdvisorConfigEditPath,
13
+ saveWatchdogConfigFile,
14
+ } from "../../advisor";
15
+ import { reset as resetCapabilities } from "../../capability";
16
+ import {
17
+ formatModelSelectorValue,
18
+ resolveAdvisorRoleSelection,
19
+ resolveModelRoleValue,
20
+ } from "../../config/model-resolver";
21
+ import { getRoleInfo } from "../../config/model-roles";
22
+ import { settings } from "../../config/settings";
23
+ import { disableProvider, enableProvider } from "../../discovery";
24
+ import { clearPluginRootsAndCaches, resolveActiveProjectRegistryPath } from "../../discovery/helpers";
25
+ import {
26
+ getInstalledPluginsRegistryPath,
27
+ getMarketplacesCacheDir,
28
+ getMarketplacesRegistryPath,
29
+ getPluginsCacheDir,
30
+ MarketplaceManager,
31
+ } from "../../extensibility/plugins/marketplace";
32
+ import {
33
+ getAvailableThemes,
34
+ getSymbolTheme,
35
+ previewTheme,
36
+ setColorBlindMode,
37
+ setMarkdownMermaidRendering,
38
+ setSymbolPreset,
39
+ setTheme,
40
+ theme,
41
+ } from "../../modes/theme/theme";
42
+ import type { InteractiveModeContext } from "../../modes/types";
43
+ import type { SessionOAuthAccountList } from "../../session/agent-session-types";
44
+ import type { ResetCreditAccountStatus, ResetCreditRedeemOutcome } from "../../session/auth-storage";
45
+ import type { SessionInfo } from "../../session/session-listing";
46
+ import { SessionManager } from "../../session/session-manager";
47
+ import { FileSessionStorage } from "../../session/session-storage";
48
+ import { type LogoutAccount, toLogoutAccounts } from "../../slash-commands/helpers/logout";
49
+ import {
50
+ describeRedeemOutcome,
51
+ type ResetUsageAccount,
52
+ toResetUsageAccounts,
53
+ } from "../../slash-commands/helpers/reset-usage";
54
+ import { toSessionPinAccounts } from "../../slash-commands/helpers/session-pin";
55
+ import {
56
+ AUTO_THINKING,
57
+ type ConfiguredThinkingLevel,
58
+ concreteThinkingLevel,
59
+ parseConfiguredThinkingLevel,
60
+ } from "../../thinking";
61
+ import {
62
+ isSearchProviderId,
63
+ setExcludedSearchProviders,
64
+ setImageProviderOrder,
65
+ setSearchProviderOrder,
66
+ type ToolSession,
67
+ } from "../../tools";
68
+ import { AskTool, type AskToolDetails, type AskToolInput } from "../../tools/ask";
69
+ import { shortenPath } from "../../tools/render-utils";
70
+ import { ToolAbortError } from "../../tools/tool-errors";
71
+ import { copyToClipboard } from "../../utils/clipboard";
72
+ import { repo } from "../../utils/git";
73
+ import { setSessionTerminalTitle } from "../../utils/title-generator";
74
+ import { type AdvisorConfigDeps, AdvisorConfigOverlayComponent } from "../components/advisor-config";
75
+ import { AgentDashboard } from "../components/agent-dashboard";
76
+ import { AgentHubOverlayComponent } from "../components/agent-hub";
77
+ import { AssistantMessageComponent } from "../components/assistant-message";
78
+ import { CopySelectorComponent } from "../components/copy-selector";
79
+ import { ExtensionDashboard } from "../components/extensions";
80
+ import { HistorySearchComponent } from "../components/history-search";
81
+ import { LoginDialogComponent } from "../components/login-dialog";
82
+ import { LogoutAccountSelectorComponent } from "../components/logout-account-selector";
83
+ import { ModelHubComponent, type ModelRoleSelectionScope } from "../components/model-hub";
84
+ import { ModelPickerComponent } from "../components/model-picker";
85
+ import { OAuthSelectorComponent } from "../components/oauth-selector";
86
+ import { PluginSelectorComponent } from "../components/plugin-selector";
87
+ import { ResetUsageSelectorComponent } from "../components/reset-usage-selector";
88
+ import { renderSegmentTrack } from "../components/segment-track";
89
+ import { SessionAccountSelectorComponent } from "../components/session-account-selector";
90
+ import { SessionSelectorComponent } from "../components/session-selector";
91
+ import { SettingsSelectorComponent } from "../components/settings-selector";
92
+ import { ToolExecutionComponent } from "../components/tool-execution";
93
+ import { TranscriptBlock } from "../components/transcript-container";
94
+ import { TreeSelectorComponent } from "../components/tree-selector";
95
+ import { UserMessageSelectorComponent } from "../components/user-message-selector";
96
+ import type { SessionObserverRegistry } from "../session-observer-registry";
97
+ import { buildCopyTargets } from "../utils/copy-targets";
98
+
99
+ const MANUAL_LOGIN_PROMPT = "Paste the authorization code (or full redirect URL), then press Enter:";
100
+
101
+ export class SelectorController {
102
+ constructor(private ctx: InteractiveModeContext) {}
103
+ #defaultRoleMutationTail = Promise.resolve();
104
+
105
+ async #acquireDefaultRoleMutation(): Promise<() => void> {
106
+ const previous = this.#defaultRoleMutationTail;
107
+ const { promise, resolve } = Promise.withResolvers<void>();
108
+ this.#defaultRoleMutationTail = previous.then(() => promise);
109
+ await previous;
110
+ return resolve;
111
+ }
112
+
113
+ async #refreshOAuthProviderAuthState(): Promise<void> {
114
+ const oauthProviders = getOAuthProviders();
115
+ await Promise.all(
116
+ oauthProviders.map(provider =>
117
+ this.ctx.session.modelRegistry
118
+ .getApiKeyForProvider(provider.id, this.ctx.session.sessionId)
119
+ .catch(() => undefined),
120
+ ),
121
+ );
122
+ }
123
+
124
+ /**
125
+ * Restore keyboard focus to whatever currently owns the editor slot. The
126
+ * slot can hold the editor itself or a hook selector/input/editor pushed
127
+ * in by `ExtensionUiController` — e.g. an approval prompt that fired while
128
+ * a fullscreen overlay was up. `overlayHandle.hide()` restores focus to
129
+ * the component focused when the overlay opened, which is stale in that
130
+ * case (the editor was swapped out): keys land on a hidden editor and the
131
+ * visible prompt receives nothing (issue #3349). Call this after the
132
+ * overlay hides to re-target focus at the visible slot owner.
133
+ */
134
+ focusActiveEditorArea(): void {
135
+ const visible = this.ctx.editorContainer.children[0] ?? this.ctx.editor;
136
+ this.ctx.ui.setFocus(visible);
137
+ }
138
+
139
+ /**
140
+ * Shows a selector component in place of the editor.
141
+ * @param create Factory that receives a `done` callback and returns the component and focus target
142
+ */
143
+ showSelector(create: (done: () => void) => { component: Component; focus: Component }): void {
144
+ const done = () => {
145
+ this.ctx.editorContainer.clear();
146
+ this.ctx.editorContainer.addChild(this.ctx.editor);
147
+ this.ctx.ui.setFocus(this.ctx.editor);
148
+ };
149
+ const { component, focus } = create(done);
150
+ this.ctx.editorContainer.clear();
151
+ this.ctx.editorContainer.addChild(component);
152
+ this.ctx.ui.setFocus(focus);
153
+ this.ctx.ui.requestRender();
154
+ }
155
+
156
+ showSettingsSelector(): void {
157
+ getAvailableThemes().then(availableThemes => {
158
+ // Fullscreen settings editor on the alternate screen: the overlay
159
+ // enables mouse tracking (click/hover/wheel) for its lifetime and
160
+ // the transcript stays untouched underneath.
161
+ let overlayHandle: OverlayHandle | undefined;
162
+ const done = () => {
163
+ overlayHandle?.hide();
164
+ this.focusActiveEditorArea();
165
+ this.ctx.ui.requestRender();
166
+ };
167
+ const selector = new SettingsSelectorComponent(
168
+ {
169
+ availableThinkingLevels: [...this.ctx.session.getAvailableThinkingLevels()],
170
+ thinkingLevel: this.ctx.session.thinkingLevel,
171
+ availableThemes,
172
+ providers: [...new Set(this.ctx.session.getAvailableModels().map(model => model.provider))].sort(
173
+ (a, b) => a.localeCompare(b),
174
+ ),
175
+ cwd: getProjectDir(),
176
+ model: this.ctx.session.model,
177
+ imageBudget: this.ctx.ui.imageBudget,
178
+ requestRender: () => this.ctx.ui.requestRender(),
179
+ },
180
+ {
181
+ onChange: (id, value) => this.handleSettingChange(id, value),
182
+ onThemePreview: async themeName => {
183
+ const result = await previewTheme(themeName);
184
+ if (result.success) {
185
+ this.ctx.statusLine.invalidate();
186
+ this.ctx.ui.invalidate();
187
+ this.ctx.ui.requestRender();
188
+ }
189
+ },
190
+ onStatusLinePreview: previewSettings => {
191
+ // Update status line with preview settings
192
+ this.ctx.statusLine.updateSettings({
193
+ preset: settings.get("statusLine.preset"),
194
+ leftSegments: settings.get("statusLine.leftSegments"),
195
+ rightSegments: settings.get("statusLine.rightSegments"),
196
+ separator: settings.get("statusLine.separator"),
197
+ showHookStatus: settings.get("statusLine.showHookStatus"),
198
+ sessionAccent: settings.get("statusLine.sessionAccent"),
199
+ transparent: settings.get("statusLine.transparent"),
200
+ compactThinkingLevel: settings.get("statusLine.compactThinkingLevel"),
201
+ ...previewSettings,
202
+ });
203
+ this.ctx.ui.requestRender();
204
+ },
205
+ getStatusLinePreview: () => {
206
+ // Return the rendered status line for inline preview
207
+ const availableWidth = this.ctx.editor.getTopBorderAvailableWidth(this.ctx.ui.terminal.columns);
208
+ return this.ctx.statusLine.getTopBorder(availableWidth).content;
209
+ },
210
+ onPluginsChanged: async () => {
211
+ const projectPath = await resolveActiveProjectRegistryPath(this.ctx.sessionManager.getCwd());
212
+ clearPluginRootsAndCaches(projectPath ? [projectPath] : undefined);
213
+ await this.ctx.refreshSkillState();
214
+ await this.ctx.refreshSlashCommandState();
215
+ resetCapabilities();
216
+ this.ctx.ui.requestRender();
217
+ },
218
+ onCancel: () => {
219
+ done();
220
+ // Restore status line to saved settings
221
+ this.ctx.statusLine.updateSettings({
222
+ preset: settings.get("statusLine.preset"),
223
+ leftSegments: settings.get("statusLine.leftSegments"),
224
+ rightSegments: settings.get("statusLine.rightSegments"),
225
+ separator: settings.get("statusLine.separator"),
226
+ showHookStatus: settings.get("statusLine.showHookStatus"),
227
+ sessionAccent: settings.get("statusLine.sessionAccent"),
228
+ transparent: settings.get("statusLine.transparent"),
229
+ compactThinkingLevel: settings.get("statusLine.compactThinkingLevel"),
230
+ });
231
+ this.ctx.ui.requestRender();
232
+ },
233
+ },
234
+ );
235
+ overlayHandle = this.ctx.ui.showOverlay(selector, {
236
+ anchor: "bottom-center",
237
+ width: "100%",
238
+ maxHeight: "100%",
239
+ margin: 0,
240
+ fullscreen: true,
241
+ });
242
+ this.ctx.ui.setFocus(selector);
243
+ this.ctx.ui.requestRender();
244
+ });
245
+ }
246
+
247
+ showAdvisorConfigure(): void {
248
+ const cwd = this.ctx.sessionManager.getCwd();
249
+ const agentDir = getAgentDir() ?? getProjectDir();
250
+ const initialScope: AdvisorConfigScope = "project";
251
+ void (async () => {
252
+ // "Project" scope edits the repo-root WATCHDOG.yml (the project-level file
253
+ // discovery walks), not the launch subdir — `getProjectDir()` is only cwd.
254
+ let projectDir = cwd;
255
+ try {
256
+ projectDir = (await repo.root(cwd)) ?? cwd;
257
+ } catch {
258
+ projectDir = cwd;
259
+ }
260
+ const dirs = { projectDir, agentDir };
261
+ const initialDoc = await loadWatchdogConfigFile(await resolveAdvisorConfigEditPath(initialScope, dirs));
262
+ // Fullscreen editor on the alternate screen (the /settings idiom): the
263
+ // overlay holds the alt buffer + mouse tracking; the transcript stays put.
264
+ let overlayHandle: OverlayHandle | undefined;
265
+ const done = () => {
266
+ overlayHandle?.hide();
267
+ this.focusActiveEditorArea();
268
+ this.ctx.ui.requestRender();
269
+ };
270
+ // Label the seeded implicit-default row with the actual advisor-role model
271
+ // (NOT the first live advisor, which may be a named advisor from another scope).
272
+ const advisorRoleSel = resolveAdvisorRoleSelection(
273
+ this.ctx.settings,
274
+ this.ctx.session.modelRegistry.getAvailable(),
275
+ );
276
+ const defaultAdvisorModel = advisorRoleSel?.model;
277
+ const deps: AdvisorConfigDeps = {
278
+ modelRegistry: this.ctx.session.modelRegistry,
279
+ settings: this.ctx.settings,
280
+ scopedModels: this.ctx.session.scopedModels,
281
+ availableToolNames: this.ctx.session.getAdvisorAvailableToolNames(),
282
+ defaultModelLabel: defaultAdvisorModel
283
+ ? `${defaultAdvisorModel.provider}/${defaultAdvisorModel.id}`
284
+ : undefined,
285
+ };
286
+ const overlay = new AdvisorConfigOverlayComponent(this.ctx.ui, deps, initialScope, initialDoc, {
287
+ loadDoc: async scope => loadWatchdogConfigFile(await resolveAdvisorConfigEditPath(scope, dirs)),
288
+ save: async (scope, doc) => {
289
+ await saveWatchdogConfigFile(await resolveAdvisorConfigEditPath(scope, dirs), doc);
290
+ // Re-discover the merged roster (project + user) so the live advisors
291
+ // reflect cross-level precedence, not just the edited file.
292
+ const discovered = await discoverAdvisorConfigs(cwd, agentDir);
293
+ const count = this.ctx.session.applyAdvisorConfigs(discovered.advisors, discovered.sharedInstructions);
294
+ this.ctx.statusLine.invalidate();
295
+ this.ctx.showStatus(
296
+ count > 0
297
+ ? `Saved ${scope} WATCHDOG.yml — ${count} advisor${count === 1 ? "" : "s"} active.`
298
+ : `Saved ${scope} WATCHDOG.yml. Run /advisor on to activate the configured advisors.`,
299
+ );
300
+ this.ctx.ui.requestRender();
301
+ },
302
+ close: done,
303
+ requestRender: () => this.ctx.ui.requestRender(),
304
+ notify: message => this.ctx.showStatus(message),
305
+ getAdvisorStats: () => this.ctx.session.getAdvisorStats().advisors,
306
+ getUsageReports: async () => this.ctx.session.fetchUsageReports?.() ?? null,
307
+ resolveActiveAccount: (provider, sessionId) =>
308
+ this.ctx.session.modelRegistry.authStorage.getOAuthAccountIdentity(
309
+ provider,
310
+ sessionId ?? this.ctx.session.sessionId,
311
+ ),
312
+ });
313
+ overlayHandle = this.ctx.ui.showOverlay(overlay, {
314
+ anchor: "bottom-center",
315
+ width: "100%",
316
+ maxHeight: "100%",
317
+ margin: 0,
318
+ fullscreen: true,
319
+ });
320
+ this.ctx.ui.setFocus(overlay);
321
+ this.ctx.ui.requestRender();
322
+ })();
323
+ }
324
+
325
+ showHistorySearch(): void {
326
+ const historyStorage = this.ctx.historyStorage;
327
+ if (!historyStorage) return;
328
+
329
+ this.showSelector(done => {
330
+ const component = new HistorySearchComponent(
331
+ historyStorage,
332
+ prompt => {
333
+ done();
334
+ this.ctx.editor.setText(prompt);
335
+ this.ctx.ui.requestRender();
336
+ },
337
+ () => {
338
+ done();
339
+ this.ctx.ui.requestRender();
340
+ },
341
+ );
342
+ return { component, focus: component };
343
+ });
344
+ }
345
+
346
+ /**
347
+ * Show the Extension Control Center dashboard.
348
+ * Replaces /status with a unified view of all providers and extensions.
349
+ */
350
+ async showExtensionsDashboard(): Promise<void> {
351
+ const dashboard = await ExtensionDashboard.create(getProjectDir(), this.ctx.settings, this.ctx.ui.terminal.rows);
352
+ // Fullscreen dashboard on the alternate screen (the /settings idiom): the
353
+ // overlay borrows the terminal's alt buffer and enables mouse tracking for
354
+ // its lifetime, leaving the transcript untouched underneath.
355
+ const overlay = this.ctx.ui.showOverlay(dashboard, {
356
+ width: "100%",
357
+ maxHeight: "100%",
358
+ anchor: "top-left",
359
+ margin: 0,
360
+ fullscreen: true,
361
+ });
362
+ dashboard.onClose = () => {
363
+ overlay.hide();
364
+ this.focusActiveEditorArea();
365
+ this.ctx.ui.requestRender();
366
+ };
367
+ dashboard.onRequestRender = () => {
368
+ this.ctx.ui.requestRender();
369
+ };
370
+ }
371
+
372
+ /**
373
+ * Show the Agent Control Center dashboard.
374
+ */
375
+ async showAgentsDashboard(): Promise<void> {
376
+ const activeModel = this.ctx.session.model;
377
+ const activeModelPattern = activeModel ? `${activeModel.provider}/${activeModel.id}` : undefined;
378
+ const defaultModelPattern = this.ctx.settings.getModelRole("default");
379
+ const dashboard = await AgentDashboard.create(getProjectDir(), this.ctx.settings, this.ctx.ui.terminal.rows, {
380
+ modelRegistry: this.ctx.session.modelRegistry,
381
+ activeModelPattern,
382
+ defaultModelPattern,
383
+ });
384
+ const overlay = this.ctx.ui.showOverlay(dashboard, {
385
+ width: "100%",
386
+ maxHeight: "100%",
387
+ anchor: "top-left",
388
+ margin: 0,
389
+ });
390
+ dashboard.onClose = () => {
391
+ overlay.hide();
392
+ this.focusActiveEditorArea();
393
+ this.ctx.ui.requestRender();
394
+ };
395
+ dashboard.onRequestRender = () => {
396
+ this.ctx.ui.requestRender();
397
+ };
398
+ }
399
+
400
+ /**
401
+ * Handle setting changes from the settings selector.
402
+ * Most settings are saved directly via SettingsManager in the definitions.
403
+ * This handles side effects and session-specific settings.
404
+ */
405
+ handleSettingChange(id: string, value: unknown): void {
406
+ // Discovery provider toggles
407
+ if (id.startsWith("discovery.")) {
408
+ const providerId = id.replace("discovery.", "");
409
+ if (value) {
410
+ enableProvider(providerId);
411
+ } else {
412
+ disableProvider(providerId);
413
+ }
414
+ return;
415
+ }
416
+
417
+ switch (id) {
418
+ // Session-managed settings (not in SettingsManager)
419
+ case "autoCompact":
420
+ this.ctx.session.setAutoCompactionEnabled(value as boolean);
421
+ this.ctx.statusLine.setAutoCompactEnabled(value as boolean);
422
+ break;
423
+ case "advisor.enabled":
424
+ this.ctx.session.setAdvisorEnabled(value as boolean);
425
+ this.ctx.statusLine.invalidate();
426
+ this.ctx.ui.requestRender();
427
+ break;
428
+ case "steeringMode":
429
+ this.ctx.session.setSteeringMode(value as "all" | "one-at-a-time");
430
+ break;
431
+ case "followUpMode":
432
+ this.ctx.session.setFollowUpMode(value as "all" | "one-at-a-time");
433
+ break;
434
+ case "interruptMode":
435
+ this.ctx.session.setInterruptMode(value as "immediate" | "wait");
436
+ break;
437
+ case "thinkingLevel":
438
+ case "defaultThinkingLevel":
439
+ this.ctx.session.setThinkingLevel(value as ConfiguredThinkingLevel, true);
440
+ this.ctx.statusLine.invalidate();
441
+ this.ctx.updateEditorBorderColor();
442
+ break;
443
+ case "personality":
444
+ void this.ctx.session.refreshBaseSystemPrompt().catch(err => {
445
+ this.ctx.showError(`Failed to apply personality: ${err}`);
446
+ });
447
+ break;
448
+ case "tools.xdevDocs":
449
+ void this.ctx.session.refreshBaseSystemPrompt().catch(err => {
450
+ this.ctx.showError(`Failed to apply xd:// prompt docs setting: ${err}`);
451
+ });
452
+ break;
453
+ case "memory.backend":
454
+ void this.ctx.session.applyMemoryBackend().catch(err => {
455
+ this.ctx.showError(`Failed to apply memory backend: ${err}`);
456
+ });
457
+ break;
458
+ case "inspect_image.mode":
459
+ void this.ctx.session.applyInspectImageModeChange().catch(err => {
460
+ this.ctx.showError(`Failed to apply vision mode: ${err}`);
461
+ });
462
+ break;
463
+
464
+ case "autocompleteMaxVisible":
465
+ this.ctx.editor.setAutocompleteMaxVisible(typeof value === "number" ? value : Number(value));
466
+ break;
467
+
468
+ // Settings with UI side effects
469
+ case "terminal.showImages":
470
+ case "showImages": {
471
+ const visible = value as boolean;
472
+ for (const child of this.ctx.chatContainer.children) {
473
+ if (child instanceof ToolExecutionComponent) {
474
+ child.setShowImages(visible);
475
+ } else if (child instanceof AssistantMessageComponent) {
476
+ child.setImagesVisible(visible);
477
+ }
478
+ }
479
+ if (!visible) this.ctx.ui.clearInlineImages();
480
+ this.ctx.ui.resetDisplay();
481
+ break;
482
+ }
483
+ case "hideThinkingBlock":
484
+ this.ctx.hideThinkingBlock = value as boolean;
485
+ for (const child of this.ctx.chatContainer.children) {
486
+ if (child instanceof AssistantMessageComponent) {
487
+ child.setHideThinkingBlock(this.ctx.effectiveHideThinkingBlock);
488
+ }
489
+ }
490
+ // Full clear + replay so blocks frozen in committed scrollback on
491
+ // ED3-risk terminals retire their stale snapshots too (see
492
+ // InputController.toggleThinkingBlockVisibility).
493
+ this.ctx.ui.resetDisplay();
494
+ break;
495
+ case "proseOnlyThinking":
496
+ this.ctx.proseOnlyThinking = value as boolean;
497
+ for (const child of this.ctx.chatContainer.children) {
498
+ if (child instanceof AssistantMessageComponent) {
499
+ child.setProseOnlyThinking(value as boolean);
500
+ }
501
+ }
502
+ this.ctx.ui.resetDisplay();
503
+ break;
504
+ case "omitThinking":
505
+ this.ctx.session.agent.hideThinkingSummary = value as boolean;
506
+ break;
507
+ case "display.cacheMissMarker":
508
+ // Rebuild re-runs the usage-based detection under the new setting so
509
+ // markers appear/disappear; full reset retires any already committed
510
+ // to native scrollback (mirrors hideThinking).
511
+ this.ctx.rebuildChatFromMessages();
512
+ this.ctx.ui.resetDisplay();
513
+ break;
514
+ case "display.collapseCompacted":
515
+ // Rebuild swaps between the collapsed tail and the full inline
516
+ // history; full reset retires blocks already committed to native
517
+ // scrollback (mirrors cacheMissMarker).
518
+ this.ctx.rebuildChatFromMessages();
519
+ this.ctx.ui.resetDisplay();
520
+ break;
521
+ case "tui.tight":
522
+ setTuiTight(value as boolean);
523
+ this.ctx.ui.invalidate();
524
+ this.ctx.ui.requestRender();
525
+ break;
526
+
527
+ case "tui.scrollbackRebuild":
528
+ this.ctx.ui.setScrollbackRebuild(value as boolean);
529
+ break;
530
+
531
+ case "tui.renderMermaid":
532
+ setMarkdownMermaidRendering(value as boolean);
533
+ this.ctx.session.refreshBaseSystemPrompt().catch(err => {
534
+ this.ctx.showError(`Failed to apply Mermaid rendering setting: ${err}`);
535
+ });
536
+ this.ctx.rebuildChatFromMessages();
537
+ this.ctx.ui.resetDisplay();
538
+ break;
539
+
540
+ case "theme": {
541
+ setTheme(value as string, true).then(result => {
542
+ this.ctx.statusLine.invalidate();
543
+ this.ctx.ui.requestRender();
544
+ this.ctx.ui.invalidate();
545
+ if (!result.success) {
546
+ this.ctx.showError(`Failed to load theme "${value}": ${result.error}\nFell back to dark theme.`);
547
+ }
548
+ });
549
+ break;
550
+ }
551
+ case "symbolPreset": {
552
+ setSymbolPreset(value as "unicode" | "nerd" | "ascii").then(() => {
553
+ this.ctx.statusLine.invalidate();
554
+ this.ctx.ui.requestRender();
555
+ this.ctx.ui.invalidate();
556
+ });
557
+ break;
558
+ }
559
+ case "colorBlindMode": {
560
+ setColorBlindMode(value === "true" || value === true).then(() => {
561
+ this.ctx.ui.invalidate();
562
+ });
563
+ break;
564
+ }
565
+ case "temperature": {
566
+ const temp = typeof value === "number" ? value : Number(value);
567
+ this.ctx.session.agent.temperature = temp >= 0 ? temp : undefined;
568
+ break;
569
+ }
570
+ case "topP": {
571
+ const topP = typeof value === "number" ? value : Number(value);
572
+ this.ctx.session.agent.topP = topP >= 0 ? topP : undefined;
573
+ break;
574
+ }
575
+ case "topK": {
576
+ const topK = typeof value === "number" ? value : Number(value);
577
+ this.ctx.session.agent.topK = topK >= 0 ? topK : undefined;
578
+ break;
579
+ }
580
+ case "minP": {
581
+ const minP = typeof value === "number" ? value : Number(value);
582
+ this.ctx.session.agent.minP = minP >= 0 ? minP : undefined;
583
+ break;
584
+ }
585
+ case "presencePenalty": {
586
+ const presencePenalty = typeof value === "number" ? value : Number(value);
587
+ this.ctx.session.agent.presencePenalty = presencePenalty >= 0 ? presencePenalty : undefined;
588
+ break;
589
+ }
590
+ case "repetitionPenalty": {
591
+ const repetitionPenalty = typeof value === "number" ? value : Number(value);
592
+ this.ctx.session.agent.repetitionPenalty = repetitionPenalty >= 0 ? repetitionPenalty : undefined;
593
+ break;
594
+ }
595
+ case "git.enabled":
596
+ case "statusLinePreset":
597
+ case "statusLine.preset":
598
+ case "statusLineSeparator":
599
+ case "statusLine.separator":
600
+ case "statusLineShowHooks":
601
+ case "statusLine.showHookStatus":
602
+ case "statusLine.sessionAccent":
603
+ case "statusLine.transparent":
604
+ case "statusLine.compactThinkingLevel":
605
+ case "statusLineSegments":
606
+ case "statusLineModelThinking":
607
+ case "statusLinePathAbbreviate":
608
+ case "statusLinePathMaxLength":
609
+ case "statusLinePathStripWorkPrefix":
610
+ case "statusLineGitShowBranch":
611
+ case "statusLineGitShowStaged":
612
+ case "statusLineGitShowUnstaged":
613
+ case "statusLineGitShowUntracked":
614
+ case "statusLineTimeFormat":
615
+ case "statusLineTimeShowSeconds": {
616
+ const statusLineSettings = {
617
+ preset: settings.get("statusLine.preset"),
618
+ leftSegments: settings.get("statusLine.leftSegments"),
619
+ rightSegments: settings.get("statusLine.rightSegments"),
620
+ separator: settings.get("statusLine.separator"),
621
+ showHookStatus: settings.get("statusLine.showHookStatus"),
622
+ sessionAccent: settings.get("statusLine.sessionAccent"),
623
+ transparent: settings.get("statusLine.transparent"),
624
+ segmentOptions: settings.get("statusLine.segmentOptions"),
625
+ compactThinkingLevel: settings.get("statusLine.compactThinkingLevel"),
626
+ };
627
+ this.ctx.statusLine.updateSettings(statusLineSettings);
628
+ this.ctx.ui.requestRender();
629
+ break;
630
+ }
631
+
632
+ // Provider settings - update runtime preferences
633
+ case "providers.webSearchOrder":
634
+ if (Array.isArray(value)) {
635
+ setSearchProviderOrder(value.filter(isSearchProviderId));
636
+ }
637
+ break;
638
+ case "providers.webSearchExclude":
639
+ if (Array.isArray(value)) {
640
+ setExcludedSearchProviders(value.filter(isSearchProviderId));
641
+ }
642
+ break;
643
+ case "providers.imageOrder":
644
+ if (Array.isArray(value)) {
645
+ setImageProviderOrder(value.filter((entry): entry is string => typeof entry === "string"));
646
+ }
647
+ break;
648
+
649
+ // MCP update injection - live subscribe/unsubscribe
650
+ case "mcp.notifications":
651
+ this.ctx.mcpManager?.setNotificationsEnabled(value as boolean);
652
+ break;
653
+
654
+ // All other settings are handled by the definitions (get/set on SettingsManager)
655
+ // No additional side effects needed
656
+ }
657
+ }
658
+
659
+ showModelSelector(options?: { temporaryOnly?: boolean }): void {
660
+ if (options?.temporaryOnly) {
661
+ this.#showModelPicker();
662
+ return;
663
+ }
664
+ this.#showModelHub({});
665
+ }
666
+
667
+ /**
668
+ * Compact session-only model picker (alt+p / `/switch`): a floating
669
+ * bottom-anchored overlay over the transcript. The current model is
670
+ * highlighted and preselected; a leading `@` searches ctrl+p quick roles.
671
+ */
672
+ #showModelPicker(): void {
673
+ const currentContextTokens = this.ctx.session.getContextUsage()?.tokens ?? 0;
674
+ const current = this.ctx.session.model;
675
+ const quickRoleOrder = this.ctx.settings.get("cycleOrder");
676
+ const quickRoleCycle = this.ctx.session.getRoleModelCycle(quickRoleOrder);
677
+ let overlayHandle: OverlayHandle | undefined;
678
+ let closed = false;
679
+ const done = () => {
680
+ if (closed) return;
681
+ closed = true;
682
+ overlayHandle?.hide();
683
+ this.focusActiveEditorArea();
684
+ this.ctx.ui.requestRender();
685
+ };
686
+ const picker = new ModelPickerComponent(
687
+ this.ctx.ui,
688
+ this.ctx.settings,
689
+ this.ctx.session.modelRegistry,
690
+ this.ctx.session.scopedModels,
691
+ {
692
+ onPick: async (model, selector) => {
693
+ try {
694
+ // Session-only: update agent state but don't persist the model to settings.
695
+ const roleThinkingLevel = this.ctx.session.resolveTemporaryModelThinkingLevel(model);
696
+ await this.ctx.session.setModelTemporary(model, roleThinkingLevel);
697
+ this.ctx.statusLine.invalidate();
698
+ this.ctx.updateEditorBorderColor();
699
+ const roleSelectorHint = this.ctx.keybindings.getKeys("app.model.select")[0] ?? "Alt+M";
700
+ this.ctx.showStatus(`Session-only model: ${selector}. Use ${roleSelectorHint} or /model for roles.`);
701
+ done();
702
+ } catch (error) {
703
+ this.ctx.showError(error instanceof Error ? error.message : String(error));
704
+ }
705
+ },
706
+ onPickRole: async entry => {
707
+ try {
708
+ await this.ctx.session.applyRoleModel(entry);
709
+ this.ctx.statusLine.invalidate();
710
+ this.ctx.updateEditorBorderColor();
711
+ this.ctx.showModelCycleTrack(
712
+ renderSegmentTrack(
713
+ quickRoleOrder.map(role => ({ label: role })),
714
+ quickRoleOrder.indexOf(entry.role),
715
+ ),
716
+ );
717
+ done();
718
+ } catch (error) {
719
+ this.ctx.showError(error instanceof Error ? error.message : String(error));
720
+ }
721
+ },
722
+ onCancel: done,
723
+ },
724
+ {
725
+ currentContextTokens,
726
+ currentSelector: current ? `${current.provider}/${current.id}` : undefined,
727
+ quickRoles: quickRoleCycle?.models,
728
+ quickRoleOrder,
729
+ currentQuickRole: quickRoleCycle?.models[quickRoleCycle.currentIndex]?.role,
730
+ },
731
+ );
732
+ overlayHandle = this.ctx.ui.showOverlay(picker, {
733
+ anchor: "bottom-center",
734
+ width: "100%",
735
+ maxHeight: "100%",
736
+ margin: 0,
737
+ });
738
+ this.ctx.ui.setFocus(picker);
739
+ this.ctx.ui.requestRender();
740
+ }
741
+
742
+ /**
743
+ * Fullscreen model hub on the alternate screen (the /settings idiom): the
744
+ * overlay enables mouse tracking for its lifetime and the transcript stays
745
+ * untouched underneath. `initialProviderId` preselects a provider's sidebar
746
+ * entry — used when reopening the hub after a /login round-trip.
747
+ */
748
+ #showModelHub(hubOptions: { initialProviderId?: string }): void {
749
+ const currentContextTokens = this.ctx.session.getContextUsage()?.tokens ?? 0;
750
+ let overlayHandle: OverlayHandle | undefined;
751
+ let hub: ModelHubComponent | undefined;
752
+ let closed = false;
753
+ const done = () => {
754
+ // Re-entrant guard: cancel paths (Esc, login forward) may race;
755
+ // the overlay must hide exactly once.
756
+ if (closed) return;
757
+ closed = true;
758
+ hub?.dispose();
759
+ overlayHandle?.hide();
760
+ this.focusActiveEditorArea();
761
+ this.ctx.ui.requestRender();
762
+ };
763
+ hub = new ModelHubComponent(
764
+ this.ctx.ui,
765
+ this.ctx.settings,
766
+ this.ctx.session.modelRegistry,
767
+ this.ctx.session.scopedModels,
768
+ {
769
+ onAssign: async (model, role, thinkingLevel, selector, scope?: ModelRoleSelectionScope) => {
770
+ const releaseDefaultMutation = role === "default" ? await this.#acquireDefaultRoleMutation() : undefined;
771
+ const configuredStorage = this.ctx.settings.get("modelRoleStorage");
772
+ const targetScope = configuredStorage === "project" ? (scope ?? "project") : "global";
773
+ // `auto` is session-global: never baked into a per-role model value
774
+ // (it can't round-trip through `model:<level>`). Apply it to the session
775
+ // separately and persist via `defaultThinkingLevel`.
776
+ const isAuto = thinkingLevel === AUTO_THINKING;
777
+ const concreteThinking = isAuto || thinkingLevel === undefined ? undefined : thinkingLevel;
778
+ const selectorValue = selector ?? `${model.provider}/${model.id}`;
779
+ const scopeLabel =
780
+ configuredStorage === "project" ? `${targetScope === "project" ? "Project" : "Global"} ` : "";
781
+ const defaultStatusLabel = configuredStorage === "project" ? `${scopeLabel}default` : "Default";
782
+ try {
783
+ if (role === "default") {
784
+ const effectiveProvenance = this.ctx.settings.getModelRoleProvenance("default");
785
+ const shadowedGlobal =
786
+ configuredStorage === "project" &&
787
+ targetScope === "global" &&
788
+ (effectiveProvenance === "project" ||
789
+ effectiveProvenance === "overlay" ||
790
+ (effectiveProvenance === "runtime" &&
791
+ this.ctx.settings.isProjectModelRoleRuntimeOverrideActive("default")));
792
+ const shadowedProject =
793
+ configuredStorage === "project" &&
794
+ targetScope === "project" &&
795
+ effectiveProvenance === "overlay";
796
+ if (shadowedGlobal) {
797
+ this.ctx.settings.setModelRole(
798
+ "default",
799
+ formatModelSelectorValue(selectorValue, concreteThinking),
800
+ );
801
+ if (isAuto) {
802
+ this.ctx.settings.set("defaultThinkingLevel", AUTO_THINKING);
803
+ }
804
+ } else if (shadowedProject) {
805
+ this.ctx.settings.setProjectModelRole(
806
+ "default",
807
+ formatModelSelectorValue(selectorValue, concreteThinking),
808
+ );
809
+ if (isAuto) {
810
+ this.ctx.settings.set("defaultThinkingLevel", AUTO_THINKING);
811
+ }
812
+ } else {
813
+ const { switched } = await this.ctx.session.setModel(model, role, {
814
+ selector,
815
+ thinkingLevel: isAuto ? ThinkingLevel.Inherit : concreteThinking,
816
+ persist: targetScope === "global",
817
+ currentContextTokens,
818
+ });
819
+ if (!switched) return;
820
+ if (targetScope === "project") {
821
+ this.ctx.settings.setProjectModelRole(
822
+ "default",
823
+ formatModelSelectorValue(selectorValue, concreteThinking),
824
+ );
825
+ }
826
+ if (isAuto) {
827
+ this.ctx.session.setThinkingLevel(AUTO_THINKING, true);
828
+ } else if (concreteThinking && concreteThinking !== ThinkingLevel.Inherit) {
829
+ this.ctx.session.setThinkingLevel(concreteThinking);
830
+ }
831
+ this.ctx.statusLine.invalidate();
832
+ this.ctx.updateEditorBorderColor();
833
+ }
834
+ this.ctx.showStatus(`${defaultStatusLabel} model: ${selector ?? model.id}`);
835
+ } else {
836
+ // Other roles (smol, slow, custom): update settings, not the current model.
837
+ const modelRoleValue = formatModelSelectorValue(selectorValue, concreteThinking);
838
+ if (targetScope === "project") {
839
+ this.ctx.settings.setProjectModelRole(role, modelRoleValue);
840
+ } else {
841
+ this.ctx.settings.setModelRole(role, modelRoleValue);
842
+ }
843
+ if (isAuto) {
844
+ this.ctx.session.setThinkingLevel(AUTO_THINKING, true);
845
+ }
846
+ const roleInfo = getRoleInfo(role, settings);
847
+ this.ctx.showStatus(
848
+ `${scopeLabel}${roleInfo?.tag ?? roleInfo?.name ?? role} model: ${selector ?? model.id}`,
849
+ );
850
+ }
851
+ } catch (error) {
852
+ this.ctx.showError(error instanceof Error ? error.message : String(error));
853
+ } finally {
854
+ releaseDefaultMutation?.();
855
+ hub?.refreshAfterExternalMutation();
856
+ }
857
+ },
858
+ onUnassign: async (role, scope?: ModelRoleSelectionScope) => {
859
+ const releaseDefaultMutation = role === "default" ? await this.#acquireDefaultRoleMutation() : undefined;
860
+ const configuredStorage = this.ctx.settings.get("modelRoleStorage");
861
+ const targetScope = configuredStorage === "project" ? (scope ?? "project") : "global";
862
+ const scopeLabel =
863
+ configuredStorage === "project" ? `${targetScope === "project" ? "Project" : "Global"} ` : "";
864
+ try {
865
+ const previousEffectiveRoleValue =
866
+ role === "default" ? this.ctx.settings.getModelRole("default") : undefined;
867
+ if (targetScope === "project") {
868
+ this.ctx.settings.clearProjectModelRole(role);
869
+ } else {
870
+ this.ctx.settings.setModelRole(role, undefined);
871
+ }
872
+ const roleInfo = getRoleInfo(role, settings);
873
+ this.ctx.showStatus(
874
+ `${scopeLabel}${roleInfo?.tag ?? roleInfo?.name ?? role} role cleared — auto-selection applies`,
875
+ );
876
+ // Clearing either persisted scope can also remove a captured
877
+ // runtime override. When that changes the effective default,
878
+ // resolve the newly exposed persisted layer and switch the live
879
+ // session without writing it back to global settings. Overlay
880
+ // and runtime provenance remain authoritative and session-neutral.
881
+ if (role === "default") {
882
+ const fallbackRoleValue = this.ctx.settings.getModelRole("default");
883
+ const fallbackProvenance = this.ctx.settings.getModelRoleProvenance("default");
884
+ const exposesPersistedFallback =
885
+ fallbackProvenance === "project" || fallbackProvenance === "global";
886
+ if (
887
+ fallbackRoleValue &&
888
+ fallbackRoleValue !== previousEffectiveRoleValue &&
889
+ exposesPersistedFallback
890
+ ) {
891
+ const scopedModels = this.ctx.session.scopedModels.map(sm => sm.model);
892
+ const availableModels =
893
+ scopedModels.length > 0 ? scopedModels : this.ctx.session.getAvailableModels();
894
+ const resolved = resolveModelRoleValue(fallbackRoleValue, availableModels, {
895
+ settings: this.ctx.settings,
896
+ });
897
+ if (resolved.model) {
898
+ const fallbackModel = resolved.model;
899
+ const isAuto = resolved.thinkingLevel === AUTO_THINKING;
900
+ let concreteThinking = concreteThinkingLevel(resolved.thinkingLevel);
901
+ let isAutoFromDefault = false;
902
+ if (!resolved.explicitThinkingLevel && !concreteThinking) {
903
+ const defaultLevel = parseConfiguredThinkingLevel(
904
+ this.ctx.settings.get("defaultThinkingLevel"),
905
+ );
906
+ if (defaultLevel === AUTO_THINKING) {
907
+ isAutoFromDefault = true;
908
+ } else if (defaultLevel) {
909
+ concreteThinking = defaultLevel;
910
+ }
911
+ }
912
+ const effectiveIsAuto = isAuto || isAutoFromDefault;
913
+ const { switched } = await this.ctx.session.setModel(fallbackModel, "default", {
914
+ persist: false,
915
+ thinkingLevel: effectiveIsAuto
916
+ ? ThinkingLevel.Inherit
917
+ : (concreteThinking ?? ThinkingLevel.Inherit),
918
+ currentContextTokens,
919
+ });
920
+ if (!switched) return;
921
+ if (effectiveIsAuto) {
922
+ this.ctx.session.setThinkingLevel(AUTO_THINKING, true);
923
+ } else if (concreteThinking && concreteThinking !== ThinkingLevel.Inherit) {
924
+ this.ctx.session.setThinkingLevel(concreteThinking);
925
+ }
926
+ this.ctx.statusLine.invalidate();
927
+ this.ctx.updateEditorBorderColor();
928
+ }
929
+ }
930
+ }
931
+ } catch (error) {
932
+ this.ctx.showError(error instanceof Error ? error.message : String(error));
933
+ } finally {
934
+ releaseDefaultMutation?.();
935
+ hub?.refreshAfterExternalMutation();
936
+ }
937
+ },
938
+ onFallbackChainChange: (role, chain) => {
939
+ try {
940
+ const chains = { ...this.ctx.settings.get("retry.fallbackChains") };
941
+ if (chain.length === 0) {
942
+ delete chains[role];
943
+ } else {
944
+ chains[role] = chain;
945
+ }
946
+ this.ctx.settings.set("retry.fallbackChains", chains);
947
+ const roleInfo = getRoleInfo(role, settings);
948
+ this.ctx.showStatus(
949
+ chain.length > 0
950
+ ? `${roleInfo?.tag ?? roleInfo?.name ?? role} fallbacks: ${chain.join(" → ")}`
951
+ : `${roleInfo?.tag ?? roleInfo?.name ?? role} fallbacks cleared`,
952
+ );
953
+ } catch (error) {
954
+ this.ctx.showError(error instanceof Error ? error.message : String(error));
955
+ }
956
+ },
957
+
958
+ onLoginRequest: providerId => {
959
+ done();
960
+ void this.#loginThenReopenModelHub(providerId);
961
+ },
962
+ onCycleOrderChange: order => {
963
+ try {
964
+ this.ctx.settings.set("cycleOrder", order);
965
+ this.ctx.showStatus(
966
+ order.length > 0 ? `Quick-switch cycle: ${order.join(" → ")}` : "Quick-switch cycle cleared",
967
+ );
968
+ } catch (error) {
969
+ this.ctx.showError(error instanceof Error ? error.message : String(error));
970
+ }
971
+ },
972
+ onCancel: () => done(),
973
+ },
974
+ {
975
+ initialProviderId: hubOptions.initialProviderId,
976
+ },
977
+ );
978
+ overlayHandle = this.ctx.ui.showOverlay(hub, {
979
+ anchor: "bottom-center",
980
+ width: "100%",
981
+ maxHeight: "100%",
982
+ margin: 0,
983
+ fullscreen: true,
984
+ });
985
+ this.ctx.ui.setFocus(hub);
986
+ this.ctx.ui.requestRender();
987
+ }
988
+
989
+ /** /login round-trip for a locked provider; reopen the hub on that provider only after a successful login. */
990
+ async #loginThenReopenModelHub(providerId: string): Promise<void> {
991
+ const succeeded = await this.#handleOAuthLogin(providerId);
992
+ if (succeeded) {
993
+ this.#showModelHub({ initialProviderId: providerId });
994
+ }
995
+ }
996
+
997
+ async showPluginSelector(mode: "install" | "uninstall" = "install"): Promise<void> {
998
+ const mgr = new MarketplaceManager({
999
+ marketplacesRegistryPath: getMarketplacesRegistryPath(),
1000
+ installedRegistryPath: getInstalledPluginsRegistryPath(),
1001
+ projectInstalledRegistryPath: (await resolveActiveProjectRegistryPath(getProjectDir())) ?? undefined,
1002
+ marketplacesCacheDir: getMarketplacesCacheDir(),
1003
+ pluginsCacheDir: getPluginsCacheDir(),
1004
+ clearPluginRootsCache: clearPluginRootsAndCaches,
1005
+ });
1006
+
1007
+ const [marketplaces, installed] = await Promise.all([mgr.listMarketplaces(), mgr.listInstalledPlugins()]);
1008
+ const installedIds = new Set(installed.map(p => p.id));
1009
+
1010
+ if (mode === "uninstall") {
1011
+ // Show only installed plugins for uninstall
1012
+ const items = installed.map(p => {
1013
+ const entry = p.entries[0];
1014
+ const atIdx = p.id.lastIndexOf("@");
1015
+ const pluginName = atIdx > 0 ? p.id.slice(0, atIdx) : p.id;
1016
+ const mkt = atIdx > 0 ? p.id.slice(atIdx + 1) : "unknown";
1017
+ return {
1018
+ plugin: { name: pluginName, version: entry?.version, description: undefined as string | undefined },
1019
+ marketplace: mkt,
1020
+ scope: p.scope,
1021
+ };
1022
+ });
1023
+ this.showSelector(done => {
1024
+ const selector = new PluginSelectorComponent(marketplaces.length, items, new Set(), {
1025
+ onSelect: async (name, marketplace, scope) => {
1026
+ done();
1027
+ const pluginId = `${name}@${marketplace}`;
1028
+ this.ctx.showStatus(`Uninstalling ${pluginId}...`);
1029
+ this.ctx.ui.requestRender();
1030
+ try {
1031
+ await mgr.uninstallPlugin(pluginId, scope);
1032
+ this.ctx.showStatus(`Uninstalled ${pluginId}`);
1033
+ } catch (err) {
1034
+ this.ctx.showStatus(`Uninstall failed: ${err}`);
1035
+ }
1036
+ this.ctx.ui.requestRender();
1037
+ },
1038
+ onCancel: () => {
1039
+ done();
1040
+ this.ctx.ui.requestRender();
1041
+ },
1042
+ });
1043
+ return { component: selector, focus: selector.getSelectList() };
1044
+ });
1045
+ return;
1046
+ }
1047
+
1048
+ // Install mode: show all available plugins from all marketplaces
1049
+ const allPlugins: Array<{
1050
+ plugin: { name: string; version?: string; description?: string };
1051
+ marketplace: string;
1052
+ }> = [];
1053
+ for (const mkt of marketplaces) {
1054
+ const plugins = await mgr.listAvailablePlugins(mkt.name);
1055
+ for (const plugin of plugins) {
1056
+ allPlugins.push({ plugin, marketplace: mkt.name });
1057
+ }
1058
+ }
1059
+
1060
+ this.showSelector(done => {
1061
+ const selector = new PluginSelectorComponent(marketplaces.length, allPlugins, installedIds, {
1062
+ onSelect: async (name, marketplace) => {
1063
+ done();
1064
+ this.ctx.showStatus(`Installing ${name} from ${marketplace}...`);
1065
+ this.ctx.ui.requestRender();
1066
+ try {
1067
+ const force = installedIds.has(`${name}@${marketplace}`);
1068
+ await mgr.installPlugin(name, marketplace, { force });
1069
+ this.ctx.showStatus(`Installed ${name} from ${marketplace}`);
1070
+ } catch (err) {
1071
+ this.ctx.showStatus(`Install failed: ${err}`);
1072
+ }
1073
+ this.ctx.ui.requestRender();
1074
+ },
1075
+ onCancel: () => {
1076
+ done();
1077
+ this.ctx.ui.requestRender();
1078
+ },
1079
+ });
1080
+ return { component: selector, focus: selector.getSelectList() };
1081
+ });
1082
+ }
1083
+
1084
+ showUserMessageSelector(): void {
1085
+ const userMessages = this.ctx.session.getUserMessagesForBranching();
1086
+
1087
+ if (userMessages.length === 0) {
1088
+ this.ctx.showStatus("No messages to branch from");
1089
+ return;
1090
+ }
1091
+
1092
+ this.showSelector(done => {
1093
+ const selector = new UserMessageSelectorComponent(
1094
+ userMessages.map(m => ({ id: m.entryId, text: m.text })),
1095
+ async entryId => {
1096
+ const result = await this.ctx.session.branch(entryId);
1097
+ if (result.cancelled) {
1098
+ // Hook cancelled the branch
1099
+ done();
1100
+ this.ctx.ui.requestRender();
1101
+ return;
1102
+ }
1103
+
1104
+ this.ctx.renderInitialMessages({ clearTerminalHistory: true });
1105
+ this.ctx.editor.setDraft(result.selectedText, result.selectedImages);
1106
+ done();
1107
+ this.ctx.showStatus("Branched to new session");
1108
+ },
1109
+ () => {
1110
+ done();
1111
+ this.ctx.ui.requestRender();
1112
+ },
1113
+ );
1114
+ return { component: selector, focus: selector.getMessageList() };
1115
+ });
1116
+ }
1117
+
1118
+ showCopySelector(): void {
1119
+ const targets = buildCopyTargets(this.ctx.session);
1120
+ if (targets.length === 0) {
1121
+ this.ctx.showStatus("Nothing to copy yet.");
1122
+ return;
1123
+ }
1124
+
1125
+ let overlayHandle: OverlayHandle | undefined;
1126
+ const done = () => {
1127
+ overlayHandle?.hide();
1128
+ this.ctx.ui.requestRender();
1129
+ };
1130
+ const selector = new CopySelectorComponent(targets, {
1131
+ onPick: target => {
1132
+ done();
1133
+ if (target.content === undefined) return;
1134
+ void copyToClipboard(target.content);
1135
+ this.ctx.showStatus(target.copyMessage ?? "Copied to clipboard");
1136
+ },
1137
+ onCancel: done,
1138
+ });
1139
+
1140
+ overlayHandle = this.ctx.ui.showOverlay(selector, {
1141
+ anchor: "bottom-center",
1142
+ width: "100%",
1143
+ maxHeight: "100%",
1144
+ margin: 0,
1145
+ });
1146
+ this.ctx.ui.setFocus(selector);
1147
+ this.ctx.ui.requestRender();
1148
+ }
1149
+
1150
+ showTreeSelector(): void {
1151
+ const tree = this.ctx.sessionManager.getTree();
1152
+ const realLeafId = this.ctx.sessionManager.getLeafId();
1153
+
1154
+ if (tree.length === 0) {
1155
+ this.ctx.showStatus("No entries in session");
1156
+ return;
1157
+ }
1158
+
1159
+ this.showSelector(done => {
1160
+ const selector = new TreeSelectorComponent(
1161
+ tree,
1162
+ realLeafId,
1163
+ this.ctx.ui.terminal.rows,
1164
+ async (entryId, options) => {
1165
+ // Selecting the current leaf is normally a no-op (already there) —
1166
+ // unless it's an `ask` toolResult, in which case the re-answer flow
1167
+ // must still be allowed to reopen the picker even though the leaf
1168
+ // doesn't move (chatgpt-codex review on #5895).
1169
+ if (entryId === realLeafId) {
1170
+ const currentEntry = this.ctx.sessionManager.getEntry(entryId);
1171
+ const currentIsAskResult =
1172
+ currentEntry?.type === "message" &&
1173
+ currentEntry.message.role === "toolResult" &&
1174
+ currentEntry.message.toolName === "ask";
1175
+ if (!currentIsAskResult) {
1176
+ done();
1177
+ this.ctx.showStatus("Already at this point");
1178
+ return;
1179
+ }
1180
+ }
1181
+
1182
+ // Ask about summarization
1183
+ done(); // Close selector first
1184
+
1185
+ // Loop until user makes a complete choice or cancels to tree.
1186
+ // Shift+Enter in the tree selector pre-answers "Summarize" and
1187
+ // skips the prompt entirely.
1188
+ let wantsSummary = options.summarize;
1189
+ let customInstructions: string | undefined;
1190
+
1191
+ const branchSummariesEnabled = settings.get("branchSummary.enabled");
1192
+
1193
+ while (!wantsSummary && branchSummariesEnabled) {
1194
+ const summaryChoice = await this.ctx.showHookSelector("Summarize branch?", [
1195
+ "No summary",
1196
+ "Summarize",
1197
+ "Summarize with custom prompt",
1198
+ ]);
1199
+
1200
+ if (summaryChoice === undefined) {
1201
+ // User pressed escape - re-show tree selector
1202
+ this.showTreeSelector();
1203
+ return;
1204
+ }
1205
+
1206
+ wantsSummary = summaryChoice !== "No summary";
1207
+
1208
+ if (summaryChoice === "Summarize with custom prompt") {
1209
+ customInstructions = await this.ctx.showHookEditor("Custom summarization instructions");
1210
+ if (customInstructions === undefined) {
1211
+ // User cancelled - loop back to summary selector
1212
+ continue;
1213
+ }
1214
+ }
1215
+
1216
+ // User made a complete choice
1217
+ break;
1218
+ }
1219
+
1220
+ // Set up escape handler and loader if summarizing
1221
+ let summaryLoader: Loader | undefined;
1222
+ const originalOnEscape = this.ctx.editor.onEscape;
1223
+
1224
+ if (wantsSummary) {
1225
+ this.ctx.editor.onEscape = () => {
1226
+ this.ctx.session.abortBranchSummary();
1227
+ };
1228
+ this.ctx.chatContainer.addChild(new Spacer(1));
1229
+ summaryLoader = new Loader(
1230
+ this.ctx.ui,
1231
+ spinner => theme.fg("accent", spinner),
1232
+ text => theme.fg("muted", text),
1233
+ "Summarizing branch... (esc to cancel)",
1234
+ getSymbolTheme().spinnerFrames,
1235
+ );
1236
+ this.ctx.statusContainer.addChild(summaryLoader);
1237
+ this.ctx.ui.requestRender();
1238
+ }
1239
+
1240
+ try {
1241
+ let result = await this.ctx.session.navigateTree(entryId, {
1242
+ summarize: wantsSummary,
1243
+ customInstructions,
1244
+ allowAskReopen: true,
1245
+ });
1246
+
1247
+ // Selecting an `ask` toolResult doesn't land the leaf directly —
1248
+ // re-open the picker with the original questions first, then
1249
+ // complete the navigation as a new sibling branch (issue #5642).
1250
+ if (result.reopenAsk) {
1251
+ const reanswer = await this.#reanswerAsk(result.reopenAsk.questions);
1252
+ if (!reanswer) {
1253
+ this.ctx.showStatus("Re-answer cancelled");
1254
+ return;
1255
+ }
1256
+ result = await this.ctx.session.navigateTree(entryId, {
1257
+ summarize: wantsSummary,
1258
+ customInstructions,
1259
+ allowAskReopen: true,
1260
+ reanswerAskResult: reanswer,
1261
+ });
1262
+ }
1263
+
1264
+ if (result.aborted) {
1265
+ // Summarization aborted - re-show tree selector
1266
+ this.ctx.showStatus("Branch summarization cancelled");
1267
+ this.showTreeSelector();
1268
+ return;
1269
+ }
1270
+ if (result.cancelled) {
1271
+ this.ctx.showStatus("Navigation cancelled");
1272
+ return;
1273
+ }
1274
+
1275
+ // Update UI — rebuild the display transcript for the new leaf (the
1276
+ // context from navigateTree is the LLM context, not the transcript).
1277
+ this.ctx.renderInitialMessages({ clearTerminalHistory: true });
1278
+ await this.ctx.reloadTodos();
1279
+ if (result.editorText && !this.ctx.editor.getText().trim()) {
1280
+ this.ctx.editor.setDraft(result.editorText, result.editorImages);
1281
+ }
1282
+ this.ctx.showStatus("Navigated to selected point");
1283
+
1284
+ // Re-answering a past `ask` commits a new sibling answer but,
1285
+ // unlike a live `ask`, leaves the agent idle. Resume it now —
1286
+ // after the transcript rebuild above — so the model consumes the
1287
+ // new answer without the resumed turn rendering against the stale
1288
+ // pre-rebuild UI (issue #6483).
1289
+ if (result.askReanswerCommitted) {
1290
+ this.ctx.session.resumeAfterAskReanswer();
1291
+ }
1292
+ } catch (error) {
1293
+ this.ctx.showError(error instanceof Error ? error.message : String(error));
1294
+ } finally {
1295
+ if (summaryLoader) {
1296
+ summaryLoader.stop();
1297
+ this.ctx.statusContainer.disposeChildren();
1298
+ }
1299
+ this.ctx.editor.onEscape = originalOnEscape;
1300
+ }
1301
+ },
1302
+ () => {
1303
+ done();
1304
+ this.ctx.ui.requestRender();
1305
+ },
1306
+ (entryId, label) => {
1307
+ this.ctx.sessionManager.appendLabelChange(entryId, label);
1308
+ this.ctx.ui.requestRender();
1309
+ },
1310
+ settings.get("treeFilterMode"),
1311
+ );
1312
+ return { component: selector, focus: selector };
1313
+ });
1314
+ }
1315
+
1316
+ /**
1317
+ * Re-open the `ask` picker with the original `questions` (issue #5642):
1318
+ * runs a standalone `AskTool.execute()` outside a normal agent turn,
1319
+ * reusing the same picker/dialog primitives a live `ask` tool call gets.
1320
+ * Returns `undefined` when the user cancels — mirrors `navigateTree`'s
1321
+ * cancellation contract instead of throwing.
1322
+ */
1323
+ async #reanswerAsk(questions: AskToolInput["questions"]): Promise<AgentToolResult<AskToolDetails> | undefined> {
1324
+ const uiContext = this.ctx.getToolUIContext();
1325
+ if (!uiContext) {
1326
+ this.ctx.showError("Ask tool UI is not ready");
1327
+ return undefined;
1328
+ }
1329
+ const toolSession: ToolSession = {
1330
+ cwd: this.ctx.sessionManager.getCwd(),
1331
+ hasUI: true,
1332
+ settings: this.ctx.settings,
1333
+ getSessionFile: () => this.ctx.sessionManager.getSessionFile() ?? null,
1334
+ getSessionSpawns: () => null,
1335
+ getPlanModeState: () => this.ctx.session.getPlanModeState(),
1336
+ };
1337
+ const askTool = new AskTool(toolSession);
1338
+ const context = this.ctx.session.buildAskReanswerContext(uiContext);
1339
+ let result: AgentToolResult<AskToolDetails>;
1340
+ try {
1341
+ result = await askTool.execute("tree-reanswer", { questions }, undefined, undefined, context);
1342
+ } catch (error) {
1343
+ if (error instanceof ToolAbortError) return undefined;
1344
+ throw error;
1345
+ }
1346
+ // The rich ask dialog can race a collab guest choosing "Chat about this"
1347
+ // (`AskTool`'s `chatRedirect` result); that's meaningful inside a live
1348
+ // agent turn, where the model sees the redirect and starts a
1349
+ // conversation, but this standalone re-answer has no turn to hand it
1350
+ // to — completing the navigation with it would silently drop the
1351
+ // user's intent to chat (roboomp review on #5895).
1352
+ if (result.details?.chatRedirect) {
1353
+ this.ctx.showError(
1354
+ "Chat about this isn't available when re-answering from the tree — pick an option or type a custom answer instead.",
1355
+ );
1356
+ return undefined;
1357
+ }
1358
+ return result;
1359
+ }
1360
+
1361
+ async showSessionSelector(): Promise<void> {
1362
+ const sessions = await SessionManager.list(
1363
+ this.ctx.sessionManager.getCwd(),
1364
+ this.ctx.sessionManager.getSessionDir(),
1365
+ );
1366
+ // Always open in current-folder scope; the empty-state hint in SessionList
1367
+ // invites the user to Tab into all-projects rather than silently surfacing
1368
+ // every project's history when the cwd has nothing to resume. See #3099.
1369
+ const historyStorage = this.ctx.historyStorage;
1370
+ const historyMatcher = historyStorage ? (query: string) => historyStorage.matchingSessionIds(query) : undefined;
1371
+ // Keep the fullscreen picker on the alternate buffer while a selected
1372
+ // session is loaded and its transcript is rebuilt. Closing it first exposes
1373
+ // the stale normal buffer for the entire async switch on terminals without
1374
+ // effective synchronized output.
1375
+ let overlayHandle: OverlayHandle | undefined;
1376
+ const done = () => {
1377
+ overlayHandle?.hide();
1378
+ this.focusActiveEditorArea();
1379
+ this.ctx.ui.requestRender();
1380
+ };
1381
+ const selector = new SessionSelectorComponent(
1382
+ sessions,
1383
+ async (session: SessionInfo) => {
1384
+ selector.lockInput();
1385
+ let keepOpen = false;
1386
+ try {
1387
+ const success = await this.handleResumeSession(session.path);
1388
+ if (!success) {
1389
+ keepOpen = true;
1390
+ selector.unlockInput();
1391
+ this.ctx.ui.requestRender();
1392
+ }
1393
+ } finally {
1394
+ if (!keepOpen) done();
1395
+ }
1396
+ },
1397
+ () => {
1398
+ done();
1399
+ },
1400
+ () => {
1401
+ // Release the alt buffer before teardown: shutdown() awaits flush/save/
1402
+ // dispose/drain before stop() leaves the alt screen, so without this the
1403
+ // fullscreen picker would freeze on screen for that window on Ctrl+C.
1404
+ done();
1405
+ void this.ctx.shutdown();
1406
+ },
1407
+ {
1408
+ onDelete: async (session: SessionInfo) => {
1409
+ if (!(await this.#detachActiveSessionBeforeDeletion(session.path))) {
1410
+ return false;
1411
+ }
1412
+ const storage = new FileSessionStorage();
1413
+ try {
1414
+ await storage.deleteSessionWithArtifacts(session.path);
1415
+ return true;
1416
+ } catch (err) {
1417
+ throw new Error(`Failed to delete session: ${err instanceof Error ? err.message : String(err)}`, {
1418
+ cause: err,
1419
+ });
1420
+ }
1421
+ },
1422
+ historyMatcher,
1423
+ loadAllSessions: () => SessionManager.listAll(),
1424
+ getTerminalRows: () => this.ctx.ui.terminal.rows,
1425
+ fillHeight: true,
1426
+ },
1427
+ );
1428
+ selector.setOnRequestRender(() => this.ctx.ui.requestRender());
1429
+ overlayHandle = this.ctx.ui.showOverlay(selector, {
1430
+ anchor: "top-left",
1431
+ width: "100%",
1432
+ maxHeight: "100%",
1433
+ margin: 0,
1434
+ fullscreen: true,
1435
+ });
1436
+ this.ctx.ui.setFocus(selector);
1437
+ this.ctx.ui.requestRender();
1438
+ }
1439
+
1440
+ #refreshSessionTerminalTitle(): void {
1441
+ const sessionManager = this.ctx.sessionManager as {
1442
+ getSessionName?: () => string | undefined;
1443
+ getCwd: () => string;
1444
+ titleSource?: "auto" | "user" | undefined;
1445
+ };
1446
+ setSessionTerminalTitle(sessionManager.getSessionName?.(), sessionManager.getCwd());
1447
+ }
1448
+
1449
+ async #detachActiveSessionBeforeDeletion(sessionPath: string): Promise<boolean> {
1450
+ const currentSessionFile = this.ctx.sessionManager.getSessionFile();
1451
+ if (currentSessionFile !== sessionPath) {
1452
+ return true;
1453
+ }
1454
+
1455
+ const detached = await this.ctx.session.newSession();
1456
+ if (!detached) {
1457
+ return false;
1458
+ }
1459
+ this.#refreshSessionTerminalTitle();
1460
+
1461
+ this.ctx.clearTransientSessionUi();
1462
+ this.ctx.statusLine.invalidate();
1463
+ this.ctx.statusLine.resetActiveTime();
1464
+ this.ctx.ui.requestRender();
1465
+ this.ctx.updateEditorBorderColor();
1466
+ this.ctx.renderInitialMessages({ clearTerminalHistory: true });
1467
+ await this.ctx.reloadTodos();
1468
+ this.ctx.ui.requestRender(true, { clearScrollback: true });
1469
+ return true;
1470
+ }
1471
+
1472
+ async handleResumeSession(sessionPath: string, options?: { settingsFlushed?: boolean }): Promise<boolean> {
1473
+ const previousCwd = this.ctx.sessionManager.getCwd();
1474
+ // Flush pending settings writes before switching sessions so a save
1475
+ // failure leaves the session, process project dir, and Settings in the
1476
+ // source scope — the switch below mutates the SessionManager cwd.
1477
+ if (!options?.settingsFlushed) {
1478
+ try {
1479
+ await this.ctx.settings.flush();
1480
+ } catch (err) {
1481
+ this.ctx.showError(`Failed to save pending settings: ${err instanceof Error ? err.message : String(err)}`);
1482
+ return false;
1483
+ }
1484
+ }
1485
+ // Switch session via AgentSession (emits hook and tool session events). The
1486
+ // SessionManager adopts the resumed session's own cwd when it differs.
1487
+ await this.ctx.session.switchSession(sessionPath);
1488
+ this.ctx.clearTransientSessionUi();
1489
+ const newCwd = this.ctx.sessionManager.getCwd();
1490
+ const movedProject = normalizePathForComparison(newCwd) !== normalizePathForComparison(previousCwd);
1491
+ if (movedProject) {
1492
+ // Resumed a session from another project: re-point the process and every
1493
+ // cwd-derived cache at it before rendering.
1494
+ await this.ctx.applyCwdChange(newCwd);
1495
+ }
1496
+ this.#refreshSessionTerminalTitle();
1497
+ this.ctx.updateEditorBorderColor();
1498
+
1499
+ // Clear and re-render the chat
1500
+ this.ctx.renderInitialMessages({ clearTerminalHistory: true });
1501
+ await this.ctx.reloadTodos();
1502
+ this.ctx.showStatus(movedProject ? `Resumed session in ${shortenPath(newCwd)}` : "Resumed session");
1503
+ return true;
1504
+ }
1505
+
1506
+ async handleSessionDeleteCommand(): Promise<void> {
1507
+ const sessionFile = this.ctx.sessionManager.getSessionFile();
1508
+ if (!sessionFile) {
1509
+ this.ctx.showError("No session file to delete (in-memory session)");
1510
+ return;
1511
+ }
1512
+
1513
+ // Check if session file exists (may not exist for brand new sessions)
1514
+ const storage = new FileSessionStorage();
1515
+ const fileExists = await storage.exists(sessionFile);
1516
+ if (!fileExists) {
1517
+ this.ctx.showError("Session has not been saved yet");
1518
+ return;
1519
+ }
1520
+
1521
+ const confirmed = await this.ctx.showHookConfirm(
1522
+ "Delete Session",
1523
+ "This will permanently delete the current session.\nYou will be returned to the session selector.",
1524
+ );
1525
+
1526
+ if (!confirmed) {
1527
+ this.ctx.showStatus("Delete cancelled");
1528
+ return;
1529
+ }
1530
+
1531
+ if (!(await this.#detachActiveSessionBeforeDeletion(sessionFile))) {
1532
+ this.ctx.showStatus("Delete cancelled");
1533
+ return;
1534
+ }
1535
+
1536
+ // Delete the session file and artifacts directory
1537
+ await storage.deleteSessionWithArtifacts(sessionFile);
1538
+
1539
+ // Show session selector
1540
+ this.ctx.showStatus("Session deleted");
1541
+ await this.showSessionSelector();
1542
+ }
1543
+
1544
+ /**
1545
+ * Run the OAuth login flow for `providerId` inside a cancellable
1546
+ * {@link LoginDialogComponent} that replaces the editor slot. Esc aborts:
1547
+ * the dialog's abort signal reaches the provider flow, any pending prompt
1548
+ * rejects, and the editor is restored immediately. Returns true when
1549
+ * credentials were stored.
1550
+ */
1551
+ async #handleOAuthLogin(providerId: string): Promise<boolean> {
1552
+ this.ctx.showStatus(`Logging in to ${providerId}…`);
1553
+ const useManualInput = PASTE_CODE_LOGIN_PROVIDERS.has(providerId);
1554
+ let restored = false;
1555
+ const restoreEditor = () => {
1556
+ if (restored) return;
1557
+ restored = true;
1558
+ this.ctx.editorContainer.clear();
1559
+ this.ctx.editorContainer.addChild(this.ctx.editor);
1560
+ this.ctx.ui.setFocus(this.ctx.editor);
1561
+ this.ctx.ui.requestRender();
1562
+ };
1563
+ const dialog = new LoginDialogComponent(this.ctx.ui, providerId, (_success, message) => {
1564
+ // Fires on Esc: unblock the editor immediately; the aborted flow's
1565
+ // rejection settles the awaited login below.
1566
+ restoreEditor();
1567
+ if (message) this.ctx.showStatus(message);
1568
+ });
1569
+ this.ctx.editorContainer.clear();
1570
+ this.ctx.editorContainer.addChild(dialog);
1571
+ this.ctx.ui.setFocus(dialog);
1572
+ this.ctx.ui.requestRender();
1573
+ try {
1574
+ const identity = await this.ctx.session.modelRegistry.authStorage.login(providerId as OAuthProvider, {
1575
+ signal: dialog.signal,
1576
+ onAuth: (info: { url: string; launchUrl?: string; instructions?: string }) => {
1577
+ // The dialog renders the full URL (SSH-safe copy target) and
1578
+ // opens the browser best-effort.
1579
+ dialog.showAuth(info.url, info.instructions, info.launchUrl);
1580
+ },
1581
+ onPrompt: (prompt: { message: string; placeholder?: string }) =>
1582
+ dialog.showPrompt(prompt.message, prompt.placeholder),
1583
+ onProgress: (message: string) => {
1584
+ dialog.showProgress(message);
1585
+ },
1586
+ // Paste-code providers (e.g. Codex) may need the user to paste the
1587
+ // fallback redirect URL when the loopback callback can't complete
1588
+ // (headless/remote/Windows). Mount a focused input in the dialog so
1589
+ // the paste lands somewhere the OAuth flow consumes — the hidden
1590
+ // editor's `/login <url>` path is unreachable while the dialog holds
1591
+ // focus (#5339).
1592
+ onManualCodeInput: useManualInput ? () => dialog.showManualInput(MANUAL_LOGIN_PROMPT) : undefined,
1593
+ });
1594
+ // Scope the post-login refresh to the just-authenticated provider with an
1595
+ // `online` strategy: the default all-provider `online-if-uncached` reuses
1596
+ // a fresh authoritative cache row (e.g. an empty result fetched before
1597
+ // login), so newly persisted credentials would never re-run discovery and
1598
+ // models would stay unavailable in-session (#5780). Unrelated providers
1599
+ // are left untouched. `refreshProvider` swallows discovery failures, so
1600
+ // awaiting cannot reject the login.
1601
+ await this.ctx.session.modelRegistry.refreshProvider(providerId, "online");
1602
+ const block = new TranscriptBlock();
1603
+ // Name the account (and Anthropic organization) that was stored so a
1604
+ // login that lands on an unintended account/subscription is visible
1605
+ // immediately instead of silently replacing an existing registration.
1606
+ const whoBase = identity?.type === "oauth" ? (identity.email ?? identity.accountId) : undefined;
1607
+ const whoOrg = identity?.type === "oauth" ? (identity.orgName ?? identity.orgId) : undefined;
1608
+ const who = whoBase ? ` as ${whoBase}${whoOrg ? ` (${whoOrg})` : ""}` : whoOrg ? ` as ${whoOrg}` : "";
1609
+ block.addChild(
1610
+ new Text(
1611
+ theme.fg("success", `${theme.status.success} Successfully logged in to ${providerId}${who}`),
1612
+ 1,
1613
+ 0,
1614
+ ),
1615
+ );
1616
+ block.addChild(new Text(theme.fg("dim", `Credentials saved to ${getAgentDbPath()}`), 1, 0));
1617
+ this.ctx.present(block);
1618
+ return true;
1619
+ } catch (error: unknown) {
1620
+ if (dialog.signal.aborted) {
1621
+ // User-cancelled: the dialog already restored the editor and
1622
+ // surfaced "Login cancelled".
1623
+ return false;
1624
+ }
1625
+ this.ctx.showError(`Login failed: ${error instanceof Error ? error.message : String(error)}`);
1626
+ return false;
1627
+ } finally {
1628
+ restoreEditor();
1629
+ }
1630
+ }
1631
+
1632
+ async #handleCredentialLogout(providerId: string, account: LogoutAccount): Promise<void> {
1633
+ try {
1634
+ const authStorage = this.ctx.session.modelRegistry.authStorage;
1635
+ const removed = await authStorage.removeCredential(providerId, account.credentialId);
1636
+ if (!removed) {
1637
+ this.ctx.showError(`Logout skipped: ${account.label} is no longer stored for ${providerId}.`);
1638
+ return;
1639
+ }
1640
+
1641
+ // Provider-scoped online refresh so the removed credential's stale
1642
+ // endpoint/deployment models are invalidated deterministically; the
1643
+ // default all-provider `online-if-uncached` would reuse the fresh
1644
+ // authoritative cache row and keep showing models the credential
1645
+ // unlocked (#5780). Other providers are left untouched.
1646
+ await this.ctx.session.modelRegistry.refreshProvider(providerId, "online");
1647
+ const block = new TranscriptBlock();
1648
+ block.addChild(
1649
+ new Text(
1650
+ theme.fg(
1651
+ "success",
1652
+ `${theme.status.success} Successfully logged out ${account.label} from ${providerId}`,
1653
+ ),
1654
+ 1,
1655
+ 0,
1656
+ ),
1657
+ );
1658
+ block.addChild(new Text(theme.fg("dim", `Credential removed from ${getAgentDbPath()}`), 1, 0));
1659
+ const remainingSource = authStorage.describeCredentialSource(providerId, this.ctx.session.sessionId);
1660
+ if (remainingSource) {
1661
+ block.addChild(
1662
+ new Text(theme.fg("warning", `${providerId} is still authenticated via ${remainingSource}`), 1, 0),
1663
+ );
1664
+ }
1665
+ this.ctx.present(block);
1666
+ } catch (error: unknown) {
1667
+ this.ctx.showError(`Logout failed: ${error instanceof Error ? error.message : String(error)}`);
1668
+ }
1669
+ }
1670
+
1671
+ async #showOAuthLogoutAccountSelector(providerId: string): Promise<void> {
1672
+ const authStorage = this.ctx.session.modelRegistry.authStorage;
1673
+ try {
1674
+ await authStorage.reload();
1675
+ } catch (error: unknown) {
1676
+ this.ctx.showError(
1677
+ `Could not load stored credentials: ${error instanceof Error ? error.message : String(error)}`,
1678
+ );
1679
+ return;
1680
+ }
1681
+ const provider = getOAuthProviders().find(candidate => candidate.id === providerId);
1682
+ const accounts = toLogoutAccounts(providerId, authStorage.listStoredCredentials(providerId), {
1683
+ activeIdentity: authStorage.getOAuthAccountIdentity(providerId, this.ctx.session.sessionId),
1684
+ activeApiKey: authStorage.getCredentialOrigin(providerId)?.kind === "api_key",
1685
+ });
1686
+ if (accounts.length === 0) {
1687
+ const source = authStorage.describeCredentialSource(providerId, this.ctx.session.sessionId);
1688
+ const suffix = source ? ` Current auth comes from ${source}; remove that source to log out.` : "";
1689
+ this.ctx.showError(`Logout skipped: no stored credentials for ${providerId}.${suffix}`);
1690
+ return;
1691
+ }
1692
+
1693
+ this.showSelector(done => {
1694
+ const selector = new LogoutAccountSelectorComponent(
1695
+ provider?.name ?? providerId,
1696
+ accounts,
1697
+ account => {
1698
+ done();
1699
+ void this.#handleCredentialLogout(providerId, account);
1700
+ },
1701
+ () => {
1702
+ done();
1703
+ this.ctx.ui.requestRender();
1704
+ },
1705
+ );
1706
+ return { component: selector, focus: selector };
1707
+ });
1708
+ }
1709
+
1710
+ async showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void> {
1711
+ if (providerId) {
1712
+ if (mode === "login") {
1713
+ await this.#handleOAuthLogin(providerId);
1714
+ } else {
1715
+ await this.#showOAuthLogoutAccountSelector(providerId);
1716
+ }
1717
+ return;
1718
+ }
1719
+
1720
+ if (mode === "logout") {
1721
+ await this.#refreshOAuthProviderAuthState();
1722
+ const oauthProviders = getOAuthProviders();
1723
+ const loggedInProviders = oauthProviders.filter(provider =>
1724
+ this.ctx.session.modelRegistry.authStorage.has(provider.id),
1725
+ );
1726
+ if (loggedInProviders.length === 0) {
1727
+ this.ctx.showStatus("No stored provider credentials to log out. Remove env or config auth at its source.");
1728
+ return;
1729
+ }
1730
+ }
1731
+
1732
+ this.showSelector(done => {
1733
+ let selector: OAuthSelectorComponent;
1734
+ selector = new OAuthSelectorComponent(
1735
+ mode,
1736
+ this.ctx.session.modelRegistry.authStorage,
1737
+ async (selectedProviderId: string) => {
1738
+ selector.stopValidation();
1739
+ done();
1740
+ if (mode === "login") {
1741
+ await this.#handleOAuthLogin(selectedProviderId);
1742
+ } else {
1743
+ await this.#showOAuthLogoutAccountSelector(selectedProviderId);
1744
+ }
1745
+ },
1746
+ () => {
1747
+ selector.stopValidation();
1748
+ done();
1749
+ this.ctx.ui.requestRender();
1750
+ },
1751
+ {
1752
+ validateAuth: async (selectedProviderId: string) => {
1753
+ const apiKey = await this.ctx.session.modelRegistry.getApiKeyForProvider(
1754
+ selectedProviderId,
1755
+ this.ctx.session.sessionId,
1756
+ );
1757
+ return !!apiKey;
1758
+ },
1759
+ requestRender: () => {
1760
+ this.ctx.ui.requestRender();
1761
+ },
1762
+ },
1763
+ );
1764
+ return { component: selector, focus: selector };
1765
+ });
1766
+ }
1767
+
1768
+ async showSessionPinSelector(): Promise<void> {
1769
+ const session = this.ctx.session;
1770
+ if (session.isStreaming) {
1771
+ this.ctx.showStatus("Cannot pin an account while the session is streaming.");
1772
+ return;
1773
+ }
1774
+ this.ctx.showStatus("Loading provider accounts…", { dim: true });
1775
+ let accountList: SessionOAuthAccountList | undefined;
1776
+ try {
1777
+ accountList = await session.listCurrentProviderOAuthAccounts();
1778
+ } catch (error) {
1779
+ this.ctx.showError(
1780
+ `Could not load provider accounts: ${error instanceof Error ? error.message : String(error)}`,
1781
+ );
1782
+ return;
1783
+ }
1784
+ if (!accountList) {
1785
+ this.ctx.showStatus("Select a model before pinning a provider account.");
1786
+ return;
1787
+ }
1788
+ const provider = getOAuthProviders().find(candidate => candidate.id === accountList.provider);
1789
+ const providerName = provider?.name ?? accountList.provider;
1790
+ const accounts = toSessionPinAccounts(accountList.accounts);
1791
+ if (accounts.length === 0) {
1792
+ const source = session.modelRegistry.authStorage.describeCredentialSource(
1793
+ accountList.provider,
1794
+ session.sessionId,
1795
+ );
1796
+ this.ctx.showStatus(
1797
+ source
1798
+ ? `No stored OAuth accounts for ${providerName}. Current auth comes from ${source}.`
1799
+ : `No stored OAuth accounts for ${providerName}. Use /login to add one.`,
1800
+ );
1801
+ return;
1802
+ }
1803
+
1804
+ this.showSelector(done => {
1805
+ const selector = new SessionAccountSelectorComponent(
1806
+ providerName,
1807
+ accounts,
1808
+ account => {
1809
+ done();
1810
+ if (!session.pinCurrentProviderOAuthAccount(account.credentialId)) {
1811
+ this.ctx.showWarning(`${account.label} is no longer available to pin.`);
1812
+ return;
1813
+ }
1814
+ this.ctx.showStatus(`Pinned ${account.label} to this session for ${providerName}.`);
1815
+ this.ctx.statusLine.invalidate();
1816
+ this.ctx.ui.requestRender();
1817
+ },
1818
+ () => {
1819
+ done();
1820
+ this.ctx.ui.requestRender();
1821
+ },
1822
+ );
1823
+ return { component: selector, focus: selector };
1824
+ });
1825
+ }
1826
+
1827
+ async showResetUsageSelector(): Promise<void> {
1828
+ const session = this.ctx.session;
1829
+ this.ctx.showStatus("Checking saved rate-limit resets…", { dim: true });
1830
+ let statuses: ResetCreditAccountStatus[];
1831
+ try {
1832
+ statuses = await session.listResetCredits();
1833
+ } catch (error) {
1834
+ this.ctx.showError(`Could not load saved resets: ${error instanceof Error ? error.message : String(error)}`);
1835
+ return;
1836
+ }
1837
+ const accounts = toResetUsageAccounts(statuses);
1838
+ if (accounts.length === 0) {
1839
+ this.ctx.showStatus("No Codex accounts found. Use /login to add one.");
1840
+ return;
1841
+ }
1842
+ if (!accounts.some(account => account.availableCount > 0)) {
1843
+ this.ctx.showStatus(
1844
+ accounts.some(account => account.error)
1845
+ ? "No saved resets available — some accounts couldn't be reached (try /login)."
1846
+ : "No saved rate-limit resets available to spend right now.",
1847
+ );
1848
+ return;
1849
+ }
1850
+ this.showSelector(done => {
1851
+ const selector = new ResetUsageSelectorComponent(
1852
+ accounts,
1853
+ account => {
1854
+ done();
1855
+ void this.#redeemReset(account);
1856
+ },
1857
+ () => {
1858
+ done();
1859
+ this.ctx.ui.requestRender();
1860
+ },
1861
+ );
1862
+ return { component: selector, focus: selector };
1863
+ });
1864
+ }
1865
+
1866
+ async #redeemReset(account: ResetUsageAccount): Promise<void> {
1867
+ this.ctx.showStatus(`Spending 1 saved reset for ${account.label}…`, { dim: true });
1868
+ let outcome: ResetCreditRedeemOutcome;
1869
+ try {
1870
+ outcome = await this.ctx.session.redeemResetCredit(account.target);
1871
+ } catch (error) {
1872
+ this.ctx.showError(
1873
+ `Reset failed for ${account.label}: ${error instanceof Error ? error.message : String(error)}`,
1874
+ );
1875
+ return;
1876
+ }
1877
+ const message = describeRedeemOutcome(outcome, account.label);
1878
+ if (outcome.ok) {
1879
+ this.ctx.showStatus(message);
1880
+ // Refresh the status-line usage so the freshly-reset window shows.
1881
+ this.ctx.statusLine.invalidate();
1882
+ this.ctx.ui.requestRender();
1883
+ } else {
1884
+ this.ctx.showWarning(message);
1885
+ }
1886
+ }
1887
+
1888
+ async showDebugSelector(): Promise<void> {
1889
+ const { DebugSelectorComponent } = await import("../../debug");
1890
+ this.showSelector(done => {
1891
+ const selector = new DebugSelectorComponent(this.ctx, done);
1892
+ return { component: selector, focus: selector };
1893
+ });
1894
+ }
1895
+
1896
+ showAgentHub(
1897
+ observers: SessionObserverRegistry,
1898
+ options?: { requireContent?: boolean; armCloseTap?: boolean },
1899
+ ): void {
1900
+ const hubKeys = [
1901
+ ...this.ctx.keybindings.getKeys("app.agents.hub"),
1902
+ ...this.ctx.keybindings.getKeys("app.session.observe"),
1903
+ ];
1904
+ let hub: AgentHubOverlayComponent | undefined;
1905
+
1906
+ // Render the hub inline in the editor slot — the same anchored region
1907
+ // every other selector (model, session, tree, the `ask` tool) uses —
1908
+ // rather than a floating overlay. A non-fullscreen overlay composited over
1909
+ // a live transcript strands a stale copy in native scrollback every time a
1910
+ // running subagent's progress grows the frame and scrolls the window; the
1911
+ // hub is opened mid-run, so those copies stacked into a wall of duplicate
1912
+ // "Agent Hub" frames bleeding the task tree behind them. As an editor-slot
1913
+ // component it rides the normal append-only commit path: the transcript
1914
+ // commits above it exactly once and the hub repaints in place.
1915
+ const done = () => {
1916
+ hub?.dispose();
1917
+ this.ctx.editorContainer.clear();
1918
+ this.ctx.editorContainer.addChild(this.ctx.editor);
1919
+ this.ctx.ui.setFocus(this.ctx.editor);
1920
+ this.ctx.ui.requestRender();
1921
+ };
1922
+
1923
+ hub = new AgentHubOverlayComponent({
1924
+ observers,
1925
+ hubKeys,
1926
+ expandKeys: this.ctx.keybindings.getKeys("app.tools.expand"),
1927
+ onDone: done,
1928
+ requestRender: () => this.ctx.ui.requestRender(),
1929
+ registry: this.ctx.collabGuest?.agentRegistry,
1930
+ remote: this.ctx.collabGuest?.hubRemote,
1931
+ ui: this.ctx.ui,
1932
+ getTool: name => this.ctx.session.getToolByName(name),
1933
+ getMessageRenderer: type => this.ctx.session.extensionRunner?.getMessageRenderer(type),
1934
+ cwd: this.ctx.sessionManager.getCwd(),
1935
+ hideThinkingBlock: () => this.ctx.effectiveHideThinkingBlock,
1936
+ proseOnlyThinking: () => this.ctx.proseOnlyThinking,
1937
+ focusAgent: id => this.ctx.focusAgentSession(id),
1938
+ sessionFile: this.ctx.sessionManager.getSessionFile() ?? null,
1939
+ });
1940
+
1941
+ const showReadyHub = () => {
1942
+ // The double-← gesture passes requireContent so it stays inert when
1943
+ // neither live nor persisted subagents are available. Persisted rows now
1944
+ // load asynchronously, so defer the gate until that scan has refreshed the
1945
+ // hub instead of treating the initial empty table as authoritative.
1946
+ if (options?.requireContent && hub.isEmpty) {
1947
+ hub.dispose();
1948
+ return;
1949
+ }
1950
+
1951
+ this.ctx.editorContainer.clear();
1952
+ this.ctx.editorContainer.addChild(hub);
1953
+ this.ctx.ui.setFocus(hub);
1954
+ // When the hub was raised by the editor's double-← gesture, prime its own
1955
+ // close detector so the *next* single ← dismisses it — the two taps that
1956
+ // opened it were consumed by the editor's detector (issue #4780).
1957
+ if (options?.armCloseTap) hub.armCloseTap();
1958
+ this.ctx.ui.requestRender();
1959
+ };
1960
+
1961
+ if (options?.requireContent && hub.isEmpty) {
1962
+ void hub.persistedSubagentsReady.then(showReadyHub);
1963
+ return;
1964
+ }
1965
+
1966
+ showReadyHub();
1967
+ }
1968
+ }