@draht/agent-core 2026.7.30 → 2026.10.4-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (456) hide show
  1. package/dist/agent-loop.d.ts +27 -2
  2. package/dist/agent-loop.d.ts.map +1 -1
  3. package/dist/agent-loop.js +181 -63
  4. package/dist/agent-loop.js.map +1 -1
  5. package/dist/agent.d.ts +14 -4
  6. package/dist/agent.d.ts.map +1 -1
  7. package/dist/agent.js +68 -19
  8. package/dist/agent.js.map +1 -1
  9. package/dist/harness/agent-harness.d.ts +713 -91
  10. package/dist/harness/agent-harness.d.ts.map +1 -1
  11. package/dist/harness/agent-harness.js +5 -950
  12. package/dist/harness/agent-harness.js.map +1 -1
  13. package/dist/harness/compaction/branch-summarization.d.ts +23 -10
  14. package/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  15. package/dist/harness/compaction/branch-summarization.js +39 -36
  16. package/dist/harness/compaction/branch-summarization.js.map +1 -1
  17. package/dist/harness/compaction/compaction.d.ts +37 -18
  18. package/dist/harness/compaction/compaction.d.ts.map +1 -1
  19. package/dist/harness/compaction/compaction.js +74 -97
  20. package/dist/harness/compaction/compaction.js.map +1 -1
  21. package/dist/harness/config.d.ts +9 -0
  22. package/dist/harness/config.d.ts.map +1 -0
  23. package/dist/harness/config.js +35 -0
  24. package/dist/harness/config.js.map +1 -0
  25. package/dist/harness/context.d.ts +9 -0
  26. package/dist/harness/context.d.ts.map +1 -0
  27. package/dist/harness/context.js +13 -0
  28. package/dist/harness/context.js.map +1 -0
  29. package/dist/harness/env/nodejs.d.ts +25 -27
  30. package/dist/harness/env/nodejs.d.ts.map +1 -1
  31. package/dist/harness/env/nodejs.js +355 -110
  32. package/dist/harness/env/nodejs.js.map +1 -1
  33. package/dist/harness/events.d.ts +24 -0
  34. package/dist/harness/events.d.ts.map +1 -0
  35. package/dist/harness/events.js +233 -0
  36. package/dist/harness/events.js.map +1 -0
  37. package/dist/harness/execution/assistant.d.ts +42 -0
  38. package/dist/harness/execution/assistant.d.ts.map +1 -0
  39. package/dist/harness/execution/assistant.js +82 -0
  40. package/dist/harness/execution/assistant.js.map +1 -0
  41. package/dist/harness/execution/effect-gate.d.ts +22 -0
  42. package/dist/harness/execution/effect-gate.d.ts.map +1 -0
  43. package/dist/harness/execution/effect-gate.js +49 -0
  44. package/dist/harness/execution/effect-gate.js.map +1 -0
  45. package/dist/harness/execution/tools.d.ts +67 -0
  46. package/dist/harness/execution/tools.d.ts.map +1 -0
  47. package/dist/harness/execution/tools.js +119 -0
  48. package/dist/harness/execution/tools.js.map +1 -0
  49. package/dist/harness/hooks.d.ts +38 -0
  50. package/dist/harness/hooks.d.ts.map +1 -0
  51. package/dist/harness/hooks.js +406 -0
  52. package/dist/harness/hooks.js.map +1 -0
  53. package/dist/harness/messages.d.ts +4 -4
  54. package/dist/harness/messages.d.ts.map +1 -1
  55. package/dist/harness/messages.js +4 -3
  56. package/dist/harness/messages.js.map +1 -1
  57. package/dist/harness/pico3/bash.d.ts +10 -0
  58. package/dist/harness/pico3/bash.d.ts.map +1 -0
  59. package/dist/harness/pico3/bash.js +25 -0
  60. package/dist/harness/pico3/bash.js.map +1 -0
  61. package/dist/harness/pico3/bounded.d.ts +21 -0
  62. package/dist/harness/pico3/bounded.d.ts.map +1 -0
  63. package/dist/harness/pico3/bounded.js +98 -0
  64. package/dist/harness/pico3/bounded.js.map +1 -0
  65. package/dist/harness/pico3/chord.d.ts +41 -0
  66. package/dist/harness/pico3/chord.d.ts.map +1 -0
  67. package/dist/harness/pico3/chord.js +147 -0
  68. package/dist/harness/pico3/chord.js.map +1 -0
  69. package/dist/harness/pico3/context.d.ts +16 -0
  70. package/dist/harness/pico3/context.d.ts.map +1 -0
  71. package/dist/harness/pico3/context.js +88 -0
  72. package/dist/harness/pico3/context.js.map +1 -0
  73. package/dist/harness/pico3/harness.d.ts +198 -0
  74. package/dist/harness/pico3/harness.d.ts.map +1 -0
  75. package/dist/harness/pico3/harness.js +654 -0
  76. package/dist/harness/pico3/harness.js.map +1 -0
  77. package/dist/harness/pico3/hooks.d.ts +10 -0
  78. package/dist/harness/pico3/hooks.d.ts.map +1 -0
  79. package/dist/harness/pico3/hooks.js +33 -0
  80. package/dist/harness/pico3/hooks.js.map +1 -0
  81. package/dist/harness/pico3/index.d.ts +19 -0
  82. package/dist/harness/pico3/index.d.ts.map +1 -0
  83. package/dist/harness/pico3/index.js +15 -0
  84. package/dist/harness/pico3/index.js.map +1 -0
  85. package/dist/harness/pico3/jsonl.d.ts +58 -0
  86. package/dist/harness/pico3/jsonl.d.ts.map +1 -0
  87. package/dist/harness/pico3/jsonl.js +325 -0
  88. package/dist/harness/pico3/jsonl.js.map +1 -0
  89. package/dist/harness/pico3/kinds/collapse.d.ts +49 -0
  90. package/dist/harness/pico3/kinds/collapse.d.ts.map +1 -0
  91. package/dist/harness/pico3/kinds/collapse.js +191 -0
  92. package/dist/harness/pico3/kinds/collapse.js.map +1 -0
  93. package/dist/harness/pico3/kinds/entries.d.ts +78 -0
  94. package/dist/harness/pico3/kinds/entries.d.ts.map +1 -0
  95. package/dist/harness/pico3/kinds/entries.js +13 -0
  96. package/dist/harness/pico3/kinds/entries.js.map +1 -0
  97. package/dist/harness/pico3/kinds/frames.d.ts +9 -0
  98. package/dist/harness/pico3/kinds/frames.d.ts.map +1 -0
  99. package/dist/harness/pico3/kinds/frames.js +75 -0
  100. package/dist/harness/pico3/kinds/frames.js.map +1 -0
  101. package/dist/harness/pico3/kinds/generation.d.ts +94 -0
  102. package/dist/harness/pico3/kinds/generation.d.ts.map +1 -0
  103. package/dist/harness/pico3/kinds/generation.js +504 -0
  104. package/dist/harness/pico3/kinds/generation.js.map +1 -0
  105. package/dist/harness/pico3/kinds/job.d.ts +44 -0
  106. package/dist/harness/pico3/kinds/job.d.ts.map +1 -0
  107. package/dist/harness/pico3/kinds/job.js +143 -0
  108. package/dist/harness/pico3/kinds/job.js.map +1 -0
  109. package/dist/harness/pico3/kinds/plugin.d.ts +15 -0
  110. package/dist/harness/pico3/kinds/plugin.d.ts.map +1 -0
  111. package/dist/harness/pico3/kinds/plugin.js +35 -0
  112. package/dist/harness/pico3/kinds/plugin.js.map +1 -0
  113. package/dist/harness/pico3/kinds/post-tools.d.ts +22 -0
  114. package/dist/harness/pico3/kinds/post-tools.d.ts.map +1 -0
  115. package/dist/harness/pico3/kinds/post-tools.js +145 -0
  116. package/dist/harness/pico3/kinds/post-tools.js.map +1 -0
  117. package/dist/harness/pico3/kinds/task-api.d.ts +3 -0
  118. package/dist/harness/pico3/kinds/task-api.d.ts.map +1 -0
  119. package/dist/harness/pico3/kinds/task-api.js +45 -0
  120. package/dist/harness/pico3/kinds/task-api.js.map +1 -0
  121. package/dist/harness/pico3/kinds/tool.d.ts +43 -0
  122. package/dist/harness/pico3/kinds/tool.d.ts.map +1 -0
  123. package/dist/harness/pico3/kinds/tool.js +373 -0
  124. package/dist/harness/pico3/kinds/tool.js.map +1 -0
  125. package/dist/harness/pico3/legacy-tracker.d.ts +11 -0
  126. package/dist/harness/pico3/legacy-tracker.d.ts.map +1 -0
  127. package/dist/harness/pico3/legacy-tracker.js +41 -0
  128. package/dist/harness/pico3/legacy-tracker.js.map +1 -0
  129. package/dist/harness/pico3/membrane.d.ts +23 -0
  130. package/dist/harness/pico3/membrane.d.ts.map +1 -0
  131. package/dist/harness/pico3/membrane.js +141 -0
  132. package/dist/harness/pico3/membrane.js.map +1 -0
  133. package/dist/harness/pico3/memory.d.ts +53 -0
  134. package/dist/harness/pico3/memory.d.ts.map +1 -0
  135. package/dist/harness/pico3/memory.js +264 -0
  136. package/dist/harness/pico3/memory.js.map +1 -0
  137. package/dist/harness/pico3/scheduler.d.ts +49 -0
  138. package/dist/harness/pico3/scheduler.d.ts.map +1 -0
  139. package/dist/harness/pico3/scheduler.js +438 -0
  140. package/dist/harness/pico3/scheduler.js.map +1 -0
  141. package/dist/harness/pico3/session.d.ts +264 -0
  142. package/dist/harness/pico3/session.d.ts.map +1 -0
  143. package/dist/harness/pico3/session.js +1348 -0
  144. package/dist/harness/pico3/session.js.map +1 -0
  145. package/dist/harness/pico3/system.d.ts +126 -0
  146. package/dist/harness/pico3/system.d.ts.map +1 -0
  147. package/dist/harness/pico3/system.js +244 -0
  148. package/dist/harness/pico3/system.js.map +1 -0
  149. package/dist/harness/pico3/types.d.ts +973 -0
  150. package/dist/harness/pico3/types.d.ts.map +1 -0
  151. package/dist/harness/pico3/types.js +106 -0
  152. package/dist/harness/pico3/types.js.map +1 -0
  153. package/dist/harness/pico3/view.d.ts +34 -0
  154. package/dist/harness/pico3/view.d.ts.map +1 -0
  155. package/dist/harness/pico3/view.js +411 -0
  156. package/dist/harness/pico3/view.js.map +1 -0
  157. package/dist/harness/prompt-templates.d.ts +3 -2
  158. package/dist/harness/prompt-templates.d.ts.map +1 -1
  159. package/dist/harness/prompt-templates.js +18 -23
  160. package/dist/harness/prompt-templates.js.map +1 -1
  161. package/dist/harness/result.d.ts +133 -0
  162. package/dist/harness/result.d.ts.map +1 -0
  163. package/dist/harness/result.js +81 -0
  164. package/dist/harness/result.js.map +1 -0
  165. package/dist/harness/runtime/drive/boundary.d.ts +28 -0
  166. package/dist/harness/runtime/drive/boundary.d.ts.map +1 -0
  167. package/dist/harness/runtime/drive/boundary.js +173 -0
  168. package/dist/harness/runtime/drive/boundary.js.map +1 -0
  169. package/dist/harness/runtime/drive/checkpoint.d.ts +8 -0
  170. package/dist/harness/runtime/drive/checkpoint.d.ts.map +1 -0
  171. package/dist/harness/runtime/drive/checkpoint.js +133 -0
  172. package/dist/harness/runtime/drive/checkpoint.js.map +1 -0
  173. package/dist/harness/runtime/drive/deferred.d.ts +15 -0
  174. package/dist/harness/runtime/drive/deferred.d.ts.map +1 -0
  175. package/dist/harness/runtime/drive/deferred.js +179 -0
  176. package/dist/harness/runtime/drive/deferred.js.map +1 -0
  177. package/dist/harness/runtime/drive/generation.d.ts +8 -0
  178. package/dist/harness/runtime/drive/generation.d.ts.map +1 -0
  179. package/dist/harness/runtime/drive/generation.js +205 -0
  180. package/dist/harness/runtime/drive/generation.js.map +1 -0
  181. package/dist/harness/runtime/drive/reconcile.d.ts +5 -0
  182. package/dist/harness/runtime/drive/reconcile.d.ts.map +1 -0
  183. package/dist/harness/runtime/drive/reconcile.js +140 -0
  184. package/dist/harness/runtime/drive/reconcile.js.map +1 -0
  185. package/dist/harness/runtime/drive/recovery.d.ts +8 -0
  186. package/dist/harness/runtime/drive/recovery.d.ts.map +1 -0
  187. package/dist/harness/runtime/drive/recovery.js +85 -0
  188. package/dist/harness/runtime/drive/recovery.js.map +1 -0
  189. package/dist/harness/runtime/drive/response.d.ts +23 -0
  190. package/dist/harness/runtime/drive/response.d.ts.map +1 -0
  191. package/dist/harness/runtime/drive/response.js +394 -0
  192. package/dist/harness/runtime/drive/response.js.map +1 -0
  193. package/dist/harness/runtime/drive/retry.d.ts +4 -0
  194. package/dist/harness/runtime/drive/retry.d.ts.map +1 -0
  195. package/dist/harness/runtime/drive/retry.js +34 -0
  196. package/dist/harness/runtime/drive/retry.js.map +1 -0
  197. package/dist/harness/runtime/drive/structural.d.ts +32 -0
  198. package/dist/harness/runtime/drive/structural.d.ts.map +1 -0
  199. package/dist/harness/runtime/drive/structural.js +929 -0
  200. package/dist/harness/runtime/drive/structural.js.map +1 -0
  201. package/dist/harness/runtime/drive/terminal.d.ts +7 -0
  202. package/dist/harness/runtime/drive/terminal.d.ts.map +1 -0
  203. package/dist/harness/runtime/drive/terminal.js +49 -0
  204. package/dist/harness/runtime/drive/terminal.js.map +1 -0
  205. package/dist/harness/runtime/drive/tool-placement.d.ts +14 -0
  206. package/dist/harness/runtime/drive/tool-placement.d.ts.map +1 -0
  207. package/dist/harness/runtime/drive/tool-placement.js +219 -0
  208. package/dist/harness/runtime/drive/tool-placement.js.map +1 -0
  209. package/dist/harness/runtime/drive/tools.d.ts +6 -0
  210. package/dist/harness/runtime/drive/tools.d.ts.map +1 -0
  211. package/dist/harness/runtime/drive/tools.js +449 -0
  212. package/dist/harness/runtime/drive/tools.js.map +1 -0
  213. package/dist/harness/runtime/drive.d.ts +6 -0
  214. package/dist/harness/runtime/drive.d.ts.map +1 -0
  215. package/dist/harness/runtime/drive.js +93 -0
  216. package/dist/harness/runtime/drive.js.map +1 -0
  217. package/dist/harness/runtime/harness.d.ts +59 -0
  218. package/dist/harness/runtime/harness.d.ts.map +1 -0
  219. package/dist/harness/runtime/harness.js +311 -0
  220. package/dist/harness/runtime/harness.js.map +1 -0
  221. package/dist/harness/runtime/index.d.ts +2 -0
  222. package/dist/harness/runtime/index.d.ts.map +1 -0
  223. package/dist/harness/runtime/index.js +2 -0
  224. package/dist/harness/runtime/index.js.map +1 -0
  225. package/dist/harness/runtime/lane.d.ts +118 -0
  226. package/dist/harness/runtime/lane.d.ts.map +1 -0
  227. package/dist/harness/runtime/lane.js +1575 -0
  228. package/dist/harness/runtime/lane.js.map +1 -0
  229. package/dist/harness/runtime/progress.d.ts +15 -0
  230. package/dist/harness/runtime/progress.d.ts.map +1 -0
  231. package/dist/harness/runtime/progress.js +66 -0
  232. package/dist/harness/runtime/progress.js.map +1 -0
  233. package/dist/harness/runtime/reducer.d.ts +5 -0
  234. package/dist/harness/runtime/reducer.d.ts.map +1 -0
  235. package/dist/harness/runtime/reducer.js +240 -0
  236. package/dist/harness/runtime/reducer.js.map +1 -0
  237. package/dist/harness/runtime/restore.d.ts +24 -0
  238. package/dist/harness/runtime/restore.d.ts.map +1 -0
  239. package/dist/harness/runtime/restore.js +117 -0
  240. package/dist/harness/runtime/restore.js.map +1 -0
  241. package/dist/harness/runtime/transcript.d.ts +21 -0
  242. package/dist/harness/runtime/transcript.d.ts.map +1 -0
  243. package/dist/harness/runtime/transcript.js +72 -0
  244. package/dist/harness/runtime/transcript.js.map +1 -0
  245. package/dist/harness/runtime/types.d.ts +105 -0
  246. package/dist/harness/runtime/types.d.ts.map +1 -0
  247. package/dist/harness/runtime/types.js +61 -0
  248. package/dist/harness/runtime/types.js.map +1 -0
  249. package/dist/harness/session/commit.d.ts +53 -0
  250. package/dist/harness/session/commit.d.ts.map +1 -0
  251. package/dist/harness/session/commit.js +57 -0
  252. package/dist/harness/session/commit.js.map +1 -0
  253. package/dist/harness/session/context.d.ts +10 -0
  254. package/dist/harness/session/context.d.ts.map +1 -0
  255. package/dist/harness/session/context.js +49 -0
  256. package/dist/harness/session/context.js.map +1 -0
  257. package/dist/harness/session/fork-policy.d.ts +21 -0
  258. package/dist/harness/session/fork-policy.d.ts.map +1 -0
  259. package/dist/harness/session/fork-policy.js +55 -0
  260. package/dist/harness/session/fork-policy.js.map +1 -0
  261. package/dist/harness/session/fork.d.ts +16 -0
  262. package/dist/harness/session/fork.d.ts.map +1 -0
  263. package/dist/harness/session/fork.js +79 -0
  264. package/dist/harness/session/fork.js.map +1 -0
  265. package/dist/harness/session/in-memory-storage-state.d.ts +39 -0
  266. package/dist/harness/session/in-memory-storage-state.d.ts.map +1 -0
  267. package/dist/harness/session/in-memory-storage-state.js +276 -0
  268. package/dist/harness/session/in-memory-storage-state.js.map +1 -0
  269. package/dist/harness/session/index.d.ts +11 -0
  270. package/dist/harness/session/index.d.ts.map +1 -0
  271. package/dist/harness/session/index.js +9 -0
  272. package/dist/harness/session/index.js.map +1 -0
  273. package/dist/harness/session/jsonl/codec.d.ts +21 -0
  274. package/dist/harness/session/jsonl/codec.d.ts.map +1 -0
  275. package/dist/harness/session/jsonl/codec.js +45 -0
  276. package/dist/harness/session/jsonl/codec.js.map +1 -0
  277. package/dist/harness/session/jsonl/fork.d.ts +38 -0
  278. package/dist/harness/session/jsonl/fork.d.ts.map +1 -0
  279. package/dist/harness/session/jsonl/fork.js +264 -0
  280. package/dist/harness/session/jsonl/fork.js.map +1 -0
  281. package/dist/harness/session/jsonl/index.d.ts +4 -0
  282. package/dist/harness/session/jsonl/index.d.ts.map +1 -0
  283. package/dist/harness/session/jsonl/index.js +4 -0
  284. package/dist/harness/session/jsonl/index.js.map +1 -0
  285. package/dist/harness/session/jsonl/io.d.ts +14 -0
  286. package/dist/harness/session/jsonl/io.d.ts.map +1 -0
  287. package/dist/harness/session/jsonl/io.js +86 -0
  288. package/dist/harness/session/jsonl/io.js.map +1 -0
  289. package/dist/harness/session/jsonl/legacy-v3.d.ts +44 -0
  290. package/dist/harness/session/jsonl/legacy-v3.d.ts.map +1 -0
  291. package/dist/harness/session/jsonl/legacy-v3.js +462 -0
  292. package/dist/harness/session/jsonl/legacy-v3.js.map +1 -0
  293. package/dist/harness/session/jsonl/repo.d.ts +35 -0
  294. package/dist/harness/session/jsonl/repo.d.ts.map +1 -0
  295. package/dist/harness/session/jsonl/repo.js +301 -0
  296. package/dist/harness/session/jsonl/repo.js.map +1 -0
  297. package/dist/harness/session/jsonl/storage.d.ts +41 -0
  298. package/dist/harness/session/jsonl/storage.d.ts.map +1 -0
  299. package/dist/harness/session/jsonl/storage.js +200 -0
  300. package/dist/harness/session/jsonl/storage.js.map +1 -0
  301. package/dist/harness/session/jsonl/types.d.ts +39 -0
  302. package/dist/harness/session/jsonl/types.d.ts.map +1 -0
  303. package/dist/harness/session/jsonl/types.js +3 -0
  304. package/dist/harness/session/jsonl/types.js.map +1 -0
  305. package/dist/harness/session/memory.d.ts +48 -0
  306. package/dist/harness/session/memory.d.ts.map +1 -0
  307. package/dist/harness/session/memory.js +369 -0
  308. package/dist/harness/session/memory.js.map +1 -0
  309. package/dist/harness/session/mutation-line.d.ts +8 -0
  310. package/dist/harness/session/mutation-line.d.ts.map +1 -0
  311. package/dist/harness/session/mutation-line.js +21 -0
  312. package/dist/harness/session/mutation-line.js.map +1 -0
  313. package/dist/harness/session/session.d.ts +79 -46
  314. package/dist/harness/session/session.d.ts.map +1 -1
  315. package/dist/harness/session/session.js +320 -220
  316. package/dist/harness/session/session.js.map +1 -1
  317. package/dist/harness/session/testing/benchmark/datasets.d.ts +12 -0
  318. package/dist/harness/session/testing/benchmark/datasets.d.ts.map +1 -0
  319. package/dist/harness/session/testing/benchmark/datasets.js +24 -0
  320. package/dist/harness/session/testing/benchmark/datasets.js.map +1 -0
  321. package/dist/harness/session/testing/benchmark/session-repo.d.ts +42 -0
  322. package/dist/harness/session/testing/benchmark/session-repo.d.ts.map +1 -0
  323. package/dist/harness/session/testing/benchmark/session-repo.js +127 -0
  324. package/dist/harness/session/testing/benchmark/session-repo.js.map +1 -0
  325. package/dist/harness/session/testing/benchmark/storage.d.ts +25 -0
  326. package/dist/harness/session/testing/benchmark/storage.d.ts.map +1 -0
  327. package/dist/harness/session/testing/benchmark/storage.js +114 -0
  328. package/dist/harness/session/testing/benchmark/storage.js.map +1 -0
  329. package/dist/harness/session/testing/conformance/session-repo.d.ts +23 -0
  330. package/dist/harness/session/testing/conformance/session-repo.d.ts.map +1 -0
  331. package/dist/harness/session/testing/conformance/session-repo.js +809 -0
  332. package/dist/harness/session/testing/conformance/session-repo.js.map +1 -0
  333. package/dist/harness/session/testing/conformance/storage.d.ts +4 -0
  334. package/dist/harness/session/testing/conformance/storage.d.ts.map +1 -0
  335. package/dist/harness/session/testing/conformance/storage.js +600 -0
  336. package/dist/harness/session/testing/conformance/storage.js.map +1 -0
  337. package/dist/harness/session/testing/gating-storage.d.ts +26 -0
  338. package/dist/harness/session/testing/gating-storage.d.ts.map +1 -0
  339. package/dist/harness/session/testing/gating-storage.js +100 -0
  340. package/dist/harness/session/testing/gating-storage.js.map +1 -0
  341. package/dist/harness/session/testing/index.d.ts +10 -0
  342. package/dist/harness/session/testing/index.d.ts.map +1 -0
  343. package/dist/harness/session/testing/index.js +9 -0
  344. package/dist/harness/session/testing/index.js.map +1 -0
  345. package/dist/harness/session/testing/instrumented-storage.d.ts +11 -0
  346. package/dist/harness/session/testing/instrumented-storage.d.ts.map +1 -0
  347. package/dist/harness/session/testing/instrumented-storage.js +16 -0
  348. package/dist/harness/session/testing/instrumented-storage.js.map +1 -0
  349. package/dist/harness/session/testing/storage-decorator.d.ts +20 -0
  350. package/dist/harness/session/testing/storage-decorator.d.ts.map +1 -0
  351. package/dist/harness/session/testing/storage-decorator.js +41 -0
  352. package/dist/harness/session/testing/storage-decorator.js.map +1 -0
  353. package/dist/harness/session/testing/types.d.ts +12 -0
  354. package/dist/harness/session/testing/types.d.ts.map +1 -0
  355. package/dist/harness/session/testing/types.js +2 -0
  356. package/dist/harness/session/testing/types.js.map +1 -0
  357. package/dist/harness/session/types.d.ts +512 -0
  358. package/dist/harness/session/types.d.ts.map +1 -0
  359. package/dist/harness/session/types.js +9 -0
  360. package/dist/harness/session/types.js.map +1 -0
  361. package/dist/harness/session/values.d.ts +95 -0
  362. package/dist/harness/session/values.d.ts.map +1 -0
  363. package/dist/harness/session/values.js +81 -0
  364. package/dist/harness/session/values.js.map +1 -0
  365. package/dist/harness/skills.d.ts +6 -4
  366. package/dist/harness/skills.d.ts.map +1 -1
  367. package/dist/harness/skills.js +59 -44
  368. package/dist/harness/skills.js.map +1 -1
  369. package/dist/harness/telemetry.d.ts +1242 -0
  370. package/dist/harness/telemetry.d.ts.map +1 -0
  371. package/dist/harness/telemetry.js +527 -0
  372. package/dist/harness/telemetry.js.map +1 -0
  373. package/dist/harness/tools/bash.d.ts +4 -4
  374. package/dist/harness/tools/bash.d.ts.map +1 -1
  375. package/dist/harness/tools/bash.js +66 -93
  376. package/dist/harness/tools/bash.js.map +1 -1
  377. package/dist/harness/tools/edit.d.ts.map +1 -1
  378. package/dist/harness/tools/edit.js +24 -11
  379. package/dist/harness/tools/edit.js.map +1 -1
  380. package/dist/harness/tools/file-mutation-queue.d.ts +2 -1
  381. package/dist/harness/tools/file-mutation-queue.d.ts.map +1 -1
  382. package/dist/harness/tools/file-mutation-queue.js +5 -5
  383. package/dist/harness/tools/file-mutation-queue.js.map +1 -1
  384. package/dist/harness/tools/image.js +1 -1
  385. package/dist/harness/tools/image.js.map +1 -1
  386. package/dist/harness/tools/path-utils.d.ts +3 -2
  387. package/dist/harness/tools/path-utils.d.ts.map +1 -1
  388. package/dist/harness/tools/path-utils.js +5 -5
  389. package/dist/harness/tools/path-utils.js.map +1 -1
  390. package/dist/harness/tools/read.d.ts +2 -1
  391. package/dist/harness/tools/read.d.ts.map +1 -1
  392. package/dist/harness/tools/read.js +4 -6
  393. package/dist/harness/tools/read.js.map +1 -1
  394. package/dist/harness/tools/write.d.ts.map +1 -1
  395. package/dist/harness/tools/write.js +7 -7
  396. package/dist/harness/tools/write.js.map +1 -1
  397. package/dist/harness/types.d.ts +126 -502
  398. package/dist/harness/types.d.ts.map +1 -1
  399. package/dist/harness/types.js +10 -16
  400. package/dist/harness/types.js.map +1 -1
  401. package/dist/harness/utils/adaptive-publisher.d.ts +24 -0
  402. package/dist/harness/utils/adaptive-publisher.d.ts.map +1 -0
  403. package/dist/harness/utils/adaptive-publisher.js +79 -0
  404. package/dist/harness/utils/adaptive-publisher.js.map +1 -0
  405. package/dist/harness/utils/output-capture.d.ts +31 -0
  406. package/dist/harness/utils/output-capture.d.ts.map +1 -0
  407. package/dist/harness/utils/output-capture.js +217 -0
  408. package/dist/harness/utils/output-capture.js.map +1 -0
  409. package/dist/harness/utils/shell-output.d.ts +12 -5
  410. package/dist/harness/utils/shell-output.d.ts.map +1 -1
  411. package/dist/harness/utils/shell-output.js +64 -174
  412. package/dist/harness/utils/shell-output.js.map +1 -1
  413. package/dist/harness/utils/truncate.d.ts +1 -0
  414. package/dist/harness/utils/truncate.d.ts.map +1 -1
  415. package/dist/harness/utils/truncate.js +1 -1
  416. package/dist/harness/utils/truncate.js.map +1 -1
  417. package/dist/harness/utils/usage.d.ts +4 -0
  418. package/dist/harness/utils/usage.d.ts.map +1 -0
  419. package/dist/harness/utils/usage.js +33 -0
  420. package/dist/harness/utils/usage.js.map +1 -0
  421. package/dist/index.d.ts +13 -9
  422. package/dist/index.d.ts.map +1 -1
  423. package/dist/index.js +9 -13
  424. package/dist/index.js.map +1 -1
  425. package/dist/proxy.d.ts +6 -3
  426. package/dist/proxy.d.ts.map +1 -1
  427. package/dist/proxy.js +42 -10
  428. package/dist/proxy.js.map +1 -1
  429. package/dist/search/index.d.ts +29 -0
  430. package/dist/search/index.d.ts.map +1 -0
  431. package/dist/search/index.js +2 -0
  432. package/dist/search/index.js.map +1 -0
  433. package/dist/types.d.ts +113 -31
  434. package/dist/types.d.ts.map +1 -1
  435. package/dist/types.js.map +1 -1
  436. package/package.json +50 -4
  437. package/dist/harness/session/jsonl-repo.d.ts +0 -26
  438. package/dist/harness/session/jsonl-repo.d.ts.map +0 -1
  439. package/dist/harness/session/jsonl-repo.js +0 -100
  440. package/dist/harness/session/jsonl-repo.js.map +0 -1
  441. package/dist/harness/session/jsonl-storage.d.ts +0 -42
  442. package/dist/harness/session/jsonl-storage.d.ts.map +0 -1
  443. package/dist/harness/session/jsonl-storage.js +0 -286
  444. package/dist/harness/session/jsonl-storage.js.map +0 -1
  445. package/dist/harness/session/memory-repo.d.ts +0 -18
  446. package/dist/harness/session/memory-repo.d.ts.map +0 -1
  447. package/dist/harness/session/memory-repo.js +0 -44
  448. package/dist/harness/session/memory-repo.js.map +0 -1
  449. package/dist/harness/session/memory-storage.d.ts +0 -33
  450. package/dist/harness/session/memory-storage.d.ts.map +0 -1
  451. package/dist/harness/session/memory-storage.js +0 -163
  452. package/dist/harness/session/memory-storage.js.map +0 -1
  453. package/dist/harness/session/repo-utils.d.ts +0 -11
  454. package/dist/harness/session/repo-utils.d.ts.map +0 -1
  455. package/dist/harness/session/repo-utils.js +0 -39
  456. package/dist/harness/session/repo-utils.js.map +0 -1
@@ -1,15 +1,16 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { randomUUID } from "node:crypto";
3
- import { constants, createReadStream } from "node:fs";
4
- import { access, appendFile, lstat, mkdir, mkdtemp, readdir, readFile, realpath, rm, writeFile, } from "node:fs/promises";
5
- import { homedir, tmpdir } from "node:os";
6
- import { isAbsolute, join, resolve } from "node:path";
7
- import { createInterface } from "node:readline";
3
+ import { constants, createWriteStream } from "node:fs";
4
+ import { access, appendFile, lstat, mkdir, mkdtemp, open as openFile, readdir, readFile, realpath, rename, rm, writeFile, } from "node:fs/promises";
5
+ import { homedir, constants as osConstants, tmpdir } from "node:os";
6
+ import { basename, isAbsolute, join, resolve } from "node:path";
8
7
  import { fileURLToPath } from "node:url";
9
8
  import { ExecutionError, err, FileError, ok, toError, } from "../types.js";
9
+ import { OutputCapture } from "../utils/output-capture.js";
10
10
  const MAX_TIMEOUT_MS = 2_147_483_647;
11
11
  const MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;
12
12
  const EXIT_STDIO_GRACE_MS = 100;
13
+ const SPILL_HIGH_WATER_MARK = 8 * 1024 * 1024;
13
14
  function resolveTimeoutMs(timeout) {
14
15
  if (timeout === undefined)
15
16
  return ok(undefined);
@@ -54,7 +55,7 @@ function fileInfoFromStats(path, stats) {
54
55
  if (!kind)
55
56
  return err(new FileError("invalid", "Unsupported file type", path));
56
57
  return ok({
57
- name: path.replace(/\/+$/, "").split("/").pop() ?? path,
58
+ name: basename(path),
58
59
  path,
59
60
  kind,
60
61
  size: stats.size,
@@ -64,13 +65,15 @@ function fileInfoFromStats(path, stats) {
64
65
  function isNodeError(error) {
65
66
  return error instanceof Error && "code" in error;
66
67
  }
67
- function toFileError(error, path) {
68
+ function toFileError(error, fallbackPath) {
68
69
  if (error instanceof FileError)
69
70
  return error;
70
71
  const cause = toError(error);
71
- if (isNodeError(error)) {
72
- const message = error.message;
73
- switch (error.code) {
72
+ const nodeError = isNodeError(error) ? error : undefined;
73
+ const path = typeof nodeError?.path === "string" ? nodeError.path : fallbackPath;
74
+ if (nodeError) {
75
+ const message = nodeError.message;
76
+ switch (nodeError.code) {
74
77
  case "ABORT_ERR":
75
78
  return new FileError("aborted", message, path, cause);
76
79
  case "ENOENT":
@@ -199,11 +202,13 @@ function getShellEnv(baseEnv, extraEnv, inheritEnv = true) {
199
202
  function killProcessTree(pid) {
200
203
  if (process.platform === "win32") {
201
204
  try {
202
- spawn("taskkill", ["/F", "/T", "/PID", String(pid)], {
205
+ const child = spawn(join(process.env.SystemRoot ?? "C:\\Windows", "System32", "taskkill.exe"), ["/F", "/T", "/PID", String(pid)], {
203
206
  stdio: "ignore",
204
207
  detached: true,
205
208
  windowsHide: true,
206
209
  });
210
+ // A failed spawn emits "error" asynchronously; consume it to avoid crashing Node.
211
+ child.once("error", () => { });
207
212
  }
208
213
  catch {
209
214
  // Ignore errors.
@@ -222,11 +227,12 @@ function killProcessTree(pid) {
222
227
  }
223
228
  }
224
229
  }
225
- function waitForChildProcess(child) {
230
+ function waitForChildProcess(child, spillIsDraining) {
226
231
  return new Promise((resolvePromise, reject) => {
227
232
  let settled = false;
228
233
  let exited = false;
229
234
  let exitCode = null;
235
+ let exitSignal = null;
230
236
  let postExitTimer;
231
237
  let stdoutEnded = child.stdout === null;
232
238
  let stderrEnded = child.stderr === null;
@@ -241,23 +247,28 @@ function waitForChildProcess(child) {
241
247
  child.stdout?.removeListener("data", onData);
242
248
  child.stderr?.removeListener("data", onData);
243
249
  };
244
- const finalize = (code) => {
250
+ const finalize = () => {
245
251
  if (settled)
246
252
  return;
247
253
  settled = true;
248
254
  cleanup();
249
255
  child.stdout?.destroy();
250
256
  child.stderr?.destroy();
251
- resolvePromise(code);
257
+ resolvePromise({ code: exitCode, signal: exitSignal });
252
258
  };
253
259
  const maybeFinalizeAfterExit = () => {
254
260
  if (exited && stdoutEnded && stderrEnded)
255
- finalize(exitCode);
261
+ finalize();
256
262
  };
257
263
  const armIdleTimer = () => {
258
264
  if (postExitTimer)
259
265
  clearTimeout(postExitTimer);
260
- postExitTimer = setTimeout(() => finalize(exitCode), EXIT_STDIO_GRACE_MS);
266
+ postExitTimer = setTimeout(() => {
267
+ if (spillIsDraining())
268
+ armIdleTimer();
269
+ else
270
+ finalize();
271
+ }, EXIT_STDIO_GRACE_MS);
261
272
  };
262
273
  const onData = () => {
263
274
  if (exited && !settled)
@@ -278,14 +289,19 @@ function waitForChildProcess(child) {
278
289
  cleanup();
279
290
  reject(error);
280
291
  };
281
- const onExit = (code) => {
292
+ const onExit = (code, signal) => {
282
293
  exited = true;
283
294
  exitCode = code;
295
+ exitSignal = signal;
284
296
  maybeFinalizeAfterExit();
285
297
  if (!settled)
286
298
  armIdleTimer();
287
299
  };
288
- const onClose = (code) => finalize(code);
300
+ const onClose = (code, signal) => {
301
+ exitCode = code;
302
+ exitSignal = signal;
303
+ finalize();
304
+ };
289
305
  child.stdout?.once("end", onStdoutEnd);
290
306
  child.stderr?.once("end", onStderrEnd);
291
307
  child.stdout?.on("data", onData);
@@ -295,21 +311,92 @@ function waitForChildProcess(child) {
295
311
  child.once("close", onClose);
296
312
  });
297
313
  }
314
+ /** Strict LF reader; Node readline does not report whether its final line was newline-terminated. */
315
+ class NodeTextLineReader {
316
+ file;
317
+ path;
318
+ decoder = new TextDecoder();
319
+ chunk = new Uint8Array(64 * 1024);
320
+ byteOffset = 0;
321
+ buffered = "";
322
+ ended = false;
323
+ closed = false;
324
+ constructor(file, path) {
325
+ this.file = file;
326
+ this.path = path;
327
+ }
328
+ async readLine(context) {
329
+ const aborted = abortResult(context.abortSignal, this.path);
330
+ if (aborted)
331
+ return aborted;
332
+ if (this.closed)
333
+ return err(new FileError("invalid", "Text line reader is closed", this.path));
334
+ try {
335
+ while (true) {
336
+ const newline = this.buffered.indexOf("\n");
337
+ if (newline !== -1) {
338
+ const text = this.buffered.slice(0, newline);
339
+ this.buffered = this.buffered.slice(newline + 1);
340
+ return ok({ text, terminated: true });
341
+ }
342
+ if (this.ended) {
343
+ if (this.buffered.length === 0)
344
+ return ok(undefined);
345
+ const text = this.buffered;
346
+ this.buffered = "";
347
+ return ok({ text, terminated: false });
348
+ }
349
+ // Explicit positions allow an aborted read to be retried without skipping bytes.
350
+ const { bytesRead } = await this.file.read(this.chunk, 0, this.chunk.length, this.byteOffset);
351
+ const afterReadAbort = abortResult(context.abortSignal, this.path);
352
+ if (afterReadAbort)
353
+ return afterReadAbort;
354
+ this.byteOffset += bytesRead;
355
+ if (bytesRead === 0) {
356
+ this.buffered += this.decoder.decode();
357
+ this.ended = true;
358
+ }
359
+ else {
360
+ this.buffered += this.decoder.decode(this.chunk.subarray(0, bytesRead), { stream: true });
361
+ }
362
+ }
363
+ }
364
+ catch (error) {
365
+ return err(toFileError(error, this.path));
366
+ }
367
+ }
368
+ async close(_context) {
369
+ if (this.closed)
370
+ return;
371
+ this.closed = true;
372
+ this.buffered = "";
373
+ try {
374
+ await this.file.close();
375
+ }
376
+ catch {
377
+ // Closing is best-effort, including after cancellation or an earlier I/O failure.
378
+ }
379
+ }
380
+ }
298
381
  export class NodeExecutionEnv {
382
+ cwd;
383
+ shellPath;
384
+ shellEnv;
385
+ activeChildPids = new Set();
299
386
  constructor(options) {
300
- this.activeChildPids = new Set();
301
387
  this.cwd = options.cwd;
302
388
  this.shellPath = options.shellPath;
303
389
  this.shellEnv = options.shellEnv;
304
390
  }
305
- async absolutePath(path) {
391
+ async absolutePath(path, _context) {
306
392
  return ok(resolvePath(this.cwd, path));
307
393
  }
308
- async joinPath(parts) {
394
+ async joinPath(parts, _context) {
309
395
  return ok(join(...parts));
310
396
  }
311
- async exec(command, options) {
312
- if (options?.abortSignal?.aborted)
397
+ async exec(command, options, context) {
398
+ const signal = context.abortSignal;
399
+ if (signal?.aborted)
313
400
  return err(new ExecutionError("aborted", "aborted"));
314
401
  const timeoutMsResult = resolveTimeoutMs(options?.timeout);
315
402
  if (!timeoutMsResult.ok)
@@ -327,30 +414,119 @@ export class NodeExecutionEnv {
327
414
  return err(new ExecutionError("spawn_error", `Working directory does not exist: ${cwd}\nCannot execute bash commands.`, cause));
328
415
  }
329
416
  return await new Promise((resolvePromise) => {
330
- let stdout = "";
331
- let stderr = "";
332
417
  let settled = false;
333
418
  let timedOut = false;
334
419
  let callbackError;
420
+ let spillError;
335
421
  let child;
336
422
  let timeoutId;
423
+ const spillPrefix = [];
424
+ let spillPath;
425
+ const spillQueue = [];
426
+ let spillStart;
427
+ let spillStream;
428
+ let spillBackpressured = false;
337
429
  const onAbort = () => {
338
- if (child?.pid) {
430
+ if (child?.pid)
339
431
  killProcessTree(child.pid);
340
- }
341
432
  };
433
+ const failCallback = (error) => {
434
+ if (callbackError !== undefined)
435
+ return;
436
+ const cause = toError(error);
437
+ callbackError = new ExecutionError("callback_error", cause.message, cause);
438
+ onAbort();
439
+ };
440
+ let capture;
441
+ try {
442
+ capture = new OutputCapture(options?.capture, context, {
443
+ onUpdate: options?.onUpdate,
444
+ onError: failCallback,
445
+ });
446
+ }
447
+ catch (error) {
448
+ const cause = toError(error);
449
+ resolvePromise(err(new ExecutionError("unknown", cause.message, cause)));
450
+ return;
451
+ }
342
452
  const settle = (result) => {
453
+ if (settled)
454
+ return;
455
+ settled = true;
343
456
  if (timeoutId)
344
457
  clearTimeout(timeoutId);
345
- if (options?.abortSignal)
346
- options.abortSignal.removeEventListener("abort", onAbort);
458
+ if (signal)
459
+ signal.removeEventListener("abort", onAbort);
347
460
  if (child?.pid)
348
461
  this.activeChildPids.delete(child.pid);
349
- if (settled)
350
- return;
351
- settled = true;
462
+ capture.dispose();
352
463
  resolvePromise(result);
353
464
  };
465
+ const pauseOutput = () => {
466
+ child?.stdout?.pause();
467
+ child?.stderr?.pause();
468
+ };
469
+ const resumeOutput = () => {
470
+ if (callbackError || spillError || timedOut || signal?.aborted || spillBackpressured)
471
+ return;
472
+ child?.stdout?.resume();
473
+ child?.stderr?.resume();
474
+ };
475
+ const failSpill = (error) => {
476
+ if (spillError !== undefined)
477
+ return;
478
+ const cause = toError(error);
479
+ spillError = new ExecutionError("unknown", `Failed to preserve complete shell output: ${cause.message}`, cause);
480
+ spillBackpressured = false;
481
+ onAbort();
482
+ };
483
+ const writeSpill = (chunk) => {
484
+ if (spillStream === undefined || chunk.length === 0)
485
+ return;
486
+ if (spillStream.write(chunk) || spillBackpressured)
487
+ return;
488
+ spillBackpressured = true;
489
+ pauseOutput();
490
+ spillStream.once("drain", () => {
491
+ spillBackpressured = false;
492
+ resumeOutput();
493
+ });
494
+ };
495
+ const startSpill = (chunk) => {
496
+ if (spillStream !== undefined) {
497
+ writeSpill(chunk);
498
+ return;
499
+ }
500
+ spillQueue.push(chunk);
501
+ if (spillStart !== undefined)
502
+ return;
503
+ pauseOutput();
504
+ spillStart = (async () => {
505
+ const created = await this.createTempFile({ prefix: "draht-output-", suffix: ".log" }, context);
506
+ if (!created.ok)
507
+ throw created.error;
508
+ spillPath = created.value;
509
+ capture.setSpillPath(spillPath);
510
+ spillStream = createWriteStream(spillPath, { flags: "a", highWaterMark: SPILL_HIGH_WATER_MARK });
511
+ spillStream.on("error", failSpill);
512
+ for (const queued of spillQueue)
513
+ writeSpill(queued);
514
+ spillQueue.length = 0;
515
+ })()
516
+ .catch(failSpill)
517
+ .finally(resumeOutput);
518
+ };
519
+ const finishSpill = async () => {
520
+ await spillStart;
521
+ const stream = spillStream;
522
+ if (stream === undefined || spillError !== undefined || stream.destroyed)
523
+ return;
524
+ await new Promise((resolveFinish) => {
525
+ stream.once("error", () => resolveFinish());
526
+ stream.once("finish", resolveFinish);
527
+ stream.end();
528
+ });
529
+ };
354
530
  try {
355
531
  const commandFromStdin = shellConfig.value.commandTransport === "stdin";
356
532
  child = spawn(shellConfig.value.shell, commandFromStdin ? shellConfig.value.args : [...shellConfig.value.args, command], {
@@ -373,47 +549,54 @@ export class NodeExecutionEnv {
373
549
  return;
374
550
  }
375
551
  timeoutId =
376
- timeoutMs !== undefined
377
- ? setTimeout(() => {
552
+ timeoutMs === undefined
553
+ ? undefined
554
+ : setTimeout(() => {
378
555
  timedOut = true;
379
- if (child?.pid) {
380
- killProcessTree(child.pid);
381
- }
382
- }, timeoutMs)
383
- : undefined;
384
- if (options?.abortSignal) {
385
- if (options.abortSignal.aborted) {
556
+ onAbort();
557
+ }, timeoutMs);
558
+ if (signal) {
559
+ if (signal.aborted)
386
560
  onAbort();
387
- }
388
- else {
389
- options.abortSignal.addEventListener("abort", onAbort, { once: true });
390
- }
561
+ else
562
+ signal.addEventListener("abort", onAbort, { once: true });
391
563
  }
392
- child.stdout?.setEncoding("utf8");
393
- child.stderr?.setEncoding("utf8");
394
- child.stdout?.on("data", (chunk) => {
395
- stdout += chunk;
564
+ const feed = (chunk) => {
396
565
  try {
397
- options?.onStdout?.(chunk);
566
+ const wasTruncated = capture.truncated;
567
+ capture.push(chunk);
568
+ if (!options?.capture?.spill || chunk.length === 0)
569
+ return;
570
+ if (spillPath !== undefined || wasTruncated) {
571
+ startSpill(chunk);
572
+ }
573
+ else if (capture.truncated) {
574
+ for (const prefix of spillPrefix)
575
+ startSpill(prefix);
576
+ spillPrefix.length = 0;
577
+ startSpill(chunk);
578
+ }
579
+ else {
580
+ spillPrefix.push(chunk);
581
+ }
398
582
  }
399
583
  catch (error) {
400
- const cause = toError(error);
401
- callbackError = new ExecutionError("callback_error", cause.message, cause);
402
- onAbort();
584
+ failCallback(error);
403
585
  }
404
- });
405
- child.stderr?.on("data", (chunk) => {
406
- stderr += chunk;
586
+ };
587
+ child.stdout?.on("data", feed);
588
+ child.stderr?.on("data", feed);
589
+ void waitForChildProcess(child, () => spillError === undefined &&
590
+ spillStart !== undefined &&
591
+ (spillStream === undefined || spillBackpressured)).then(async ({ code, signal: exitSignal }) => {
592
+ await finishSpill();
407
593
  try {
408
- options?.onStderr?.(chunk);
594
+ capture.finish();
595
+ capture.flush();
409
596
  }
410
597
  catch (error) {
411
- const cause = toError(error);
412
- callbackError = new ExecutionError("callback_error", cause.message, cause);
413
- onAbort();
598
+ failCallback(error);
414
599
  }
415
- });
416
- void waitForChildProcess(child).then((code) => {
417
600
  if (callbackError) {
418
601
  settle(err(callbackError));
419
602
  return;
@@ -422,102 +605,150 @@ export class NodeExecutionEnv {
422
605
  settle(err(new ExecutionError("timeout", `timeout:${options?.timeout}`)));
423
606
  return;
424
607
  }
425
- if (options?.abortSignal?.aborted) {
608
+ if (signal?.aborted) {
426
609
  settle(err(new ExecutionError("aborted", "aborted")));
427
610
  return;
428
611
  }
429
- settle(ok({ stdout, stderr, exitCode: code ?? 0 }));
612
+ if (spillError) {
613
+ settle(err(spillError));
614
+ return;
615
+ }
616
+ const output = capture.snapshot();
617
+ // A process killed by a signal (e.g. OOM killer) has no exit code; map it
618
+ // to the conventional 128 + signal number so callers do not mistake it
619
+ // for a successful exit.
620
+ const exitCode = code ?? (exitSignal ? 128 + (osConstants.signals[exitSignal] ?? 0) : 1);
621
+ settle(ok({
622
+ exitCode,
623
+ truncation: output.truncation,
624
+ ...(output.spillPath === undefined ? {} : { spillPath: output.spillPath }),
625
+ ...(output.lastLineBytes === undefined ? {} : { lastLineBytes: output.lastLineBytes }),
626
+ }));
430
627
  }, (error) => settle(err(new ExecutionError("spawn_error", error.message, error))));
431
628
  });
432
629
  }
433
- async readTextFile(path, abortSignal) {
630
+ async openTextLineReader(path, context) {
434
631
  const resolved = resolvePath(this.cwd, path);
435
- const aborted = abortResult(abortSignal, resolved);
632
+ const aborted = abortResult(context.abortSignal, resolved);
436
633
  if (aborted)
437
634
  return aborted;
438
635
  try {
439
- return ok(await readFile(resolved, { encoding: "utf8", signal: abortSignal }));
636
+ const file = await openFile(resolved, "r");
637
+ const afterOpenAbort = abortResult(context.abortSignal, resolved);
638
+ if (afterOpenAbort) {
639
+ await file.close().catch(() => undefined);
640
+ return afterOpenAbort;
641
+ }
642
+ return ok(new NodeTextLineReader(file, resolved));
440
643
  }
441
644
  catch (error) {
442
645
  return err(toFileError(error, resolved));
443
646
  }
444
647
  }
445
- async readTextLines(path, options) {
648
+ async readTextFile(path, context) {
446
649
  const resolved = resolvePath(this.cwd, path);
447
- const aborted = abortResult(options?.abortSignal, resolved);
650
+ const signal = context.abortSignal;
651
+ const aborted = abortResult(signal, resolved);
448
652
  if (aborted)
449
653
  return aborted;
654
+ try {
655
+ return ok(await readFile(resolved, { encoding: "utf8", signal }));
656
+ }
657
+ catch (error) {
658
+ return err(toFileError(error, resolved));
659
+ }
660
+ }
661
+ async readTextLines(path, options, context) {
450
662
  if (options?.maxLines !== undefined && options.maxLines <= 0)
451
663
  return ok([]);
452
- let stream;
453
- let lineReader;
664
+ const opened = await this.openTextLineReader(path, context);
665
+ if (!opened.ok)
666
+ return opened;
667
+ const lines = [];
454
668
  try {
455
- stream = createReadStream(resolved, { encoding: "utf8", signal: options?.abortSignal });
456
- lineReader = createInterface({ input: stream, crlfDelay: Infinity });
457
- const lines = [];
458
- for await (const line of lineReader) {
459
- const loopAbort = abortResult(options?.abortSignal, resolved);
460
- if (loopAbort)
461
- return loopAbort;
462
- lines.push(line);
463
- if (options?.maxLines !== undefined && lines.length >= options.maxLines)
669
+ while (options?.maxLines === undefined || lines.length < options.maxLines) {
670
+ const line = await opened.value.readLine(context);
671
+ if (!line.ok)
672
+ return line;
673
+ if (line.value === undefined)
464
674
  break;
675
+ lines.push(line.value.text);
465
676
  }
466
- const afterReadAbort = abortResult(options?.abortSignal, resolved);
467
- if (afterReadAbort)
468
- return afterReadAbort;
469
677
  return ok(lines);
470
678
  }
471
- catch (error) {
472
- return err(toFileError(error, resolved));
473
- }
474
679
  finally {
475
- lineReader?.close();
476
- stream?.destroy();
680
+ await opened.value.close(context);
477
681
  }
478
682
  }
479
- async readBinaryFile(path, abortSignal) {
683
+ async readBinaryFile(path, context) {
480
684
  const resolved = resolvePath(this.cwd, path);
481
- const aborted = abortResult(abortSignal, resolved);
685
+ const signal = context.abortSignal;
686
+ const aborted = abortResult(signal, resolved);
482
687
  if (aborted)
483
688
  return aborted;
484
689
  try {
485
- return ok(await readFile(resolved, { signal: abortSignal }));
690
+ return ok(await readFile(resolved, { signal }));
486
691
  }
487
692
  catch (error) {
488
693
  return err(toFileError(error, resolved));
489
694
  }
490
695
  }
491
- async writeFile(path, content, abortSignal) {
696
+ async writeFile(path, content, context) {
492
697
  const resolved = resolvePath(this.cwd, path);
493
- const aborted = abortResult(abortSignal, resolved);
698
+ const signal = context.abortSignal;
699
+ const aborted = abortResult(signal, resolved);
494
700
  if (aborted)
495
701
  return aborted;
496
702
  try {
497
703
  await mkdir(resolve(resolved, ".."), { recursive: true });
498
- const afterMkdirAbort = abortResult(abortSignal, resolved);
704
+ const afterMkdirAbort = abortResult(signal, resolved);
499
705
  if (afterMkdirAbort)
500
706
  return afterMkdirAbort;
501
- await writeFile(resolved, content, { signal: abortSignal });
707
+ await writeFile(resolved, content, { signal });
502
708
  return ok(undefined);
503
709
  }
504
710
  catch (error) {
505
711
  return err(toFileError(error, resolved));
506
712
  }
507
713
  }
508
- async appendFile(path, content) {
714
+ async appendFile(path, content, context) {
509
715
  const resolved = resolvePath(this.cwd, path);
716
+ const signal = context.abortSignal;
717
+ const aborted = abortResult(signal, resolved);
718
+ if (aborted)
719
+ return aborted;
510
720
  try {
511
721
  await mkdir(resolve(resolved, ".."), { recursive: true });
722
+ const afterMkdirAbort = abortResult(signal, resolved);
723
+ if (afterMkdirAbort)
724
+ return afterMkdirAbort;
512
725
  await appendFile(resolved, content);
513
- return ok(undefined);
726
+ const afterAppendAbort = abortResult(signal, resolved);
727
+ return afterAppendAbort ?? ok(undefined);
514
728
  }
515
729
  catch (error) {
516
730
  return err(toFileError(error, resolved));
517
731
  }
518
732
  }
519
- async fileInfo(path) {
733
+ async renameFile(sourcePath, destinationPath, context) {
734
+ const source = resolvePath(this.cwd, sourcePath);
735
+ const destination = resolvePath(this.cwd, destinationPath);
736
+ const aborted = abortResult(context.abortSignal, destination);
737
+ if (aborted)
738
+ return aborted;
739
+ try {
740
+ await rename(source, destination);
741
+ return ok(undefined);
742
+ }
743
+ catch (error) {
744
+ return err(toFileError(error, source));
745
+ }
746
+ }
747
+ async fileInfo(path, context) {
520
748
  const resolved = resolvePath(this.cwd, path);
749
+ const aborted = abortResult(context.abortSignal, resolved);
750
+ if (aborted)
751
+ return aborted;
521
752
  try {
522
753
  return fileInfoFromStats(resolved, await lstat(resolved));
523
754
  }
@@ -525,16 +756,17 @@ export class NodeExecutionEnv {
525
756
  return err(toFileError(error, resolved));
526
757
  }
527
758
  }
528
- async listDir(path, abortSignal) {
759
+ async listDir(path, context) {
529
760
  const resolved = resolvePath(this.cwd, path);
530
- const aborted = abortResult(abortSignal, resolved);
761
+ const signal = context.abortSignal;
762
+ const aborted = abortResult(signal, resolved);
531
763
  if (aborted)
532
764
  return aborted;
533
765
  try {
534
766
  const entries = await readdir(resolved, { withFileTypes: true });
535
767
  const infos = [];
536
768
  for (const entry of entries) {
537
- const loopAbort = abortResult(abortSignal, resolved);
769
+ const loopAbort = abortResult(signal, resolved);
538
770
  if (loopAbort)
539
771
  return loopAbort;
540
772
  const entryPath = resolve(resolved, entry.name);
@@ -553,8 +785,11 @@ export class NodeExecutionEnv {
553
785
  return err(toFileError(error, resolved));
554
786
  }
555
787
  }
556
- async canonicalPath(path) {
788
+ async canonicalPath(path, context) {
557
789
  const resolved = resolvePath(this.cwd, path);
790
+ const aborted = abortResult(context.abortSignal, resolved);
791
+ if (aborted)
792
+ return aborted;
558
793
  try {
559
794
  return ok(await realpath(resolved));
560
795
  }
@@ -562,16 +797,19 @@ export class NodeExecutionEnv {
562
797
  return err(toFileError(error, resolved));
563
798
  }
564
799
  }
565
- async exists(path) {
566
- const result = await this.fileInfo(path);
800
+ async exists(path, context) {
801
+ const result = await this.fileInfo(path, context);
567
802
  if (result.ok)
568
803
  return ok(true);
569
804
  if (result.error.code === "not_found")
570
805
  return ok(false);
571
806
  return err(result.error);
572
807
  }
573
- async createDir(path, options) {
808
+ async createDir(path, options, context) {
574
809
  const resolved = resolvePath(this.cwd, path);
810
+ const aborted = abortResult(context.abortSignal, resolved);
811
+ if (aborted)
812
+ return aborted;
575
813
  try {
576
814
  await mkdir(resolved, { recursive: options?.recursive ?? true });
577
815
  return ok(undefined);
@@ -580,8 +818,11 @@ export class NodeExecutionEnv {
580
818
  return err(toFileError(error, resolved));
581
819
  }
582
820
  }
583
- async remove(path, options) {
821
+ async remove(path, options, context) {
584
822
  const resolved = resolvePath(this.cwd, path);
823
+ const aborted = abortResult(context.abortSignal, resolved);
824
+ if (aborted)
825
+ return aborted;
585
826
  try {
586
827
  await rm(resolved, { recursive: options?.recursive ?? false, force: options?.force ?? false });
587
828
  return ok(undefined);
@@ -590,16 +831,20 @@ export class NodeExecutionEnv {
590
831
  return err(toFileError(error, resolved));
591
832
  }
592
833
  }
593
- async createTempDir(prefix = "tmp-") {
834
+ async createTempDir(prefix, context) {
835
+ const aborted = abortResult(context.abortSignal);
836
+ if (aborted)
837
+ return aborted;
594
838
  try {
839
+ prefix ??= "tmp-";
595
840
  return ok(await mkdtemp(join(tmpdir(), prefix)));
596
841
  }
597
842
  catch (error) {
598
843
  return err(toFileError(error));
599
844
  }
600
845
  }
601
- async createTempFile(options) {
602
- const dir = await this.createTempDir("tmp-");
846
+ async createTempFile(options, context) {
847
+ const dir = await this.createTempDir("tmp-", context);
603
848
  if (!dir.ok)
604
849
  return dir;
605
850
  const filePath = join(dir.value, `${options?.prefix ?? ""}${randomUUID()}${options?.suffix ?? ""}`);
@@ -611,7 +856,7 @@ export class NodeExecutionEnv {
611
856
  return err(toFileError(error, filePath));
612
857
  }
613
858
  }
614
- async cleanup() {
859
+ async cleanup(_context) {
615
860
  for (const pid of this.activeChildPids)
616
861
  killProcessTree(pid);
617
862
  this.activeChildPids.clear();