oma-coding-agent 1.1.4

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 (1298) hide show
  1. package/CHANGELOG.md +12164 -0
  2. package/README.md +35 -0
  3. package/dist/cli.js +18266 -0
  4. package/examples/README.md +21 -0
  5. package/examples/custom-tools/README.md +104 -0
  6. package/examples/custom-tools/hello/index.ts +20 -0
  7. package/examples/extensions/README.md +142 -0
  8. package/examples/extensions/api-demo.ts +79 -0
  9. package/examples/extensions/chalk-logger.ts +25 -0
  10. package/examples/extensions/hello.ts +31 -0
  11. package/examples/extensions/pirate.ts +43 -0
  12. package/examples/extensions/plan-mode.ts +549 -0
  13. package/examples/extensions/reload-runtime.ts +38 -0
  14. package/examples/extensions/thinking-note.ts +13 -0
  15. package/examples/extensions/tools.ts +145 -0
  16. package/examples/extensions/with-deps/index.ts +36 -0
  17. package/examples/extensions/with-deps/package-lock.json +31 -0
  18. package/examples/extensions/with-deps/package.json +17 -0
  19. package/examples/hooks/README.md +56 -0
  20. package/examples/hooks/auto-commit-on-exit.ts +48 -0
  21. package/examples/hooks/confirm-destructive.ts +58 -0
  22. package/examples/hooks/custom-compaction.ts +115 -0
  23. package/examples/hooks/dirty-repo-guard.ts +51 -0
  24. package/examples/hooks/file-trigger.ts +40 -0
  25. package/examples/hooks/git-checkpoint.ts +52 -0
  26. package/examples/hooks/handoff.ts +149 -0
  27. package/examples/hooks/permission-gate.ts +33 -0
  28. package/examples/hooks/protected-paths.ts +29 -0
  29. package/examples/hooks/qna.ts +118 -0
  30. package/examples/hooks/status-line.ts +39 -0
  31. package/examples/sdk/01-minimal.ts +21 -0
  32. package/examples/sdk/02-custom-model.ts +49 -0
  33. package/examples/sdk/03-custom-prompt.ts +46 -0
  34. package/examples/sdk/04-skills.ts +43 -0
  35. package/examples/sdk/06-extensions.ts +82 -0
  36. package/examples/sdk/06-hooks.ts +61 -0
  37. package/examples/sdk/07-context-files.ts +35 -0
  38. package/examples/sdk/08-prompt-templates.ts +41 -0
  39. package/examples/sdk/08-slash-commands.ts +46 -0
  40. package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
  41. package/examples/sdk/11-sessions.ts +47 -0
  42. package/examples/sdk/12-redis-sessions.ts +54 -0
  43. package/examples/sdk/13-sql-sessions.ts +61 -0
  44. package/examples/sdk/README.md +172 -0
  45. package/package.json +573 -0
  46. package/scripts/bench-guard.ts +71 -0
  47. package/scripts/build-binary.ts +108 -0
  48. package/scripts/bundle-dist.ts +110 -0
  49. package/scripts/embed-mupdf-wasm.ts +67 -0
  50. package/scripts/format-prompts.ts +68 -0
  51. package/scripts/generate-docs-index.ts +56 -0
  52. package/scripts/generate-share-viewer.ts +34 -0
  53. package/scripts/measure-prompt-tokens.ts +63 -0
  54. package/scripts/omp +42 -0
  55. package/scripts/omp.ts +19 -0
  56. package/src/advisor/__tests__/advisor.test.ts +915 -0
  57. package/src/advisor/advise-tool.ts +165 -0
  58. package/src/advisor/index.ts +4 -0
  59. package/src/advisor/runtime.ts +270 -0
  60. package/src/advisor/transcript-recorder.ts +136 -0
  61. package/src/advisor/watchdog.ts +83 -0
  62. package/src/async/index.ts +1 -0
  63. package/src/async/job-manager.ts +674 -0
  64. package/src/auto-thinking/classifier.ts +190 -0
  65. package/src/autolearn/controller.ts +139 -0
  66. package/src/autolearn/managed-skills.ts +255 -0
  67. package/src/autoresearch/command-resume.md +14 -0
  68. package/src/autoresearch/dashboard.ts +436 -0
  69. package/src/autoresearch/git.ts +319 -0
  70. package/src/autoresearch/helpers.ts +218 -0
  71. package/src/autoresearch/index.ts +536 -0
  72. package/src/autoresearch/prompt-setup.md +43 -0
  73. package/src/autoresearch/prompt.md +103 -0
  74. package/src/autoresearch/resume-message.md +10 -0
  75. package/src/autoresearch/state.ts +273 -0
  76. package/src/autoresearch/storage.ts +700 -0
  77. package/src/autoresearch/tools/init-experiment.ts +269 -0
  78. package/src/autoresearch/tools/log-experiment.ts +521 -0
  79. package/src/autoresearch/tools/run-experiment.ts +407 -0
  80. package/src/autoresearch/tools/update-notes.ts +109 -0
  81. package/src/autoresearch/types.ts +168 -0
  82. package/src/capability/context-file.ts +44 -0
  83. package/src/capability/extension-module.ts +34 -0
  84. package/src/capability/extension.ts +47 -0
  85. package/src/capability/fs.ts +117 -0
  86. package/src/capability/hook.ts +40 -0
  87. package/src/capability/index.ts +436 -0
  88. package/src/capability/instruction.ts +37 -0
  89. package/src/capability/mcp.ts +76 -0
  90. package/src/capability/prompt.ts +35 -0
  91. package/src/capability/rule-buckets.ts +66 -0
  92. package/src/capability/rule.ts +261 -0
  93. package/src/capability/settings.ts +34 -0
  94. package/src/capability/skill.ts +63 -0
  95. package/src/capability/slash-command.ts +40 -0
  96. package/src/capability/ssh.ts +41 -0
  97. package/src/capability/system-prompt.ts +34 -0
  98. package/src/capability/tool.ts +38 -0
  99. package/src/capability/types.ts +168 -0
  100. package/src/cli/agents-cli.ts +138 -0
  101. package/src/cli/args.ts +361 -0
  102. package/src/cli/auth-broker-cli.ts +893 -0
  103. package/src/cli/auth-gateway-cli.ts +608 -0
  104. package/src/cli/bench-cli.ts +552 -0
  105. package/src/cli/classify-install-target.ts +76 -0
  106. package/src/cli/claude-trace-cli.ts +795 -0
  107. package/src/cli/commands/init-xdg.ts +27 -0
  108. package/src/cli/completion-gen.ts +550 -0
  109. package/src/cli/config-cli.ts +418 -0
  110. package/src/cli/dry-balance-cli.ts +858 -0
  111. package/src/cli/extension-flags.ts +48 -0
  112. package/src/cli/file-processor.ts +133 -0
  113. package/src/cli/flag-tables.ts +280 -0
  114. package/src/cli/gallery-cli.ts +231 -0
  115. package/src/cli/gallery-fixtures/agentic.ts +407 -0
  116. package/src/cli/gallery-fixtures/codeintel.ts +187 -0
  117. package/src/cli/gallery-fixtures/edit.ts +194 -0
  118. package/src/cli/gallery-fixtures/fs.ts +220 -0
  119. package/src/cli/gallery-fixtures/index.ts +40 -0
  120. package/src/cli/gallery-fixtures/interaction.ts +49 -0
  121. package/src/cli/gallery-fixtures/memory.ts +81 -0
  122. package/src/cli/gallery-fixtures/misc.ts +250 -0
  123. package/src/cli/gallery-fixtures/search.ts +213 -0
  124. package/src/cli/gallery-fixtures/shell.ts +167 -0
  125. package/src/cli/gallery-fixtures/types.ts +57 -0
  126. package/src/cli/gallery-fixtures/web.ts +158 -0
  127. package/src/cli/gallery-screenshot.ts +279 -0
  128. package/src/cli/grep-cli.ts +160 -0
  129. package/src/cli/grievances-cli.ts +256 -0
  130. package/src/cli/initial-message.ts +58 -0
  131. package/src/cli/models-cli.ts +427 -0
  132. package/src/cli/plugin-cli.ts +996 -0
  133. package/src/cli/profile-alias.ts +338 -0
  134. package/src/cli/profile-bootstrap.ts +243 -0
  135. package/src/cli/read-cli.ts +57 -0
  136. package/src/cli/session-picker.ts +80 -0
  137. package/src/cli/setup-cli.ts +332 -0
  138. package/src/cli/setup-model-picker.ts +43 -0
  139. package/src/cli/shell-cli.ts +176 -0
  140. package/src/cli/ssh-cli.ts +179 -0
  141. package/src/cli/startup-cwd.ts +58 -0
  142. package/src/cli/stats-cli.ts +229 -0
  143. package/src/cli/tiny-models-cli.ts +127 -0
  144. package/src/cli/ttsr-cli.ts +995 -0
  145. package/src/cli/update-cli.ts +671 -0
  146. package/src/cli/usage-cli.ts +774 -0
  147. package/src/cli/web-search-cli.ts +132 -0
  148. package/src/cli/worktree-cli.ts +291 -0
  149. package/src/cli-commands.ts +85 -0
  150. package/src/cli.ts +326 -0
  151. package/src/collab/crypto.ts +63 -0
  152. package/src/collab/guest.ts +450 -0
  153. package/src/collab/host.ts +577 -0
  154. package/src/collab/protocol.ts +274 -0
  155. package/src/collab/relay-client.ts +216 -0
  156. package/src/commands/acp.ts +24 -0
  157. package/src/commands/agents.ts +57 -0
  158. package/src/commands/auth-broker.ts +99 -0
  159. package/src/commands/auth-gateway.ts +69 -0
  160. package/src/commands/bench.ts +42 -0
  161. package/src/commands/commit.ts +46 -0
  162. package/src/commands/complete.ts +66 -0
  163. package/src/commands/completions.ts +60 -0
  164. package/src/commands/config.ts +51 -0
  165. package/src/commands/dry-balance.ts +43 -0
  166. package/src/commands/gallery.ts +52 -0
  167. package/src/commands/grep.ts +48 -0
  168. package/src/commands/grievances.ts +51 -0
  169. package/src/commands/install.ts +107 -0
  170. package/src/commands/join.ts +39 -0
  171. package/src/commands/launch.ts +182 -0
  172. package/src/commands/models.ts +61 -0
  173. package/src/commands/plugin.ts +78 -0
  174. package/src/commands/read.ts +38 -0
  175. package/src/commands/say.ts +102 -0
  176. package/src/commands/setup.ts +67 -0
  177. package/src/commands/shell.ts +29 -0
  178. package/src/commands/ssh.ts +60 -0
  179. package/src/commands/stats.ts +29 -0
  180. package/src/commands/tiny-models.ts +36 -0
  181. package/src/commands/token.ts +108 -0
  182. package/src/commands/ttsr.ts +125 -0
  183. package/src/commands/update.ts +21 -0
  184. package/src/commands/usage.ts +43 -0
  185. package/src/commands/web-search.ts +42 -0
  186. package/src/commands/worktree.ts +56 -0
  187. package/src/commit/agentic/agent.ts +318 -0
  188. package/src/commit/agentic/fallback.ts +96 -0
  189. package/src/commit/agentic/index.ts +355 -0
  190. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  191. package/src/commit/agentic/prompts/session-user.md +25 -0
  192. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  193. package/src/commit/agentic/prompts/system.md +38 -0
  194. package/src/commit/agentic/state.ts +60 -0
  195. package/src/commit/agentic/tools/analyze-file.ts +149 -0
  196. package/src/commit/agentic/tools/git-file-diff.ts +191 -0
  197. package/src/commit/agentic/tools/git-hunk.ts +52 -0
  198. package/src/commit/agentic/tools/git-overview.ts +81 -0
  199. package/src/commit/agentic/tools/index.ts +54 -0
  200. package/src/commit/agentic/tools/propose-changelog.ts +147 -0
  201. package/src/commit/agentic/tools/propose-commit.ts +109 -0
  202. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  203. package/src/commit/agentic/tools/schemas.ts +11 -0
  204. package/src/commit/agentic/tools/split-commit.ts +241 -0
  205. package/src/commit/agentic/topo-sort.ts +44 -0
  206. package/src/commit/agentic/trivial.ts +51 -0
  207. package/src/commit/agentic/validation.ts +183 -0
  208. package/src/commit/analysis/conventional.ts +64 -0
  209. package/src/commit/analysis/index.ts +4 -0
  210. package/src/commit/analysis/scope.ts +242 -0
  211. package/src/commit/analysis/summary.ts +107 -0
  212. package/src/commit/analysis/validation.ts +66 -0
  213. package/src/commit/changelog/detect.ts +40 -0
  214. package/src/commit/changelog/generate.ts +101 -0
  215. package/src/commit/changelog/index.ts +234 -0
  216. package/src/commit/changelog/parse.ts +44 -0
  217. package/src/commit/cli.ts +85 -0
  218. package/src/commit/git/diff.ts +148 -0
  219. package/src/commit/index.ts +5 -0
  220. package/src/commit/map-reduce/index.ts +69 -0
  221. package/src/commit/map-reduce/map-phase.ts +193 -0
  222. package/src/commit/map-reduce/reduce-phase.ts +49 -0
  223. package/src/commit/map-reduce/utils.ts +9 -0
  224. package/src/commit/message.ts +11 -0
  225. package/src/commit/model-selection.ts +89 -0
  226. package/src/commit/pipeline.ts +243 -0
  227. package/src/commit/prompts/analysis-system.md +148 -0
  228. package/src/commit/prompts/analysis-user.md +38 -0
  229. package/src/commit/prompts/changelog-system.md +50 -0
  230. package/src/commit/prompts/changelog-user.md +18 -0
  231. package/src/commit/prompts/file-observer-system.md +24 -0
  232. package/src/commit/prompts/file-observer-user.md +8 -0
  233. package/src/commit/prompts/reduce-system.md +50 -0
  234. package/src/commit/prompts/reduce-user.md +17 -0
  235. package/src/commit/prompts/summary-retry.md +3 -0
  236. package/src/commit/prompts/summary-system.md +38 -0
  237. package/src/commit/prompts/summary-user.md +13 -0
  238. package/src/commit/prompts/types-description.md +2 -0
  239. package/src/commit/shared-llm.ts +70 -0
  240. package/src/commit/types.ts +118 -0
  241. package/src/commit/utils/exclusions.ts +42 -0
  242. package/src/commit/utils.ts +58 -0
  243. package/src/config/api-key-resolver.ts +67 -0
  244. package/src/config/append-only-context-mode.ts +76 -0
  245. package/src/config/config-file.ts +315 -0
  246. package/src/config/file-lock.ts +164 -0
  247. package/src/config/keybindings.ts +634 -0
  248. package/src/config/mcp-schema.json +238 -0
  249. package/src/config/model-discovery.ts +589 -0
  250. package/src/config/model-registry.ts +2260 -0
  251. package/src/config/model-resolver.ts +1819 -0
  252. package/src/config/model-roles.ts +99 -0
  253. package/src/config/models-config-schema.ts +266 -0
  254. package/src/config/models-config.ts +131 -0
  255. package/src/config/prompt-templates.ts +185 -0
  256. package/src/config/resolve-config-value.ts +94 -0
  257. package/src/config/settings-schema.ts +4740 -0
  258. package/src/config/settings.ts +1243 -0
  259. package/src/config.ts +242 -0
  260. package/src/cursor.ts +340 -0
  261. package/src/dap/client.ts +760 -0
  262. package/src/dap/config.ts +189 -0
  263. package/src/dap/defaults.json +212 -0
  264. package/src/dap/index.ts +4 -0
  265. package/src/dap/session.ts +1441 -0
  266. package/src/dap/types.ts +610 -0
  267. package/src/debug/index.ts +559 -0
  268. package/src/debug/log-formatting.ts +58 -0
  269. package/src/debug/log-viewer.ts +908 -0
  270. package/src/debug/profiler.ts +162 -0
  271. package/src/debug/protocol-probe.ts +267 -0
  272. package/src/debug/raw-sse-buffer.ts +294 -0
  273. package/src/debug/raw-sse.ts +292 -0
  274. package/src/debug/remote-debugger.ts +151 -0
  275. package/src/debug/report-bundle.ts +375 -0
  276. package/src/debug/system-info.ts +111 -0
  277. package/src/debug/terminal-info.ts +124 -0
  278. package/src/discovery/agents-md.ts +67 -0
  279. package/src/discovery/agents.ts +230 -0
  280. package/src/discovery/at-imports.ts +273 -0
  281. package/src/discovery/builtin-defaults.ts +39 -0
  282. package/src/discovery/builtin-rules/index.ts +63 -0
  283. package/src/discovery/builtin-rules/low-end/no-hallucinated-apis.md +14 -0
  284. package/src/discovery/builtin-rules/low-end/no-hallucinated-paths.md +14 -0
  285. package/src/discovery/builtin-rules/low-end/no-premature-completion.md +14 -0
  286. package/src/discovery/builtin-rules/rs-box-leak.md +48 -0
  287. package/src/discovery/builtin-rules/rs-future-prelude.md +23 -0
  288. package/src/discovery/builtin-rules/rs-lazylock.md +51 -0
  289. package/src/discovery/builtin-rules/rs-match-ergonomics.md +67 -0
  290. package/src/discovery/builtin-rules/rs-parking-lot.md +44 -0
  291. package/src/discovery/builtin-rules/rs-result-type.md +19 -0
  292. package/src/discovery/builtin-rules/ts-bare-catch.md +38 -0
  293. package/src/discovery/builtin-rules/ts-import-type.md +42 -0
  294. package/src/discovery/builtin-rules/ts-no-any.md +65 -0
  295. package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +44 -0
  296. package/src/discovery/builtin-rules/ts-no-dynamic-import.md +39 -0
  297. package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +55 -0
  298. package/src/discovery/builtin-rules/ts-no-return-type.md +44 -0
  299. package/src/discovery/builtin-rules/ts-no-test-timers.md +55 -0
  300. package/src/discovery/builtin-rules/ts-no-tiny-functions.md +51 -0
  301. package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +65 -0
  302. package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +75 -0
  303. package/src/discovery/builtin-rules/ts-set-map.md +28 -0
  304. package/src/discovery/builtin.ts +934 -0
  305. package/src/discovery/claude-plugins.ts +386 -0
  306. package/src/discovery/claude.ts +584 -0
  307. package/src/discovery/cline.ts +83 -0
  308. package/src/discovery/codex.ts +522 -0
  309. package/src/discovery/cursor.ts +220 -0
  310. package/src/discovery/gemini.ts +383 -0
  311. package/src/discovery/github.ts +337 -0
  312. package/src/discovery/helpers.ts +1092 -0
  313. package/src/discovery/index.ts +81 -0
  314. package/src/discovery/mcp-json.ts +172 -0
  315. package/src/discovery/omp-extension-roots.ts +190 -0
  316. package/src/discovery/omp-plugins.ts +383 -0
  317. package/src/discovery/opencode.ts +398 -0
  318. package/src/discovery/plugin-dir-roots.ts +28 -0
  319. package/src/discovery/ssh.ts +153 -0
  320. package/src/discovery/substitute-plugin-root.ts +29 -0
  321. package/src/discovery/vscode.ts +105 -0
  322. package/src/discovery/windsurf.ts +147 -0
  323. package/src/edit/apply-patch/index.ts +87 -0
  324. package/src/edit/apply-patch/parser.ts +174 -0
  325. package/src/edit/diff.ts +999 -0
  326. package/src/edit/file-snapshot-store.ts +143 -0
  327. package/src/edit/hashline/block-resolver.ts +33 -0
  328. package/src/edit/hashline/diff.ts +290 -0
  329. package/src/edit/hashline/execute.ts +237 -0
  330. package/src/edit/hashline/filesystem.ts +130 -0
  331. package/src/edit/hashline/index.ts +5 -0
  332. package/src/edit/hashline/noop-loop-guard.ts +99 -0
  333. package/src/edit/hashline/params.ts +19 -0
  334. package/src/edit/index.ts +620 -0
  335. package/src/edit/modes/apply-patch.lark +19 -0
  336. package/src/edit/modes/apply-patch.ts +53 -0
  337. package/src/edit/modes/patch.ts +1888 -0
  338. package/src/edit/modes/replace.ts +1133 -0
  339. package/src/edit/normalize.ts +345 -0
  340. package/src/edit/notebook.ts +242 -0
  341. package/src/edit/read-file.ts +25 -0
  342. package/src/edit/renderer.ts +823 -0
  343. package/src/edit/streaming.ts +517 -0
  344. package/src/eval/__tests__/agent-bridge.test.ts +769 -0
  345. package/src/eval/__tests__/bridge-timeout.test.ts +64 -0
  346. package/src/eval/__tests__/budget-bridge.test.ts +69 -0
  347. package/src/eval/__tests__/completion-bridge.test.ts +412 -0
  348. package/src/eval/__tests__/helpers-local-roots.test.ts +58 -0
  349. package/src/eval/__tests__/idle-timeout.test.ts +80 -0
  350. package/src/eval/__tests__/js-context-manager.test.ts +291 -0
  351. package/src/eval/__tests__/kernel-spawn.test.ts +103 -0
  352. package/src/eval/__tests__/prelude-agent.test.ts +73 -0
  353. package/src/eval/agent-bridge.ts +319 -0
  354. package/src/eval/backend.ts +71 -0
  355. package/src/eval/bridge-timeout.ts +44 -0
  356. package/src/eval/budget-bridge.ts +48 -0
  357. package/src/eval/completion-bridge.ts +211 -0
  358. package/src/eval/concurrency-bridge.ts +34 -0
  359. package/src/eval/idle-timeout.ts +91 -0
  360. package/src/eval/index.ts +4 -0
  361. package/src/eval/js/context-manager.ts +621 -0
  362. package/src/eval/js/executor.ts +173 -0
  363. package/src/eval/js/index.ts +51 -0
  364. package/src/eval/js/shared/helpers.ts +283 -0
  365. package/src/eval/js/shared/indirect-eval.ts +30 -0
  366. package/src/eval/js/shared/local-module-loader.ts +342 -0
  367. package/src/eval/js/shared/prelude.ts +2 -0
  368. package/src/eval/js/shared/prelude.txt +307 -0
  369. package/src/eval/js/shared/rewrite-imports.ts +532 -0
  370. package/src/eval/js/shared/runtime.ts +580 -0
  371. package/src/eval/js/shared/types.ts +18 -0
  372. package/src/eval/js/tool-bridge.ts +163 -0
  373. package/src/eval/js/worker-core.ts +151 -0
  374. package/src/eval/js/worker-entry.ts +37 -0
  375. package/src/eval/js/worker-protocol.ts +47 -0
  376. package/src/eval/py/__tests__/prelude.test.ts +19 -0
  377. package/src/eval/py/display.ts +71 -0
  378. package/src/eval/py/executor.ts +742 -0
  379. package/src/eval/py/index.ts +68 -0
  380. package/src/eval/py/kernel.ts +748 -0
  381. package/src/eval/py/prelude.py +683 -0
  382. package/src/eval/py/prelude.ts +3 -0
  383. package/src/eval/py/runner.py +1177 -0
  384. package/src/eval/py/runtime.ts +276 -0
  385. package/src/eval/py/spawn-options.ts +126 -0
  386. package/src/eval/py/tool-bridge.ts +182 -0
  387. package/src/eval/session-id.ts +8 -0
  388. package/src/eval/types.ts +48 -0
  389. package/src/exa/index.ts +2 -0
  390. package/src/exa/mcp-client.ts +370 -0
  391. package/src/exa/types.ts +69 -0
  392. package/src/exec/bash-executor.ts +434 -0
  393. package/src/exec/exec.ts +53 -0
  394. package/src/exec/non-interactive-env.ts +119 -0
  395. package/src/export/custom-share.ts +65 -0
  396. package/src/export/html/index.ts +266 -0
  397. package/src/export/html/share-loader.js +102 -0
  398. package/src/export/html/template.css +1337 -0
  399. package/src/export/html/template.html +49 -0
  400. package/src/export/html/template.js +1626 -0
  401. package/src/export/html/tool-views.generated.js +37 -0
  402. package/src/export/html/vendor/highlight.min.js +1213 -0
  403. package/src/export/html/vendor/marked.min.js +6 -0
  404. package/src/export/share.ts +268 -0
  405. package/src/export/ttsr.ts +583 -0
  406. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +54 -0
  407. package/src/extensibility/custom-commands/bundled/review/index.ts +698 -0
  408. package/src/extensibility/custom-commands/index.ts +2 -0
  409. package/src/extensibility/custom-commands/loader.ts +242 -0
  410. package/src/extensibility/custom-commands/types.ts +119 -0
  411. package/src/extensibility/custom-tools/index.ts +7 -0
  412. package/src/extensibility/custom-tools/loader.ts +268 -0
  413. package/src/extensibility/custom-tools/types.ts +277 -0
  414. package/src/extensibility/custom-tools/wrapper.ts +47 -0
  415. package/src/extensibility/extensions/compact-handler.ts +40 -0
  416. package/src/extensibility/extensions/get-commands-handler.ts +78 -0
  417. package/src/extensibility/extensions/index.ts +16 -0
  418. package/src/extensibility/extensions/loader.ts +587 -0
  419. package/src/extensibility/extensions/model-api.ts +41 -0
  420. package/src/extensibility/extensions/runner.ts +989 -0
  421. package/src/extensibility/extensions/types.ts +1394 -0
  422. package/src/extensibility/extensions/wrapper.ts +259 -0
  423. package/src/extensibility/hooks/index.ts +6 -0
  424. package/src/extensibility/hooks/loader.ts +262 -0
  425. package/src/extensibility/hooks/runner.ts +425 -0
  426. package/src/extensibility/hooks/tool-wrapper.ts +107 -0
  427. package/src/extensibility/hooks/types.ts +613 -0
  428. package/src/extensibility/legacy-pi-ai-shim.ts +61 -0
  429. package/src/extensibility/legacy-pi-coding-agent-shim.ts +128 -0
  430. package/src/extensibility/plugins/doctor.ts +65 -0
  431. package/src/extensibility/plugins/git-url.ts +367 -0
  432. package/src/extensibility/plugins/index.ts +9 -0
  433. package/src/extensibility/plugins/installer.ts +192 -0
  434. package/src/extensibility/plugins/legacy-pi-compat.ts +712 -0
  435. package/src/extensibility/plugins/loader.ts +458 -0
  436. package/src/extensibility/plugins/manager.ts +1026 -0
  437. package/src/extensibility/plugins/marketplace/cache.ts +136 -0
  438. package/src/extensibility/plugins/marketplace/fetcher.ts +315 -0
  439. package/src/extensibility/plugins/marketplace/index.ts +6 -0
  440. package/src/extensibility/plugins/marketplace/manager.ts +770 -0
  441. package/src/extensibility/plugins/marketplace/registry.ts +196 -0
  442. package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
  443. package/src/extensibility/plugins/marketplace/types.ts +191 -0
  444. package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
  445. package/src/extensibility/plugins/parser.ts +105 -0
  446. package/src/extensibility/plugins/runtime-config.ts +9 -0
  447. package/src/extensibility/plugins/types.ts +194 -0
  448. package/src/extensibility/shared-events.ts +367 -0
  449. package/src/extensibility/skills.ts +408 -0
  450. package/src/extensibility/slash-commands.ts +131 -0
  451. package/src/extensibility/tool-proxy.ts +28 -0
  452. package/src/extensibility/typebox.ts +945 -0
  453. package/src/extensibility/utils.ts +44 -0
  454. package/src/goals/guided-setup.ts +142 -0
  455. package/src/goals/index.ts +3 -0
  456. package/src/goals/runtime.ts +521 -0
  457. package/src/goals/state.ts +37 -0
  458. package/src/goals/tools/goal-tool.ts +251 -0
  459. package/src/hindsight/backend.ts +354 -0
  460. package/src/hindsight/bank.ts +156 -0
  461. package/src/hindsight/client.ts +623 -0
  462. package/src/hindsight/config.ts +175 -0
  463. package/src/hindsight/content.ts +210 -0
  464. package/src/hindsight/index.ts +8 -0
  465. package/src/hindsight/mental-models.ts +429 -0
  466. package/src/hindsight/seeds.json +32 -0
  467. package/src/hindsight/state.ts +492 -0
  468. package/src/hindsight/transcript.ts +71 -0
  469. package/src/index.ts +66 -0
  470. package/src/internal-urls/agent-protocol.ts +146 -0
  471. package/src/internal-urls/artifact-protocol.ts +107 -0
  472. package/src/internal-urls/docs-index.generated.txt +2 -0
  473. package/src/internal-urls/docs-index.ts +102 -0
  474. package/src/internal-urls/history-protocol.ts +118 -0
  475. package/src/internal-urls/index.ts +25 -0
  476. package/src/internal-urls/issue-pr-protocol.ts +594 -0
  477. package/src/internal-urls/json-query.ts +126 -0
  478. package/src/internal-urls/local-protocol.ts +309 -0
  479. package/src/internal-urls/mcp-protocol.ts +151 -0
  480. package/src/internal-urls/memory-protocol.ts +169 -0
  481. package/src/internal-urls/omp-protocol.ts +94 -0
  482. package/src/internal-urls/parse.ts +72 -0
  483. package/src/internal-urls/registry-helpers.ts +25 -0
  484. package/src/internal-urls/router.ts +105 -0
  485. package/src/internal-urls/rule-protocol.ts +45 -0
  486. package/src/internal-urls/skill-protocol.ts +96 -0
  487. package/src/internal-urls/types.ts +152 -0
  488. package/src/internal-urls/vault-protocol.ts +936 -0
  489. package/src/irc/bus.ts +311 -0
  490. package/src/lib/xai-http.ts +124 -0
  491. package/src/lsp/client.ts +1217 -0
  492. package/src/lsp/clients/biome-client.ts +264 -0
  493. package/src/lsp/clients/index.ts +50 -0
  494. package/src/lsp/clients/lsp-linter-client.ts +85 -0
  495. package/src/lsp/clients/swiftlint-client.ts +120 -0
  496. package/src/lsp/config.ts +502 -0
  497. package/src/lsp/defaults.json +499 -0
  498. package/src/lsp/diagnostics-ledger.ts +51 -0
  499. package/src/lsp/edits.ts +267 -0
  500. package/src/lsp/format-options.ts +119 -0
  501. package/src/lsp/index.ts +2480 -0
  502. package/src/lsp/lspmux.ts +233 -0
  503. package/src/lsp/render.ts +668 -0
  504. package/src/lsp/startup-events.ts +13 -0
  505. package/src/lsp/types.ts +444 -0
  506. package/src/lsp/utils.ts +718 -0
  507. package/src/main.ts +1421 -0
  508. package/src/markit/NOTICE +32 -0
  509. package/src/markit/converters/docx.ts +56 -0
  510. package/src/markit/converters/epub.ts +136 -0
  511. package/src/markit/converters/mammoth.d.ts +24 -0
  512. package/src/markit/converters/pdf/columns.ts +103 -0
  513. package/src/markit/converters/pdf/extract.ts +574 -0
  514. package/src/markit/converters/pdf/grid.ts +780 -0
  515. package/src/markit/converters/pdf/headers.ts +106 -0
  516. package/src/markit/converters/pdf/index.ts +146 -0
  517. package/src/markit/converters/pdf/render.ts +501 -0
  518. package/src/markit/converters/pdf/types.ts +84 -0
  519. package/src/markit/converters/pptx.ts +325 -0
  520. package/src/markit/converters/xlsx.ts +173 -0
  521. package/src/markit/index.ts +2 -0
  522. package/src/markit/registry.ts +59 -0
  523. package/src/markit/types.ts +35 -0
  524. package/src/mcp/client.ts +509 -0
  525. package/src/mcp/config-writer.ts +229 -0
  526. package/src/mcp/config.ts +365 -0
  527. package/src/mcp/index.ts +29 -0
  528. package/src/mcp/json-rpc.ts +122 -0
  529. package/src/mcp/loader.ts +124 -0
  530. package/src/mcp/manager.ts +1326 -0
  531. package/src/mcp/oauth-credentials.ts +104 -0
  532. package/src/mcp/oauth-discovery.ts +467 -0
  533. package/src/mcp/oauth-flow.ts +555 -0
  534. package/src/mcp/render.ts +155 -0
  535. package/src/mcp/smithery-auth.ts +104 -0
  536. package/src/mcp/smithery-connect.ts +145 -0
  537. package/src/mcp/smithery-registry.ts +477 -0
  538. package/src/mcp/startup-events.ts +21 -0
  539. package/src/mcp/timeout.ts +59 -0
  540. package/src/mcp/tool-bridge.ts +429 -0
  541. package/src/mcp/tool-cache.ts +117 -0
  542. package/src/mcp/transports/http.ts +519 -0
  543. package/src/mcp/transports/index.ts +6 -0
  544. package/src/mcp/transports/stdio.ts +606 -0
  545. package/src/mcp/types.ts +427 -0
  546. package/src/memories/index.ts +1281 -0
  547. package/src/memories/storage.ts +578 -0
  548. package/src/memory-backend/index.ts +18 -0
  549. package/src/memory-backend/local-backend.ts +45 -0
  550. package/src/memory-backend/off-backend.ts +25 -0
  551. package/src/memory-backend/resolve.ts +25 -0
  552. package/src/memory-backend/runtime.ts +66 -0
  553. package/src/memory-backend/types.ts +166 -0
  554. package/src/mnemopi/backend.ts +612 -0
  555. package/src/mnemopi/config.ts +265 -0
  556. package/src/mnemopi/embed-client.ts +401 -0
  557. package/src/mnemopi/embed-protocol.ts +35 -0
  558. package/src/mnemopi/embed-worker.ts +113 -0
  559. package/src/mnemopi/index.ts +3 -0
  560. package/src/mnemopi/state.ts +657 -0
  561. package/src/modes/acp/acp-agent.ts +2362 -0
  562. package/src/modes/acp/acp-client-bridge.ts +154 -0
  563. package/src/modes/acp/acp-event-mapper.ts +933 -0
  564. package/src/modes/acp/acp-mode.ts +23 -0
  565. package/src/modes/acp/index.ts +2 -0
  566. package/src/modes/acp/terminal-auth.ts +37 -0
  567. package/src/modes/components/__tests__/skill-message.test.ts +92 -0
  568. package/src/modes/components/advisor-message.ts +99 -0
  569. package/src/modes/components/agent-dashboard.ts +1206 -0
  570. package/src/modes/components/agent-hub.ts +566 -0
  571. package/src/modes/components/agent-transcript-viewer.ts +461 -0
  572. package/src/modes/components/assistant-message.ts +612 -0
  573. package/src/modes/components/background-tan-message.ts +36 -0
  574. package/src/modes/components/bash-execution.ts +220 -0
  575. package/src/modes/components/bordered-loader.ts +41 -0
  576. package/src/modes/components/btw-panel.ts +112 -0
  577. package/src/modes/components/cache-invalidation-marker.ts +110 -0
  578. package/src/modes/components/chat-block.ts +111 -0
  579. package/src/modes/components/chat-transcript-builder.ts +476 -0
  580. package/src/modes/components/collab-prompt-message.ts +32 -0
  581. package/src/modes/components/compaction-summary-message.ts +215 -0
  582. package/src/modes/components/copy-selector.ts +206 -0
  583. package/src/modes/components/countdown-timer.ts +75 -0
  584. package/src/modes/components/custom-editor.test.ts +142 -0
  585. package/src/modes/components/custom-editor.ts +620 -0
  586. package/src/modes/components/custom-message.ts +67 -0
  587. package/src/modes/components/diff.ts +254 -0
  588. package/src/modes/components/dynamic-border.ts +34 -0
  589. package/src/modes/components/error-banner.ts +33 -0
  590. package/src/modes/components/eval-execution.ts +158 -0
  591. package/src/modes/components/execution-shared.ts +101 -0
  592. package/src/modes/components/extensions/extension-dashboard.ts +399 -0
  593. package/src/modes/components/extensions/extension-list.ts +502 -0
  594. package/src/modes/components/extensions/index.ts +9 -0
  595. package/src/modes/components/extensions/inspector-panel.ts +321 -0
  596. package/src/modes/components/extensions/state-manager.ts +627 -0
  597. package/src/modes/components/extensions/types.ts +186 -0
  598. package/src/modes/components/footer.ts +275 -0
  599. package/src/modes/components/history-search.ts +280 -0
  600. package/src/modes/components/hook-editor.ts +167 -0
  601. package/src/modes/components/hook-input.ts +87 -0
  602. package/src/modes/components/hook-message.ts +67 -0
  603. package/src/modes/components/hook-selector.ts +659 -0
  604. package/src/modes/components/index.ts +38 -0
  605. package/src/modes/components/keybinding-hints.ts +65 -0
  606. package/src/modes/components/late-diagnostics-message.ts +60 -0
  607. package/src/modes/components/login-dialog.ts +164 -0
  608. package/src/modes/components/logout-account-selector.ts +130 -0
  609. package/src/modes/components/mcp-add-wizard.ts +1360 -0
  610. package/src/modes/components/message-frame.ts +92 -0
  611. package/src/modes/components/model-selector.ts +1315 -0
  612. package/src/modes/components/oauth-selector.ts +457 -0
  613. package/src/modes/components/omfg-panel.ts +141 -0
  614. package/src/modes/components/overlay-box.ts +109 -0
  615. package/src/modes/components/plan-review-overlay.ts +847 -0
  616. package/src/modes/components/plan-toc.ts +138 -0
  617. package/src/modes/components/plugin-selector.ts +95 -0
  618. package/src/modes/components/plugin-settings.ts +739 -0
  619. package/src/modes/components/queue-mode-selector.ts +56 -0
  620. package/src/modes/components/read-tool-group.ts +676 -0
  621. package/src/modes/components/reset-usage-selector.ts +161 -0
  622. package/src/modes/components/segment-track.ts +89 -0
  623. package/src/modes/components/session-selector.ts +631 -0
  624. package/src/modes/components/settings-defs.ts +225 -0
  625. package/src/modes/components/settings-selector.ts +1095 -0
  626. package/src/modes/components/show-images-selector.ts +45 -0
  627. package/src/modes/components/skill-message.ts +110 -0
  628. package/src/modes/components/snapcompact-shape-preview-doc.md +18 -0
  629. package/src/modes/components/snapcompact-shape-preview.ts +192 -0
  630. package/src/modes/components/status-line/component.ts +1001 -0
  631. package/src/modes/components/status-line/context-thresholds.ts +78 -0
  632. package/src/modes/components/status-line/git-utils.ts +42 -0
  633. package/src/modes/components/status-line/index.ts +5 -0
  634. package/src/modes/components/status-line/presets.ts +106 -0
  635. package/src/modes/components/status-line/segments.ts +616 -0
  636. package/src/modes/components/status-line/separators.ts +55 -0
  637. package/src/modes/components/status-line/token-rate.ts +66 -0
  638. package/src/modes/components/status-line/types.ts +124 -0
  639. package/src/modes/components/theme-selector.ts +63 -0
  640. package/src/modes/components/thinking-selector.ts +52 -0
  641. package/src/modes/components/tiny-title-download-progress.ts +90 -0
  642. package/src/modes/components/tips.txt +24 -0
  643. package/src/modes/components/todo-reminder.ts +39 -0
  644. package/src/modes/components/tool-execution.ts +1165 -0
  645. package/src/modes/components/transcript-container.ts +806 -0
  646. package/src/modes/components/tree-selector.ts +994 -0
  647. package/src/modes/components/ttsr-notification.ts +123 -0
  648. package/src/modes/components/usage-row.ts +18 -0
  649. package/src/modes/components/user-message-selector.ts +227 -0
  650. package/src/modes/components/user-message.ts +68 -0
  651. package/src/modes/components/visual-truncate.ts +63 -0
  652. package/src/modes/components/welcome.ts +581 -0
  653. package/src/modes/controllers/btw-controller.ts +173 -0
  654. package/src/modes/controllers/command-controller-shared.ts +109 -0
  655. package/src/modes/controllers/command-controller.ts +1653 -0
  656. package/src/modes/controllers/event-controller.ts +1153 -0
  657. package/src/modes/controllers/extension-ui-controller.ts +893 -0
  658. package/src/modes/controllers/input-controller.ts +1627 -0
  659. package/src/modes/controllers/mcp-command-controller.ts +2162 -0
  660. package/src/modes/controllers/omfg-controller.ts +283 -0
  661. package/src/modes/controllers/omfg-rule.ts +647 -0
  662. package/src/modes/controllers/selector-controller.ts +1285 -0
  663. package/src/modes/controllers/session-focus-controller.ts +112 -0
  664. package/src/modes/controllers/ssh-command-controller.ts +384 -0
  665. package/src/modes/controllers/streaming-reveal.ts +295 -0
  666. package/src/modes/controllers/tan-command-controller.ts +190 -0
  667. package/src/modes/controllers/todo-command-controller.ts +485 -0
  668. package/src/modes/controllers/tool-args-reveal.ts +174 -0
  669. package/src/modes/data/emojis.json +1 -0
  670. package/src/modes/emoji-autocomplete.ts +285 -0
  671. package/src/modes/gradient-highlight.ts +99 -0
  672. package/src/modes/image-references.ts +137 -0
  673. package/src/modes/index.ts +17 -0
  674. package/src/modes/interactive-mode.ts +3940 -0
  675. package/src/modes/internal-url-autocomplete.ts +143 -0
  676. package/src/modes/loop-limit.ts +192 -0
  677. package/src/modes/magic-keywords.ts +42 -0
  678. package/src/modes/markdown-prose.ts +247 -0
  679. package/src/modes/oauth-manual-input.ts +69 -0
  680. package/src/modes/orchestrate.ts +42 -0
  681. package/src/modes/print-mode.ts +130 -0
  682. package/src/modes/prompt-action-autocomplete.ts +260 -0
  683. package/src/modes/rpc/host-tools.ts +186 -0
  684. package/src/modes/rpc/host-uris.ts +235 -0
  685. package/src/modes/rpc/rpc-client.ts +995 -0
  686. package/src/modes/rpc/rpc-mode.ts +1156 -0
  687. package/src/modes/rpc/rpc-subagents.ts +265 -0
  688. package/src/modes/rpc/rpc-types.ts +487 -0
  689. package/src/modes/runtime-init.ts +142 -0
  690. package/src/modes/session-observer-registry.ts +215 -0
  691. package/src/modes/setup-version.ts +11 -0
  692. package/src/modes/setup-wizard/index.ts +101 -0
  693. package/src/modes/setup-wizard/lazy.ts +16 -0
  694. package/src/modes/setup-wizard/scenes/glyph.ts +114 -0
  695. package/src/modes/setup-wizard/scenes/outro.ts +35 -0
  696. package/src/modes/setup-wizard/scenes/providers.ts +103 -0
  697. package/src/modes/setup-wizard/scenes/sign-in.ts +286 -0
  698. package/src/modes/setup-wizard/scenes/splash.ts +201 -0
  699. package/src/modes/setup-wizard/scenes/theme.ts +326 -0
  700. package/src/modes/setup-wizard/scenes/types.ts +57 -0
  701. package/src/modes/setup-wizard/scenes/web-search.ts +145 -0
  702. package/src/modes/setup-wizard/startup-splash.ts +107 -0
  703. package/src/modes/setup-wizard/wizard-overlay.ts +334 -0
  704. package/src/modes/shared.ts +49 -0
  705. package/src/modes/theme/dark.json +95 -0
  706. package/src/modes/theme/defaults/alabaster.json +93 -0
  707. package/src/modes/theme/defaults/amethyst.json +96 -0
  708. package/src/modes/theme/defaults/anthracite.json +93 -0
  709. package/src/modes/theme/defaults/basalt.json +91 -0
  710. package/src/modes/theme/defaults/birch.json +95 -0
  711. package/src/modes/theme/defaults/dark-abyss.json +91 -0
  712. package/src/modes/theme/defaults/dark-arctic.json +104 -0
  713. package/src/modes/theme/defaults/dark-aurora.json +95 -0
  714. package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
  715. package/src/modes/theme/defaults/dark-cavern.json +91 -0
  716. package/src/modes/theme/defaults/dark-copper.json +95 -0
  717. package/src/modes/theme/defaults/dark-cosmos.json +90 -0
  718. package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
  719. package/src/modes/theme/defaults/dark-dracula.json +98 -0
  720. package/src/modes/theme/defaults/dark-eclipse.json +91 -0
  721. package/src/modes/theme/defaults/dark-ember.json +95 -0
  722. package/src/modes/theme/defaults/dark-equinox.json +90 -0
  723. package/src/modes/theme/defaults/dark-forest.json +96 -0
  724. package/src/modes/theme/defaults/dark-github.json +105 -0
  725. package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
  726. package/src/modes/theme/defaults/dark-lavender.json +95 -0
  727. package/src/modes/theme/defaults/dark-lunar.json +89 -0
  728. package/src/modes/theme/defaults/dark-midnight.json +95 -0
  729. package/src/modes/theme/defaults/dark-monochrome.json +94 -0
  730. package/src/modes/theme/defaults/dark-monokai.json +98 -0
  731. package/src/modes/theme/defaults/dark-nebula.json +90 -0
  732. package/src/modes/theme/defaults/dark-nord.json +97 -0
  733. package/src/modes/theme/defaults/dark-ocean.json +101 -0
  734. package/src/modes/theme/defaults/dark-one.json +100 -0
  735. package/src/modes/theme/defaults/dark-poimandres.json +142 -0
  736. package/src/modes/theme/defaults/dark-rainforest.json +91 -0
  737. package/src/modes/theme/defaults/dark-reef.json +91 -0
  738. package/src/modes/theme/defaults/dark-retro.json +92 -0
  739. package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
  740. package/src/modes/theme/defaults/dark-sakura.json +95 -0
  741. package/src/modes/theme/defaults/dark-slate.json +95 -0
  742. package/src/modes/theme/defaults/dark-solarized.json +97 -0
  743. package/src/modes/theme/defaults/dark-solstice.json +90 -0
  744. package/src/modes/theme/defaults/dark-starfall.json +91 -0
  745. package/src/modes/theme/defaults/dark-sunset.json +99 -0
  746. package/src/modes/theme/defaults/dark-swamp.json +90 -0
  747. package/src/modes/theme/defaults/dark-synthwave.json +103 -0
  748. package/src/modes/theme/defaults/dark-taiga.json +91 -0
  749. package/src/modes/theme/defaults/dark-terminal.json +95 -0
  750. package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
  751. package/src/modes/theme/defaults/dark-tundra.json +91 -0
  752. package/src/modes/theme/defaults/dark-twilight.json +91 -0
  753. package/src/modes/theme/defaults/dark-volcanic.json +91 -0
  754. package/src/modes/theme/defaults/graphite.json +92 -0
  755. package/src/modes/theme/defaults/index.ts +199 -0
  756. package/src/modes/theme/defaults/light-arctic.json +107 -0
  757. package/src/modes/theme/defaults/light-aurora-day.json +91 -0
  758. package/src/modes/theme/defaults/light-canyon.json +91 -0
  759. package/src/modes/theme/defaults/light-catppuccin.json +106 -0
  760. package/src/modes/theme/defaults/light-cirrus.json +90 -0
  761. package/src/modes/theme/defaults/light-coral.json +95 -0
  762. package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
  763. package/src/modes/theme/defaults/light-dawn.json +90 -0
  764. package/src/modes/theme/defaults/light-dunes.json +91 -0
  765. package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
  766. package/src/modes/theme/defaults/light-forest.json +100 -0
  767. package/src/modes/theme/defaults/light-frost.json +95 -0
  768. package/src/modes/theme/defaults/light-github.json +115 -0
  769. package/src/modes/theme/defaults/light-glacier.json +91 -0
  770. package/src/modes/theme/defaults/light-gruvbox.json +108 -0
  771. package/src/modes/theme/defaults/light-haze.json +90 -0
  772. package/src/modes/theme/defaults/light-honeycomb.json +95 -0
  773. package/src/modes/theme/defaults/light-lagoon.json +91 -0
  774. package/src/modes/theme/defaults/light-lavender.json +95 -0
  775. package/src/modes/theme/defaults/light-meadow.json +91 -0
  776. package/src/modes/theme/defaults/light-mint.json +95 -0
  777. package/src/modes/theme/defaults/light-monochrome.json +101 -0
  778. package/src/modes/theme/defaults/light-ocean.json +99 -0
  779. package/src/modes/theme/defaults/light-one.json +99 -0
  780. package/src/modes/theme/defaults/light-opal.json +91 -0
  781. package/src/modes/theme/defaults/light-orchard.json +91 -0
  782. package/src/modes/theme/defaults/light-paper.json +95 -0
  783. package/src/modes/theme/defaults/light-poimandres.json +142 -0
  784. package/src/modes/theme/defaults/light-prism.json +90 -0
  785. package/src/modes/theme/defaults/light-retro.json +98 -0
  786. package/src/modes/theme/defaults/light-sand.json +95 -0
  787. package/src/modes/theme/defaults/light-savanna.json +91 -0
  788. package/src/modes/theme/defaults/light-solarized.json +102 -0
  789. package/src/modes/theme/defaults/light-soleil.json +90 -0
  790. package/src/modes/theme/defaults/light-sunset.json +99 -0
  791. package/src/modes/theme/defaults/light-synthwave.json +98 -0
  792. package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
  793. package/src/modes/theme/defaults/light-wetland.json +91 -0
  794. package/src/modes/theme/defaults/light-zenith.json +89 -0
  795. package/src/modes/theme/defaults/limestone.json +94 -0
  796. package/src/modes/theme/defaults/mahogany.json +97 -0
  797. package/src/modes/theme/defaults/marble.json +93 -0
  798. package/src/modes/theme/defaults/obsidian.json +91 -0
  799. package/src/modes/theme/defaults/onyx.json +91 -0
  800. package/src/modes/theme/defaults/pearl.json +93 -0
  801. package/src/modes/theme/defaults/porcelain.json +91 -0
  802. package/src/modes/theme/defaults/quartz.json +96 -0
  803. package/src/modes/theme/defaults/sandstone.json +95 -0
  804. package/src/modes/theme/defaults/titanium.json +90 -0
  805. package/src/modes/theme/light.json +93 -0
  806. package/src/modes/theme/mermaid-cache.ts +92 -0
  807. package/src/modes/theme/shimmer.ts +235 -0
  808. package/src/modes/theme/theme-schema.json +459 -0
  809. package/src/modes/theme/theme.ts +2915 -0
  810. package/src/modes/turn-budget.ts +31 -0
  811. package/src/modes/types.ts +406 -0
  812. package/src/modes/ultrathink.ts +41 -0
  813. package/src/modes/utils/context-usage.ts +432 -0
  814. package/src/modes/utils/copy-targets.ts +360 -0
  815. package/src/modes/utils/hotkeys-markdown.ts +62 -0
  816. package/src/modes/utils/keybinding-matchers.ts +51 -0
  817. package/src/modes/utils/tools-markdown.ts +27 -0
  818. package/src/modes/utils/ui-helpers.ts +886 -0
  819. package/src/modes/workflow.ts +42 -0
  820. package/src/plan-mode/approved-plan.ts +186 -0
  821. package/src/plan-mode/plan-handoff.ts +37 -0
  822. package/src/plan-mode/plan-protection.ts +31 -0
  823. package/src/plan-mode/state.ts +6 -0
  824. package/src/priority.json +45 -0
  825. package/src/prompts/advisor/advise-tool.md +3 -0
  826. package/src/prompts/advisor/system.md +113 -0
  827. package/src/prompts/agents/designer.md +74 -0
  828. package/src/prompts/agents/explore.md +58 -0
  829. package/src/prompts/agents/frontmatter.md +11 -0
  830. package/src/prompts/agents/init.md +33 -0
  831. package/src/prompts/agents/librarian.md +119 -0
  832. package/src/prompts/agents/oracle.md +54 -0
  833. package/src/prompts/agents/plan.md +48 -0
  834. package/src/prompts/agents/reviewer.md +139 -0
  835. package/src/prompts/agents/task.md +17 -0
  836. package/src/prompts/bench.md +12 -0
  837. package/src/prompts/ci-green-request.md +36 -0
  838. package/src/prompts/dry-balance-bench.md +8 -0
  839. package/src/prompts/goals/goal-budget-limit.md +16 -0
  840. package/src/prompts/goals/goal-continuation.md +28 -0
  841. package/src/prompts/goals/goal-mode-active.md +23 -0
  842. package/src/prompts/goals/guided-goal-interview.md +8 -0
  843. package/src/prompts/goals/guided-goal-system.md +12 -0
  844. package/src/prompts/low-end/system.md +47 -0
  845. package/src/prompts/memories/consolidation.md +30 -0
  846. package/src/prompts/memories/consolidation_system.md +4 -0
  847. package/src/prompts/memories/read-path.md +17 -0
  848. package/src/prompts/memories/stage_one_input.md +6 -0
  849. package/src/prompts/memories/stage_one_system.md +21 -0
  850. package/src/prompts/review-custom-request.md +22 -0
  851. package/src/prompts/review-headless-request.md +16 -0
  852. package/src/prompts/review-request.md +69 -0
  853. package/src/prompts/steering/user-interjection.md +9 -0
  854. package/src/prompts/system/agent-creation-architect.md +50 -0
  855. package/src/prompts/system/agent-creation-user.md +6 -0
  856. package/src/prompts/system/auto-continue.md +1 -0
  857. package/src/prompts/system/auto-thinking-difficulty-local.md +14 -0
  858. package/src/prompts/system/auto-thinking-difficulty.md +12 -0
  859. package/src/prompts/system/autolearn-guidance-learn.md +1 -0
  860. package/src/prompts/system/autolearn-guidance.md +7 -0
  861. package/src/prompts/system/autolearn-nudge.md +3 -0
  862. package/src/prompts/system/background-tan-dispatch.md +8 -0
  863. package/src/prompts/system/btw-user.md +8 -0
  864. package/src/prompts/system/commit-message-system.md +14 -0
  865. package/src/prompts/system/custom-system-prompt.md +64 -0
  866. package/src/prompts/system/eager-task.md +7 -0
  867. package/src/prompts/system/eager-todo.md +18 -0
  868. package/src/prompts/system/empty-stop-retry.md +4 -0
  869. package/src/prompts/system/irc-autoreply.md +6 -0
  870. package/src/prompts/system/irc-incoming.md +7 -0
  871. package/src/prompts/system/manual-continue.md +7 -0
  872. package/src/prompts/system/memory-consolidation-system.md +8 -0
  873. package/src/prompts/system/memory-extraction-system.md +26 -0
  874. package/src/prompts/system/omfg-user.md +50 -0
  875. package/src/prompts/system/orchestrate-notice.md +40 -0
  876. package/src/prompts/system/personalities/default.md +18 -0
  877. package/src/prompts/system/personalities/friendly.md +17 -0
  878. package/src/prompts/system/personalities/pragmatic.md +15 -0
  879. package/src/prompts/system/plan-mode-active.md +109 -0
  880. package/src/prompts/system/plan-mode-approved.md +25 -0
  881. package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
  882. package/src/prompts/system/plan-mode-reference.md +11 -0
  883. package/src/prompts/system/plan-mode-subagent.md +33 -0
  884. package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
  885. package/src/prompts/system/project-prompt.md +52 -0
  886. package/src/prompts/system/snapcompact-context-frames-note.md +1 -0
  887. package/src/prompts/system/snapcompact-context-stub.md +1 -0
  888. package/src/prompts/system/snapcompact-system-frames-note.md +1 -0
  889. package/src/prompts/system/snapcompact-system-stub.md +1 -0
  890. package/src/prompts/system/snapcompact-toolresult-note.md +1 -0
  891. package/src/prompts/system/subagent-system-prompt.md +71 -0
  892. package/src/prompts/system/subagent-user-prompt.md +3 -0
  893. package/src/prompts/system/subagent-yield-reminder.md +12 -0
  894. package/src/prompts/system/system-prompt.md +251 -0
  895. package/src/prompts/system/tiny-title-system.md +8 -0
  896. package/src/prompts/system/title-marker-instruction.md +1 -0
  897. package/src/prompts/system/title-system-marker.md +16 -0
  898. package/src/prompts/system/title-system.md +16 -0
  899. package/src/prompts/system/ttsr-interrupt.md +7 -0
  900. package/src/prompts/system/ttsr-tool-reminder.md +5 -0
  901. package/src/prompts/system/ultrathink-notice.md +3 -0
  902. package/src/prompts/system/unexpected-stop-classifier.md +17 -0
  903. package/src/prompts/system/unexpected-stop-retry.md +4 -0
  904. package/src/prompts/system/web-search.md +25 -0
  905. package/src/prompts/system/workflow-notice.md +70 -0
  906. package/src/prompts/tools/apply-patch.md +65 -0
  907. package/src/prompts/tools/ask.md +22 -0
  908. package/src/prompts/tools/ast-edit.md +22 -0
  909. package/src/prompts/tools/ast-grep.md +25 -0
  910. package/src/prompts/tools/async-result.md +8 -0
  911. package/src/prompts/tools/bash.md +45 -0
  912. package/src/prompts/tools/browser.md +42 -0
  913. package/src/prompts/tools/checkpoint.md +15 -0
  914. package/src/prompts/tools/debug.md +17 -0
  915. package/src/prompts/tools/eval.md +70 -0
  916. package/src/prompts/tools/find.md +19 -0
  917. package/src/prompts/tools/github.md +17 -0
  918. package/src/prompts/tools/goal.md +11 -0
  919. package/src/prompts/tools/image-attachment-describe-system.md +8 -0
  920. package/src/prompts/tools/image-attachment-describe.md +10 -0
  921. package/src/prompts/tools/image-gen.md +7 -0
  922. package/src/prompts/tools/inspect-image-system.md +20 -0
  923. package/src/prompts/tools/inspect-image.md +22 -0
  924. package/src/prompts/tools/irc.md +33 -0
  925. package/src/prompts/tools/job.md +17 -0
  926. package/src/prompts/tools/learn.md +7 -0
  927. package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
  928. package/src/prompts/tools/lsp.md +39 -0
  929. package/src/prompts/tools/manage-skill.md +9 -0
  930. package/src/prompts/tools/memory-edit.md +8 -0
  931. package/src/prompts/tools/patch.md +57 -0
  932. package/src/prompts/tools/read.md +76 -0
  933. package/src/prompts/tools/recall.md +5 -0
  934. package/src/prompts/tools/reflect.md +5 -0
  935. package/src/prompts/tools/replace.md +29 -0
  936. package/src/prompts/tools/resolve.md +4 -0
  937. package/src/prompts/tools/retain.md +6 -0
  938. package/src/prompts/tools/rewind.md +13 -0
  939. package/src/prompts/tools/search-tool-bm25.md +32 -0
  940. package/src/prompts/tools/search.md +22 -0
  941. package/src/prompts/tools/ssh.md +22 -0
  942. package/src/prompts/tools/task-summary.md +17 -0
  943. package/src/prompts/tools/task.md +91 -0
  944. package/src/prompts/tools/todo.md +39 -0
  945. package/src/prompts/tools/web-search.md +6 -0
  946. package/src/prompts/tools/write.md +14 -0
  947. package/src/registry/agent-lifecycle.ts +270 -0
  948. package/src/registry/agent-registry.ts +190 -0
  949. package/src/sdk.ts +2919 -0
  950. package/src/secrets/index.ts +123 -0
  951. package/src/secrets/obfuscator.ts +298 -0
  952. package/src/secrets/regex.ts +21 -0
  953. package/src/session/agent-session.ts +12539 -0
  954. package/src/session/agent-storage.ts +478 -0
  955. package/src/session/artifacts.ts +153 -0
  956. package/src/session/auth-broker-config.ts +92 -0
  957. package/src/session/auth-storage.ts +24 -0
  958. package/src/session/blob-store.ts +255 -0
  959. package/src/session/client-bridge.ts +85 -0
  960. package/src/session/codex-auto-reset.ts +202 -0
  961. package/src/session/compact-modes.ts +105 -0
  962. package/src/session/history-storage.ts +361 -0
  963. package/src/session/indexed-session-storage.ts +427 -0
  964. package/src/session/messages.ts +546 -0
  965. package/src/session/redis-session-storage.ts +170 -0
  966. package/src/session/session-context.ts +399 -0
  967. package/src/session/session-dump-format.ts +216 -0
  968. package/src/session/session-entries.ts +198 -0
  969. package/src/session/session-history-format.ts +308 -0
  970. package/src/session/session-listing.ts +588 -0
  971. package/src/session/session-loader.ts +93 -0
  972. package/src/session/session-manager.ts +1748 -0
  973. package/src/session/session-migrations.ts +78 -0
  974. package/src/session/session-paths.ts +193 -0
  975. package/src/session/session-persistence.ts +147 -0
  976. package/src/session/session-storage.ts +590 -0
  977. package/src/session/shake-types.ts +43 -0
  978. package/src/session/snapcompact-inline.ts +542 -0
  979. package/src/session/snapcompact-savings-journal.ts +113 -0
  980. package/src/session/sql-session-storage.ts +314 -0
  981. package/src/session/streaming-output.ts +1330 -0
  982. package/src/session/tool-choice-queue.ts +290 -0
  983. package/src/session/unexpected-stop-classifier.ts +129 -0
  984. package/src/session/yield-queue.ts +183 -0
  985. package/src/slash-commands/acp-builtins.ts +70 -0
  986. package/src/slash-commands/available-commands.ts +105 -0
  987. package/src/slash-commands/builtin-registry.ts +2332 -0
  988. package/src/slash-commands/helpers/active-oauth-account.ts +44 -0
  989. package/src/slash-commands/helpers/collab-qrcode.ts +28 -0
  990. package/src/slash-commands/helpers/context-report.ts +66 -0
  991. package/src/slash-commands/helpers/format.ts +46 -0
  992. package/src/slash-commands/helpers/logout.ts +88 -0
  993. package/src/slash-commands/helpers/marketplace-manager.ts +25 -0
  994. package/src/slash-commands/helpers/mcp.ts +532 -0
  995. package/src/slash-commands/helpers/parse.ts +85 -0
  996. package/src/slash-commands/helpers/reset-usage.ts +66 -0
  997. package/src/slash-commands/helpers/ssh.ts +195 -0
  998. package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
  999. package/src/slash-commands/helpers/todo.ts +279 -0
  1000. package/src/slash-commands/helpers/usage-report.ts +128 -0
  1001. package/src/slash-commands/marketplace-install-parser.ts +99 -0
  1002. package/src/slash-commands/types.ts +135 -0
  1003. package/src/ssh/config-writer.ts +183 -0
  1004. package/src/ssh/connection-manager.ts +510 -0
  1005. package/src/ssh/ssh-executor.ts +189 -0
  1006. package/src/ssh/sshfs-mount.ts +140 -0
  1007. package/src/ssh/utils.ts +8 -0
  1008. package/src/startup-splash.ts +19 -0
  1009. package/src/stt/asr-client.ts +521 -0
  1010. package/src/stt/asr-protocol.ts +65 -0
  1011. package/src/stt/asr-worker.ts +790 -0
  1012. package/src/stt/downloader.ts +138 -0
  1013. package/src/stt/endpointer.ts +259 -0
  1014. package/src/stt/index.ts +7 -0
  1015. package/src/stt/models.ts +150 -0
  1016. package/src/stt/recorder.ts +538 -0
  1017. package/src/stt/stt-controller.ts +380 -0
  1018. package/src/stt/transcriber.ts +60 -0
  1019. package/src/stt/wav.ts +173 -0
  1020. package/src/system-prompt.ts +709 -0
  1021. package/src/task/agents.ts +166 -0
  1022. package/src/task/commands.ts +132 -0
  1023. package/src/task/discovery.ts +122 -0
  1024. package/src/task/executor.ts +2356 -0
  1025. package/src/task/index.ts +1580 -0
  1026. package/src/task/name-generator.ts +1577 -0
  1027. package/src/task/omp-command.ts +26 -0
  1028. package/src/task/output-manager.ts +93 -0
  1029. package/src/task/parallel.ts +116 -0
  1030. package/src/task/persisted-revive.ts +128 -0
  1031. package/src/task/render.ts +1558 -0
  1032. package/src/task/repair-args.ts +129 -0
  1033. package/src/task/subprocess-tool-registry.ts +88 -0
  1034. package/src/task/types.ts +401 -0
  1035. package/src/task/worktree.ts +514 -0
  1036. package/src/telemetry-export.ts +144 -0
  1037. package/src/thinking.ts +187 -0
  1038. package/src/tiny/device.ts +111 -0
  1039. package/src/tiny/dtype.ts +101 -0
  1040. package/src/tiny/models.ts +252 -0
  1041. package/src/tiny/text.ts +169 -0
  1042. package/src/tiny/title-client.ts +538 -0
  1043. package/src/tiny/title-protocol.ts +56 -0
  1044. package/src/tiny/worker.ts +491 -0
  1045. package/src/tool-discovery/mode.ts +24 -0
  1046. package/src/tool-discovery/tool-index.ts +271 -0
  1047. package/src/tools/__tests__/json-tree.test.ts +35 -0
  1048. package/src/tools/approval.ts +189 -0
  1049. package/src/tools/ask.ts +977 -0
  1050. package/src/tools/ast-edit.ts +700 -0
  1051. package/src/tools/ast-grep.ts +483 -0
  1052. package/src/tools/auto-generated-guard.ts +322 -0
  1053. package/src/tools/bash-command-fixup.ts +37 -0
  1054. package/src/tools/bash-interactive.ts +408 -0
  1055. package/src/tools/bash-interceptor.ts +67 -0
  1056. package/src/tools/bash-pty-selection.ts +14 -0
  1057. package/src/tools/bash-skill-urls.ts +248 -0
  1058. package/src/tools/bash.ts +1405 -0
  1059. package/src/tools/browser/attach.ts +194 -0
  1060. package/src/tools/browser/cmux/cmux-tab.ts +1264 -0
  1061. package/src/tools/browser/cmux/rpc.ts +156 -0
  1062. package/src/tools/browser/cmux/socket-client.ts +309 -0
  1063. package/src/tools/browser/launch.ts +673 -0
  1064. package/src/tools/browser/readable.ts +112 -0
  1065. package/src/tools/browser/registry.ts +241 -0
  1066. package/src/tools/browser/render.ts +221 -0
  1067. package/src/tools/browser/tab-protocol.ts +107 -0
  1068. package/src/tools/browser/tab-supervisor.ts +799 -0
  1069. package/src/tools/browser/tab-worker-entry.ts +29 -0
  1070. package/src/tools/browser/tab-worker.ts +1226 -0
  1071. package/src/tools/browser.ts +403 -0
  1072. package/src/tools/builtin-names.ts +34 -0
  1073. package/src/tools/checkpoint.ts +136 -0
  1074. package/src/tools/conflict-detect.ts +718 -0
  1075. package/src/tools/context.ts +39 -0
  1076. package/src/tools/debug.ts +1087 -0
  1077. package/src/tools/eval-backends.ts +27 -0
  1078. package/src/tools/eval-render.ts +762 -0
  1079. package/src/tools/eval.ts +600 -0
  1080. package/src/tools/fetch.ts +1902 -0
  1081. package/src/tools/file-recorder.ts +35 -0
  1082. package/src/tools/find.ts +629 -0
  1083. package/src/tools/fs-cache-invalidation.ts +28 -0
  1084. package/src/tools/gh-cache-invalidation.ts +255 -0
  1085. package/src/tools/gh-format.ts +12 -0
  1086. package/src/tools/gh-renderer.ts +481 -0
  1087. package/src/tools/gh.ts +3752 -0
  1088. package/src/tools/github-cache.ts +663 -0
  1089. package/src/tools/grouped-file-output.ts +210 -0
  1090. package/src/tools/image-gen.ts +1586 -0
  1091. package/src/tools/index.ts +649 -0
  1092. package/src/tools/inspect-image-renderer.ts +132 -0
  1093. package/src/tools/inspect-image.ts +260 -0
  1094. package/src/tools/irc.ts +788 -0
  1095. package/src/tools/job.ts +612 -0
  1096. package/src/tools/json-tree.ts +260 -0
  1097. package/src/tools/jtd-to-json-schema.ts +219 -0
  1098. package/src/tools/jtd-to-typescript.ts +136 -0
  1099. package/src/tools/jtd-utils.ts +102 -0
  1100. package/src/tools/learn.ts +141 -0
  1101. package/src/tools/list-limit.ts +40 -0
  1102. package/src/tools/manage-skill.ts +100 -0
  1103. package/src/tools/match-line-format.ts +20 -0
  1104. package/src/tools/memory-edit.ts +59 -0
  1105. package/src/tools/memory-recall.ts +102 -0
  1106. package/src/tools/memory-reflect.ts +88 -0
  1107. package/src/tools/memory-render.ts +202 -0
  1108. package/src/tools/memory-retain.ts +89 -0
  1109. package/src/tools/output-meta.ts +768 -0
  1110. package/src/tools/output-schema-validator.ts +132 -0
  1111. package/src/tools/path-utils.ts +1116 -0
  1112. package/src/tools/plan-mode-guard.ts +142 -0
  1113. package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
  1114. package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
  1115. package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
  1116. package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
  1117. package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
  1118. package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
  1119. package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
  1120. package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
  1121. package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
  1122. package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
  1123. package/src/tools/puppeteer/10_stealth_plugins.txt +208 -0
  1124. package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
  1125. package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
  1126. package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
  1127. package/src/tools/read.ts +3124 -0
  1128. package/src/tools/render-utils.ts +895 -0
  1129. package/src/tools/renderers.ts +86 -0
  1130. package/src/tools/report-tool-issue.ts +530 -0
  1131. package/src/tools/resolve.ts +302 -0
  1132. package/src/tools/review.ts +251 -0
  1133. package/src/tools/search-tool-bm25.ts +351 -0
  1134. package/src/tools/search.ts +1583 -0
  1135. package/src/tools/sqlite-reader.ts +828 -0
  1136. package/src/tools/ssh.ts +369 -0
  1137. package/src/tools/todo.ts +938 -0
  1138. package/src/tools/tool-errors.ts +62 -0
  1139. package/src/tools/tool-result.ts +102 -0
  1140. package/src/tools/tool-timeouts.ts +30 -0
  1141. package/src/tools/tts.ts +265 -0
  1142. package/src/tools/write.ts +1182 -0
  1143. package/src/tools/yield.ts +269 -0
  1144. package/src/tts/downloader.ts +64 -0
  1145. package/src/tts/index.ts +8 -0
  1146. package/src/tts/models.ts +137 -0
  1147. package/src/tts/player.ts +137 -0
  1148. package/src/tts/runtime.ts +21 -0
  1149. package/src/tts/streaming-player.ts +266 -0
  1150. package/src/tts/tts-client.ts +642 -0
  1151. package/src/tts/tts-protocol.ts +60 -0
  1152. package/src/tts/tts-worker.ts +505 -0
  1153. package/src/tts/vocalizer.ts +162 -0
  1154. package/src/tts/wav.ts +58 -0
  1155. package/src/tui/code-cell.ts +257 -0
  1156. package/src/tui/file-list.ts +55 -0
  1157. package/src/tui/hyperlink.ts +178 -0
  1158. package/src/tui/index.ts +13 -0
  1159. package/src/tui/output-block.ts +240 -0
  1160. package/src/tui/status-line.ts +54 -0
  1161. package/src/tui/tree-list.ts +133 -0
  1162. package/src/tui/types.ts +15 -0
  1163. package/src/tui/utils.ts +103 -0
  1164. package/src/tui/width-aware-text.ts +58 -0
  1165. package/src/utils/block-context.ts +312 -0
  1166. package/src/utils/changelog.ts +132 -0
  1167. package/src/utils/clipboard.ts +262 -0
  1168. package/src/utils/command-args.ts +76 -0
  1169. package/src/utils/commit-message-generator.ts +147 -0
  1170. package/src/utils/edit-mode.ts +41 -0
  1171. package/src/utils/enhanced-paste.ts +230 -0
  1172. package/src/utils/event-bus.ts +33 -0
  1173. package/src/utils/external-editor.ts +78 -0
  1174. package/src/utils/file-display-mode.ts +45 -0
  1175. package/src/utils/file-mentions.ts +284 -0
  1176. package/src/utils/git.ts +1838 -0
  1177. package/src/utils/image-loading.ts +231 -0
  1178. package/src/utils/image-resize.ts +309 -0
  1179. package/src/utils/image-vision-fallback.ts +197 -0
  1180. package/src/utils/ipc.ts +38 -0
  1181. package/src/utils/jj.ts +248 -0
  1182. package/src/utils/lang-from-path.ts +244 -0
  1183. package/src/utils/markit.ts +143 -0
  1184. package/src/utils/mupdf-wasm-embed.ts +12 -0
  1185. package/src/utils/open.ts +55 -0
  1186. package/src/utils/qrcode.ts +535 -0
  1187. package/src/utils/session-color.ts +142 -0
  1188. package/src/utils/shell-snapshot.ts +187 -0
  1189. package/src/utils/sixel.ts +69 -0
  1190. package/src/utils/thinking-display.ts +11 -0
  1191. package/src/utils/title-generator.ts +416 -0
  1192. package/src/utils/tool-choice.ts +49 -0
  1193. package/src/utils/tools-manager.ts +372 -0
  1194. package/src/utils/turndown.ts +83 -0
  1195. package/src/utils/zip.ts +1091 -0
  1196. package/src/web/kagi.ts +304 -0
  1197. package/src/web/parallel.ts +353 -0
  1198. package/src/web/scrapers/artifacthub.ts +207 -0
  1199. package/src/web/scrapers/arxiv.ts +83 -0
  1200. package/src/web/scrapers/aur.ts +162 -0
  1201. package/src/web/scrapers/biorxiv.ts +133 -0
  1202. package/src/web/scrapers/bluesky.ts +262 -0
  1203. package/src/web/scrapers/brew.ts +172 -0
  1204. package/src/web/scrapers/cheatsh.ts +68 -0
  1205. package/src/web/scrapers/chocolatey.ts +196 -0
  1206. package/src/web/scrapers/choosealicense.ts +95 -0
  1207. package/src/web/scrapers/cisa-kev.ts +87 -0
  1208. package/src/web/scrapers/clojars.ts +154 -0
  1209. package/src/web/scrapers/coingecko.ts +177 -0
  1210. package/src/web/scrapers/crates-io.ts +97 -0
  1211. package/src/web/scrapers/crossref.ts +136 -0
  1212. package/src/web/scrapers/devto.ts +147 -0
  1213. package/src/web/scrapers/discogs.ts +306 -0
  1214. package/src/web/scrapers/discourse.ts +197 -0
  1215. package/src/web/scrapers/dockerhub.ts +138 -0
  1216. package/src/web/scrapers/docs-rs.ts +652 -0
  1217. package/src/web/scrapers/fdroid.ts +134 -0
  1218. package/src/web/scrapers/firefox-addons.ts +191 -0
  1219. package/src/web/scrapers/flathub.ts +223 -0
  1220. package/src/web/scrapers/github-gist.ts +58 -0
  1221. package/src/web/scrapers/github.ts +800 -0
  1222. package/src/web/scrapers/gitlab.ts +401 -0
  1223. package/src/web/scrapers/go-pkg.ts +266 -0
  1224. package/src/web/scrapers/hackage.ts +140 -0
  1225. package/src/web/scrapers/hackernews.ts +189 -0
  1226. package/src/web/scrapers/hex.ts +105 -0
  1227. package/src/web/scrapers/huggingface.ts +321 -0
  1228. package/src/web/scrapers/iacr.ts +89 -0
  1229. package/src/web/scrapers/index.ts +252 -0
  1230. package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
  1231. package/src/web/scrapers/lemmy.ts +203 -0
  1232. package/src/web/scrapers/lobsters.ts +175 -0
  1233. package/src/web/scrapers/mastodon.ts +292 -0
  1234. package/src/web/scrapers/maven.ts +138 -0
  1235. package/src/web/scrapers/mdn.ts +173 -0
  1236. package/src/web/scrapers/metacpan.ts +222 -0
  1237. package/src/web/scrapers/musicbrainz.ts +250 -0
  1238. package/src/web/scrapers/npm.ts +98 -0
  1239. package/src/web/scrapers/nuget.ts +183 -0
  1240. package/src/web/scrapers/nvd.ts +222 -0
  1241. package/src/web/scrapers/ollama.ts +239 -0
  1242. package/src/web/scrapers/open-vsx.ts +106 -0
  1243. package/src/web/scrapers/opencorporates.ts +292 -0
  1244. package/src/web/scrapers/openlibrary.ts +336 -0
  1245. package/src/web/scrapers/orcid.ts +286 -0
  1246. package/src/web/scrapers/osv.ts +176 -0
  1247. package/src/web/scrapers/packagist.ts +160 -0
  1248. package/src/web/scrapers/pub-dev.ts +143 -0
  1249. package/src/web/scrapers/pubmed.ts +211 -0
  1250. package/src/web/scrapers/pypi.ts +112 -0
  1251. package/src/web/scrapers/rawg.ts +110 -0
  1252. package/src/web/scrapers/readthedocs.ts +120 -0
  1253. package/src/web/scrapers/reddit.ts +95 -0
  1254. package/src/web/scrapers/repology.ts +251 -0
  1255. package/src/web/scrapers/rfc.ts +201 -0
  1256. package/src/web/scrapers/rubygems.ts +103 -0
  1257. package/src/web/scrapers/searchcode.ts +189 -0
  1258. package/src/web/scrapers/sec-edgar.ts +261 -0
  1259. package/src/web/scrapers/semantic-scholar.ts +171 -0
  1260. package/src/web/scrapers/snapcraft.ts +187 -0
  1261. package/src/web/scrapers/sourcegraph.ts +336 -0
  1262. package/src/web/scrapers/spdx.ts +108 -0
  1263. package/src/web/scrapers/spotify.ts +198 -0
  1264. package/src/web/scrapers/stackoverflow.ts +120 -0
  1265. package/src/web/scrapers/terraform.ts +277 -0
  1266. package/src/web/scrapers/tldr.ts +47 -0
  1267. package/src/web/scrapers/twitter.ts +94 -0
  1268. package/src/web/scrapers/types.ts +354 -0
  1269. package/src/web/scrapers/utils.ts +109 -0
  1270. package/src/web/scrapers/vimeo.ts +133 -0
  1271. package/src/web/scrapers/vscode-marketplace.ts +187 -0
  1272. package/src/web/scrapers/w3c.ts +156 -0
  1273. package/src/web/scrapers/wikidata.ts +344 -0
  1274. package/src/web/scrapers/wikipedia.ts +84 -0
  1275. package/src/web/scrapers/youtube.ts +325 -0
  1276. package/src/web/search/index.ts +317 -0
  1277. package/src/web/search/provider.ts +169 -0
  1278. package/src/web/search/providers/anthropic.ts +343 -0
  1279. package/src/web/search/providers/base.ts +90 -0
  1280. package/src/web/search/providers/brave.ts +152 -0
  1281. package/src/web/search/providers/codex.ts +593 -0
  1282. package/src/web/search/providers/exa.ts +400 -0
  1283. package/src/web/search/providers/gemini.ts +518 -0
  1284. package/src/web/search/providers/jina.ts +111 -0
  1285. package/src/web/search/providers/kagi.ts +86 -0
  1286. package/src/web/search/providers/kimi.ts +196 -0
  1287. package/src/web/search/providers/parallel.ts +225 -0
  1288. package/src/web/search/providers/perplexity-auth.ts +133 -0
  1289. package/src/web/search/providers/perplexity.ts +866 -0
  1290. package/src/web/search/providers/searxng.ts +325 -0
  1291. package/src/web/search/providers/synthetic.ts +114 -0
  1292. package/src/web/search/providers/tavily.ts +176 -0
  1293. package/src/web/search/providers/utils.ts +128 -0
  1294. package/src/web/search/providers/zai.ts +333 -0
  1295. package/src/web/search/render.ts +262 -0
  1296. package/src/web/search/types.ts +462 -0
  1297. package/src/web/search/utils.ts +17 -0
  1298. package/src/workspace-tree.ts +326 -0
@@ -0,0 +1,1182 @@
1
+ import { Database } from "bun:sqlite";
2
+ import * as fs from "node:fs/promises";
3
+ import * as path from "node:path";
4
+
5
+ import { formatHashlineHeader, stripHashlinePrefixes } from "@oh-my-pi/hashline";
6
+ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
7
+ import type { Component } from "@oh-my-pi/pi-tui";
8
+ import { isEnoent, isRecord, prompt, untilAborted } from "@oh-my-pi/pi-utils";
9
+ import { type } from "arktype";
10
+
11
+ import { canonicalSnapshotKey, getFileSnapshotStore } from "../edit/file-snapshot-store";
12
+ import { normalizeToLF } from "../edit/normalize";
13
+ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
14
+ import { InternalUrlRouter } from "../internal-urls";
15
+ import { parseInternalUrl } from "../internal-urls/parse";
16
+ import { createLspWritethrough, type FileDiagnosticsResult, type WritethroughCallback, writethroughNoop } from "../lsp";
17
+ import { getDiagnosticsLedger } from "../lsp/diagnostics-ledger";
18
+ import { getLanguageFromPath, highlightCode, type Theme } from "../modes/theme/theme";
19
+ import writeDescription from "../prompts/tools/write.md" with { type: "text" };
20
+ import type { ToolSession } from "../sdk";
21
+ import { fileHyperlink, framedBlock, renderStatusLine } from "../tui";
22
+ import { resolveFileDisplayMode } from "../utils/file-display-mode";
23
+ import {
24
+ type ArchiveMemberContent,
25
+ archiveFormatFromPath,
26
+ parseArchivePathCandidates,
27
+ readArchiveEntries,
28
+ writeArchive,
29
+ } from "../utils/zip";
30
+ import { truncateForPrompt } from "./approval";
31
+ import { assertEditableFile } from "./auto-generated-guard";
32
+ import {
33
+ type ConflictEntry,
34
+ conflictRegionPresent,
35
+ conflictRegionsEqual,
36
+ expandContentTokens,
37
+ getConflictHistory,
38
+ parseConflictUri,
39
+ spliceConflict,
40
+ } from "./conflict-detect";
41
+ import { invalidateFsScanAfterWrite } from "./fs-cache-invalidation";
42
+ import { type OutputMeta, outputMeta } from "./output-meta";
43
+ import { formatPathRelativeToCwd, isInternalUrlPath } from "./path-utils";
44
+ import { enforcePlanModeWrite, resolvePlanPath, unwrapHashlineHeaderPath } from "./plan-mode-guard";
45
+ import {
46
+ cachedRenderedString,
47
+ createRenderedStringCache,
48
+ formatDiagnostics,
49
+ formatErrorDetail,
50
+ formatExpandHint,
51
+ formatMoreItems,
52
+ formatStatusIcon,
53
+ getLspBatchRequest,
54
+ type RenderedStringCache,
55
+ replaceTabs,
56
+ shortenPath,
57
+ } from "./render-utils";
58
+ import {
59
+ deleteRowByKey,
60
+ deleteRowByRowId,
61
+ insertRow,
62
+ isSqliteFile,
63
+ parseSqlitePathCandidates,
64
+ resolveTableRowLookup,
65
+ updateRowByKey,
66
+ updateRowByRowId,
67
+ } from "./sqlite-reader";
68
+ import { ToolError } from "./tool-errors";
69
+ import { toolResult } from "./tool-result";
70
+
71
+ const LOOSE_HASHLINE_HEADER_RE = /^\s*\[[^#\r\n]+#[^ \t\r\n]*\]\s*$/;
72
+ const EXECUTABLE_NOTICE = "[Notice: Made executable via chmod +x]";
73
+
74
+ const writeSchema = type({
75
+ path: type("string").describe("file path"),
76
+ content: type("string").describe("file content"),
77
+ });
78
+
79
+ export type WriteToolInput = typeof writeSchema.infer;
80
+
81
+ /** Details returned by the write tool for TUI rendering */
82
+ export interface WriteToolDetails {
83
+ diagnostics?: FileDiagnosticsResult;
84
+ meta?: OutputMeta;
85
+ /** Set when the file was auto-chmod'd because content begins with a `#!` shebang. */
86
+ madeExecutable?: boolean;
87
+ /** Absolute filesystem path the write resolved to. Used by the renderer to wrap
88
+ * the (possibly cwd-relative) header path in an OSC 8 `file://` hyperlink. */
89
+ resolvedPath?: string;
90
+ }
91
+
92
+ /**
93
+ * Strip hashline display prefixes from write content.
94
+ *
95
+ * Includes a fallback for loosely-formed section headers that still carry
96
+ * line-number prefixes (for example legacy or malformed hashline echoes).
97
+ */
98
+ function stripWriteContentWithPotentialLooseHeader(lines: string[]): { text: string; stripped: boolean } {
99
+ const cleaned = stripHashlinePrefixes(lines);
100
+ if (cleaned !== lines) {
101
+ return { text: cleaned.join("\n"), stripped: true };
102
+ }
103
+
104
+ const headerIndex = lines.findIndex(line => line.trim().length > 0);
105
+ if (headerIndex === -1 || !LOOSE_HASHLINE_HEADER_RE.test(lines[headerIndex])) {
106
+ return { text: lines.join("\n"), stripped: false };
107
+ }
108
+
109
+ const linesWithoutHeader = lines.slice(0, headerIndex).concat(lines.slice(headerIndex + 1));
110
+ const cleanedWithoutHeader = stripHashlinePrefixes(linesWithoutHeader);
111
+ if (cleanedWithoutHeader === linesWithoutHeader) {
112
+ return { text: lines.join("\n"), stripped: false };
113
+ }
114
+ return { text: cleanedWithoutHeader.join("\n"), stripped: true };
115
+ }
116
+
117
+ /**
118
+ * Strip hashline display prefixes from write content.
119
+ *
120
+ * Only active when hashline edit mode is enabled — the model sees `[PATH#HASH]`
121
+ * headers plus `LINE:` prefixes in read output and sometimes copies them into write content.
122
+ */
123
+ function stripWriteContent(session: ToolSession, content: string): { text: string; stripped: boolean } {
124
+ if (!resolveFileDisplayMode(session).hashLines) {
125
+ return { text: content, stripped: false };
126
+ }
127
+ return stripWriteContentWithPotentialLooseHeader(content.split("\n"));
128
+ }
129
+
130
+ /**
131
+ * Record a snapshot of the freshly-written `content` for `absolutePath`
132
+ * so subsequent hashline edits address the new file with a current tag,
133
+ * and return the matching `[displayPath#TAG]` header. Returns `undefined`
134
+ * when the session is not in hashline mode so callers can no-op cheaply.
135
+ *
136
+ * Mirrors the post-commit snapshot recording the hashline patcher performs
137
+ * after a successful edit: the model gets a tag without an extra `read`.
138
+ */
139
+ function maybeWriteSnapshotHeader(session: ToolSession, absolutePath: string, content: string): string | undefined {
140
+ if (!resolveFileDisplayMode(session).hashLines) return undefined;
141
+ const normalized = normalizeToLF(content);
142
+ const tag = getFileSnapshotStore(session).record(canonicalSnapshotKey(absolutePath), normalized);
143
+ return formatHashlineHeader(formatPathRelativeToCwd(absolutePath, session.cwd), tag);
144
+ }
145
+
146
+ function shouldRouteWriteThroughBridge(session: ToolSession, requestedPath: string, absolutePath: string): boolean {
147
+ if (isInternalUrlPath(requestedPath)) return false;
148
+
149
+ const state = session.getPlanModeState?.();
150
+ if (!state?.enabled || !isInternalUrlPath(state.planFilePath)) return true;
151
+
152
+ return absolutePath !== resolvePlanPath(session, state.planFilePath);
153
+ }
154
+
155
+ /**
156
+ * Append a trailing note line to the first text block of a tool result.
157
+ * Mutates `result` in place (the result object is owned by this call).
158
+ */
159
+ function appendNoteToResult(result: AgentToolResult<WriteToolDetails>, note: string): void {
160
+ const firstText = result.content.find(
161
+ (block): block is { type: "text"; text: string } => block.type === "text" && typeof block.text === "string",
162
+ );
163
+ if (firstText) {
164
+ firstText.text = firstText.text.length > 0 ? `${firstText.text}\n${note}` : note;
165
+ } else {
166
+ result.content.push({ type: "text", text: note });
167
+ }
168
+ }
169
+
170
+ /**
171
+ * If `content` begins with a `#!` shebang, ensure the file is executable.
172
+ *
173
+ * Mirrors `chmod a+x` (adds user/group/other execute bits to existing mode).
174
+ * Errors are swallowed: chmod failure (e.g. Windows ACL, read-only mount)
175
+ * MUST NOT fail an otherwise successful write. Returns whether the mode
176
+ * actually changed so the caller can surface a note.
177
+ */
178
+ async function maybeMarkExecutableForShebang(absolutePath: string, content: string): Promise<boolean> {
179
+ if (!content.startsWith("#!")) return false;
180
+ try {
181
+ const stat = await fs.stat(absolutePath);
182
+ const currentMode = stat.mode & 0o7777;
183
+ const newMode = currentMode | 0o111;
184
+ if (newMode === currentMode) return false;
185
+ await fs.chmod(absolutePath, newMode);
186
+ return true;
187
+ } catch {
188
+ return false;
189
+ }
190
+ }
191
+
192
+ // ═══════════════════════════════════════════════════════════════════════════
193
+ // Tool Class
194
+ // ═══════════════════════════════════════════════════════════════════════════
195
+
196
+ type WriteParams = WriteToolInput;
197
+
198
+ interface ResolvedArchiveWritePath {
199
+ absolutePath: string;
200
+ archivePath: string;
201
+ archiveSubPath: string;
202
+ exists: boolean;
203
+ }
204
+
205
+ interface ResolvedSqliteWritePath {
206
+ absolutePath: string;
207
+ sqlitePath: string;
208
+ table: string;
209
+ key?: string;
210
+ exists: boolean;
211
+ }
212
+
213
+ function isArchivePathNotFound(error: unknown): boolean {
214
+ if (isEnoent(error)) return true;
215
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOTDIR";
216
+ }
217
+
218
+ function normalizeArchiveWriteSubPath(rawPath: string): string {
219
+ const normalized = rawPath.replace(/\\/g, "/");
220
+ if (normalized.length === 0) {
221
+ throw new ToolError("Archive write path must target a file inside the archive");
222
+ }
223
+ if (normalized.endsWith("/")) {
224
+ throw new ToolError("Archive write path must target a file, not a directory");
225
+ }
226
+
227
+ const parts = normalized.split("/");
228
+ const normalizedParts: string[] = [];
229
+ for (const part of parts) {
230
+ if (!part || part === ".") continue;
231
+ if (part === "..") {
232
+ throw new ToolError("Archive path cannot contain '..'");
233
+ }
234
+ normalizedParts.push(part);
235
+ }
236
+
237
+ if (normalizedParts.length === 0) {
238
+ throw new ToolError("Archive write path must target a file inside the archive");
239
+ }
240
+
241
+ return normalizedParts.join("/");
242
+ }
243
+
244
+ function parseSqliteWriteTarget(subPath: string, queryString: string): { table: string; key?: string } {
245
+ if (queryString.trim().length > 0) {
246
+ throw new ToolError("SQLite write paths do not support query parameters");
247
+ }
248
+
249
+ const normalized = subPath.replace(/^:+/, "").trim();
250
+ if (!normalized) {
251
+ throw new ToolError("SQLite write path must target a table");
252
+ }
253
+
254
+ const separatorIndex = normalized.indexOf(":");
255
+ const table = separatorIndex === -1 ? normalized : normalized.slice(0, separatorIndex);
256
+ const key = separatorIndex === -1 ? undefined : normalized.slice(separatorIndex + 1);
257
+ if (!table) {
258
+ throw new ToolError("SQLite write path must target a table");
259
+ }
260
+ if (key !== undefined && key.length === 0) {
261
+ throw new ToolError("SQLite row writes require a non-empty row key");
262
+ }
263
+
264
+ return { table, key };
265
+ }
266
+
267
+ /**
268
+ * Write tool implementation.
269
+ *
270
+ * Creates or overwrites files with optional LSP formatting and diagnostics.
271
+ */
272
+ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails> {
273
+ readonly name = "write";
274
+ readonly approval = (args: unknown) => {
275
+ const rawPath = (args as Partial<WriteParams>).path;
276
+ if (typeof rawPath !== "string" || !isInternalUrlPath(rawPath)) return "write";
277
+ // Internal URLs are usually session-local artifacts (read tier), but a
278
+ // scheme whose handler exposes a `write` hook mutates handler-owned
279
+ // user data (e.g. vault:// notes, host-owned mcp:// URIs) and must take
280
+ // the write tier so always-ask mode actually prompts.
281
+ const match = /^([a-z][a-z0-9+.-]*):\/\//i.exec(rawPath.trim());
282
+ const handler = match ? InternalUrlRouter.instance().getHandler(match[1]!.toLowerCase()) : undefined;
283
+ return handler?.write ? "write" : "read";
284
+ };
285
+ readonly formatApprovalDetails = (args: unknown): string[] => {
286
+ const params = args as Partial<WriteParams>;
287
+ const targetPath = typeof params.path === "string" ? params.path : "(missing)";
288
+ const content = typeof params.content === "string" ? params.content : "";
289
+ return [`Path: ${truncateForPrompt(targetPath)}`, `Content:\n${truncateForPrompt(content)}`];
290
+ };
291
+ readonly label = "Write";
292
+ readonly description: string;
293
+ readonly parameters = writeSchema;
294
+ readonly strict = true;
295
+ readonly concurrency = "exclusive";
296
+ readonly loadMode = "discoverable";
297
+ readonly summary = "Write content to a file (creates or overwrites)";
298
+
299
+ /** Stream matchers should see the real file content, not its JSON-escaped argument encoding. */
300
+ matcherDigest(args: unknown): string | undefined {
301
+ const content = (args as Partial<WriteParams>).content;
302
+ return typeof content === "string" ? content : undefined;
303
+ }
304
+
305
+ readonly #writethrough: WritethroughCallback;
306
+
307
+ constructor(private readonly session: ToolSession) {
308
+ const enableLsp = session.enableLsp ?? true;
309
+ const enableFormat = enableLsp && session.settings.get("lsp.formatOnWrite");
310
+ const enableDiagnostics = enableLsp && session.settings.get("lsp.diagnosticsOnWrite");
311
+ const dedup = enableDiagnostics && session.settings.get("lsp.diagnosticsDeduplicate");
312
+ this.#writethrough = enableLsp
313
+ ? createLspWritethrough(session.cwd, {
314
+ enableFormat,
315
+ enableDiagnostics,
316
+ transformDiagnostics: dedup
317
+ ? (path, result) => getDiagnosticsLedger(session).reduce(path, result)
318
+ : undefined,
319
+ })
320
+ : writethroughNoop;
321
+ this.description = prompt.render(writeDescription);
322
+ }
323
+
324
+ async #resolveArchiveWritePath(writePath: string): Promise<ResolvedArchiveWritePath | null> {
325
+ const candidates = parseArchivePathCandidates(writePath).filter(candidate => candidate.archivePath !== writePath);
326
+ if (candidates.length === 0) {
327
+ return null;
328
+ }
329
+
330
+ const fallbackCandidate = candidates[candidates.length - 1]!;
331
+ const fallback: ResolvedArchiveWritePath = {
332
+ absolutePath: resolvePlanPath(this.session, fallbackCandidate.archivePath),
333
+ archivePath: fallbackCandidate.archivePath,
334
+ archiveSubPath: normalizeArchiveWriteSubPath(fallbackCandidate.subPath),
335
+ exists: false,
336
+ };
337
+
338
+ for (const candidate of candidates) {
339
+ const absolutePath = resolvePlanPath(this.session, candidate.archivePath);
340
+ try {
341
+ const stat = await Bun.file(absolutePath).stat();
342
+ if (stat.isDirectory()) {
343
+ continue;
344
+ }
345
+
346
+ return {
347
+ absolutePath,
348
+ archivePath: candidate.archivePath,
349
+ archiveSubPath: normalizeArchiveWriteSubPath(candidate.subPath),
350
+ exists: true,
351
+ };
352
+ } catch (error) {
353
+ if (!isArchivePathNotFound(error)) {
354
+ throw error;
355
+ }
356
+ }
357
+ }
358
+
359
+ return fallback;
360
+ }
361
+
362
+ async #writeArchiveEntry(
363
+ content: string,
364
+ resolvedArchivePath: ResolvedArchiveWritePath,
365
+ ): Promise<AgentToolResult<WriteToolDetails>> {
366
+ // Resolve symlinks before the tmp+rename swap: renaming over a symlink
367
+ // replaces the link itself with a regular file instead of writing
368
+ // through to its target.
369
+ const finalPath = resolvedArchivePath.exists
370
+ ? await fs.realpath(resolvedArchivePath.absolutePath).catch(() => resolvedArchivePath.absolutePath)
371
+ : resolvedArchivePath.absolutePath;
372
+ // A realpath swap can land on a name without an archive extension; a
373
+ // whole-archive rewrite then defaults to an uncompressed tar, matching the
374
+ // previous `isZip`/`isGzip`/else fallthrough.
375
+ const format = archiveFormatFromPath(finalPath) ?? "tar";
376
+ // Rewrites are whole-archive: write to a temp file and rename so a
377
+ // crash/disk-full mid-write can't destroy the original archive.
378
+ const tmpPath = `${finalPath}.tmp-${process.pid}`;
379
+
380
+ const parentDir = path.dirname(resolvedArchivePath.absolutePath);
381
+ if (parentDir && parentDir !== ".") {
382
+ await fs.mkdir(parentDir, { recursive: true });
383
+ }
384
+
385
+ const entries = new Map<string, ArchiveMemberContent>();
386
+ if (resolvedArchivePath.exists) {
387
+ try {
388
+ const existing = await readArchiveEntries({ bytes: await Bun.file(finalPath).bytes(), format });
389
+ for (const [entryPath, data] of existing) {
390
+ entries.set(entryPath, data);
391
+ }
392
+ } catch (error) {
393
+ throw new ToolError(error instanceof Error ? error.message : String(error));
394
+ }
395
+ }
396
+ entries.set(resolvedArchivePath.archiveSubPath, content);
397
+
398
+ try {
399
+ await writeArchive(tmpPath, format, entries);
400
+ await fs.rename(tmpPath, finalPath);
401
+ } catch (error) {
402
+ await fs.rm(tmpPath, { force: true }).catch(() => {});
403
+ throw new ToolError(error instanceof Error ? error.message : String(error));
404
+ }
405
+
406
+ invalidateFsScanAfterWrite(resolvedArchivePath.absolutePath);
407
+ const outputPath = `${formatPathRelativeToCwd(resolvedArchivePath.absolutePath, this.session.cwd)}:${
408
+ resolvedArchivePath.archiveSubPath
409
+ }`;
410
+ return {
411
+ content: [{ type: "text", text: `Successfully wrote ${content.length} bytes to ${outputPath}` }],
412
+ details: { resolvedPath: resolvedArchivePath.absolutePath },
413
+ };
414
+ }
415
+
416
+ async #resolveSqliteWritePath(writePath: string): Promise<ResolvedSqliteWritePath | null> {
417
+ const candidates = parseSqlitePathCandidates(writePath).filter(candidate => candidate.sqlitePath !== writePath);
418
+ if (candidates.length === 0) {
419
+ return null;
420
+ }
421
+
422
+ const fallbackCandidate = candidates[candidates.length - 1]!;
423
+ const fallbackTarget = parseSqliteWriteTarget(fallbackCandidate.subPath, fallbackCandidate.queryString);
424
+ const fallback: ResolvedSqliteWritePath = {
425
+ absolutePath: resolvePlanPath(this.session, fallbackCandidate.sqlitePath),
426
+ sqlitePath: fallbackCandidate.sqlitePath,
427
+ table: fallbackTarget.table,
428
+ key: fallbackTarget.key,
429
+ exists: false,
430
+ };
431
+
432
+ let sawExistingNonSqlite = false;
433
+ for (const candidate of candidates) {
434
+ const target = parseSqliteWriteTarget(candidate.subPath, candidate.queryString);
435
+ const absolutePath = resolvePlanPath(this.session, candidate.sqlitePath);
436
+ try {
437
+ const stat = await Bun.file(absolutePath).stat();
438
+ if (stat.isDirectory()) {
439
+ continue;
440
+ }
441
+ if (!(await isSqliteFile(absolutePath))) {
442
+ sawExistingNonSqlite = true;
443
+ continue;
444
+ }
445
+
446
+ return {
447
+ absolutePath,
448
+ sqlitePath: candidate.sqlitePath,
449
+ table: target.table,
450
+ key: target.key,
451
+ exists: true,
452
+ };
453
+ } catch (error) {
454
+ if (!isArchivePathNotFound(error)) {
455
+ throw error;
456
+ }
457
+ }
458
+ }
459
+
460
+ if (sawExistingNonSqlite) {
461
+ return null;
462
+ }
463
+
464
+ return fallback;
465
+ }
466
+
467
+ async #writeSqliteRow(
468
+ displayPath: string,
469
+ content: string,
470
+ resolvedSqlitePath: ResolvedSqliteWritePath,
471
+ ): Promise<AgentToolResult<WriteToolDetails>> {
472
+ let db: Database | null = null;
473
+ try {
474
+ if (!resolvedSqlitePath.exists) {
475
+ throw new ToolError(`SQLite database '${displayPath}' not found`);
476
+ }
477
+
478
+ db = new Database(resolvedSqlitePath.absolutePath, { create: false, strict: true });
479
+ db.run("PRAGMA busy_timeout = 3000");
480
+
481
+ const trimmedContent = content.trim();
482
+ let resultText: string;
483
+ if (trimmedContent.length === 0) {
484
+ if (!resolvedSqlitePath.key) {
485
+ throw new ToolError("SQLite deletes require a row key in the path");
486
+ }
487
+
488
+ const lookup = resolveTableRowLookup(db, resolvedSqlitePath.table);
489
+ const deleted =
490
+ lookup.kind === "pk"
491
+ ? deleteRowByKey(db, resolvedSqlitePath.table, lookup, resolvedSqlitePath.key)
492
+ : deleteRowByRowId(db, resolvedSqlitePath.table, resolvedSqlitePath.key);
493
+ resultText =
494
+ deleted > 0
495
+ ? `Deleted row '${resolvedSqlitePath.key}' from ${resolvedSqlitePath.table}`
496
+ : `No row deleted from ${resolvedSqlitePath.table} for key '${resolvedSqlitePath.key}'`;
497
+ } else {
498
+ let parsedContent: unknown;
499
+ try {
500
+ parsedContent = Bun.JSON5.parse(content);
501
+ } catch (error) {
502
+ throw new ToolError(
503
+ `SQLite write content must be valid JSON5: ${error instanceof Error ? error.message : String(error)}`,
504
+ );
505
+ }
506
+
507
+ if (!isRecord(parsedContent)) {
508
+ throw new ToolError("SQLite write content must be a JSON object");
509
+ }
510
+
511
+ if (resolvedSqlitePath.key) {
512
+ const lookup = resolveTableRowLookup(db, resolvedSqlitePath.table);
513
+ const updated =
514
+ lookup.kind === "pk"
515
+ ? updateRowByKey(db, resolvedSqlitePath.table, lookup, resolvedSqlitePath.key, parsedContent)
516
+ : updateRowByRowId(db, resolvedSqlitePath.table, resolvedSqlitePath.key, parsedContent);
517
+ resultText =
518
+ updated > 0
519
+ ? `Updated row '${resolvedSqlitePath.key}' in ${resolvedSqlitePath.table}`
520
+ : `No row updated in ${resolvedSqlitePath.table} for key '${resolvedSqlitePath.key}'`;
521
+ } else {
522
+ insertRow(db, resolvedSqlitePath.table, parsedContent);
523
+ resultText = `Inserted row into ${resolvedSqlitePath.table}`;
524
+ }
525
+ }
526
+
527
+ invalidateFsScanAfterWrite(resolvedSqlitePath.absolutePath);
528
+ return toolResult<WriteToolDetails>({ resolvedPath: resolvedSqlitePath.absolutePath })
529
+ .text(resultText)
530
+ .sourcePath(resolvedSqlitePath.absolutePath)
531
+ .done();
532
+ } catch (error) {
533
+ if (isEnoent(error)) {
534
+ throw new ToolError(`SQLite database '${displayPath}' not found`);
535
+ }
536
+ if (error instanceof ToolError) {
537
+ throw error;
538
+ }
539
+ throw new ToolError(error instanceof Error ? error.message : String(error));
540
+ } finally {
541
+ db?.close();
542
+ }
543
+ }
544
+
545
+ /**
546
+ * Resolve a single `conflict://<N>` write by splicing the recorded
547
+ * marker region in the registered file with `replacementContent`.
548
+ * The write deliberately bypasses the LSP writethrough: the file may
549
+ * still hold other unresolved marker blocks, so formatting could
550
+ * corrupt them and diagnostics would be marker-noise anyway.
551
+ *
552
+ * Entry ids are session-stable: they keep working even after later
553
+ * writes resolve other blocks in the same file. The recorded range
554
+ * is re-validated on disk before splicing so an out-of-band edit
555
+ * surfaces as a clear error instead of corrupting the file.
556
+ */
557
+ async #resolveConflict(
558
+ entry: ConflictEntry,
559
+ replacementContent: string,
560
+ stripped: boolean,
561
+ signal: AbortSignal | undefined,
562
+ ): Promise<AgentToolResult<WriteToolDetails>> {
563
+ const absolutePath = entry.absolutePath;
564
+ if (!(await fs.exists(absolutePath))) {
565
+ throw new ToolError(`Conflict #${entry.id} target '${entry.displayPath}' no longer exists.`);
566
+ }
567
+
568
+ const expanded = expandContentTokens(replacementContent, entry);
569
+ const originalText = await Bun.file(absolutePath).text();
570
+ const newContent = spliceConflict(originalText, entry, expanded);
571
+
572
+ await writethroughNoop(absolutePath, newContent, signal);
573
+ invalidateFsScanAfterWrite(absolutePath);
574
+ this.session.bumpFileMutationVersion?.(absolutePath);
575
+ this.session.fileSnapshotStore?.invalidate(absolutePath);
576
+ const history = this.session.conflictHistory;
577
+ history?.invalidate(entry.id);
578
+ if (history) {
579
+ // Drop stale duplicate registrations of the same region: a re-read
580
+ // after an out-of-band shift registers a fresh id at the new
581
+ // startLine while the stale twin persists at the old one. A DISTINCT
582
+ // conflict block that is merely byte-identical still occurs in the
583
+ // post-splice content and must stay addressable.
584
+ for (const other of history.entries()) {
585
+ if (
586
+ other.absolutePath === absolutePath &&
587
+ conflictRegionsEqual(other, entry) &&
588
+ !conflictRegionPresent(newContent, other)
589
+ ) {
590
+ history.invalidate(other.id);
591
+ }
592
+ }
593
+ }
594
+
595
+ const header = maybeWriteSnapshotHeader(this.session, absolutePath, newContent);
596
+ const range =
597
+ entry.startLine === entry.endLine
598
+ ? `line ${entry.startLine}`
599
+ : `lines ${entry.startLine}\u2013${entry.endLine}`;
600
+ const summary = `Resolved conflict #${entry.id} at ${range} in ${entry.displayPath}.`;
601
+ let resultText = header ? `${header}\n${summary}` : summary;
602
+ if (stripped) {
603
+ resultText += `\nNote: auto-stripped hashline display prefixes from content before writing.`;
604
+ }
605
+
606
+ return {
607
+ content: [{ type: "text", text: resultText }],
608
+ details: { resolvedPath: absolutePath },
609
+ };
610
+ }
611
+
612
+ /**
613
+ * Look up a single conflict entry by id and dispatch to {@link #resolveConflict}.
614
+ * Throws a clear `not found` error when the id has been invalidated.
615
+ */
616
+ async #resolveSingleConflictById(
617
+ id: number,
618
+ replacementContent: string,
619
+ stripped: boolean,
620
+ signal: AbortSignal | undefined,
621
+ ): Promise<AgentToolResult<WriteToolDetails>> {
622
+ const entry = getConflictHistory(this.session).get(id);
623
+ if (!entry) {
624
+ throw new ToolError(
625
+ `Conflict #${id} not found. Conflict ids are registered when \`read\` surfaces a marker block; re-read the file to get a current id.`,
626
+ );
627
+ }
628
+ return this.#resolveConflict(entry, replacementContent, stripped, signal);
629
+ }
630
+
631
+ /**
632
+ * Bulk-resolve every registered conflict via `conflict://*`.
633
+ *
634
+ * Entries are grouped by file and applied bottom-up by recorded start
635
+ * line so each splice keeps later anchors valid. `content` tokens are
636
+ * expanded *per entry*, so `content: "@ours"` keeps each block's own
637
+ * ours side rather than collapsing every conflict to the first
638
+ * block's ours.
639
+ *
640
+ * All-or-nothing semantics within a file: if any splice for a file
641
+ * fails (stale anchors, missing base for `@base`, etc.), that file is
642
+ * left untouched and the error is surfaced. Files that succeed are
643
+ * still written. The result text reports per-file counts so the agent
644
+ * can re-read the failed files and retry.
645
+ */
646
+ async #resolveAllConflicts(
647
+ replacementContent: string,
648
+ stripped: boolean,
649
+ signal: AbortSignal | undefined,
650
+ ): Promise<AgentToolResult<WriteToolDetails>> {
651
+ const history = getConflictHistory(this.session);
652
+ const allEntries = history.entries();
653
+ if (allEntries.length === 0) {
654
+ throw new ToolError(
655
+ "`conflict://*` has nothing to resolve — no conflicts are currently registered. Re-read the file(s) with conflicts first.",
656
+ );
657
+ }
658
+
659
+ const byFile = new Map<string, ConflictEntry[]>();
660
+ for (const entry of allEntries) {
661
+ const bucket = byFile.get(entry.absolutePath) ?? [];
662
+ bucket.push(entry);
663
+ byFile.set(entry.absolutePath, bucket);
664
+ }
665
+
666
+ const succeededFiles: { displayPath: string; count: number; header?: string }[] = [];
667
+ const failedFiles: { displayPath: string; count: number; error: string }[] = [];
668
+ let totalResolvedIds = 0;
669
+
670
+ for (const [absolutePath, fileEntries] of byFile) {
671
+ const sample = fileEntries[0]!;
672
+ if (!(await fs.exists(absolutePath))) {
673
+ failedFiles.push({
674
+ displayPath: sample.displayPath,
675
+ count: fileEntries.length,
676
+ error: "file no longer exists",
677
+ });
678
+ continue;
679
+ }
680
+
681
+ fileEntries.sort((a, b) => b.startLine - a.startLine);
682
+
683
+ let text: string;
684
+ const resolvedEntries: ConflictEntry[] = [];
685
+ const staleEntries: ConflictEntry[] = [];
686
+ let failure: string | undefined;
687
+ try {
688
+ text = await Bun.file(absolutePath).text();
689
+ } catch (error) {
690
+ failedFiles.push({
691
+ displayPath: sample.displayPath,
692
+ count: fileEntries.length,
693
+ error: error instanceof Error ? error.message : String(error),
694
+ });
695
+ continue;
696
+ }
697
+ for (const entry of fileEntries) {
698
+ try {
699
+ const expanded = expandContentTokens(replacementContent, entry);
700
+ text = spliceConflict(text, entry, expanded);
701
+ resolvedEntries.push(entry);
702
+ } catch (error) {
703
+ // A locate-miss for a region an earlier entry already spliced
704
+ // in this pass is a stale duplicate registration (re-read after
705
+ // an out-of-band shift) — treat it as already resolved.
706
+ if (resolvedEntries.some(done => conflictRegionsEqual(done, entry))) {
707
+ staleEntries.push(entry);
708
+ continue;
709
+ }
710
+ failure = error instanceof Error ? error.message : String(error);
711
+ break;
712
+ }
713
+ }
714
+ if (failure !== undefined) {
715
+ failedFiles.push({
716
+ displayPath: sample.displayPath,
717
+ count: fileEntries.length,
718
+ error: failure,
719
+ });
720
+ continue;
721
+ }
722
+
723
+ await writethroughNoop(absolutePath, text, signal);
724
+ invalidateFsScanAfterWrite(absolutePath);
725
+ this.session.bumpFileMutationVersion?.(absolutePath);
726
+ this.session.fileSnapshotStore?.invalidate(absolutePath);
727
+ for (const entry of resolvedEntries) history.invalidate(entry.id);
728
+ for (const entry of staleEntries) history.invalidate(entry.id);
729
+ const header = maybeWriteSnapshotHeader(this.session, absolutePath, text);
730
+ succeededFiles.push({ displayPath: sample.displayPath, count: resolvedEntries.length, header });
731
+ totalResolvedIds += resolvedEntries.length;
732
+ }
733
+
734
+ const summaryLines: string[] = [];
735
+ const fileWord = (n: number) => (n === 1 ? "file" : "files");
736
+ const conflictWord = (n: number) => (n === 1 ? "conflict" : "conflicts");
737
+ if (succeededFiles.length > 0) {
738
+ summaryLines.push(
739
+ `Resolved ${totalResolvedIds} ${conflictWord(totalResolvedIds)} across ${succeededFiles.length} ${fileWord(succeededFiles.length)}:`,
740
+ );
741
+ for (const file of succeededFiles) {
742
+ summaryLines.push(` ${file.displayPath}: ${file.count} ${conflictWord(file.count)}`);
743
+ }
744
+ }
745
+ if (failedFiles.length > 0) {
746
+ summaryLines.push(
747
+ `Failed to resolve ${failedFiles.length} ${fileWord(failedFiles.length)} — registered entries left intact for retry:`,
748
+ );
749
+ for (const file of failedFiles) {
750
+ summaryLines.push(` ${file.displayPath}: ${file.count} ${conflictWord(file.count)} (${file.error})`);
751
+ }
752
+ }
753
+ const headerLines = succeededFiles
754
+ .map(file => file.header)
755
+ .filter((header): header is string => header !== undefined);
756
+ if (headerLines.length > 0) {
757
+ summaryLines.push("Snapshots:");
758
+ for (const header of headerLines) summaryLines.push(` ${header}`);
759
+ }
760
+ if (stripped) {
761
+ summaryLines.push("Note: auto-stripped hashline display prefixes from content before writing.");
762
+ }
763
+ const resultText = summaryLines.join("\n");
764
+
765
+ if (failedFiles.length > 0 && succeededFiles.length === 0) {
766
+ throw new ToolError(resultText);
767
+ }
768
+ return {
769
+ content: [{ type: "text", text: resultText }],
770
+ details: {},
771
+ isError: failedFiles.length > 0 ? true : undefined,
772
+ };
773
+ }
774
+
775
+ #routeWriteThroughBridge(absolutePath: string, content: string): Promise<void> | undefined {
776
+ const bridge = this.session.getClientBridge?.();
777
+ if (!bridge?.capabilities.writeTextFile || !bridge.writeTextFile) return undefined;
778
+ return bridge.writeTextFile({ path: absolutePath, content });
779
+ }
780
+ async execute(
781
+ _toolCallId: string,
782
+ { path: rawPath, content }: WriteParams,
783
+ signal?: AbortSignal,
784
+ _onUpdate?: AgentToolUpdateCallback<WriteToolDetails>,
785
+ context?: AgentToolContext,
786
+ ): Promise<AgentToolResult<WriteToolDetails>> {
787
+ // Strip a hashline `[path#TAG]` wrapper up front so every downstream
788
+ // decision (scheme routing, internal-URL handler dispatch, plan-mode
789
+ // guard, plan path resolution, ACP bridge routing) sees the same
790
+ // filesystem target. Without this, a model that pastes a `read`
791
+ // header as the `path` arg would slip past `isInternalUrlPath`
792
+ // (which fails on a leading `[`) and the bridge router would send a
793
+ // `[local://scratch.md#ABCD]` write to the editor instead of the
794
+ // session-local sandbox.
795
+ const path = unwrapHashlineHeaderPath(rawPath);
796
+ return untilAborted(signal, async () => {
797
+ // Strip hashline display prefixes ([PATH#HASH] + LINE:) if the model copied them from read output
798
+ const { text: cleanContent, stripped } = stripWriteContent(this.session, content);
799
+ const internalRouter = InternalUrlRouter.instance();
800
+ if (internalRouter.canHandle(path)) {
801
+ const parsed = parseInternalUrl(path);
802
+ const scheme = parsed.protocol.replace(/:$/, "").toLowerCase();
803
+ const handler = internalRouter.getHandler(scheme);
804
+ if (handler?.write) {
805
+ // Handler-owned writes (vault:// notes, host URIs) mutate user
806
+ // data outside the local sandbox — plan mode must reject them.
807
+ enforcePlanModeWrite(this.session, path, { op: "update" });
808
+ await handler.write(parsed, cleanContent, { cwd: this.session.cwd, signal });
809
+ let resultText = `Successfully wrote ${cleanContent.length} bytes to ${path}`;
810
+ if (stripped) {
811
+ resultText += `\nNote: auto-stripped hashline display prefixes from content before writing.`;
812
+ }
813
+ return { content: [{ type: "text", text: resultText }], details: {} };
814
+ }
815
+ // Schemes without a `write` hook fall through to existing logic
816
+ // (local:// resolves to a backing file via plan-mode-guard) or are
817
+ // rejected downstream when no backing file exists.
818
+ }
819
+
820
+ const conflictUri = parseConflictUri(path);
821
+ if (conflictUri) {
822
+ if (conflictUri.scope) {
823
+ throw new ToolError(
824
+ `Conflict URI scope '/${conflictUri.scope}' is read-only — read \`conflict://${conflictUri.id}/${conflictUri.scope}\` to inspect that side. To write, drop the scope (\`conflict://${conflictUri.id}\`) and put the chosen content (or shorthand like \`@${conflictUri.scope}\`) in \`content\`.`,
825
+ );
826
+ }
827
+ const result =
828
+ conflictUri.id === "*"
829
+ ? await this.#resolveAllConflicts(cleanContent, stripped, signal)
830
+ : await this.#resolveSingleConflictById(conflictUri.id, cleanContent, stripped, signal);
831
+ if (conflictUri.recoveredPrefix !== undefined) {
832
+ appendNoteToResult(
833
+ result,
834
+ `Note: stripped erroneous '${conflictUri.recoveredPrefix}:' prefix from path; conflict URIs are global (use \`conflict://${conflictUri.id}\`, not \`<file>:conflict://${conflictUri.id}\`).`,
835
+ );
836
+ }
837
+ return result;
838
+ }
839
+ const resolvedArchivePath = await this.#resolveArchiveWritePath(path);
840
+ if (resolvedArchivePath) {
841
+ enforcePlanModeWrite(this.session, resolvedArchivePath.archivePath, {
842
+ op: resolvedArchivePath.exists ? "update" : "create",
843
+ });
844
+
845
+ const archiveResult = await this.#writeArchiveEntry(cleanContent, resolvedArchivePath);
846
+ if (stripped) {
847
+ const firstText = archiveResult.content.find(
848
+ (block): block is { type: "text"; text: string } =>
849
+ block.type === "text" && typeof block.text === "string",
850
+ );
851
+ if (firstText) {
852
+ firstText.text += `\nNote: auto-stripped hashline display prefixes from content before writing.`;
853
+ }
854
+ }
855
+ return archiveResult;
856
+ }
857
+
858
+ const resolvedSqlitePath = await this.#resolveSqliteWritePath(path);
859
+ if (resolvedSqlitePath) {
860
+ enforcePlanModeWrite(this.session, resolvedSqlitePath.sqlitePath, { op: "update" });
861
+
862
+ const sqliteResult = await this.#writeSqliteRow(path, cleanContent, resolvedSqlitePath);
863
+ if (stripped) {
864
+ const firstText = sqliteResult.content.find(
865
+ (block): block is { type: "text"; text: string } =>
866
+ block.type === "text" && typeof block.text === "string",
867
+ );
868
+ if (firstText) {
869
+ firstText.text += `\nNote: auto-stripped hashline display prefixes from content before writing.`;
870
+ }
871
+ }
872
+ return sqliteResult;
873
+ }
874
+
875
+ enforcePlanModeWrite(this.session, path, { op: "create" });
876
+ const absolutePath = resolvePlanPath(this.session, path);
877
+ const batchRequest = getLspBatchRequest(context?.toolCall);
878
+
879
+ // Check if file exists and is auto-generated before overwriting
880
+ if (await fs.exists(absolutePath)) {
881
+ await assertEditableFile(absolutePath, path);
882
+ }
883
+
884
+ // Try ACP bridge first for editor-visible filesystem paths. Internal
885
+ // artifacts such as local:// plans are owned by OMP, not the editor.
886
+ const bridgePromise = shouldRouteWriteThroughBridge(this.session, path, absolutePath)
887
+ ? this.#routeWriteThroughBridge(absolutePath, cleanContent)
888
+ : undefined;
889
+ if (bridgePromise !== undefined) {
890
+ try {
891
+ await bridgePromise;
892
+ } catch (error) {
893
+ throw new ToolError(error instanceof Error ? error.message : String(error));
894
+ }
895
+ invalidateFsScanAfterWrite(absolutePath);
896
+ this.session.bumpFileMutationVersion?.(absolutePath);
897
+ const madeExecutable = await maybeMarkExecutableForShebang(absolutePath, cleanContent);
898
+ const displayPath = formatPathRelativeToCwd(absolutePath, this.session.cwd);
899
+ const header = maybeWriteSnapshotHeader(this.session, absolutePath, cleanContent);
900
+ const writeLine = `Successfully wrote ${cleanContent.length} bytes to ${displayPath}`;
901
+ let resultText = header ? `${header}\n${writeLine}` : writeLine;
902
+ if (stripped) {
903
+ resultText += `\nNote: auto-stripped hashline display prefixes from content before writing.`;
904
+ }
905
+ if (madeExecutable) {
906
+ resultText += `\n${EXECUTABLE_NOTICE}`;
907
+ }
908
+ return {
909
+ content: [{ type: "text", text: resultText }],
910
+ details: { resolvedPath: absolutePath, madeExecutable: madeExecutable || undefined },
911
+ };
912
+ }
913
+
914
+ const diagnostics = await this.#writethrough(absolutePath, cleanContent, signal, undefined, batchRequest);
915
+ invalidateFsScanAfterWrite(absolutePath);
916
+ this.session.bumpFileMutationVersion?.(absolutePath);
917
+ const madeExecutable = await maybeMarkExecutableForShebang(absolutePath, cleanContent);
918
+
919
+ const displayPath = formatPathRelativeToCwd(absolutePath, this.session.cwd);
920
+ const header = maybeWriteSnapshotHeader(this.session, absolutePath, cleanContent);
921
+ const writeLine = `Successfully wrote ${cleanContent.length} bytes to ${displayPath}`;
922
+ let resultText = header ? `${header}\n${writeLine}` : writeLine;
923
+ if (stripped) {
924
+ resultText += `\nNote: auto-stripped hashline display prefixes from content before writing.`;
925
+ }
926
+ if (madeExecutable) {
927
+ resultText += `\n${EXECUTABLE_NOTICE}`;
928
+ }
929
+ if (!diagnostics) {
930
+ return {
931
+ content: [{ type: "text", text: resultText }],
932
+ details: { resolvedPath: absolutePath, madeExecutable: madeExecutable || undefined },
933
+ };
934
+ }
935
+
936
+ return {
937
+ content: [{ type: "text", text: resultText }],
938
+ details: {
939
+ resolvedPath: absolutePath,
940
+ diagnostics,
941
+ madeExecutable: madeExecutable || undefined,
942
+ meta: outputMeta()
943
+ .diagnostics(diagnostics.summary, diagnostics.messages ?? [])
944
+ .get(),
945
+ },
946
+ };
947
+ });
948
+ }
949
+ }
950
+
951
+ // =============================================================================
952
+ // TUI Renderer
953
+ // =============================================================================
954
+
955
+ interface WriteRenderArgs {
956
+ path?: string;
957
+ file_path?: string;
958
+ content?: string;
959
+ }
960
+
961
+ const WRITE_PREVIEW_LINES = 6;
962
+ const WRITE_STREAMING_PREVIEW_LINES = 12;
963
+
964
+ function countLines(text: string): number {
965
+ if (!text) return 0;
966
+ return text.split("\n").length;
967
+ }
968
+
969
+ function formatLineCountSuffix(lineCount: number, uiTheme: Theme): string {
970
+ if (lineCount <= 0) return "";
971
+ return uiTheme.fg("dim", ` · ${lineCount} line${lineCount === 1 ? "" : "s"}`);
972
+ }
973
+
974
+ function normalizeDisplayText(text: string): string {
975
+ return text.replace(/\r/g, "");
976
+ }
977
+
978
+ /**
979
+ * Minimum line-number gutter width for write previews. The streaming preview's
980
+ * gutter must stay byte-stable as the line count grows: a width derived purely
981
+ * from `String(totalLines).length` widens at the 10/100/1000-line crossings,
982
+ * rewriting every already-rendered row — which forces the transcript's commit
983
+ * audit to recommit the block's committed prefix (a full duplicate in native
984
+ * scrollback). Reserving 3 digits keeps the gutter constant through 999 lines
985
+ * and keeps the streamed rows byte-identical to the final result render.
986
+ */
987
+ const WRITE_GUTTER_MIN_WIDTH = 3;
988
+
989
+ function formatStreamingContent(
990
+ content: string,
991
+ expanded: boolean,
992
+ language: string | undefined,
993
+ uiTheme: Theme,
994
+ spinnerFrame?: number,
995
+ cache?: RenderedStringCache,
996
+ ): string {
997
+ if (!content) return "";
998
+ const bodyText = cachedRenderedString(cache, uiTheme, expanded, language ?? "", content, () => {
999
+ const lines = normalizeDisplayText(content).split("\n");
1000
+ const totalLines = lines.length;
1001
+ // Collapsed: follow the streaming edge with a bounded tail window so the box
1002
+ // stays short enough not to strand its scrolled-off head above the viewport
1003
+ // while the block is volatile. `Ctrl+O` (expanded) lifts the cap for a
1004
+ // deliberate full view — matching the eval streaming preview.
1005
+ const startIndex = expanded ? 0 : Math.max(0, totalLines - WRITE_STREAMING_PREVIEW_LINES);
1006
+ const visibleLines = lines.slice(startIndex);
1007
+ const hidden = startIndex;
1008
+ const highlighted = highlightCode(visibleLines.join("\n"), language);
1009
+ const lineNumberWidth = Math.max(WRITE_GUTTER_MIN_WIDTH, String(totalLines).length);
1010
+
1011
+ let text = "\n\n";
1012
+ if (hidden > 0) {
1013
+ text += `${uiTheme.fg("dim", `… (${hidden} earlier line${hidden === 1 ? "" : "s"})`)}\n`;
1014
+ }
1015
+ for (let i = 0; i < highlighted.length; i++) {
1016
+ const lineNum = startIndex + i + 1;
1017
+ const gutter = uiTheme.fg("dim", `${String(lineNum).padStart(lineNumberWidth, " ")} `);
1018
+ const body = replaceTabs(highlighted[i] ?? "");
1019
+ text += `${gutter}${body}\n`;
1020
+ }
1021
+ return text;
1022
+ });
1023
+ // The animated glyph lives on this trailing line — inside the transcript's
1024
+ // volatile-tail holdback — never in the header: an animating head row pins
1025
+ // the native-scrollback commit boundary at the top of the block, so a long
1026
+ // expanded preview could never scroll-append mid-stream.
1027
+ const spinner = spinnerFrame !== undefined ? `${formatStatusIcon("running", uiTheme, spinnerFrame)} ` : "";
1028
+ return `${bodyText}${spinner}${uiTheme.fg("dim", `… (streaming)`)}`;
1029
+ }
1030
+
1031
+ function renderContentPreview(
1032
+ content: string,
1033
+ expanded: boolean,
1034
+ language: string | undefined,
1035
+ uiTheme: Theme,
1036
+ cache?: RenderedStringCache,
1037
+ ): string {
1038
+ if (!content) return "";
1039
+ return cachedRenderedString(cache, uiTheme, expanded, language ?? "", content, () => {
1040
+ const rawLines = normalizeDisplayText(content).split("\n");
1041
+ const totalLines = rawLines.length;
1042
+ const maxLines = expanded ? totalLines : Math.min(totalLines, WRITE_PREVIEW_LINES);
1043
+ const visibleLines = rawLines.slice(0, maxLines);
1044
+ const highlighted = highlightCode(visibleLines.join("\n"), language);
1045
+ const lineNumberWidth = Math.max(WRITE_GUTTER_MIN_WIDTH, String(totalLines).length);
1046
+ const hidden = totalLines - maxLines;
1047
+
1048
+ let text = "\n\n";
1049
+ for (let i = 0; i < highlighted.length; i++) {
1050
+ const lineNum = i + 1;
1051
+ const gutter = uiTheme.fg("dim", `${String(lineNum).padStart(lineNumberWidth, " ")} `);
1052
+ const body = replaceTabs(highlighted[i] ?? "");
1053
+ text += `${gutter}${body}\n`;
1054
+ }
1055
+ if (!expanded && hidden > 0) {
1056
+ const hint = formatExpandHint(uiTheme, expanded, hidden > 0);
1057
+ const moreLine = `${formatMoreItems(hidden, "line")}${hint ? ` ${hint}` : ""}`;
1058
+ text += uiTheme.fg("dim", moreLine);
1059
+ }
1060
+ return text.trimEnd();
1061
+ });
1062
+ }
1063
+
1064
+ export const writeToolRenderer = {
1065
+ renderCall(args: WriteRenderArgs, options: RenderResultOptions, uiTheme: Theme): Component {
1066
+ const rawPath = args.file_path || args.path || "";
1067
+ const filePath = shortenPath(rawPath);
1068
+ const lang = getLanguageFromPath(rawPath) ?? "text";
1069
+ const langIcon = uiTheme.fg("muted", uiTheme.getLangIcon(lang));
1070
+ const pathDisplay = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput", "…");
1071
+ // Static pending icon, never the animated glyph: the header is the head
1072
+ // row of the framed block, and native-scrollback commits are prefix-only
1073
+ // — an animating head row would pin the commit boundary at the top and
1074
+ // keep a tall expanded preview from scroll-appending mid-stream. The
1075
+ // liveness cue rides the trailing "(streaming)" line instead.
1076
+ const header = renderStatusLine(
1077
+ {
1078
+ icon: "pending",
1079
+ title: "Write",
1080
+ description: `${langIcon} ${pathDisplay}`,
1081
+ },
1082
+ uiTheme,
1083
+ );
1084
+ const streamingCache = createRenderedStringCache();
1085
+ return framedBlock(uiTheme, width => {
1086
+ const body = args.content
1087
+ ? formatStreamingContent(
1088
+ args.content,
1089
+ Boolean(options?.expanded),
1090
+ lang,
1091
+ uiTheme,
1092
+ options?.spinnerFrame,
1093
+ streamingCache,
1094
+ )
1095
+ : "";
1096
+ const bodyLines = body ? body.split("\n") : [];
1097
+ while (bodyLines.length > 0 && bodyLines[0].trim() === "") bodyLines.shift();
1098
+ return {
1099
+ header,
1100
+ sections: bodyLines.length > 0 ? [{ lines: bodyLines }] : [],
1101
+ state: "pending",
1102
+ borderColor: "borderMuted",
1103
+ width,
1104
+ };
1105
+ });
1106
+ },
1107
+
1108
+ renderResult(
1109
+ result: { content: Array<{ type: string; text?: string }>; details?: WriteToolDetails; isError?: boolean },
1110
+ options: RenderResultOptions,
1111
+ uiTheme: Theme,
1112
+ args?: WriteRenderArgs,
1113
+ ): Component {
1114
+ const rawPath = args?.file_path || args?.path || "";
1115
+ const filePath = shortenPath(rawPath);
1116
+ const fileContent = args?.content || "";
1117
+ const lang = getLanguageFromPath(rawPath);
1118
+ const langIcon = uiTheme.fg("muted", uiTheme.getLangIcon(lang));
1119
+ // The header shows the cwd-relative path but links to the absolute path the
1120
+ // write resolved to (args.path may be relative, which would yield a broken
1121
+ // `file://` URI). Falls back to plain text when the result lacks a path.
1122
+ const linkTarget = result.details?.resolvedPath;
1123
+ const styledPath = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput", "…");
1124
+ const pathDisplay = filePath && linkTarget ? fileHyperlink(linkTarget, styledPath) : styledPath;
1125
+
1126
+ if (result.isError) {
1127
+ const errorText = result.content?.find(c => c.type === "text")?.text ?? "";
1128
+ const header = renderStatusLine(
1129
+ { icon: "error", title: "Write", description: `${langIcon} ${pathDisplay}` },
1130
+ uiTheme,
1131
+ );
1132
+ return framedBlock(uiTheme, width => ({
1133
+ header,
1134
+ sections: [{ lines: formatErrorDetail(errorText, uiTheme).split("\n") }],
1135
+ state: "error",
1136
+ borderColor: "error",
1137
+ width,
1138
+ }));
1139
+ }
1140
+
1141
+ const lineCount = countLines(fileContent);
1142
+ const lineSuffix = formatLineCountSuffix(lineCount, uiTheme);
1143
+ const execSuffix = result.details?.madeExecutable
1144
+ ? `${uiTheme.fg("dim", " · ")}${uiTheme.fg("success", "made executable!")}`
1145
+ : "";
1146
+ const header = renderStatusLine(
1147
+ {
1148
+ iconOverride: uiTheme.styledSymbol("tool.write", "accent"),
1149
+ title: "Write",
1150
+ description: `${langIcon} ${pathDisplay}${lineSuffix}${execSuffix}`,
1151
+ },
1152
+ uiTheme,
1153
+ );
1154
+ const diagnostics = result.details?.diagnostics;
1155
+
1156
+ const previewCache = createRenderedStringCache();
1157
+ return framedBlock(uiTheme, width => {
1158
+ const { expanded } = options;
1159
+ let body = renderContentPreview(fileContent, expanded, lang, uiTheme, previewCache);
1160
+ if (diagnostics) {
1161
+ const diagText = formatDiagnostics(diagnostics, expanded, uiTheme, fp =>
1162
+ uiTheme.getLangIcon(getLanguageFromPath(fp)),
1163
+ );
1164
+ if (diagText.trim()) {
1165
+ const diagLines = diagText.split("\n");
1166
+ const firstNonEmpty = diagLines.findIndex(line => line.trim());
1167
+ if (firstNonEmpty >= 0) body += `\n${diagLines.slice(firstNonEmpty).join("\n")}`;
1168
+ }
1169
+ }
1170
+ const bodyLines = body.split("\n");
1171
+ while (bodyLines.length > 0 && bodyLines[0].trim() === "") bodyLines.shift();
1172
+ return {
1173
+ header,
1174
+ sections: bodyLines.length > 0 ? [{ lines: bodyLines }] : [],
1175
+ state: "success",
1176
+ borderColor: "borderMuted",
1177
+ width,
1178
+ };
1179
+ });
1180
+ },
1181
+ mergeCallAndResult: true,
1182
+ };