reeval 0.7.0 → 0.9.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.
- package/README.md +12 -12
- package/dist/{agent-Dhd5FJCZ.js → agent-6FefIhX7.js} +6 -6
- package/dist/{agent-Dhd5FJCZ.js.map → agent-6FefIhX7.js.map} +1 -1
- package/dist/{agent-gjBiZis8.js → agent-WSmTaesf.js} +52 -17
- package/dist/agent-WSmTaesf.js.map +1 -0
- package/dist/{analysis-BV3TCznv.js → analysis-DlGBDjTj.js} +4 -4
- package/dist/{analysis-BV3TCznv.js.map → analysis-DlGBDjTj.js.map} +1 -1
- package/dist/{assemble-Dd_mZYnu.js → assemble-BCZzTyR7.js} +259 -18
- package/dist/assemble-BCZzTyR7.js.map +1 -0
- package/dist/assemble-C5qq5yT2.js +2 -0
- package/dist/capture-Bp74Z6Fr.js +1257 -0
- package/dist/capture-Bp74Z6Fr.js.map +1 -0
- package/dist/capture-DS-cPyuE.js +2 -0
- package/dist/{cli-r9CDqoFL.js → cli-CVrMh_qz.js} +210 -112
- package/dist/cli-CVrMh_qz.js.map +1 -0
- package/dist/{cli-spec-DOyxAMc2.js → cli-spec-CKEYa8V2.js} +6 -5
- package/dist/cli-spec-CKEYa8V2.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{client-LsfDiD-X.js → client-Bbo9SPlK.js} +31 -201
- package/dist/client-Bbo9SPlK.js.map +1 -0
- package/dist/{command-l4ZFCeMh.js → command-BFP0hKEb.js} +7 -7
- package/dist/{command-l4ZFCeMh.js.map → command-BFP0hKEb.js.map} +1 -1
- package/dist/command-BrmXUC-W.js +2 -0
- package/dist/{command-DMR69l5G.js → command-C5xFPKHM.js} +21 -20
- package/dist/command-C5xFPKHM.js.map +1 -0
- package/dist/{command-Cej2t3y-.js → command-CzIFp1JQ.js} +10 -10
- package/dist/{command-Cej2t3y-.js.map → command-CzIFp1JQ.js.map} +1 -1
- package/dist/{command-D6r2pwO5.js → command-DUT5l13I.js} +221 -54
- package/dist/command-DUT5l13I.js.map +1 -0
- package/dist/{commands-BA_NCh2h.js → commands-CLmPBrTS.js} +6 -6
- package/dist/{commands-BA_NCh2h.js.map → commands-CLmPBrTS.js.map} +1 -1
- package/dist/{commands-DgOUkcSO.js → commands-fI3G2Wnh.js} +1 -1
- package/dist/{config-DuQDCx0B.js → config-CGvBeewH.js} +18 -8
- package/dist/config-CGvBeewH.js.map +1 -0
- package/dist/{context-CvUv7DUb.js → context-DbSMEVKs.js} +1 -5
- package/dist/{context-CvUv7DUb.js.map → context-DbSMEVKs.js.map} +1 -1
- package/dist/{db-o_osRkqr.js → db-CSSFtGcN.js} +1 -1
- package/dist/{db-CjX7JF4o.js → db-CfQFwJtq.js} +209 -40
- package/dist/db-CfQFwJtq.js.map +1 -0
- package/dist/{docker-DaUaG4XZ.js → docker-CRQGQbIt.js} +17 -5
- package/dist/docker-CRQGQbIt.js.map +1 -0
- package/dist/{docker-ZaYeKE2w.js → docker-DV2GNgle.js} +2 -2
- package/dist/{docker-ZaYeKE2w.js.map → docker-DV2GNgle.js.map} +1 -1
- package/dist/{docker-Dnya8eo9.js → docker-Df_YOxxB.js} +1 -1
- package/dist/{doctor-Bk6aJeec.js → doctor-DlKycx5H.js} +13 -13
- package/dist/{doctor-Bk6aJeec.js.map → doctor-DlKycx5H.js.map} +1 -1
- package/dist/{egress-BKbyriEa.js → egress-BhzNh7Yi.js} +18 -10
- package/dist/egress-BhzNh7Yi.js.map +1 -0
- package/dist/{environment-DiCljXMD.js → environment-1jE-HhO-.js} +2 -2
- package/dist/{environment-DiCljXMD.js.map → environment-1jE-HhO-.js.map} +1 -1
- package/dist/fake-instructions-CUI33I_F.js +32 -0
- package/dist/fake-instructions-CUI33I_F.js.map +1 -0
- package/dist/family-D2b7WD10.js +67 -0
- package/dist/family-D2b7WD10.js.map +1 -0
- package/dist/files-AiEKuEZe.js +2 -0
- package/dist/files-BMCvfB4X.js +2 -0
- package/dist/{files-TNrZJQ3Y.js → files-CSzVADHn.js} +5 -5
- package/dist/{files-TNrZJQ3Y.js.map → files-CSzVADHn.js.map} +1 -1
- package/dist/{files-BSMSnQMa.js → files-DJUFg-4e.js} +3 -3
- package/dist/{files-BSMSnQMa.js.map → files-DJUFg-4e.js.map} +1 -1
- package/dist/{git-DNGtrOg9.js → git-DfG-YJ1u.js} +2 -2
- package/dist/{git-DNGtrOg9.js.map → git-DfG-YJ1u.js.map} +1 -1
- package/dist/{harness-CDRaaGvR.js → harness-CeCp2GSW.js} +52 -12
- package/dist/harness-CeCp2GSW.js.map +1 -0
- package/dist/harness.d.ts +26 -13
- package/dist/harness.js +1 -1
- package/dist/{header-BZF8Xss1.js → header-CALhmafp.js} +10 -3
- package/dist/{header-BZF8Xss1.js.map → header-CALhmafp.js.map} +1 -1
- package/dist/{images-BpwFDT1E.js → images-BMgdpMAX.js} +6 -6
- package/dist/{images-BpwFDT1E.js.map → images-BMgdpMAX.js.map} +1 -1
- package/dist/index.d.ts +17 -5
- package/dist/index.js +165 -67
- package/dist/index.js.map +1 -1
- package/dist/init-B6vegaP_.js +2 -0
- package/dist/{init-CBWt1rZT.js → init-BIdLF0F9.js} +4 -4
- package/dist/{init-CBWt1rZT.js.map → init-BIdLF0F9.js.map} +1 -1
- package/dist/{invocations-DArYWyXN.js → invocations-CLaL8AuW.js} +3 -3
- package/dist/{invocations-DArYWyXN.js.map → invocations-CLaL8AuW.js.map} +1 -1
- package/dist/{judge-7WjNdU9z.js → judge-CeYPN8P_.js} +2 -2
- package/dist/{judge-7WjNdU9z.js.map → judge-CeYPN8P_.js.map} +1 -1
- package/dist/judge.d.ts +5 -4
- package/dist/judge.js +4 -3
- package/dist/judge.js.map +1 -1
- package/dist/{live-DZkCtmNP.js → live-S0qODb6o.js} +2 -2
- package/dist/{live-DZkCtmNP.js.map → live-S0qODb6o.js.map} +1 -1
- package/dist/{model-Cp6NoAT3.js → model-B1BZoZ9b.js} +9 -8
- package/dist/model-B1BZoZ9b.js.map +1 -0
- package/dist/{model-DyQbu7KF.js → model-BOnlAPzs.js} +288 -38
- package/dist/model-BOnlAPzs.js.map +1 -0
- package/dist/{model-Bv8uUZ07.js → model-DEQo3FkZ.js} +6 -6
- package/dist/model-DEQo3FkZ.js.map +1 -0
- package/dist/model-DWeg5J7z.js +2 -0
- package/dist/{model-BeoRxCcJ.js → model-FXko2kl7.js} +1 -1
- package/dist/{options-Ge_x32XE.js → options-CKqyPGxX.js} +161 -34
- package/dist/options-CKqyPGxX.js.map +1 -0
- package/dist/pairs-DDsjgm5F.js +149 -0
- package/dist/pairs-DDsjgm5F.js.map +1 -0
- package/dist/{patch-CGCVipPu.js → patch-bDV8YFW0.js} +2 -2
- package/dist/{patch-CGCVipPu.js.map → patch-bDV8YFW0.js.map} +1 -1
- package/dist/{plan-BqBadHYj.js → plan-DUydFc_1.js} +69 -31
- package/dist/plan-DUydFc_1.js.map +1 -0
- package/dist/{preflight-CyaAZE9r.js → preflight-BkoSxf4C.js} +3 -3
- package/dist/{preflight-CyaAZE9r.js.map → preflight-BkoSxf4C.js.map} +1 -1
- package/dist/{preflight-CFtZNTLt.js → preflight-D5LW7Oqi.js} +1 -1
- package/dist/{prepare-Zr1xOMUX.js → prepare-CUAWHebF.js} +5 -5
- package/dist/{prepare-Zr1xOMUX.js.map → prepare-CUAWHebF.js.map} +1 -1
- package/dist/{prepare-Dl7-t3fO.js → prepare-oji2oO8W.js} +2 -2
- package/dist/process-CSVO_jsc.js +119 -0
- package/dist/process-CSVO_jsc.js.map +1 -0
- package/dist/{provenance-Byl2T6LJ.js → provenance-D7HK3vzt.js} +2 -2
- package/dist/{provenance-Byl2T6LJ.js.map → provenance-D7HK3vzt.js.map} +1 -1
- package/dist/{providers-Cflw7Ks-.js → providers-B1DzMvmH.js} +3 -3
- package/dist/{providers-Cflw7Ks-.js.map → providers-B1DzMvmH.js.map} +1 -1
- package/dist/{providers-SBMExI53.js → providers-CpEfNU1F.js} +1 -1
- package/dist/{query-DUSLlic0.js → query-BjBMLa-C.js} +2 -2
- package/dist/{query-DUSLlic0.js.map → query-BjBMLa-C.js.map} +1 -1
- package/dist/query-oPO_XrTy.js +2 -0
- package/dist/{questions-ZdT3JDyQ.js → questions-B8by4Bbt.js} +28 -119
- package/dist/questions-B8by4Bbt.js.map +1 -0
- package/dist/{record-CbuQH4l1.js → record-BRP9vZrj.js} +21 -1
- package/dist/record-BRP9vZrj.js.map +1 -0
- package/dist/{results-owJR-NFm.js → results-Di7m8dQ3.js} +4 -4
- package/dist/{results-owJR-NFm.js.map → results-Di7m8dQ3.js.map} +1 -1
- package/dist/{resume-BL4Yw7Ld.js → resume-SUz1GskV.js} +4 -4
- package/dist/{resume-BL4Yw7Ld.js.map → resume-SUz1GskV.js.map} +1 -1
- package/dist/runtime-DdsfnRz_.js +344 -0
- package/dist/runtime-DdsfnRz_.js.map +1 -0
- package/dist/{sandbox--ZXuscAZ.js → sandbox-D5v-of6d.js} +10 -5
- package/dist/sandbox-D5v-of6d.js.map +1 -0
- package/dist/sandbox.d.ts +4 -3
- package/dist/sandbox.js +1 -1
- package/dist/{server-yFVUxAm0.js → server-BNnXtmS8.js} +9 -9
- package/dist/{server-yFVUxAm0.js.map → server-BNnXtmS8.js.map} +1 -1
- package/dist/server-BNwoKzlm.js +2 -0
- package/dist/source-Bk_0ZaEY.js +2 -0
- package/dist/{source-M3gS517R.js → source-Dof0NQBm.js} +2 -2
- package/dist/{source-M3gS517R.js.map → source-Dof0NQBm.js.map} +1 -1
- package/dist/{src-79JhW-zG.js → src-8rRXy4u9.js} +71 -124
- package/dist/src-8rRXy4u9.js.map +1 -0
- package/dist/src-BGWuWp6I.js +3 -0
- package/dist/src-BRt0O02i.js +3 -0
- package/dist/src-Bx2x1ekD.js +3 -0
- package/dist/{src-s-VffoYK.js → src-C1E9HDWO.js} +5 -3
- package/dist/{src-s-VffoYK.js.map → src-C1E9HDWO.js.map} +1 -1
- package/dist/{src-IOr1rhEg.js → src-COgE7991.js} +10 -8
- package/dist/{src-IOr1rhEg.js.map → src-COgE7991.js.map} +1 -1
- package/dist/{src-CokPbYCb.js → src-C_4Umgh2.js} +23 -14
- package/dist/{src-CokPbYCb.js.map → src-C_4Umgh2.js.map} +1 -1
- package/dist/{src-DxFJrMUA.js → src-D95O-Smv.js} +12 -7
- package/dist/{src-DxFJrMUA.js.map → src-D95O-Smv.js.map} +1 -1
- package/dist/{src-DTcalvuF.js → src-DDNXsD9H.js} +28 -4
- package/dist/{src-DTcalvuF.js.map → src-DDNXsD9H.js.map} +1 -1
- package/dist/src-DLa-ESW0.js +4 -0
- package/dist/{src-DSE0FWaU.js → src-DVy58-zZ.js} +2 -2
- package/dist/{src-DSE0FWaU.js.map → src-DVy58-zZ.js.map} +1 -1
- package/dist/src-cN0aB-WR.js +3 -0
- package/dist/{src-DH0jhpoi.js → src-cdIVjC5b.js} +1 -1
- package/dist/src-sIsDHWYq.js +3 -0
- package/dist/state-Bo5zg4da.js +2 -0
- package/dist/{state-DEj_utaE.js → state-CiXyLqg0.js} +10 -10
- package/dist/{state-DEj_utaE.js.map → state-CiXyLqg0.js.map} +1 -1
- package/dist/studio-app/assets/index-B9MCTfuu.css +2 -0
- package/dist/studio-app/assets/{index-Bbl0oTxu.js → index-CROH2NB3.js} +12 -12
- package/dist/studio-app/index.html +2 -2
- package/dist/{summary-D012KlUM.js → summary-2OAWF2N7.js} +7 -7
- package/dist/{summary-D012KlUM.js.map → summary-2OAWF2N7.js.map} +1 -1
- package/dist/{summary--FBuB_sr.js → summary-BTksrIxn.js} +63 -5
- package/dist/summary-BTksrIxn.js.map +1 -0
- package/dist/testing.d.ts +14 -0
- package/dist/testing.js +2 -0
- package/dist/{tools-CJHw-zCo.js → tools-B10Uj7OI.js} +4 -4
- package/dist/tools-B10Uj7OI.js.map +1 -0
- package/dist/types-C5vI3g1C.js.map +1 -1
- package/dist/{types-BsRSknLe.d.ts → types-D8RLfkFP.d.ts} +453 -42
- package/dist/{usage-DsYUqIUM.js → usage-DDF_6tkV.js} +4 -2
- package/dist/{usage-DsYUqIUM.js.map → usage-DDF_6tkV.js.map} +1 -1
- package/dist/view/index.d.ts +60 -15
- package/dist/view/index.js +7 -6
- package/dist/views-Cs2Oqayd.js +3 -0
- package/dist/{views-jhL9Jb8A.js → views-Dqa5ojfZ.js} +4 -4
- package/dist/{views-jhL9Jb8A.js.map → views-Dqa5ojfZ.js.map} +1 -1
- package/dist/{worker-entry-OwnsrUdr.js → worker-entry-BAikHl9F.js} +9 -4
- package/dist/worker-entry-BAikHl9F.js.map +1 -0
- package/dist/{workspace-C4_J0pqb.js → workspace-C-TrNIUc.js} +4 -4
- package/dist/{workspace-C4_J0pqb.js.map → workspace-C-TrNIUc.js.map} +1 -1
- package/dist/{workspace-wudSz_W-.js → workspace-Do_SiWBs.js} +1 -1
- package/docker/Dockerfile +7 -5
- package/package.json +9 -4
- package/dist/agent-gjBiZis8.js.map +0 -1
- package/dist/assemble-D8sZ4Jiv.js +0 -2
- package/dist/assemble-Dd_mZYnu.js.map +0 -1
- package/dist/capture-CisAmy-G.js +0 -587
- package/dist/capture-CisAmy-G.js.map +0 -1
- package/dist/capture-DquyqAHC.js +0 -2
- package/dist/cli-r9CDqoFL.js.map +0 -1
- package/dist/cli-spec-DOyxAMc2.js.map +0 -1
- package/dist/client-LsfDiD-X.js.map +0 -1
- package/dist/command-Cxfgghqo.js +0 -2
- package/dist/command-D6r2pwO5.js.map +0 -1
- package/dist/command-DMR69l5G.js.map +0 -1
- package/dist/config-DuQDCx0B.js.map +0 -1
- package/dist/db-CjX7JF4o.js.map +0 -1
- package/dist/docker-DaUaG4XZ.js.map +0 -1
- package/dist/egress-BKbyriEa.js.map +0 -1
- package/dist/files-DmZGPsWK.js +0 -2
- package/dist/files-Tb8wY0Ze.js +0 -2
- package/dist/harness-CDRaaGvR.js.map +0 -1
- package/dist/init-1THeGfut.js +0 -2
- package/dist/model-Bv8uUZ07.js.map +0 -1
- package/dist/model-Cp6NoAT3.js.map +0 -1
- package/dist/model-D_pF3Vcl.js +0 -2
- package/dist/model-DyQbu7KF.js.map +0 -1
- package/dist/options-Ge_x32XE.js.map +0 -1
- package/dist/plan-BqBadHYj.js.map +0 -1
- package/dist/query-CvutWHaL.js +0 -2
- package/dist/questions-ZdT3JDyQ.js.map +0 -1
- package/dist/record-CbuQH4l1.js.map +0 -1
- package/dist/sandbox--ZXuscAZ.js.map +0 -1
- package/dist/server-CNPsB0cT.js +0 -2
- package/dist/source-Cmc5SKFn.js +0 -2
- package/dist/src--L8B4WGa.js +0 -3
- package/dist/src-79JhW-zG.js.map +0 -1
- package/dist/src-BLN459er.js +0 -3
- package/dist/src-Bz66jDtE.js +0 -3
- package/dist/src-CfUwg9UY.js +0 -3
- package/dist/src-DV_3QDHA.js +0 -4
- package/dist/src-Ljh2vKXm.js +0 -3
- package/dist/state-DkqbCVVp.js +0 -2
- package/dist/studio-app/assets/index-CUx6GoL5.css +0 -2
- package/dist/summary--FBuB_sr.js.map +0 -1
- package/dist/tools-CJHw-zCo.js.map +0 -1
- package/dist/views-yPmmoo8f.js +0 -3
- package/dist/worker-entry-OwnsrUdr.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as HarnessCapabilityError, r as withLease } from "./client-Bbo9SPlK.js";
|
|
2
2
|
import { n as UsageError, r as isTimeout, t as TimeoutError } from "./errors-yDAEwmZo.js";
|
|
3
3
|
import { t as parseDuration } from "./duration-JsJrIWXq.js";
|
|
4
4
|
import { t as inCI } from "./env-BQqj93gu.js";
|
|
5
5
|
import { o as redactSecrets, s as registerSecret } from "./redact-DJ9JCShu.js";
|
|
6
|
-
import { C as stepCommand, E as workspaceOf, T as workspaceLabel, _ as isSecret, b as parseGitRepo, c as defineEnvironment, d as filesOf, h as isHostFile, n as DEFAULT_SKILL_EXCLUDE, t as DEFAULT_DIRECTORY_IGNORES, v as isSecretTemplate, y as mcpHosts } from "./environment-
|
|
6
|
+
import { C as stepCommand, E as workspaceOf, T as workspaceLabel, _ as isSecret, b as parseGitRepo, c as defineEnvironment, d as filesOf, h as isHostFile, n as DEFAULT_SKILL_EXCLUDE, t as DEFAULT_DIRECTORY_IGNORES, v as isSecretTemplate, y as mcpHosts } from "./environment-1jE-HhO-.js";
|
|
7
7
|
import { t as InfraError } from "./types-C5vI3g1C.js";
|
|
8
|
-
import { _ as layoutOf, a as unenforceable, h as expectedBlockedFor, n as allowedHosts, o as createFakeSandbox, p as brokeringFor, r as egressLabel, t as DEFAULT_EGRESS_ALLOW, v as refusedMcp } from "./egress-
|
|
8
|
+
import { _ as layoutOf, a as unenforceable, h as expectedBlockedFor, n as allowedHosts, o as createFakeSandbox, p as brokeringFor, r as egressLabel, t as DEFAULT_EGRESS_ALLOW, v as refusedMcp } from "./egress-BhzNh7Yi.js";
|
|
9
9
|
import { c as relativeFile, i as evalSlug, l as sha256, n as attemptKey, r as evalId, s as recordFileName, t as attemptId } from "./ids-Bp6ut7ZD.js";
|
|
10
|
-
import { c as judgeModelName, d as isApiError, i as badJudgeList, u as runJudge } from "./judge-
|
|
11
|
-
import { S as placeholder
|
|
12
|
-
import {
|
|
13
|
-
import { n as
|
|
10
|
+
import { c as judgeModelName, d as isApiError, i as badJudgeList, u as runJudge } from "./judge-CeYPN8P_.js";
|
|
11
|
+
import { S as placeholder } from "./src-8rRXy4u9.js";
|
|
12
|
+
import { n as shellQuote, t as run } from "./process-CSVO_jsc.js";
|
|
13
|
+
import { a as evalPlan, d as sandboxId, f as sandboxSetBy, h as unbrokeredError, i as checkOptions, l as matchesTags, m as unbrokered, n as cascade, o as expand, p as secretVarsIn, s as harnessId, t as brokeredIn } from "./options-CKqyPGxX.js";
|
|
14
|
+
import { n as badCharacterAt, s as defineConfig } from "./config-CGvBeewH.js";
|
|
15
|
+
import { i as registerTest, n as getRunContext, o as SUBJECT, r as registerGroup, t as collectingFile, u as expect } from "./runtime-DdsfnRz_.js";
|
|
14
16
|
import { a as withDebug, i as debugTrace, n as attemptDebug, r as debugLog, t as AttemptDebug } from "./attempt-CGPV3BZY.js";
|
|
15
17
|
import { t as attemptDebugDir } from "./files-Ca0d6Uq3.js";
|
|
16
18
|
import { n as clip, r as formatDuration, t as capMiddle } from "./text-gEcKjAyp.js";
|
|
17
|
-
import { a as asCheck, i as writeCaptureSidecars, n as serveCommand, o as createChecks, t as capturePage } from "./capture-
|
|
18
|
-
import { t as contextTaker } from "./context-
|
|
19
|
+
import { a as asCheck, c as snapshot, i as writeCaptureSidecars, n as serveCommand, o as createChecks, s as diffSinceSnapshot, t as capturePage } from "./capture-Bp74Z6Fr.js";
|
|
20
|
+
import { t as contextTaker } from "./context-DbSMEVKs.js";
|
|
19
21
|
import { t as PrepareError } from "./provider-CmAYTQQs.js";
|
|
20
|
-
import { i as preparedWorkspace } from "./workspace-
|
|
21
|
-
import { n as judgeDiff } from "./patch-
|
|
22
|
+
import { i as preparedWorkspace } from "./workspace-C-TrNIUc.js";
|
|
23
|
+
import { n as judgeDiff } from "./patch-bDV8YFW0.js";
|
|
22
24
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
23
25
|
import { basename, isAbsolute, join, relative, sep } from "node:path";
|
|
24
26
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
@@ -864,7 +866,7 @@ async function callMcpTool(sandbox, servers, name, tool, signal) {
|
|
|
864
866
|
//#region src/harness/index.ts
|
|
865
867
|
async function createHarness(descriptor) {
|
|
866
868
|
if (descriptor.kind === "fake") return createFakeHarness(descriptor);
|
|
867
|
-
const { createAgentHarness } = await import("./agent-
|
|
869
|
+
const { createAgentHarness } = await import("./agent-WSmTaesf.js");
|
|
868
870
|
return createAgentHarness(descriptor);
|
|
869
871
|
}
|
|
870
872
|
/** Where each harness's agent looks for repo skills, relative to the workspace. */
|
|
@@ -891,8 +893,8 @@ async function prepareEnvironment(a, root, runId, where, signal) {
|
|
|
891
893
|
if (debug) traceEnvironment(debug, spec, env);
|
|
892
894
|
record.image = null;
|
|
893
895
|
if (spec.sandbox.kind === "docker") {
|
|
894
|
-
const { preparedFor } = await import("./preflight-
|
|
895
|
-
const { dockerProvider } = await import("./providers-
|
|
896
|
+
const { preparedFor } = await import("./preflight-D5LW7Oqi.js");
|
|
897
|
+
const { dockerProvider } = await import("./providers-CpEfNU1F.js");
|
|
896
898
|
signal.throwIfAborted();
|
|
897
899
|
const prepared = preparedFor(root, runId, dockerProvider(), spec.sandbox, spec.harness);
|
|
898
900
|
if (!prepared) throw new InfraError(`The sandbox image for ${where} wasn't prepared before the run started`);
|
|
@@ -903,6 +905,62 @@ async function prepareEnvironment(a, root, runId, where, signal) {
|
|
|
903
905
|
} else debugLog("image", `none: the ${spec.sandbox.kind} sandbox runs on the host`);
|
|
904
906
|
}
|
|
905
907
|
//#endregion
|
|
908
|
+
//#region src/judge/artifacts.ts
|
|
909
|
+
/** A capture handle: a name plus the file the attempt wrote. */
|
|
910
|
+
function isCaptureHandle(value) {
|
|
911
|
+
if (typeof value !== "object" || value === null) return false;
|
|
912
|
+
const v = value;
|
|
913
|
+
return typeof v.name === "string" && typeof v.file?.path === "string";
|
|
914
|
+
}
|
|
915
|
+
/** The first `artifacts` value that isn't a list of capture handles or names. */
|
|
916
|
+
function badJudgeArtifacts(artifacts) {
|
|
917
|
+
if (artifacts === void 0) return void 0;
|
|
918
|
+
if (!Array.isArray(artifacts)) return `must be a list of capture handles or names (got ${JSON.stringify(artifacts)})`;
|
|
919
|
+
for (const item of artifacts) {
|
|
920
|
+
if (typeof item === "string" && item.trim()) continue;
|
|
921
|
+
if (isCaptureHandle(item)) continue;
|
|
922
|
+
return `must be a list of capture handles or names (got ${JSON.stringify(item)})`;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
const nameOf = (item) => typeof item === "string" ? item.trim() : item.name;
|
|
926
|
+
/**
|
|
927
|
+
* Resolves call `artifacts` (a capture handle or its name) to PNG bytes this attempt captured.
|
|
928
|
+
* Unknown names throw: a mistake in the call, before the provider is asked.
|
|
929
|
+
*/
|
|
930
|
+
function resolveJudgeArtifacts(artifacts, blobs) {
|
|
931
|
+
if (!artifacts?.length) return [];
|
|
932
|
+
return artifacts.map((item) => {
|
|
933
|
+
const name = nameOf(item);
|
|
934
|
+
const data = blobs.get(name);
|
|
935
|
+
if (!data) throw new Error(`c.judge() artifacts names a capture this attempt doesn't have: ${JSON.stringify(name)}`);
|
|
936
|
+
return {
|
|
937
|
+
name,
|
|
938
|
+
path: `artifacts/${name}.png`,
|
|
939
|
+
sha256: sha256(data),
|
|
940
|
+
bytes: data.byteLength,
|
|
941
|
+
mediaType: "image/png",
|
|
942
|
+
data
|
|
943
|
+
};
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
const filePartsOf = (resolved) => resolved.map((a) => ({
|
|
947
|
+
type: "file",
|
|
948
|
+
mediaType: a.mediaType,
|
|
949
|
+
data: a.data
|
|
950
|
+
}));
|
|
951
|
+
const artifactRefsOf = (resolved) => resolved.map(({ data: _data, ...ref }) => ref);
|
|
952
|
+
/**
|
|
953
|
+
* JSON-only state stays an object so TypeSafe and other JSON judges are unchanged.
|
|
954
|
+
* File parts are an ordered decide-state array: one JSON part, then each capture.
|
|
955
|
+
*/
|
|
956
|
+
function decideState(json, files) {
|
|
957
|
+
if (files.length === 0) return json;
|
|
958
|
+
return [{
|
|
959
|
+
type: "json",
|
|
960
|
+
value: json
|
|
961
|
+
}, ...files];
|
|
962
|
+
}
|
|
963
|
+
//#endregion
|
|
906
964
|
//#region src/judge/size.ts
|
|
907
965
|
/** Roughly four characters a token, as `reeval analyze` counts: an estimate, not the model's. */
|
|
908
966
|
const CHARS_PER_TOKEN = 4;
|
|
@@ -989,12 +1047,14 @@ async function judgeState(turn, output, { include, files }, readFile) {
|
|
|
989
1047
|
* checks after it still run.
|
|
990
1048
|
*/
|
|
991
1049
|
function judgeCaller(a, readFile) {
|
|
992
|
-
|
|
1050
|
+
const ask = async (question, { on, ...call } = {}) => {
|
|
993
1051
|
if (typeof question !== "string" || !question.trim()) throw new Error(`c.judge() needs a question: a non-empty string (got ${JSON.stringify(question)})`);
|
|
994
1052
|
const { threshold } = call;
|
|
995
1053
|
if (threshold !== void 0 && !(typeof threshold === "number" && threshold >= 0 && threshold <= 1)) throw new Error(`c.judge() threshold must be between 0 and 1 (got ${String(threshold)})`);
|
|
996
1054
|
const bad = badJudgeList(call);
|
|
997
1055
|
if (bad) throw new Error(`c.judge() ${bad.key} must be a list of non-empty strings (got ${bad.got})`);
|
|
1056
|
+
const badArts = badJudgeArtifacts(call.artifacts);
|
|
1057
|
+
if (badArts) throw new Error(`c.judge() artifacts ${badArts}`);
|
|
998
1058
|
const subject = isTurn(on) ? on : a.turns.at(-1);
|
|
999
1059
|
if (!subject) throw new Error("c.judge() has no turn to grade: call c.send() first");
|
|
1000
1060
|
const options = {
|
|
@@ -1011,11 +1071,15 @@ function judgeCaller(a, readFile) {
|
|
|
1011
1071
|
include,
|
|
1012
1072
|
files
|
|
1013
1073
|
}, readFile);
|
|
1074
|
+
const resolved = resolveJudgeArtifacts(call.artifacts, a.artifactBlobs);
|
|
1075
|
+
const refs = artifactRefsOf(resolved);
|
|
1076
|
+
const decide = decideState(state, filePartsOf(resolved));
|
|
1014
1077
|
const name = judgeModelName(model);
|
|
1015
1078
|
const input = {
|
|
1016
1079
|
question,
|
|
1017
1080
|
model: name,
|
|
1018
1081
|
state,
|
|
1082
|
+
...refs.length ? { artifacts: refs } : {},
|
|
1019
1083
|
...dropped.length ? { dropped } : {}
|
|
1020
1084
|
};
|
|
1021
1085
|
a.record.judgeInputs?.push(input);
|
|
@@ -1053,20 +1117,25 @@ function judgeCaller(a, readFile) {
|
|
|
1053
1117
|
threshold: atLeast,
|
|
1054
1118
|
question,
|
|
1055
1119
|
model: name,
|
|
1056
|
-
error: message
|
|
1120
|
+
error: message,
|
|
1121
|
+
...refs.length ? { artifacts: refs } : {}
|
|
1057
1122
|
};
|
|
1058
1123
|
};
|
|
1059
1124
|
const provider = name.split("/")[0];
|
|
1060
1125
|
try {
|
|
1061
|
-
const { verdict, retries } = await a.timed("judgeMs", () => withLease(maxConcurrent ? { [`judge:${provider}`]: maxConcurrent } : {}, () => runJudge(question,
|
|
1126
|
+
const { verdict, retries } = await a.timed("judgeMs", () => withLease(maxConcurrent ? { [`judge:${provider}`]: maxConcurrent } : {}, () => runJudge(question, decide, {
|
|
1062
1127
|
...judgeOptions,
|
|
1063
1128
|
model,
|
|
1064
1129
|
threshold: atLeast
|
|
1065
1130
|
}, a.signal), a.signal));
|
|
1066
|
-
|
|
1131
|
+
const recorded = refs.length ? {
|
|
1067
1132
|
...verdict,
|
|
1133
|
+
artifacts: refs
|
|
1134
|
+
} : verdict;
|
|
1135
|
+
a.record.judgements.push(retries.length ? {
|
|
1136
|
+
...recorded,
|
|
1068
1137
|
retries
|
|
1069
|
-
} :
|
|
1138
|
+
} : recorded);
|
|
1070
1139
|
const { score } = verdict;
|
|
1071
1140
|
debugLog("judge", `${verdict.resolvedModel ?? verdict.model} · ${formatDuration(ms())} · score ${score.toFixed(2)} ${score >= verdict.threshold ? "≥" : "<"} ${verdict.threshold} · ${verdict.verdict}${retries.length ? ` · ${retries.length} retries` : ""} · reason: P(yes) ${score.toFixed(2)} is ${score >= verdict.threshold ? "at or above" : "below"} the ${verdict.threshold} threshold`);
|
|
1072
1141
|
debugTrace("judge", "response", {
|
|
@@ -1081,7 +1150,7 @@ function judgeCaller(a, readFile) {
|
|
|
1081
1150
|
threshold: verdict.threshold,
|
|
1082
1151
|
ms: ms()
|
|
1083
1152
|
});
|
|
1084
|
-
return
|
|
1153
|
+
return recorded;
|
|
1085
1154
|
} catch (error) {
|
|
1086
1155
|
if (a.signal.aborted) {
|
|
1087
1156
|
a.judgeErrored = true;
|
|
@@ -1092,6 +1161,7 @@ function judgeCaller(a, readFile) {
|
|
|
1092
1161
|
return failed(isApiError(error) ? withInputSize(message, state, question) : message, retries);
|
|
1093
1162
|
}
|
|
1094
1163
|
};
|
|
1164
|
+
return async (question, options) => Object.defineProperty(await ask(question, options), SUBJECT, { value: question });
|
|
1095
1165
|
}
|
|
1096
1166
|
//#endregion
|
|
1097
1167
|
//#region src/sandbox/index.ts
|
|
@@ -1100,7 +1170,7 @@ async function createSandbox(descriptor, options) {
|
|
|
1100
1170
|
switch (descriptor.kind) {
|
|
1101
1171
|
case "fake": return await createFakeSandbox(descriptor, options.env);
|
|
1102
1172
|
case "docker": {
|
|
1103
|
-
const { createDockerSandbox } = await import("./docker-
|
|
1173
|
+
const { createDockerSandbox } = await import("./docker-Df_YOxxB.js");
|
|
1104
1174
|
return await createDockerSandbox(descriptor, options);
|
|
1105
1175
|
}
|
|
1106
1176
|
}
|
|
@@ -1156,6 +1226,27 @@ function recordFailure(a, error, timedOut) {
|
|
|
1156
1226
|
record.outcome = record.error.kind === "infra" ? "infra_error" : "fail";
|
|
1157
1227
|
}
|
|
1158
1228
|
/**
|
|
1229
|
+
* A process the kernel killed at the sandbox's memory limit makes the attempt an infra error,
|
|
1230
|
+
* whatever its checks said: the limit, not the agent, decided it. Returns the error to fail it with.
|
|
1231
|
+
*/
|
|
1232
|
+
async function recordOom(a, sandbox) {
|
|
1233
|
+
const oom = await sandbox?.oomKills?.().catch(() => null);
|
|
1234
|
+
const at = oom && `the ${oom.limit} limit${oom.swap ? ` (+${oom.swap} swap)` : ""}`;
|
|
1235
|
+
if (oom) debugLog("teardown", `oom_kill ${oom.kills} at ${at}`);
|
|
1236
|
+
if (!oom?.kills) return void 0;
|
|
1237
|
+
const message = `out of memory: ${oom.kills === 1 ? "1 process" : `${oom.kills} processes`} killed at ${at}; raise docker({ memory })`;
|
|
1238
|
+
a.record.error = {
|
|
1239
|
+
kind: "infra",
|
|
1240
|
+
message,
|
|
1241
|
+
resource: {
|
|
1242
|
+
cause: "oom",
|
|
1243
|
+
kills: oom.kills
|
|
1244
|
+
}
|
|
1245
|
+
};
|
|
1246
|
+
a.record.outcome = "infra_error";
|
|
1247
|
+
return new InfraError(message);
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1159
1250
|
* The attempt's egress policy and, when its sandbox records it, what it contacted and was refused.
|
|
1160
1251
|
* Refused hosts the harness always tries are `expectedBlocked`, summarised in one `-v` line.
|
|
1161
1252
|
*/
|
|
@@ -1212,36 +1303,6 @@ function turnErrors(transcripts) {
|
|
|
1212
1303
|
});
|
|
1213
1304
|
}
|
|
1214
1305
|
//#endregion
|
|
1215
|
-
//#region src/diff.ts
|
|
1216
|
-
const GIT = "git -c user.name=reeval -c user.email=reeval@localhost -c core.hooksPath=/dev/null";
|
|
1217
|
-
/** Records the workspace state before the agent runs, in a git dir outside the workspace. */
|
|
1218
|
-
async function snapshot(sandbox, signal) {
|
|
1219
|
-
const r = await sandbox.exec(`export GIT_DIR="$PWD/../.reeval-git-$(basename "$PWD")" GIT_WORK_TREE="$PWD" && ${GIT} init -q && ${GIT} add -A && ${GIT} commit -q --allow-empty -m base`, { signal });
|
|
1220
|
-
if (r.exitCode !== 0) throw new InfraError(`Failed to snapshot the workspace: ${r.stderr.trim()}`);
|
|
1221
|
-
}
|
|
1222
|
-
async function diffSinceSnapshot(sandbox, signal) {
|
|
1223
|
-
const env = `export GIT_DIR="$PWD/../.reeval-git-$(basename "$PWD")" GIT_WORK_TREE="$PWD" && ${GIT} add -A && `;
|
|
1224
|
-
const patch = await sandbox.exec(`${env}${GIT} diff --cached --binary HEAD`, { signal });
|
|
1225
|
-
const names = await sandbox.exec(`${env}${GIT} diff --cached --name-status --no-renames HEAD`, { signal });
|
|
1226
|
-
if (patch.exitCode !== 0 || names.exitCode !== 0) throw new InfraError(`Failed to diff the workspace: ${patch.stderr || names.stderr}`);
|
|
1227
|
-
const status = {
|
|
1228
|
-
A: "added",
|
|
1229
|
-
M: "modified",
|
|
1230
|
-
D: "deleted"
|
|
1231
|
-
};
|
|
1232
|
-
const files = names.stdout.split("\n").filter(Boolean).map((line) => {
|
|
1233
|
-
const [code = "M", ...rest] = line.split(" ");
|
|
1234
|
-
return {
|
|
1235
|
-
path: rest.join(" "),
|
|
1236
|
-
status: status[code[0]] ?? "modified"
|
|
1237
|
-
};
|
|
1238
|
-
});
|
|
1239
|
-
return {
|
|
1240
|
-
patch: patch.stdout,
|
|
1241
|
-
files
|
|
1242
|
-
};
|
|
1243
|
-
}
|
|
1244
|
-
//#endregion
|
|
1245
1306
|
//#region src/sandbox/phases.ts
|
|
1246
1307
|
const strip = ({ phase: _, ...sub }) => sub;
|
|
1247
1308
|
/**
|
|
@@ -1642,7 +1703,7 @@ async function runAttempt(spec, fn, handle) {
|
|
|
1642
1703
|
});
|
|
1643
1704
|
return withDebug(debug, () => attemptBody(spec, fn, handle, id, debug));
|
|
1644
1705
|
}
|
|
1645
|
-
async function attemptBody(spec, fn, { signal: testSignal, setMeta, progress, unawaited }, id, debug) {
|
|
1706
|
+
async function attemptBody(spec, fn, { signal: testSignal, setMeta, progress, unawaited, assertions }, id, debug) {
|
|
1646
1707
|
const setupStart = performance.now();
|
|
1647
1708
|
const ctx = getRunContext();
|
|
1648
1709
|
const { runId, stagingDir, config } = ctx;
|
|
@@ -1665,7 +1726,7 @@ async function attemptBody(spec, fn, { signal: testSignal, setMeta, progress, un
|
|
|
1665
1726
|
return starting;
|
|
1666
1727
|
};
|
|
1667
1728
|
const takeContext = contextTaker(a);
|
|
1668
|
-
const { exec, readFile } = createChecks(a);
|
|
1729
|
+
const { exec, readFile, writeFile } = createChecks(a);
|
|
1669
1730
|
const c = {
|
|
1670
1731
|
get signal() {
|
|
1671
1732
|
return a.signal;
|
|
@@ -1673,6 +1734,7 @@ async function attemptBody(spec, fn, { signal: testSignal, setMeta, progress, un
|
|
|
1673
1734
|
turns: a.turns,
|
|
1674
1735
|
exec,
|
|
1675
1736
|
readFile,
|
|
1737
|
+
writeFile,
|
|
1676
1738
|
serve: (command, port) => serveCommand(a, command, port),
|
|
1677
1739
|
capture: (target, options) => capturePage(a, target, options),
|
|
1678
1740
|
attempt: {
|
|
@@ -1694,6 +1756,8 @@ async function attemptBody(spec, fn, { signal: testSignal, setMeta, progress, un
|
|
|
1694
1756
|
judge: judgeCaller(a, readFile)
|
|
1695
1757
|
};
|
|
1696
1758
|
const timedOut = () => !!timer?.aborted && !testSignal.aborted;
|
|
1759
|
+
let failure;
|
|
1760
|
+
let oom;
|
|
1697
1761
|
try {
|
|
1698
1762
|
a.report({ kind: "sandbox" });
|
|
1699
1763
|
const where = `${id} [${attemptId(spec.cell.key, spec.n)}]`;
|
|
@@ -1710,8 +1774,7 @@ async function attemptBody(spec, fn, { signal: testSignal, setMeta, progress, un
|
|
|
1710
1774
|
if (only) throw new Error(more.length ? `${more.length + 1} judge calls failed:\n${a.judgeErrors.join("\n")}` : only);
|
|
1711
1775
|
} catch (error) {
|
|
1712
1776
|
recordFailure(a, error, timedOut());
|
|
1713
|
-
|
|
1714
|
-
throw error;
|
|
1777
|
+
failure = { error: timedOut() ? new TimeoutError(`Eval timed out after ${spec.timeoutMs / 1e3}s`) : error };
|
|
1715
1778
|
} finally {
|
|
1716
1779
|
if (!a.signal.aborted) await unawaited().catch(() => {});
|
|
1717
1780
|
clock?.clear();
|
|
@@ -1724,9 +1787,16 @@ async function attemptBody(spec, fn, { signal: testSignal, setMeta, progress, un
|
|
|
1724
1787
|
await a.session?.close().catch(() => {});
|
|
1725
1788
|
if (a.session) debug.log("teardown", "harness session closed");
|
|
1726
1789
|
recordEgress(a, sandbox);
|
|
1790
|
+
oom = a.signal.aborted ? void 0 : await recordOom(a, sandbox);
|
|
1727
1791
|
await sandbox?.destroy();
|
|
1728
1792
|
if (sandbox) debug.log("teardown", `sandbox destroyed (${formatDuration(performance.now() - teardown)} for teardown)`);
|
|
1729
1793
|
const { record } = a;
|
|
1794
|
+
const checked = assertions();
|
|
1795
|
+
if (checked.length) record.assertions = checked;
|
|
1796
|
+
for (const x of checked) {
|
|
1797
|
+
const why = x.message ? ` · ${clip(x.message.split("\n")[0] ?? "", 160)}` : "";
|
|
1798
|
+
debug.log("check", `assert ${x.status === "pass" ? "✓" : "✗"} ${x.label} (${x.matcher}, ${x.status})${why}`);
|
|
1799
|
+
}
|
|
1730
1800
|
const error = record.error ? ` · ${record.error.kind}: ${record.error.message}` : "";
|
|
1731
1801
|
debug.log("teardown", `outcome ${record.outcome}${error}`);
|
|
1732
1802
|
const rel = (path) => relativeFile(config.root, path) || ".";
|
|
@@ -1735,6 +1805,8 @@ async function attemptBody(spec, fn, { signal: testSignal, setMeta, progress, un
|
|
|
1735
1805
|
setMeta(await writeRecord(a, stagingDir, id));
|
|
1736
1806
|
await debug.finish(debug.verbosity === 2 || record.outcome !== "pass");
|
|
1737
1807
|
}
|
|
1808
|
+
if (oom) throw oom;
|
|
1809
|
+
if (failure) throw failure.error;
|
|
1738
1810
|
}
|
|
1739
1811
|
//#endregion
|
|
1740
1812
|
//#region src/plan-eval.ts
|
|
@@ -1793,6 +1865,11 @@ function planEval(declaration, ctx) {
|
|
|
1793
1865
|
if (mcp) throw new UsageError(`${where} on ${harnessId(planned.harness)}: ${mcp}`);
|
|
1794
1866
|
}
|
|
1795
1867
|
const path = ctx.file ? relativeFile(ctx.config.root, ctx.file) : null;
|
|
1868
|
+
const rankFile = relativeFile(ctx.config.root, ctx.file ?? "");
|
|
1869
|
+
const family = declaration.family && {
|
|
1870
|
+
id: evalId(rankFile, [...groups, declaration.family.name]),
|
|
1871
|
+
...declaration.family
|
|
1872
|
+
};
|
|
1796
1873
|
const harnessBy = resolved.sources?.harness ?? ctx.config.file;
|
|
1797
1874
|
const plan = evalPlan(resolvedEval, plannedAttempts, {
|
|
1798
1875
|
configFile: ctx.config.file,
|
|
@@ -1819,7 +1896,8 @@ function planEval(declaration, ctx) {
|
|
|
1819
1896
|
brokered: [],
|
|
1820
1897
|
secretVars: [],
|
|
1821
1898
|
egress: first.egress,
|
|
1822
|
-
plan
|
|
1899
|
+
plan,
|
|
1900
|
+
...family ? { family } : {}
|
|
1823
1901
|
};
|
|
1824
1902
|
return [{
|
|
1825
1903
|
name: `${name} [${attemptId(first.cell.key, 1)}]`,
|
|
@@ -1833,7 +1911,6 @@ function planEval(declaration, ctx) {
|
|
|
1833
1911
|
const workspace = workspaceOf(planned.environment.layers);
|
|
1834
1912
|
const files = filesOf(planned.environment.layers);
|
|
1835
1913
|
const setBy = setByOf(planned);
|
|
1836
|
-
const rankFile = relativeFile(ctx.config.root, ctx.file ?? "");
|
|
1837
1914
|
const id = evalId(rankFile, [...groups, name]);
|
|
1838
1915
|
const key = attemptKey(id, planned.cell.key, planned.n);
|
|
1839
1916
|
const skip = ctx.completed?.includes(key) ? "already completed in this run" : void 0;
|
|
@@ -1858,7 +1935,8 @@ function planEval(declaration, ctx) {
|
|
|
1858
1935
|
...plan,
|
|
1859
1936
|
skip
|
|
1860
1937
|
} : plan,
|
|
1861
|
-
...skip ? { skip } : {}
|
|
1938
|
+
...skip ? { skip } : {},
|
|
1939
|
+
...family ? { family } : {}
|
|
1862
1940
|
};
|
|
1863
1941
|
return {
|
|
1864
1942
|
name: `${name} [${attemptId(planned.cell.key, planned.n)}]`,
|
|
@@ -1981,7 +2059,7 @@ function checkUnique(where, groups, name, hint) {
|
|
|
1981
2059
|
if (declared.has(key)) throw new UsageError(`${where} is declared twice in this file. Each eval needs its own name, or its attempts are merged into one eval.${hint}`);
|
|
1982
2060
|
declared.add(key);
|
|
1983
2061
|
}
|
|
1984
|
-
function register(mode, name, own, fn, hint = "") {
|
|
2062
|
+
function register(mode, name, own, fn, hint = "", family) {
|
|
1985
2063
|
const groups = groupStack.map((g) => g.name);
|
|
1986
2064
|
checkUnique(`evaluate("${[...groups, name].join(" › ")}")`, groups, name, hint);
|
|
1987
2065
|
const body = `b${bodies.size + 1}`;
|
|
@@ -1991,7 +2069,8 @@ function register(mode, name, own, fn, hint = "") {
|
|
|
1991
2069
|
name,
|
|
1992
2070
|
mode,
|
|
1993
2071
|
options: data(own),
|
|
1994
|
-
body
|
|
2072
|
+
body,
|
|
2073
|
+
...family ? { family } : {}
|
|
1995
2074
|
});
|
|
1996
2075
|
const tests = planEval({
|
|
1997
2076
|
name,
|
|
@@ -2000,7 +2079,8 @@ function register(mode, name, own, fn, hint = "") {
|
|
|
2000
2079
|
name,
|
|
2001
2080
|
options
|
|
2002
2081
|
})),
|
|
2003
|
-
options: own
|
|
2082
|
+
options: own,
|
|
2083
|
+
...family ? { family } : {}
|
|
2004
2084
|
}, {
|
|
2005
2085
|
...getRunContext(),
|
|
2006
2086
|
file: collectingFile(),
|
|
@@ -2021,19 +2101,37 @@ const defineEval = (mode) => (name, a, b) => {
|
|
|
2021
2101
|
function formatName(template, item, index) {
|
|
2022
2102
|
return template.replace(/%#/g, String(index)).replace(/%s/g, typeof item === "string" ? item : JSON.stringify(item)).replace(/\$([A-Za-z_][A-Za-z0-9_]*)/g, (whole, key) => typeof item === "object" && item !== null && key in item ? String(item[key]) : whole);
|
|
2023
2103
|
}
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
const
|
|
2027
|
-
const
|
|
2104
|
+
function checkEachOptions(options) {
|
|
2105
|
+
if (options === void 0) return {};
|
|
2106
|
+
const keys = typeof options === "object" && options !== null ? Object.keys(options) : null;
|
|
2107
|
+
const pool = options?.pool;
|
|
2108
|
+
if (keys?.every((k) => k === "pool") && (pool === void 0 || typeof pool === "boolean")) return options;
|
|
2109
|
+
throw new UsageError(`evaluate.each(cases, options) takes { pool?: boolean } (got ${JSON.stringify(options)}). Eval options such as compare go after the name: evaluate.each(cases)(name, { compare }, fn).`);
|
|
2110
|
+
}
|
|
2111
|
+
/**
|
|
2112
|
+
* One eval per case, pooled into one suite:
|
|
2113
|
+
* `evaluate.each(cases)('adds $a and $b', async (c, { a, b }) => …)`.
|
|
2114
|
+
*/
|
|
2115
|
+
const evalEach = (cases, options) => (name, a, b) => {
|
|
2116
|
+
const { pool = true } = checkEachOptions(options);
|
|
2117
|
+
if (!Array.isArray(cases)) throw new UsageError(`evaluate.each takes an array of cases (got ${typeof cases}), e.g. evaluate.each([{ n: 1 }, { n: 2 }])("case $n", async (c, item) => { … }).`);
|
|
2118
|
+
const [own, fn] = splitArgs("evaluate.each", name, a, b);
|
|
2119
|
+
const hint = ` For evaluate.each, put $key, %s or %# in the name ("${name}") so each case's name differs.`;
|
|
2120
|
+
const pooled = pool && cases.length >= 2;
|
|
2028
2121
|
cases.forEach((item, i) => {
|
|
2029
|
-
|
|
2122
|
+
const family = pooled ? {
|
|
2123
|
+
name,
|
|
2124
|
+
case: i,
|
|
2125
|
+
cases: cases.length
|
|
2126
|
+
} : void 0;
|
|
2127
|
+
register("run", formatName(name, item, i), own, (c) => fn(c, item), hint, family);
|
|
2030
2128
|
});
|
|
2031
2129
|
};
|
|
2032
2130
|
const evaluate = Object.assign(defineEval("run"), {
|
|
2033
2131
|
skip: defineEval("skip"),
|
|
2034
2132
|
only: defineEval("only"),
|
|
2035
2133
|
todo: registerTodo,
|
|
2036
|
-
|
|
2134
|
+
each: evalEach
|
|
2037
2135
|
});
|
|
2038
2136
|
//#endregion
|
|
2039
2137
|
export { DEFAULT_DIRECTORY_IGNORES, DEFAULT_EGRESS_ALLOW, DEFAULT_SKILL_EXCLUDE, HarnessCapabilityError, defineConfig, defineEnvironment, evaluate, expect, group };
|