@runcofactor/cli 0.54.0 → 0.56.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 +2 -1
- package/dist/{account-6YJAU53I.js → account-CZYZD2JS.js} +5 -5
- package/dist/{alert-Z7V2ZUEW.js → alert-JQ4SDEB7.js} +8 -8
- package/dist/{api-catalog-UEDTRM6E.js → api-catalog-IWQC35P2.js} +5 -5
- package/dist/{api-key-V5GEPRRG.js → api-key-GUDXIIEA.js} +5 -5
- package/dist/{attachment-M7VZ6GSE.js → attachment-CPZYOBUB.js} +5 -5
- package/dist/{auth-DVTMWJKF.js → auth-DS6MBVEI.js} +3 -3
- package/dist/{benchmark-KZJZYUTQ.js → benchmark-6HPCIQHD.js} +5 -5
- package/dist/{blackcat-QJXYDE66.js → blackcat-V3L63WFE.js} +3 -3
- package/dist/{chunk-FLDIN6VX.js → chunk-2E3STBHS.js} +2 -2
- package/dist/{chunk-KNWKOKM7.js → chunk-2OHYMT3A.js} +20 -11
- package/dist/chunk-2OHYMT3A.js.map +1 -0
- package/dist/{chunk-L4Y5PZUE.js → chunk-3LGCHNBC.js} +2 -2
- package/dist/{chunk-ZFN5FWN2.js → chunk-4MFMPC5P.js} +46 -2
- package/dist/chunk-4MFMPC5P.js.map +1 -0
- package/dist/{chunk-2M4PZK6Q.js → chunk-56HFZHQM.js} +8 -8
- package/dist/{chunk-AQOHNAEN.js → chunk-5OYWNS6D.js} +20 -9
- package/dist/chunk-5OYWNS6D.js.map +1 -0
- package/dist/{chunk-RA2NRAWU.js → chunk-62EXS76C.js} +6 -6
- package/dist/{chunk-HGEJHS45.js → chunk-6ILWJFKY.js} +368 -6
- package/dist/chunk-6ILWJFKY.js.map +1 -0
- package/dist/{chunk-4EWSONHO.js → chunk-BDOL622T.js} +4 -4
- package/dist/{chunk-T6EQFICG.js → chunk-C3CXVX2B.js} +4 -4
- package/dist/{chunk-33U56YGD.js → chunk-CWICLBLU.js} +2 -1
- package/dist/{chunk-33U56YGD.js.map → chunk-CWICLBLU.js.map} +1 -1
- package/dist/{chunk-MQQCUU5S.js → chunk-DEVD2WD2.js} +2 -2
- package/dist/{chunk-TRC63RSK.js → chunk-EWK44F6V.js} +3 -3
- package/dist/chunk-EWK44F6V.js.map +1 -0
- package/dist/{chunk-Q7UAEFW5.js → chunk-FNHPTTRF.js} +7 -5
- package/dist/chunk-FNHPTTRF.js.map +1 -0
- package/dist/{chunk-JAIMLQOU.js → chunk-GCD4EHCD.js} +6 -6
- package/dist/{chunk-7MRZWPVC.js → chunk-H6ZMKNP7.js} +3 -3
- package/dist/{chunk-ZOPVBINJ.js → chunk-IEWAH7W3.js} +5 -5
- package/dist/{chunk-74TU6PGO.js → chunk-IV4HRGKX.js} +77 -12
- package/dist/chunk-IV4HRGKX.js.map +1 -0
- package/dist/{chunk-ZO5MSM4Q.js → chunk-J2ZQULU3.js} +2 -2
- package/dist/{chunk-IVWWYKAM.js → chunk-K2IDR6FR.js} +3 -3
- package/dist/{chunk-QGP67JOK.js → chunk-KTZRI27M.js} +4 -4
- package/dist/{chunk-HESV3F6U.js → chunk-L644NMDI.js} +3 -3
- package/dist/{chunk-HESV3F6U.js.map → chunk-L644NMDI.js.map} +1 -1
- package/dist/{chunk-LPQTXBJF.js → chunk-LFT7GUWS.js} +63 -17
- package/dist/chunk-LFT7GUWS.js.map +1 -0
- package/dist/{chunk-O7MBDOMO.js → chunk-O7B2IYCZ.js} +30 -14
- package/dist/chunk-O7B2IYCZ.js.map +1 -0
- package/dist/{chunk-R2CVV7QT.js → chunk-RHWPZKRV.js} +28 -1
- package/dist/chunk-RHWPZKRV.js.map +1 -0
- package/dist/{chunk-3YNR6U6Q.js → chunk-UJSW72LG.js} +3 -3
- package/dist/{chunk-G2SCV2CY.js → chunk-VACACCD6.js} +3 -3
- package/dist/{chunk-CV22445U.js → chunk-VMAR67FF.js} +2 -2
- package/dist/{chunk-QYHJUHL7.js → chunk-VMJ7TBVM.js} +2 -2
- package/dist/chunk-WRRA4ATV.js +332 -0
- package/dist/chunk-WRRA4ATV.js.map +1 -0
- package/dist/{chunk-YACDH6MJ.js → chunk-XHEVDABB.js} +2 -2
- package/dist/{chunk-7VBX2M4F.js → chunk-XHGF6VC6.js} +4 -4
- package/dist/{credential-546ER7WQ.js → credential-GJW7LGYP.js} +5 -5
- package/dist/{credential-template-BWMEBGBN.js → credential-template-UWBYKKWD.js} +5 -5
- package/dist/dev-PBW7BSOD.js +605 -0
- package/dist/dev-PBW7BSOD.js.map +1 -0
- package/dist/{digest-NIVBDDI2.js → digest-XEHGCJM4.js} +8 -8
- package/dist/{docs-AK4MDP6K.js → docs-KH4BCEQF.js} +5 -5
- package/dist/{doctor-NCLA47EL.js → doctor-FOXXE5SK.js} +3 -3
- package/dist/{environment-X3PV5IN2.js → environment-EBDPQTIS.js} +7 -7
- package/dist/{eval-5FZKYZ6O.js → eval-QZSSEICV.js} +67 -27
- package/dist/eval-QZSSEICV.js.map +1 -0
- package/dist/{exploration-2RVGIUKT.js → exploration-LCGKRGOQ.js} +5 -5
- package/dist/{exploratory-test-SJ5HFI3L.js → exploratory-test-SGECQGIX.js} +13 -5
- package/dist/exploratory-test-SGECQGIX.js.map +1 -0
- package/dist/{external-run-4NDVAHQB.js → external-run-2AJAI5O7.js} +9 -9
- package/dist/{feature-flag-C4IRE724.js → feature-flag-P7N4WQIH.js} +5 -5
- package/dist/{feedback-337OZCKC.js → feedback-LAT7TQ2T.js} +6 -6
- package/dist/{flow-D7ZLBKCH.js → flow-NH2DC6AP.js} +5 -5
- package/dist/{github-LKXYIALH.js → github-FCEKBLXI.js} +6 -6
- package/dist/index.js +106 -408
- package/dist/index.js.map +1 -1
- package/dist/{init-GKEC6LPH.js → init-5U5EZOAW.js} +5 -5
- package/dist/{install-K45SAT2V.js → install-X3UNVXKY.js} +5 -5
- package/dist/{issues-2HMTQYWR.js → issues-4P6I3YQW.js} +8 -8
- package/dist/{knobs-KUCGLO5Z.js → knobs-JKTWJ6ZG.js} +5 -5
- package/dist/{landing-KAET2I73.js → landing-6AGLKI66.js} +7 -7
- package/dist/{list-GDV4UYWV.js → list-TWP2RP33.js} +5 -5
- package/dist/{local-NFOSJLLV.js → local-D75QE5TB.js} +7 -7
- package/dist/{login-Y77HWROY.js → login-RBET4TIP.js} +5 -5
- package/dist/{mcp-CPCFMU6B.js → mcp-562SUUMK.js} +11 -11
- package/dist/{metrics-Y245ST63.js → metrics-4WF2GEPA.js} +5 -5
- package/dist/{monitor-BUDWSC3S.js → monitor-WJXH54H2.js} +5 -5
- package/dist/{perf-3JOAXPHP.js → perf-C6N6P7YG.js} +12 -361
- package/dist/perf-C6N6P7YG.js.map +1 -0
- package/dist/{product-CXL3YTMD.js → product-CYEQ7HOB.js} +5 -5
- package/dist/{product-map-656BTU74.js → product-map-MSDLIFZY.js} +7 -7
- package/dist/{prompts-3SZ7O5E6.js → prompts-ME53WPN4.js} +5 -5
- package/dist/{proofs-4CSCCSNL.js → proofs-D3G6ZUFP.js} +11 -9
- package/dist/{property-IEKBXRVY.js → property-5GLJNAVB.js} +29 -10
- package/dist/property-5GLJNAVB.js.map +1 -0
- package/dist/{psql-M4CM6TSI.js → psql-EXAUDU3W.js} +5 -5
- package/dist/{record-QP4TYZBS.js → record-EE7NGNKY.js} +6 -6
- package/dist/{redis-KG47IGJV.js → redis-M4EYWKOJ.js} +5 -5
- package/dist/{release-QHPSQULK.js → release-4KUWVWWC.js} +5 -5
- package/dist/{runbook-YVBG2QK3.js → runbook-AHU77ANQ.js} +5 -5
- package/dist/{sandbox-ZXDZTCCN.js → sandbox-FBLJEYA2.js} +1917 -1633
- package/dist/sandbox-FBLJEYA2.js.map +1 -0
- package/dist/{scenarios-2SX2NUCD.js → scenarios-TU656T2B.js} +5 -5
- package/dist/{schedule-P6F7MLXX.js → schedule-DXJI6SYO.js} +8 -8
- package/dist/{session-SZMCZTPE.js → session-RUFTJHF4.js} +10 -10
- package/dist/{skill-D4XFW6QI.js → skill-ZK76GQ47.js} +111 -13
- package/dist/skill-ZK76GQ47.js.map +1 -0
- package/dist/skills/cofactor-debug-run/SKILL.md +6 -1
- package/dist/skills/cofactor-debug-run/history/2.0.10.md +320 -0
- package/dist/skills/cofactor-debug-run/history/2.0.9.md +319 -0
- package/dist/skills/cofactor-debug-run/version.json +1 -1
- package/dist/{slack-UDXTPOSW.js → slack-M3OKDVMY.js} +6 -6
- package/dist/{spec-YCBBIV27.js → spec-5MXEBLYR.js} +5 -5
- package/dist/{src-DY7GLRO2.js → src-2X5OQRPJ.js} +4 -4
- package/dist/{src-NG7DRE5A.js → src-72EFBA2R.js} +3 -3
- package/dist/{src-DEGBASCD.js → src-KH6WSBJV.js} +5 -5
- package/dist/{src-ZKVNVLXY.js → src-VLV36QYH.js} +127 -20
- package/dist/src-VLV36QYH.js.map +1 -0
- package/dist/{start-ZYZSORPY.js → start-PDYBRB5T.js} +5 -5
- package/dist/{status-ESIG6A7W.js → status-VMVPVCDA.js} +5 -5
- package/dist/{tag-3K5Y25AR.js → tag-7KTDLPVU.js} +6 -6
- package/dist/{task-JLNX7O3M.js → task-QLFYZNKR.js} +6 -6
- package/dist/{teams-F4IU3EXE.js → teams-Y7BXCY6P.js} +7 -7
- package/dist/{test-suite-QHDUW5W5.js → test-suite-6U22AYFG.js} +15 -14
- package/dist/test-suite-6U22AYFG.js.map +1 -0
- package/dist/{tickets-NBL5WACL.js → tickets-CQDJDNPY.js} +5 -5
- package/dist/{trace-ZKYAI5JF.js → trace-QDORWXYX.js} +8 -8
- package/dist/{triage-5NWCREUM.js → triage-GY7M3UGG.js} +6 -6
- package/dist/{trigger-KXYYY5IR.js → trigger-DLFAORX4.js} +9 -9
- package/dist/{update-check-Q2URVJLC.js → update-check-ES6XQ7OF.js} +4 -4
- package/dist/{upgrade-4XSASC7U.js → upgrade-WKEOW5GS.js} +5 -5
- package/dist/{usage-UY7VZYVY.js → usage-E6FDTR3W.js} +7 -7
- package/dist/{utilities-53NXNLA7.js → utilities-4Z6YX3L5.js} +6 -6
- package/dist/{visual-IJAT7X7D.js → visual-TA6LPVDJ.js} +5 -5
- package/dist/{workflow-OQNH2FIS.js → workflow-B5FXS2CJ.js} +92 -36
- package/dist/workflow-B5FXS2CJ.js.map +1 -0
- package/dist/{workflow-cache-FP6MKLVR.js → workflow-cache-MNLEMRMM.js} +16 -16
- package/dist/{workflow-cache-convergence-resolve-HS5KO7US.js → workflow-cache-convergence-resolve-G5HJM6MF.js} +5 -5
- package/dist/{workflow-debug-EM55H2QE.js → workflow-debug-TNBUGSBK.js} +11 -11
- package/dist/{workflow-feedback-GNWNWVHH.js → workflow-feedback-G2ZXAUGI.js} +5 -5
- package/dist/{workflow-fork-M5AQWST7.js → workflow-fork-6HHOMC2D.js} +5 -5
- package/dist/{workflow-promotion-HYULZDYL.js → workflow-promotion-RG7L6JZT.js} +5 -5
- package/dist/{workflow-proposals-EN327FSE.js → workflow-proposals-ZNF2F3UE.js} +5 -5
- package/dist/{workflow-revisions-ZMTVNWRW.js → workflow-revisions-TP64Z6FO.js} +5 -5
- package/dist/{workflow-status-FNAJG34W.js → workflow-status-5RG3JX56.js} +5 -5
- package/package.json +3 -2
- package/dist/chunk-74TU6PGO.js.map +0 -1
- package/dist/chunk-AQOHNAEN.js.map +0 -1
- package/dist/chunk-HGEJHS45.js.map +0 -1
- package/dist/chunk-KNWKOKM7.js.map +0 -1
- package/dist/chunk-LPQTXBJF.js.map +0 -1
- package/dist/chunk-O7MBDOMO.js.map +0 -1
- package/dist/chunk-Q7UAEFW5.js.map +0 -1
- package/dist/chunk-R2CVV7QT.js.map +0 -1
- package/dist/chunk-TRC63RSK.js.map +0 -1
- package/dist/chunk-ZFN5FWN2.js.map +0 -1
- package/dist/eval-5FZKYZ6O.js.map +0 -1
- package/dist/exploratory-test-SJ5HFI3L.js.map +0 -1
- package/dist/perf-3JOAXPHP.js.map +0 -1
- package/dist/property-IEKBXRVY.js.map +0 -1
- package/dist/sandbox-ZXDZTCCN.js.map +0 -1
- package/dist/skill-D4XFW6QI.js.map +0 -1
- package/dist/src-ZKVNVLXY.js.map +0 -1
- package/dist/test-suite-QHDUW5W5.js.map +0 -1
- package/dist/workflow-OQNH2FIS.js.map +0 -1
- /package/dist/{account-6YJAU53I.js.map → account-CZYZD2JS.js.map} +0 -0
- /package/dist/{alert-Z7V2ZUEW.js.map → alert-JQ4SDEB7.js.map} +0 -0
- /package/dist/{api-catalog-UEDTRM6E.js.map → api-catalog-IWQC35P2.js.map} +0 -0
- /package/dist/{api-key-V5GEPRRG.js.map → api-key-GUDXIIEA.js.map} +0 -0
- /package/dist/{attachment-M7VZ6GSE.js.map → attachment-CPZYOBUB.js.map} +0 -0
- /package/dist/{auth-DVTMWJKF.js.map → auth-DS6MBVEI.js.map} +0 -0
- /package/dist/{benchmark-KZJZYUTQ.js.map → benchmark-6HPCIQHD.js.map} +0 -0
- /package/dist/{blackcat-QJXYDE66.js.map → blackcat-V3L63WFE.js.map} +0 -0
- /package/dist/{chunk-FLDIN6VX.js.map → chunk-2E3STBHS.js.map} +0 -0
- /package/dist/{chunk-L4Y5PZUE.js.map → chunk-3LGCHNBC.js.map} +0 -0
- /package/dist/{chunk-2M4PZK6Q.js.map → chunk-56HFZHQM.js.map} +0 -0
- /package/dist/{chunk-RA2NRAWU.js.map → chunk-62EXS76C.js.map} +0 -0
- /package/dist/{chunk-4EWSONHO.js.map → chunk-BDOL622T.js.map} +0 -0
- /package/dist/{chunk-T6EQFICG.js.map → chunk-C3CXVX2B.js.map} +0 -0
- /package/dist/{chunk-MQQCUU5S.js.map → chunk-DEVD2WD2.js.map} +0 -0
- /package/dist/{chunk-JAIMLQOU.js.map → chunk-GCD4EHCD.js.map} +0 -0
- /package/dist/{chunk-7MRZWPVC.js.map → chunk-H6ZMKNP7.js.map} +0 -0
- /package/dist/{chunk-ZOPVBINJ.js.map → chunk-IEWAH7W3.js.map} +0 -0
- /package/dist/{chunk-ZO5MSM4Q.js.map → chunk-J2ZQULU3.js.map} +0 -0
- /package/dist/{chunk-IVWWYKAM.js.map → chunk-K2IDR6FR.js.map} +0 -0
- /package/dist/{chunk-QGP67JOK.js.map → chunk-KTZRI27M.js.map} +0 -0
- /package/dist/{chunk-3YNR6U6Q.js.map → chunk-UJSW72LG.js.map} +0 -0
- /package/dist/{chunk-G2SCV2CY.js.map → chunk-VACACCD6.js.map} +0 -0
- /package/dist/{chunk-CV22445U.js.map → chunk-VMAR67FF.js.map} +0 -0
- /package/dist/{chunk-QYHJUHL7.js.map → chunk-VMJ7TBVM.js.map} +0 -0
- /package/dist/{chunk-YACDH6MJ.js.map → chunk-XHEVDABB.js.map} +0 -0
- /package/dist/{chunk-7VBX2M4F.js.map → chunk-XHGF6VC6.js.map} +0 -0
- /package/dist/{credential-546ER7WQ.js.map → credential-GJW7LGYP.js.map} +0 -0
- /package/dist/{credential-template-BWMEBGBN.js.map → credential-template-UWBYKKWD.js.map} +0 -0
- /package/dist/{digest-NIVBDDI2.js.map → digest-XEHGCJM4.js.map} +0 -0
- /package/dist/{docs-AK4MDP6K.js.map → docs-KH4BCEQF.js.map} +0 -0
- /package/dist/{doctor-NCLA47EL.js.map → doctor-FOXXE5SK.js.map} +0 -0
- /package/dist/{environment-X3PV5IN2.js.map → environment-EBDPQTIS.js.map} +0 -0
- /package/dist/{exploration-2RVGIUKT.js.map → exploration-LCGKRGOQ.js.map} +0 -0
- /package/dist/{external-run-4NDVAHQB.js.map → external-run-2AJAI5O7.js.map} +0 -0
- /package/dist/{feature-flag-C4IRE724.js.map → feature-flag-P7N4WQIH.js.map} +0 -0
- /package/dist/{feedback-337OZCKC.js.map → feedback-LAT7TQ2T.js.map} +0 -0
- /package/dist/{flow-D7ZLBKCH.js.map → flow-NH2DC6AP.js.map} +0 -0
- /package/dist/{github-LKXYIALH.js.map → github-FCEKBLXI.js.map} +0 -0
- /package/dist/{init-GKEC6LPH.js.map → init-5U5EZOAW.js.map} +0 -0
- /package/dist/{install-K45SAT2V.js.map → install-X3UNVXKY.js.map} +0 -0
- /package/dist/{issues-2HMTQYWR.js.map → issues-4P6I3YQW.js.map} +0 -0
- /package/dist/{knobs-KUCGLO5Z.js.map → knobs-JKTWJ6ZG.js.map} +0 -0
- /package/dist/{landing-KAET2I73.js.map → landing-6AGLKI66.js.map} +0 -0
- /package/dist/{list-GDV4UYWV.js.map → list-TWP2RP33.js.map} +0 -0
- /package/dist/{local-NFOSJLLV.js.map → local-D75QE5TB.js.map} +0 -0
- /package/dist/{login-Y77HWROY.js.map → login-RBET4TIP.js.map} +0 -0
- /package/dist/{mcp-CPCFMU6B.js.map → mcp-562SUUMK.js.map} +0 -0
- /package/dist/{metrics-Y245ST63.js.map → metrics-4WF2GEPA.js.map} +0 -0
- /package/dist/{monitor-BUDWSC3S.js.map → monitor-WJXH54H2.js.map} +0 -0
- /package/dist/{product-CXL3YTMD.js.map → product-CYEQ7HOB.js.map} +0 -0
- /package/dist/{product-map-656BTU74.js.map → product-map-MSDLIFZY.js.map} +0 -0
- /package/dist/{prompts-3SZ7O5E6.js.map → prompts-ME53WPN4.js.map} +0 -0
- /package/dist/{proofs-4CSCCSNL.js.map → proofs-D3G6ZUFP.js.map} +0 -0
- /package/dist/{psql-M4CM6TSI.js.map → psql-EXAUDU3W.js.map} +0 -0
- /package/dist/{record-QP4TYZBS.js.map → record-EE7NGNKY.js.map} +0 -0
- /package/dist/{redis-KG47IGJV.js.map → redis-M4EYWKOJ.js.map} +0 -0
- /package/dist/{release-QHPSQULK.js.map → release-4KUWVWWC.js.map} +0 -0
- /package/dist/{runbook-YVBG2QK3.js.map → runbook-AHU77ANQ.js.map} +0 -0
- /package/dist/{scenarios-2SX2NUCD.js.map → scenarios-TU656T2B.js.map} +0 -0
- /package/dist/{schedule-P6F7MLXX.js.map → schedule-DXJI6SYO.js.map} +0 -0
- /package/dist/{session-SZMCZTPE.js.map → session-RUFTJHF4.js.map} +0 -0
- /package/dist/{slack-UDXTPOSW.js.map → slack-M3OKDVMY.js.map} +0 -0
- /package/dist/{spec-YCBBIV27.js.map → spec-5MXEBLYR.js.map} +0 -0
- /package/dist/{src-DEGBASCD.js.map → src-2X5OQRPJ.js.map} +0 -0
- /package/dist/{src-DY7GLRO2.js.map → src-72EFBA2R.js.map} +0 -0
- /package/dist/{src-NG7DRE5A.js.map → src-KH6WSBJV.js.map} +0 -0
- /package/dist/{start-ZYZSORPY.js.map → start-PDYBRB5T.js.map} +0 -0
- /package/dist/{status-ESIG6A7W.js.map → status-VMVPVCDA.js.map} +0 -0
- /package/dist/{tag-3K5Y25AR.js.map → tag-7KTDLPVU.js.map} +0 -0
- /package/dist/{task-JLNX7O3M.js.map → task-QLFYZNKR.js.map} +0 -0
- /package/dist/{teams-F4IU3EXE.js.map → teams-Y7BXCY6P.js.map} +0 -0
- /package/dist/{tickets-NBL5WACL.js.map → tickets-CQDJDNPY.js.map} +0 -0
- /package/dist/{trace-ZKYAI5JF.js.map → trace-QDORWXYX.js.map} +0 -0
- /package/dist/{triage-5NWCREUM.js.map → triage-GY7M3UGG.js.map} +0 -0
- /package/dist/{trigger-KXYYY5IR.js.map → trigger-DLFAORX4.js.map} +0 -0
- /package/dist/{update-check-Q2URVJLC.js.map → update-check-ES6XQ7OF.js.map} +0 -0
- /package/dist/{upgrade-4XSASC7U.js.map → upgrade-WKEOW5GS.js.map} +0 -0
- /package/dist/{usage-UY7VZYVY.js.map → usage-E6FDTR3W.js.map} +0 -0
- /package/dist/{utilities-53NXNLA7.js.map → utilities-4Z6YX3L5.js.map} +0 -0
- /package/dist/{visual-IJAT7X7D.js.map → visual-TA6LPVDJ.js.map} +0 -0
- /package/dist/{workflow-cache-FP6MKLVR.js.map → workflow-cache-MNLEMRMM.js.map} +0 -0
- /package/dist/{workflow-cache-convergence-resolve-HS5KO7US.js.map → workflow-cache-convergence-resolve-G5HJM6MF.js.map} +0 -0
- /package/dist/{workflow-debug-EM55H2QE.js.map → workflow-debug-TNBUGSBK.js.map} +0 -0
- /package/dist/{workflow-feedback-GNWNWVHH.js.map → workflow-feedback-G2ZXAUGI.js.map} +0 -0
- /package/dist/{workflow-fork-M5AQWST7.js.map → workflow-fork-6HHOMC2D.js.map} +0 -0
- /package/dist/{workflow-promotion-HYULZDYL.js.map → workflow-promotion-RG7L6JZT.js.map} +0 -0
- /package/dist/{workflow-proposals-EN327FSE.js.map → workflow-proposals-ZNF2F3UE.js.map} +0 -0
- /package/dist/{workflow-revisions-ZMTVNWRW.js.map → workflow-revisions-TP64Z6FO.js.map} +0 -0
- /package/dist/{workflow-status-FNAJG34W.js.map → workflow-status-5RG3JX56.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dev.ts","../../sandbox-helper/src/ade-manifest.ts","../src/dev-ssh.ts","../../ade-relay-protocol/src/index.ts"],"sourcesContent":["/**\n * `cofactor dev`: dev environments (ADEs), remote sandboxes a coding agent\n * works in.\n *\n * cofactor dev [--template <name>] claim a session, follow its phases, and attach once its home is mounted\n * cofactor dev attach [<id>] SSH into a session's tmux from this machine (grants this machine's key)\n * cofactor dev proxy <id> ssh's ProxyCommand (written into ~/.ssh/config.d/cofactor-ade)\n * cofactor dev list [--all] your sessions (`--all`: and those ended in the last 7 days)\n * cofactor dev destroy <id> end a session, wait, and print the final save's result\n * cofactor dev template publish [<path-to-yaml>] admin: publish a pushed cofactor.ade.yaml and wait for its build\n * cofactor dev template list versions, status, source commit, setup-prompt hash\n *\n * @module dev\n * @see specs/pending/ade.md (CLI surface)\n */\nimport { execFileSync } from 'node:child_process';\nimport path from 'node:path';\nimport process from 'node:process';\nimport { stripVTControlCharacters } from 'node:util';\nimport { ADE_MANIFEST_FILE, validateAdeManifest } from '@chatsdet/sandbox-helper/ade-manifest';\nimport { GLOBAL_VALUE_FLAGS, getArgValue, hasFlag, resolveConfig } from './auth.js';\nimport { writeRawOutput } from './brand.js';\nimport { apiRequest, getPositionalArg } from './cli-helpers.js';\nimport { attachSsh, grantAndConfigure, runProxy } from './dev-ssh.js';\nimport { ProcessExitSignal } from './user-event-tracking.js';\n\ntype TemplateVersion = {\n id: string;\n name: string;\n version: number;\n status: 'building' | 'ready' | 'failed';\n sourceRepo: string;\n sourceCommit: string;\n baseVersion: number;\n setupPromptSha256: string;\n error: string | null;\n createdAt: string;\n};\n\ntype VersionResponse = { ok: boolean; error?: string; data?: TemplateVersion };\ntype PublishResponse = {\n ok: boolean;\n error?: string;\n issues?: Array<{ path: string; message: string }>;\n data?: { id: string; name: string; version: number };\n};\n\ntype Session = {\n id: string;\n templateId: string;\n status: 'requested' | 'claiming' | 'provisioning' | 'running' | 'ending' | 'ended';\n phase: string | null;\n endReason: string | null;\n endDetail: string | null;\n vcpus: number;\n memoryMib: number;\n leaseCapAt: string | null;\n /** The guest's latest event; guest-written, so printed through `guestText`. */\n lastEvent: { identity?: string; error?: string; branches?: string[] } | null;\n createdAt: string;\n endedAt: string | null;\n};\n\ntype SessionResponse = { ok: boolean; error?: string; data?: Session };\n\n/** A build takes minutes (a base import, apt and agent installs); its status is polled at this interval. */\nconst POLL_MS = 5_000;\n/**\n * `dev destroy` waits for `ended`. The final save is bounded at 5 min; a session\n * that runs out of time is finished by the first 5-min reconcile pass after it\n * has been ending for 10 min, so up to about 15.\n */\nconst DESTROY_WAIT_MS = 16 * 60_000;\nconst DEV_VALUE_FLAGS = [...GLOBAL_VALUE_FLAGS, '--template'];\n\nfunction printHelp(): void {\n console.log(\n [\n 'Usage: cofactor dev [<sub-command>] [options]',\n '',\n 'Dev environments (ADEs): remote sandboxes a coding agent works in.',\n '',\n 'Sub-commands:',\n ' (none) [--template <name>] Claim a session, follow it, and attach once it is ready. --template is required when the org has several',\n ' attach [<id>] SSH into a session (your only live one by default) from this machine. Makes',\n ' ~/.config/cofactor/ade/id_ed25519 (no passphrase) once; each grant lasts 12 h',\n ' proxy <id> The SSH ProxyCommand `cofactor dev attach` writes; not run by hand',\n ' list [--all] Your sessions: status, phase, size, lease end, last event; --all adds those ended in 7 days',\n ' destroy <id> End a session (its home is saved), wait for it, and print the result',\n ` template publish [<path>] Admin. Publish a pushed ${ADE_MANIFEST_FILE} (default: the repo root's) and wait for its build`,\n ' template list Template versions: status, source commit, setup-prompt hash, error',\n '',\n 'Options:',\n ' --json Output raw JSON (list, template list)',\n ' --env <env> Target environment (prod, dev, local)',\n ].join('\\n')\n );\n}\n\nfunction fail(message: string): never {\n console.error(`Error: ${message}`);\n process.exit(1);\n}\n\nconst git = (cwd: string, ...args: string[]) =>\n execFileSync('git', args, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });\n\n/** `owner/name` of a github.com remote URL (https or ssh), or null. */\nfunction githubRepoOf(url: string): string | null {\n const match = url.match(/^(?:https:\\/\\/github\\.com\\/|git@github\\.com:|ssh:\\/\\/git@github\\.com\\/)([A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+?)(?:\\.git)?\\/?$/);\n return match ? match[1]! : null;\n}\n\n/** The template's repo; `commit` (HEAD, the commit the template records) must be on its upstream. */\nfunction publishedRepo(root: string, commit: string): string {\n let upstream: string;\n try {\n upstream = git(root, 'rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}').trim();\n } catch {\n fail('this branch has no upstream: push it first (git push -u)');\n }\n try {\n git(root, 'merge-base', '--is-ancestor', commit, '@{u}');\n } catch {\n fail(`HEAD (${commit.slice(0, 12)}) is not on ${upstream}: push it first`);\n }\n const remote = upstream.split('/')[0]!;\n const repo = githubRepoOf(git(root, 'remote', 'get-url', remote).trim());\n if (!repo) fail(`the ${remote} remote is not a github.com repository`);\n return repo;\n}\n\n/**\n * A file as committed at `commit`, never the working tree: the bytes published\n * are exactly the commit's, and a committed symlink is read as its link text,\n * not followed to a file outside the repo.\n */\nfunction committed(root: string, commit: string, file: string): string {\n try {\n return git(root, 'show', `${commit}:${file}`);\n } catch {\n fail(`${file} is not committed at ${commit.slice(0, 12)} (paths in ${ADE_MANIFEST_FILE} are relative to the repo root)`);\n }\n}\n\n/** Every page of a cursor-paged list route (`?limit=100&cursor=`), or exit with its error. */\nasync function allPages<T>(apiUrl: string, token: string, route: string, what: string): Promise<T[]> {\n const items: T[] = [];\n let cursor: string | null = null;\n do {\n const separator = route.includes('?') ? '&' : '?';\n const query: string = `${separator}limit=100${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ''}`;\n const page = await apiRequest<{ ok: boolean; error?: string; data?: T[]; nextCursor?: string | null }>(apiUrl, token, 'GET', `${route}${query}`);\n if (!page.ok || !page.data) fail(page.error ?? `could not list ${what}`);\n items.push(...page.data);\n cursor = page.nextCursor ?? null;\n } while (cursor);\n return items;\n}\n\nconst allTemplates = (apiUrl: string, token: string) => allPages<TemplateVersion>(apiUrl, token, '/org/ade/templates', 'templates');\n\nfunction printVersion(template: TemplateVersion): void {\n const source = `${template.sourceRepo}@${template.sourceCommit.slice(0, 12)}`;\n console.log(\n `${template.name} v${template.version} ${template.status.padEnd(8)} ${source} base v${template.baseVersion} setup-prompt ${template.setupPromptSha256.slice(0, 12)}`\n );\n if (template.status === 'failed' && template.error) console.log(` ${template.error.trim().split('\\n').slice(-20).join('\\n ')}`);\n}\n\nasync function publish(argv: string[], apiUrl: string, token: string): Promise<void> {\n const given = getPositionalArg(argv, GLOBAL_VALUE_FLAGS);\n const start = given ? path.dirname(path.resolve(given)) : process.cwd();\n let root: string;\n try {\n root = git(start, 'rev-parse', '--show-toplevel').trim();\n } catch {\n fail(`${start} is not inside a git repository`);\n }\n const yamlFile = given ? path.relative(root, path.resolve(given)) : ADE_MANIFEST_FILE;\n if (yamlFile.startsWith('..')) fail(`${given} is outside the repository at ${root}`);\n const commit = git(root, 'rev-parse', 'HEAD').trim();\n const yaml = committed(root, commit, yamlFile);\n const { manifest, issues } = validateAdeManifest(yaml);\n if (!manifest) {\n console.error(`Error: ${yamlFile} is invalid:`);\n for (const issue of issues) console.error(` ${issue.path}: ${issue.message}`);\n process.exit(1);\n }\n const repo = publishedRepo(root, commit);\n if (git(root, 'status', '--porcelain', '--', yamlFile, manifest.setup_prompt, manifest.guidance).trim() !== '') {\n console.error(`Note: uncommitted changes to the template's files are not published; publishing them as of ${commit.slice(0, 12)}.`);\n }\n\n const result = await apiRequest<PublishResponse>(apiUrl, token, 'POST', '/org/ade/templates/publish', {\n yaml,\n setupPrompt: committed(root, commit, manifest.setup_prompt),\n guidance: committed(root, commit, manifest.guidance),\n repo,\n commit,\n });\n if (!result.ok || !result.data) {\n console.error(`Error: ${result.error ?? 'publish failed'}`);\n for (const issue of result.issues ?? []) console.error(` ${issue.path}: ${issue.message}`);\n process.exit(1);\n }\n const { id, name, version } = result.data;\n console.log(`Published ${name} v${version} (${id}) from ${repo}@${commit.slice(0, 12)}; building…`);\n console.log('Ctrl-C stops waiting; the build carries on (`cofactor dev template list`).');\n const started = Date.now();\n // The server always moves the version out of `building` (the job's onFailure marks it failed).\n for (;;) {\n await new Promise((resolve) => setTimeout(resolve, POLL_MS));\n const current = await apiRequest<VersionResponse>(apiUrl, token, 'GET', `/org/ade/templates/${id}`);\n // A transport failure already exited in `apiRequest`; the build carries on server-side either way.\n if (!current.ok || !current.data) {\n fail(`could not read the build's status (${current.error ?? 'unknown error'}); it carries on: check \\`cofactor dev template list\\``);\n }\n if (current.data.status === 'building') continue;\n console.log(`${current.data.status === 'ready' ? '✓' : '✗'} after ${Math.round((Date.now() - started) / 1000)} s`);\n printVersion(current.data);\n if (current.data.status === 'failed') process.exit(1);\n return;\n }\n}\n\nasync function list(argv: string[], apiUrl: string, token: string): Promise<void> {\n const templates = await allTemplates(apiUrl, token);\n if (hasFlag(argv, '--json')) {\n writeRawOutput(JSON.stringify(templates, null, 2));\n return;\n }\n if (templates.length === 0) {\n console.log('No ADE templates yet. Publish one with `cofactor dev template publish`.');\n return;\n }\n for (const template of templates) printVersion(template);\n}\n\n/**\n * Text the guest wrote (`last_event`), printed with control characters removed:\n * the guest is untrusted, and an escape sequence must not reach the terminal.\n */\nconst guestText = (value: string | undefined | null) =>\n // eslint-disable-next-line no-control-regex -- C0 and C1 controls are exactly what is stripped\n value ? stripVTControlCharacters(value).replace(/[\\u0000-\\u001f\\u007f-\\u009f]/g, ' ') : '';\n\nfunction printSession(session: Session): void {\n const size = `${session.vcpus}c/${Math.round(session.memoryMib / 1024)}G`;\n const lease = session.leaseCapAt ? ` lease ends ${session.leaseCapAt}` : '';\n console.log(`${session.id} ${session.status.padEnd(12)} ${session.phase ?? '-'} ${size}${lease}`);\n if (session.lastEvent?.identity) console.log(` logged in as ${guestText(session.lastEvent.identity)}`);\n if (session.lastEvent?.branches?.length) console.log(` branches: ${session.lastEvent.branches.map(guestText).join(', ')}`);\n if (session.lastEvent?.error) console.log(` ${guestText(session.lastEvent.error)}`);\n if (session.endReason) console.log(` ended: ${session.endReason}${session.endDetail ? ` (${session.endDetail})` : ''}`);\n}\n\n/** The template to claim: `--template`, else the org's only one. */\nasync function templateToClaim(argv: string[], apiUrl: string, token: string): Promise<string> {\n const given = getArgValue(argv, '--template');\n if (given) return given;\n const names = new Set((await allTemplates(apiUrl, token)).map((template) => template.name));\n if (names.size === 1) return [...names][0]!;\n if (names.size === 0) fail('this org has no ADE template yet: an admin publishes one with `cofactor dev template publish`');\n fail(`this org has several ADE templates; pass --template <name> (one of: ${[...names].sort().join(', ')})`);\n}\n\n/** Phases after which the box has its home and tmux: attach can start (the setup prompt may still be waiting on the user). */\nconst ATTACHABLE_PHASES = new Set(['home_mounted', 'setup_done', 'needs_user', 'repos_synced', 'agent_started']);\n/** How long `dev` and `attach` follow a session before giving up on it becoming attachable. */\nconst ATTACH_WAIT_MS = 70 * 60_000;\n\n/** `--env`, `--api-url`, `--org`, `--target-org` as given, so the ProxyCommand reaches the same API and org. */\nfunction envArgs(argv: string[]): string[] {\n const out: string[] = [];\n for (const flag of ['--env', '--api-url', '--org', '--target-org']) {\n const value = getArgValue(argv, flag);\n if (value) out.push(flag, value);\n }\n return out;\n}\n\n/** Poll until the session can be attached, printing each status and phase change. */\nasync function followUntilAttachable(apiUrl: string, token: string, id: string): Promise<Session> {\n const sessionPath = `/org/ade/sessions/${encodeURIComponent(id)}`;\n const deadline = Date.now() + ATTACH_WAIT_MS;\n let shown = '';\n for (;;) {\n const current = await apiRequest<SessionResponse>(apiUrl, token, 'GET', sessionPath);\n if (!current.ok || !current.data) fail(current.error ?? 'could not read the session');\n const session = current.data;\n const state = `${session.status}${session.phase ? ` (${session.phase})` : ''}`;\n if (state !== shown) {\n console.log(` ${state}`);\n shown = state;\n }\n if (session.status === 'ending' || session.status === 'ended') {\n printSession(session);\n process.exit(1);\n }\n if (session.status === 'running' || (session.phase && ATTACHABLE_PHASES.has(session.phase))) return session;\n if (Date.now() > deadline) fail(`${id} is still ${state}; it carries on: check \\`cofactor dev list\\``);\n await new Promise((resolve) => setTimeout(resolve, 3_000));\n }\n}\n\nasync function attach(id: string, argv: string[], apiUrl: string, token: string): Promise<void> {\n await followUntilAttachable(apiUrl, token, id);\n const alias = await grantAndConfigure(apiUrl, token, id, envArgs(argv)).catch((error: unknown) => fail(error instanceof Error ? error.message : String(error)));\n console.log(`Attaching to ${id} (ssh ${alias}). Detach with Ctrl-b d; reattach with \\`cofactor dev attach ${id}\\`.`);\n process.exit(attachSsh(alias));\n}\n\nasync function claim(argv: string[], apiUrl: string, token: string): Promise<void> {\n const template = await templateToClaim(argv, apiUrl, token);\n const result = await apiRequest<SessionResponse>(apiUrl, token, 'POST', '/org/ade/sessions', { template });\n if (!result.ok || !result.data) fail(result.error ?? 'the claim failed');\n console.log(`Claimed ${result.data.id} from ${template}. Ctrl-C stops following; the session carries on.`);\n await attach(result.data.id, argv, apiUrl, token);\n}\n\n/** `attach`'s session: the one named, else the user's only live one. */\nasync function sessionToAttach(argv: string[], apiUrl: string, token: string): Promise<string> {\n const given = getPositionalArg(argv, DEV_VALUE_FLAGS);\n if (given) return given;\n const live = await allPages<Session>(apiUrl, token, '/org/ade/sessions', 'sessions');\n if (live.length === 1) return live[0]!.id;\n if (live.length === 0) fail('you have no live ADE session: claim one with `cofactor dev`');\n fail(`you have several live sessions; pass one: ${live.map((session) => session.id).join(', ')}`);\n}\n\nasync function listSessions(argv: string[], apiUrl: string, token: string): Promise<void> {\n const all = hasFlag(argv, '--all');\n const sessions = await allPages<Session>(apiUrl, token, all ? '/org/ade/sessions?all=true' : '/org/ade/sessions', 'sessions');\n if (hasFlag(argv, '--json')) {\n writeRawOutput(JSON.stringify(sessions, null, 2));\n return;\n }\n if (sessions.length === 0) {\n console.log(all ? 'No ADE sessions in the last 7 days.' : 'No live ADE sessions. Claim one with `cofactor dev`.');\n return;\n }\n for (const session of sessions) printSession(session);\n}\n\nasync function destroy(argv: string[], apiUrl: string, token: string): Promise<void> {\n const id = getPositionalArg(argv, DEV_VALUE_FLAGS);\n if (!id) fail('usage: cofactor dev destroy <id>');\n const sessionPath = `/org/ade/sessions/${encodeURIComponent(id)}`;\n const result = await apiRequest<SessionResponse>(apiUrl, token, 'DELETE', sessionPath);\n if (!result.ok || !result.data) fail(result.error ?? 'the destroy failed');\n console.log(`Ending ${id}…`);\n const deadline = Date.now() + DESTROY_WAIT_MS;\n let session = result.data;\n while (session.status !== 'ended') {\n if (Date.now() > deadline) fail(`${id} is still ${session.status}; it carries on: check \\`cofactor dev list --all\\``);\n await new Promise((resolve) => setTimeout(resolve, 3_000));\n const current = await apiRequest<SessionResponse>(apiUrl, token, 'GET', sessionPath);\n if (!current.ok || !current.data) fail(current.error ?? 'could not read the session');\n session = current.data;\n }\n printSession(session);\n // The API's FINAL_SAVE_FAILED (apps/api/src/ade/destroy.job.ts).\n if (session.endDetail === 'final save failed') console.log('Warning: the final save of the home failed; changes since its last save are lost.');\n}\n\nexport async function runDev(argv: string[]): Promise<void> {\n const [group, subCommand, ...rest] = argv;\n if (group === 'help' || hasFlag(argv, '--help', '-h')) {\n printHelp();\n return;\n }\n // `cofactor dev [--template <name>]`: no sub-command claims.\n if (group === undefined || group.startsWith('--')) {\n const { apiUrl, token } = await resolveConfig(argv);\n await claim(argv, apiUrl, token);\n return;\n }\n if (group === 'attach' || group === 'proxy') {\n const args = argv.slice(1);\n const { apiUrl, token } = await resolveConfig(args);\n if (group === 'attach') {\n await attach(await sessionToAttach(args, apiUrl, token), args, apiUrl, token);\n return;\n }\n const id = getPositionalArg(args, DEV_VALUE_FLAGS);\n if (!id) fail('usage: cofactor dev proxy <id>');\n const status = await runProxy(apiUrl, token, id, envArgs(args)).catch((error: unknown) => {\n // The CLI's own exit (an auth failure inside apiRequest) already said why: pass it on.\n if (error instanceof ProcessExitSignal) throw error;\n console.error(`cofactor dev proxy: ${error instanceof Error ? error.message : String(error)}`);\n return 1;\n });\n process.exit(status);\n }\n if (group === 'list' || group === 'destroy') {\n const args = argv.slice(1);\n const { apiUrl, token } = await resolveConfig(args);\n if (group === 'list') await listSessions(args, apiUrl, token);\n else await destroy(args, apiUrl, token);\n return;\n }\n if (group !== 'template' || (subCommand !== 'publish' && subCommand !== 'list')) {\n console.error(`Unknown dev sub-command: ${[group, subCommand].filter(Boolean).join(' ')}`);\n printHelp();\n process.exit(1);\n }\n const { apiUrl, token } = await resolveConfig(rest);\n if (subCommand === 'publish') await publish(rest, apiUrl, token);\n else await list(rest, apiUrl, token);\n}\n","/**\n * `cofactor.ade.yaml`: an org's ADE (agentic development environment)\n * template, parsed by the CLI before it publishes and by the API that builds\n * it. A separate lineage from `cofactor.sandbox.yaml` (manifest.ts): an ADE\n * template holds a toolchain and coding agents, never a checkout, so its\n * build needs no repository credential.\n *\n * The build reuses the sbv2 supervisor's one-shot root `setup`, which parses\n * only an sbv2 definition, so `synthesizeBuildDefinition` wraps the template\n * in the smallest sbv2-valid definition that carries one setup script.\n *\n * @module ade-manifest\n * @see specs/pending/ade.md (`cofactor.ade.yaml` schema, Template build)\n */\nimport { parse, stringify } from 'yaml';\nimport { z } from 'zod';\n\n/** The file `cofactor dev template publish` reads by default, at the repo root. */\nexport const ADE_MANIFEST_FILE = 'cofactor.ade.yaml';\n\n/**\n * The ADE base image's version: the published platform image plus the\n * `packages/sandbox-helper/ade/` layer, tagged `adeBaseImageTag` by\n * `ade-image.sh`. A published tag is never rebuilt, so a change to that layer\n * needs a bump (ade-base-version.test.ts fails until the new hash is\n * recorded). A template records the version it was built on.\n *\n * 1: Ubuntu 24.04, tmux, git, gh, OpenSSH, Node 24 with npm, the cofactor CLI,\n * and the uid-1000 account renamed to `agent` (home `/home/agent`).\n * 2: `ade-init` (the claim's CLI login) and a no-op `ade-home`, the agent-owned\n * `/run/cofactor/ade`, and `COFACTOR_CONFIG_DIR` in `/etc/profile.d`.\n * 3: the uid-1000 account is renamed by editing the account files\n * (`rename-account.sh`), not usermod, which refuses while the build's own\n * uid-1000 process runs: every v2 build failed with \"user ubuntu is currently\n * used by process\" (prod 2026-11-05).\n * 4: `ade-start` (the session's tmux window: phases, the setup prompt on a\n * first claim, the agent), `ade-sync-repos`, `ade-event`, and `COFACTOR_ENV=ade`\n * in `/etc/profile.d`.\n */\nexport const ADE_BASE_VERSION = 4;\n\n/**\n * The published platform image (`platformImageTag`, manifest.ts) the ADE base\n * image is built on: its sandbox-helper supervisor runs the build's root\n * `setup`. Pinned here, not read from `PLATFORM_VERSION`, so an sbv2 platform\n * bump does not force every ADE template to republish. Moving it changes the\n * base image, so it comes with an `ADE_BASE_VERSION` bump.\n *\n * The contract this creates: `synthesizeBuildDefinition`'s output, and every\n * `cofactor-sandbox` call the API makes on an ADE sandbox, must be accepted by\n * this version's helper, not only by the current `parseDefinition`. An sbv2\n * change to those fields moves the pin (and so bumps `ADE_BASE_VERSION`).\n */\nexport const ADE_PLATFORM_VERSION = 22;\n\n/** The ADE base image's tag in the platform repository (immutable). */\nexport function adeBaseImageTag(version: number): string {\n return `ade-base-v${version}`;\n}\n\n/** Root-run base install inside the ADE base image; the first line of every build's setup. */\nconst ADE_BASE_SETUP = '/usr/local/lib/cofactor-ade/base-setup.sh';\n\n/** Where the build writes the template's files for the guest; root-owned, read-only. */\nconst ADE_ETC_DIR = '/etc/cofactor/ade';\n\nconst KIB = 1024;\n/** The setup prompt and guidance each travel base64 inside one `bash -c` argument (Linux caps one at 128 KiB). */\nconst ADE_TEXT_MAX_BYTES = 32 * KIB;\n/** The whole synthesized setup script. */\nconst ADE_SETUP_MAX_BYTES = 96 * KIB;\n\n/** A template or agent name: also part of a Blackcat template name. */\nconst NAME = /^[a-z][a-z0-9-]{0,31}$/;\n/** `owner/name` on github.com; `.` and `..` segments are refused separately. */\nconst GITHUB_REPO = /^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/;\n\n/** A relative path inside the repo: no leading `/`, and no empty, `.` or `..` segment. */\nconst repoPath = z\n .string()\n .min(1)\n .refine(\n (value) => !value.startsWith('/') && value.split('/').every((segment) => segment !== '' && segment !== '.' && segment !== '..'),\n 'must be a relative path inside the repo'\n );\n\nconst command = z.string().trim().min(1);\n\nconst repoSchema = z.strictObject({\n github: z\n .string()\n .regex(GITHUB_REPO, 'must be owner/name on github.com')\n .refine((value) => value.split('/').every((segment) => segment !== '.' && segment !== '..'), 'must be owner/name on github.com'),\n install: z.array(command),\n});\n\nconst agentSchema = z.strictObject({\n install: command,\n run: command,\n /** The headless command for `--task`; an agent without one is interactive-only. */\n task: command.optional(),\n});\n\n/**\n * The largest template a Blackcat worker in every stage can build, so a larger\n * shape fails at publish (here, in the API and in the CLI) instead of in the\n * build. A template build boots a fresh guest that takes host vCPUs one for one\n * (no overcommit), on an otherwise empty worker.\n *\n * The authority is production's `blackcat fleet capacity-shapes`, which on\n * 2026-11-05 offered at most 14 guest vCPU / 31130 MiB: Blackcat refused a\n * 16 vCPU / 32768 MiB build with exactly that. Memory is rounded down to a\n * whole GiB. infra/components/blackcat-dev.constants.ts also lists c7i.8xlarge\n * and m7i.4xlarge for production, which capacity-shapes did not offer then;\n * dev offers more. One ceiling for every stage, the smallest.\n *\n * Raising it, once production's capacity-shapes offers more: change it here,\n * deploy the API, and release the CLI (an older CLI keeps refusing the larger\n * shape). If the fleet ever offers less, the build's unplaceable failure\n * (template-build.job.ts) is the backstop.\n */\nconst ADE_MAX_SHAPE = { vcpus: 14, memory_mib: 30720 } as const;\n\nconst largestShape = `the largest template a Blackcat worker can build is ${ADE_MAX_SHAPE.vcpus} vCPU / ${ADE_MAX_SHAPE.memory_mib} MiB`;\n\nconst memoryMib = z\n .number()\n .int()\n .min(1024)\n .max(ADE_MAX_SHAPE.memory_mib, `at most ${ADE_MAX_SHAPE.memory_mib}: ${largestShape}`)\n .refine((value) => value % 128 === 0, 'must be a multiple of 128');\n\n/*\n * `max` (the `--size` ceiling) and `secrets` arrive in S6 and `github_app_proxy`\n * in S3b; until then the strict schema rejects them as unrecognized keys.\n */\nconst adeManifestSchema = z.strictObject({\n version: z.literal(1),\n name: z.string().regex(NAME, 'must be lowercase letters, digits and -, starting with a letter (at most 32)'),\n resources: z.strictObject({\n vcpus: z.number().int().min(1).max(ADE_MAX_SHAPE.vcpus, `at most ${ADE_MAX_SHAPE.vcpus}: ${largestShape}`),\n memory_mib: memoryMib,\n disk_gib: z.number().int().min(1).max(256),\n }),\n /** Root commands run once per template version at build; absent when the base image's toolchain is enough. */\n setup: z.array(command).optional(),\n repos: z\n .array(repoSchema)\n .min(1)\n .superRefine((repos, ctx) => {\n const seen = new Set<string>();\n repos.forEach((repo, index) => {\n const name = repo.github.split('/')[1] ?? '';\n if (seen.has(name)) {\n ctx.addIssue({ code: 'custom', path: [index, 'github'], message: `another repo is also named ${name}: both would be /workspace/${name}` });\n }\n seen.add(name);\n });\n }),\n agents: z\n .record(z.string().regex(NAME, 'agent names must be lowercase letters, digits and -'), agentSchema)\n .refine((agents) => Object.keys(agents).length > 0, 'list at least one agent'),\n setup_prompt: repoPath,\n guidance: repoPath,\n});\n\nexport type AdeManifest = z.infer<typeof adeManifestSchema>;\ntype AdeManifestIssue = { path: string; message: string };\n\n/** Parse and validate the yaml; each issue names its field path. */\nexport function validateAdeManifest(yamlText: string): { manifest?: AdeManifest; issues: AdeManifestIssue[] } {\n let raw: unknown;\n try {\n raw = parse(yamlText);\n } catch (error) {\n return { issues: [{ path: '', message: `invalid YAML: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n const parsed = adeManifestSchema.safeParse(raw);\n if (!parsed.success) {\n return { issues: parsed.error.issues.map((issue) => ({ path: issue.path.map(String).join('.') || '(root)', message: issue.message })) };\n }\n return { manifest: parsed.data, issues: [] };\n}\n\n/** A manifest the API stored after validating it (`ade_templates.definition`); throws if it no longer parses. */\nexport function adeManifestFromStored(value: unknown): AdeManifest {\n return adeManifestSchema.parse(value);\n}\n\n/**\n * The base template a template of this shape builds on. A Blackcat checkpoint\n * fixes its vCPUs, memory hot-plug region and writable disk, so there is one\n * per shape, imported from the base image the first time a template of that\n * shape is built. `0h`: no hot-plug region until S6 adds `max`.\n */\nexport function adeBaseTemplateName(resources: AdeManifest['resources'], version: number): string {\n return `ade-base-v${version}-${resources.vcpus}c-${resources.memory_mib}m-0h-${resources.disk_gib}d`;\n}\n\n/** One built template version's Blackcat name; the org id keeps orgs' templates apart. */\nexport function adeTemplateName(orgId: string, name: string, version: number): string {\n return `ade-${orgId}-${name}-v${version}`;\n}\n\n/** What the guest reads from `/etc/cofactor/ade/template.json`. */\nfunction adeTemplateJson(manifest: AdeManifest): string {\n return JSON.stringify({\n name: manifest.name,\n repos: manifest.repos,\n agents: manifest.agents,\n });\n}\n\n/** `printf %s <base64> | base64 -d > path`: no heredoc, so no content can end a delimiter early. */\nconst writeFile = (path: string, content: string) =>\n `printf %s '${Buffer.from(content, 'utf8').toString('base64')}' | base64 -d > ${path}`;\n\n/**\n * The template's root build script: the base install, the template's\n * `setup`, each agent's `install`, then the guest's files, root-owned and\n * read-only. The supervisor's prelude (`set -euo pipefail`) runs first, so the\n * first failing line fails the build.\n */\nexport function adeSetupScript(manifest: AdeManifest, setupPrompt: string, guidance: string): string {\n return [\n `bash ${ADE_BASE_SETUP}`,\n ...(manifest.setup ?? []),\n ...Object.values(manifest.agents).map((agent) => agent.install),\n `install -d -o root -g root -m 0755 ${ADE_ETC_DIR}`,\n writeFile(`${ADE_ETC_DIR}/template.json`, adeTemplateJson(manifest)),\n writeFile(`${ADE_ETC_DIR}/setup-prompt.md`, setupPrompt),\n writeFile(`${ADE_ETC_DIR}/guidance.md`, guidance),\n `chown root:root ${ADE_ETC_DIR}/*`,\n `chmod 0444 ${ADE_ETC_DIR}/*`,\n '',\n ].join('\\n');\n}\n\n/**\n * A validated template plus its two files; else the issues. The files' caps\n * and the build script's are checked here, so a template that cannot build\n * fails at publish.\n */\nexport function validateAdeTemplate(\n yamlText: string,\n setupPrompt: string,\n guidance: string\n): { manifest?: AdeManifest; issues: AdeManifestIssue[] } {\n const { manifest, issues } = validateAdeManifest(yamlText);\n if (!manifest) return { issues };\n const tooLarge: AdeManifestIssue[] = [];\n if (Buffer.byteLength(setupPrompt) > ADE_TEXT_MAX_BYTES) {\n tooLarge.push({ path: 'setup_prompt', message: `${manifest.setup_prompt} is larger than ${ADE_TEXT_MAX_BYTES / KIB} KiB` });\n }\n if (Buffer.byteLength(guidance) > ADE_TEXT_MAX_BYTES) {\n tooLarge.push({ path: 'guidance', message: `${manifest.guidance} is larger than ${ADE_TEXT_MAX_BYTES / KIB} KiB` });\n }\n if (tooLarge.length > 0) return { issues: tooLarge };\n if (Buffer.byteLength(adeSetupScript(manifest, setupPrompt, guidance)) > ADE_SETUP_MAX_BYTES) {\n return { issues: [{ path: 'setup', message: `the build script (setup, agent installs, setup prompt and guidance) is larger than ${ADE_SETUP_MAX_BYTES / KIB} KiB` }] };\n }\n return { manifest, issues: [] };\n}\n\n/**\n * The sbv2 definition the supervisor's root `setup` parses: only the\n * template's `{vcpus, memory_mib}` (disk is the base template's), the empty\n * records the strict schema requires, a `lifecycle.build` step that never\n * runs, and the one setup script.\n */\nexport function synthesizeBuildDefinition(manifest: AdeManifest, setupScript: string): string {\n return stringify({\n version: 1,\n resources: { vcpus: manifest.resources.vcpus, memory_mib: manifest.resources.memory_mib },\n setup: setupScript,\n ports: {},\n params: {},\n env: {},\n services: {},\n lifecycle: { build: [{ name: 'unused', run: 'true', inputs: ['**'] }], prepare: [] },\n environments: { default: { description: 'ADE template build; never prepared.' } },\n });\n}\n","/**\n * SSH into an ADE session from the laptop (specs/pending/ade.md, SSH and\n * attach; D16/D22):\n *\n * - **One key per machine** at `~/.config/cofactor/ade/id_ed25519`, made on\n * first use. Only its public half leaves the machine: `ssh-grant` asks\n * Blackcat to accept it on the box for 12 h.\n * - **The host key is pinned**: the grant returns it, and it is the only entry\n * for the session's host in `~/.config/cofactor/ade/known_hosts`.\n * - **`Host ade-<short>`** in `~/.ssh/config.d/cofactor-ade`, which\n * `~/.ssh/config` includes, so plain `ssh ade-<short>` (and scp, rsync) work.\n * Its `ProxyCommand` is `cofactor dev proxy <id>`.\n * - **The proxy** asks the API for a 60 s relay ticket and carries ssh's bytes\n * over a WebSocket to `ade-relay`, offering the ticket as a subprotocol so it\n * is never in a URL. It re-grants when the grant has under 1 h left.\n */\nimport { spawnSync } from 'node:child_process';\nimport { existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, renameSync, writeFileSync } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport process from 'node:process';\nimport { ADE_SSH_SUBPROTOCOL } from '@chatsdet/ade-relay-protocol';\nimport { apiRequest } from './cli-helpers.js';\nimport { ProcessExitSignal } from './user-event-tracking.js';\n\nconst adeDir = () => path.join(os.homedir(), '.config', 'cofactor', 'ade');\nconst keyPath = () => path.join(adeDir(), 'id_ed25519');\nconst knownHostsPath = () => path.join(adeDir(), 'known_hosts');\nconst grantsPath = () => path.join(adeDir(), 'grants.json');\nconst sshConfigDir = () => path.join(os.homedir(), '.ssh', 'config.d');\nconst sshConfigPath = () => path.join(sshConfigDir(), 'cofactor-ade');\n\n/** The proxy re-grants once a grant has less than this left. */\nconst REGRANT_BEFORE_MS = 3600_000;\n/** Failed WebSocket upgrades the proxy retries, each with a fresh ticket. */\nconst PROXY_ATTEMPTS = 5;\n/** What to do next, by the relay's close code (apps/ade-relay/src/relay.ts `CLOSE`). */\nconst RELAY_CLOSE_HINTS: Record<number, string> = {\n 4001: 'the relay restarted; run `cofactor dev attach` again',\n 4410: 'the session has ended (`cofactor dev list --all`)',\n 4502: 'the box could not be reached; it is being woken, so try again in a minute',\n 4503: 'the Cofactor API did not answer; try again shortly',\n};\n\n/** stdin the proxy holds while it (re)connects; ssh sends its version line and key exchange first. */\nconst MAX_BUFFERED_STDIN = 1024 * 1024;\n\ntype Grant = { user: string; hostKey: string; expiresAt: string };\ntype GrantResponse = { ok: boolean; error?: string; data?: Grant };\ntype TicketResponse = { ok: boolean; error?: string; data?: { ticket: string; url: string; expiresAt: string } };\n\n/** A whole ADE session id: it is written into the SSH config, so nothing else may pass. */\nconst SESSION_ID = /^ades_([1-9A-HJ-NP-Za-km-z]{8})[1-9A-HJ-NP-Za-km-z]*$/;\n/** One shell word, single-quoted: ssh runs `ProxyCommand` through the user's shell. */\nconst shellQuote = (value: string) => `'${value.replaceAll(\"'\", `'\\\\''`)}'`;\n\n/** `ades_<base58>` → `ade-<first 8>`: the SSH host alias. Throws on anything that is not a session id. */\nexport function adeHostAlias(sessionId: string): string {\n const match = SESSION_ID.exec(sessionId);\n if (!match) throw new Error(`not an ADE session id: ${JSON.stringify(sessionId)}`);\n return `ade-${match[1]}`;\n}\n\n/**\n * A relay URL the ticket may be sent to: `wss://`, or `ws://` to this machine\n * (a local stack). Anything else would carry the ticket in clear.\n */\nexport function isTicketSafeUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'wss:' || (parsed.protocol === 'ws:' && ['localhost', '127.0.0.1', '[::1]'].includes(parsed.hostname));\n } catch {\n return false;\n }\n}\n\n/** Write through a temp file and a rename, so a reader never sees half a file. */\nfunction writeAtomic(file: string, content: string, mode: number): void {\n const temp = `${file}.${process.pid}.tmp`;\n writeFileSync(temp, content, { mode });\n renameSync(temp, file);\n}\n\n/** The machine's key pair, made once; returns the public key line. */\nexport function ensureMachineKey(): string {\n mkdirSync(adeDir(), { recursive: true, mode: 0o700 });\n if (!existsSync(keyPath())) {\n // stdout is ignored: under `dev proxy` it is ssh's connection.\n const made = spawnSync('ssh-keygen', ['-q', '-t', 'ed25519', '-N', '', '-C', `cofactor-ade@${os.hostname()}`, '-f', keyPath()], {\n stdio: ['ignore', 'ignore', 'inherit'],\n });\n if (made.error || made.status !== 0) throw new Error('ssh-keygen failed: install the OpenSSH client and retry');\n }\n return readFileSync(`${keyPath()}.pub`, 'utf8').trim();\n}\n\nfunction readGrants(): Record<string, Grant> {\n try {\n return JSON.parse(readFileSync(grantsPath(), 'utf8')) as Record<string, Grant>;\n } catch {\n return {};\n }\n}\n\n/** Replace `alias`'s lines in a file of blocks or entries keyed by it. */\nexport function replaceEntry(existing: string, alias: string, entry: string, isOwn: (line: string) => boolean): string {\n const kept = existing.split('\\n').filter((line) => line.trim() !== '' && !isOwn(line));\n return [...kept, entry].join('\\n') + '\\n';\n}\n\n/** The `Host` block `ssh ade-<short>` uses. */\nexport function sshConfigBlock(alias: string, sessionId: string, user: string, envArgs: string[]): string {\n adeHostAlias(sessionId);\n // A line break would end the directive and start another; nothing else is unsafe once quoted.\n if (envArgs.some((arg) => /[\\r\\n]/.test(arg))) throw new Error('a CLI flag value with a line break cannot go into the SSH config');\n return [\n `Host ${alias}`,\n ` HostName ${alias}`,\n ` User ${user}`,\n ` IdentityFile \"${keyPath()}\"`,\n ' IdentitiesOnly yes',\n ` UserKnownHostsFile \"${knownHostsPath()}\"`,\n ' StrictHostKeyChecking yes',\n ' ForwardAgent no',\n ' ServerAliveInterval 30',\n ' ServerAliveCountMax 4',\n // `%` would be one of ssh's own tokens (`%h`); `%%` is a literal one.\n ` ProxyCommand cofactor dev proxy ${[sessionId, ...envArgs].map(shellQuote).join(' ').replaceAll('%', '%%')}`,\n ].join('\\n');\n}\n\n/** `~/.ssh/config` includes `config.d/*` once, ahead of every other block. */\nfunction ensureSshInclude(): void {\n // A dotfile manager's symlink (even one whose target is not there yet) is followed, so the\n // link survives and its target gets the line.\n const link = path.join(os.homedir(), '.ssh', 'config');\n const isLink = lstatSync(link, { throwIfNoEntry: false })?.isSymbolicLink() ?? false;\n const config = isLink ? path.resolve(path.dirname(link), readlinkSync(link)) : link;\n mkdirSync(sshConfigDir(), { recursive: true, mode: 0o700 });\n const existing = existsSync(config) ? readFileSync(config, 'utf8') : '';\n if (/^\\s*Include\\s+config\\.d\\/\\*\\s*$/m.test(existing)) return;\n try {\n writeAtomic(config, `Include config.d/*\\n\\n${existing}`, 0o600);\n } catch (error) {\n // A read-only config (a store path, say): say what to add rather than fail the attach.\n throw new Error(`could not add \\`Include config.d/*\\` to ${config} (${error instanceof Error ? error.message : String(error)}); add it at the top yourself, then retry`);\n }\n}\n\n/**\n * Grant this machine's key on the session's box, pin the host key it returns,\n * and write the session's `Host` block. Returns the alias to `ssh`.\n */\nexport async function grantAndConfigure(apiUrl: string, token: string, sessionId: string, envArgs: string[]): Promise<string> {\n const publicKey = ensureMachineKey();\n const result = await apiRequest<GrantResponse>(apiUrl, token, 'POST', `/org/ade/sessions/${encodeURIComponent(sessionId)}/ssh-grant`, {\n publicKey,\n });\n if (!result.ok || !result.data) throw new Error(result.error ?? 'the SSH grant failed');\n const { user, hostKey, expiresAt } = result.data;\n if (!/^ssh-ed25519 [A-Za-z0-9+/=]+(?: \\S*)?$/.test(hostKey)) throw new Error('the box returned an unexpected host key');\n if (!/^[a-z_][a-z0-9_-]{0,31}$/.test(user)) throw new Error('the box returned an unexpected login user');\n const alias = adeHostAlias(sessionId);\n\n const known = existsSync(knownHostsPath()) ? readFileSync(knownHostsPath(), 'utf8') : '';\n const pinned = hostKey.split(' ').slice(0, 2).join(' ');\n writeAtomic(knownHostsPath(), replaceEntry(known, alias, `${alias} ${pinned}`, (line) => line.startsWith(`${alias} `)), 0o600);\n\n ensureSshInclude();\n const config = existsSync(sshConfigPath()) ? readFileSync(sshConfigPath(), 'utf8') : '';\n const blocks = config.split(/\\n(?=Host )/).filter((block) => block.trim() !== '' && !block.startsWith(`Host ${alias}\\n`));\n writeAtomic(sshConfigPath(), [...blocks.map((block) => block.trimEnd()), sshConfigBlock(alias, sessionId, user, envArgs)].join('\\n\\n') + '\\n', 0o600);\n\n writeAtomic(grantsPath(), JSON.stringify({ ...readGrants(), [sessionId]: { user, hostKey: pinned, expiresAt } }, null, 2), 0o600);\n return alias;\n}\n\n/** `ssh -t ade-<short> tmux attach -t ade`, with this terminal; returns ssh's status. */\nexport function attachSsh(alias: string): number {\n const ssh = spawnSync('ssh', ['-t', alias, 'tmux', 'attach-session', '-t', 'ade'], { stdio: 'inherit' });\n if (ssh.error) throw new Error(`ssh failed to start: ${ssh.error.message}`);\n return ssh.status ?? 1;\n}\n\n/**\n * `cofactor dev proxy <id>`: ssh's ProxyCommand. stdin and stdout are ssh's\n * connection, so everything else goes to stderr. A failed upgrade is retried\n * with a fresh ticket, up to 5 attempts, replaying what ssh already sent.\n * Resolves with the exit status once the connection ends.\n */\nexport async function runProxy(apiUrl: string, token: string, sessionId: string, envArgs: string[]): Promise<number> {\n const grant = readGrants()[sessionId];\n if (!grant || new Date(grant.expiresAt).getTime() - Date.now() < REGRANT_BEFORE_MS) {\n await grantAndConfigure(apiUrl, token, sessionId, envArgs);\n }\n\n let resolveFinished: (status: number) => void = () => undefined;\n const finished = new Promise<number>((resolve) => {\n resolveFinished = resolve;\n });\n // Releasing stdin lets the process end even when the CLI's exit is a no-op (a clean 0), so ssh sees EOF.\n const finish = (status: number) => {\n process.stdin.destroy();\n resolveFinished(status);\n };\n const buffered: Buffer[] = [];\n let bufferedBytes = 0;\n let socket: WebSocket | null = null;\n let stdinEnded = false;\n process.stdin.on('data', (chunk: Buffer) => {\n if (socket?.readyState === WebSocket.OPEN) {\n socket.send(new Uint8Array(chunk));\n return;\n }\n bufferedBytes += chunk.length;\n if (bufferedBytes > MAX_BUFFERED_STDIN) {\n console.error('cofactor dev proxy: ssh sent too much before the relay answered');\n finish(1);\n return;\n }\n buffered.push(chunk);\n });\n process.stdin.on('end', () => {\n stdinEnded = true;\n socket?.close(1000);\n });\n\n const connect = async (attempt: number): Promise<void> => {\n const ticket = await apiRequest<TicketResponse>(apiUrl, token, 'POST', `/org/ade/sessions/${encodeURIComponent(sessionId)}/relay-ticket`);\n if (!ticket.ok || !ticket.data) {\n console.error(`cofactor dev proxy: ${ticket.error ?? 'no relay ticket'}`);\n finish(1);\n return;\n }\n if (!isTicketSafeUrl(ticket.data.url)) {\n console.error('cofactor dev proxy: the API returned a relay URL that is not wss://; refusing to send the ticket');\n finish(1);\n return;\n }\n const ws = new WebSocket(ticket.data.url, [ADE_SSH_SUBPROTOCOL, ticket.data.ticket]);\n ws.binaryType = 'arraybuffer';\n ws.onopen = () => {\n socket = ws;\n for (const chunk of buffered.splice(0)) ws.send(new Uint8Array(chunk));\n if (stdinEnded) ws.close(1000);\n };\n ws.onmessage = (event) => {\n process.stdout.write(Buffer.from(event.data as ArrayBuffer));\n };\n ws.onclose = (event) => {\n if (socket === ws) {\n if (event.code !== 1000) {\n console.error(`cofactor dev proxy: the relay closed the connection (${event.code}${event.reason ? `: ${event.reason}` : ''})`);\n const hint = RELAY_CLOSE_HINTS[event.code];\n if (hint) console.error(`cofactor dev proxy: ${hint}`);\n }\n finish(event.code === 1000 ? 0 : 1);\n return;\n }\n // The upgrade failed: try again with a fresh ticket.\n if (attempt >= PROXY_ATTEMPTS) {\n console.error(`cofactor dev proxy: could not reach the relay after ${PROXY_ATTEMPTS} attempts`);\n finish(1);\n return;\n }\n setTimeout(() => {\n connect(attempt + 1).catch((error: unknown) => {\n // The CLI's own exit (an auth failure inside apiRequest) already said why.\n if (error instanceof ProcessExitSignal) {\n finish(error.exitCode);\n return;\n }\n console.error(`cofactor dev proxy: ${error instanceof Error ? error.message : String(error)}`);\n finish(1);\n });\n }, attempt * 500);\n };\n };\n await connect(1);\n return finished;\n}\n","/**\n * The wire contract between the Cofactor API and `ade-relay` (apps/ade-relay):\n * the relay ticket the API issues and the relay verifies, and the activity\n * calls the relay makes back to the API. See specs/pending/ade.md (SSH and\n * attach).\n *\n * This package imports nothing but Node built-ins, and the relay imports no\n * other workspace package (the boundary check in infra/ade-relay.test.ts), so the relay\n * image changes only when its own inputs do.\n *\n * Changing the ticket or the activity schema is two PRs, relay first: bump\n * {@link ADE_RELAY_PROTOCOL_VERSION}, ship a relay that accepts both, then\n * move the API.\n */\nimport { createHmac, timingSafeEqual } from 'node:crypto';\n\nexport const ADE_RELAY_PROTOCOL_VERSION = 1;\n\n/** The `Sec-WebSocket-Protocol` value the proxy offers ahead of its ticket. */\nexport const ADE_SSH_SUBPROTOCOL = 'ade-ssh.v1';\n\n/** The shortest ticket key and service token the API and the relay accept. */\nexport const ADE_RELAY_SECRET_MIN_LENGTH = 32;\n\n/** A ticket is good for this long after issue. */\nexport const ADE_RELAY_TICKET_TTL_SECONDS = 60;\n\n/** What a relay ticket binds. `exp` is epoch seconds. */\nexport interface AdeRelayTicketClaims {\n v: typeof ADE_RELAY_PROTOCOL_VERSION;\n orgId: string;\n sessionId: string;\n userId: string;\n sandboxId: string;\n exp: number;\n}\n\n/**\n * The client address the load balancer appended: the last `X-Forwarded-For`\n * entry, which a client cannot choose (it can only prepend). Both the relay and\n * the API's activity route key their failed-check limits on it.\n */\nexport function forwardedClientAddress(forwardedFor: string | null): string {\n return forwardedFor?.split(',').at(-1)?.trim() || 'unknown';\n}\n\nexport type AdeRelayTicketResult =\n | { ok: true; claims: AdeRelayTicketClaims }\n | { ok: false; reason: 'malformed' | 'signature' | 'version' | 'expired' };\n\nconst TICKET_PART = /^[A-Za-z0-9_-]+$/;\n/** Org, session, user and sandbox ids: UUIDs and prefixed ids, safe in a URL path. */\nconst ID = /^[A-Za-z0-9_-]{1,128}$/;\n/** How far past a fresh ticket's expiry a verified `exp` may sit (the API's and relay's clocks differ). */\nconst EXPIRY_SLACK_SECONDS = 5;\n\nfunction sign(payload: string, key: string): string {\n return createHmac('sha256', key).update(payload).digest('base64url');\n}\n\nfunction isId(value: unknown): value is string {\n return typeof value === 'string' && ID.test(value);\n}\n\n/**\n * `<base64url(JSON claims)>.<base64url(HMAC-SHA256)>`. Both halves use only\n * HTTP token characters, so the ticket travels in `Sec-WebSocket-Protocol`.\n */\nexport function encodeAdeRelayTicket(\n input: Omit<AdeRelayTicketClaims, 'v' | 'exp'>,\n key: string,\n nowMs: number\n): { ticket: string; claims: AdeRelayTicketClaims } {\n if (key.length < ADE_RELAY_SECRET_MIN_LENGTH) throw new Error('ade relay ticket key is too short');\n for (const id of [input.orgId, input.sessionId, input.userId, input.sandboxId]) {\n if (!isId(id)) throw new Error('ade relay ticket ids must match [A-Za-z0-9_-]{1,128}');\n }\n const claims: AdeRelayTicketClaims = {\n v: ADE_RELAY_PROTOCOL_VERSION,\n orgId: input.orgId,\n sessionId: input.sessionId,\n userId: input.userId,\n sandboxId: input.sandboxId,\n exp: Math.floor(nowMs / 1000) + ADE_RELAY_TICKET_TTL_SECONDS,\n };\n const payload = Buffer.from(JSON.stringify(claims)).toString('base64url');\n return { ticket: `${payload}.${sign(payload, key)}`, claims };\n}\n\n/** Checks the signature before reading anything the ticket claims. */\nexport function verifyAdeRelayTicket(\n ticket: string,\n key: string,\n nowMs: number\n): AdeRelayTicketResult {\n if (ticket.length > 2048) return { ok: false, reason: 'malformed' };\n const parts = ticket.split('.');\n if (parts.length !== 2) return { ok: false, reason: 'malformed' };\n const [payload, signature] = parts as [string, string];\n if (!TICKET_PART.test(payload) || !TICKET_PART.test(signature)) {\n return { ok: false, reason: 'malformed' };\n }\n const expected = Buffer.from(sign(payload, key));\n const given = Buffer.from(signature);\n if (expected.length !== given.length || !timingSafeEqual(expected, given)) {\n return { ok: false, reason: 'signature' };\n }\n let raw: unknown;\n try {\n raw = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));\n } catch {\n return { ok: false, reason: 'malformed' };\n }\n if (typeof raw !== 'object' || raw === null) return { ok: false, reason: 'malformed' };\n const claims = raw as Record<string, unknown>;\n if (claims.v !== ADE_RELAY_PROTOCOL_VERSION) return { ok: false, reason: 'version' };\n const { orgId, sessionId, userId, sandboxId, exp } = claims;\n if (\n !isId(orgId) ||\n !isId(sessionId) ||\n !isId(userId) ||\n !isId(sandboxId) ||\n typeof exp !== 'number' ||\n !Number.isInteger(exp)\n ) {\n return { ok: false, reason: 'malformed' };\n }\n if (exp * 1000 <= nowMs) return { ok: false, reason: 'expired' };\n // A ticket never lives longer than the API issues it for, whoever signed it.\n if (exp * 1000 > nowMs + (ADE_RELAY_TICKET_TTL_SECONDS + EXPIRY_SLACK_SECONDS) * 1000) {\n return { ok: false, reason: 'malformed' };\n }\n return {\n ok: true,\n claims: { v: ADE_RELAY_PROTOCOL_VERSION, orgId, sessionId, userId, sandboxId, exp },\n };\n}\n\n/**\n * `POST /internal/ade/relay/:sessionId/activity`, authenticated by the relay's\n * service token. `open` before the gateway CONNECT, `heartbeat` each minute\n * while open, `close` and `connect_failed` for audit. `connId` names one relayed\n * connection, so a retried audit event can be told apart from a second one.\n */\nexport const ADE_RELAY_ACTIVITY_EVENTS = ['open', 'heartbeat', 'close', 'connect_failed'] as const;\nexport type AdeRelayActivityEvent = (typeof ADE_RELAY_ACTIVITY_EVENTS)[number];\n\nexport interface AdeRelayActivityRequest {\n v: typeof ADE_RELAY_PROTOCOL_VERSION;\n event: AdeRelayActivityEvent;\n connId: string;\n /** From the verified ticket: the API scopes its lookup to this org and user. */\n orgId: string;\n userId: string;\n sandboxId: string;\n}\n\n/** `close: true` means the relay must close the connection now. */\nexport interface AdeRelayActivityResponse {\n status: string;\n close: boolean;\n}\n\nconst CONN_ID = /^[A-Za-z0-9_-]{8,64}$/;\n\nexport function parseAdeRelayActivityRequest(value: unknown): AdeRelayActivityRequest | null {\n if (typeof value !== 'object' || value === null) return null;\n const body = value as Record<string, unknown>;\n if (body.v !== ADE_RELAY_PROTOCOL_VERSION) return null;\n const { event, connId, orgId, userId, sandboxId } = body;\n if (!ADE_RELAY_ACTIVITY_EVENTS.includes(event as AdeRelayActivityEvent)) return null;\n if (typeof connId !== 'string' || !CONN_ID.test(connId)) return null;\n if (!isId(orgId) || !isId(userId) || !isId(sandboxId)) return null;\n return {\n v: ADE_RELAY_PROTOCOL_VERSION,\n event: event as AdeRelayActivityEvent,\n connId,\n orgId,\n userId,\n sandboxId,\n };\n}\n\nexport function parseAdeRelayActivityResponse(value: unknown): AdeRelayActivityResponse | null {\n if (typeof value !== 'object' || value === null) return null;\n const body = value as Record<string, unknown>;\n if (typeof body.status !== 'string' || typeof body.close !== 'boolean') return null;\n return { status: body.status, close: body.close };\n}\n"],"mappings":"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","names":["path","process","envArgs","process","path","apiUrl","token"]}
|
|
@@ -5,25 +5,25 @@ import {
|
|
|
5
5
|
formatSlackChannel,
|
|
6
6
|
loadSlackChannels,
|
|
7
7
|
resolveSlackChannelIds
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-62EXS76C.js";
|
|
9
|
+
import "./chunk-DEVD2WD2.js";
|
|
10
|
+
import "./chunk-XHEVDABB.js";
|
|
11
11
|
import "./chunk-DEK6B6LX.js";
|
|
12
12
|
import {
|
|
13
13
|
apiRequest,
|
|
14
14
|
getPositionalArgs
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-EWK44F6V.js";
|
|
16
16
|
import "./chunk-S3Q7MDCS.js";
|
|
17
17
|
import {
|
|
18
18
|
GLOBAL_VALUE_FLAGS,
|
|
19
19
|
getArgValue,
|
|
20
20
|
hasFlag,
|
|
21
21
|
resolveConfig
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-4MFMPC5P.js";
|
|
23
23
|
import {
|
|
24
24
|
writeRawOutput
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import "./chunk-
|
|
25
|
+
} from "./chunk-2OHYMT3A.js";
|
|
26
|
+
import "./chunk-RHWPZKRV.js";
|
|
27
27
|
import "./chunk-TOWZAG3I.js";
|
|
28
28
|
|
|
29
29
|
// src/digest.ts
|
|
@@ -303,4 +303,4 @@ export {
|
|
|
303
303
|
formatDigest,
|
|
304
304
|
runDigest
|
|
305
305
|
};
|
|
306
|
-
//# sourceMappingURL=digest-
|
|
306
|
+
//# sourceMappingURL=digest-XEHGCJM4.js.map
|
|
@@ -2,7 +2,7 @@ import { createRequire as __cr } from "module"; import { fileURLToPath as __fup
|
|
|
2
2
|
import {
|
|
3
3
|
apiRequest,
|
|
4
4
|
getPositionalArgs
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-EWK44F6V.js";
|
|
6
6
|
import {
|
|
7
7
|
getSubDir
|
|
8
8
|
} from "./chunk-S3Q7MDCS.js";
|
|
@@ -11,11 +11,11 @@ import {
|
|
|
11
11
|
getArgValue,
|
|
12
12
|
hasFlag,
|
|
13
13
|
resolveConfig
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-4MFMPC5P.js";
|
|
15
15
|
import {
|
|
16
16
|
writeRawOutput
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
} from "./chunk-2OHYMT3A.js";
|
|
18
|
+
import "./chunk-RHWPZKRV.js";
|
|
19
19
|
import "./chunk-TOWZAG3I.js";
|
|
20
20
|
|
|
21
21
|
// src/docs.ts
|
|
@@ -451,4 +451,4 @@ async function runDocs(argv) {
|
|
|
451
451
|
export {
|
|
452
452
|
runDocs
|
|
453
453
|
};
|
|
454
|
-
//# sourceMappingURL=docs-
|
|
454
|
+
//# sourceMappingURL=docs-KH4BCEQF.js.map
|
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
printNoSessionForOrg,
|
|
13
13
|
readAllProfiles,
|
|
14
14
|
readStoredAuth
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-4MFMPC5P.js";
|
|
16
16
|
import {
|
|
17
17
|
readBrandEnv
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-2OHYMT3A.js";
|
|
19
19
|
import "./chunk-TOWZAG3I.js";
|
|
20
20
|
|
|
21
21
|
// src/doctor.ts
|
|
@@ -154,4 +154,4 @@ async function runAuthDoctor(argv) {
|
|
|
154
154
|
export {
|
|
155
155
|
runAuthDoctor
|
|
156
156
|
};
|
|
157
|
-
//# sourceMappingURL=doctor-
|
|
157
|
+
//# sourceMappingURL=doctor-FOXXE5SK.js.map
|
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
resolveOrCreateSandboxApplication,
|
|
9
9
|
runEnvironment,
|
|
10
10
|
stdinAssignment
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-6ILWJFKY.js";
|
|
12
|
+
import "./chunk-VMJ7TBVM.js";
|
|
13
|
+
import "./chunk-EWK44F6V.js";
|
|
14
14
|
import "./chunk-S3Q7MDCS.js";
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-4MFMPC5P.js";
|
|
16
|
+
import "./chunk-2OHYMT3A.js";
|
|
17
|
+
import "./chunk-RHWPZKRV.js";
|
|
18
18
|
import "./chunk-TOWZAG3I.js";
|
|
19
19
|
export {
|
|
20
20
|
fetchEnvironments,
|
|
@@ -26,4 +26,4 @@ export {
|
|
|
26
26
|
runEnvironment,
|
|
27
27
|
stdinAssignment
|
|
28
28
|
};
|
|
29
|
-
//# sourceMappingURL=environment-
|
|
29
|
+
//# sourceMappingURL=environment-EBDPQTIS.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; import { fileURLToPath as __fup } from "url"; import { dirname as __dn } from "path"; const require = __cr(import.meta.url); const __filename = __fup(import.meta.url); const __dirname = __dn(__filename);
|
|
2
2
|
import {
|
|
3
3
|
resolveApplicationId
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-6ILWJFKY.js";
|
|
5
|
+
import "./chunk-VMJ7TBVM.js";
|
|
6
6
|
import {
|
|
7
7
|
EVALS,
|
|
8
8
|
getEval,
|
|
@@ -10,27 +10,27 @@ import {
|
|
|
10
10
|
requestAll,
|
|
11
11
|
requestText,
|
|
12
12
|
requestTolerant
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-L644NMDI.js";
|
|
14
14
|
import {
|
|
15
15
|
printServedGuide
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-O7B2IYCZ.js";
|
|
17
17
|
import {
|
|
18
18
|
getArgValues,
|
|
19
19
|
getPositionalArg,
|
|
20
20
|
getPositionalArgs,
|
|
21
21
|
getScalarArgValue,
|
|
22
22
|
readStdin
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-EWK44F6V.js";
|
|
24
24
|
import "./chunk-S3Q7MDCS.js";
|
|
25
25
|
import {
|
|
26
26
|
GLOBAL_VALUE_FLAGS,
|
|
27
27
|
hasFlag,
|
|
28
28
|
resolveConfig
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-4MFMPC5P.js";
|
|
30
30
|
import {
|
|
31
31
|
writeRawOutput
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-
|
|
32
|
+
} from "./chunk-2OHYMT3A.js";
|
|
33
|
+
import "./chunk-RHWPZKRV.js";
|
|
34
34
|
import "./chunk-TOWZAG3I.js";
|
|
35
35
|
|
|
36
36
|
// src/eval.ts
|
|
@@ -97,8 +97,9 @@ var AgentEvalTemplateSchema = z.strictObject({
|
|
|
97
97
|
// absent, or an absent entry: the standard names; every entry's provider must be used by a model
|
|
98
98
|
}),
|
|
99
99
|
graders: z.array(z.discriminatedUnion("kind", [ScriptGrader, JudgeGrader])).min(1),
|
|
100
|
-
repeats: z.number().int().min(1).max(7).default(
|
|
101
|
-
passAtLeast
|
|
100
|
+
repeats: z.number().int().min(1).max(7).default(1),
|
|
101
|
+
// attempts per case; a stochastic agent raises it together with passAtLeast
|
|
102
|
+
passAtLeast: z.number().int().min(1).default(1),
|
|
102
103
|
// <= repeats
|
|
103
104
|
passBar: z.number().min(0.1).max(1),
|
|
104
105
|
// minimum case pass rate for the eval to pass
|
|
@@ -374,7 +375,7 @@ function renderAgentEvalRun(result) {
|
|
|
374
375
|
`| Case | Result | Attempts | Score | ${multiTurn ? "Turns | " : ""}Cost/attempt | Time/attempt | Tokens in/out |`,
|
|
375
376
|
`|---|---|---|---|${multiTurn ? "---|" : ""}---|---|---|`,
|
|
376
377
|
...result.cases.map(
|
|
377
|
-
(c) => `| ${cell(c.key)} | ${c.passed ? "PASS" : "FAIL"} | ${c.passedAttempts}/${c.attempts.length} | ${c.meanScore.toFixed(1)} | ${multiTurn ? `${turnsToSuccess(c)} | ` : ""}${money(
|
|
378
|
+
(c) => `| ${cell(c.key)}${c.version === void 0 ? "" : ` (v${c.version})`} | ${c.passed ? "PASS" : "FAIL"} | ${c.passedAttempts}/${c.attempts.length} | ${c.meanScore.toFixed(1)} | ${multiTurn ? `${turnsToSuccess(c)} | ` : ""}${money(
|
|
378
379
|
c.costCentsPerAttempt,
|
|
379
380
|
c.attempts.some((a) => !a.costComplete)
|
|
380
381
|
)} | ${minutes(c.durationMsPerAttempt)} min | ${tokenPair(c.tokensPerAttempt)} |`
|
|
@@ -552,6 +553,8 @@ async function getRun(argv, target2, apiUrl, token) {
|
|
|
552
553
|
const json = hasFlag(argv, "--json");
|
|
553
554
|
const caseKey = getScalarArgValue(argv, "--case");
|
|
554
555
|
const transcript = hasFlag(argv, "--transcript");
|
|
556
|
+
const stdout = hasFlag(argv, "--stdout");
|
|
557
|
+
if (stdout && !caseKey) throw new Error("--stdout needs --case <key>: each attempt carries up to 16 KiB of stdout, so the CLI prints one case at a time.");
|
|
555
558
|
if (transcript && !caseKey) throw new Error("--transcript needs --case <key>: transcripts are large, so the CLI prints one case at a time.");
|
|
556
559
|
const run = await request(apiUrl, token, "GET", runPath(target2, transcript));
|
|
557
560
|
if (!run.result) {
|
|
@@ -564,7 +567,8 @@ async function getRun(argv, target2, apiUrl, token) {
|
|
|
564
567
|
...c,
|
|
565
568
|
attempts: c.attempts.map((attempt) => ({
|
|
566
569
|
...attempt,
|
|
567
|
-
transcript: transcript ? run.attempts.find((a) => a.case.key === c.key && a.attemptIndex === attempt.index)?.transcript ?? attempt.transcript : attempt.transcript
|
|
570
|
+
transcript: transcript ? run.attempts.find((a) => a.case.key === c.key && a.attemptIndex === attempt.index)?.transcript ?? attempt.transcript : attempt.transcript,
|
|
571
|
+
...stdout ? { stdoutTail: run.attempts.find((a) => a.case.key === c.key && a.attemptIndex === attempt.index)?.stdoutTail } : {}
|
|
568
572
|
}))
|
|
569
573
|
}))
|
|
570
574
|
};
|
|
@@ -725,9 +729,10 @@ graders:
|
|
|
725
729
|
provider: anthropic
|
|
726
730
|
model: claude-opus-4-8
|
|
727
731
|
|
|
728
|
-
# Each case runs \`repeats\` times and passes when at least \`passAtLeast\` attempts pass.
|
|
729
|
-
repeats
|
|
730
|
-
|
|
732
|
+
# Each case runs \`repeats\` times (1 to 7) and passes when at least \`passAtLeast\` attempts pass.
|
|
733
|
+
# One attempt, which must pass, is the default; for a stochastic agent raise repeats and passAtLeast together.
|
|
734
|
+
repeats: 1
|
|
735
|
+
passAtLeast: 1
|
|
731
736
|
|
|
732
737
|
# The eval passes when this share of cases pass.
|
|
733
738
|
passBar: 0.5
|
|
@@ -822,10 +827,11 @@ var USAGE = {
|
|
|
822
827
|
runbook: "runbook <name>",
|
|
823
828
|
list: "list",
|
|
824
829
|
cases: "cases <name> [--download <dir>]",
|
|
830
|
+
case: "case <name> <key> [--version N]",
|
|
825
831
|
"rm-case": "rm-case <name> <key>",
|
|
826
|
-
"add-case": 'add-case <name> --key <k> --input <dir|file.tar.gz> --expected <file|-> --source "<provenance>" [--title <t>] [--conversation <file.json>]',
|
|
832
|
+
"add-case": 'add-case <name> --key <k> --input <dir|file.tar.gz> --expected <file|-> --source "<provenance>" [--title <t>] [--conversation <file.json>] [--replace [--reason <why>]]',
|
|
827
833
|
run: "run <name> [--model <alias>]... [--environment <env>] [--at <sha>] [--case <key>]... [--repeats N] [--parallel N] [--no-wait]",
|
|
828
|
-
get: "get <run-id> [--case <key>] [--transcript]",
|
|
834
|
+
get: "get <run-id> [--case <key>] [--transcript] [--stdout]",
|
|
829
835
|
runs: "runs <name> [--limit N]",
|
|
830
836
|
compare: "compare (<run-id>... | --batch <id>)"
|
|
831
837
|
};
|
|
@@ -839,6 +845,8 @@ var VALUE_FLAGS = [
|
|
|
839
845
|
"--source",
|
|
840
846
|
"--title",
|
|
841
847
|
"--conversation",
|
|
848
|
+
"--reason",
|
|
849
|
+
"--version",
|
|
842
850
|
"--model",
|
|
843
851
|
"--environment",
|
|
844
852
|
"--at",
|
|
@@ -853,6 +861,7 @@ var POSITIONALS = {
|
|
|
853
861
|
show: 1,
|
|
854
862
|
runbook: 1,
|
|
855
863
|
cases: 1,
|
|
864
|
+
case: 2,
|
|
856
865
|
"rm-case": 2,
|
|
857
866
|
"add-case": 1,
|
|
858
867
|
run: 1,
|
|
@@ -886,8 +895,12 @@ function printHelp(command) {
|
|
|
886
895
|
" and dedup is by tar content; gzip is transport only.",
|
|
887
896
|
" The template's input.require paths are checked first.",
|
|
888
897
|
" --expected is a JSON file, or - for stdin. --source says where the data came from and what corroborates the",
|
|
889
|
-
" label.
|
|
890
|
-
"
|
|
898
|
+
" label. --replace stores a new version of an existing key (new --expected and/or --input), recording who and when;",
|
|
899
|
+
" --reason says why. Past runs keep the version they graded and new runs use the latest; compare refuses runs",
|
|
900
|
+
" that graded different versions. Without --replace an existing key is an error.",
|
|
901
|
+
" Never include customer data in a case. --conversation <file.json> is required for a multi-turn eval.",
|
|
902
|
+
"case: one case's expected label, provenance and version history (newest first); --version N shows an older version.",
|
|
903
|
+
"rm-case: deletes a case (all its versions) that no run has used.",
|
|
891
904
|
"run: starts one run per --model (alias from the template; none means its default) and waits, printing one",
|
|
892
905
|
" section per model and then the comparison grid. --case and a --repeats that differs from the template make a partial run",
|
|
893
906
|
" that never counts for coverage or proofs. Polls every 5 seconds for at most 8.5 hours; a timeout leaves the",
|
|
@@ -895,7 +908,7 @@ function printHelp(command) {
|
|
|
895
908
|
" ids and exits 0. --json prints an array with one entry per run, in order: the run's result, or",
|
|
896
909
|
" {id, status, verdict, error} for a run with no result.",
|
|
897
910
|
"get: a run's result. --case <key> narrows to one case; --case <key> --transcript adds a multi-turn attempt's",
|
|
898
|
-
" conversation. runs: recent runs for an eval, newest first (--limit N).",
|
|
911
|
+
" conversation; --case <key> --stdout adds each attempt's stdout tail (why an attempt exited). runs: recent runs for an eval, newest first (--limit N).",
|
|
899
912
|
"compare: the grid for run ids or a --batch; --json prints the array of runs.",
|
|
900
913
|
"",
|
|
901
914
|
"Common options:",
|
|
@@ -908,7 +921,7 @@ function printHelp(command) {
|
|
|
908
921
|
"",
|
|
909
922
|
"Requires the sandbox-v2 organization flag. API-key scopes:",
|
|
910
923
|
" run: sandbox:create + sandbox:exec, named explicitly (sandbox:* does not grant sandbox:exec).",
|
|
911
|
-
" push, add-case, rm-case: sandbox:edit. show, list, cases, runbook, get, runs, compare: sandbox:read.",
|
|
924
|
+
" push, add-case, rm-case: sandbox:edit. show, list, cases, case, runbook, get, runs, compare: sandbox:read.",
|
|
912
925
|
"",
|
|
913
926
|
"Exit codes (run):",
|
|
914
927
|
" 0 every run's verdict is pass",
|
|
@@ -1058,7 +1071,7 @@ async function listCases(ctx) {
|
|
|
1058
1071
|
const download = getScalarArgValue(ctx.argv, "--download");
|
|
1059
1072
|
if (download) await downloadBundles(ctx, evaluation, download);
|
|
1060
1073
|
writeRawOutput(
|
|
1061
|
-
ctx.json ? JSON.stringify(cases, null, 2) : cases.map((c) => `${c.key} ${c.bundleSha256.slice(0, 12)} ${c.bundleBytes} bytes ${c.title} [${c.source}]`).join("\n") || "No cases."
|
|
1074
|
+
ctx.json ? JSON.stringify(cases, null, 2) : cases.map((c) => `${c.key} v${c.version} ${c.bundleSha256.slice(0, 12)} ${c.bundleBytes} bytes ${c.title} [${c.source}]`).join("\n") || "No cases."
|
|
1062
1075
|
);
|
|
1063
1076
|
}
|
|
1064
1077
|
async function showRunbook(ctx) {
|
|
@@ -1066,6 +1079,27 @@ async function showRunbook(ctx) {
|
|
|
1066
1079
|
const text = await requestText(ctx.apiUrl, ctx.token, `${EVALS}/${encodeURIComponent(name)}/runbook`);
|
|
1067
1080
|
writeRawOutput(ctx.json ? JSON.stringify({ name, runbook: text }, null, 2) : text.trimEnd());
|
|
1068
1081
|
}
|
|
1082
|
+
async function showCase(ctx) {
|
|
1083
|
+
const key = ctx.positionals[1];
|
|
1084
|
+
if (!key) throw new Error(`Usage: cofactor eval ${USAGE.case}`);
|
|
1085
|
+
const version = getScalarArgValue(ctx.argv, "--version");
|
|
1086
|
+
if (version !== void 0 && !/^[1-9]\d*$/.test(version)) throw new Error("--version must be a positive whole number.");
|
|
1087
|
+
const evaluation = await getEval(ctx.apiUrl, ctx.token, target(ctx, "case"));
|
|
1088
|
+
const query = version === void 0 ? "" : `?version=${version}`;
|
|
1089
|
+
const detail = await request(ctx.apiUrl, ctx.token, "GET", `${EVALS}/${encodeURIComponent(evaluation.id)}/cases/${encodeURIComponent(key)}${query}`);
|
|
1090
|
+
writeRawOutput(
|
|
1091
|
+
ctx.json ? JSON.stringify(detail, null, 2) : [
|
|
1092
|
+
`${detail.key} v${detail.version}${detail.version === detail.latestVersion ? " (latest)" : ` (latest is v${detail.latestVersion})`} ${detail.title}`,
|
|
1093
|
+
`Source: ${detail.source}`,
|
|
1094
|
+
`sha256 ${detail.bundleSha256} (${detail.bundleBytes} bytes)`,
|
|
1095
|
+
`Expected: ${JSON.stringify(detail.expected, null, 2)}`,
|
|
1096
|
+
"Versions:",
|
|
1097
|
+
...detail.versions.map(
|
|
1098
|
+
(v) => ` v${v.version} ${v.createdAt} ${v.createdBy ?? "before versioning"} ${v.bundleSha256.slice(0, 12)}${v.reason ? ` ${v.reason}` : ""}`
|
|
1099
|
+
)
|
|
1100
|
+
].join("\n")
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1069
1103
|
async function removeCase(ctx) {
|
|
1070
1104
|
const name = target(ctx, "rm-case");
|
|
1071
1105
|
const key = ctx.positionals[1];
|
|
@@ -1082,6 +1116,9 @@ async function addCase(ctx) {
|
|
|
1082
1116
|
const expectedSource = expectedArg(argv);
|
|
1083
1117
|
const source = required(argv, "--source");
|
|
1084
1118
|
const conversationFile = getScalarArgValue(argv, "--conversation");
|
|
1119
|
+
const replace = hasFlag(argv, "--replace");
|
|
1120
|
+
const reason = getScalarArgValue(argv, "--reason");
|
|
1121
|
+
if (reason && !replace) throw new Error("--reason only goes with --replace.");
|
|
1085
1122
|
if (!/^[a-z0-9][a-z0-9-]{0,99}$/.test(key))
|
|
1086
1123
|
throw new Error("--key must be lowercase letters, digits and dashes, starting with a letter or digit (at most 100 characters).");
|
|
1087
1124
|
const expected = await readJson(expectedSource, expectedSource === "-" ? "the expected value on stdin" : `--expected ${expectedSource}`);
|
|
@@ -1112,17 +1149,19 @@ async function addCase(ctx) {
|
|
|
1112
1149
|
if (!response.ok)
|
|
1113
1150
|
throw new Error(`Uploading the bundle failed (${response.status}): ${(await response.text()).slice(0, 300)}`);
|
|
1114
1151
|
}
|
|
1115
|
-
await request(apiUrl, token, "POST", `${evalPath}/cases`, {
|
|
1152
|
+
const stored = await request(apiUrl, token, "POST", `${evalPath}/cases`, {
|
|
1116
1153
|
key,
|
|
1117
1154
|
title: getScalarArgValue(argv, "--title") ?? key,
|
|
1118
1155
|
sha256: bundle.sha256,
|
|
1119
1156
|
expected,
|
|
1120
1157
|
source,
|
|
1121
|
-
...conversation ? { conversation } : {}
|
|
1158
|
+
...conversation ? { conversation } : {},
|
|
1159
|
+
...replace ? { replace: true } : {},
|
|
1160
|
+
...reason ? { reason } : {}
|
|
1122
1161
|
});
|
|
1123
|
-
const result = { eval: name, key, sha256: bundle.sha256, bytes: bundle.bytes, deduplicated };
|
|
1162
|
+
const result = { eval: name, key, version: stored.version, sha256: bundle.sha256, bytes: bundle.bytes, deduplicated };
|
|
1124
1163
|
writeRawOutput(
|
|
1125
|
-
json ? JSON.stringify(result, null, 2) : `Added case ${key} to ${name}
|
|
1164
|
+
json ? JSON.stringify(result, null, 2) : `${replace ? `Stored version ${stored.version} of case ${key} in ${name}` : `Added case ${key} to ${name}`}
|
|
1126
1165
|
sha256 ${bundle.sha256} (${bundle.bytes} bytes local gzip), ${deduplicated ? "deduplicated: the bundle already existed" : "uploaded"}`
|
|
1127
1166
|
);
|
|
1128
1167
|
}
|
|
@@ -1132,6 +1171,7 @@ var HANDLERS = {
|
|
|
1132
1171
|
runbook: showRunbook,
|
|
1133
1172
|
list: listEvals,
|
|
1134
1173
|
cases: listCases,
|
|
1174
|
+
case: showCase,
|
|
1135
1175
|
"rm-case": removeCase,
|
|
1136
1176
|
"add-case": addCase,
|
|
1137
1177
|
run: (ctx) => runEval(ctx.argv, target(ctx, "run"), ctx.apiUrl, ctx.token),
|
|
@@ -1175,4 +1215,4 @@ async function runEvalCommand(argv) {
|
|
|
1175
1215
|
export {
|
|
1176
1216
|
runEvalCommand
|
|
1177
1217
|
};
|
|
1178
|
-
//# sourceMappingURL=eval-
|
|
1218
|
+
//# sourceMappingURL=eval-QZSSEICV.js.map
|