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,1516 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
4
+ import type { AssistantMessage, UsageLimit, UsageReport } from "@oh-my-pi/pi-ai";
5
+ import { type Component, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
6
+ import { getProjectDir } from "@oh-my-pi/pi-utils";
7
+ import { settings } from "../../../config/settings";
8
+ import type { AgentSession } from "../../../session/agent-session";
9
+ import type { OAuthAccountIdentity } from "../../../session/auth-storage";
10
+ import { limitMatchesActiveAccount } from "../../../slash-commands/helpers/active-oauth-account";
11
+ import { type ActiveRepoContext, resolveActiveRepoContextSync } from "../../../utils/active-repo-context";
12
+ import * as git from "../../../utils/git";
13
+ import * as jj from "../../../utils/jj";
14
+ import { getSessionAccentAnsi, getSessionAccentHex } from "../../../utils/session-color";
15
+ import { calculateTokensPerSecond } from "../../../utils/token-rate";
16
+ import { sanitizeStatusText } from "../../shared";
17
+ import { theme } from "../../theme/theme";
18
+ import { canReuseCachedPr, createPrCacheContext, isSamePrCacheContext, type PrCacheContext } from "./git-utils";
19
+ import { getPreset } from "./presets";
20
+ import { renderSegment, type SegmentContext } from "./segments";
21
+ import { getSeparator } from "./separators";
22
+ import type {
23
+ CollabStatus,
24
+ EffectiveStatusLineSettings,
25
+ StatusLineSegmentId,
26
+ StatusLineSegmentOptions,
27
+ StatusLineSettings,
28
+ } from "./types";
29
+
30
+ const JJ_REFRESH_TTL_MS = 5000;
31
+
32
+ // ═══════════════════════════════════════════════════════════════════════════
33
+ // Context-usage memo
34
+ // ═══════════════════════════════════════════════════════════════════════════
35
+
36
+ /**
37
+ * Cheap structural fingerprint of a message's tokenizable content. O(blocks) —
38
+ * only reads string `.length` and primitives, never copies or serializes.
39
+ * Detects in-place growth of the streaming tail (and other in-place mutations)
40
+ * so the cached `getContextUsage()` result is recomputed when — and only when —
41
+ * the numbers it depends on change.
42
+ */
43
+ function messageFingerprint(msg: AgentMessage): string {
44
+ const role = (msg as { role?: string }).role ?? "";
45
+ const ts = (msg as { timestamp?: number }).timestamp ?? 0;
46
+ let textLen = 0;
47
+ let blocks = 0;
48
+ let images = 0;
49
+ if (role === "bashExecution") {
50
+ const b = msg as { command?: unknown; output?: unknown };
51
+ if (typeof b.command === "string") textLen += b.command.length;
52
+ if (typeof b.output === "string") textLen += b.output.length;
53
+ } else if (role === "user") {
54
+ const content = (msg as { content?: unknown }).content;
55
+ if (typeof content === "string") {
56
+ textLen += content.length;
57
+ } else if (Array.isArray(content)) {
58
+ blocks = content.length;
59
+ for (const block of content) {
60
+ if (block?.type === "text" && typeof block.text === "string") textLen += block.text.length;
61
+ }
62
+ }
63
+ } else if (role === "assistant") {
64
+ const assistantMsg = msg as AssistantMessage;
65
+ const usageExt = assistantMsg.usage as unknown as { promptTokensDetails?: unknown };
66
+ const usageTotal = assistantMsg.usage?.totalTokens ?? 0;
67
+ const promptBuckets = usageExt?.promptTokensDetails ? 1 : 0;
68
+ const stopReason = assistantMsg.stopReason ?? "";
69
+
70
+ let signatureLen = 0;
71
+ let redactedLen = 0;
72
+ const msgExt = assistantMsg as unknown as {
73
+ thinkingSignature?: string;
74
+ textSignature?: string;
75
+ thoughtSignature?: string;
76
+ redactedThinking?: { data?: string };
77
+ };
78
+ const thinkingSignature = msgExt.thinkingSignature;
79
+ if (typeof thinkingSignature === "string") {
80
+ signatureLen += thinkingSignature.length;
81
+ }
82
+ const textSignature = msgExt.textSignature;
83
+ if (typeof textSignature === "string") {
84
+ signatureLen += textSignature.length;
85
+ }
86
+ const thoughtSignature = msgExt.thoughtSignature;
87
+ if (typeof thoughtSignature === "string") {
88
+ signatureLen += thoughtSignature.length;
89
+ }
90
+ const redactedData = msgExt.redactedThinking?.data;
91
+ if (typeof redactedData === "string") {
92
+ redactedLen += redactedData.length;
93
+ }
94
+
95
+ const content = (msg as { content?: unknown }).content;
96
+ if (Array.isArray(content)) {
97
+ blocks = content.length;
98
+ for (const block of content) {
99
+ if (!block || typeof block !== "object") continue;
100
+ const b = block as {
101
+ type?: string;
102
+ text?: string;
103
+ thinking?: string;
104
+ thinkingSignature?: string;
105
+ signature?: string;
106
+ textSignature?: string;
107
+ thoughtSignature?: string;
108
+ data?: string;
109
+ name?: string;
110
+ arguments?: unknown;
111
+ };
112
+ if (b.type === "text" && typeof b.text === "string") textLen += b.text.length;
113
+ else if (b.type === "thinking") {
114
+ if (typeof b.thinking === "string") textLen += b.thinking.length;
115
+ if (typeof b.thinkingSignature === "string") signatureLen += b.thinkingSignature.length;
116
+ if (typeof b.signature === "string") signatureLen += b.signature.length;
117
+ if (typeof b.textSignature === "string") signatureLen += b.textSignature.length;
118
+ if (typeof b.thoughtSignature === "string") signatureLen += b.thoughtSignature.length;
119
+ } else if (b.type === "redactedThinking" && typeof b.data === "string") {
120
+ redactedLen += b.data.length;
121
+ } else if (b.type === "toolCall") {
122
+ if (typeof b.name === "string") textLen += b.name.length;
123
+ if (b.arguments !== undefined) {
124
+ try {
125
+ textLen += JSON.stringify(b.arguments, (_key, value) =>
126
+ typeof value === "bigint" ? value.toString() : value,
127
+ ).length;
128
+ } catch {
129
+ textLen += String(b.arguments).length;
130
+ }
131
+ }
132
+ }
133
+ }
134
+ }
135
+ return `${role}:${ts}:${textLen}:${blocks}:${images}:${signatureLen}:${redactedLen}:${usageTotal}:${promptBuckets}:${stopReason}`;
136
+ } else if (role === "toolResult" || role === "hookMessage") {
137
+ const content = (msg as { content?: unknown }).content;
138
+ if (typeof content === "string") {
139
+ textLen += content.length;
140
+ } else if (Array.isArray(content)) {
141
+ blocks = content.length;
142
+ for (const block of content) {
143
+ if (!block || typeof block !== "object") continue;
144
+ const b = block as { type?: string; text?: string };
145
+ if (b.type === "text" && typeof b.text === "string") textLen += b.text.length;
146
+ else if (b.type === "image") images++;
147
+ }
148
+ }
149
+ } else if (role === "branchSummary" || role === "compactionSummary") {
150
+ const s = (msg as { summary?: unknown }).summary;
151
+ if (typeof s === "string") textLen += s.length;
152
+ }
153
+ return `${role}:${ts}:${textLen}:${blocks}:${images}`;
154
+ }
155
+
156
+ interface ContextUsageMemo {
157
+ messagesRef: readonly AgentMessage[];
158
+ length: number;
159
+ lastFingerprint: string | undefined;
160
+ modelContextWindow: number;
161
+ contextUsageRevision: number;
162
+ usedTokens: number;
163
+ contextWindow: number;
164
+ systemPromptRef: readonly string[] | undefined;
165
+ toolsRef: readonly any[] | undefined;
166
+ skillsRef: readonly any[] | undefined;
167
+ }
168
+
169
+ interface ActiveRepoCache {
170
+ projectDir: string;
171
+ activeRepo: ActiveRepoContext | null;
172
+ effectiveGitCwd: string;
173
+ /** Project + worktree dir name when `projectDir` is a linked worktree, else null. */
174
+ worktree: WorktreeContext | null;
175
+ }
176
+
177
+ interface WorktreeContext {
178
+ /** Primary-checkout (project) name shown by the path segment. */
179
+ projectName: string;
180
+ /** Worktree directory name — suppressed from the path when it equals the branch. */
181
+ worktreeName: string;
182
+ }
183
+
184
+ /**
185
+ * Project + worktree-dir names when `cwd` is a linked git worktree, else null.
186
+ * The project name comes from the shared primary checkout; bare-repo worktrees
187
+ * resolve to the shared `foo.git` dir, so a trailing `.git` is stripped.
188
+ */
189
+ function resolveWorktreeContext(cwd: string): WorktreeContext | null {
190
+ const worktree = git.repo.linkedWorktreeSync(cwd);
191
+ if (!worktree) return null;
192
+ const base = path.basename(worktree.primaryRoot);
193
+ const projectName = base.endsWith(".git") ? base.slice(0, -4) : base;
194
+ if (!projectName) return null;
195
+ return { projectName, worktreeName: path.basename(worktree.root) };
196
+ }
197
+
198
+ /**
199
+ * Per-{@link AgentSession} active-processing meter for the `time_spent`
200
+ * segment. `activeMs` is the union of every completed `agent_start`→
201
+ * `agent_end` window; `activeStartedAt` is the start timestamp of the
202
+ * currently-running window, or `null` when idle.
203
+ *
204
+ * `sessionFile` snapshots the loaded session-file path at meter-creation
205
+ * time. `AgentSession.switchSession` (/resume, /move, ACP fork, RPC
206
+ * `switch_session`, extension `switchSession`) mutates the loaded file
207
+ * under the same {@link AgentSession} ref, so the WeakMap key alone
208
+ * cannot tell two conversations apart. `#meter()` compares this snapshot
209
+ * against the live `session.sessionFile`, and a real-to-real change
210
+ * starts the meter fresh instead of crediting the new conversation with
211
+ * the previous one's accumulated active time. The undefined → real
212
+ * first-save transition does not reset, since the session identity has
213
+ * not changed.
214
+ */
215
+ interface ActiveMeter {
216
+ activeMs: number;
217
+ activeStartedAt: number | null;
218
+ sessionFile: string | undefined;
219
+ }
220
+
221
+ const EMPTY_MESSAGES: readonly AgentMessage[] = [];
222
+ const STATUS_USAGE_START_DELAY_MS = 0;
223
+ const STATUS_USAGE_REFRESH_TIMEOUT_MS = 2_000;
224
+
225
+ function hasContextSegment(segments: readonly StatusLineSegmentId[]): boolean {
226
+ return segments.includes("context_pct") || segments.includes("context_total");
227
+ }
228
+ function hasGitSegment(segments: readonly StatusLineSegmentId[]): boolean {
229
+ return segments.includes("git");
230
+ }
231
+
232
+ function hasPrSegment(segments: readonly StatusLineSegmentId[]): boolean {
233
+ return segments.includes("pr");
234
+ }
235
+ function hasPathSegment(segments: readonly StatusLineSegmentId[]): boolean {
236
+ return segments.includes("path");
237
+ }
238
+
239
+ function hasGitBackedSegment(segments: readonly StatusLineSegmentId[]): boolean {
240
+ return hasGitSegment(segments) || hasPrSegment(segments);
241
+ }
242
+
243
+ // ═══════════════════════════════════════════════════════════════════════════
244
+ // StatusLineComponent
245
+ // ═══════════════════════════════════════════════════════════════════════════
246
+
247
+ export class StatusLineComponent implements Component {
248
+ #settings: StatusLineSettings = {};
249
+ #effectiveSettings: EffectiveStatusLineSettings | undefined;
250
+ #cachedBranch: string | null | undefined = undefined;
251
+ #cachedBranchRepoId: string | null | undefined = undefined;
252
+ #cachedBranchCwd: string | undefined = undefined;
253
+ #gitWatcher: fs.FSWatcher | null = null;
254
+ #onBranchChange: (() => void) | null = null;
255
+ #disposed = false;
256
+ #autoCompactEnabled: boolean = true;
257
+ #hookStatuses: Map<string, string> = new Map();
258
+ #subagentCount: number = 0;
259
+ /**
260
+ * Active-processing accounting for the `time_spent` segment, keyed per
261
+ * {@link AgentSession} so the focus-controller mid-turn attach path
262
+ * cannot leak an unmatched synthesized `agent_start` from a subagent
263
+ * into the main session's meter.
264
+ *
265
+ * Each meter is `{ activeMs, activeStartedAt }`: `activeMs` is the union
266
+ * of every completed `agent_start`→`agent_end` window since
267
+ * {@link resetActiveTime} last reset it; `activeStartedAt` is the start
268
+ * timestamp of the currently-running window (or `null` when idle).
269
+ * `getActiveMs()` returns `activeMs + (now - activeStartedAt)` for the
270
+ * currently-attached session, so the counter ticks live during a turn
271
+ * and freezes the instant the agent yields.
272
+ *
273
+ * WeakMap so meters die with their session (e.g. a parked subagent
274
+ * dropped from the registry); the main session's meter survives focus
275
+ * round-trips because the same {@link AgentSession} ref is reused.
276
+ */
277
+ #activeMeters: WeakMap<AgentSession, ActiveMeter> = new WeakMap();
278
+ #planModeStatus: { enabled: boolean; paused: boolean } | null = null;
279
+ #loopModeStatus: SegmentContext["loopMode"] = null;
280
+ #goalModeStatus: { enabled: boolean; paused: boolean } | null = null;
281
+ #vibeModeStatus: { enabled: boolean } | null = null;
282
+ /**
283
+ * Injected aggregator that returns the aggregate tok/s of this session's
284
+ * live vibe worker sessions, or null when no workers are streaming. Kept as
285
+ * a callback so the render layer doesn't import the heavy vibe/task
286
+ * dependency graph; interactive-mode wires it to VibeSessionRegistry.
287
+ */
288
+ #vibeWorkerTokenRate: (() => number | null) | null = null;
289
+ #collabStatus: CollabStatus | null = null;
290
+ #focusedAgentId: string | undefined;
291
+ #activeRepoCache: ActiveRepoCache | undefined;
292
+
293
+ // Git status caching (1s TTL)
294
+ #cachedGitStatus: { staged: number; unstaged: number; untracked: number } | null = null;
295
+ #cachedGitStatusCwd: string | undefined = undefined;
296
+ #gitStatusLastFetch = 0;
297
+ #gitStatusInFlightCwd: string | undefined = undefined;
298
+ #jjRoot: string | null | undefined = undefined;
299
+ #jjRootCwd: string | undefined = undefined;
300
+ #cachedJjBranch: string | null = null;
301
+ #jjBranchLastFetch = 0;
302
+ #jjBranchInFlight = false;
303
+ #cachedJjStatus: { staged: number; unstaged: number; untracked: number } | null = null;
304
+ #jjStatusLastFetch = 0;
305
+ #jjStatusInFlight = false;
306
+ // Bumped on every jj-cache reset — a cwd switch (#jjRootFor) or a HEAD /
307
+ // bookmark move (#invalidateGitCaches). An in-flight jj query captures this
308
+ // at launch; a mismatch on resolve means the caches were reset underneath it
309
+ // (including a reset that re-resolves to the SAME root, which a root-equality
310
+ // check cannot detect), so the result is stale and must be dropped rather
311
+ // than poison the fresh cache or advance its throttle.
312
+ #jjCacheGeneration = 0;
313
+
314
+ // PR lookup caching (invalidated on branch/repo context changes)
315
+ #cachedPr: { number: number; url: string } | null | undefined = undefined;
316
+ #cachedPrContext: PrCacheContext | undefined = undefined;
317
+ #prLookupInFlight = false;
318
+ #defaultBranch?: string;
319
+ #defaultBranchCwd: string | undefined = undefined;
320
+ #lastTokensPerSecond: number | null = null;
321
+ #lastTokensPerSecondTimestamp: number | null = null;
322
+
323
+ // Provider usage caching (5-min TTL, OAuth/sub only)
324
+ #cachedUsage: {
325
+ tier?: string;
326
+ fiveHour?: { percent: number; resetMinutes?: number };
327
+ sevenDay?: { percent: number; resetHours?: number };
328
+ } | null = null;
329
+ #cachedUsageContextKey: string | null = null;
330
+ #usageFetchedAt = 0;
331
+ #usageInFlight = false;
332
+ #usageStartTimer: Timer | null = null;
333
+ // Context-usage memo. The status line redraws on every agent event, so the
334
+ // hot path must not recompute context tokens unless an input changed.
335
+ // `getContextUsage()` anchors on the last assistant's real prompt-token
336
+ // count (matching the provider and the `/context` panel), so a stable
337
+ // message list + model window yields a stable result we can return verbatim.
338
+ #contextUsageCache: ContextUsageMemo | undefined;
339
+
340
+ constructor(private session: AgentSession) {
341
+ this.#settings = {
342
+ preset: settings.get("statusLine.preset"),
343
+ leftSegments: settings.get("statusLine.leftSegments"),
344
+ rightSegments: settings.get("statusLine.rightSegments"),
345
+ separator: settings.get("statusLine.separator"),
346
+ showHookStatus: settings.get("statusLine.showHookStatus"),
347
+ segmentOptions: settings.getGroup("statusLine").segmentOptions,
348
+ sessionAccent: settings.get("statusLine.sessionAccent"),
349
+ transparent: settings.get("statusLine.transparent"),
350
+ compactThinkingLevel: settings.get("statusLine.compactThinkingLevel"),
351
+ };
352
+ }
353
+ #gitEnabled(): boolean {
354
+ return settings.get("git.enabled");
355
+ }
356
+ #hasGitBackedSegment(): boolean {
357
+ const effectiveSettings = this.#resolveSettings();
358
+ return (
359
+ hasGitBackedSegment(effectiveSettings.leftSegments) || hasGitBackedSegment(effectiveSettings.rightSegments)
360
+ );
361
+ }
362
+
363
+ #resolveActiveRepoCache(): ActiveRepoCache {
364
+ const projectDir = getProjectDir();
365
+ if (this.#activeRepoCache?.projectDir === projectDir) {
366
+ return this.#activeRepoCache;
367
+ }
368
+
369
+ const activeRepo = resolveActiveRepoContextSync(projectDir);
370
+ const effectiveGitCwd = activeRepo?.repoRoot ?? projectDir;
371
+ // Only collapse the bare-cwd case: a single-direct-child-repo context
372
+ // (activeRepo set) renders `<parent> ↳ <child>`, which we leave intact.
373
+ const worktree = activeRepo ? null : resolveWorktreeContext(effectiveGitCwd);
374
+ this.#activeRepoCache = { projectDir, activeRepo, effectiveGitCwd, worktree };
375
+ return this.#activeRepoCache;
376
+ }
377
+
378
+ /**
379
+ * Re-point the status line at another session (focus proxy). Invalidate: model/context/usage all derive
380
+ * from it. `focusedAgentId` is the focused subagent id while the view is proxied, undefined for main.
381
+ */
382
+ setSession(session: AgentSession, focusedAgentId?: string): void {
383
+ const sessionChanged = this.session !== session;
384
+ if (!sessionChanged && this.#focusedAgentId === focusedAgentId) return;
385
+ this.session = session;
386
+ this.#focusedAgentId = focusedAgentId;
387
+ if (sessionChanged) {
388
+ this.#invalidateSessionCaches();
389
+ this.#closeStaleActiveWindow();
390
+ }
391
+ this.invalidate();
392
+ }
393
+
394
+ /**
395
+ * Drop a meter's in-flight window when the newly-attached session is no
396
+ * longer streaming. Handles the case where the focus controller
397
+ * synthesized an `agent_start` on a mid-turn attach but the matching
398
+ * real `agent_end` never reached us — the user detached before it
399
+ * fired, and re-focusing later (after the agent finished) would
400
+ * otherwise tick over the entire detached gap. Crediting that gap to
401
+ * `activeMs` would be wrong (the agent finished at some point we never
402
+ * observed), so the window is dropped rather than folded in.
403
+ */
404
+ #closeStaleActiveWindow(): void {
405
+ const meter = this.#meter();
406
+ if (meter.activeStartedAt === null) return;
407
+ if (this.session.isStreaming) return;
408
+ meter.activeStartedAt = null;
409
+ }
410
+
411
+ updateSettings(settings: StatusLineSettings): void {
412
+ this.#settings = settings;
413
+ this.#effectiveSettings = undefined;
414
+ if (this.#onBranchChange) this.#setupGitWatcher();
415
+ }
416
+
417
+ getEffectiveSettingsForTest(): EffectiveStatusLineSettings {
418
+ return this.#resolveSettings();
419
+ }
420
+
421
+ setAutoCompactEnabled(enabled: boolean): void {
422
+ this.#autoCompactEnabled = enabled;
423
+ }
424
+
425
+ setSubagentCount(count: number): void {
426
+ this.#subagentCount = count;
427
+ }
428
+
429
+ /**
430
+ * Compatibility shim for callers predating the simplified subagent badge.
431
+ * The status line now intentionally shows only the active count.
432
+ */
433
+ setSubagentHubHint(_hint: string | undefined): void {}
434
+
435
+ /** Active subagent count as currently displayed (collab state mirroring). */
436
+ get subagentCount(): number {
437
+ return this.#subagentCount;
438
+ }
439
+
440
+ /**
441
+ * Reset the currently-attached session's active-time accumulators so
442
+ * the `time_spent` segment starts from zero. Called from `/clear`,
443
+ * fresh-session, and joined-collab paths; both the completed
444
+ * accumulator and any in-flight window are dropped, so a reset
445
+ * mid-turn ignores the running window (the matching `markActivityEnd`
446
+ * will see an idle meter and no-op).
447
+ */
448
+ resetActiveTime(): void {
449
+ const meter = this.#meter();
450
+ meter.activeMs = 0;
451
+ meter.activeStartedAt = null;
452
+ }
453
+
454
+ /**
455
+ * Mark the currently-attached session as having started a unit of
456
+ * active processing. Idempotent: a second start while a window is
457
+ * already open is a no-op, so reentrant `agent_start` events (e.g.
458
+ * nested auto-compaction loops, focus-controller mid-turn attach onto
459
+ * an already-running window) do not double-count.
460
+ */
461
+ markActivityStart(): void {
462
+ const meter = this.#meter();
463
+ if (meter.activeStartedAt !== null) return;
464
+ meter.activeStartedAt = Date.now();
465
+ }
466
+
467
+ /**
468
+ * Close the currently-attached session's open active-processing
469
+ * window, folding its elapsed time into the accumulator. Idempotent
470
+ * when the meter is already idle so callers can fire it on every
471
+ * `agent_end` without guarding.
472
+ */
473
+ markActivityEnd(): void {
474
+ const meter = this.#meter();
475
+ if (meter.activeStartedAt === null) return;
476
+ meter.activeMs += Math.max(0, Date.now() - meter.activeStartedAt);
477
+ meter.activeStartedAt = null;
478
+ }
479
+
480
+ /**
481
+ * Snapshot of total active-processing time for the currently-attached
482
+ * session, including any in-flight window. Exposed for the segment
483
+ * context builder; tests assert against this too.
484
+ */
485
+ getActiveMs(): number {
486
+ const meter = this.#meter();
487
+ if (meter.activeStartedAt === null) return meter.activeMs;
488
+ return meter.activeMs + Math.max(0, Date.now() - meter.activeStartedAt);
489
+ }
490
+
491
+ /**
492
+ * Return (lazily creating) the meter for the currently-attached
493
+ * session. Detects an in-place session-file swap under the same
494
+ * {@link AgentSession} ref (`switchSession` paths: `/resume`, `/move`,
495
+ * ACP fork/load, RPC `switch_session`, extension `switchSession`):
496
+ * a real-to-real change starts the meter fresh so the new
497
+ * conversation does not inherit the previous one's accumulated active
498
+ * time. The undefined → real first-save transition only refreshes the
499
+ * snapshot — the conversation identity has not changed.
500
+ */
501
+ #meter(): ActiveMeter {
502
+ const currentFile = this.session.sessionFile;
503
+ let meter = this.#activeMeters.get(this.session);
504
+ if (meter) {
505
+ const switched =
506
+ currentFile !== undefined && meter.sessionFile !== undefined && meter.sessionFile !== currentFile;
507
+ if (switched) {
508
+ meter = undefined;
509
+ } else {
510
+ meter.sessionFile = currentFile;
511
+ }
512
+ }
513
+ if (!meter) {
514
+ meter = { activeMs: 0, activeStartedAt: null, sessionFile: currentFile };
515
+ this.#activeMeters.set(this.session, meter);
516
+ }
517
+ return meter;
518
+ }
519
+
520
+ setPlanModeStatus(status: { enabled: boolean; paused: boolean } | undefined): void {
521
+ this.#planModeStatus = status ?? null;
522
+ }
523
+
524
+ setLoopModeStatus(status: NonNullable<SegmentContext["loopMode"]> | undefined): void {
525
+ this.#loopModeStatus = status ?? null;
526
+ }
527
+
528
+ setGoalModeStatus(status: { enabled: boolean; paused: boolean } | undefined): void {
529
+ this.#goalModeStatus = status ?? null;
530
+ }
531
+
532
+ setVibeModeStatus(status: { enabled: boolean } | undefined): void {
533
+ this.#vibeModeStatus = status ?? null;
534
+ }
535
+
536
+ /**
537
+ * Inject the aggregator that returns the aggregate tok/s of this session's
538
+ * live vibe worker sessions (null when no workers are streaming). Wired by
539
+ * interactive-mode, which owns the VibeSessionRegistry coupling, so the
540
+ * render layer stays off the heavy vibe/task dependency graph. Pass
541
+ * `undefined` to clear.
542
+ */
543
+ setVibeWorkerTokenRateProvider(provider: (() => number | null) | undefined): void {
544
+ this.#vibeWorkerTokenRate = provider ?? null;
545
+ }
546
+
547
+ setCollabStatus(status: CollabStatus | null): void {
548
+ this.#collabStatus = status;
549
+ }
550
+
551
+ setHookStatus(key: string, text: string | undefined): void {
552
+ if (text === undefined) {
553
+ this.#hookStatuses.delete(key);
554
+ } else {
555
+ this.#hookStatuses.set(key, text);
556
+ }
557
+ }
558
+
559
+ watchBranch(onBranchChange: () => void): void {
560
+ this.#onBranchChange = onBranchChange;
561
+ this.#setupGitWatcher();
562
+ }
563
+
564
+ #setupGitWatcher(): void {
565
+ if (this.#gitWatcher) {
566
+ this.#gitWatcher.close();
567
+ this.#gitWatcher = null;
568
+ }
569
+
570
+ if (!this.#gitEnabled() || !this.#hasGitBackedSegment()) {
571
+ this.#invalidateGitCaches();
572
+ return;
573
+ }
574
+
575
+ const { effectiveGitCwd } = this.#resolveActiveRepoCache();
576
+ const repository = git.repo.resolveSync(effectiveGitCwd);
577
+ if (!repository) return;
578
+
579
+ const watchPath = git.repo.isReftableSync(repository)
580
+ ? path.join(repository.gitDir, "reftable")
581
+ : repository.headPath;
582
+
583
+ try {
584
+ this.#gitWatcher = fs.watch(watchPath, () => {
585
+ if (this.#disposed) return;
586
+ this.#invalidateGitCaches();
587
+ if (this.#onBranchChange) {
588
+ this.#onBranchChange();
589
+ }
590
+ });
591
+ } catch {
592
+ this.#invalidateGitCaches();
593
+ }
594
+ }
595
+
596
+ dispose(): void {
597
+ this.#disposed = true;
598
+ this.#onBranchChange = null;
599
+ this.#clearUsageStartTimer();
600
+ if (this.#gitWatcher) {
601
+ this.#gitWatcher.close();
602
+ this.#gitWatcher = null;
603
+ }
604
+ }
605
+
606
+ #clearUsageStartTimer(): void {
607
+ if (!this.#usageStartTimer) return;
608
+ clearTimeout(this.#usageStartTimer);
609
+ this.#usageStartTimer = null;
610
+ }
611
+
612
+ invalidate(): void {
613
+ this.#invalidateGitCaches();
614
+ }
615
+ #invalidateSessionCaches(): void {
616
+ this.#clearUsageStartTimer();
617
+ this.#cachedUsage = null;
618
+ this.#usageFetchedAt = 0;
619
+ this.#usageInFlight = false;
620
+ this.#contextUsageCache = undefined;
621
+ this.#lastTokensPerSecond = null;
622
+ this.#lastTokensPerSecondTimestamp = null;
623
+ }
624
+
625
+ #invalidateGitCaches(): void {
626
+ this.#cachedBranch = undefined;
627
+ this.#cachedBranchRepoId = undefined;
628
+ this.#cachedBranchCwd = undefined;
629
+ this.#cachedPrContext = undefined;
630
+ // jj label/status share the git segment's lifecycle: a HEAD move (e.g. a
631
+ // colocated `jj new`/bookmark move) must drop the throttled jj caches too,
632
+ // mirroring #jjRootFor's per-cwd reset so the next render refetches.
633
+ this.#jjRoot = undefined;
634
+ this.#jjRootCwd = undefined;
635
+ this.#cachedJjBranch = null;
636
+ this.#jjBranchLastFetch = 0;
637
+ this.#cachedJjStatus = null;
638
+ this.#jjStatusLastFetch = 0;
639
+ this.#jjCacheGeneration++;
640
+ }
641
+ #getCurrentBranch(effectiveGitCwd?: string): string | null {
642
+ if (!this.#gitEnabled()) return null;
643
+
644
+ const gitCwd = effectiveGitCwd ?? this.#resolveActiveRepoCache().effectiveGitCwd;
645
+ if (this.#cachedBranch !== undefined && this.#cachedBranchCwd === gitCwd) {
646
+ return this.#cachedBranch;
647
+ }
648
+
649
+ const head = git.head.resolveSync(gitCwd);
650
+ const gitHeadPath = head?.headPath ?? null;
651
+ this.#cachedBranchCwd = gitCwd;
652
+ this.#cachedBranchRepoId = gitHeadPath;
653
+ if (!head) {
654
+ this.#cachedBranch = null;
655
+ return null;
656
+ }
657
+
658
+ this.#cachedBranch = head.kind === "ref" ? (head.branchName ?? head.ref) : "detached";
659
+
660
+ return this.#cachedBranch ?? null;
661
+ }
662
+
663
+ #isDefaultBranch(branch: string, effectiveGitCwd: string): boolean {
664
+ if (this.#defaultBranchCwd !== effectiveGitCwd) {
665
+ this.#defaultBranch = undefined;
666
+ this.#defaultBranchCwd = effectiveGitCwd;
667
+ }
668
+
669
+ if (this.#defaultBranch === undefined) {
670
+ this.#defaultBranch = "main";
671
+ const lookupCwd = effectiveGitCwd;
672
+ (async () => {
673
+ const resolved = await git.branch.default(lookupCwd);
674
+ if (this.#disposed || this.#defaultBranchCwd !== lookupCwd) return;
675
+ if (resolved) {
676
+ this.#defaultBranch = resolved;
677
+ if (this.#onBranchChange) {
678
+ this.#onBranchChange();
679
+ }
680
+ }
681
+ })();
682
+ }
683
+ return branch === this.#defaultBranch;
684
+ }
685
+
686
+ #getGitStatus(effectiveGitCwd?: string): { staged: number; unstaged: number; untracked: number } | null {
687
+ if (!this.#gitEnabled()) return null;
688
+
689
+ const gitCwd = effectiveGitCwd ?? this.#resolveActiveRepoCache().effectiveGitCwd;
690
+ if (this.#gitStatusInFlightCwd !== undefined) {
691
+ return this.#cachedGitStatusCwd === gitCwd ? this.#cachedGitStatus : null;
692
+ }
693
+ if (this.#cachedGitStatusCwd === gitCwd && Date.now() - this.#gitStatusLastFetch < 1000) {
694
+ return this.#cachedGitStatus;
695
+ }
696
+
697
+ this.#gitStatusInFlightCwd = gitCwd;
698
+
699
+ (async () => {
700
+ let nextStatus: { staged: number; unstaged: number; untracked: number } | null = null;
701
+ try {
702
+ nextStatus = await git.status.summary(gitCwd);
703
+ } catch {
704
+ nextStatus = null;
705
+ } finally {
706
+ if (this.#gitStatusInFlightCwd === gitCwd) {
707
+ const prev = this.#cachedGitStatusCwd === gitCwd ? this.#cachedGitStatus : null;
708
+ this.#cachedGitStatus = nextStatus;
709
+ this.#cachedGitStatusCwd = gitCwd;
710
+ this.#gitStatusLastFetch = Date.now();
711
+ this.#gitStatusInFlightCwd = undefined;
712
+ if (!this.#disposed && this.#onBranchChange && JSON.stringify(prev) !== JSON.stringify(nextStatus)) {
713
+ this.#onBranchChange();
714
+ }
715
+ }
716
+ }
717
+ })();
718
+
719
+ return this.#cachedGitStatusCwd === gitCwd ? this.#cachedGitStatus : null;
720
+ }
721
+
722
+ // Resolve (and cache per cwd) the jj workspace root, resetting both jj caches
723
+ // on a cwd change so a directory switch refetches label + status.
724
+ #jjRootFor(cwd: string): string | null {
725
+ if (this.#jjRoot === undefined || this.#jjRootCwd !== cwd) {
726
+ this.#jjRootCwd = cwd;
727
+ this.#jjRoot = jj.repo.rootSync(cwd);
728
+ this.#cachedJjBranch = null;
729
+ this.#jjBranchLastFetch = 0;
730
+ this.#cachedJjStatus = null;
731
+ this.#jjStatusLastFetch = 0;
732
+ this.#jjCacheGeneration++;
733
+ }
734
+ return this.#jjRoot;
735
+ }
736
+
737
+ // jj working-copy bookmark label (nearest bookmark, change-id fallback), shown
738
+ // in the `git` segment where git HEAD is detached/absent under jj. Throttled,
739
+ // cached, and repaints on resolve.
740
+ #getJjBranch(effectiveGitCwd?: string): string | null {
741
+ const cwd = effectiveGitCwd ?? this.#resolveActiveRepoCache().effectiveGitCwd;
742
+ const root = this.#jjRootFor(cwd);
743
+ if (!root) return null;
744
+ if (this.#jjBranchInFlight || Date.now() - this.#jjBranchLastFetch < JJ_REFRESH_TTL_MS) {
745
+ return this.#cachedJjBranch;
746
+ }
747
+ this.#jjBranchInFlight = true;
748
+ const generation = this.#jjCacheGeneration;
749
+ (async () => {
750
+ let next: string | null = null;
751
+ try {
752
+ next = await jj.workingCopy.label(root);
753
+ } finally {
754
+ this.#jjBranchInFlight = false;
755
+ // Advance the throttle only if no reset raced this query; a reset
756
+ // leaves LastFetch at 0 so the current root refetches instead of
757
+ // being throttled on a superseded result.
758
+ if (this.#jjCacheGeneration === generation) this.#jjBranchLastFetch = Date.now();
759
+ }
760
+ // Drop a result whose caches were reset mid-flight — a repo switch OR a
761
+ // same-root HEAD/bookmark move — so a superseded label never lands in
762
+ // the live cache.
763
+ if (this.#jjCacheGeneration !== generation || this.#disposed) return;
764
+ const changed = next !== this.#cachedJjBranch;
765
+ this.#cachedJjBranch = next;
766
+ if (changed && this.#onBranchChange) this.#onBranchChange();
767
+ })();
768
+ return this.#cachedJjBranch;
769
+ }
770
+
771
+ // jj working-copy status counts (`@` vs its parent), used in place of git
772
+ // status in a jj repo where `git status` has no `.git` to read. Throttled,
773
+ // cached, and repaints on resolve like #getJjBranch.
774
+ #getJjStatus(effectiveGitCwd?: string): { staged: number; unstaged: number; untracked: number } | null {
775
+ const cwd = effectiveGitCwd ?? this.#resolveActiveRepoCache().effectiveGitCwd;
776
+ const root = this.#jjRootFor(cwd);
777
+ if (!root) return null;
778
+ if (this.#jjStatusInFlight || Date.now() - this.#jjStatusLastFetch < JJ_REFRESH_TTL_MS) {
779
+ return this.#cachedJjStatus;
780
+ }
781
+ this.#jjStatusInFlight = true;
782
+ const generation = this.#jjCacheGeneration;
783
+ (async () => {
784
+ let next: { staged: number; unstaged: number; untracked: number } | null = null;
785
+ try {
786
+ next = await jj.status.summary(root);
787
+ } finally {
788
+ this.#jjStatusInFlight = false;
789
+ if (this.#jjCacheGeneration === generation) this.#jjStatusLastFetch = Date.now();
790
+ }
791
+ if (this.#jjCacheGeneration !== generation || this.#disposed) return;
792
+ const prev = this.#cachedJjStatus;
793
+ this.#cachedJjStatus = next;
794
+ if (this.#onBranchChange && JSON.stringify(prev) !== JSON.stringify(next)) this.#onBranchChange();
795
+ })();
796
+ return this.#cachedJjStatus;
797
+ }
798
+
799
+ #lookupPr(effectiveGitCwd?: string): { number: number; url: string } | null {
800
+ if (!this.#gitEnabled()) return null;
801
+
802
+ const gitCwd = effectiveGitCwd ?? this.#resolveActiveRepoCache().effectiveGitCwd;
803
+ const branch = this.#getCurrentBranch(gitCwd);
804
+ const currentContext = branch ? createPrCacheContext(branch, this.#cachedBranchRepoId ?? null) : null;
805
+
806
+ if (canReuseCachedPr(this.#cachedPr, this.#cachedPrContext, currentContext)) {
807
+ return this.#cachedPr ?? null;
808
+ }
809
+
810
+ const stalePr = this.#cachedPr;
811
+
812
+ if (!branch) {
813
+ this.#cachedPr = null;
814
+ this.#cachedPrContext = undefined;
815
+ return null;
816
+ }
817
+
818
+ // Don't look up if detached, default branch, or already in flight.
819
+ if (branch === "detached" || this.#isDefaultBranch(branch, gitCwd) || this.#prLookupInFlight) {
820
+ return stalePr ?? null;
821
+ }
822
+
823
+ this.#prLookupInFlight = true;
824
+ const lookupContext = currentContext;
825
+ const lookupCwd = gitCwd;
826
+
827
+ // Fire async lookup, keep stale value visible until resolved
828
+ (async () => {
829
+ // Helper: only write cache if branch/repo context hasn't changed since launch
830
+ const setCachedPr = (value: { number: number; url: string } | null) => {
831
+ const latestBranch = this.#getCurrentBranch(lookupCwd);
832
+ const latestContext = latestBranch
833
+ ? createPrCacheContext(latestBranch, this.#cachedBranchRepoId ?? null)
834
+ : undefined;
835
+ if (lookupContext && isSamePrCacheContext(latestContext, lookupContext)) {
836
+ this.#cachedPr = value;
837
+ this.#cachedPrContext = lookupContext;
838
+ }
839
+ };
840
+ try {
841
+ // Route through the shared `gh` helper so the child inherits
842
+ // `GH_NON_INTERACTIVE_ENV` (disables terminal/keychain prompts) and
843
+ // hard-terminates on the git command deadline instead of stalling
844
+ // the status-line indefinitely (#4234). Requires `gh repo set-default`;
845
+ // non-zero exit still falls through to the null cache below.
846
+ const result = await git.github.run(
847
+ lookupCwd,
848
+ ["pr", "view", "--json", "number,url"],
849
+ AbortSignal.timeout(git.GIT_COMMAND_TIMEOUT_MS),
850
+ );
851
+ if (this.#disposed) return;
852
+ if (result.exitCode !== 0) {
853
+ setCachedPr(null);
854
+ return;
855
+ }
856
+ const pr = JSON.parse(result.stdout) as { number: number; url: string };
857
+ if (typeof pr.number === "number") {
858
+ setCachedPr({ number: pr.number, url: pr.url });
859
+ } else {
860
+ setCachedPr(null);
861
+ }
862
+ } catch {
863
+ if (this.#disposed) return;
864
+ setCachedPr(null);
865
+ } finally {
866
+ this.#prLookupInFlight = false;
867
+ if (!this.#disposed && this.#onBranchChange) {
868
+ this.#onBranchChange();
869
+ }
870
+ }
871
+ })();
872
+
873
+ return stalePr ?? null;
874
+ }
875
+
876
+ #getTokensPerSecond(): number | null {
877
+ // Aggregate tok/s across the main session AND every live vibe worker.
878
+ // In vibe mode the director is often idle while workers stream, so the
879
+ // main session's own rate alone would show a stale/zero value while
880
+ // parallel work is actively generating tokens.
881
+ const workerRate = this.#getVibeWorkerTokensPerSecond();
882
+ if (workerRate !== null) {
883
+ // At least one worker is streaming — add the director's live rate
884
+ // only when it is itself streaming (a finalized last-turn rate would
885
+ // double-count and overstate throughput).
886
+ const mainRate = this.session.isStreaming ? calculateTokensPerSecond(this.session.state.messages, true) : 0;
887
+ return (mainRate ?? 0) + workerRate;
888
+ }
889
+
890
+ // No workers streaming — fall back to the main session's own rate with
891
+ // its sticky per-assistant-message cache so the badge doesn't flicker
892
+ // off in the brief gap between stream end and the finalized message.
893
+ return this.#getMainSessionTokensPerSecond();
894
+ }
895
+
896
+ /**
897
+ * Main session's tok/s with sticky caching keyed on the last assistant
898
+ * message timestamp. Preserves the pre-aggregation behavior when no vibe
899
+ * workers are active.
900
+ */
901
+ #getMainSessionTokensPerSecond(): number | null {
902
+ let lastAssistantTimestamp: number | null = null;
903
+ for (let i = this.session.state.messages.length - 1; i >= 0; i--) {
904
+ const message = this.session.state.messages[i];
905
+ if (message?.role === "assistant") {
906
+ lastAssistantTimestamp = message.timestamp;
907
+ break;
908
+ }
909
+ }
910
+
911
+ if (lastAssistantTimestamp === null) {
912
+ this.#lastTokensPerSecond = null;
913
+ this.#lastTokensPerSecondTimestamp = null;
914
+ return null;
915
+ }
916
+
917
+ const rate = calculateTokensPerSecond(this.session.state.messages, this.session.isStreaming);
918
+ if (rate !== null) {
919
+ this.#lastTokensPerSecond = rate;
920
+ this.#lastTokensPerSecondTimestamp = lastAssistantTimestamp;
921
+ return rate;
922
+ }
923
+
924
+ if (this.#lastTokensPerSecondTimestamp === lastAssistantTimestamp) {
925
+ return this.#lastTokensPerSecond;
926
+ }
927
+
928
+ return null;
929
+ }
930
+
931
+ /**
932
+ * Aggregate tok/s across every live vibe worker session owned by this
933
+ * session. Returns null when no workers are streaming (so the main
934
+ * session's own rate shines through unchanged). The aggregation itself is
935
+ * injected via {@link setVibeWorkerTokenRateProvider} to keep this render
936
+ * layer off the heavy vibe/task dependency graph.
937
+ */
938
+ #getVibeWorkerTokensPerSecond(): number | null {
939
+ return this.#vibeWorkerTokenRate?.() ?? null;
940
+ }
941
+
942
+ #getUsageContextKey(session: AgentSession): string {
943
+ const activeProvider = session.state.model?.provider ?? session.model?.provider ?? "";
944
+ if (!activeProvider) return "";
945
+ const identity = session.modelRegistry?.authStorage?.getOAuthAccountIdentity(activeProvider, session.sessionId);
946
+ // orgId is part of the key: rotating between two same-email Anthropic
947
+ // subscriptions must invalidate the cached usage immediately instead of
948
+ // showing the previous org's quota for the rest of the cache TTL.
949
+ return [
950
+ activeProvider,
951
+ identity?.accountId ?? "",
952
+ identity?.email ?? "",
953
+ identity?.projectId ?? "",
954
+ identity?.orgId ?? "",
955
+ ].join("\0");
956
+ }
957
+
958
+ /**
959
+ * Startup redraws only arm a short-delayed task; timeout releases the render
960
+ * cadence while a late successful fetch can still refresh the cached segment.
961
+ */
962
+ refreshUsageInBackground(): void {
963
+ const now = Date.now();
964
+ const session = this.session;
965
+ const usageContextKey = this.#getUsageContextKey(session);
966
+ if (this.#cachedUsageContextKey !== usageContextKey) {
967
+ this.#cachedUsage = null;
968
+ this.#usageFetchedAt = 0;
969
+ this.#cachedUsageContextKey = usageContextKey;
970
+ }
971
+ if (this.#usageInFlight || this.#usageStartTimer) return;
972
+ if (this.#usageFetchedAt > 0 && now - this.#usageFetchedAt < 5 * 60_000) return;
973
+ const fetcher = (session as { fetchUsageReports?: (signal?: AbortSignal) => Promise<unknown> }).fetchUsageReports;
974
+ if (typeof fetcher !== "function") return;
975
+ this.#usageInFlight = true;
976
+ this.#usageStartTimer = setTimeout(() => {
977
+ this.#usageStartTimer = null;
978
+ void this.#runUsageRefresh(session, fetcher);
979
+ }, STATUS_USAGE_START_DELAY_MS);
980
+ }
981
+
982
+ async #runUsageRefresh(session: AgentSession, fetcher: (signal?: AbortSignal) => Promise<unknown>): Promise<void> {
983
+ if (this.#disposed || this.session !== session) {
984
+ this.#usageInFlight = false;
985
+ return;
986
+ }
987
+ const signal = AbortSignal.timeout(STATUS_USAGE_REFRESH_TIMEOUT_MS);
988
+ let reportsPromise: Promise<unknown> | undefined;
989
+ try {
990
+ reportsPromise = fetcher.call(session, signal);
991
+ this.#applyUsageRefreshReports(session, await this.#raceUsageRefreshWithSignal(reportsPromise, signal));
992
+ } catch {
993
+ if (this.session !== session) return;
994
+ this.#usageFetchedAt = Date.now();
995
+ if (signal.aborted && reportsPromise) {
996
+ this.#observeLateUsageRefresh(session, reportsPromise);
997
+ }
998
+ } finally {
999
+ if (this.session === session) this.#usageInFlight = false;
1000
+ }
1001
+ }
1002
+
1003
+ #applyUsageRefreshReports(session: AgentSession, reports: unknown): void {
1004
+ if (this.#disposed || this.session !== session) return;
1005
+ const activeProvider = session.state.model?.provider ?? session.model?.provider;
1006
+ const activeIdentity =
1007
+ activeProvider && session.modelRegistry?.authStorage
1008
+ ? session.modelRegistry.authStorage.getOAuthAccountIdentity(activeProvider, session.sessionId)
1009
+ : undefined;
1010
+ this.#cachedUsage = this.#normalizeUsageReports(reports, activeProvider, activeIdentity);
1011
+ this.#usageFetchedAt = Date.now();
1012
+ }
1013
+
1014
+ #observeLateUsageRefresh(session: AgentSession, reportsPromise: Promise<unknown>): void {
1015
+ void reportsPromise
1016
+ .then(reports => {
1017
+ this.#applyUsageRefreshReports(session, reports);
1018
+ })
1019
+ .catch(() => {
1020
+ if (this.#disposed || this.session !== session) return;
1021
+ this.#usageFetchedAt = Date.now();
1022
+ });
1023
+ }
1024
+
1025
+ async #raceUsageRefreshWithSignal(promise: Promise<unknown>, signal: AbortSignal): Promise<unknown> {
1026
+ if (signal.aborted) throw signal.reason;
1027
+ const aborted = Promise.withResolvers<never>();
1028
+ const onAbort = () => aborted.reject(signal.reason);
1029
+ signal.addEventListener("abort", onAbort, { once: true });
1030
+ try {
1031
+ return await Promise.race([promise, aborted.promise]);
1032
+ } finally {
1033
+ signal.removeEventListener("abort", onAbort);
1034
+ }
1035
+ }
1036
+
1037
+ #normalizeUsageReports(
1038
+ reports: unknown,
1039
+ activeProvider?: string,
1040
+ activeIdentity?: OAuthAccountIdentity,
1041
+ ): {
1042
+ tier?: string;
1043
+ fiveHour?: { percent: number; resetMinutes?: number };
1044
+ sevenDay?: { percent: number; resetHours?: number };
1045
+ } | null {
1046
+ if (!Array.isArray(reports)) return null;
1047
+ let fiveHour: { percent: number; resetMinutes?: number } | undefined;
1048
+ let sevenDay: { percent: number; resetHours?: number } | undefined;
1049
+ let fiveHourTier: string | undefined;
1050
+ let sevenDayTier: string | undefined;
1051
+ const now = Date.now();
1052
+ for (const report of reports) {
1053
+ if (!report || typeof report !== "object") continue;
1054
+ const provider = (report as { provider?: unknown }).provider;
1055
+ if (activeProvider && provider !== activeProvider) continue;
1056
+ const limits = (report as { limits?: unknown }).limits;
1057
+ if (!Array.isArray(limits)) continue;
1058
+ for (const limit of limits) {
1059
+ if (!limit || typeof limit !== "object") continue;
1060
+ if (
1061
+ activeIdentity &&
1062
+ !limitMatchesActiveAccount(report as UsageReport, limit as UsageLimit, activeIdentity)
1063
+ ) {
1064
+ continue;
1065
+ }
1066
+ const l = limit as {
1067
+ scope?: { windowId?: string; tier?: string };
1068
+ window?: { resetsAt?: number };
1069
+ amount?: { usedFraction?: number };
1070
+ };
1071
+ const fraction = l.amount?.usedFraction;
1072
+ if (typeof fraction !== "number") continue;
1073
+ const windowId = l.scope?.windowId;
1074
+ const tier = l.scope?.tier;
1075
+ const resetsAt = l.window?.resetsAt;
1076
+ // Accept tiered limits, but prefer untiered (backward compat with Anthropic).
1077
+ // An untiered limit always replaces a tiered one; among same-tieredness, first wins.
1078
+ if (windowId === "5h" && (!fiveHour || (fiveHourTier !== undefined && !tier))) {
1079
+ fiveHour = {
1080
+ percent: fraction * 100,
1081
+ resetMinutes:
1082
+ typeof resetsAt === "number" ? Math.max(0, Math.round((resetsAt - now) / 60_000)) : undefined,
1083
+ };
1084
+ fiveHourTier = tier || undefined;
1085
+ }
1086
+ if (windowId === "7d" && (!sevenDay || (sevenDayTier !== undefined && !tier))) {
1087
+ sevenDay = {
1088
+ percent: fraction * 100,
1089
+ resetHours:
1090
+ typeof resetsAt === "number" ? Math.max(0, Math.round((resetsAt - now) / 3_600_000)) : undefined,
1091
+ };
1092
+ sevenDayTier = tier || undefined;
1093
+ }
1094
+ }
1095
+ }
1096
+ if (!fiveHour && !sevenDay) return null;
1097
+ // Single compact label; prefer the five-hour tier if displayed windows ever disagree.
1098
+ const effectiveTier = fiveHourTier ?? sevenDayTier;
1099
+ return { tier: effectiveTier, fiveHour, sevenDay };
1100
+ }
1101
+
1102
+ /**
1103
+ * Used-tokens / context-window totals for the status-line context% segment,
1104
+ * memoized so the per-event redraw stays O(1) when nothing changed.
1105
+ *
1106
+ * The numerator comes from `session.getContextUsage()`, which anchors on the
1107
+ * last assistant's real prompt-token count — so the bar matches the provider
1108
+ * and the `/context` panel — and reports `null` while that count is unknown
1109
+ * (right after compaction, before the next response). Exposed (non-private)
1110
+ * for unit tests and the collab host's state broadcast.
1111
+ */
1112
+ getCachedContextBreakdown(): { usedTokens: number; contextWindow: number } {
1113
+ const messages = this.session.messages ?? EMPTY_MESSAGES;
1114
+ const modelContextWindow = this.session.model?.contextWindow ?? 0;
1115
+ const length = messages.length;
1116
+ const lastFingerprint = length > 0 ? messageFingerprint(messages[length - 1]!) : undefined;
1117
+ // Bumps when the in-flight pending snapshot is set/cleared. Without it a
1118
+ // value computed mid-turn (estimate of the active tail) would survive after
1119
+ // the turn ends/aborts, since clearing the snapshot touches no message.
1120
+ const contextUsageRevision = this.session.contextUsageRevision ?? 0;
1121
+
1122
+ const systemPrompt = this.session.systemPrompt;
1123
+ const tools = this.session.agent?.state?.tools;
1124
+ const skills = this.session.skills;
1125
+
1126
+ const cache = this.#contextUsageCache;
1127
+ if (
1128
+ cache &&
1129
+ cache.messagesRef === messages &&
1130
+ cache.length === length &&
1131
+ cache.lastFingerprint === lastFingerprint &&
1132
+ cache.modelContextWindow === modelContextWindow &&
1133
+ cache.contextUsageRevision === contextUsageRevision &&
1134
+ cache.systemPromptRef === systemPrompt &&
1135
+ cache.toolsRef === tools &&
1136
+ cache.skillsRef === skills
1137
+ ) {
1138
+ return { usedTokens: cache.usedTokens, contextWindow: cache.contextWindow };
1139
+ }
1140
+
1141
+ const usage = this.session.getContextUsage();
1142
+ const usedTokens = usage?.tokens ?? 0;
1143
+ const contextWindow = usage?.contextWindow ?? modelContextWindow;
1144
+ this.#contextUsageCache = {
1145
+ messagesRef: messages,
1146
+ length,
1147
+ lastFingerprint,
1148
+ modelContextWindow,
1149
+ contextUsageRevision,
1150
+ usedTokens,
1151
+ contextWindow,
1152
+ systemPromptRef: systemPrompt,
1153
+ toolsRef: tools,
1154
+ skillsRef: skills,
1155
+ };
1156
+ return { usedTokens, contextWindow };
1157
+ }
1158
+
1159
+ #buildSegmentContext(
1160
+ width: number,
1161
+ segmentOptions: StatusLineSettings["segmentOptions"],
1162
+ includePath: boolean,
1163
+ includeContext: boolean,
1164
+ includeGit: boolean,
1165
+ includePr: boolean,
1166
+ ): SegmentContext {
1167
+ const state = this.session.state;
1168
+
1169
+ // Trigger background fetch (5-min TTL); render uses cached value
1170
+ this.refreshUsageInBackground();
1171
+
1172
+ // Get usage statistics
1173
+ const aggregateUsageStats = this.session.sessionManager?.getUsageStatistics() ?? {
1174
+ input: 0,
1175
+ output: 0,
1176
+ cacheRead: 0,
1177
+ cacheWrite: 0,
1178
+ totalTokens: 0,
1179
+ orchestrationInput: 0,
1180
+ orchestrationOutput: 0,
1181
+ orchestrationCacheRead: 0,
1182
+ premiumRequests: 0,
1183
+ cost: 0,
1184
+ };
1185
+ const usageStats = {
1186
+ ...aggregateUsageStats,
1187
+ tokensPerSecond: this.#getTokensPerSecond(),
1188
+ };
1189
+
1190
+ let contextWindow = state.model?.contextWindow ?? this.session.model?.contextWindow ?? 0;
1191
+ let contextPercent: number | null = 0;
1192
+ let contextTokens = 0;
1193
+ if (includeContext) {
1194
+ const breakdown = this.getCachedContextBreakdown();
1195
+ contextTokens = breakdown.usedTokens;
1196
+ contextWindow = breakdown.contextWindow || contextWindow;
1197
+ contextPercent = contextWindow > 0 ? (breakdown.usedTokens / contextWindow) * 100 : null;
1198
+ }
1199
+
1200
+ // Collab guest: context comes from the host's state frames — the local
1201
+ // replica does no accounting of its own.
1202
+ const collabState = this.#collabStatus?.stateOverride;
1203
+ if (collabState?.contextUsage) {
1204
+ contextWindow = collabState.contextUsage.contextWindow || contextWindow;
1205
+ contextTokens = collabState.contextUsage.tokens ?? contextTokens;
1206
+ contextPercent = collabState.contextUsage.percent ?? contextPercent;
1207
+ }
1208
+
1209
+ const shouldResolveActiveRepo = this.#gitEnabled() && (includePath || includeGit || includePr);
1210
+ const projectDir = getProjectDir();
1211
+ const activeRepoCache = shouldResolveActiveRepo
1212
+ ? this.#resolveActiveRepoCache()
1213
+ : { projectDir, activeRepo: null, effectiveGitCwd: projectDir, worktree: null };
1214
+ let gitBranch = includeGit || includePr ? this.#getCurrentBranch(activeRepoCache.effectiveGitCwd) : null;
1215
+ // A jj repo has no git branch to read: git HEAD is detached (colocated) or
1216
+ // absent. Gate BOTH the jj branch label and the jj status counts on that
1217
+ // same condition, captured before the label overlay rewrites gitBranch, so
1218
+ // a nested ordinary git checkout under a parent jj workspace keeps its own
1219
+ // git branch AND its own git status instead of the ancestor jj status.
1220
+ const gitHeadIsJjLike = gitBranch === "detached" || gitBranch === null;
1221
+ if (includeGit && gitHeadIsJjLike) {
1222
+ gitBranch = this.#getJjBranch(activeRepoCache.effectiveGitCwd) ?? gitBranch;
1223
+ }
1224
+ const gitStatus = includeGit
1225
+ ? ((gitHeadIsJjLike ? this.#getJjStatus(activeRepoCache.effectiveGitCwd) : null) ??
1226
+ this.#getGitStatus(activeRepoCache.effectiveGitCwd))
1227
+ : null;
1228
+ const gitPr = includePr ? this.#lookupPr(activeRepoCache.effectiveGitCwd) : null;
1229
+ return {
1230
+ session: this.session,
1231
+ focusedAgentId: this.#focusedAgentId,
1232
+ activeRepo: activeRepoCache.activeRepo,
1233
+ width,
1234
+ options: segmentOptions ?? {},
1235
+ compactThinkingLevel: this.#resolveSettings().compactThinkingLevel ?? false,
1236
+ planMode: this.#planModeStatus,
1237
+ loopMode: this.#loopModeStatus,
1238
+ prewalk:
1239
+ typeof this.session.getPrewalkState === "function" && this.session.getPrewalkState()
1240
+ ? { enabled: true }
1241
+ : null,
1242
+ goalMode: this.#goalModeStatus,
1243
+ vibeMode: this.#vibeModeStatus,
1244
+ collab: this.#collabStatus,
1245
+ usageStats,
1246
+ contextPercent,
1247
+ contextTokens,
1248
+ contextWindow,
1249
+ autoCompactEnabled: this.#autoCompactEnabled,
1250
+ subagentCount: this.#subagentCount,
1251
+ activeMs: this.getActiveMs(),
1252
+ git: {
1253
+ branch: gitBranch,
1254
+ status: gitStatus,
1255
+ pr: gitPr,
1256
+ },
1257
+ worktree: activeRepoCache.worktree,
1258
+ usage: this.#cachedUsage,
1259
+ };
1260
+ }
1261
+
1262
+ #resolveSettings(): EffectiveStatusLineSettings {
1263
+ if (this.#effectiveSettings === undefined) {
1264
+ this.#effectiveSettings = this.#computeEffectiveSettings();
1265
+ }
1266
+ return this.#effectiveSettings;
1267
+ }
1268
+
1269
+ #computeEffectiveSettings(): EffectiveStatusLineSettings {
1270
+ const preset = this.#settings.preset ?? "default";
1271
+ const presetDef = getPreset(preset);
1272
+ const useCustomSegments = preset === "custom";
1273
+ const mergedSegmentOptions: StatusLineSettings["segmentOptions"] = {};
1274
+
1275
+ for (const [segment, options] of Object.entries(presetDef.segmentOptions ?? {})) {
1276
+ mergedSegmentOptions[segment as keyof StatusLineSegmentOptions] = { ...(options as Record<string, unknown>) };
1277
+ }
1278
+
1279
+ for (const [segment, options] of Object.entries(this.#settings.segmentOptions ?? {})) {
1280
+ const current = mergedSegmentOptions[segment as keyof StatusLineSegmentOptions] ?? {};
1281
+ mergedSegmentOptions[segment as keyof StatusLineSegmentOptions] = {
1282
+ ...(current as Record<string, unknown>),
1283
+ ...(options as Record<string, unknown>),
1284
+ };
1285
+ }
1286
+
1287
+ const leftSegments = useCustomSegments
1288
+ ? (this.#settings.leftSegments ?? presetDef.leftSegments)
1289
+ : presetDef.leftSegments;
1290
+ const rightSegments = useCustomSegments
1291
+ ? (this.#settings.rightSegments ?? presetDef.rightSegments)
1292
+ : presetDef.rightSegments;
1293
+
1294
+ return {
1295
+ ...this.#settings,
1296
+ leftSegments,
1297
+ rightSegments,
1298
+ separator: this.#settings.separator ?? presetDef.separator,
1299
+ segmentOptions: mergedSegmentOptions,
1300
+ };
1301
+ }
1302
+
1303
+ #subagentBadgeText(): string | undefined {
1304
+ if (this.#subagentCount === 0) return undefined;
1305
+ const noun = this.#subagentCount === 1 ? "agent" : "agents";
1306
+ return theme.fg("statusLineSubagents", `${theme.icon.agents} ${this.#subagentCount} ${noun}`);
1307
+ }
1308
+
1309
+ #buildStatusLine(width: number): string {
1310
+ const effectiveSettings = this.#resolveSettings();
1311
+ const includePath =
1312
+ hasPathSegment(effectiveSettings.leftSegments) || hasPathSegment(effectiveSettings.rightSegments);
1313
+ const includeContext =
1314
+ hasContextSegment(effectiveSettings.leftSegments) || hasContextSegment(effectiveSettings.rightSegments);
1315
+ const gitEnabled = this.#gitEnabled();
1316
+ const includeGit =
1317
+ gitEnabled &&
1318
+ (hasGitSegment(effectiveSettings.leftSegments) || hasGitSegment(effectiveSettings.rightSegments));
1319
+ const includePr =
1320
+ gitEnabled && (hasPrSegment(effectiveSettings.leftSegments) || hasPrSegment(effectiveSettings.rightSegments));
1321
+ const ctx = this.#buildSegmentContext(
1322
+ width,
1323
+ effectiveSettings.segmentOptions,
1324
+ includePath,
1325
+ includeContext,
1326
+ includeGit,
1327
+ includePr,
1328
+ );
1329
+ const separatorDef = getSeparator(effectiveSettings.separator ?? "powerline-thin", theme);
1330
+
1331
+ // `transparent` reuses the empty-string sentinel (`\x1b[49m`) so the bar
1332
+ // inherits the terminal's default background, matching custom themes that
1333
+ // set `statusLineBg: ""`. Powerline end caps need a contrasting fill to
1334
+ // bridge the bar into the surrounding terminal; without one they read as
1335
+ // stray glyphs, so the cap renderer drops them when the fill is empty.
1336
+ const TRANSPARENT_BG_ANSI = "\x1b[49m";
1337
+ const themeBgAnsi = theme.getBgAnsi("statusLineBg");
1338
+ const bgAnsi = effectiveSettings.transparent ? TRANSPARENT_BG_ANSI : themeBgAnsi;
1339
+ const transparentBg = bgAnsi === TRANSPARENT_BG_ANSI;
1340
+ const fgAnsi = theme.getFgAnsi("text");
1341
+ const sepAnsi = theme.getFgAnsi("statusLineSep");
1342
+ const subagentBadge = this.#subagentBadgeText();
1343
+
1344
+ // Collect visible segment contents
1345
+ const leftParts: string[] = [];
1346
+ const leftSegIds: StatusLineSegmentId[] = [];
1347
+ for (const segId of effectiveSettings.leftSegments) {
1348
+ if (subagentBadge && segId === "subagents") continue;
1349
+ const rendered = renderSegment(segId, ctx);
1350
+ if (rendered.visible && rendered.content) {
1351
+ leftParts.push(rendered.content);
1352
+ leftSegIds.push(segId);
1353
+ }
1354
+ }
1355
+
1356
+ const rightParts: string[] = [];
1357
+ for (const segId of effectiveSettings.rightSegments) {
1358
+ if (subagentBadge && segId === "subagents") continue;
1359
+ const rendered = renderSegment(segId, ctx);
1360
+ if (rendered.visible && rendered.content) {
1361
+ rightParts.push(rendered.content);
1362
+ }
1363
+ }
1364
+
1365
+ const runningBackgroundJobs = this.session.getAsyncJobSnapshot()?.running.length ?? 0;
1366
+ if (runningBackgroundJobs > 0) {
1367
+ rightParts.unshift(theme.fg("statusLineSubagents", `${theme.icon.job} ${runningBackgroundJobs}`));
1368
+ }
1369
+ if (subagentBadge) {
1370
+ rightParts.unshift(subagentBadge);
1371
+ }
1372
+ const topFillWidth = Math.max(0, width);
1373
+ const left = [...leftParts];
1374
+ const right = [...rightParts];
1375
+
1376
+ const leftSepWidth = visibleWidth(separatorDef.left);
1377
+ const rightSepWidth = visibleWidth(separatorDef.right);
1378
+ // Transparent mode drops powerline caps (they need a bg fill to bridge),
1379
+ // so the width budget excludes them too.
1380
+ const leftCapWidth = separatorDef.endCaps && !transparentBg ? visibleWidth(separatorDef.endCaps.right) : 0;
1381
+ const rightCapWidth = separatorDef.endCaps && !transparentBg ? visibleWidth(separatorDef.endCaps.left) : 0;
1382
+
1383
+ const groupWidth = (parts: string[], capWidth: number, sepWidth: number): number => {
1384
+ if (parts.length === 0) return 0;
1385
+ const partsWidth = parts.reduce((sum, part) => sum + visibleWidth(part), 0);
1386
+ const sepTotal = Math.max(0, parts.length - 1) * (sepWidth + 2);
1387
+ return partsWidth + sepTotal + 2 + capWidth;
1388
+ };
1389
+
1390
+ let leftWidth = groupWidth(left, leftCapWidth, leftSepWidth);
1391
+ let rightWidth = groupWidth(right, rightCapWidth, rightSepWidth);
1392
+ const totalWidth = () => leftWidth + rightWidth + (left.length > 0 && right.length > 0 ? 1 : 0);
1393
+
1394
+ if (topFillWidth > 0) {
1395
+ while (totalWidth() > topFillWidth && right.length > 0) {
1396
+ right.pop();
1397
+ rightWidth = groupWidth(right, rightCapWidth, rightSepWidth);
1398
+ }
1399
+ // Shrink path before dropping left segments — path is the only elastic segment
1400
+ const pathIdx = leftSegIds.indexOf("path");
1401
+ if (pathIdx >= 0 && totalWidth() > topFillWidth) {
1402
+ const overflow = totalWidth() - topFillWidth;
1403
+ const currentPathVW = visibleWidth(left[pathIdx]);
1404
+ const minPathVW = 8; // icon + ellipsis + a few chars
1405
+ const shrinkable = currentPathVW - minPathVW;
1406
+ if (shrinkable > 0) {
1407
+ const shrinkBy = Math.min(shrinkable, overflow);
1408
+ const currentMaxLen = ctx.options.path?.maxLength ?? 40;
1409
+ let newMaxLen = Math.max(4, Math.min(currentMaxLen, currentPathVW) - shrinkBy);
1410
+ const pathCtx = (maxLen: number): SegmentContext => ({
1411
+ ...ctx,
1412
+ options: { ...ctx.options, path: { ...ctx.options.path, maxLength: maxLen } },
1413
+ });
1414
+ let reRendered = renderSegment("path", pathCtx(newMaxLen));
1415
+ if (reRendered.visible && reRendered.content) {
1416
+ // maxLength governs path text, not icon prefix; iterate to compensate
1417
+ for (let i = 0; i < 8; i++) {
1418
+ const saved = currentPathVW - visibleWidth(reRendered.content);
1419
+ if (saved >= shrinkBy) break;
1420
+ const nextMaxLen = Math.max(4, newMaxLen - (shrinkBy - saved));
1421
+ if (nextMaxLen >= newMaxLen) break; // no progress or hit floor
1422
+ newMaxLen = nextMaxLen;
1423
+ const adjusted = renderSegment("path", pathCtx(newMaxLen));
1424
+ if (!adjusted.visible || !adjusted.content) break;
1425
+ reRendered = adjusted;
1426
+ }
1427
+ left[pathIdx] = reRendered.content;
1428
+ leftWidth = groupWidth(left, leftCapWidth, leftSepWidth);
1429
+ }
1430
+ }
1431
+ }
1432
+ const leftOverflowDropIndex = (): number => {
1433
+ // Preserve the current working directory as long as possible. The
1434
+ // previous right-to-left pop could collapse a normal-width bar to
1435
+ // just the model segment, hiding the path before less-critical left
1436
+ // segments such as model/mode/collab were removed.
1437
+ for (let i = leftSegIds.length - 1; i >= 0; i--) {
1438
+ if (leftSegIds[i] !== "path") return i;
1439
+ }
1440
+ return left.length - 1;
1441
+ };
1442
+
1443
+ while (totalWidth() > topFillWidth && left.length > 0) {
1444
+ const dropIdx = leftOverflowDropIndex();
1445
+ left.splice(dropIdx, 1);
1446
+ leftSegIds.splice(dropIdx, 1);
1447
+ leftWidth = groupWidth(left, leftCapWidth, leftSepWidth);
1448
+ }
1449
+ }
1450
+
1451
+ const renderGroup = (parts: string[], direction: "left" | "right"): string => {
1452
+ if (parts.length === 0) return "";
1453
+ const sep = direction === "left" ? separatorDef.left : separatorDef.right;
1454
+ const cap =
1455
+ separatorDef.endCaps && !transparentBg
1456
+ ? direction === "left"
1457
+ ? separatorDef.endCaps.right
1458
+ : separatorDef.endCaps.left
1459
+ : "";
1460
+ const capPrefix = separatorDef.endCaps?.useBgAsFg ? bgAnsi.replace("\x1b[48;", "\x1b[38;") : bgAnsi + sepAnsi;
1461
+ const capText = cap ? `${capPrefix}${cap}\x1b[0m` : "";
1462
+
1463
+ let content = bgAnsi + fgAnsi;
1464
+ content += ` ${parts.join(` ${sepAnsi}${sep}${fgAnsi} `)} `;
1465
+ content += "\x1b[0m";
1466
+
1467
+ if (capText) {
1468
+ return direction === "right" ? capText + content : content + capText;
1469
+ }
1470
+ return content;
1471
+ };
1472
+
1473
+ const leftGroup = renderGroup(left, "left");
1474
+ const rightGroup = renderGroup(right, "right");
1475
+ if (!leftGroup && !rightGroup) return "";
1476
+
1477
+ if (topFillWidth === 0 || left.length === 0 || right.length === 0) {
1478
+ return leftGroup + (leftGroup && rightGroup ? " " : "") + rightGroup;
1479
+ }
1480
+
1481
+ const gapWidth = Math.max(1, topFillWidth - leftWidth - rightWidth);
1482
+ const sessionName =
1483
+ effectiveSettings.sessionAccent !== false ? this.session.sessionManager?.getSessionName() : undefined;
1484
+ const accentHex = sessionName
1485
+ ? getSessionAccentHex(sessionName, theme.getMajorThemeColorHexes(), theme.accentSurfaceLuminance)
1486
+ : undefined;
1487
+ const gapColor = getSessionAccentAnsi(accentHex) ?? theme.getFgAnsi("border");
1488
+ const gapFill = `${gapColor}${theme.boxRound.horizontal.repeat(gapWidth)}\x1b[39m`;
1489
+ return leftGroup + gapFill + rightGroup;
1490
+ }
1491
+
1492
+ getTopBorder(width: number): { content: string; width: number } {
1493
+ let content = this.#buildStatusLine(width);
1494
+ if (this.#focusedAgentId && content) {
1495
+ // Dim the whole bar while focus-proxied. Group/cap terminators emit full
1496
+ // `\x1b[0m` resets that would cancel faint mid-bar, so re-open it after each.
1497
+ content = `\x1b[2m${content.replaceAll("\x1b[0m", "\x1b[0m\x1b[2m")}\x1b[22m`;
1498
+ }
1499
+ return {
1500
+ content,
1501
+ width: visibleWidth(content),
1502
+ };
1503
+ }
1504
+
1505
+ render(width: number): readonly string[] {
1506
+ // Only render hook statuses - main status is in editor's top border
1507
+ const showHooks = this.#settings.showHookStatus ?? true;
1508
+ if (!showHooks || this.#hookStatuses.size === 0) {
1509
+ return [];
1510
+ }
1511
+
1512
+ return Array.from(this.#hookStatuses.entries())
1513
+ .sort(([a], [b]) => a.localeCompare(b))
1514
+ .map(([, text]) => truncateToWidth(sanitizeStatusText(text), width));
1515
+ }
1516
+ }