reeval 0.9.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 (318) hide show
  1. package/README.md +42 -30
  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-6FefIhX7.js → agent-CURAwx_q.js} +6 -6
  8. package/dist/{agent-6FefIhX7.js.map → agent-CURAwx_q.js.map} +1 -1
  9. package/dist/{agent-WSmTaesf.js → agent-CaS_2Sce.js} +46 -15
  10. package/dist/agent-CaS_2Sce.js.map +1 -0
  11. package/dist/{analysis-DlGBDjTj.js → analysis-Bxub9LMT.js} +4 -4
  12. package/dist/{analysis-DlGBDjTj.js.map → analysis-Bxub9LMT.js.map} +1 -1
  13. package/dist/{assemble-BCZzTyR7.js → assemble-B9Alds-z.js} +69 -41
  14. package/dist/assemble-B9Alds-z.js.map +1 -0
  15. package/dist/assemble-J5MukZFY.js +1 -0
  16. package/dist/{client-Bbo9SPlK.js → assert-EUIoRdIt.js} +10 -113
  17. package/dist/assert-EUIoRdIt.js.map +1 -0
  18. package/dist/bridge/index.mjs +248 -55
  19. package/dist/{capture-Bp74Z6Fr.js → capture-CNb9SuU5.js} +145 -31
  20. package/dist/capture-CNb9SuU5.js.map +1 -0
  21. package/dist/capture-jquXZBKK.js +1 -0
  22. package/dist/{cli-CVrMh_qz.js → cli-D303Vj5N.js} +133 -115
  23. package/dist/cli-D303Vj5N.js.map +1 -0
  24. package/dist/{cli-spec-CKEYa8V2.js → cli-spec-BPZbQG2p.js} +36 -17
  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-CzIFp1JQ.js → command-BLfT7vnQ.js} +18 -17
  31. package/dist/command-BLfT7vnQ.js.map +1 -0
  32. package/dist/{command-C5xFPKHM.js → command-BT9a37ZR.js} +374 -72
  33. package/dist/command-BT9a37ZR.js.map +1 -0
  34. package/dist/{command-DUT5l13I.js → command-Bge8F7Ko.js} +316 -83
  35. package/dist/command-Bge8F7Ko.js.map +1 -0
  36. package/dist/command-BkFjijN2.js +1 -0
  37. package/dist/{command-BFP0hKEb.js → command-CMJtHKRa.js} +14 -14
  38. package/dist/{command-BFP0hKEb.js.map → command-CMJtHKRa.js.map} +1 -1
  39. package/dist/commands-1p-bIWhN.js +1 -0
  40. package/dist/{commands-CLmPBrTS.js → commands-BFx16WB8.js} +7 -7
  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-DbSMEVKs.js → context-C1mxXh80.js} +11 -3
  45. package/dist/context-C1mxXh80.js.map +1 -0
  46. package/dist/{db-CfQFwJtq.js → db-CdHizc4_.js} +455 -36
  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-CRQGQbIt.js → docker-7b_2SaH7.js} +22 -21
  53. package/dist/docker-7b_2SaH7.js.map +1 -0
  54. package/dist/{docker-DV2GNgle.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-DlKycx5H.js → doctor-BYNok4UO.js} +262 -83
  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-BhzNh7Yi.js → egress-C4PZTSSe.js} +146 -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/files-BAt0i00X.js +1 -0
  73. package/dist/{files-CSzVADHn.js → files-BXUdY8tr.js} +9 -8
  74. package/dist/{files-CSzVADHn.js.map → files-BXUdY8tr.js.map} +1 -1
  75. package/dist/files-BhyltlDB.js +1 -0
  76. package/dist/files-Bk1mC3AN.js +43 -0
  77. package/dist/files-Bk1mC3AN.js.map +1 -0
  78. package/dist/{files-DJUFg-4e.js → files-DQmHE7pb.js} +5 -5
  79. package/dist/{files-DJUFg-4e.js.map → files-DQmHE7pb.js.map} +1 -1
  80. package/dist/files-ZZPqfAo6.js +1 -0
  81. package/dist/harness-B8QC9u0O.js +323 -0
  82. package/dist/harness-B8QC9u0O.js.map +1 -0
  83. package/dist/harness.d.ts +16 -30
  84. package/dist/harness.js +1 -2
  85. package/dist/{header-CALhmafp.js → header-hK-Z_Po9.js} +2 -2
  86. package/dist/{header-CALhmafp.js.map → header-hK-Z_Po9.js.map} +1 -1
  87. package/dist/{images-BMgdpMAX.js → images-0On0cztu.js} +114 -45
  88. package/dist/images-0On0cztu.js.map +1 -0
  89. package/dist/index.d.ts +9 -37
  90. package/dist/index.js +6 -2138
  91. package/dist/{init-BIdLF0F9.js → init-B77Rpcqc.js} +26 -8
  92. package/dist/init-B77Rpcqc.js.map +1 -0
  93. package/dist/init-BrOWin3W.js +1 -0
  94. package/dist/{invocations-CLaL8AuW.js → invocations-DbGfBAA_.js} +4 -4
  95. package/dist/{invocations-CLaL8AuW.js.map → invocations-DbGfBAA_.js.map} +1 -1
  96. package/dist/{judge-CeYPN8P_.js → judge-DW_GDOmB.js} +11 -19
  97. package/dist/{judge-CeYPN8P_.js.map → judge-DW_GDOmB.js.map} +1 -1
  98. package/dist/judge.d.ts +2 -2
  99. package/dist/judge.js +1 -1
  100. package/dist/{live-S0qODb6o.js → live-jlfszAbb.js} +9 -20
  101. package/dist/live-jlfszAbb.js.map +1 -0
  102. package/dist/matchers-Ddmc2z7H.js +118 -0
  103. package/dist/matchers-Ddmc2z7H.js.map +1 -0
  104. package/dist/{model-DEQo3FkZ.js → model-DaVCY3rb.js} +2 -2
  105. package/dist/{model-DEQo3FkZ.js.map → model-DaVCY3rb.js.map} +1 -1
  106. package/dist/model-NM3ID0uR.js +1 -0
  107. package/dist/{model-B1BZoZ9b.js → model-h_cDtcRr.js} +18 -17
  108. package/dist/model-h_cDtcRr.js.map +1 -0
  109. package/dist/model-nwWJvaUR.js +1 -0
  110. package/dist/{model-BOnlAPzs.js → model-oqcDplJG.js} +111 -19
  111. package/dist/model-oqcDplJG.js.map +1 -0
  112. package/dist/{node-Co7EXge0.js → node-B3ydHo6t.js} +10 -47
  113. package/dist/node-B3ydHo6t.js.map +1 -0
  114. package/dist/object-CLf2-tNq.js +9 -0
  115. package/dist/object-CLf2-tNq.js.map +1 -0
  116. package/dist/{opencode-providers-ByD85Q0l.js → opencode-providers-J9colP0-.js} +96 -21
  117. package/dist/opencode-providers-J9colP0-.js.map +1 -0
  118. package/dist/options-Bh2W63dK.js +1119 -0
  119. package/dist/options-Bh2W63dK.js.map +1 -0
  120. package/dist/{pairs-DDsjgm5F.js → pairs-CnInRu-G.js} +76 -2
  121. package/dist/{pairs-DDsjgm5F.js.map → pairs-CnInRu-G.js.map} +1 -1
  122. package/dist/{patch-bDV8YFW0.js → patch-Zac5aIRM.js} +6 -6
  123. package/dist/{patch-bDV8YFW0.js.map → patch-Zac5aIRM.js.map} +1 -1
  124. package/dist/{plan-DUydFc_1.js → plan-C9Cy27Ay.js} +24 -9
  125. package/dist/plan-C9Cy27Ay.js.map +1 -0
  126. package/dist/preflight-CPWpQeBI.js +1 -0
  127. package/dist/{preflight-BkoSxf4C.js → preflight-D7iFPKeK.js} +8 -7
  128. package/dist/preflight-D7iFPKeK.js.map +1 -0
  129. package/dist/prepare-BGjePFQl.js +2 -0
  130. package/dist/{prepare-CUAWHebF.js → prepare-doGxaAGR.js} +38 -30
  131. package/dist/prepare-doGxaAGR.js.map +1 -0
  132. package/dist/{provenance-D7HK3vzt.js → provenance-DmE9uPVt.js} +3 -3
  133. package/dist/{provenance-D7HK3vzt.js.map → provenance-DmE9uPVt.js.map} +1 -1
  134. package/dist/provider-DehR4CMN.js +1 -0
  135. package/dist/providers-gDMko8fl.js +1 -0
  136. package/dist/providers-tAOD1NQN.js +165 -0
  137. package/dist/providers-tAOD1NQN.js.map +1 -0
  138. package/dist/{query-BjBMLa-C.js → query-Bes9Kh6Y.js} +3 -3
  139. package/dist/{query-BjBMLa-C.js.map → query-Bes9Kh6Y.js.map} +1 -1
  140. package/dist/query-C_G_svLU.js +1 -0
  141. package/dist/questions-DjAwMxZ3.js +524 -0
  142. package/dist/questions-DjAwMxZ3.js.map +1 -0
  143. package/dist/{record-BRP9vZrj.js → record-BKmMvZ6O.js} +9 -1
  144. package/dist/{record-BRP9vZrj.js.map → record-BKmMvZ6O.js.map} +1 -1
  145. package/dist/remote-HDRt16ew.js +378 -0
  146. package/dist/remote-HDRt16ew.js.map +1 -0
  147. package/dist/{results-Di7m8dQ3.js → results-DuauQI3Z.js} +4 -4
  148. package/dist/{results-Di7m8dQ3.js.map → results-DuauQI3Z.js.map} +1 -1
  149. package/dist/{resume-SUz1GskV.js → resume-BRfa8E_s.js} +10 -10
  150. package/dist/{resume-SUz1GskV.js.map → resume-BRfa8E_s.js.map} +1 -1
  151. package/dist/{root-CvdRlRZX.js → root-DICDHCtp.js} +4 -4
  152. package/dist/{root-CvdRlRZX.js.map → root-DICDHCtp.js.map} +1 -1
  153. package/dist/{runtime-DdsfnRz_.js → runtime-PX_oXiCS.js} +23 -71
  154. package/dist/runtime-PX_oXiCS.js.map +1 -0
  155. package/dist/sandbox-D3A8oUb7.js +70 -0
  156. package/dist/sandbox-D3A8oUb7.js.map +1 -0
  157. package/dist/sandbox.d.ts +19 -6
  158. package/dist/sandbox.js +1 -2
  159. package/dist/server-C7sg1ndo.js +1 -0
  160. package/dist/{server-BNnXtmS8.js → server-XDleKaF_.js} +11 -11
  161. package/dist/server-XDleKaF_.js.map +1 -0
  162. package/dist/shared-DYpIb1BI.js +166 -0
  163. package/dist/shared-DYpIb1BI.js.map +1 -0
  164. package/dist/{source-Dof0NQBm.js → source-C8xumIWj.js} +2 -2
  165. package/dist/{source-Dof0NQBm.js.map → source-C8xumIWj.js.map} +1 -1
  166. package/dist/source-fGd0SaKP.js +1 -0
  167. package/dist/{src-8rRXy4u9.js → src-B7treWa8.js} +1538 -180
  168. package/dist/src-B7treWa8.js.map +1 -0
  169. package/dist/{src-C1E9HDWO.js → src-C7_1SqDP.js} +3 -3
  170. package/dist/{src-C1E9HDWO.js.map → src-C7_1SqDP.js.map} +1 -1
  171. package/dist/{src-DDNXsD9H.js → src-CF17Ug08.js} +5 -4
  172. package/dist/src-CF17Ug08.js.map +1 -0
  173. package/dist/{src-C_4Umgh2.js → src-CFp86GtV.js} +52 -51
  174. package/dist/src-CFp86GtV.js.map +1 -0
  175. package/dist/src-C_lPtowT.js +2 -0
  176. package/dist/src-DIL0jST0.js +368 -0
  177. package/dist/src-DIL0jST0.js.map +1 -0
  178. package/dist/src-DNnG4e4R.js +2 -0
  179. package/dist/src-DTbrY1hi.js +2 -0
  180. package/dist/src-DdyJEh2v.js +2 -0
  181. package/dist/src-Dj9PAroc.js +2 -0
  182. package/dist/src-Du8H85Qq.js +2 -0
  183. package/dist/src-DvCg0NBs.js +324 -0
  184. package/dist/src-DvCg0NBs.js.map +1 -0
  185. package/dist/{src-COgE7991.js → src-DvK0EIZx.js} +5 -5
  186. package/dist/{src-COgE7991.js.map → src-DvK0EIZx.js.map} +1 -1
  187. package/dist/{src-DVy58-zZ.js → src-FGXhkEkH.js} +5 -5
  188. package/dist/{src-DVy58-zZ.js.map → src-FGXhkEkH.js.map} +1 -1
  189. package/dist/src-jzagbuqH.js +2 -0
  190. package/dist/src-ofUaYbuY.js +3 -0
  191. package/dist/src-pJZOrYR9.js +1 -0
  192. package/dist/{src-D95O-Smv.js → src-u8_ixn_F.js} +15 -11
  193. package/dist/src-u8_ixn_F.js.map +1 -0
  194. package/dist/{state-CiXyLqg0.js → state-C__9swoG.js} +35 -23
  195. package/dist/state-C__9swoG.js.map +1 -0
  196. package/dist/state-CeR6oz0k.js +66 -0
  197. package/dist/state-CeR6oz0k.js.map +1 -0
  198. package/dist/state-CgjQo29K.js +1 -0
  199. package/dist/studio-app/assets/index-CwQN3f_h.css +2 -0
  200. package/dist/studio-app/assets/{index-CROH2NB3.js → index-DrQc2Yxd.js} +11 -11
  201. package/dist/studio-app/index.html +2 -2
  202. package/dist/{summary-BTksrIxn.js → summary-BLAVLySU.js} +150 -19
  203. package/dist/summary-BLAVLySU.js.map +1 -0
  204. package/dist/{summary-2OAWF2N7.js → summary-DgyjUh_l.js} +7 -7
  205. package/dist/{summary-2OAWF2N7.js.map → summary-DgyjUh_l.js.map} +1 -1
  206. package/dist/testing.d.ts +3 -2
  207. package/dist/testing.js +3 -2
  208. package/dist/{tool-target-BU1JnSE9.js → tool-target-D2mcYlSQ.js} +14 -7
  209. package/dist/tool-target-D2mcYlSQ.js.map +1 -0
  210. package/dist/{tools-B10Uj7OI.js → tools-GCyNYSc1.js} +6 -6
  211. package/dist/tools-GCyNYSc1.js.map +1 -0
  212. package/dist/transcript-BNNANU8A.js +64 -0
  213. package/dist/transcript-BNNANU8A.js.map +1 -0
  214. package/dist/{types-D8RLfkFP.d.ts → types-g17bRAzt.d.ts} +389 -42
  215. package/dist/{usage-DDF_6tkV.js → usage-CleNKkly.js} +4 -2
  216. package/dist/{usage-DDF_6tkV.js.map → usage-CleNKkly.js.map} +1 -1
  217. package/dist/view/index.d.ts +42 -8
  218. package/dist/view/index.js +6 -6
  219. package/dist/views-BW6oCDUQ.js +2 -0
  220. package/dist/{views-Dqa5ojfZ.js → views-BmQF4UCI.js} +13 -8
  221. package/dist/views-BmQF4UCI.js.map +1 -0
  222. package/dist/{worker-entry-BAikHl9F.js → worker-entry-yOchGYYv.js} +16 -229
  223. package/dist/worker-entry-yOchGYYv.js.map +1 -0
  224. package/dist/{workspace-C-TrNIUc.js → workspace-CgyHEM0l.js} +6 -6
  225. package/dist/{workspace-C-TrNIUc.js.map → workspace-CgyHEM0l.js.map} +1 -1
  226. package/dist/workspace-D8sSgpiy.js +1 -0
  227. package/package.json +12 -12
  228. package/dist/agent-WSmTaesf.js.map +0 -1
  229. package/dist/assemble-BCZzTyR7.js.map +0 -1
  230. package/dist/assemble-C5qq5yT2.js +0 -2
  231. package/dist/capture-Bp74Z6Fr.js.map +0 -1
  232. package/dist/capture-DS-cPyuE.js +0 -2
  233. package/dist/cli-CVrMh_qz.js.map +0 -1
  234. package/dist/cli-spec-CKEYa8V2.js.map +0 -1
  235. package/dist/client-Bbo9SPlK.js.map +0 -1
  236. package/dist/command-BrmXUC-W.js +0 -2
  237. package/dist/command-C5xFPKHM.js.map +0 -1
  238. package/dist/command-CzIFp1JQ.js.map +0 -1
  239. package/dist/command-DUT5l13I.js.map +0 -1
  240. package/dist/commands-CLmPBrTS.js.map +0 -1
  241. package/dist/commands-fI3G2Wnh.js +0 -2
  242. package/dist/config-CGvBeewH.js +0 -457
  243. package/dist/config-CGvBeewH.js.map +0 -1
  244. package/dist/context-DbSMEVKs.js.map +0 -1
  245. package/dist/db-CSSFtGcN.js +0 -3
  246. package/dist/db-CfQFwJtq.js.map +0 -1
  247. package/dist/debug-SEmW4w8f.js +0 -2
  248. package/dist/dist-CTzThfu_.js.map +0 -1
  249. package/dist/docker-CRQGQbIt.js.map +0 -1
  250. package/dist/docker-DV2GNgle.js.map +0 -1
  251. package/dist/docker-Df_YOxxB.js +0 -2
  252. package/dist/doctor-DlKycx5H.js.map +0 -1
  253. package/dist/egress-BhzNh7Yi.js.map +0 -1
  254. package/dist/environment-1jE-HhO-.js +0 -657
  255. package/dist/environment-1jE-HhO-.js.map +0 -1
  256. package/dist/errors-C9w_ud7g.js.map +0 -1
  257. package/dist/errors-yDAEwmZo.js.map +0 -1
  258. package/dist/fake-instructions-CUI33I_F.js +0 -32
  259. package/dist/fake-instructions-CUI33I_F.js.map +0 -1
  260. package/dist/files-AiEKuEZe.js +0 -2
  261. package/dist/files-BM78_nnF.js +0 -2
  262. package/dist/files-BMCvfB4X.js +0 -2
  263. package/dist/harness-CeCp2GSW.js +0 -171
  264. package/dist/harness-CeCp2GSW.js.map +0 -1
  265. package/dist/images-BMgdpMAX.js.map +0 -1
  266. package/dist/index.js.map +0 -1
  267. package/dist/init-B6vegaP_.js +0 -2
  268. package/dist/init-BIdLF0F9.js.map +0 -1
  269. package/dist/jiti-BcJHCtrb.js +0 -46
  270. package/dist/jiti-BcJHCtrb.js.map +0 -1
  271. package/dist/live-S0qODb6o.js.map +0 -1
  272. package/dist/model-B1BZoZ9b.js.map +0 -1
  273. package/dist/model-BOnlAPzs.js.map +0 -1
  274. package/dist/model-DWeg5J7z.js +0 -2
  275. package/dist/model-FXko2kl7.js +0 -2
  276. package/dist/node-Co7EXge0.js.map +0 -1
  277. package/dist/opencode-providers-ByD85Q0l.js.map +0 -1
  278. package/dist/options-CKqyPGxX.js +0 -739
  279. package/dist/options-CKqyPGxX.js.map +0 -1
  280. package/dist/plan-DUydFc_1.js.map +0 -1
  281. package/dist/preflight-BkoSxf4C.js.map +0 -1
  282. package/dist/preflight-D5LW7Oqi.js +0 -2
  283. package/dist/prepare-CUAWHebF.js.map +0 -1
  284. package/dist/prepare-oji2oO8W.js +0 -3
  285. package/dist/provider-BDbNOQhQ.js +0 -2
  286. package/dist/providers-B1DzMvmH.js +0 -107
  287. package/dist/providers-B1DzMvmH.js.map +0 -1
  288. package/dist/providers-CpEfNU1F.js +0 -2
  289. package/dist/query-oPO_XrTy.js +0 -2
  290. package/dist/questions-B8by4Bbt.js +0 -234
  291. package/dist/questions-B8by4Bbt.js.map +0 -1
  292. package/dist/runtime-DdsfnRz_.js.map +0 -1
  293. package/dist/sandbox-D5v-of6d.js +0 -139
  294. package/dist/sandbox-D5v-of6d.js.map +0 -1
  295. package/dist/server-BNnXtmS8.js.map +0 -1
  296. package/dist/server-BNwoKzlm.js +0 -2
  297. package/dist/source-Bk_0ZaEY.js +0 -2
  298. package/dist/src-8rRXy4u9.js.map +0 -1
  299. package/dist/src-BGWuWp6I.js +0 -3
  300. package/dist/src-BRt0O02i.js +0 -3
  301. package/dist/src-Bx2x1ekD.js +0 -3
  302. package/dist/src-C_4Umgh2.js.map +0 -1
  303. package/dist/src-D95O-Smv.js.map +0 -1
  304. package/dist/src-DDNXsD9H.js.map +0 -1
  305. package/dist/src-DLa-ESW0.js +0 -4
  306. package/dist/src-cN0aB-WR.js +0 -3
  307. package/dist/src-cdIVjC5b.js +0 -2
  308. package/dist/src-sIsDHWYq.js +0 -3
  309. package/dist/state-Bo5zg4da.js +0 -2
  310. package/dist/state-CiXyLqg0.js.map +0 -1
  311. package/dist/studio-app/assets/index-B9MCTfuu.css +0 -2
  312. package/dist/summary-BTksrIxn.js.map +0 -1
  313. package/dist/tool-target-BU1JnSE9.js.map +0 -1
  314. package/dist/tools-B10Uj7OI.js.map +0 -1
  315. package/dist/views-Cs2Oqayd.js +0 -3
  316. package/dist/views-Dqa5ojfZ.js.map +0 -1
  317. package/dist/worker-entry-BAikHl9F.js.map +0 -1
  318. package/dist/workspace-Do_SiWBs.js +0 -2
@@ -1,657 +0,0 @@
1
- import { t as parseDuration } from "./duration-JsJrIWXq.js";
2
- import { n as SECRET_NAME } from "./redact-DJ9JCShu.js";
3
- import { i as PACKAGE_DIR, n as COMPILED } from "./root-CvdRlRZX.js";
4
- import picomatch from "picomatch";
5
- import { readdirSync, realpathSync, statSync } from "node:fs";
6
- import { dirname, isAbsolute, join, normalize, resolve, sep } from "node:path";
7
- import { isIP } from "node:net";
8
- import { fileURLToPath } from "node:url";
9
- //#region src/environment.ts
10
- var DefinitionError = class extends Error {
11
- name = "DefinitionError";
12
- };
13
- const NAME = /^[A-Za-z0-9][A-Za-z0-9._@+-]*$/;
14
- const VAR = /^[A-Za-z_][A-Za-z0-9_]*$/;
15
- const SPEC_KEYS = [
16
- "sandbox",
17
- "workspace",
18
- "env",
19
- "egress",
20
- "files",
21
- "rules",
22
- "setup",
23
- "skills",
24
- "mcp"
25
- ];
26
- /** Image fields that belong on `sandbox: docker({ … })`, not as sibling keys. */
27
- const SANDBOX_KEYS = [
28
- "image",
29
- "install",
30
- "dockerfile",
31
- "from"
32
- ];
33
- const SPEC_HINTS = {
34
- exec: "setup",
35
- steps: "setup",
36
- run: "setup",
37
- vars: "env",
38
- secrets: "env",
39
- network: "egress",
40
- networkPolicy: "egress",
41
- skill: "skills",
42
- file: "files",
43
- agents: "rules",
44
- use: "extend",
45
- repo: "workspace",
46
- git: "workspace",
47
- template: "workspace"
48
- };
49
- const isSecret = (value) => typeof value === "object" && value !== null && value.kind === "secret";
50
- const isSecretTemplate = (value) => typeof value === "object" && value !== null && value.kind === "secret-template";
51
- const isHostFile = (value) => typeof value === "object" && value !== null && value.kind === "file";
52
- const isEnvironment = (value) => typeof value === "object" && value !== null && value.kind === "environment" && Array.isArray(value.layers);
53
- const OWN_DIRS = COMPILED ? [join(PACKAGE_DIR, sep)] : ["src", "dist"].map((dir) => join(PACKAGE_DIR, dir, sep));
54
- /** The directory of the file that called into reeval, from the stack; relative paths resolve here. */
55
- function callerDir() {
56
- const limit = Error.stackTraceLimit;
57
- Error.stackTraceLimit = 30;
58
- const stack = (/* @__PURE__ */ new Error()).stack ?? "";
59
- Error.stackTraceLimit = limit;
60
- for (const line of stack.split("\n").slice(1)) {
61
- const match = /(?:\(|at )((?:file:\/\/)?\/[^()]*?|[A-Za-z]:[\\/][^()]*?):\d+:\d+\)?\s*$/.exec(line);
62
- if (!match?.[1]) continue;
63
- const file = normalize(match[1].startsWith("file://") ? fileURLToPath(match[1]) : match[1]);
64
- if (OWN_DIRS.some((d) => file.startsWith(d)) || file.includes(`${sep}node_modules${sep}`)) continue;
65
- return dirname(file);
66
- }
67
- }
68
- const toPath = (value, base) => {
69
- const path = value instanceof URL ? fileURLToPath(value) : value;
70
- return isAbsolute(path) ? path : resolve(base, path);
71
- };
72
- /**
73
- * A tarball or folder spec (`./x.tgz`, `../pkg`, `/abs`, `file:…`) as an absolute path, resolved
74
- * like `file()`; npm resolves relative ones against its working directory, reeval's cache.
75
- */
76
- const localNpmSpec = (spec, base) => {
77
- const path = spec.startsWith("file:") ? spec.slice(5) : spec;
78
- return /^\.{1,2}(?:\/|$)/.test(path) || isAbsolute(path) ? toPath(path, base) : spec;
79
- };
80
- /** A host name, or `*.` and a domain for its subdomains. */
81
- const HOST = /^(?:\*\.)?[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*$/i;
82
- const SUBSTITUTE_IN = [
83
- "header",
84
- "query",
85
- "body"
86
- ];
87
- /** Why `host` isn't a host name or `*.` pattern, or undefined when it is one. */
88
- function badHost(host) {
89
- if (typeof host === "string" && HOST.test(host)) {
90
- const name = host.replace(/^\*\./, "");
91
- if (/(?:^|\.)\d+$/.test(name) && (name !== host || isIP(name) !== 4)) return `'${host}' isn't a host name or an IPv4 address, and a *. pattern never matches an address.`;
92
- if (name !== host && !name.includes(".")) return `'${host}' would allow every host under .${name}; name the domain, e.g. '*.example.${name}'.`;
93
- return;
94
- }
95
- if (typeof host === "string" && /^[a-z]+:\/\//i.test(host)) return `hosts are host names, not URLs: use '${new URL(host).hostname}' (got '${host}')`;
96
- if (typeof host === "string" && /^[^:/]+:\d+$/.test(host)) return `hosts are host names without a port: use '${host.split(":")[0]}' (got '${host}')`;
97
- return `${JSON.stringify(host)} isn't a host. Use a name like 'api.example.com', or '*.example.com' for its subdomains.`;
98
- }
99
- /** Throws unless `value` is `'allow-all'`, `'deny-all'` or `{ allow: [hosts] }`. */
100
- function checkEgress(value, where, Err = DefinitionError) {
101
- if (value === "allow-all" || value === "deny-all") return;
102
- const shape = `egress is 'allow-all' (the default), 'deny-all', or { allow: ['api.example.com', '*.example.org'] }`;
103
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
104
- const list = Array.isArray(value) ? ` For a list of hosts, use { allow: ${JSON.stringify(value)} }.` : "";
105
- throw new Err(`${shape} (got ${JSON.stringify(value)}) in ${where}.${list}`);
106
- }
107
- for (const key of Object.keys(value)) {
108
- if (key === "allow") continue;
109
- throw new Err(`Unknown egress key "${key}" in ${where}.${key === "deny" ? " A policy lists what's allowed; everything else is refused." : key === "hosts" || key === "allowedHosts" ? " Did you mean \"allow\"?" : ""}`);
110
- }
111
- const allow = value.allow;
112
- if (!Array.isArray(allow)) throw new Err(`${shape} (got ${JSON.stringify(value)}) in ${where}`);
113
- for (const host of allow) {
114
- const bad = badHost(host);
115
- if (bad) throw new Err(`egress.allow in ${where}: ${bad}`);
116
- }
117
- }
118
- const SECRET_HOSTS = Object.freeze({
119
- gemini: Object.freeze(["generativelanguage.googleapis.com"]),
120
- openai: Object.freeze(["api.openai.com"]),
121
- anthropic: Object.freeze(["api.anthropic.com"]),
122
- github: Object.freeze(["api.github.com", "uploads.github.com"])
123
- });
124
- function secretOptions(options, what) {
125
- const to = options.to ?? "agent";
126
- if (to !== "agent" && to !== "checks") throw new DefinitionError(`${what}: to must be 'agent' or 'checks'`);
127
- const { hosts } = options;
128
- if (hosts !== void 0) {
129
- if (!Array.isArray(hosts) || hosts.length === 0) throw new DefinitionError(`${what}: hosts must list the hosts the secret is sent to, e.g. hosts: ['api.example.com'] or secret.hosts.gemini (got ${JSON.stringify(hosts)})`);
130
- for (const host of hosts) {
131
- const bad = badHost(host);
132
- if (bad) throw new DefinitionError(`${what}: ${bad}`);
133
- }
134
- }
135
- if (options.in !== void 0) {
136
- if (hosts === void 0) throw new DefinitionError(`${what}: in only applies to a brokered secret; add hosts, e.g. { hosts: ['api.example.com'], in: ${JSON.stringify(options.in)} }`);
137
- if ((Array.isArray(options.in) ? options.in.filter((i) => !SUBSTITUTE_IN.includes(i)) : [options.in]).length || options.in.length === 0) throw new DefinitionError(`${what}: in lists where the gateway substitutes: 'header', 'query' and/or 'body' (got ${JSON.stringify(options.in)})`);
138
- }
139
- return {
140
- ...options.optional ? { optional: true } : {},
141
- ...to === "checks" ? { to } : {},
142
- ...hosts ? { hosts: [...hosts] } : {},
143
- ...options.in ? { in: [...new Set(options.in)] } : {}
144
- };
145
- }
146
- /** Where an MCP server's header secrets are brokered to by default: its own host, over HTTPS. */
147
- function mcpHosts(url) {
148
- try {
149
- const u = new URL(url);
150
- return u.protocol === "https:" ? [u.hostname] : void 0;
151
- } catch {
152
- return;
153
- }
154
- }
155
- /**
156
- * Every secret among `env` and the layers' env and MCP servers, layered as the attempt resolves
157
- * them: a later layer's variable or MCP server replaces an earlier one of the same name.
158
- */
159
- function plannedSecrets(env, layers) {
160
- const vars = { ...env };
161
- const servers = /* @__PURE__ */ new Map();
162
- for (const { spec } of layers) {
163
- Object.assign(vars, spec.env);
164
- for (const [name, server] of Object.entries(spec.mcp ?? {})) servers.set(name, server);
165
- }
166
- const out = /* @__PURE__ */ new Map();
167
- const add = (label, from, hosts, checksOnly = false, optional = false) => out.set(`${label}\0${from}`, {
168
- label,
169
- from,
170
- ...hosts ? { hosts } : {},
171
- ...checksOnly ? { checksOnly } : {},
172
- ...optional ? { optional } : {}
173
- });
174
- const fromVars = (values, prefix) => {
175
- for (const [name, value] of Object.entries(values)) if (isSecret(value)) add(`${prefix}${name}`, value.from ?? name, value.hosts, value.to === "checks", value.optional === true);
176
- };
177
- fromVars(vars, "");
178
- for (const [server, s] of servers) {
179
- if (s.transport === "stdio") {
180
- fromVars(s.env, `mcp.${server}.env.`);
181
- continue;
182
- }
183
- const own = mcpHosts(s.url);
184
- for (const [header, value] of Object.entries(s.headers)) {
185
- const label = `mcp.${server}.headers.${header}`;
186
- if (isSecret(value)) add(label, value.from ?? header, value.hosts ?? own);
187
- if (isSecretTemplate(value)) for (const [, name] of value.template.matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g)) add(label, name, own);
188
- }
189
- }
190
- return [...out.values()];
191
- }
192
- /** The secrets the sandbox gets as real values: no `hosts`, and none implied by an MCP URL. */
193
- const unbrokeredSecrets = (env, layers) => plannedSecrets(env, layers).flatMap(({ hosts, ...s }) => hosts ? [] : [s]);
194
- function secretHelper() {
195
- const secret = ((options = {}) => ({
196
- kind: "secret",
197
- ...secretOptions(options, "secret()")
198
- }));
199
- secret.fromEnv = (host, options = {}) => {
200
- if (typeof host !== "string" || !VAR.test(host)) throw new DefinitionError(`secret.fromEnv(${JSON.stringify(host)}) needs a host variable name`);
201
- return {
202
- kind: "secret",
203
- from: host,
204
- ...secretOptions(options, `secret.fromEnv("${host}")`)
205
- };
206
- };
207
- secret.template = (template) => ({
208
- kind: "secret-template",
209
- template
210
- });
211
- secret.hosts = SECRET_HOSTS;
212
- return secret;
213
- }
214
- const MOVING = /^(?:main|master|HEAD|trunk|develop|dev|latest)$/;
215
- /** A git ref that isn't a commit SHA or a version-like tag. */
216
- const isMovingRef = (ref) => ref === void 0 || MOVING.test(ref) || !/^(?:[0-9a-f]{7,40}|v?\d+(?:\.\d+)*(?:[-+].*)?)$/.test(ref);
217
- /** `github:owner/repo` and GitHub `/tree/<ref>/<path>` URLs, as a clone URL plus ref and path. */
218
- function parseGitRepo(repo) {
219
- const short = /^github:([\w.-]+\/[\w.-]+?)(?:\.git)?$/.exec(repo);
220
- if (short) return { url: `https://github.com/${short[1]}.git` };
221
- const tree = /^https:\/\/github\.com\/([\w.-]+\/[\w.-]+)\/tree\/([^/]+)(?:\/(.+))?$/.exec(repo);
222
- if (tree) return {
223
- url: `https://github.com/${tree[1]}.git`,
224
- ref: tree[2],
225
- path: tree[3]
226
- };
227
- return { url: repo };
228
- }
229
- /** `repo#ref:path`, as the plan and the record name a git workspace. */
230
- const workspaceLabel = (w) => `${w.repo}${w.ref ? `#${w.ref}` : ""}${w.path ? `:${w.path}` : ""}`;
231
- /** The workspace an attempt starts as: the last layer that sets one. */
232
- const workspaceOf = (layers) => layers.findLast((l) => l.spec.workspace)?.spec.workspace;
233
- /** The paths the layers' `files` write, sorted. */
234
- const filesOf = (layers) => [...new Set(layers.flatMap((l) => Object.keys(l.spec.files ?? {})))].sort();
235
- /** A URL with its password (or an https username, which is where tokens go) masked. */
236
- function credentialsIn(repo) {
237
- if (!URL.canParse(repo)) return void 0;
238
- const u = new URL(repo);
239
- if (!u.password && !(u.username && /^https?:$/.test(u.protocol))) return void 0;
240
- u.username = u.username && "***";
241
- u.password = u.password && "***";
242
- return u.href;
243
- }
244
- const GIT_OPTIONS = [
245
- "ref",
246
- "path",
247
- "init",
248
- "token"
249
- ];
250
- const isLocalPath = (repo) => /^\.{1,2}(?:\/|$)/.test(repo) || isAbsolute(repo);
251
- function gitHelper(base) {
252
- return (repo, options = {}) => {
253
- const written = repo instanceof URL ? repo.href : repo;
254
- if (typeof written !== "string" || !written.trim()) throw new DefinitionError(`git() needs a repository: a URL, github:owner/repo or a local path (got ${JSON.stringify(repo)})`);
255
- const what = `git(${JSON.stringify(written)})`;
256
- const masked = credentialsIn(written);
257
- if (masked) throw new DefinitionError(`git(${JSON.stringify(masked)}): the URL has a password or token in it. reeval fetches the repository on the host with your own git credentials (a credential helper, gh auth setup-git or an SSH key), and the sandbox never gets them; remove it from the URL.`);
258
- if (typeof options !== "object" || options === null || Array.isArray(options)) throw new DefinitionError(`${what}: options are { ref?, path? }`);
259
- const extra = Object.keys(options).filter((k) => !GIT_OPTIONS.includes(k));
260
- if (extra.length) {
261
- const hint = extra.includes("branch") || extra.includes("tag") ? " Use ref for a branch, tag or commit." : "";
262
- throw new DefinitionError(`${what}: unknown option "${extra.join("\", \"")}"; it takes ${GIT_OPTIONS.slice(0, -1).join(", ")} and ${GIT_OPTIONS.at(-1)}.${hint}`);
263
- }
264
- const local = repo instanceof URL ? repo.protocol === "file:" : isLocalPath(written);
265
- const parsed = local ? { url: toPath(repo, base) } : parseGitRepo(written);
266
- const ref = options.ref ?? parsed.ref;
267
- if (ref !== void 0 && (typeof ref !== "string" || !ref.trim() || ref.startsWith("-"))) throw new DefinitionError(`${what}: ref is a branch, tag or commit SHA (got ${JSON.stringify(ref)})`);
268
- const path = options.path ?? parsed.path;
269
- if (path !== void 0) {
270
- const clean = typeof path === "string" ? path.replace(/\/+$/, "") : path;
271
- if (typeof clean !== "string" || !clean || clean.includes("\\") || clean.startsWith("/") || clean.split("/").some((p) => p === ".." || p === "." || p === "")) throw new DefinitionError(`${what}: path is a directory in the repository, relative, with forward slashes and no . or .. (got ${JSON.stringify(path)})`);
272
- }
273
- const cleanPath = path?.replace(/\/+$/, "");
274
- const { init, token } = options;
275
- if (init !== void 0 && typeof init !== "boolean") throw new DefinitionError(`${what}: init is true or false (got ${JSON.stringify(init)})`);
276
- if (token !== void 0) {
277
- if (typeof token !== "string" || !VAR.test(token) || /^(?:gh[opsur]_|github_pat_)/.test(token)) throw new DefinitionError(`${what}: token names the host variable that holds the token, e.g. token: 'GITHUB_TOKEN'. Don't put the token itself in the eval.`);
278
- if (local || !/^https?:\/\//.test(parsed.url)) throw new DefinitionError(`${what}: token only works with an https:// URL; for SSH or a local repository, git uses this machine's own credentials`);
279
- }
280
- return {
281
- kind: "git",
282
- repo: "ref" in parsed || "path" in parsed ? parsed.url.replace(/\.git$/, "") : written,
283
- url: parsed.url,
284
- ...ref ? { ref } : {},
285
- ...cleanPath ? { path: cleanPath } : {},
286
- ...init ? { init } : {},
287
- ...token ? { token } : {}
288
- };
289
- };
290
- }
291
- /**
292
- * What a skill directory leaves out of the sandbox unless `exclude` says otherwise: eval material
293
- * (skill-creator keeps `evals/` in the skill), run history and reeval eval files. `.git` is always left out.
294
- */
295
- const DEFAULT_SKILL_EXCLUDE = [
296
- "/evals/",
297
- ".history/",
298
- "*.eval.ts"
299
- ];
300
- function skillHelper(base) {
301
- const placement = (p) => {
302
- if (p === void 0 || p === "harness" || p === "workspace") return p ?? "harness";
303
- throw new DefinitionError(`skill placement must be 'harness' or 'workspace' (got ${p})`);
304
- };
305
- const exclude = (e) => {
306
- if (e === void 0) return {};
307
- if (!Array.isArray(e) || e.some((p) => typeof p !== "string" || !p.replace(/\//g, ""))) throw new DefinitionError(`skill exclude must be an array of paths or globs, e.g. ['/evals/', '*.eval.ts'] (got ${JSON.stringify(e)})`);
308
- return { exclude: [...e] };
309
- };
310
- return {
311
- local: (path, o = {}) => ({
312
- kind: "skill",
313
- source: "local",
314
- path: toPath(path, base),
315
- ...o.only ? { only: [...o.only] } : {},
316
- ...exclude(o.exclude),
317
- placement: placement(o.placement)
318
- }),
319
- git: (repo, o = {}) => {
320
- if (typeof repo !== "string" || !repo) throw new DefinitionError("skill.git() needs a repository URL");
321
- const parsed = parseGitRepo(repo);
322
- const ref = o.ref ?? parsed.ref;
323
- const path = o.path ?? parsed.path;
324
- return {
325
- kind: "skill",
326
- source: "git",
327
- repo,
328
- ...ref ? { ref } : {},
329
- ...path ? { path } : {},
330
- ...o.only ? { only: [...o.only] } : {},
331
- ...exclude(o.exclude),
332
- placement: placement(o.placement)
333
- };
334
- },
335
- registry: (id, o = {}) => {
336
- if (!/^[\w.-]+\/[\w.-]+@[a-z0-9-]+$/.test(id)) throw new DefinitionError(`skill.registry("${id}") needs an id like owner/repo@skill`);
337
- return {
338
- kind: "skill",
339
- source: "registry",
340
- id,
341
- ...o.version ? { version: o.version } : {},
342
- placement: placement(o.placement)
343
- };
344
- },
345
- npm: (spec, o = {}) => ({
346
- kind: "skill",
347
- source: "npm",
348
- spec: localNpmSpec(spec, base),
349
- path: o.path ?? "skills",
350
- ...o.only ? { only: [...o.only] } : {},
351
- ...exclude(o.exclude),
352
- placement: placement(o.placement)
353
- }),
354
- inline: (skill, o = {}) => ({
355
- kind: "skill",
356
- source: "inline",
357
- name: skill.name,
358
- description: skill.description,
359
- content: skill.content,
360
- files: { ...skill.files },
361
- placement: placement(o.placement)
362
- })
363
- };
364
- }
365
- /**
366
- * What `directory()` leaves out unless `defaultIgnores: false`: dependency, build-output, cache
367
- * and editor directories, in its `glob` syntax. `build/` and `target/` are anchored to the top of
368
- * the directory, where Flutter, Dart, Gradle and Cargo put their output, since a nested one can be
369
- * source. `vendor/` isn't here: a committed Go or PHP vendor directory is what an offline build needs.
370
- */
371
- const DEFAULT_DIRECTORY_IGNORES = Object.freeze([
372
- "node_modules/",
373
- ".DS_Store",
374
- "dist/",
375
- ".next/",
376
- ".turbo/",
377
- "coverage/",
378
- ".cache/",
379
- "__pycache__/",
380
- ".venv/",
381
- "venv/",
382
- ".pytest_cache/",
383
- ".mypy_cache/",
384
- "*.pyc",
385
- ".dart_tool/",
386
- "/build/",
387
- "/target/",
388
- ".gradle/",
389
- ".idea/",
390
- ".vscode/"
391
- ]);
392
- /**
393
- * A gitignore-style pattern as a test of a file's path, matched by picomatch: a pattern without an
394
- * inner `/` matches a name at any depth, a leading `/` anchors, a trailing `/` names a directory,
395
- * and a pattern also matches every file in a directory it names.
396
- */
397
- function globTest(pattern) {
398
- const dirOnly = pattern.endsWith("/");
399
- const body = pattern.replace(/\/+$/, "").replaceAll("[!", "[^");
400
- const glob = body.includes("/") ? body.replace(/^\/+/, "") : `**/${body}`;
401
- const self = picomatch(glob, { dot: true });
402
- const inside = picomatch(`${glob}/**/*`, { dot: true });
403
- return (path, isDir = false) => inside(path) || (isDir || !dirOnly) && self(path);
404
- }
405
- /**
406
- * `glob` as a test of a directory-relative file path: the last pattern that matches decides, a
407
- * `!` one excluding; a file no pattern matches is in unless some pattern includes.
408
- */
409
- function globFilter(patterns) {
410
- const rules = patterns.map((p) => ({
411
- include: !p.startsWith("!"),
412
- test: globTest(p.replace(/^!/, ""))
413
- }));
414
- const start = !rules.some((r) => r.include);
415
- return (path, isDir) => rules.reduce((keep, r) => r.test(path, isDir) ? r.include : keep, start);
416
- }
417
- const DIRECTORY_OPTIONS = [
418
- "into",
419
- "glob",
420
- "defaultIgnores"
421
- ];
422
- function directoryHelper(base) {
423
- return (path, options = {}) => {
424
- const written = path instanceof URL ? path.href : path;
425
- const what = `directory(${JSON.stringify(written)})`;
426
- if (typeof written !== "string" || !written) throw new DefinitionError(`directory() needs a path to a directory, relative to this file (got ${JSON.stringify(path)})`);
427
- if (typeof options !== "object" || options === null || Array.isArray(options)) throw new DefinitionError(`${what}: options are { into?, glob?, defaultIgnores? }`);
428
- const extra = Object.keys(options).filter((k) => !DIRECTORY_OPTIONS.includes(k));
429
- if (extra.length) {
430
- const hint = extra.includes("ignore") || extra.includes("exclude") ? " Exclude with a '!' pattern in glob, e.g. glob: ['!dist/']." : "";
431
- throw new DefinitionError(`${what}: unknown option "${extra.join("\", \"")}"; it takes into, glob and defaultIgnores.${hint}`);
432
- }
433
- const { into, glob = [], defaultIgnores = true } = options;
434
- if (into !== void 0 && (typeof into !== "string" || into.includes("\\") || isAbsolute(into) || into.split("/").some((p) => p === ".."))) throw new DefinitionError(`${what}: into is a directory relative to the workspace (or ~/…), with forward slashes and no .. (got ${JSON.stringify(into)})`);
435
- if (!Array.isArray(glob) || glob.some((p) => typeof p !== "string" || !p.replace(/^!/, "").replace(/\//g, ""))) throw new DefinitionError(`${what}: glob is a list of patterns, e.g. ['src/**', 'package.json', '!**/*.test.ts'] (got ${JSON.stringify(glob)})`);
436
- if (typeof defaultIgnores !== "boolean") throw new DefinitionError(`${what}: defaultIgnores is true or false (got ${JSON.stringify(defaultIgnores)})`);
437
- const root = toPath(path, base);
438
- const stat = statSync(root, { throwIfNoEntry: false });
439
- if (!stat) throw new DefinitionError(`${what}: ${root} doesn't exist`);
440
- if (!stat.isDirectory()) throw new DefinitionError(`${what}: ${root} is a file, not a directory. Use file(${JSON.stringify(written)}) for one file.`);
441
- const skip = defaultIgnores ? globFilter(DEFAULT_DIRECTORY_IGNORES) : () => false;
442
- const keep = globFilter(glob);
443
- const prefix = into?.replace(/\/+$/, "").replace(/^\.\/?/, "");
444
- const files = {};
445
- const walk = (dir, rel, seen) => {
446
- for (const name of readdirSync(dir).sort()) {
447
- if (name === ".git") continue;
448
- const full = join(dir, name);
449
- const relPath = rel ? `${rel}/${name}` : name;
450
- const target = statSync(full, { throwIfNoEntry: false });
451
- if (!target) throw new DefinitionError(`${what}: ${relPath} is a symlink to something that doesn't exist. Remove it, or leave it out with glob: ['!${relPath}'].`);
452
- if (target.isDirectory()) {
453
- if (skip(relPath, true)) continue;
454
- const real = realpathSync(full);
455
- if (seen.includes(real)) throw new DefinitionError(`${what}: ${relPath} is a symlink to a directory that contains it. Leave it out with glob: ['!${relPath}/'].`);
456
- walk(full, relPath, [...seen, real]);
457
- } else if (target.isFile() && !skip(relPath) && keep(relPath)) files[prefix ? `${prefix}/${relPath}` : relPath] = {
458
- kind: "file",
459
- path: full
460
- };
461
- }
462
- };
463
- walk(root, "", [realpathSync(root)]);
464
- if (Object.keys(files).length === 0) throw new DefinitionError(`${what}: no files in ${root}${glob.length || defaultIgnores ? ` match (glob ${JSON.stringify(glob)}${defaultIgnores ? ", after DEFAULT_DIRECTORY_IGNORES" : ""})` : ""}. Empty directories aren't seeded; create one with a setup step.`);
465
- return files;
466
- };
467
- }
468
- const mcpHelper = {
469
- stdio: (command, args = [], o = {}) => {
470
- if (typeof command !== "string" || !command) throw new DefinitionError("mcp.stdio() needs a command");
471
- return {
472
- kind: "mcp",
473
- transport: "stdio",
474
- command,
475
- args: [...args],
476
- env: { ...o.env }
477
- };
478
- },
479
- http: (url, o = {}) => ({
480
- kind: "mcp",
481
- transport: "http",
482
- url,
483
- headers: { ...o.headers }
484
- }),
485
- sse: (url, o = {}) => ({
486
- kind: "mcp",
487
- transport: "sse",
488
- url,
489
- headers: { ...o.headers }
490
- })
491
- };
492
- /** The helpers a callback gets, with relative paths resolving against `base`. */
493
- function helpersFor(base) {
494
- return {
495
- secret: secretHelper(),
496
- skill: skillHelper(base),
497
- mcp: mcpHelper,
498
- file: (path) => ({
499
- kind: "file",
500
- path: toPath(path, base)
501
- }),
502
- directory: directoryHelper(base),
503
- git: gitHelper(base)
504
- };
505
- }
506
- /** Throws on env variables that aren't strings or secrets, or look like literal secrets. */
507
- function checkEnv(env, where, Err = DefinitionError) {
508
- if (typeof env !== "object" || env === null || Array.isArray(env)) throw new Err(`env must be an object of variables in ${where}`);
509
- for (const [name, value] of Object.entries(env)) {
510
- if (!VAR.test(name)) throw new Err(`env.${name} in ${where} isn't a valid variable name`);
511
- if (isSecret(value)) continue;
512
- if (typeof value !== "string") throw new Err(`env.${name} in ${where} must be a string or secret.fromEnv()`);
513
- if (SECRET_NAME.test(name)) throw new Err(`env.${name} in ${where} is a literal string. Pass secrets with secret.fromEnv() so they're redacted and never recorded.`);
514
- }
515
- }
516
- const stepCommand = (step) => typeof step === "string" ? step : step.run;
517
- function checkSpec(spec, where) {
518
- if (typeof spec !== "object" || spec === null || Array.isArray(spec)) throw new DefinitionError(`${where} must be an object or a callback that returns one`);
519
- for (const key of Object.keys(spec)) {
520
- if (SPEC_KEYS.includes(key)) continue;
521
- if (SANDBOX_KEYS.includes(key)) {
522
- const value = spec[key];
523
- throw new DefinitionError(`"${key}" isn't an environment field (${where}). Put the image on the sandbox: sandbox: docker({ ${key === "image" ? typeof value === "string" ? "from" : "install" : key}: … }).`);
524
- }
525
- throw new DefinitionError(`Unknown field "${key}" in ${where}.${SPEC_HINTS[key] ? ` Did you mean "${SPEC_HINTS[key]}"?` : ""}`);
526
- }
527
- const s = spec;
528
- if (s.sandbox !== void 0) checkSandbox(s.sandbox, where);
529
- if (s.workspace !== void 0 && s.workspace?.kind !== "git") throw new DefinitionError(`workspace in ${where} must come from the git helper, e.g. workspace: git('https://github.com/acme/app', { ref: 'v1.0.0' }) (got ${JSON.stringify(s.workspace)})`);
530
- if (s.env !== void 0) checkEnv(s.env, where);
531
- if (s.egress !== void 0) checkEgress(s.egress, where);
532
- const list = (key) => {
533
- const value = s[key];
534
- if (value !== void 0 && !Array.isArray(value)) throw new DefinitionError(`${key} in ${where} must be a list`);
535
- return value ?? [];
536
- };
537
- for (const step of list("setup")) {
538
- const shape = `Steps in ${where} are strings or { run, timeout?, cwd? } objects`;
539
- const run = typeof step === "string" ? step : step?.run;
540
- if (typeof run !== "string" || !run.trim()) throw new DefinitionError(shape);
541
- if (typeof step === "string") continue;
542
- const extra = Object.keys(step).filter((k) => ![
543
- "run",
544
- "timeout",
545
- "cwd"
546
- ].includes(k));
547
- if (extra.length) throw new DefinitionError(`${shape} (got "${extra.join("\", \"")}")`);
548
- const { cwd, timeout } = step;
549
- if (timeout !== void 0) try {
550
- parseDuration(timeout);
551
- } catch (error) {
552
- throw new DefinitionError(`setup step "${run}" in ${where}: ${error.message}`);
553
- }
554
- if (cwd !== void 0 && (typeof cwd !== "string" || !cwd.trim())) throw new DefinitionError(`setup step "${run}" in ${where}: cwd must be a directory path, relative to the workspace or absolute (got ${JSON.stringify(cwd)})`);
555
- }
556
- for (const skill of list("skills")) if (skill?.kind !== "skill") throw new DefinitionError(`skills in ${where} must come from the skill helper, e.g. skills: [skill.local('./skills')] (got ${JSON.stringify(skill)})`);
557
- for (const [name, server] of Object.entries(s.mcp ?? {})) if (server?.kind !== "mcp") throw new DefinitionError(`mcp.${name} in ${where} must come from the mcp helper, e.g. mcp.stdio('npx', ['-y', 'server'])`);
558
- for (const [path, value] of Object.entries(s.files ?? {})) {
559
- const key = `files[${JSON.stringify(path)}] in ${where}`;
560
- if (path.includes("\\")) throw new DefinitionError(`${key}: use forward slashes (${path.replaceAll("\\", "/")})`);
561
- const rest = path.startsWith("~/") ? path.slice(2) : path;
562
- if (!rest || isAbsolute(rest) || rest.split("/").includes("..")) throw new DefinitionError(`${key}: paths are relative to the workspace, or start with ~/ for the home directory, and never use ..`);
563
- if (typeof value !== "string" && !isHostFile(value)) throw new DefinitionError(`${key} must be a string or file(path)`);
564
- }
565
- if (s.rules !== void 0 && typeof s.rules !== "string" && !isHostFile(s.rules)) throw new DefinitionError(`rules in ${where} must be markdown or file(path)`);
566
- return structuredClone(s);
567
- }
568
- function buildSpec(input, where, base) {
569
- const spec = typeof input === "function" ? input(helpersFor(base)) : input;
570
- if (spec instanceof Promise || typeof spec?.then === "function") throw new DefinitionError(`${where} returned a Promise. The callback runs once at definition time and must return the environment synchronously; fetch remote content in a setup step instead.`);
571
- return checkSpec(spec, where);
572
- }
573
- function makeEnvironment(name, layers) {
574
- const env = {
575
- kind: "environment",
576
- name,
577
- layers: Object.freeze(layers)
578
- };
579
- const extend = (child, input) => {
580
- checkName(child, `${name}.extend`);
581
- const where = `${name}.extend("${child}")`;
582
- const base = callerDir() ?? process.cwd();
583
- return makeEnvironment(child, [...layers, {
584
- name: child,
585
- spec: buildSpec(input, where, base)
586
- }]);
587
- };
588
- Object.defineProperty(env, "extendEnvironment", {
589
- enumerable: false,
590
- value: extend
591
- });
592
- Object.defineProperty(env, "extend", {
593
- enumerable: false,
594
- value: extend
595
- });
596
- return Object.freeze(env);
597
- }
598
- function checkName(name, what) {
599
- if (typeof name !== "string" || !NAME.test(name)) throw new DefinitionError(`${what} needs a name of letters, digits, ".", "_", "@", "+" or "-" (got ${JSON.stringify(name)})`);
600
- }
601
- /**
602
- * What an eval runs in: the sandbox, skills, MCP servers, files, rules, variables, secrets and
603
- * setup steps. Pass a spec, or a callback that destructures the typed helpers it needs:
604
- *
605
- * defineEnvironment('genkit', ({ secret, skill }) => ({
606
- * sandbox: docker({ from: 'node:24-bookworm' }),
607
- * env: { GOOGLE_GENAI_API_KEY: secret.fromEnv('GOOGLE_GENERATIVE_AI_API_KEY') },
608
- * skills: [skill.local('../skills/genkit')],
609
- * }))
610
- *
611
- * The callback runs once, synchronously. Relative paths resolve against the calling file.
612
- * `extend` / `extendEnvironment` replace `sandbox` entirely when the child sets one; when
613
- * the child omits it, the parent's sandbox is kept. A bare `defineEnvironment('plain', {})`
614
- * that is not an extend uses the cascaded option sandbox, else implicit Docker.
615
- */
616
- function defineEnvironment(name, input) {
617
- checkName(name, "defineEnvironment");
618
- const base = callerDir() ?? process.cwd();
619
- return makeEnvironment(name, [{
620
- name,
621
- spec: buildSpec(input, `defineEnvironment("${name}")`, base)
622
- }]);
623
- }
624
- /** The control of a compare without a `baseline` when nothing in the cascade sets an environment. */
625
- const EMPTY_BASELINE = "baseline";
626
- /**
627
- * An environment with no layers. As a compare's empty control it uses the first
628
- * variant's sandbox when that variant sets one, else the cascaded option sandbox,
629
- * else the implicit default Docker sandbox.
630
- */
631
- const emptyEnvironment = (name) => makeEnvironment(name, []);
632
- /** The last layer that sets `sandbox`, else `fallback` (the cascaded option sandbox). */
633
- const sandboxOf = (layers, fallback) => layers.findLast((l) => l.spec.sandbox)?.spec.sandbox ?? fallback;
634
- /** The sandbox an environment names, else `fallback`. */
635
- const environmentSandbox = (env, fallback) => sandboxOf(env?.layers ?? [], fallback);
636
- function checkSandbox(value, where) {
637
- const kind = value?.kind;
638
- if (kind !== "docker" && kind !== "fake") throw new DefinitionError(`sandbox in ${where} must come from docker() or fakeSandbox() (got ${JSON.stringify(value)})`);
639
- const max = value.maxConcurrent;
640
- if (max !== void 0 && !(Number.isInteger(max) && max >= 1)) throw new DefinitionError(`sandbox.maxConcurrent in ${where} must be a whole number of at least 1 (got ${String(max)})`);
641
- }
642
- function applied(env) {
643
- if (!env) return {
644
- name: "-",
645
- parent: null,
646
- layers: []
647
- };
648
- return {
649
- name: env.name,
650
- parent: env.layers.at(-2)?.name ?? null,
651
- layers: [...env.layers]
652
- };
653
- }
654
- //#endregion
655
- export { stepCommand as C, workspaceOf as E, sandboxOf as S, workspaceLabel as T, isSecret as _, callerDir as a, parseGitRepo as b, defineEnvironment as c, filesOf as d, globFilter as f, isMovingRef as g, isHostFile as h, applied as i, emptyEnvironment as l, isEnvironment as m, DEFAULT_SKILL_EXCLUDE as n, checkEgress as o, helpersFor as p, EMPTY_BASELINE as r, checkEnv as s, DEFAULT_DIRECTORY_IGNORES as t, environmentSandbox as u, isSecretTemplate as v, unbrokeredSecrets as w, plannedSecrets as x, mcpHosts as y };
656
-
657
- //# sourceMappingURL=environment-1jE-HhO-.js.map