@ny4n/durable 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +711 -2
  3. package/dist/documents.d.ts +66 -0
  4. package/dist/documents.d.ts.map +1 -0
  5. package/dist/documents.js +98 -0
  6. package/dist/documents.js.map +1 -0
  7. package/dist/entries.d.ts +31 -0
  8. package/dist/entries.d.ts.map +1 -0
  9. package/dist/entries.js +31 -0
  10. package/dist/entries.js.map +1 -0
  11. package/dist/env/decode.d.ts +16 -0
  12. package/dist/env/decode.d.ts.map +1 -0
  13. package/dist/env/decode.js +28 -0
  14. package/dist/env/decode.js.map +1 -0
  15. package/dist/env/index.d.ts +263 -0
  16. package/dist/env/index.d.ts.map +1 -0
  17. package/dist/env/index.js +49 -0
  18. package/dist/env/index.js.map +1 -0
  19. package/dist/env/line-scan.d.ts +13 -0
  20. package/dist/env/line-scan.d.ts.map +1 -0
  21. package/dist/env/line-scan.js +147 -0
  22. package/dist/env/line-scan.js.map +1 -0
  23. package/dist/env/node-watch.d.ts +29 -0
  24. package/dist/env/node-watch.d.ts.map +1 -0
  25. package/dist/env/node-watch.js +485 -0
  26. package/dist/env/node-watch.js.map +1 -0
  27. package/dist/env/node.d.ts +56 -0
  28. package/dist/env/node.d.ts.map +1 -0
  29. package/dist/env/node.js +1166 -0
  30. package/dist/env/node.js.map +1 -0
  31. package/dist/errors.d.ts +32 -0
  32. package/dist/errors.d.ts.map +1 -0
  33. package/dist/errors.js +53 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/harness/agent.d.ts +33 -0
  36. package/dist/harness/agent.d.ts.map +1 -0
  37. package/dist/harness/agent.js +235 -0
  38. package/dist/harness/agent.js.map +1 -0
  39. package/dist/harness/assistant.d.ts +15 -0
  40. package/dist/harness/assistant.d.ts.map +1 -0
  41. package/dist/harness/assistant.js +23 -0
  42. package/dist/harness/assistant.js.map +1 -0
  43. package/dist/harness/compaction.d.ts +56 -0
  44. package/dist/harness/compaction.d.ts.map +1 -0
  45. package/dist/harness/compaction.js +384 -0
  46. package/dist/harness/compaction.js.map +1 -0
  47. package/dist/harness/context.d.ts +63 -0
  48. package/dist/harness/context.d.ts.map +1 -0
  49. package/dist/harness/context.js +221 -0
  50. package/dist/harness/context.js.map +1 -0
  51. package/dist/harness/define.d.ts +18 -0
  52. package/dist/harness/define.d.ts.map +1 -0
  53. package/dist/harness/define.js +25 -0
  54. package/dist/harness/define.js.map +1 -0
  55. package/dist/harness/events.d.ts +180 -0
  56. package/dist/harness/events.d.ts.map +1 -0
  57. package/dist/harness/events.js +370 -0
  58. package/dist/harness/events.js.map +1 -0
  59. package/dist/harness/generation.d.ts +54 -0
  60. package/dist/harness/generation.d.ts.map +1 -0
  61. package/dist/harness/generation.js +514 -0
  62. package/dist/harness/generation.js.map +1 -0
  63. package/dist/harness/harness.d.ts +17 -0
  64. package/dist/harness/harness.d.ts.map +1 -0
  65. package/dist/harness/harness.js +332 -0
  66. package/dist/harness/harness.js.map +1 -0
  67. package/dist/harness/inbox.d.ts +59 -0
  68. package/dist/harness/inbox.d.ts.map +1 -0
  69. package/dist/harness/inbox.js +97 -0
  70. package/dist/harness/inbox.js.map +1 -0
  71. package/dist/harness/json.d.ts +10 -0
  72. package/dist/harness/json.d.ts.map +1 -0
  73. package/dist/harness/json.js +33 -0
  74. package/dist/harness/json.js.map +1 -0
  75. package/dist/harness/live.d.ts +142 -0
  76. package/dist/harness/live.d.ts.map +1 -0
  77. package/dist/harness/live.js +149 -0
  78. package/dist/harness/live.js.map +1 -0
  79. package/dist/harness/output.d.ts +69 -0
  80. package/dist/harness/output.d.ts.map +1 -0
  81. package/dist/harness/output.js +318 -0
  82. package/dist/harness/output.js.map +1 -0
  83. package/dist/harness/prompt.d.ts +27 -0
  84. package/dist/harness/prompt.d.ts.map +1 -0
  85. package/dist/harness/prompt.js +131 -0
  86. package/dist/harness/prompt.js.map +1 -0
  87. package/dist/harness/provider.d.ts +14 -0
  88. package/dist/harness/provider.d.ts.map +1 -0
  89. package/dist/harness/provider.js +30 -0
  90. package/dist/harness/provider.js.map +1 -0
  91. package/dist/harness/registry.d.ts +6 -0
  92. package/dist/harness/registry.d.ts.map +1 -0
  93. package/dist/harness/registry.js +101 -0
  94. package/dist/harness/registry.js.map +1 -0
  95. package/dist/harness/run.d.ts +17 -0
  96. package/dist/harness/run.d.ts.map +1 -0
  97. package/dist/harness/run.js +26 -0
  98. package/dist/harness/run.js.map +1 -0
  99. package/dist/harness/scheduler.d.ts +106 -0
  100. package/dist/harness/scheduler.d.ts.map +1 -0
  101. package/dist/harness/scheduler.js +1743 -0
  102. package/dist/harness/scheduler.js.map +1 -0
  103. package/dist/harness/submissions.d.ts +29 -0
  104. package/dist/harness/submissions.d.ts.map +1 -0
  105. package/dist/harness/submissions.js +175 -0
  106. package/dist/harness/submissions.js.map +1 -0
  107. package/dist/harness/task-graph.d.ts +49 -0
  108. package/dist/harness/task-graph.d.ts.map +1 -0
  109. package/dist/harness/task-graph.js +168 -0
  110. package/dist/harness/task-graph.js.map +1 -0
  111. package/dist/harness/tool.d.ts +76 -0
  112. package/dist/harness/tool.d.ts.map +1 -0
  113. package/dist/harness/tool.js +736 -0
  114. package/dist/harness/tool.js.map +1 -0
  115. package/dist/harness/types.d.ts +713 -0
  116. package/dist/harness/types.d.ts.map +1 -0
  117. package/dist/harness/types.js +2 -0
  118. package/dist/harness/types.js.map +1 -0
  119. package/dist/harness/usage.d.ts +18 -0
  120. package/dist/harness/usage.d.ts.map +1 -0
  121. package/dist/harness/usage.js +57 -0
  122. package/dist/harness/usage.js.map +1 -0
  123. package/dist/harness/util.d.ts +19 -0
  124. package/dist/harness/util.d.ts.map +1 -0
  125. package/dist/harness/util.js +58 -0
  126. package/dist/harness/util.js.map +1 -0
  127. package/dist/harness/view.d.ts +47 -0
  128. package/dist/harness/view.d.ts.map +1 -0
  129. package/dist/harness/view.js +206 -0
  130. package/dist/harness/view.js.map +1 -0
  131. package/dist/ids.d.ts +6 -0
  132. package/dist/ids.d.ts.map +1 -0
  133. package/dist/ids.js +9 -0
  134. package/dist/ids.js.map +1 -0
  135. package/dist/images/cloudflare.d.ts +4 -0
  136. package/dist/images/cloudflare.d.ts.map +1 -0
  137. package/dist/images/cloudflare.js +9 -0
  138. package/dist/images/cloudflare.js.map +1 -0
  139. package/dist/images/exif.d.ts +3 -0
  140. package/dist/images/exif.d.ts.map +1 -0
  141. package/dist/images/exif.js +71 -0
  142. package/dist/images/exif.js.map +1 -0
  143. package/dist/images/index.d.ts +18 -0
  144. package/dist/images/index.d.ts.map +1 -0
  145. package/dist/images/index.js +125 -0
  146. package/dist/images/index.js.map +1 -0
  147. package/dist/images/node-worker.d.ts +17 -0
  148. package/dist/images/node-worker.d.ts.map +1 -0
  149. package/dist/images/node-worker.js +16 -0
  150. package/dist/images/node-worker.js.map +1 -0
  151. package/dist/images/node.d.ts +21 -0
  152. package/dist/images/node.d.ts.map +1 -0
  153. package/dist/images/node.js +121 -0
  154. package/dist/images/node.js.map +1 -0
  155. package/dist/index.d.ts +24 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +20 -0
  158. package/dist/index.js.map +1 -0
  159. package/dist/session/forks.d.ts +10 -0
  160. package/dist/session/forks.d.ts.map +1 -0
  161. package/dist/session/forks.js +42 -0
  162. package/dist/session/forks.js.map +1 -0
  163. package/dist/session/observation.d.ts +42 -0
  164. package/dist/session/observation.d.ts.map +1 -0
  165. package/dist/session/observation.js +281 -0
  166. package/dist/session/observation.js.map +1 -0
  167. package/dist/session/session.d.ts +133 -0
  168. package/dist/session/session.d.ts.map +1 -0
  169. package/dist/session/session.js +811 -0
  170. package/dist/session/session.js.map +1 -0
  171. package/dist/session/transaction.d.ts +119 -0
  172. package/dist/session/transaction.d.ts.map +1 -0
  173. package/dist/session/transaction.js +795 -0
  174. package/dist/session/transaction.js.map +1 -0
  175. package/dist/storage/jsonl/index.d.ts +2 -0
  176. package/dist/storage/jsonl/index.d.ts.map +1 -0
  177. package/dist/storage/jsonl/index.js +2 -0
  178. package/dist/storage/jsonl/index.js.map +1 -0
  179. package/dist/storage/jsonl/node.d.ts +6 -0
  180. package/dist/storage/jsonl/node.d.ts.map +1 -0
  181. package/dist/storage/jsonl/node.js +8 -0
  182. package/dist/storage/jsonl/node.js.map +1 -0
  183. package/dist/storage/jsonl/storage.d.ts +143 -0
  184. package/dist/storage/jsonl/storage.d.ts.map +1 -0
  185. package/dist/storage/jsonl/storage.js +682 -0
  186. package/dist/storage/jsonl/storage.js.map +1 -0
  187. package/dist/storage/memory.d.ts +62 -0
  188. package/dist/storage/memory.d.ts.map +1 -0
  189. package/dist/storage/memory.js +733 -0
  190. package/dist/storage/memory.js.map +1 -0
  191. package/dist/storage/scan.d.ts +18 -0
  192. package/dist/storage/scan.d.ts.map +1 -0
  193. package/dist/storage/scan.js +29 -0
  194. package/dist/storage/scan.js.map +1 -0
  195. package/dist/storage/sqlite/cloudflare.d.ts +46 -0
  196. package/dist/storage/sqlite/cloudflare.d.ts.map +1 -0
  197. package/dist/storage/sqlite/cloudflare.js +106 -0
  198. package/dist/storage/sqlite/cloudflare.js.map +1 -0
  199. package/dist/storage/sqlite/database.d.ts +37 -0
  200. package/dist/storage/sqlite/database.d.ts.map +1 -0
  201. package/dist/storage/sqlite/database.js +2 -0
  202. package/dist/storage/sqlite/database.js.map +1 -0
  203. package/dist/storage/sqlite/index.d.ts +4 -0
  204. package/dist/storage/sqlite/index.d.ts.map +1 -0
  205. package/dist/storage/sqlite/index.js +3 -0
  206. package/dist/storage/sqlite/index.js.map +1 -0
  207. package/dist/storage/sqlite/migrations.d.ts +11 -0
  208. package/dist/storage/sqlite/migrations.d.ts.map +1 -0
  209. package/dist/storage/sqlite/migrations.js +111 -0
  210. package/dist/storage/sqlite/migrations.js.map +1 -0
  211. package/dist/storage/sqlite/node.d.ts +41 -0
  212. package/dist/storage/sqlite/node.d.ts.map +1 -0
  213. package/dist/storage/sqlite/node.js +179 -0
  214. package/dist/storage/sqlite/node.js.map +1 -0
  215. package/dist/storage/sqlite/storage.d.ts +65 -0
  216. package/dist/storage/sqlite/storage.d.ts.map +1 -0
  217. package/dist/storage/sqlite/storage.js +670 -0
  218. package/dist/storage/sqlite/storage.js.map +1 -0
  219. package/dist/tasks.d.ts +6 -0
  220. package/dist/tasks.d.ts.map +1 -0
  221. package/dist/tasks.js +5 -0
  222. package/dist/tasks.js.map +1 -0
  223. package/dist/testing/assertions.d.ts +5 -0
  224. package/dist/testing/assertions.d.ts.map +1 -0
  225. package/dist/testing/assertions.js +25 -0
  226. package/dist/testing/assertions.js.map +1 -0
  227. package/dist/testing/env-conformance.d.ts +7 -0
  228. package/dist/testing/env-conformance.d.ts.map +1 -0
  229. package/dist/testing/env-conformance.js +431 -0
  230. package/dist/testing/env-conformance.js.map +1 -0
  231. package/dist/testing/index.d.ts +7 -0
  232. package/dist/testing/index.d.ts.map +1 -0
  233. package/dist/testing/index.js +6 -0
  234. package/dist/testing/index.js.map +1 -0
  235. package/dist/testing/runner.d.ts +12 -0
  236. package/dist/testing/runner.d.ts.map +1 -0
  237. package/dist/testing/runner.js +23 -0
  238. package/dist/testing/runner.js.map +1 -0
  239. package/dist/testing/storage-benchmark.d.ts +41 -0
  240. package/dist/testing/storage-benchmark.d.ts.map +1 -0
  241. package/dist/testing/storage-benchmark.js +350 -0
  242. package/dist/testing/storage-benchmark.js.map +1 -0
  243. package/dist/testing/storage-conformance.d.ts +4 -0
  244. package/dist/testing/storage-conformance.d.ts.map +1 -0
  245. package/dist/testing/storage-conformance.js +1213 -0
  246. package/dist/testing/storage-conformance.js.map +1 -0
  247. package/dist/testing/types.d.ts +37 -0
  248. package/dist/testing/types.d.ts.map +1 -0
  249. package/dist/testing/types.js +2 -0
  250. package/dist/testing/types.js.map +1 -0
  251. package/dist/tools/bash.d.ts +55 -0
  252. package/dist/tools/bash.d.ts.map +1 -0
  253. package/dist/tools/bash.js +138 -0
  254. package/dist/tools/bash.js.map +1 -0
  255. package/dist/tools/edit-diff.d.ts +89 -0
  256. package/dist/tools/edit-diff.d.ts.map +1 -0
  257. package/dist/tools/edit-diff.js +386 -0
  258. package/dist/tools/edit-diff.js.map +1 -0
  259. package/dist/tools/edit.d.ts +18 -0
  260. package/dist/tools/edit.d.ts.map +1 -0
  261. package/dist/tools/edit.js +117 -0
  262. package/dist/tools/edit.js.map +1 -0
  263. package/dist/tools/env.d.ts +5 -0
  264. package/dist/tools/env.d.ts.map +1 -0
  265. package/dist/tools/env.js +7 -0
  266. package/dist/tools/env.js.map +1 -0
  267. package/dist/tools/file-mutation-queue.d.ts +9 -0
  268. package/dist/tools/file-mutation-queue.d.ts.map +1 -0
  269. package/dist/tools/file-mutation-queue.js +52 -0
  270. package/dist/tools/file-mutation-queue.js.map +1 -0
  271. package/dist/tools/image-processor.d.ts +47 -0
  272. package/dist/tools/image-processor.d.ts.map +1 -0
  273. package/dist/tools/image-processor.js +30 -0
  274. package/dist/tools/image-processor.js.map +1 -0
  275. package/dist/tools/image.d.ts +20 -0
  276. package/dist/tools/image.d.ts.map +1 -0
  277. package/dist/tools/image.js +178 -0
  278. package/dist/tools/image.js.map +1 -0
  279. package/dist/tools/index.d.ts +46 -0
  280. package/dist/tools/index.d.ts.map +1 -0
  281. package/dist/tools/index.js +23 -0
  282. package/dist/tools/index.js.map +1 -0
  283. package/dist/tools/path-utils.d.ts +5 -0
  284. package/dist/tools/path-utils.d.ts.map +1 -0
  285. package/dist/tools/path-utils.js +26 -0
  286. package/dist/tools/path-utils.js.map +1 -0
  287. package/dist/tools/read.d.ts +25 -0
  288. package/dist/tools/read.d.ts.map +1 -0
  289. package/dist/tools/read.js +235 -0
  290. package/dist/tools/read.js.map +1 -0
  291. package/dist/tools/write.d.ts +10 -0
  292. package/dist/tools/write.d.ts.map +1 -0
  293. package/dist/tools/write.js +31 -0
  294. package/dist/tools/write.js.map +1 -0
  295. package/dist/truncate.d.ts +64 -0
  296. package/dist/truncate.d.ts.map +1 -0
  297. package/dist/truncate.js +154 -0
  298. package/dist/truncate.js.map +1 -0
  299. package/dist/types.d.ts +932 -0
  300. package/dist/types.d.ts.map +1 -0
  301. package/dist/types.js +3 -0
  302. package/dist/types.js.map +1 -0
  303. package/package.json +140 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context } from \"@ny4n/chord\";\nimport { type Static, Type } from \"typebox\";\nimport { defineTool } from \"../harness/define.ts\";\nimport type { ToolExecutionApi, ToolExecutionResult, ToolRegistration } from \"../harness/types.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from \"../truncate.ts\";\nimport { requireEnv } from \"./env.ts\";\n\nconst MAX_TIMEOUT_SECONDS = 2_147_483_647 / 1000;\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Bash command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\nconst powershellSchema = Type.Object({\n\tcommand: Type.String({ description: \"PowerShell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n});\n\n/** What a program that calls `bash` or `powershell` receives. */\nconst shellStructuredOutputSchema = Type.Object({\n\toutput: Type.String({ description: \"Combined stdout and stderr: the retained tail, as the model sees it\" }),\n\ttruncated: Type.Boolean({ description: \"Whether earlier output was dropped\" }),\n\tfullOutputPath: Type.Optional(Type.String({ description: \"File with the complete output, when it was spilled\" })),\n\texitCode: Type.Number(),\n});\n\nexport type BashToolInput = Static<typeof bashSchema>;\nexport type PowerShellToolInput = Static<typeof powershellSchema>;\nexport type ShellStructuredOutput = Static<typeof shellStructuredOutputSchema>;\n\n/** A command about to run, which `prepare` may change: the script, its working directory and environment. */\nexport interface BashExecution {\n\tcommand: string;\n\tcwd: string;\n\tenv: Record<string, string>;\n\tinheritEnv: boolean;\n}\n\nexport type BashPrepare = (execution: BashExecution, api: ToolExecutionApi, context: Context) => void | Promise<void>;\n\nexport interface BashToolOptions {\n\tcommandPrefix?: string;\n\tprepare?: BashPrepare;\n}\n\nexport interface PowerShellToolOptions {\n\t/** Lines run before each command. */\n\tcommandPrefix?: string;\n\tprepare?: BashPrepare;\n\t/** PowerShell programs to try in order; default `pwsh`, then `powershell`. A program that cannot start is skipped. */\n\tprograms?: readonly string[];\n}\n\nfunction validateTimeout(timeout: number | undefined): void {\n\tif (timeout === undefined) return;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\tif (timeout > MAX_TIMEOUT_SECONDS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n}\n\n/** The execution of one call: the command with its prefix, in the environment's working directory, then `prepare`. */\nasync function prepareExecution(\n\tcommand: string,\n\toptions: { commandPrefix?: string; prepare?: BashPrepare } | undefined,\n\tapi: ToolExecutionApi,\n\tcontext: Context,\n): Promise<BashExecution> {\n\tconst execution: BashExecution = {\n\t\tcommand: options?.commandPrefix ? `${options.commandPrefix}\\n${command}` : command,\n\t\tcwd: requireEnv(api).cwd,\n\t\tenv: {},\n\t\tinheritEnv: true,\n\t};\n\tawait options?.prepare?.(execution, api, context);\n\treturn execution;\n}\n\n/**\n * Run each command form in turn until one starts, streaming output to `api.output()` within the retained window, and\n * turn the result into the tool's result: a spill diagnostic, an error result for a nonzero exit, and a thrown error for\n * a failure such as a timeout. The structured output repeats the retained output with the exit code.\n */\nasync function runCommand(\n\tcommands: readonly (string | readonly string[])[],\n\texecution: BashExecution,\n\ttimeout: number | undefined,\n\tapi: ToolExecutionApi,\n\tcontext: Context,\n): Promise<ToolExecutionResult> {\n\tconst env = requireEnv(api);\n\tlet result: Awaited<ReturnType<typeof env.exec>> | undefined;\n\tfor (const command of commands) {\n\t\tresult = await env.exec(\n\t\t\tcommand,\n\t\t\t{\n\t\t\t\tcwd: execution.cwd,\n\t\t\t\tenv: execution.env,\n\t\t\t\tinheritEnv: execution.inheritEnv,\n\t\t\t\t...(timeout === undefined ? {} : { timeout }),\n\t\t\t\tonOutput: (text, _context, info) => api.output(text, info.skipped),\n\t\t\t\tspill: { afterBytes: DEFAULT_MAX_BYTES, afterLines: DEFAULT_MAX_LINES },\n\t\t\t\t// An environment may then omit output outside the retained tail and report the omission.\n\t\t\t\t...(api.outputWindow === undefined ? {} : { window: api.outputWindow }),\n\t\t\t},\n\t\t\tcontext,\n\t\t);\n\t\t// A program that could not start produced no output; the next form may.\n\t\tif (result.ok || result.error.code !== \"spawn_error\") break;\n\t}\n\tif (result === undefined) throw new Error(\"No command to run\");\n\tconst spillPath = result.ok ? result.value.spillPath : result.error.spillPath;\n\tif (spillPath !== undefined) {\n\t\tapi.diagnostic({ severity: \"info\", code: \"full_output\", message: `Full output: ${spillPath}` });\n\t}\n\tif (!result.ok) {\n\t\tif (result.error.code === \"aborted\" && context.abortSignal?.aborted) throw result.error;\n\t\tif (result.error.code === \"timeout\") throw new Error(`Command timed out after ${timeout} seconds`);\n\t\tif (result.error.code === \"aborted\") throw new Error(\"Command aborted\");\n\t\tthrow result.error;\n\t}\n\tconst exitCode = result.value.exitCode;\n\tconst retained = api.retainedOutput();\n\tconst structuredOutput: ShellStructuredOutput = {\n\t\toutput: retained.text,\n\t\ttruncated: retained.truncated,\n\t\t...(spillPath === undefined ? {} : { fullOutputPath: spillPath }),\n\t\texitCode,\n\t};\n\tif (exitCode === 0) return { structuredOutput };\n\tconst exited = { severity: \"error\", code: \"exit_code\", message: `Command exited with code ${exitCode}` } as const;\n\treturn { structuredOutput, isError: true, diagnostics: [exited] };\n}\n\n/**\n * Runs a command through the environment's shell. Its output streams to `api.output()`, where the Harness keeps the\n * tail within the default limits; the result content is that retained output. The retained window goes to the\n * environment, which may omit output outside it and report how much it omitted, so dropped counts stay exact. Output\n * beyond the limits is spilled to a file whose path is reported as a diagnostic. A nonzero exit is an error result with\n * the exit code; a timeout throws, which makes an error result that still carries the output and diagnostics.\n */\nexport function createBashTool(options?: BashToolOptions): ToolRegistration<typeof bashSchema> {\n\treturn defineTool({\n\t\tname: \"bash\",\n\t\tdescription: `Execute a bash command in the current working directory. Returns combined stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tparameters: bashSchema,\n\t\tstructuredOutputSchema: shellStructuredOutputSchema,\n\t\toutputLimits: { retain: \"tail\" },\n\t\tasync execute(args, api, context) {\n\t\t\tvalidateTimeout(args.timeout);\n\t\t\tconst execution = await prepareExecution(args.command, options, api, context);\n\t\t\treturn runCommand([execution.command], execution, args.timeout, api, context);\n\t\t},\n\t});\n}\n\n/** Output in UTF-8 whatever the console's code page, as the coding agent's `powershell` tool does. */\nconst UTF8_OUTPUT = \"try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\";\nconst POWERSHELL_ARGS = [\"-NoProfile\", \"-NonInteractive\", \"-ExecutionPolicy\", \"Bypass\", \"-Command\"] as const;\n\n/**\n * Runs a PowerShell command, like `bash` but through PowerShell instead of the environment's shell: `pwsh` (PowerShell\n * 7), else Windows PowerShell, started directly with the command as an argument, so no other shell parses it.\n */\nexport function createPowerShellTool(options?: PowerShellToolOptions): ToolRegistration<typeof powershellSchema> {\n\tconst programs = options?.programs ?? [\"pwsh\", \"powershell\"];\n\treturn defineTool({\n\t\tname: \"powershell\",\n\t\tdescription: `Execute a PowerShell command in the current working directory. Returns combined stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,\n\t\tparameters: powershellSchema,\n\t\tstructuredOutputSchema: shellStructuredOutputSchema,\n\t\toutputLimits: { retain: \"tail\" },\n\t\tasync execute(args, api, context) {\n\t\t\tvalidateTimeout(args.timeout);\n\t\t\tconst execution = await prepareExecution(args.command, options, api, context);\n\t\t\tconst script = `${UTF8_OUTPUT}\\n${execution.command}`;\n\t\t\tconst commands = programs.map((program) => [program, ...POWERSHELL_ARGS, script]);\n\t\t\treturn runCommand(commands, execution, args.timeout, api, context);\n\t\t},\n\t});\n}\n"]}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Shared diff computation utilities for the edit and similar tools.
3
+ */
4
+ export declare function detectLineEnding(content: string): "\r\n" | "\n";
5
+ export declare function normalizeToLF(text: string): string;
6
+ export declare function restoreLineEndings(text: string, ending: "\r\n" | "\n"): string;
7
+ /**
8
+ * Normalize text for fuzzy matching. Applies progressive transformations:
9
+ * - Strip trailing whitespace from each line
10
+ * - Normalize smart quotes to ASCII equivalents
11
+ * - Normalize Unicode dashes/hyphens to ASCII hyphen
12
+ * - Normalize special Unicode spaces to regular space
13
+ */
14
+ export declare function normalizeForFuzzyMatch(text: string): string;
15
+ interface MatchedEdit {
16
+ editIndex: number;
17
+ matchIndex: number;
18
+ matchLength: number;
19
+ newText: string;
20
+ }
21
+ type TextReplacement = Pick<MatchedEdit, "matchIndex" | "matchLength" | "newText">;
22
+ /**
23
+ * Apply replacements matched against `baseContent` to `originalContent` while
24
+ * preserving unchanged line blocks from the original.
25
+ *
26
+ * This is useful when `baseContent` is a normalized view of the original. Each
27
+ * replacement is widened to the lines it actually touches, those touched lines
28
+ * are rewritten from the normalized base, and all other lines are copied back
29
+ * from `originalContent`. The actual replacement ranges drive preservation so
30
+ * duplicate normalized lines cannot be aligned to the wrong occurrence.
31
+ */
32
+ export declare function applyReplacementsPreservingUnchangedLines(originalContent: string, baseContent: string, replacements: TextReplacement[]): string;
33
+ export interface FuzzyMatchResult {
34
+ /** Whether a match was found */
35
+ found: boolean;
36
+ /** The index where the match starts (in the content that should be used for replacement) */
37
+ index: number;
38
+ /** Length of the matched text */
39
+ matchLength: number;
40
+ /** Whether fuzzy matching was used (false = exact match) */
41
+ usedFuzzyMatch: boolean;
42
+ /**
43
+ * The content to use for replacement operations.
44
+ * When exact match: original content. When fuzzy match: normalized content.
45
+ */
46
+ contentForReplacement: string;
47
+ }
48
+ export interface Edit {
49
+ oldText: string;
50
+ newText: string;
51
+ }
52
+ export interface AppliedEditsResult {
53
+ baseContent: string;
54
+ newContent: string;
55
+ }
56
+ /**
57
+ * Find oldText in content, trying exact match first, then fuzzy match.
58
+ * When fuzzy matching is used, the returned contentForReplacement is the
59
+ * fuzzy-normalized version of the content (trailing whitespace stripped,
60
+ * Unicode quotes/dashes normalized to ASCII).
61
+ */
62
+ export declare function fuzzyFindText(content: string, oldText: string): FuzzyMatchResult;
63
+ /** Strip UTF-8 BOM if present, return both the BOM (if any) and the text without it */
64
+ export declare function stripBom(content: string): {
65
+ bom: string;
66
+ text: string;
67
+ };
68
+ /**
69
+ * Apply one or more exact-text replacements to LF-normalized content.
70
+ *
71
+ * All edits are matched against the same original content. Replacements are
72
+ * then applied in reverse order so offsets remain stable. If any edit needs
73
+ * fuzzy matching, the operation runs in fuzzy-normalized content space and then
74
+ * overlays those line-level changes onto the original content so unchanged line
75
+ * blocks keep their original bytes.
76
+ */
77
+ export declare function applyEditsToNormalizedContent(normalizedContent: string, edits: Edit[], path: string): AppliedEditsResult;
78
+ /** Generate a standard unified patch. */
79
+ export declare function generateUnifiedPatch(path: string, oldContent: string, newContent: string, contextLines?: number): string;
80
+ /**
81
+ * Generate a display-oriented diff string with line numbers and context.
82
+ * Returns both the diff string and the first changed line number (in the new file).
83
+ */
84
+ export declare function generateDiffString(oldContent: string, newContent: string, contextLines?: number): {
85
+ diff: string;
86
+ firstChangedLine: number | undefined;
87
+ };
88
+ export {};
89
+ //# sourceMappingURL=edit-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-diff.d.ts","sourceRoot":"","sources":["../../src/tools/edit-diff.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM/D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAE9E;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB3D;AAWD,UAAU,WAAW;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,YAAY,GAAG,aAAa,GAAG,SAAS,CAAC,CAAC;AAiDnF;;;;;;;;;GASG;AACH,wBAAgB,yCAAyC,CACxD,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,eAAe,EAAE,GAC7B,MAAM,CAqCR;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;AAED,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;AAED,uFAAuF;AACvF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAEvE;AA8CD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC5C,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,IAAI,EAAE,EACb,IAAI,EAAE,MAAM,GACV,kBAAkB,CA0DpB;AAED,yCAAyC;AACzC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,MAAM,CAKnH;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CACjC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,YAAY,SAAI,GACd;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAuHxD"}
@@ -0,0 +1,386 @@
1
+ /**
2
+ * Shared diff computation utilities for the edit and similar tools.
3
+ */
4
+ import * as Diff from "diff";
5
+ export function detectLineEnding(content) {
6
+ const crlfIdx = content.indexOf("\r\n");
7
+ const lfIdx = content.indexOf("\n");
8
+ if (lfIdx === -1)
9
+ return "\n";
10
+ if (crlfIdx === -1)
11
+ return "\n";
12
+ return crlfIdx < lfIdx ? "\r\n" : "\n";
13
+ }
14
+ export function normalizeToLF(text) {
15
+ return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
16
+ }
17
+ export function restoreLineEndings(text, ending) {
18
+ return ending === "\r\n" ? text.replace(/\n/g, "\r\n") : text;
19
+ }
20
+ /**
21
+ * Normalize text for fuzzy matching. Applies progressive transformations:
22
+ * - Strip trailing whitespace from each line
23
+ * - Normalize smart quotes to ASCII equivalents
24
+ * - Normalize Unicode dashes/hyphens to ASCII hyphen
25
+ * - Normalize special Unicode spaces to regular space
26
+ */
27
+ export function normalizeForFuzzyMatch(text) {
28
+ return (text
29
+ .normalize("NFKC")
30
+ // Strip trailing whitespace per line
31
+ .split("\n")
32
+ .map((line) => line.trimEnd())
33
+ .join("\n")
34
+ // Smart single quotes → '
35
+ .replace(/[\u2018\u2019\u201A\u201B]/g, "'")
36
+ // Smart double quotes → "
37
+ .replace(/[\u201C\u201D\u201E\u201F]/g, '"')
38
+ // Various dashes/hyphens → -
39
+ // U+2010 hyphen, U+2011 non-breaking hyphen, U+2012 figure dash,
40
+ // U+2013 en-dash, U+2014 em-dash, U+2015 horizontal bar, U+2212 minus
41
+ .replace(/[\u2010\u2011\u2012\u2013\u2014\u2015\u2212]/g, "-")
42
+ // Special spaces → regular space
43
+ // U+00A0 NBSP, U+2002-U+200A various spaces, U+202F narrow NBSP,
44
+ // U+205F medium math space, U+3000 ideographic space
45
+ .replace(/[\u00A0\u2002-\u200A\u202F\u205F\u3000]/g, " "));
46
+ }
47
+ function splitLinesWithEndings(content) {
48
+ return content.match(/[^\n]*\n|[^\n]+/g) ?? [];
49
+ }
50
+ function getLineSpans(content) {
51
+ let offset = 0;
52
+ return splitLinesWithEndings(content).map((line) => {
53
+ const span = { start: offset, end: offset + line.length };
54
+ offset = span.end;
55
+ return span;
56
+ });
57
+ }
58
+ function getReplacementLineRange(lines, replacement) {
59
+ const replacementStart = replacement.matchIndex;
60
+ const replacementEnd = replacement.matchIndex + replacement.matchLength;
61
+ let startLine = -1;
62
+ for (let i = 0; i < lines.length; i++) {
63
+ const line = lines[i];
64
+ if (replacementStart >= line.start && replacementStart < line.end) {
65
+ startLine = i;
66
+ break;
67
+ }
68
+ }
69
+ if (startLine === -1) {
70
+ throw new Error("Replacement range is outside the base content.");
71
+ }
72
+ let endLine = startLine;
73
+ while (endLine < lines.length && lines[endLine].end < replacementEnd) {
74
+ endLine++;
75
+ }
76
+ if (endLine >= lines.length) {
77
+ throw new Error("Replacement range is outside the base content.");
78
+ }
79
+ return { startLine, endLine: endLine + 1 };
80
+ }
81
+ function applyReplacements(content, replacements, offset = 0) {
82
+ let result = content;
83
+ for (let i = replacements.length - 1; i >= 0; i--) {
84
+ const replacement = replacements[i];
85
+ const matchIndex = replacement.matchIndex - offset;
86
+ result =
87
+ result.substring(0, matchIndex) + replacement.newText + result.substring(matchIndex + replacement.matchLength);
88
+ }
89
+ return result;
90
+ }
91
+ /**
92
+ * Apply replacements matched against `baseContent` to `originalContent` while
93
+ * preserving unchanged line blocks from the original.
94
+ *
95
+ * This is useful when `baseContent` is a normalized view of the original. Each
96
+ * replacement is widened to the lines it actually touches, those touched lines
97
+ * are rewritten from the normalized base, and all other lines are copied back
98
+ * from `originalContent`. The actual replacement ranges drive preservation so
99
+ * duplicate normalized lines cannot be aligned to the wrong occurrence.
100
+ */
101
+ export function applyReplacementsPreservingUnchangedLines(originalContent, baseContent, replacements) {
102
+ const originalLines = splitLinesWithEndings(originalContent);
103
+ const baseLines = getLineSpans(baseContent);
104
+ if (originalLines.length !== baseLines.length) {
105
+ throw new Error("Cannot preserve unchanged lines because the base content has a different line count.");
106
+ }
107
+ const groups = [];
108
+ const sortedReplacements = [...replacements].sort((a, b) => a.matchIndex - b.matchIndex);
109
+ for (const replacement of sortedReplacements) {
110
+ const range = getReplacementLineRange(baseLines, replacement);
111
+ const current = groups[groups.length - 1];
112
+ if (current && range.startLine < current.endLine) {
113
+ current.endLine = Math.max(current.endLine, range.endLine);
114
+ current.replacements.push(replacement);
115
+ continue;
116
+ }
117
+ groups.push({ ...range, replacements: [replacement] });
118
+ }
119
+ let originalLineIndex = 0;
120
+ let result = "";
121
+ for (const group of groups) {
122
+ result += originalLines.slice(originalLineIndex, group.startLine).join("");
123
+ const groupStartOffset = baseLines[group.startLine].start;
124
+ const groupEndOffset = baseLines[group.endLine - 1].end;
125
+ result += applyReplacements(baseContent.slice(groupStartOffset, groupEndOffset), group.replacements, groupStartOffset);
126
+ originalLineIndex = group.endLine;
127
+ }
128
+ result += originalLines.slice(originalLineIndex).join("");
129
+ return result;
130
+ }
131
+ /**
132
+ * Find oldText in content, trying exact match first, then fuzzy match.
133
+ * When fuzzy matching is used, the returned contentForReplacement is the
134
+ * fuzzy-normalized version of the content (trailing whitespace stripped,
135
+ * Unicode quotes/dashes normalized to ASCII).
136
+ */
137
+ export function fuzzyFindText(content, oldText) {
138
+ // Try exact match first
139
+ const exactIndex = content.indexOf(oldText);
140
+ if (exactIndex !== -1) {
141
+ return {
142
+ found: true,
143
+ index: exactIndex,
144
+ matchLength: oldText.length,
145
+ usedFuzzyMatch: false,
146
+ contentForReplacement: content,
147
+ };
148
+ }
149
+ // Try fuzzy match - work entirely in normalized space
150
+ const fuzzyContent = normalizeForFuzzyMatch(content);
151
+ const fuzzyOldText = normalizeForFuzzyMatch(oldText);
152
+ const fuzzyIndex = fuzzyContent.indexOf(fuzzyOldText);
153
+ if (fuzzyIndex === -1) {
154
+ return {
155
+ found: false,
156
+ index: -1,
157
+ matchLength: 0,
158
+ usedFuzzyMatch: false,
159
+ contentForReplacement: content,
160
+ };
161
+ }
162
+ // When fuzzy matching, return offsets in normalized space. Callers can use
163
+ // the normalized content to compute replacements, then decide how much of
164
+ // that normalized output should be written back.
165
+ return {
166
+ found: true,
167
+ index: fuzzyIndex,
168
+ matchLength: fuzzyOldText.length,
169
+ usedFuzzyMatch: true,
170
+ contentForReplacement: fuzzyContent,
171
+ };
172
+ }
173
+ /** Strip UTF-8 BOM if present, return both the BOM (if any) and the text without it */
174
+ export function stripBom(content) {
175
+ return content.startsWith("\uFEFF") ? { bom: "\uFEFF", text: content.slice(1) } : { bom: "", text: content };
176
+ }
177
+ function countOccurrences(content, oldText) {
178
+ const fuzzyContent = normalizeForFuzzyMatch(content);
179
+ const fuzzyOldText = normalizeForFuzzyMatch(oldText);
180
+ return fuzzyContent.split(fuzzyOldText).length - 1;
181
+ }
182
+ function getNotFoundError(path, editIndex, totalEdits) {
183
+ if (totalEdits === 1) {
184
+ return new Error(`Could not find the exact text in ${path}. The old text must match exactly including all whitespace and newlines.`);
185
+ }
186
+ return new Error(`Could not find edits[${editIndex}] in ${path}. The oldText must match exactly including all whitespace and newlines.`);
187
+ }
188
+ function getDuplicateError(path, editIndex, totalEdits, occurrences) {
189
+ if (totalEdits === 1) {
190
+ return new Error(`Found ${occurrences} occurrences of the text in ${path}. The text must be unique. Please provide more context to make it unique.`);
191
+ }
192
+ return new Error(`Found ${occurrences} occurrences of edits[${editIndex}] in ${path}. Each oldText must be unique. Please provide more context to make it unique.`);
193
+ }
194
+ function getEmptyOldTextError(path, editIndex, totalEdits) {
195
+ if (totalEdits === 1) {
196
+ return new Error(`oldText must not be empty in ${path}.`);
197
+ }
198
+ return new Error(`edits[${editIndex}].oldText must not be empty in ${path}.`);
199
+ }
200
+ function getNoChangeError(path, totalEdits) {
201
+ if (totalEdits === 1) {
202
+ return new Error(`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.`);
203
+ }
204
+ return new Error(`No changes made to ${path}. The replacements produced identical content.`);
205
+ }
206
+ /**
207
+ * Apply one or more exact-text replacements to LF-normalized content.
208
+ *
209
+ * All edits are matched against the same original content. Replacements are
210
+ * then applied in reverse order so offsets remain stable. If any edit needs
211
+ * fuzzy matching, the operation runs in fuzzy-normalized content space and then
212
+ * overlays those line-level changes onto the original content so unchanged line
213
+ * blocks keep their original bytes.
214
+ */
215
+ export function applyEditsToNormalizedContent(normalizedContent, edits, path) {
216
+ const normalizedEdits = edits.map((edit) => ({
217
+ oldText: normalizeToLF(edit.oldText),
218
+ newText: normalizeToLF(edit.newText),
219
+ }));
220
+ for (let i = 0; i < normalizedEdits.length; i++) {
221
+ if (normalizedEdits[i].oldText.length === 0) {
222
+ throw getEmptyOldTextError(path, i, normalizedEdits.length);
223
+ }
224
+ }
225
+ const initialMatches = normalizedEdits.map((edit) => fuzzyFindText(normalizedContent, edit.oldText));
226
+ const usedFuzzyMatch = initialMatches.some((match) => match.usedFuzzyMatch);
227
+ const replacementBaseContent = usedFuzzyMatch ? normalizeForFuzzyMatch(normalizedContent) : normalizedContent;
228
+ const matchedEdits = [];
229
+ for (let i = 0; i < normalizedEdits.length; i++) {
230
+ const edit = normalizedEdits[i];
231
+ const matchResult = fuzzyFindText(replacementBaseContent, edit.oldText);
232
+ if (!matchResult.found) {
233
+ throw getNotFoundError(path, i, normalizedEdits.length);
234
+ }
235
+ const occurrences = countOccurrences(replacementBaseContent, edit.oldText);
236
+ if (occurrences > 1) {
237
+ throw getDuplicateError(path, i, normalizedEdits.length, occurrences);
238
+ }
239
+ matchedEdits.push({
240
+ editIndex: i,
241
+ matchIndex: matchResult.index,
242
+ matchLength: matchResult.matchLength,
243
+ newText: edit.newText,
244
+ });
245
+ }
246
+ matchedEdits.sort((a, b) => a.matchIndex - b.matchIndex);
247
+ for (let i = 1; i < matchedEdits.length; i++) {
248
+ const previous = matchedEdits[i - 1];
249
+ const current = matchedEdits[i];
250
+ if (previous.matchIndex + previous.matchLength > current.matchIndex) {
251
+ throw new Error(`edits[${previous.editIndex}] and edits[${current.editIndex}] overlap in ${path}. Merge them into one edit or target disjoint regions.`);
252
+ }
253
+ }
254
+ const baseContent = normalizedContent;
255
+ const newContent = usedFuzzyMatch
256
+ ? applyReplacementsPreservingUnchangedLines(normalizedContent, replacementBaseContent, matchedEdits)
257
+ : applyReplacements(replacementBaseContent, matchedEdits);
258
+ if (baseContent === newContent) {
259
+ throw getNoChangeError(path, normalizedEdits.length);
260
+ }
261
+ return { baseContent, newContent };
262
+ }
263
+ /** Generate a standard unified patch. */
264
+ export function generateUnifiedPatch(path, oldContent, newContent, contextLines = 4) {
265
+ return Diff.createTwoFilesPatch(path, path, oldContent, newContent, undefined, undefined, {
266
+ context: contextLines,
267
+ headerOptions: Diff.FILE_HEADERS_ONLY,
268
+ });
269
+ }
270
+ /**
271
+ * Generate a display-oriented diff string with line numbers and context.
272
+ * Returns both the diff string and the first changed line number (in the new file).
273
+ */
274
+ export function generateDiffString(oldContent, newContent, contextLines = 4) {
275
+ const parts = Diff.diffLines(oldContent, newContent);
276
+ const output = [];
277
+ const oldLines = oldContent.split("\n");
278
+ const newLines = newContent.split("\n");
279
+ const maxLineNum = Math.max(oldLines.length, newLines.length);
280
+ const lineNumWidth = String(maxLineNum).length;
281
+ let oldLineNum = 1;
282
+ let newLineNum = 1;
283
+ let lastWasChange = false;
284
+ let firstChangedLine;
285
+ for (let i = 0; i < parts.length; i++) {
286
+ const part = parts[i];
287
+ const raw = part.value.split("\n");
288
+ if (raw[raw.length - 1] === "") {
289
+ raw.pop();
290
+ }
291
+ if (part.added || part.removed) {
292
+ // Capture the first changed line (in the new file)
293
+ if (firstChangedLine === undefined) {
294
+ firstChangedLine = newLineNum;
295
+ }
296
+ // Show the change
297
+ for (const line of raw) {
298
+ if (part.added) {
299
+ const lineNum = String(newLineNum).padStart(lineNumWidth, " ");
300
+ output.push(`+${lineNum} ${line}`);
301
+ newLineNum++;
302
+ }
303
+ else {
304
+ // removed
305
+ const lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
306
+ output.push(`-${lineNum} ${line}`);
307
+ oldLineNum++;
308
+ }
309
+ }
310
+ lastWasChange = true;
311
+ }
312
+ else {
313
+ // Context lines - only show a few before/after changes
314
+ const nextPartIsChange = i < parts.length - 1 && (parts[i + 1].added || parts[i + 1].removed);
315
+ const hasLeadingChange = lastWasChange;
316
+ const hasTrailingChange = nextPartIsChange;
317
+ if (hasLeadingChange && hasTrailingChange) {
318
+ if (raw.length <= contextLines * 2) {
319
+ for (const line of raw) {
320
+ const lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
321
+ output.push(` ${lineNum} ${line}`);
322
+ oldLineNum++;
323
+ newLineNum++;
324
+ }
325
+ }
326
+ else {
327
+ const leadingLines = raw.slice(0, contextLines);
328
+ const trailingLines = raw.slice(raw.length - contextLines);
329
+ const skippedLines = raw.length - leadingLines.length - trailingLines.length;
330
+ for (const line of leadingLines) {
331
+ const lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
332
+ output.push(` ${lineNum} ${line}`);
333
+ oldLineNum++;
334
+ newLineNum++;
335
+ }
336
+ output.push(` ${"".padStart(lineNumWidth, " ")} ...`);
337
+ oldLineNum += skippedLines;
338
+ newLineNum += skippedLines;
339
+ for (const line of trailingLines) {
340
+ const lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
341
+ output.push(` ${lineNum} ${line}`);
342
+ oldLineNum++;
343
+ newLineNum++;
344
+ }
345
+ }
346
+ }
347
+ else if (hasLeadingChange) {
348
+ const shownLines = raw.slice(0, contextLines);
349
+ const skippedLines = raw.length - shownLines.length;
350
+ for (const line of shownLines) {
351
+ const lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
352
+ output.push(` ${lineNum} ${line}`);
353
+ oldLineNum++;
354
+ newLineNum++;
355
+ }
356
+ if (skippedLines > 0) {
357
+ output.push(` ${"".padStart(lineNumWidth, " ")} ...`);
358
+ oldLineNum += skippedLines;
359
+ newLineNum += skippedLines;
360
+ }
361
+ }
362
+ else if (hasTrailingChange) {
363
+ const skippedLines = Math.max(0, raw.length - contextLines);
364
+ if (skippedLines > 0) {
365
+ output.push(` ${"".padStart(lineNumWidth, " ")} ...`);
366
+ oldLineNum += skippedLines;
367
+ newLineNum += skippedLines;
368
+ }
369
+ for (const line of raw.slice(skippedLines)) {
370
+ const lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
371
+ output.push(` ${lineNum} ${line}`);
372
+ oldLineNum++;
373
+ newLineNum++;
374
+ }
375
+ }
376
+ else {
377
+ // Skip these context lines entirely
378
+ oldLineNum += raw.length;
379
+ newLineNum += raw.length;
380
+ }
381
+ lastWasChange = false;
382
+ }
383
+ }
384
+ return { diff: output.join("\n"), firstChangedLine };
385
+ }
386
+ //# sourceMappingURL=edit-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-diff.js","sourceRoot":"","sources":["../../src/tools/edit-diff.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared diff computation utilities for the edit and similar tools.\n */\n\nimport * as Diff from \"diff\";\n\nexport function detectLineEnding(content: string): \"\\r\\n\" | \"\\n\" {\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: \"\\r\\n\" | \"\\n\"): 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\nfunction splitLinesWithEndings(content: string): string[] {\n\treturn content.match(/[^\\n]*\\n|[^\\n]+/g) ?? [];\n}\n\ninterface LineSpan {\n\tstart: number;\n\tend: number;\n}\n\ninterface MatchedEdit {\n\teditIndex: number;\n\tmatchIndex: number;\n\tmatchLength: number;\n\tnewText: string;\n}\n\ntype TextReplacement = Pick<MatchedEdit, \"matchIndex\" | \"matchLength\" | \"newText\">;\n\nfunction getLineSpans(content: string): LineSpan[] {\n\tlet offset = 0;\n\treturn splitLinesWithEndings(content).map((line) => {\n\t\tconst span = { start: offset, end: offset + line.length };\n\t\toffset = span.end;\n\t\treturn span;\n\t});\n}\n\nfunction getReplacementLineRange(lines: LineSpan[], replacement: TextReplacement) {\n\tconst replacementStart = replacement.matchIndex;\n\tconst replacementEnd = replacement.matchIndex + replacement.matchLength;\n\n\tlet startLine = -1;\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i];\n\t\tif (replacementStart >= line.start && replacementStart < line.end) {\n\t\t\tstartLine = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (startLine === -1) {\n\t\tthrow new Error(\"Replacement range is outside the base content.\");\n\t}\n\n\tlet endLine = startLine;\n\twhile (endLine < lines.length && lines[endLine].end < replacementEnd) {\n\t\tendLine++;\n\t}\n\tif (endLine >= lines.length) {\n\t\tthrow new Error(\"Replacement range is outside the base content.\");\n\t}\n\n\treturn { startLine, endLine: endLine + 1 };\n}\n\nfunction applyReplacements(content: string, replacements: TextReplacement[], offset = 0): string {\n\tlet result = content;\n\tfor (let i = replacements.length - 1; i >= 0; i--) {\n\t\tconst replacement = replacements[i];\n\t\tconst matchIndex = replacement.matchIndex - offset;\n\t\tresult =\n\t\t\tresult.substring(0, matchIndex) + replacement.newText + result.substring(matchIndex + replacement.matchLength);\n\t}\n\treturn result;\n}\n\n/**\n * Apply replacements matched against `baseContent` to `originalContent` while\n * preserving unchanged line blocks from the original.\n *\n * This is useful when `baseContent` is a normalized view of the original. Each\n * replacement is widened to the lines it actually touches, those touched lines\n * are rewritten from the normalized base, and all other lines are copied back\n * from `originalContent`. The actual replacement ranges drive preservation so\n * duplicate normalized lines cannot be aligned to the wrong occurrence.\n */\nexport function applyReplacementsPreservingUnchangedLines(\n\toriginalContent: string,\n\tbaseContent: string,\n\treplacements: TextReplacement[],\n): string {\n\tconst originalLines = splitLinesWithEndings(originalContent);\n\tconst baseLines = getLineSpans(baseContent);\n\tif (originalLines.length !== baseLines.length) {\n\t\tthrow new Error(\"Cannot preserve unchanged lines because the base content has a different line count.\");\n\t}\n\n\tconst groups: Array<{ startLine: number; endLine: number; replacements: TextReplacement[] }> = [];\n\tconst sortedReplacements = [...replacements].sort((a, b) => a.matchIndex - b.matchIndex);\n\tfor (const replacement of sortedReplacements) {\n\t\tconst range = getReplacementLineRange(baseLines, replacement);\n\t\tconst current = groups[groups.length - 1];\n\t\tif (current && range.startLine < current.endLine) {\n\t\t\tcurrent.endLine = Math.max(current.endLine, range.endLine);\n\t\t\tcurrent.replacements.push(replacement);\n\t\t\tcontinue;\n\t\t}\n\t\tgroups.push({ ...range, replacements: [replacement] });\n\t}\n\n\tlet originalLineIndex = 0;\n\tlet result = \"\";\n\tfor (const group of groups) {\n\t\tresult += originalLines.slice(originalLineIndex, group.startLine).join(\"\");\n\n\t\tconst groupStartOffset = baseLines[group.startLine].start;\n\t\tconst groupEndOffset = baseLines[group.endLine - 1].end;\n\t\tresult += applyReplacements(\n\t\t\tbaseContent.slice(groupStartOffset, groupEndOffset),\n\t\t\tgroup.replacements,\n\t\t\tgroupStartOffset,\n\t\t);\n\t\toriginalLineIndex = group.endLine;\n\t}\n\tresult += originalLines.slice(originalLineIndex).join(\"\");\n\n\treturn result;\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\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, return offsets in normalized space. Callers can use\n\t// the normalized content to compute replacements, then decide how much of\n\t// that normalized output should be written back.\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}\n\n/** Strip UTF-8 BOM if present, return both the BOM (if any) and the text without it */\nexport function stripBom(content: string): { bom: string; text: string } {\n\treturn content.startsWith(\"\\uFEFF\") ? { bom: \"\\uFEFF\", text: content.slice(1) } : { bom: \"\", text: content };\n}\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 and then\n * overlays those line-level changes onto the original content so unchanged line\n * blocks keep their original bytes.\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 usedFuzzyMatch = initialMatches.some((match) => match.usedFuzzyMatch);\n\tconst replacementBaseContent = usedFuzzyMatch ? normalizeForFuzzyMatch(normalizedContent) : 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(replacementBaseContent, 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(replacementBaseContent, 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\tconst baseContent = normalizedContent;\n\tconst newContent = usedFuzzyMatch\n\t\t? applyReplacementsPreservingUnchangedLines(normalizedContent, replacementBaseContent, matchedEdits)\n\t\t: applyReplacements(replacementBaseContent, matchedEdits);\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\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(\n\toldContent: string,\n\tnewContent: string,\n\tcontextLines = 4,\n): { diff: string; firstChangedLine: number | undefined } {\n\tconst parts = Diff.diffLines(oldContent, newContent);\n\tconst output: string[] = [];\n\n\tconst oldLines = oldContent.split(\"\\n\");\n\tconst newLines = newContent.split(\"\\n\");\n\tconst maxLineNum = Math.max(oldLines.length, newLines.length);\n\tconst lineNumWidth = String(maxLineNum).length;\n\n\tlet oldLineNum = 1;\n\tlet newLineNum = 1;\n\tlet lastWasChange = false;\n\tlet firstChangedLine: number | undefined;\n\n\tfor (let i = 0; i < parts.length; i++) {\n\t\tconst part = parts[i];\n\t\tconst raw = part.value.split(\"\\n\");\n\t\tif (raw[raw.length - 1] === \"\") {\n\t\t\traw.pop();\n\t\t}\n\n\t\tif (part.added || part.removed) {\n\t\t\t// Capture the first changed line (in the new file)\n\t\t\tif (firstChangedLine === undefined) {\n\t\t\t\tfirstChangedLine = newLineNum;\n\t\t\t}\n\n\t\t\t// Show the change\n\t\t\tfor (const line of raw) {\n\t\t\t\tif (part.added) {\n\t\t\t\t\tconst lineNum = String(newLineNum).padStart(lineNumWidth, \" \");\n\t\t\t\t\toutput.push(`+${lineNum} ${line}`);\n\t\t\t\t\tnewLineNum++;\n\t\t\t\t} else {\n\t\t\t\t\t// removed\n\t\t\t\t\tconst lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n\t\t\t\t\toutput.push(`-${lineNum} ${line}`);\n\t\t\t\t\toldLineNum++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tlastWasChange = true;\n\t\t} else {\n\t\t\t// Context lines - only show a few before/after changes\n\t\t\tconst nextPartIsChange = i < parts.length - 1 && (parts[i + 1].added || parts[i + 1].removed);\n\t\t\tconst hasLeadingChange = lastWasChange;\n\t\t\tconst hasTrailingChange = nextPartIsChange;\n\n\t\t\tif (hasLeadingChange && hasTrailingChange) {\n\t\t\t\tif (raw.length <= contextLines * 2) {\n\t\t\t\t\tfor (const line of raw) {\n\t\t\t\t\t\tconst lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n\t\t\t\t\t\toutput.push(` ${lineNum} ${line}`);\n\t\t\t\t\t\toldLineNum++;\n\t\t\t\t\t\tnewLineNum++;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst leadingLines = raw.slice(0, contextLines);\n\t\t\t\t\tconst trailingLines = raw.slice(raw.length - contextLines);\n\t\t\t\t\tconst skippedLines = raw.length - leadingLines.length - trailingLines.length;\n\n\t\t\t\t\tfor (const line of leadingLines) {\n\t\t\t\t\t\tconst lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n\t\t\t\t\t\toutput.push(` ${lineNum} ${line}`);\n\t\t\t\t\t\toldLineNum++;\n\t\t\t\t\t\tnewLineNum++;\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n\t\t\t\t\toldLineNum += skippedLines;\n\t\t\t\t\tnewLineNum += skippedLines;\n\n\t\t\t\t\tfor (const line of trailingLines) {\n\t\t\t\t\t\tconst lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n\t\t\t\t\t\toutput.push(` ${lineNum} ${line}`);\n\t\t\t\t\t\toldLineNum++;\n\t\t\t\t\t\tnewLineNum++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (hasLeadingChange) {\n\t\t\t\tconst shownLines = raw.slice(0, contextLines);\n\t\t\t\tconst skippedLines = raw.length - shownLines.length;\n\n\t\t\t\tfor (const line of shownLines) {\n\t\t\t\t\tconst lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n\t\t\t\t\toutput.push(` ${lineNum} ${line}`);\n\t\t\t\t\toldLineNum++;\n\t\t\t\t\tnewLineNum++;\n\t\t\t\t}\n\n\t\t\t\tif (skippedLines > 0) {\n\t\t\t\t\toutput.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n\t\t\t\t\toldLineNum += skippedLines;\n\t\t\t\t\tnewLineNum += skippedLines;\n\t\t\t\t}\n\t\t\t} else if (hasTrailingChange) {\n\t\t\t\tconst skippedLines = Math.max(0, raw.length - contextLines);\n\t\t\t\tif (skippedLines > 0) {\n\t\t\t\t\toutput.push(` ${\"\".padStart(lineNumWidth, \" \")} ...`);\n\t\t\t\t\toldLineNum += skippedLines;\n\t\t\t\t\tnewLineNum += skippedLines;\n\t\t\t\t}\n\n\t\t\t\tfor (const line of raw.slice(skippedLines)) {\n\t\t\t\t\tconst lineNum = String(oldLineNum).padStart(lineNumWidth, \" \");\n\t\t\t\t\toutput.push(` ${lineNum} ${line}`);\n\t\t\t\t\toldLineNum++;\n\t\t\t\t\tnewLineNum++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Skip these context lines entirely\n\t\t\t\toldLineNum += raw.length;\n\t\t\t\tnewLineNum += raw.length;\n\t\t\t}\n\n\t\t\tlastWasChange = false;\n\t\t}\n\t}\n\n\treturn { diff: output.join(\"\\n\"), firstChangedLine };\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import { type Static, Type } from "typebox";
2
+ import type { ToolRegistration } from "../harness/types.ts";
3
+ declare const editSchema: Type.TObject<{
4
+ path: Type.TString;
5
+ edits: Type.TArray<Type.TObject<{
6
+ oldText: Type.TString;
7
+ newText: Type.TString;
8
+ }>>;
9
+ }>;
10
+ export type EditToolInput = Static<typeof editSchema>;
11
+ export type EditToolDetails = {
12
+ diff: string;
13
+ patch: string;
14
+ firstChangedLine?: number;
15
+ };
16
+ export declare function createEditTool(): ToolRegistration<typeof editSchema, EditToolDetails>;
17
+ export {};
18
+ //# sourceMappingURL=edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAuB5D,QAAA,MAAM,UAAU;;;;;;EAMd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAsCtD,MAAM,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAaF,wBAAgB,cAAc,IAAI,gBAAgB,CAAC,OAAO,UAAU,EAAE,eAAe,CAAC,CAsDrF"}