@code-yeongyu/senpi-agent-core 2026.9.12 → 2026.9.13

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 (344) hide show
  1. package/README.md +4 -0
  2. package/dist/harness/agent-harness.d.ts +639 -384
  3. package/dist/harness/agent-harness.d.ts.map +1 -1
  4. package/dist/harness/agent-harness.js +5 -250
  5. package/dist/harness/agent-harness.js.map +1 -1
  6. package/dist/harness/compaction/branch-summarization.d.ts +12 -6
  7. package/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  8. package/dist/harness/compaction/branch-summarization.js +33 -27
  9. package/dist/harness/compaction/branch-summarization.js.map +1 -1
  10. package/dist/harness/compaction/compaction.d.ts +30 -8
  11. package/dist/harness/compaction/compaction.d.ts.map +1 -1
  12. package/dist/harness/compaction/compaction.js +53 -64
  13. package/dist/harness/compaction/compaction.js.map +1 -1
  14. package/dist/harness/config.d.ts +9 -0
  15. package/dist/harness/config.d.ts.map +1 -0
  16. package/dist/harness/config.js +35 -0
  17. package/dist/harness/config.js.map +1 -0
  18. package/dist/harness/context.d.ts +9 -0
  19. package/dist/harness/context.d.ts.map +1 -0
  20. package/dist/harness/context.js +13 -0
  21. package/dist/harness/context.js.map +1 -0
  22. package/dist/harness/env/nodejs.d.ts +25 -28
  23. package/dist/harness/env/nodejs.d.ts.map +1 -1
  24. package/dist/harness/env/nodejs.js +368 -125
  25. package/dist/harness/env/nodejs.js.map +1 -1
  26. package/dist/harness/events.d.ts +20 -38
  27. package/dist/harness/events.d.ts.map +1 -1
  28. package/dist/harness/events.js +233 -55
  29. package/dist/harness/events.js.map +1 -1
  30. package/dist/harness/execution/assistant.d.ts +42 -0
  31. package/dist/harness/execution/assistant.d.ts.map +1 -0
  32. package/dist/harness/execution/assistant.js +82 -0
  33. package/dist/harness/execution/assistant.js.map +1 -0
  34. package/dist/harness/execution/effect-gate.d.ts +22 -0
  35. package/dist/harness/execution/effect-gate.d.ts.map +1 -0
  36. package/dist/harness/execution/effect-gate.js +48 -0
  37. package/dist/harness/execution/effect-gate.js.map +1 -0
  38. package/dist/harness/execution/tools.d.ts +67 -0
  39. package/dist/harness/execution/tools.d.ts.map +1 -0
  40. package/dist/harness/execution/tools.js +121 -0
  41. package/dist/harness/execution/tools.js.map +1 -0
  42. package/dist/harness/hooks.d.ts +38 -0
  43. package/dist/harness/hooks.d.ts.map +1 -0
  44. package/dist/harness/hooks.js +404 -0
  45. package/dist/harness/hooks.js.map +1 -0
  46. package/dist/harness/messages.d.ts +2 -2
  47. package/dist/harness/messages.d.ts.map +1 -1
  48. package/dist/harness/messages.js.map +1 -1
  49. package/dist/harness/prompt-templates.d.ts +3 -2
  50. package/dist/harness/prompt-templates.d.ts.map +1 -1
  51. package/dist/harness/prompt-templates.js +17 -17
  52. package/dist/harness/prompt-templates.js.map +1 -1
  53. package/dist/harness/result.d.ts +93 -0
  54. package/dist/harness/result.d.ts.map +1 -1
  55. package/dist/harness/result.js +39 -0
  56. package/dist/harness/result.js.map +1 -1
  57. package/dist/harness/runtime/drive/boundary.d.ts +28 -0
  58. package/dist/harness/runtime/drive/boundary.d.ts.map +1 -0
  59. package/dist/harness/runtime/drive/boundary.js +173 -0
  60. package/dist/harness/runtime/drive/boundary.js.map +1 -0
  61. package/dist/harness/runtime/drive/checkpoint.d.ts +8 -0
  62. package/dist/harness/runtime/drive/checkpoint.d.ts.map +1 -0
  63. package/dist/harness/runtime/drive/checkpoint.js +133 -0
  64. package/dist/harness/runtime/drive/checkpoint.js.map +1 -0
  65. package/dist/harness/runtime/drive/deferred.d.ts +15 -0
  66. package/dist/harness/runtime/drive/deferred.d.ts.map +1 -0
  67. package/dist/harness/runtime/drive/deferred.js +179 -0
  68. package/dist/harness/runtime/drive/deferred.js.map +1 -0
  69. package/dist/harness/runtime/drive/generation.d.ts +8 -0
  70. package/dist/harness/runtime/drive/generation.d.ts.map +1 -0
  71. package/dist/harness/runtime/drive/generation.js +205 -0
  72. package/dist/harness/runtime/drive/generation.js.map +1 -0
  73. package/dist/harness/runtime/drive/reconcile.d.ts +5 -0
  74. package/dist/harness/runtime/drive/reconcile.d.ts.map +1 -0
  75. package/dist/harness/runtime/drive/reconcile.js +140 -0
  76. package/dist/harness/runtime/drive/reconcile.js.map +1 -0
  77. package/dist/harness/runtime/drive/recovery.d.ts +8 -0
  78. package/dist/harness/runtime/drive/recovery.d.ts.map +1 -0
  79. package/dist/harness/runtime/drive/recovery.js +85 -0
  80. package/dist/harness/runtime/drive/recovery.js.map +1 -0
  81. package/dist/harness/runtime/drive/response.d.ts +23 -0
  82. package/dist/harness/runtime/drive/response.d.ts.map +1 -0
  83. package/dist/harness/runtime/drive/response.js +394 -0
  84. package/dist/harness/runtime/drive/response.js.map +1 -0
  85. package/dist/harness/runtime/drive/retry.d.ts +4 -0
  86. package/dist/harness/runtime/drive/retry.d.ts.map +1 -0
  87. package/dist/harness/runtime/drive/retry.js +34 -0
  88. package/dist/harness/runtime/drive/retry.js.map +1 -0
  89. package/dist/harness/runtime/drive/structural.d.ts +32 -0
  90. package/dist/harness/runtime/drive/structural.d.ts.map +1 -0
  91. package/dist/harness/runtime/drive/structural.js +929 -0
  92. package/dist/harness/runtime/drive/structural.js.map +1 -0
  93. package/dist/harness/runtime/drive/terminal.d.ts +7 -0
  94. package/dist/harness/runtime/drive/terminal.d.ts.map +1 -0
  95. package/dist/harness/runtime/drive/terminal.js +49 -0
  96. package/dist/harness/runtime/drive/terminal.js.map +1 -0
  97. package/dist/harness/runtime/drive/tool-placement.d.ts +14 -0
  98. package/dist/harness/runtime/drive/tool-placement.d.ts.map +1 -0
  99. package/dist/harness/runtime/drive/tool-placement.js +244 -0
  100. package/dist/harness/runtime/drive/tool-placement.js.map +1 -0
  101. package/dist/harness/runtime/drive/tools.d.ts +6 -0
  102. package/dist/harness/runtime/drive/tools.d.ts.map +1 -0
  103. package/dist/harness/runtime/drive/tools.js +449 -0
  104. package/dist/harness/runtime/drive/tools.js.map +1 -0
  105. package/dist/harness/runtime/drive.d.ts +6 -0
  106. package/dist/harness/runtime/drive.d.ts.map +1 -0
  107. package/dist/harness/runtime/drive.js +93 -0
  108. package/dist/harness/runtime/drive.js.map +1 -0
  109. package/dist/harness/runtime/harness.d.ts +59 -0
  110. package/dist/harness/runtime/harness.d.ts.map +1 -0
  111. package/dist/harness/runtime/harness.js +302 -0
  112. package/dist/harness/runtime/harness.js.map +1 -0
  113. package/dist/harness/runtime/index.d.ts +2 -0
  114. package/dist/harness/runtime/index.d.ts.map +1 -0
  115. package/dist/harness/runtime/index.js +2 -0
  116. package/dist/harness/runtime/index.js.map +1 -0
  117. package/dist/harness/runtime/lane.d.ts +118 -0
  118. package/dist/harness/runtime/lane.d.ts.map +1 -0
  119. package/dist/harness/runtime/lane.js +1559 -0
  120. package/dist/harness/runtime/lane.js.map +1 -0
  121. package/dist/harness/runtime/progress.d.ts +15 -0
  122. package/dist/harness/runtime/progress.d.ts.map +1 -0
  123. package/dist/harness/runtime/progress.js +66 -0
  124. package/dist/harness/runtime/progress.js.map +1 -0
  125. package/dist/harness/runtime/reducer.d.ts +5 -0
  126. package/dist/harness/runtime/reducer.d.ts.map +1 -0
  127. package/dist/harness/runtime/reducer.js +240 -0
  128. package/dist/harness/runtime/reducer.js.map +1 -0
  129. package/dist/harness/runtime/restore.d.ts +24 -0
  130. package/dist/harness/runtime/restore.d.ts.map +1 -0
  131. package/dist/harness/runtime/restore.js +117 -0
  132. package/dist/harness/runtime/restore.js.map +1 -0
  133. package/dist/harness/runtime/transcript.d.ts +21 -0
  134. package/dist/harness/runtime/transcript.d.ts.map +1 -0
  135. package/dist/harness/runtime/transcript.js +72 -0
  136. package/dist/harness/runtime/transcript.js.map +1 -0
  137. package/dist/harness/runtime/types.d.ts +105 -0
  138. package/dist/harness/runtime/types.d.ts.map +1 -0
  139. package/dist/harness/runtime/types.js +50 -0
  140. package/dist/harness/runtime/types.js.map +1 -0
  141. package/dist/harness/session/commit.d.ts +53 -0
  142. package/dist/harness/session/commit.d.ts.map +1 -0
  143. package/dist/harness/session/commit.js +57 -0
  144. package/dist/harness/session/commit.js.map +1 -0
  145. package/dist/harness/session/context.d.ts +6 -19
  146. package/dist/harness/session/context.d.ts.map +1 -1
  147. package/dist/harness/session/context.js +31 -53
  148. package/dist/harness/session/context.js.map +1 -1
  149. package/dist/harness/session/fork-policy.d.ts +21 -0
  150. package/dist/harness/session/fork-policy.d.ts.map +1 -0
  151. package/dist/harness/session/fork-policy.js +55 -0
  152. package/dist/harness/session/fork-policy.js.map +1 -0
  153. package/dist/harness/session/fork.d.ts +16 -0
  154. package/dist/harness/session/fork.d.ts.map +1 -0
  155. package/dist/harness/session/fork.js +79 -0
  156. package/dist/harness/session/fork.js.map +1 -0
  157. package/dist/harness/session/in-memory-storage-state.d.ts +39 -0
  158. package/dist/harness/session/in-memory-storage-state.d.ts.map +1 -0
  159. package/dist/harness/session/in-memory-storage-state.js +269 -0
  160. package/dist/harness/session/in-memory-storage-state.js.map +1 -0
  161. package/dist/harness/session/index.d.ts +9 -5
  162. package/dist/harness/session/index.d.ts.map +1 -1
  163. package/dist/harness/session/index.js +7 -4
  164. package/dist/harness/session/index.js.map +1 -1
  165. package/dist/harness/session/jsonl/codec.d.ts +19 -8
  166. package/dist/harness/session/jsonl/codec.d.ts.map +1 -1
  167. package/dist/harness/session/jsonl/codec.js +34 -219
  168. package/dist/harness/session/jsonl/codec.js.map +1 -1
  169. package/dist/harness/session/jsonl/fork.d.ts +38 -0
  170. package/dist/harness/session/jsonl/fork.d.ts.map +1 -0
  171. package/dist/harness/session/jsonl/fork.js +266 -0
  172. package/dist/harness/session/jsonl/fork.js.map +1 -0
  173. package/dist/harness/session/jsonl/index.d.ts +4 -0
  174. package/dist/harness/session/jsonl/index.d.ts.map +1 -0
  175. package/dist/harness/session/jsonl/index.js +4 -0
  176. package/dist/harness/session/jsonl/index.js.map +1 -0
  177. package/dist/harness/session/jsonl/io.d.ts +14 -0
  178. package/dist/harness/session/jsonl/io.d.ts.map +1 -0
  179. package/dist/harness/session/jsonl/io.js +86 -0
  180. package/dist/harness/session/jsonl/io.js.map +1 -0
  181. package/dist/harness/session/jsonl/legacy-v3.d.ts +44 -0
  182. package/dist/harness/session/jsonl/legacy-v3.d.ts.map +1 -0
  183. package/dist/harness/session/jsonl/legacy-v3.js +454 -0
  184. package/dist/harness/session/jsonl/legacy-v3.js.map +1 -0
  185. package/dist/harness/session/jsonl/repo.d.ts +27 -24
  186. package/dist/harness/session/jsonl/repo.d.ts.map +1 -1
  187. package/dist/harness/session/jsonl/repo.js +276 -151
  188. package/dist/harness/session/jsonl/repo.js.map +1 -1
  189. package/dist/harness/session/jsonl/storage.d.ts +39 -41
  190. package/dist/harness/session/jsonl/storage.d.ts.map +1 -1
  191. package/dist/harness/session/jsonl/storage.js +175 -196
  192. package/dist/harness/session/jsonl/storage.js.map +1 -1
  193. package/dist/harness/session/jsonl/types.d.ts +23 -22
  194. package/dist/harness/session/jsonl/types.d.ts.map +1 -1
  195. package/dist/harness/session/jsonl/types.js +2 -1
  196. package/dist/harness/session/jsonl/types.js.map +1 -1
  197. package/dist/harness/session/memory.d.ts +44 -40
  198. package/dist/harness/session/memory.d.ts.map +1 -1
  199. package/dist/harness/session/memory.js +333 -115
  200. package/dist/harness/session/memory.js.map +1 -1
  201. package/dist/harness/session/mutation-line.d.ts +8 -0
  202. package/dist/harness/session/mutation-line.d.ts.map +1 -0
  203. package/dist/harness/session/mutation-line.js +22 -0
  204. package/dist/harness/session/mutation-line.js.map +1 -0
  205. package/dist/harness/session/session.d.ts +78 -51
  206. package/dist/harness/session/session.d.ts.map +1 -1
  207. package/dist/harness/session/session.js +327 -207
  208. package/dist/harness/session/session.js.map +1 -1
  209. package/dist/harness/session/testing/benchmark/datasets.d.ts +12 -0
  210. package/dist/harness/session/testing/benchmark/datasets.d.ts.map +1 -0
  211. package/dist/harness/session/testing/benchmark/datasets.js +24 -0
  212. package/dist/harness/session/testing/benchmark/datasets.js.map +1 -0
  213. package/dist/harness/session/testing/benchmark/session-repo.d.ts +42 -0
  214. package/dist/harness/session/testing/benchmark/session-repo.d.ts.map +1 -0
  215. package/dist/harness/session/testing/benchmark/session-repo.js +127 -0
  216. package/dist/harness/session/testing/benchmark/session-repo.js.map +1 -0
  217. package/dist/harness/session/testing/benchmark/storage.d.ts +25 -0
  218. package/dist/harness/session/testing/benchmark/storage.d.ts.map +1 -0
  219. package/dist/harness/session/testing/benchmark/storage.js +114 -0
  220. package/dist/harness/session/testing/benchmark/storage.js.map +1 -0
  221. package/dist/harness/session/testing/conformance/session-repo.d.ts +23 -0
  222. package/dist/harness/session/testing/conformance/session-repo.d.ts.map +1 -0
  223. package/dist/harness/session/testing/conformance/session-repo.js +809 -0
  224. package/dist/harness/session/testing/conformance/session-repo.js.map +1 -0
  225. package/dist/harness/session/testing/conformance/storage.d.ts +4 -0
  226. package/dist/harness/session/testing/conformance/storage.d.ts.map +1 -0
  227. package/dist/harness/session/testing/conformance/storage.js +600 -0
  228. package/dist/harness/session/testing/conformance/storage.js.map +1 -0
  229. package/dist/harness/session/testing/gating-storage.d.ts +26 -0
  230. package/dist/harness/session/testing/gating-storage.d.ts.map +1 -0
  231. package/dist/harness/session/testing/gating-storage.js +103 -0
  232. package/dist/harness/session/testing/gating-storage.js.map +1 -0
  233. package/dist/harness/session/testing/index.d.ts +9 -2
  234. package/dist/harness/session/testing/index.d.ts.map +1 -1
  235. package/dist/harness/session/testing/index.js +8 -1
  236. package/dist/harness/session/testing/index.js.map +1 -1
  237. package/dist/harness/session/testing/instrumented-storage.d.ts +11 -0
  238. package/dist/harness/session/testing/instrumented-storage.d.ts.map +1 -0
  239. package/dist/harness/session/testing/instrumented-storage.js +19 -0
  240. package/dist/harness/session/testing/instrumented-storage.js.map +1 -0
  241. package/dist/harness/session/testing/storage-decorator.d.ts +20 -0
  242. package/dist/harness/session/testing/storage-decorator.d.ts.map +1 -0
  243. package/dist/harness/session/testing/storage-decorator.js +40 -0
  244. package/dist/harness/session/testing/storage-decorator.js.map +1 -0
  245. package/dist/harness/session/testing/types.d.ts +5 -7
  246. package/dist/harness/session/testing/types.d.ts.map +1 -1
  247. package/dist/harness/session/testing/types.js.map +1 -1
  248. package/dist/harness/session/types.d.ts +425 -265
  249. package/dist/harness/session/types.d.ts.map +1 -1
  250. package/dist/harness/session/types.js +7 -7
  251. package/dist/harness/session/types.js.map +1 -1
  252. package/dist/harness/session/values.d.ts +95 -0
  253. package/dist/harness/session/values.d.ts.map +1 -0
  254. package/dist/harness/session/values.js +81 -0
  255. package/dist/harness/session/values.js.map +1 -0
  256. package/dist/harness/skills.d.ts +3 -2
  257. package/dist/harness/skills.d.ts.map +1 -1
  258. package/dist/harness/skills.js +29 -26
  259. package/dist/harness/skills.js.map +1 -1
  260. package/dist/harness/telemetry.d.ts +64 -43
  261. package/dist/harness/telemetry.d.ts.map +1 -1
  262. package/dist/harness/telemetry.js +45 -26
  263. package/dist/harness/telemetry.js.map +1 -1
  264. package/dist/harness/tools/bash.d.ts +4 -4
  265. package/dist/harness/tools/bash.d.ts.map +1 -1
  266. package/dist/harness/tools/bash.js +66 -93
  267. package/dist/harness/tools/bash.js.map +1 -1
  268. package/dist/harness/tools/edit.d.ts.map +1 -1
  269. package/dist/harness/tools/edit.js +17 -13
  270. package/dist/harness/tools/edit.js.map +1 -1
  271. package/dist/harness/tools/file-mutation-queue.d.ts +2 -1
  272. package/dist/harness/tools/file-mutation-queue.d.ts.map +1 -1
  273. package/dist/harness/tools/file-mutation-queue.js +5 -5
  274. package/dist/harness/tools/file-mutation-queue.js.map +1 -1
  275. package/dist/harness/tools/path-utils.d.ts +3 -2
  276. package/dist/harness/tools/path-utils.d.ts.map +1 -1
  277. package/dist/harness/tools/path-utils.js +5 -5
  278. package/dist/harness/tools/path-utils.js.map +1 -1
  279. package/dist/harness/tools/read.d.ts +2 -1
  280. package/dist/harness/tools/read.d.ts.map +1 -1
  281. package/dist/harness/tools/read.js +4 -6
  282. package/dist/harness/tools/read.js.map +1 -1
  283. package/dist/harness/tools/write.d.ts.map +1 -1
  284. package/dist/harness/tools/write.js +12 -8
  285. package/dist/harness/tools/write.js.map +1 -1
  286. package/dist/harness/types.d.ts +128 -45
  287. package/dist/harness/types.d.ts.map +1 -1
  288. package/dist/harness/types.js.map +1 -1
  289. package/dist/harness/utils/adaptive-publisher.d.ts +24 -0
  290. package/dist/harness/utils/adaptive-publisher.d.ts.map +1 -0
  291. package/dist/harness/utils/adaptive-publisher.js +79 -0
  292. package/dist/harness/utils/adaptive-publisher.js.map +1 -0
  293. package/dist/harness/utils/output-capture.d.ts +31 -0
  294. package/dist/harness/utils/output-capture.d.ts.map +1 -0
  295. package/dist/harness/utils/output-capture.js +217 -0
  296. package/dist/harness/utils/output-capture.js.map +1 -0
  297. package/dist/harness/utils/shell-output.d.ts +19 -5
  298. package/dist/harness/utils/shell-output.d.ts.map +1 -1
  299. package/dist/harness/utils/shell-output.js +65 -192
  300. package/dist/harness/utils/shell-output.js.map +1 -1
  301. package/dist/harness/utils/truncate.d.ts +1 -0
  302. package/dist/harness/utils/truncate.d.ts.map +1 -1
  303. package/dist/harness/utils/truncate.js +1 -1
  304. package/dist/harness/utils/truncate.js.map +1 -1
  305. package/dist/harness/utils/usage.d.ts +4 -0
  306. package/dist/harness/utils/usage.d.ts.map +1 -0
  307. package/dist/harness/utils/usage.js +33 -0
  308. package/dist/harness/utils/usage.js.map +1 -0
  309. package/dist/index.d.ts +4 -1
  310. package/dist/index.d.ts.map +1 -1
  311. package/dist/index.js +3 -6
  312. package/dist/index.js.map +1 -1
  313. package/dist/search/index.d.ts +24 -16
  314. package/dist/search/index.d.ts.map +1 -1
  315. package/dist/search/index.js +1 -1
  316. package/dist/search/index.js.map +1 -1
  317. package/dist/types.d.ts +2 -0
  318. package/dist/types.d.ts.map +1 -1
  319. package/dist/types.js.map +1 -1
  320. package/package.json +27 -6
  321. package/dist/harness/reducer.d.ts +0 -100
  322. package/dist/harness/reducer.d.ts.map +0 -1
  323. package/dist/harness/reducer.js +0 -420
  324. package/dist/harness/reducer.js.map +0 -1
  325. package/dist/harness/session/jsonl/errors.d.ts +0 -9
  326. package/dist/harness/session/jsonl/errors.d.ts.map +0 -1
  327. package/dist/harness/session/jsonl/errors.js +0 -18
  328. package/dist/harness/session/jsonl/errors.js.map +0 -1
  329. package/dist/harness/session/jsonl.d.ts +0 -3
  330. package/dist/harness/session/jsonl.d.ts.map +0 -1
  331. package/dist/harness/session/jsonl.js +0 -2
  332. package/dist/harness/session/jsonl.js.map +0 -1
  333. package/dist/harness/session/state.d.ts +0 -65
  334. package/dist/harness/session/state.d.ts.map +0 -1
  335. package/dist/harness/session/state.js +0 -320
  336. package/dist/harness/session/state.js.map +0 -1
  337. package/dist/harness/session/testing/conformance.d.ts +0 -4
  338. package/dist/harness/session/testing/conformance.d.ts.map +0 -1
  339. package/dist/harness/session/testing/conformance.js +0 -762
  340. package/dist/harness/session/testing/conformance.js.map +0 -1
  341. package/dist/search/scanning.d.ts +0 -29
  342. package/dist/search/scanning.d.ts.map +0 -1
  343. package/dist/search/scanning.js +0 -103
  344. package/dist/search/scanning.js.map +0 -1
@@ -64,42 +64,46 @@ export function createEditTool() {
64
64
  description: "Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.",
65
65
  parameters: editSchema,
66
66
  prepareArguments: prepareEditArguments,
67
- async execute(_toolCallId, input, signal, _onUpdate, { env, postMutate }) {
67
+ async execute(_toolCallId, input, _onUpdate, { env, postMutate }, _invocation, context) {
68
68
  const { path, edits } = validateEditInput(input);
69
- const absolutePath = await resolveToolPath(env, path, signal);
69
+ const absolutePath = await resolveToolPath(env, path, context);
70
70
  return withFileMutationQueue(env, absolutePath, async () => {
71
- if (signal?.aborted)
71
+ if (context.abortSignal?.aborted)
72
72
  throw new Error("Operation aborted");
73
- const info = await env.fileInfo(absolutePath, signal);
73
+ const info = await env.fileInfo(absolutePath, context);
74
74
  if (!info.ok)
75
75
  throw editAccessError(path, info.error);
76
76
  if (info.value.kind !== "file" && info.value.kind !== "symlink") {
77
77
  throw new Error(`Could not edit file: ${path}. Path is not a file.`);
78
78
  }
79
- const readResult = await env.readTextFile(absolutePath, signal);
79
+ const readResult = await env.readTextFile(absolutePath, context);
80
80
  if (!readResult.ok)
81
81
  throw editAccessError(path, readResult.error);
82
- if (signal?.aborted)
82
+ if (context.abortSignal?.aborted)
83
83
  throw new Error("Operation aborted");
84
84
  const { bom, text: content } = stripBom(readResult.value);
85
85
  const originalEnding = detectLineEnding(content);
86
86
  const normalizedContent = normalizeToLF(content);
87
87
  const { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path);
88
- if (signal?.aborted)
88
+ if (context.abortSignal?.aborted)
89
89
  throw new Error("Operation aborted");
90
90
  const finalContent = bom + restoreLineEndings(newContent, originalEnding);
91
- const writeResult = await env.writeFile(absolutePath, finalContent, signal);
91
+ const writeResult = await env.writeFile(absolutePath, finalContent, context);
92
92
  if (!writeResult.ok)
93
93
  throw editAccessError(path, writeResult.error);
94
- if (signal?.aborted)
94
+ if (context.abortSignal?.aborted)
95
95
  throw new Error("Operation aborted");
96
- const outcome = await runPostMutate(postMutate, { tool: "edit", path: absolutePath, signal });
97
- if (signal?.aborted)
96
+ const outcome = await runPostMutate(postMutate, {
97
+ tool: "edit",
98
+ path: absolutePath,
99
+ signal: context.abortSignal,
100
+ });
101
+ if (context.abortSignal?.aborted)
98
102
  throw new Error("Operation aborted");
99
103
  let committedContent = newContent;
100
104
  let rereadNote;
101
105
  if (outcome.fileMayHaveChanged) {
102
- const postMutateRead = await env.readTextFile(absolutePath, signal);
106
+ const postMutateRead = await env.readTextFile(absolutePath, context);
103
107
  // The edit itself already landed, so an unreadable file is the hook's doing, not a
104
108
  // failed edit. Report it as a note rather than an error that misattributes the failure.
105
109
  if (postMutateRead.ok)
@@ -117,7 +121,7 @@ export function createEditTool() {
117
121
  firstChangedLine: diffResult.firstChangedLine,
118
122
  },
119
123
  };
120
- });
124
+ }, context);
121
125
  },
122
126
  };
123
127
  }
@@ -1 +1 @@
1
- {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/harness/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { AgentHarnessTool, FileError } from \"../types.ts\";\nimport {\n\tapplyEditsToNormalizedContent,\n\tdetectLineEnding,\n\ttype Edit,\n\tgenerateDiffString,\n\tgenerateUnifiedPatch,\n\tnormalizeToLF,\n\trestoreLineEndings,\n\tstripBom,\n} from \"./edit-diff.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { resolveToolPath } from \"./path-utils.ts\";\nimport { appendPostMutateNote, runPostMutate } from \"./post-mutate.ts\";\nimport type { ExecutionToolContext } from \"./tool-context.ts\";\n\nconst replaceEditSchema = Type.Object(\n\t{\n\t\toldText: Type.String({\n\t\t\tdescription:\n\t\t\t\t\"Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call.\",\n\t\t}),\n\t\tnewText: Type.String({ description: \"Replacement text for this targeted edit.\" }),\n\t},\n\t{},\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\tedits: Type.Array(replaceEditSchema, {\n\t\t\tdescription:\n\t\t\t\t\"One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead.\",\n\t\t}),\n\t},\n\t{},\n);\n\nexport type EditToolInput = Static<typeof editSchema>;\ntype LegacyEditToolInput = EditToolInput & { oldText?: unknown; newText?: unknown };\ntype SingleEditInput = { oldText: string; newText: string };\n\nfunction isSingleEditInput(value: unknown): value is SingleEditInput {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst edit = value as Record<string, unknown>;\n\treturn typeof edit.oldText === \"string\" && typeof edit.newText === \"string\";\n}\n\nexport interface EditToolDetails {\n\tdiff: string;\n\tpatch: string;\n\tfirstChangedLine?: number;\n}\n\nfunction prepareEditArguments(input: unknown): EditToolInput {\n\tif (!input || typeof input !== \"object\") return input as EditToolInput;\n\tconst args = input as Record<string, unknown>;\n\tif (typeof args.edits === \"string\") {\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(args.edits);\n\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\targs.edits = parsed;\n\t\t\t} else if (isSingleEditInput(parsed)) {\n\t\t\t\targs.edits = [parsed];\n\t\t\t}\n\t\t} catch {}\n\t} else if (isSingleEditInput(args.edits)) {\n\t\targs.edits = [args.edits];\n\t}\n\n\tconst legacy = args as LegacyEditToolInput;\n\tif (typeof legacy.oldText !== \"string\" || typeof legacy.newText !== \"string\") return args as EditToolInput;\n\tconst edits = Array.isArray(legacy.edits) ? [...legacy.edits] : [];\n\tedits.push({ oldText: legacy.oldText, newText: legacy.newText });\n\tconst { oldText: _oldText, newText: _newText, ...rest } = legacy;\n\treturn { ...rest, edits } as EditToolInput;\n}\n\nfunction validateEditInput(input: EditToolInput): { path: string; edits: Edit[] } {\n\tif (!Array.isArray(input.edits) || input.edits.length === 0) {\n\t\tthrow new Error(\"Edit tool input is invalid. edits must contain at least one replacement.\");\n\t}\n\treturn { path: input.path, edits: input.edits };\n}\n\nfunction editAccessError(path: string, error: FileError): Error {\n\treturn new Error(`Could not edit file: ${path}. Error code: ${error.code}.`, { cause: error });\n}\n\nexport function createEditTool<TContext extends ExecutionToolContext = ExecutionToolContext>(): AgentHarnessTool<\n\tTContext,\n\ttypeof editSchema,\n\tEditToolDetails | undefined\n> {\n\treturn {\n\t\tname: \"edit\",\n\t\tlabel: \"edit\",\n\t\tdescription:\n\t\t\t\"Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.\",\n\t\tparameters: editSchema,\n\t\tprepareArguments: prepareEditArguments,\n\t\tasync execute(_toolCallId, input, signal, _onUpdate, { env, postMutate }) {\n\t\t\tconst { path, edits } = validateEditInput(input);\n\t\t\tconst absolutePath = await resolveToolPath(env, path, signal);\n\t\t\treturn withFileMutationQueue(env, absolutePath, async () => {\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\tconst info = await env.fileInfo(absolutePath, signal);\n\t\t\t\tif (!info.ok) throw editAccessError(path, info.error);\n\t\t\t\tif (info.value.kind !== \"file\" && info.value.kind !== \"symlink\") {\n\t\t\t\t\tthrow new Error(`Could not edit file: ${path}. Path is not a file.`);\n\t\t\t\t}\n\n\t\t\t\tconst readResult = await env.readTextFile(absolutePath, signal);\n\t\t\t\tif (!readResult.ok) throw editAccessError(path, readResult.error);\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\tconst { bom, text: content } = stripBom(readResult.value);\n\t\t\t\tconst originalEnding = detectLineEnding(content);\n\t\t\t\tconst normalizedContent = normalizeToLF(content);\n\t\t\t\tconst { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path);\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\tconst finalContent = bom + restoreLineEndings(newContent, originalEnding);\n\t\t\t\tconst writeResult = await env.writeFile(absolutePath, finalContent, signal);\n\t\t\t\tif (!writeResult.ok) throw editAccessError(path, writeResult.error);\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\tconst outcome = await runPostMutate(postMutate, { tool: \"edit\", path: absolutePath, signal });\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\tlet committedContent = newContent;\n\t\t\t\tlet rereadNote: string | undefined;\n\t\t\t\tif (outcome.fileMayHaveChanged) {\n\t\t\t\t\tconst postMutateRead = await env.readTextFile(absolutePath, signal);\n\t\t\t\t\t// The edit itself already landed, so an unreadable file is the hook's doing, not a\n\t\t\t\t\t// failed edit. Report it as a note rather than an error that misattributes the failure.\n\t\t\t\t\tif (postMutateRead.ok) committedContent = normalizeToLF(stripBom(postMutateRead.value).text);\n\t\t\t\t\telse\n\t\t\t\t\t\trereadNote = `postMutate left the file unreadable: ${postMutateRead.error.code}. Reported diff describes the edit before the hook ran.`;\n\t\t\t\t}\n\n\t\t\t\tconst diffResult = generateDiffString(baseContent, committedContent);\n\t\t\t\tconst text = appendPostMutateNote(\n\t\t\t\t\t`Successfully replaced ${edits.length} block(s) in ${path}.`,\n\t\t\t\t\toutcome.note,\n\t\t\t\t\trereadNote,\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tdiff: diffResult.diff,\n\t\t\t\t\t\tpatch: generateUnifiedPatch(path, baseContent, committedContent),\n\t\t\t\t\t\tfirstChangedLine: diffResult.firstChangedLine,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/harness/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { AgentHarnessTool, FileError } from \"../types.ts\";\nimport {\n\tapplyEditsToNormalizedContent,\n\tdetectLineEnding,\n\ttype Edit,\n\tgenerateDiffString,\n\tgenerateUnifiedPatch,\n\tnormalizeToLF,\n\trestoreLineEndings,\n\tstripBom,\n} from \"./edit-diff.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { resolveToolPath } from \"./path-utils.ts\";\nimport { appendPostMutateNote, runPostMutate } from \"./post-mutate.ts\";\nimport type { ExecutionToolContext } from \"./tool-context.ts\";\n\nconst replaceEditSchema = Type.Object(\n\t{\n\t\toldText: Type.String({\n\t\t\tdescription:\n\t\t\t\t\"Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call.\",\n\t\t}),\n\t\tnewText: Type.String({ description: \"Replacement text for this targeted edit.\" }),\n\t},\n\t{},\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\tedits: Type.Array(replaceEditSchema, {\n\t\t\tdescription:\n\t\t\t\t\"One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead.\",\n\t\t}),\n\t},\n\t{},\n);\n\nexport type EditToolInput = Static<typeof editSchema>;\ntype LegacyEditToolInput = EditToolInput & { oldText?: unknown; newText?: unknown };\ntype SingleEditInput = { oldText: string; newText: string };\n\nfunction isSingleEditInput(value: unknown): value is SingleEditInput {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst edit = value as Record<string, unknown>;\n\treturn typeof edit.oldText === \"string\" && typeof edit.newText === \"string\";\n}\n\nexport interface EditToolDetails {\n\tdiff: string;\n\tpatch: string;\n\tfirstChangedLine?: number;\n}\n\nfunction prepareEditArguments(input: unknown): EditToolInput {\n\tif (!input || typeof input !== \"object\") return input as EditToolInput;\n\tconst args = input as Record<string, unknown>;\n\tif (typeof args.edits === \"string\") {\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(args.edits);\n\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\targs.edits = parsed;\n\t\t\t} else if (isSingleEditInput(parsed)) {\n\t\t\t\targs.edits = [parsed];\n\t\t\t}\n\t\t} catch {}\n\t} else if (isSingleEditInput(args.edits)) {\n\t\targs.edits = [args.edits];\n\t}\n\n\tconst legacy = args as LegacyEditToolInput;\n\tif (typeof legacy.oldText !== \"string\" || typeof legacy.newText !== \"string\") return args as EditToolInput;\n\tconst edits = Array.isArray(legacy.edits) ? [...legacy.edits] : [];\n\tedits.push({ oldText: legacy.oldText, newText: legacy.newText });\n\tconst { oldText: _oldText, newText: _newText, ...rest } = legacy;\n\treturn { ...rest, edits } as EditToolInput;\n}\n\nfunction validateEditInput(input: EditToolInput): { path: string; edits: Edit[] } {\n\tif (!Array.isArray(input.edits) || input.edits.length === 0) {\n\t\tthrow new Error(\"Edit tool input is invalid. edits must contain at least one replacement.\");\n\t}\n\treturn { path: input.path, edits: input.edits };\n}\n\nfunction editAccessError(path: string, error: FileError): Error {\n\treturn new Error(`Could not edit file: ${path}. Error code: ${error.code}.`, { cause: error });\n}\n\nexport function createEditTool<TContext extends ExecutionToolContext = ExecutionToolContext>(): AgentHarnessTool<\n\tTContext,\n\ttypeof editSchema,\n\tEditToolDetails | undefined\n> {\n\treturn {\n\t\tname: \"edit\",\n\t\tlabel: \"edit\",\n\t\tdescription:\n\t\t\t\"Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.\",\n\t\tparameters: editSchema,\n\t\tprepareArguments: prepareEditArguments,\n\t\tasync execute(_toolCallId, input, _onUpdate, { env, postMutate }, _invocation, context) {\n\t\t\tconst { path, edits } = validateEditInput(input);\n\t\t\tconst absolutePath = await resolveToolPath(env, path, context);\n\t\t\treturn withFileMutationQueue(\n\t\t\t\tenv,\n\t\t\t\tabsolutePath,\n\t\t\t\tasync () => {\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t\tconst info = await env.fileInfo(absolutePath, context);\n\t\t\t\t\tif (!info.ok) throw editAccessError(path, info.error);\n\t\t\t\t\tif (info.value.kind !== \"file\" && info.value.kind !== \"symlink\") {\n\t\t\t\t\t\tthrow new Error(`Could not edit file: ${path}. Path is not a file.`);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst readResult = await env.readTextFile(absolutePath, context);\n\t\t\t\t\tif (!readResult.ok) throw editAccessError(path, readResult.error);\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\t\tconst { bom, text: content } = stripBom(readResult.value);\n\t\t\t\t\tconst originalEnding = detectLineEnding(content);\n\t\t\t\t\tconst normalizedContent = normalizeToLF(content);\n\t\t\t\t\tconst { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path);\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\t\tconst finalContent = bom + restoreLineEndings(newContent, originalEnding);\n\t\t\t\t\tconst writeResult = await env.writeFile(absolutePath, finalContent, context);\n\t\t\t\t\tif (!writeResult.ok) throw editAccessError(path, writeResult.error);\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\t\tconst outcome = await runPostMutate(postMutate, {\n\t\t\t\t\t\ttool: \"edit\",\n\t\t\t\t\t\tpath: absolutePath,\n\t\t\t\t\t\tsignal: context.abortSignal,\n\t\t\t\t\t});\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\n\t\t\t\t\tlet committedContent = newContent;\n\t\t\t\t\tlet rereadNote: string | undefined;\n\t\t\t\t\tif (outcome.fileMayHaveChanged) {\n\t\t\t\t\t\tconst postMutateRead = await env.readTextFile(absolutePath, context);\n\t\t\t\t\t\t// The edit itself already landed, so an unreadable file is the hook's doing, not a\n\t\t\t\t\t\t// failed edit. Report it as a note rather than an error that misattributes the failure.\n\t\t\t\t\t\tif (postMutateRead.ok) committedContent = normalizeToLF(stripBom(postMutateRead.value).text);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\trereadNote = `postMutate left the file unreadable: ${postMutateRead.error.code}. Reported diff describes the edit before the hook ran.`;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst diffResult = generateDiffString(baseContent, committedContent);\n\t\t\t\t\tconst text = appendPostMutateNote(\n\t\t\t\t\t\t`Successfully replaced ${edits.length} block(s) in ${path}.`,\n\t\t\t\t\t\toutcome.note,\n\t\t\t\t\t\trereadNote,\n\t\t\t\t\t);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\tdiff: diffResult.diff,\n\t\t\t\t\t\t\tpatch: generateUnifiedPatch(path, baseContent, committedContent),\n\t\t\t\t\t\t\tfirstChangedLine: diffResult.firstChangedLine,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tcontext,\n\t\t\t);\n\t\t},\n\t};\n}\n"]}
@@ -1,4 +1,5 @@
1
+ import type { Context } from "../context.ts";
1
2
  import type { ExecutionEnv } from "../types.ts";
2
3
  /** Serialize file mutations targeting the same environment and canonical path. */
3
- export declare function withFileMutationQueue<T>(env: ExecutionEnv, path: string, fn: () => Promise<T>): Promise<T>;
4
+ export declare function withFileMutationQueue<T>(env: ExecutionEnv, path: string, fn: () => Promise<T>, context: Context): Promise<T>;
4
5
  //# sourceMappingURL=file-mutation-queue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-mutation-queue.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/file-mutation-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA2BhD,kFAAkF;AAClF,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA2BhH"}
1
+ {"version":3,"file":"file-mutation-queue.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/file-mutation-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA2BhD,kFAAkF;AAClF,wBAAsB,qBAAqB,CAAC,CAAC,EAC5C,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,CAAC,CAAC,CA2BZ"}
@@ -8,9 +8,9 @@ function getState(env) {
8
8
  }
9
9
  return state;
10
10
  }
11
- async function getMutationQueueKey(env, path) {
12
- const absolutePath = getOrThrow(await env.absolutePath(path));
13
- const canonicalPath = await env.canonicalPath(absolutePath);
11
+ async function getMutationQueueKey(env, path, context) {
12
+ const absolutePath = getOrThrow(await env.absolutePath(path, context));
13
+ const canonicalPath = await env.canonicalPath(absolutePath, context);
14
14
  if (canonicalPath.ok)
15
15
  return canonicalPath.value;
16
16
  if (canonicalPath.error.code === "not_found" || canonicalPath.error.code === "not_supported")
@@ -18,10 +18,10 @@ async function getMutationQueueKey(env, path) {
18
18
  throw canonicalPath.error;
19
19
  }
20
20
  /** Serialize file mutations targeting the same environment and canonical path. */
21
- export async function withFileMutationQueue(env, path, fn) {
21
+ export async function withFileMutationQueue(env, path, fn, context) {
22
22
  const state = getState(env);
23
23
  const registration = state.registration.then(async () => {
24
- const key = await getMutationQueueKey(env, path);
24
+ const key = await getMutationQueueKey(env, path, context);
25
25
  const currentQueue = state.queues.get(key) ?? Promise.resolve();
26
26
  let releaseNext = () => { };
27
27
  const nextQueue = new Promise((resolve) => {
@@ -1 +1 @@
1
- {"version":3,"file":"file-mutation-queue.js","sourceRoot":"","sources":["../../../src/harness/tools/file-mutation-queue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC,MAAM,MAAM,GAAG,IAAI,OAAO,EAAoC,CAAC;AAE/D,SAAS,QAAQ,CAAC,GAAiB;IAClC,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,KAAK,GAAG,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE,EAAE,YAAY,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/D,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,GAAiB,EAAE,IAAY;IACjE,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,MAAM,aAAa,GAAG,MAAM,GAAG,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;IAC5D,IAAI,aAAa,CAAC,EAAE;QAAE,OAAO,aAAa,CAAC,KAAK,CAAC;IACjD,IAAI,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe;QAAE,OAAO,YAAY,CAAC;IAClH,MAAM,aAAa,CAAC,KAAK,CAAC;AAC3B,CAAC;AAED,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAI,GAAiB,EAAE,IAAY,EAAE,EAAoB;IACnG,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;QACvD,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAEhE,IAAI,WAAW,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;QAC3B,MAAM,SAAS,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAC/C,WAAW,GAAG,OAAO,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACxD,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACpC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC;IACzD,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,YAAY,GAAG,YAAY,CAAC,IAAI,CACrC,GAAG,EAAE,CAAC,SAAS,EACf,GAAG,EAAE,CAAC,SAAS,CACf,CAAC;IAEF,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,MAAM,YAAY,CAAC;IAC5E,MAAM,YAAY,CAAC;IACnB,IAAI,CAAC;QACJ,OAAO,MAAM,EAAE,EAAE,CAAC;IACnB,CAAC;YAAS,CAAC;QACV,WAAW,EAAE,CAAC;QACd,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,YAAY;YAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACtE,CAAC;AACF,CAAC","sourcesContent":["import type { ExecutionEnv } from \"../types.ts\";\nimport { getOrThrow } from \"../types.ts\";\n\ntype MutationQueueState = {\n\tqueues: Map<string, Promise<void>>;\n\tregistration: Promise<void>;\n};\n\nconst states = new WeakMap<ExecutionEnv, MutationQueueState>();\n\nfunction getState(env: ExecutionEnv): MutationQueueState {\n\tlet state = states.get(env);\n\tif (!state) {\n\t\tstate = { queues: new Map(), registration: Promise.resolve() };\n\t\tstates.set(env, state);\n\t}\n\treturn state;\n}\n\nasync function getMutationQueueKey(env: ExecutionEnv, path: string): Promise<string> {\n\tconst absolutePath = getOrThrow(await env.absolutePath(path));\n\tconst canonicalPath = await env.canonicalPath(absolutePath);\n\tif (canonicalPath.ok) return canonicalPath.value;\n\tif (canonicalPath.error.code === \"not_found\" || canonicalPath.error.code === \"not_supported\") return absolutePath;\n\tthrow canonicalPath.error;\n}\n\n/** Serialize file mutations targeting the same environment and canonical path. */\nexport async function withFileMutationQueue<T>(env: ExecutionEnv, path: string, fn: () => Promise<T>): Promise<T> {\n\tconst state = getState(env);\n\tconst registration = state.registration.then(async () => {\n\t\tconst key = await getMutationQueueKey(env, path);\n\t\tconst currentQueue = state.queues.get(key) ?? Promise.resolve();\n\n\t\tlet releaseNext = () => {};\n\t\tconst nextQueue = new Promise<void>((resolve) => {\n\t\t\treleaseNext = resolve;\n\t\t});\n\t\tconst chainedQueue = currentQueue.then(() => nextQueue);\n\t\tstate.queues.set(key, chainedQueue);\n\t\treturn { key, currentQueue, chainedQueue, releaseNext };\n\t});\n\tstate.registration = 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\treturn await fn();\n\t} finally {\n\t\treleaseNext();\n\t\tif (state.queues.get(key) === chainedQueue) state.queues.delete(key);\n\t}\n}\n"]}
1
+ {"version":3,"file":"file-mutation-queue.js","sourceRoot":"","sources":["../../../src/harness/tools/file-mutation-queue.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC,MAAM,MAAM,GAAG,IAAI,OAAO,EAAoC,CAAC;AAE/D,SAAS,QAAQ,CAAC,GAAiB;IAClC,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,KAAK,GAAG,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE,EAAE,YAAY,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/D,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,GAAiB,EAAE,IAAY,EAAE,OAAgB;IACnF,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACvE,MAAM,aAAa,GAAG,MAAM,GAAG,CAAC,aAAa,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACrE,IAAI,aAAa,CAAC,EAAE;QAAE,OAAO,aAAa,CAAC,KAAK,CAAC;IACjD,IAAI,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe;QAAE,OAAO,YAAY,CAAC;IAClH,MAAM,aAAa,CAAC,KAAK,CAAC;AAC3B,CAAC;AAED,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAC1C,GAAiB,EACjB,IAAY,EACZ,EAAoB,EACpB,OAAgB;IAEhB,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;QACvD,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1D,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAEhE,IAAI,WAAW,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;QAC3B,MAAM,SAAS,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAC/C,WAAW,GAAG,OAAO,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACxD,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACpC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC;IACzD,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,YAAY,GAAG,YAAY,CAAC,IAAI,CACrC,GAAG,EAAE,CAAC,SAAS,EACf,GAAG,EAAE,CAAC,SAAS,CACf,CAAC;IAEF,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,MAAM,YAAY,CAAC;IAC5E,MAAM,YAAY,CAAC;IACnB,IAAI,CAAC;QACJ,OAAO,MAAM,EAAE,EAAE,CAAC;IACnB,CAAC;YAAS,CAAC;QACV,WAAW,EAAE,CAAC;QACd,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,YAAY;YAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACtE,CAAC;AACF,CAAC","sourcesContent":["import type { Context } from \"../context.ts\";\nimport type { ExecutionEnv } from \"../types.ts\";\nimport { getOrThrow } from \"../types.ts\";\n\ntype MutationQueueState = {\n\tqueues: Map<string, Promise<void>>;\n\tregistration: Promise<void>;\n};\n\nconst states = new WeakMap<ExecutionEnv, MutationQueueState>();\n\nfunction getState(env: ExecutionEnv): MutationQueueState {\n\tlet state = states.get(env);\n\tif (!state) {\n\t\tstate = { queues: new Map(), registration: Promise.resolve() };\n\t\tstates.set(env, state);\n\t}\n\treturn state;\n}\n\nasync function getMutationQueueKey(env: ExecutionEnv, path: string, context: Context): Promise<string> {\n\tconst absolutePath = getOrThrow(await env.absolutePath(path, context));\n\tconst canonicalPath = await env.canonicalPath(absolutePath, context);\n\tif (canonicalPath.ok) return canonicalPath.value;\n\tif (canonicalPath.error.code === \"not_found\" || canonicalPath.error.code === \"not_supported\") return absolutePath;\n\tthrow canonicalPath.error;\n}\n\n/** Serialize file mutations targeting the same environment and canonical path. */\nexport async function withFileMutationQueue<T>(\n\tenv: ExecutionEnv,\n\tpath: string,\n\tfn: () => Promise<T>,\n\tcontext: Context,\n): Promise<T> {\n\tconst state = getState(env);\n\tconst registration = state.registration.then(async () => {\n\t\tconst key = await getMutationQueueKey(env, path, context);\n\t\tconst currentQueue = state.queues.get(key) ?? Promise.resolve();\n\n\t\tlet releaseNext = () => {};\n\t\tconst nextQueue = new Promise<void>((resolve) => {\n\t\t\treleaseNext = resolve;\n\t\t});\n\t\tconst chainedQueue = currentQueue.then(() => nextQueue);\n\t\tstate.queues.set(key, chainedQueue);\n\t\treturn { key, currentQueue, chainedQueue, releaseNext };\n\t});\n\tstate.registration = 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\treturn await fn();\n\t} finally {\n\t\treleaseNext();\n\t\tif (state.queues.get(key) === chainedQueue) state.queues.delete(key);\n\t}\n}\n"]}
@@ -1,4 +1,5 @@
1
+ import type { Context } from "../context.ts";
1
2
  import type { ExecutionEnv } from "../types.ts";
2
- export declare function resolveToolPath(env: ExecutionEnv, path: string, signal?: AbortSignal): Promise<string>;
3
- export declare function resolveReadToolPath(env: ExecutionEnv, path: string, signal?: AbortSignal): Promise<string>;
3
+ export declare function resolveToolPath(env: ExecutionEnv, path: string, context: Context): Promise<string>;
4
+ export declare function resolveReadToolPath(env: ExecutionEnv, path: string, context: Context): Promise<string>;
4
5
  //# sourceMappingURL=path-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/path-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAWhD,wBAAsB,eAAe,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAE5G;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAchH"}
1
+ {"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/path-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAWhD,wBAAsB,eAAe,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAExG;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAc5G"}
@@ -5,11 +5,11 @@ function normalizeToolPath(path) {
5
5
  const normalized = path.replace(UNICODE_SPACES, " ");
6
6
  return normalized.startsWith("@") ? normalized.slice(1) : normalized;
7
7
  }
8
- export async function resolveToolPath(env, path, signal) {
9
- return getOrThrow(await env.absolutePath(normalizeToolPath(path), signal));
8
+ export async function resolveToolPath(env, path, context) {
9
+ return getOrThrow(await env.absolutePath(normalizeToolPath(path), context));
10
10
  }
11
- export async function resolveReadToolPath(env, path, signal) {
12
- const resolved = await resolveToolPath(env, path, signal);
11
+ export async function resolveReadToolPath(env, path, context) {
12
+ const resolved = await resolveToolPath(env, path, context);
13
13
  const variants = [
14
14
  resolved,
15
15
  resolved.replace(/ (AM|PM)\./gi, `${NARROW_NO_BREAK_SPACE}$1.`),
@@ -18,7 +18,7 @@ export async function resolveReadToolPath(env, path, signal) {
18
18
  resolved.normalize("NFD").replace(/'/g, "\u2019"),
19
19
  ];
20
20
  for (const variant of new Set(variants)) {
21
- if (getOrThrow(await env.exists(variant, signal)))
21
+ if (getOrThrow(await env.exists(variant, context)))
22
22
  return variant;
23
23
  }
24
24
  return resolved;
@@ -1 +1 @@
1
- {"version":3,"file":"path-utils.js","sourceRoot":"","sources":["../../../src/harness/tools/path-utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,cAAc,GAAG,0CAA0C,CAAC;AAClE,MAAM,qBAAqB,GAAG,QAAQ,CAAC;AAEvC,SAAS,iBAAiB,CAAC,IAAY;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACrD,OAAO,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;AACtE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAiB,EAAE,IAAY,EAAE,MAAoB;IAC1F,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAiB,EAAE,IAAY,EAAE,MAAoB;IAC9F,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG;QAChB,QAAQ;QACR,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,qBAAqB,KAAK,CAAC;QAC/D,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC;QACzB,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;QAChC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;KACjD,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC;IACnE,CAAC;IACD,OAAO,QAAQ,CAAC;AACjB,CAAC","sourcesContent":["import type { ExecutionEnv } from \"../types.ts\";\nimport { getOrThrow } from \"../types.ts\";\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\nconst NARROW_NO_BREAK_SPACE = \"\\u202F\";\n\nfunction normalizeToolPath(path: string): string {\n\tconst normalized = path.replace(UNICODE_SPACES, \" \");\n\treturn normalized.startsWith(\"@\") ? normalized.slice(1) : normalized;\n}\n\nexport async function resolveToolPath(env: ExecutionEnv, path: string, signal?: AbortSignal): Promise<string> {\n\treturn getOrThrow(await env.absolutePath(normalizeToolPath(path), signal));\n}\n\nexport async function resolveReadToolPath(env: ExecutionEnv, path: string, signal?: AbortSignal): Promise<string> {\n\tconst resolved = await resolveToolPath(env, path, signal);\n\tconst variants = [\n\t\tresolved,\n\t\tresolved.replace(/ (AM|PM)\\./gi, `${NARROW_NO_BREAK_SPACE}$1.`),\n\t\tresolved.normalize(\"NFD\"),\n\t\tresolved.replace(/'/g, \"\\u2019\"),\n\t\tresolved.normalize(\"NFD\").replace(/'/g, \"\\u2019\"),\n\t];\n\n\tfor (const variant of new Set(variants)) {\n\t\tif (getOrThrow(await env.exists(variant, signal))) return variant;\n\t}\n\treturn resolved;\n}\n"]}
1
+ {"version":3,"file":"path-utils.js","sourceRoot":"","sources":["../../../src/harness/tools/path-utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,cAAc,GAAG,0CAA0C,CAAC;AAClE,MAAM,qBAAqB,GAAG,QAAQ,CAAC;AAEvC,SAAS,iBAAiB,CAAC,IAAY;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACrD,OAAO,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;AACtE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAiB,EAAE,IAAY,EAAE,OAAgB;IACtF,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,YAAY,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAiB,EAAE,IAAY,EAAE,OAAgB;IAC1F,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG;QAChB,QAAQ;QACR,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,qBAAqB,KAAK,CAAC;QAC/D,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC;QACzB,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;QAChC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;KACjD,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC;IACpE,CAAC;IACD,OAAO,QAAQ,CAAC;AACjB,CAAC","sourcesContent":["import type { Context } from \"../context.ts\";\nimport type { ExecutionEnv } from \"../types.ts\";\nimport { getOrThrow } from \"../types.ts\";\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\nconst NARROW_NO_BREAK_SPACE = \"\\u202F\";\n\nfunction normalizeToolPath(path: string): string {\n\tconst normalized = path.replace(UNICODE_SPACES, \" \");\n\treturn normalized.startsWith(\"@\") ? normalized.slice(1) : normalized;\n}\n\nexport async function resolveToolPath(env: ExecutionEnv, path: string, context: Context): Promise<string> {\n\treturn getOrThrow(await env.absolutePath(normalizeToolPath(path), context));\n}\n\nexport async function resolveReadToolPath(env: ExecutionEnv, path: string, context: Context): Promise<string> {\n\tconst resolved = await resolveToolPath(env, path, context);\n\tconst variants = [\n\t\tresolved,\n\t\tresolved.replace(/ (AM|PM)\\./gi, `${NARROW_NO_BREAK_SPACE}$1.`),\n\t\tresolved.normalize(\"NFD\"),\n\t\tresolved.replace(/'/g, \"\\u2019\"),\n\t\tresolved.normalize(\"NFD\").replace(/'/g, \"\\u2019\"),\n\t];\n\n\tfor (const variant of new Set(variants)) {\n\t\tif (getOrThrow(await env.exists(variant, context))) return variant;\n\t}\n\treturn resolved;\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { type Static, Type } from "typebox";
2
+ import type { Context } from "../context.ts";
2
3
  import type { AgentHarnessTool } from "../types.ts";
3
4
  import { type TruncationResult } from "../utils/truncate.ts";
4
5
  import type { ExecutionToolContext } from "./tool-context.ts";
@@ -22,7 +23,7 @@ export type ReadImageProcessorResult = {
22
23
  };
23
24
  export type ReadImageProcessor = (bytes: Uint8Array, mimeType: string, options: {
24
25
  autoResizeImages: boolean;
25
- }) => Promise<ReadImageProcessorResult>;
26
+ }, context: Context) => Promise<ReadImageProcessorResult>;
26
27
  export interface ReadToolOptions {
27
28
  /** Whether an injected image processor should resize images. Default: true. */
28
29
  autoResizeImages?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/read.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,EAIN,KAAK,gBAAgB,EAErB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,QAAA,MAAM,UAAU;;;;EAId,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,MAAM,MAAM,wBAAwB,GACjC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAC7D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC,MAAM,MAAM,kBAAkB,GAAG,CAChC,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;IAAE,gBAAgB,EAAE,OAAO,CAAA;CAAE,KAClC,OAAO,CAAC,wBAAwB,CAAC,CAAC;AAEvC,MAAM,WAAW,eAAe;IAC/B,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,yDAAyD;IACzD,cAAc,CAAC,EAAE,kBAAkB,CAAC;CACpC;AAED,wBAAgB,cAAc,CAAC,QAAQ,SAAS,oBAAoB,GAAG,oBAAoB,EAC1F,OAAO,CAAC,EAAE,eAAe,GACvB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAiG5E"}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/read.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,EAIN,KAAK,gBAAgB,EAErB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,QAAA,MAAM,UAAU;;;;EAId,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,MAAM,MAAM,wBAAwB,GACjC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAC7D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC,MAAM,MAAM,kBAAkB,GAAG,CAChC,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;IAAE,gBAAgB,EAAE,OAAO,CAAA;CAAE,EACtC,OAAO,EAAE,OAAO,KACZ,OAAO,CAAC,wBAAwB,CAAC,CAAC;AAEvC,MAAM,WAAW,eAAe;IAC/B,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,yDAAyD;IACzD,cAAc,CAAC,EAAE,kBAAkB,CAAC;CACpC;AAED,wBAAgB,cAAc,CAAC,QAAQ,SAAS,oBAAoB,GAAG,oBAAoB,EAC1F,OAAO,CAAC,EAAE,eAAe,GACvB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAoG5E"}
@@ -14,15 +14,13 @@ export function createReadTool(options) {
14
14
  label: "read",
15
15
  description: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,
16
16
  parameters: readSchema,
17
- async execute(_toolCallId, { path, offset, limit }, signal, _onUpdate, { env }) {
18
- const absolutePath = await resolveReadToolPath(env, path, signal);
19
- const bytes = getOrThrow(await env.readBinaryFile(absolutePath, signal));
17
+ async execute(_toolCallId, { path, offset, limit }, _onUpdate, { env }, _invocation, context) {
18
+ const absolutePath = await resolveReadToolPath(env, path, context);
19
+ const bytes = getOrThrow(await env.readBinaryFile(absolutePath, context));
20
20
  const mimeType = detectSupportedImageMimeType(bytes);
21
21
  if (mimeType) {
22
22
  if (options?.imageProcessor) {
23
- const processed = await options.imageProcessor(bytes, mimeType, {
24
- autoResizeImages: options.autoResizeImages ?? true,
25
- });
23
+ const processed = await options.imageProcessor(bytes, mimeType, { autoResizeImages: options.autoResizeImages ?? true }, context);
26
24
  if (!processed.ok) {
27
25
  return {
28
26
  content: [{ type: "text", text: `Read image file [${mimeType}]\n${processed.message}` }],
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/harness/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport { type Static, Type } from \"typebox\";\nimport type { AgentHarnessTool } from \"../types.ts\";\nimport { getOrThrow } from \"../types.ts\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationResult,\n\ttruncateHead,\n} from \"../utils/truncate.ts\";\nimport { detectSupportedImageMimeType, encodeBase64 } from \"./image.ts\";\nimport { resolveReadToolPath } from \"./path-utils.ts\";\nimport type { ExecutionToolContext } from \"./tool-context.ts\";\n\nconst readSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to read (relative or absolute)\" }),\n\toffset: Type.Optional(Type.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of lines to read\" })),\n});\n\nexport type ReadToolInput = Static<typeof readSchema>;\n\nexport interface ReadToolDetails {\n\ttruncation?: TruncationResult;\n}\n\nexport type ReadImageProcessorResult =\n\t| { ok: true; data: string; mimeType: string; hints: string[] }\n\t| { ok: false; message: string };\n\nexport type ReadImageProcessor = (\n\tbytes: Uint8Array,\n\tmimeType: string,\n\toptions: { autoResizeImages: boolean },\n) => Promise<ReadImageProcessorResult>;\n\nexport interface ReadToolOptions {\n\t/** Whether an injected image processor should resize images. Default: true. */\n\tautoResizeImages?: boolean;\n\t/** Optional image conversion/resizing implementation. */\n\timageProcessor?: ReadImageProcessor;\n}\n\nexport function createReadTool<TContext extends ExecutionToolContext = ExecutionToolContext>(\n\toptions?: ReadToolOptions,\n): AgentHarnessTool<TContext, typeof readSchema, ReadToolDetails | undefined> {\n\treturn {\n\t\tname: \"read\",\n\t\tlabel: \"read\",\n\t\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\n\t\tparameters: readSchema,\n\t\tasync execute(_toolCallId, { path, offset, limit }, signal, _onUpdate, { env }) {\n\t\t\tconst absolutePath = await resolveReadToolPath(env, path, signal);\n\t\t\tconst bytes = getOrThrow(await env.readBinaryFile(absolutePath, signal));\n\t\t\tconst mimeType = detectSupportedImageMimeType(bytes);\n\t\t\tif (mimeType) {\n\t\t\t\tif (options?.imageProcessor) {\n\t\t\t\t\tconst processed = await options.imageProcessor(bytes, mimeType, {\n\t\t\t\t\t\tautoResizeImages: options.autoResizeImages ?? true,\n\t\t\t\t\t});\n\t\t\t\t\tif (!processed.ok) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: `Read image file [${mimeType}]\\n${processed.message}` }],\n\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tconst hints = processed.hints.length > 0 ? `\\n${processed.hints.join(\"\\n\")}` : \"\";\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{ type: \"text\", text: `Read image file [${processed.mimeType}]${hints}` },\n\t\t\t\t\t\t\t{ type: \"image\", data: processed.data, mimeType: processed.mimeType },\n\t\t\t\t\t\t] satisfies Array<TextContent | ImageContent>,\n\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (mimeType === \"image/bmp\") {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\ttext: \"Read image file [image/bmp]\\n[Image omitted: configure an imageProcessor to convert BMP images.]\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: `Read image file [${mimeType}]` },\n\t\t\t\t\t\t{ type: \"image\", data: encodeBase64(bytes), mimeType },\n\t\t\t\t\t] satisfies Array<TextContent | ImageContent>,\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst textContent = new TextDecoder().decode(bytes);\n\t\t\tconst allLines = textContent.split(\"\\n\");\n\t\t\tconst totalFileLines = allLines.length;\n\t\t\tconst startLine = offset ? Math.max(0, offset - 1) : 0;\n\t\t\tconst startLineDisplay = startLine + 1;\n\t\t\tif (startLine >= allLines.length) {\n\t\t\t\tthrow new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\n\t\t\t}\n\n\t\t\tlet selectedContent: string;\n\t\t\tlet userLimitedLines: number | undefined;\n\t\t\tif (limit !== undefined) {\n\t\t\t\tconst endLine = Math.min(startLine + limit, allLines.length);\n\t\t\t\tselectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\n\t\t\t\tuserLimitedLines = endLine - startLine;\n\t\t\t} else {\n\t\t\t\tselectedContent = allLines.slice(startLine).join(\"\\n\");\n\t\t\t}\n\n\t\t\tconst truncation = truncateHead(selectedContent);\n\t\t\tlet outputText: string;\n\t\t\tlet details: ReadToolDetails | undefined;\n\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\tconst firstLineSize = formatSize(new TextEncoder().encode(allLines[startLine]).byteLength);\n\t\t\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;\n\t\t\t\tdetails = { truncation };\n\t\t\t} else if (truncation.truncated) {\n\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n\t\t\t\tconst nextOffset = endLineDisplay + 1;\n\t\t\t\toutputText = truncation.content;\n\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t} else {\n\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;\n\t\t\t\t}\n\t\t\t\tdetails = { truncation };\n\t\t\t} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\n\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\n\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\n\t\t\t\toutputText = `${truncation.content}\\n\\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;\n\t\t\t} else {\n\t\t\t\toutputText = truncation.content;\n\t\t\t}\n\n\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/harness/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport { type Static, Type } from \"typebox\";\nimport type { Context } from \"../context.ts\";\nimport type { AgentHarnessTool } from \"../types.ts\";\nimport { getOrThrow } from \"../types.ts\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationResult,\n\ttruncateHead,\n} from \"../utils/truncate.ts\";\nimport { detectSupportedImageMimeType, encodeBase64 } from \"./image.ts\";\nimport { resolveReadToolPath } from \"./path-utils.ts\";\nimport type { ExecutionToolContext } from \"./tool-context.ts\";\n\nconst readSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to read (relative or absolute)\" }),\n\toffset: Type.Optional(Type.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of lines to read\" })),\n});\n\nexport type ReadToolInput = Static<typeof readSchema>;\n\nexport interface ReadToolDetails {\n\ttruncation?: TruncationResult;\n}\n\nexport type ReadImageProcessorResult =\n\t| { ok: true; data: string; mimeType: string; hints: string[] }\n\t| { ok: false; message: string };\n\nexport type ReadImageProcessor = (\n\tbytes: Uint8Array,\n\tmimeType: string,\n\toptions: { autoResizeImages: boolean },\n\tcontext: Context,\n) => Promise<ReadImageProcessorResult>;\n\nexport interface ReadToolOptions {\n\t/** Whether an injected image processor should resize images. Default: true. */\n\tautoResizeImages?: boolean;\n\t/** Optional image conversion/resizing implementation. */\n\timageProcessor?: ReadImageProcessor;\n}\n\nexport function createReadTool<TContext extends ExecutionToolContext = ExecutionToolContext>(\n\toptions?: ReadToolOptions,\n): AgentHarnessTool<TContext, typeof readSchema, ReadToolDetails | undefined> {\n\treturn {\n\t\tname: \"read\",\n\t\tlabel: \"read\",\n\t\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\n\t\tparameters: readSchema,\n\t\tasync execute(_toolCallId, { path, offset, limit }, _onUpdate, { env }, _invocation, context) {\n\t\t\tconst absolutePath = await resolveReadToolPath(env, path, context);\n\t\t\tconst bytes = getOrThrow(await env.readBinaryFile(absolutePath, context));\n\t\t\tconst mimeType = detectSupportedImageMimeType(bytes);\n\t\t\tif (mimeType) {\n\t\t\t\tif (options?.imageProcessor) {\n\t\t\t\t\tconst processed = await options.imageProcessor(\n\t\t\t\t\t\tbytes,\n\t\t\t\t\t\tmimeType,\n\t\t\t\t\t\t{ autoResizeImages: options.autoResizeImages ?? true },\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t);\n\t\t\t\t\tif (!processed.ok) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: `Read image file [${mimeType}]\\n${processed.message}` }],\n\t\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tconst hints = processed.hints.length > 0 ? `\\n${processed.hints.join(\"\\n\")}` : \"\";\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{ type: \"text\", text: `Read image file [${processed.mimeType}]${hints}` },\n\t\t\t\t\t\t\t{ type: \"image\", data: processed.data, mimeType: processed.mimeType },\n\t\t\t\t\t\t] satisfies Array<TextContent | ImageContent>,\n\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (mimeType === \"image/bmp\") {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\ttext: \"Read image file [image/bmp]\\n[Image omitted: configure an imageProcessor to convert BMP images.]\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: `Read image file [${mimeType}]` },\n\t\t\t\t\t\t{ type: \"image\", data: encodeBase64(bytes), mimeType },\n\t\t\t\t\t] satisfies Array<TextContent | ImageContent>,\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst textContent = new TextDecoder().decode(bytes);\n\t\t\tconst allLines = textContent.split(\"\\n\");\n\t\t\tconst totalFileLines = allLines.length;\n\t\t\tconst startLine = offset ? Math.max(0, offset - 1) : 0;\n\t\t\tconst startLineDisplay = startLine + 1;\n\t\t\tif (startLine >= allLines.length) {\n\t\t\t\tthrow new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\n\t\t\t}\n\n\t\t\tlet selectedContent: string;\n\t\t\tlet userLimitedLines: number | undefined;\n\t\t\tif (limit !== undefined) {\n\t\t\t\tconst endLine = Math.min(startLine + limit, allLines.length);\n\t\t\t\tselectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\n\t\t\t\tuserLimitedLines = endLine - startLine;\n\t\t\t} else {\n\t\t\t\tselectedContent = allLines.slice(startLine).join(\"\\n\");\n\t\t\t}\n\n\t\t\tconst truncation = truncateHead(selectedContent);\n\t\t\tlet outputText: string;\n\t\t\tlet details: ReadToolDetails | undefined;\n\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\tconst firstLineSize = formatSize(new TextEncoder().encode(allLines[startLine]).byteLength);\n\t\t\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;\n\t\t\t\tdetails = { truncation };\n\t\t\t} else if (truncation.truncated) {\n\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n\t\t\t\tconst nextOffset = endLineDisplay + 1;\n\t\t\t\toutputText = truncation.content;\n\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t} else {\n\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;\n\t\t\t\t}\n\t\t\t\tdetails = { truncation };\n\t\t\t} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\n\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\n\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\n\t\t\t\toutputText = `${truncation.content}\\n\\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;\n\t\t\t} else {\n\t\t\t\toutputText = truncation.content;\n\t\t\t}\n\n\t\t\treturn { content: [{ type: \"text\", text: outputText }], details };\n\t\t},\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAKpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,QAAA,MAAM,WAAW;;;EAGf,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAExD,wBAAgB,eAAe,CAAC,QAAQ,SAAS,oBAAoB,GAAG,oBAAoB,KAAK,gBAAgB,CAChH,QAAQ,EACR,OAAO,WAAW,EAClB,SAAS,CACT,CAuBA"}
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAKpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,QAAA,MAAM,WAAW;;;EAGf,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAExD,wBAAgB,eAAe,CAAC,QAAQ,SAAS,oBAAoB,GAAG,oBAAoB,KAAK,gBAAgB,CAChH,QAAQ,EACR,OAAO,WAAW,EAClB,SAAS,CACT,CAgCA"}
@@ -13,23 +13,27 @@ export function createWriteTool() {
13
13
  label: "write",
14
14
  description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.",
15
15
  parameters: writeSchema,
16
- async execute(_toolCallId, { path, content }, signal, _onUpdate, { env, postMutate }) {
17
- const absolutePath = await resolveToolPath(env, path, signal);
16
+ async execute(_toolCallId, { path, content }, _onUpdate, { env, postMutate }, _invocation, context) {
17
+ const absolutePath = await resolveToolPath(env, path, context);
18
18
  return withFileMutationQueue(env, absolutePath, async () => {
19
- if (signal?.aborted)
19
+ if (context.abortSignal?.aborted)
20
20
  throw new Error("Operation aborted");
21
- getOrThrow(await env.writeFile(absolutePath, content, signal));
22
- if (signal?.aborted)
21
+ getOrThrow(await env.writeFile(absolutePath, content, context));
22
+ if (context.abortSignal?.aborted)
23
23
  throw new Error("Operation aborted");
24
- const outcome = await runPostMutate(postMutate, { tool: "write", path: absolutePath, signal });
25
- if (signal?.aborted)
24
+ const outcome = await runPostMutate(postMutate, {
25
+ tool: "write",
26
+ path: absolutePath,
27
+ signal: context.abortSignal,
28
+ });
29
+ if (context.abortSignal?.aborted)
26
30
  throw new Error("Operation aborted");
27
31
  const text = appendPostMutateNote(`Successfully wrote to ${path}`, outcome.note);
28
32
  return {
29
33
  content: [{ type: "text", text }],
30
34
  details: undefined,
31
35
  };
32
- });
36
+ }, context);
33
37
  },
34
38
  };
35
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/harness/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGvE,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;IACtF,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,8BAA8B,EAAE,CAAC;CACrE,CAAC,CAAC;AAIH,MAAM,UAAU,eAAe;IAK9B,OAAO;QACN,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,WAAW,EACV,iIAAiI;QAClI,UAAU,EAAE,WAAW;QACvB,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE;YACnF,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;YAC9D,OAAO,qBAAqB,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,IAAI,EAAE;gBAC1D,IAAI,MAAM,EAAE,OAAO;oBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBAC1D,UAAU,CAAC,MAAM,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;gBAC/D,IAAI,MAAM,EAAE,OAAO;oBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBAC1D,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC/F,IAAI,MAAM,EAAE,OAAO;oBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBAC1D,MAAM,IAAI,GAAG,oBAAoB,CAAC,yBAAyB,IAAI,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;gBACjF,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;oBACjC,OAAO,EAAE,SAAS;iBAClB,CAAC;YACH,CAAC,CAAC,CAAC;QACJ,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { AgentHarnessTool } from \"../types.ts\";\nimport { getOrThrow } from \"../types.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { resolveToolPath } from \"./path-utils.ts\";\nimport { appendPostMutateNote, runPostMutate } from \"./post-mutate.ts\";\nimport type { ExecutionToolContext } from \"./tool-context.ts\";\n\nconst writeSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport type WriteToolInput = Static<typeof writeSchema>;\n\nexport function createWriteTool<TContext extends ExecutionToolContext = ExecutionToolContext>(): AgentHarnessTool<\n\tTContext,\n\ttypeof writeSchema,\n\tundefined\n> {\n\treturn {\n\t\tname: \"write\",\n\t\tlabel: \"write\",\n\t\tdescription:\n\t\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\t\tparameters: writeSchema,\n\t\tasync execute(_toolCallId, { path, content }, signal, _onUpdate, { env, postMutate }) {\n\t\t\tconst absolutePath = await resolveToolPath(env, path, signal);\n\t\t\treturn withFileMutationQueue(env, absolutePath, async () => {\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\tgetOrThrow(await env.writeFile(absolutePath, content, signal));\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\tconst outcome = await runPostMutate(postMutate, { tool: \"write\", path: absolutePath, signal });\n\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\tconst text = appendPostMutateNote(`Successfully wrote to ${path}`, outcome.note);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/harness/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGvE,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;IACtF,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,8BAA8B,EAAE,CAAC;CACrE,CAAC,CAAC;AAIH,MAAM,UAAU,eAAe;IAK9B,OAAO;QACN,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,WAAW,EACV,iIAAiI;QAClI,UAAU,EAAE,WAAW;QACvB,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,WAAW,EAAE,OAAO;YACjG,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;YAC/D,OAAO,qBAAqB,CAC3B,GAAG,EACH,YAAY,EACZ,KAAK,IAAI,EAAE;gBACV,IAAI,OAAO,CAAC,WAAW,EAAE,OAAO;oBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBACvE,UAAU,CAAC,MAAM,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;gBAChE,IAAI,OAAO,CAAC,WAAW,EAAE,OAAO;oBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBACvE,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE;oBAC/C,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,YAAY;oBAClB,MAAM,EAAE,OAAO,CAAC,WAAW;iBAC3B,CAAC,CAAC;gBACH,IAAI,OAAO,CAAC,WAAW,EAAE,OAAO;oBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBACvE,MAAM,IAAI,GAAG,oBAAoB,CAAC,yBAAyB,IAAI,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;gBACjF,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;oBACjC,OAAO,EAAE,SAAS;iBAClB,CAAC;YACH,CAAC,EACD,OAAO,CACP,CAAC;QACH,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { AgentHarnessTool } from \"../types.ts\";\nimport { getOrThrow } from \"../types.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { resolveToolPath } from \"./path-utils.ts\";\nimport { appendPostMutateNote, runPostMutate } from \"./post-mutate.ts\";\nimport type { ExecutionToolContext } from \"./tool-context.ts\";\n\nconst writeSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport type WriteToolInput = Static<typeof writeSchema>;\n\nexport function createWriteTool<TContext extends ExecutionToolContext = ExecutionToolContext>(): AgentHarnessTool<\n\tTContext,\n\ttypeof writeSchema,\n\tundefined\n> {\n\treturn {\n\t\tname: \"write\",\n\t\tlabel: \"write\",\n\t\tdescription:\n\t\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\t\tparameters: writeSchema,\n\t\tasync execute(_toolCallId, { path, content }, _onUpdate, { env, postMutate }, _invocation, context) {\n\t\t\tconst absolutePath = await resolveToolPath(env, path, context);\n\t\t\treturn withFileMutationQueue(\n\t\t\t\tenv,\n\t\t\t\tabsolutePath,\n\t\t\t\tasync () => {\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t\tgetOrThrow(await env.writeFile(absolutePath, content, context));\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t\tconst outcome = await runPostMutate(postMutate, {\n\t\t\t\t\t\ttool: \"write\",\n\t\t\t\t\t\tpath: absolutePath,\n\t\t\t\t\t\tsignal: context.abortSignal,\n\t\t\t\t\t});\n\t\t\t\t\tif (context.abortSignal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t\tconst text = appendPostMutateNote(`Successfully wrote to ${path}`, outcome.note);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\t\t\t\tdetails: undefined,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tcontext,\n\t\t\t);\n\t\t},\n\t};\n}\n"]}