reeval 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/README.md +52 -40
  2. package/THIRD_PARTY_NOTICES.md +218 -11
  3. package/assets/package.json +1 -1
  4. package/assets/pnpm-lock.yaml +30 -30
  5. package/dist/adapter-DWlpOtRn.js +279 -0
  6. package/dist/adapter-DWlpOtRn.js.map +1 -0
  7. package/dist/{agent-B72lZ6w5.js → agent-CURAwx_q.js} +6 -6
  8. package/dist/{agent-B72lZ6w5.js.map → agent-CURAwx_q.js.map} +1 -1
  9. package/dist/{agent-Cfj1wD4D.js → agent-CaS_2Sce.js} +92 -26
  10. package/dist/agent-CaS_2Sce.js.map +1 -0
  11. package/dist/{analysis-BTNnKh1w.js → analysis-Bxub9LMT.js} +4 -4
  12. package/dist/{analysis-BTNnKh1w.js.map → analysis-Bxub9LMT.js.map} +1 -1
  13. package/dist/{assemble-BbFVjHeS.js → assemble-B9Alds-z.js} +290 -30
  14. package/dist/assemble-B9Alds-z.js.map +1 -0
  15. package/dist/assemble-J5MukZFY.js +1 -0
  16. package/dist/{client-CwzU9CiW.js → assert-EUIoRdIt.js} +38 -112
  17. package/dist/assert-EUIoRdIt.js.map +1 -0
  18. package/dist/bridge/index.mjs +248 -55
  19. package/dist/{capture-BXhBfmsM.js → capture-CNb9SuU5.js} +204 -39
  20. package/dist/capture-CNb9SuU5.js.map +1 -0
  21. package/dist/capture-jquXZBKK.js +1 -0
  22. package/dist/{cli-BMjTKY-D.js → cli-D303Vj5N.js} +257 -146
  23. package/dist/cli-D303Vj5N.js.map +1 -0
  24. package/dist/{cli-spec-DSvKsOK4.js → cli-spec-BPZbQG2p.js} +38 -19
  25. package/dist/cli-spec-BPZbQG2p.js.map +1 -0
  26. package/dist/cli.js +4 -2
  27. package/dist/cli.js.map +1 -1
  28. package/dist/client-fcwgwOAD.js +106 -0
  29. package/dist/client-fcwgwOAD.js.map +1 -0
  30. package/dist/{command-JPGNzFsA.js → command-BLfT7vnQ.js} +19 -18
  31. package/dist/command-BLfT7vnQ.js.map +1 -0
  32. package/dist/{command-BK4kOgkH.js → command-BT9a37ZR.js} +381 -78
  33. package/dist/command-BT9a37ZR.js.map +1 -0
  34. package/dist/{command-BqJtFiPy.js → command-Bge8F7Ko.js} +384 -101
  35. package/dist/command-Bge8F7Ko.js.map +1 -0
  36. package/dist/command-BkFjijN2.js +1 -0
  37. package/dist/{command-BdstSEHu.js → command-CMJtHKRa.js} +14 -14
  38. package/dist/{command-BdstSEHu.js.map → command-CMJtHKRa.js.map} +1 -1
  39. package/dist/commands-1p-bIWhN.js +1 -0
  40. package/dist/{commands-B618jg3C.js → commands-BFx16WB8.js} +8 -8
  41. package/dist/commands-BFx16WB8.js.map +1 -0
  42. package/dist/config-DEgnUiU-.js +756 -0
  43. package/dist/config-DEgnUiU-.js.map +1 -0
  44. package/dist/{context-CvUv7DUb.js → context-C1mxXh80.js} +11 -7
  45. package/dist/context-C1mxXh80.js.map +1 -0
  46. package/dist/{db-DFbtGIYy.js → db-CdHizc4_.js} +582 -53
  47. package/dist/db-CdHizc4_.js.map +1 -0
  48. package/dist/db-Dm1cRJJP.js +2 -0
  49. package/dist/debug-D7bEv_UV.js +1 -0
  50. package/dist/{dist-CTzThfu_.js → dist-B8hJImYt.js} +17 -4
  51. package/dist/dist-B8hJImYt.js.map +1 -0
  52. package/dist/{docker-2qns7hJ2.js → docker-7b_2SaH7.js} +35 -22
  53. package/dist/docker-7b_2SaH7.js.map +1 -0
  54. package/dist/{docker-IFRW8K5f.js → docker-sZrNrr82.js} +3 -3
  55. package/dist/docker-sZrNrr82.js.map +1 -0
  56. package/dist/docker-yauK-9X8.js +1 -0
  57. package/dist/{doctor-B6oYTPoR.js → doctor-BYNok4UO.js} +263 -84
  58. package/dist/doctor-BYNok4UO.js.map +1 -0
  59. package/dist/{duration-JsJrIWXq.js → duration-CEOQww97.js} +2 -2
  60. package/dist/{duration-JsJrIWXq.js.map → duration-CEOQww97.js.map} +1 -1
  61. package/dist/{egress-IUKdeayc.js → egress-C4PZTSSe.js} +147 -14
  62. package/dist/egress-C4PZTSSe.js.map +1 -0
  63. package/dist/environment-DNjRk0nU.js +1133 -0
  64. package/dist/environment-DNjRk0nU.js.map +1 -0
  65. package/dist/{errors-yDAEwmZo.js → errors-B6BSMs03.js} +2 -2
  66. package/dist/errors-B6BSMs03.js.map +1 -0
  67. package/dist/{errors-C9w_ud7g.js → errors-r025B0Zb.js} +4 -4
  68. package/dist/errors-r025B0Zb.js.map +1 -0
  69. package/dist/evaluate-C1UVL21l.d.ts +92 -0
  70. package/dist/evaluate-D4zeRGBF.js +2351 -0
  71. package/dist/evaluate-D4zeRGBF.js.map +1 -0
  72. package/dist/family-D2b7WD10.js +67 -0
  73. package/dist/family-D2b7WD10.js.map +1 -0
  74. package/dist/files-BAt0i00X.js +1 -0
  75. package/dist/{files-CMSUXAEg.js → files-BXUdY8tr.js} +10 -9
  76. package/dist/{files-CMSUXAEg.js.map → files-BXUdY8tr.js.map} +1 -1
  77. package/dist/files-BhyltlDB.js +1 -0
  78. package/dist/files-Bk1mC3AN.js +43 -0
  79. package/dist/files-Bk1mC3AN.js.map +1 -0
  80. package/dist/{files-B6aVVGrk.js → files-DQmHE7pb.js} +5 -5
  81. package/dist/{files-B6aVVGrk.js.map → files-DQmHE7pb.js.map} +1 -1
  82. package/dist/files-ZZPqfAo6.js +1 -0
  83. package/dist/{git-EmdFJ4DY.js → git-DfG-YJ1u.js} +2 -2
  84. package/dist/{git-EmdFJ4DY.js.map → git-DfG-YJ1u.js.map} +1 -1
  85. package/dist/harness-B8QC9u0O.js +323 -0
  86. package/dist/harness-B8QC9u0O.js.map +1 -0
  87. package/dist/harness.d.ts +19 -31
  88. package/dist/harness.js +1 -2
  89. package/dist/{header-_F0EWob3.js → header-hK-Z_Po9.js} +10 -3
  90. package/dist/{header-_F0EWob3.js.map → header-hK-Z_Po9.js.map} +1 -1
  91. package/dist/{images-CscddrJU.js → images-0On0cztu.js} +114 -45
  92. package/dist/images-0On0cztu.js.map +1 -0
  93. package/dist/index.d.ts +10 -26
  94. package/dist/index.js +6 -2108
  95. package/dist/{init-NQfIvi-0.js → init-B77Rpcqc.js} +26 -8
  96. package/dist/init-B77Rpcqc.js.map +1 -0
  97. package/dist/init-BrOWin3W.js +1 -0
  98. package/dist/{invocations-nPvrlZPj.js → invocations-DbGfBAA_.js} +4 -4
  99. package/dist/{invocations-nPvrlZPj.js.map → invocations-DbGfBAA_.js.map} +1 -1
  100. package/dist/{judge-CeYPN8P_.js → judge-DW_GDOmB.js} +11 -19
  101. package/dist/{judge-CeYPN8P_.js.map → judge-DW_GDOmB.js.map} +1 -1
  102. package/dist/judge.d.ts +2 -2
  103. package/dist/judge.js +1 -1
  104. package/dist/{live-S0qODb6o.js → live-jlfszAbb.js} +9 -20
  105. package/dist/live-jlfszAbb.js.map +1 -0
  106. package/dist/matchers-Ddmc2z7H.js +118 -0
  107. package/dist/matchers-Ddmc2z7H.js.map +1 -0
  108. package/dist/{model-DEQo3FkZ.js → model-DaVCY3rb.js} +2 -2
  109. package/dist/{model-DEQo3FkZ.js.map → model-DaVCY3rb.js.map} +1 -1
  110. package/dist/model-NM3ID0uR.js +1 -0
  111. package/dist/{model-Cl507trk.js → model-h_cDtcRr.js} +19 -18
  112. package/dist/model-h_cDtcRr.js.map +1 -0
  113. package/dist/model-nwWJvaUR.js +1 -0
  114. package/dist/{model-BndnmcLm.js → model-oqcDplJG.js} +271 -34
  115. package/dist/model-oqcDplJG.js.map +1 -0
  116. package/dist/{node-Co7EXge0.js → node-B3ydHo6t.js} +10 -47
  117. package/dist/node-B3ydHo6t.js.map +1 -0
  118. package/dist/object-CLf2-tNq.js +9 -0
  119. package/dist/object-CLf2-tNq.js.map +1 -0
  120. package/dist/{opencode-providers-ByD85Q0l.js → opencode-providers-J9colP0-.js} +96 -21
  121. package/dist/opencode-providers-J9colP0-.js.map +1 -0
  122. package/dist/options-Bh2W63dK.js +1119 -0
  123. package/dist/options-Bh2W63dK.js.map +1 -0
  124. package/dist/{pairs-DDsjgm5F.js → pairs-CnInRu-G.js} +76 -2
  125. package/dist/{pairs-DDsjgm5F.js.map → pairs-CnInRu-G.js.map} +1 -1
  126. package/dist/{patch-CGCVipPu.js → patch-Zac5aIRM.js} +6 -6
  127. package/dist/{patch-CGCVipPu.js.map → patch-Zac5aIRM.js.map} +1 -1
  128. package/dist/{plan-PPc4-6xd.js → plan-C9Cy27Ay.js} +75 -32
  129. package/dist/plan-C9Cy27Ay.js.map +1 -0
  130. package/dist/preflight-CPWpQeBI.js +1 -0
  131. package/dist/{preflight-CddycK92.js → preflight-D7iFPKeK.js} +8 -7
  132. package/dist/preflight-D7iFPKeK.js.map +1 -0
  133. package/dist/prepare-BGjePFQl.js +2 -0
  134. package/dist/{prepare-CsP-057p.js → prepare-doGxaAGR.js} +38 -30
  135. package/dist/prepare-doGxaAGR.js.map +1 -0
  136. package/dist/process-CSVO_jsc.js +119 -0
  137. package/dist/process-CSVO_jsc.js.map +1 -0
  138. package/dist/{provenance-CsX6PHDR.js → provenance-DmE9uPVt.js} +4 -4
  139. package/dist/{provenance-CsX6PHDR.js.map → provenance-DmE9uPVt.js.map} +1 -1
  140. package/dist/provider-DehR4CMN.js +1 -0
  141. package/dist/providers-gDMko8fl.js +1 -0
  142. package/dist/providers-tAOD1NQN.js +165 -0
  143. package/dist/providers-tAOD1NQN.js.map +1 -0
  144. package/dist/{query-BUcwCYsI.js → query-Bes9Kh6Y.js} +3 -3
  145. package/dist/{query-BUcwCYsI.js.map → query-Bes9Kh6Y.js.map} +1 -1
  146. package/dist/query-C_G_svLU.js +1 -0
  147. package/dist/questions-DjAwMxZ3.js +524 -0
  148. package/dist/questions-DjAwMxZ3.js.map +1 -0
  149. package/dist/{record-BRP9vZrj.js → record-BKmMvZ6O.js} +9 -1
  150. package/dist/{record-BRP9vZrj.js.map → record-BKmMvZ6O.js.map} +1 -1
  151. package/dist/remote-HDRt16ew.js +378 -0
  152. package/dist/remote-HDRt16ew.js.map +1 -0
  153. package/dist/{results-BcSHWbgB.js → results-DuauQI3Z.js} +4 -4
  154. package/dist/{results-BcSHWbgB.js.map → results-DuauQI3Z.js.map} +1 -1
  155. package/dist/{resume-DZ9AmfPv.js → resume-BRfa8E_s.js} +10 -10
  156. package/dist/{resume-DZ9AmfPv.js.map → resume-BRfa8E_s.js.map} +1 -1
  157. package/dist/{root-CvdRlRZX.js → root-DICDHCtp.js} +4 -4
  158. package/dist/{root-CvdRlRZX.js.map → root-DICDHCtp.js.map} +1 -1
  159. package/dist/{runtime-Dfb2r-cS.js → runtime-PX_oXiCS.js} +105 -11
  160. package/dist/runtime-PX_oXiCS.js.map +1 -0
  161. package/dist/sandbox-D3A8oUb7.js +70 -0
  162. package/dist/sandbox-D3A8oUb7.js.map +1 -0
  163. package/dist/sandbox.d.ts +22 -8
  164. package/dist/sandbox.js +1 -2
  165. package/dist/server-C7sg1ndo.js +1 -0
  166. package/dist/{server-Da60oe4b.js → server-XDleKaF_.js} +11 -11
  167. package/dist/server-XDleKaF_.js.map +1 -0
  168. package/dist/shared-DYpIb1BI.js +166 -0
  169. package/dist/shared-DYpIb1BI.js.map +1 -0
  170. package/dist/{source-BVOnL3sn.js → source-C8xumIWj.js} +2 -2
  171. package/dist/{source-BVOnL3sn.js.map → source-C8xumIWj.js.map} +1 -1
  172. package/dist/source-fGd0SaKP.js +1 -0
  173. package/dist/{src-TdJuDYqB.js → src-B7treWa8.js} +1597 -292
  174. package/dist/src-B7treWa8.js.map +1 -0
  175. package/dist/{src-C1E9HDWO.js → src-C7_1SqDP.js} +3 -3
  176. package/dist/{src-C1E9HDWO.js.map → src-C7_1SqDP.js.map} +1 -1
  177. package/dist/{src-DDNXsD9H.js → src-CF17Ug08.js} +5 -4
  178. package/dist/src-CF17Ug08.js.map +1 -0
  179. package/dist/{src-D_cXqmnI.js → src-CFp86GtV.js} +60 -60
  180. package/dist/src-CFp86GtV.js.map +1 -0
  181. package/dist/src-C_lPtowT.js +2 -0
  182. package/dist/src-DIL0jST0.js +368 -0
  183. package/dist/src-DIL0jST0.js.map +1 -0
  184. package/dist/src-DNnG4e4R.js +2 -0
  185. package/dist/src-DTbrY1hi.js +2 -0
  186. package/dist/src-DdyJEh2v.js +2 -0
  187. package/dist/src-Dj9PAroc.js +2 -0
  188. package/dist/src-Du8H85Qq.js +2 -0
  189. package/dist/src-DvCg0NBs.js +324 -0
  190. package/dist/src-DvCg0NBs.js.map +1 -0
  191. package/dist/{src-CxTC5kNI.js → src-DvK0EIZx.js} +8 -10
  192. package/dist/{src-CxTC5kNI.js.map → src-DvK0EIZx.js.map} +1 -1
  193. package/dist/{src-DVy58-zZ.js → src-FGXhkEkH.js} +5 -5
  194. package/dist/{src-DVy58-zZ.js.map → src-FGXhkEkH.js.map} +1 -1
  195. package/dist/src-jzagbuqH.js +2 -0
  196. package/dist/src-ofUaYbuY.js +3 -0
  197. package/dist/src-pJZOrYR9.js +1 -0
  198. package/dist/{src-D95O-Smv.js → src-u8_ixn_F.js} +15 -11
  199. package/dist/src-u8_ixn_F.js.map +1 -0
  200. package/dist/{state-B72h_jEw.js → state-C__9swoG.js} +36 -24
  201. package/dist/state-C__9swoG.js.map +1 -0
  202. package/dist/state-CeR6oz0k.js +66 -0
  203. package/dist/state-CeR6oz0k.js.map +1 -0
  204. package/dist/state-CgjQo29K.js +1 -0
  205. package/dist/studio-app/assets/index-CwQN3f_h.css +2 -0
  206. package/dist/studio-app/assets/{index-Bgr-efZm.js → index-DrQc2Yxd.js} +12 -12
  207. package/dist/studio-app/index.html +2 -2
  208. package/dist/{summary-k3mhWWXv.js → summary-BLAVLySU.js} +202 -17
  209. package/dist/summary-BLAVLySU.js.map +1 -0
  210. package/dist/{summary-CJdxaRdM.js → summary-DgyjUh_l.js} +7 -7
  211. package/dist/{summary-CJdxaRdM.js.map → summary-DgyjUh_l.js.map} +1 -1
  212. package/dist/testing.d.ts +3 -2
  213. package/dist/testing.js +3 -2
  214. package/dist/{tool-target-BU1JnSE9.js → tool-target-D2mcYlSQ.js} +14 -7
  215. package/dist/tool-target-D2mcYlSQ.js.map +1 -0
  216. package/dist/{tools-D0gF2QoV.js → tools-GCyNYSc1.js} +7 -7
  217. package/dist/tools-GCyNYSc1.js.map +1 -0
  218. package/dist/transcript-BNNANU8A.js +64 -0
  219. package/dist/transcript-BNNANU8A.js.map +1 -0
  220. package/dist/types-C5vI3g1C.js.map +1 -1
  221. package/dist/{types-_LOFdPUf.d.ts → types-g17bRAzt.d.ts} +578 -49
  222. package/dist/{usage-DDF_6tkV.js → usage-CleNKkly.js} +4 -2
  223. package/dist/{usage-DDF_6tkV.js.map → usage-CleNKkly.js.map} +1 -1
  224. package/dist/view/index.d.ts +83 -17
  225. package/dist/view/index.js +7 -6
  226. package/dist/views-BW6oCDUQ.js +2 -0
  227. package/dist/{views-DZ1YDqey.js → views-BmQF4UCI.js} +13 -8
  228. package/dist/views-BmQF4UCI.js.map +1 -0
  229. package/dist/{worker-entry-DXeyWY-m.js → worker-entry-yOchGYYv.js} +16 -225
  230. package/dist/worker-entry-yOchGYYv.js.map +1 -0
  231. package/dist/{workspace-DpXdrslo.js → workspace-CgyHEM0l.js} +7 -7
  232. package/dist/{workspace-DpXdrslo.js.map → workspace-CgyHEM0l.js.map} +1 -1
  233. package/dist/workspace-D8sSgpiy.js +1 -0
  234. package/docker/Dockerfile +7 -5
  235. package/package.json +12 -12
  236. package/dist/agent-Cfj1wD4D.js.map +0 -1
  237. package/dist/assemble-BbFVjHeS.js.map +0 -1
  238. package/dist/assemble-CXiTVyHD.js +0 -2
  239. package/dist/capture-BXhBfmsM.js.map +0 -1
  240. package/dist/capture-N7r3yeak.js +0 -2
  241. package/dist/cli-BMjTKY-D.js.map +0 -1
  242. package/dist/cli-spec-DSvKsOK4.js.map +0 -1
  243. package/dist/client-CwzU9CiW.js.map +0 -1
  244. package/dist/command-BK4kOgkH.js.map +0 -1
  245. package/dist/command-BqJtFiPy.js.map +0 -1
  246. package/dist/command-CTVGuH8y.js +0 -2
  247. package/dist/command-JPGNzFsA.js.map +0 -1
  248. package/dist/commands-B618jg3C.js.map +0 -1
  249. package/dist/commands-Duo2ur3r.js +0 -2
  250. package/dist/config-B-E0xRkf.js +0 -447
  251. package/dist/config-B-E0xRkf.js.map +0 -1
  252. package/dist/context-CvUv7DUb.js.map +0 -1
  253. package/dist/db-CnoUy-FZ.js +0 -3
  254. package/dist/db-DFbtGIYy.js.map +0 -1
  255. package/dist/debug-SEmW4w8f.js +0 -2
  256. package/dist/dist-CTzThfu_.js.map +0 -1
  257. package/dist/docker-2qns7hJ2.js.map +0 -1
  258. package/dist/docker-D6t23fZl.js +0 -2
  259. package/dist/docker-IFRW8K5f.js.map +0 -1
  260. package/dist/doctor-B6oYTPoR.js.map +0 -1
  261. package/dist/egress-IUKdeayc.js.map +0 -1
  262. package/dist/environment-DiCljXMD.js +0 -657
  263. package/dist/environment-DiCljXMD.js.map +0 -1
  264. package/dist/errors-C9w_ud7g.js.map +0 -1
  265. package/dist/errors-yDAEwmZo.js.map +0 -1
  266. package/dist/fake-instructions-CUI33I_F.js +0 -32
  267. package/dist/fake-instructions-CUI33I_F.js.map +0 -1
  268. package/dist/files-BM78_nnF.js +0 -2
  269. package/dist/files-BpYgF2z0.js +0 -2
  270. package/dist/files-YCCVaTQC.js +0 -2
  271. package/dist/harness-iqWeJQMM.js +0 -154
  272. package/dist/harness-iqWeJQMM.js.map +0 -1
  273. package/dist/images-CscddrJU.js.map +0 -1
  274. package/dist/index.js.map +0 -1
  275. package/dist/init-DBHyi92L.js +0 -2
  276. package/dist/init-NQfIvi-0.js.map +0 -1
  277. package/dist/jiti-BcJHCtrb.js +0 -46
  278. package/dist/jiti-BcJHCtrb.js.map +0 -1
  279. package/dist/live-S0qODb6o.js.map +0 -1
  280. package/dist/model-BbLGRtOs.js +0 -2
  281. package/dist/model-BndnmcLm.js.map +0 -1
  282. package/dist/model-Cl507trk.js.map +0 -1
  283. package/dist/model-DMOraCcm.js +0 -2
  284. package/dist/node-Co7EXge0.js.map +0 -1
  285. package/dist/opencode-providers-ByD85Q0l.js.map +0 -1
  286. package/dist/options-DPUlm4FI.js +0 -735
  287. package/dist/options-DPUlm4FI.js.map +0 -1
  288. package/dist/plan-PPc4-6xd.js.map +0 -1
  289. package/dist/preflight-CddycK92.js.map +0 -1
  290. package/dist/preflight-Zumy0adT.js +0 -2
  291. package/dist/prepare-CKdMoC7e.js +0 -3
  292. package/dist/prepare-CsP-057p.js.map +0 -1
  293. package/dist/provider-BDbNOQhQ.js +0 -2
  294. package/dist/providers-DkwiLKDS.js +0 -107
  295. package/dist/providers-DkwiLKDS.js.map +0 -1
  296. package/dist/providers-yXZZcPfx.js +0 -2
  297. package/dist/query-noGbekGF.js +0 -2
  298. package/dist/questions-BEPj98fZ.js +0 -234
  299. package/dist/questions-BEPj98fZ.js.map +0 -1
  300. package/dist/runtime-Dfb2r-cS.js.map +0 -1
  301. package/dist/sandbox--ZXuscAZ.js +0 -134
  302. package/dist/sandbox--ZXuscAZ.js.map +0 -1
  303. package/dist/server-Da60oe4b.js.map +0 -1
  304. package/dist/server-DiGR4JxK.js +0 -2
  305. package/dist/source-Dqu0jKwx.js +0 -2
  306. package/dist/src-BHNiP-5A.js +0 -4
  307. package/dist/src-BT4dB5CO.js +0 -2
  308. package/dist/src-BT5pwco0.js +0 -3
  309. package/dist/src-BrMbt1B2.js +0 -3
  310. package/dist/src-D13vpMh0.js +0 -3
  311. package/dist/src-D95O-Smv.js.map +0 -1
  312. package/dist/src-DDNXsD9H.js.map +0 -1
  313. package/dist/src-D_cXqmnI.js.map +0 -1
  314. package/dist/src-DdRlaiRc.js +0 -3
  315. package/dist/src-TdJuDYqB.js.map +0 -1
  316. package/dist/src-xczuQbE6.js +0 -3
  317. package/dist/state-B72h_jEw.js.map +0 -1
  318. package/dist/state-Bf_Vq_pV.js +0 -2
  319. package/dist/studio-app/assets/index-CUx6GoL5.css +0 -2
  320. package/dist/summary-k3mhWWXv.js.map +0 -1
  321. package/dist/tool-target-BU1JnSE9.js.map +0 -1
  322. package/dist/tools-D0gF2QoV.js.map +0 -1
  323. package/dist/views-DZ1YDqey.js.map +0 -1
  324. package/dist/views-Ds0GXWtX.js +0 -3
  325. package/dist/worker-entry-DXeyWY-m.js.map +0 -1
  326. package/dist/workspace-DzNL-3iO.js +0 -2
@@ -1,11 +1,13 @@
1
- import { u as ownFileURL } from "./root-CvdRlRZX.js";
2
- import { existsSync, lstatSync, readFileSync, readdirSync, readlinkSync } from "node:fs";
3
- import { basename, dirname, join, posix, relative, win32 } from "node:path";
1
+ import { u as ownFileURL } from "./root-DICDHCtp.js";
2
+ import { n as shellQuote, t as run } from "./process-CSVO_jsc.js";
3
+ import { existsSync, lstatSync, readFileSync, readdirSync, readlinkSync, renameSync, writeFileSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { basename, dirname, join, posix, relative } from "node:path";
4
6
  import net, { BlockList, isIP } from "node:net";
5
- import { fileURLToPath } from "node:url";
6
7
  import { createHash, generateKeyPairSync, randomBytes, randomInt, sign } from "node:crypto";
8
+ import { fileURLToPath } from "node:url";
9
+ import { execFileSync, spawn } from "node:child_process";
7
10
  import { createHarnessSandboxTemplate } from "@ai-sdk/harness/agent";
8
- import { spawn } from "node:child_process";
9
11
  import { isUtf8 } from "node:buffer";
10
12
  import { Duplex, Readable, Transform } from "node:stream";
11
13
  import http from "node:http";
@@ -13,6 +15,1073 @@ import http2 from "node:http2";
13
15
  import https from "node:https";
14
16
  import tls from "node:tls";
15
17
  import { lookup } from "node:dns/promises";
18
+ //#region ../sandbox-docker/src/seccomp-profile.ts
19
+ const DOCKER_SECCOMP_PROFILE = {
20
+ defaultAction: "SCMP_ACT_ERRNO",
21
+ defaultErrnoRet: 1,
22
+ archMap: [
23
+ {
24
+ architecture: "SCMP_ARCH_X86_64",
25
+ subArchitectures: ["SCMP_ARCH_X86", "SCMP_ARCH_X32"]
26
+ },
27
+ {
28
+ architecture: "SCMP_ARCH_AARCH64",
29
+ subArchitectures: ["SCMP_ARCH_ARM"]
30
+ },
31
+ {
32
+ architecture: "SCMP_ARCH_MIPS64",
33
+ subArchitectures: ["SCMP_ARCH_MIPS", "SCMP_ARCH_MIPS64N32"]
34
+ },
35
+ {
36
+ architecture: "SCMP_ARCH_MIPS64N32",
37
+ subArchitectures: ["SCMP_ARCH_MIPS", "SCMP_ARCH_MIPS64"]
38
+ },
39
+ {
40
+ architecture: "SCMP_ARCH_MIPSEL64",
41
+ subArchitectures: ["SCMP_ARCH_MIPSEL", "SCMP_ARCH_MIPSEL64N32"]
42
+ },
43
+ {
44
+ architecture: "SCMP_ARCH_MIPSEL64N32",
45
+ subArchitectures: ["SCMP_ARCH_MIPSEL", "SCMP_ARCH_MIPSEL64"]
46
+ },
47
+ {
48
+ architecture: "SCMP_ARCH_S390X",
49
+ subArchitectures: ["SCMP_ARCH_S390"]
50
+ },
51
+ {
52
+ architecture: "SCMP_ARCH_RISCV64",
53
+ subArchitectures: null
54
+ },
55
+ {
56
+ architecture: "SCMP_ARCH_LOONGARCH64",
57
+ subArchitectures: null
58
+ }
59
+ ],
60
+ syscalls: [
61
+ {
62
+ names: [
63
+ "accept",
64
+ "accept4",
65
+ "access",
66
+ "adjtimex",
67
+ "alarm",
68
+ "bind",
69
+ "brk",
70
+ "cachestat",
71
+ "capget",
72
+ "capset",
73
+ "chdir",
74
+ "chmod",
75
+ "chown",
76
+ "chown32",
77
+ "clock_adjtime",
78
+ "clock_adjtime64",
79
+ "clock_getres",
80
+ "clock_getres_time64",
81
+ "clock_gettime",
82
+ "clock_gettime64",
83
+ "clock_nanosleep",
84
+ "clock_nanosleep_time64",
85
+ "close",
86
+ "close_range",
87
+ "connect",
88
+ "copy_file_range",
89
+ "creat",
90
+ "dup",
91
+ "dup2",
92
+ "dup3",
93
+ "epoll_create",
94
+ "epoll_create1",
95
+ "epoll_ctl",
96
+ "epoll_ctl_old",
97
+ "epoll_pwait",
98
+ "epoll_pwait2",
99
+ "epoll_wait",
100
+ "epoll_wait_old",
101
+ "eventfd",
102
+ "eventfd2",
103
+ "execve",
104
+ "execveat",
105
+ "exit",
106
+ "exit_group",
107
+ "faccessat",
108
+ "faccessat2",
109
+ "fadvise64",
110
+ "fadvise64_64",
111
+ "fallocate",
112
+ "fanotify_mark",
113
+ "fchdir",
114
+ "fchmod",
115
+ "fchmodat",
116
+ "fchmodat2",
117
+ "fchown",
118
+ "fchown32",
119
+ "fchownat",
120
+ "fcntl",
121
+ "fcntl64",
122
+ "fdatasync",
123
+ "fgetxattr",
124
+ "flistxattr",
125
+ "flock",
126
+ "fork",
127
+ "fremovexattr",
128
+ "fsetxattr",
129
+ "fstat",
130
+ "fstat64",
131
+ "fstatat64",
132
+ "fstatfs",
133
+ "fstatfs64",
134
+ "fsync",
135
+ "ftruncate",
136
+ "ftruncate64",
137
+ "futex",
138
+ "futex_requeue",
139
+ "futex_time64",
140
+ "futex_wait",
141
+ "futex_waitv",
142
+ "futex_wake",
143
+ "futimesat",
144
+ "getcpu",
145
+ "getcwd",
146
+ "getdents",
147
+ "getdents64",
148
+ "getegid",
149
+ "getegid32",
150
+ "geteuid",
151
+ "geteuid32",
152
+ "getgid",
153
+ "getgid32",
154
+ "getgroups",
155
+ "getgroups32",
156
+ "getitimer",
157
+ "getpeername",
158
+ "getpgid",
159
+ "getpgrp",
160
+ "getpid",
161
+ "getppid",
162
+ "getpriority",
163
+ "getrandom",
164
+ "getresgid",
165
+ "getresgid32",
166
+ "getresuid",
167
+ "getresuid32",
168
+ "getrlimit",
169
+ "get_robust_list",
170
+ "getrusage",
171
+ "getsid",
172
+ "getsockname",
173
+ "getsockopt",
174
+ "get_thread_area",
175
+ "gettid",
176
+ "gettimeofday",
177
+ "getuid",
178
+ "getuid32",
179
+ "getxattr",
180
+ "getxattrat",
181
+ "inotify_add_watch",
182
+ "inotify_init",
183
+ "inotify_init1",
184
+ "inotify_rm_watch",
185
+ "io_cancel",
186
+ "ioctl",
187
+ "io_destroy",
188
+ "io_getevents",
189
+ "io_pgetevents",
190
+ "io_pgetevents_time64",
191
+ "ioprio_get",
192
+ "ioprio_set",
193
+ "io_setup",
194
+ "io_submit",
195
+ "ipc",
196
+ "kill",
197
+ "landlock_add_rule",
198
+ "landlock_create_ruleset",
199
+ "landlock_restrict_self",
200
+ "lchown",
201
+ "lchown32",
202
+ "lgetxattr",
203
+ "link",
204
+ "linkat",
205
+ "listen",
206
+ "listmount",
207
+ "listxattr",
208
+ "listxattrat",
209
+ "llistxattr",
210
+ "_llseek",
211
+ "lremovexattr",
212
+ "lseek",
213
+ "lsetxattr",
214
+ "lstat",
215
+ "lstat64",
216
+ "madvise",
217
+ "map_shadow_stack",
218
+ "membarrier",
219
+ "memfd_create",
220
+ "memfd_secret",
221
+ "mincore",
222
+ "mkdir",
223
+ "mkdirat",
224
+ "mknod",
225
+ "mknodat",
226
+ "mlock",
227
+ "mlock2",
228
+ "mlockall",
229
+ "mmap",
230
+ "mmap2",
231
+ "mprotect",
232
+ "mq_getsetattr",
233
+ "mq_notify",
234
+ "mq_open",
235
+ "mq_timedreceive",
236
+ "mq_timedreceive_time64",
237
+ "mq_timedsend",
238
+ "mq_timedsend_time64",
239
+ "mq_unlink",
240
+ "mremap",
241
+ "mseal",
242
+ "msgctl",
243
+ "msgget",
244
+ "msgrcv",
245
+ "msgsnd",
246
+ "msync",
247
+ "munlock",
248
+ "munlockall",
249
+ "munmap",
250
+ "name_to_handle_at",
251
+ "nanosleep",
252
+ "newfstatat",
253
+ "_newselect",
254
+ "open",
255
+ "openat",
256
+ "openat2",
257
+ "pause",
258
+ "pidfd_open",
259
+ "pidfd_send_signal",
260
+ "pipe",
261
+ "pipe2",
262
+ "pkey_alloc",
263
+ "pkey_free",
264
+ "pkey_mprotect",
265
+ "poll",
266
+ "ppoll",
267
+ "ppoll_time64",
268
+ "prctl",
269
+ "pread64",
270
+ "preadv",
271
+ "preadv2",
272
+ "prlimit64",
273
+ "process_mrelease",
274
+ "pselect6",
275
+ "pselect6_time64",
276
+ "pwrite64",
277
+ "pwritev",
278
+ "pwritev2",
279
+ "read",
280
+ "readahead",
281
+ "readlink",
282
+ "readlinkat",
283
+ "readv",
284
+ "recv",
285
+ "recvfrom",
286
+ "recvmmsg",
287
+ "recvmmsg_time64",
288
+ "recvmsg",
289
+ "remap_file_pages",
290
+ "removexattr",
291
+ "removexattrat",
292
+ "rename",
293
+ "renameat",
294
+ "renameat2",
295
+ "restart_syscall",
296
+ "riscv_hwprobe",
297
+ "rmdir",
298
+ "rseq",
299
+ "rt_sigaction",
300
+ "rt_sigpending",
301
+ "rt_sigprocmask",
302
+ "rt_sigqueueinfo",
303
+ "rt_sigreturn",
304
+ "rt_sigsuspend",
305
+ "rt_sigtimedwait",
306
+ "rt_sigtimedwait_time64",
307
+ "rt_tgsigqueueinfo",
308
+ "sched_getaffinity",
309
+ "sched_getattr",
310
+ "sched_getparam",
311
+ "sched_get_priority_max",
312
+ "sched_get_priority_min",
313
+ "sched_getscheduler",
314
+ "sched_rr_get_interval",
315
+ "sched_rr_get_interval_time64",
316
+ "sched_setaffinity",
317
+ "sched_setattr",
318
+ "sched_setparam",
319
+ "sched_setscheduler",
320
+ "sched_yield",
321
+ "seccomp",
322
+ "select",
323
+ "semctl",
324
+ "semget",
325
+ "semop",
326
+ "semtimedop",
327
+ "semtimedop_time64",
328
+ "send",
329
+ "sendfile",
330
+ "sendfile64",
331
+ "sendmmsg",
332
+ "sendmsg",
333
+ "sendto",
334
+ "setfsgid",
335
+ "setfsgid32",
336
+ "setfsuid",
337
+ "setfsuid32",
338
+ "setgid",
339
+ "setgid32",
340
+ "setgroups",
341
+ "setgroups32",
342
+ "setitimer",
343
+ "setpgid",
344
+ "setpriority",
345
+ "setregid",
346
+ "setregid32",
347
+ "setresgid",
348
+ "setresgid32",
349
+ "setresuid",
350
+ "setresuid32",
351
+ "setreuid",
352
+ "setreuid32",
353
+ "setrlimit",
354
+ "set_robust_list",
355
+ "setsid",
356
+ "setsockopt",
357
+ "set_thread_area",
358
+ "set_tid_address",
359
+ "setuid",
360
+ "setuid32",
361
+ "setxattr",
362
+ "setxattrat",
363
+ "shmat",
364
+ "shmctl",
365
+ "shmdt",
366
+ "shmget",
367
+ "shutdown",
368
+ "sigaltstack",
369
+ "signalfd",
370
+ "signalfd4",
371
+ "sigprocmask",
372
+ "sigreturn",
373
+ "socketcall",
374
+ "socketpair",
375
+ "splice",
376
+ "stat",
377
+ "stat64",
378
+ "statfs",
379
+ "statfs64",
380
+ "statmount",
381
+ "statx",
382
+ "symlink",
383
+ "symlinkat",
384
+ "sync",
385
+ "sync_file_range",
386
+ "syncfs",
387
+ "sysinfo",
388
+ "tee",
389
+ "tgkill",
390
+ "time",
391
+ "timer_create",
392
+ "timer_delete",
393
+ "timer_getoverrun",
394
+ "timer_gettime",
395
+ "timer_gettime64",
396
+ "timer_settime",
397
+ "timer_settime64",
398
+ "timerfd_create",
399
+ "timerfd_gettime",
400
+ "timerfd_gettime64",
401
+ "timerfd_settime",
402
+ "timerfd_settime64",
403
+ "times",
404
+ "tkill",
405
+ "truncate",
406
+ "truncate64",
407
+ "ugetrlimit",
408
+ "umask",
409
+ "uname",
410
+ "unlink",
411
+ "unlinkat",
412
+ "uretprobe",
413
+ "utime",
414
+ "utimensat",
415
+ "utimensat_time64",
416
+ "utimes",
417
+ "vfork",
418
+ "vmsplice",
419
+ "wait4",
420
+ "waitid",
421
+ "waitpid",
422
+ "write",
423
+ "writev"
424
+ ],
425
+ action: "SCMP_ACT_ALLOW"
426
+ },
427
+ {
428
+ names: [
429
+ "process_vm_readv",
430
+ "process_vm_writev",
431
+ "ptrace"
432
+ ],
433
+ action: "SCMP_ACT_ALLOW",
434
+ includes: { minKernel: "4.8" }
435
+ },
436
+ {
437
+ names: ["socket"],
438
+ action: "SCMP_ACT_ALLOW",
439
+ args: [{
440
+ index: 0,
441
+ value: 3,
442
+ op: "SCMP_CMP_LT"
443
+ }]
444
+ },
445
+ {
446
+ names: ["socket"],
447
+ action: "SCMP_ACT_ALLOW",
448
+ args: [{
449
+ index: 0,
450
+ value: 7,
451
+ op: "SCMP_CMP_EQ"
452
+ }]
453
+ },
454
+ {
455
+ names: ["socket"],
456
+ action: "SCMP_ACT_ALLOW",
457
+ args: [{
458
+ index: 0,
459
+ value: 8,
460
+ op: "SCMP_CMP_EQ"
461
+ }]
462
+ },
463
+ {
464
+ names: ["socket"],
465
+ action: "SCMP_ACT_ALLOW",
466
+ args: [{
467
+ index: 0,
468
+ value: 9,
469
+ op: "SCMP_CMP_EQ"
470
+ }]
471
+ },
472
+ {
473
+ names: ["socket"],
474
+ action: "SCMP_ACT_ALLOW",
475
+ args: [{
476
+ index: 0,
477
+ value: 10,
478
+ op: "SCMP_CMP_EQ"
479
+ }]
480
+ },
481
+ {
482
+ names: ["socket"],
483
+ action: "SCMP_ACT_ALLOW",
484
+ args: [{
485
+ index: 0,
486
+ value: 13,
487
+ op: "SCMP_CMP_EQ"
488
+ }]
489
+ },
490
+ {
491
+ names: ["socket"],
492
+ action: "SCMP_ACT_ALLOW",
493
+ args: [{
494
+ index: 0,
495
+ value: 14,
496
+ op: "SCMP_CMP_EQ"
497
+ }]
498
+ },
499
+ {
500
+ names: ["socket"],
501
+ action: "SCMP_ACT_ALLOW",
502
+ args: [{
503
+ index: 0,
504
+ value: 15,
505
+ op: "SCMP_CMP_EQ"
506
+ }]
507
+ },
508
+ {
509
+ names: ["socket"],
510
+ action: "SCMP_ACT_ALLOW",
511
+ args: [{
512
+ index: 0,
513
+ value: 16,
514
+ op: "SCMP_CMP_EQ"
515
+ }]
516
+ },
517
+ {
518
+ names: ["socket"],
519
+ action: "SCMP_ACT_ALLOW",
520
+ args: [{
521
+ index: 0,
522
+ value: 17,
523
+ op: "SCMP_CMP_EQ"
524
+ }]
525
+ },
526
+ {
527
+ names: ["socket"],
528
+ action: "SCMP_ACT_ALLOW",
529
+ args: [{
530
+ index: 0,
531
+ value: 18,
532
+ op: "SCMP_CMP_EQ"
533
+ }]
534
+ },
535
+ {
536
+ names: ["socket"],
537
+ action: "SCMP_ACT_ALLOW",
538
+ args: [{
539
+ index: 0,
540
+ value: 21,
541
+ op: "SCMP_CMP_EQ"
542
+ }]
543
+ },
544
+ {
545
+ names: ["socket"],
546
+ action: "SCMP_ACT_ALLOW",
547
+ args: [{
548
+ index: 0,
549
+ value: 22,
550
+ op: "SCMP_CMP_EQ"
551
+ }]
552
+ },
553
+ {
554
+ names: ["socket"],
555
+ action: "SCMP_ACT_ALLOW",
556
+ args: [{
557
+ index: 0,
558
+ value: 24,
559
+ op: "SCMP_CMP_EQ"
560
+ }]
561
+ },
562
+ {
563
+ names: ["socket"],
564
+ action: "SCMP_ACT_ALLOW",
565
+ args: [{
566
+ index: 0,
567
+ value: 26,
568
+ op: "SCMP_CMP_EQ"
569
+ }]
570
+ },
571
+ {
572
+ names: ["socket"],
573
+ action: "SCMP_ACT_ALLOW",
574
+ args: [{
575
+ index: 0,
576
+ value: 27,
577
+ op: "SCMP_CMP_EQ"
578
+ }]
579
+ },
580
+ {
581
+ names: ["socket"],
582
+ action: "SCMP_ACT_ALLOW",
583
+ args: [{
584
+ index: 0,
585
+ value: 28,
586
+ op: "SCMP_CMP_EQ"
587
+ }]
588
+ },
589
+ {
590
+ names: ["socket"],
591
+ action: "SCMP_ACT_ALLOW",
592
+ args: [{
593
+ index: 0,
594
+ value: 29,
595
+ op: "SCMP_CMP_EQ"
596
+ }]
597
+ },
598
+ {
599
+ names: ["socket"],
600
+ action: "SCMP_ACT_ALLOW",
601
+ args: [{
602
+ index: 0,
603
+ value: 30,
604
+ op: "SCMP_CMP_EQ"
605
+ }]
606
+ },
607
+ {
608
+ names: ["socket"],
609
+ action: "SCMP_ACT_ALLOW",
610
+ args: [{
611
+ index: 0,
612
+ value: 31,
613
+ op: "SCMP_CMP_EQ"
614
+ }]
615
+ },
616
+ {
617
+ names: ["socket"],
618
+ action: "SCMP_ACT_ALLOW",
619
+ args: [{
620
+ index: 0,
621
+ value: 32,
622
+ op: "SCMP_CMP_EQ"
623
+ }]
624
+ },
625
+ {
626
+ names: ["socket"],
627
+ action: "SCMP_ACT_ALLOW",
628
+ args: [{
629
+ index: 0,
630
+ value: 33,
631
+ op: "SCMP_CMP_EQ"
632
+ }]
633
+ },
634
+ {
635
+ names: ["socket"],
636
+ action: "SCMP_ACT_ALLOW",
637
+ args: [{
638
+ index: 0,
639
+ value: 35,
640
+ op: "SCMP_CMP_EQ"
641
+ }]
642
+ },
643
+ {
644
+ names: ["socket"],
645
+ action: "SCMP_ACT_ALLOW",
646
+ args: [{
647
+ index: 0,
648
+ value: 36,
649
+ op: "SCMP_CMP_EQ"
650
+ }]
651
+ },
652
+ {
653
+ names: ["socket"],
654
+ action: "SCMP_ACT_ALLOW",
655
+ args: [{
656
+ index: 0,
657
+ value: 39,
658
+ op: "SCMP_CMP_EQ"
659
+ }]
660
+ },
661
+ {
662
+ names: ["socket"],
663
+ action: "SCMP_ACT_ALLOW",
664
+ args: [{
665
+ index: 0,
666
+ value: 41,
667
+ op: "SCMP_CMP_EQ"
668
+ }]
669
+ },
670
+ {
671
+ names: ["socket"],
672
+ action: "SCMP_ACT_ALLOW",
673
+ args: [{
674
+ index: 0,
675
+ value: 42,
676
+ op: "SCMP_CMP_EQ"
677
+ }]
678
+ },
679
+ {
680
+ names: ["socket"],
681
+ action: "SCMP_ACT_ALLOW",
682
+ args: [{
683
+ index: 0,
684
+ value: 43,
685
+ op: "SCMP_CMP_EQ"
686
+ }]
687
+ },
688
+ {
689
+ names: ["socket"],
690
+ action: "SCMP_ACT_ALLOW",
691
+ args: [{
692
+ index: 0,
693
+ value: 44,
694
+ op: "SCMP_CMP_EQ"
695
+ }]
696
+ },
697
+ {
698
+ names: ["socket"],
699
+ action: "SCMP_ACT_ALLOW",
700
+ args: [{
701
+ index: 0,
702
+ value: 45,
703
+ op: "SCMP_CMP_EQ"
704
+ }]
705
+ },
706
+ {
707
+ names: ["personality"],
708
+ action: "SCMP_ACT_ALLOW",
709
+ args: [{
710
+ index: 0,
711
+ value: 0,
712
+ op: "SCMP_CMP_EQ"
713
+ }]
714
+ },
715
+ {
716
+ names: ["personality"],
717
+ action: "SCMP_ACT_ALLOW",
718
+ args: [{
719
+ index: 0,
720
+ value: 8,
721
+ op: "SCMP_CMP_EQ"
722
+ }]
723
+ },
724
+ {
725
+ names: ["personality"],
726
+ action: "SCMP_ACT_ALLOW",
727
+ args: [{
728
+ index: 0,
729
+ value: 131072,
730
+ op: "SCMP_CMP_EQ"
731
+ }]
732
+ },
733
+ {
734
+ names: ["personality"],
735
+ action: "SCMP_ACT_ALLOW",
736
+ args: [{
737
+ index: 0,
738
+ value: 131080,
739
+ op: "SCMP_CMP_EQ"
740
+ }]
741
+ },
742
+ {
743
+ names: ["personality"],
744
+ action: "SCMP_ACT_ALLOW",
745
+ args: [{
746
+ index: 0,
747
+ value: 4294967295,
748
+ op: "SCMP_CMP_EQ"
749
+ }]
750
+ },
751
+ {
752
+ names: ["sync_file_range2", "swapcontext"],
753
+ action: "SCMP_ACT_ALLOW",
754
+ includes: { arches: ["ppc64le"] }
755
+ },
756
+ {
757
+ names: [
758
+ "arm_fadvise64_64",
759
+ "arm_sync_file_range",
760
+ "sync_file_range2",
761
+ "breakpoint",
762
+ "cacheflush",
763
+ "set_tls"
764
+ ],
765
+ action: "SCMP_ACT_ALLOW",
766
+ includes: { arches: ["arm", "arm64"] }
767
+ },
768
+ {
769
+ names: ["arch_prctl"],
770
+ action: "SCMP_ACT_ALLOW",
771
+ includes: { arches: ["amd64", "x32"] }
772
+ },
773
+ {
774
+ names: ["modify_ldt"],
775
+ action: "SCMP_ACT_ALLOW",
776
+ includes: { arches: [
777
+ "amd64",
778
+ "x32",
779
+ "x86"
780
+ ] }
781
+ },
782
+ {
783
+ names: [
784
+ "s390_pci_mmio_read",
785
+ "s390_pci_mmio_write",
786
+ "s390_runtime_instr"
787
+ ],
788
+ action: "SCMP_ACT_ALLOW",
789
+ includes: { arches: ["s390", "s390x"] }
790
+ },
791
+ {
792
+ names: ["riscv_flush_icache"],
793
+ action: "SCMP_ACT_ALLOW",
794
+ includes: { arches: ["riscv64"] }
795
+ },
796
+ {
797
+ names: ["open_by_handle_at"],
798
+ action: "SCMP_ACT_ALLOW",
799
+ includes: { caps: ["CAP_DAC_READ_SEARCH"] }
800
+ },
801
+ {
802
+ names: [
803
+ "bpf",
804
+ "clone",
805
+ "clone3",
806
+ "fanotify_init",
807
+ "fsconfig",
808
+ "fsmount",
809
+ "fsopen",
810
+ "fspick",
811
+ "lookup_dcookie",
812
+ "lsm_get_self_attr",
813
+ "lsm_list_modules",
814
+ "lsm_set_self_attr",
815
+ "mount",
816
+ "mount_setattr",
817
+ "move_mount",
818
+ "open_tree",
819
+ "perf_event_open",
820
+ "quotactl",
821
+ "quotactl_fd",
822
+ "setdomainname",
823
+ "sethostname",
824
+ "setns",
825
+ "syslog",
826
+ "umount",
827
+ "umount2",
828
+ "unshare"
829
+ ],
830
+ action: "SCMP_ACT_ALLOW",
831
+ includes: { caps: ["CAP_SYS_ADMIN"] }
832
+ },
833
+ {
834
+ names: ["clone"],
835
+ action: "SCMP_ACT_ALLOW",
836
+ args: [{
837
+ index: 0,
838
+ value: 2114060288,
839
+ op: "SCMP_CMP_MASKED_EQ"
840
+ }],
841
+ excludes: {
842
+ caps: ["CAP_SYS_ADMIN"],
843
+ arches: ["s390", "s390x"]
844
+ }
845
+ },
846
+ {
847
+ names: ["clone"],
848
+ action: "SCMP_ACT_ALLOW",
849
+ args: [{
850
+ index: 1,
851
+ value: 2114060288,
852
+ op: "SCMP_CMP_MASKED_EQ"
853
+ }],
854
+ comment: "s390 parameter ordering for clone is different",
855
+ includes: { arches: ["s390", "s390x"] },
856
+ excludes: { caps: ["CAP_SYS_ADMIN"] }
857
+ },
858
+ {
859
+ names: ["clone3"],
860
+ action: "SCMP_ACT_ERRNO",
861
+ errnoRet: 38,
862
+ excludes: { caps: ["CAP_SYS_ADMIN"] }
863
+ },
864
+ {
865
+ names: ["reboot"],
866
+ action: "SCMP_ACT_ALLOW",
867
+ includes: { caps: ["CAP_SYS_BOOT"] }
868
+ },
869
+ {
870
+ names: ["chroot"],
871
+ action: "SCMP_ACT_ALLOW",
872
+ includes: { caps: ["CAP_SYS_CHROOT"] }
873
+ },
874
+ {
875
+ names: [
876
+ "delete_module",
877
+ "init_module",
878
+ "finit_module"
879
+ ],
880
+ action: "SCMP_ACT_ALLOW",
881
+ includes: { caps: ["CAP_SYS_MODULE"] }
882
+ },
883
+ {
884
+ names: ["acct"],
885
+ action: "SCMP_ACT_ALLOW",
886
+ includes: { caps: ["CAP_SYS_PACCT"] }
887
+ },
888
+ {
889
+ names: [
890
+ "kcmp",
891
+ "pidfd_getfd",
892
+ "process_madvise",
893
+ "process_vm_readv",
894
+ "process_vm_writev",
895
+ "ptrace"
896
+ ],
897
+ action: "SCMP_ACT_ALLOW",
898
+ includes: { caps: ["CAP_SYS_PTRACE"] }
899
+ },
900
+ {
901
+ names: ["iopl", "ioperm"],
902
+ action: "SCMP_ACT_ALLOW",
903
+ includes: { caps: ["CAP_SYS_RAWIO"] }
904
+ },
905
+ {
906
+ names: [
907
+ "settimeofday",
908
+ "stime",
909
+ "clock_settime",
910
+ "clock_settime64"
911
+ ],
912
+ action: "SCMP_ACT_ALLOW",
913
+ includes: { caps: ["CAP_SYS_TIME"] }
914
+ },
915
+ {
916
+ names: ["vhangup"],
917
+ action: "SCMP_ACT_ALLOW",
918
+ includes: { caps: ["CAP_SYS_TTY_CONFIG"] }
919
+ },
920
+ {
921
+ names: [
922
+ "get_mempolicy",
923
+ "mbind",
924
+ "set_mempolicy",
925
+ "set_mempolicy_home_node"
926
+ ],
927
+ action: "SCMP_ACT_ALLOW",
928
+ includes: { caps: ["CAP_SYS_NICE"] }
929
+ },
930
+ {
931
+ names: ["syslog"],
932
+ action: "SCMP_ACT_ALLOW",
933
+ includes: { caps: ["CAP_SYSLOG"] }
934
+ },
935
+ {
936
+ names: ["bpf"],
937
+ action: "SCMP_ACT_ALLOW",
938
+ includes: { caps: ["CAP_BPF"] }
939
+ },
940
+ {
941
+ names: ["perf_event_open"],
942
+ action: "SCMP_ACT_ALLOW",
943
+ includes: { caps: ["CAP_PERFMON"] }
944
+ }
945
+ ]
946
+ };
947
+ //#endregion
948
+ //#region ../sandbox-docker/src/engine.ts
949
+ let seccompFile;
950
+ /**
951
+ * Docker's default seccomp profile as a file Podman can read, written once per content under the
952
+ * temp directory (a compiled reeval has no real file of its own to point at).
953
+ */
954
+ function dockerSeccompFile() {
955
+ if (seccompFile && existsSync(seccompFile)) return seccompFile;
956
+ const json = JSON.stringify(DOCKER_SECCOMP_PROFILE);
957
+ const hash = createHash("sha256").update(json).digest("hex").slice(0, 16);
958
+ const path = join(tmpdir(), `reeval-seccomp-${hash}.json`);
959
+ if (!existsSync(path)) {
960
+ const partial = `${path}.${process.pid}.tmp`;
961
+ writeFileSync(partial, json);
962
+ renameSync(partial, path);
963
+ }
964
+ seccompFile = path;
965
+ return path;
966
+ }
967
+ const ENGINES = {
968
+ docker: {
969
+ bin: "docker",
970
+ name: "Docker",
971
+ fn: "docker",
972
+ stateFormat: "{{.ServerVersion}} {{.OSType}}",
973
+ capacityFormat: "{{.NCPU}} {{.MemTotal}}",
974
+ imageId: ".Id",
975
+ rmForce: ["rm", "-f"],
976
+ runArgs: () => [],
977
+ createsWorkdir: true
978
+ },
979
+ podman: {
980
+ bin: "podman",
981
+ name: "Podman",
982
+ fn: "podman",
983
+ stateFormat: "{{.Version.Version}} {{.Host.OS}}",
984
+ capacityFormat: "{{.Host.CPUs}} {{.Host.MemTotal}}",
985
+ imageId: ".ID",
986
+ rmForce: [
987
+ "rm",
988
+ "-f",
989
+ "--time",
990
+ "0"
991
+ ],
992
+ runArgs: () => [
993
+ "--network",
994
+ "bridge",
995
+ "--security-opt",
996
+ `seccomp=${dockerSeccompFile()}`
997
+ ],
998
+ createsWorkdir: false
999
+ }
1000
+ };
1001
+ const engineSpec = (engine = "docker") => ENGINES[engine];
1002
+ /**
1003
+ * The `CONTAINER_HOST` that reaches a `podman machine` straight through its API socket (macOS) or
1004
+ * named pipe (Windows), from `podman machine inspect`'s JSON.
1005
+ */
1006
+ function machineHost(inspect, platform) {
1007
+ const machine = Array.isArray(inspect) ? inspect[0] : void 0;
1008
+ const info = machine?.ConnectionInfo;
1009
+ const name = machine?.Name ?? "podman-machine-default";
1010
+ if (platform === "darwin" && info?.PodmanSocket?.Path) {
1011
+ const path = info.PodmanSocket.Path;
1012
+ return {
1013
+ host: `unix://${path}`,
1014
+ path,
1015
+ name
1016
+ };
1017
+ }
1018
+ if (platform === "win32" && info?.PodmanPipe?.Path) {
1019
+ const path = info.PodmanPipe.Path;
1020
+ return {
1021
+ host: `npipe://${path.replaceAll("\\", "/")}`,
1022
+ path,
1023
+ name
1024
+ };
1025
+ }
1026
+ return null;
1027
+ }
1028
+ /**
1029
+ * The environment every podman command gets. On macOS and Windows the client talks to the
1030
+ * machine's VM over SSH, a connection per command, and sshd's `MaxStartups` drops some of a burst
1031
+ * (exit 125, `ssh: handshake failed`), so commands go through the machine's API socket instead.
1032
+ * Not when the user picked a host (`CONTAINER_HOST`, `CONTAINER_CONNECTION`, or a default
1033
+ * connection that isn't the machine's), or the socket isn't there.
1034
+ */
1035
+ function podmanHostEnv(inputs) {
1036
+ const { platform, env } = inputs;
1037
+ if (platform !== "darwin" && platform !== "win32") return {};
1038
+ if (env.CONTAINER_HOST || env.CONTAINER_CONNECTION) return {};
1039
+ const machine = machineHost(inputs.inspect(), platform);
1040
+ if (!machine || !inputs.exists(machine.path)) return {};
1041
+ const connections = inputs.connections();
1042
+ const chosen = Array.isArray(connections) ? connections.find((c) => c.Default)?.Name : void 0;
1043
+ if (chosen && chosen !== machine.name && chosen !== `${machine.name}-root`) return {};
1044
+ return { CONTAINER_HOST: machine.host };
1045
+ }
1046
+ const readJson = (bin, args) => {
1047
+ try {
1048
+ const out = execFileSync(bin, args, {
1049
+ encoding: "utf8",
1050
+ stdio: [
1051
+ "ignore",
1052
+ "pipe",
1053
+ "ignore"
1054
+ ],
1055
+ timeout: 1e4,
1056
+ windowsHide: true
1057
+ });
1058
+ return JSON.parse(out);
1059
+ } catch {
1060
+ return;
1061
+ }
1062
+ };
1063
+ let podmanEnv;
1064
+ /** What every command on `engine` adds to its environment; read once per process. */
1065
+ function engineEnv(engine = "docker") {
1066
+ if (engine !== "podman") return {};
1067
+ podmanEnv ??= podmanHostEnv({
1068
+ platform: process.platform,
1069
+ env: process.env,
1070
+ inspect: () => readJson("podman", ["machine", "inspect"]),
1071
+ connections: () => readJson("podman", [
1072
+ "system",
1073
+ "connection",
1074
+ "list",
1075
+ "--format",
1076
+ "json"
1077
+ ]),
1078
+ exists: existsSync
1079
+ });
1080
+ return podmanEnv;
1081
+ }
1082
+ /** Docker's ids are `sha256:…`; Podman's are the bare hex. */
1083
+ const normalizeImageId = (id) => id.includes(":") ? id : `sha256:${id}`;
1084
+ //#endregion
16
1085
  //#region ../sandbox-docker/src/build-failure.ts
17
1086
  var ImageBuildError = class extends Error {
18
1087
  name = "ImageBuildError";
@@ -26,6 +1095,7 @@ const stripAnsi = (text) => text.replace(/\x1b\[[0-9;]*[A-Za-z]/g, "");
26
1095
  /** The failing step and its output from `--progress plain` build output. */
27
1096
  function parseBuildOutput(text) {
28
1097
  const lines = stripAnsi(text).split(/\r?\n/);
1098
+ if (!lines.some((l) => /^(?:#\d+ )?ERROR: /.test(l)) && lines.some((l) => l.startsWith("Error: "))) return parseBuildahOutput(lines);
29
1099
  let step = null;
30
1100
  let error = null;
31
1101
  for (const line of lines) {
@@ -46,14 +1116,35 @@ function parseBuildOutput(text) {
46
1116
  exitCode: code ? Number(code) : null
47
1117
  };
48
1118
  }
1119
+ /**
1120
+ * buildah's output (`podman build`): `STEP n/m: …` headers, each step's output as is, then
1121
+ * `Error: building at STEP "…": …`. Its own warnings are `time="…" level=…` lines.
1122
+ */
1123
+ function parseBuildahOutput(lines) {
1124
+ let error = null;
1125
+ let output = [];
1126
+ for (const line of lines) if (/^STEP \d+\/\d+: /.test(line)) output = [];
1127
+ else if (line.startsWith("Error: ")) error = line.slice(7);
1128
+ else if (!error && line.trim() && !/^time="[^"]*" level=|^--> /.test(line)) output.push(line);
1129
+ error = (error ?? "").replace(/^building at STEP "(?:[^"\\]|\\.)*": /, "").replace(/ &imagebuilder\.Step\{.*$/, "").trim() || null;
1130
+ const code = /exit status (\d+)$/.exec(error ?? "")?.[1];
1131
+ return {
1132
+ error,
1133
+ output: output.slice(-8),
1134
+ exitCode: code ? Number(code) : null
1135
+ };
1136
+ }
49
1137
  /** ENOSPC or a SIGKILL (137, usually the out-of-memory killer), from anything the build printed. */
50
1138
  function failureCause(text, exitCode) {
51
1139
  if (/no space left on device|ENOSPC/i.test(text)) return "enospc";
52
- if (exitCode === 137 || /exit(?:ed| code:?) 137\b|signal: killed|OOMKilled/i.test(text)) return "oom";
1140
+ if (exitCode === 137 || /exit(?:ed| code:?| status) 137\b|signal: killed|OOMKilled/i.test(text)) return "oom";
53
1141
  return null;
54
1142
  }
55
- const causeLine = (cause) => cause === "enospc" ? "out of disk space (ENOSPC): free space for Docker (docker system df, reeval clean --images) and rerun" : "killed (exit 137): usually out of memory; give Docker more memory or lower the concurrency";
56
- const DETERMINISTIC = /did not complete successfully|dockerfile parse error|unknown instruction|should not be blank|pull access denied|repository does not exist|manifest unknown|not found: manifest|: not found\b|unauthorized|denied:|reeval needs a Debian or Ubuntu based image/i;
1143
+ const causeLine = (cause, engine) => {
1144
+ const { name, bin } = engineSpec(engine);
1145
+ return cause === "enospc" ? `out of disk space (ENOSPC): free space for ${name} (${bin} system df, reeval clean --images) and rerun` : `killed (exit 137): usually out of memory; give ${name} more memory or lower the concurrency`;
1146
+ };
1147
+ const DETERMINISTIC = /did not complete successfully|while running runtime: exit status|did not resolve to an alias|requested access to the resource is denied|dockerfile parse error|unknown instruction|should not be blank|pull access denied|repository does not exist|manifest unknown|not found: manifest|: not found\b|unauthorized|denied:|reeval needs a Debian or Ubuntu based image/i;
57
1148
  const TRANSIENT = /EAI_AGAIN|ECONNRESET|ETIMEDOUT|ECONNREFUSED|i\/o timeout|TLS handshake timeout|no such host|temporary failure in name resolution|connection reset by peer|dial tcp|net\/http: request canceled|unexpected EOF|\b(?:500|502|503|504) |429 Too Many Requests|toomanyrequests|Service Unavailable|Bad Gateway|Gateway Timeout|ENOTFOUND/i;
58
1149
  /** A registry or network error: a pull, a metadata lookup, or a download in the harness bootstrap. */
59
1150
  const isTransient = (text) => !DETERMINISTIC.test(text) && TRANSIENT.test(text);
@@ -76,7 +1167,7 @@ const RETRY_DELAYS = [2e3, 8e3];
76
1167
  */
77
1168
  function failureMessage(parts) {
78
1169
  const lines = [parts.headline];
79
- if (parts.cause) lines.push(causeLine(parts.cause));
1170
+ if (parts.cause) lines.push(causeLine(parts.cause, parts.engine));
80
1171
  if (parts.output.length) lines.push(...parts.output.map((l) => ` | ${l}`));
81
1172
  if (parts.log) lines.push(`(full log: ${parts.log})`);
82
1173
  return lines.join("\n");
@@ -86,119 +1177,6 @@ function outputTail(text, max = 8) {
86
1177
  return stripAnsi(text).split(/\r?\n/).map((l) => l.trimEnd()).filter((l) => l.trim()).slice(-max);
87
1178
  }
88
1179
  //#endregion
89
- //#region ../sandbox-docker/src/process.ts
90
- const CMD_META = /([()\][%!^"`<>&|;, *?])/g;
91
- const cmdEscape = (arg, twice) => {
92
- const quoted = `"${arg.replace(/(\\*)"/g, "$1$1\\\"").replace(/(\\*)$/, "$1$1")}"`.replace(CMD_META, "^$1");
93
- return twice ? quoted.replace(CMD_META, "^$1") : quoted;
94
- };
95
- /**
96
- * How to spawn `cmd` on Windows, where npm, npx and pnpm are `.cmd` scripts that only cmd.exe
97
- * runs: the program PATH and PATHEXT find, and for a script, cmd.exe with every argument escaped.
98
- */
99
- function windowsSpawn(cmd, args, env = process.env, exists = existsSync) {
100
- const exts = (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean);
101
- const file = (/[\\/]/.test(cmd) ? [""] : (env.PATH ?? env.Path ?? "").split(";").filter(Boolean)).flatMap((dir) => {
102
- const base = dir ? win32.join(dir, cmd) : cmd;
103
- return [...win32.extname(cmd) ? [base] : [], ...exts.map((ext) => base + ext.toLowerCase())];
104
- }).find(exists) ?? cmd;
105
- if (!/\.(cmd|bat)$/i.test(file)) return {
106
- file,
107
- args,
108
- verbatim: false
109
- };
110
- const twice = /node_modules[\\/]\.bin[\\/][^\\/]+\.cmd$/i.test(file);
111
- const line = [win32.normalize(file).replace(CMD_META, "^$1"), ...args.map((a) => cmdEscape(a, twice))].join(" ");
112
- return {
113
- file: env.ComSpec ?? "cmd.exe",
114
- args: [
115
- "/d",
116
- "/s",
117
- "/c",
118
- `"${line}"`
119
- ],
120
- verbatim: true
121
- };
122
- }
123
- /**
124
- * Kills a process and everything it started: its process group on POSIX (a detached child leads
125
- * one), its process tree with `taskkill` on Windows, which has neither groups nor signals.
126
- */
127
- function killTree(pid) {
128
- if (process.platform === "win32") {
129
- spawn("taskkill", [
130
- "/pid",
131
- String(pid),
132
- "/t",
133
- "/f"
134
- ], {
135
- stdio: "ignore",
136
- windowsHide: true
137
- }).on("error", () => {});
138
- return;
139
- }
140
- try {
141
- process.kill(-pid, "SIGKILL");
142
- } catch {
143
- try {
144
- process.kill(pid, "SIGKILL");
145
- } catch {}
146
- }
147
- }
148
- /** `s` as one single-quoted POSIX shell word. */
149
- const shellQuote = (s) => `'${s.replaceAll("'", `'\\''`)}'`;
150
- function run(cmd, args, options = {}) {
151
- const { signal } = options;
152
- return new Promise((resolve, reject) => {
153
- if (signal?.aborted) return reject(signal.reason);
154
- const detached = options.detached ?? true;
155
- const target = process.platform === "win32" ? windowsSpawn(cmd, args, options.env ? {
156
- ...process.env,
157
- ...options.env
158
- } : process.env) : {
159
- file: cmd,
160
- args,
161
- verbatim: false
162
- };
163
- const child = spawn(target.file, target.args, {
164
- cwd: options.cwd,
165
- stdio: "pipe",
166
- detached: detached && !target.verbatim,
167
- windowsHide: true,
168
- windowsVerbatimArguments: target.verbatim,
169
- env: options.env ? {
170
- ...process.env,
171
- ...options.env
172
- } : process.env
173
- });
174
- const out = [];
175
- let stderr = "";
176
- child.stdout.on("data", (d) => out.push(d));
177
- child.stderr.on("data", (d) => {
178
- stderr += d;
179
- });
180
- const onAbort = () => {
181
- if ((detached || process.platform === "win32") && child.pid) killTree(child.pid);
182
- else child.kill("SIGKILL");
183
- };
184
- signal?.addEventListener("abort", onAbort, { once: true });
185
- child.on("error", reject);
186
- child.on("close", (code) => {
187
- signal?.removeEventListener("abort", onAbort);
188
- if (signal?.aborted) return reject(signal.reason);
189
- const stdout = Buffer.concat(out);
190
- resolve({
191
- exitCode: code ?? 1,
192
- stdout: options.binary ? stdout : stdout.toString(),
193
- stderr
194
- });
195
- });
196
- if (child.pid) options.onSpawn?.(child.pid);
197
- child.stdin.on("error", () => {});
198
- child.stdin.end(options.input ?? "");
199
- });
200
- }
201
- //#endregion
202
1180
  //#region ../sandbox-docker/src/trace.ts
203
1181
  /** Most of each stream a trace keeps; the rest is counted. */
204
1182
  const MAX_STREAM = 4096;
@@ -216,9 +1194,10 @@ function streamPreview(data) {
216
1194
  if (data.includes(0) || !isUtf8(data)) return `<${data.length} bytes>`;
217
1195
  return clip(data.toString("utf8"), MAX_STREAM);
218
1196
  }
219
- function traceDocker(args, startedAt, result) {
1197
+ function traceDocker(args, startedAt, result, bin = "docker") {
220
1198
  if (!listener) return;
221
1199
  const base = {
1200
+ bin,
222
1201
  args: args.map((a) => clip(a, MAX_ARG)),
223
1202
  ms: Date.now() - startedAt
224
1203
  };
@@ -245,107 +1224,199 @@ function traceDocker(args, startedAt, result) {
245
1224
  }
246
1225
  //#endregion
247
1226
  //#region ../sandbox-docker/src/docker-cli.ts
248
- /** Runs the docker CLI. `env` values are passed via the CLI's environment, never argv. */
1227
+ /** How long to wait before each retry of a command that never reached Podman. */
1228
+ const CONNECTION_RETRY_MS = [
1229
+ 100,
1230
+ 250,
1231
+ 500,
1232
+ 1e3,
1233
+ 2e3
1234
+ ];
1235
+ /**
1236
+ * Whether a podman command failed before reaching the engine: the remote client's SSH handshake
1237
+ * or socket connection to `podman machine`, so running it again is safe.
1238
+ */
1239
+ const isConnectionFailure = (r) => r.exitCode === 125 && /ssh: handshake failed|unable to connect to Podman socket/.test(r.stderr);
1240
+ const sleep = (ms, signal) => new Promise((resolve) => {
1241
+ const timer = setTimeout(done, ms);
1242
+ function done() {
1243
+ clearTimeout(timer);
1244
+ signal?.removeEventListener("abort", done);
1245
+ resolve();
1246
+ }
1247
+ signal?.addEventListener("abort", done, { once: true });
1248
+ });
1249
+ /**
1250
+ * Runs `attempt` again, after each of `delays`, while its result is a connection failure (see
1251
+ * {@link isConnectionFailure}), and returns the last result.
1252
+ */
1253
+ async function retryConnection(attempt, options = {}) {
1254
+ const { delays = CONNECTION_RETRY_MS, signal, wait = sleep } = options;
1255
+ let r = await attempt();
1256
+ for (const ms of delays) {
1257
+ if (!isConnectionFailure(r) || signal?.aborted) break;
1258
+ await wait(ms, signal);
1259
+ r = await attempt();
1260
+ }
1261
+ return r;
1262
+ }
1263
+ /** Runs the docker (or podman) CLI. `env` values are passed via the CLI's environment, never argv. */
249
1264
  async function docker(args, options = {}) {
250
- const startedAt = Date.now();
1265
+ const { engine, ...rest } = options;
1266
+ const { bin } = engineSpec(engine);
251
1267
  const stdin = options.input?.length ?? 0;
252
- try {
253
- const r = await run("docker", args, {
254
- ...options,
255
- binary: true
256
- });
257
- traceDocker(args, startedAt, {
258
- ...r,
259
- stdin
260
- });
261
- return r;
262
- } catch (error) {
263
- traceDocker(args, startedAt, { error });
264
- throw error;
265
- }
1268
+ const env = {
1269
+ ...engineEnv(engine),
1270
+ ...rest.env
1271
+ };
1272
+ const once = async () => {
1273
+ const startedAt = Date.now();
1274
+ try {
1275
+ const r = await run(bin, args, {
1276
+ ...rest,
1277
+ env,
1278
+ binary: true
1279
+ });
1280
+ traceDocker(args, startedAt, {
1281
+ ...r,
1282
+ stdin
1283
+ }, bin);
1284
+ return r;
1285
+ } catch (error) {
1286
+ traceDocker(args, startedAt, { error }, bin);
1287
+ throw error;
1288
+ }
1289
+ };
1290
+ return engine === "podman" ? retryConnection(once, { signal: options.signal }) : once();
266
1291
  }
267
1292
  async function dockerOk(args, opts) {
268
1293
  const r = await docker(args, opts);
269
- if (r.exitCode !== 0) throw new Error(`docker ${args[0]} failed: ${r.stderr.trim()}`);
1294
+ if (r.exitCode !== 0) throw new Error(`${engineSpec(opts?.engine).bin} ${args[0]} failed: ${r.stderr.trim()}`);
270
1295
  return r.stdout.toString("utf8").trim();
271
1296
  }
272
- /** Removes a container in its own process group, so removal survives this process being killed. */
273
- function removeContainerDetached(id) {
274
- return new Promise((resolve) => {
1297
+ /** Whether `rm -f` left the container gone: it removed it, or it was already gone. */
1298
+ const removalDone = (r) => r.exitCode === 0 || /no such container/i.test(r.stderr);
1299
+ /** How long to wait before each retry of a removal that failed. */
1300
+ const REMOVAL_RETRY_MS = [
1301
+ 250,
1302
+ 500,
1303
+ 1e3,
1304
+ 2e3,
1305
+ 4e3
1306
+ ];
1307
+ /**
1308
+ * Removes a container in its own process group, so removal survives this process being killed,
1309
+ * and tries again while it fails. Resolves either way.
1310
+ */
1311
+ async function removeContainerDetached(id, engine, options = {}) {
1312
+ const { bin, rmForce } = engineSpec(engine);
1313
+ const { delays = REMOVAL_RETRY_MS, wait = sleep } = options;
1314
+ const args = [...rmForce, id];
1315
+ const env = {
1316
+ ...process.env,
1317
+ ...engineEnv(engine)
1318
+ };
1319
+ const once = () => new Promise((resolve) => {
275
1320
  const keepAlive = setInterval(() => {}, 1e3);
276
1321
  const startedAt = Date.now();
277
- const args = [
278
- "rm",
279
- "-f",
280
- id
281
- ];
1322
+ let stderr = "";
1323
+ let settled = false;
282
1324
  const done = (exitCode) => {
1325
+ if (settled) return;
1326
+ settled = true;
283
1327
  clearInterval(keepAlive);
284
- traceDocker(args, startedAt, { exitCode });
285
- resolve();
1328
+ traceDocker(args, startedAt, {
1329
+ exitCode,
1330
+ stderr
1331
+ }, bin);
1332
+ resolve({
1333
+ exitCode,
1334
+ stderr
1335
+ });
286
1336
  };
287
- const child = spawn("docker", args, {
1337
+ const child = spawn(bin, args, {
288
1338
  detached: true,
289
- stdio: "ignore",
290
- windowsHide: true
1339
+ stdio: [
1340
+ "ignore",
1341
+ "ignore",
1342
+ "pipe"
1343
+ ],
1344
+ windowsHide: true,
1345
+ env
1346
+ });
1347
+ child.stderr.on("data", (d) => {
1348
+ stderr += d;
1349
+ });
1350
+ child.on("error", (error) => {
1351
+ stderr += String(error);
1352
+ done(null);
291
1353
  });
292
- child.on("error", () => done(null));
293
1354
  child.on("close", done);
294
1355
  });
1356
+ let r = await once();
1357
+ for (const ms of delays) {
1358
+ if (removalDone(r) || r.exitCode === null) return;
1359
+ await wait(ms);
1360
+ r = await once();
1361
+ }
295
1362
  }
296
1363
  /**
297
1364
  * Removes every container with `label` (`key=value`) for the next few seconds, in its own process
298
1365
  * group so it outlives this process. For a `docker run` killed mid-way: the daemon may create the
299
1366
  * container after the CLI dies, and its id never came back.
300
1367
  */
301
- function sweepLabelDetached(label, seconds = 15) {
1368
+ function sweepLabelDetached(label, seconds = 15, engine) {
1369
+ const { bin, rmForce } = engineSpec(engine);
302
1370
  const child = spawn(process.execPath, [
303
1371
  "-e",
304
1372
  `const { execFileSync } = require('node:child_process')
305
- const [filter, seconds] = process.argv.slice(1)
1373
+ const [filter, seconds, bin, ...rm] = process.argv.slice(1)
306
1374
  const o = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true }
307
1375
  for (let i = 0; i < Number(seconds); i++) {
308
1376
  try {
309
- const ids = execFileSync('docker', ['ps', '-aq', '--filter', filter], o).split(/\\s+/).filter(Boolean)
310
- if (ids.length) execFileSync('docker', ['rm', '-f', ...ids], o)
1377
+ const ids = execFileSync(bin, ['ps', '-aq', '--filter', filter], o).split(/\\s+/).filter(Boolean)
1378
+ if (ids.length) execFileSync(bin, [...rm, ...ids], o)
311
1379
  } catch {}
312
1380
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 1000)
313
1381
  }`,
314
1382
  `label=${label}`,
315
- String(seconds)
1383
+ String(seconds),
1384
+ bin,
1385
+ ...rmForce
316
1386
  ], {
317
1387
  detached: true,
318
1388
  stdio: "ignore",
319
1389
  windowsHide: true,
320
1390
  env: {
321
1391
  ...process.env,
1392
+ ...engineEnv(engine),
322
1393
  BUN_BE_BUN: "1"
323
1394
  }
324
1395
  });
325
1396
  child.on("error", () => {});
326
1397
  child.unref();
327
1398
  }
328
- async function dockerState() {
1399
+ async function dockerState(engine) {
329
1400
  const r = await docker([
330
1401
  "info",
331
1402
  "--format",
332
- "{{.ServerVersion}} {{.OSType}}"
333
- ]).catch(() => null);
1403
+ engineSpec(engine).stateFormat
1404
+ ], { engine }).catch(() => null);
334
1405
  const [version, os] = r?.exitCode === 0 ? r.stdout.toString("utf8").trim().split(/\s+/) : [];
335
1406
  if (!version) return "down";
336
1407
  return os === "windows" ? "windows-containers" : "running";
337
1408
  }
338
- /** Whether Docker is running Linux containers, as every sandbox needs. */
339
- async function dockerAvailable() {
340
- return await dockerState() === "running";
1409
+ /** Whether Docker (or Podman) is running Linux containers, as every sandbox needs. */
1410
+ async function dockerAvailable(engine) {
1411
+ return await dockerState(engine) === "running";
341
1412
  }
342
- /** CPUs and memory of the machine containers run on (the VM, under Docker Desktop). */
343
- async function dockerCapacity() {
1413
+ /** CPUs and memory of the machine containers run on (the VM, under Docker Desktop or `podman machine`). */
1414
+ async function dockerCapacity(engine) {
344
1415
  const r = await docker([
345
1416
  "info",
346
1417
  "--format",
347
- "{{.NCPU}} {{.MemTotal}}"
348
- ]).catch(() => null);
1418
+ engineSpec(engine).capacityFormat
1419
+ ], { engine }).catch(() => null);
349
1420
  if (r?.exitCode !== 0) return null;
350
1421
  const [cpus, memoryBytes] = r.stdout.toString("utf8").trim().split(/\s+/).map(Number);
351
1422
  return cpus && memoryBytes ? {
@@ -359,23 +1430,51 @@ async function dockerCapacity() {
359
1430
  * their bare local name (`reeval-sandbox@sha256:…`). A bare name is Docker Hub's `library/`
360
1431
  * namespace, which only official images can push to, so only a digest whose name has a registry
361
1432
  * host or a namespace counts. Official images such as `busybox` count as local; no image with
362
- * the harness baked in is one.
1433
+ * the harness baked in is one. Podman names local images `localhost/…`, which no one pulls from.
1434
+ */
1435
+ const isRegistryDigest = (digest) => {
1436
+ const name = digest.split("@")[0] ?? "";
1437
+ return name.includes("/") && !name.startsWith("localhost/");
1438
+ };
1439
+ /** `repository:tag` of every local image in `repository`; none when the CLI fails. */
1440
+ async function imageTags(repository, engine) {
1441
+ const r = await docker([
1442
+ "image",
1443
+ "ls",
1444
+ "--format",
1445
+ "{{.Repository}}:{{.Tag}}",
1446
+ repository
1447
+ ], { engine }).catch(() => null);
1448
+ if (r?.exitCode !== 0) return [];
1449
+ return r.stdout.toString("utf8").split(/\r?\n/).filter(Boolean).map((t) => t.replace(/^localhost\//, ""));
1450
+ }
1451
+ /** `image inspect`'s answer when the engine has no such image (Docker's wording, then Podman's). */
1452
+ const isNoSuchImage = (stderr) => /no such image|image not known/i.test(stderr);
1453
+ /**
1454
+ * The image, or null when the engine says it has no such image. A CLI that can't start or a daemon
1455
+ * that doesn't answer throws instead, naming the error: that's not knowing, not a missing image.
363
1456
  */
364
- const isRegistryDigest = (digest) => (digest.split("@")[0] ?? "").includes("/");
365
- async function imageInfo(image) {
1457
+ async function imageInfo(image, engine) {
1458
+ const { bin, imageId } = engineSpec(engine);
366
1459
  const r = await docker([
367
1460
  "image",
368
1461
  "inspect",
369
1462
  "--format",
370
- "{\"config\":{{json .Config}},\"id\":{{json .Id}},\"repoDigests\":{{json .RepoDigests}}}",
1463
+ `{"config":{{json .Config}},"id":{{json ${imageId}}},"repoDigests":{{json .RepoDigests}}}`,
371
1464
  image
372
- ]).catch(() => null);
373
- if (r?.exitCode !== 0) return null;
1465
+ ], { engine }).catch((error) => {
1466
+ throw new Error(`${bin} image inspect ${image} couldn't run: ${error.message}`);
1467
+ });
1468
+ if (r.exitCode !== 0) {
1469
+ const stderr = r.stderr.trim();
1470
+ if (isNoSuchImage(stderr)) return null;
1471
+ throw new Error(`${bin} image inspect ${image} failed: ${stderr || `exit ${r.exitCode}`}`);
1472
+ }
374
1473
  const info = JSON.parse(r.stdout.toString("utf8"));
375
1474
  const repoDigests = (info.repoDigests ?? []).filter(isRegistryDigest);
376
1475
  return {
377
1476
  labels: info.config?.Labels ?? {},
378
- id: info.id,
1477
+ id: normalizeImageId(info.id),
379
1478
  repoDigests
380
1479
  };
381
1480
  }
@@ -390,32 +1489,40 @@ async function imageInfo(image) {
390
1489
  const HARNESS_PACKAGES = {
391
1490
  cursor: {
392
1491
  name: "@reeval/harness-cursor-sdk",
393
- version: "0.1.4"
1492
+ version: "0.1.5"
394
1493
  },
395
1494
  "claude-code": {
396
1495
  name: "@ai-sdk/harness-claude-code",
397
- version: "1.0.152",
398
- patch: "8edc594f"
1496
+ version: "1.0.158",
1497
+ patch: "6c1cff12"
399
1498
  },
400
1499
  antigravity: {
401
1500
  name: "@reeval/harness-antigravity",
402
- version: "0.1.6"
1501
+ version: "0.1.8"
403
1502
  },
404
1503
  opencode: {
405
1504
  name: "@reeval/harness-opencode",
406
- version: "0.2.7"
1505
+ version: "0.2.8"
407
1506
  },
408
1507
  goose: {
409
1508
  name: "@reeval/harness-goose",
410
- version: "0.1.2"
1509
+ version: "0.1.3"
411
1510
  },
412
1511
  pi: {
413
1512
  name: "@reeval/harness-pi",
414
- version: "0.2.6"
1513
+ version: "0.2.7"
415
1514
  },
416
1515
  codex: {
417
1516
  name: "@reeval/harness-codex",
418
- version: "0.1.6"
1517
+ version: "0.1.7"
1518
+ },
1519
+ fx: {
1520
+ name: "@reeval/harness-fx",
1521
+ version: "0.1.0"
1522
+ },
1523
+ "grok-build": {
1524
+ name: "@reeval/harness-grok-build",
1525
+ version: "0.1.0"
419
1526
  }
420
1527
  };
421
1528
  /** Every harness with an image, in {@link HARNESS_PACKAGES} order. */
@@ -780,7 +1887,9 @@ const HARNESS_HOSTS = {
780
1887
  opencode: ["generativelanguage.googleapis.com", "mcp.exa.ai"],
781
1888
  goose: ["generativelanguage.googleapis.com"],
782
1889
  pi: ["generativelanguage.googleapis.com"],
783
- codex: ["api.openai.com"]
1890
+ codex: ["api.openai.com"],
1891
+ fx: ["ai-gateway.vercel.sh"],
1892
+ "grok-build": ["api.x.ai"]
784
1893
  };
785
1894
  /** The package registries and GitHub, for a restricted policy that still installs. */
786
1895
  const PACKAGE_HOSTS = Object.freeze([
@@ -1894,14 +3003,14 @@ const PROXY_PORT = 43128;
1894
3003
  const CA_PATH = "/usr/local/share/ca-certificates/reeval-egress.crt";
1895
3004
  /** Debian's system bundle, which `update-ca-certificates` rebuilds with the gateway's CA in it. */
1896
3005
  const CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt";
1897
- const BUNDLED = "es:ca-bundle";
3006
+ const BUNDLED = "reeval:ca-bundle";
1898
3007
  const READY_TIMEOUT_MS = 15e3;
1899
3008
  /**
1900
3009
  * The gateway's side of the container runs as root, whoever the sandbox runs as: the sandbox user
1901
3010
  * can't signal, trace or replace the forwarder, or change the CA it installed.
1902
3011
  */
1903
3012
  const AS_ROOT = ["--user", "0:0"];
1904
- const installCa = (containerId, cert, signal) => docker([
3013
+ const installCa = (containerId, cert, signal, engine) => docker([
1905
3014
  "exec",
1906
3015
  "--interactive",
1907
3016
  ...AS_ROOT,
@@ -1911,15 +3020,16 @@ const installCa = (containerId, cert, signal) => docker([
1911
3020
  `umask 022 && mkdir -p "$(dirname ${CA_PATH})" && cat > ${CA_PATH} && { command -v update-ca-certificates >/dev/null && update-ca-certificates >/dev/null 2>&1 && grep -q "$(sed -n 2p ${CA_PATH})" ${CA_BUNDLE} && echo ${BUNDLED}; true; }`
1912
3021
  ], {
1913
3022
  input: cert,
1914
- signal
3023
+ signal,
3024
+ engine
1915
3025
  });
1916
3026
  /**
1917
3027
  * Starts the egress gateway for one container: a forwarder inside it, tunnelled over one
1918
3028
  * `docker exec -i`, and the proxy in this process, which holds the real credentials.
1919
3029
  */
1920
- async function startGateway(containerId, options, signal) {
3030
+ async function startGateway(containerId, options, signal, engine) {
1921
3031
  const ca = createCertificateAuthority();
1922
- const installed = await installCa(containerId, ca.cert, signal);
3032
+ const installed = await installCa(containerId, ca.cert, signal, engine);
1923
3033
  if (installed.exitCode !== 0) throw new Error(`couldn't install the gateway CA: ${installed.stderr.trim()}`);
1924
3034
  const bundled = installed.stdout.toString("utf8").includes(BUNDLED);
1925
3035
  const proxy = createEgressProxy({
@@ -1936,14 +3046,19 @@ async function startGateway(containerId, options, signal) {
1936
3046
  forwarderScript(PROXY_PORT)
1937
3047
  ];
1938
3048
  const startedAt = Date.now();
1939
- const child = spawn("docker", args, {
3049
+ const { bin } = engineSpec(engine);
3050
+ const child = spawn(bin, args, {
1940
3051
  stdio: "pipe",
1941
- detached: true
3052
+ detached: true,
3053
+ env: {
3054
+ ...process.env,
3055
+ ...engineEnv(engine)
3056
+ }
1942
3057
  });
1943
3058
  child.once("close", (code) => traceDocker(args, startedAt, {
1944
3059
  exitCode: code,
1945
3060
  stderr
1946
- }));
3061
+ }, bin));
1947
3062
  let stderr = "";
1948
3063
  child.stderr.on("data", (d) => {
1949
3064
  stderr += d;
@@ -2057,6 +3172,35 @@ const DEFAULT_LIMITS = {
2057
3172
  cpus: 2,
2058
3173
  pids: 1024
2059
3174
  };
3175
+ const UNITS = {
3176
+ b: 1,
3177
+ k: 1024,
3178
+ m: 1024 ** 2,
3179
+ g: 1024 ** 3
3180
+ };
3181
+ /** A Docker memory size in bytes, as Docker reads it (binary units). */
3182
+ function sizeBytes(size) {
3183
+ if (typeof size === "number") return size;
3184
+ const m = /^(\d+(?:\.\d+)?)([bkmg])?$/i.exec(size.trim());
3185
+ if (!m) throw new Error(`not a Docker memory size: ${JSON.stringify(size)}`);
3186
+ const unit = m[2]?.toLowerCase() ?? "b";
3187
+ return Math.floor(Number(m[1]) * UNITS[unit]);
3188
+ }
3189
+ /** Bytes in the largest unit that divides them evenly: `8g`, `1536m`, or plain bytes. */
3190
+ function formatSize(bytes) {
3191
+ for (const unit of [
3192
+ "g",
3193
+ "m",
3194
+ "k"
3195
+ ]) if (bytes % UNITS[unit] === 0) return `${bytes / UNITS[unit]}${unit}`;
3196
+ return String(bytes);
3197
+ }
3198
+ /** Docker's `--memory-swap`: the total of memory and swap. */
3199
+ function memorySwap(limits) {
3200
+ const memory = sizeBytes(limits.memory);
3201
+ const swap = limits.swap === void 0 ? memory : sizeBytes(limits.swap);
3202
+ return swap === 0 ? String(limits.memory) : formatSize(memory + swap);
3203
+ }
2060
3204
  /** What `root` adds back: what `apt-get` (and its `_apt` sandbox) and `dpkg` need as root. */
2061
3205
  const ROOT_CAPABILITIES = [
2062
3206
  "CHOWN",
@@ -2065,14 +3209,21 @@ const ROOT_CAPABILITIES = [
2065
3209
  "SETUID",
2066
3210
  "SETGID"
2067
3211
  ];
2068
- let hostCpus;
3212
+ const hostCpus = /* @__PURE__ */ new Map();
2069
3213
  /** Docker refuses `--cpus` above the host's count, so cap it there. */
2070
- async function cpuLimit(cpus) {
2071
- hostCpus ??= dockerCapacity().then((c) => c?.cpus, () => void 0);
2072
- const available = await hostCpus;
3214
+ async function cpuLimit(cpus, engine = "docker") {
3215
+ let known = hostCpus.get(engine);
3216
+ if (!known) {
3217
+ known = dockerCapacity(engine).then((c) => c?.cpus, () => void 0);
3218
+ hostCpus.set(engine, known);
3219
+ }
3220
+ const available = await known;
2073
3221
  return String(available ? Math.min(cpus, available) : cpus);
2074
3222
  }
2075
- /** The `docker run` flags that confine the container: its user, capabilities and limits. */
3223
+ /**
3224
+ * The `docker run` flags that confine the container: its user, capabilities and limits, and on
3225
+ * Podman the bridge network and Docker's seccomp profile.
3226
+ */
2076
3227
  async function confinementArgs(options) {
2077
3228
  const limits = {
2078
3229
  ...DEFAULT_LIMITS,
@@ -2090,27 +3241,63 @@ async function confinementArgs(options) {
2090
3241
  "--memory",
2091
3242
  String(limits.memory),
2092
3243
  "--memory-swap",
2093
- String(limits.memory),
3244
+ memorySwap(limits),
2094
3245
  "--pids-limit",
2095
3246
  String(limits.pids),
2096
3247
  "--cpus",
2097
- await cpuLimit(limits.cpus)
3248
+ await cpuLimit(limits.cpus, options.engine),
3249
+ ...engineSpec(options.engine).runArgs()
2098
3250
  ];
2099
3251
  }
2100
3252
  /** Runtime `npm i -g` goes to the sandbox user's own prefix, whose `bin` the images put on PATH. */
2101
3253
  const userEnv = (options) => options.root ? {} : { NPM_CONFIG_PREFIX: `${SANDBOX_HOME}/.local` };
2102
3254
  /** Set on every exec, so a kill can find the command's whole process tree in the container. */
2103
3255
  const EXEC_MARKER = "REEVAL_EXEC_ID";
3256
+ /**
3257
+ * The container's cgroup counts every process the kernel killed at its memory limit: cgroup v2's
3258
+ * `memory.events` and v1's `memory.oom_control` both have an `oom_kill` line. Without either,
3259
+ * Docker's `OOMKilled` says only whether there was one.
3260
+ */
3261
+ async function oomKills(id, engine) {
3262
+ const events = await docker([
3263
+ "exec",
3264
+ id,
3265
+ "sh",
3266
+ "-c",
3267
+ "cat /sys/fs/cgroup/memory.events 2>/dev/null || cat /sys/fs/cgroup/memory/memory.oom_control"
3268
+ ], { engine }).catch(() => null);
3269
+ const count = events?.stdout.toString("utf8").match(/^oom_kill (\d+)$/m)?.[1];
3270
+ if (events?.exitCode === 0 && count !== void 0) return Number(count);
3271
+ const inspected = await docker([
3272
+ "inspect",
3273
+ "--format",
3274
+ "{{.State.OOMKilled}}",
3275
+ id
3276
+ ], { engine }).catch(() => null);
3277
+ if (inspected?.exitCode !== 0) return null;
3278
+ const killed = inspected.stdout.toString("utf8").trim();
3279
+ return killed === "true" ? 1 : killed === "false" ? 0 : null;
3280
+ }
2104
3281
  /** The Docker networks a container is attached to. */
2105
- async function networksOf(id) {
3282
+ async function networksOf(id, engine) {
2106
3283
  const out = await dockerOk([
2107
3284
  "inspect",
2108
3285
  "--format",
2109
3286
  "{{json .NetworkSettings.Networks}}",
2110
3287
  id
2111
- ]);
3288
+ ], { engine });
2112
3289
  return Object.keys(JSON.parse(out) ?? {});
2113
3290
  }
3291
+ /** How the container is networked when it's on no network: `host`, `slirp4netns`, `pasta`… */
3292
+ async function networkMode(id, engine) {
3293
+ const r = await docker([
3294
+ "inspect",
3295
+ "--format",
3296
+ "{{.HostConfig.NetworkMode}}",
3297
+ id
3298
+ ], { engine }).catch(() => null);
3299
+ return r?.exitCode === 0 ? r.stdout.toString("utf8").trim() || "unknown" : "unknown";
3300
+ }
2114
3301
  /**
2115
3302
  * A harness sandbox session backed by one local Docker container. Commands and file I/O go
2116
3303
  * through `docker exec`. With the egress gateway, ports are reached through its tunnel whatever
@@ -2125,6 +3312,8 @@ async function createDockerSession(options) {
2125
3312
  };
2126
3313
  const lifetime = Math.ceil((options.lifetimeMs ?? 864e5) / 1e3);
2127
3314
  const signal = options.abortSignal;
3315
+ const { engine } = options;
3316
+ const spec = engineSpec(engine);
2128
3317
  const env = {
2129
3318
  ...userEnv(options),
2130
3319
  ...options.env
@@ -2139,20 +3328,21 @@ async function createDockerSession(options) {
2139
3328
  ...Object.keys(env).flatMap((k) => ["--env", k]),
2140
3329
  "--publish",
2141
3330
  `127.0.0.1::${BRIDGE_PORT}`,
2142
- "--workdir",
2143
- SANDBOX_ROOT,
3331
+ ...spec.createsWorkdir ? ["--workdir", SANDBOX_ROOT] : [],
2144
3332
  "--entrypoint",
2145
3333
  "sleep",
2146
3334
  options.image,
2147
3335
  String(lifetime)
2148
3336
  ], {
2149
3337
  signal,
2150
- env
3338
+ env,
3339
+ engine
2151
3340
  }).catch((error) => {
2152
- if (signal?.aborted) sweepLabelDetached(`${LABEL.session}=${nonce}`);
2153
- if (/unable to find user/i.test(error.message)) {
2154
- sweepLabelDetached(`${LABEL.session}=${nonce}`);
2155
- throw new Error(`${options.image} has no ${SANDBOX_USER} user to run the sandbox as. Images reeval builds have one: rebuild it (reeval image build), or start from reeval's image or docker({ from }). An eval that needs root at run time can opt in with docker({ root: true }).`);
3341
+ const sweep = () => sweepLabelDetached(`${LABEL.session}=${nonce}`, void 0, engine);
3342
+ if (signal?.aborted) sweep();
3343
+ if (/unable to find user|no matching entries in passwd/i.test(error.message)) {
3344
+ sweep();
3345
+ throw new Error(`${options.image} has no ${SANDBOX_USER} user to run the sandbox as. Images reeval builds have one: rebuild it (reeval image build), or start from reeval's image or ${spec.fn}({ from }). An eval that needs root at run time can opt in with ${spec.fn}({ root: true }).`);
2156
3346
  }
2157
3347
  throw error;
2158
3348
  });
@@ -2160,33 +3350,57 @@ async function createDockerSession(options) {
2160
3350
  let removed;
2161
3351
  const remove = () => {
2162
3352
  gateway?.close();
2163
- removed ??= removeContainerDetached(id);
3353
+ removed ??= removeContainerDetached(id, engine);
2164
3354
  return removed;
2165
3355
  };
2166
3356
  if (signal?.aborted) {
2167
3357
  await remove();
2168
3358
  throw signal.reason;
2169
3359
  }
3360
+ if (!spec.createsWorkdir) {
3361
+ const made = await docker([
3362
+ "exec",
3363
+ "--user",
3364
+ "0:0",
3365
+ id,
3366
+ "mkdir",
3367
+ "-p",
3368
+ SANDBOX_ROOT
3369
+ ], {
3370
+ engine,
3371
+ signal
3372
+ }).catch((error) => ({
3373
+ exitCode: 1,
3374
+ stderr: error.message
3375
+ }));
3376
+ if (made.exitCode !== 0) {
3377
+ await remove();
3378
+ if (signal?.aborted) throw signal.reason;
3379
+ throw new Error(`Couldn't create ${SANDBOX_ROOT} in the container: ${made.stderr.trim()}`);
3380
+ }
3381
+ }
2170
3382
  const egressOptions = options.egress === true ? {} : options.egress || void 0;
2171
3383
  let egress;
2172
3384
  let detached = [];
2173
3385
  const attach = async (policy) => {
2174
3386
  if (isRestricted(policy) && detached.length === 0) {
2175
- detached = await networksOf(id);
3387
+ detached = await networksOf(id, engine);
3388
+ const mode = detached.length === 0 ? await networkMode(id, engine) : "none";
3389
+ if (detached.length === 0 && mode !== "none") throw new Error(`the container's network is ${mode}, which ${spec.name} can't detach it from, so a restricted policy would still have a route out`);
2176
3390
  for (const n of detached) await dockerOk([
2177
3391
  "network",
2178
3392
  "disconnect",
2179
3393
  "--force",
2180
3394
  n,
2181
3395
  id
2182
- ]);
3396
+ ], { engine });
2183
3397
  } else if (!isRestricted(policy) && detached.length > 0) {
2184
3398
  for (const n of detached) await dockerOk([
2185
3399
  "network",
2186
3400
  "connect",
2187
3401
  n,
2188
3402
  id
2189
- ]);
3403
+ ], { engine });
2190
3404
  detached = [];
2191
3405
  }
2192
3406
  };
@@ -2197,7 +3411,7 @@ async function createDockerSession(options) {
2197
3411
  gateway = await startGateway(id, {
2198
3412
  ...rest,
2199
3413
  policy
2200
- }, signal);
3414
+ }, signal, engine);
2201
3415
  egress = { active: true };
2202
3416
  } catch (error) {
2203
3417
  if (signal?.aborted || isRestricted(policy)) {
@@ -2240,14 +3454,15 @@ async function createDockerSession(options) {
2240
3454
  "sh",
2241
3455
  "-c",
2242
3456
  `for e in /proc/[0-9]*/environ; do grep -qsxzF ${shellQuote(`${EXEC_MARKER}=${marker}`)} "$e" && kill -9 "$(basename "$(dirname "$e")")" 2>/dev/null; done; true`
2243
- ]).then(() => {}, () => {});
3457
+ ], { engine }).then(() => {}, () => {});
2244
3458
  const run = async (o) => {
2245
3459
  const env = envFor(o.env);
2246
3460
  const marker = nextMarker();
2247
3461
  try {
2248
3462
  const r = await docker(execArgs(o.command, marker, o.workingDirectory, env), {
2249
3463
  env,
2250
- signal: o.abortSignal
3464
+ signal: o.abortSignal,
3465
+ engine
2251
3466
  });
2252
3467
  return {
2253
3468
  exitCode: r.exitCode,
@@ -2266,7 +3481,10 @@ async function createDockerSession(options) {
2266
3481
  "cat",
2267
3482
  "--",
2268
3483
  posix.resolve(SANDBOX_ROOT, o.path)
2269
- ], { signal: o.abortSignal });
3484
+ ], {
3485
+ signal: o.abortSignal,
3486
+ engine
3487
+ });
2270
3488
  return r.exitCode === 0 ? new Uint8Array(r.stdout) : null;
2271
3489
  };
2272
3490
  const writeBinaryFile = async (o) => {
@@ -2280,7 +3498,8 @@ async function createDockerSession(options) {
2280
3498
  `mkdir -p ${shellQuote(posix.dirname(path))} && cat > ${shellQuote(path)}`
2281
3499
  ], {
2282
3500
  input: Buffer.from(o.content),
2283
- signal: o.abortSignal
3501
+ signal: o.abortSignal,
3502
+ engine
2284
3503
  });
2285
3504
  };
2286
3505
  const brokering = gateway ? {
@@ -2303,7 +3522,7 @@ async function createDockerSession(options) {
2303
3522
  } : {};
2304
3523
  const session = {
2305
3524
  id,
2306
- description: `Docker container ${id.slice(0, 12)} (${options.image})`,
3525
+ description: `${spec.name} container ${id.slice(0, 12)} (${options.image})`,
2307
3526
  defaultWorkingDirectory: SANDBOX_ROOT,
2308
3527
  ports: [BRIDGE_PORT],
2309
3528
  get egress() {
@@ -2315,29 +3534,31 @@ async function createDockerSession(options) {
2315
3534
  },
2316
3535
  ...brokering,
2317
3536
  ...substituting,
3537
+ oomKills: () => oomKills(id, engine),
2318
3538
  run,
2319
3539
  async spawn(o) {
2320
3540
  const env = envFor(o.env);
2321
3541
  const marker = nextMarker();
2322
3542
  const args = execArgs(o.command, marker, o.workingDirectory, env);
2323
3543
  const startedAt = Date.now();
2324
- const child = spawn("docker", args, {
3544
+ const child = spawn(spec.bin, args, {
2325
3545
  stdio: [
2326
3546
  "ignore",
2327
3547
  "pipe",
2328
3548
  "pipe"
2329
3549
  ],
2330
3550
  detached: true,
2331
- env: env ? {
3551
+ env: {
2332
3552
  ...process.env,
3553
+ ...engineEnv(engine),
2333
3554
  ...env
2334
- } : process.env
3555
+ }
2335
3556
  });
2336
3557
  const exited = new Promise((resolve) => child.on("close", (code) => {
2337
3558
  traceDocker(args, startedAt, {
2338
3559
  exitCode: code,
2339
3560
  stdout: "<streamed>"
2340
- });
3561
+ }, spec.bin);
2341
3562
  resolve({ exitCode: code ?? 1 });
2342
3563
  }));
2343
3564
  const kill = async () => {
@@ -2386,10 +3607,10 @@ async function createDockerSession(options) {
2386
3607
  "port",
2387
3608
  id,
2388
3609
  `${port}/tcp`
2389
- ]);
3610
+ ], { engine });
2390
3611
  const hostPort = mapped.stdout.toString("utf8").split("\n")[0]?.split(":").at(-1);
2391
3612
  if (mapped.exitCode !== 0 || !hostPort) {
2392
- const reason = mapped.stderr.trim() || "Docker reports no host port for it";
3613
+ const reason = mapped.stderr.trim() || `${spec.name} reports no host port for it`;
2393
3614
  throw new Error(`Port ${port} of ${id.slice(0, 12)} isn't reachable: ${reason}`);
2394
3615
  }
2395
3616
  return { url: `${scheme}://127.0.0.1:${hostPort}` };
@@ -2420,7 +3641,7 @@ async function createDockerSession(options) {
2420
3641
  /** The session as an AI SDK harness sandbox provider. */
2421
3642
  const dockerSandboxProvider = (options) => ({
2422
3643
  specificationVersion: "harness-sandbox-v1",
2423
- providerId: "reeval-docker",
3644
+ providerId: options.engine === "podman" ? "reeval-podman" : "reeval-docker",
2424
3645
  async createSession(o) {
2425
3646
  const session = await createDockerSession({
2426
3647
  ...options,
@@ -2433,7 +3654,7 @@ const dockerSandboxProvider = (options) => ({
2433
3654
  //#endregion
2434
3655
  //#region ../sandbox-docker/src/build-image.ts
2435
3656
  const PNPM_VERSION = "10.33.3";
2436
- /** npm before 11.6 (node:22 ships 10.9) can crash on circular peer sets (npm/cli#8261); the same as docker/Dockerfile's. */
3657
+ /** npm before 11.6 (node:22 ships 10.9) can crash on circular peer sets (npm/cli#8261). */
2437
3658
  const NPM_VERSION = "11.20.0";
2438
3659
  const sha256 = (text) => createHash("sha256").update(text).digest("hex");
2439
3660
  const slugify = (text, max) => text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, max).replace(/-+$/, "");
@@ -2453,22 +3674,22 @@ const BOOTSTRAPS = {
2453
3674
  name: "Cursor",
2454
3675
  cli: "@cursor/sdk",
2455
3676
  version: `node -p "'@cursor/sdk ' + require(process.env.HOME + '/.ai-sdk-harness/.harness-bootstrap/cursor-sdk/node_modules/@cursor/sdk/package.json').version"`,
2456
- adapter: async () => (await import("./src-BT5pwco0.js")).createCursorSdk()
3677
+ adapter: async () => (await import("./src-DTbrY1hi.js")).createCursorSdk()
2457
3678
  },
2458
3679
  "claude-code": {
2459
3680
  name: "Claude Code",
2460
3681
  cli: "claude",
2461
- adapter: async () => (await import("./dist-CTzThfu_.js")).createClaudeCode()
3682
+ adapter: async () => (await import("./dist-B8hJImYt.js")).createClaudeCode()
2462
3683
  },
2463
3684
  antigravity: {
2464
3685
  name: "Antigravity",
2465
3686
  cli: "agy",
2466
- adapter: async () => (await import("./src-DdRlaiRc.js")).createAntigravity()
3687
+ adapter: async () => (await import("./src-DNnG4e4R.js")).createAntigravity()
2467
3688
  },
2468
3689
  opencode: {
2469
3690
  name: "OpenCode",
2470
3691
  cli: "opencode",
2471
- adapter: async () => (await import("./src-BHNiP-5A.js")).createOpenCode({
3692
+ adapter: async () => (await import("./src-ofUaYbuY.js")).createOpenCode({
2472
3693
  auth: { GOOGLE_GENERATIVE_AI_API_KEY: "unused" },
2473
3694
  model: "google/unused"
2474
3695
  })
@@ -2476,7 +3697,7 @@ const BOOTSTRAPS = {
2476
3697
  goose: {
2477
3698
  name: "Goose",
2478
3699
  cli: "goose",
2479
- adapter: async () => (await import("./src-BrMbt1B2.js")).createGoose({
3700
+ adapter: async () => (await import("./src-DdyJEh2v.js")).createGoose({
2480
3701
  auth: { GOOGLE_API_KEY: "unused" },
2481
3702
  model: "unused"
2482
3703
  })
@@ -2484,12 +3705,28 @@ const BOOTSTRAPS = {
2484
3705
  pi: {
2485
3706
  name: "pi",
2486
3707
  cli: "pi",
2487
- adapter: async () => (await import("./src-D13vpMh0.js")).createPi({ auth: { GEMINI_API_KEY: "unused" } })
3708
+ adapter: async () => (await import("./src-jzagbuqH.js")).createPi({ auth: { GEMINI_API_KEY: "unused" } })
2488
3709
  },
2489
3710
  codex: {
2490
3711
  name: "Codex",
2491
3712
  cli: "codex",
2492
- adapter: async () => (await import("./src-xczuQbE6.js")).createCodex({ auth: { OPENAI_API_KEY: "unused" } })
3713
+ adapter: async () => (await import("./src-Dj9PAroc.js")).createCodex({ auth: { OPENAI_API_KEY: "unused" } })
3714
+ },
3715
+ fx: {
3716
+ name: "fx",
3717
+ cli: "fx",
3718
+ adapter: async () => (await import("./src-C_lPtowT.js")).createFx({
3719
+ auth: { AI_GATEWAY_API_KEY: "unused" },
3720
+ model: "unused/unused"
3721
+ })
3722
+ },
3723
+ "grok-build": {
3724
+ name: "Grok Build",
3725
+ cli: "grok",
3726
+ adapter: async () => (await import("./src-Du8H85Qq.js")).createGrokBuild({
3727
+ auth: { XAI_API_KEY: "unused" },
3728
+ model: "unused"
3729
+ })
2493
3730
  }
2494
3731
  };
2495
3732
  /** Keeps the image's `PATH` in login shells, which Debian's `/etc/profile` resets. */
@@ -2521,10 +3758,10 @@ WORKDIR ${SANDBOX_ROOT}/${WORKSPACE_DIR}
2521
3758
  `;
2522
3759
  const tail = (text) => text.trim().split("\n").slice(-15).join("\n");
2523
3760
  const clipLine = (text, max = 300) => text.length > max ? `${text.slice(0, max - 1)}…` : text;
2524
- /** Why a `docker build` failed, in a line: the failing step's exit, or BuildKit's own error. */
2525
- function buildReason(error) {
2526
- if (!error) return "docker build failed";
2527
- const exit = /^process ".*" did not complete successfully: exit code: (\d+)$/s.exec(error);
3761
+ /** Why a `docker build` failed, in a line: the failing step's exit, or BuildKit's (or buildah's) own error. */
3762
+ function buildReason(error, engine) {
3763
+ if (!error) return `${engineSpec(engine).bin} build failed`;
3764
+ const exit = /^process ".*" did not complete successfully: exit code: (\d+)$/s.exec(error) ?? /^while running runtime: exit status (\d+)$/.exec(error);
2528
3765
  return exit ? `a RUN step exited ${exit[1]}` : clipLine(error.replace(/\s+/g, " "));
2529
3766
  }
2530
3767
  /**
@@ -2536,12 +3773,13 @@ function buildError(output, what, reason, keep = () => true) {
2536
3773
  const text = [parsed.error ?? "", ...parsed.output].join("\n");
2537
3774
  const cause = failureCause(text, parsed.exitCode);
2538
3775
  parsed.output = parsed.output.filter(keep);
2539
- const why = reason?.(parsed) ?? buildReason(parsed.error);
3776
+ const why = reason?.(parsed) ?? buildReason(parsed.error, what.engine);
2540
3777
  return new ImageBuildError(failureMessage({
2541
3778
  headline: `${what.headline} failed: ${why}`,
2542
3779
  cause,
2543
3780
  output: parsed.output,
2544
- log: what.log ?? null
3781
+ log: what.log ?? null,
3782
+ ...what.engine ? { engine: what.engine } : {}
2545
3783
  }), {
2546
3784
  stage: what.stage,
2547
3785
  ref: what.ref,
@@ -2556,12 +3794,12 @@ const BUILT_BY = ["--label", `${LABEL.managed}=image`];
2556
3794
  * Removes the images reeval built that nothing tags any more (a rebuild's old image) and the
2557
3795
  * intermediate `-base` tags of `from` builds. Returns how many it removed.
2558
3796
  */
2559
- async function pruneImages() {
3797
+ async function pruneImages(engine) {
2560
3798
  const list = async (args) => (await docker([
2561
3799
  "image",
2562
3800
  "ls",
2563
3801
  ...args
2564
- ])).stdout.toString("utf8").split("\n").map((l) => l.trim()).filter(Boolean);
3802
+ ], { engine })).stdout.toString("utf8").split("\n").map((l) => l.trim()).filter(Boolean);
2565
3803
  const dangling = [...await list([
2566
3804
  "-q",
2567
3805
  "--filter",
@@ -2585,46 +3823,93 @@ async function pruneImages() {
2585
3823
  "image",
2586
3824
  "rm",
2587
3825
  ref
2588
- ]).catch(() => null))?.exitCode === 0) removed++;
3826
+ ], { engine }).catch(() => null))?.exitCode === 0) removed++;
2589
3827
  return removed;
2590
3828
  }
3829
+ /** Docker's names for Node's architectures, as image indexes list platforms. */
3830
+ const OCI_ARCH = {
3831
+ x64: "amd64",
3832
+ arm64: "arm64",
3833
+ arm: "arm",
3834
+ ppc64: "ppc64le"
3835
+ };
3836
+ /**
3837
+ * A registry digest for `from` without Docker's buildx: skopeo's, which is the same digest
3838
+ * buildx gives, or else this platform's manifest from `podman manifest inspect`.
3839
+ */
3840
+ async function podmanRemoteDigest(from, signal) {
3841
+ const skopeo = await run("skopeo", [
3842
+ "inspect",
3843
+ "--format",
3844
+ "{{.Digest}}",
3845
+ `docker://${from}`
3846
+ ], { ...signal ? { signal } : {} }).catch(() => null);
3847
+ const digest = skopeo?.exitCode === 0 ? skopeo.stdout.trim() : "";
3848
+ if (digest.startsWith("sha256:")) return { digest };
3849
+ const r = await docker([
3850
+ "manifest",
3851
+ "inspect",
3852
+ from
3853
+ ], {
3854
+ signal,
3855
+ engine: "podman"
3856
+ }).catch(() => null);
3857
+ if (r?.exitCode === 0) {
3858
+ const manifest = JSON.parse(r.stdout.toString("utf8"));
3859
+ const arch = OCI_ARCH[process.arch] ?? process.arch;
3860
+ const own = manifest.manifests?.find((m) => m.platform?.os === "linux" && m.platform.architecture === arch)?.digest;
3861
+ if (own?.startsWith("sha256:")) return { digest: own };
3862
+ }
3863
+ return { error: (r?.stderr.trim() || skopeo?.stderr.trim() || "").replace(/^(?:Error|time="[^"]*" level=fatal msg=): ?/, "").replace(/\s+/g, " ") || `${from} doesn't resolve` };
3864
+ }
2591
3865
  /**
2592
3866
  * What a `from` names now, without pulling: its registry digest, or for an image that's only
2593
3867
  * local, its id (`local`). `error` when neither resolves, e.g. a typo or no network.
2594
3868
  */
2595
- async function resolveFrom(from, signal) {
3869
+ async function resolveFrom(from, signal, engine) {
2596
3870
  const pinned = /@(sha256:[0-9a-f]{64})$/.exec(from)?.[1];
2597
3871
  if (pinned) return {
2598
3872
  digest: pinned,
2599
3873
  local: false
2600
3874
  };
2601
- const remote = await docker([
2602
- "buildx",
2603
- "imagetools",
2604
- "inspect",
2605
- "--format",
2606
- "{{json .Manifest.Digest}}",
2607
- from
2608
- ], { signal }).catch(() => null);
2609
- const digest = remote?.exitCode === 0 ? JSON.parse(remote.stdout.toString("utf8").trim()) : null;
2610
- if (typeof digest === "string" && digest.startsWith("sha256:")) return {
2611
- digest,
2612
- local: false
2613
- };
2614
- const local = await imageInfo(from);
3875
+ let error = null;
3876
+ if (engine === "podman") {
3877
+ const remote = await podmanRemoteDigest(from, signal);
3878
+ if ("digest" in remote) return {
3879
+ digest: remote.digest,
3880
+ local: false
3881
+ };
3882
+ error = remote.error;
3883
+ } else {
3884
+ const remote = await docker([
3885
+ "buildx",
3886
+ "imagetools",
3887
+ "inspect",
3888
+ "--format",
3889
+ "{{json .Manifest.Digest}}",
3890
+ from
3891
+ ], { signal }).catch(() => null);
3892
+ const digest = remote?.exitCode === 0 ? JSON.parse(remote.stdout.toString("utf8").trim()) : null;
3893
+ if (typeof digest === "string" && digest.startsWith("sha256:")) return {
3894
+ digest,
3895
+ local: false
3896
+ };
3897
+ error = remote?.stderr.trim().replace(/^ERROR: /, "").replace(/\s+/g, " ") || null;
3898
+ }
3899
+ const local = await imageInfo(from, engine).catch(() => null);
2615
3900
  if (local) return {
2616
3901
  digest: local.id,
2617
3902
  local: true
2618
3903
  };
2619
- return { error: remote?.stderr.trim().replace(/^ERROR: /, "").replace(/\s+/g, " ") || `${from} doesn't resolve` };
3904
+ return { error: error || `${from} doesn't resolve` };
2620
3905
  }
2621
3906
  /** Removes a tag or an image reeval replaced, unless something still uses it. */
2622
- const removeQuietly = async (ref) => {
3907
+ const removeQuietly = async (ref, engine) => {
2623
3908
  await docker([
2624
3909
  "image",
2625
3910
  "rm",
2626
3911
  ref
2627
- ]).catch(() => {});
3912
+ ], { engine }).catch(() => {});
2628
3913
  };
2629
3914
  /** The hash of reeval's base image build context, which its images carry as a label. */
2630
3915
  function contextHash() {
@@ -2644,14 +3929,14 @@ function contextHash() {
2644
3929
  * intermediate `-base` tag of a `from` build, are removed once the new one is committed.
2645
3930
  */
2646
3931
  async function buildImage(log, options) {
2647
- const { harness, from, signal } = options;
2648
- const resolved = from ? await resolveFrom(from, signal) : null;
3932
+ const { harness, from, signal, engine } = options;
3933
+ const resolved = from ? await resolveFrom(from, signal, engine) : null;
2649
3934
  const digest = resolved && "digest" in resolved ? resolved.digest : null;
2650
3935
  const pinned = from && digest && resolved && "local" in resolved && !resolved.local && !from.includes("@") ? `${from}@${digest}` : from;
2651
3936
  const bootstrap = BOOTSTRAPS[harness];
2652
3937
  const base = from ? `${harnessImageFor(harness, from)}-base` : BASE_IMAGE;
2653
3938
  const target = from ? harnessImageFor(harness, from) : imageFor(harness);
2654
- const previous = [(await imageInfo(target))?.id, from ? null : (await imageInfo(base))?.id];
3939
+ const previous = [(await imageInfo(target, engine))?.id, from ? null : (await imageInfo(base, engine))?.id];
2655
3940
  log(`Building ${base}${from ? ` from ${from}` : ""}`);
2656
3941
  const build = from ? await docker([
2657
3942
  "build",
@@ -2664,29 +3949,39 @@ async function buildImage(log, options) {
2664
3949
  "-"
2665
3950
  ], {
2666
3951
  input: toolchainDockerfile(pinned ?? from),
2667
- signal
3952
+ signal,
3953
+ engine
2668
3954
  }) : await docker([
2669
3955
  "build",
2670
3956
  "--progress",
2671
3957
  "plain",
2672
3958
  ...BUILT_BY,
3959
+ "--build-arg",
3960
+ `NPM_VERSION=${NPM_VERSION}`,
3961
+ "--build-arg",
3962
+ `PNPM_VERSION=${PNPM_VERSION}`,
2673
3963
  "--tag",
2674
3964
  base,
2675
3965
  DOCKER_CONTEXT
2676
- ], { signal });
3966
+ ], {
3967
+ signal,
3968
+ engine
3969
+ });
2677
3970
  const output = `${build.stdout.toString("utf8")}${build.stderr}`;
2678
3971
  options.output?.write(output);
2679
3972
  if (build.exitCode !== 0) throw buildError(output, {
2680
3973
  stage: from ? "from" : "harness",
2681
3974
  ref: target,
2682
3975
  headline: from ? `Building the toolchain layer FROM ${from}` : "Building reeval's base image",
2683
- log: options.output?.path ?? null
3976
+ log: options.output?.path ?? null,
3977
+ engine
2684
3978
  }, (parsed) => parsed.output.find((l) => l.startsWith("reeval needs a Debian")) ?? null);
2685
3979
  log(`Installing the ${bootstrap.name} harness bootstrap`);
2686
3980
  const session = await createDockerSession({
2687
3981
  image: base,
2688
3982
  lifetimeMs: 18e5,
2689
- ...signal ? { abortSignal: signal } : {}
3983
+ ...signal ? { abortSignal: signal } : {},
3984
+ ...engine ? { engine } : {}
2690
3985
  });
2691
3986
  let agentVersion;
2692
3987
  try {
@@ -2706,7 +4001,7 @@ async function buildImage(log, options) {
2706
4001
  "CMD [\"bash\"]",
2707
4002
  session.id,
2708
4003
  target
2709
- ]);
4004
+ ], { engine });
2710
4005
  } catch (error) {
2711
4006
  if (signal?.aborted || error instanceof ImageBuildError) throw error;
2712
4007
  const [first = "", ...rest] = error.message.split("\n");
@@ -2716,7 +4011,8 @@ async function buildImage(log, options) {
2716
4011
  headline: `Baking the ${bootstrap.name} CLI onto ${from ?? "reeval-sandbox-base:latest"} failed: ${clipLine(first)}`,
2717
4012
  cause,
2718
4013
  output: outputTail(rest.join("\n")),
2719
- log: options.output?.path ?? null
4014
+ log: options.output?.path ?? null,
4015
+ ...engine ? { engine } : {}
2720
4016
  }), {
2721
4017
  stage: "harness",
2722
4018
  ref: target,
@@ -2727,9 +4023,9 @@ async function buildImage(log, options) {
2727
4023
  } finally {
2728
4024
  await session.destroy();
2729
4025
  }
2730
- if (from) await removeQuietly(base);
2731
- const now = (await imageInfo(target))?.id;
2732
- for (const id of previous) if (id && id !== now) await removeQuietly(id);
4026
+ if (from) await removeQuietly(base, engine);
4027
+ const now = (await imageInfo(target, engine))?.id;
4028
+ for (const id of previous) if (id && id !== now) await removeQuietly(id, engine);
2733
4029
  return {
2734
4030
  image: target,
2735
4031
  agentVersion
@@ -2772,15 +4068,18 @@ function installScript(steps) {
2772
4068
  }
2773
4069
  /** Builds the install layer if it's missing. `output` gets the build's output, for a log file. */
2774
4070
  async function buildInstallLayer(parent, steps, options = {}) {
2775
- const { signal } = options;
4071
+ const { signal, engine } = options;
2776
4072
  const tag = installLayerTag(parent, steps);
2777
4073
  if ((await docker([
2778
4074
  "image",
2779
4075
  "inspect",
2780
4076
  "--format",
2781
- "{{.Id}}",
4077
+ "{{.Created}}",
2782
4078
  tag
2783
- ], { signal })).exitCode === 0) return tag;
4079
+ ], {
4080
+ signal,
4081
+ engine
4082
+ })).exitCode === 0) return tag;
2784
4083
  const script = installScript(steps);
2785
4084
  const encoded = Buffer.from(script).toString("base64");
2786
4085
  const home = `$(getent passwd ${SANDBOX_USER} | cut -d: -f6)`;
@@ -2803,7 +4102,8 @@ async function buildInstallLayer(parent, steps, options = {}) {
2803
4102
  "-"
2804
4103
  ], {
2805
4104
  input: dockerfile,
2806
- signal
4105
+ signal,
4106
+ engine
2807
4107
  });
2808
4108
  const output = `${build.stdout.toString("utf8")}${build.stderr}`;
2809
4109
  options.output?.write(`${script}\n${dockerfile}\n\n${output}`);
@@ -2813,7 +4113,8 @@ async function buildInstallLayer(parent, steps, options = {}) {
2813
4113
  stage: "install",
2814
4114
  ref: tag,
2815
4115
  headline: `Building the install layer (${`${steps.length} command${steps.length === 1 ? "" : "s"}`})`,
2816
- log: options.output?.path ?? null
4116
+ log: options.output?.path ?? null,
4117
+ engine
2817
4118
  }, () => failed ? `install ${failed[1]} exited ${failed[2]}: ${clipLine(failed[3] ?? "")}` : null, (line) => !line.startsWith("reeval: install "));
2818
4119
  }
2819
4120
  return tag;
@@ -2873,16 +4174,16 @@ function contextFiles(context, dockerfile) {
2873
4174
  return files.sort();
2874
4175
  }
2875
4176
  /** Whether the Dockerfile starts from reeval's sandbox image, which then has to exist first. */
2876
- const usesEsBase = (dockerfile) => new RegExp(`\\$\\{?${REEVAL_BASE_ARG}\\b`).test(readFileSync(dockerfile, "utf8"));
4177
+ const usesReevalBase = (dockerfile) => new RegExp(`\\$\\{?${REEVAL_BASE_ARG}\\b`).test(readFileSync(dockerfile, "utf8"));
2877
4178
  /**
2878
4179
  * The tag of a `docker({ dockerfile })` build for a harness: a hash of the Dockerfile, every file
2879
4180
  * of its build context (its directory, less `.dockerignore`) and, for a Dockerfile `FROM
2880
4181
  * ${REEVAL_BASE}`, the id of the harness's image it names, so an edit to any of them, or a rebuilt reeval
2881
- * image, builds anew. `esBase` is that id (null when it isn't built).
4182
+ * image, builds anew. `reevalBase` is that id (null when it isn't built).
2882
4183
  */
2883
- function dockerfileTag(dockerfile, harness, esBase = null) {
4184
+ function dockerfileTag(dockerfile, harness, reevalBase = null) {
2884
4185
  const context = dirname(dockerfile);
2885
- const base = usesEsBase(dockerfile) ? `${imageFor(harness)}@${esBase ?? "unbuilt"}` : "";
4186
+ const base = usesReevalBase(dockerfile) ? `${imageFor(harness)}@${reevalBase ?? "unbuilt"}` : "";
2886
4187
  const hash = createHash("sha256").update(`${REEVAL_BASE_ARG}=${base}\0`);
2887
4188
  for (const path of contextFiles(context, dockerfile)) {
2888
4189
  const full = join(context, path);
@@ -2899,14 +4200,14 @@ function dockerfileTag(dockerfile, harness, esBase = null) {
2899
4200
  }
2900
4201
  /**
2901
4202
  * Builds the user's Dockerfile with plain `docker build` (so Docker's layer cache applies), from
2902
- * its directory, with `REEVAL_BASE` set to the harness's sandbox image (whose id is `esBase`).
4203
+ * its directory, with `REEVAL_BASE` set to the harness's sandbox image (whose id is `reevalBase`).
2903
4204
  * Rebuilds even when the tag exists with `force`, as `reeval image build` does, and then removes the
2904
4205
  * image the tag pointed at before. `name` is the path failures name.
2905
4206
  */
2906
4207
  async function buildDockerfile(dockerfile, options) {
2907
- const { harness, signal } = options;
2908
- const { tag } = dockerfileTag(dockerfile, harness, options.esBase ?? null);
2909
- const previous = (await imageInfo(tag))?.id;
4208
+ const { harness, signal, engine } = options;
4209
+ const { tag } = dockerfileTag(dockerfile, harness, options.reevalBase ?? null);
4210
+ const previous = (await imageInfo(tag, engine))?.id;
2910
4211
  if (previous && !options.force) return tag;
2911
4212
  const build = await docker([
2912
4213
  "build",
@@ -2921,20 +4222,24 @@ async function buildDockerfile(dockerfile, options) {
2921
4222
  "--tag",
2922
4223
  tag,
2923
4224
  dirname(dockerfile)
2924
- ], { signal });
4225
+ ], {
4226
+ signal,
4227
+ engine
4228
+ });
2925
4229
  const output = `${build.stdout.toString("utf8")}${build.stderr}`;
2926
4230
  options.output?.write(output);
2927
4231
  if (build.exitCode !== 0) throw buildError(output, {
2928
4232
  stage: "dockerfile",
2929
4233
  ref: tag,
2930
4234
  headline: `Building ${options.name ?? dockerfile}`,
2931
- log: options.output?.path ?? null
4235
+ log: options.output?.path ?? null,
4236
+ engine
2932
4237
  });
2933
- const now = (await imageInfo(tag))?.id;
2934
- if (previous && previous !== now) await removeQuietly(previous);
4238
+ const now = (await imageInfo(tag, engine))?.id;
4239
+ if (previous && previous !== now) await removeQuietly(previous, engine);
2935
4240
  return tag;
2936
4241
  }
2937
4242
  //#endregion
2938
- export { onDockerCommand as $, hostAllowed as A, WORKSPACE_DIR as B, applyTransformations as C, HARNESS_HOSTS as D, DOCKER_EGRESS as E, HARNESS_PACKAGES as F, docker as G, harnessLabel as H, LABEL as I, dockerOk as J, dockerAvailable as K, SANDBOX_HOME as L, BASE_IMAGE as M, BRIDGE_PORT as N, PACKAGE_HOSTS as O, DEFAULT_IMAGE as P, removeContainerDetached as Q, SANDBOX_ROOT as R, placeholder as S, onEndpoint as T, imageFor as U, adapterVersion as V, isBakedHarness as W, imageInfo as X, dockerState as Y, isRegistryDigest as Z, ROOT_CAPABILITIES as _, buildInstallLayer as a, failureCause as at, CA_PATH as b, dockerfileTag as c, retryTransient as ct, installLayerTag as d, run as et, installScript as f, DEFAULT_LIMITS as g, usesEsBase as h, buildImage as i, causeLine as it, BAKED_HARNESSES as j, defaultAllowedHosts as k, dockerignoreMatcher as l, resolveFrom as m, REEVAL_BASE_ARG as n, ImageBuildError as nt, contextFiles as o, isTransient as ot, pruneImages as p, dockerCapacity as q, buildDockerfile as r, RETRY_DELAYS as rt, contextHash as s, parseBuildOutput as st, DOCKER_CONTEXT as t, shellQuote as tt, harnessImageFor as u, createDockerSession as v, matches as w, PROXY_PORT as x, dockerSandboxProvider as y, SANDBOX_USER as z };
4243
+ export { removeContainerDetached as $, hostAllowed as A, WORKSPACE_DIR as B, applyTransformations as C, HARNESS_HOSTS as D, DOCKER_EGRESS as E, HARNESS_PACKAGES as F, docker as G, harnessLabel as H, LABEL as I, dockerOk as J, dockerAvailable as K, SANDBOX_HOME as L, BASE_IMAGE as M, BRIDGE_PORT as N, PACKAGE_HOSTS as O, DEFAULT_IMAGE as P, isRegistryDigest as Q, SANDBOX_ROOT as R, placeholder as S, onEndpoint as T, imageFor as U, adapterVersion as V, isBakedHarness as W, imageInfo as X, dockerState as Y, imageTags as Z, ROOT_CAPABILITIES as _, buildInstallLayer as a, isTransient as at, CA_PATH as b, dockerfileTag as c, ENGINES as ct, installLayerTag as d, normalizeImageId as dt, onDockerCommand as et, installScript as f, DEFAULT_LIMITS as g, usesReevalBase as h, buildImage as i, failureCause as it, BAKED_HARNESSES as j, defaultAllowedHosts as k, dockerignoreMatcher as l, dockerSeccompFile as lt, resolveFrom as m, REEVAL_BASE_ARG as n, RETRY_DELAYS as nt, contextFiles as o, parseBuildOutput as ot, pruneImages as p, dockerCapacity as q, buildDockerfile as r, causeLine as rt, contextHash as s, retryTransient as st, DOCKER_CONTEXT as t, ImageBuildError as tt, harnessImageFor as u, engineSpec as ut, createDockerSession as v, matches as w, PROXY_PORT as x, dockerSandboxProvider as y, SANDBOX_USER as z };
2939
4244
 
2940
- //# sourceMappingURL=src-TdJuDYqB.js.map
4245
+ //# sourceMappingURL=src-B7treWa8.js.map