@sns-myagent/cli 0.2.0

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