reeval 0.11.0 → 0.12.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 +3 -1
- package/bin/mcp-timer.cjs +224 -0
- package/dist/{adapter-Bwy3QxAK.js → adapter-DigeVFWC.js} +3 -3
- package/dist/{adapter-Bwy3QxAK.js.map → adapter-DigeVFWC.js.map} +1 -1
- package/dist/{agent-DpE80WPz.js → agent-CatUEo5h.js} +21 -6
- package/dist/{agent-DpE80WPz.js.map → agent-CatUEo5h.js.map} +1 -1
- package/dist/{assemble-D9GWr-HS.js → assemble-CF063ms6.js} +19 -17
- package/dist/assemble-CF063ms6.js.map +1 -0
- package/dist/assemble-CJoD_Rzr.js +1 -0
- package/dist/bridge/index.mjs +2 -1
- package/dist/{capture-BQlGHiMC.js → capture-BiD7lVaM.js} +25 -17
- package/dist/{capture-BQlGHiMC.js.map → capture-BiD7lVaM.js.map} +1 -1
- package/dist/capture-Dp3q7K7Y.js +1 -0
- package/dist/{cli-ClpPT8kn.js → cli-B5zQCR2r.js} +161 -116
- package/dist/cli-B5zQCR2r.js.map +1 -0
- package/dist/{cli-spec-qmEnQ25_.js → cli-spec-BXIBUlaK.js} +34 -15
- package/dist/cli-spec-BXIBUlaK.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{command-TgbzPizb.js → command-BMHXHqMT.js} +15 -14
- package/dist/command-BMHXHqMT.js.map +1 -0
- package/dist/command-C94CQNh8.js +91 -0
- package/dist/command-C94CQNh8.js.map +1 -0
- package/dist/command-CVtgyqlM.js +335 -0
- package/dist/command-CVtgyqlM.js.map +1 -0
- package/dist/{command-DbAe1Rzb.js → command-CaZgCTIw.js} +14 -17
- package/dist/command-CaZgCTIw.js.map +1 -0
- package/dist/{command-BlM0y8jN.js → command-DTgBZR0k.js} +6 -6
- package/dist/{command-BlM0y8jN.js.map → command-DTgBZR0k.js.map} +1 -1
- package/dist/{commands-CthqwkAn.js → commands-BXzIDB3X.js} +1 -1
- package/dist/commands-CjpGBUWr.js +666 -0
- package/dist/commands-CjpGBUWr.js.map +1 -0
- package/dist/{config-DrVSEVN0.js → config-Dv5MG7Rp.js} +27 -48
- package/dist/config-Dv5MG7Rp.js.map +1 -0
- package/dist/{context-C1mxXh80.js → context-Dgn48BqT.js} +13 -2
- package/dist/context-Dgn48BqT.js.map +1 -0
- package/dist/{contrasts-5zsj32gk.js → contrasts-CcoMLC_y.js} +3 -3
- package/dist/{contrasts-5zsj32gk.js.map → contrasts-CcoMLC_y.js.map} +1 -1
- package/dist/db-BeqRiWLl.js +602 -0
- package/dist/db-BeqRiWLl.js.map +1 -0
- package/dist/db-CJDRVQal.js +2 -0
- package/dist/{dist-CuY4ehEk.js → dist-CMjp3qqF.js} +2 -2
- package/dist/{dist-CuY4ehEk.js.map → dist-CMjp3qqF.js.map} +1 -1
- package/dist/{docker-DOvjji9I.js → docker-BbTlMmYi.js} +2 -2
- package/dist/{docker-DOvjji9I.js.map → docker-BbTlMmYi.js.map} +1 -1
- package/dist/{docker-D1HZDS6q.js → docker-CCXdbREk.js} +20 -4
- package/dist/{docker-D1HZDS6q.js.map → docker-CCXdbREk.js.map} +1 -1
- package/dist/{docker-DNmMPOBb.js → docker-DC69dKxB.js} +1 -1
- package/dist/{doctor-D2MbNO8L.js → doctor-CqttrZcs.js} +57 -22
- package/dist/doctor-CqttrZcs.js.map +1 -0
- package/dist/{egress-2-qzPvGi.js → egress-BfK_O9ce.js} +435 -30
- package/dist/egress-BfK_O9ce.js.map +1 -0
- package/dist/env-BQqj93gu.js +21 -0
- package/dist/env-BQqj93gu.js.map +1 -0
- package/dist/{environment-Cca6a4wB.js → environment-BBz1Yes9.js} +224 -10
- package/dist/environment-BBz1Yes9.js.map +1 -0
- package/dist/{evaluate-DKIl54Hb.js → evaluate-CXQ1o-pd.js} +539 -559
- package/dist/evaluate-CXQ1o-pd.js.map +1 -0
- package/dist/{evaluate-DMyaGQEj.d.ts → evaluate-yjZKUexW.d.ts} +2 -2
- package/dist/facts-DtENlf9s.js +898 -0
- package/dist/facts-DtENlf9s.js.map +1 -0
- package/dist/{files-BpUYBwGu.js → files-B-eUpCZ1.js} +30 -7
- package/dist/files-B-eUpCZ1.js.map +1 -0
- package/dist/files-BsQbYz2i.js +65 -0
- package/dist/files-BsQbYz2i.js.map +1 -0
- package/dist/{files-BXHZFWmx.js → files-COHQLEHE.js} +6 -17
- package/dist/files-COHQLEHE.js.map +1 -0
- package/dist/files-DqCBW7i8.js +1 -0
- package/dist/files-Ha-jsQXf.js +1 -0
- package/dist/generate-Cs2TMH_k.js +1647 -0
- package/dist/generate-Cs2TMH_k.js.map +1 -0
- package/dist/{git-Crl3b87o.js → git-DhykwgKF.js} +2 -2
- package/dist/{git-Crl3b87o.js.map → git-DhykwgKF.js.map} +1 -1
- package/dist/{harness-CEuntrla.js → harness-BAjw1fcr.js} +2 -2
- package/dist/{harness-CEuntrla.js.map → harness-BAjw1fcr.js.map} +1 -1
- package/dist/harness.d.ts +1 -1
- package/dist/harness.js +1 -1
- package/dist/{header-DHQv_ZrF.js → header-kSmWatcO.js} +10 -3
- package/dist/{header-DHQv_ZrF.js.map → header-kSmWatcO.js.map} +1 -1
- package/dist/{images-Bi3aGxb9.js → images-BmJRuTpm.js} +61 -13
- package/dist/images-BmJRuTpm.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/init-Bwc9byQr.js +543 -0
- package/dist/init-Bwc9byQr.js.map +1 -0
- package/dist/init-D7Y1ny1z.js +1 -0
- package/dist/insights-B2Xmhz9o.js +64 -0
- package/dist/insights-B2Xmhz9o.js.map +1 -0
- package/dist/{invocations-BYDPe3fV.js → invocations-CQTbP092.js} +3 -3
- package/dist/{invocations-BYDPe3fV.js.map → invocations-CQTbP092.js.map} +1 -1
- package/dist/{judge-DW_GDOmB.js → judge-Dt6KW6_O.js} +5 -3
- package/dist/judge-Dt6KW6_O.js.map +1 -0
- package/dist/judge.d.ts +7 -6
- package/dist/judge.js +8 -7
- package/dist/judge.js.map +1 -1
- package/dist/{live-jlfszAbb.js → live-DYd2QEyR.js} +2 -2
- package/dist/{live-jlfszAbb.js.map → live-DYd2QEyR.js.map} +1 -1
- package/dist/{model-D0IcOQao.js → model-B-mel-Gv.js} +43 -18
- package/dist/model-B-mel-Gv.js.map +1 -0
- package/dist/model-BGKYVpoj.js +1 -0
- package/dist/{model-DaVCY3rb.js → model-C7tSwT7f.js} +2 -2
- package/dist/{model-DaVCY3rb.js.map → model-C7tSwT7f.js.map} +1 -1
- package/dist/{model-DaX4bNLZ.js → model-CWlAqmbU.js} +135 -40
- package/dist/model-CWlAqmbU.js.map +1 -0
- package/dist/model-DHY-dfoO.js +1 -0
- package/dist/{node-B3ydHo6t.js → node-D0mtjRAO.js} +3 -3
- package/dist/{node-B3ydHo6t.js.map → node-D0mtjRAO.js.map} +1 -1
- package/dist/{options-C0d0AzeR.js → options-CPUW97_7.js} +7 -9
- package/dist/options-CPUW97_7.js.map +1 -0
- package/dist/{pairs-CnInRu-G.js → pairs-DP6XOJby.js} +2 -2
- package/dist/{pairs-CnInRu-G.js.map → pairs-DP6XOJby.js.map} +1 -1
- package/dist/{patch-B1bnfhN-.js → patch-D4oluWzH.js} +2 -2
- package/dist/{patch-B1bnfhN-.js.map → patch-D4oluWzH.js.map} +1 -1
- package/dist/{plan-DgQxp9yy.js → plan-OkwUcJQ9.js} +21 -8
- package/dist/plan-OkwUcJQ9.js.map +1 -0
- package/dist/plugins-CUWMnSNb.js +654 -0
- package/dist/plugins-CUWMnSNb.js.map +1 -0
- package/dist/{preflight-DlQvbySb.js → preflight-B6pY89bF.js} +1 -1
- package/dist/{preflight-BRzD30L5.js → preflight-Bjm7_ylE.js} +14 -10
- package/dist/preflight-Bjm7_ylE.js.map +1 -0
- package/dist/{prepare-B_y-AFMv.js → prepare-CQmK3SBn.js} +70 -23
- package/dist/prepare-CQmK3SBn.js.map +1 -0
- package/dist/prepare-DbdgtZKe.js +2 -0
- package/dist/{provenance-DQ0AXn6c.js → provenance-B3Y17oCC.js} +3 -3
- package/dist/{provenance-DQ0AXn6c.js.map → provenance-B3Y17oCC.js.map} +1 -1
- package/dist/providers-CXN2RFz-.js +1 -0
- package/dist/{providers-DoTq1jHW.js → providers-eoniqK6w.js} +24 -10
- package/dist/providers-eoniqK6w.js.map +1 -0
- package/dist/{query-BO-ux7RB.js → query-CLRZmWBT.js} +3 -3
- package/dist/{query-BO-ux7RB.js.map → query-CLRZmWBT.js.map} +1 -1
- package/dist/query-CmBDYt0_.js +1 -0
- package/dist/{questions-C2dym2ce.js → questions-1XOulevV.js} +6 -6
- package/dist/{questions-C2dym2ce.js.map → questions-1XOulevV.js.map} +1 -1
- package/dist/{record-BKmMvZ6O.js → record-kk9M1hj-.js} +8 -4
- package/dist/record-kk9M1hj-.js.map +1 -0
- package/dist/remarks-1521zwfW.js +38 -0
- package/dist/remarks-1521zwfW.js.map +1 -0
- package/dist/remarks-BhAV1H4V.js +1 -0
- package/dist/remarks-DlJCqWRs.js +278 -0
- package/dist/remarks-DlJCqWRs.js.map +1 -0
- package/dist/{remote-CPPW86Q9.js → remote-cE2VWfkJ.js} +3 -3
- package/dist/{remote-CPPW86Q9.js.map → remote-cE2VWfkJ.js.map} +1 -1
- package/dist/resolve-C4zeccCH.js +724 -0
- package/dist/resolve-C4zeccCH.js.map +1 -0
- package/dist/resolve-D30yZYmB.js +1 -0
- package/dist/{results-BE2f-1XS.js → results-Drtt0uFl.js} +33 -8
- package/dist/results-Drtt0uFl.js.map +1 -0
- package/dist/{resume-Ca1c8vix.js → resume-BEFazUfy.js} +4 -4
- package/dist/{resume-Ca1c8vix.js.map → resume-BEFazUfy.js.map} +1 -1
- package/dist/rules-BFzQqPIm.js +317 -0
- package/dist/rules-BFzQqPIm.js.map +1 -0
- package/dist/run-BeMy92Us.js +88 -0
- package/dist/run-BeMy92Us.js.map +1 -0
- package/dist/{sandbox-DLrsvu7U.js → sandbox-CQaJj7n9.js} +2 -2
- package/dist/{sandbox-DLrsvu7U.js.map → sandbox-CQaJj7n9.js.map} +1 -1
- package/dist/sandbox.d.ts +1 -1
- package/dist/sandbox.js +1 -1
- package/dist/server-V4-2w0l8.js +1 -0
- package/dist/{server-TUY5xA_A.js → server-xK0les4f.js} +8 -8
- package/dist/{server-TUY5xA_A.js.map → server-xK0les4f.js.map} +1 -1
- package/dist/source-BDow_oW8.js +1 -0
- package/dist/{source-DJGS0a0u.js → source-Q1hEKbCs.js} +2 -2
- package/dist/{source-DJGS0a0u.js.map → source-Q1hEKbCs.js.map} +1 -1
- package/dist/src-B9L9yGKI.js +1 -0
- package/dist/{src-CLoOMVWI.js → src-Bcah6ZkT.js} +1 -1
- package/dist/{src-DvCg0NBs.js → src-BhmaorOU.js} +28 -6
- package/dist/{src-DvCg0NBs.js.map → src-BhmaorOU.js.map} +1 -1
- package/dist/{src-CF17Ug08.js → src-C0CeKiLU.js} +19 -4
- package/dist/{src-CF17Ug08.js.map → src-C0CeKiLU.js.map} +1 -1
- package/dist/src-C0xowZ3C.js +2 -0
- package/dist/src-CHIfIKUu.js +2 -0
- package/dist/src-DLtyz4w5.js +2 -0
- package/dist/src-DPIjmReZ.js +2 -0
- package/dist/{src-BxfCKA3_.js → src-DXNh5mTr.js} +1 -1
- package/dist/{src-FGXhkEkH.js → src-DiLMkIr9.js} +142 -13
- package/dist/src-DiLMkIr9.js.map +1 -0
- package/dist/{src-ftu5wPSt.js → src-LekQrr_S.js} +209 -29
- package/dist/src-LekQrr_S.js.map +1 -0
- package/dist/src-bCnsA6Vp.js +2 -0
- package/dist/{src-u8_ixn_F.js → src-cbCb-MPy.js} +20 -4
- package/dist/src-cbCb-MPy.js.map +1 -0
- package/dist/{src-DvK0EIZx.js → src-qGoFkuJF.js} +55 -6
- package/dist/{src-DvK0EIZx.js.map → src-qGoFkuJF.js.map} +1 -1
- package/dist/{src-DSYYPEOj.js → src-ynBVosfX.js} +1 -1
- package/dist/state-BQR_BCm4.js +1 -0
- package/dist/{state-DfpHox6b.js → state-BmZ8QVZ8.js} +12 -12
- package/dist/{state-DfpHox6b.js.map → state-BmZ8QVZ8.js.map} +1 -1
- package/dist/studio-app/assets/{index-CBkhNAv8.js → index-CnYJijyI.js} +9 -9
- package/dist/studio-app/index.html +1 -1
- package/dist/suite-BaHPmAGy.js +1 -0
- package/dist/{suite-Cw_7G2RM.js → suite-C8sw2pox.js} +80 -28
- package/dist/suite-C8sw2pox.js.map +1 -0
- package/dist/{summary-BUKfU-9l.js → summary-0oQNGskv.js} +273 -47
- package/dist/summary-0oQNGskv.js.map +1 -0
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +2 -2
- package/dist/{text-gEcKjAyp.js → text-CrVy5ioL.js} +18 -2
- package/dist/text-CrVy5ioL.js.map +1 -0
- package/dist/{transcript-BNNANU8A.js → transcript-BTxJpW4R.js} +2 -2
- package/dist/{transcript-BNNANU8A.js.map → transcript-BTxJpW4R.js.map} +1 -1
- package/dist/types-C5vI3g1C.js.map +1 -1
- package/dist/{types-BYdlwMwo.d.ts → types-GraZtfHN.d.ts} +848 -34
- package/dist/usage-BDo2q_yu.js +1 -0
- package/dist/{command-Bj39y-Wm.js → validate-BdoXUuL_.js} +15 -372
- package/dist/validate-BdoXUuL_.js.map +1 -0
- package/dist/view/index.d.ts +20 -257
- package/dist/view/index.js +7 -6
- package/dist/{views-B8w2J-gD.js → views-BoUoX4_A.js} +8 -98
- package/dist/views-BoUoX4_A.js.map +1 -0
- package/dist/views-noVQNCUP.js +2 -0
- package/dist/{worker-entry-DNnveLqx.js → worker-entry-D0-GErmU.js} +2 -2
- package/dist/{worker-entry-DNnveLqx.js.map → worker-entry-D0-GErmU.js.map} +1 -1
- package/dist/{workspace-C_X0tdv6.js → workspace-B90YDU_a.js} +1 -1
- package/dist/{workspace-C4RA3srV.js → workspace-tjZFkjxC.js} +4 -4
- package/dist/{workspace-C4RA3srV.js.map → workspace-tjZFkjxC.js.map} +1 -1
- package/package.json +3 -1
- package/skills/eval-rubric/SKILL.md +130 -0
- package/dist/agent-D483ru7D.js +0 -334
- package/dist/agent-D483ru7D.js.map +0 -1
- package/dist/assemble-D5KGrwnJ.js +0 -1
- package/dist/assemble-D9GWr-HS.js.map +0 -1
- package/dist/capture-CYGLpWxR.js +0 -1
- package/dist/cli-ClpPT8kn.js.map +0 -1
- package/dist/cli-spec-qmEnQ25_.js.map +0 -1
- package/dist/command-Bj39y-Wm.js.map +0 -1
- package/dist/command-C-cVjlny.js +0 -1
- package/dist/command-DbAe1Rzb.js.map +0 -1
- package/dist/command-TgbzPizb.js.map +0 -1
- package/dist/commands-YUwlyTbr.js +0 -228
- package/dist/commands-YUwlyTbr.js.map +0 -1
- package/dist/config-DrVSEVN0.js.map +0 -1
- package/dist/context-C1mxXh80.js.map +0 -1
- package/dist/db-CKg5NtiW.js +0 -2
- package/dist/db-DfhipHEF.js +0 -1416
- package/dist/db-DfhipHEF.js.map +0 -1
- package/dist/doctor-D2MbNO8L.js.map +0 -1
- package/dist/egress-2-qzPvGi.js.map +0 -1
- package/dist/environment-Cca6a4wB.js.map +0 -1
- package/dist/evaluate-DKIl54Hb.js.map +0 -1
- package/dist/files-BXHZFWmx.js.map +0 -1
- package/dist/files-BpUYBwGu.js.map +0 -1
- package/dist/files-Bw8lWEjg.js +0 -1
- package/dist/files-D6J0iSdx.js +0 -1
- package/dist/images-Bi3aGxb9.js.map +0 -1
- package/dist/init-Cl3f3NBT.js +0 -360
- package/dist/init-Cl3f3NBT.js.map +0 -1
- package/dist/init-fhOXED8F.js +0 -1
- package/dist/judge-DW_GDOmB.js.map +0 -1
- package/dist/model-CXhrziBe.js +0 -1
- package/dist/model-D0IcOQao.js.map +0 -1
- package/dist/model-DaX4bNLZ.js.map +0 -1
- package/dist/model-_bxNrk2h.js +0 -1
- package/dist/options-C0d0AzeR.js.map +0 -1
- package/dist/plan-DgQxp9yy.js.map +0 -1
- package/dist/preflight-BRzD30L5.js.map +0 -1
- package/dist/prepare-B_y-AFMv.js.map +0 -1
- package/dist/prepare-DCKTLHN3.js +0 -2
- package/dist/providers-B9yTdIqF.js +0 -1
- package/dist/providers-DoTq1jHW.js.map +0 -1
- package/dist/query-CRQfsw0e.js +0 -1
- package/dist/record-BKmMvZ6O.js.map +0 -1
- package/dist/results-BE2f-1XS.js.map +0 -1
- package/dist/server-Dp8eOeK5.js +0 -1
- package/dist/source-DdbLGR1M.js +0 -1
- package/dist/src-CcrQbpG8.js +0 -2
- package/dist/src-DCFtJRp0.js +0 -2
- package/dist/src-DYO3DdnQ.js +0 -1
- package/dist/src-FGXhkEkH.js.map +0 -1
- package/dist/src-WD-zgQYZ.js +0 -2
- package/dist/src-_oI9AePb.js +0 -2
- package/dist/src-ftu5wPSt.js.map +0 -1
- package/dist/src-qsKCqv7a.js +0 -2
- package/dist/src-u8_ixn_F.js.map +0 -1
- package/dist/state-DpAxYyED.js +0 -1
- package/dist/suite-Cw_7G2RM.js.map +0 -1
- package/dist/suite-DamAEnNF.js +0 -1
- package/dist/summary-BUKfU-9l.js.map +0 -1
- package/dist/summary-Baa4rTHS.js +0 -192
- package/dist/summary-Baa4rTHS.js.map +0 -1
- package/dist/text-gEcKjAyp.js.map +0 -1
- package/dist/tools-DLHgetpx.js +0 -249
- package/dist/tools-DLHgetpx.js.map +0 -1
- package/dist/views-B8w2J-gD.js.map +0 -1
- package/dist/views-DblnI3kA.js +0 -2
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
import { p as parseDuration } from "./shared-CA61BuPJ.js";
|
|
2
|
+
import { A as workspaceLabel, C as parseGitRepo, D as stepCommand, S as mcpHosts, b as isSecret, n as DEFAULT_SKILL_EXCLUDE, v as isHostFile, x as isSecretTemplate } from "./environment-BBz1Yes9.js";
|
|
3
|
+
import { l as sha256 } from "./ids-Bp6ut7ZD.js";
|
|
4
|
+
import { r as badCharacterAt } from "./config-Dv5MG7Rp.js";
|
|
5
|
+
import { L as hostAllowed, k as placeholder, lt as run } from "./src-LekQrr_S.js";
|
|
6
|
+
import { s as registerSecret } from "./redact-DJ9JCShu.js";
|
|
7
|
+
import { A as readPlugin, D as pluginServerName, E as pluginParts, M as skillCall, O as pluginSourceLabel, T as pluginFiles, _ as localMarketplace, c as PluginProblem, g as leavesSource, j as samePluginTwice, k as readMarketplace, m as fetchesAtStart, w as pluginCall, x as marketplaceLabel } from "./plugins-CUWMnSNb.js";
|
|
8
|
+
import { t as InfraError } from "./types-C5vI3g1C.js";
|
|
9
|
+
import { x as refusedPlugins, y as layoutOf } from "./egress-BfK_O9ce.js";
|
|
10
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
11
|
+
import { basename, isAbsolute, join, relative, sep } from "node:path";
|
|
12
|
+
import { parse } from "yaml";
|
|
13
|
+
import { mkdir, rm } from "node:fs/promises";
|
|
14
|
+
//#region src/environment/resolve.ts
|
|
15
|
+
const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
16
|
+
const DEFAULT_SETUP_TIMEOUT = "5m";
|
|
17
|
+
function broker(secrets, name, value, hosts, where = ["header"], phase = "agent") {
|
|
18
|
+
const at = badCharacterAt(value);
|
|
19
|
+
if (at && where.includes("header")) throw new InfraError(`${name} has whitespace or a line break in it (character ${at}), so it can't go in a request header. A key copied from a wrapped terminal line picks these up; set it again as one line.`);
|
|
20
|
+
const sub = {
|
|
21
|
+
name,
|
|
22
|
+
placeholder: placeholder(),
|
|
23
|
+
value,
|
|
24
|
+
hosts: [...hosts],
|
|
25
|
+
in: [...where],
|
|
26
|
+
phase
|
|
27
|
+
};
|
|
28
|
+
secrets.brokered.push(sub);
|
|
29
|
+
return sub.placeholder;
|
|
30
|
+
}
|
|
31
|
+
/** The host value, or its placeholder when it's brokered to `secret.hosts` (else `hosts`). */
|
|
32
|
+
function hostValue(name, secret, where, secrets, hosts = secret.hosts) {
|
|
33
|
+
const from = secret.from ?? name;
|
|
34
|
+
const value = process.env[from];
|
|
35
|
+
if (!value) {
|
|
36
|
+
if (secret.optional) {
|
|
37
|
+
secrets.unset.push(name);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const source = from === name ? name : `${name} (from ${from})`;
|
|
41
|
+
throw new InfraError(`Secret ${source} for ${where} isn't set. Set it in the environment or .env.local.`);
|
|
42
|
+
}
|
|
43
|
+
registerSecret(value);
|
|
44
|
+
if (secret.to === "checks") secrets.checks.push(name);
|
|
45
|
+
else secrets.names.push(name);
|
|
46
|
+
if (!hosts) return value;
|
|
47
|
+
return broker(secrets, name, value, hosts, secret.in, secret.to === "checks" ? "checks" : "agent");
|
|
48
|
+
}
|
|
49
|
+
/** Each host variable in the template, or with `hosts` one placeholder per variable. */
|
|
50
|
+
function template(value, where, secrets, hosts) {
|
|
51
|
+
const placeholders = /* @__PURE__ */ new Map();
|
|
52
|
+
return value.template.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_, name) => {
|
|
53
|
+
const v = process.env[name];
|
|
54
|
+
if (!v) throw new InfraError(`secret.template for ${where} needs ${name}, which isn't set. Set it in the environment or .env.local.`);
|
|
55
|
+
registerSecret(v);
|
|
56
|
+
if (!hosts) return v;
|
|
57
|
+
const p = placeholders.get(name) ?? broker(secrets, name, v, hosts);
|
|
58
|
+
placeholders.set(name, p);
|
|
59
|
+
return p;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/** A `SKILL.md` split into its YAML frontmatter's `name` and `description` and its body. */
|
|
63
|
+
function parseSkillMd(text, where) {
|
|
64
|
+
const match = /^---\r?\n(?:([\s\S]*?)\r?\n)?---[ \t]*(?:\r?\n|$)([\s\S]*)$/.exec(text);
|
|
65
|
+
if (!match) return { body: text };
|
|
66
|
+
let front;
|
|
67
|
+
try {
|
|
68
|
+
front = parse(match[1] ?? "");
|
|
69
|
+
} catch (error) {
|
|
70
|
+
const reason = error.message.split("\n")[0];
|
|
71
|
+
throw new InfraError(`${where}: the SKILL.md frontmatter isn't valid YAML (${reason}). Quote values that contain ": ".`);
|
|
72
|
+
}
|
|
73
|
+
if (front != null && (typeof front !== "object" || Array.isArray(front))) throw new InfraError(`${where}: the SKILL.md frontmatter must be a YAML mapping, e.g. name: my-skill and description: … on their own lines`);
|
|
74
|
+
const field = (key) => {
|
|
75
|
+
const value = front?.[key];
|
|
76
|
+
if (value == null) return void 0;
|
|
77
|
+
if (typeof value !== "string") throw new InfraError(`${where}: the SKILL.md ${key} must be a string (got ${typeof value})`);
|
|
78
|
+
return value.trim() || void 0;
|
|
79
|
+
};
|
|
80
|
+
return {
|
|
81
|
+
name: field("name"),
|
|
82
|
+
description: field("description"),
|
|
83
|
+
body: match[2] ?? ""
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** A gitignore-style test for `DEFAULT_SKILL_EXCLUDE`-shaped patterns against a skill-relative path. */
|
|
87
|
+
function excludeMatcher(patterns) {
|
|
88
|
+
const rules = patterns.map((pattern) => {
|
|
89
|
+
const dirOnly = pattern.endsWith("/");
|
|
90
|
+
const body = pattern.replace(/\/+$/, "");
|
|
91
|
+
const anchored = body.includes("/");
|
|
92
|
+
const glob = body.replace(/^\/+/, "").split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join("[^/]*");
|
|
93
|
+
return {
|
|
94
|
+
dirOnly,
|
|
95
|
+
re: new RegExp(`${anchored ? "^" : "(?:^|/)"}${glob}$`)
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
return (path, isDir) => rules.some((r) => (isDir || !r.dirOnly) && r.re.test(path));
|
|
99
|
+
}
|
|
100
|
+
function parseSkill(dir, source, exclude) {
|
|
101
|
+
const front = parseSkillMd(readFileSync(join(dir, "SKILL.md"), "utf8"), `Skill ${basename(dir)} in ${source}`);
|
|
102
|
+
const name = front.name || basename(dir);
|
|
103
|
+
checkSkill(name, front.description, source);
|
|
104
|
+
const skip = excludeMatcher(exclude);
|
|
105
|
+
const paths = [];
|
|
106
|
+
const excluded = [];
|
|
107
|
+
const walk = (rel) => {
|
|
108
|
+
for (const entry of readdirSync(join(dir, rel), { withFileTypes: true })) {
|
|
109
|
+
const path = rel ? `${rel}/${entry.name}` : entry.name;
|
|
110
|
+
const isDir = entry.isDirectory();
|
|
111
|
+
if (entry.name === ".git") continue;
|
|
112
|
+
if (skip(path, isDir)) excluded.push(isDir ? `${path}/` : path);
|
|
113
|
+
else if (isDir) walk(path);
|
|
114
|
+
else if (entry.isFile() && path !== "SKILL.md") paths.push(path);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
walk("");
|
|
118
|
+
const files = paths.sort().map((path) => ({
|
|
119
|
+
path,
|
|
120
|
+
content: readFileSync(join(dir, path), "utf8")
|
|
121
|
+
}));
|
|
122
|
+
return {
|
|
123
|
+
skill: {
|
|
124
|
+
name,
|
|
125
|
+
description: front.description ?? "",
|
|
126
|
+
content: front.body,
|
|
127
|
+
files
|
|
128
|
+
},
|
|
129
|
+
excluded: excluded.sort()
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function checkSkill(name, description, source) {
|
|
133
|
+
if (!SKILL_NAME.test(name)) throw new InfraError(`Skill "${name}" in ${source}: the name must be kebab-case, e.g. my-skill (lower-case letters, digits and -)`);
|
|
134
|
+
if (!description) throw new InfraError(`Skill "${name}" in ${source} has no description in its SKILL.md frontmatter. Add a description: line saying when to use it.`);
|
|
135
|
+
}
|
|
136
|
+
function loadSkills(dir, source, only, exclude = DEFAULT_SKILL_EXCLUDE) {
|
|
137
|
+
if (!existsSync(dir) || !statSync(dir).isDirectory()) throw new InfraError(`Skill source ${source} isn't a directory. Point it at a skill's directory, or at a directory of skills.`);
|
|
138
|
+
const dirs = existsSync(join(dir, "SKILL.md")) ? [dir] : readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync(join(dir, e.name, "SKILL.md"))).map((e) => join(dir, e.name)).sort();
|
|
139
|
+
if (dirs.length === 0) throw new InfraError(`Skill source ${source} has no SKILL.md (and no subdirectories with one)`);
|
|
140
|
+
const skills = dirs.map((d) => parseSkill(d, source, exclude));
|
|
141
|
+
if (!only) return skills;
|
|
142
|
+
const missing = only.filter((n) => !skills.some((s) => s.skill.name === n));
|
|
143
|
+
if (missing.length) throw new InfraError(`only: ${JSON.stringify(missing)} not found in ${source} (found: ${skills.map((s) => s.skill.name).join(", ")})`);
|
|
144
|
+
return skills.filter((s) => only.includes(s.skill.name));
|
|
145
|
+
}
|
|
146
|
+
async function git(args, cwd, what) {
|
|
147
|
+
const r = await run("git", args, { cwd });
|
|
148
|
+
if (r.exitCode !== 0) throw new InfraError(`${what} failed: ${r.stderr.trim()}`);
|
|
149
|
+
return r.stdout.trim();
|
|
150
|
+
}
|
|
151
|
+
/** One clone per source and ref per worker process; the commit is recorded. */
|
|
152
|
+
const clones = /* @__PURE__ */ new Map();
|
|
153
|
+
/** A clone checks out the committed bytes, whatever the host's line-ending settings. */
|
|
154
|
+
const AS_COMMITTED = [
|
|
155
|
+
"-c",
|
|
156
|
+
"core.autocrlf=false",
|
|
157
|
+
"-c",
|
|
158
|
+
"core.eol=lf"
|
|
159
|
+
];
|
|
160
|
+
function cloneSkills(root, url, ref) {
|
|
161
|
+
const key = `${url}#${ref ?? ""}`;
|
|
162
|
+
let clone = clones.get(key);
|
|
163
|
+
if (!clone) {
|
|
164
|
+
clone = (async () => {
|
|
165
|
+
const dir = join(root, ".reeval", "cache", "skills", `${sha256(key).slice(0, 16)}-${process.pid}`);
|
|
166
|
+
await rm(dir, {
|
|
167
|
+
recursive: true,
|
|
168
|
+
force: true
|
|
169
|
+
});
|
|
170
|
+
await mkdir(dir, { recursive: true });
|
|
171
|
+
const what = `Cloning ${url}${ref ? ` at ${ref}` : ""}`;
|
|
172
|
+
await git(["init", "-q"], dir, what);
|
|
173
|
+
await git([
|
|
174
|
+
...AS_COMMITTED,
|
|
175
|
+
"fetch",
|
|
176
|
+
"-q",
|
|
177
|
+
"--depth",
|
|
178
|
+
"1",
|
|
179
|
+
"--end-of-options",
|
|
180
|
+
url,
|
|
181
|
+
ref ?? "HEAD"
|
|
182
|
+
], dir, what);
|
|
183
|
+
await git([
|
|
184
|
+
...AS_COMMITTED,
|
|
185
|
+
"-c",
|
|
186
|
+
"advice.detachedHead=false",
|
|
187
|
+
"checkout",
|
|
188
|
+
"-q",
|
|
189
|
+
"FETCH_HEAD"
|
|
190
|
+
], dir, what);
|
|
191
|
+
return {
|
|
192
|
+
dir,
|
|
193
|
+
commit: await git(["rev-parse", "HEAD"], dir, what)
|
|
194
|
+
};
|
|
195
|
+
})();
|
|
196
|
+
clones.set(key, clone);
|
|
197
|
+
clone.catch(() => clones.delete(key));
|
|
198
|
+
}
|
|
199
|
+
return clone;
|
|
200
|
+
}
|
|
201
|
+
const packs = /* @__PURE__ */ new Map();
|
|
202
|
+
/** `npm pack` into the cache, unpacked; returns the package directory. */
|
|
203
|
+
function unpackNpm(root, spec) {
|
|
204
|
+
let pack = packs.get(spec);
|
|
205
|
+
if (!pack) {
|
|
206
|
+
pack = (async () => {
|
|
207
|
+
const dir = join(root, ".reeval", "cache", "skills", `npm-${sha256(spec).slice(0, 16)}-${process.pid}`);
|
|
208
|
+
await rm(dir, {
|
|
209
|
+
recursive: true,
|
|
210
|
+
force: true
|
|
211
|
+
});
|
|
212
|
+
await mkdir(dir, { recursive: true });
|
|
213
|
+
const packed = await run("npm", [
|
|
214
|
+
"pack",
|
|
215
|
+
spec,
|
|
216
|
+
"--silent",
|
|
217
|
+
"--pack-destination",
|
|
218
|
+
dir
|
|
219
|
+
], { cwd: dir });
|
|
220
|
+
const tarball = packed.stdout.trim().split("\n").at(-1);
|
|
221
|
+
if (packed.exitCode !== 0 || !tarball) throw new InfraError(`npm pack ${spec} failed: ${packed.stderr.trim()}`);
|
|
222
|
+
const untar = await run("tar", ["-xzf", tarball], { cwd: dir });
|
|
223
|
+
if (untar.exitCode !== 0) throw new InfraError(`Unpacking ${spec} failed: ${untar.stderr.trim()}`);
|
|
224
|
+
return join(dir, "package");
|
|
225
|
+
})();
|
|
226
|
+
packs.set(spec, pack);
|
|
227
|
+
pack.catch(() => packs.delete(spec));
|
|
228
|
+
}
|
|
229
|
+
return pack;
|
|
230
|
+
}
|
|
231
|
+
async function resolveSkills(root, s) {
|
|
232
|
+
switch (s.source) {
|
|
233
|
+
case "local": {
|
|
234
|
+
const label = `local:${relative(root, s.path).split(sep).join("/") || "."}`;
|
|
235
|
+
return {
|
|
236
|
+
skills: loadSkills(s.path, label, s.only, s.exclude),
|
|
237
|
+
source: label,
|
|
238
|
+
commit: null
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
case "git": {
|
|
242
|
+
const { url } = parseGitRepo(s.repo);
|
|
243
|
+
const { dir, commit } = await cloneSkills(root, url, s.ref);
|
|
244
|
+
const path = s.path ?? (!existsSync(join(dir, "SKILL.md")) && existsSync(join(dir, "skills")) ? "skills" : "");
|
|
245
|
+
const label = `${s.repo}${s.ref ? `#${s.ref}` : ""}${path ? `:${path}` : ""}`;
|
|
246
|
+
return {
|
|
247
|
+
skills: loadSkills(join(dir, path), label, s.only, s.exclude),
|
|
248
|
+
source: label,
|
|
249
|
+
commit
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
case "registry": {
|
|
253
|
+
const [repo = "", name = ""] = s.id.split("@");
|
|
254
|
+
const { dir, commit } = await cloneSkills(root, `https://github.com/${repo}.git`, s.version);
|
|
255
|
+
const label = `registry:${s.id}${s.version ? `#${s.version}` : ""}`;
|
|
256
|
+
return {
|
|
257
|
+
skills: loadSkills(existsSync(join(dir, "skills")) ? join(dir, "skills") : dir, label, [name]),
|
|
258
|
+
source: label,
|
|
259
|
+
commit
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
case "npm": {
|
|
263
|
+
const dir = await unpackNpm(root, s.spec);
|
|
264
|
+
const label = `npm:${isAbsolute(s.spec) ? relative(root, s.spec).split(sep).join("/") : s.spec}:${s.path}`;
|
|
265
|
+
return {
|
|
266
|
+
skills: loadSkills(join(dir, s.path), label, s.only, s.exclude),
|
|
267
|
+
source: label,
|
|
268
|
+
commit: null
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
case "inline": {
|
|
272
|
+
checkSkill(s.name, s.description, "skill.inline");
|
|
273
|
+
const files = Object.entries(s.files).sort(([a], [b]) => a < b ? -1 : 1).map(([path, content]) => ({
|
|
274
|
+
path,
|
|
275
|
+
content
|
|
276
|
+
}));
|
|
277
|
+
return {
|
|
278
|
+
skills: [{
|
|
279
|
+
skill: {
|
|
280
|
+
name: s.name,
|
|
281
|
+
description: s.description,
|
|
282
|
+
content: s.content,
|
|
283
|
+
files
|
|
284
|
+
},
|
|
285
|
+
excluded: []
|
|
286
|
+
}],
|
|
287
|
+
source: "inline",
|
|
288
|
+
commit: null
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/** A marketplace entry's source: the marketplace itself for a `./` entry, else the entry's own. */
|
|
294
|
+
async function entrySourceDir(root, p) {
|
|
295
|
+
const m = p.marketplace;
|
|
296
|
+
const label = marketplaceLabel(m, root);
|
|
297
|
+
const fetched = m.source === "git" ? await cloneSkills(root, parseGitRepo(m.repo).url, m.ref) : {
|
|
298
|
+
dir: await unpackNpm(root, m.spec),
|
|
299
|
+
commit: null
|
|
300
|
+
};
|
|
301
|
+
const { marketplace: name, entry } = readMarketplace(fetched.dir, pluginCall(p, root), label, p.name, localMarketplace(m));
|
|
302
|
+
const marketplace = {
|
|
303
|
+
name,
|
|
304
|
+
source: label,
|
|
305
|
+
commit: fetched.commit
|
|
306
|
+
};
|
|
307
|
+
switch (entry.source) {
|
|
308
|
+
case "path": return {
|
|
309
|
+
context: fetched.dir,
|
|
310
|
+
path: entry.path || ".",
|
|
311
|
+
commit: fetched.commit,
|
|
312
|
+
source: entry.path ? `${label}:${entry.path}` : label,
|
|
313
|
+
marketplace
|
|
314
|
+
};
|
|
315
|
+
case "git": {
|
|
316
|
+
const clone = await cloneSkills(root, entry.url, entry.ref);
|
|
317
|
+
if (entry.path && leavesSource(clone.dir, entry.path)) throw new PluginProblem(`the ${name} marketplace's entry "${p.name}" has path ${entry.path}, which leaves ${entry.repo} through a symlink`);
|
|
318
|
+
return {
|
|
319
|
+
context: clone.dir,
|
|
320
|
+
path: entry.path ?? ".",
|
|
321
|
+
commit: clone.commit,
|
|
322
|
+
source: `${entry.repo}${entry.ref ? `#${entry.ref}` : ""}${entry.path ? `:${entry.path}` : ""}`,
|
|
323
|
+
marketplace
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
case "npm": return {
|
|
327
|
+
context: await unpackNpm(root, entry.spec),
|
|
328
|
+
path: ".",
|
|
329
|
+
commit: null,
|
|
330
|
+
source: `npm:${entry.spec}`,
|
|
331
|
+
marketplace
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* A plugin's whole source on the host, fetched once per process: the repository at its commit,
|
|
337
|
+
* the unpacked package, or the local directory, with the plugin's `path` in it (`.` for the root).
|
|
338
|
+
* A marketplace entry's is its marketplace's for a `./` entry, else the entry's own source.
|
|
339
|
+
*/
|
|
340
|
+
async function pluginSourceDir(root, p) {
|
|
341
|
+
const labelled = {
|
|
342
|
+
source: pluginSourceLabel(p, root),
|
|
343
|
+
marketplace: null
|
|
344
|
+
};
|
|
345
|
+
switch (p.source) {
|
|
346
|
+
case "local": return {
|
|
347
|
+
context: p.path,
|
|
348
|
+
path: ".",
|
|
349
|
+
commit: null,
|
|
350
|
+
...labelled
|
|
351
|
+
};
|
|
352
|
+
case "git": {
|
|
353
|
+
const clone = await cloneSkills(root, parseGitRepo(p.repo).url, p.ref);
|
|
354
|
+
return {
|
|
355
|
+
context: clone.dir,
|
|
356
|
+
path: p.path ?? ".",
|
|
357
|
+
commit: clone.commit,
|
|
358
|
+
...labelled
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
case "npm": return {
|
|
362
|
+
context: await unpackNpm(root, p.spec),
|
|
363
|
+
path: p.path ?? ".",
|
|
364
|
+
commit: null,
|
|
365
|
+
...labelled
|
|
366
|
+
};
|
|
367
|
+
case "marketplace": return entrySourceDir(root, p);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
async function resolvePlugin(root, p, where) {
|
|
371
|
+
try {
|
|
372
|
+
const { context, path, commit, source, marketplace } = await pluginSourceDir(root, p);
|
|
373
|
+
return {
|
|
374
|
+
contents: readPlugin(join(context, path), pluginCall(p, root), p.only),
|
|
375
|
+
declared: p,
|
|
376
|
+
source,
|
|
377
|
+
commit,
|
|
378
|
+
marketplace
|
|
379
|
+
};
|
|
380
|
+
} catch (error) {
|
|
381
|
+
if (error instanceof PluginProblem) throw new InfraError(`${where}: ${error.message}`);
|
|
382
|
+
throw error;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const skillHash = (s) => sha256(JSON.stringify(s));
|
|
386
|
+
const readHostFile = (f, where) => {
|
|
387
|
+
if (!existsSync(f.path)) throw new InfraError(`${f.path} for ${where} doesn't exist. file() paths resolve against the file that calls it, or reeval.yaml's directory.`);
|
|
388
|
+
return readFileSync(f.path);
|
|
389
|
+
};
|
|
390
|
+
/**
|
|
391
|
+
* Layers the environment (root first; a later layer wins on shared keys, and each such key is
|
|
392
|
+
* an override), over the options `env` merged down the cascade. `where` names the attempt, and
|
|
393
|
+
* `rulesFile` is the workspace file the harness's agent reads `rules` from.
|
|
394
|
+
*/
|
|
395
|
+
async function resolveEnvironment(environment, optionsEnv, root, where, rulesFile, egress = "allow-all", prepared = () => void 0, options = {}) {
|
|
396
|
+
const envWhere = `environment ${environment.name} (${where})`;
|
|
397
|
+
const overrides = /* @__PURE__ */ new Set();
|
|
398
|
+
const env = { ...optionsEnv };
|
|
399
|
+
const files = /* @__PURE__ */ new Map();
|
|
400
|
+
const mcp = /* @__PURE__ */ new Map();
|
|
401
|
+
const skills = /* @__PURE__ */ new Map();
|
|
402
|
+
const plugins = /* @__PURE__ */ new Map();
|
|
403
|
+
let rules;
|
|
404
|
+
const setup = [];
|
|
405
|
+
const seen = {
|
|
406
|
+
env: /* @__PURE__ */ new Set(),
|
|
407
|
+
files: /* @__PURE__ */ new Set(),
|
|
408
|
+
mcp: /* @__PURE__ */ new Set()
|
|
409
|
+
};
|
|
410
|
+
let egressSet = false;
|
|
411
|
+
let workspace;
|
|
412
|
+
let sandboxSet = false;
|
|
413
|
+
for (const layer of environment.layers) {
|
|
414
|
+
const { spec } = layer;
|
|
415
|
+
if (spec.sandbox !== void 0) {
|
|
416
|
+
if (sandboxSet) overrides.add("sandbox");
|
|
417
|
+
sandboxSet = true;
|
|
418
|
+
}
|
|
419
|
+
if (spec.workspace !== void 0) {
|
|
420
|
+
if (workspace) overrides.add("workspace");
|
|
421
|
+
workspace = spec.workspace;
|
|
422
|
+
}
|
|
423
|
+
if (spec.egress !== void 0) {
|
|
424
|
+
if (egressSet) overrides.add("egress");
|
|
425
|
+
egressSet = true;
|
|
426
|
+
}
|
|
427
|
+
for (const [k, v] of Object.entries(spec.env ?? {})) {
|
|
428
|
+
if (seen.env.has(k)) overrides.add(`env.${k}`);
|
|
429
|
+
seen.env.add(k);
|
|
430
|
+
env[k] = v;
|
|
431
|
+
}
|
|
432
|
+
for (const [path, v] of Object.entries(spec.files ?? {})) {
|
|
433
|
+
if (seen.files.has(path)) overrides.add(`files.${path}`);
|
|
434
|
+
seen.files.add(path);
|
|
435
|
+
files.set(path, v);
|
|
436
|
+
}
|
|
437
|
+
if (spec.rules !== void 0) {
|
|
438
|
+
if (rules !== void 0) overrides.add("rules");
|
|
439
|
+
rules = spec.rules;
|
|
440
|
+
}
|
|
441
|
+
for (const [name, server] of Object.entries(spec.mcp ?? {})) {
|
|
442
|
+
if (seen.mcp.has(name)) overrides.add(`mcp.${name}`);
|
|
443
|
+
seen.mcp.add(name);
|
|
444
|
+
mcp.set(name, server);
|
|
445
|
+
}
|
|
446
|
+
for (const step of spec.setup ?? []) {
|
|
447
|
+
const s = typeof step === "string" ? { run: step } : step;
|
|
448
|
+
setup.push({
|
|
449
|
+
run: s.run,
|
|
450
|
+
timeoutMs: parseDuration(s.timeout ?? DEFAULT_SETUP_TIMEOUT),
|
|
451
|
+
...s.cwd ? { cwd: s.cwd } : {}
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
const layerSkills = /* @__PURE__ */ new Set();
|
|
455
|
+
for (const source of spec.skills ?? []) {
|
|
456
|
+
const found = await resolveSkills(root, source);
|
|
457
|
+
for (const loaded of found.skills) {
|
|
458
|
+
const name = loaded.skill.name;
|
|
459
|
+
if (skills.has(name) && !layerSkills.has(name)) overrides.add(`skills.${name}`);
|
|
460
|
+
layerSkills.add(name);
|
|
461
|
+
skills.delete(name);
|
|
462
|
+
skills.set(name, {
|
|
463
|
+
...loaded,
|
|
464
|
+
placement: source.placement,
|
|
465
|
+
source: found.source,
|
|
466
|
+
commit: found.commit,
|
|
467
|
+
call: skillCall(source, root)
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
const layerPlugins = /* @__PURE__ */ new Map();
|
|
472
|
+
for (const source of spec.plugins ?? []) {
|
|
473
|
+
const found = await resolvePlugin(root, source, envWhere);
|
|
474
|
+
const { name, call } = found.contents;
|
|
475
|
+
const first = layerPlugins.get(name);
|
|
476
|
+
if (first) throw new InfraError(`${envWhere}: ${samePluginTwice(layer.name, name, first, call)}`);
|
|
477
|
+
if (plugins.has(name)) overrides.add(`plugins.${name}`);
|
|
478
|
+
layerPlugins.set(name, call);
|
|
479
|
+
plugins.delete(name);
|
|
480
|
+
plugins.set(name, found);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const pluginList = [...plugins.values()];
|
|
484
|
+
const harness = options.harness ?? { kind: "fake" };
|
|
485
|
+
const refused = refusedPlugins(harness, pluginList.map((p) => p.contents), {
|
|
486
|
+
skills: [...skills.values()].filter((s) => s.placement === "harness").map((s) => ({
|
|
487
|
+
name: s.skill.name,
|
|
488
|
+
call: s.call
|
|
489
|
+
})),
|
|
490
|
+
mcp: [...mcp.keys()]
|
|
491
|
+
});
|
|
492
|
+
if (refused) throw new InfraError(`${envWhere}: ${refused}`);
|
|
493
|
+
const allowed = options.allowed ?? null;
|
|
494
|
+
const fetches = fetchesAtStart(pluginList.map((p) => p.contents), allowed);
|
|
495
|
+
if (fetches.refusal) throw new InfraError(`${envWhere}: ${fetches.refusal}`);
|
|
496
|
+
const pluginSkills = [];
|
|
497
|
+
const resolvedPlugins = [];
|
|
498
|
+
const pluginRecords = [];
|
|
499
|
+
for (const { contents: p, declared, source, commit, marketplace } of pluginList) {
|
|
500
|
+
const loaded = p.skills.length ? loadSkills(join(p.dir, "skills"), source, p.skills.map((s) => s.name)) : [];
|
|
501
|
+
for (const l of loaded) pluginSkills.push({
|
|
502
|
+
...l,
|
|
503
|
+
plugin: p.name,
|
|
504
|
+
source,
|
|
505
|
+
commit
|
|
506
|
+
});
|
|
507
|
+
const servers = [];
|
|
508
|
+
for (const [name, server] of Object.entries(p.mcp)) {
|
|
509
|
+
if (allowed && server.transport !== "stdio") {
|
|
510
|
+
const host = new URL(server.url).hostname;
|
|
511
|
+
if (!hostAllowed(allowed, host)) throw new InfraError(`${envWhere}: the ${p.name} plugin's MCP server "${name}" is at ${host}, which egress doesn't allow: add it to egress.allow`);
|
|
512
|
+
}
|
|
513
|
+
const key = pluginServerName(p.name, name);
|
|
514
|
+
mcp.set(key, server);
|
|
515
|
+
servers.push(key);
|
|
516
|
+
}
|
|
517
|
+
const files = pluginFiles(p);
|
|
518
|
+
resolvedPlugins.push({
|
|
519
|
+
name: p.name,
|
|
520
|
+
files,
|
|
521
|
+
parts: p.kept,
|
|
522
|
+
servers,
|
|
523
|
+
declared,
|
|
524
|
+
commit
|
|
525
|
+
});
|
|
526
|
+
pluginRecords.push({
|
|
527
|
+
name: p.name,
|
|
528
|
+
source,
|
|
529
|
+
marketplace,
|
|
530
|
+
commit,
|
|
531
|
+
sha256: sha256(JSON.stringify(files.map((f) => [f.path, sha256(f.content)]))),
|
|
532
|
+
build: null,
|
|
533
|
+
parts: pluginParts(p, loaded.map((l) => l.skill.name))
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
const secrets = {
|
|
537
|
+
names: [],
|
|
538
|
+
checks: [],
|
|
539
|
+
unset: [],
|
|
540
|
+
brokered: []
|
|
541
|
+
};
|
|
542
|
+
const vars = {};
|
|
543
|
+
const checkVars = {};
|
|
544
|
+
for (const [name, value] of Object.entries(env)) {
|
|
545
|
+
if (!isSecret(value)) {
|
|
546
|
+
vars[name] = value;
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const resolved = hostValue(name, value, envWhere, secrets);
|
|
550
|
+
if (resolved === void 0) continue;
|
|
551
|
+
if (value.to === "checks") checkVars[name] = resolved;
|
|
552
|
+
else vars[name] = resolved;
|
|
553
|
+
}
|
|
554
|
+
const secretOf = (value, key, hosts) => {
|
|
555
|
+
if (typeof value === "string") return value;
|
|
556
|
+
if (isSecretTemplate(value)) return template(value, envWhere, secrets, hosts);
|
|
557
|
+
return hostValue(key, value, envWhere, secrets, value.hosts ?? hosts);
|
|
558
|
+
};
|
|
559
|
+
const resolvedMcp = {};
|
|
560
|
+
for (const [name, s] of mcp) if (s.transport === "stdio") {
|
|
561
|
+
const e = {};
|
|
562
|
+
for (const [k, v] of Object.entries(s.env)) {
|
|
563
|
+
const r = secretOf(v, k);
|
|
564
|
+
if (r !== void 0) e[k] = r;
|
|
565
|
+
}
|
|
566
|
+
resolvedMcp[name] = {
|
|
567
|
+
transport: "stdio",
|
|
568
|
+
command: s.command,
|
|
569
|
+
args: s.args,
|
|
570
|
+
env: e
|
|
571
|
+
};
|
|
572
|
+
} else {
|
|
573
|
+
const h = {};
|
|
574
|
+
const hosts = mcpHosts(s.url);
|
|
575
|
+
for (const [k, v] of Object.entries(s.headers)) {
|
|
576
|
+
const r = secretOf(v, k, hosts);
|
|
577
|
+
if (r !== void 0) h[k] = r;
|
|
578
|
+
}
|
|
579
|
+
resolvedMcp[name] = {
|
|
580
|
+
transport: s.transport,
|
|
581
|
+
url: s.url,
|
|
582
|
+
headers: h
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
const fileList = [...files].map(([path, v]) => ({
|
|
586
|
+
path,
|
|
587
|
+
content: isHostFile(v) ? readHostFile(v, envWhere) : v,
|
|
588
|
+
...isHostFile(v) && statSync(v.path).mode & 64 ? { executable: true } : {}
|
|
589
|
+
}));
|
|
590
|
+
const rulesContent = rules === void 0 ? void 0 : isHostFile(rules) ? Buffer.from(readHostFile(rules, envWhere)).toString("utf8") : rules;
|
|
591
|
+
const skillList = [...skills.values()];
|
|
592
|
+
const skillRecords = [...skillList.map(({ skill, placement, source, commit, excluded }) => ({
|
|
593
|
+
name: skill.name,
|
|
594
|
+
source,
|
|
595
|
+
commit,
|
|
596
|
+
sha256: skillHash(skill),
|
|
597
|
+
placement,
|
|
598
|
+
excluded
|
|
599
|
+
})), ...pluginSkills.map(({ skill, source, commit, excluded, plugin }) => ({
|
|
600
|
+
name: skill.name,
|
|
601
|
+
source,
|
|
602
|
+
commit,
|
|
603
|
+
sha256: skillHash(skill),
|
|
604
|
+
placement: "harness",
|
|
605
|
+
excluded,
|
|
606
|
+
plugin
|
|
607
|
+
}))];
|
|
608
|
+
const fileRecords = fileList.map((f) => ({
|
|
609
|
+
path: f.path,
|
|
610
|
+
sha256: sha256(f.content)
|
|
611
|
+
}));
|
|
612
|
+
const executable = fileList.flatMap((f) => f.executable ? [f.path] : []);
|
|
613
|
+
const rulesRecord = rulesContent === void 0 ? void 0 : {
|
|
614
|
+
path: rulesFile,
|
|
615
|
+
sha256: sha256(rulesContent)
|
|
616
|
+
};
|
|
617
|
+
if (rulesContent !== void 0) fileList.push({
|
|
618
|
+
path: rulesFile,
|
|
619
|
+
content: rulesContent
|
|
620
|
+
});
|
|
621
|
+
const secretNames = [.../* @__PURE__ */ new Set([...secrets.names, ...secrets.checks])].sort();
|
|
622
|
+
const brokered = secrets.brokered.map((b) => JSON.stringify([
|
|
623
|
+
b.name,
|
|
624
|
+
b.hosts,
|
|
625
|
+
b.in,
|
|
626
|
+
b.phase
|
|
627
|
+
])).sort();
|
|
628
|
+
const brokeredNames = [...new Set(secrets.brokered.map((b) => b.name))].sort();
|
|
629
|
+
const varNames = Object.keys(vars).filter((n) => !secrets.names.includes(n)).sort();
|
|
630
|
+
const literalVars = Object.fromEntries(varNames.map((n) => [n, vars[n]]));
|
|
631
|
+
const mcpShape = Object.fromEntries(Object.entries(resolvedMcp).map(([name, s]) => s.transport === "stdio" ? [name, {
|
|
632
|
+
command: s.command,
|
|
633
|
+
args: s.args,
|
|
634
|
+
env: Object.keys(s.env).sort()
|
|
635
|
+
}] : [name, {
|
|
636
|
+
transport: s.transport,
|
|
637
|
+
url: s.url,
|
|
638
|
+
headers: Object.keys(s.headers).sort()
|
|
639
|
+
}]));
|
|
640
|
+
const tree = workspace && prepared(workspace);
|
|
641
|
+
if (workspace && !tree) throw new InfraError(`The workspace git(${JSON.stringify(workspaceLabel(workspace))}) for ${envWhere} wasn't prepared before the run started`);
|
|
642
|
+
const workspaceRecord = workspace && tree ? {
|
|
643
|
+
source: isAbsolute(workspace.url) ? relative(root, workspace.url).split(sep).join("/") || "." : workspace.repo,
|
|
644
|
+
ref: workspace.ref ?? null,
|
|
645
|
+
path: workspace.path ?? null,
|
|
646
|
+
commit: tree.commit,
|
|
647
|
+
tree: tree.tree,
|
|
648
|
+
...workspace.init ? { init: true } : {}
|
|
649
|
+
} : void 0;
|
|
650
|
+
const digest = `sha256:${sha256(JSON.stringify({
|
|
651
|
+
setup,
|
|
652
|
+
skills: skillRecords.map((s) => [
|
|
653
|
+
s.name,
|
|
654
|
+
s.sha256,
|
|
655
|
+
s.placement
|
|
656
|
+
]),
|
|
657
|
+
mcp: mcpShape,
|
|
658
|
+
files: fileRecords,
|
|
659
|
+
...executable.length ? { executable } : {},
|
|
660
|
+
rules: rulesRecord?.sha256,
|
|
661
|
+
vars: literalVars,
|
|
662
|
+
secrets: secretNames,
|
|
663
|
+
checks: [...secrets.checks].sort(),
|
|
664
|
+
unset: [...secrets.unset].sort(),
|
|
665
|
+
brokered,
|
|
666
|
+
...egress === "allow-all" ? {} : { egress: typeof egress === "string" ? egress : [...egress.allow].sort() },
|
|
667
|
+
...pluginRecords.length ? { plugins: pluginRecords.map((p, i) => {
|
|
668
|
+
const r = resolvedPlugins[i];
|
|
669
|
+
const build = r?.declared.build;
|
|
670
|
+
return [
|
|
671
|
+
p.name,
|
|
672
|
+
p.sha256,
|
|
673
|
+
r?.parts,
|
|
674
|
+
...build === void 0 ? [] : [build]
|
|
675
|
+
];
|
|
676
|
+
}) } : {},
|
|
677
|
+
...workspaceRecord ? { workspace: workspaceRecord.init ? [workspaceRecord.tree, "init"] : workspaceRecord.tree } : {}
|
|
678
|
+
}))}`;
|
|
679
|
+
return {
|
|
680
|
+
record: {
|
|
681
|
+
name: environment.name,
|
|
682
|
+
parent: environment.parent,
|
|
683
|
+
overrides: [...overrides],
|
|
684
|
+
digest,
|
|
685
|
+
setup: setup.map(stepCommand),
|
|
686
|
+
skills: skillRecords,
|
|
687
|
+
mcp: Object.keys(resolvedMcp).sort(),
|
|
688
|
+
...pluginRecords.length ? { plugins: pluginRecords } : {},
|
|
689
|
+
files: rulesRecord ? [...fileRecords, rulesRecord] : fileRecords,
|
|
690
|
+
vars: varNames,
|
|
691
|
+
secrets: secretNames,
|
|
692
|
+
brokered: brokeredNames,
|
|
693
|
+
unset: [...secrets.unset].sort(),
|
|
694
|
+
egress,
|
|
695
|
+
...workspaceRecord ? { workspace: workspaceRecord } : {}
|
|
696
|
+
},
|
|
697
|
+
setup,
|
|
698
|
+
skills: [...skillList.filter((s) => s.placement === "harness").map((s) => s.skill), ...layoutOf(harness).pluginPlacement === "flat" ? pluginSkills.map((s) => s.skill) : []],
|
|
699
|
+
workspaceSkills: skillList.filter((s) => s.placement === "workspace").map((s) => s.skill),
|
|
700
|
+
mcp: resolvedMcp,
|
|
701
|
+
files: fileList,
|
|
702
|
+
vars,
|
|
703
|
+
checkVars,
|
|
704
|
+
substitutions: secrets.brokered,
|
|
705
|
+
plugins: resolvedPlugins,
|
|
706
|
+
...workspace && tree ? { workspace: {
|
|
707
|
+
tar: tree.tar,
|
|
708
|
+
label: workspaceLabel(workspace),
|
|
709
|
+
commit: tree.commit,
|
|
710
|
+
...workspace.init ? { init: true } : {}
|
|
711
|
+
} } : {}
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
/** A skill as a `SKILL.md` file plus its other files, for writing into a directory. */
|
|
715
|
+
function skillFiles(skill) {
|
|
716
|
+
return [{
|
|
717
|
+
path: "SKILL.md",
|
|
718
|
+
content: `${`---\nname: ${skill.name}\ndescription: ${JSON.stringify(skill.description)}\n---\n`}${skill.content}`
|
|
719
|
+
}, ...skill.files];
|
|
720
|
+
}
|
|
721
|
+
//#endregion
|
|
722
|
+
export { skillFiles as a, resolveEnvironment as i, parseSkillMd as n, pluginSourceDir as r, excludeMatcher as t };
|
|
723
|
+
|
|
724
|
+
//# sourceMappingURL=resolve-C4zeccCH.js.map
|