@wahack/pi-coding-agent 15.11.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 (1152) hide show
  1. package/CHANGELOG.md +10031 -0
  2. package/README.md +36 -0
  3. package/examples/README.md +21 -0
  4. package/examples/custom-tools/README.md +104 -0
  5. package/examples/custom-tools/hello/index.ts +20 -0
  6. package/examples/extensions/README.md +142 -0
  7. package/examples/extensions/api-demo.ts +79 -0
  8. package/examples/extensions/chalk-logger.ts +25 -0
  9. package/examples/extensions/hello.ts +31 -0
  10. package/examples/extensions/pirate.ts +43 -0
  11. package/examples/extensions/plan-mode.ts +549 -0
  12. package/examples/extensions/reload-runtime.ts +38 -0
  13. package/examples/extensions/thinking-note.ts +13 -0
  14. package/examples/extensions/tools.ts +145 -0
  15. package/examples/extensions/with-deps/index.ts +36 -0
  16. package/examples/extensions/with-deps/package-lock.json +31 -0
  17. package/examples/extensions/with-deps/package.json +17 -0
  18. package/examples/hooks/README.md +56 -0
  19. package/examples/hooks/auto-commit-on-exit.ts +48 -0
  20. package/examples/hooks/confirm-destructive.ts +58 -0
  21. package/examples/hooks/custom-compaction.ts +115 -0
  22. package/examples/hooks/dirty-repo-guard.ts +51 -0
  23. package/examples/hooks/file-trigger.ts +40 -0
  24. package/examples/hooks/git-checkpoint.ts +52 -0
  25. package/examples/hooks/handoff.ts +149 -0
  26. package/examples/hooks/permission-gate.ts +33 -0
  27. package/examples/hooks/protected-paths.ts +29 -0
  28. package/examples/hooks/qna.ts +118 -0
  29. package/examples/hooks/status-line.ts +39 -0
  30. package/examples/sdk/01-minimal.ts +21 -0
  31. package/examples/sdk/02-custom-model.ts +49 -0
  32. package/examples/sdk/03-custom-prompt.ts +46 -0
  33. package/examples/sdk/04-skills.ts +43 -0
  34. package/examples/sdk/06-extensions.ts +82 -0
  35. package/examples/sdk/06-hooks.ts +61 -0
  36. package/examples/sdk/07-context-files.ts +35 -0
  37. package/examples/sdk/08-prompt-templates.ts +41 -0
  38. package/examples/sdk/08-slash-commands.ts +46 -0
  39. package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
  40. package/examples/sdk/11-sessions.ts +47 -0
  41. package/examples/sdk/12-redis-sessions.ts +54 -0
  42. package/examples/sdk/13-sql-sessions.ts +61 -0
  43. package/examples/sdk/README.md +172 -0
  44. package/package.json +554 -0
  45. package/scripts/build-binary.ts +100 -0
  46. package/scripts/bundle-dist.ts +90 -0
  47. package/scripts/format-prompts.ts +68 -0
  48. package/scripts/generate-docs-index.ts +40 -0
  49. package/scripts/generate-template.ts +33 -0
  50. package/scripts/omp +42 -0
  51. package/scripts/omp.ts +19 -0
  52. package/src/async/index.ts +1 -0
  53. package/src/async/job-manager.ts +625 -0
  54. package/src/auto-thinking/classifier.ts +185 -0
  55. package/src/autoresearch/command-resume.md +14 -0
  56. package/src/autoresearch/dashboard.ts +436 -0
  57. package/src/autoresearch/git.ts +319 -0
  58. package/src/autoresearch/helpers.ts +218 -0
  59. package/src/autoresearch/index.ts +536 -0
  60. package/src/autoresearch/prompt-setup.md +43 -0
  61. package/src/autoresearch/prompt.md +103 -0
  62. package/src/autoresearch/resume-message.md +10 -0
  63. package/src/autoresearch/state.ts +273 -0
  64. package/src/autoresearch/storage.ts +699 -0
  65. package/src/autoresearch/tools/init-experiment.ts +272 -0
  66. package/src/autoresearch/tools/log-experiment.ts +524 -0
  67. package/src/autoresearch/tools/run-experiment.ts +407 -0
  68. package/src/autoresearch/tools/update-notes.ts +109 -0
  69. package/src/autoresearch/types.ts +168 -0
  70. package/src/bun-imports.d.ts +28 -0
  71. package/src/capability/context-file.ts +44 -0
  72. package/src/capability/extension-module.ts +34 -0
  73. package/src/capability/extension.ts +47 -0
  74. package/src/capability/fs.ts +117 -0
  75. package/src/capability/hook.ts +40 -0
  76. package/src/capability/index.ts +436 -0
  77. package/src/capability/instruction.ts +37 -0
  78. package/src/capability/mcp.ts +74 -0
  79. package/src/capability/prompt.ts +35 -0
  80. package/src/capability/rule-buckets.ts +66 -0
  81. package/src/capability/rule.ts +261 -0
  82. package/src/capability/settings.ts +34 -0
  83. package/src/capability/skill.ts +63 -0
  84. package/src/capability/slash-command.ts +40 -0
  85. package/src/capability/ssh.ts +41 -0
  86. package/src/capability/system-prompt.ts +34 -0
  87. package/src/capability/tool.ts +38 -0
  88. package/src/capability/types.ts +168 -0
  89. package/src/cli/agents-cli.ts +138 -0
  90. package/src/cli/args.ts +340 -0
  91. package/src/cli/auth-broker-cli.ts +895 -0
  92. package/src/cli/auth-gateway-cli.ts +611 -0
  93. package/src/cli/classify-install-target.ts +76 -0
  94. package/src/cli/claude-trace-cli.ts +795 -0
  95. package/src/cli/commands/init-xdg.ts +27 -0
  96. package/src/cli/completion-gen.ts +550 -0
  97. package/src/cli/config-cli.ts +418 -0
  98. package/src/cli/dry-balance-cli.ts +856 -0
  99. package/src/cli/extension-flags.ts +48 -0
  100. package/src/cli/file-processor.ts +133 -0
  101. package/src/cli/gallery-cli.ts +230 -0
  102. package/src/cli/gallery-fixtures/agentic.ts +407 -0
  103. package/src/cli/gallery-fixtures/codeintel.ts +187 -0
  104. package/src/cli/gallery-fixtures/edit.ts +194 -0
  105. package/src/cli/gallery-fixtures/fs.ts +220 -0
  106. package/src/cli/gallery-fixtures/index.ts +40 -0
  107. package/src/cli/gallery-fixtures/interaction.ts +49 -0
  108. package/src/cli/gallery-fixtures/memory.ts +81 -0
  109. package/src/cli/gallery-fixtures/misc.ts +250 -0
  110. package/src/cli/gallery-fixtures/search.ts +213 -0
  111. package/src/cli/gallery-fixtures/shell.ts +167 -0
  112. package/src/cli/gallery-fixtures/types.ts +57 -0
  113. package/src/cli/gallery-fixtures/web.ts +158 -0
  114. package/src/cli/gallery-screenshot.ts +279 -0
  115. package/src/cli/grep-cli.ts +160 -0
  116. package/src/cli/grievances-cli.ts +256 -0
  117. package/src/cli/initial-message.ts +58 -0
  118. package/src/cli/list-models.ts +194 -0
  119. package/src/cli/plugin-cli.ts +996 -0
  120. package/src/cli/read-cli.ts +57 -0
  121. package/src/cli/session-picker.ts +79 -0
  122. package/src/cli/setup-cli.ts +231 -0
  123. package/src/cli/shell-cli.ts +176 -0
  124. package/src/cli/ssh-cli.ts +179 -0
  125. package/src/cli/startup-cwd.ts +68 -0
  126. package/src/cli/stats-cli.ts +238 -0
  127. package/src/cli/tiny-models-cli.ts +127 -0
  128. package/src/cli/update-cli.ts +611 -0
  129. package/src/cli/usage-cli.ts +603 -0
  130. package/src/cli/web-search-cli.ts +132 -0
  131. package/src/cli/worktree-cli.ts +291 -0
  132. package/src/cli-commands.ts +79 -0
  133. package/src/cli.ts +200 -0
  134. package/src/commands/acp.ts +24 -0
  135. package/src/commands/agents.ts +57 -0
  136. package/src/commands/auth-broker.ts +99 -0
  137. package/src/commands/auth-gateway.ts +69 -0
  138. package/src/commands/commit.ts +46 -0
  139. package/src/commands/complete.ts +66 -0
  140. package/src/commands/completions.ts +60 -0
  141. package/src/commands/config.ts +51 -0
  142. package/src/commands/dry-balance.ts +43 -0
  143. package/src/commands/gallery.ts +52 -0
  144. package/src/commands/grep.ts +48 -0
  145. package/src/commands/grievances.ts +51 -0
  146. package/src/commands/install.ts +107 -0
  147. package/src/commands/launch.ts +169 -0
  148. package/src/commands/plugin.ts +78 -0
  149. package/src/commands/read.ts +38 -0
  150. package/src/commands/setup.ts +67 -0
  151. package/src/commands/shell.ts +29 -0
  152. package/src/commands/ssh.ts +60 -0
  153. package/src/commands/stats.ts +29 -0
  154. package/src/commands/tiny-models.ts +36 -0
  155. package/src/commands/update.ts +21 -0
  156. package/src/commands/usage.ts +35 -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 +317 -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 +146 -0
  168. package/src/commit/agentic/tools/git-file-diff.ts +191 -0
  169. package/src/commit/agentic/tools/git-hunk.ts +50 -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 +144 -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 +23 -0
  176. package/src/commit/agentic/tools/split-commit.ts +245 -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 +105 -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 +97 -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 +92 -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 +77 -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 +60 -0
  216. package/src/config/append-only-context-mode.ts +31 -0
  217. package/src/config/config-file.ts +317 -0
  218. package/src/config/file-lock.ts +164 -0
  219. package/src/config/keybindings.ts +628 -0
  220. package/src/config/mcp-schema.json +230 -0
  221. package/src/config/model-discovery.ts +554 -0
  222. package/src/config/model-registry.ts +2090 -0
  223. package/src/config/model-resolver.ts +1502 -0
  224. package/src/config/model-roles.ts +74 -0
  225. package/src/config/models-config-schema.ts +226 -0
  226. package/src/config/models-config.ts +129 -0
  227. package/src/config/prompt-templates.ts +185 -0
  228. package/src/config/resolve-config-value.ts +94 -0
  229. package/src/config/settings-schema.ts +3530 -0
  230. package/src/config/settings.ts +1178 -0
  231. package/src/config.ts +242 -0
  232. package/src/cursor.ts +340 -0
  233. package/src/dap/client.ts +760 -0
  234. package/src/dap/config.ts +189 -0
  235. package/src/dap/defaults.json +212 -0
  236. package/src/dap/index.ts +4 -0
  237. package/src/dap/session.ts +1441 -0
  238. package/src/dap/types.ts +610 -0
  239. package/src/debug/index.ts +515 -0
  240. package/src/debug/log-formatting.ts +58 -0
  241. package/src/debug/log-viewer.ts +908 -0
  242. package/src/debug/profiler.ts +162 -0
  243. package/src/debug/protocol-probe.ts +267 -0
  244. package/src/debug/raw-sse-buffer.ts +273 -0
  245. package/src/debug/raw-sse.ts +292 -0
  246. package/src/debug/report-bundle.ts +374 -0
  247. package/src/debug/system-info.ts +111 -0
  248. package/src/debug/terminal-info.ts +124 -0
  249. package/src/discovery/agents-md.ts +67 -0
  250. package/src/discovery/agents.ts +230 -0
  251. package/src/discovery/at-imports.ts +273 -0
  252. package/src/discovery/builtin-defaults.ts +39 -0
  253. package/src/discovery/builtin-rules/index.ts +54 -0
  254. package/src/discovery/builtin-rules/rs-box-leak.md +48 -0
  255. package/src/discovery/builtin-rules/rs-future-prelude.md +23 -0
  256. package/src/discovery/builtin-rules/rs-lazylock.md +51 -0
  257. package/src/discovery/builtin-rules/rs-match-ergonomics.md +67 -0
  258. package/src/discovery/builtin-rules/rs-parking-lot.md +44 -0
  259. package/src/discovery/builtin-rules/rs-result-type.md +19 -0
  260. package/src/discovery/builtin-rules/ts-bare-catch.md +38 -0
  261. package/src/discovery/builtin-rules/ts-import-type.md +42 -0
  262. package/src/discovery/builtin-rules/ts-no-any.md +56 -0
  263. package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +44 -0
  264. package/src/discovery/builtin-rules/ts-no-dynamic-import.md +39 -0
  265. package/src/discovery/builtin-rules/ts-no-return-type.md +45 -0
  266. package/src/discovery/builtin-rules/ts-no-test-timers.md +55 -0
  267. package/src/discovery/builtin-rules/ts-no-tiny-functions.md +51 -0
  268. package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +65 -0
  269. package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +75 -0
  270. package/src/discovery/builtin-rules/ts-set-map.md +28 -0
  271. package/src/discovery/builtin.ts +906 -0
  272. package/src/discovery/claude-plugins.ts +386 -0
  273. package/src/discovery/claude.ts +584 -0
  274. package/src/discovery/cline.ts +83 -0
  275. package/src/discovery/codex.ts +522 -0
  276. package/src/discovery/cursor.ts +220 -0
  277. package/src/discovery/gemini.ts +383 -0
  278. package/src/discovery/github.ts +154 -0
  279. package/src/discovery/helpers.ts +1016 -0
  280. package/src/discovery/index.ts +81 -0
  281. package/src/discovery/mcp-json.ts +171 -0
  282. package/src/discovery/omp-extension-roots.ts +190 -0
  283. package/src/discovery/omp-plugins.ts +383 -0
  284. package/src/discovery/opencode.ts +398 -0
  285. package/src/discovery/plugin-dir-roots.ts +28 -0
  286. package/src/discovery/ssh.ts +153 -0
  287. package/src/discovery/substitute-plugin-root.ts +29 -0
  288. package/src/discovery/vscode.ts +105 -0
  289. package/src/discovery/windsurf.ts +147 -0
  290. package/src/edit/apply-patch/index.ts +87 -0
  291. package/src/edit/apply-patch/parser.ts +174 -0
  292. package/src/edit/diff.ts +999 -0
  293. package/src/edit/file-snapshot-store.ts +91 -0
  294. package/src/edit/hashline/block-resolver.ts +33 -0
  295. package/src/edit/hashline/diff.ts +290 -0
  296. package/src/edit/hashline/execute.ts +242 -0
  297. package/src/edit/hashline/filesystem.ts +130 -0
  298. package/src/edit/hashline/index.ts +5 -0
  299. package/src/edit/hashline/noop-loop-guard.ts +99 -0
  300. package/src/edit/hashline/params.ts +18 -0
  301. package/src/edit/index.ts +571 -0
  302. package/src/edit/modes/apply-patch.lark +19 -0
  303. package/src/edit/modes/apply-patch.ts +53 -0
  304. package/src/edit/modes/patch.ts +1891 -0
  305. package/src/edit/modes/replace.ts +1137 -0
  306. package/src/edit/normalize.ts +345 -0
  307. package/src/edit/notebook.ts +242 -0
  308. package/src/edit/read-file.ts +25 -0
  309. package/src/edit/renderer.ts +769 -0
  310. package/src/edit/streaming.ts +517 -0
  311. package/src/eval/__tests__/agent-bridge.test.ts +708 -0
  312. package/src/eval/__tests__/bridge-timeout.test.ts +64 -0
  313. package/src/eval/__tests__/budget-bridge.test.ts +69 -0
  314. package/src/eval/__tests__/completion-bridge.test.ts +412 -0
  315. package/src/eval/__tests__/helpers-local-roots.test.ts +58 -0
  316. package/src/eval/__tests__/idle-timeout.test.ts +80 -0
  317. package/src/eval/__tests__/js-context-manager.test.ts +241 -0
  318. package/src/eval/__tests__/kernel-spawn.test.ts +103 -0
  319. package/src/eval/agent-bridge.ts +319 -0
  320. package/src/eval/backend.ts +71 -0
  321. package/src/eval/bridge-timeout.ts +44 -0
  322. package/src/eval/budget-bridge.ts +48 -0
  323. package/src/eval/completion-bridge.ts +207 -0
  324. package/src/eval/concurrency-bridge.ts +34 -0
  325. package/src/eval/idle-timeout.ts +91 -0
  326. package/src/eval/index.ts +4 -0
  327. package/src/eval/js/context-manager.ts +502 -0
  328. package/src/eval/js/executor.ts +173 -0
  329. package/src/eval/js/index.ts +51 -0
  330. package/src/eval/js/shared/helpers.ts +283 -0
  331. package/src/eval/js/shared/indirect-eval.ts +30 -0
  332. package/src/eval/js/shared/local-module-loader.ts +342 -0
  333. package/src/eval/js/shared/prelude.ts +2 -0
  334. package/src/eval/js/shared/prelude.txt +246 -0
  335. package/src/eval/js/shared/rewrite-imports.ts +532 -0
  336. package/src/eval/js/shared/runtime.ts +352 -0
  337. package/src/eval/js/shared/types.ts +18 -0
  338. package/src/eval/js/tool-bridge.ts +162 -0
  339. package/src/eval/js/worker-core.ts +132 -0
  340. package/src/eval/js/worker-entry.ts +30 -0
  341. package/src/eval/js/worker-protocol.ts +47 -0
  342. package/src/eval/py/__tests__/prelude.test.ts +19 -0
  343. package/src/eval/py/display.ts +71 -0
  344. package/src/eval/py/executor.ts +742 -0
  345. package/src/eval/py/index.ts +68 -0
  346. package/src/eval/py/kernel.ts +748 -0
  347. package/src/eval/py/prelude.py +658 -0
  348. package/src/eval/py/prelude.ts +3 -0
  349. package/src/eval/py/runner.py +1133 -0
  350. package/src/eval/py/runtime.ts +276 -0
  351. package/src/eval/py/spawn-options.ts +126 -0
  352. package/src/eval/py/tool-bridge.ts +182 -0
  353. package/src/eval/session-id.ts +8 -0
  354. package/src/eval/types.ts +48 -0
  355. package/src/exa/index.ts +2 -0
  356. package/src/exa/mcp-client.ts +370 -0
  357. package/src/exa/types.ts +69 -0
  358. package/src/exec/bash-executor.ts +419 -0
  359. package/src/exec/exec.ts +53 -0
  360. package/src/exec/non-interactive-env.ts +48 -0
  361. package/src/export/custom-share.ts +65 -0
  362. package/src/export/html/index.ts +164 -0
  363. package/src/export/html/template.css +1051 -0
  364. package/src/export/html/template.generated.ts +2 -0
  365. package/src/export/html/template.html +46 -0
  366. package/src/export/html/template.js +2271 -0
  367. package/src/export/html/template.macro.ts +25 -0
  368. package/src/export/html/vendor/highlight.min.js +1213 -0
  369. package/src/export/html/vendor/marked.min.js +6 -0
  370. package/src/export/ttsr.ts +583 -0
  371. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +54 -0
  372. package/src/extensibility/custom-commands/bundled/review/index.ts +489 -0
  373. package/src/extensibility/custom-commands/index.ts +2 -0
  374. package/src/extensibility/custom-commands/loader.ts +238 -0
  375. package/src/extensibility/custom-commands/types.ts +113 -0
  376. package/src/extensibility/custom-tools/index.ts +7 -0
  377. package/src/extensibility/custom-tools/loader.ts +269 -0
  378. package/src/extensibility/custom-tools/types.ts +270 -0
  379. package/src/extensibility/custom-tools/wrapper.ts +47 -0
  380. package/src/extensibility/extensions/compact-handler.ts +40 -0
  381. package/src/extensibility/extensions/get-commands-handler.ts +78 -0
  382. package/src/extensibility/extensions/index.ts +16 -0
  383. package/src/extensibility/extensions/loader.ts +572 -0
  384. package/src/extensibility/extensions/runner.ts +922 -0
  385. package/src/extensibility/extensions/types.ts +1322 -0
  386. package/src/extensibility/extensions/wrapper.ts +223 -0
  387. package/src/extensibility/hooks/index.ts +5 -0
  388. package/src/extensibility/hooks/loader.ts +257 -0
  389. package/src/extensibility/hooks/runner.ts +425 -0
  390. package/src/extensibility/hooks/tool-wrapper.ts +107 -0
  391. package/src/extensibility/hooks/types.ts +606 -0
  392. package/src/extensibility/legacy-pi-ai-shim.ts +24 -0
  393. package/src/extensibility/legacy-pi-coding-agent-shim.ts +15 -0
  394. package/src/extensibility/plugins/doctor.ts +65 -0
  395. package/src/extensibility/plugins/git-url.ts +367 -0
  396. package/src/extensibility/plugins/index.ts +9 -0
  397. package/src/extensibility/plugins/installer.ts +192 -0
  398. package/src/extensibility/plugins/legacy-pi-compat.ts +682 -0
  399. package/src/extensibility/plugins/loader.ts +313 -0
  400. package/src/extensibility/plugins/manager.ts +827 -0
  401. package/src/extensibility/plugins/marketplace/cache.ts +136 -0
  402. package/src/extensibility/plugins/marketplace/fetcher.ts +317 -0
  403. package/src/extensibility/plugins/marketplace/index.ts +6 -0
  404. package/src/extensibility/plugins/marketplace/manager.ts +770 -0
  405. package/src/extensibility/plugins/marketplace/registry.ts +196 -0
  406. package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
  407. package/src/extensibility/plugins/marketplace/types.ts +191 -0
  408. package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
  409. package/src/extensibility/plugins/parser.ts +105 -0
  410. package/src/extensibility/plugins/types.ts +194 -0
  411. package/src/extensibility/shared-events.ts +343 -0
  412. package/src/extensibility/skills.ts +312 -0
  413. package/src/extensibility/slash-commands.ts +227 -0
  414. package/src/extensibility/tool-proxy.ts +25 -0
  415. package/src/extensibility/typebox.ts +418 -0
  416. package/src/extensibility/utils.ts +44 -0
  417. package/src/goals/index.ts +3 -0
  418. package/src/goals/runtime.ts +528 -0
  419. package/src/goals/state.ts +37 -0
  420. package/src/goals/tools/goal-tool.ts +251 -0
  421. package/src/hindsight/backend.ts +354 -0
  422. package/src/hindsight/bank.ts +156 -0
  423. package/src/hindsight/client.ts +598 -0
  424. package/src/hindsight/config.ts +175 -0
  425. package/src/hindsight/content.ts +210 -0
  426. package/src/hindsight/index.ts +8 -0
  427. package/src/hindsight/mental-models.ts +429 -0
  428. package/src/hindsight/seeds.json +32 -0
  429. package/src/hindsight/state.ts +488 -0
  430. package/src/hindsight/transcript.ts +71 -0
  431. package/src/index.ts +59 -0
  432. package/src/internal-urls/agent-protocol.ts +146 -0
  433. package/src/internal-urls/artifact-protocol.ts +107 -0
  434. package/src/internal-urls/docs-index.generated.ts +106 -0
  435. package/src/internal-urls/history-protocol.ts +113 -0
  436. package/src/internal-urls/index.ts +25 -0
  437. package/src/internal-urls/issue-pr-protocol.ts +584 -0
  438. package/src/internal-urls/json-query.ts +126 -0
  439. package/src/internal-urls/local-protocol.ts +287 -0
  440. package/src/internal-urls/mcp-protocol.ts +151 -0
  441. package/src/internal-urls/memory-protocol.ts +169 -0
  442. package/src/internal-urls/omp-protocol.ts +93 -0
  443. package/src/internal-urls/parse.ts +72 -0
  444. package/src/internal-urls/registry-helpers.ts +25 -0
  445. package/src/internal-urls/router.ts +105 -0
  446. package/src/internal-urls/rule-protocol.ts +45 -0
  447. package/src/internal-urls/skill-protocol.ts +96 -0
  448. package/src/internal-urls/types.ts +152 -0
  449. package/src/internal-urls/vault-protocol.ts +936 -0
  450. package/src/irc/bus.ts +292 -0
  451. package/src/lib/xai-http.ts +124 -0
  452. package/src/lsp/client.ts +1193 -0
  453. package/src/lsp/clients/biome-client.ts +264 -0
  454. package/src/lsp/clients/index.ts +50 -0
  455. package/src/lsp/clients/lsp-linter-client.ts +93 -0
  456. package/src/lsp/clients/swiftlint-client.ts +120 -0
  457. package/src/lsp/config.ts +502 -0
  458. package/src/lsp/defaults.json +493 -0
  459. package/src/lsp/diagnostics-ledger.ts +51 -0
  460. package/src/lsp/edits.ts +267 -0
  461. package/src/lsp/index.ts +2477 -0
  462. package/src/lsp/lspmux.ts +233 -0
  463. package/src/lsp/render.ts +694 -0
  464. package/src/lsp/startup-events.ts +13 -0
  465. package/src/lsp/types.ts +455 -0
  466. package/src/lsp/utils.ts +718 -0
  467. package/src/main.ts +1325 -0
  468. package/src/mcp/client.ts +484 -0
  469. package/src/mcp/config-writer.ts +225 -0
  470. package/src/mcp/config.ts +365 -0
  471. package/src/mcp/index.ts +29 -0
  472. package/src/mcp/json-rpc.ts +122 -0
  473. package/src/mcp/loader.ts +124 -0
  474. package/src/mcp/manager.ts +1275 -0
  475. package/src/mcp/oauth-discovery.ts +442 -0
  476. package/src/mcp/oauth-flow.ts +442 -0
  477. package/src/mcp/render.ts +132 -0
  478. package/src/mcp/smithery-auth.ts +104 -0
  479. package/src/mcp/smithery-connect.ts +145 -0
  480. package/src/mcp/smithery-registry.ts +477 -0
  481. package/src/mcp/timeout.ts +59 -0
  482. package/src/mcp/tool-bridge.ts +426 -0
  483. package/src/mcp/tool-cache.ts +117 -0
  484. package/src/mcp/transports/http.ts +519 -0
  485. package/src/mcp/transports/index.ts +6 -0
  486. package/src/mcp/transports/stdio.ts +528 -0
  487. package/src/mcp/types.ts +423 -0
  488. package/src/memories/index.ts +1150 -0
  489. package/src/memories/storage.ts +577 -0
  490. package/src/memory-backend/index.ts +18 -0
  491. package/src/memory-backend/local-backend.ts +39 -0
  492. package/src/memory-backend/off-backend.ts +25 -0
  493. package/src/memory-backend/resolve.ts +25 -0
  494. package/src/memory-backend/runtime.ts +66 -0
  495. package/src/memory-backend/types.ts +166 -0
  496. package/src/mnemopi/backend.ts +547 -0
  497. package/src/mnemopi/config.ts +160 -0
  498. package/src/mnemopi/index.ts +3 -0
  499. package/src/mnemopi/state.ts +584 -0
  500. package/src/modes/acp/acp-agent.ts +2407 -0
  501. package/src/modes/acp/acp-client-bridge.ts +154 -0
  502. package/src/modes/acp/acp-event-mapper.ts +929 -0
  503. package/src/modes/acp/acp-mode.ts +23 -0
  504. package/src/modes/acp/index.ts +2 -0
  505. package/src/modes/acp/terminal-auth.ts +37 -0
  506. package/src/modes/components/agent-dashboard.ts +1206 -0
  507. package/src/modes/components/agent-hub.ts +1071 -0
  508. package/src/modes/components/assistant-message.ts +307 -0
  509. package/src/modes/components/bash-execution.ts +220 -0
  510. package/src/modes/components/bordered-loader.ts +41 -0
  511. package/src/modes/components/branch-summary-message.ts +45 -0
  512. package/src/modes/components/btw-panel.ts +104 -0
  513. package/src/modes/components/chat-block.ts +111 -0
  514. package/src/modes/components/compaction-summary-message.ts +87 -0
  515. package/src/modes/components/copy-selector.ts +206 -0
  516. package/src/modes/components/countdown-timer.ts +75 -0
  517. package/src/modes/components/custom-editor.ts +398 -0
  518. package/src/modes/components/custom-message.ts +63 -0
  519. package/src/modes/components/diff.ts +277 -0
  520. package/src/modes/components/dynamic-border.ts +34 -0
  521. package/src/modes/components/error-banner.ts +33 -0
  522. package/src/modes/components/eval-execution.ts +158 -0
  523. package/src/modes/components/execution-shared.ts +101 -0
  524. package/src/modes/components/extensions/extension-dashboard.ts +399 -0
  525. package/src/modes/components/extensions/extension-list.ts +502 -0
  526. package/src/modes/components/extensions/index.ts +9 -0
  527. package/src/modes/components/extensions/inspector-panel.ts +317 -0
  528. package/src/modes/components/extensions/state-manager.ts +627 -0
  529. package/src/modes/components/extensions/types.ts +186 -0
  530. package/src/modes/components/footer.ts +274 -0
  531. package/src/modes/components/history-search.ts +280 -0
  532. package/src/modes/components/hook-editor.ts +167 -0
  533. package/src/modes/components/hook-input.ts +87 -0
  534. package/src/modes/components/hook-message.ts +66 -0
  535. package/src/modes/components/hook-selector.ts +660 -0
  536. package/src/modes/components/index.ts +38 -0
  537. package/src/modes/components/keybinding-hints.ts +65 -0
  538. package/src/modes/components/late-diagnostics-message.ts +60 -0
  539. package/src/modes/components/login-dialog.ts +164 -0
  540. package/src/modes/components/mcp-add-wizard.ts +1340 -0
  541. package/src/modes/components/message-frame.ts +88 -0
  542. package/src/modes/components/model-selector.ts +1271 -0
  543. package/src/modes/components/oauth-selector.ts +368 -0
  544. package/src/modes/components/omfg-panel.ts +141 -0
  545. package/src/modes/components/overlay-box.ts +108 -0
  546. package/src/modes/components/plan-review-overlay.ts +820 -0
  547. package/src/modes/components/plan-toc.ts +138 -0
  548. package/src/modes/components/plugin-selector.ts +95 -0
  549. package/src/modes/components/plugin-settings.ts +722 -0
  550. package/src/modes/components/queue-mode-selector.ts +56 -0
  551. package/src/modes/components/read-tool-group.ts +670 -0
  552. package/src/modes/components/segment-track.ts +52 -0
  553. package/src/modes/components/session-selector.ts +625 -0
  554. package/src/modes/components/settings-defs.ts +189 -0
  555. package/src/modes/components/settings-selector.ts +651 -0
  556. package/src/modes/components/show-images-selector.ts +45 -0
  557. package/src/modes/components/skill-message.ts +89 -0
  558. package/src/modes/components/status-line/component.ts +869 -0
  559. package/src/modes/components/status-line/context-thresholds.ts +79 -0
  560. package/src/modes/components/status-line/git-utils.ts +42 -0
  561. package/src/modes/components/status-line/index.ts +5 -0
  562. package/src/modes/components/status-line/presets.ts +106 -0
  563. package/src/modes/components/status-line/segments.ts +584 -0
  564. package/src/modes/components/status-line/separators.ts +55 -0
  565. package/src/modes/components/status-line/token-rate.ts +66 -0
  566. package/src/modes/components/status-line/types.ts +108 -0
  567. package/src/modes/components/theme-selector.ts +63 -0
  568. package/src/modes/components/thinking-selector.ts +52 -0
  569. package/src/modes/components/tiny-title-download-progress.ts +90 -0
  570. package/src/modes/components/tips.txt +19 -0
  571. package/src/modes/components/todo-reminder.ts +38 -0
  572. package/src/modes/components/tool-execution.ts +1024 -0
  573. package/src/modes/components/transcript-container.ts +608 -0
  574. package/src/modes/components/tree-selector.ts +978 -0
  575. package/src/modes/components/ttsr-notification.ts +122 -0
  576. package/src/modes/components/user-message-selector.ts +227 -0
  577. package/src/modes/components/user-message.ts +66 -0
  578. package/src/modes/components/visual-truncate.ts +63 -0
  579. package/src/modes/components/welcome.ts +493 -0
  580. package/src/modes/controllers/btw-controller.ts +105 -0
  581. package/src/modes/controllers/command-controller-shared.ts +109 -0
  582. package/src/modes/controllers/command-controller.ts +1566 -0
  583. package/src/modes/controllers/event-controller.ts +1054 -0
  584. package/src/modes/controllers/extension-ui-controller.ts +886 -0
  585. package/src/modes/controllers/input-controller.ts +1073 -0
  586. package/src/modes/controllers/mcp-command-controller.ts +2017 -0
  587. package/src/modes/controllers/omfg-controller.ts +283 -0
  588. package/src/modes/controllers/omfg-rule.ts +647 -0
  589. package/src/modes/controllers/selector-controller.ts +1108 -0
  590. package/src/modes/controllers/ssh-command-controller.ts +384 -0
  591. package/src/modes/controllers/streaming-reveal.ts +279 -0
  592. package/src/modes/controllers/tan-command-controller.ts +173 -0
  593. package/src/modes/controllers/todo-command-controller.ts +485 -0
  594. package/src/modes/data/emojis.json +1 -0
  595. package/src/modes/emoji-autocomplete.ts +285 -0
  596. package/src/modes/gradient-highlight.ts +87 -0
  597. package/src/modes/image-references.ts +117 -0
  598. package/src/modes/index.ts +17 -0
  599. package/src/modes/interactive-mode.ts +3370 -0
  600. package/src/modes/internal-url-autocomplete.ts +143 -0
  601. package/src/modes/loop-limit.ts +140 -0
  602. package/src/modes/magic-keywords.ts +20 -0
  603. package/src/modes/markdown-prose.ts +247 -0
  604. package/src/modes/oauth-manual-input.ts +69 -0
  605. package/src/modes/orchestrate.ts +42 -0
  606. package/src/modes/print-mode.ts +126 -0
  607. package/src/modes/prompt-action-autocomplete.ts +260 -0
  608. package/src/modes/rpc/host-tools.ts +186 -0
  609. package/src/modes/rpc/host-uris.ts +235 -0
  610. package/src/modes/rpc/rpc-client.ts +963 -0
  611. package/src/modes/rpc/rpc-mode.ts +947 -0
  612. package/src/modes/rpc/rpc-subagents.ts +265 -0
  613. package/src/modes/rpc/rpc-types.ts +458 -0
  614. package/src/modes/runtime-init.ts +116 -0
  615. package/src/modes/session-observer-registry.ts +146 -0
  616. package/src/modes/setup-version.ts +11 -0
  617. package/src/modes/setup-wizard/index.ts +99 -0
  618. package/src/modes/setup-wizard/lazy.ts +16 -0
  619. package/src/modes/setup-wizard/scenes/glyph.ts +96 -0
  620. package/src/modes/setup-wizard/scenes/outro.ts +35 -0
  621. package/src/modes/setup-wizard/scenes/providers.ts +69 -0
  622. package/src/modes/setup-wizard/scenes/sign-in.ts +205 -0
  623. package/src/modes/setup-wizard/scenes/splash.ts +201 -0
  624. package/src/modes/setup-wizard/scenes/theme.ts +299 -0
  625. package/src/modes/setup-wizard/scenes/types.ts +48 -0
  626. package/src/modes/setup-wizard/scenes/web-search.ts +129 -0
  627. package/src/modes/setup-wizard/wizard-overlay.ts +275 -0
  628. package/src/modes/shared.ts +47 -0
  629. package/src/modes/theme/dark.json +95 -0
  630. package/src/modes/theme/defaults/alabaster.json +93 -0
  631. package/src/modes/theme/defaults/amethyst.json +96 -0
  632. package/src/modes/theme/defaults/anthracite.json +93 -0
  633. package/src/modes/theme/defaults/basalt.json +91 -0
  634. package/src/modes/theme/defaults/birch.json +95 -0
  635. package/src/modes/theme/defaults/dark-abyss.json +91 -0
  636. package/src/modes/theme/defaults/dark-arctic.json +104 -0
  637. package/src/modes/theme/defaults/dark-aurora.json +95 -0
  638. package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
  639. package/src/modes/theme/defaults/dark-cavern.json +91 -0
  640. package/src/modes/theme/defaults/dark-copper.json +95 -0
  641. package/src/modes/theme/defaults/dark-cosmos.json +90 -0
  642. package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
  643. package/src/modes/theme/defaults/dark-dracula.json +98 -0
  644. package/src/modes/theme/defaults/dark-eclipse.json +91 -0
  645. package/src/modes/theme/defaults/dark-ember.json +95 -0
  646. package/src/modes/theme/defaults/dark-equinox.json +90 -0
  647. package/src/modes/theme/defaults/dark-forest.json +96 -0
  648. package/src/modes/theme/defaults/dark-github.json +105 -0
  649. package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
  650. package/src/modes/theme/defaults/dark-lavender.json +95 -0
  651. package/src/modes/theme/defaults/dark-lunar.json +89 -0
  652. package/src/modes/theme/defaults/dark-midnight.json +95 -0
  653. package/src/modes/theme/defaults/dark-monochrome.json +94 -0
  654. package/src/modes/theme/defaults/dark-monokai.json +98 -0
  655. package/src/modes/theme/defaults/dark-nebula.json +90 -0
  656. package/src/modes/theme/defaults/dark-nord.json +97 -0
  657. package/src/modes/theme/defaults/dark-ocean.json +101 -0
  658. package/src/modes/theme/defaults/dark-one.json +100 -0
  659. package/src/modes/theme/defaults/dark-poimandres.json +142 -0
  660. package/src/modes/theme/defaults/dark-rainforest.json +91 -0
  661. package/src/modes/theme/defaults/dark-reef.json +91 -0
  662. package/src/modes/theme/defaults/dark-retro.json +92 -0
  663. package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
  664. package/src/modes/theme/defaults/dark-sakura.json +95 -0
  665. package/src/modes/theme/defaults/dark-slate.json +95 -0
  666. package/src/modes/theme/defaults/dark-solarized.json +97 -0
  667. package/src/modes/theme/defaults/dark-solstice.json +90 -0
  668. package/src/modes/theme/defaults/dark-starfall.json +91 -0
  669. package/src/modes/theme/defaults/dark-sunset.json +99 -0
  670. package/src/modes/theme/defaults/dark-swamp.json +90 -0
  671. package/src/modes/theme/defaults/dark-synthwave.json +103 -0
  672. package/src/modes/theme/defaults/dark-taiga.json +91 -0
  673. package/src/modes/theme/defaults/dark-terminal.json +95 -0
  674. package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
  675. package/src/modes/theme/defaults/dark-tundra.json +91 -0
  676. package/src/modes/theme/defaults/dark-twilight.json +91 -0
  677. package/src/modes/theme/defaults/dark-volcanic.json +91 -0
  678. package/src/modes/theme/defaults/graphite.json +92 -0
  679. package/src/modes/theme/defaults/index.ts +199 -0
  680. package/src/modes/theme/defaults/light-arctic.json +107 -0
  681. package/src/modes/theme/defaults/light-aurora-day.json +91 -0
  682. package/src/modes/theme/defaults/light-canyon.json +91 -0
  683. package/src/modes/theme/defaults/light-catppuccin.json +106 -0
  684. package/src/modes/theme/defaults/light-cirrus.json +90 -0
  685. package/src/modes/theme/defaults/light-coral.json +95 -0
  686. package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
  687. package/src/modes/theme/defaults/light-dawn.json +90 -0
  688. package/src/modes/theme/defaults/light-dunes.json +91 -0
  689. package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
  690. package/src/modes/theme/defaults/light-forest.json +100 -0
  691. package/src/modes/theme/defaults/light-frost.json +95 -0
  692. package/src/modes/theme/defaults/light-github.json +115 -0
  693. package/src/modes/theme/defaults/light-glacier.json +91 -0
  694. package/src/modes/theme/defaults/light-gruvbox.json +108 -0
  695. package/src/modes/theme/defaults/light-haze.json +90 -0
  696. package/src/modes/theme/defaults/light-honeycomb.json +95 -0
  697. package/src/modes/theme/defaults/light-lagoon.json +91 -0
  698. package/src/modes/theme/defaults/light-lavender.json +95 -0
  699. package/src/modes/theme/defaults/light-meadow.json +91 -0
  700. package/src/modes/theme/defaults/light-mint.json +95 -0
  701. package/src/modes/theme/defaults/light-monochrome.json +101 -0
  702. package/src/modes/theme/defaults/light-ocean.json +99 -0
  703. package/src/modes/theme/defaults/light-one.json +99 -0
  704. package/src/modes/theme/defaults/light-opal.json +91 -0
  705. package/src/modes/theme/defaults/light-orchard.json +91 -0
  706. package/src/modes/theme/defaults/light-paper.json +95 -0
  707. package/src/modes/theme/defaults/light-poimandres.json +142 -0
  708. package/src/modes/theme/defaults/light-prism.json +90 -0
  709. package/src/modes/theme/defaults/light-retro.json +98 -0
  710. package/src/modes/theme/defaults/light-sand.json +95 -0
  711. package/src/modes/theme/defaults/light-savanna.json +91 -0
  712. package/src/modes/theme/defaults/light-solarized.json +102 -0
  713. package/src/modes/theme/defaults/light-soleil.json +90 -0
  714. package/src/modes/theme/defaults/light-sunset.json +99 -0
  715. package/src/modes/theme/defaults/light-synthwave.json +98 -0
  716. package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
  717. package/src/modes/theme/defaults/light-wetland.json +91 -0
  718. package/src/modes/theme/defaults/light-zenith.json +89 -0
  719. package/src/modes/theme/defaults/limestone.json +94 -0
  720. package/src/modes/theme/defaults/mahogany.json +97 -0
  721. package/src/modes/theme/defaults/marble.json +93 -0
  722. package/src/modes/theme/defaults/obsidian.json +91 -0
  723. package/src/modes/theme/defaults/onyx.json +91 -0
  724. package/src/modes/theme/defaults/pearl.json +93 -0
  725. package/src/modes/theme/defaults/porcelain.json +91 -0
  726. package/src/modes/theme/defaults/quartz.json +96 -0
  727. package/src/modes/theme/defaults/sandstone.json +95 -0
  728. package/src/modes/theme/defaults/titanium.json +90 -0
  729. package/src/modes/theme/light.json +93 -0
  730. package/src/modes/theme/mermaid-cache.ts +29 -0
  731. package/src/modes/theme/shimmer.ts +235 -0
  732. package/src/modes/theme/theme-schema.json +459 -0
  733. package/src/modes/theme/theme.ts +2676 -0
  734. package/src/modes/turn-budget.ts +31 -0
  735. package/src/modes/types.ts +359 -0
  736. package/src/modes/ultrathink.ts +41 -0
  737. package/src/modes/utils/context-usage.ts +339 -0
  738. package/src/modes/utils/copy-targets.ts +360 -0
  739. package/src/modes/utils/hotkeys-markdown.ts +61 -0
  740. package/src/modes/utils/keybinding-matchers.ts +51 -0
  741. package/src/modes/utils/tools-markdown.ts +27 -0
  742. package/src/modes/utils/ui-helpers.ts +801 -0
  743. package/src/modes/workflow.ts +42 -0
  744. package/src/plan-mode/approved-plan.ts +186 -0
  745. package/src/plan-mode/plan-handoff.ts +37 -0
  746. package/src/plan-mode/plan-protection.ts +31 -0
  747. package/src/plan-mode/state.ts +6 -0
  748. package/src/priority.json +41 -0
  749. package/src/prompts/agents/designer.md +66 -0
  750. package/src/prompts/agents/explore.md +58 -0
  751. package/src/prompts/agents/frontmatter.md +11 -0
  752. package/src/prompts/agents/init.md +33 -0
  753. package/src/prompts/agents/librarian.md +119 -0
  754. package/src/prompts/agents/oracle.md +55 -0
  755. package/src/prompts/agents/plan.md +48 -0
  756. package/src/prompts/agents/reviewer.md +140 -0
  757. package/src/prompts/agents/task.md +16 -0
  758. package/src/prompts/ci-green-request.md +36 -0
  759. package/src/prompts/dry-balance-bench.md +8 -0
  760. package/src/prompts/goals/goal-budget-limit.md +16 -0
  761. package/src/prompts/goals/goal-continuation.md +28 -0
  762. package/src/prompts/goals/goal-mode-active.md +23 -0
  763. package/src/prompts/memories/consolidation.md +30 -0
  764. package/src/prompts/memories/read-path.md +11 -0
  765. package/src/prompts/memories/stage_one_input.md +6 -0
  766. package/src/prompts/memories/stage_one_system.md +21 -0
  767. package/src/prompts/review-custom-request.md +22 -0
  768. package/src/prompts/review-headless-request.md +16 -0
  769. package/src/prompts/review-request.md +69 -0
  770. package/src/prompts/steering/user-interjection.md +10 -0
  771. package/src/prompts/system/agent-creation-architect.md +50 -0
  772. package/src/prompts/system/agent-creation-user.md +6 -0
  773. package/src/prompts/system/auto-continue.md +1 -0
  774. package/src/prompts/system/auto-thinking-difficulty-local.md +14 -0
  775. package/src/prompts/system/auto-thinking-difficulty.md +12 -0
  776. package/src/prompts/system/background-tan-dispatch.md +8 -0
  777. package/src/prompts/system/btw-user.md +8 -0
  778. package/src/prompts/system/commit-message-system.md +14 -0
  779. package/src/prompts/system/custom-system-prompt.md +64 -0
  780. package/src/prompts/system/eager-todo.md +13 -0
  781. package/src/prompts/system/empty-stop-retry.md +6 -0
  782. package/src/prompts/system/irc-incoming.md +7 -0
  783. package/src/prompts/system/manual-continue.md +7 -0
  784. package/src/prompts/system/memory-consolidation-system.md +8 -0
  785. package/src/prompts/system/memory-extraction-system.md +26 -0
  786. package/src/prompts/system/omfg-user.md +50 -0
  787. package/src/prompts/system/orchestrate-notice.md +40 -0
  788. package/src/prompts/system/plan-mode-active.md +109 -0
  789. package/src/prompts/system/plan-mode-approved.md +25 -0
  790. package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
  791. package/src/prompts/system/plan-mode-reference.md +11 -0
  792. package/src/prompts/system/plan-mode-subagent.md +33 -0
  793. package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
  794. package/src/prompts/system/project-prompt.md +52 -0
  795. package/src/prompts/system/subagent-system-prompt.md +64 -0
  796. package/src/prompts/system/subagent-user-prompt.md +3 -0
  797. package/src/prompts/system/subagent-yield-reminder.md +12 -0
  798. package/src/prompts/system/system-prompt.md +258 -0
  799. package/src/prompts/system/tiny-title-system.md +8 -0
  800. package/src/prompts/system/title-system.md +16 -0
  801. package/src/prompts/system/ttsr-interrupt.md +7 -0
  802. package/src/prompts/system/ttsr-tool-reminder.md +5 -0
  803. package/src/prompts/system/ultrathink-notice.md +3 -0
  804. package/src/prompts/system/web-search.md +25 -0
  805. package/src/prompts/system/workflow-notice.md +70 -0
  806. package/src/prompts/tools/apply-patch.md +65 -0
  807. package/src/prompts/tools/ask.md +30 -0
  808. package/src/prompts/tools/ast-edit.md +39 -0
  809. package/src/prompts/tools/ast-grep.md +42 -0
  810. package/src/prompts/tools/async-result.md +8 -0
  811. package/src/prompts/tools/bash.md +46 -0
  812. package/src/prompts/tools/browser.md +73 -0
  813. package/src/prompts/tools/checkpoint.md +16 -0
  814. package/src/prompts/tools/debug.md +34 -0
  815. package/src/prompts/tools/eval.md +92 -0
  816. package/src/prompts/tools/find.md +36 -0
  817. package/src/prompts/tools/github.md +21 -0
  818. package/src/prompts/tools/goal.md +18 -0
  819. package/src/prompts/tools/image-gen.md +7 -0
  820. package/src/prompts/tools/inspect-image-system.md +20 -0
  821. package/src/prompts/tools/inspect-image.md +32 -0
  822. package/src/prompts/tools/irc.md +59 -0
  823. package/src/prompts/tools/job.md +19 -0
  824. package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
  825. package/src/prompts/tools/lsp.md +42 -0
  826. package/src/prompts/tools/memory-edit.md +8 -0
  827. package/src/prompts/tools/patch.md +70 -0
  828. package/src/prompts/tools/read.md +84 -0
  829. package/src/prompts/tools/recall.md +5 -0
  830. package/src/prompts/tools/reflect.md +5 -0
  831. package/src/prompts/tools/render-mermaid.md +9 -0
  832. package/src/prompts/tools/replace.md +30 -0
  833. package/src/prompts/tools/resolve.md +9 -0
  834. package/src/prompts/tools/retain.md +6 -0
  835. package/src/prompts/tools/rewind.md +13 -0
  836. package/src/prompts/tools/search-tool-bm25.md +32 -0
  837. package/src/prompts/tools/search.md +24 -0
  838. package/src/prompts/tools/ssh.md +31 -0
  839. package/src/prompts/tools/task-summary.md +17 -0
  840. package/src/prompts/tools/task.md +88 -0
  841. package/src/prompts/tools/todo.md +62 -0
  842. package/src/prompts/tools/web-search.md +10 -0
  843. package/src/prompts/tools/write.md +14 -0
  844. package/src/registry/agent-lifecycle.ts +218 -0
  845. package/src/registry/agent-registry.ts +151 -0
  846. package/src/sdk.ts +2558 -0
  847. package/src/secrets/index.ts +123 -0
  848. package/src/secrets/obfuscator.ts +298 -0
  849. package/src/secrets/regex.ts +21 -0
  850. package/src/session/agent-session.ts +10121 -0
  851. package/src/session/agent-storage.ts +455 -0
  852. package/src/session/artifacts.ts +135 -0
  853. package/src/session/auth-broker-config.ts +131 -0
  854. package/src/session/auth-storage.ts +29 -0
  855. package/src/session/blob-store.ts +255 -0
  856. package/src/session/client-bridge.ts +85 -0
  857. package/src/session/history-storage.ts +348 -0
  858. package/src/session/indexed-session-storage.ts +430 -0
  859. package/src/session/messages.ts +541 -0
  860. package/src/session/redis-session-storage.ts +170 -0
  861. package/src/session/session-dump-format.ts +209 -0
  862. package/src/session/session-history-format.ts +246 -0
  863. package/src/session/session-manager.ts +3676 -0
  864. package/src/session/session-storage.ts +529 -0
  865. package/src/session/shake-types.ts +43 -0
  866. package/src/session/sql-session-storage.ts +314 -0
  867. package/src/session/streaming-output.ts +1330 -0
  868. package/src/session/tool-choice-queue.ts +213 -0
  869. package/src/session/yield-queue.ts +173 -0
  870. package/src/slash-commands/acp-builtins.ts +70 -0
  871. package/src/slash-commands/builtin-registry.ts +1798 -0
  872. package/src/slash-commands/helpers/context-report.ts +39 -0
  873. package/src/slash-commands/helpers/format.ts +46 -0
  874. package/src/slash-commands/helpers/marketplace-manager.ts +25 -0
  875. package/src/slash-commands/helpers/mcp.ts +532 -0
  876. package/src/slash-commands/helpers/parse.ts +85 -0
  877. package/src/slash-commands/helpers/ssh.ts +195 -0
  878. package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
  879. package/src/slash-commands/helpers/todo.ts +279 -0
  880. package/src/slash-commands/helpers/usage-report.ts +95 -0
  881. package/src/slash-commands/marketplace-install-parser.ts +99 -0
  882. package/src/slash-commands/types.ts +135 -0
  883. package/src/ssh/config-writer.ts +183 -0
  884. package/src/ssh/connection-manager.ts +509 -0
  885. package/src/ssh/ssh-executor.ts +189 -0
  886. package/src/ssh/sshfs-mount.ts +140 -0
  887. package/src/ssh/utils.ts +8 -0
  888. package/src/stt/downloader.ts +71 -0
  889. package/src/stt/index.ts +3 -0
  890. package/src/stt/recorder.ts +351 -0
  891. package/src/stt/setup.ts +52 -0
  892. package/src/stt/stt-controller.ts +160 -0
  893. package/src/stt/transcribe.py +70 -0
  894. package/src/stt/transcriber.ts +91 -0
  895. package/src/stubs/natives/index.ts +814 -0
  896. package/src/stubs/natives/package.json +7 -0
  897. package/src/stubs/tui/index.ts +282 -0
  898. package/src/stubs/tui/package.json +7 -0
  899. package/src/system-prompt.ts +611 -0
  900. package/src/task/agents.ts +167 -0
  901. package/src/task/commands.ts +132 -0
  902. package/src/task/discovery.ts +122 -0
  903. package/src/task/executor.ts +2133 -0
  904. package/src/task/index.ts +1419 -0
  905. package/src/task/name-generator.ts +1577 -0
  906. package/src/task/omp-command.ts +26 -0
  907. package/src/task/output-manager.ts +88 -0
  908. package/src/task/parallel.ts +116 -0
  909. package/src/task/render.ts +1381 -0
  910. package/src/task/repair-args.ts +129 -0
  911. package/src/task/subprocess-tool-registry.ts +88 -0
  912. package/src/task/types.ts +336 -0
  913. package/src/task/worktree.ts +514 -0
  914. package/src/telemetry-export.ts +144 -0
  915. package/src/thinking.ts +167 -0
  916. package/src/tiny/compiled-runtime.ts +179 -0
  917. package/src/tiny/device.ts +111 -0
  918. package/src/tiny/dtype.ts +101 -0
  919. package/src/tiny/models.ts +242 -0
  920. package/src/tiny/text.ts +165 -0
  921. package/src/tiny/title-client.ts +543 -0
  922. package/src/tiny/title-protocol.ts +56 -0
  923. package/src/tiny/worker.ts +568 -0
  924. package/src/tool-discovery/mode.ts +24 -0
  925. package/src/tool-discovery/tool-index.ts +256 -0
  926. package/src/tools/approval.ts +189 -0
  927. package/src/tools/archive-reader.ts +721 -0
  928. package/src/tools/ask.ts +928 -0
  929. package/src/tools/ast-edit.ts +642 -0
  930. package/src/tools/ast-grep.ts +452 -0
  931. package/src/tools/auto-generated-guard.ts +322 -0
  932. package/src/tools/bash-command-fixup.ts +37 -0
  933. package/src/tools/bash-interactive.ts +408 -0
  934. package/src/tools/bash-interceptor.ts +67 -0
  935. package/src/tools/bash-pty-selection.ts +14 -0
  936. package/src/tools/bash-skill-urls.ts +248 -0
  937. package/src/tools/bash.ts +1386 -0
  938. package/src/tools/browser/attach.ts +175 -0
  939. package/src/tools/browser/launch.ts +660 -0
  940. package/src/tools/browser/readable.ts +112 -0
  941. package/src/tools/browser/registry.ts +197 -0
  942. package/src/tools/browser/render.ts +216 -0
  943. package/src/tools/browser/tab-protocol.ts +105 -0
  944. package/src/tools/browser/tab-supervisor.ts +628 -0
  945. package/src/tools/browser/tab-worker-entry.ts +21 -0
  946. package/src/tools/browser/tab-worker.ts +1226 -0
  947. package/src/tools/browser.ts +343 -0
  948. package/src/tools/checkpoint.ts +136 -0
  949. package/src/tools/conflict-detect.ts +718 -0
  950. package/src/tools/context.ts +39 -0
  951. package/src/tools/debug.ts +1067 -0
  952. package/src/tools/eval-backends.ts +27 -0
  953. package/src/tools/eval-render.ts +752 -0
  954. package/src/tools/eval.ts +577 -0
  955. package/src/tools/fetch.ts +1926 -0
  956. package/src/tools/file-recorder.ts +35 -0
  957. package/src/tools/find.ts +609 -0
  958. package/src/tools/fs-cache-invalidation.ts +28 -0
  959. package/src/tools/gh-cache-invalidation.ts +255 -0
  960. package/src/tools/gh-format.ts +12 -0
  961. package/src/tools/gh-renderer.ts +481 -0
  962. package/src/tools/gh.ts +3720 -0
  963. package/src/tools/github-cache.ts +637 -0
  964. package/src/tools/grouped-file-output.ts +210 -0
  965. package/src/tools/image-gen.ts +1517 -0
  966. package/src/tools/index.ts +599 -0
  967. package/src/tools/inspect-image-renderer.ts +132 -0
  968. package/src/tools/inspect-image.ts +174 -0
  969. package/src/tools/irc.ts +723 -0
  970. package/src/tools/job.ts +557 -0
  971. package/src/tools/json-tree.ts +243 -0
  972. package/src/tools/jtd-to-json-schema.ts +219 -0
  973. package/src/tools/jtd-to-typescript.ts +136 -0
  974. package/src/tools/jtd-utils.ts +102 -0
  975. package/src/tools/list-limit.ts +40 -0
  976. package/src/tools/match-line-format.ts +20 -0
  977. package/src/tools/memory-edit.ts +59 -0
  978. package/src/tools/memory-recall.ts +100 -0
  979. package/src/tools/memory-reflect.ts +88 -0
  980. package/src/tools/memory-render.ts +202 -0
  981. package/src/tools/memory-retain.ts +91 -0
  982. package/src/tools/output-meta.ts +754 -0
  983. package/src/tools/output-schema-validator.ts +132 -0
  984. package/src/tools/path-utils.ts +1054 -0
  985. package/src/tools/plan-mode-guard.ts +108 -0
  986. package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
  987. package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
  988. package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
  989. package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
  990. package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
  991. package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
  992. package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
  993. package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
  994. package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
  995. package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
  996. package/src/tools/puppeteer/10_stealth_plugins.txt +206 -0
  997. package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
  998. package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
  999. package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
  1000. package/src/tools/read.ts +2929 -0
  1001. package/src/tools/render-mermaid.ts +69 -0
  1002. package/src/tools/render-utils.ts +838 -0
  1003. package/src/tools/renderers.ts +77 -0
  1004. package/src/tools/report-tool-issue.ts +534 -0
  1005. package/src/tools/resolve.ts +276 -0
  1006. package/src/tools/review.ts +253 -0
  1007. package/src/tools/search-tool-bm25.ts +351 -0
  1008. package/src/tools/search.ts +1580 -0
  1009. package/src/tools/sqlite-reader.ts +828 -0
  1010. package/src/tools/ssh.ts +349 -0
  1011. package/src/tools/todo.ts +982 -0
  1012. package/src/tools/tool-errors.ts +62 -0
  1013. package/src/tools/tool-result.ts +94 -0
  1014. package/src/tools/tool-timeouts.ts +30 -0
  1015. package/src/tools/tts.ts +133 -0
  1016. package/src/tools/write.ts +1217 -0
  1017. package/src/tools/yield.ts +269 -0
  1018. package/src/tui/code-cell.ts +216 -0
  1019. package/src/tui/file-list.ts +55 -0
  1020. package/src/tui/hyperlink.ts +175 -0
  1021. package/src/tui/index.ts +12 -0
  1022. package/src/tui/output-block.ts +240 -0
  1023. package/src/tui/status-line.ts +54 -0
  1024. package/src/tui/tree-list.ts +84 -0
  1025. package/src/tui/types.ts +15 -0
  1026. package/src/tui/utils.ts +103 -0
  1027. package/src/utils/block-context.ts +312 -0
  1028. package/src/utils/changelog.ts +132 -0
  1029. package/src/utils/clipboard.ts +193 -0
  1030. package/src/utils/command-args.ts +76 -0
  1031. package/src/utils/commit-message-generator.ts +151 -0
  1032. package/src/utils/edit-mode.ts +41 -0
  1033. package/src/utils/enhanced-paste.ts +230 -0
  1034. package/src/utils/event-bus.ts +33 -0
  1035. package/src/utils/external-editor.ts +65 -0
  1036. package/src/utils/file-display-mode.ts +45 -0
  1037. package/src/utils/file-mentions.ts +281 -0
  1038. package/src/utils/git.ts +1833 -0
  1039. package/src/utils/image-loading.ts +132 -0
  1040. package/src/utils/image-resize.ts +309 -0
  1041. package/src/utils/jj.ts +248 -0
  1042. package/src/utils/lang-from-path.ts +239 -0
  1043. package/src/utils/markit.ts +89 -0
  1044. package/src/utils/open.ts +55 -0
  1045. package/src/utils/session-color.ts +68 -0
  1046. package/src/utils/shell-snapshot.ts +187 -0
  1047. package/src/utils/sixel.ts +69 -0
  1048. package/src/utils/title-generator.ts +373 -0
  1049. package/src/utils/tool-choice.ts +33 -0
  1050. package/src/utils/tools-manager.ts +363 -0
  1051. package/src/web/kagi.ts +305 -0
  1052. package/src/web/parallel.ts +353 -0
  1053. package/src/web/scrapers/artifacthub.ts +207 -0
  1054. package/src/web/scrapers/arxiv.ts +83 -0
  1055. package/src/web/scrapers/aur.ts +162 -0
  1056. package/src/web/scrapers/biorxiv.ts +133 -0
  1057. package/src/web/scrapers/bluesky.ts +262 -0
  1058. package/src/web/scrapers/brew.ts +172 -0
  1059. package/src/web/scrapers/cheatsh.ts +68 -0
  1060. package/src/web/scrapers/chocolatey.ts +196 -0
  1061. package/src/web/scrapers/choosealicense.ts +95 -0
  1062. package/src/web/scrapers/cisa-kev.ts +87 -0
  1063. package/src/web/scrapers/clojars.ts +154 -0
  1064. package/src/web/scrapers/coingecko.ts +177 -0
  1065. package/src/web/scrapers/crates-io.ts +97 -0
  1066. package/src/web/scrapers/crossref.ts +136 -0
  1067. package/src/web/scrapers/devto.ts +147 -0
  1068. package/src/web/scrapers/discogs.ts +306 -0
  1069. package/src/web/scrapers/discourse.ts +197 -0
  1070. package/src/web/scrapers/dockerhub.ts +138 -0
  1071. package/src/web/scrapers/docs-rs.ts +653 -0
  1072. package/src/web/scrapers/fdroid.ts +134 -0
  1073. package/src/web/scrapers/firefox-addons.ts +191 -0
  1074. package/src/web/scrapers/flathub.ts +223 -0
  1075. package/src/web/scrapers/github-gist.ts +58 -0
  1076. package/src/web/scrapers/github.ts +704 -0
  1077. package/src/web/scrapers/gitlab.ts +401 -0
  1078. package/src/web/scrapers/go-pkg.ts +266 -0
  1079. package/src/web/scrapers/hackage.ts +140 -0
  1080. package/src/web/scrapers/hackernews.ts +189 -0
  1081. package/src/web/scrapers/hex.ts +105 -0
  1082. package/src/web/scrapers/huggingface.ts +321 -0
  1083. package/src/web/scrapers/iacr.ts +89 -0
  1084. package/src/web/scrapers/index.ts +252 -0
  1085. package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
  1086. package/src/web/scrapers/lemmy.ts +203 -0
  1087. package/src/web/scrapers/lobsters.ts +175 -0
  1088. package/src/web/scrapers/mastodon.ts +292 -0
  1089. package/src/web/scrapers/maven.ts +138 -0
  1090. package/src/web/scrapers/mdn.ts +173 -0
  1091. package/src/web/scrapers/metacpan.ts +222 -0
  1092. package/src/web/scrapers/musicbrainz.ts +250 -0
  1093. package/src/web/scrapers/npm.ts +98 -0
  1094. package/src/web/scrapers/nuget.ts +183 -0
  1095. package/src/web/scrapers/nvd.ts +222 -0
  1096. package/src/web/scrapers/ollama.ts +239 -0
  1097. package/src/web/scrapers/open-vsx.ts +106 -0
  1098. package/src/web/scrapers/opencorporates.ts +292 -0
  1099. package/src/web/scrapers/openlibrary.ts +336 -0
  1100. package/src/web/scrapers/orcid.ts +286 -0
  1101. package/src/web/scrapers/osv.ts +176 -0
  1102. package/src/web/scrapers/packagist.ts +160 -0
  1103. package/src/web/scrapers/pub-dev.ts +143 -0
  1104. package/src/web/scrapers/pubmed.ts +211 -0
  1105. package/src/web/scrapers/pypi.ts +112 -0
  1106. package/src/web/scrapers/rawg.ts +110 -0
  1107. package/src/web/scrapers/readthedocs.ts +120 -0
  1108. package/src/web/scrapers/reddit.ts +95 -0
  1109. package/src/web/scrapers/repology.ts +251 -0
  1110. package/src/web/scrapers/rfc.ts +201 -0
  1111. package/src/web/scrapers/rubygems.ts +103 -0
  1112. package/src/web/scrapers/searchcode.ts +189 -0
  1113. package/src/web/scrapers/sec-edgar.ts +261 -0
  1114. package/src/web/scrapers/semantic-scholar.ts +171 -0
  1115. package/src/web/scrapers/snapcraft.ts +187 -0
  1116. package/src/web/scrapers/sourcegraph.ts +336 -0
  1117. package/src/web/scrapers/spdx.ts +108 -0
  1118. package/src/web/scrapers/spotify.ts +198 -0
  1119. package/src/web/scrapers/stackoverflow.ts +120 -0
  1120. package/src/web/scrapers/terraform.ts +277 -0
  1121. package/src/web/scrapers/tldr.ts +47 -0
  1122. package/src/web/scrapers/twitter.ts +94 -0
  1123. package/src/web/scrapers/types.ts +397 -0
  1124. package/src/web/scrapers/utils.ts +109 -0
  1125. package/src/web/scrapers/vimeo.ts +133 -0
  1126. package/src/web/scrapers/vscode-marketplace.ts +187 -0
  1127. package/src/web/scrapers/w3c.ts +156 -0
  1128. package/src/web/scrapers/wikidata.ts +344 -0
  1129. package/src/web/scrapers/wikipedia.ts +84 -0
  1130. package/src/web/scrapers/youtube.ts +325 -0
  1131. package/src/web/search/index.ts +292 -0
  1132. package/src/web/search/provider.ts +157 -0
  1133. package/src/web/search/providers/anthropic.ts +318 -0
  1134. package/src/web/search/providers/base.ts +89 -0
  1135. package/src/web/search/providers/brave.ts +152 -0
  1136. package/src/web/search/providers/codex.ts +591 -0
  1137. package/src/web/search/providers/exa.ts +400 -0
  1138. package/src/web/search/providers/gemini.ts +460 -0
  1139. package/src/web/search/providers/jina.ts +111 -0
  1140. package/src/web/search/providers/kagi.ts +86 -0
  1141. package/src/web/search/providers/kimi.ts +196 -0
  1142. package/src/web/search/providers/parallel.ts +225 -0
  1143. package/src/web/search/providers/perplexity.ts +730 -0
  1144. package/src/web/search/providers/searxng.ts +313 -0
  1145. package/src/web/search/providers/synthetic.ts +114 -0
  1146. package/src/web/search/providers/tavily.ts +176 -0
  1147. package/src/web/search/providers/utils.ts +128 -0
  1148. package/src/web/search/providers/zai.ts +333 -0
  1149. package/src/web/search/render.ts +262 -0
  1150. package/src/web/search/types.ts +482 -0
  1151. package/src/web/search/utils.ts +17 -0
  1152. package/src/workspace-tree.ts +286 -0
@@ -0,0 +1,1137 @@
1
+ /**
2
+ * Fuzzy matching utilities for the edit tool.
3
+ *
4
+ * Provides both character-level and line-level fuzzy matching with progressive
5
+ * fallback strategies for finding text in files.
6
+ */
7
+ import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
8
+ import * as z from "zod/v4";
9
+ import type { WritethroughCallback, WritethroughDeferredHandle } from "../../lsp";
10
+ import type { ToolSession } from "../../tools";
11
+ import { invalidateFsScanAfterWrite } from "../../tools/fs-cache-invalidation";
12
+ import { outputMeta } from "../../tools/output-meta";
13
+ import { enforcePlanModeWrite, resolvePlanPath } from "../../tools/plan-mode-guard";
14
+ import { generateDiffString, replaceText } from "../diff";
15
+ import {
16
+ countLeadingWhitespace,
17
+ detectLineEnding,
18
+ normalizeForFuzzy,
19
+ normalizeToLF,
20
+ normalizeUnicode,
21
+ restoreLineEndings,
22
+ stripBom,
23
+ } from "../normalize";
24
+ import { readEditFileText, serializeEditFileText } from "../read-file";
25
+ import type { EditToolDetails, LspBatchRequest } from "../renderer";
26
+
27
+ export interface FuzzyMatch {
28
+ actualText: string;
29
+ startIndex: number;
30
+ startLine: number;
31
+ confidence: number;
32
+ }
33
+
34
+ export interface MatchOutcome {
35
+ match?: FuzzyMatch;
36
+ closest?: FuzzyMatch;
37
+ occurrences?: number;
38
+ occurrenceLines?: number[];
39
+ occurrencePreviews?: string[];
40
+ fuzzyMatches?: number;
41
+ dominantFuzzy?: boolean;
42
+ }
43
+
44
+ export type SequenceMatchStrategy =
45
+ | "exact"
46
+ | "trim-trailing"
47
+ | "trim"
48
+ | "comment-prefix"
49
+ | "unicode"
50
+ | "prefix"
51
+ | "substring"
52
+ | "fuzzy"
53
+ | "fuzzy-dominant"
54
+ | "character";
55
+
56
+ export interface SequenceSearchResult {
57
+ index: number | undefined;
58
+ confidence: number;
59
+ matchCount?: number;
60
+ matchIndices?: number[];
61
+ strategy?: SequenceMatchStrategy;
62
+ }
63
+
64
+ export type ContextMatchStrategy = "exact" | "trim" | "unicode" | "prefix" | "substring" | "fuzzy";
65
+
66
+ export interface ContextLineResult {
67
+ index: number | undefined;
68
+ confidence: number;
69
+ matchCount?: number;
70
+ matchIndices?: number[];
71
+ strategy?: ContextMatchStrategy;
72
+ }
73
+
74
+ export class EditMatchError extends Error {
75
+ constructor(
76
+ readonly path: string,
77
+ readonly searchText: string,
78
+ readonly closest: FuzzyMatch | undefined,
79
+ readonly options: { allowFuzzy: boolean; threshold: number; fuzzyMatches?: number },
80
+ ) {
81
+ super(EditMatchError.formatMessage(path, searchText, closest, options));
82
+ this.name = "EditMatchError";
83
+ }
84
+
85
+ static formatMessage(
86
+ path: string,
87
+ searchText: string,
88
+ closest: FuzzyMatch | undefined,
89
+ options: { allowFuzzy: boolean; threshold: number; fuzzyMatches?: number },
90
+ ): string {
91
+ if (!closest) {
92
+ return options.allowFuzzy
93
+ ? `Could not find a close enough match in ${path}.`
94
+ : `Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`;
95
+ }
96
+
97
+ const similarity = Math.round(closest.confidence * 100);
98
+ const searchLines = searchText.split("\n");
99
+ const actualLines = closest.actualText.split("\n");
100
+ const { oldLine, newLine } = findFirstDifferentLine(searchLines, actualLines);
101
+ const thresholdPercent = Math.round(options.threshold * 100);
102
+
103
+ const hint = options.allowFuzzy
104
+ ? options.fuzzyMatches && options.fuzzyMatches > 1
105
+ ? `Found ${options.fuzzyMatches} high-confidence matches. Provide more context to make it unique.`
106
+ : `Closest match was below the ${thresholdPercent}% similarity threshold.`
107
+ : "Fuzzy matching is disabled. Enable 'Edit fuzzy match' in settings to accept high-confidence matches.";
108
+
109
+ return [
110
+ options.allowFuzzy
111
+ ? `Could not find a close enough match in ${path}.`
112
+ : `Could not find the exact text in ${path}.`,
113
+ ``,
114
+ `Closest match (${similarity}% similar) at line ${closest.startLine}:`,
115
+ ` - ${oldLine}`,
116
+ ` + ${newLine}`,
117
+ hint,
118
+ ].join("\n");
119
+ }
120
+ }
121
+
122
+ function findFirstDifferentLine(oldLines: string[], newLines: string[]): { oldLine: string; newLine: string } {
123
+ const max = Math.max(oldLines.length, newLines.length);
124
+ for (let i = 0; i < max; i++) {
125
+ const oldLine = oldLines[i] ?? "";
126
+ const newLine = newLines[i] ?? "";
127
+ if (oldLine !== newLine) {
128
+ return { oldLine, newLine };
129
+ }
130
+ }
131
+ return { oldLine: oldLines[0] ?? "", newLine: newLines[0] ?? "" };
132
+ }
133
+
134
+ function formatOccurrenceError(path: string, matchOutcome: MatchOutcome): string {
135
+ const previews = matchOutcome.occurrencePreviews?.join("\n\n") ?? "";
136
+ const moreMsg =
137
+ matchOutcome.occurrences && matchOutcome.occurrences > MAX_RECORDED_MATCHES
138
+ ? ` (showing first ${MAX_RECORDED_MATCHES} of ${matchOutcome.occurrences})`
139
+ : "";
140
+ return `Found ${matchOutcome.occurrences} occurrences in ${path}${moreMsg}:\n\n${previews}\n\nAdd more context lines to disambiguate.`;
141
+ }
142
+
143
+ // ═══════════════════════════════════════════════════════════════════════════
144
+ // Constants
145
+ // ═══════════════════════════════════════════════════════════════════════════
146
+
147
+ /** Default similarity threshold for fuzzy matching */
148
+ export const DEFAULT_FUZZY_THRESHOLD = 0.95;
149
+
150
+ /** Threshold for sequence-based fuzzy matching */
151
+ const SEQUENCE_FUZZY_THRESHOLD = 0.92;
152
+
153
+ /** Fallback threshold for line-based matching */
154
+ const FALLBACK_THRESHOLD = 0.8;
155
+
156
+ /** Threshold for context line matching */
157
+ const CONTEXT_FUZZY_THRESHOLD = 0.8;
158
+
159
+ /** Minimum length for partial/substring matching */
160
+ const PARTIAL_MATCH_MIN_LENGTH = 6;
161
+
162
+ /** Minimum ratio of pattern to line length for substring match */
163
+ const PARTIAL_MATCH_MIN_RATIO = 0.3;
164
+
165
+ /** Context lines to show before/after an ambiguous match preview */
166
+ const OCCURRENCE_PREVIEW_CONTEXT = 5;
167
+
168
+ /** Maximum line length for ambiguous match previews */
169
+ const OCCURRENCE_PREVIEW_MAX_LEN = 80;
170
+
171
+ /** Maximum number of match indices or previews to retain for diagnostics */
172
+ const MAX_RECORDED_MATCHES = 5;
173
+
174
+ /** Minimum confidence for a dominant fuzzy match to be auto-selected */
175
+ const DOMINANT_FUZZY_MIN_CONFIDENCE = 0.97;
176
+
177
+ /** Minimum score gap between the best and second-best fuzzy matches */
178
+ const DOMINANT_FUZZY_DELTA = 0.08;
179
+
180
+ interface IndexedMatches {
181
+ firstMatch: number | undefined;
182
+ matchCount: number;
183
+ matchIndices: number[];
184
+ }
185
+
186
+ interface PreviewWindowOptions {
187
+ context: number;
188
+ maxLen: number;
189
+ }
190
+
191
+ function collectIndexedMatches(
192
+ start: number,
193
+ endInclusive: number,
194
+ predicate: (index: number) => boolean,
195
+ ): IndexedMatches {
196
+ let firstMatch: number | undefined;
197
+ let matchCount = 0;
198
+ const matchIndices: number[] = [];
199
+
200
+ for (let index = start; index <= endInclusive; index++) {
201
+ if (!predicate(index)) continue;
202
+ if (firstMatch === undefined) {
203
+ firstMatch = index;
204
+ }
205
+ matchCount++;
206
+ if (matchIndices.length < MAX_RECORDED_MATCHES) {
207
+ matchIndices.push(index);
208
+ }
209
+ }
210
+
211
+ return { firstMatch, matchCount, matchIndices };
212
+ }
213
+
214
+ function toSingleMatchResult<TStrategy extends SequenceMatchStrategy | ContextMatchStrategy>(
215
+ matches: IndexedMatches,
216
+ confidence: number,
217
+ strategy: TStrategy,
218
+ ): { index: number; confidence: number; strategy: TStrategy } | undefined {
219
+ if (matches.firstMatch === undefined) {
220
+ return undefined;
221
+ }
222
+ return {
223
+ index: matches.firstMatch,
224
+ confidence,
225
+ strategy,
226
+ };
227
+ }
228
+
229
+ function toAmbiguousMatchResult<TStrategy extends SequenceMatchStrategy | ContextMatchStrategy>(
230
+ matches: IndexedMatches,
231
+ confidence: number,
232
+ strategy: TStrategy,
233
+ ): { index: number; confidence: number; matchCount: number; matchIndices: number[]; strategy: TStrategy } | undefined {
234
+ if (matches.firstMatch === undefined) {
235
+ return undefined;
236
+ }
237
+ return {
238
+ index: matches.firstMatch,
239
+ confidence,
240
+ matchCount: matches.matchCount,
241
+ matchIndices: matches.matchIndices,
242
+ strategy,
243
+ };
244
+ }
245
+
246
+ function formatPreviewWindow(lines: string[], centerIndex: number, options: PreviewWindowOptions): string {
247
+ const start = Math.max(0, centerIndex - options.context);
248
+ const end = Math.min(lines.length, centerIndex + options.context + 1);
249
+ return lines
250
+ .slice(start, end)
251
+ .map((line, index) => {
252
+ const num = start + index + 1;
253
+ const truncated = line.length > options.maxLen ? `${line.slice(0, options.maxLen - 1)}…` : line;
254
+ return ` ${num} | ${truncated}`;
255
+ })
256
+ .join("\n");
257
+ }
258
+
259
+ function findExactMatchOutcome(content: string, target: string): MatchOutcome | undefined {
260
+ const exactIndex = content.indexOf(target);
261
+ if (exactIndex === -1) {
262
+ return undefined;
263
+ }
264
+
265
+ const occurrences = content.split(target).length - 1;
266
+ if (occurrences > 1) {
267
+ const contentLines = content.split("\n");
268
+ const occurrenceLines: number[] = [];
269
+ const occurrencePreviews: string[] = [];
270
+ let searchStart = 0;
271
+
272
+ for (let i = 0; i < MAX_RECORDED_MATCHES; i++) {
273
+ const idx = content.indexOf(target, searchStart);
274
+ if (idx === -1) break;
275
+ const lineNumber = content.slice(0, idx).split("\n").length;
276
+ occurrenceLines.push(lineNumber);
277
+ occurrencePreviews.push(
278
+ formatPreviewWindow(contentLines, lineNumber - 1, {
279
+ context: OCCURRENCE_PREVIEW_CONTEXT,
280
+ maxLen: OCCURRENCE_PREVIEW_MAX_LEN,
281
+ }),
282
+ );
283
+ searchStart = idx + 1;
284
+ }
285
+
286
+ return { occurrences, occurrenceLines, occurrencePreviews };
287
+ }
288
+
289
+ const startLine = content.slice(0, exactIndex).split("\n").length;
290
+ return {
291
+ match: {
292
+ actualText: target,
293
+ startIndex: exactIndex,
294
+ startLine,
295
+ confidence: 1,
296
+ },
297
+ };
298
+ }
299
+
300
+ // ═══════════════════════════════════════════════════════════════════════════
301
+ // Core Algorithms
302
+ // ═══════════════════════════════════════════════════════════════════════════
303
+
304
+ /** Compute Levenshtein distance between two strings */
305
+ export function levenshteinDistance(a: string, b: string): number {
306
+ if (a === b) return 0;
307
+ const aLen = a.length;
308
+ const bLen = b.length;
309
+ if (aLen === 0) return bLen;
310
+ if (bLen === 0) return aLen;
311
+
312
+ let prev = new Array<number>(bLen + 1);
313
+ let curr = new Array<number>(bLen + 1);
314
+ for (let j = 0; j <= bLen; j++) {
315
+ prev[j] = j;
316
+ }
317
+
318
+ for (let i = 1; i <= aLen; i++) {
319
+ curr[0] = i;
320
+ const aCode = a.charCodeAt(i - 1);
321
+ for (let j = 1; j <= bLen; j++) {
322
+ const cost = aCode === b.charCodeAt(j - 1) ? 0 : 1;
323
+ const deletion = prev[j] + 1;
324
+ const insertion = curr[j - 1] + 1;
325
+ const substitution = prev[j - 1] + cost;
326
+ curr[j] = Math.min(deletion, insertion, substitution);
327
+ }
328
+ const tmp = prev;
329
+ prev = curr;
330
+ curr = tmp;
331
+ }
332
+
333
+ return prev[bLen];
334
+ }
335
+
336
+ /** Compute similarity score between two strings (0 to 1) */
337
+ export function similarity(a: string, b: string): number {
338
+ if (a.length === 0 && b.length === 0) return 1;
339
+ const maxLen = Math.max(a.length, b.length);
340
+ if (maxLen === 0) return 1;
341
+ const distance = levenshteinDistance(a, b);
342
+ return 1 - distance / maxLen;
343
+ }
344
+
345
+ // ═══════════════════════════════════════════════════════════════════════════
346
+ // Line-Based Utilities
347
+ // ═══════════════════════════════════════════════════════════════════════════
348
+
349
+ /** Compute relative indent depths for lines */
350
+ function computeRelativeIndentDepths(lines: string[]): number[] {
351
+ const indents = lines.map(countLeadingWhitespace);
352
+ const nonEmptyIndents: number[] = [];
353
+ for (let i = 0; i < lines.length; i++) {
354
+ if (lines[i].trim().length > 0) {
355
+ nonEmptyIndents.push(indents[i]);
356
+ }
357
+ }
358
+ const minIndent = nonEmptyIndents.length > 0 ? Math.min(...nonEmptyIndents) : 0;
359
+ const indentSteps = nonEmptyIndents.map(indent => indent - minIndent).filter(step => step > 0);
360
+ const indentUnit = indentSteps.length > 0 ? Math.min(...indentSteps) : 1;
361
+
362
+ return lines.map((line, index) => {
363
+ if (line.trim().length === 0) return 0;
364
+ if (indentUnit <= 0) return 0;
365
+ const relativeIndent = indents[index] - minIndent;
366
+ return Math.round(relativeIndent / indentUnit);
367
+ });
368
+ }
369
+
370
+ /** Normalize lines for matching, optionally including indent depth */
371
+ function normalizeLines(lines: string[], includeDepth = true): string[] {
372
+ const indentDepths = includeDepth ? computeRelativeIndentDepths(lines) : null;
373
+ return lines.map((line, index) => {
374
+ const trimmed = line.trim();
375
+ const prefix = indentDepths ? `${indentDepths[index]}|` : "|";
376
+ if (trimmed.length === 0) return prefix;
377
+ return `${prefix}${normalizeForFuzzy(trimmed)}`;
378
+ });
379
+ }
380
+
381
+ /** Compute character offsets for each line in content */
382
+ function computeLineOffsets(lines: string[]): number[] {
383
+ const offsets: number[] = [];
384
+ let offset = 0;
385
+ for (let i = 0; i < lines.length; i++) {
386
+ offsets.push(offset);
387
+ offset += lines[i].length;
388
+ if (i < lines.length - 1) offset += 1; // newline
389
+ }
390
+ return offsets;
391
+ }
392
+
393
+ // ═══════════════════════════════════════════════════════════════════════════
394
+ // Character-Level Fuzzy Match (for replace mode)
395
+ // ═══════════════════════════════════════════════════════════════════════════
396
+
397
+ interface BestFuzzyMatchResult {
398
+ best?: FuzzyMatch;
399
+ aboveThresholdCount: number;
400
+ secondBestScore: number;
401
+ }
402
+
403
+ function findBestFuzzyMatchCore(
404
+ contentLines: string[],
405
+ targetLines: string[],
406
+ offsets: number[],
407
+ threshold: number,
408
+ includeDepth: boolean,
409
+ ): BestFuzzyMatchResult {
410
+ const targetNormalized = normalizeLines(targetLines, includeDepth);
411
+
412
+ let best: FuzzyMatch | undefined;
413
+ let bestScore = -1;
414
+ let secondBestScore = -1;
415
+ let aboveThresholdCount = 0;
416
+
417
+ for (let start = 0; start <= contentLines.length - targetLines.length; start++) {
418
+ const windowLines = contentLines.slice(start, start + targetLines.length);
419
+ const windowNormalized = normalizeLines(windowLines, includeDepth);
420
+ let score = 0;
421
+ for (let i = 0; i < targetLines.length; i++) {
422
+ score += similarity(targetNormalized[i], windowNormalized[i]);
423
+ }
424
+ score = score / targetLines.length;
425
+
426
+ if (score >= threshold) {
427
+ aboveThresholdCount++;
428
+ }
429
+
430
+ if (score > bestScore) {
431
+ secondBestScore = bestScore;
432
+ bestScore = score;
433
+ best = {
434
+ actualText: windowLines.join("\n"),
435
+ startIndex: offsets[start],
436
+ startLine: start + 1,
437
+ confidence: score,
438
+ };
439
+ } else if (score > secondBestScore) {
440
+ secondBestScore = score;
441
+ }
442
+ }
443
+
444
+ return { best, aboveThresholdCount, secondBestScore };
445
+ }
446
+
447
+ function findBestFuzzyMatch(content: string, target: string, threshold: number): BestFuzzyMatchResult {
448
+ const contentLines = content.split("\n");
449
+ const targetLines = target.split("\n");
450
+
451
+ if (targetLines.length === 0 || target.length === 0) {
452
+ return { aboveThresholdCount: 0, secondBestScore: 0 };
453
+ }
454
+ if (targetLines.length > contentLines.length) {
455
+ return { aboveThresholdCount: 0, secondBestScore: 0 };
456
+ }
457
+
458
+ const offsets = computeLineOffsets(contentLines);
459
+ let result = findBestFuzzyMatchCore(contentLines, targetLines, offsets, threshold, true);
460
+
461
+ // Retry without indent depth if match is close but below threshold
462
+ if (result.best && result.best.confidence < threshold && result.best.confidence >= FALLBACK_THRESHOLD) {
463
+ const noDepthResult = findBestFuzzyMatchCore(contentLines, targetLines, offsets, threshold, false);
464
+ if (noDepthResult.best && noDepthResult.best.confidence > result.best.confidence) {
465
+ result = noDepthResult;
466
+ }
467
+ }
468
+
469
+ return result;
470
+ }
471
+
472
+ /**
473
+ * Find a match for target text within content.
474
+ * Used primarily for replace-mode edits.
475
+ */
476
+ export function findMatch(
477
+ content: string,
478
+ target: string,
479
+ options: { allowFuzzy: boolean; threshold?: number },
480
+ ): MatchOutcome {
481
+ if (target.length === 0) {
482
+ return {};
483
+ }
484
+
485
+ const exactMatch = findExactMatchOutcome(content, target);
486
+ if (exactMatch) {
487
+ return exactMatch;
488
+ }
489
+
490
+ // Try fuzzy match
491
+ const threshold = options.threshold ?? DEFAULT_FUZZY_THRESHOLD;
492
+ const { best, aboveThresholdCount, secondBestScore } = findBestFuzzyMatch(content, target, threshold);
493
+
494
+ if (!best) {
495
+ return {};
496
+ }
497
+
498
+ if (options.allowFuzzy && best.confidence >= threshold) {
499
+ if (aboveThresholdCount === 1) {
500
+ return { match: best, closest: best };
501
+ }
502
+ if (
503
+ aboveThresholdCount > 1 &&
504
+ best.confidence >= DOMINANT_FUZZY_MIN_CONFIDENCE &&
505
+ best.confidence - secondBestScore >= DOMINANT_FUZZY_DELTA
506
+ ) {
507
+ return { match: best, closest: best, fuzzyMatches: aboveThresholdCount, dominantFuzzy: true };
508
+ }
509
+ }
510
+
511
+ return { closest: best, fuzzyMatches: aboveThresholdCount };
512
+ }
513
+
514
+ // ═══════════════════════════════════════════════════════════════════════════
515
+ // Line-Based Sequence Match (for patch mode)
516
+ // ═══════════════════════════════════════════════════════════════════════════
517
+
518
+ /** Check if pattern matches lines starting at index using comparison function */
519
+ function matchesAt(lines: string[], pattern: string[], i: number, compare: (a: string, b: string) => boolean): boolean {
520
+ for (let j = 0; j < pattern.length; j++) {
521
+ if (!compare(lines[i + j], pattern[j])) {
522
+ return false;
523
+ }
524
+ }
525
+ return true;
526
+ }
527
+
528
+ /**
529
+ * Compute average similarity score for pre-normalized pattern lines at
530
+ * position `i` of pre-normalized file lines.
531
+ *
532
+ * `minScore` is a bail threshold: when even perfect similarity on the
533
+ * remaining lines cannot lift the average to `minScore`, returns the partial
534
+ * average early (always ≤ the true score). The length-difference lower bound
535
+ * on Levenshtein distance is used to skip the DP entirely for line pairs the
536
+ * bail test already rules out.
537
+ */
538
+ function fuzzyScoreAt(linesNorm: string[], patternNorm: string[], i: number, minScore = 0): number {
539
+ const count = patternNorm.length;
540
+ let totalScore = 0;
541
+ for (let j = 0; j < count; j++) {
542
+ const lineNorm = linesNorm[i + j];
543
+ const patNorm = patternNorm[j];
544
+ if (lineNorm === patNorm) {
545
+ totalScore += 1;
546
+ continue;
547
+ }
548
+ const remaining = count - j - 1;
549
+ const maxLen = Math.max(lineNorm.length, patNorm.length);
550
+ // similarity ≤ 1 − |lenA−lenB|/maxLen: test the bound before the DP.
551
+ const upperBound = 1 - Math.abs(lineNorm.length - patNorm.length) / maxLen;
552
+ if ((totalScore + upperBound + remaining) / count < minScore) return totalScore / count;
553
+ if (upperBound > 0) totalScore += similarity(lineNorm, patNorm);
554
+ if ((totalScore + remaining) / count < minScore) return totalScore / count;
555
+ }
556
+ return totalScore / count;
557
+ }
558
+
559
+ /** Check if pre-normalized line starts with pre-normalized pattern */
560
+ function normStartsWith(lineNorm: string, patternNorm: string): boolean {
561
+ if (patternNorm.length === 0) return lineNorm.length === 0;
562
+ return lineNorm.startsWith(patternNorm);
563
+ }
564
+
565
+ /** Check if pre-normalized line contains pre-normalized pattern as significant substring */
566
+ function normIncludes(lineNorm: string, patternNorm: string): boolean {
567
+ if (patternNorm.length === 0) return lineNorm.length === 0;
568
+ if (patternNorm.length < PARTIAL_MATCH_MIN_LENGTH) return false;
569
+ if (!lineNorm.includes(patternNorm)) return false;
570
+ return patternNorm.length / Math.max(1, lineNorm.length) >= PARTIAL_MATCH_MIN_RATIO;
571
+ }
572
+
573
+ function stripCommentPrefix(line: string): string {
574
+ let trimmed = line.trimStart();
575
+ if (trimmed.startsWith("/*")) {
576
+ trimmed = trimmed.slice(2);
577
+ } else if (trimmed.startsWith("*/")) {
578
+ trimmed = trimmed.slice(2);
579
+ } else if (trimmed.startsWith("//")) {
580
+ trimmed = trimmed.slice(2);
581
+ } else if (trimmed.startsWith("*")) {
582
+ trimmed = trimmed.slice(1);
583
+ } else if (trimmed.startsWith("#")) {
584
+ trimmed = trimmed.slice(1);
585
+ } else if (trimmed.startsWith(";")) {
586
+ trimmed = trimmed.slice(1);
587
+ } else if (trimmed.startsWith("/") && trimmed[1] === " ") {
588
+ trimmed = trimmed.slice(1);
589
+ }
590
+ return trimmed.trimStart();
591
+ }
592
+
593
+ /**
594
+ * Find a sequence of pattern lines within content lines.
595
+ *
596
+ * Attempts matches with decreasing strictness:
597
+ * 1. Exact match
598
+ * 2. Trailing whitespace ignored
599
+ * 3. All whitespace trimmed
600
+ * 4. Unicode punctuation normalized
601
+ * 5. Prefix match (pattern is prefix of line)
602
+ * 6. Substring match (pattern is substring of line)
603
+ * 7. Fuzzy similarity match
604
+ *
605
+ * @param lines - The lines of the file content
606
+ * @param pattern - The lines to search for
607
+ * @param start - Starting index for the search
608
+ * @param eof - If true, prefer matching at end of file first
609
+ */
610
+ export function seekSequence(
611
+ lines: string[],
612
+ pattern: string[],
613
+ start: number,
614
+ eof: boolean,
615
+ options?: { allowFuzzy?: boolean },
616
+ ): SequenceSearchResult {
617
+ const allowFuzzy = options?.allowFuzzy ?? true;
618
+ // Empty pattern matches immediately
619
+ if (pattern.length === 0) {
620
+ return { index: start, confidence: 1.0, strategy: "exact" };
621
+ }
622
+
623
+ // Pattern longer than available content cannot match
624
+ if (pattern.length > lines.length) {
625
+ return { index: undefined, confidence: 0 };
626
+ }
627
+
628
+ // Determine search start position
629
+ const searchStart = eof && lines.length >= pattern.length ? lines.length - pattern.length : start;
630
+ const maxStart = lines.length - pattern.length;
631
+
632
+ // Fuzzy and partial passes compare normalizeForFuzzy forms; normalize the
633
+ // file and pattern once per call instead of once per candidate position.
634
+ let linesNormCache: string[] | undefined;
635
+ let patternNormCache: string[] | undefined;
636
+ const getLinesNorm = () => (linesNormCache ??= lines.map(normalizeForFuzzy));
637
+ const getPatternNorm = () => (patternNormCache ??= pattern.map(normalizeForFuzzy));
638
+
639
+ const runExactPasses = (from: number, to: number): SequenceSearchResult | undefined => {
640
+ const comparisonPasses: Array<{
641
+ compare: (a: string, b: string) => boolean;
642
+ confidence: number;
643
+ strategy: SequenceMatchStrategy;
644
+ }> = [
645
+ { compare: (a, b) => a === b, confidence: 1.0, strategy: "exact" },
646
+ { compare: (a, b) => a.trimEnd() === b.trimEnd(), confidence: 0.99, strategy: "trim-trailing" },
647
+ { compare: (a, b) => a.trim() === b.trim(), confidence: 0.98, strategy: "trim" },
648
+ {
649
+ compare: (a, b) => stripCommentPrefix(a) === stripCommentPrefix(b),
650
+ confidence: 0.975,
651
+ strategy: "comment-prefix",
652
+ },
653
+ {
654
+ compare: (a, b) => normalizeUnicode(a) === normalizeUnicode(b),
655
+ confidence: 0.97,
656
+ strategy: "unicode",
657
+ },
658
+ ];
659
+
660
+ for (const pass of comparisonPasses) {
661
+ const matches = collectIndexedMatches(from, to, i => matchesAt(lines, pattern, i, pass.compare));
662
+ const result = toSingleMatchResult(matches, pass.confidence, pass.strategy);
663
+ if (result) {
664
+ return result;
665
+ }
666
+ }
667
+
668
+ if (!allowFuzzy) {
669
+ return undefined;
670
+ }
671
+
672
+ const linesNorm = getLinesNorm();
673
+ const patternNorm = getPatternNorm();
674
+ const partialPasses: Array<{
675
+ compare: (lineNorm: string, patternLineNorm: string) => boolean;
676
+ confidence: number;
677
+ strategy: SequenceMatchStrategy;
678
+ }> = [
679
+ { compare: normStartsWith, confidence: 0.965, strategy: "prefix" },
680
+ { compare: normIncludes, confidence: 0.94, strategy: "substring" },
681
+ ];
682
+
683
+ for (const pass of partialPasses) {
684
+ const matches = collectIndexedMatches(from, to, i => matchesAt(linesNorm, patternNorm, i, pass.compare));
685
+ const result = toAmbiguousMatchResult(matches, pass.confidence, pass.strategy);
686
+ if (result) {
687
+ return result;
688
+ }
689
+ }
690
+
691
+ return undefined;
692
+ };
693
+
694
+ const primaryPassResult = runExactPasses(searchStart, maxStart);
695
+ if (primaryPassResult) {
696
+ return primaryPassResult;
697
+ }
698
+
699
+ if (eof && searchStart > start) {
700
+ const fromStartResult = runExactPasses(start, maxStart);
701
+ if (fromStartResult) {
702
+ return fromStartResult;
703
+ }
704
+ }
705
+
706
+ if (!allowFuzzy) {
707
+ return { index: undefined, confidence: 0 };
708
+ }
709
+
710
+ // Pass 7: Fuzzy matching - find best match above threshold
711
+ let bestScore = 0;
712
+ let secondBestScore = 0;
713
+ let bestIndex: number | undefined;
714
+ const fuzzyMatches: IndexedMatches = {
715
+ firstMatch: undefined,
716
+ matchCount: 0,
717
+ matchIndices: [],
718
+ };
719
+
720
+ const fuzzyLinesNorm = getLinesNorm();
721
+ const fuzzyPatternNorm = getPatternNorm();
722
+ // Positions scoring below this can neither become a fuzzy match nor affect
723
+ // the dominant-fuzzy gap test; let fuzzyScoreAt bail early on them.
724
+ const fuzzyBail = SEQUENCE_FUZZY_THRESHOLD - DOMINANT_FUZZY_DELTA;
725
+ const scoreFuzzyRange = (from: number, to: number): void => {
726
+ for (let i = from; i <= to; i++) {
727
+ const score = fuzzyScoreAt(fuzzyLinesNorm, fuzzyPatternNorm, i, fuzzyBail);
728
+ if (score >= SEQUENCE_FUZZY_THRESHOLD) {
729
+ if (fuzzyMatches.firstMatch === undefined) {
730
+ fuzzyMatches.firstMatch = i;
731
+ }
732
+ fuzzyMatches.matchCount++;
733
+ if (fuzzyMatches.matchIndices.length < MAX_RECORDED_MATCHES) {
734
+ fuzzyMatches.matchIndices.push(i);
735
+ }
736
+ }
737
+ if (score > bestScore) {
738
+ secondBestScore = bestScore;
739
+ bestScore = score;
740
+ bestIndex = i;
741
+ } else if (score > secondBestScore) {
742
+ secondBestScore = score;
743
+ }
744
+ }
745
+ };
746
+
747
+ scoreFuzzyRange(searchStart, maxStart);
748
+
749
+ // Also search from start if eof mode started from end
750
+ if (eof && searchStart > start) {
751
+ scoreFuzzyRange(start, searchStart - 1);
752
+ }
753
+
754
+ if (bestIndex !== undefined && bestScore >= SEQUENCE_FUZZY_THRESHOLD) {
755
+ if (
756
+ fuzzyMatches.matchCount > 1 &&
757
+ bestScore >= DOMINANT_FUZZY_MIN_CONFIDENCE &&
758
+ bestScore - secondBestScore >= DOMINANT_FUZZY_DELTA
759
+ ) {
760
+ return {
761
+ index: bestIndex,
762
+ confidence: bestScore,
763
+ matchCount: 1,
764
+ matchIndices: fuzzyMatches.matchIndices,
765
+ strategy: "fuzzy-dominant",
766
+ };
767
+ }
768
+ return {
769
+ index: bestIndex,
770
+ confidence: bestScore,
771
+ matchCount: fuzzyMatches.matchCount,
772
+ matchIndices: fuzzyMatches.matchIndices,
773
+ strategy: "fuzzy",
774
+ };
775
+ }
776
+
777
+ // Pass 8: Character-based fuzzy matching via findMatch
778
+ // This is the final fallback for when line-based matching fails
779
+ const CHARACTER_MATCH_THRESHOLD = 0.92;
780
+ const patternText = pattern.join("\n");
781
+ const contentText = lines.slice(start).join("\n");
782
+ const matchOutcome = findMatch(contentText, patternText, {
783
+ allowFuzzy: true,
784
+ threshold: CHARACTER_MATCH_THRESHOLD,
785
+ });
786
+
787
+ if (matchOutcome.match) {
788
+ // Convert character index back to line index
789
+ const matchedContent = contentText.substring(0, matchOutcome.match.startIndex);
790
+ const lineIndex = start + matchedContent.split("\n").length - 1;
791
+ const fallbackMatchCount = matchOutcome.occurrences ?? matchOutcome.fuzzyMatches ?? 1;
792
+ return {
793
+ index: lineIndex,
794
+ confidence: matchOutcome.match.confidence,
795
+ matchCount: fallbackMatchCount,
796
+ strategy: "character",
797
+ };
798
+ }
799
+
800
+ const fallbackMatchCount = matchOutcome.occurrences ?? matchOutcome.fuzzyMatches;
801
+ return { index: undefined, confidence: bestScore, matchCount: fallbackMatchCount };
802
+ }
803
+
804
+ export function findClosestSequenceMatch(
805
+ lines: string[],
806
+ pattern: string[],
807
+ options?: { start?: number; eof?: boolean },
808
+ ): { index: number | undefined; confidence: number; strategy: SequenceMatchStrategy } {
809
+ if (pattern.length === 0) {
810
+ return { index: options?.start ?? 0, confidence: 1, strategy: "exact" };
811
+ }
812
+ if (pattern.length > lines.length) {
813
+ return { index: undefined, confidence: 0, strategy: "fuzzy" };
814
+ }
815
+
816
+ const start = options?.start ?? 0;
817
+ const eof = options?.eof ?? false;
818
+ const maxStart = lines.length - pattern.length;
819
+ const searchStart = eof && lines.length >= pattern.length ? maxStart : start;
820
+ const linesNorm = lines.map(normalizeForFuzzy);
821
+ const patternNorm = pattern.map(normalizeForFuzzy);
822
+
823
+ let bestIndex: number | undefined;
824
+ let bestScore = 0;
825
+
826
+ // Passing the running best as the bail threshold is exact: a bailed
827
+ // position returns a value strictly below it, so it can never win.
828
+ for (let i = searchStart; i <= maxStart; i++) {
829
+ const score = fuzzyScoreAt(linesNorm, patternNorm, i, bestScore);
830
+ if (score > bestScore) {
831
+ bestScore = score;
832
+ bestIndex = i;
833
+ }
834
+ }
835
+
836
+ if (eof && searchStart > start) {
837
+ for (let i = start; i < searchStart; i++) {
838
+ const score = fuzzyScoreAt(linesNorm, patternNorm, i, bestScore);
839
+ if (score > bestScore) {
840
+ bestScore = score;
841
+ bestIndex = i;
842
+ }
843
+ }
844
+ }
845
+
846
+ return { index: bestIndex, confidence: bestScore, strategy: "fuzzy" };
847
+ }
848
+
849
+ /**
850
+ * Find a context line in the file using progressive matching strategies.
851
+ *
852
+ * @param lines - The lines of the file content
853
+ * @param context - The context line to search for
854
+ * @param startFrom - Starting index for the search
855
+ */
856
+ export function findContextLine(
857
+ lines: string[],
858
+ context: string,
859
+ startFrom: number,
860
+ options?: { allowFuzzy?: boolean; skipFunctionFallback?: boolean },
861
+ ): ContextLineResult {
862
+ const allowFuzzy = options?.allowFuzzy ?? true;
863
+ const trimmedContext = context.trim();
864
+
865
+ const endIndex = lines.length - 1;
866
+ const exactPasses: Array<{
867
+ confidence: number;
868
+ strategy: ContextMatchStrategy;
869
+ predicate: (index: number) => boolean;
870
+ }> = [
871
+ { confidence: 1.0, strategy: "exact", predicate: i => lines[i] === context },
872
+ { confidence: 0.99, strategy: "trim", predicate: i => lines[i].trim() === trimmedContext },
873
+ ];
874
+
875
+ for (const pass of exactPasses) {
876
+ const matches = collectIndexedMatches(startFrom, endIndex, pass.predicate);
877
+ const result = toAmbiguousMatchResult(matches, pass.confidence, pass.strategy);
878
+ if (result) {
879
+ return result;
880
+ }
881
+ }
882
+
883
+ // Pass 3: Unicode normalization match
884
+ const normalizedContext = normalizeUnicode(context);
885
+ const unicodeMatches = collectIndexedMatches(
886
+ startFrom,
887
+ endIndex,
888
+ i => normalizeUnicode(lines[i]) === normalizedContext,
889
+ );
890
+ const unicodeResult = toAmbiguousMatchResult(unicodeMatches, 0.98, "unicode");
891
+ if (unicodeResult) {
892
+ return unicodeResult;
893
+ }
894
+
895
+ if (!allowFuzzy) {
896
+ return { index: undefined, confidence: 0 };
897
+ }
898
+
899
+ // Pass 4: Prefix match (file line starts with context)
900
+ const contextNorm = normalizeForFuzzy(context);
901
+ if (contextNorm.length > 0) {
902
+ const prefixMatches = collectIndexedMatches(startFrom, endIndex, i =>
903
+ normalizeForFuzzy(lines[i]).startsWith(contextNorm),
904
+ );
905
+ const prefixResult = toAmbiguousMatchResult(prefixMatches, 0.96, "prefix");
906
+ if (prefixResult) {
907
+ return prefixResult;
908
+ }
909
+ }
910
+
911
+ // Pass 5: Substring match (file line contains context)
912
+ // First pass: find all substring matches (ignoring ratio)
913
+ // If exactly one match exists, accept it (uniqueness is sufficient)
914
+ // If multiple matches, apply ratio filter to disambiguate
915
+ if (contextNorm.length >= PARTIAL_MATCH_MIN_LENGTH) {
916
+ const allSubstringMatches: Array<{ index: number; ratio: number }> = [];
917
+ for (let i = startFrom; i < lines.length; i++) {
918
+ const lineNorm = normalizeForFuzzy(lines[i]);
919
+ if (lineNorm.includes(contextNorm)) {
920
+ const ratio = contextNorm.length / Math.max(1, lineNorm.length);
921
+ allSubstringMatches.push({ index: i, ratio });
922
+ }
923
+ }
924
+ const matchIndices = allSubstringMatches.slice(0, 5).map(match => match.index);
925
+
926
+ // If exactly one substring match, accept it regardless of ratio
927
+ if (allSubstringMatches.length === 1) {
928
+ return {
929
+ index: allSubstringMatches[0].index,
930
+ confidence: 0.94,
931
+ matchCount: 1,
932
+ matchIndices,
933
+ strategy: "substring",
934
+ };
935
+ }
936
+
937
+ // Multiple matches: filter by ratio to disambiguate
938
+ let firstMatch: number | undefined;
939
+ let matchCount = 0;
940
+ for (const match of allSubstringMatches) {
941
+ if (match.ratio >= PARTIAL_MATCH_MIN_RATIO) {
942
+ if (firstMatch === undefined) firstMatch = match.index;
943
+ matchCount++;
944
+ }
945
+ }
946
+ if (matchCount > 0) {
947
+ return { index: firstMatch, confidence: 0.94, matchCount, matchIndices, strategy: "substring" };
948
+ }
949
+
950
+ // If we had substring matches but none passed ratio filter,
951
+ // return ambiguous result so caller knows matches exist
952
+ if (allSubstringMatches.length > 1) {
953
+ return {
954
+ index: allSubstringMatches[0].index,
955
+ confidence: 0.94,
956
+ matchCount: allSubstringMatches.length,
957
+ matchIndices,
958
+ strategy: "substring",
959
+ };
960
+ }
961
+ }
962
+
963
+ // Pass 6: Fuzzy match using similarity
964
+ let bestIndex: number | undefined;
965
+ let bestScore = 0;
966
+ const fuzzyMatches: IndexedMatches = {
967
+ firstMatch: undefined,
968
+ matchCount: 0,
969
+ matchIndices: [],
970
+ };
971
+
972
+ for (let i = startFrom; i < lines.length; i++) {
973
+ const lineNorm = normalizeForFuzzy(lines[i]);
974
+ const score = similarity(lineNorm, contextNorm);
975
+ if (score >= CONTEXT_FUZZY_THRESHOLD) {
976
+ if (fuzzyMatches.firstMatch === undefined) {
977
+ fuzzyMatches.firstMatch = i;
978
+ }
979
+ fuzzyMatches.matchCount++;
980
+ if (fuzzyMatches.matchIndices.length < MAX_RECORDED_MATCHES) {
981
+ fuzzyMatches.matchIndices.push(i);
982
+ }
983
+ }
984
+ if (score > bestScore) {
985
+ bestScore = score;
986
+ bestIndex = i;
987
+ }
988
+ }
989
+
990
+ if (bestIndex !== undefined && bestScore >= CONTEXT_FUZZY_THRESHOLD) {
991
+ return {
992
+ index: bestIndex,
993
+ confidence: bestScore,
994
+ matchCount: fuzzyMatches.matchCount,
995
+ matchIndices: fuzzyMatches.matchIndices,
996
+ strategy: "fuzzy",
997
+ };
998
+ }
999
+
1000
+ if (!options?.skipFunctionFallback && trimmedContext.endsWith("()")) {
1001
+ const withParen = trimmedContext.replace(/\(\)\s*$/u, "(");
1002
+ const withoutParen = trimmedContext.replace(/\(\)\s*$/u, "");
1003
+ const parenResult = findContextLine(lines, withParen, startFrom, { allowFuzzy, skipFunctionFallback: true });
1004
+ if (parenResult.index !== undefined || (parenResult.matchCount ?? 0) > 0) {
1005
+ return parenResult;
1006
+ }
1007
+ return findContextLine(lines, withoutParen, startFrom, { allowFuzzy, skipFunctionFallback: true });
1008
+ }
1009
+
1010
+ return { index: undefined, confidence: bestScore };
1011
+ }
1012
+
1013
+ export const replaceEditEntrySchema = z
1014
+ .object({
1015
+ old_text: z.string().describe("text to find"),
1016
+ new_text: z.string().describe("replacement text"),
1017
+ all: z.boolean().describe("replace all occurrences").optional(),
1018
+ })
1019
+ .strict();
1020
+
1021
+ export const replaceEditSchema = z
1022
+ .object({
1023
+ path: z.string().describe("file path"),
1024
+ edits: z.array(replaceEditEntrySchema).min(1).describe("replacements"),
1025
+ })
1026
+ .strict();
1027
+
1028
+ export type ReplaceEditEntry = z.infer<typeof replaceEditEntrySchema>;
1029
+ export type ReplaceParams = z.infer<typeof replaceEditSchema>;
1030
+
1031
+ export interface ExecuteReplaceSingleOptions {
1032
+ session: ToolSession;
1033
+ path: string;
1034
+ params: ReplaceEditEntry;
1035
+ signal?: AbortSignal;
1036
+ batchRequest?: LspBatchRequest;
1037
+ allowFuzzy: boolean;
1038
+ fuzzyThreshold: number;
1039
+ writethrough: WritethroughCallback;
1040
+ beginDeferredDiagnosticsForPath: (path: string) => WritethroughDeferredHandle;
1041
+ }
1042
+
1043
+ export async function executeReplaceSingle(
1044
+ options: ExecuteReplaceSingleOptions,
1045
+ ): Promise<AgentToolResult<EditToolDetails, typeof replaceEditEntrySchema>> {
1046
+ const {
1047
+ session,
1048
+ path,
1049
+ params,
1050
+ signal,
1051
+ batchRequest,
1052
+ allowFuzzy,
1053
+ fuzzyThreshold,
1054
+ writethrough,
1055
+ beginDeferredDiagnosticsForPath,
1056
+ } = options;
1057
+ const { old_text, new_text, all } = params;
1058
+
1059
+ enforcePlanModeWrite(session, path);
1060
+
1061
+ if (old_text.length === 0) {
1062
+ throw new Error("old_text must not be empty.");
1063
+ }
1064
+
1065
+ const absolutePath = resolvePlanPath(session, path);
1066
+ const rawContent = await readEditFileText(absolutePath, path);
1067
+ const { bom, text: content } = stripBom(rawContent);
1068
+ const originalEnding = detectLineEnding(content);
1069
+ const normalizedContent = normalizeToLF(content);
1070
+ const normalizedOldText = normalizeToLF(old_text);
1071
+ const normalizedNewText = normalizeToLF(new_text);
1072
+
1073
+ const result = replaceText(normalizedContent, normalizedOldText, normalizedNewText, {
1074
+ fuzzy: allowFuzzy,
1075
+ all: all ?? false,
1076
+ threshold: fuzzyThreshold,
1077
+ });
1078
+
1079
+ if (result.count === 0) {
1080
+ const matchOutcome = findMatch(normalizedContent, normalizedOldText, {
1081
+ allowFuzzy,
1082
+ threshold: fuzzyThreshold,
1083
+ });
1084
+
1085
+ if (matchOutcome.occurrences && matchOutcome.occurrences > 1) {
1086
+ throw new Error(formatOccurrenceError(path, matchOutcome));
1087
+ }
1088
+
1089
+ throw new EditMatchError(path, normalizedOldText, matchOutcome.closest, {
1090
+ allowFuzzy,
1091
+ threshold: fuzzyThreshold,
1092
+ fuzzyMatches: matchOutcome.fuzzyMatches,
1093
+ });
1094
+ }
1095
+
1096
+ if (normalizedContent === result.content) {
1097
+ throw new Error(`Edits to ${path} resulted in no changes being made.`);
1098
+ }
1099
+
1100
+ const finalContent = await serializeEditFileText(
1101
+ absolutePath,
1102
+ path,
1103
+ bom + restoreLineEndings(result.content, originalEnding),
1104
+ );
1105
+ const diagnostics = await writethrough(
1106
+ absolutePath,
1107
+ finalContent,
1108
+ signal,
1109
+ Bun.file(absolutePath),
1110
+ batchRequest,
1111
+ dst => (dst === absolutePath ? beginDeferredDiagnosticsForPath(absolutePath) : undefined),
1112
+ );
1113
+ invalidateFsScanAfterWrite(absolutePath);
1114
+
1115
+ const diffResult = generateDiffString(normalizedContent, result.content, undefined, { path });
1116
+ const resultText =
1117
+ result.count > 1
1118
+ ? `Successfully replaced ${result.count} occurrences in ${path}.`
1119
+ : `Successfully replaced text in ${path}.`;
1120
+
1121
+ const meta = outputMeta()
1122
+ .diagnostics(diagnostics?.summary ?? "", diagnostics?.messages ?? [])
1123
+ .get();
1124
+
1125
+ return {
1126
+ content: [{ type: "text", text: resultText }],
1127
+ details: {
1128
+ diff: diffResult.diff,
1129
+ path: absolutePath,
1130
+ firstChangedLine: diffResult.firstChangedLine,
1131
+ diagnostics,
1132
+ meta,
1133
+ oldText: rawContent,
1134
+ newText: finalContent,
1135
+ },
1136
+ };
1137
+ }