@f5-sales-demo/xcsh 19.51.2

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 (899) hide show
  1. package/CHANGELOG.md +7073 -0
  2. package/README.md +14 -0
  3. package/examples/README.md +21 -0
  4. package/examples/custom-tools/README.md +109 -0
  5. package/examples/custom-tools/hello/index.ts +20 -0
  6. package/examples/custom-tools/todo/index.ts +206 -0
  7. package/examples/extensions/README.md +143 -0
  8. package/examples/extensions/api-demo.ts +89 -0
  9. package/examples/extensions/chalk-logger.ts +25 -0
  10. package/examples/extensions/hello.ts +32 -0
  11. package/examples/extensions/pirate.ts +43 -0
  12. package/examples/extensions/plan-mode.ts +551 -0
  13. package/examples/extensions/reload-runtime.ts +37 -0
  14. package/examples/extensions/todo.ts +296 -0
  15. package/examples/extensions/tools.ts +145 -0
  16. package/examples/extensions/with-deps/index.ts +36 -0
  17. package/examples/extensions/with-deps/package-lock.json +31 -0
  18. package/examples/extensions/with-deps/package.json +16 -0
  19. package/examples/hooks/README.md +56 -0
  20. package/examples/hooks/auto-commit-on-exit.ts +48 -0
  21. package/examples/hooks/confirm-destructive.ts +58 -0
  22. package/examples/hooks/custom-compaction.ts +115 -0
  23. package/examples/hooks/dirty-repo-guard.ts +51 -0
  24. package/examples/hooks/file-trigger.ts +40 -0
  25. package/examples/hooks/git-checkpoint.ts +52 -0
  26. package/examples/hooks/handoff.ts +149 -0
  27. package/examples/hooks/permission-gate.ts +33 -0
  28. package/examples/hooks/protected-paths.ts +29 -0
  29. package/examples/hooks/qna.ts +118 -0
  30. package/examples/hooks/status-line.ts +39 -0
  31. package/examples/sdk/01-minimal.ts +21 -0
  32. package/examples/sdk/02-custom-model.ts +49 -0
  33. package/examples/sdk/03-custom-prompt.ts +43 -0
  34. package/examples/sdk/04-skills.ts +43 -0
  35. package/examples/sdk/06-extensions.ts +80 -0
  36. package/examples/sdk/06-hooks.ts +61 -0
  37. package/examples/sdk/07-context-files.ts +35 -0
  38. package/examples/sdk/08-prompt-templates.ts +41 -0
  39. package/examples/sdk/08-slash-commands.ts +46 -0
  40. package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
  41. package/examples/sdk/11-sessions.ts +47 -0
  42. package/examples/sdk/README.md +172 -0
  43. package/package.json +539 -0
  44. package/scripts/build-info/resolvers.ts +51 -0
  45. package/scripts/capture-ax-fixture.ts +84 -0
  46. package/scripts/capture-login-fixture.ts +30 -0
  47. package/scripts/check-workflow-field-coverage.ts +101 -0
  48. package/scripts/extension-uat-harness.ts +340 -0
  49. package/scripts/format-prompts.ts +68 -0
  50. package/scripts/generate-api-spec-index.ts +580 -0
  51. package/scripts/generate-branding-index.ts +81 -0
  52. package/scripts/generate-build-info.ts +106 -0
  53. package/scripts/generate-console-catalog.ts +88 -0
  54. package/scripts/generate-console-field-metadata.ts +74 -0
  55. package/scripts/generate-docs-index.ts +40 -0
  56. package/scripts/generate-template.ts +32 -0
  57. package/scripts/generate-terraform-index.ts +81 -0
  58. package/scripts/mermaid-gallery.ts +132 -0
  59. package/scripts/uat-matrix-modalities.ts +451 -0
  60. package/scripts/uat-matrix-report.ts +175 -0
  61. package/scripts/uat-matrix.ts +353 -0
  62. package/src/async/index.ts +2 -0
  63. package/src/async/job-manager.ts +416 -0
  64. package/src/async/support.ts +5 -0
  65. package/src/autoresearch/apply-contract-to-state.ts +1 -0
  66. package/src/autoresearch/command-resume.md +17 -0
  67. package/src/autoresearch/contract.ts +205 -0
  68. package/src/autoresearch/dashboard.ts +374 -0
  69. package/src/autoresearch/git.ts +191 -0
  70. package/src/autoresearch/helpers.ts +328 -0
  71. package/src/autoresearch/index.ts +402 -0
  72. package/src/autoresearch/prompt.md +236 -0
  73. package/src/autoresearch/resume-message.md +16 -0
  74. package/src/autoresearch/state.ts +303 -0
  75. package/src/autoresearch/tools/init-experiment.ts +400 -0
  76. package/src/autoresearch/tools/log-experiment.ts +793 -0
  77. package/src/autoresearch/tools/run-experiment.ts +679 -0
  78. package/src/autoresearch/types.ts +114 -0
  79. package/src/browser/acquire.ts +249 -0
  80. package/src/browser/actions.ts +126 -0
  81. package/src/browser/auth.ts +176 -0
  82. package/src/browser/ax.ts +134 -0
  83. package/src/browser/cdp-core.ts +45 -0
  84. package/src/browser/cdp-page-actions.ts +51 -0
  85. package/src/browser/chrome-locate.ts +66 -0
  86. package/src/browser/dom-context.ts +89 -0
  87. package/src/browser/dt-context.ts +100 -0
  88. package/src/browser/extension-bridge.ts +182 -0
  89. package/src/browser/extension-page-actions.ts +397 -0
  90. package/src/browser/extension-provider.ts +373 -0
  91. package/src/browser/index.ts +17 -0
  92. package/src/browser/input-commit.ts +74 -0
  93. package/src/browser/native-messaging.ts +20 -0
  94. package/src/browser/page-actions.ts +18 -0
  95. package/src/browser/provider.ts +155 -0
  96. package/src/browser/resolver.ts +126 -0
  97. package/src/browser/selector.ts +40 -0
  98. package/src/bun-imports.d.ts +22 -0
  99. package/src/capability/context-file.ts +43 -0
  100. package/src/capability/extension-module.ts +34 -0
  101. package/src/capability/extension.ts +47 -0
  102. package/src/capability/fs.ts +107 -0
  103. package/src/capability/hook.ts +40 -0
  104. package/src/capability/index.ts +438 -0
  105. package/src/capability/instruction.ts +37 -0
  106. package/src/capability/mcp.ts +74 -0
  107. package/src/capability/prompt.ts +35 -0
  108. package/src/capability/rule.ts +224 -0
  109. package/src/capability/settings.ts +34 -0
  110. package/src/capability/skill.ts +50 -0
  111. package/src/capability/slash-command.ts +40 -0
  112. package/src/capability/ssh.ts +41 -0
  113. package/src/capability/system-prompt.ts +34 -0
  114. package/src/capability/tool.ts +38 -0
  115. package/src/capability/types.ts +168 -0
  116. package/src/cli/agents-cli.ts +138 -0
  117. package/src/cli/args.ts +286 -0
  118. package/src/cli/chrome-cli.ts +88 -0
  119. package/src/cli/classify-install-target.ts +50 -0
  120. package/src/cli/commands/init-xdg.ts +27 -0
  121. package/src/cli/config-cli.ts +418 -0
  122. package/src/cli/file-processor.ts +121 -0
  123. package/src/cli/grep-cli.ts +160 -0
  124. package/src/cli/grievances-cli.ts +78 -0
  125. package/src/cli/initial-message.ts +58 -0
  126. package/src/cli/jupyter-cli.ts +106 -0
  127. package/src/cli/list-models.ts +128 -0
  128. package/src/cli/plugin-cli.ts +964 -0
  129. package/src/cli/read-cli.ts +68 -0
  130. package/src/cli/session-picker.ts +52 -0
  131. package/src/cli/setup-cli.ts +479 -0
  132. package/src/cli/shell-cli.ts +174 -0
  133. package/src/cli/ssh-cli.ts +179 -0
  134. package/src/cli/stats-cli.ts +182 -0
  135. package/src/cli/update-cli.ts +446 -0
  136. package/src/cli/web-search-cli.ts +203 -0
  137. package/src/cli.ts +123 -0
  138. package/src/commands/agents.ts +57 -0
  139. package/src/commands/chrome-host.ts +71 -0
  140. package/src/commands/chrome.ts +28 -0
  141. package/src/commands/commit.ts +36 -0
  142. package/src/commands/config.ts +51 -0
  143. package/src/commands/grep.ts +48 -0
  144. package/src/commands/grievances.ts +20 -0
  145. package/src/commands/jupyter.ts +32 -0
  146. package/src/commands/launch.ts +144 -0
  147. package/src/commands/plugin.ts +78 -0
  148. package/src/commands/read.ts +33 -0
  149. package/src/commands/setup.ts +42 -0
  150. package/src/commands/shell.ts +29 -0
  151. package/src/commands/ssh.ts +60 -0
  152. package/src/commands/stats.ts +29 -0
  153. package/src/commands/update.ts +21 -0
  154. package/src/commands/web-search.ts +46 -0
  155. package/src/commit/agentic/agent.ts +314 -0
  156. package/src/commit/agentic/fallback.ts +96 -0
  157. package/src/commit/agentic/index.ts +354 -0
  158. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  159. package/src/commit/agentic/prompts/session-user.md +25 -0
  160. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  161. package/src/commit/agentic/prompts/system.md +38 -0
  162. package/src/commit/agentic/state.ts +60 -0
  163. package/src/commit/agentic/tools/analyze-file.ts +127 -0
  164. package/src/commit/agentic/tools/git-file-diff.ts +191 -0
  165. package/src/commit/agentic/tools/git-hunk.ts +50 -0
  166. package/src/commit/agentic/tools/git-overview.ts +81 -0
  167. package/src/commit/agentic/tools/index.ts +54 -0
  168. package/src/commit/agentic/tools/propose-changelog.ts +139 -0
  169. package/src/commit/agentic/tools/propose-commit.ts +122 -0
  170. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  171. package/src/commit/agentic/tools/schemas.ts +31 -0
  172. package/src/commit/agentic/tools/split-commit.ts +251 -0
  173. package/src/commit/agentic/topo-sort.ts +44 -0
  174. package/src/commit/agentic/trivial.ts +51 -0
  175. package/src/commit/agentic/validation.ts +183 -0
  176. package/src/commit/analysis/conventional.ts +122 -0
  177. package/src/commit/analysis/index.ts +4 -0
  178. package/src/commit/analysis/scope.ts +242 -0
  179. package/src/commit/analysis/summary.ts +105 -0
  180. package/src/commit/analysis/validation.ts +66 -0
  181. package/src/commit/changelog/detect.ts +40 -0
  182. package/src/commit/changelog/generate.ts +101 -0
  183. package/src/commit/changelog/index.ts +234 -0
  184. package/src/commit/changelog/parse.ts +44 -0
  185. package/src/commit/cli.ts +85 -0
  186. package/src/commit/git/diff.ts +148 -0
  187. package/src/commit/index.ts +5 -0
  188. package/src/commit/map-reduce/index.ts +69 -0
  189. package/src/commit/map-reduce/map-phase.ts +193 -0
  190. package/src/commit/map-reduce/reduce-phase.ts +108 -0
  191. package/src/commit/map-reduce/utils.ts +9 -0
  192. package/src/commit/message.ts +11 -0
  193. package/src/commit/model-selection.ts +66 -0
  194. package/src/commit/pipeline.ts +242 -0
  195. package/src/commit/prompts/analysis-system.md +148 -0
  196. package/src/commit/prompts/analysis-user.md +38 -0
  197. package/src/commit/prompts/changelog-system.md +50 -0
  198. package/src/commit/prompts/changelog-user.md +18 -0
  199. package/src/commit/prompts/file-observer-system.md +24 -0
  200. package/src/commit/prompts/file-observer-user.md +8 -0
  201. package/src/commit/prompts/reduce-system.md +50 -0
  202. package/src/commit/prompts/reduce-user.md +17 -0
  203. package/src/commit/prompts/summary-retry.md +3 -0
  204. package/src/commit/prompts/summary-system.md +38 -0
  205. package/src/commit/prompts/summary-user.md +13 -0
  206. package/src/commit/prompts/types-description.md +2 -0
  207. package/src/commit/types.ts +118 -0
  208. package/src/commit/utils/exclusions.ts +42 -0
  209. package/src/commit/utils.ts +44 -0
  210. package/src/config/auto-config.ts +698 -0
  211. package/src/config/context-schema.json +115 -0
  212. package/src/config/file-lock.ts +121 -0
  213. package/src/config/keybindings.ts +493 -0
  214. package/src/config/mcp-schema.json +230 -0
  215. package/src/config/model-equivalence.ts +675 -0
  216. package/src/config/model-registry.ts +2265 -0
  217. package/src/config/model-resolver.ts +1289 -0
  218. package/src/config/prompt-templates.ts +271 -0
  219. package/src/config/resolve-config-value.ts +110 -0
  220. package/src/config/settings-schema.ts +2155 -0
  221. package/src/config/settings.ts +730 -0
  222. package/src/config.ts +418 -0
  223. package/src/cursor.ts +323 -0
  224. package/src/dap/client.ts +674 -0
  225. package/src/dap/config.ts +150 -0
  226. package/src/dap/defaults.json +211 -0
  227. package/src/dap/index.ts +4 -0
  228. package/src/dap/session.ts +1255 -0
  229. package/src/dap/types.ts +600 -0
  230. package/src/debug/index.ts +440 -0
  231. package/src/debug/log-formatting.ts +58 -0
  232. package/src/debug/log-viewer.ts +908 -0
  233. package/src/debug/profiler.ts +158 -0
  234. package/src/debug/report-bundle.ts +365 -0
  235. package/src/debug/system-info.ts +107 -0
  236. package/src/discovery/agents-md.ts +67 -0
  237. package/src/discovery/agents.ts +219 -0
  238. package/src/discovery/builtin.ts +851 -0
  239. package/src/discovery/claude-plugins.ts +297 -0
  240. package/src/discovery/claude.ts +543 -0
  241. package/src/discovery/cline.ts +83 -0
  242. package/src/discovery/codex.ts +535 -0
  243. package/src/discovery/cursor.ts +220 -0
  244. package/src/discovery/gemini.ts +396 -0
  245. package/src/discovery/github.ts +118 -0
  246. package/src/discovery/helpers.ts +934 -0
  247. package/src/discovery/index.ts +79 -0
  248. package/src/discovery/language.ts +46 -0
  249. package/src/discovery/mcp-json.ts +171 -0
  250. package/src/discovery/opencode.ts +393 -0
  251. package/src/discovery/plugin-dir-roots.ts +28 -0
  252. package/src/discovery/ssh.ts +153 -0
  253. package/src/discovery/substitute-plugin-root.ts +29 -0
  254. package/src/discovery/vscode.ts +105 -0
  255. package/src/discovery/windsurf.ts +147 -0
  256. package/src/edit/diff.ts +818 -0
  257. package/src/edit/index.ts +481 -0
  258. package/src/edit/line-hash.ts +67 -0
  259. package/src/edit/modes/chunk.ts +762 -0
  260. package/src/edit/modes/hashline.ts +1366 -0
  261. package/src/edit/modes/patch.ts +1791 -0
  262. package/src/edit/modes/replace.ts +1115 -0
  263. package/src/edit/normalize.ts +375 -0
  264. package/src/edit/renderer.ts +627 -0
  265. package/src/exa/factory.ts +61 -0
  266. package/src/exa/index.ts +27 -0
  267. package/src/exa/mcp-client.ts +293 -0
  268. package/src/exa/render.ts +232 -0
  269. package/src/exa/researcher.ts +47 -0
  270. package/src/exa/search.ts +86 -0
  271. package/src/exa/types.ts +166 -0
  272. package/src/exa/websets.ts +247 -0
  273. package/src/exec/bash-executor.ts +332 -0
  274. package/src/exec/exec.ts +53 -0
  275. package/src/exec/idle-timeout-watchdog.ts +126 -0
  276. package/src/exec/non-interactive-env.ts +48 -0
  277. package/src/export/custom-share.ts +65 -0
  278. package/src/export/html/index.ts +161 -0
  279. package/src/export/html/template.css +1001 -0
  280. package/src/export/html/template.generated.ts +2 -0
  281. package/src/export/html/template.html +46 -0
  282. package/src/export/html/template.js +1950 -0
  283. package/src/export/html/template.macro.ts +24 -0
  284. package/src/export/html/vendor/highlight.min.js +1213 -0
  285. package/src/export/html/vendor/marked.min.js +6 -0
  286. package/src/export/ttsr.ts +434 -0
  287. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +25 -0
  288. package/src/extensibility/custom-commands/bundled/review/index.ts +456 -0
  289. package/src/extensibility/custom-commands/index.ts +2 -0
  290. package/src/extensibility/custom-commands/loader.ts +236 -0
  291. package/src/extensibility/custom-commands/types.ts +111 -0
  292. package/src/extensibility/custom-tools/index.ts +7 -0
  293. package/src/extensibility/custom-tools/loader.ts +238 -0
  294. package/src/extensibility/custom-tools/types.ts +251 -0
  295. package/src/extensibility/custom-tools/wrapper.ts +47 -0
  296. package/src/extensibility/extensions/index.ts +15 -0
  297. package/src/extensibility/extensions/loader.ts +572 -0
  298. package/src/extensibility/extensions/runner.ts +848 -0
  299. package/src/extensibility/extensions/types.ts +1394 -0
  300. package/src/extensibility/extensions/wrapper.ts +191 -0
  301. package/src/extensibility/hooks/index.ts +5 -0
  302. package/src/extensibility/hooks/loader.ts +255 -0
  303. package/src/extensibility/hooks/runner.ts +425 -0
  304. package/src/extensibility/hooks/tool-wrapper.ts +108 -0
  305. package/src/extensibility/hooks/types.ts +826 -0
  306. package/src/extensibility/plugins/doctor.ts +66 -0
  307. package/src/extensibility/plugins/git-url.ts +281 -0
  308. package/src/extensibility/plugins/index.ts +9 -0
  309. package/src/extensibility/plugins/installer.ts +192 -0
  310. package/src/extensibility/plugins/loader.ts +267 -0
  311. package/src/extensibility/plugins/manager.ts +731 -0
  312. package/src/extensibility/plugins/marketplace/cache.ts +136 -0
  313. package/src/extensibility/plugins/marketplace/fetcher.ts +318 -0
  314. package/src/extensibility/plugins/marketplace/index.ts +6 -0
  315. package/src/extensibility/plugins/marketplace/manager.ts +781 -0
  316. package/src/extensibility/plugins/marketplace/prerequisites.ts +255 -0
  317. package/src/extensibility/plugins/marketplace/registry.ts +196 -0
  318. package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
  319. package/src/extensibility/plugins/marketplace/types.ts +201 -0
  320. package/src/extensibility/plugins/parser.ts +105 -0
  321. package/src/extensibility/plugins/types.ts +194 -0
  322. package/src/extensibility/skills.ts +269 -0
  323. package/src/extensibility/slash-commands.ts +246 -0
  324. package/src/extensibility/tool-proxy.ts +25 -0
  325. package/src/extensibility/utils.ts +38 -0
  326. package/src/index.ts +61 -0
  327. package/src/internal-urls/agent-protocol.ts +136 -0
  328. package/src/internal-urls/api-catalog-resolve.ts +495 -0
  329. package/src/internal-urls/api-catalog-types.ts +94 -0
  330. package/src/internal-urls/api-spec-resolve.ts +1036 -0
  331. package/src/internal-urls/api-spec-types.ts +239 -0
  332. package/src/internal-urls/artifact-protocol.ts +97 -0
  333. package/src/internal-urls/branding-index.generated.ts +88 -0
  334. package/src/internal-urls/build-info-runtime.ts +302 -0
  335. package/src/internal-urls/build-info.generated.ts +33 -0
  336. package/src/internal-urls/computer-profile.ts +692 -0
  337. package/src/internal-urls/console-catalog-types.ts +21 -0
  338. package/src/internal-urls/console-catalog.generated.ts +532 -0
  339. package/src/internal-urls/console-field-metadata-types.ts +59 -0
  340. package/src/internal-urls/console-field-metadata.generated.ts +4841 -0
  341. package/src/internal-urls/console-resolve.ts +178 -0
  342. package/src/internal-urls/docs-index.generated.ts +698 -0
  343. package/src/internal-urls/extension-api.md +147 -0
  344. package/src/internal-urls/index.ts +46 -0
  345. package/src/internal-urls/jobs-protocol.ts +119 -0
  346. package/src/internal-urls/json-query.ts +126 -0
  347. package/src/internal-urls/local-protocol.ts +206 -0
  348. package/src/internal-urls/mcp-protocol.ts +156 -0
  349. package/src/internal-urls/memory-protocol.ts +133 -0
  350. package/src/internal-urls/parse.ts +72 -0
  351. package/src/internal-urls/profile-collectors.ts +106 -0
  352. package/src/internal-urls/router.ts +55 -0
  353. package/src/internal-urls/rule-protocol.ts +55 -0
  354. package/src/internal-urls/skill-protocol.ts +111 -0
  355. package/src/internal-urls/terraform-index.generated.ts +1852 -0
  356. package/src/internal-urls/terraform-resolve.ts +184 -0
  357. package/src/internal-urls/terraform-types.ts +45 -0
  358. package/src/internal-urls/types.ts +52 -0
  359. package/src/internal-urls/user-profile.ts +363 -0
  360. package/src/internal-urls/xcsh-protocol.ts +644 -0
  361. package/src/ipy/cancellation.ts +28 -0
  362. package/src/ipy/executor.ts +1155 -0
  363. package/src/ipy/gateway-coordinator.ts +424 -0
  364. package/src/ipy/kernel.ts +1091 -0
  365. package/src/ipy/modules.ts +144 -0
  366. package/src/ipy/prelude.py +849 -0
  367. package/src/ipy/prelude.ts +3 -0
  368. package/src/ipy/runtime.ts +221 -0
  369. package/src/locales/ar.json +512 -0
  370. package/src/locales/de.json +512 -0
  371. package/src/locales/en.json +549 -0
  372. package/src/locales/es.json +512 -0
  373. package/src/locales/fr.json +512 -0
  374. package/src/locales/hi.json +512 -0
  375. package/src/locales/index.ts +29 -0
  376. package/src/locales/it.json +512 -0
  377. package/src/locales/ja.json +512 -0
  378. package/src/locales/ko.json +512 -0
  379. package/src/locales/pt-br.json +512 -0
  380. package/src/locales/th.json +512 -0
  381. package/src/locales/zh-cn.json +512 -0
  382. package/src/locales/zh-tw.json +512 -0
  383. package/src/lsp/client.ts +941 -0
  384. package/src/lsp/clients/biome-client.ts +202 -0
  385. package/src/lsp/clients/index.ts +50 -0
  386. package/src/lsp/clients/lsp-linter-client.ts +93 -0
  387. package/src/lsp/clients/swiftlint-client.ts +120 -0
  388. package/src/lsp/config.ts +418 -0
  389. package/src/lsp/defaults.json +999 -0
  390. package/src/lsp/edits.ts +109 -0
  391. package/src/lsp/index.ts +1746 -0
  392. package/src/lsp/lspmux.ts +233 -0
  393. package/src/lsp/render.ts +692 -0
  394. package/src/lsp/startup-events.ts +13 -0
  395. package/src/lsp/types.ts +444 -0
  396. package/src/lsp/utils.ts +691 -0
  397. package/src/main.ts +944 -0
  398. package/src/mcp/client.ts +482 -0
  399. package/src/mcp/config-writer.ts +225 -0
  400. package/src/mcp/config.ts +365 -0
  401. package/src/mcp/discoverable-tool-metadata.ts +202 -0
  402. package/src/mcp/index.ts +29 -0
  403. package/src/mcp/json-rpc.ts +84 -0
  404. package/src/mcp/loader.ts +124 -0
  405. package/src/mcp/manager.ts +1152 -0
  406. package/src/mcp/oauth-discovery.ts +349 -0
  407. package/src/mcp/oauth-flow.ts +387 -0
  408. package/src/mcp/render.ts +157 -0
  409. package/src/mcp/smithery-auth.ts +104 -0
  410. package/src/mcp/smithery-connect.ts +145 -0
  411. package/src/mcp/smithery-registry.ts +477 -0
  412. package/src/mcp/tool-bridge.ts +417 -0
  413. package/src/mcp/tool-cache.ts +117 -0
  414. package/src/mcp/transports/http.ts +475 -0
  415. package/src/mcp/transports/index.ts +6 -0
  416. package/src/mcp/transports/stdio.ts +325 -0
  417. package/src/mcp/types.ts +423 -0
  418. package/src/memories/index.ts +1115 -0
  419. package/src/memories/storage.ts +577 -0
  420. package/src/modes/acp/acp-agent.ts +1361 -0
  421. package/src/modes/acp/acp-event-mapper.ts +538 -0
  422. package/src/modes/acp/acp-mode.ts +15 -0
  423. package/src/modes/acp/index.ts +2 -0
  424. package/src/modes/components/agent-dashboard.ts +1124 -0
  425. package/src/modes/components/assistant-message.ts +213 -0
  426. package/src/modes/components/bash-execution.ts +345 -0
  427. package/src/modes/components/bordered-loader.ts +41 -0
  428. package/src/modes/components/branch-summary-message.ts +45 -0
  429. package/src/modes/components/btw-panel.ts +103 -0
  430. package/src/modes/components/compaction-summary-message.ts +51 -0
  431. package/src/modes/components/context-add-wizard.ts +534 -0
  432. package/src/modes/components/countdown-timer.ts +75 -0
  433. package/src/modes/components/custom-editor.ts +238 -0
  434. package/src/modes/components/custom-message.ts +91 -0
  435. package/src/modes/components/diff.ts +210 -0
  436. package/src/modes/components/dynamic-border.ts +25 -0
  437. package/src/modes/components/extensions/extension-dashboard.ts +326 -0
  438. package/src/modes/components/extensions/extension-list.ts +492 -0
  439. package/src/modes/components/extensions/index.ts +9 -0
  440. package/src/modes/components/extensions/inspector-panel.ts +317 -0
  441. package/src/modes/components/extensions/state-manager.ts +587 -0
  442. package/src/modes/components/extensions/types.ts +191 -0
  443. package/src/modes/components/footer.ts +262 -0
  444. package/src/modes/components/gutter-block.ts +315 -0
  445. package/src/modes/components/history-search.ts +158 -0
  446. package/src/modes/components/hook-editor.ts +151 -0
  447. package/src/modes/components/hook-input.ts +81 -0
  448. package/src/modes/components/hook-message.ts +100 -0
  449. package/src/modes/components/hook-selector.ts +192 -0
  450. package/src/modes/components/index.ts +36 -0
  451. package/src/modes/components/keybinding-hints.ts +65 -0
  452. package/src/modes/components/login-dialog.ts +164 -0
  453. package/src/modes/components/mcp-add-wizard.ts +1314 -0
  454. package/src/modes/components/model-selector.ts +946 -0
  455. package/src/modes/components/oauth-selector.ts +211 -0
  456. package/src/modes/components/plugin-selector.ts +95 -0
  457. package/src/modes/components/plugin-settings.ts +477 -0
  458. package/src/modes/components/plugins/index.ts +5 -0
  459. package/src/modes/components/plugins/plugin-dashboard.ts +523 -0
  460. package/src/modes/components/plugins/plugin-inspector-pane.ts +84 -0
  461. package/src/modes/components/plugins/plugin-list-pane.ts +109 -0
  462. package/src/modes/components/plugins/state-manager.ts +229 -0
  463. package/src/modes/components/plugins/types.ts +51 -0
  464. package/src/modes/components/plugins/utils.ts +6 -0
  465. package/src/modes/components/python-execution.ts +244 -0
  466. package/src/modes/components/queue-mode-selector.ts +56 -0
  467. package/src/modes/components/read-tool-group.ts +137 -0
  468. package/src/modes/components/session-observer-overlay.ts +483 -0
  469. package/src/modes/components/session-selector.ts +343 -0
  470. package/src/modes/components/settings-defs.ts +568 -0
  471. package/src/modes/components/settings-selector.ts +641 -0
  472. package/src/modes/components/show-images-selector.ts +45 -0
  473. package/src/modes/components/skill-message.ts +90 -0
  474. package/src/modes/components/status-line/context-gradient.ts +64 -0
  475. package/src/modes/components/status-line/git-utils.ts +42 -0
  476. package/src/modes/components/status-line/hex-ansi.ts +29 -0
  477. package/src/modes/components/status-line/index.ts +4 -0
  478. package/src/modes/components/status-line/presets.ts +174 -0
  479. package/src/modes/components/status-line/segments.ts +494 -0
  480. package/src/modes/components/status-line/separators.ts +55 -0
  481. package/src/modes/components/status-line/token-rate.ts +66 -0
  482. package/src/modes/components/status-line/types.ts +96 -0
  483. package/src/modes/components/status-line-segment-editor.ts +361 -0
  484. package/src/modes/components/status-line.ts +729 -0
  485. package/src/modes/components/theme-selector.ts +63 -0
  486. package/src/modes/components/thinking-selector.ts +52 -0
  487. package/src/modes/components/todo-reminder.ts +54 -0
  488. package/src/modes/components/tool-execution.ts +781 -0
  489. package/src/modes/components/tree-selector.ts +908 -0
  490. package/src/modes/components/ttsr-notification.ts +80 -0
  491. package/src/modes/components/user-message-selector.ts +141 -0
  492. package/src/modes/components/user-message.ts +100 -0
  493. package/src/modes/components/visual-truncate.ts +63 -0
  494. package/src/modes/components/welcome-checks.ts +313 -0
  495. package/src/modes/components/welcome.ts +270 -0
  496. package/src/modes/controllers/btw-controller.ts +193 -0
  497. package/src/modes/controllers/chord-routing.ts +37 -0
  498. package/src/modes/controllers/command-controller.ts +1293 -0
  499. package/src/modes/controllers/context-command-controller.ts +61 -0
  500. package/src/modes/controllers/event-controller.ts +743 -0
  501. package/src/modes/controllers/extension-ui-controller.ts +983 -0
  502. package/src/modes/controllers/input-controller.ts +877 -0
  503. package/src/modes/controllers/mcp-command-controller.ts +1940 -0
  504. package/src/modes/controllers/selector-controller.ts +1292 -0
  505. package/src/modes/controllers/ssh-command-controller.ts +421 -0
  506. package/src/modes/index.ts +34 -0
  507. package/src/modes/interactive-mode.ts +1781 -0
  508. package/src/modes/oauth-manual-input.ts +42 -0
  509. package/src/modes/print-mode.ts +196 -0
  510. package/src/modes/prompt-action-autocomplete.ts +231 -0
  511. package/src/modes/rpc/host-tools.ts +186 -0
  512. package/src/modes/rpc/rpc-client.ts +762 -0
  513. package/src/modes/rpc/rpc-mode.ts +877 -0
  514. package/src/modes/rpc/rpc-types.ts +322 -0
  515. package/src/modes/session-observer-registry.ts +146 -0
  516. package/src/modes/shared.ts +30 -0
  517. package/src/modes/theme/defaults/index.ts +7 -0
  518. package/src/modes/theme/defaults/xcsh-dark.json +113 -0
  519. package/src/modes/theme/defaults/xcsh-light.json +115 -0
  520. package/src/modes/theme/mermaid-cache.ts +151 -0
  521. package/src/modes/theme/mermaid-palette.ts +39 -0
  522. package/src/modes/theme/theme-schema.json +553 -0
  523. package/src/modes/theme/theme.ts +2563 -0
  524. package/src/modes/types.ts +273 -0
  525. package/src/modes/utils/hotkeys-markdown.ts +60 -0
  526. package/src/modes/utils/keybinding-matchers.ts +30 -0
  527. package/src/modes/utils/read-group-outcome-aggregator.ts +55 -0
  528. package/src/modes/utils/sanitize-error-message.ts +60 -0
  529. package/src/modes/utils/tools-markdown.ts +28 -0
  530. package/src/modes/utils/ui-helpers.ts +734 -0
  531. package/src/plan-mode/approved-plan.ts +55 -0
  532. package/src/plan-mode/state.ts +6 -0
  533. package/src/priority.json +37 -0
  534. package/src/prompts/agents/designer.md +67 -0
  535. package/src/prompts/agents/explore.md +61 -0
  536. package/src/prompts/agents/frontmatter.md +10 -0
  537. package/src/prompts/agents/init.md +36 -0
  538. package/src/prompts/agents/librarian.md +121 -0
  539. package/src/prompts/agents/plan.md +49 -0
  540. package/src/prompts/agents/reviewer.md +127 -0
  541. package/src/prompts/agents/task.md +16 -0
  542. package/src/prompts/ci-green-request.md +35 -0
  543. package/src/prompts/compaction/branch-summary-context.md +5 -0
  544. package/src/prompts/compaction/branch-summary-preamble.md +2 -0
  545. package/src/prompts/compaction/branch-summary.md +30 -0
  546. package/src/prompts/compaction/compaction-short-summary.md +9 -0
  547. package/src/prompts/compaction/compaction-summary-context.md +5 -0
  548. package/src/prompts/compaction/compaction-summary.md +38 -0
  549. package/src/prompts/compaction/compaction-turn-prefix.md +17 -0
  550. package/src/prompts/compaction/compaction-update-summary.md +45 -0
  551. package/src/prompts/memories/consolidation.md +30 -0
  552. package/src/prompts/memories/read-path.md +11 -0
  553. package/src/prompts/memories/stage_one_input.md +6 -0
  554. package/src/prompts/memories/stage_one_system.md +21 -0
  555. package/src/prompts/review-request.md +70 -0
  556. package/src/prompts/system/agent-creation-architect.md +65 -0
  557. package/src/prompts/system/agent-creation-user.md +6 -0
  558. package/src/prompts/system/auto-handoff-threshold-focus.md +1 -0
  559. package/src/prompts/system/btw-user.md +8 -0
  560. package/src/prompts/system/commit-message-system.md +2 -0
  561. package/src/prompts/system/custom-system-prompt.md +82 -0
  562. package/src/prompts/system/eager-todo.md +13 -0
  563. package/src/prompts/system/file-operations.md +10 -0
  564. package/src/prompts/system/handoff-document.md +48 -0
  565. package/src/prompts/system/plan-mode-active.md +114 -0
  566. package/src/prompts/system/plan-mode-approved.md +23 -0
  567. package/src/prompts/system/plan-mode-reference.md +14 -0
  568. package/src/prompts/system/plan-mode-subagent.md +34 -0
  569. package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
  570. package/src/prompts/system/subagent-submit-reminder.md +7 -0
  571. package/src/prompts/system/subagent-system-prompt.md +36 -0
  572. package/src/prompts/system/subagent-user-prompt.md +12 -0
  573. package/src/prompts/system/summarization-system.md +3 -0
  574. package/src/prompts/system/system-prompt.md +698 -0
  575. package/src/prompts/system/title-system.md +2 -0
  576. package/src/prompts/system/ttsr-interrupt.md +7 -0
  577. package/src/prompts/system/web-search.md +28 -0
  578. package/src/prompts/tools/ask.md +28 -0
  579. package/src/prompts/tools/ast-edit.md +48 -0
  580. package/src/prompts/tools/ast-grep.md +54 -0
  581. package/src/prompts/tools/async-result.md +5 -0
  582. package/src/prompts/tools/bash.md +67 -0
  583. package/src/prompts/tools/browser.md +26 -0
  584. package/src/prompts/tools/calculator.md +10 -0
  585. package/src/prompts/tools/cancel-job.md +5 -0
  586. package/src/prompts/tools/catalog-workflow-runner.md +13 -0
  587. package/src/prompts/tools/checkpoint.md +16 -0
  588. package/src/prompts/tools/chunk-edit.md +279 -0
  589. package/src/prompts/tools/debug.md +43 -0
  590. package/src/prompts/tools/display-image.md +23 -0
  591. package/src/prompts/tools/exit-plan-mode.md +41 -0
  592. package/src/prompts/tools/find.md +26 -0
  593. package/src/prompts/tools/gemini-image.md +7 -0
  594. package/src/prompts/tools/grep.md +29 -0
  595. package/src/prompts/tools/hashline.md +131 -0
  596. package/src/prompts/tools/inspect-image-system.md +20 -0
  597. package/src/prompts/tools/inspect-image.md +32 -0
  598. package/src/prompts/tools/lsp.md +33 -0
  599. package/src/prompts/tools/patch.md +77 -0
  600. package/src/prompts/tools/poll.md +5 -0
  601. package/src/prompts/tools/python.md +60 -0
  602. package/src/prompts/tools/read-chunk.md +35 -0
  603. package/src/prompts/tools/read.md +63 -0
  604. package/src/prompts/tools/render-mermaid.md +9 -0
  605. package/src/prompts/tools/replace.md +36 -0
  606. package/src/prompts/tools/resolve.md +8 -0
  607. package/src/prompts/tools/rewind.md +13 -0
  608. package/src/prompts/tools/search-tool-bm25.md +34 -0
  609. package/src/prompts/tools/ssh.md +44 -0
  610. package/src/prompts/tools/task-summary.md +28 -0
  611. package/src/prompts/tools/task.md +131 -0
  612. package/src/prompts/tools/todo-write.md +89 -0
  613. package/src/prompts/tools/vim.md +98 -0
  614. package/src/prompts/tools/web-search.md +10 -0
  615. package/src/prompts/tools/write.md +14 -0
  616. package/src/prompts/tools/xcsh-api.md +283 -0
  617. package/src/resource-management/index.ts +42 -0
  618. package/src/sdk.ts +2123 -0
  619. package/src/secrets/index.ts +146 -0
  620. package/src/secrets/obfuscator.ts +290 -0
  621. package/src/secrets/regex.ts +21 -0
  622. package/src/services/context-env.ts +102 -0
  623. package/src/services/xcsh-api-client.ts +230 -0
  624. package/src/services/xcsh-context-command.ts +803 -0
  625. package/src/services/xcsh-context-display.ts +49 -0
  626. package/src/services/xcsh-context-indicators.ts +17 -0
  627. package/src/services/xcsh-context-segment.ts +39 -0
  628. package/src/services/xcsh-context.ts +1410 -0
  629. package/src/services/xcsh-env.ts +107 -0
  630. package/src/services/xcsh-knowledge.ts +177 -0
  631. package/src/services/xcsh-table.ts +164 -0
  632. package/src/session/agent-session.ts +6690 -0
  633. package/src/session/agent-storage.ts +451 -0
  634. package/src/session/artifacts.ts +132 -0
  635. package/src/session/auth-storage.ts +17 -0
  636. package/src/session/blob-store.ts +135 -0
  637. package/src/session/compaction/branch-summarization.ts +322 -0
  638. package/src/session/compaction/compaction.ts +1388 -0
  639. package/src/session/compaction/index.ts +7 -0
  640. package/src/session/compaction/pruning.ts +91 -0
  641. package/src/session/compaction/utils.ts +184 -0
  642. package/src/session/history-storage.ts +253 -0
  643. package/src/session/messages.ts +597 -0
  644. package/src/session/session-dump-format.ts +203 -0
  645. package/src/session/session-manager.ts +2816 -0
  646. package/src/session/session-storage.ts +370 -0
  647. package/src/session/streaming-output.ts +770 -0
  648. package/src/session/tool-choice-queue.ts +213 -0
  649. package/src/slash-commands/builtin-registry.ts +1614 -0
  650. package/src/slash-commands/export-command.ts +178 -0
  651. package/src/slash-commands/marketplace-install-parser.ts +99 -0
  652. package/src/slash-commands/resource-commands.ts +250 -0
  653. package/src/ssh/config-writer.ts +183 -0
  654. package/src/ssh/connection-manager.ts +445 -0
  655. package/src/ssh/ssh-executor.ts +131 -0
  656. package/src/ssh/sshfs-mount.ts +137 -0
  657. package/src/ssh/utils.ts +8 -0
  658. package/src/stt/downloader.ts +71 -0
  659. package/src/stt/index.ts +3 -0
  660. package/src/stt/recorder.ts +351 -0
  661. package/src/stt/setup.ts +52 -0
  662. package/src/stt/stt-controller.ts +160 -0
  663. package/src/stt/transcribe.py +70 -0
  664. package/src/stt/transcriber.ts +91 -0
  665. package/src/system-prompt.ts +688 -0
  666. package/src/task/agents.ts +166 -0
  667. package/src/task/commands.ts +131 -0
  668. package/src/task/discovery.ts +126 -0
  669. package/src/task/executor.ts +1324 -0
  670. package/src/task/index.ts +1197 -0
  671. package/src/task/isolation-backend.ts +72 -0
  672. package/src/task/name-generator.ts +1577 -0
  673. package/src/task/output-manager.ts +107 -0
  674. package/src/task/parallel.ts +116 -0
  675. package/src/task/render.ts +1035 -0
  676. package/src/task/subprocess-tool-registry.ts +88 -0
  677. package/src/task/template.ts +33 -0
  678. package/src/task/types.ts +230 -0
  679. package/src/task/worktree.ts +580 -0
  680. package/src/task/xcsh-command.ts +26 -0
  681. package/src/thinking.ts +87 -0
  682. package/src/tools/action-renderer.ts +198 -0
  683. package/src/tools/archive-reader.ts +315 -0
  684. package/src/tools/ask.ts +791 -0
  685. package/src/tools/ast-edit.ts +492 -0
  686. package/src/tools/ast-grep.ts +453 -0
  687. package/src/tools/auto-generated-guard.ts +305 -0
  688. package/src/tools/bash-interactive.ts +383 -0
  689. package/src/tools/bash-interceptor.ts +67 -0
  690. package/src/tools/bash-normalize.ts +107 -0
  691. package/src/tools/bash-skill-urls.ts +246 -0
  692. package/src/tools/bash.ts +878 -0
  693. package/src/tools/browser-renderer.ts +129 -0
  694. package/src/tools/browser.ts +1366 -0
  695. package/src/tools/calculator.ts +543 -0
  696. package/src/tools/cancel-job.ts +100 -0
  697. package/src/tools/catalog-workflow-runner.ts +718 -0
  698. package/src/tools/checkpoint.ts +133 -0
  699. package/src/tools/context.ts +39 -0
  700. package/src/tools/debug.ts +1004 -0
  701. package/src/tools/display-image-renderer.ts +96 -0
  702. package/src/tools/display-image.ts +109 -0
  703. package/src/tools/exit-plan-mode.ts +101 -0
  704. package/src/tools/fetch.ts +1462 -0
  705. package/src/tools/find.ts +437 -0
  706. package/src/tools/fs-cache-invalidation.ts +33 -0
  707. package/src/tools/gemini-image.ts +1004 -0
  708. package/src/tools/grep.ts +705 -0
  709. package/src/tools/index.ts +442 -0
  710. package/src/tools/inspect-image-renderer.ts +101 -0
  711. package/src/tools/inspect-image.ts +176 -0
  712. package/src/tools/json-tree.ts +266 -0
  713. package/src/tools/jtd-to-json-schema.ts +199 -0
  714. package/src/tools/jtd-to-typescript.ts +136 -0
  715. package/src/tools/jtd-utils.ts +102 -0
  716. package/src/tools/list-limit.ts +40 -0
  717. package/src/tools/mermaid-renderer.ts +127 -0
  718. package/src/tools/notebook.ts +288 -0
  719. package/src/tools/output-meta.ts +588 -0
  720. package/src/tools/path-utils.ts +560 -0
  721. package/src/tools/plan-mode-guard.ts +41 -0
  722. package/src/tools/poll-tool.ts +177 -0
  723. package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
  724. package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
  725. package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
  726. package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
  727. package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
  728. package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
  729. package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
  730. package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
  731. package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
  732. package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
  733. package/src/tools/puppeteer/10_stealth_plugins.txt +206 -0
  734. package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
  735. package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
  736. package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
  737. package/src/tools/python.ts +1184 -0
  738. package/src/tools/read.ts +1591 -0
  739. package/src/tools/render-mermaid.ts +93 -0
  740. package/src/tools/render-utils.ts +677 -0
  741. package/src/tools/renderers.ts +82 -0
  742. package/src/tools/report-tool-issue.ts +80 -0
  743. package/src/tools/resolve.ts +196 -0
  744. package/src/tools/review.ts +238 -0
  745. package/src/tools/search-tool-bm25.ts +288 -0
  746. package/src/tools/sqlite-reader.ts +623 -0
  747. package/src/tools/ssh.ts +322 -0
  748. package/src/tools/submit-result.ts +229 -0
  749. package/src/tools/todo-render.ts +33 -0
  750. package/src/tools/todo-write.ts +440 -0
  751. package/src/tools/tool-errors.ts +62 -0
  752. package/src/tools/tool-result.ts +93 -0
  753. package/src/tools/tool-timeouts.ts +30 -0
  754. package/src/tools/vim.ts +981 -0
  755. package/src/tools/write.ts +671 -0
  756. package/src/tools/xcsh-api-renderer.ts +402 -0
  757. package/src/tools/xcsh-api.ts +887 -0
  758. package/src/tui/code-cell.ts +101 -0
  759. package/src/tui/file-list.ts +47 -0
  760. package/src/tui/index.ts +11 -0
  761. package/src/tui/output-block.ts +175 -0
  762. package/src/tui/status-line.ts +39 -0
  763. package/src/tui/tree-list.ts +84 -0
  764. package/src/tui/types.ts +15 -0
  765. package/src/tui/utils.ts +103 -0
  766. package/src/utils/changelog.ts +98 -0
  767. package/src/utils/clipboard.ts +80 -0
  768. package/src/utils/command-args.ts +76 -0
  769. package/src/utils/commit-message-generator.ts +137 -0
  770. package/src/utils/edit-mode.ts +50 -0
  771. package/src/utils/event-bus.ts +33 -0
  772. package/src/utils/external-editor.ts +65 -0
  773. package/src/utils/file-display-mode.ts +37 -0
  774. package/src/utils/file-mentions.ts +376 -0
  775. package/src/utils/fuzzy.ts +108 -0
  776. package/src/utils/git.ts +1495 -0
  777. package/src/utils/gitstatus.ts +140 -0
  778. package/src/utils/image-convert.ts +27 -0
  779. package/src/utils/image-loading.ts +98 -0
  780. package/src/utils/image-passthrough.ts +118 -0
  781. package/src/utils/image-resize.ts +272 -0
  782. package/src/utils/image-viewer.ts +17 -0
  783. package/src/utils/lang-from-path.ts +239 -0
  784. package/src/utils/markit.ts +81 -0
  785. package/src/utils/open.ts +20 -0
  786. package/src/utils/session-color.ts +55 -0
  787. package/src/utils/shell-snapshot.ts +188 -0
  788. package/src/utils/title-generator.ts +193 -0
  789. package/src/utils/tool-choice.ts +28 -0
  790. package/src/utils/tools-manager.ts +356 -0
  791. package/src/vim/buffer.ts +309 -0
  792. package/src/vim/commands.ts +382 -0
  793. package/src/vim/engine.ts +2426 -0
  794. package/src/vim/parser.ts +151 -0
  795. package/src/vim/render.ts +252 -0
  796. package/src/vim/types.ts +197 -0
  797. package/src/web/kagi.ts +174 -0
  798. package/src/web/parallel.ts +346 -0
  799. package/src/web/scrapers/artifacthub.ts +207 -0
  800. package/src/web/scrapers/arxiv.ts +83 -0
  801. package/src/web/scrapers/aur.ts +162 -0
  802. package/src/web/scrapers/biorxiv.ts +133 -0
  803. package/src/web/scrapers/bluesky.ts +262 -0
  804. package/src/web/scrapers/brew.ts +172 -0
  805. package/src/web/scrapers/cheatsh.ts +68 -0
  806. package/src/web/scrapers/chocolatey.ts +196 -0
  807. package/src/web/scrapers/choosealicense.ts +95 -0
  808. package/src/web/scrapers/cisa-kev.ts +87 -0
  809. package/src/web/scrapers/clojars.ts +154 -0
  810. package/src/web/scrapers/coingecko.ts +177 -0
  811. package/src/web/scrapers/crates-io.ts +110 -0
  812. package/src/web/scrapers/crossref.ts +136 -0
  813. package/src/web/scrapers/devto.ts +147 -0
  814. package/src/web/scrapers/discogs.ts +306 -0
  815. package/src/web/scrapers/discourse.ts +197 -0
  816. package/src/web/scrapers/dockerhub.ts +138 -0
  817. package/src/web/scrapers/docs-rs.ts +653 -0
  818. package/src/web/scrapers/fdroid.ts +134 -0
  819. package/src/web/scrapers/firefox-addons.ts +191 -0
  820. package/src/web/scrapers/flathub.ts +223 -0
  821. package/src/web/scrapers/github-gist.ts +58 -0
  822. package/src/web/scrapers/github.ts +452 -0
  823. package/src/web/scrapers/gitlab.ts +401 -0
  824. package/src/web/scrapers/go-pkg.ts +266 -0
  825. package/src/web/scrapers/hackage.ts +140 -0
  826. package/src/web/scrapers/hackernews.ts +189 -0
  827. package/src/web/scrapers/hex.ts +105 -0
  828. package/src/web/scrapers/huggingface.ts +321 -0
  829. package/src/web/scrapers/iacr.ts +89 -0
  830. package/src/web/scrapers/index.ts +252 -0
  831. package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
  832. package/src/web/scrapers/lemmy.ts +203 -0
  833. package/src/web/scrapers/lobsters.ts +175 -0
  834. package/src/web/scrapers/mastodon.ts +292 -0
  835. package/src/web/scrapers/maven.ts +138 -0
  836. package/src/web/scrapers/mdn.ts +169 -0
  837. package/src/web/scrapers/metacpan.ts +222 -0
  838. package/src/web/scrapers/musicbrainz.ts +250 -0
  839. package/src/web/scrapers/npm.ts +98 -0
  840. package/src/web/scrapers/nuget.ts +183 -0
  841. package/src/web/scrapers/nvd.ts +222 -0
  842. package/src/web/scrapers/ollama.ts +239 -0
  843. package/src/web/scrapers/open-vsx.ts +106 -0
  844. package/src/web/scrapers/opencorporates.ts +292 -0
  845. package/src/web/scrapers/openlibrary.ts +336 -0
  846. package/src/web/scrapers/orcid.ts +286 -0
  847. package/src/web/scrapers/osv.ts +176 -0
  848. package/src/web/scrapers/packagist.ts +160 -0
  849. package/src/web/scrapers/pub-dev.ts +143 -0
  850. package/src/web/scrapers/pubmed.ts +211 -0
  851. package/src/web/scrapers/pypi.ts +112 -0
  852. package/src/web/scrapers/rawg.ts +110 -0
  853. package/src/web/scrapers/readthedocs.ts +120 -0
  854. package/src/web/scrapers/reddit.ts +95 -0
  855. package/src/web/scrapers/repology.ts +251 -0
  856. package/src/web/scrapers/rfc.ts +201 -0
  857. package/src/web/scrapers/rubygems.ts +103 -0
  858. package/src/web/scrapers/searchcode.ts +190 -0
  859. package/src/web/scrapers/sec-edgar.ts +261 -0
  860. package/src/web/scrapers/semantic-scholar.ts +171 -0
  861. package/src/web/scrapers/snapcraft.ts +187 -0
  862. package/src/web/scrapers/sourcegraph.ts +336 -0
  863. package/src/web/scrapers/spdx.ts +108 -0
  864. package/src/web/scrapers/spotify.ts +198 -0
  865. package/src/web/scrapers/stackoverflow.ts +120 -0
  866. package/src/web/scrapers/terraform.ts +277 -0
  867. package/src/web/scrapers/tldr.ts +47 -0
  868. package/src/web/scrapers/twitter.ts +93 -0
  869. package/src/web/scrapers/types.ts +267 -0
  870. package/src/web/scrapers/utils.ts +109 -0
  871. package/src/web/scrapers/vimeo.ts +133 -0
  872. package/src/web/scrapers/vscode-marketplace.ts +187 -0
  873. package/src/web/scrapers/w3c.ts +156 -0
  874. package/src/web/scrapers/wikidata.ts +344 -0
  875. package/src/web/scrapers/wikipedia.ts +84 -0
  876. package/src/web/scrapers/youtube.ts +313 -0
  877. package/src/web/search/errors.ts +120 -0
  878. package/src/web/search/index.ts +346 -0
  879. package/src/web/search/params.ts +129 -0
  880. package/src/web/search/provider.ts +97 -0
  881. package/src/web/search/providers/anthropic.ts +339 -0
  882. package/src/web/search/providers/base.ts +35 -0
  883. package/src/web/search/providers/brave.ts +150 -0
  884. package/src/web/search/providers/codex.ts +402 -0
  885. package/src/web/search/providers/exa.ts +264 -0
  886. package/src/web/search/providers/firecrawl.ts +115 -0
  887. package/src/web/search/providers/gemini.ts +566 -0
  888. package/src/web/search/providers/jina.ts +99 -0
  889. package/src/web/search/providers/kagi.ts +70 -0
  890. package/src/web/search/providers/kimi.ts +157 -0
  891. package/src/web/search/providers/parallel.ts +63 -0
  892. package/src/web/search/providers/perplexity.ts +546 -0
  893. package/src/web/search/providers/synthetic.ts +113 -0
  894. package/src/web/search/providers/tavily.ts +162 -0
  895. package/src/web/search/providers/utils.ts +36 -0
  896. package/src/web/search/providers/zai.ts +311 -0
  897. package/src/web/search/render.ts +348 -0
  898. package/src/web/search/types.ts +438 -0
  899. package/src/web/search/utils.ts +17 -0
@@ -0,0 +1,1115 @@
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
+
8
+ import type { AgentToolResult } from "@f5xc-salesdemos/pi-agent-core";
9
+ import { isEnoent } from "@f5xc-salesdemos/pi-utils";
10
+ import { type Static, Type } from "@sinclair/typebox";
11
+ import type { WritethroughCallback, WritethroughDeferredHandle } from "../../lsp";
12
+ import type { ToolSession } from "../../tools";
13
+ import { invalidateFsScanAfterWrite } from "../../tools/fs-cache-invalidation";
14
+ import { outputMeta } from "../../tools/output-meta";
15
+ import { enforcePlanModeWrite, resolvePlanPath } from "../../tools/plan-mode-guard";
16
+ import { generateDiffString, replaceText } from "../diff";
17
+ import {
18
+ countLeadingWhitespace,
19
+ detectLineEnding,
20
+ normalizeForFuzzy,
21
+ normalizeToLF,
22
+ normalizeUnicode,
23
+ restoreLineEndings,
24
+ stripBom,
25
+ } from "../normalize";
26
+ import type { EditToolDetails, LspBatchRequest } from "../renderer";
27
+
28
+ export interface FuzzyMatch {
29
+ actualText: string;
30
+ startIndex: number;
31
+ startLine: number;
32
+ confidence: number;
33
+ }
34
+
35
+ export interface MatchOutcome {
36
+ match?: FuzzyMatch;
37
+ closest?: FuzzyMatch;
38
+ occurrences?: number;
39
+ occurrenceLines?: number[];
40
+ occurrencePreviews?: string[];
41
+ fuzzyMatches?: number;
42
+ dominantFuzzy?: boolean;
43
+ }
44
+
45
+ export type SequenceMatchStrategy =
46
+ | "exact"
47
+ | "trim-trailing"
48
+ | "trim"
49
+ | "comment-prefix"
50
+ | "unicode"
51
+ | "prefix"
52
+ | "substring"
53
+ | "fuzzy"
54
+ | "fuzzy-dominant"
55
+ | "character";
56
+
57
+ export interface SequenceSearchResult {
58
+ index: number | undefined;
59
+ confidence: number;
60
+ matchCount?: number;
61
+ matchIndices?: number[];
62
+ strategy?: SequenceMatchStrategy;
63
+ }
64
+
65
+ export type ContextMatchStrategy = "exact" | "trim" | "unicode" | "prefix" | "substring" | "fuzzy";
66
+
67
+ export interface ContextLineResult {
68
+ index: number | undefined;
69
+ confidence: number;
70
+ matchCount?: number;
71
+ matchIndices?: number[];
72
+ strategy?: ContextMatchStrategy;
73
+ }
74
+
75
+ export class EditMatchError extends Error {
76
+ constructor(
77
+ readonly path: string,
78
+ readonly searchText: string,
79
+ readonly closest: FuzzyMatch | undefined,
80
+ readonly options: { allowFuzzy: boolean; threshold: number; fuzzyMatches?: number },
81
+ ) {
82
+ super(EditMatchError.formatMessage(path, searchText, closest, options));
83
+ this.name = "EditMatchError";
84
+ }
85
+
86
+ static formatMessage(
87
+ path: string,
88
+ searchText: string,
89
+ closest: FuzzyMatch | undefined,
90
+ options: { allowFuzzy: boolean; threshold: number; fuzzyMatches?: number },
91
+ ): string {
92
+ if (!closest) {
93
+ return options.allowFuzzy
94
+ ? `Could not find a close enough match in ${path}.`
95
+ : `Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`;
96
+ }
97
+
98
+ const similarity = Math.round(closest.confidence * 100);
99
+ const searchLines = searchText.split("\n");
100
+ const actualLines = closest.actualText.split("\n");
101
+ const { oldLine, newLine } = findFirstDifferentLine(searchLines, actualLines);
102
+ const thresholdPercent = Math.round(options.threshold * 100);
103
+
104
+ const hint = options.allowFuzzy
105
+ ? options.fuzzyMatches && options.fuzzyMatches > 1
106
+ ? `Found ${options.fuzzyMatches} high-confidence matches. Provide more context to make it unique.`
107
+ : `Closest match was below the ${thresholdPercent}% similarity threshold.`
108
+ : "Fuzzy matching is disabled. Enable 'Edit fuzzy match' in settings to accept high-confidence matches.";
109
+
110
+ return [
111
+ options.allowFuzzy
112
+ ? `Could not find a close enough match in ${path}.`
113
+ : `Could not find the exact text in ${path}.`,
114
+ ``,
115
+ `Closest match (${similarity}% similar) at line ${closest.startLine}:`,
116
+ ` - ${oldLine}`,
117
+ ` + ${newLine}`,
118
+ hint,
119
+ ].join("\n");
120
+ }
121
+ }
122
+
123
+ function findFirstDifferentLine(oldLines: string[], newLines: string[]): { oldLine: string; newLine: string } {
124
+ const max = Math.max(oldLines.length, newLines.length);
125
+ for (let i = 0; i < max; i++) {
126
+ const oldLine = oldLines[i] ?? "";
127
+ const newLine = newLines[i] ?? "";
128
+ if (oldLine !== newLine) {
129
+ return { oldLine, newLine };
130
+ }
131
+ }
132
+ return { oldLine: oldLines[0] ?? "", newLine: newLines[0] ?? "" };
133
+ }
134
+
135
+ function formatOccurrenceError(path: string, matchOutcome: MatchOutcome): string {
136
+ const previews = matchOutcome.occurrencePreviews?.join("\n\n") ?? "";
137
+ const moreMsg =
138
+ matchOutcome.occurrences && matchOutcome.occurrences > MAX_RECORDED_MATCHES
139
+ ? ` (showing first ${MAX_RECORDED_MATCHES} of ${matchOutcome.occurrences})`
140
+ : "";
141
+ return `Found ${matchOutcome.occurrences} occurrences in ${path}${moreMsg}:\n\n${previews}\n\nAdd more context lines to disambiguate.`;
142
+ }
143
+
144
+ async function readReplaceFileContent(absolutePath: string, path: string): Promise<string> {
145
+ try {
146
+ return await Bun.file(absolutePath).text();
147
+ } catch (error) {
148
+ if (isEnoent(error)) {
149
+ throw new Error(`File not found: ${path}`);
150
+ }
151
+ throw error;
152
+ }
153
+ }
154
+
155
+ // ═══════════════════════════════════════════════════════════════════════════
156
+ // Constants
157
+ // ═══════════════════════════════════════════════════════════════════════════
158
+
159
+ /** Default similarity threshold for fuzzy matching */
160
+ export const DEFAULT_FUZZY_THRESHOLD = 0.95;
161
+
162
+ /** Threshold for sequence-based fuzzy matching */
163
+ const SEQUENCE_FUZZY_THRESHOLD = 0.92;
164
+
165
+ /** Fallback threshold for line-based matching */
166
+ const FALLBACK_THRESHOLD = 0.8;
167
+
168
+ /** Threshold for context line matching */
169
+ const CONTEXT_FUZZY_THRESHOLD = 0.8;
170
+
171
+ /** Minimum length for partial/substring matching */
172
+ const PARTIAL_MATCH_MIN_LENGTH = 6;
173
+
174
+ /** Minimum ratio of pattern to line length for substring match */
175
+ const PARTIAL_MATCH_MIN_RATIO = 0.3;
176
+
177
+ /** Context lines to show before/after an ambiguous match preview */
178
+ const OCCURRENCE_PREVIEW_CONTEXT = 5;
179
+
180
+ /** Maximum line length for ambiguous match previews */
181
+ const OCCURRENCE_PREVIEW_MAX_LEN = 80;
182
+
183
+ /** Maximum number of match indices or previews to retain for diagnostics */
184
+ const MAX_RECORDED_MATCHES = 5;
185
+
186
+ /** Minimum confidence for a dominant fuzzy match to be auto-selected */
187
+ const DOMINANT_FUZZY_MIN_CONFIDENCE = 0.97;
188
+
189
+ /** Minimum score gap between the best and second-best fuzzy matches */
190
+ const DOMINANT_FUZZY_DELTA = 0.08;
191
+
192
+ interface IndexedMatches {
193
+ firstMatch: number | undefined;
194
+ matchCount: number;
195
+ matchIndices: number[];
196
+ }
197
+
198
+ interface PreviewWindowOptions {
199
+ context: number;
200
+ maxLen: number;
201
+ }
202
+
203
+ function collectIndexedMatches(
204
+ start: number,
205
+ endInclusive: number,
206
+ predicate: (index: number) => boolean,
207
+ ): IndexedMatches {
208
+ let firstMatch: number | undefined;
209
+ let matchCount = 0;
210
+ const matchIndices: number[] = [];
211
+
212
+ for (let index = start; index <= endInclusive; index++) {
213
+ if (!predicate(index)) continue;
214
+ if (firstMatch === undefined) {
215
+ firstMatch = index;
216
+ }
217
+ matchCount++;
218
+ if (matchIndices.length < MAX_RECORDED_MATCHES) {
219
+ matchIndices.push(index);
220
+ }
221
+ }
222
+
223
+ return { firstMatch, matchCount, matchIndices };
224
+ }
225
+
226
+ function toSingleMatchResult<TStrategy extends SequenceMatchStrategy | ContextMatchStrategy>(
227
+ matches: IndexedMatches,
228
+ confidence: number,
229
+ strategy: TStrategy,
230
+ ): { index: number; confidence: number; strategy: TStrategy } | undefined {
231
+ if (matches.firstMatch === undefined) {
232
+ return undefined;
233
+ }
234
+ return {
235
+ index: matches.firstMatch,
236
+ confidence,
237
+ strategy,
238
+ };
239
+ }
240
+
241
+ function toAmbiguousMatchResult<TStrategy extends SequenceMatchStrategy | ContextMatchStrategy>(
242
+ matches: IndexedMatches,
243
+ confidence: number,
244
+ strategy: TStrategy,
245
+ ): { index: number; confidence: number; matchCount: number; matchIndices: number[]; strategy: TStrategy } | undefined {
246
+ if (matches.firstMatch === undefined) {
247
+ return undefined;
248
+ }
249
+ return {
250
+ index: matches.firstMatch,
251
+ confidence,
252
+ matchCount: matches.matchCount,
253
+ matchIndices: matches.matchIndices,
254
+ strategy,
255
+ };
256
+ }
257
+
258
+ function formatPreviewWindow(lines: string[], centerIndex: number, options: PreviewWindowOptions): string {
259
+ const start = Math.max(0, centerIndex - options.context);
260
+ const end = Math.min(lines.length, centerIndex + options.context + 1);
261
+ return lines
262
+ .slice(start, end)
263
+ .map((line, index) => {
264
+ const num = start + index + 1;
265
+ const truncated = line.length > options.maxLen ? `${line.slice(0, options.maxLen - 1)}…` : line;
266
+ return ` ${num} | ${truncated}`;
267
+ })
268
+ .join("\n");
269
+ }
270
+
271
+ function findExactMatchOutcome(content: string, target: string): MatchOutcome | undefined {
272
+ const exactIndex = content.indexOf(target);
273
+ if (exactIndex === -1) {
274
+ return undefined;
275
+ }
276
+
277
+ const occurrences = content.split(target).length - 1;
278
+ if (occurrences > 1) {
279
+ const contentLines = content.split("\n");
280
+ const occurrenceLines: number[] = [];
281
+ const occurrencePreviews: string[] = [];
282
+ let searchStart = 0;
283
+
284
+ for (let i = 0; i < MAX_RECORDED_MATCHES; i++) {
285
+ const idx = content.indexOf(target, searchStart);
286
+ if (idx === -1) break;
287
+ const lineNumber = content.slice(0, idx).split("\n").length;
288
+ occurrenceLines.push(lineNumber);
289
+ occurrencePreviews.push(
290
+ formatPreviewWindow(contentLines, lineNumber - 1, {
291
+ context: OCCURRENCE_PREVIEW_CONTEXT,
292
+ maxLen: OCCURRENCE_PREVIEW_MAX_LEN,
293
+ }),
294
+ );
295
+ searchStart = idx + 1;
296
+ }
297
+
298
+ return { occurrences, occurrenceLines, occurrencePreviews };
299
+ }
300
+
301
+ const startLine = content.slice(0, exactIndex).split("\n").length;
302
+ return {
303
+ match: {
304
+ actualText: target,
305
+ startIndex: exactIndex,
306
+ startLine,
307
+ confidence: 1,
308
+ },
309
+ };
310
+ }
311
+
312
+ // ═══════════════════════════════════════════════════════════════════════════
313
+ // Core Algorithms
314
+ // ═══════════════════════════════════════════════════════════════════════════
315
+
316
+ /** Compute Levenshtein distance between two strings */
317
+ export function levenshteinDistance(a: string, b: string): number {
318
+ if (a === b) return 0;
319
+ const aLen = a.length;
320
+ const bLen = b.length;
321
+ if (aLen === 0) return bLen;
322
+ if (bLen === 0) return aLen;
323
+
324
+ let prev = new Array<number>(bLen + 1);
325
+ let curr = new Array<number>(bLen + 1);
326
+ for (let j = 0; j <= bLen; j++) {
327
+ prev[j] = j;
328
+ }
329
+
330
+ for (let i = 1; i <= aLen; i++) {
331
+ curr[0] = i;
332
+ const aCode = a.charCodeAt(i - 1);
333
+ for (let j = 1; j <= bLen; j++) {
334
+ const cost = aCode === b.charCodeAt(j - 1) ? 0 : 1;
335
+ const deletion = prev[j] + 1;
336
+ const insertion = curr[j - 1] + 1;
337
+ const substitution = prev[j - 1] + cost;
338
+ curr[j] = Math.min(deletion, insertion, substitution);
339
+ }
340
+ const tmp = prev;
341
+ prev = curr;
342
+ curr = tmp;
343
+ }
344
+
345
+ return prev[bLen];
346
+ }
347
+
348
+ /** Compute similarity score between two strings (0 to 1) */
349
+ export function similarity(a: string, b: string): number {
350
+ if (a.length === 0 && b.length === 0) return 1;
351
+ const maxLen = Math.max(a.length, b.length);
352
+ if (maxLen === 0) return 1;
353
+ const distance = levenshteinDistance(a, b);
354
+ return 1 - distance / maxLen;
355
+ }
356
+
357
+ // ═══════════════════════════════════════════════════════════════════════════
358
+ // Line-Based Utilities
359
+ // ═══════════════════════════════════════════════════════════════════════════
360
+
361
+ /** Compute relative indent depths for lines */
362
+ function computeRelativeIndentDepths(lines: string[]): number[] {
363
+ const indents = lines.map(countLeadingWhitespace);
364
+ const nonEmptyIndents: number[] = [];
365
+ for (let i = 0; i < lines.length; i++) {
366
+ if (lines[i].trim().length > 0) {
367
+ nonEmptyIndents.push(indents[i]);
368
+ }
369
+ }
370
+ const minIndent = nonEmptyIndents.length > 0 ? Math.min(...nonEmptyIndents) : 0;
371
+ const indentSteps = nonEmptyIndents.map(indent => indent - minIndent).filter(step => step > 0);
372
+ const indentUnit = indentSteps.length > 0 ? Math.min(...indentSteps) : 1;
373
+
374
+ return lines.map((line, index) => {
375
+ if (line.trim().length === 0) return 0;
376
+ if (indentUnit <= 0) return 0;
377
+ const relativeIndent = indents[index] - minIndent;
378
+ return Math.round(relativeIndent / indentUnit);
379
+ });
380
+ }
381
+
382
+ /** Normalize lines for matching, optionally including indent depth */
383
+ function normalizeLines(lines: string[], includeDepth = true): string[] {
384
+ const indentDepths = includeDepth ? computeRelativeIndentDepths(lines) : null;
385
+ return lines.map((line, index) => {
386
+ const trimmed = line.trim();
387
+ const prefix = indentDepths ? `${indentDepths[index]}|` : "|";
388
+ if (trimmed.length === 0) return prefix;
389
+ return `${prefix}${normalizeForFuzzy(trimmed)}`;
390
+ });
391
+ }
392
+
393
+ /** Compute character offsets for each line in content */
394
+ function computeLineOffsets(lines: string[]): number[] {
395
+ const offsets: number[] = [];
396
+ let offset = 0;
397
+ for (let i = 0; i < lines.length; i++) {
398
+ offsets.push(offset);
399
+ offset += lines[i].length;
400
+ if (i < lines.length - 1) offset += 1; // newline
401
+ }
402
+ return offsets;
403
+ }
404
+
405
+ // ═══════════════════════════════════════════════════════════════════════════
406
+ // Character-Level Fuzzy Match (for replace mode)
407
+ // ═══════════════════════════════════════════════════════════════════════════
408
+
409
+ interface BestFuzzyMatchResult {
410
+ best?: FuzzyMatch;
411
+ aboveThresholdCount: number;
412
+ secondBestScore: number;
413
+ }
414
+
415
+ function findBestFuzzyMatchCore(
416
+ contentLines: string[],
417
+ targetLines: string[],
418
+ offsets: number[],
419
+ threshold: number,
420
+ includeDepth: boolean,
421
+ ): BestFuzzyMatchResult {
422
+ const targetNormalized = normalizeLines(targetLines, includeDepth);
423
+
424
+ let best: FuzzyMatch | undefined;
425
+ let bestScore = -1;
426
+ let secondBestScore = -1;
427
+ let aboveThresholdCount = 0;
428
+
429
+ for (let start = 0; start <= contentLines.length - targetLines.length; start++) {
430
+ const windowLines = contentLines.slice(start, start + targetLines.length);
431
+ const windowNormalized = normalizeLines(windowLines, includeDepth);
432
+ let score = 0;
433
+ for (let i = 0; i < targetLines.length; i++) {
434
+ score += similarity(targetNormalized[i], windowNormalized[i]);
435
+ }
436
+ score = score / targetLines.length;
437
+
438
+ if (score >= threshold) {
439
+ aboveThresholdCount++;
440
+ }
441
+
442
+ if (score > bestScore) {
443
+ secondBestScore = bestScore;
444
+ bestScore = score;
445
+ best = {
446
+ actualText: windowLines.join("\n"),
447
+ startIndex: offsets[start],
448
+ startLine: start + 1,
449
+ confidence: score,
450
+ };
451
+ } else if (score > secondBestScore) {
452
+ secondBestScore = score;
453
+ }
454
+ }
455
+
456
+ return { best, aboveThresholdCount, secondBestScore };
457
+ }
458
+
459
+ function findBestFuzzyMatch(content: string, target: string, threshold: number): BestFuzzyMatchResult {
460
+ const contentLines = content.split("\n");
461
+ const targetLines = target.split("\n");
462
+
463
+ if (targetLines.length === 0 || target.length === 0) {
464
+ return { aboveThresholdCount: 0, secondBestScore: 0 };
465
+ }
466
+ if (targetLines.length > contentLines.length) {
467
+ return { aboveThresholdCount: 0, secondBestScore: 0 };
468
+ }
469
+
470
+ const offsets = computeLineOffsets(contentLines);
471
+ let result = findBestFuzzyMatchCore(contentLines, targetLines, offsets, threshold, true);
472
+
473
+ // Retry without indent depth if match is close but below threshold
474
+ if (result.best && result.best.confidence < threshold && result.best.confidence >= FALLBACK_THRESHOLD) {
475
+ const noDepthResult = findBestFuzzyMatchCore(contentLines, targetLines, offsets, threshold, false);
476
+ if (noDepthResult.best && noDepthResult.best.confidence > result.best.confidence) {
477
+ result = noDepthResult;
478
+ }
479
+ }
480
+
481
+ return result;
482
+ }
483
+
484
+ /**
485
+ * Find a match for target text within content.
486
+ * Used primarily for replace-mode edits.
487
+ */
488
+ export function findMatch(
489
+ content: string,
490
+ target: string,
491
+ options: { allowFuzzy: boolean; threshold?: number },
492
+ ): MatchOutcome {
493
+ if (target.length === 0) {
494
+ return {};
495
+ }
496
+
497
+ const exactMatch = findExactMatchOutcome(content, target);
498
+ if (exactMatch) {
499
+ return exactMatch;
500
+ }
501
+
502
+ // Try fuzzy match
503
+ const threshold = options.threshold ?? DEFAULT_FUZZY_THRESHOLD;
504
+ const { best, aboveThresholdCount, secondBestScore } = findBestFuzzyMatch(content, target, threshold);
505
+
506
+ if (!best) {
507
+ return {};
508
+ }
509
+
510
+ if (options.allowFuzzy && best.confidence >= threshold) {
511
+ if (aboveThresholdCount === 1) {
512
+ return { match: best, closest: best };
513
+ }
514
+ if (
515
+ aboveThresholdCount > 1 &&
516
+ best.confidence >= DOMINANT_FUZZY_MIN_CONFIDENCE &&
517
+ best.confidence - secondBestScore >= DOMINANT_FUZZY_DELTA
518
+ ) {
519
+ return { match: best, closest: best, fuzzyMatches: aboveThresholdCount, dominantFuzzy: true };
520
+ }
521
+ }
522
+
523
+ return { closest: best, fuzzyMatches: aboveThresholdCount };
524
+ }
525
+
526
+ // ═══════════════════════════════════════════════════════════════════════════
527
+ // Line-Based Sequence Match (for patch mode)
528
+ // ═══════════════════════════════════════════════════════════════════════════
529
+
530
+ /** Check if pattern matches lines starting at index using comparison function */
531
+ function matchesAt(lines: string[], pattern: string[], i: number, compare: (a: string, b: string) => boolean): boolean {
532
+ for (let j = 0; j < pattern.length; j++) {
533
+ if (!compare(lines[i + j], pattern[j])) {
534
+ return false;
535
+ }
536
+ }
537
+ return true;
538
+ }
539
+
540
+ /** Compute average similarity score for pattern at position */
541
+ function fuzzyScoreAt(lines: string[], pattern: string[], i: number): number {
542
+ let totalScore = 0;
543
+ for (let j = 0; j < pattern.length; j++) {
544
+ const lineNorm = normalizeForFuzzy(lines[i + j]);
545
+ const patternNorm = normalizeForFuzzy(pattern[j]);
546
+ totalScore += similarity(lineNorm, patternNorm);
547
+ }
548
+ return totalScore / pattern.length;
549
+ }
550
+
551
+ /** Check if line starts with pattern (normalized) */
552
+ function lineStartsWithPattern(line: string, pattern: string): boolean {
553
+ const lineNorm = normalizeForFuzzy(line);
554
+ const patternNorm = normalizeForFuzzy(pattern);
555
+ if (patternNorm.length === 0) return lineNorm.length === 0;
556
+ return lineNorm.startsWith(patternNorm);
557
+ }
558
+
559
+ /** Check if line contains pattern as significant substring */
560
+ function lineIncludesPattern(line: string, pattern: string): boolean {
561
+ const lineNorm = normalizeForFuzzy(line);
562
+ const patternNorm = normalizeForFuzzy(pattern);
563
+ if (patternNorm.length === 0) return lineNorm.length === 0;
564
+ if (patternNorm.length < PARTIAL_MATCH_MIN_LENGTH) return false;
565
+ if (!lineNorm.includes(patternNorm)) return false;
566
+ return patternNorm.length / Math.max(1, lineNorm.length) >= PARTIAL_MATCH_MIN_RATIO;
567
+ }
568
+
569
+ function stripCommentPrefix(line: string): string {
570
+ let trimmed = line.trimStart();
571
+ if (trimmed.startsWith("/*")) {
572
+ trimmed = trimmed.slice(2);
573
+ } else if (trimmed.startsWith("*/")) {
574
+ trimmed = trimmed.slice(2);
575
+ } else if (trimmed.startsWith("//")) {
576
+ trimmed = trimmed.slice(2);
577
+ } else if (trimmed.startsWith("*")) {
578
+ trimmed = trimmed.slice(1);
579
+ } else if (trimmed.startsWith("#")) {
580
+ trimmed = trimmed.slice(1);
581
+ } else if (trimmed.startsWith(";")) {
582
+ trimmed = trimmed.slice(1);
583
+ } else if (trimmed.startsWith("/") && trimmed[1] === " ") {
584
+ trimmed = trimmed.slice(1);
585
+ }
586
+ return trimmed.trimStart();
587
+ }
588
+
589
+ /**
590
+ * Find a sequence of pattern lines within content lines.
591
+ *
592
+ * Attempts matches with decreasing strictness:
593
+ * 1. Exact match
594
+ * 2. Trailing whitespace ignored
595
+ * 3. All whitespace trimmed
596
+ * 4. Unicode punctuation normalized
597
+ * 5. Prefix match (pattern is prefix of line)
598
+ * 6. Substring match (pattern is substring of line)
599
+ * 7. Fuzzy similarity match
600
+ *
601
+ * @param lines - The lines of the file content
602
+ * @param pattern - The lines to search for
603
+ * @param start - Starting index for the search
604
+ * @param eof - If true, prefer matching at end of file first
605
+ */
606
+ export function seekSequence(
607
+ lines: string[],
608
+ pattern: string[],
609
+ start: number,
610
+ eof: boolean,
611
+ options?: { allowFuzzy?: boolean },
612
+ ): SequenceSearchResult {
613
+ const allowFuzzy = options?.allowFuzzy ?? true;
614
+ // Empty pattern matches immediately
615
+ if (pattern.length === 0) {
616
+ return { index: start, confidence: 1.0, strategy: "exact" };
617
+ }
618
+
619
+ // Pattern longer than available content cannot match
620
+ if (pattern.length > lines.length) {
621
+ return { index: undefined, confidence: 0 };
622
+ }
623
+
624
+ // Determine search start position
625
+ const searchStart = eof && lines.length >= pattern.length ? lines.length - pattern.length : start;
626
+ const maxStart = lines.length - pattern.length;
627
+
628
+ const runExactPasses = (from: number, to: number): SequenceSearchResult | undefined => {
629
+ const comparisonPasses: Array<{
630
+ compare: (a: string, b: string) => boolean;
631
+ confidence: number;
632
+ strategy: SequenceMatchStrategy;
633
+ }> = [
634
+ { compare: (a, b) => a === b, confidence: 1.0, strategy: "exact" },
635
+ { compare: (a, b) => a.trimEnd() === b.trimEnd(), confidence: 0.99, strategy: "trim-trailing" },
636
+ { compare: (a, b) => a.trim() === b.trim(), confidence: 0.98, strategy: "trim" },
637
+ {
638
+ compare: (a, b) => stripCommentPrefix(a) === stripCommentPrefix(b),
639
+ confidence: 0.975,
640
+ strategy: "comment-prefix",
641
+ },
642
+ {
643
+ compare: (a, b) => normalizeUnicode(a) === normalizeUnicode(b),
644
+ confidence: 0.97,
645
+ strategy: "unicode",
646
+ },
647
+ ];
648
+
649
+ for (const pass of comparisonPasses) {
650
+ const matches = collectIndexedMatches(from, to, i => matchesAt(lines, pattern, i, pass.compare));
651
+ const result = toSingleMatchResult(matches, pass.confidence, pass.strategy);
652
+ if (result) {
653
+ return result;
654
+ }
655
+ }
656
+
657
+ if (!allowFuzzy) {
658
+ return undefined;
659
+ }
660
+
661
+ const partialPasses: Array<{
662
+ compare: (line: string, patternLine: string) => boolean;
663
+ confidence: number;
664
+ strategy: SequenceMatchStrategy;
665
+ }> = [
666
+ { compare: lineStartsWithPattern, confidence: 0.965, strategy: "prefix" },
667
+ { compare: lineIncludesPattern, confidence: 0.94, strategy: "substring" },
668
+ ];
669
+
670
+ for (const pass of partialPasses) {
671
+ const matches = collectIndexedMatches(from, to, i => matchesAt(lines, pattern, i, pass.compare));
672
+ const result = toAmbiguousMatchResult(matches, pass.confidence, pass.strategy);
673
+ if (result) {
674
+ return result;
675
+ }
676
+ }
677
+
678
+ return undefined;
679
+ };
680
+
681
+ const primaryPassResult = runExactPasses(searchStart, maxStart);
682
+ if (primaryPassResult) {
683
+ return primaryPassResult;
684
+ }
685
+
686
+ if (eof && searchStart > start) {
687
+ const fromStartResult = runExactPasses(start, maxStart);
688
+ if (fromStartResult) {
689
+ return fromStartResult;
690
+ }
691
+ }
692
+
693
+ if (!allowFuzzy) {
694
+ return { index: undefined, confidence: 0 };
695
+ }
696
+
697
+ // Pass 7: Fuzzy matching - find best match above threshold
698
+ let bestScore = 0;
699
+ let secondBestScore = 0;
700
+ let bestIndex: number | undefined;
701
+ const fuzzyMatches: IndexedMatches = {
702
+ firstMatch: undefined,
703
+ matchCount: 0,
704
+ matchIndices: [],
705
+ };
706
+
707
+ const scoreFuzzyRange = (from: number, to: number): void => {
708
+ for (let i = from; i <= to; i++) {
709
+ const score = fuzzyScoreAt(lines, pattern, i);
710
+ if (score >= SEQUENCE_FUZZY_THRESHOLD) {
711
+ if (fuzzyMatches.firstMatch === undefined) {
712
+ fuzzyMatches.firstMatch = i;
713
+ }
714
+ fuzzyMatches.matchCount++;
715
+ if (fuzzyMatches.matchIndices.length < MAX_RECORDED_MATCHES) {
716
+ fuzzyMatches.matchIndices.push(i);
717
+ }
718
+ }
719
+ if (score > bestScore) {
720
+ secondBestScore = bestScore;
721
+ bestScore = score;
722
+ bestIndex = i;
723
+ } else if (score > secondBestScore) {
724
+ secondBestScore = score;
725
+ }
726
+ }
727
+ };
728
+
729
+ scoreFuzzyRange(searchStart, maxStart);
730
+
731
+ // Also search from start if eof mode started from end
732
+ if (eof && searchStart > start) {
733
+ scoreFuzzyRange(start, searchStart - 1);
734
+ }
735
+
736
+ if (bestIndex !== undefined && bestScore >= SEQUENCE_FUZZY_THRESHOLD) {
737
+ if (
738
+ fuzzyMatches.matchCount > 1 &&
739
+ bestScore >= DOMINANT_FUZZY_MIN_CONFIDENCE &&
740
+ bestScore - secondBestScore >= DOMINANT_FUZZY_DELTA
741
+ ) {
742
+ return {
743
+ index: bestIndex,
744
+ confidence: bestScore,
745
+ matchCount: 1,
746
+ matchIndices: fuzzyMatches.matchIndices,
747
+ strategy: "fuzzy-dominant",
748
+ };
749
+ }
750
+ return {
751
+ index: bestIndex,
752
+ confidence: bestScore,
753
+ matchCount: fuzzyMatches.matchCount,
754
+ matchIndices: fuzzyMatches.matchIndices,
755
+ strategy: "fuzzy",
756
+ };
757
+ }
758
+
759
+ // Pass 8: Character-based fuzzy matching via findMatch
760
+ // This is the final fallback for when line-based matching fails
761
+ const CHARACTER_MATCH_THRESHOLD = 0.92;
762
+ const patternText = pattern.join("\n");
763
+ const contentText = lines.slice(start).join("\n");
764
+ const matchOutcome = findMatch(contentText, patternText, {
765
+ allowFuzzy: true,
766
+ threshold: CHARACTER_MATCH_THRESHOLD,
767
+ });
768
+
769
+ if (matchOutcome.match) {
770
+ // Convert character index back to line index
771
+ const matchedContent = contentText.substring(0, matchOutcome.match.startIndex);
772
+ const lineIndex = start + matchedContent.split("\n").length - 1;
773
+ const fallbackMatchCount = matchOutcome.occurrences ?? matchOutcome.fuzzyMatches ?? 1;
774
+ return {
775
+ index: lineIndex,
776
+ confidence: matchOutcome.match.confidence,
777
+ matchCount: fallbackMatchCount,
778
+ strategy: "character",
779
+ };
780
+ }
781
+
782
+ const fallbackMatchCount = matchOutcome.occurrences ?? matchOutcome.fuzzyMatches;
783
+ return { index: undefined, confidence: bestScore, matchCount: fallbackMatchCount };
784
+ }
785
+
786
+ export function findClosestSequenceMatch(
787
+ lines: string[],
788
+ pattern: string[],
789
+ options?: { start?: number; eof?: boolean },
790
+ ): { index: number | undefined; confidence: number; strategy: SequenceMatchStrategy } {
791
+ if (pattern.length === 0) {
792
+ return { index: options?.start ?? 0, confidence: 1, strategy: "exact" };
793
+ }
794
+ if (pattern.length > lines.length) {
795
+ return { index: undefined, confidence: 0, strategy: "fuzzy" };
796
+ }
797
+
798
+ const start = options?.start ?? 0;
799
+ const eof = options?.eof ?? false;
800
+ const maxStart = lines.length - pattern.length;
801
+ const searchStart = eof && lines.length >= pattern.length ? maxStart : start;
802
+
803
+ let bestIndex: number | undefined;
804
+ let bestScore = 0;
805
+
806
+ for (let i = searchStart; i <= maxStart; i++) {
807
+ const score = fuzzyScoreAt(lines, pattern, i);
808
+ if (score > bestScore) {
809
+ bestScore = score;
810
+ bestIndex = i;
811
+ }
812
+ }
813
+
814
+ if (eof && searchStart > start) {
815
+ for (let i = start; i < searchStart; i++) {
816
+ const score = fuzzyScoreAt(lines, pattern, i);
817
+ if (score > bestScore) {
818
+ bestScore = score;
819
+ bestIndex = i;
820
+ }
821
+ }
822
+ }
823
+
824
+ return { index: bestIndex, confidence: bestScore, strategy: "fuzzy" };
825
+ }
826
+
827
+ /**
828
+ * Find a context line in the file using progressive matching strategies.
829
+ *
830
+ * @param lines - The lines of the file content
831
+ * @param context - The context line to search for
832
+ * @param startFrom - Starting index for the search
833
+ */
834
+ export function findContextLine(
835
+ lines: string[],
836
+ context: string,
837
+ startFrom: number,
838
+ options?: { allowFuzzy?: boolean; skipFunctionFallback?: boolean },
839
+ ): ContextLineResult {
840
+ const allowFuzzy = options?.allowFuzzy ?? true;
841
+ const trimmedContext = context.trim();
842
+
843
+ const endIndex = lines.length - 1;
844
+ const exactPasses: Array<{
845
+ confidence: number;
846
+ strategy: ContextMatchStrategy;
847
+ predicate: (index: number) => boolean;
848
+ }> = [
849
+ { confidence: 1.0, strategy: "exact", predicate: i => lines[i] === context },
850
+ { confidence: 0.99, strategy: "trim", predicate: i => lines[i].trim() === trimmedContext },
851
+ ];
852
+
853
+ for (const pass of exactPasses) {
854
+ const matches = collectIndexedMatches(startFrom, endIndex, pass.predicate);
855
+ const result = toAmbiguousMatchResult(matches, pass.confidence, pass.strategy);
856
+ if (result) {
857
+ return result;
858
+ }
859
+ }
860
+
861
+ // Pass 3: Unicode normalization match
862
+ const normalizedContext = normalizeUnicode(context);
863
+ const unicodeMatches = collectIndexedMatches(
864
+ startFrom,
865
+ endIndex,
866
+ i => normalizeUnicode(lines[i]) === normalizedContext,
867
+ );
868
+ const unicodeResult = toAmbiguousMatchResult(unicodeMatches, 0.98, "unicode");
869
+ if (unicodeResult) {
870
+ return unicodeResult;
871
+ }
872
+
873
+ if (!allowFuzzy) {
874
+ return { index: undefined, confidence: 0 };
875
+ }
876
+
877
+ // Pass 4: Prefix match (file line starts with context)
878
+ const contextNorm = normalizeForFuzzy(context);
879
+ if (contextNorm.length > 0) {
880
+ const prefixMatches = collectIndexedMatches(startFrom, endIndex, i =>
881
+ normalizeForFuzzy(lines[i]).startsWith(contextNorm),
882
+ );
883
+ const prefixResult = toAmbiguousMatchResult(prefixMatches, 0.96, "prefix");
884
+ if (prefixResult) {
885
+ return prefixResult;
886
+ }
887
+ }
888
+
889
+ // Pass 5: Substring match (file line contains context)
890
+ // First pass: find all substring matches (ignoring ratio)
891
+ // If exactly one match exists, accept it (uniqueness is sufficient)
892
+ // If multiple matches, apply ratio filter to disambiguate
893
+ if (contextNorm.length >= PARTIAL_MATCH_MIN_LENGTH) {
894
+ const allSubstringMatches: Array<{ index: number; ratio: number }> = [];
895
+ for (let i = startFrom; i < lines.length; i++) {
896
+ const lineNorm = normalizeForFuzzy(lines[i]);
897
+ if (lineNorm.includes(contextNorm)) {
898
+ const ratio = contextNorm.length / Math.max(1, lineNorm.length);
899
+ allSubstringMatches.push({ index: i, ratio });
900
+ }
901
+ }
902
+ const matchIndices = allSubstringMatches.slice(0, 5).map(match => match.index);
903
+
904
+ // If exactly one substring match, accept it regardless of ratio
905
+ if (allSubstringMatches.length === 1) {
906
+ return {
907
+ index: allSubstringMatches[0].index,
908
+ confidence: 0.94,
909
+ matchCount: 1,
910
+ matchIndices,
911
+ strategy: "substring",
912
+ };
913
+ }
914
+
915
+ // Multiple matches: filter by ratio to disambiguate
916
+ let firstMatch: number | undefined;
917
+ let matchCount = 0;
918
+ for (const match of allSubstringMatches) {
919
+ if (match.ratio >= PARTIAL_MATCH_MIN_RATIO) {
920
+ if (firstMatch === undefined) firstMatch = match.index;
921
+ matchCount++;
922
+ }
923
+ }
924
+ if (matchCount > 0) {
925
+ return { index: firstMatch, confidence: 0.94, matchCount, matchIndices, strategy: "substring" };
926
+ }
927
+
928
+ // If we had substring matches but none passed ratio filter,
929
+ // return ambiguous result so caller knows matches exist
930
+ if (allSubstringMatches.length > 1) {
931
+ return {
932
+ index: allSubstringMatches[0].index,
933
+ confidence: 0.94,
934
+ matchCount: allSubstringMatches.length,
935
+ matchIndices,
936
+ strategy: "substring",
937
+ };
938
+ }
939
+ }
940
+
941
+ // Pass 6: Fuzzy match using similarity
942
+ let bestIndex: number | undefined;
943
+ let bestScore = 0;
944
+ const fuzzyMatches: IndexedMatches = {
945
+ firstMatch: undefined,
946
+ matchCount: 0,
947
+ matchIndices: [],
948
+ };
949
+
950
+ for (let i = startFrom; i < lines.length; i++) {
951
+ const lineNorm = normalizeForFuzzy(lines[i]);
952
+ const score = similarity(lineNorm, contextNorm);
953
+ if (score >= CONTEXT_FUZZY_THRESHOLD) {
954
+ if (fuzzyMatches.firstMatch === undefined) {
955
+ fuzzyMatches.firstMatch = i;
956
+ }
957
+ fuzzyMatches.matchCount++;
958
+ if (fuzzyMatches.matchIndices.length < MAX_RECORDED_MATCHES) {
959
+ fuzzyMatches.matchIndices.push(i);
960
+ }
961
+ }
962
+ if (score > bestScore) {
963
+ bestScore = score;
964
+ bestIndex = i;
965
+ }
966
+ }
967
+
968
+ if (bestIndex !== undefined && bestScore >= CONTEXT_FUZZY_THRESHOLD) {
969
+ return {
970
+ index: bestIndex,
971
+ confidence: bestScore,
972
+ matchCount: fuzzyMatches.matchCount,
973
+ matchIndices: fuzzyMatches.matchIndices,
974
+ strategy: "fuzzy",
975
+ };
976
+ }
977
+
978
+ if (!options?.skipFunctionFallback && trimmedContext.endsWith("()")) {
979
+ const withParen = trimmedContext.replace(/\(\)\s*$/u, "(");
980
+ const withoutParen = trimmedContext.replace(/\(\)\s*$/u, "");
981
+ const parenResult = findContextLine(lines, withParen, startFrom, { allowFuzzy, skipFunctionFallback: true });
982
+ if (parenResult.index !== undefined || (parenResult.matchCount ?? 0) > 0) {
983
+ return parenResult;
984
+ }
985
+ return findContextLine(lines, withoutParen, startFrom, { allowFuzzy, skipFunctionFallback: true });
986
+ }
987
+
988
+ return { index: undefined, confidence: bestScore };
989
+ }
990
+
991
+ export const replaceEditEntrySchema = Type.Object({
992
+ path: Type.String({ description: "File path (relative or absolute)" }),
993
+ old_text: Type.String({ description: "Text to find (fuzzy whitespace matching enabled)" }),
994
+ new_text: Type.String({ description: "Replacement text" }),
995
+ all: Type.Optional(Type.Boolean({ description: "Replace all occurrences (default: unique match required)" })),
996
+ });
997
+
998
+ export const replaceEditSchema = Type.Object({
999
+ edits: Type.Array(replaceEditEntrySchema, { description: "Replacements", minItems: 1 }),
1000
+ });
1001
+
1002
+ export type ReplaceEditEntry = Static<typeof replaceEditEntrySchema>;
1003
+ export type ReplaceParams = Static<typeof replaceEditSchema>;
1004
+
1005
+ export interface ExecuteReplaceSingleOptions {
1006
+ session: ToolSession;
1007
+ params: ReplaceEditEntry;
1008
+ signal?: AbortSignal;
1009
+ batchRequest?: LspBatchRequest;
1010
+ allowFuzzy: boolean;
1011
+ fuzzyThreshold: number;
1012
+ writethrough: WritethroughCallback;
1013
+ beginDeferredDiagnosticsForPath: (path: string) => WritethroughDeferredHandle;
1014
+ }
1015
+
1016
+ export function isReplaceParams(params: unknown): params is ReplaceParams {
1017
+ if (typeof params !== "object" || params === null) return false;
1018
+ if (!("edits" in params) || !Array.isArray((params as any).edits)) return false;
1019
+ const first = (params as any).edits[0];
1020
+ return first && typeof first === "object" && "old_text" in first && "new_text" in first;
1021
+ }
1022
+
1023
+ export async function executeReplaceSingle(
1024
+ options: ExecuteReplaceSingleOptions,
1025
+ ): Promise<AgentToolResult<EditToolDetails, typeof replaceEditEntrySchema>> {
1026
+ const {
1027
+ session,
1028
+ params,
1029
+ signal,
1030
+ batchRequest,
1031
+ allowFuzzy,
1032
+ fuzzyThreshold,
1033
+ writethrough,
1034
+ beginDeferredDiagnosticsForPath,
1035
+ } = options;
1036
+ const { path, old_text, new_text, all } = params;
1037
+
1038
+ enforcePlanModeWrite(session, path);
1039
+
1040
+ if (path.endsWith(".ipynb")) {
1041
+ throw new Error("Cannot edit Jupyter notebooks with the Edit tool. Use the NotebookEdit tool instead.");
1042
+ }
1043
+
1044
+ if (old_text.length === 0) {
1045
+ throw new Error("old_text must not be empty.");
1046
+ }
1047
+
1048
+ const absolutePath = resolvePlanPath(session, path);
1049
+ const rawContent = await readReplaceFileContent(absolutePath, path);
1050
+ const { bom, text: content } = stripBom(rawContent);
1051
+ const originalEnding = detectLineEnding(content);
1052
+ const normalizedContent = normalizeToLF(content);
1053
+ const normalizedOldText = normalizeToLF(old_text);
1054
+ const normalizedNewText = normalizeToLF(new_text);
1055
+
1056
+ const result = replaceText(normalizedContent, normalizedOldText, normalizedNewText, {
1057
+ fuzzy: allowFuzzy,
1058
+ all: all ?? false,
1059
+ threshold: fuzzyThreshold,
1060
+ });
1061
+
1062
+ if (result.count === 0) {
1063
+ const matchOutcome = findMatch(normalizedContent, normalizedOldText, {
1064
+ allowFuzzy,
1065
+ threshold: fuzzyThreshold,
1066
+ });
1067
+
1068
+ if (matchOutcome.occurrences && matchOutcome.occurrences > 1) {
1069
+ throw new Error(formatOccurrenceError(path, matchOutcome));
1070
+ }
1071
+
1072
+ throw new EditMatchError(path, normalizedOldText, matchOutcome.closest, {
1073
+ allowFuzzy,
1074
+ threshold: fuzzyThreshold,
1075
+ fuzzyMatches: matchOutcome.fuzzyMatches,
1076
+ });
1077
+ }
1078
+
1079
+ if (normalizedContent === result.content) {
1080
+ throw new Error(
1081
+ `No changes made to ${path}. The replacement produced identical content. This might indicate an issue with special characters or the text not existing as expected.`,
1082
+ );
1083
+ }
1084
+
1085
+ const finalContent = bom + restoreLineEndings(result.content, originalEnding);
1086
+ const diagnostics = await writethrough(
1087
+ absolutePath,
1088
+ finalContent,
1089
+ signal,
1090
+ Bun.file(absolutePath),
1091
+ batchRequest,
1092
+ dst => (dst === absolutePath ? beginDeferredDiagnosticsForPath(absolutePath) : undefined),
1093
+ );
1094
+ invalidateFsScanAfterWrite(absolutePath);
1095
+
1096
+ const diffResult = generateDiffString(normalizedContent, result.content);
1097
+ const resultText =
1098
+ result.count > 1
1099
+ ? `Successfully replaced ${result.count} occurrences in ${path}.`
1100
+ : `Successfully replaced text in ${path}.`;
1101
+
1102
+ const meta = outputMeta()
1103
+ .diagnostics(diagnostics?.summary ?? "", diagnostics?.messages ?? [])
1104
+ .get();
1105
+
1106
+ return {
1107
+ content: [{ type: "text", text: resultText }],
1108
+ details: {
1109
+ diff: diffResult.diff,
1110
+ firstChangedLine: diffResult.firstChangedLine,
1111
+ diagnostics,
1112
+ meta,
1113
+ },
1114
+ };
1115
+ }