@greppleai/grip 0.1.5 → 0.1.7

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 (587) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +1 -1
  3. package/dist/bun/cli.d.ts.map +1 -1
  4. package/dist/bun/cli.js.map +1 -1
  5. package/dist/bun/embedded-assets.d.ts.map +1 -1
  6. package/dist/bun/embedded-assets.js.map +1 -1
  7. package/dist/bun/register-bedrock.d.ts.map +1 -1
  8. package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
  9. package/dist/bun/restore-sandbox-env.js.map +1 -1
  10. package/dist/cli/args.d.ts.map +1 -1
  11. package/dist/cli/args.js.map +1 -1
  12. package/dist/cli/config-selector.d.ts.map +1 -1
  13. package/dist/cli/config-selector.js.map +1 -1
  14. package/dist/cli/file-processor.d.ts.map +1 -1
  15. package/dist/cli/file-processor.js.map +1 -1
  16. package/dist/cli/initial-message.d.ts +1 -1
  17. package/dist/cli/initial-message.d.ts.map +1 -1
  18. package/dist/cli/initial-message.js.map +1 -1
  19. package/dist/cli/list-models.d.ts.map +1 -1
  20. package/dist/cli/list-models.js.map +1 -1
  21. package/dist/cli/session-picker.d.ts.map +1 -1
  22. package/dist/cli/session-picker.js.map +1 -1
  23. package/dist/cli.d.ts.map +1 -1
  24. package/dist/cli.js.map +1 -1
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js +2 -0
  27. package/dist/config.js.map +1 -1
  28. package/dist/core/agent-session.d.ts +38 -1
  29. package/dist/core/agent-session.d.ts.map +1 -1
  30. package/dist/core/agent-session.js +289 -154
  31. package/dist/core/agent-session.js.map +1 -1
  32. package/dist/core/auth-guidance.d.ts.map +1 -1
  33. package/dist/core/auth-guidance.js.map +1 -1
  34. package/dist/core/auth-storage.d.ts +4 -0
  35. package/dist/core/auth-storage.d.ts.map +1 -1
  36. package/dist/core/auth-storage.js +3 -10
  37. package/dist/core/auth-storage.js.map +1 -1
  38. package/dist/core/bash-executor.d.ts.map +1 -1
  39. package/dist/core/bash-executor.js +19 -23
  40. package/dist/core/bash-executor.js.map +1 -1
  41. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  42. package/dist/core/compaction/branch-summarization.js.map +1 -1
  43. package/dist/core/compaction/compaction.d.ts.map +1 -1
  44. package/dist/core/compaction/compaction.js +9 -2
  45. package/dist/core/compaction/compaction.js.map +1 -1
  46. package/dist/core/compaction/compression-detection-ledger.d.ts.map +1 -1
  47. package/dist/core/compaction/compression-detection-ledger.js.map +1 -1
  48. package/dist/core/compaction/compression-detector.d.ts +1 -0
  49. package/dist/core/compaction/compression-detector.d.ts.map +1 -1
  50. package/dist/core/compaction/compression-detector.js +10 -21
  51. package/dist/core/compaction/compression-detector.js.map +1 -1
  52. package/dist/core/compaction/compression-economics.d.ts.map +1 -1
  53. package/dist/core/compaction/compression-economics.js.map +1 -1
  54. package/dist/core/compaction/utils.d.ts.map +1 -1
  55. package/dist/core/compaction/utils.js.map +1 -1
  56. package/dist/core/defaults.d.ts.map +1 -1
  57. package/dist/core/diagnostics.d.ts.map +1 -1
  58. package/dist/core/event-bus.d.ts.map +1 -1
  59. package/dist/core/event-bus.js.map +1 -1
  60. package/dist/core/exec.d.ts.map +1 -1
  61. package/dist/core/exec.js.map +1 -1
  62. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  63. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  64. package/dist/core/export-html/index.d.ts.map +1 -1
  65. package/dist/core/export-html/index.js.map +1 -1
  66. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  67. package/dist/core/export-html/tool-renderer.js.map +1 -1
  68. package/dist/core/extensions/loader.d.ts.map +1 -1
  69. package/dist/core/extensions/loader.js.map +1 -1
  70. package/dist/core/extensions/runner.d.ts +3 -0
  71. package/dist/core/extensions/runner.d.ts.map +1 -1
  72. package/dist/core/extensions/runner.js +40 -30
  73. package/dist/core/extensions/runner.js.map +1 -1
  74. package/dist/core/extensions/types.d.ts +21 -1
  75. package/dist/core/extensions/types.d.ts.map +1 -1
  76. package/dist/core/extensions/types.js.map +1 -1
  77. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  78. package/dist/core/extensions/wrapper.js.map +1 -1
  79. package/dist/core/footer-data-provider.d.ts.map +1 -1
  80. package/dist/core/footer-data-provider.js +15 -16
  81. package/dist/core/footer-data-provider.js.map +1 -1
  82. package/dist/core/grip-agent.d.ts.map +1 -1
  83. package/dist/core/grip-agent.js +7 -21
  84. package/dist/core/grip-agent.js.map +1 -1
  85. package/dist/core/grip-manifest.d.ts.map +1 -1
  86. package/dist/core/grip-manifest.js.map +1 -1
  87. package/dist/core/hooks/aggregate.d.ts.map +1 -1
  88. package/dist/core/hooks/aggregate.js.map +1 -1
  89. package/dist/core/hooks/config.d.ts.map +1 -1
  90. package/dist/core/hooks/config.js.map +1 -1
  91. package/dist/core/hooks/executor.d.ts.map +1 -1
  92. package/dist/core/hooks/executor.js.map +1 -1
  93. package/dist/core/hooks/index.d.ts.map +1 -1
  94. package/dist/core/hooks/index.js.map +1 -1
  95. package/dist/core/hooks/matcher.d.ts.map +1 -1
  96. package/dist/core/hooks/matcher.js.map +1 -1
  97. package/dist/core/hooks/trust-store.d.ts.map +1 -1
  98. package/dist/core/hooks/trust-store.js +0 -3
  99. package/dist/core/hooks/trust-store.js.map +1 -1
  100. package/dist/core/hooks/types.d.ts.map +1 -1
  101. package/dist/core/hooks/types.js.map +1 -1
  102. package/dist/core/http-dispatcher.d.ts.map +1 -1
  103. package/dist/core/http-dispatcher.js.map +1 -1
  104. package/dist/core/instruction-resource-loader.d.ts +1 -0
  105. package/dist/core/instruction-resource-loader.d.ts.map +1 -1
  106. package/dist/core/instruction-resource-loader.js +2 -4
  107. package/dist/core/instruction-resource-loader.js.map +1 -1
  108. package/dist/core/keybindings.d.ts.map +1 -1
  109. package/dist/core/keybindings.js +0 -1
  110. package/dist/core/keybindings.js.map +1 -1
  111. package/dist/core/lsp/abort.d.ts.map +1 -1
  112. package/dist/core/lsp/abort.js.map +1 -1
  113. package/dist/core/lsp/client.d.ts.map +1 -1
  114. package/dist/core/lsp/client.js +8 -22
  115. package/dist/core/lsp/client.js.map +1 -1
  116. package/dist/core/lsp/config-loader.d.ts.map +1 -1
  117. package/dist/core/lsp/config-loader.js.map +1 -1
  118. package/dist/core/lsp/config.d.ts.map +1 -1
  119. package/dist/core/lsp/config.js.map +1 -1
  120. package/dist/core/lsp/diagnostics.d.ts.map +1 -1
  121. package/dist/core/lsp/diagnostics.js.map +1 -1
  122. package/dist/core/lsp/file-sync.d.ts.map +1 -1
  123. package/dist/core/lsp/file-sync.js +7 -9
  124. package/dist/core/lsp/file-sync.js.map +1 -1
  125. package/dist/core/lsp/integration.d.ts.map +1 -1
  126. package/dist/core/lsp/integration.js.map +1 -1
  127. package/dist/core/lsp/language-map.d.ts.map +1 -1
  128. package/dist/core/lsp/language-map.js +2 -7
  129. package/dist/core/lsp/language-map.js.map +1 -1
  130. package/dist/core/lsp/manager.d.ts.map +1 -1
  131. package/dist/core/lsp/manager.js +18 -29
  132. package/dist/core/lsp/manager.js.map +1 -1
  133. package/dist/core/lsp/navigation.d.ts.map +1 -1
  134. package/dist/core/lsp/navigation.js.map +1 -1
  135. package/dist/core/lsp/portable-path.d.ts.map +1 -1
  136. package/dist/core/lsp/portable-path.js.map +1 -1
  137. package/dist/core/lsp/refactor.d.ts.map +1 -1
  138. package/dist/core/lsp/refactor.js.map +1 -1
  139. package/dist/core/lsp/transport.d.ts.map +1 -1
  140. package/dist/core/lsp/transport.js.map +1 -1
  141. package/dist/core/messages.d.ts.map +1 -1
  142. package/dist/core/messages.js +30 -1
  143. package/dist/core/messages.js.map +1 -1
  144. package/dist/core/model-registry.d.ts.map +1 -1
  145. package/dist/core/model-registry.js +5 -7
  146. package/dist/core/model-registry.js.map +1 -1
  147. package/dist/core/model-resolver.d.ts.map +1 -1
  148. package/dist/core/model-resolver.js.map +1 -1
  149. package/dist/core/output-guard.d.ts.map +1 -1
  150. package/dist/core/output-guard.js.map +1 -1
  151. package/dist/core/package-manager.d.ts.map +1 -1
  152. package/dist/core/package-manager.js +0 -6
  153. package/dist/core/package-manager.js.map +1 -1
  154. package/dist/core/prompt-templates.d.ts.map +1 -1
  155. package/dist/core/prompt-templates.js.map +1 -1
  156. package/dist/core/provider-display-names.d.ts.map +1 -1
  157. package/dist/core/remote-workspace-protocol/contract.d.ts.map +1 -1
  158. package/dist/core/remote-workspace-protocol/contract.js +4 -2
  159. package/dist/core/remote-workspace-protocol/contract.js.map +1 -1
  160. package/dist/core/remote-workspace-protocol/guest-shared-client.d.ts.map +1 -1
  161. package/dist/core/remote-workspace-protocol/guest-shared-client.js +1 -5
  162. package/dist/core/remote-workspace-protocol/guest-shared-client.js.map +1 -1
  163. package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.d.ts.map +1 -1
  164. package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js +5 -10
  165. package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js.map +1 -1
  166. package/dist/core/remote-workspace-protocol/guest-shared-uplink.d.ts.map +1 -1
  167. package/dist/core/remote-workspace-protocol/guest-shared-uplink.js +2 -9
  168. package/dist/core/remote-workspace-protocol/guest-shared-uplink.js.map +1 -1
  169. package/dist/core/remote-workspace-protocol/lima-owner-directory.d.ts.map +1 -1
  170. package/dist/core/remote-workspace-protocol/lima-owner-directory.js.map +1 -1
  171. package/dist/core/remote-workspace-protocol/lima-owner-lock.d.ts.map +1 -1
  172. package/dist/core/remote-workspace-protocol/lima-owner-lock.js.map +1 -1
  173. package/dist/core/remote-workspace-protocol/session.d.ts.map +1 -1
  174. package/dist/core/remote-workspace-protocol/session.js +27 -65
  175. package/dist/core/remote-workspace-protocol/session.js.map +1 -1
  176. package/dist/core/remote-workspace-protocol/shared-transport.d.ts.map +1 -1
  177. package/dist/core/remote-workspace-protocol/shared-transport.js.map +1 -1
  178. package/dist/core/resolve-config-value.d.ts.map +1 -1
  179. package/dist/core/resolve-config-value.js.map +1 -1
  180. package/dist/core/resource-loader.d.ts.map +1 -1
  181. package/dist/core/resource-loader.js +0 -48
  182. package/dist/core/resource-loader.js.map +1 -1
  183. package/dist/core/rules.d.ts.map +1 -1
  184. package/dist/core/rules.js.map +1 -1
  185. package/dist/core/sandbox/command.d.ts.map +1 -1
  186. package/dist/core/sandbox/command.js.map +1 -1
  187. package/dist/core/sandbox/config.d.ts.map +1 -1
  188. package/dist/core/sandbox/config.js.map +1 -1
  189. package/dist/core/sandbox/lima-guest-binary.d.ts.map +1 -1
  190. package/dist/core/sandbox/lima-guest-binary.js.map +1 -1
  191. package/dist/core/sandbox/lima.d.ts +2 -0
  192. package/dist/core/sandbox/lima.d.ts.map +1 -1
  193. package/dist/core/sandbox/lima.js +3 -9
  194. package/dist/core/sandbox/lima.js.map +1 -1
  195. package/dist/core/sandbox/shared-lima-roots.d.ts.map +1 -1
  196. package/dist/core/sandbox/shared-lima-roots.js.map +1 -1
  197. package/dist/core/sandbox/update-shared-guest-binary.d.ts.map +1 -1
  198. package/dist/core/sandbox/update-shared-guest-binary.js.map +1 -1
  199. package/dist/core/session/constants.d.ts.map +1 -1
  200. package/dist/core/session/context-metadata.d.ts.map +1 -1
  201. package/dist/core/session/context-metadata.js.map +1 -1
  202. package/dist/core/session/context.d.ts.map +1 -1
  203. package/dist/core/session/context.js.map +1 -1
  204. package/dist/core/session/ids.d.ts.map +1 -1
  205. package/dist/core/session/ids.js.map +1 -1
  206. package/dist/core/session/in-memory-session-manager.d.ts.map +1 -1
  207. package/dist/core/session/in-memory-session-manager.js +0 -1
  208. package/dist/core/session/in-memory-session-manager.js.map +1 -1
  209. package/dist/core/session/in-memory-session.d.ts.map +1 -1
  210. package/dist/core/session/in-memory-session.js.map +1 -1
  211. package/dist/core/session/jsonl-errors.d.ts.map +1 -1
  212. package/dist/core/session/jsonl-errors.js +0 -11
  213. package/dist/core/session/jsonl-errors.js.map +1 -1
  214. package/dist/core/session/jsonl-helpers.d.ts.map +1 -1
  215. package/dist/core/session/jsonl-helpers.js.map +1 -1
  216. package/dist/core/session/local-session-manager.d.ts.map +1 -1
  217. package/dist/core/session/local-session-manager.js +4 -6
  218. package/dist/core/session/local-session-manager.js.map +1 -1
  219. package/dist/core/session/local-session.d.ts.map +1 -1
  220. package/dist/core/session/local-session.js.map +1 -1
  221. package/dist/core/session/migrations.d.ts.map +1 -1
  222. package/dist/core/session/migrations.js.map +1 -1
  223. package/dist/core/session/remote-session-client.d.ts.map +1 -1
  224. package/dist/core/session/remote-session-client.js +0 -6
  225. package/dist/core/session/remote-session-client.js.map +1 -1
  226. package/dist/core/session/remote-session-manager.d.ts.map +1 -1
  227. package/dist/core/session/remote-session-manager.js +0 -3
  228. package/dist/core/session/remote-session-manager.js.map +1 -1
  229. package/dist/core/session/remote-session.d.ts.map +1 -1
  230. package/dist/core/session/remote-session.js +0 -1
  231. package/dist/core/session/remote-session.js.map +1 -1
  232. package/dist/core/session/session-manager.d.ts.map +1 -1
  233. package/dist/core/session/session.d.ts.map +1 -1
  234. package/dist/core/session/session.js +1 -5
  235. package/dist/core/session/session.js.map +1 -1
  236. package/dist/core/session/stores/in-memory-session-store.d.ts.map +1 -1
  237. package/dist/core/session/stores/in-memory-session-store.js +7 -6
  238. package/dist/core/session/stores/in-memory-session-store.js.map +1 -1
  239. package/dist/core/session/stores/jsonl-session-store.d.ts.map +1 -1
  240. package/dist/core/session/stores/jsonl-session-store.js +6 -14
  241. package/dist/core/session/stores/jsonl-session-store.js.map +1 -1
  242. package/dist/core/session/stores/remote-session-store.d.ts.map +1 -1
  243. package/dist/core/session/stores/remote-session-store.js +3 -8
  244. package/dist/core/session/stores/remote-session-store.js.map +1 -1
  245. package/dist/core/session/stores/session-store.d.ts.map +1 -1
  246. package/dist/core/session/types.d.ts.map +1 -1
  247. package/dist/core/session/usage-ledger.d.ts.map +1 -1
  248. package/dist/core/session/usage-ledger.js.map +1 -1
  249. package/dist/core/session-cwd.d.ts.map +1 -1
  250. package/dist/core/session-cwd.js +0 -1
  251. package/dist/core/session-cwd.js.map +1 -1
  252. package/dist/core/settings-manager.d.ts.map +1 -1
  253. package/dist/core/settings-manager.js +9 -17
  254. package/dist/core/settings-manager.js.map +1 -1
  255. package/dist/core/skills.d.ts.map +1 -1
  256. package/dist/core/skills.js +3 -2
  257. package/dist/core/skills.js.map +1 -1
  258. package/dist/core/slash-commands.d.ts.map +1 -1
  259. package/dist/core/source-info.d.ts.map +1 -1
  260. package/dist/core/source-info.js.map +1 -1
  261. package/dist/core/system-prompt.d.ts +1 -1
  262. package/dist/core/system-prompt.d.ts.map +1 -1
  263. package/dist/core/system-prompt.js +3 -2
  264. package/dist/core/system-prompt.js.map +1 -1
  265. package/dist/core/telemetry.d.ts.map +1 -1
  266. package/dist/core/telemetry.js.map +1 -1
  267. package/dist/core/timings.d.ts.map +1 -1
  268. package/dist/core/timings.js.map +1 -1
  269. package/dist/core/tools/bash.d.ts +1 -0
  270. package/dist/core/tools/bash.d.ts.map +1 -1
  271. package/dist/core/tools/bash.js +34 -28
  272. package/dist/core/tools/bash.js.map +1 -1
  273. package/dist/core/tools/compress-context.d.ts.map +1 -1
  274. package/dist/core/tools/compress-context.js.map +1 -1
  275. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  276. package/dist/core/tools/edit-diff.js.map +1 -1
  277. package/dist/core/tools/edit.d.ts.map +1 -1
  278. package/dist/core/tools/edit.js.map +1 -1
  279. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  280. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  281. package/dist/core/tools/find.d.ts.map +1 -1
  282. package/dist/core/tools/find.js.map +1 -1
  283. package/dist/core/tools/grep.d.ts.map +1 -1
  284. package/dist/core/tools/grep.js.map +1 -1
  285. package/dist/core/tools/hash-store.d.ts.map +1 -1
  286. package/dist/core/tools/hash-store.js.map +1 -1
  287. package/dist/core/tools/hashline/apply.d.ts.map +1 -1
  288. package/dist/core/tools/hashline/apply.js.map +1 -1
  289. package/dist/core/tools/hashline/hash.d.ts.map +1 -1
  290. package/dist/core/tools/hashline/hash.js.map +1 -1
  291. package/dist/core/tools/hashline/parse.d.ts.map +1 -1
  292. package/dist/core/tools/hashline/parse.js.map +1 -1
  293. package/dist/core/tools/hashline/resolve.d.ts.map +1 -1
  294. package/dist/core/tools/hashline/resolve.js.map +1 -1
  295. package/dist/core/tools/hashline-utils.d.ts.map +1 -1
  296. package/dist/core/tools/hashline-utils.js.map +1 -1
  297. package/dist/core/tools/index.d.ts.map +1 -1
  298. package/dist/core/tools/index.js.map +1 -1
  299. package/dist/core/tools/ls.d.ts.map +1 -1
  300. package/dist/core/tools/ls.js.map +1 -1
  301. package/dist/core/tools/operations.d.ts +11 -0
  302. package/dist/core/tools/operations.d.ts.map +1 -1
  303. package/dist/core/tools/operations.js +54 -28
  304. package/dist/core/tools/operations.js.map +1 -1
  305. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  306. package/dist/core/tools/output-accumulator.js +12 -18
  307. package/dist/core/tools/output-accumulator.js.map +1 -1
  308. package/dist/core/tools/path-utils.d.ts.map +1 -1
  309. package/dist/core/tools/path-utils.js.map +1 -1
  310. package/dist/core/tools/read.d.ts.map +1 -1
  311. package/dist/core/tools/read.js.map +1 -1
  312. package/dist/core/tools/render-utils.d.ts.map +1 -1
  313. package/dist/core/tools/render-utils.js.map +1 -1
  314. package/dist/core/tools/replace-diff.d.ts.map +1 -1
  315. package/dist/core/tools/replace-diff.js.map +1 -1
  316. package/dist/core/tools/replace-normalize.d.ts.map +1 -1
  317. package/dist/core/tools/replace-normalize.js.map +1 -1
  318. package/dist/core/tools/replace-render.d.ts +1 -1
  319. package/dist/core/tools/replace-render.d.ts.map +1 -1
  320. package/dist/core/tools/replace-render.js.map +1 -1
  321. package/dist/core/tools/runtime.d.ts.map +1 -1
  322. package/dist/core/tools/runtime.js.map +1 -1
  323. package/dist/core/tools/session-history.d.ts.map +1 -1
  324. package/dist/core/tools/session-history.js.map +1 -1
  325. package/dist/core/tools/subagent-agents.d.ts.map +1 -1
  326. package/dist/core/tools/subagent-agents.js.map +1 -1
  327. package/dist/core/tools/subagent.d.ts.map +1 -1
  328. package/dist/core/tools/subagent.js.map +1 -1
  329. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  330. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  331. package/dist/core/tools/truncate.d.ts.map +1 -1
  332. package/dist/core/tools/truncate.js.map +1 -1
  333. package/dist/core/tools/websearch.d.ts.map +1 -1
  334. package/dist/core/tools/websearch.js.map +1 -1
  335. package/dist/core/tools/workspace-tool-host.d.ts +1 -0
  336. package/dist/core/tools/workspace-tool-host.d.ts.map +1 -1
  337. package/dist/core/tools/workspace-tool-host.js +36 -22
  338. package/dist/core/tools/workspace-tool-host.js.map +1 -1
  339. package/dist/core/tools/write.d.ts.map +1 -1
  340. package/dist/core/tools/write.js +0 -1
  341. package/dist/core/tools/write.js.map +1 -1
  342. package/dist/core/workspace-identity.d.ts.map +1 -1
  343. package/dist/daemon/activity-budget.d.ts.map +1 -1
  344. package/dist/daemon/activity-budget.js +2 -3
  345. package/dist/daemon/activity-budget.js.map +1 -1
  346. package/dist/daemon/command.d.ts.map +1 -1
  347. package/dist/daemon/command.js.map +1 -1
  348. package/dist/daemon/config.d.ts +2 -0
  349. package/dist/daemon/config.d.ts.map +1 -1
  350. package/dist/daemon/config.js +4 -0
  351. package/dist/daemon/config.js.map +1 -1
  352. package/dist/daemon/help.d.ts.map +1 -1
  353. package/dist/daemon/help.js +4 -3
  354. package/dist/daemon/help.js.map +1 -1
  355. package/dist/daemon/lsp-config.d.ts.map +1 -1
  356. package/dist/daemon/lsp-config.js.map +1 -1
  357. package/dist/daemon/outbound-budget.d.ts.map +1 -1
  358. package/dist/daemon/outbound-budget.js +2 -4
  359. package/dist/daemon/outbound-budget.js.map +1 -1
  360. package/dist/daemon/security.d.ts.map +1 -1
  361. package/dist/daemon/security.js.map +1 -1
  362. package/dist/daemon/server.d.ts.map +1 -1
  363. package/dist/daemon/server.js.map +1 -1
  364. package/dist/daemon/shared-connection.d.ts.map +1 -1
  365. package/dist/daemon/shared-connection.js +10 -15
  366. package/dist/daemon/shared-connection.js.map +1 -1
  367. package/dist/daemon/shared-revision.d.ts.map +1 -1
  368. package/dist/daemon/shared-revision.js +2 -1
  369. package/dist/daemon/shared-revision.js.map +1 -1
  370. package/dist/daemon/shared-roots.d.ts.map +1 -1
  371. package/dist/daemon/shared-roots.js +0 -1
  372. package/dist/daemon/shared-roots.js.map +1 -1
  373. package/dist/daemon/workspace-runtime.d.ts +2 -0
  374. package/dist/daemon/workspace-runtime.d.ts.map +1 -1
  375. package/dist/daemon/workspace-runtime.js +43 -15
  376. package/dist/daemon/workspace-runtime.js.map +1 -1
  377. package/dist/index.d.ts +1 -1
  378. package/dist/index.d.ts.map +1 -1
  379. package/dist/index.js.map +1 -1
  380. package/dist/main.d.ts.map +1 -1
  381. package/dist/main.js +8 -3
  382. package/dist/main.js.map +1 -1
  383. package/dist/migrations.d.ts.map +1 -1
  384. package/dist/migrations.js.map +1 -1
  385. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  386. package/dist/modes/interactive/components/assistant-message.js +3 -10
  387. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  388. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  389. package/dist/modes/interactive/components/bash-execution.js +4 -9
  390. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  391. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  392. package/dist/modes/interactive/components/bordered-loader.js +0 -3
  393. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  394. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  395. package/dist/modes/interactive/components/branch-summary-message.js +1 -3
  396. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  397. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  398. package/dist/modes/interactive/components/compaction-summary-message.js +1 -3
  399. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  400. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  401. package/dist/modes/interactive/components/config-selector.js +6 -16
  402. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  403. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  404. package/dist/modes/interactive/components/countdown-timer.js +0 -5
  405. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  406. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  407. package/dist/modes/interactive/components/custom-editor.js +1 -8
  408. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  409. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  410. package/dist/modes/interactive/components/custom-message.js +1 -6
  411. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  412. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  413. package/dist/modes/interactive/components/diff.js.map +1 -1
  414. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  415. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  416. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  417. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  418. package/dist/modes/interactive/components/extension-editor.js +1 -7
  419. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  420. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  421. package/dist/modes/interactive/components/extension-input.js +2 -8
  422. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  423. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  424. package/dist/modes/interactive/components/extension-selector.js +1 -9
  425. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  426. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  427. package/dist/modes/interactive/components/footer.js +8 -4
  428. package/dist/modes/interactive/components/footer.js.map +1 -1
  429. package/dist/modes/interactive/components/hook-execution.d.ts.map +1 -1
  430. package/dist/modes/interactive/components/hook-execution.js +2 -5
  431. package/dist/modes/interactive/components/hook-execution.js.map +1 -1
  432. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  433. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  434. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  435. package/dist/modes/interactive/components/login-dialog.js +3 -9
  436. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  437. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -1
  438. package/dist/modes/interactive/components/markdown-transform.js.map +1 -1
  439. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  440. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  441. package/dist/modes/interactive/components/message-card.d.ts.map +1 -1
  442. package/dist/modes/interactive/components/message-card.js +0 -1
  443. package/dist/modes/interactive/components/message-card.js.map +1 -1
  444. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  445. package/dist/modes/interactive/components/model-selector.js +13 -28
  446. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  447. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  448. package/dist/modes/interactive/components/oauth-selector.js +3 -12
  449. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  450. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  451. package/dist/modes/interactive/components/scoped-models-selector.js +9 -13
  452. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  453. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  454. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  455. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  456. package/dist/modes/interactive/components/session-selector.js +33 -58
  457. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  458. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  459. package/dist/modes/interactive/components/settings-selector.js +0 -4
  460. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  461. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  462. package/dist/modes/interactive/components/show-images-selector.js +0 -1
  463. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  464. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  465. package/dist/modes/interactive/components/skill-invocation-message.js +1 -3
  466. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  467. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  468. package/dist/modes/interactive/components/theme-selector.js +0 -2
  469. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  470. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  471. package/dist/modes/interactive/components/thinking-selector.js +0 -1
  472. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  473. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  474. package/dist/modes/interactive/components/tool-execution.js +9 -24
  475. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  476. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  477. package/dist/modes/interactive/components/tree-selector.js +18 -34
  478. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  479. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  480. package/dist/modes/interactive/components/user-message-selector.js +3 -6
  481. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  482. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  483. package/dist/modes/interactive/components/user-message.js +0 -4
  484. package/dist/modes/interactive/components/user-message.js.map +1 -1
  485. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  486. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  487. package/dist/modes/interactive/interactive-mode.d.ts +13 -0
  488. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  489. package/dist/modes/interactive/interactive-mode.js +162 -136
  490. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  491. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  492. package/dist/modes/interactive/theme/theme.js +0 -7
  493. package/dist/modes/interactive/theme/theme.js.map +1 -1
  494. package/dist/modes/json-event.d.ts.map +1 -1
  495. package/dist/modes/json-event.js.map +1 -1
  496. package/dist/modes/print-mode.d.ts.map +1 -1
  497. package/dist/modes/print-mode.js.map +1 -1
  498. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  499. package/dist/modes/rpc/jsonl.js.map +1 -1
  500. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  501. package/dist/modes/rpc/rpc-client.js +10 -11
  502. package/dist/modes/rpc/rpc-client.js.map +1 -1
  503. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  504. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  505. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  506. package/dist/package-manager-cli.d.ts.map +1 -1
  507. package/dist/package-manager-cli.js +33 -2
  508. package/dist/package-manager-cli.js.map +1 -1
  509. package/dist/utils/ansi.d.ts.map +1 -1
  510. package/dist/utils/ansi.js.map +1 -1
  511. package/dist/utils/binary-self-update.d.ts +25 -0
  512. package/dist/utils/binary-self-update.d.ts.map +1 -0
  513. package/dist/utils/binary-self-update.js +159 -0
  514. package/dist/utils/binary-self-update.js.map +1 -0
  515. package/dist/utils/changelog.d.ts.map +1 -1
  516. package/dist/utils/changelog.js.map +1 -1
  517. package/dist/utils/child-process.d.ts.map +1 -1
  518. package/dist/utils/child-process.js.map +1 -1
  519. package/dist/utils/clipboard-image.d.ts.map +1 -1
  520. package/dist/utils/clipboard-image.js.map +1 -1
  521. package/dist/utils/clipboard-native.d.ts.map +1 -1
  522. package/dist/utils/clipboard-native.js.map +1 -1
  523. package/dist/utils/clipboard.d.ts.map +1 -1
  524. package/dist/utils/clipboard.js.map +1 -1
  525. package/dist/utils/deprecation.d.ts.map +1 -1
  526. package/dist/utils/deprecation.js.map +1 -1
  527. package/dist/utils/directory-completions.d.ts +8 -0
  528. package/dist/utils/directory-completions.d.ts.map +1 -1
  529. package/dist/utils/directory-completions.js +42 -1
  530. package/dist/utils/directory-completions.js.map +1 -1
  531. package/dist/utils/exif-orientation.d.ts.map +1 -1
  532. package/dist/utils/exif-orientation.js.map +1 -1
  533. package/dist/utils/frontmatter.d.ts.map +1 -1
  534. package/dist/utils/frontmatter.js.map +1 -1
  535. package/dist/utils/fs-watch.d.ts.map +1 -1
  536. package/dist/utils/fs-watch.js.map +1 -1
  537. package/dist/utils/git.d.ts.map +1 -1
  538. package/dist/utils/git.js.map +1 -1
  539. package/dist/utils/grip-user-agent.d.ts.map +1 -1
  540. package/dist/utils/grip-user-agent.js.map +1 -1
  541. package/dist/utils/html.d.ts.map +1 -1
  542. package/dist/utils/html.js.map +1 -1
  543. package/dist/utils/image-convert.d.ts.map +1 -1
  544. package/dist/utils/image-convert.js.map +1 -1
  545. package/dist/utils/image-process.d.ts.map +1 -1
  546. package/dist/utils/image-process.js.map +1 -1
  547. package/dist/utils/image-resize-core.d.ts.map +1 -1
  548. package/dist/utils/image-resize-core.js.map +1 -1
  549. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  550. package/dist/utils/image-resize-worker.js.map +1 -1
  551. package/dist/utils/image-resize.d.ts.map +1 -1
  552. package/dist/utils/image-resize.js.map +1 -1
  553. package/dist/utils/json.d.ts.map +1 -1
  554. package/dist/utils/json.js.map +1 -1
  555. package/dist/utils/mime.d.ts.map +1 -1
  556. package/dist/utils/mime.js.map +1 -1
  557. package/dist/utils/open-browser.d.ts.map +1 -1
  558. package/dist/utils/open-browser.js.map +1 -1
  559. package/dist/utils/paths.d.ts.map +1 -1
  560. package/dist/utils/paths.js.map +1 -1
  561. package/dist/utils/photon.d.ts.map +1 -1
  562. package/dist/utils/photon.js +10 -5
  563. package/dist/utils/photon.js.map +1 -1
  564. package/dist/utils/shell.d.ts.map +1 -1
  565. package/dist/utils/shell.js.map +1 -1
  566. package/dist/utils/sleep.d.ts.map +1 -1
  567. package/dist/utils/sleep.js.map +1 -1
  568. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  569. package/dist/utils/syntax-highlight.js +1 -1
  570. package/dist/utils/syntax-highlight.js.map +1 -1
  571. package/dist/utils/tools-manager.d.ts.map +1 -1
  572. package/dist/utils/tools-manager.js.map +1 -1
  573. package/dist/utils/version-check.d.ts.map +1 -1
  574. package/dist/utils/version-check.js.map +1 -1
  575. package/dist/utils/windows-self-update.d.ts.map +1 -1
  576. package/dist/utils/windows-self-update.js.map +1 -1
  577. package/docs/extensions.md +31 -1
  578. package/docs/sandbox.md +6 -0
  579. package/docs/sessions.md +1 -1
  580. package/docs/skills.md +4 -4
  581. package/docs/usage.md +2 -1
  582. package/examples/extensions/custom-provider-anthropic/package.json +2 -2
  583. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  584. package/examples/extensions/sandbox/package.json +2 -2
  585. package/examples/extensions/with-deps/package.json +1 -1
  586. package/npm-shrinkwrap.json +602 -834
  587. package/package.json +20 -21
@@ -1 +1 @@
1
- {"version":3,"file":"edit-diff.d.ts","sourceRoot":"","sources":["../../../src/core/tools/edit-diff.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAE,KAAK,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAAE,QAAQ,IAAI,QAAQ,EAAE,CAAC;AAEhC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAM5D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAE3E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB3D;AAED,MAAM,WAAW,gBAAgB;IAChC,gCAAgC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,4FAA4F;IAC5F,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,cAAc,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,qBAAqB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,IAAI;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AASD,MAAM,WAAW,kBAAkB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAsChF;AA6CD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC5C,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,IAAI,EAAE,EACb,IAAI,EAAE,MAAM,GACV,kBAAkB,CA+DpB;AAED,yCAAyC;AACzC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,MAAM,CAKnH;AA8FD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,cAAc,CAgC3G;AAGD,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,IAAI,EAAE,EACb,UAAU,EAAE,cAAc,GACxB,OAAO,CAAC,cAAc,GAAG,aAAa,CAAC,CAyBzC;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,cAAc,GACxB,OAAO,CAAC,cAAc,GAAG,aAAa,CAAC,CAEzC","sourcesContent":["/**\n * Shared diff computation utilities for the edit tool.\n * Used by both edit.ts (for execution) and tool-execution.ts (for preview rendering).\n */\n\nimport * as Diff from \"diff\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { type LineEnding, stripBOM } from \"./replace-diff.ts\";\n\nexport { stripBOM as stripBom };\n\nexport function detectLineEnding(content: string): LineEnding {\n\tconst crlfIdx = content.indexOf(\"\\r\\n\");\n\tconst lfIdx = content.indexOf(\"\\n\");\n\tif (lfIdx === -1) return \"\\n\";\n\tif (crlfIdx === -1) return \"\\n\";\n\treturn crlfIdx < lfIdx ? \"\\r\\n\" : \"\\n\";\n}\n\nexport function normalizeToLF(text: string): string {\n\treturn text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n}\n\nexport function restoreLineEndings(text: string, ending: LineEnding): string {\n\treturn ending === \"\\r\\n\" ? text.replace(/\\n/g, \"\\r\\n\") : text;\n}\n\n/**\n * Normalize text for fuzzy matching. Applies progressive transformations:\n * - Strip trailing whitespace from each line\n * - Normalize smart quotes to ASCII equivalents\n * - Normalize Unicode dashes/hyphens to ASCII hyphen\n * - Normalize special Unicode spaces to regular space\n */\nexport function normalizeForFuzzyMatch(text: string): string {\n\treturn (\n\t\ttext\n\t\t\t.normalize(\"NFKC\")\n\t\t\t// Strip trailing whitespace per line\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => line.trimEnd())\n\t\t\t.join(\"\\n\")\n\t\t\t// Smart single quotes → '\n\t\t\t.replace(/[\\u2018\\u2019\\u201A\\u201B]/g, \"'\")\n\t\t\t// Smart double quotes → \"\n\t\t\t.replace(/[\\u201C\\u201D\\u201E\\u201F]/g, '\"')\n\t\t\t// Various dashes/hyphens → -\n\t\t\t// U+2010 hyphen, U+2011 non-breaking hyphen, U+2012 figure dash,\n\t\t\t// U+2013 en-dash, U+2014 em-dash, U+2015 horizontal bar, U+2212 minus\n\t\t\t.replace(/[\\u2010\\u2011\\u2012\\u2013\\u2014\\u2015\\u2212]/g, \"-\")\n\t\t\t// Special spaces → regular space\n\t\t\t// U+00A0 NBSP, U+2002-U+200A various spaces, U+202F narrow NBSP,\n\t\t\t// U+205F medium math space, U+3000 ideographic space\n\t\t\t.replace(/[\\u00A0\\u2002-\\u200A\\u202F\\u205F\\u3000]/g, \" \")\n\t);\n}\n\nexport interface FuzzyMatchResult {\n\t/** Whether a match was found */\n\tfound: boolean;\n\t/** The index where the match starts (in the content that should be used for replacement) */\n\tindex: number;\n\t/** Length of the matched text */\n\tmatchLength: number;\n\t/** Whether fuzzy matching was used (false = exact match) */\n\tusedFuzzyMatch: boolean;\n\t/**\n\t * The content to use for replacement operations.\n\t * When exact match: original content. When fuzzy match: normalized content.\n\t */\n\tcontentForReplacement: string;\n}\n\nexport interface Edit {\n\toldText: string;\n\tnewText: string;\n}\n\ninterface MatchedEdit {\n\teditIndex: number;\n\tmatchIndex: number;\n\tmatchLength: number;\n\tnewText: string;\n}\n\nexport interface AppliedEditsResult {\n\tbaseContent: string;\n\tnewContent: string;\n}\n\n/**\n * Find oldText in content, trying exact match first, then fuzzy match.\n * When fuzzy matching is used, the returned contentForReplacement is the\n * fuzzy-normalized version of the content (trailing whitespace stripped,\n * Unicode quotes/dashes normalized to ASCII).\n */\nexport function fuzzyFindText(content: string, oldText: string): FuzzyMatchResult {\n\t// Try exact match first\n\tconst exactIndex = content.indexOf(oldText);\n\tif (exactIndex !== -1) {\n\t\treturn {\n\t\t\tfound: true,\n\t\t\tindex: exactIndex,\n\t\t\tmatchLength: oldText.length,\n\t\t\tusedFuzzyMatch: false,\n\t\t\tcontentForReplacement: content,\n\t\t};\n\t}\n\n\t// Try fuzzy match - work entirely in normalized space\n\tconst fuzzyContent = normalizeForFuzzyMatch(content);\n\tconst fuzzyOldText = normalizeForFuzzyMatch(oldText);\n\tconst fuzzyIndex = fuzzyContent.indexOf(fuzzyOldText);\n\n\tif (fuzzyIndex === -1) {\n\t\treturn {\n\t\t\tfound: false,\n\t\t\tindex: -1,\n\t\t\tmatchLength: 0,\n\t\t\tusedFuzzyMatch: false,\n\t\t\tcontentForReplacement: content,\n\t\t};\n\t}\n\n\t// When fuzzy matching, we work in the normalized space for replacement.\n\t// This means the output will have normalized whitespace/quotes/dashes,\n\t// which is acceptable since we're fixing minor formatting differences anyway.\n\treturn {\n\t\tfound: true,\n\t\tindex: fuzzyIndex,\n\t\tmatchLength: fuzzyOldText.length,\n\t\tusedFuzzyMatch: true,\n\t\tcontentForReplacement: fuzzyContent,\n\t};\n}\nfunction countOccurrences(content: string, oldText: string): number {\n\tconst fuzzyContent = normalizeForFuzzyMatch(content);\n\tconst fuzzyOldText = normalizeForFuzzyMatch(oldText);\n\treturn fuzzyContent.split(fuzzyOldText).length - 1;\n}\n\nfunction getNotFoundError(path: string, editIndex: number, totalEdits: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(\n\t\t\t`Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`,\n\t\t);\n\t}\n\treturn new Error(\n\t\t`Could not find edits[${editIndex}] in ${path}. The oldText must match exactly including all whitespace and newlines.`,\n\t);\n}\n\nfunction getDuplicateError(path: string, editIndex: number, totalEdits: number, occurrences: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(\n\t\t\t`Found ${occurrences} occurrences of the text in ${path}. The text must be unique. Please provide more context to make it unique.`,\n\t\t);\n\t}\n\treturn new Error(\n\t\t`Found ${occurrences} occurrences of edits[${editIndex}] in ${path}. Each oldText must be unique. Please provide more context to make it unique.`,\n\t);\n}\n\nfunction getEmptyOldTextError(path: string, editIndex: number, totalEdits: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(`oldText must not be empty in ${path}.`);\n\t}\n\treturn new Error(`edits[${editIndex}].oldText must not be empty in ${path}.`);\n}\n\nfunction getNoChangeError(path: string, totalEdits: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(\n\t\t\t`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.`,\n\t\t);\n\t}\n\treturn new Error(`No changes made to ${path}. The replacements produced identical content.`);\n}\n\n/**\n * Apply one or more exact-text replacements to LF-normalized content.\n *\n * All edits are matched against the same original content. Replacements are\n * then applied in reverse order so offsets remain stable. If any edit needs\n * fuzzy matching, the operation runs in fuzzy-normalized content space to\n * preserve current single-edit behavior.\n */\nexport function applyEditsToNormalizedContent(\n\tnormalizedContent: string,\n\tedits: Edit[],\n\tpath: string,\n): AppliedEditsResult {\n\tconst normalizedEdits = edits.map((edit) => ({\n\t\toldText: normalizeToLF(edit.oldText),\n\t\tnewText: normalizeToLF(edit.newText),\n\t}));\n\n\tfor (let i = 0; i < normalizedEdits.length; i++) {\n\t\tif (normalizedEdits[i].oldText.length === 0) {\n\t\t\tthrow getEmptyOldTextError(path, i, normalizedEdits.length);\n\t\t}\n\t}\n\n\tconst initialMatches = normalizedEdits.map((edit) => fuzzyFindText(normalizedContent, edit.oldText));\n\tconst baseContent = initialMatches.some((match) => match.usedFuzzyMatch)\n\t\t? normalizeForFuzzyMatch(normalizedContent)\n\t\t: normalizedContent;\n\n\tconst matchedEdits: MatchedEdit[] = [];\n\tfor (let i = 0; i < normalizedEdits.length; i++) {\n\t\tconst edit = normalizedEdits[i];\n\t\tconst matchResult = fuzzyFindText(baseContent, edit.oldText);\n\t\tif (!matchResult.found) {\n\t\t\tthrow getNotFoundError(path, i, normalizedEdits.length);\n\t\t}\n\n\t\tconst occurrences = countOccurrences(baseContent, edit.oldText);\n\t\tif (occurrences > 1) {\n\t\t\tthrow getDuplicateError(path, i, normalizedEdits.length, occurrences);\n\t\t}\n\n\t\tmatchedEdits.push({\n\t\t\teditIndex: i,\n\t\t\tmatchIndex: matchResult.index,\n\t\t\tmatchLength: matchResult.matchLength,\n\t\t\tnewText: edit.newText,\n\t\t});\n\t}\n\n\tmatchedEdits.sort((a, b) => a.matchIndex - b.matchIndex);\n\tfor (let i = 1; i < matchedEdits.length; i++) {\n\t\tconst previous = matchedEdits[i - 1];\n\t\tconst current = matchedEdits[i];\n\t\tif (previous.matchIndex + previous.matchLength > current.matchIndex) {\n\t\t\tthrow new Error(\n\t\t\t\t`edits[${previous.editIndex}] and edits[${current.editIndex}] overlap in ${path}. Merge them into one edit or target disjoint regions.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tlet newContent = baseContent;\n\tfor (let i = matchedEdits.length - 1; i >= 0; i--) {\n\t\tconst edit = matchedEdits[i];\n\t\tnewContent =\n\t\t\tnewContent.substring(0, edit.matchIndex) +\n\t\t\tedit.newText +\n\t\t\tnewContent.substring(edit.matchIndex + edit.matchLength);\n\t}\n\n\tif (baseContent === newContent) {\n\t\tthrow getNoChangeError(path, normalizedEdits.length);\n\t}\n\n\treturn { baseContent, newContent };\n}\n\n/** Generate a standard unified patch. */\nexport function generateUnifiedPatch(path: string, oldContent: string, newContent: string, contextLines = 4): string {\n\treturn Diff.createTwoFilesPatch(path, path, oldContent, newContent, undefined, undefined, {\n\t\tcontext: contextLines,\n\t\theaderOptions: Diff.FILE_HEADERS_ONLY,\n\t});\n}\n\ninterface DiffRenderState {\n\toutput: string[];\n\toldLineNumber: number;\n\tnewLineNumber: number;\n\tlineNumberWidth: number;\n\tfirstChangedLine: number | undefined;\n}\n\nfunction getDiffPartLines(part: Diff.Change): string[] {\n\tconst lines = part.value.split(\"\\n\");\n\tif (lines.at(-1) === \"\") lines.pop();\n\treturn lines;\n}\n\nfunction appendChangedDiffLines(state: DiffRenderState, part: Diff.Change, lines: string[]): void {\n\tstate.firstChangedLine ??= state.newLineNumber;\n\tfor (const line of lines) {\n\t\tif (part.added) {\n\t\t\tconst lineNumber = String(state.newLineNumber).padStart(state.lineNumberWidth, \" \");\n\t\t\tstate.output.push(`+${lineNumber} ${line}`);\n\t\t\tstate.newLineNumber++;\n\t\t} else {\n\t\t\tconst lineNumber = String(state.oldLineNumber).padStart(state.lineNumberWidth, \" \");\n\t\t\tstate.output.push(`-${lineNumber} ${line}`);\n\t\t\tstate.oldLineNumber++;\n\t\t}\n\t}\n}\n\nfunction appendContextDiffLines(state: DiffRenderState, lines: string[]): void {\n\tfor (const line of lines) {\n\t\tconst lineNumber = String(state.oldLineNumber).padStart(state.lineNumberWidth, \" \");\n\t\tstate.output.push(` ${lineNumber} ${line}`);\n\t\tstate.oldLineNumber++;\n\t\tstate.newLineNumber++;\n\t}\n}\n\nfunction appendSkippedDiffLines(state: DiffRenderState, count: number): void {\n\tif (count <= 0) return;\n\tstate.output.push(` ${\"\".padStart(state.lineNumberWidth, \" \")} ...`);\n\tstate.oldLineNumber += count;\n\tstate.newLineNumber += count;\n}\n\nfunction appendContextBetweenChanges(state: DiffRenderState, lines: string[], contextLines: number): void {\n\tif (lines.length <= contextLines * 2) {\n\t\tappendContextDiffLines(state, lines);\n\t\treturn;\n\t}\n\tconst leadingLines = lines.slice(0, contextLines);\n\tconst trailingLines = lines.slice(lines.length - contextLines);\n\tappendContextDiffLines(state, leadingLines);\n\tappendSkippedDiffLines(state, lines.length - leadingLines.length - trailingLines.length);\n\tappendContextDiffLines(state, trailingLines);\n}\n\nfunction appendContextAfterChange(state: DiffRenderState, lines: string[], contextLines: number): void {\n\tconst shownLines = lines.slice(0, contextLines);\n\tappendContextDiffLines(state, shownLines);\n\tappendSkippedDiffLines(state, lines.length - shownLines.length);\n}\n\nfunction appendContextBeforeChange(state: DiffRenderState, lines: string[], contextLines: number): void {\n\tconst skippedLines = Math.max(0, lines.length - contextLines);\n\tappendSkippedDiffLines(state, skippedLines);\n\tappendContextDiffLines(state, lines.slice(skippedLines));\n}\n\nfunction appendUnchangedDiffPart(\n\tstate: DiffRenderState,\n\tlines: string[],\n\thasLeadingChange: boolean,\n\thasTrailingChange: boolean,\n\tcontextLines: number,\n): void {\n\tif (hasLeadingChange && hasTrailingChange) {\n\t\tappendContextBetweenChanges(state, lines, contextLines);\n\t\treturn;\n\t}\n\tif (hasLeadingChange) {\n\t\tappendContextAfterChange(state, lines, contextLines);\n\t\treturn;\n\t}\n\tif (hasTrailingChange) {\n\t\tappendContextBeforeChange(state, lines, contextLines);\n\t\treturn;\n\t}\n\tstate.oldLineNumber += lines.length;\n\tstate.newLineNumber += lines.length;\n}\n\n/**\n * Generate a display-oriented diff string with line numbers and context.\n * Returns both the diff string and the first changed line number (in the new file).\n */\nexport function generateDiffString(oldContent: string, newContent: string, contextLines = 4): EditDiffResult {\n\tconst parts = Diff.diffLines(oldContent, newContent);\n\tconst maxLineNumber = Math.max(oldContent.split(\"\\n\").length, newContent.split(\"\\n\").length);\n\tconst state: DiffRenderState = {\n\t\toutput: [],\n\t\toldLineNumber: 1,\n\t\tnewLineNumber: 1,\n\t\tlineNumberWidth: String(maxLineNumber).length,\n\t\tfirstChangedLine: undefined,\n\t};\n\tlet lastWasChange = false;\n\n\tfor (let index = 0; index < parts.length; index++) {\n\t\tconst part = parts[index];\n\t\tconst lines = getDiffPartLines(part);\n\t\tif (part.added || part.removed) {\n\t\t\tappendChangedDiffLines(state, part, lines);\n\t\t\tlastWasChange = true;\n\t\t\tcontinue;\n\t\t}\n\t\tconst nextPart = parts[index + 1];\n\t\tappendUnchangedDiffPart(\n\t\t\tstate,\n\t\t\tlines,\n\t\t\tlastWasChange,\n\t\t\tindex < parts.length - 1 && Boolean(nextPart.added || nextPart.removed),\n\t\t\tcontextLines,\n\t\t);\n\t\tlastWasChange = false;\n\t}\n\n\treturn { diff: state.output.join(\"\\n\"), firstChangedLine: state.firstChangedLine };\n}\n\n// grip-ignore noNearIdenticalDataStructures: Plain line-number diffs and hashline-anchored diffs use distinct rendering formats and evolve independently.\nexport interface EditDiffResult {\n\tdiff: string;\n\tfirstChangedLine: number | undefined;\n}\n\nexport interface EditDiffError {\n\terror: string;\n}\n\n/**\n * Compute the diff for one or more edit operations without applying them.\n * Used for preview rendering in the TUI before the tool executes.\n */\nexport async function computeEditsDiff(\n\tpath: string,\n\tedits: Edit[],\n\toperations: ToolOperations,\n): Promise<EditDiffResult | EditDiffError> {\n\tconst absolutePath = resolveToCwd(path, operations.cwd);\n\n\ttry {\n\t\t// Check if file exists and is readable\n\t\ttry {\n\t\t\tawait operations.access(absolutePath, \"read\");\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error && \"code\" in error ? `Error code: ${error.code}` : String(error);\n\t\t\treturn { error: `Could not edit file: ${path}. ${errorMessage}.` };\n\t\t}\n\n\t\t// Read the file\n\t\tconst rawContent = (await operations.readFile(absolutePath)).toString(\"utf-8\");\n\n\t\t// Strip BOM before matching (LLM won't include invisible BOM in oldText)\n\t\tconst { text: content } = stripBOM(rawContent);\n\t\tconst normalizedContent = normalizeToLF(content);\n\t\tconst { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path);\n\n\t\t// Generate the diff\n\t\treturn generateDiffString(baseContent, newContent);\n\t} catch (err) {\n\t\treturn { error: err instanceof Error ? err.message : String(err) };\n\t}\n}\n\n/**\n * Compute the diff for a single edit operation without applying it.\n * Kept as a convenience wrapper for single-edit callers.\n */\nexport async function computeEditDiff(\n\tpath: string,\n\toldText: string,\n\tnewText: string,\n\toperations: ToolOperations,\n): Promise<EditDiffResult | EditDiffError> {\n\treturn computeEditsDiff(path, [{ oldText, newText }], operations);\n}\n"]}
1
+ {"version":3,"file":"edit-diff.d.ts","sourceRoot":"","sources":["../../../src/core/tools/edit-diff.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAE,KAAK,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAAE,QAAQ,IAAI,QAAQ,EAAE,CAAC;AAEhC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAM5D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAE3E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB3D;AAED,MAAM,WAAW,gBAAgB;IAChC,gCAAgC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,4FAA4F;IAC5F,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,cAAc,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,qBAAqB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,IAAI;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AASD,MAAM,WAAW,kBAAkB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAsChF;AA6CD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC5C,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,IAAI,EAAE,EACb,IAAI,EAAE,MAAM,GACV,kBAAkB,CA+DpB;AAED,yCAAyC;AACzC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,MAAM,CAKnH;AA8FD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,cAAc,CAgC3G;AAGD,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,IAAI,EAAE,EACb,UAAU,EAAE,cAAc,GACxB,OAAO,CAAC,cAAc,GAAG,aAAa,CAAC,CAyBzC;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,cAAc,GACxB,OAAO,CAAC,cAAc,GAAG,aAAa,CAAC,CAEzC"}
@@ -1 +1 @@
1
- {"version":3,"file":"edit-diff.js","sourceRoot":"","sources":["../../../src/core/tools/edit-diff.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared diff computation utilities for the edit tool.\n * Used by both edit.ts (for execution) and tool-execution.ts (for preview rendering).\n */\n\nimport * as Diff from \"diff\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { type LineEnding, stripBOM } from \"./replace-diff.ts\";\n\nexport { stripBOM as stripBom };\n\nexport function detectLineEnding(content: string): LineEnding {\n\tconst crlfIdx = content.indexOf(\"\\r\\n\");\n\tconst lfIdx = content.indexOf(\"\\n\");\n\tif (lfIdx === -1) return \"\\n\";\n\tif (crlfIdx === -1) return \"\\n\";\n\treturn crlfIdx < lfIdx ? \"\\r\\n\" : \"\\n\";\n}\n\nexport function normalizeToLF(text: string): string {\n\treturn text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n}\n\nexport function restoreLineEndings(text: string, ending: LineEnding): string {\n\treturn ending === \"\\r\\n\" ? text.replace(/\\n/g, \"\\r\\n\") : text;\n}\n\n/**\n * Normalize text for fuzzy matching. Applies progressive transformations:\n * - Strip trailing whitespace from each line\n * - Normalize smart quotes to ASCII equivalents\n * - Normalize Unicode dashes/hyphens to ASCII hyphen\n * - Normalize special Unicode spaces to regular space\n */\nexport function normalizeForFuzzyMatch(text: string): string {\n\treturn (\n\t\ttext\n\t\t\t.normalize(\"NFKC\")\n\t\t\t// Strip trailing whitespace per line\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => line.trimEnd())\n\t\t\t.join(\"\\n\")\n\t\t\t// Smart single quotes → '\n\t\t\t.replace(/[\\u2018\\u2019\\u201A\\u201B]/g, \"'\")\n\t\t\t// Smart double quotes → \"\n\t\t\t.replace(/[\\u201C\\u201D\\u201E\\u201F]/g, '\"')\n\t\t\t// Various dashes/hyphens → -\n\t\t\t// U+2010 hyphen, U+2011 non-breaking hyphen, U+2012 figure dash,\n\t\t\t// U+2013 en-dash, U+2014 em-dash, U+2015 horizontal bar, U+2212 minus\n\t\t\t.replace(/[\\u2010\\u2011\\u2012\\u2013\\u2014\\u2015\\u2212]/g, \"-\")\n\t\t\t// Special spaces → regular space\n\t\t\t// U+00A0 NBSP, U+2002-U+200A various spaces, U+202F narrow NBSP,\n\t\t\t// U+205F medium math space, U+3000 ideographic space\n\t\t\t.replace(/[\\u00A0\\u2002-\\u200A\\u202F\\u205F\\u3000]/g, \" \")\n\t);\n}\n\nexport interface FuzzyMatchResult {\n\t/** Whether a match was found */\n\tfound: boolean;\n\t/** The index where the match starts (in the content that should be used for replacement) */\n\tindex: number;\n\t/** Length of the matched text */\n\tmatchLength: number;\n\t/** Whether fuzzy matching was used (false = exact match) */\n\tusedFuzzyMatch: boolean;\n\t/**\n\t * The content to use for replacement operations.\n\t * When exact match: original content. When fuzzy match: normalized content.\n\t */\n\tcontentForReplacement: string;\n}\n\nexport interface Edit {\n\toldText: string;\n\tnewText: string;\n}\n\ninterface MatchedEdit {\n\teditIndex: number;\n\tmatchIndex: number;\n\tmatchLength: number;\n\tnewText: string;\n}\n\nexport interface AppliedEditsResult {\n\tbaseContent: string;\n\tnewContent: string;\n}\n\n/**\n * Find oldText in content, trying exact match first, then fuzzy match.\n * When fuzzy matching is used, the returned contentForReplacement is the\n * fuzzy-normalized version of the content (trailing whitespace stripped,\n * Unicode quotes/dashes normalized to ASCII).\n */\nexport function fuzzyFindText(content: string, oldText: string): FuzzyMatchResult {\n\t// Try exact match first\n\tconst exactIndex = content.indexOf(oldText);\n\tif (exactIndex !== -1) {\n\t\treturn {\n\t\t\tfound: true,\n\t\t\tindex: exactIndex,\n\t\t\tmatchLength: oldText.length,\n\t\t\tusedFuzzyMatch: false,\n\t\t\tcontentForReplacement: content,\n\t\t};\n\t}\n\n\t// Try fuzzy match - work entirely in normalized space\n\tconst fuzzyContent = normalizeForFuzzyMatch(content);\n\tconst fuzzyOldText = normalizeForFuzzyMatch(oldText);\n\tconst fuzzyIndex = fuzzyContent.indexOf(fuzzyOldText);\n\n\tif (fuzzyIndex === -1) {\n\t\treturn {\n\t\t\tfound: false,\n\t\t\tindex: -1,\n\t\t\tmatchLength: 0,\n\t\t\tusedFuzzyMatch: false,\n\t\t\tcontentForReplacement: content,\n\t\t};\n\t}\n\n\t// When fuzzy matching, we work in the normalized space for replacement.\n\t// This means the output will have normalized whitespace/quotes/dashes,\n\t// which is acceptable since we're fixing minor formatting differences anyway.\n\treturn {\n\t\tfound: true,\n\t\tindex: fuzzyIndex,\n\t\tmatchLength: fuzzyOldText.length,\n\t\tusedFuzzyMatch: true,\n\t\tcontentForReplacement: fuzzyContent,\n\t};\n}\nfunction countOccurrences(content: string, oldText: string): number {\n\tconst fuzzyContent = normalizeForFuzzyMatch(content);\n\tconst fuzzyOldText = normalizeForFuzzyMatch(oldText);\n\treturn fuzzyContent.split(fuzzyOldText).length - 1;\n}\n\nfunction getNotFoundError(path: string, editIndex: number, totalEdits: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(\n\t\t\t`Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`,\n\t\t);\n\t}\n\treturn new Error(\n\t\t`Could not find edits[${editIndex}] in ${path}. The oldText must match exactly including all whitespace and newlines.`,\n\t);\n}\n\nfunction getDuplicateError(path: string, editIndex: number, totalEdits: number, occurrences: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(\n\t\t\t`Found ${occurrences} occurrences of the text in ${path}. The text must be unique. Please provide more context to make it unique.`,\n\t\t);\n\t}\n\treturn new Error(\n\t\t`Found ${occurrences} occurrences of edits[${editIndex}] in ${path}. Each oldText must be unique. Please provide more context to make it unique.`,\n\t);\n}\n\nfunction getEmptyOldTextError(path: string, editIndex: number, totalEdits: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(`oldText must not be empty in ${path}.`);\n\t}\n\treturn new Error(`edits[${editIndex}].oldText must not be empty in ${path}.`);\n}\n\nfunction getNoChangeError(path: string, totalEdits: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(\n\t\t\t`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.`,\n\t\t);\n\t}\n\treturn new Error(`No changes made to ${path}. The replacements produced identical content.`);\n}\n\n/**\n * Apply one or more exact-text replacements to LF-normalized content.\n *\n * All edits are matched against the same original content. Replacements are\n * then applied in reverse order so offsets remain stable. If any edit needs\n * fuzzy matching, the operation runs in fuzzy-normalized content space to\n * preserve current single-edit behavior.\n */\nexport function applyEditsToNormalizedContent(\n\tnormalizedContent: string,\n\tedits: Edit[],\n\tpath: string,\n): AppliedEditsResult {\n\tconst normalizedEdits = edits.map((edit) => ({\n\t\toldText: normalizeToLF(edit.oldText),\n\t\tnewText: normalizeToLF(edit.newText),\n\t}));\n\n\tfor (let i = 0; i < normalizedEdits.length; i++) {\n\t\tif (normalizedEdits[i].oldText.length === 0) {\n\t\t\tthrow getEmptyOldTextError(path, i, normalizedEdits.length);\n\t\t}\n\t}\n\n\tconst initialMatches = normalizedEdits.map((edit) => fuzzyFindText(normalizedContent, edit.oldText));\n\tconst baseContent = initialMatches.some((match) => match.usedFuzzyMatch)\n\t\t? normalizeForFuzzyMatch(normalizedContent)\n\t\t: normalizedContent;\n\n\tconst matchedEdits: MatchedEdit[] = [];\n\tfor (let i = 0; i < normalizedEdits.length; i++) {\n\t\tconst edit = normalizedEdits[i];\n\t\tconst matchResult = fuzzyFindText(baseContent, edit.oldText);\n\t\tif (!matchResult.found) {\n\t\t\tthrow getNotFoundError(path, i, normalizedEdits.length);\n\t\t}\n\n\t\tconst occurrences = countOccurrences(baseContent, edit.oldText);\n\t\tif (occurrences > 1) {\n\t\t\tthrow getDuplicateError(path, i, normalizedEdits.length, occurrences);\n\t\t}\n\n\t\tmatchedEdits.push({\n\t\t\teditIndex: i,\n\t\t\tmatchIndex: matchResult.index,\n\t\t\tmatchLength: matchResult.matchLength,\n\t\t\tnewText: edit.newText,\n\t\t});\n\t}\n\n\tmatchedEdits.sort((a, b) => a.matchIndex - b.matchIndex);\n\tfor (let i = 1; i < matchedEdits.length; i++) {\n\t\tconst previous = matchedEdits[i - 1];\n\t\tconst current = matchedEdits[i];\n\t\tif (previous.matchIndex + previous.matchLength > current.matchIndex) {\n\t\t\tthrow new Error(\n\t\t\t\t`edits[${previous.editIndex}] and edits[${current.editIndex}] overlap in ${path}. Merge them into one edit or target disjoint regions.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tlet newContent = baseContent;\n\tfor (let i = matchedEdits.length - 1; i >= 0; i--) {\n\t\tconst edit = matchedEdits[i];\n\t\tnewContent =\n\t\t\tnewContent.substring(0, edit.matchIndex) +\n\t\t\tedit.newText +\n\t\t\tnewContent.substring(edit.matchIndex + edit.matchLength);\n\t}\n\n\tif (baseContent === newContent) {\n\t\tthrow getNoChangeError(path, normalizedEdits.length);\n\t}\n\n\treturn { baseContent, newContent };\n}\n\n/** Generate a standard unified patch. */\nexport function generateUnifiedPatch(path: string, oldContent: string, newContent: string, contextLines = 4): string {\n\treturn Diff.createTwoFilesPatch(path, path, oldContent, newContent, undefined, undefined, {\n\t\tcontext: contextLines,\n\t\theaderOptions: Diff.FILE_HEADERS_ONLY,\n\t});\n}\n\ninterface DiffRenderState {\n\toutput: string[];\n\toldLineNumber: number;\n\tnewLineNumber: number;\n\tlineNumberWidth: number;\n\tfirstChangedLine: number | undefined;\n}\n\nfunction getDiffPartLines(part: Diff.Change): string[] {\n\tconst lines = part.value.split(\"\\n\");\n\tif (lines.at(-1) === \"\") lines.pop();\n\treturn lines;\n}\n\nfunction appendChangedDiffLines(state: DiffRenderState, part: Diff.Change, lines: string[]): void {\n\tstate.firstChangedLine ??= state.newLineNumber;\n\tfor (const line of lines) {\n\t\tif (part.added) {\n\t\t\tconst lineNumber = String(state.newLineNumber).padStart(state.lineNumberWidth, \" \");\n\t\t\tstate.output.push(`+${lineNumber} ${line}`);\n\t\t\tstate.newLineNumber++;\n\t\t} else {\n\t\t\tconst lineNumber = String(state.oldLineNumber).padStart(state.lineNumberWidth, \" \");\n\t\t\tstate.output.push(`-${lineNumber} ${line}`);\n\t\t\tstate.oldLineNumber++;\n\t\t}\n\t}\n}\n\nfunction appendContextDiffLines(state: DiffRenderState, lines: string[]): void {\n\tfor (const line of lines) {\n\t\tconst lineNumber = String(state.oldLineNumber).padStart(state.lineNumberWidth, \" \");\n\t\tstate.output.push(` ${lineNumber} ${line}`);\n\t\tstate.oldLineNumber++;\n\t\tstate.newLineNumber++;\n\t}\n}\n\nfunction appendSkippedDiffLines(state: DiffRenderState, count: number): void {\n\tif (count <= 0) return;\n\tstate.output.push(` ${\"\".padStart(state.lineNumberWidth, \" \")} ...`);\n\tstate.oldLineNumber += count;\n\tstate.newLineNumber += count;\n}\n\nfunction appendContextBetweenChanges(state: DiffRenderState, lines: string[], contextLines: number): void {\n\tif (lines.length <= contextLines * 2) {\n\t\tappendContextDiffLines(state, lines);\n\t\treturn;\n\t}\n\tconst leadingLines = lines.slice(0, contextLines);\n\tconst trailingLines = lines.slice(lines.length - contextLines);\n\tappendContextDiffLines(state, leadingLines);\n\tappendSkippedDiffLines(state, lines.length - leadingLines.length - trailingLines.length);\n\tappendContextDiffLines(state, trailingLines);\n}\n\nfunction appendContextAfterChange(state: DiffRenderState, lines: string[], contextLines: number): void {\n\tconst shownLines = lines.slice(0, contextLines);\n\tappendContextDiffLines(state, shownLines);\n\tappendSkippedDiffLines(state, lines.length - shownLines.length);\n}\n\nfunction appendContextBeforeChange(state: DiffRenderState, lines: string[], contextLines: number): void {\n\tconst skippedLines = Math.max(0, lines.length - contextLines);\n\tappendSkippedDiffLines(state, skippedLines);\n\tappendContextDiffLines(state, lines.slice(skippedLines));\n}\n\nfunction appendUnchangedDiffPart(\n\tstate: DiffRenderState,\n\tlines: string[],\n\thasLeadingChange: boolean,\n\thasTrailingChange: boolean,\n\tcontextLines: number,\n): void {\n\tif (hasLeadingChange && hasTrailingChange) {\n\t\tappendContextBetweenChanges(state, lines, contextLines);\n\t\treturn;\n\t}\n\tif (hasLeadingChange) {\n\t\tappendContextAfterChange(state, lines, contextLines);\n\t\treturn;\n\t}\n\tif (hasTrailingChange) {\n\t\tappendContextBeforeChange(state, lines, contextLines);\n\t\treturn;\n\t}\n\tstate.oldLineNumber += lines.length;\n\tstate.newLineNumber += lines.length;\n}\n\n/**\n * Generate a display-oriented diff string with line numbers and context.\n * Returns both the diff string and the first changed line number (in the new file).\n */\nexport function generateDiffString(oldContent: string, newContent: string, contextLines = 4): EditDiffResult {\n\tconst parts = Diff.diffLines(oldContent, newContent);\n\tconst maxLineNumber = Math.max(oldContent.split(\"\\n\").length, newContent.split(\"\\n\").length);\n\tconst state: DiffRenderState = {\n\t\toutput: [],\n\t\toldLineNumber: 1,\n\t\tnewLineNumber: 1,\n\t\tlineNumberWidth: String(maxLineNumber).length,\n\t\tfirstChangedLine: undefined,\n\t};\n\tlet lastWasChange = false;\n\n\tfor (let index = 0; index < parts.length; index++) {\n\t\tconst part = parts[index];\n\t\tconst lines = getDiffPartLines(part);\n\t\tif (part.added || part.removed) {\n\t\t\tappendChangedDiffLines(state, part, lines);\n\t\t\tlastWasChange = true;\n\t\t\tcontinue;\n\t\t}\n\t\tconst nextPart = parts[index + 1];\n\t\tappendUnchangedDiffPart(\n\t\t\tstate,\n\t\t\tlines,\n\t\t\tlastWasChange,\n\t\t\tindex < parts.length - 1 && Boolean(nextPart.added || nextPart.removed),\n\t\t\tcontextLines,\n\t\t);\n\t\tlastWasChange = false;\n\t}\n\n\treturn { diff: state.output.join(\"\\n\"), firstChangedLine: state.firstChangedLine };\n}\n\n// grip-ignore noNearIdenticalDataStructures: Plain line-number diffs and hashline-anchored diffs use distinct rendering formats and evolve independently.\nexport interface EditDiffResult {\n\tdiff: string;\n\tfirstChangedLine: number | undefined;\n}\n\nexport interface EditDiffError {\n\terror: string;\n}\n\n/**\n * Compute the diff for one or more edit operations without applying them.\n * Used for preview rendering in the TUI before the tool executes.\n */\nexport async function computeEditsDiff(\n\tpath: string,\n\tedits: Edit[],\n\toperations: ToolOperations,\n): Promise<EditDiffResult | EditDiffError> {\n\tconst absolutePath = resolveToCwd(path, operations.cwd);\n\n\ttry {\n\t\t// Check if file exists and is readable\n\t\ttry {\n\t\t\tawait operations.access(absolutePath, \"read\");\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error && \"code\" in error ? `Error code: ${error.code}` : String(error);\n\t\t\treturn { error: `Could not edit file: ${path}. ${errorMessage}.` };\n\t\t}\n\n\t\t// Read the file\n\t\tconst rawContent = (await operations.readFile(absolutePath)).toString(\"utf-8\");\n\n\t\t// Strip BOM before matching (LLM won't include invisible BOM in oldText)\n\t\tconst { text: content } = stripBOM(rawContent);\n\t\tconst normalizedContent = normalizeToLF(content);\n\t\tconst { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path);\n\n\t\t// Generate the diff\n\t\treturn generateDiffString(baseContent, newContent);\n\t} catch (err) {\n\t\treturn { error: err instanceof Error ? err.message : String(err) };\n\t}\n}\n\n/**\n * Compute the diff for a single edit operation without applying it.\n * Kept as a convenience wrapper for single-edit callers.\n */\nexport async function computeEditDiff(\n\tpath: string,\n\toldText: string,\n\tnewText: string,\n\toperations: ToolOperations,\n): Promise<EditDiffResult | EditDiffError> {\n\treturn computeEditsDiff(path, [{ oldText, newText }], operations);\n}\n"]}
1
+ {"version":3,"file":"edit-diff.js","sourceRoot":"","sources":["../../../src/core/tools/edit-diff.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared diff computation utilities for the edit tool.\n * Used by both edit.ts (for execution) and tool-execution.ts (for preview rendering).\n */\n\nimport * as Diff from \"diff\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { type LineEnding, stripBOM } from \"./replace-diff.ts\";\n\nexport { stripBOM as stripBom };\n\nexport function detectLineEnding(content: string): LineEnding {\n\tconst crlfIdx = content.indexOf(\"\\r\\n\");\n\tconst lfIdx = content.indexOf(\"\\n\");\n\tif (lfIdx === -1) return \"\\n\";\n\tif (crlfIdx === -1) return \"\\n\";\n\treturn crlfIdx < lfIdx ? \"\\r\\n\" : \"\\n\";\n}\n\nexport function normalizeToLF(text: string): string {\n\treturn text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n}\n\nexport function restoreLineEndings(text: string, ending: LineEnding): string {\n\treturn ending === \"\\r\\n\" ? text.replace(/\\n/g, \"\\r\\n\") : text;\n}\n\n/**\n * Normalize text for fuzzy matching. Applies progressive transformations:\n * - Strip trailing whitespace from each line\n * - Normalize smart quotes to ASCII equivalents\n * - Normalize Unicode dashes/hyphens to ASCII hyphen\n * - Normalize special Unicode spaces to regular space\n */\nexport function normalizeForFuzzyMatch(text: string): string {\n\treturn (\n\t\ttext\n\t\t\t.normalize(\"NFKC\")\n\t\t\t// Strip trailing whitespace per line\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => line.trimEnd())\n\t\t\t.join(\"\\n\")\n\t\t\t// Smart single quotes → '\n\t\t\t.replace(/[\\u2018\\u2019\\u201A\\u201B]/g, \"'\")\n\t\t\t// Smart double quotes → \"\n\t\t\t.replace(/[\\u201C\\u201D\\u201E\\u201F]/g, '\"')\n\t\t\t// Various dashes/hyphens → -\n\t\t\t// U+2010 hyphen, U+2011 non-breaking hyphen, U+2012 figure dash,\n\t\t\t// U+2013 en-dash, U+2014 em-dash, U+2015 horizontal bar, U+2212 minus\n\t\t\t.replace(/[\\u2010\\u2011\\u2012\\u2013\\u2014\\u2015\\u2212]/g, \"-\")\n\t\t\t// Special spaces → regular space\n\t\t\t// U+00A0 NBSP, U+2002-U+200A various spaces, U+202F narrow NBSP,\n\t\t\t// U+205F medium math space, U+3000 ideographic space\n\t\t\t.replace(/[\\u00A0\\u2002-\\u200A\\u202F\\u205F\\u3000]/g, \" \")\n\t);\n}\n\nexport interface FuzzyMatchResult {\n\t/** Whether a match was found */\n\tfound: boolean;\n\t/** The index where the match starts (in the content that should be used for replacement) */\n\tindex: number;\n\t/** Length of the matched text */\n\tmatchLength: number;\n\t/** Whether fuzzy matching was used (false = exact match) */\n\tusedFuzzyMatch: boolean;\n\t/**\n\t * The content to use for replacement operations.\n\t * When exact match: original content. When fuzzy match: normalized content.\n\t */\n\tcontentForReplacement: string;\n}\n\nexport interface Edit {\n\toldText: string;\n\tnewText: string;\n}\n\ninterface MatchedEdit {\n\teditIndex: number;\n\tmatchIndex: number;\n\tmatchLength: number;\n\tnewText: string;\n}\n\nexport interface AppliedEditsResult {\n\tbaseContent: string;\n\tnewContent: string;\n}\n\n/**\n * Find oldText in content, trying exact match first, then fuzzy match.\n * When fuzzy matching is used, the returned contentForReplacement is the\n * fuzzy-normalized version of the content (trailing whitespace stripped,\n * Unicode quotes/dashes normalized to ASCII).\n */\nexport function fuzzyFindText(content: string, oldText: string): FuzzyMatchResult {\n\t// Try exact match first\n\tconst exactIndex = content.indexOf(oldText);\n\tif (exactIndex !== -1) {\n\t\treturn {\n\t\t\tfound: true,\n\t\t\tindex: exactIndex,\n\t\t\tmatchLength: oldText.length,\n\t\t\tusedFuzzyMatch: false,\n\t\t\tcontentForReplacement: content,\n\t\t};\n\t}\n\n\t// Try fuzzy match - work entirely in normalized space\n\tconst fuzzyContent = normalizeForFuzzyMatch(content);\n\tconst fuzzyOldText = normalizeForFuzzyMatch(oldText);\n\tconst fuzzyIndex = fuzzyContent.indexOf(fuzzyOldText);\n\n\tif (fuzzyIndex === -1) {\n\t\treturn {\n\t\t\tfound: false,\n\t\t\tindex: -1,\n\t\t\tmatchLength: 0,\n\t\t\tusedFuzzyMatch: false,\n\t\t\tcontentForReplacement: content,\n\t\t};\n\t}\n\n\t// When fuzzy matching, we work in the normalized space for replacement.\n\t// This means the output will have normalized whitespace/quotes/dashes,\n\t// which is acceptable since we're fixing minor formatting differences anyway.\n\treturn {\n\t\tfound: true,\n\t\tindex: fuzzyIndex,\n\t\tmatchLength: fuzzyOldText.length,\n\t\tusedFuzzyMatch: true,\n\t\tcontentForReplacement: fuzzyContent,\n\t};\n}\nfunction countOccurrences(content: string, oldText: string): number {\n\tconst fuzzyContent = normalizeForFuzzyMatch(content);\n\tconst fuzzyOldText = normalizeForFuzzyMatch(oldText);\n\treturn fuzzyContent.split(fuzzyOldText).length - 1;\n}\n\nfunction getNotFoundError(path: string, editIndex: number, totalEdits: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(\n\t\t\t`Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`,\n\t\t);\n\t}\n\treturn new Error(\n\t\t`Could not find edits[${editIndex}] in ${path}. The oldText must match exactly including all whitespace and newlines.`,\n\t);\n}\n\nfunction getDuplicateError(path: string, editIndex: number, totalEdits: number, occurrences: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(\n\t\t\t`Found ${occurrences} occurrences of the text in ${path}. The text must be unique. Please provide more context to make it unique.`,\n\t\t);\n\t}\n\treturn new Error(\n\t\t`Found ${occurrences} occurrences of edits[${editIndex}] in ${path}. Each oldText must be unique. Please provide more context to make it unique.`,\n\t);\n}\n\nfunction getEmptyOldTextError(path: string, editIndex: number, totalEdits: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(`oldText must not be empty in ${path}.`);\n\t}\n\treturn new Error(`edits[${editIndex}].oldText must not be empty in ${path}.`);\n}\n\nfunction getNoChangeError(path: string, totalEdits: number): Error {\n\tif (totalEdits === 1) {\n\t\treturn new Error(\n\t\t\t`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.`,\n\t\t);\n\t}\n\treturn new Error(`No changes made to ${path}. The replacements produced identical content.`);\n}\n\n/**\n * Apply one or more exact-text replacements to LF-normalized content.\n *\n * All edits are matched against the same original content. Replacements are\n * then applied in reverse order so offsets remain stable. If any edit needs\n * fuzzy matching, the operation runs in fuzzy-normalized content space to\n * preserve current single-edit behavior.\n */\nexport function applyEditsToNormalizedContent(\n\tnormalizedContent: string,\n\tedits: Edit[],\n\tpath: string,\n): AppliedEditsResult {\n\tconst normalizedEdits = edits.map((edit) => ({\n\t\toldText: normalizeToLF(edit.oldText),\n\t\tnewText: normalizeToLF(edit.newText),\n\t}));\n\n\tfor (let i = 0; i < normalizedEdits.length; i++) {\n\t\tif (normalizedEdits[i].oldText.length === 0) {\n\t\t\tthrow getEmptyOldTextError(path, i, normalizedEdits.length);\n\t\t}\n\t}\n\n\tconst initialMatches = normalizedEdits.map((edit) => fuzzyFindText(normalizedContent, edit.oldText));\n\tconst baseContent = initialMatches.some((match) => match.usedFuzzyMatch)\n\t\t? normalizeForFuzzyMatch(normalizedContent)\n\t\t: normalizedContent;\n\n\tconst matchedEdits: MatchedEdit[] = [];\n\tfor (let i = 0; i < normalizedEdits.length; i++) {\n\t\tconst edit = normalizedEdits[i];\n\t\tconst matchResult = fuzzyFindText(baseContent, edit.oldText);\n\t\tif (!matchResult.found) {\n\t\t\tthrow getNotFoundError(path, i, normalizedEdits.length);\n\t\t}\n\n\t\tconst occurrences = countOccurrences(baseContent, edit.oldText);\n\t\tif (occurrences > 1) {\n\t\t\tthrow getDuplicateError(path, i, normalizedEdits.length, occurrences);\n\t\t}\n\n\t\tmatchedEdits.push({\n\t\t\teditIndex: i,\n\t\t\tmatchIndex: matchResult.index,\n\t\t\tmatchLength: matchResult.matchLength,\n\t\t\tnewText: edit.newText,\n\t\t});\n\t}\n\n\tmatchedEdits.sort((a, b) => a.matchIndex - b.matchIndex);\n\tfor (let i = 1; i < matchedEdits.length; i++) {\n\t\tconst previous = matchedEdits[i - 1];\n\t\tconst current = matchedEdits[i];\n\t\tif (previous.matchIndex + previous.matchLength > current.matchIndex) {\n\t\t\tthrow new Error(\n\t\t\t\t`edits[${previous.editIndex}] and edits[${current.editIndex}] overlap in ${path}. Merge them into one edit or target disjoint regions.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tlet newContent = baseContent;\n\tfor (let i = matchedEdits.length - 1; i >= 0; i--) {\n\t\tconst edit = matchedEdits[i];\n\t\tnewContent =\n\t\t\tnewContent.substring(0, edit.matchIndex) +\n\t\t\tedit.newText +\n\t\t\tnewContent.substring(edit.matchIndex + edit.matchLength);\n\t}\n\n\tif (baseContent === newContent) {\n\t\tthrow getNoChangeError(path, normalizedEdits.length);\n\t}\n\n\treturn { baseContent, newContent };\n}\n\n/** Generate a standard unified patch. */\nexport function generateUnifiedPatch(path: string, oldContent: string, newContent: string, contextLines = 4): string {\n\treturn Diff.createTwoFilesPatch(path, path, oldContent, newContent, undefined, undefined, {\n\t\tcontext: contextLines,\n\t\theaderOptions: Diff.FILE_HEADERS_ONLY,\n\t});\n}\n\ninterface DiffRenderState {\n\toutput: string[];\n\toldLineNumber: number;\n\tnewLineNumber: number;\n\tlineNumberWidth: number;\n\tfirstChangedLine: number | undefined;\n}\n\nfunction getDiffPartLines(part: Diff.Change): string[] {\n\tconst lines = part.value.split(\"\\n\");\n\tif (lines.at(-1) === \"\") lines.pop();\n\treturn lines;\n}\n\nfunction appendChangedDiffLines(state: DiffRenderState, part: Diff.Change, lines: string[]): void {\n\tstate.firstChangedLine ??= state.newLineNumber;\n\tfor (const line of lines) {\n\t\tif (part.added) {\n\t\t\tconst lineNumber = String(state.newLineNumber).padStart(state.lineNumberWidth, \" \");\n\t\t\tstate.output.push(`+${lineNumber} ${line}`);\n\t\t\tstate.newLineNumber++;\n\t\t} else {\n\t\t\tconst lineNumber = String(state.oldLineNumber).padStart(state.lineNumberWidth, \" \");\n\t\t\tstate.output.push(`-${lineNumber} ${line}`);\n\t\t\tstate.oldLineNumber++;\n\t\t}\n\t}\n}\n\nfunction appendContextDiffLines(state: DiffRenderState, lines: string[]): void {\n\tfor (const line of lines) {\n\t\tconst lineNumber = String(state.oldLineNumber).padStart(state.lineNumberWidth, \" \");\n\t\tstate.output.push(` ${lineNumber} ${line}`);\n\t\tstate.oldLineNumber++;\n\t\tstate.newLineNumber++;\n\t}\n}\n\nfunction appendSkippedDiffLines(state: DiffRenderState, count: number): void {\n\tif (count <= 0) return;\n\tstate.output.push(` ${\"\".padStart(state.lineNumberWidth, \" \")} ...`);\n\tstate.oldLineNumber += count;\n\tstate.newLineNumber += count;\n}\n\nfunction appendContextBetweenChanges(state: DiffRenderState, lines: string[], contextLines: number): void {\n\tif (lines.length <= contextLines * 2) {\n\t\tappendContextDiffLines(state, lines);\n\t\treturn;\n\t}\n\tconst leadingLines = lines.slice(0, contextLines);\n\tconst trailingLines = lines.slice(lines.length - contextLines);\n\tappendContextDiffLines(state, leadingLines);\n\tappendSkippedDiffLines(state, lines.length - leadingLines.length - trailingLines.length);\n\tappendContextDiffLines(state, trailingLines);\n}\n\nfunction appendContextAfterChange(state: DiffRenderState, lines: string[], contextLines: number): void {\n\tconst shownLines = lines.slice(0, contextLines);\n\tappendContextDiffLines(state, shownLines);\n\tappendSkippedDiffLines(state, lines.length - shownLines.length);\n}\n\nfunction appendContextBeforeChange(state: DiffRenderState, lines: string[], contextLines: number): void {\n\tconst skippedLines = Math.max(0, lines.length - contextLines);\n\tappendSkippedDiffLines(state, skippedLines);\n\tappendContextDiffLines(state, lines.slice(skippedLines));\n}\n\nfunction appendUnchangedDiffPart(\n\tstate: DiffRenderState,\n\tlines: string[],\n\thasLeadingChange: boolean,\n\thasTrailingChange: boolean,\n\tcontextLines: number,\n): void {\n\tif (hasLeadingChange && hasTrailingChange) {\n\t\tappendContextBetweenChanges(state, lines, contextLines);\n\t\treturn;\n\t}\n\tif (hasLeadingChange) {\n\t\tappendContextAfterChange(state, lines, contextLines);\n\t\treturn;\n\t}\n\tif (hasTrailingChange) {\n\t\tappendContextBeforeChange(state, lines, contextLines);\n\t\treturn;\n\t}\n\tstate.oldLineNumber += lines.length;\n\tstate.newLineNumber += lines.length;\n}\n\n/**\n * Generate a display-oriented diff string with line numbers and context.\n * Returns both the diff string and the first changed line number (in the new file).\n */\nexport function generateDiffString(oldContent: string, newContent: string, contextLines = 4): EditDiffResult {\n\tconst parts = Diff.diffLines(oldContent, newContent);\n\tconst maxLineNumber = Math.max(oldContent.split(\"\\n\").length, newContent.split(\"\\n\").length);\n\tconst state: DiffRenderState = {\n\t\toutput: [],\n\t\toldLineNumber: 1,\n\t\tnewLineNumber: 1,\n\t\tlineNumberWidth: String(maxLineNumber).length,\n\t\tfirstChangedLine: undefined,\n\t};\n\tlet lastWasChange = false;\n\n\tfor (let index = 0; index < parts.length; index++) {\n\t\tconst part = parts[index];\n\t\tconst lines = getDiffPartLines(part);\n\t\tif (part.added || part.removed) {\n\t\t\tappendChangedDiffLines(state, part, lines);\n\t\t\tlastWasChange = true;\n\t\t\tcontinue;\n\t\t}\n\t\tconst nextPart = parts[index + 1];\n\t\tappendUnchangedDiffPart(\n\t\t\tstate,\n\t\t\tlines,\n\t\t\tlastWasChange,\n\t\t\tindex < parts.length - 1 && Boolean(nextPart.added || nextPart.removed),\n\t\t\tcontextLines,\n\t\t);\n\t\tlastWasChange = false;\n\t}\n\n\treturn { diff: state.output.join(\"\\n\"), firstChangedLine: state.firstChangedLine };\n}\n\n// grip-ignore noNearIdenticalDataStructures: Plain line-number diffs and hashline-anchored diffs use distinct rendering formats and evolve independently.\nexport interface EditDiffResult {\n\tdiff: string;\n\tfirstChangedLine: number | undefined;\n}\n\nexport interface EditDiffError {\n\terror: string;\n}\n\n/**\n * Compute the diff for one or more edit operations without applying them.\n * Used for preview rendering in the TUI before the tool executes.\n */\nexport async function computeEditsDiff(\n\tpath: string,\n\tedits: Edit[],\n\toperations: ToolOperations,\n): Promise<EditDiffResult | EditDiffError> {\n\tconst absolutePath = resolveToCwd(path, operations.cwd);\n\n\ttry {\n\t\t// Check if file exists and is readable\n\t\ttry {\n\t\t\tawait operations.access(absolutePath, \"read\");\n\t\t} catch (error: unknown) {\n\t\t\tconst errorMessage = error instanceof Error && \"code\" in error ? `Error code: ${error.code}` : String(error);\n\t\t\treturn { error: `Could not edit file: ${path}. ${errorMessage}.` };\n\t\t}\n\n\t\t// Read the file\n\t\tconst rawContent = (await operations.readFile(absolutePath)).toString(\"utf-8\");\n\n\t\t// Strip BOM before matching (LLM won't include invisible BOM in oldText)\n\t\tconst { text: content } = stripBOM(rawContent);\n\t\tconst normalizedContent = normalizeToLF(content);\n\t\tconst { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path);\n\n\t\t// Generate the diff\n\t\treturn generateDiffString(baseContent, newContent);\n\t} catch (err) {\n\t\treturn { error: err instanceof Error ? err.message : String(err) };\n\t}\n}\n\n/**\n * Compute the diff for a single edit operation without applying it.\n * Kept as a convenience wrapper for single-edit callers.\n */\nexport async function computeEditDiff(\n\tpath: string,\n\toldText: string,\n\tnewText: string,\n\toperations: ToolOperations,\n): Promise<EditDiffResult | EditDiffError> {\n\treturn computeEditsDiff(path, [{ oldText, newText }], operations);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../../src/core/tools/edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAGtG,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAI7D,OAAO,EAAc,KAAK,MAAM,EAAY,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKvE,OAAO,EAA2C,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAuB5F,QAAA,MAAM,UAAU;;;;;;EAQf,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AACF,UAAU,oBAAoB;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,QAAQ,GAAG;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,SAAS,GAAG,MAAM,CAAC;IACnC,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC;AAE7C,MAAM,WAAW,eAAe;CAAG;AAEnC,KAAK,eAAe,GAAG,OAAO,CAAC;AA2R/B,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CAAC;AAEjH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,kBAAkB,CA2EnH;AAED,KAAK,uBAAuB,GAAG,SAAS,CAAC,OAAO,UAAU,EAAE,eAAe,CAAC,GAAG;IAC9E,OAAO,EAAE,CACR,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,uBAAuB,CAAC,eAAe,CAAC,KAC/C,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAC;CAC/C,CAAC;AAEF,wBAAgB,cAAc,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,uBAAuB,CAE7G","sourcesContent":["import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from \"@greppleai/grip-agent-core\";\nimport { Text } from \"@greppleai/grip-tui\";\nimport { createTwoFilesPatch } from \"diff\";\nimport { type Static, Type } from \"typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { type ApplyEditsResult, applyEdits, fmtBoundaryWarning } from \"./hashline/apply.ts\";\nimport { initHasher, lineHashes } from \"./hashline/hash.ts\";\nimport { type HEdit, type HTEdit, resEdits } from \"./hashline/resolve.ts\";\nimport type { ToolBackendInfo, ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { formatBackendIcon, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { detectEnding, genDiff, type LineEnding, restoreEndings, stripBOM, toLF } from \"./replace-diff.ts\";\nimport { normReq } from \"./replace-normalize.ts\";\nimport { fmtCall, getPreviewInput, type RPreview, type RRState } from \"./replace-render.ts\";\nimport { abortIf } from \"./runtime.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst contentLinesSchema = Type.Array(Type.String(), {\n\tdescription:\n\t\t\"Literal replacement content, one string per line. Use [] to delete the range. Do not include HASH│ prefixes from read output.\",\n});\n\nconst hashRangeInclusiveSchema = Type.Array(Type.String(), {\n\tdescription: \"Inclusive hash range to replace [start_hash, end_hash]. Use hash anchors only.\",\n\tminItems: 2,\n\tmaxItems: 2,\n});\n\nconst editItemSchema = Type.Object(\n\t{\n\t\thash_range_inclusive: hashRangeInclusiveSchema,\n\t\tcontent_lines: contentLinesSchema,\n\t},\n\t{ additionalProperties: false },\n);\n\nconst editSchema = Type.Object(\n\t{\n\t\tpath: Type.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n\t\tchanges: Type.Array(editItemSchema, {\n\t\t\tdescription: \"One or more hash-anchored replacements. All anchors must come from the same read snapshot.\",\n\t\t}),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport type EditToolInput = Static<typeof editSchema>;\n\nexport type ReqParams = {\n\tpath: string;\n\tchanges: HTEdit[];\n};\ninterface EditChangedLineRange {\n\tfirst: number;\n\tlast: number;\n}\n\nexport type RMetrics = {\n\tedits_attempted: number;\n\tedits_noop: number;\n\twarnings: number;\n\tclassification: \"applied\" | \"noop\";\n\tchanged_lines?: EditChangedLineRange;\n\tadded_lines?: number;\n\tremoved_lines?: number;\n};\n\nexport interface ReplaceDetails {\n\tdiff: string;\n\tpatch: string;\n\tfirstChangedLine?: number;\n\tclassification?: \"noop\";\n\tmetrics?: RMetrics;\n}\n\nexport type EditToolDetails = ReplaceDetails;\n\nexport interface EditToolOptions {}\n\ntype EditRenderState = RRState;\ntype DiffLineMarker = \"+\" | \"-\";\n\ntype RenderableEditArgs = {\n\tpath?: string;\n\tfile_path?: string;\n\tchanges?: HTEdit[];\n\tedits?: HTEdit[];\n\thash_range_inclusive?: [string, string];\n\tcontent_lines?: string[];\n};\n\nfunction countDiffLines(diff: string, marker: DiffLineMarker): number {\n\tlet count = 0;\n\tfor (const line of diff.split(\"\\n\")) {\n\t\tif (line.startsWith(marker) && !line.startsWith(`${marker}${marker}${marker}`)) {\n\t\t\tcount++;\n\t\t}\n\t}\n\treturn count;\n}\n\nfunction hashStoreKey(operations: ToolOperations, absolutePath: string): string {\n\tconst backend = operations.getBackendInfo?.();\n\tif (!backend) return absolutePath;\n\tif (backend.type === \"remote\" && backend.configured) return `remote:${backend.url}:${absolutePath}`;\n\treturn absolutePath;\n}\n\nfunction formatEditCall(\n\targs: RenderableEditArgs | undefined,\n\ttheme: Theme,\n\tbackendInfo: ToolBackendInfo | undefined,\n): string {\n\tconst previewInput = getPreviewInput(args);\n\tif (previewInput) {\n\t\treturn formatBackendIcon(backendInfo, theme) + fmtCall(previewInput, {}, false, theme).replace(\"replace\", \"edit\");\n\t}\n\tconst invalidArg = invalidArgText(theme);\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath) : null;\n\tconst pathDisplay = path === null ? invalidArg : path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\treturn `${formatBackendIcon(backendInfo, theme)}${theme.fg(\"toolTitle\", theme.bold(\"edit\"))} ${pathDisplay}`;\n}\n\nasync function computePreview(request: ReqParams, operations: ToolOperations): Promise<RPreview> {\n\ttry {\n\t\tawait initHasher();\n\t\tconst absolutePath = resolveToCwd(request.path, operations.cwd);\n\t\tawait operations.access(absolutePath, \"read\");\n\t\tconst rawContent = (await operations.readFile(absolutePath)).toString(\"utf-8\");\n\t\tconst { text } = stripBOM(rawContent);\n\t\tconst originalNormalized = toLF(text);\n\t\tconst originalHashes = await lineHashes(originalNormalized, hashStoreKey(operations, absolutePath));\n\t\tconst result = applyEdits(\n\t\t\toriginalNormalized,\n\t\t\tresEdits(request.changes),\n\t\t\tundefined,\n\t\t\toriginalHashes,\n\t\t\trequest.path,\n\t\t).content;\n\t\tif (originalNormalized === result) {\n\t\t\treturn { error: `No changes made to ${request.path}. The edits produced identical content.` };\n\t\t}\n\t\tconst resultHashes = await lineHashes(result);\n\t\treturn { diff: genDiff(originalNormalized, result, 4, resultHashes, originalHashes).diff };\n\t} catch (error) {\n\t\treturn { error: error instanceof Error ? error.message : String(error) };\n\t}\n}\n\nfunction normalizeEditArguments(input: unknown): EditToolInput {\n\treturn normReq(input) as EditToolInput;\n}\n\nfunction assertReq(request: unknown): asserts request is ReqParams {\n\tif (!request || typeof request !== \"object\" || Array.isArray(request)) {\n\t\tthrow new Error(\"[E_BAD_SHAPE] Edit request must be an object.\");\n\t}\n\tconst record = request as Record<string, unknown>;\n\tfor (const legacyKey of [\"oldText\", \"newText\", \"old_text\", \"new_text\", \"old_range\", \"start\", \"end\", \"lines\"]) {\n\t\tif (Object.hasOwn(record, legacyKey)) {\n\t\t\tthrow new Error(\n\t\t\t\t`[E_LEGACY_SHAPE] \"${legacyKey}\" is not supported. Call read first, then use {hash_range_inclusive: [\"<START>\", \"<END>\"], content_lines: [...]}.`,\n\t\t\t);\n\t\t}\n\t}\n\tconst unknown = Object.keys(record).filter((key) => key !== \"path\" && key !== \"changes\");\n\tif (unknown.length > 0) {\n\t\tthrow new Error(`[E_BAD_SHAPE] Edit request contains unknown or unsupported fields: ${unknown.join(\", \")}.`);\n\t}\n\tif (typeof record.path !== \"string\" || record.path.length === 0) {\n\t\tthrow new Error('[E_BAD_SHAPE] Edit request requires a non-empty \"path\" string.');\n\t}\n\tif (!Array.isArray(record.changes) || record.changes.length === 0) {\n\t\tthrow new Error('[E_BAD_SHAPE] Edit request requires a non-empty \"changes\" array.');\n\t}\n}\ninterface EditSourceSnapshot {\n\tbom: string;\n\toriginalEnding: LineEnding;\n\toriginalContent: string;\n\toriginalHashes: string[];\n\tstoreKey: string;\n}\n\ninterface AppliedEditResultOptions {\n\tpath: string;\n\teditCount: number;\n\tanchorResult: ApplyEditsResult;\n\twarnings: string[];\n\toriginalContent: string;\n\tresultContent: string;\n\toriginalHashes: string[];\n\tresultHashes: string[];\n}\n\nasync function readEditSource(\n\tpath: string,\n\tabsolutePath: string,\n\toperations: ToolOperations,\n): Promise<EditSourceSnapshot> {\n\ttry {\n\t\tawait operations.access(absolutePath, \"readwrite\");\n\t} catch (error) {\n\t\tconst message = error instanceof Error && \"code\" in error ? `Error code: ${String(error.code)}` : String(error);\n\t\tthrow new Error(`Could not edit file: ${path}. ${message}.`);\n\t}\n\tconst rawContent = (await operations.readFile(absolutePath)).toString(\"utf-8\");\n\tconst { bom, text } = stripBOM(rawContent);\n\tconst originalContent = toLF(text);\n\tconst storeKey = hashStoreKey(operations, absolutePath);\n\treturn {\n\t\tbom,\n\t\toriginalEnding: detectEnding(text),\n\t\toriginalContent,\n\t\toriginalHashes: await lineHashes(originalContent, storeKey),\n\t\tstoreKey,\n\t};\n}\n\nfunction collectRemovedHashes(edits: HEdit[], originalHashes: string[]): Set<string> {\n\tconst hashIndexes = new Map<string, number>();\n\tfor (let index = 0; index < originalHashes.length; index++) {\n\t\tconst hash = originalHashes[index];\n\t\tif (hash !== undefined && !hashIndexes.has(hash)) hashIndexes.set(hash, index);\n\t}\n\tconst removedHashes = new Set<string>();\n\tfor (const edit of edits) {\n\t\tconst startLine = hashIndexes.get(edit.hash_range_inclusive[0].hash) ?? -1;\n\t\tconst endLine = hashIndexes.get(edit.hash_range_inclusive[1].hash) ?? -1;\n\t\tif (startLine < 0 || endLine < 0) continue;\n\t\tfor (let index = startLine; index <= endLine; index++) {\n\t\t\tconst hash = originalHashes[index];\n\t\t\tif (hash) removedHashes.add(hash);\n\t\t}\n\t}\n\treturn removedHashes;\n}\n\nfunction indexLineOccurrences(lines: string[]): Map<string, number[]> {\n\tconst indexesByLine = new Map<string, number[]>();\n\tfor (let index = 0; index < lines.length; index++) {\n\t\tconst line = lines[index];\n\t\tconst indexes = indexesByLine.get(line);\n\t\tif (indexes) indexes.push(index);\n\t\telse indexesByLine.set(line, [index]);\n\t}\n\treturn indexesByLine;\n}\n\nfunction collectEditWarnings(anchorResult: ApplyEditsResult, resultContent: string, resultHashes: string[]): string[] {\n\tconst warnings = [...(anchorResult.warnings ?? [])];\n\tconst resultLines = resultContent.split(\"\\n\");\n\tconst indexesByLine = indexLineOccurrences(resultLines);\n\tfor (const warning of anchorResult.boundaryWarnings ?? []) {\n\t\tconst matchIndex = indexesByLine.get(warning.survivingLineContent)?.[warning.occurrence] ?? -1;\n\t\tif (matchIndex < 0) continue;\n\t\twarnings.push(\n\t\t\tfmtBoundaryWarning({\n\t\t\t\tkind: warning.kind,\n\t\t\t\tsurvivingContent: warning.survivingLineContent,\n\t\t\t\tmatchIndex,\n\t\t\t\tresultLines,\n\t\t\t\tresultHashes,\n\t\t\t}),\n\t\t);\n\t}\n\treturn warnings;\n}\n\nfunction buildNoopEditResult(\n\tpath: string,\n\teditCount: number,\n\tanchorResult: ApplyEditsResult,\n\twarnings: string[],\n): AgentToolResult<EditToolDetails> {\n\treturn {\n\t\tcontent: [{ type: \"text\", text: `No changes made to ${path}. The edits produced identical content.` }],\n\t\tdetails: {\n\t\t\tdiff: \"\",\n\t\t\tpatch: \"\",\n\t\t\tclassification: \"noop\",\n\t\t\tmetrics: {\n\t\t\t\tedits_attempted: editCount,\n\t\t\t\tedits_noop: anchorResult.noopEdits?.length ?? 0,\n\t\t\t\twarnings: warnings.length,\n\t\t\t\tclassification: \"noop\",\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction buildAppliedEditResult(options: AppliedEditResultOptions): AgentToolResult<EditToolDetails> {\n\tconst diffResult = genDiff(\n\t\toptions.originalContent,\n\t\toptions.resultContent,\n\t\t2,\n\t\toptions.resultHashes,\n\t\toptions.originalHashes,\n\t);\n\tconst warningBlock = options.warnings.length > 0 ? `\\n\\nWarnings:\\n${options.warnings.join(\"\\n\")}` : \"\";\n\tconst changedLines =\n\t\toptions.anchorResult.firstChangedLine !== undefined && options.anchorResult.lastChangedLine !== undefined\n\t\t\t? {\n\t\t\t\t\tfirst: options.anchorResult.firstChangedLine,\n\t\t\t\t\tlast: options.anchorResult.lastChangedLine,\n\t\t\t\t}\n\t\t\t: undefined;\n\treturn {\n\t\tcontent: [{ type: \"text\", text: `Successfully replaced in ${options.path}.${warningBlock}` }],\n\t\tdetails: {\n\t\t\tdiff: diffResult.diff,\n\t\t\tpatch: createTwoFilesPatch(options.path, options.path, options.originalContent, options.resultContent),\n\t\t\tfirstChangedLine: options.anchorResult.firstChangedLine ?? diffResult.firstChangedLine,\n\t\t\tmetrics: {\n\t\t\t\tedits_attempted: options.editCount,\n\t\t\t\tedits_noop: options.anchorResult.noopEdits?.length ?? 0,\n\t\t\t\twarnings: options.warnings.length,\n\t\t\t\tclassification: \"applied\",\n\t\t\t\t...(changedLines ? { changed_lines: changedLines } : {}),\n\t\t\t\tadded_lines: countDiffLines(diffResult.diff, \"+\"),\n\t\t\t\tremoved_lines: countDiffLines(diffResult.diff, \"-\"),\n\t\t\t},\n\t\t},\n\t};\n}\n\nasync function executeEditMutation(\n\trequest: ReqParams,\n\tabsolutePath: string,\n\toperations: ToolOperations,\n\tsignal: AbortSignal | undefined,\n): Promise<AgentToolResult<EditToolDetails>> {\n\tabortIf(signal);\n\tawait initHasher();\n\tconst source = await readEditSource(request.path, absolutePath, operations);\n\tconst resolvedEdits = resEdits(request.changes);\n\tconst anchorResult = applyEdits(source.originalContent, resolvedEdits, signal, source.originalHashes, request.path);\n\tconst resultContent = anchorResult.content;\n\tconst resultHashes = await lineHashes(resultContent, source.storeKey, {\n\t\tcontent: source.originalContent,\n\t\thashes: source.originalHashes,\n\t\tremovedHashes: collectRemovedHashes(resolvedEdits, source.originalHashes),\n\t});\n\tconst warnings = collectEditWarnings(anchorResult, resultContent, resultHashes);\n\tif (source.originalContent === resultContent) {\n\t\treturn buildNoopEditResult(request.path, request.changes.length, anchorResult, warnings);\n\t}\n\tabortIf(signal);\n\tawait operations.writeFile(absolutePath, source.bom + restoreEndings(resultContent, source.originalEnding));\n\treturn buildAppliedEditResult({\n\t\tpath: request.path,\n\t\teditCount: request.changes.length,\n\t\tanchorResult,\n\t\twarnings,\n\t\toriginalContent: source.originalContent,\n\t\tresultContent,\n\t\toriginalHashes: source.originalHashes,\n\t\tresultHashes,\n\t});\n}\n\nexport type EditToolDefinition = ToolDefinition<typeof editSchema, EditToolDetails | undefined, EditRenderState>;\n\nexport function createEditToolDefinition(operations: ToolOperations, _options?: EditToolOptions): EditToolDefinition {\n\treturn {\n\t\tname: \"edit\",\n\t\tlabel: \"edit\",\n\t\tdescription:\n\t\t\t\"Edit a file using hash-anchored line replacements. Call read first; it returns HASH│content lines. Use hash_range_inclusive with the 3-character start/end hashes and content_lines with literal replacement lines only.\",\n\t\tpromptSnippet: \"Edit files using hashline anchors from read output\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use read before edit to get HASH│content anchors.\",\n\t\t\t\"Use edit with changes: [{ hash_range_inclusive: [startHash, endHash], content_lines: [...] }].\",\n\t\t\t\"hash_range_inclusive contains only the 3-character hashes, not line numbers and not HASH│content.\",\n\t\t\t\"content_lines contains literal file content only; do not include HASH│ prefixes. Use [] to delete a range.\",\n\t\t\t\"After a successful edit, call read again before follow-up edits unless the response includes current warning anchors.\",\n\t\t],\n\t\tparameters: editSchema,\n\t\trenderShell: \"default\",\n\t\tprepareArguments: normalizeEditArguments,\n\t\tasync execute(_toolCallId, input: EditToolInput, signal?: AbortSignal) {\n\t\t\tconst normalized = normReq(input);\n\t\t\tassertReq(normalized);\n\t\t\tconst absolutePath = resolveToCwd(normalized.path, operations.cwd);\n\t\t\treturn withFileMutationQueue(absolutePath, () =>\n\t\t\t\texecuteEditMutation(normalized, absolutePath, operations, signal),\n\t\t\t);\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tconst previewInput = getPreviewInput(args);\n\t\t\tif (!context.executionStarted && context.argsComplete && previewInput) {\n\t\t\t\tconst argsKey = JSON.stringify(previewInput);\n\t\t\t\tif (context.state.argsKey !== argsKey) {\n\t\t\t\t\tcontext.state.argsKey = argsKey;\n\t\t\t\t\tcontext.state.preview = undefined;\n\t\t\t\t\tconst generation = (context.state.previewGeneration ?? 0) + 1;\n\t\t\t\t\tcontext.state.previewGeneration = generation;\n\t\t\t\t\tvoid computePreview(previewInput, operations).then((preview) => {\n\t\t\t\t\t\tif (context.state.argsKey === argsKey && context.state.previewGeneration === generation) {\n\t\t\t\t\t\t\tcontext.state.preview = preview;\n\t\t\t\t\t\t\tcontext.invalidate();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\ttext.setText(\n\t\t\t\t\tformatBackendIcon(operations.getBackendInfo?.(), theme) +\n\t\t\t\t\t\tfmtCall(previewInput, context.state, context.expanded, theme).replace(\"replace\", \"edit\"),\n\t\t\t\t);\n\t\t\t\treturn text;\n\t\t\t}\n\t\t\ttext.setText(formatEditCall(args as RenderableEditArgs | undefined, theme, operations.getBackendInfo?.()));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, _options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tif (context.isError) {\n\t\t\t\tconst errorText = result.content\n\t\t\t\t\t?.filter((entry) => entry.type === \"text\")\n\t\t\t\t\t.map((entry) => entry.text ?? \"\")\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\ttext.setText(errorText ? `\\n${theme.fg(\"error\", errorText)}` : \"\");\n\t\t\t\treturn text;\n\t\t\t}\n\t\t\tconst diff = result.details?.diff;\n\t\t\tif (!diff) {\n\t\t\t\ttext.setText(\"\");\n\t\t\t\treturn text;\n\t\t\t}\n\t\t\tconst lines = diff.split(\"\\n\").map((line) => {\n\t\t\t\tif (line.startsWith(\"+\") && !line.startsWith(\"+++\")) return theme.fg(\"success\", line);\n\t\t\t\tif (line.startsWith(\"-\") && !line.startsWith(\"---\")) return theme.fg(\"error\", line);\n\t\t\t\treturn theme.fg(\"dim\", line);\n\t\t\t});\n\t\t\ttext.setText(`\\n${lines.join(\"\\n\")}`);\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\ntype CompatibleEditAgentTool = AgentTool<typeof editSchema, EditToolDetails> & {\n\texecute: (\n\t\ttoolCallId: string,\n\t\tparams: Record<string, unknown>,\n\t\tsignal?: AbortSignal,\n\t\tonUpdate?: AgentToolUpdateCallback<EditToolDetails>,\n\t) => Promise<AgentToolResult<EditToolDetails>>;\n};\n\nexport function createEditTool(operations: ToolOperations, options?: EditToolOptions): CompatibleEditAgentTool {\n\treturn wrapToolDefinition(createEditToolDefinition(operations, options)) as CompatibleEditAgentTool;\n}\n"]}
1
+ {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../../src/core/tools/edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAGtG,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAI7D,OAAO,EAAc,KAAK,MAAM,EAAY,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKvE,OAAO,EAA2C,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAuB5F,QAAA,MAAM,UAAU;;;;;;EAQf,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,MAAM,SAAS,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AACF,UAAU,oBAAoB;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,QAAQ,GAAG;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,SAAS,GAAG,MAAM,CAAC;IACnC,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC;AAE7C,MAAM,WAAW,eAAe;CAAG;AAEnC,KAAK,eAAe,GAAG,OAAO,CAAC;AA2R/B,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CAAC;AAEjH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,kBAAkB,CA2EnH;AAED,KAAK,uBAAuB,GAAG,SAAS,CAAC,OAAO,UAAU,EAAE,eAAe,CAAC,GAAG;IAC9E,OAAO,EAAE,CACR,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,uBAAuB,CAAC,eAAe,CAAC,KAC/C,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAC;CAC/C,CAAC;AAEF,wBAAgB,cAAc,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,uBAAuB,CAE7G"}
@@ -1 +1 @@
1
- {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/core/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from \"@greppleai/grip-agent-core\";\nimport { Text } from \"@greppleai/grip-tui\";\nimport { createTwoFilesPatch } from \"diff\";\nimport { type Static, Type } from \"typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { type ApplyEditsResult, applyEdits, fmtBoundaryWarning } from \"./hashline/apply.ts\";\nimport { initHasher, lineHashes } from \"./hashline/hash.ts\";\nimport { type HEdit, type HTEdit, resEdits } from \"./hashline/resolve.ts\";\nimport type { ToolBackendInfo, ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { formatBackendIcon, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { detectEnding, genDiff, type LineEnding, restoreEndings, stripBOM, toLF } from \"./replace-diff.ts\";\nimport { normReq } from \"./replace-normalize.ts\";\nimport { fmtCall, getPreviewInput, type RPreview, type RRState } from \"./replace-render.ts\";\nimport { abortIf } from \"./runtime.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst contentLinesSchema = Type.Array(Type.String(), {\n\tdescription:\n\t\t\"Literal replacement content, one string per line. Use [] to delete the range. Do not include HASH│ prefixes from read output.\",\n});\n\nconst hashRangeInclusiveSchema = Type.Array(Type.String(), {\n\tdescription: \"Inclusive hash range to replace [start_hash, end_hash]. Use hash anchors only.\",\n\tminItems: 2,\n\tmaxItems: 2,\n});\n\nconst editItemSchema = Type.Object(\n\t{\n\t\thash_range_inclusive: hashRangeInclusiveSchema,\n\t\tcontent_lines: contentLinesSchema,\n\t},\n\t{ additionalProperties: false },\n);\n\nconst editSchema = Type.Object(\n\t{\n\t\tpath: Type.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n\t\tchanges: Type.Array(editItemSchema, {\n\t\t\tdescription: \"One or more hash-anchored replacements. All anchors must come from the same read snapshot.\",\n\t\t}),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport type EditToolInput = Static<typeof editSchema>;\n\nexport type ReqParams = {\n\tpath: string;\n\tchanges: HTEdit[];\n};\ninterface EditChangedLineRange {\n\tfirst: number;\n\tlast: number;\n}\n\nexport type RMetrics = {\n\tedits_attempted: number;\n\tedits_noop: number;\n\twarnings: number;\n\tclassification: \"applied\" | \"noop\";\n\tchanged_lines?: EditChangedLineRange;\n\tadded_lines?: number;\n\tremoved_lines?: number;\n};\n\nexport interface ReplaceDetails {\n\tdiff: string;\n\tpatch: string;\n\tfirstChangedLine?: number;\n\tclassification?: \"noop\";\n\tmetrics?: RMetrics;\n}\n\nexport type EditToolDetails = ReplaceDetails;\n\nexport interface EditToolOptions {}\n\ntype EditRenderState = RRState;\ntype DiffLineMarker = \"+\" | \"-\";\n\ntype RenderableEditArgs = {\n\tpath?: string;\n\tfile_path?: string;\n\tchanges?: HTEdit[];\n\tedits?: HTEdit[];\n\thash_range_inclusive?: [string, string];\n\tcontent_lines?: string[];\n};\n\nfunction countDiffLines(diff: string, marker: DiffLineMarker): number {\n\tlet count = 0;\n\tfor (const line of diff.split(\"\\n\")) {\n\t\tif (line.startsWith(marker) && !line.startsWith(`${marker}${marker}${marker}`)) {\n\t\t\tcount++;\n\t\t}\n\t}\n\treturn count;\n}\n\nfunction hashStoreKey(operations: ToolOperations, absolutePath: string): string {\n\tconst backend = operations.getBackendInfo?.();\n\tif (!backend) return absolutePath;\n\tif (backend.type === \"remote\" && backend.configured) return `remote:${backend.url}:${absolutePath}`;\n\treturn absolutePath;\n}\n\nfunction formatEditCall(\n\targs: RenderableEditArgs | undefined,\n\ttheme: Theme,\n\tbackendInfo: ToolBackendInfo | undefined,\n): string {\n\tconst previewInput = getPreviewInput(args);\n\tif (previewInput) {\n\t\treturn formatBackendIcon(backendInfo, theme) + fmtCall(previewInput, {}, false, theme).replace(\"replace\", \"edit\");\n\t}\n\tconst invalidArg = invalidArgText(theme);\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath) : null;\n\tconst pathDisplay = path === null ? invalidArg : path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\treturn `${formatBackendIcon(backendInfo, theme)}${theme.fg(\"toolTitle\", theme.bold(\"edit\"))} ${pathDisplay}`;\n}\n\nasync function computePreview(request: ReqParams, operations: ToolOperations): Promise<RPreview> {\n\ttry {\n\t\tawait initHasher();\n\t\tconst absolutePath = resolveToCwd(request.path, operations.cwd);\n\t\tawait operations.access(absolutePath, \"read\");\n\t\tconst rawContent = (await operations.readFile(absolutePath)).toString(\"utf-8\");\n\t\tconst { text } = stripBOM(rawContent);\n\t\tconst originalNormalized = toLF(text);\n\t\tconst originalHashes = await lineHashes(originalNormalized, hashStoreKey(operations, absolutePath));\n\t\tconst result = applyEdits(\n\t\t\toriginalNormalized,\n\t\t\tresEdits(request.changes),\n\t\t\tundefined,\n\t\t\toriginalHashes,\n\t\t\trequest.path,\n\t\t).content;\n\t\tif (originalNormalized === result) {\n\t\t\treturn { error: `No changes made to ${request.path}. The edits produced identical content.` };\n\t\t}\n\t\tconst resultHashes = await lineHashes(result);\n\t\treturn { diff: genDiff(originalNormalized, result, 4, resultHashes, originalHashes).diff };\n\t} catch (error) {\n\t\treturn { error: error instanceof Error ? error.message : String(error) };\n\t}\n}\n\nfunction normalizeEditArguments(input: unknown): EditToolInput {\n\treturn normReq(input) as EditToolInput;\n}\n\nfunction assertReq(request: unknown): asserts request is ReqParams {\n\tif (!request || typeof request !== \"object\" || Array.isArray(request)) {\n\t\tthrow new Error(\"[E_BAD_SHAPE] Edit request must be an object.\");\n\t}\n\tconst record = request as Record<string, unknown>;\n\tfor (const legacyKey of [\"oldText\", \"newText\", \"old_text\", \"new_text\", \"old_range\", \"start\", \"end\", \"lines\"]) {\n\t\tif (Object.hasOwn(record, legacyKey)) {\n\t\t\tthrow new Error(\n\t\t\t\t`[E_LEGACY_SHAPE] \"${legacyKey}\" is not supported. Call read first, then use {hash_range_inclusive: [\"<START>\", \"<END>\"], content_lines: [...]}.`,\n\t\t\t);\n\t\t}\n\t}\n\tconst unknown = Object.keys(record).filter((key) => key !== \"path\" && key !== \"changes\");\n\tif (unknown.length > 0) {\n\t\tthrow new Error(`[E_BAD_SHAPE] Edit request contains unknown or unsupported fields: ${unknown.join(\", \")}.`);\n\t}\n\tif (typeof record.path !== \"string\" || record.path.length === 0) {\n\t\tthrow new Error('[E_BAD_SHAPE] Edit request requires a non-empty \"path\" string.');\n\t}\n\tif (!Array.isArray(record.changes) || record.changes.length === 0) {\n\t\tthrow new Error('[E_BAD_SHAPE] Edit request requires a non-empty \"changes\" array.');\n\t}\n}\ninterface EditSourceSnapshot {\n\tbom: string;\n\toriginalEnding: LineEnding;\n\toriginalContent: string;\n\toriginalHashes: string[];\n\tstoreKey: string;\n}\n\ninterface AppliedEditResultOptions {\n\tpath: string;\n\teditCount: number;\n\tanchorResult: ApplyEditsResult;\n\twarnings: string[];\n\toriginalContent: string;\n\tresultContent: string;\n\toriginalHashes: string[];\n\tresultHashes: string[];\n}\n\nasync function readEditSource(\n\tpath: string,\n\tabsolutePath: string,\n\toperations: ToolOperations,\n): Promise<EditSourceSnapshot> {\n\ttry {\n\t\tawait operations.access(absolutePath, \"readwrite\");\n\t} catch (error) {\n\t\tconst message = error instanceof Error && \"code\" in error ? `Error code: ${String(error.code)}` : String(error);\n\t\tthrow new Error(`Could not edit file: ${path}. ${message}.`);\n\t}\n\tconst rawContent = (await operations.readFile(absolutePath)).toString(\"utf-8\");\n\tconst { bom, text } = stripBOM(rawContent);\n\tconst originalContent = toLF(text);\n\tconst storeKey = hashStoreKey(operations, absolutePath);\n\treturn {\n\t\tbom,\n\t\toriginalEnding: detectEnding(text),\n\t\toriginalContent,\n\t\toriginalHashes: await lineHashes(originalContent, storeKey),\n\t\tstoreKey,\n\t};\n}\n\nfunction collectRemovedHashes(edits: HEdit[], originalHashes: string[]): Set<string> {\n\tconst hashIndexes = new Map<string, number>();\n\tfor (let index = 0; index < originalHashes.length; index++) {\n\t\tconst hash = originalHashes[index];\n\t\tif (hash !== undefined && !hashIndexes.has(hash)) hashIndexes.set(hash, index);\n\t}\n\tconst removedHashes = new Set<string>();\n\tfor (const edit of edits) {\n\t\tconst startLine = hashIndexes.get(edit.hash_range_inclusive[0].hash) ?? -1;\n\t\tconst endLine = hashIndexes.get(edit.hash_range_inclusive[1].hash) ?? -1;\n\t\tif (startLine < 0 || endLine < 0) continue;\n\t\tfor (let index = startLine; index <= endLine; index++) {\n\t\t\tconst hash = originalHashes[index];\n\t\t\tif (hash) removedHashes.add(hash);\n\t\t}\n\t}\n\treturn removedHashes;\n}\n\nfunction indexLineOccurrences(lines: string[]): Map<string, number[]> {\n\tconst indexesByLine = new Map<string, number[]>();\n\tfor (let index = 0; index < lines.length; index++) {\n\t\tconst line = lines[index];\n\t\tconst indexes = indexesByLine.get(line);\n\t\tif (indexes) indexes.push(index);\n\t\telse indexesByLine.set(line, [index]);\n\t}\n\treturn indexesByLine;\n}\n\nfunction collectEditWarnings(anchorResult: ApplyEditsResult, resultContent: string, resultHashes: string[]): string[] {\n\tconst warnings = [...(anchorResult.warnings ?? [])];\n\tconst resultLines = resultContent.split(\"\\n\");\n\tconst indexesByLine = indexLineOccurrences(resultLines);\n\tfor (const warning of anchorResult.boundaryWarnings ?? []) {\n\t\tconst matchIndex = indexesByLine.get(warning.survivingLineContent)?.[warning.occurrence] ?? -1;\n\t\tif (matchIndex < 0) continue;\n\t\twarnings.push(\n\t\t\tfmtBoundaryWarning({\n\t\t\t\tkind: warning.kind,\n\t\t\t\tsurvivingContent: warning.survivingLineContent,\n\t\t\t\tmatchIndex,\n\t\t\t\tresultLines,\n\t\t\t\tresultHashes,\n\t\t\t}),\n\t\t);\n\t}\n\treturn warnings;\n}\n\nfunction buildNoopEditResult(\n\tpath: string,\n\teditCount: number,\n\tanchorResult: ApplyEditsResult,\n\twarnings: string[],\n): AgentToolResult<EditToolDetails> {\n\treturn {\n\t\tcontent: [{ type: \"text\", text: `No changes made to ${path}. The edits produced identical content.` }],\n\t\tdetails: {\n\t\t\tdiff: \"\",\n\t\t\tpatch: \"\",\n\t\t\tclassification: \"noop\",\n\t\t\tmetrics: {\n\t\t\t\tedits_attempted: editCount,\n\t\t\t\tedits_noop: anchorResult.noopEdits?.length ?? 0,\n\t\t\t\twarnings: warnings.length,\n\t\t\t\tclassification: \"noop\",\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction buildAppliedEditResult(options: AppliedEditResultOptions): AgentToolResult<EditToolDetails> {\n\tconst diffResult = genDiff(\n\t\toptions.originalContent,\n\t\toptions.resultContent,\n\t\t2,\n\t\toptions.resultHashes,\n\t\toptions.originalHashes,\n\t);\n\tconst warningBlock = options.warnings.length > 0 ? `\\n\\nWarnings:\\n${options.warnings.join(\"\\n\")}` : \"\";\n\tconst changedLines =\n\t\toptions.anchorResult.firstChangedLine !== undefined && options.anchorResult.lastChangedLine !== undefined\n\t\t\t? {\n\t\t\t\t\tfirst: options.anchorResult.firstChangedLine,\n\t\t\t\t\tlast: options.anchorResult.lastChangedLine,\n\t\t\t\t}\n\t\t\t: undefined;\n\treturn {\n\t\tcontent: [{ type: \"text\", text: `Successfully replaced in ${options.path}.${warningBlock}` }],\n\t\tdetails: {\n\t\t\tdiff: diffResult.diff,\n\t\t\tpatch: createTwoFilesPatch(options.path, options.path, options.originalContent, options.resultContent),\n\t\t\tfirstChangedLine: options.anchorResult.firstChangedLine ?? diffResult.firstChangedLine,\n\t\t\tmetrics: {\n\t\t\t\tedits_attempted: options.editCount,\n\t\t\t\tedits_noop: options.anchorResult.noopEdits?.length ?? 0,\n\t\t\t\twarnings: options.warnings.length,\n\t\t\t\tclassification: \"applied\",\n\t\t\t\t...(changedLines ? { changed_lines: changedLines } : {}),\n\t\t\t\tadded_lines: countDiffLines(diffResult.diff, \"+\"),\n\t\t\t\tremoved_lines: countDiffLines(diffResult.diff, \"-\"),\n\t\t\t},\n\t\t},\n\t};\n}\n\nasync function executeEditMutation(\n\trequest: ReqParams,\n\tabsolutePath: string,\n\toperations: ToolOperations,\n\tsignal: AbortSignal | undefined,\n): Promise<AgentToolResult<EditToolDetails>> {\n\tabortIf(signal);\n\tawait initHasher();\n\tconst source = await readEditSource(request.path, absolutePath, operations);\n\tconst resolvedEdits = resEdits(request.changes);\n\tconst anchorResult = applyEdits(source.originalContent, resolvedEdits, signal, source.originalHashes, request.path);\n\tconst resultContent = anchorResult.content;\n\tconst resultHashes = await lineHashes(resultContent, source.storeKey, {\n\t\tcontent: source.originalContent,\n\t\thashes: source.originalHashes,\n\t\tremovedHashes: collectRemovedHashes(resolvedEdits, source.originalHashes),\n\t});\n\tconst warnings = collectEditWarnings(anchorResult, resultContent, resultHashes);\n\tif (source.originalContent === resultContent) {\n\t\treturn buildNoopEditResult(request.path, request.changes.length, anchorResult, warnings);\n\t}\n\tabortIf(signal);\n\tawait operations.writeFile(absolutePath, source.bom + restoreEndings(resultContent, source.originalEnding));\n\treturn buildAppliedEditResult({\n\t\tpath: request.path,\n\t\teditCount: request.changes.length,\n\t\tanchorResult,\n\t\twarnings,\n\t\toriginalContent: source.originalContent,\n\t\tresultContent,\n\t\toriginalHashes: source.originalHashes,\n\t\tresultHashes,\n\t});\n}\n\nexport type EditToolDefinition = ToolDefinition<typeof editSchema, EditToolDetails | undefined, EditRenderState>;\n\nexport function createEditToolDefinition(operations: ToolOperations, _options?: EditToolOptions): EditToolDefinition {\n\treturn {\n\t\tname: \"edit\",\n\t\tlabel: \"edit\",\n\t\tdescription:\n\t\t\t\"Edit a file using hash-anchored line replacements. Call read first; it returns HASH│content lines. Use hash_range_inclusive with the 3-character start/end hashes and content_lines with literal replacement lines only.\",\n\t\tpromptSnippet: \"Edit files using hashline anchors from read output\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use read before edit to get HASH│content anchors.\",\n\t\t\t\"Use edit with changes: [{ hash_range_inclusive: [startHash, endHash], content_lines: [...] }].\",\n\t\t\t\"hash_range_inclusive contains only the 3-character hashes, not line numbers and not HASH│content.\",\n\t\t\t\"content_lines contains literal file content only; do not include HASH│ prefixes. Use [] to delete a range.\",\n\t\t\t\"After a successful edit, call read again before follow-up edits unless the response includes current warning anchors.\",\n\t\t],\n\t\tparameters: editSchema,\n\t\trenderShell: \"default\",\n\t\tprepareArguments: normalizeEditArguments,\n\t\tasync execute(_toolCallId, input: EditToolInput, signal?: AbortSignal) {\n\t\t\tconst normalized = normReq(input);\n\t\t\tassertReq(normalized);\n\t\t\tconst absolutePath = resolveToCwd(normalized.path, operations.cwd);\n\t\t\treturn withFileMutationQueue(absolutePath, () =>\n\t\t\t\texecuteEditMutation(normalized, absolutePath, operations, signal),\n\t\t\t);\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tconst previewInput = getPreviewInput(args);\n\t\t\tif (!context.executionStarted && context.argsComplete && previewInput) {\n\t\t\t\tconst argsKey = JSON.stringify(previewInput);\n\t\t\t\tif (context.state.argsKey !== argsKey) {\n\t\t\t\t\tcontext.state.argsKey = argsKey;\n\t\t\t\t\tcontext.state.preview = undefined;\n\t\t\t\t\tconst generation = (context.state.previewGeneration ?? 0) + 1;\n\t\t\t\t\tcontext.state.previewGeneration = generation;\n\t\t\t\t\tvoid computePreview(previewInput, operations).then((preview) => {\n\t\t\t\t\t\tif (context.state.argsKey === argsKey && context.state.previewGeneration === generation) {\n\t\t\t\t\t\t\tcontext.state.preview = preview;\n\t\t\t\t\t\t\tcontext.invalidate();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\ttext.setText(\n\t\t\t\t\tformatBackendIcon(operations.getBackendInfo?.(), theme) +\n\t\t\t\t\t\tfmtCall(previewInput, context.state, context.expanded, theme).replace(\"replace\", \"edit\"),\n\t\t\t\t);\n\t\t\t\treturn text;\n\t\t\t}\n\t\t\ttext.setText(formatEditCall(args as RenderableEditArgs | undefined, theme, operations.getBackendInfo?.()));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, _options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tif (context.isError) {\n\t\t\t\tconst errorText = result.content\n\t\t\t\t\t?.filter((entry) => entry.type === \"text\")\n\t\t\t\t\t.map((entry) => entry.text ?? \"\")\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\ttext.setText(errorText ? `\\n${theme.fg(\"error\", errorText)}` : \"\");\n\t\t\t\treturn text;\n\t\t\t}\n\t\t\tconst diff = result.details?.diff;\n\t\t\tif (!diff) {\n\t\t\t\ttext.setText(\"\");\n\t\t\t\treturn text;\n\t\t\t}\n\t\t\tconst lines = diff.split(\"\\n\").map((line) => {\n\t\t\t\tif (line.startsWith(\"+\") && !line.startsWith(\"+++\")) return theme.fg(\"success\", line);\n\t\t\t\tif (line.startsWith(\"-\") && !line.startsWith(\"---\")) return theme.fg(\"error\", line);\n\t\t\t\treturn theme.fg(\"dim\", line);\n\t\t\t});\n\t\t\ttext.setText(`\\n${lines.join(\"\\n\")}`);\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\ntype CompatibleEditAgentTool = AgentTool<typeof editSchema, EditToolDetails> & {\n\texecute: (\n\t\ttoolCallId: string,\n\t\tparams: Record<string, unknown>,\n\t\tsignal?: AbortSignal,\n\t\tonUpdate?: AgentToolUpdateCallback<EditToolDetails>,\n\t) => Promise<AgentToolResult<EditToolDetails>>;\n};\n\nexport function createEditTool(operations: ToolOperations, options?: EditToolOptions): CompatibleEditAgentTool {\n\treturn wrapToolDefinition(createEditToolDefinition(operations, options)) as CompatibleEditAgentTool;\n}\n"]}
1
+ {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/core/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from \"@greppleai/grip-agent-core\";\nimport { Text } from \"@greppleai/grip-tui\";\nimport { createTwoFilesPatch } from \"diff\";\nimport { type Static, Type } from \"typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { type ApplyEditsResult, applyEdits, fmtBoundaryWarning } from \"./hashline/apply.ts\";\nimport { initHasher, lineHashes } from \"./hashline/hash.ts\";\nimport { type HEdit, type HTEdit, resEdits } from \"./hashline/resolve.ts\";\nimport type { ToolBackendInfo, ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { formatBackendIcon, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { detectEnding, genDiff, type LineEnding, restoreEndings, stripBOM, toLF } from \"./replace-diff.ts\";\nimport { normReq } from \"./replace-normalize.ts\";\nimport { fmtCall, getPreviewInput, type RPreview, type RRState } from \"./replace-render.ts\";\nimport { abortIf } from \"./runtime.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst contentLinesSchema = Type.Array(Type.String(), {\n\tdescription:\n\t\t\"Literal replacement content, one string per line. Use [] to delete the range. Do not include HASH│ prefixes from read output.\",\n});\n\nconst hashRangeInclusiveSchema = Type.Array(Type.String(), {\n\tdescription: \"Inclusive hash range to replace [start_hash, end_hash]. Use hash anchors only.\",\n\tminItems: 2,\n\tmaxItems: 2,\n});\n\nconst editItemSchema = Type.Object(\n\t{\n\t\thash_range_inclusive: hashRangeInclusiveSchema,\n\t\tcontent_lines: contentLinesSchema,\n\t},\n\t{ additionalProperties: false },\n);\n\nconst editSchema = Type.Object(\n\t{\n\t\tpath: Type.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n\t\tchanges: Type.Array(editItemSchema, {\n\t\t\tdescription: \"One or more hash-anchored replacements. All anchors must come from the same read snapshot.\",\n\t\t}),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport type EditToolInput = Static<typeof editSchema>;\n\nexport type ReqParams = {\n\tpath: string;\n\tchanges: HTEdit[];\n};\ninterface EditChangedLineRange {\n\tfirst: number;\n\tlast: number;\n}\n\nexport type RMetrics = {\n\tedits_attempted: number;\n\tedits_noop: number;\n\twarnings: number;\n\tclassification: \"applied\" | \"noop\";\n\tchanged_lines?: EditChangedLineRange;\n\tadded_lines?: number;\n\tremoved_lines?: number;\n};\n\nexport interface ReplaceDetails {\n\tdiff: string;\n\tpatch: string;\n\tfirstChangedLine?: number;\n\tclassification?: \"noop\";\n\tmetrics?: RMetrics;\n}\n\nexport type EditToolDetails = ReplaceDetails;\n\nexport interface EditToolOptions {}\n\ntype EditRenderState = RRState;\ntype DiffLineMarker = \"+\" | \"-\";\n\ntype RenderableEditArgs = {\n\tpath?: string;\n\tfile_path?: string;\n\tchanges?: HTEdit[];\n\tedits?: HTEdit[];\n\thash_range_inclusive?: [string, string];\n\tcontent_lines?: string[];\n};\n\nfunction countDiffLines(diff: string, marker: DiffLineMarker): number {\n\tlet count = 0;\n\tfor (const line of diff.split(\"\\n\")) {\n\t\tif (line.startsWith(marker) && !line.startsWith(`${marker}${marker}${marker}`)) {\n\t\t\tcount++;\n\t\t}\n\t}\n\treturn count;\n}\n\nfunction hashStoreKey(operations: ToolOperations, absolutePath: string): string {\n\tconst backend = operations.getBackendInfo?.();\n\tif (!backend) return absolutePath;\n\tif (backend.type === \"remote\" && backend.configured) return `remote:${backend.url}:${absolutePath}`;\n\treturn absolutePath;\n}\n\nfunction formatEditCall(\n\targs: RenderableEditArgs | undefined,\n\ttheme: Theme,\n\tbackendInfo: ToolBackendInfo | undefined,\n): string {\n\tconst previewInput = getPreviewInput(args);\n\tif (previewInput) {\n\t\treturn formatBackendIcon(backendInfo, theme) + fmtCall(previewInput, {}, false, theme).replace(\"replace\", \"edit\");\n\t}\n\tconst invalidArg = invalidArgText(theme);\n\tconst rawPath = str(args?.file_path ?? args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath) : null;\n\tconst pathDisplay = path === null ? invalidArg : path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\treturn `${formatBackendIcon(backendInfo, theme)}${theme.fg(\"toolTitle\", theme.bold(\"edit\"))} ${pathDisplay}`;\n}\n\nasync function computePreview(request: ReqParams, operations: ToolOperations): Promise<RPreview> {\n\ttry {\n\t\tawait initHasher();\n\t\tconst absolutePath = resolveToCwd(request.path, operations.cwd);\n\t\tawait operations.access(absolutePath, \"read\");\n\t\tconst rawContent = (await operations.readFile(absolutePath)).toString(\"utf-8\");\n\t\tconst { text } = stripBOM(rawContent);\n\t\tconst originalNormalized = toLF(text);\n\t\tconst originalHashes = await lineHashes(originalNormalized, hashStoreKey(operations, absolutePath));\n\t\tconst result = applyEdits(\n\t\t\toriginalNormalized,\n\t\t\tresEdits(request.changes),\n\t\t\tundefined,\n\t\t\toriginalHashes,\n\t\t\trequest.path,\n\t\t).content;\n\t\tif (originalNormalized === result) {\n\t\t\treturn { error: `No changes made to ${request.path}. The edits produced identical content.` };\n\t\t}\n\t\tconst resultHashes = await lineHashes(result);\n\t\treturn { diff: genDiff(originalNormalized, result, 4, resultHashes, originalHashes).diff };\n\t} catch (error) {\n\t\treturn { error: error instanceof Error ? error.message : String(error) };\n\t}\n}\n\nfunction normalizeEditArguments(input: unknown): EditToolInput {\n\treturn normReq(input) as EditToolInput;\n}\n\nfunction assertReq(request: unknown): asserts request is ReqParams {\n\tif (!request || typeof request !== \"object\" || Array.isArray(request)) {\n\t\tthrow new Error(\"[E_BAD_SHAPE] Edit request must be an object.\");\n\t}\n\tconst record = request as Record<string, unknown>;\n\tfor (const legacyKey of [\"oldText\", \"newText\", \"old_text\", \"new_text\", \"old_range\", \"start\", \"end\", \"lines\"]) {\n\t\tif (Object.hasOwn(record, legacyKey)) {\n\t\t\tthrow new Error(\n\t\t\t\t`[E_LEGACY_SHAPE] \"${legacyKey}\" is not supported. Call read first, then use {hash_range_inclusive: [\"<START>\", \"<END>\"], content_lines: [...]}.`,\n\t\t\t);\n\t\t}\n\t}\n\tconst unknown = Object.keys(record).filter((key) => key !== \"path\" && key !== \"changes\");\n\tif (unknown.length > 0) {\n\t\tthrow new Error(`[E_BAD_SHAPE] Edit request contains unknown or unsupported fields: ${unknown.join(\", \")}.`);\n\t}\n\tif (typeof record.path !== \"string\" || record.path.length === 0) {\n\t\tthrow new Error('[E_BAD_SHAPE] Edit request requires a non-empty \"path\" string.');\n\t}\n\tif (!Array.isArray(record.changes) || record.changes.length === 0) {\n\t\tthrow new Error('[E_BAD_SHAPE] Edit request requires a non-empty \"changes\" array.');\n\t}\n}\ninterface EditSourceSnapshot {\n\tbom: string;\n\toriginalEnding: LineEnding;\n\toriginalContent: string;\n\toriginalHashes: string[];\n\tstoreKey: string;\n}\n\ninterface AppliedEditResultOptions {\n\tpath: string;\n\teditCount: number;\n\tanchorResult: ApplyEditsResult;\n\twarnings: string[];\n\toriginalContent: string;\n\tresultContent: string;\n\toriginalHashes: string[];\n\tresultHashes: string[];\n}\n\nasync function readEditSource(\n\tpath: string,\n\tabsolutePath: string,\n\toperations: ToolOperations,\n): Promise<EditSourceSnapshot> {\n\ttry {\n\t\tawait operations.access(absolutePath, \"readwrite\");\n\t} catch (error) {\n\t\tconst message = error instanceof Error && \"code\" in error ? `Error code: ${String(error.code)}` : String(error);\n\t\tthrow new Error(`Could not edit file: ${path}. ${message}.`);\n\t}\n\tconst rawContent = (await operations.readFile(absolutePath)).toString(\"utf-8\");\n\tconst { bom, text } = stripBOM(rawContent);\n\tconst originalContent = toLF(text);\n\tconst storeKey = hashStoreKey(operations, absolutePath);\n\treturn {\n\t\tbom,\n\t\toriginalEnding: detectEnding(text),\n\t\toriginalContent,\n\t\toriginalHashes: await lineHashes(originalContent, storeKey),\n\t\tstoreKey,\n\t};\n}\n\nfunction collectRemovedHashes(edits: HEdit[], originalHashes: string[]): Set<string> {\n\tconst hashIndexes = new Map<string, number>();\n\tfor (let index = 0; index < originalHashes.length; index++) {\n\t\tconst hash = originalHashes[index];\n\t\tif (hash !== undefined && !hashIndexes.has(hash)) hashIndexes.set(hash, index);\n\t}\n\tconst removedHashes = new Set<string>();\n\tfor (const edit of edits) {\n\t\tconst startLine = hashIndexes.get(edit.hash_range_inclusive[0].hash) ?? -1;\n\t\tconst endLine = hashIndexes.get(edit.hash_range_inclusive[1].hash) ?? -1;\n\t\tif (startLine < 0 || endLine < 0) continue;\n\t\tfor (let index = startLine; index <= endLine; index++) {\n\t\t\tconst hash = originalHashes[index];\n\t\t\tif (hash) removedHashes.add(hash);\n\t\t}\n\t}\n\treturn removedHashes;\n}\n\nfunction indexLineOccurrences(lines: string[]): Map<string, number[]> {\n\tconst indexesByLine = new Map<string, number[]>();\n\tfor (let index = 0; index < lines.length; index++) {\n\t\tconst line = lines[index];\n\t\tconst indexes = indexesByLine.get(line);\n\t\tif (indexes) indexes.push(index);\n\t\telse indexesByLine.set(line, [index]);\n\t}\n\treturn indexesByLine;\n}\n\nfunction collectEditWarnings(anchorResult: ApplyEditsResult, resultContent: string, resultHashes: string[]): string[] {\n\tconst warnings = [...(anchorResult.warnings ?? [])];\n\tconst resultLines = resultContent.split(\"\\n\");\n\tconst indexesByLine = indexLineOccurrences(resultLines);\n\tfor (const warning of anchorResult.boundaryWarnings ?? []) {\n\t\tconst matchIndex = indexesByLine.get(warning.survivingLineContent)?.[warning.occurrence] ?? -1;\n\t\tif (matchIndex < 0) continue;\n\t\twarnings.push(\n\t\t\tfmtBoundaryWarning({\n\t\t\t\tkind: warning.kind,\n\t\t\t\tsurvivingContent: warning.survivingLineContent,\n\t\t\t\tmatchIndex,\n\t\t\t\tresultLines,\n\t\t\t\tresultHashes,\n\t\t\t}),\n\t\t);\n\t}\n\treturn warnings;\n}\n\nfunction buildNoopEditResult(\n\tpath: string,\n\teditCount: number,\n\tanchorResult: ApplyEditsResult,\n\twarnings: string[],\n): AgentToolResult<EditToolDetails> {\n\treturn {\n\t\tcontent: [{ type: \"text\", text: `No changes made to ${path}. The edits produced identical content.` }],\n\t\tdetails: {\n\t\t\tdiff: \"\",\n\t\t\tpatch: \"\",\n\t\t\tclassification: \"noop\",\n\t\t\tmetrics: {\n\t\t\t\tedits_attempted: editCount,\n\t\t\t\tedits_noop: anchorResult.noopEdits?.length ?? 0,\n\t\t\t\twarnings: warnings.length,\n\t\t\t\tclassification: \"noop\",\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction buildAppliedEditResult(options: AppliedEditResultOptions): AgentToolResult<EditToolDetails> {\n\tconst diffResult = genDiff(\n\t\toptions.originalContent,\n\t\toptions.resultContent,\n\t\t2,\n\t\toptions.resultHashes,\n\t\toptions.originalHashes,\n\t);\n\tconst warningBlock = options.warnings.length > 0 ? `\\n\\nWarnings:\\n${options.warnings.join(\"\\n\")}` : \"\";\n\tconst changedLines =\n\t\toptions.anchorResult.firstChangedLine !== undefined && options.anchorResult.lastChangedLine !== undefined\n\t\t\t? {\n\t\t\t\t\tfirst: options.anchorResult.firstChangedLine,\n\t\t\t\t\tlast: options.anchorResult.lastChangedLine,\n\t\t\t\t}\n\t\t\t: undefined;\n\treturn {\n\t\tcontent: [{ type: \"text\", text: `Successfully replaced in ${options.path}.${warningBlock}` }],\n\t\tdetails: {\n\t\t\tdiff: diffResult.diff,\n\t\t\tpatch: createTwoFilesPatch(options.path, options.path, options.originalContent, options.resultContent),\n\t\t\tfirstChangedLine: options.anchorResult.firstChangedLine ?? diffResult.firstChangedLine,\n\t\t\tmetrics: {\n\t\t\t\tedits_attempted: options.editCount,\n\t\t\t\tedits_noop: options.anchorResult.noopEdits?.length ?? 0,\n\t\t\t\twarnings: options.warnings.length,\n\t\t\t\tclassification: \"applied\",\n\t\t\t\t...(changedLines ? { changed_lines: changedLines } : {}),\n\t\t\t\tadded_lines: countDiffLines(diffResult.diff, \"+\"),\n\t\t\t\tremoved_lines: countDiffLines(diffResult.diff, \"-\"),\n\t\t\t},\n\t\t},\n\t};\n}\n\nasync function executeEditMutation(\n\trequest: ReqParams,\n\tabsolutePath: string,\n\toperations: ToolOperations,\n\tsignal: AbortSignal | undefined,\n): Promise<AgentToolResult<EditToolDetails>> {\n\tabortIf(signal);\n\tawait initHasher();\n\tconst source = await readEditSource(request.path, absolutePath, operations);\n\tconst resolvedEdits = resEdits(request.changes);\n\tconst anchorResult = applyEdits(source.originalContent, resolvedEdits, signal, source.originalHashes, request.path);\n\tconst resultContent = anchorResult.content;\n\tconst resultHashes = await lineHashes(resultContent, source.storeKey, {\n\t\tcontent: source.originalContent,\n\t\thashes: source.originalHashes,\n\t\tremovedHashes: collectRemovedHashes(resolvedEdits, source.originalHashes),\n\t});\n\tconst warnings = collectEditWarnings(anchorResult, resultContent, resultHashes);\n\tif (source.originalContent === resultContent) {\n\t\treturn buildNoopEditResult(request.path, request.changes.length, anchorResult, warnings);\n\t}\n\tabortIf(signal);\n\tawait operations.writeFile(absolutePath, source.bom + restoreEndings(resultContent, source.originalEnding));\n\treturn buildAppliedEditResult({\n\t\tpath: request.path,\n\t\teditCount: request.changes.length,\n\t\tanchorResult,\n\t\twarnings,\n\t\toriginalContent: source.originalContent,\n\t\tresultContent,\n\t\toriginalHashes: source.originalHashes,\n\t\tresultHashes,\n\t});\n}\n\nexport type EditToolDefinition = ToolDefinition<typeof editSchema, EditToolDetails | undefined, EditRenderState>;\n\nexport function createEditToolDefinition(operations: ToolOperations, _options?: EditToolOptions): EditToolDefinition {\n\treturn {\n\t\tname: \"edit\",\n\t\tlabel: \"edit\",\n\t\tdescription:\n\t\t\t\"Edit a file using hash-anchored line replacements. Call read first; it returns HASH│content lines. Use hash_range_inclusive with the 3-character start/end hashes and content_lines with literal replacement lines only.\",\n\t\tpromptSnippet: \"Edit files using hashline anchors from read output\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use read before edit to get HASH│content anchors.\",\n\t\t\t\"Use edit with changes: [{ hash_range_inclusive: [startHash, endHash], content_lines: [...] }].\",\n\t\t\t\"hash_range_inclusive contains only the 3-character hashes, not line numbers and not HASH│content.\",\n\t\t\t\"content_lines contains literal file content only; do not include HASH│ prefixes. Use [] to delete a range.\",\n\t\t\t\"After a successful edit, call read again before follow-up edits unless the response includes current warning anchors.\",\n\t\t],\n\t\tparameters: editSchema,\n\t\trenderShell: \"default\",\n\t\tprepareArguments: normalizeEditArguments,\n\t\tasync execute(_toolCallId, input: EditToolInput, signal?: AbortSignal) {\n\t\t\tconst normalized = normReq(input);\n\t\t\tassertReq(normalized);\n\t\t\tconst absolutePath = resolveToCwd(normalized.path, operations.cwd);\n\t\t\treturn withFileMutationQueue(absolutePath, () =>\n\t\t\t\texecuteEditMutation(normalized, absolutePath, operations, signal),\n\t\t\t);\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tconst previewInput = getPreviewInput(args);\n\t\t\tif (!context.executionStarted && context.argsComplete && previewInput) {\n\t\t\t\tconst argsKey = JSON.stringify(previewInput);\n\t\t\t\tif (context.state.argsKey !== argsKey) {\n\t\t\t\t\tcontext.state.argsKey = argsKey;\n\t\t\t\t\tcontext.state.preview = undefined;\n\t\t\t\t\tconst generation = (context.state.previewGeneration ?? 0) + 1;\n\t\t\t\t\tcontext.state.previewGeneration = generation;\n\t\t\t\t\tvoid computePreview(previewInput, operations).then((preview) => {\n\t\t\t\t\t\tif (context.state.argsKey === argsKey && context.state.previewGeneration === generation) {\n\t\t\t\t\t\t\tcontext.state.preview = preview;\n\t\t\t\t\t\t\tcontext.invalidate();\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\ttext.setText(\n\t\t\t\t\tformatBackendIcon(operations.getBackendInfo?.(), theme) +\n\t\t\t\t\t\tfmtCall(previewInput, context.state, context.expanded, theme).replace(\"replace\", \"edit\"),\n\t\t\t\t);\n\t\t\t\treturn text;\n\t\t\t}\n\t\t\ttext.setText(formatEditCall(args as RenderableEditArgs | undefined, theme, operations.getBackendInfo?.()));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, _options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tif (context.isError) {\n\t\t\t\tconst errorText = result.content\n\t\t\t\t\t?.filter((entry) => entry.type === \"text\")\n\t\t\t\t\t.map((entry) => entry.text ?? \"\")\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\ttext.setText(errorText ? `\\n${theme.fg(\"error\", errorText)}` : \"\");\n\t\t\t\treturn text;\n\t\t\t}\n\t\t\tconst diff = result.details?.diff;\n\t\t\tif (!diff) {\n\t\t\t\ttext.setText(\"\");\n\t\t\t\treturn text;\n\t\t\t}\n\t\t\tconst lines = diff.split(\"\\n\").map((line) => {\n\t\t\t\tif (line.startsWith(\"+\") && !line.startsWith(\"+++\")) return theme.fg(\"success\", line);\n\t\t\t\tif (line.startsWith(\"-\") && !line.startsWith(\"---\")) return theme.fg(\"error\", line);\n\t\t\t\treturn theme.fg(\"dim\", line);\n\t\t\t});\n\t\t\ttext.setText(`\\n${lines.join(\"\\n\")}`);\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\ntype CompatibleEditAgentTool = AgentTool<typeof editSchema, EditToolDetails> & {\n\texecute: (\n\t\ttoolCallId: string,\n\t\tparams: Record<string, unknown>,\n\t\tsignal?: AbortSignal,\n\t\tonUpdate?: AgentToolUpdateCallback<EditToolDetails>,\n\t) => Promise<AgentToolResult<EditToolDetails>>;\n};\n\nexport function createEditTool(operations: ToolOperations, options?: EditToolOptions): CompatibleEditAgentTool {\n\treturn wrapToolDefinition(createEditToolDefinition(operations, options)) as CompatibleEditAgentTool;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"file-mutation-queue.d.ts","sourceRoot":"","sources":["../../../src/core/tools/file-mutation-queue.ts"],"names":[],"mappings":"AAKA,0FAA0F;AAC1F,wBAAgB,qBAAqB,CAAC,CAAC,EACtC,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EAC1C,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACtB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAgCD;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA+BjG","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { realpath } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\n\nconst mutationGuard = new AsyncLocalStorage<(filePath: string) => Promise<void>>();\n/** Apply a channel-local precondition inside the existing process-wide per-file queue. */\nexport function withFileMutationGuard<T>(\n\tguard: (filePath: string) => Promise<void>,\n\taction: () => Promise<T>,\n): Promise<T> {\n\treturn mutationGuard.run(guard, action);\n}\nconst fileMutationQueues = new Map<string, Promise<void>>();\nlet registrationQueue = Promise.resolve();\n\nfunction isMissingPathError(error: unknown): boolean {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t\"code\" in error &&\n\t\t(error.code === \"ENOENT\" || error.code === \"ENOTDIR\")\n\t);\n}\n\nasync function getMutationQueueKey(filePath: string): Promise<string> {\n\tconst resolvedPath = resolve(filePath);\n\tconst missingSegments: string[] = [];\n\tlet existingAncestor = resolvedPath;\n\n\twhile (true) {\n\t\ttry {\n\t\t\tconst canonicalAncestor = await realpath(existingAncestor);\n\t\t\treturn missingSegments.length > 0 ? join(canonicalAncestor, ...missingSegments) : canonicalAncestor;\n\t\t} catch (error) {\n\t\t\tif (!isMissingPathError(error)) throw error;\n\t\t\tconst parent = dirname(existingAncestor);\n\t\t\tif (parent === existingAncestor) return resolvedPath;\n\t\t\tmissingSegments.unshift(basename(existingAncestor));\n\t\t\texistingAncestor = parent;\n\t\t}\n\t}\n}\n\n/**\n * Serialize file mutation operations targeting the same file.\n * Operations for different files still run in parallel.\n */\nexport async function withFileMutationQueue<T>(filePath: string, fn: () => Promise<T>): Promise<T> {\n\tconst guard = mutationGuard.getStore();\n\tconst registration = registrationQueue.then(async () => {\n\t\tconst key = await getMutationQueueKey(filePath);\n\t\tconst currentQueue = fileMutationQueues.get(key) ?? Promise.resolve();\n\n\t\tlet releaseNext!: () => void;\n\t\tconst nextQueue = new Promise<void>((resolveQueue) => {\n\t\t\treleaseNext = resolveQueue;\n\t\t});\n\t\tconst chainedQueue = currentQueue.then(() => nextQueue);\n\t\tfileMutationQueues.set(key, chainedQueue);\n\n\t\treturn { key, currentQueue, chainedQueue, releaseNext };\n\t});\n\tregistrationQueue = registration.then(\n\t\t() => undefined,\n\t\t() => undefined,\n\t);\n\n\tconst { key, currentQueue, chainedQueue, releaseNext } = await registration;\n\tawait currentQueue;\n\ttry {\n\t\tif (guard) await guard(filePath);\n\t\treturn await fn();\n\t} finally {\n\t\treleaseNext();\n\t\tif (fileMutationQueues.get(key) === chainedQueue) {\n\t\t\tfileMutationQueues.delete(key);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"file-mutation-queue.d.ts","sourceRoot":"","sources":["../../../src/core/tools/file-mutation-queue.ts"],"names":[],"mappings":"AAKA,0FAA0F;AAC1F,wBAAgB,qBAAqB,CAAC,CAAC,EACtC,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EAC1C,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACtB,OAAO,CAAC,CAAC,CAAC,CAEZ;AAgCD;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA+BjG"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-mutation-queue.js","sourceRoot":"","sources":["../../../src/core/tools/file-mutation-queue.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { realpath } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\n\nconst mutationGuard = new AsyncLocalStorage<(filePath: string) => Promise<void>>();\n/** Apply a channel-local precondition inside the existing process-wide per-file queue. */\nexport function withFileMutationGuard<T>(\n\tguard: (filePath: string) => Promise<void>,\n\taction: () => Promise<T>,\n): Promise<T> {\n\treturn mutationGuard.run(guard, action);\n}\nconst fileMutationQueues = new Map<string, Promise<void>>();\nlet registrationQueue = Promise.resolve();\n\nfunction isMissingPathError(error: unknown): boolean {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t\"code\" in error &&\n\t\t(error.code === \"ENOENT\" || error.code === \"ENOTDIR\")\n\t);\n}\n\nasync function getMutationQueueKey(filePath: string): Promise<string> {\n\tconst resolvedPath = resolve(filePath);\n\tconst missingSegments: string[] = [];\n\tlet existingAncestor = resolvedPath;\n\n\twhile (true) {\n\t\ttry {\n\t\t\tconst canonicalAncestor = await realpath(existingAncestor);\n\t\t\treturn missingSegments.length > 0 ? join(canonicalAncestor, ...missingSegments) : canonicalAncestor;\n\t\t} catch (error) {\n\t\t\tif (!isMissingPathError(error)) throw error;\n\t\t\tconst parent = dirname(existingAncestor);\n\t\t\tif (parent === existingAncestor) return resolvedPath;\n\t\t\tmissingSegments.unshift(basename(existingAncestor));\n\t\t\texistingAncestor = parent;\n\t\t}\n\t}\n}\n\n/**\n * Serialize file mutation operations targeting the same file.\n * Operations for different files still run in parallel.\n */\nexport async function withFileMutationQueue<T>(filePath: string, fn: () => Promise<T>): Promise<T> {\n\tconst guard = mutationGuard.getStore();\n\tconst registration = registrationQueue.then(async () => {\n\t\tconst key = await getMutationQueueKey(filePath);\n\t\tconst currentQueue = fileMutationQueues.get(key) ?? Promise.resolve();\n\n\t\tlet releaseNext!: () => void;\n\t\tconst nextQueue = new Promise<void>((resolveQueue) => {\n\t\t\treleaseNext = resolveQueue;\n\t\t});\n\t\tconst chainedQueue = currentQueue.then(() => nextQueue);\n\t\tfileMutationQueues.set(key, chainedQueue);\n\n\t\treturn { key, currentQueue, chainedQueue, releaseNext };\n\t});\n\tregistrationQueue = registration.then(\n\t\t() => undefined,\n\t\t() => undefined,\n\t);\n\n\tconst { key, currentQueue, chainedQueue, releaseNext } = await registration;\n\tawait currentQueue;\n\ttry {\n\t\tif (guard) await guard(filePath);\n\t\treturn await fn();\n\t} finally {\n\t\treleaseNext();\n\t\tif (fileMutationQueues.get(key) === chainedQueue) {\n\t\t\tfileMutationQueues.delete(key);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"file-mutation-queue.js","sourceRoot":"","sources":["../../../src/core/tools/file-mutation-queue.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { realpath } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\n\nconst mutationGuard = new AsyncLocalStorage<(filePath: string) => Promise<void>>();\n/** Apply a channel-local precondition inside the existing process-wide per-file queue. */\nexport function withFileMutationGuard<T>(\n\tguard: (filePath: string) => Promise<void>,\n\taction: () => Promise<T>,\n): Promise<T> {\n\treturn mutationGuard.run(guard, action);\n}\nconst fileMutationQueues = new Map<string, Promise<void>>();\nlet registrationQueue = Promise.resolve();\n\nfunction isMissingPathError(error: unknown): boolean {\n\treturn (\n\t\ttypeof error === \"object\" &&\n\t\terror !== null &&\n\t\t\"code\" in error &&\n\t\t(error.code === \"ENOENT\" || error.code === \"ENOTDIR\")\n\t);\n}\n\nasync function getMutationQueueKey(filePath: string): Promise<string> {\n\tconst resolvedPath = resolve(filePath);\n\tconst missingSegments: string[] = [];\n\tlet existingAncestor = resolvedPath;\n\n\twhile (true) {\n\t\ttry {\n\t\t\tconst canonicalAncestor = await realpath(existingAncestor);\n\t\t\treturn missingSegments.length > 0 ? join(canonicalAncestor, ...missingSegments) : canonicalAncestor;\n\t\t} catch (error) {\n\t\t\tif (!isMissingPathError(error)) throw error;\n\t\t\tconst parent = dirname(existingAncestor);\n\t\t\tif (parent === existingAncestor) return resolvedPath;\n\t\t\tmissingSegments.unshift(basename(existingAncestor));\n\t\t\texistingAncestor = parent;\n\t\t}\n\t}\n}\n\n/**\n * Serialize file mutation operations targeting the same file.\n * Operations for different files still run in parallel.\n */\nexport async function withFileMutationQueue<T>(filePath: string, fn: () => Promise<T>): Promise<T> {\n\tconst guard = mutationGuard.getStore();\n\tconst registration = registrationQueue.then(async () => {\n\t\tconst key = await getMutationQueueKey(filePath);\n\t\tconst currentQueue = fileMutationQueues.get(key) ?? Promise.resolve();\n\n\t\tlet releaseNext!: () => void;\n\t\tconst nextQueue = new Promise<void>((resolveQueue) => {\n\t\t\treleaseNext = resolveQueue;\n\t\t});\n\t\tconst chainedQueue = currentQueue.then(() => nextQueue);\n\t\tfileMutationQueues.set(key, chainedQueue);\n\n\t\treturn { key, currentQueue, chainedQueue, releaseNext };\n\t});\n\tregistrationQueue = registration.then(\n\t\t() => undefined,\n\t\t() => undefined,\n\t);\n\n\tconst { key, currentQueue, chainedQueue, releaseNext } = await registration;\n\tawait currentQueue;\n\ttry {\n\t\tif (guard) await guard(filePath);\n\t\treturn await fn();\n\t} finally {\n\t\treleaseNext();\n\t\tif (fileMutationQueues.get(key) === chainedQueue) {\n\t\t\tfileMutationQueues.delete(key);\n\t\t}\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../../src/core/tools/find.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,4BAA4B,CAAC;AAI7E,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAWtD,OAAO,EAAiC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAMnG,QAAA,MAAM,UAAU;;;;EAMd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAItD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;CAAG;AAwPnC,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAAC;AAEhG,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,kBAAkB,CAoCnH;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAElH","sourcesContent":["import { createInterface } from \"node:readline\";\nimport type { AgentTool, AgentToolResult } from \"@greppleai/grip-agent-core\";\nimport { Text } from \"@greppleai/grip-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport type { ToolOperations } from \"./operations.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport {\n\tformatBackendIcon,\n\tformatHiddenLinesHint,\n\tgetTextOutput,\n\tinvalidArgText,\n\tshortenPath,\n\tstr,\n} from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nfunction toPosixPath(value: string): string {\n\treturn value.split(path.sep).join(\"/\");\n}\n\nconst findSchema = Type.Object({\n\tpattern: Type.String({\n\t\tdescription: \"Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'\",\n\t}),\n\tpath: Type.Optional(Type.String({ description: \"Directory to search in (default: current directory)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of results (default: 1000)\" })),\n});\n\nexport type FindToolInput = Static<typeof findSchema>;\n\nconst DEFAULT_LIMIT = 1000;\n\nexport interface FindToolDetails {\n\ttruncation?: TruncationResult;\n\tresultLimitReached?: number;\n}\n\nexport interface FindToolOptions {}\n\nfunction formatFindCall(args: FindToolInput | undefined, theme: Theme): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"find\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", pattern || \"\")) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (limit !== undefined) {\n\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t}\n\treturn text;\n}\n\nfunction formatFindResult(\n\tresult: AgentToolResult<FindToolDetails | undefined>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `\\n\\n${formatHiddenLinesHint(remaining, theme)}`;\n\t\t}\n\t}\n\n\tconst resultLimit = result.details?.resultLimitReached;\n\tconst truncation = result.details?.truncation;\n\tif (resultLimit || truncation?.truncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (resultLimit) warnings.push(`${resultLimit} results limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\ntype FindExecutionResult = AgentToolResult<FindToolDetails | undefined>;\n\ninterface FindExecutionRequest {\n\toperations: ToolOperations;\n\tcwd: string;\n\tpattern: string;\n\tsearchDir: string | undefined;\n\tlimit: number | undefined;\n\tsignal: AbortSignal | undefined;\n}\n\ntype RegisterFindChildStop = (stop: () => void) => void;\n\nfunction throwIfFindAborted(signal: AbortSignal | undefined): void {\n\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n}\n\nfunction noFindResults(): FindExecutionResult {\n\treturn { content: [{ type: \"text\", text: \"No files found matching pattern\" }], details: undefined };\n}\n\nfunction formatFindMatches(paths: string[], limit: number, includeRefineHint: boolean): FindExecutionResult {\n\tconst resultLimitReached = paths.length >= limit;\n\tconst truncation = truncateHead(paths.join(\"\\n\"), { maxLines: Number.MAX_SAFE_INTEGER });\n\tlet output = truncation.content;\n\tconst details: FindToolDetails = {};\n\tconst notices: string[] = [];\n\tif (resultLimitReached) {\n\t\tnotices.push(\n\t\t\tincludeRefineHint\n\t\t\t\t? `${limit} results limit reached. Use limit=${limit * 2} for more, or refine pattern`\n\t\t\t\t: `${limit} results limit reached`,\n\t\t);\n\t\tdetails.resultLimitReached = limit;\n\t}\n\tif (truncation.truncated) {\n\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\tdetails.truncation = truncation;\n\t}\n\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\treturn {\n\t\tcontent: [{ type: \"text\", text: output }],\n\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t};\n}\n\nfunction relativizeGlobMatches(paths: string[], searchPath: string): string[] {\n\treturn paths.map((matchedPath) => {\n\t\tif (matchedPath.startsWith(searchPath)) return toPosixPath(matchedPath.slice(searchPath.length + 1));\n\t\treturn toPosixPath(path.relative(searchPath, matchedPath));\n\t});\n}\n\nasync function executeOperationsFind(\n\trequest: FindExecutionRequest,\n\tsearchPath: string,\n\teffectiveLimit: number,\n): Promise<FindExecutionResult> {\n\ttry {\n\t\tawait request.operations.access(searchPath, \"exists\");\n\t} catch {\n\t\tthrow new Error(`Path not found: ${searchPath}`);\n\t}\n\tthrowIfFindAborted(request.signal);\n\tif (!request.operations.glob) throw new Error(\"Glob operation is unavailable\");\n\tconst results = await request.operations.glob(request.pattern, searchPath, {\n\t\tignore: [\"**/node_modules/**\", \"**/.git/**\"],\n\t\tlimit: effectiveLimit,\n\t});\n\tthrowIfFindAborted(request.signal);\n\tif (results.length === 0) return noFindResults();\n\treturn formatFindMatches(relativizeGlobMatches(results, searchPath), effectiveLimit, false);\n}\n\nfunction buildFdArguments(pattern: string, searchPath: string, limit: number): string[] {\n\tconst args = [\"--glob\", \"--color=never\", \"--hidden\", \"--no-require-git\", \"--max-results\", String(limit)];\n\tlet effectivePattern = pattern;\n\tif (pattern.includes(\"/\")) {\n\t\targs.push(\"--full-path\");\n\t\tif (!pattern.startsWith(\"/\") && !pattern.startsWith(\"**/\") && pattern !== \"**\") {\n\t\t\teffectivePattern = `**/${pattern}`;\n\t\t}\n\t}\n\targs.push(\"--\", effectivePattern, searchPath);\n\treturn args;\n}\n\nfunction relativizeFdMatches(lines: string[], searchPath: string): string[] {\n\tconst relativized: string[] = [];\n\tfor (const rawLine of lines) {\n\t\tconst line = rawLine.replace(/\\r$/, \"\").trim();\n\t\tif (!line) continue;\n\t\tconst hadTrailingSlash = line.endsWith(\"/\") || line.endsWith(\"\\\\\");\n\t\tlet relativePath = line;\n\t\tif (line.startsWith(searchPath)) {\n\t\t\trelativePath = line.slice(searchPath.length + 1);\n\t\t} else {\n\t\t\trelativePath = path.relative(searchPath, line);\n\t\t}\n\t\tif (hadTrailingSlash && !relativePath.endsWith(\"/\")) relativePath += \"/\";\n\t\trelativized.push(toPosixPath(relativePath));\n\t}\n\treturn relativized;\n}\n\nfunction executeFdFind(\n\tfdPath: string,\n\trequest: FindExecutionRequest,\n\tsearchPath: string,\n\teffectiveLimit: number,\n\tregisterStop: RegisterFindChildStop,\n): Promise<FindExecutionResult> {\n\treturn new Promise((resolveFind, rejectFind) => {\n\t\tconst child = spawn(fdPath, buildFdArguments(request.pattern, searchPath, effectiveLimit), {\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t});\n\t\tconst rl = createInterface({ input: child.stdout });\n\t\tlet stderr = \"\";\n\t\tconst lines: string[] = [];\n\t\tregisterStop(() => {\n\t\t\tif (!child.killed) child.kill();\n\t\t});\n\t\tconst cleanup = (): void => rl.close();\n\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\tstderr += chunk.toString();\n\t\t});\n\t\trl.on(\"line\", (line) => lines.push(line));\n\t\tchild.on(\"error\", (error) => {\n\t\t\tcleanup();\n\t\t\trejectFind(new Error(`Failed to run fd: ${error.message}`));\n\t\t});\n\t\tchild.on(\"close\", (code) => {\n\t\t\tcleanup();\n\t\t\tif (request.signal?.aborted) {\n\t\t\t\trejectFind(new Error(\"Operation aborted\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst output = lines.join(\"\\n\");\n\t\t\tif (code !== 0 && !output) {\n\t\t\t\trejectFind(new Error(stderr.trim() || `fd exited with code ${code}`));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!output) {\n\t\t\t\tresolveFind(noFindResults());\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tresolveFind(formatFindMatches(relativizeFdMatches(lines, searchPath), effectiveLimit, true));\n\t\t});\n\t});\n}\n\nasync function dispatchFindExecution(\n\trequest: FindExecutionRequest,\n\tregisterStop: RegisterFindChildStop,\n): Promise<FindExecutionResult> {\n\tconst searchPath = resolveToCwd(request.searchDir || \".\", request.cwd);\n\tconst effectiveLimit = request.limit ?? DEFAULT_LIMIT;\n\tif (request.operations.glob) return executeOperationsFind(request, searchPath, effectiveLimit);\n\tconst fdPath = await ensureTool(\"fd\", true);\n\tthrowIfFindAborted(request.signal);\n\tif (!fdPath) throw new Error(\"fd is not available and could not be downloaded\");\n\treturn executeFdFind(fdPath, request, searchPath, effectiveLimit, registerStop);\n}\n\nfunction executeFind(request: FindExecutionRequest): Promise<FindExecutionResult> {\n\treturn new Promise((resolveFind, rejectFind) => {\n\t\tif (request.signal?.aborted) {\n\t\t\trejectFind(new Error(\"Operation aborted\"));\n\t\t\treturn;\n\t\t}\n\t\tlet settled = false;\n\t\tlet stopChild: (() => void) | undefined;\n\t\tconst settle = (complete: () => void): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\trequest.signal?.removeEventListener(\"abort\", onAbort);\n\t\t\tstopChild = undefined;\n\t\t\tcomplete();\n\t\t};\n\t\tconst onAbort = (): void => {\n\t\t\tstopChild?.();\n\t\t\tsettle(() => rejectFind(new Error(\"Operation aborted\")));\n\t\t};\n\t\trequest.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tvoid dispatchFindExecution(request, (stop) => {\n\t\t\tstopChild = stop;\n\t\t}).then(\n\t\t\t(result) => settle(() => resolveFind(result)),\n\t\t\t(error: unknown) => {\n\t\t\t\tif (request.signal?.aborted) {\n\t\t\t\t\tsettle(() => rejectFind(new Error(\"Operation aborted\")));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsettle(() => rejectFind(error instanceof Error ? error : new Error(String(error))));\n\t\t\t},\n\t\t);\n\t});\n}\n\nexport type FindToolDefinition = ToolDefinition<typeof findSchema, FindToolDetails | undefined>;\n\nexport function createFindToolDefinition(operations: ToolOperations, _options?: FindToolOptions): FindToolDefinition {\n\tconst ops = operations;\n\tconst cwd = operations.cwd;\n\treturn {\n\t\tname: \"find\",\n\t\tlabel: \"find\",\n\t\tdescription: `Search for files by glob pattern. Returns matching file paths relative to the search directory. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} results or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first).`,\n\t\tpromptSnippet: \"Find files by glob pattern (respects .gitignore)\",\n\t\tparameters: findSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ pattern, path: searchDir, limit }: FindToolInput,\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn executeFind({\n\t\t\t\toperations: ops,\n\t\t\t\tcwd,\n\t\t\t\tpattern,\n\t\t\t\tsearchDir,\n\t\t\t\tlimit,\n\t\t\t\tsignal,\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatBackendIcon(ops.getBackendInfo?.(), theme) + formatFindCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatFindResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createFindTool(operations: ToolOperations, options?: FindToolOptions): AgentTool<typeof findSchema> {\n\treturn wrapToolDefinition(createFindToolDefinition(operations, options));\n}\n"]}
1
+ {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../../src/core/tools/find.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,4BAA4B,CAAC;AAI7E,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAWtD,OAAO,EAAiC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAMnG,QAAA,MAAM,UAAU;;;;EAMd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAItD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;CAAG;AAwPnC,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAAC;AAEhG,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,kBAAkB,CAoCnH;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAElH"}