@theokit/sdk 4.63.0 → 4.63.1
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/CHANGELOG.md +31 -0
- package/dist/a2a/index.cjs +2 -2
- package/dist/a2a/index.js +1 -1
- package/dist/agent-WK7MKIMH.cjs +66 -0
- package/dist/{agent-5KYMG63I.cjs.map → agent-WK7MKIMH.cjs.map} +1 -1
- package/dist/agent-YWMBM7LX.js +57 -0
- package/dist/{agent-536OOESZ.js.map → agent-YWMBM7LX.js.map} +1 -1
- package/dist/agent-session-store-6EL5NPA4.cjs +24 -0
- package/dist/{agent-session-store-WAKLOKWK.cjs.map → agent-session-store-6EL5NPA4.cjs.map} +1 -1
- package/dist/agent-session-store-OPGRB4XM.js +7 -0
- package/dist/{agent-session-store-G2BMUZQV.js.map → agent-session-store-OPGRB4XM.js.map} +1 -1
- package/dist/auth/index.cjs +18 -18
- package/dist/auth/index.js +6 -6
- package/dist/{batch-ND32UKZS.cjs → batch-BXYTW2DP.cjs} +27 -27
- package/dist/{batch-ND32UKZS.cjs.map → batch-BXYTW2DP.cjs.map} +1 -1
- package/dist/{batch-2TGJMNCJ.js → batch-L4ZXS46M.js} +10 -10
- package/dist/{batch-2TGJMNCJ.js.map → batch-L4ZXS46M.js.map} +1 -1
- package/dist/{chunk-VF7EWVDG.js → chunk-2GUYQR5P.js} +3 -3
- package/dist/{chunk-VF7EWVDG.js.map → chunk-2GUYQR5P.js.map} +1 -1
- package/dist/{chunk-J2UROOIG.cjs → chunk-2HVF2WJY.cjs} +8 -8
- package/dist/{chunk-J2UROOIG.cjs.map → chunk-2HVF2WJY.cjs.map} +1 -1
- package/dist/{chunk-44MBDIHG.js → chunk-2QDYBS2A.js} +3 -3
- package/dist/{chunk-44MBDIHG.js.map → chunk-2QDYBS2A.js.map} +1 -1
- package/dist/{chunk-NGESVVJN.cjs → chunk-3FFAEAUJ.cjs} +17 -17
- package/dist/{chunk-NGESVVJN.cjs.map → chunk-3FFAEAUJ.cjs.map} +1 -1
- package/dist/{chunk-GWC3HADL.cjs → chunk-3NSS2OIZ.cjs} +4 -4
- package/dist/{chunk-GWC3HADL.cjs.map → chunk-3NSS2OIZ.cjs.map} +1 -1
- package/dist/{chunk-CV7XMBHP.js → chunk-3O42QOMJ.js} +3 -3
- package/dist/{chunk-CV7XMBHP.js.map → chunk-3O42QOMJ.js.map} +1 -1
- package/dist/{chunk-IWBGCBR6.cjs → chunk-4CLOXP6H.cjs} +4 -4
- package/dist/{chunk-IWBGCBR6.cjs.map → chunk-4CLOXP6H.cjs.map} +1 -1
- package/dist/{chunk-YEXA3PGR.js → chunk-4FFBAUFS.js} +5 -5
- package/dist/{chunk-YEXA3PGR.js.map → chunk-4FFBAUFS.js.map} +1 -1
- package/dist/{chunk-HY57ULY2.cjs → chunk-4PYZ5AX3.cjs} +5 -5
- package/dist/{chunk-HY57ULY2.cjs.map → chunk-4PYZ5AX3.cjs.map} +1 -1
- package/dist/{chunk-OC4NTGMN.js → chunk-4QZSA2HJ.js} +3 -3
- package/dist/{chunk-OC4NTGMN.js.map → chunk-4QZSA2HJ.js.map} +1 -1
- package/dist/{chunk-K3FW2XZD.cjs → chunk-4ZHTIJNE.cjs} +9 -9
- package/dist/{chunk-K3FW2XZD.cjs.map → chunk-4ZHTIJNE.cjs.map} +1 -1
- package/dist/{chunk-BUIK7GUA.cjs → chunk-5HEG4CQH.cjs} +8 -8
- package/dist/{chunk-BUIK7GUA.cjs.map → chunk-5HEG4CQH.cjs.map} +1 -1
- package/dist/{chunk-NXH4GPAQ.cjs → chunk-5VB22SYX.cjs} +7 -7
- package/dist/{chunk-NXH4GPAQ.cjs.map → chunk-5VB22SYX.cjs.map} +1 -1
- package/dist/{chunk-5USCYPPI.cjs → chunk-6HKGLTJI.cjs} +8 -8
- package/dist/{chunk-5USCYPPI.cjs.map → chunk-6HKGLTJI.cjs.map} +1 -1
- package/dist/{chunk-EHJEZAOO.cjs → chunk-6RKUO7AW.cjs} +32 -32
- package/dist/{chunk-EHJEZAOO.cjs.map → chunk-6RKUO7AW.cjs.map} +1 -1
- package/dist/{chunk-5JLFFPCH.js → chunk-7YGCPMGB.js} +4 -4
- package/dist/{chunk-5JLFFPCH.js.map → chunk-7YGCPMGB.js.map} +1 -1
- package/dist/{chunk-SUKXXLWD.js → chunk-A46SWMIF.js} +6 -6
- package/dist/{chunk-SUKXXLWD.js.map → chunk-A46SWMIF.js.map} +1 -1
- package/dist/{chunk-F7AQV62G.js → chunk-A4JVILQU.js} +5 -5
- package/dist/{chunk-F7AQV62G.js.map → chunk-A4JVILQU.js.map} +1 -1
- package/dist/{chunk-44JAAH4X.js → chunk-B3IMEBOA.js} +3 -3
- package/dist/{chunk-44JAAH4X.js.map → chunk-B3IMEBOA.js.map} +1 -1
- package/dist/{chunk-QDED6YO6.cjs → chunk-B4EOJWOY.cjs} +5 -5
- package/dist/{chunk-QDED6YO6.cjs.map → chunk-B4EOJWOY.cjs.map} +1 -1
- package/dist/{chunk-YJDH3CKG.js → chunk-BP46RJ5X.js} +5 -5
- package/dist/{chunk-YJDH3CKG.js.map → chunk-BP46RJ5X.js.map} +1 -1
- package/dist/{chunk-QRSUA2CV.js → chunk-BU4KFWXF.js} +3 -3
- package/dist/{chunk-QRSUA2CV.js.map → chunk-BU4KFWXF.js.map} +1 -1
- package/dist/{chunk-MG3SOM3M.js → chunk-BVJJ3DRV.js} +6 -6
- package/dist/{chunk-MG3SOM3M.js.map → chunk-BVJJ3DRV.js.map} +1 -1
- package/dist/{chunk-AQLGBKNT.js → chunk-BZRFXJHA.js} +3 -3
- package/dist/{chunk-AQLGBKNT.js.map → chunk-BZRFXJHA.js.map} +1 -1
- package/dist/{chunk-UQGQFBRL.js → chunk-C3NT3PVE.js} +3 -3
- package/dist/{chunk-UQGQFBRL.js.map → chunk-C3NT3PVE.js.map} +1 -1
- package/dist/{chunk-UC3HT2S4.js → chunk-C72AZW7J.js} +3 -3
- package/dist/{chunk-UC3HT2S4.js.map → chunk-C72AZW7J.js.map} +1 -1
- package/dist/{chunk-WNTAPVU5.cjs → chunk-CQBXOJ6U.cjs} +13 -13
- package/dist/{chunk-WNTAPVU5.cjs.map → chunk-CQBXOJ6U.cjs.map} +1 -1
- package/dist/{chunk-T7XEKOVW.js → chunk-D4CUGAKZ.js} +3 -3
- package/dist/{chunk-T7XEKOVW.js.map → chunk-D4CUGAKZ.js.map} +1 -1
- package/dist/{chunk-R6TA2DRJ.js → chunk-DKD3MH6A.js} +6 -6
- package/dist/{chunk-R6TA2DRJ.js.map → chunk-DKD3MH6A.js.map} +1 -1
- package/dist/{chunk-YXGAW7BB.js → chunk-DN2PACRI.js} +10 -10
- package/dist/{chunk-YXGAW7BB.js.map → chunk-DN2PACRI.js.map} +1 -1
- package/dist/{chunk-XSX2UU6Y.cjs → chunk-DXGZ2NUG.cjs} +10 -10
- package/dist/{chunk-XSX2UU6Y.cjs.map → chunk-DXGZ2NUG.cjs.map} +1 -1
- package/dist/{chunk-NUKRL3I6.cjs → chunk-EG4QM7ZJ.cjs} +18 -2
- package/dist/chunk-EG4QM7ZJ.cjs.map +1 -0
- package/dist/{chunk-C7QPML3L.js → chunk-GEEXBYFL.js} +9 -9
- package/dist/{chunk-C7QPML3L.js.map → chunk-GEEXBYFL.js.map} +1 -1
- package/dist/{chunk-A4VHSE56.cjs → chunk-GKEFRLU7.cjs} +6 -6
- package/dist/{chunk-A4VHSE56.cjs.map → chunk-GKEFRLU7.cjs.map} +1 -1
- package/dist/{chunk-NIRE5CNO.cjs → chunk-HCZD23VS.cjs} +13 -13
- package/dist/{chunk-NIRE5CNO.cjs.map → chunk-HCZD23VS.cjs.map} +1 -1
- package/dist/{chunk-IRCJ7EHV.cjs → chunk-HOXVQ5FR.cjs} +14 -14
- package/dist/{chunk-IRCJ7EHV.cjs.map → chunk-HOXVQ5FR.cjs.map} +1 -1
- package/dist/{chunk-QARJGQSA.js → chunk-HS7AVXTF.js} +3 -3
- package/dist/{chunk-QARJGQSA.js.map → chunk-HS7AVXTF.js.map} +1 -1
- package/dist/{chunk-4I55V454.cjs → chunk-I6HGWHPU.cjs} +4 -4
- package/dist/{chunk-4I55V454.cjs.map → chunk-I6HGWHPU.cjs.map} +1 -1
- package/dist/{chunk-T73NA43R.js → chunk-IPYYKCRC.js} +3 -3
- package/dist/{chunk-T73NA43R.js.map → chunk-IPYYKCRC.js.map} +1 -1
- package/dist/{chunk-UUP3MUZ6.cjs → chunk-ITYQ6VBP.cjs} +18 -18
- package/dist/{chunk-UUP3MUZ6.cjs.map → chunk-ITYQ6VBP.cjs.map} +1 -1
- package/dist/chunk-JPBKYL3B.cjs +18 -0
- package/dist/{chunk-6HTXPPHK.cjs.map → chunk-JPBKYL3B.cjs.map} +1 -1
- package/dist/{chunk-MZ2FGBLZ.js → chunk-K5OJUYSZ.js} +4 -4
- package/dist/{chunk-MZ2FGBLZ.js.map → chunk-K5OJUYSZ.js.map} +1 -1
- package/dist/{chunk-CHKH5452.js → chunk-KIH6IZ43.js} +60 -45
- package/dist/chunk-KIH6IZ43.js.map +1 -0
- package/dist/{chunk-EI2Q7SJ5.cjs → chunk-KQ7TS7WW.cjs} +10 -10
- package/dist/{chunk-EI2Q7SJ5.cjs.map → chunk-KQ7TS7WW.cjs.map} +1 -1
- package/dist/{chunk-RUDY2GTT.js → chunk-KQRW2GPZ.js} +5 -5
- package/dist/{chunk-RUDY2GTT.js.map → chunk-KQRW2GPZ.js.map} +1 -1
- package/dist/{chunk-P5LCASTC.cjs → chunk-KYAJINUI.cjs} +125 -125
- package/dist/{chunk-P5LCASTC.cjs.map → chunk-KYAJINUI.cjs.map} +1 -1
- package/dist/{chunk-AMFXSENK.js → chunk-LWGSI6M3.js} +4 -4
- package/dist/{chunk-AMFXSENK.js.map → chunk-LWGSI6M3.js.map} +1 -1
- package/dist/{chunk-ZHPWGIUX.js → chunk-LXI4XZEC.js} +5 -5
- package/dist/{chunk-ZHPWGIUX.js.map → chunk-LXI4XZEC.js.map} +1 -1
- package/dist/{chunk-AG5JPQIY.js → chunk-LXQ6HKPS.js} +3 -3
- package/dist/{chunk-AG5JPQIY.js.map → chunk-LXQ6HKPS.js.map} +1 -1
- package/dist/{chunk-ROYPRJH4.cjs → chunk-LYRDF5TQ.cjs} +9 -9
- package/dist/{chunk-ROYPRJH4.cjs.map → chunk-LYRDF5TQ.cjs.map} +1 -1
- package/dist/{chunk-G24KZRSA.js → chunk-N2U4AZGB.js} +3 -3
- package/dist/{chunk-G24KZRSA.js.map → chunk-N2U4AZGB.js.map} +1 -1
- package/dist/{chunk-4ERPXIVB.js → chunk-O73J46PV.js} +5 -5
- package/dist/{chunk-4ERPXIVB.js.map → chunk-O73J46PV.js.map} +1 -1
- package/dist/{chunk-F3YZMOAU.cjs → chunk-O7DK5PBJ.cjs} +4 -4
- package/dist/{chunk-F3YZMOAU.cjs.map → chunk-O7DK5PBJ.cjs.map} +1 -1
- package/dist/{chunk-Z4BCLVTI.cjs → chunk-O7LZFG6O.cjs} +5 -5
- package/dist/{chunk-Z4BCLVTI.cjs.map → chunk-O7LZFG6O.cjs.map} +1 -1
- package/dist/{chunk-3YJNUKYN.cjs → chunk-OHLDPWTA.cjs} +15 -15
- package/dist/{chunk-3YJNUKYN.cjs.map → chunk-OHLDPWTA.cjs.map} +1 -1
- package/dist/{chunk-FUL2I7G5.js → chunk-OSEG74VJ.js} +8 -8
- package/dist/{chunk-FUL2I7G5.js.map → chunk-OSEG74VJ.js.map} +1 -1
- package/dist/{chunk-UCBJBJ27.js → chunk-PUAEFLYK.js} +4 -4
- package/dist/{chunk-UCBJBJ27.js.map → chunk-PUAEFLYK.js.map} +1 -1
- package/dist/{chunk-CASUEY42.cjs → chunk-Q7LPTOD6.cjs} +24 -24
- package/dist/{chunk-CASUEY42.cjs.map → chunk-Q7LPTOD6.cjs.map} +1 -1
- package/dist/{chunk-2C72DXQF.cjs → chunk-RFMBZPOW.cjs} +9 -9
- package/dist/{chunk-2C72DXQF.cjs.map → chunk-RFMBZPOW.cjs.map} +1 -1
- package/dist/{chunk-NLTVXLGT.js → chunk-RFXWMRFC.js} +3 -3
- package/dist/{chunk-NLTVXLGT.js.map → chunk-RFXWMRFC.js.map} +1 -1
- package/dist/{chunk-2DG7KW4L.cjs → chunk-RMWTPV3M.cjs} +8 -8
- package/dist/{chunk-2DG7KW4L.cjs.map → chunk-RMWTPV3M.cjs.map} +1 -1
- package/dist/{chunk-P6A3M6VD.cjs → chunk-SZVR77EJ.cjs} +10 -10
- package/dist/{chunk-P6A3M6VD.cjs.map → chunk-SZVR77EJ.cjs.map} +1 -1
- package/dist/{chunk-3E77SX4H.js → chunk-TAZVKYWJ.js} +3 -3
- package/dist/{chunk-3E77SX4H.js.map → chunk-TAZVKYWJ.js.map} +1 -1
- package/dist/{chunk-WKRSH2VR.js → chunk-U6IFHFWK.js} +3 -3
- package/dist/{chunk-WKRSH2VR.js.map → chunk-U6IFHFWK.js.map} +1 -1
- package/dist/{chunk-I6TGFUCO.cjs → chunk-UALX2J2Q.cjs} +4 -4
- package/dist/{chunk-I6TGFUCO.cjs.map → chunk-UALX2J2Q.cjs.map} +1 -1
- package/dist/{chunk-XN7NOENA.js → chunk-UBDMVMBZ.js} +5 -5
- package/dist/{chunk-XN7NOENA.js.map → chunk-UBDMVMBZ.js.map} +1 -1
- package/dist/{chunk-YTR3RBUZ.js → chunk-UEXIJTLC.js} +4 -4
- package/dist/{chunk-YTR3RBUZ.js.map → chunk-UEXIJTLC.js.map} +1 -1
- package/dist/{chunk-DQKERTND.cjs → chunk-UGT7GK7I.cjs} +11 -11
- package/dist/{chunk-DQKERTND.cjs.map → chunk-UGT7GK7I.cjs.map} +1 -1
- package/dist/{chunk-FKMUFNQE.js → chunk-UMP6OJIM.js} +4 -4
- package/dist/{chunk-FKMUFNQE.js.map → chunk-UMP6OJIM.js.map} +1 -1
- package/dist/{chunk-AEOZTXVW.js → chunk-UNYXQ4M5.js} +3 -3
- package/dist/{chunk-AEOZTXVW.js.map → chunk-UNYXQ4M5.js.map} +1 -1
- package/dist/{chunk-2BDH744Z.js → chunk-UTSRIDKZ.js} +3 -3
- package/dist/{chunk-2BDH744Z.js.map → chunk-UTSRIDKZ.js.map} +1 -1
- package/dist/{chunk-2ADR2GSO.cjs → chunk-UU36SHFY.cjs} +5 -5
- package/dist/{chunk-2ADR2GSO.cjs.map → chunk-UU36SHFY.cjs.map} +1 -1
- package/dist/{chunk-R3UPQFKK.cjs → chunk-V2BOS4WF.cjs} +9 -9
- package/dist/{chunk-R3UPQFKK.cjs.map → chunk-V2BOS4WF.cjs.map} +1 -1
- package/dist/{chunk-Q4CMI2LP.js → chunk-WLQNMXQE.js} +5 -5
- package/dist/{chunk-Q4CMI2LP.js.map → chunk-WLQNMXQE.js.map} +1 -1
- package/dist/{chunk-XWL6O3SW.cjs → chunk-WNO3C3N2.cjs} +4 -4
- package/dist/{chunk-XWL6O3SW.cjs.map → chunk-WNO3C3N2.cjs.map} +1 -1
- package/dist/{chunk-T7O6K6PX.js → chunk-XEQ3TM66.js} +18 -3
- package/dist/chunk-XEQ3TM66.js.map +1 -0
- package/dist/{chunk-BVZW2B5V.cjs → chunk-XJCXEKMD.cjs} +4 -4
- package/dist/{chunk-BVZW2B5V.cjs.map → chunk-XJCXEKMD.cjs.map} +1 -1
- package/dist/{chunk-JTB5Q42C.cjs → chunk-XL7Q7HB2.cjs} +4 -4
- package/dist/{chunk-JTB5Q42C.cjs.map → chunk-XL7Q7HB2.cjs.map} +1 -1
- package/dist/{chunk-LW7G5DYW.js → chunk-XO4SOZN6.js} +4 -4
- package/dist/{chunk-LW7G5DYW.js.map → chunk-XO4SOZN6.js.map} +1 -1
- package/dist/{chunk-CQGYNZ3K.cjs → chunk-XWTLIGO3.cjs} +4 -4
- package/dist/{chunk-CQGYNZ3K.cjs.map → chunk-XWTLIGO3.cjs.map} +1 -1
- package/dist/{chunk-6SBW4QR2.cjs → chunk-YML4ME27.cjs} +11 -11
- package/dist/{chunk-6SBW4QR2.cjs.map → chunk-YML4ME27.cjs.map} +1 -1
- package/dist/{chunk-P6H23T43.cjs → chunk-ZCIRZE37.cjs} +11 -11
- package/dist/{chunk-P6H23T43.cjs.map → chunk-ZCIRZE37.cjs.map} +1 -1
- package/dist/{chunk-QI7WE46I.cjs → chunk-ZLQSWSJ2.cjs} +11 -11
- package/dist/{chunk-QI7WE46I.cjs.map → chunk-ZLQSWSJ2.cjs.map} +1 -1
- package/dist/{chunk-NLXOGBRJ.cjs → chunk-ZMRD5DZQ.cjs} +338 -323
- package/dist/chunk-ZMRD5DZQ.cjs.map +1 -0
- package/dist/{chunk-ILCGLTSA.cjs → chunk-ZSWPZ23K.cjs} +4 -4
- package/dist/{chunk-ILCGLTSA.cjs.map → chunk-ZSWPZ23K.cjs.map} +1 -1
- package/dist/{chunk-IDCKSLYH.js → chunk-ZZMZWBR6.js} +3 -3
- package/dist/{chunk-IDCKSLYH.js.map → chunk-ZZMZWBR6.js.map} +1 -1
- package/dist/compact-session-QV57KR66.cjs +59 -0
- package/dist/{compact-session-GJXJD73F.cjs.map → compact-session-QV57KR66.cjs.map} +1 -1
- package/dist/compact-session-RIGOWC4Y.js +22 -0
- package/dist/{compact-session-TSMQOIHO.js.map → compact-session-RIGOWC4Y.js.map} +1 -1
- package/dist/compaction.cjs +17 -17
- package/dist/compaction.js +4 -4
- package/dist/concurrency.cjs +7 -7
- package/dist/concurrency.js +5 -5
- package/dist/context-AGQ3DIZU.cjs +24 -0
- package/dist/{context-LCKNH2XI.cjs.map → context-AGQ3DIZU.cjs.map} +1 -1
- package/dist/context-GQRFBCLP.js +7 -0
- package/dist/{context-MZSKGKYR.js.map → context-GQRFBCLP.js.map} +1 -1
- package/dist/cron.cjs +36 -36
- package/dist/cron.js +35 -35
- package/dist/errors.cjs +22 -22
- package/dist/errors.js +3 -3
- package/dist/eval.cjs +41 -41
- package/dist/eval.js +35 -35
- package/dist/{executor-ZERJ3DGN.cjs → executor-6CYCA7MI.cjs} +25 -25
- package/dist/{executor-ZERJ3DGN.cjs.map → executor-6CYCA7MI.cjs.map} +1 -1
- package/dist/{executor-BMEHFOXZ.js → executor-QSEC3MRH.js} +8 -8
- package/dist/{executor-BMEHFOXZ.js.map → executor-QSEC3MRH.js.map} +1 -1
- package/dist/filesystem/index.cjs +8 -8
- package/dist/filesystem/index.js +4 -4
- package/dist/fs-session-store-4PIHT5UX.cjs +20 -0
- package/dist/{fs-session-store-XZ7ZTB3A.cjs.map → fs-session-store-4PIHT5UX.cjs.map} +1 -1
- package/dist/fs-session-store-NM6YSTE2.js +11 -0
- package/dist/{fs-session-store-4BHGIWRE.js.map → fs-session-store-NM6YSTE2.js.map} +1 -1
- package/dist/generate-object-GUNAUVBX.js +8 -0
- package/dist/{generate-object-N5MDZUJI.js.map → generate-object-GUNAUVBX.js.map} +1 -1
- package/dist/generate-object-R7HTMW7F.cjs +21 -0
- package/dist/{generate-object-PGSP5U7N.cjs.map → generate-object-R7HTMW7F.cjs.map} +1 -1
- package/dist/index-manager-RBDHP3PM.js +17 -0
- package/dist/{index-manager-ACEQG3IJ.js.map → index-manager-RBDHP3PM.js.map} +1 -1
- package/dist/index-manager-UZBF22BJ.cjs +26 -0
- package/dist/{index-manager-6TEEIWM7.cjs.map → index-manager-UZBF22BJ.cjs.map} +1 -1
- package/dist/index.cjs +139 -139
- package/dist/index.js +50 -50
- package/dist/{inject-session-ZCQUB3IT.js → inject-session-DAR7OUCW.js} +8 -8
- package/dist/{inject-session-ZCQUB3IT.js.map → inject-session-DAR7OUCW.js.map} +1 -1
- package/dist/{inject-session-PPSO2IDD.cjs → inject-session-WQKMC3GR.cjs} +10 -10
- package/dist/{inject-session-PPSO2IDD.cjs.map → inject-session-WQKMC3GR.cjs.map} +1 -1
- package/dist/internal/memory/adapters/index.cjs +9 -9
- package/dist/internal/memory/adapters/index.js +8 -8
- package/dist/internal/memory/storage/index.cjs +39 -39
- package/dist/internal/memory/storage/index.js +10 -10
- package/dist/internal/persistence/index.cjs +21 -21
- package/dist/internal/persistence/index.js +7 -7
- package/dist/internal/security/index.cjs +14 -14
- package/dist/internal/security/index.js +4 -4
- package/dist/judge-call-LAHMBJ57.cjs +23 -0
- package/dist/{judge-call-EGYRC2RE.cjs.map → judge-call-LAHMBJ57.cjs.map} +1 -1
- package/dist/judge-call-LVXABPS3.js +6 -0
- package/dist/{judge-call-DWHAJATE.js.map → judge-call-LVXABPS3.js.map} +1 -1
- package/dist/mcp-auth.cjs +15 -15
- package/dist/mcp-auth.js +5 -5
- package/dist/models.cjs +22 -22
- package/dist/models.js +7 -7
- package/dist/path-safety.cjs +11 -11
- package/dist/path-safety.js +4 -4
- package/dist/persistence.cjs +28 -28
- package/dist/persistence.js +9 -9
- package/dist/project.cjs +6 -6
- package/dist/project.js +4 -4
- package/dist/providers.cjs +9 -9
- package/dist/providers.js +7 -7
- package/dist/registry-75W33OGL.js +10 -0
- package/dist/{registry-VFP3WWQP.js.map → registry-75W33OGL.js.map} +1 -1
- package/dist/registry-V7BDQ6QB.cjs +47 -0
- package/dist/{registry-VFKX7WOP.cjs.map → registry-V7BDQ6QB.cjs.map} +1 -1
- package/dist/retry.cjs +5 -5
- package/dist/retry.js +4 -4
- package/dist/sandbox/index.cjs +7 -7
- package/dist/sandbox/index.js +3 -3
- package/dist/server/errors-envelope.cjs +15 -15
- package/dist/server/errors-envelope.js +4 -4
- package/dist/session-transcript-6WNITKRE.cjs +63 -0
- package/dist/{session-transcript-HF5GEU5M.cjs.map → session-transcript-6WNITKRE.cjs.map} +1 -1
- package/dist/session-transcript-XAEKW6P7.js +6 -0
- package/dist/{session-transcript-P462ZRHX.js.map → session-transcript-XAEKW6P7.js.map} +1 -1
- package/dist/skills.cjs +8 -8
- package/dist/skills.js +6 -6
- package/dist/stream-object-UF4QRQRU.js +8 -0
- package/dist/{stream-object-L57K4OFS.js.map → stream-object-UF4QRQRU.js.map} +1 -1
- package/dist/stream-object-ZJTQNKY3.cjs +21 -0
- package/dist/{stream-object-BUCF5PHO.cjs.map → stream-object-ZJTQNKY3.cjs.map} +1 -1
- package/dist/subagents-loader-CRT5LLL3.js +8 -0
- package/dist/{subagents-loader-6ATCDEKN.js.map → subagents-loader-CRT5LLL3.js.map} +1 -1
- package/dist/subagents-loader-YEUFFPAL.cjs +17 -0
- package/dist/{subagents-loader-X5QKODCL.cjs.map → subagents-loader-YEUFFPAL.cjs.map} +1 -1
- package/dist/subagents-loader.cjs +7 -7
- package/dist/subagents-loader.js +5 -5
- package/dist/subscription/index.cjs +4 -4
- package/dist/subscription/index.js +3 -3
- package/dist/task-store.cjs +8 -8
- package/dist/task-store.js +5 -5
- package/dist/workflow.cjs +28 -28
- package/dist/workflow.js +7 -7
- package/package.json +1 -1
- package/dist/agent-536OOESZ.js +0 -57
- package/dist/agent-5KYMG63I.cjs +0 -66
- package/dist/agent-session-store-G2BMUZQV.js +0 -7
- package/dist/agent-session-store-WAKLOKWK.cjs +0 -24
- package/dist/chunk-6HTXPPHK.cjs +0 -18
- package/dist/chunk-CHKH5452.js.map +0 -1
- package/dist/chunk-NLXOGBRJ.cjs.map +0 -1
- package/dist/chunk-NUKRL3I6.cjs.map +0 -1
- package/dist/chunk-T7O6K6PX.js.map +0 -1
- package/dist/compact-session-GJXJD73F.cjs +0 -59
- package/dist/compact-session-TSMQOIHO.js +0 -22
- package/dist/context-LCKNH2XI.cjs +0 -24
- package/dist/context-MZSKGKYR.js +0 -7
- package/dist/fs-session-store-4BHGIWRE.js +0 -11
- package/dist/fs-session-store-XZ7ZTB3A.cjs +0 -20
- package/dist/generate-object-N5MDZUJI.js +0 -8
- package/dist/generate-object-PGSP5U7N.cjs +0 -21
- package/dist/index-manager-6TEEIWM7.cjs +0 -26
- package/dist/index-manager-ACEQG3IJ.js +0 -17
- package/dist/judge-call-DWHAJATE.js +0 -6
- package/dist/judge-call-EGYRC2RE.cjs +0 -23
- package/dist/registry-VFKX7WOP.cjs +0 -47
- package/dist/registry-VFP3WWQP.js +0 -10
- package/dist/session-transcript-HF5GEU5M.cjs +0 -63
- package/dist/session-transcript-P462ZRHX.js +0 -6
- package/dist/stream-object-BUCF5PHO.cjs +0 -21
- package/dist/stream-object-L57K4OFS.js +0 -8
- package/dist/subagents-loader-6ATCDEKN.js +0 -8
- package/dist/subagents-loader-X5QKODCL.cjs +0 -17
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types/workflow.ts","../src/internal/workflow/snapshot-store.ts"],"names":[],"mappings":"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","file":"chunk-AQLGBKNT.js","sourcesContent":["/**\n * Public type contract for `Workflow.create / .run / .resume` (Adoption\n * Roadmap #5; ADRs D230-D248).\n *\n * Step types form a discriminated union by `kind`. Helper factory functions\n * (`fn()`, `agentStep()`) live in `workflow.ts` and hide the discriminator\n * from end users.\n *\n * @public\n */\n\nimport type { ZodType } from \"zod\";\n\nimport type { SDKAgent } from \"./agent.js\";\nimport type { MessageOrigin } from \"./run.js\";\n\n/* ─── Step discriminated union (D232) ─── */\n\n/**\n * Any node of a committed workflow, discriminated by `kind`.\n *\n * Build these with the helpers rather than by hand: `fn()` and `agentStep()` set the discriminator,\n * validate the id, and parse the retry policy at construction — where a mistake is cheap — while the\n * builder methods `.parallel()`, `.branch()`, `.foreach()`, `.dowhile()`, `.sleep()` and `.suspend()`\n * cover the remaining variants and mint a positional default id (`parallel_0`, `branch_1`, ...) when\n * you do not pass one.\n *\n * Every id, nested ones included, must match `^[a-z0-9][a-z0-9_-]*$` case-insensitively and be at\n * most 64 characters, and must be unique across the whole workflow. `.commit()` walks the tree —\n * parallel branches, branch predicates, the fallback, and the inner step of a `foreach`/`dowhile` —\n * and throws {@link WorkflowDuplicateStepIdError} on the second occurrence.\n */\nexport type Step =\n | FnStep\n | AgentStep\n | ParallelStep\n | BranchStep\n | ForeachStep\n | DowhileStep\n | SleepStep\n | SuspendStep;\n\n/** A pure function step. */\nexport interface FnStep {\n readonly kind: \"fn\";\n readonly id: string;\n readonly fn: (input: unknown, ctx: StepContext) => Promise<unknown> | unknown;\n readonly inputSchema?: ZodType;\n readonly outputSchema?: ZodType;\n readonly retry?: RetryPolicy;\n /** D238 — slot reserved; runtime throws if engine not yet implemented. */\n readonly compensate?: (input: unknown, output: unknown, error: Error) => Promise<void> | void;\n}\n\n/** An agent.send-driven step. */\nexport interface AgentStep {\n readonly kind: \"agent\";\n readonly id: string;\n readonly agent: SDKAgent;\n readonly promptTemplate: string | ((input: unknown) => string);\n readonly retry?: RetryPolicy;\n /**\n * SE3 — provenance stamped onto this step's `agent.send()` (forwarded to\n * `RunResult.origin`). Squad sets `{ kind: \"peer\", from: \"agent-<i-1>\" }` on\n * every step after the first so a peer-driven turn is attributable.\n */\n readonly origin?: MessageOrigin;\n}\n\n/** N concurrent branches, each its own mini-step-list. */\nexport interface ParallelStep {\n readonly kind: \"parallel\";\n readonly id: string;\n readonly branches: ReadonlyArray<ReadonlyArray<Step>>;\n readonly concurrency?: number;\n readonly errorPolicy?: \"fail-fast\" | \"collect\";\n}\n\n/** First-match-wins predicates + optional fallback. */\nexport interface BranchStep {\n readonly kind: \"branch\";\n readonly id: string;\n readonly predicates: ReadonlyArray<\n readonly [(input: unknown) => boolean | Promise<boolean>, ReadonlyArray<Step>]\n >;\n readonly fallback?: ReadonlyArray<Step>;\n}\n\n/** Map a step over an upstream array output. */\nexport interface ForeachStep {\n readonly kind: \"foreach\";\n readonly id: string;\n /** ID of an upstream top-level step whose output is iterable. */\n readonly iterableFrom: string;\n readonly step: Step;\n readonly concurrency?: number;\n}\n\n/** Loop a step until condFn returns false. */\nexport interface DowhileStep {\n readonly kind: \"dowhile\";\n readonly id: string;\n readonly step: Step;\n readonly condFn: (output: unknown, iteration: number) => boolean | Promise<boolean>;\n readonly maxIterations?: number;\n}\n\n/** Pause for a fixed duration. */\nexport interface SleepStep {\n readonly kind: \"sleep\";\n readonly id: string;\n readonly durationMs: number;\n}\n\n/** Standalone explicit suspend point. */\nexport interface SuspendStep {\n readonly kind: \"suspend\";\n readonly id: string;\n readonly payloadSchema?: ZodType;\n}\n\n/* ─── Reflection (theokit#161) ─── */\n\n/**\n * theokit#161 — one step of a workflow, as a reflection surface sees it.\n *\n * `id` and `kind` are the only fields every step variant shares, and they are what a reflection\n * endpoint renders. Everything else a step carries is an executable — a predicate, a condition, an\n * agent, a prompt template — which cannot cross a process boundary and means nothing to a caller\n * enumerating shape.\n *\n * @public\n */\nexport interface WorkflowStepDescription {\n readonly id: string;\n readonly kind: Step[\"kind\"];\n /**\n * Nested steps, for the variants that contain them: `parallel` (all branches, flattened — the\n * branch grouping is a scheduling detail, not shape a reader needs), `branch` (each predicate's\n * steps plus the fallback), `foreach` and `dowhile` (their single inner step).\n *\n * Absent for leaf steps. A flat list would misreport a parallel or branching workflow as linear.\n */\n readonly steps?: readonly WorkflowStepDescription[];\n}\n\n/**\n * theokit#161 — the read-only shape of a committed workflow.\n *\n * Returned by `Workflow.describe()`. There is deliberately NO workflow registry to enumerate: a\n * `Workflow` is a value the caller constructs and holds, so the caller already knows which ones\n * exist. What it lacked was a way to DESCRIBE one. A registry would have added process-global state\n * that nothing ever releases, to re-answer a question the host can answer itself.\n *\n * @public\n */\nexport interface WorkflowDescription {\n readonly name: string;\n readonly steps: readonly WorkflowStepDescription[];\n}\n\n/* ─── Supporting types ─── */\n\n/** D237 — retry policy applied per fn/agent step. */\nexport interface RetryPolicy {\n /** Total attempts (MIN 1, MAX 20). `1` = no retry. */\n readonly maxAttempts: number;\n readonly initialBackoffMs?: number;\n readonly backoffCoefficient?: number;\n readonly maximumBackoffMs?: number;\n readonly nonRetryableErrors?: ReadonlyArray<string>;\n}\n\n/** D247 — context handed to every step.fn. */\nexport interface StepContext {\n readonly runId: string;\n readonly signal: AbortSignal;\n readonly log: {\n debug: (msg: string, attrs?: Record<string, unknown>) => void;\n info: (msg: string, attrs?: Record<string, unknown>) => void;\n warn: (msg: string, attrs?: Record<string, unknown>) => void;\n };\n /** Pause the workflow; resume via `Workflow.resume({...})`. */\n readonly suspend: (payload?: unknown) => Promise<never>;\n /**\n * SE29 — the workflow's shared state (from `WorkflowOptions.initialState`,\n * mutated by {@link setState}), visible to every subsequent step in the run.\n * `undefined` when no `initialState`/`setState` has run. Persisted across\n * suspend/resume.\n */\n readonly state: unknown;\n /**\n * SE29 — update the shared state for subsequent steps. Validated against\n * `WorkflowOptions.stateSchema` when set (a mismatch throws\n * {@link WorkflowStateError}, which fails the step/run — Rule 8).\n */\n readonly setState: (next: unknown) => void;\n}\n\n/* ─── Result types ─── */\n\n/**\n * The outcome of one step, appended to `WorkflowRun.stepResults` in execution order.\n *\n * A failing step does not throw out of `run()`. It lands here with `status: \"failed\"` and its error\n * flattened to `{ name, message }` — the thrown instance is gone by the time a caller sees it, so\n * match on `error.name` and never on `instanceof`.\n *\n * `\"skipped\"` occurs only for a `branch` step whose predicates all returned false and which declared\n * no fallback; its `output` is the step input, passed through unchanged. `\"suspended\"` marks the step\n * that called `StepContext.suspend()`, is always the last entry of the run, and carries no output.\n *\n * `attempts` means different things per kind. For `fn` and `agent` it counts execution attempts: 1\n * without a `retry` policy, and 0 when the step failed before its body ran — an `inputSchema`\n * rejection, a prompt template that threw, a `compensate` v1 refuses, or a cloud agent. For `dowhile`\n * it counts loop iterations instead.\n */\nexport interface StepResult {\n readonly stepId: string;\n readonly kind: Step[\"kind\"];\n readonly status: \"completed\" | \"failed\" | \"skipped\" | \"suspended\";\n readonly attempts: number;\n readonly durationMs: number;\n readonly output?: unknown;\n readonly error?: { name: string; message: string };\n}\n\n/**\n * The terminal record of one run — what `Workflow.run()` resolves to, what `Workflow.resume()`\n * returns, and what the `result` promise of `Workflow.stream()` settles with.\n *\n * Read `status`; do not rely on `catch`. A step that throws does not reject the promise, it ends the\n * run with `status: \"failed\"` and the error in `error`. Only `completed` populates `output`; `failed`\n * and `cancelled` (an aborted `signal`) populate `error`; `suspended` populates neither and means a\n * snapshot exists under `id` for `Workflow.resume()`. `running` is part of the union for the benefit\n * of a host tracking a run in flight — the executor only ever assembles a terminal one.\n *\n * `stepResults` is cumulative across a resume: the executor seeds it with the snapshot's prior\n * results, so the record of a resumed run covers the steps that ran before the suspend as well.\n */\nexport interface WorkflowRun<TOutput = unknown> {\n readonly id: string;\n readonly name: string;\n readonly status: \"running\" | \"completed\" | \"failed\" | \"suspended\" | \"cancelled\";\n readonly output?: TOutput;\n readonly error?: { name: string; message: string };\n readonly startedAt: number;\n readonly endedAt?: number;\n readonly stepResults: ReadonlyArray<StepResult>;\n}\n\n/**\n * The persisted state of a suspended run: written when a step calls `StepContext.suspend()`, read\n * back by `Workflow.resume()`. Callers never construct one — the type is exported so a host can\n * inspect what the persistence backend wrote.\n *\n * Snapshots are single-shot. `resume()` deletes the snapshot before re-entering the executor, so the\n * same one cannot be resumed twice; a second attempt raises\n * {@link WorkflowSnapshotNotFoundError}.\n *\n * Everything reachable from here must survive `JSON.stringify` — the store serializes on save even\n * for the memory backend, and raises `WorkflowNotSerializableError` rather than letting a `TypeError`\n * escape. That rules out BigInt, circular references and class instances in step outputs, in\n * `accumulatedInput` and in `state`.\n *\n * `currentStepId` is the suspending step, and resume continues from the step AFTER it. A workflow\n * definition edited between suspend and resume therefore either fails with\n * `WorkflowResumeStepNotFoundError` (the id is gone) or resumes at a position the author did not\n * intend (the id moved).\n */\nexport interface WorkflowSnapshot {\n /** v1 = pre-SE29 (no `state`); v2 = SE29 (carries `state`). Resume reads both. */\n readonly _schemaVersion: 1 | 2;\n readonly runId: string;\n readonly workflowName: string;\n readonly currentStepId: string;\n readonly suspendedPayload?: unknown;\n readonly stepResults: ReadonlyArray<StepResult>;\n readonly accumulatedInput: unknown;\n /** SE29 — shared state captured at suspend (v2). Absent on a v1 snapshot. */\n readonly state?: unknown;\n readonly suspendedAt: number;\n}\n\n/* ─── SE28 — streaming ─── */\n\n/**\n * SE28 — a step-level workflow event emitted by `Workflow.stream()` as top-level\n * steps run. Coarse-grained (one event per top-level step; nested\n * parallel/branch/foreach emit as their single wrapping step), distinct from the\n * token-delta agent stream. Discriminate on `type`.\n *\n * @public\n */\nexport type WorkflowEvent =\n | { readonly type: \"step_started\"; readonly stepId: string }\n | { readonly type: \"step_completed\"; readonly stepId: string; readonly output: unknown }\n | {\n readonly type: \"step_failed\";\n readonly stepId: string;\n readonly error: { readonly name: string; readonly message: string };\n }\n | { readonly type: \"workflow_suspended\"; readonly stepId: string }\n | { readonly type: \"workflow_completed\" };\n\n/**\n * SE28 — the async iterator returned by `Workflow.stream()`. Yields\n * {@link WorkflowEvent}s in execution order; `result` resolves to the same\n * terminal {@link WorkflowRun} the `run()` path returns (the authoritative\n * outcome — the stream ends when the run terminates).\n *\n * @public\n */\nexport type WorkflowStream<TOutput = unknown> = AsyncIterableIterator<WorkflowEvent> & {\n readonly result: Promise<WorkflowRun<TOutput>>;\n};\n\n/* ─── Options ─── */\n\n/**\n * Where suspend snapshots are kept. Omitting `WorkflowOptions.persistence` selects the same store\n * `backend: \"memory\"` selects explicitly.\n *\n * `\"memory\"` is one process-wide map shared by every workflow, so a run suspended under it can only\n * be resumed by the process that suspended it, and only until it exits. `\"json\"` writes one\n * `{runId}.json` per snapshot into `dir` through an atomic write and survives a restart. Any suspend\n * point that waits on a human or an external system needs `\"json\"`; `\"memory\"` is for tests and for\n * suspends resolved within the same process.\n *\n * `dir` is required when `backend` is `\"json\"` and ignored otherwise — `Workflow.create()` rejects\n * the options up front when it is missing or empty, rather than failing at the first suspend.\n */\nexport interface WorkflowPersistenceOptions {\n readonly backend: \"memory\" | \"json\";\n /** Required for `backend: \"json\"`. */\n readonly dir?: string;\n}\n\n/**\n * Configuration for `Workflow.create()`, validated by Zod before the builder is handed back: a `name`\n * outside 1..128 characters, or `persistence.backend: \"json\"` without a `dir`, throws there rather\n * than at run time.\n *\n * `name` is an observability and error-message label, not an identity. Two workflows may share one;\n * the identity behind the single-flight lock is minted per `.commit()` call, so two separately\n * committed workflows never block each other however they are named.\n *\n * The three schemas are independent and each optional: `inputSchema` guards `run(input)` before step\n * 1, `outputSchema` guards the final value on the completed path only (a suspended or failed run\n * skips it), and `stateSchema` guards `initialState` plus every `StepContext.setState()` call. All\n * three must be synchronous — a schema carrying an async refinement is reported as a validation\n * failure with that explanation, never awaited.\n */\nexport interface WorkflowOptions {\n readonly name: string;\n readonly persistence?: WorkflowPersistenceOptions;\n /**\n * SE27 — Zod schema for the WHOLE workflow's input. When set, `run(input)`\n * validates `input` BEFORE step 1; a mismatch yields `status: \"failed\"` with a\n * typed {@link WorkflowInputError} in `error` (fail-fast, no step runs, no\n * silent coerce). Absent ⇒ no whole-workflow input validation (unchanged).\n */\n readonly inputSchema?: ZodType;\n /**\n * SE27 — Zod schema for the workflow's final output. When set, the terminal\n * `completed` output is validated before `WorkflowRun.output` is populated; a\n * mismatch yields `status: \"failed\"` with a typed {@link WorkflowOutputError}.\n * Only validated on the `completed` path (suspended/failed runs skip it).\n */\n readonly outputSchema?: ZodType;\n /**\n * SE29 — Zod schema for the workflow's shared state (see `StepContext.state` /\n * `setState`). When set, `initialState` and every `setState(next)` are\n * validated against it (a mismatch throws {@link WorkflowStateError}). When\n * `initialState` is absent, `state` starts as `undefined` and validation fires\n * on the first `setState` call.\n */\n readonly stateSchema?: ZodType;\n /**\n * SE29 — the initial shared state, seeded onto `StepContext.state` before\n * step 1. Validated against `stateSchema` when both are set. Persisted across\n * suspend/resume.\n */\n readonly initialState?: unknown;\n /** Internal — minted at `.commit()`. Not user-facing. */\n readonly workflowId?: string;\n}\n\n/**\n * Per-run options for `Workflow.run()` and `Workflow.stream()`.\n *\n * `signal` is combined with the run's internal single-flight signal and reaches every step through\n * `StepContext.signal`. The executor itself checks it at step boundaries, so a step that ignores the\n * signal runs to completion before the run reports `status: \"cancelled\"` — a step doing long I/O\n * should pass `ctx.signal` down to make abort prompt.\n *\n * `runId` is minted per call (`wfr-` plus 8 hex) unless you pass it, which is why concurrent runs of\n * one workflow do not interfere. Pinning it buys a deterministic id for resume, and buys the\n * single-flight lock with it: starting a second run of the same committed workflow under a `runId`\n * that is still in flight throws {@link WorkflowAlreadyRunningError}.\n */\nexport interface WorkflowRunOptions {\n readonly signal?: AbortSignal;\n /** Override run ID for deterministic resume (advanced; default = mintRunId). */\n readonly runId?: string;\n /**\n * Opt-in Task wrapping (ADRs D363, D374). Registers the workflow run\n * as a `Task` (kind=\"workflow\") with a `wf-` namespaced id (D368,\n * EC-5). The task transitions terminal when `Workflow.run` resolves.\n *\n * Auto-id: `wf-{runId}`.\n *\n * @public\n */\n readonly task?: true | { id?: string; meta?: Record<string, unknown> };\n}\n\n/**\n * Arguments for `Workflow.resume()`.\n *\n * `workflow` is typed structurally as `{ run }`, but resume needs more than `run`: it reads the\n * committed steps and options off the instance and throws a plain `Error` — \"Workflow.resume requires\n * an instance from Workflow.create().commit()\" — for anything else. Pass the same committed\n * `Workflow` the suspended run came from, not a stand-in.\n *\n * `runId` selects the snapshot. An id with no snapshot throws\n * {@link WorkflowSnapshotNotFoundError}.\n *\n * `payload` becomes the input of the step after the suspend point, and is parsed against the\n * suspending step's `payloadSchema` first when it declared one (a mismatch throws out of `resume`).\n * Omit it to resume from the accumulated input captured in the snapshot instead — the two are\n * alternatives, not a merge.\n */\nexport interface WorkflowResumeOptions<TI = unknown> {\n readonly runId: string;\n readonly workflow: { run: (input: TI, opts?: WorkflowRunOptions) => Promise<WorkflowRun> };\n readonly payload?: unknown;\n readonly signal?: AbortSignal;\n}\n\n/* ─── Error classes ─── */\n\n/**\n * Thrown by `.commit()` when one step id appears twice anywhere in the workflow — including inside a\n * parallel branch, a branch predicate, the fallback, and the inner step of a `foreach` or `dowhile`.\n *\n * Ids address steps in snapshots and on resume, so this is refused at build time rather than\n * discovered mid-run. Workflows nested with `workflowStep()` are exempt: the child runs in its own\n * executor with its own id-space, so its ids cannot collide with the parent's.\n */\nexport class WorkflowDuplicateStepIdError extends Error {\n override readonly name = \"WorkflowDuplicateStepIdError\";\n constructor(public readonly stepId: string) {\n super(`Duplicate step id \"${stepId}\" in workflow.`);\n }\n}\n\n/**\n * SE27 — the whole-workflow `inputSchema` rejected `run(input)` (before step 1).\n * `detail` is a pre-formatted issues summary (a string, NOT Zod's `ZodIssue[]`).\n */\nexport class WorkflowInputError extends Error {\n override readonly name = \"WorkflowInputError\";\n constructor(\n public readonly workflowName: string,\n public readonly detail: string,\n ) {\n super(`Workflow \"${workflowName}\" input failed schema validation: ${detail}`);\n }\n}\n\n/**\n * SE27 — the whole-workflow `outputSchema` rejected the final output (on `completed`).\n * `detail` is a pre-formatted issues summary (a string, NOT Zod's `ZodIssue[]`).\n */\nexport class WorkflowOutputError extends Error {\n override readonly name = \"WorkflowOutputError\";\n constructor(\n public readonly workflowName: string,\n public readonly detail: string,\n ) {\n super(`Workflow \"${workflowName}\" output failed schema validation: ${detail}`);\n }\n}\n\n/**\n * SE29 — `WorkflowOptions.stateSchema` rejected an `initialState` or a\n * `setState(next)` call. `detail` is a pre-formatted issues summary.\n */\nexport class WorkflowStateError extends Error {\n override readonly name = \"WorkflowStateError\";\n constructor(\n public readonly workflowName: string,\n public readonly detail: string,\n ) {\n super(`Workflow \"${workflowName}\" state failed schema validation: ${detail}`);\n }\n}\n\n/**\n * SE30 — a nested workflow (via `workflowStep`) did not `complete`. A nested\n * `suspended` is NOT resumable in v1 (resume continues AFTER the step, so the\n * child would be skipped) — restructure with a top-level suspend. A nested\n * `failed`/`cancelled` fails the parent step with the child's error attached.\n */\nexport class WorkflowNestedError extends Error {\n override readonly name = \"WorkflowNestedError\";\n constructor(\n public readonly stepId: string,\n public readonly childName: string,\n public readonly childStatus: Exclude<WorkflowRun[\"status\"], \"completed\">,\n public readonly childError?: { name: string; message: string },\n ) {\n super(\n `Nested workflow \"${childName}\" (step \"${stepId}\") ended with status \"${childStatus}\"${\n childStatus === \"suspended\"\n ? \" — nested suspend/resume is not supported in v1 (use a top-level suspend)\"\n : \"\"\n }${childError ? `: ${childError.name}: ${childError.message}` : \"\"}`,\n // Reconstruct a synthetic Error from the serialized child-error shape so\n // debuggers surface the nested cause chain — the original Error instance is\n // lost at the WorkflowRun serialization boundary, so this is the best\n // achievable without changing the run protocol.\n childError\n ? { cause: Object.assign(new Error(childError.message), { name: childError.name }) }\n : undefined,\n );\n }\n}\n\n/**\n * Thrown out of `Workflow.run()` — one of the few workflow failures that rejects instead of arriving\n * as `run.status === \"failed\"` — when the committed workflow already has a run in flight under the\n * same run id.\n *\n * The lock key pairs the id minted at `.commit()` with the run id, not `WorkflowOptions.name`, so\n * two workflows sharing a name are independent and concurrent runs with distinct minted ids never\n * collide. In practice this only fires when a caller pins `WorkflowRunOptions.runId`, or resumes a\n * run id that is still executing. The registry is an in-process map: a crash releases every lock, and\n * it says nothing about runs in other processes.\n */\nexport class WorkflowAlreadyRunningError extends Error {\n override readonly name = \"WorkflowAlreadyRunningError\";\n constructor(\n public readonly workflowName: string,\n public readonly runId: string,\n ) {\n super(`Workflow \"${workflowName}\" run \"${runId}\" already in-flight.`);\n }\n}\n\n/**\n * Thrown by `Workflow.resume()` when no snapshot exists for the given run id.\n *\n * The message suggests configuring persistence, which is the common cause but not the only one. The\n * run may never have suspended; it may have suspended under the default memory backend in a process\n * that has since exited; or the snapshot may already have been consumed, since resume deletes it\n * before re-entering the executor and a second resume of the same run id lands here.\n */\nexport class WorkflowSnapshotNotFoundError extends Error {\n override readonly name = \"WorkflowSnapshotNotFoundError\";\n constructor(public readonly runId: string) {\n super(`No snapshot found for runId \"${runId}\". Configure persistence to enable resume.`);\n }\n}\n\n/**\n * Raised when a `dowhile` step's condition kept returning true past `maxIterations` (default 100).\n *\n * It does not escape `run()`: the step fails, the run ends `status: \"failed\"`, and the error reaches\n * the caller flattened as `run.error` with `name: \"WorkflowMaxIterationsExceededError\"` — match on\n * the name, the instance does not survive. The guard is evaluated before each iteration, so the inner\n * step runs at most `maxIterations` times; raising the ceiling is a `maxIterations` on the step, and\n * there is no global default to change.\n */\nexport class WorkflowMaxIterationsExceededError extends Error {\n override readonly name = \"WorkflowMaxIterationsExceededError\";\n constructor(\n public readonly stepId: string,\n public readonly maxIterations: number,\n ) {\n super(`Step \"${stepId}\" exceeded max iterations (${maxIterations}).`);\n }\n}\n\n/** EC-4 absorbed — JSON.stringify failed on snapshot payload. */\nexport class WorkflowNotSerializableError extends Error {\n override readonly name = \"WorkflowNotSerializableError\";\n constructor(\n public readonly stepId: string,\n public readonly underlying: Error,\n ) {\n super(\n `Workflow snapshot at step \"${stepId}\" failed to serialize as JSON: ${underlying.message}. ` +\n `Persisted snapshots support only JSON-serializable values (no BigInt, no circular refs, no class instances with cycles).`,\n );\n }\n}\n\n/** EC-8 absorbed — `currentStepId` from snapshot not found in resumed workflow. */\nexport class WorkflowResumeStepNotFoundError extends Error {\n override readonly name = \"WorkflowResumeStepNotFoundError\";\n constructor(\n public readonly stepId: string,\n public readonly workflowName: string,\n ) {\n super(\n `Cannot resume: step \"${stepId}\" not found in workflow \"${workflowName}\". ` +\n `The Workflow definition diverged from the snapshot.`,\n );\n }\n}\n\n/** Aggregate failure from parallel branches. */\nexport class WorkflowParallelError extends AggregateError {\n override readonly name = \"WorkflowParallelError\";\n constructor(\n errors: ReadonlyArray<Error>,\n public readonly stepId: string,\n ) {\n super(errors, `${errors.length} branch(es) failed in parallel step \"${stepId}\".`);\n }\n}\n\n/** D238 — saga engine not yet implemented. */\nexport class WorkflowCompensateNotImplementedError extends Error {\n override readonly name = \"WorkflowCompensateNotImplementedError\";\n constructor(public readonly stepId: string) {\n super(\n `Step \"${stepId}\" defines compensate, but saga engine is deferred to v1.2. ` +\n `Remove compensate or implement rollback manually.`,\n );\n }\n}\n","/**\n * Snapshot store interface + InMemory and JsonFile backends (ADR D235).\n *\n * EC-4 absorbed: serialization happens here. `JSON.stringify` failure raises\n * `WorkflowNotSerializableError` instead of letting the underlying `TypeError`\n * leak.\n *\n * @internal\n */\n\nimport { mkdir, readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n WorkflowNotSerializableError,\n type WorkflowOptions,\n type WorkflowSnapshot,\n} from \"../../types/workflow.js\";\nimport { atomicWriteText } from \"../persistence/atomic-write.js\";\n\nexport interface WorkflowSnapshotStore {\n save(snapshot: WorkflowSnapshot): Promise<void>;\n load(runId: string): Promise<WorkflowSnapshot | undefined>;\n delete(runId: string): Promise<void>;\n list(\n workflowName?: string,\n ): Promise<ReadonlyArray<{ runId: string; workflowName: string; suspendedAt: number }>>;\n}\n\n/* ─── InMemory backend (default) ─── */\n\nclass InMemoryWorkflowSnapshotStore implements WorkflowSnapshotStore {\n private readonly map = new Map<string, WorkflowSnapshot>();\n\n async save(snapshot: WorkflowSnapshot): Promise<void> {\n // Verify serializability even in-memory so behavior is consistent with json backend.\n try {\n JSON.stringify(snapshot);\n } catch (err) {\n throw new WorkflowNotSerializableError(\n snapshot.currentStepId,\n err instanceof Error ? err : new Error(String(err)),\n );\n }\n this.map.set(snapshot.runId, snapshot);\n }\n async load(runId: string): Promise<WorkflowSnapshot | undefined> {\n return this.map.get(runId);\n }\n async delete(runId: string): Promise<void> {\n this.map.delete(runId);\n }\n async list(\n workflowName?: string,\n ): Promise<ReadonlyArray<{ runId: string; workflowName: string; suspendedAt: number }>> {\n return [...this.map.values()]\n .filter((s) => workflowName === undefined || s.workflowName === workflowName)\n .map((s) => ({\n runId: s.runId,\n workflowName: s.workflowName,\n suspendedAt: s.suspendedAt,\n }));\n }\n}\n\n/* ─── Json file backend (opt-in) ─── */\n\nclass JsonFileWorkflowSnapshotStore implements WorkflowSnapshotStore {\n constructor(private readonly dir: string) {}\n\n private filePath(runId: string): string {\n return join(this.dir, `${runId}.json`);\n }\n\n async save(snapshot: WorkflowSnapshot): Promise<void> {\n let serialized: string;\n try {\n serialized = JSON.stringify(snapshot);\n } catch (err) {\n throw new WorkflowNotSerializableError(\n snapshot.currentStepId,\n err instanceof Error ? err : new Error(String(err)),\n );\n }\n await mkdir(this.dir, { recursive: true });\n await atomicWriteText(this.filePath(snapshot.runId), serialized);\n }\n\n async load(runId: string): Promise<WorkflowSnapshot | undefined> {\n try {\n const raw = await readFile(this.filePath(runId), \"utf8\");\n return JSON.parse(raw) as WorkflowSnapshot;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw err;\n }\n }\n\n async delete(runId: string): Promise<void> {\n try {\n await (await import(\"node:fs/promises\")).unlink(this.filePath(runId));\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n }\n }\n\n private async readEntriesOrEmpty(): Promise<string[]> {\n try {\n return await readdir(this.dir);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw err;\n }\n }\n\n private async readSnapshotSafe(file: string): Promise<WorkflowSnapshot | undefined> {\n try {\n const raw = await readFile(join(this.dir, file), \"utf8\");\n return JSON.parse(raw) as WorkflowSnapshot;\n } catch {\n return undefined;\n }\n }\n\n async list(\n workflowName?: string,\n ): Promise<ReadonlyArray<{ runId: string; workflowName: string; suspendedAt: number }>> {\n const entries = await this.readEntriesOrEmpty();\n const results: Array<{ runId: string; workflowName: string; suspendedAt: number }> = [];\n for (const file of entries) {\n if (!file.endsWith(\".json\")) continue;\n const snap = await this.readSnapshotSafe(file);\n if (snap === undefined) continue;\n if (workflowName !== undefined && snap.workflowName !== workflowName) continue;\n results.push({\n runId: snap.runId,\n workflowName: snap.workflowName,\n suspendedAt: snap.suspendedAt,\n });\n }\n return results;\n }\n}\n\n/* ─── Resolver: per-Workflow store cache ─── */\n\nconst memoryStore = new InMemoryWorkflowSnapshotStore();\nconst jsonStores = new Map<string, JsonFileWorkflowSnapshotStore>();\n\nexport function getSnapshotStoreFor(options: WorkflowOptions): WorkflowSnapshotStore {\n if (options.persistence?.backend === \"json\") {\n const dir = options.persistence.dir as string; // schema enforces dir is set\n let store = jsonStores.get(dir);\n if (store === undefined) {\n store = new JsonFileWorkflowSnapshotStore(dir);\n jsonStores.set(dir, store);\n }\n return store;\n }\n return memoryStore;\n}\n\n/** Test seam — clear in-memory store between tests. */\nexport function __resetSnapshotStoresForTests(): void {\n jsonStores.clear();\n // memoryStore has private map; reset via assignment.\n // biome-ignore lint/suspicious/noExplicitAny: test-only seam\n (memoryStore as any).map.clear();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types/workflow.ts","../src/internal/workflow/snapshot-store.ts"],"names":[],"mappings":"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","file":"chunk-BZRFXJHA.js","sourcesContent":["/**\n * Public type contract for `Workflow.create / .run / .resume` (Adoption\n * Roadmap #5; ADRs D230-D248).\n *\n * Step types form a discriminated union by `kind`. Helper factory functions\n * (`fn()`, `agentStep()`) live in `workflow.ts` and hide the discriminator\n * from end users.\n *\n * @public\n */\n\nimport type { ZodType } from \"zod\";\n\nimport type { SDKAgent } from \"./agent.js\";\nimport type { MessageOrigin } from \"./run.js\";\n\n/* ─── Step discriminated union (D232) ─── */\n\n/**\n * Any node of a committed workflow, discriminated by `kind`.\n *\n * Build these with the helpers rather than by hand: `fn()` and `agentStep()` set the discriminator,\n * validate the id, and parse the retry policy at construction — where a mistake is cheap — while the\n * builder methods `.parallel()`, `.branch()`, `.foreach()`, `.dowhile()`, `.sleep()` and `.suspend()`\n * cover the remaining variants and mint a positional default id (`parallel_0`, `branch_1`, ...) when\n * you do not pass one.\n *\n * Every id, nested ones included, must match `^[a-z0-9][a-z0-9_-]*$` case-insensitively and be at\n * most 64 characters, and must be unique across the whole workflow. `.commit()` walks the tree —\n * parallel branches, branch predicates, the fallback, and the inner step of a `foreach`/`dowhile` —\n * and throws {@link WorkflowDuplicateStepIdError} on the second occurrence.\n */\nexport type Step =\n | FnStep\n | AgentStep\n | ParallelStep\n | BranchStep\n | ForeachStep\n | DowhileStep\n | SleepStep\n | SuspendStep;\n\n/** A pure function step. */\nexport interface FnStep {\n readonly kind: \"fn\";\n readonly id: string;\n readonly fn: (input: unknown, ctx: StepContext) => Promise<unknown> | unknown;\n readonly inputSchema?: ZodType;\n readonly outputSchema?: ZodType;\n readonly retry?: RetryPolicy;\n /** D238 — slot reserved; runtime throws if engine not yet implemented. */\n readonly compensate?: (input: unknown, output: unknown, error: Error) => Promise<void> | void;\n}\n\n/** An agent.send-driven step. */\nexport interface AgentStep {\n readonly kind: \"agent\";\n readonly id: string;\n readonly agent: SDKAgent;\n readonly promptTemplate: string | ((input: unknown) => string);\n readonly retry?: RetryPolicy;\n /**\n * SE3 — provenance stamped onto this step's `agent.send()` (forwarded to\n * `RunResult.origin`). Squad sets `{ kind: \"peer\", from: \"agent-<i-1>\" }` on\n * every step after the first so a peer-driven turn is attributable.\n */\n readonly origin?: MessageOrigin;\n}\n\n/** N concurrent branches, each its own mini-step-list. */\nexport interface ParallelStep {\n readonly kind: \"parallel\";\n readonly id: string;\n readonly branches: ReadonlyArray<ReadonlyArray<Step>>;\n readonly concurrency?: number;\n readonly errorPolicy?: \"fail-fast\" | \"collect\";\n}\n\n/** First-match-wins predicates + optional fallback. */\nexport interface BranchStep {\n readonly kind: \"branch\";\n readonly id: string;\n readonly predicates: ReadonlyArray<\n readonly [(input: unknown) => boolean | Promise<boolean>, ReadonlyArray<Step>]\n >;\n readonly fallback?: ReadonlyArray<Step>;\n}\n\n/** Map a step over an upstream array output. */\nexport interface ForeachStep {\n readonly kind: \"foreach\";\n readonly id: string;\n /** ID of an upstream top-level step whose output is iterable. */\n readonly iterableFrom: string;\n readonly step: Step;\n readonly concurrency?: number;\n}\n\n/** Loop a step until condFn returns false. */\nexport interface DowhileStep {\n readonly kind: \"dowhile\";\n readonly id: string;\n readonly step: Step;\n readonly condFn: (output: unknown, iteration: number) => boolean | Promise<boolean>;\n readonly maxIterations?: number;\n}\n\n/** Pause for a fixed duration. */\nexport interface SleepStep {\n readonly kind: \"sleep\";\n readonly id: string;\n readonly durationMs: number;\n}\n\n/** Standalone explicit suspend point. */\nexport interface SuspendStep {\n readonly kind: \"suspend\";\n readonly id: string;\n readonly payloadSchema?: ZodType;\n}\n\n/* ─── Reflection (theokit#161) ─── */\n\n/**\n * theokit#161 — one step of a workflow, as a reflection surface sees it.\n *\n * `id` and `kind` are the only fields every step variant shares, and they are what a reflection\n * endpoint renders. Everything else a step carries is an executable — a predicate, a condition, an\n * agent, a prompt template — which cannot cross a process boundary and means nothing to a caller\n * enumerating shape.\n *\n * @public\n */\nexport interface WorkflowStepDescription {\n readonly id: string;\n readonly kind: Step[\"kind\"];\n /**\n * Nested steps, for the variants that contain them: `parallel` (all branches, flattened — the\n * branch grouping is a scheduling detail, not shape a reader needs), `branch` (each predicate's\n * steps plus the fallback), `foreach` and `dowhile` (their single inner step).\n *\n * Absent for leaf steps. A flat list would misreport a parallel or branching workflow as linear.\n */\n readonly steps?: readonly WorkflowStepDescription[];\n}\n\n/**\n * theokit#161 — the read-only shape of a committed workflow.\n *\n * Returned by `Workflow.describe()`. There is deliberately NO workflow registry to enumerate: a\n * `Workflow` is a value the caller constructs and holds, so the caller already knows which ones\n * exist. What it lacked was a way to DESCRIBE one. A registry would have added process-global state\n * that nothing ever releases, to re-answer a question the host can answer itself.\n *\n * @public\n */\nexport interface WorkflowDescription {\n readonly name: string;\n readonly steps: readonly WorkflowStepDescription[];\n}\n\n/* ─── Supporting types ─── */\n\n/** D237 — retry policy applied per fn/agent step. */\nexport interface RetryPolicy {\n /** Total attempts (MIN 1, MAX 20). `1` = no retry. */\n readonly maxAttempts: number;\n readonly initialBackoffMs?: number;\n readonly backoffCoefficient?: number;\n readonly maximumBackoffMs?: number;\n readonly nonRetryableErrors?: ReadonlyArray<string>;\n}\n\n/** D247 — context handed to every step.fn. */\nexport interface StepContext {\n readonly runId: string;\n readonly signal: AbortSignal;\n readonly log: {\n debug: (msg: string, attrs?: Record<string, unknown>) => void;\n info: (msg: string, attrs?: Record<string, unknown>) => void;\n warn: (msg: string, attrs?: Record<string, unknown>) => void;\n };\n /** Pause the workflow; resume via `Workflow.resume({...})`. */\n readonly suspend: (payload?: unknown) => Promise<never>;\n /**\n * SE29 — the workflow's shared state (from `WorkflowOptions.initialState`,\n * mutated by {@link setState}), visible to every subsequent step in the run.\n * `undefined` when no `initialState`/`setState` has run. Persisted across\n * suspend/resume.\n */\n readonly state: unknown;\n /**\n * SE29 — update the shared state for subsequent steps. Validated against\n * `WorkflowOptions.stateSchema` when set (a mismatch throws\n * {@link WorkflowStateError}, which fails the step/run — Rule 8).\n */\n readonly setState: (next: unknown) => void;\n}\n\n/* ─── Result types ─── */\n\n/**\n * The outcome of one step, appended to `WorkflowRun.stepResults` in execution order.\n *\n * A failing step does not throw out of `run()`. It lands here with `status: \"failed\"` and its error\n * flattened to `{ name, message }` — the thrown instance is gone by the time a caller sees it, so\n * match on `error.name` and never on `instanceof`.\n *\n * `\"skipped\"` occurs only for a `branch` step whose predicates all returned false and which declared\n * no fallback; its `output` is the step input, passed through unchanged. `\"suspended\"` marks the step\n * that called `StepContext.suspend()`, is always the last entry of the run, and carries no output.\n *\n * `attempts` means different things per kind. For `fn` and `agent` it counts execution attempts: 1\n * without a `retry` policy, and 0 when the step failed before its body ran — an `inputSchema`\n * rejection, a prompt template that threw, a `compensate` v1 refuses, or a cloud agent. For `dowhile`\n * it counts loop iterations instead.\n */\nexport interface StepResult {\n readonly stepId: string;\n readonly kind: Step[\"kind\"];\n readonly status: \"completed\" | \"failed\" | \"skipped\" | \"suspended\";\n readonly attempts: number;\n readonly durationMs: number;\n readonly output?: unknown;\n readonly error?: { name: string; message: string };\n}\n\n/**\n * The terminal record of one run — what `Workflow.run()` resolves to, what `Workflow.resume()`\n * returns, and what the `result` promise of `Workflow.stream()` settles with.\n *\n * Read `status`; do not rely on `catch`. A step that throws does not reject the promise, it ends the\n * run with `status: \"failed\"` and the error in `error`. Only `completed` populates `output`; `failed`\n * and `cancelled` (an aborted `signal`) populate `error`; `suspended` populates neither and means a\n * snapshot exists under `id` for `Workflow.resume()`. `running` is part of the union for the benefit\n * of a host tracking a run in flight — the executor only ever assembles a terminal one.\n *\n * `stepResults` is cumulative across a resume: the executor seeds it with the snapshot's prior\n * results, so the record of a resumed run covers the steps that ran before the suspend as well.\n */\nexport interface WorkflowRun<TOutput = unknown> {\n readonly id: string;\n readonly name: string;\n readonly status: \"running\" | \"completed\" | \"failed\" | \"suspended\" | \"cancelled\";\n readonly output?: TOutput;\n readonly error?: { name: string; message: string };\n readonly startedAt: number;\n readonly endedAt?: number;\n readonly stepResults: ReadonlyArray<StepResult>;\n}\n\n/**\n * The persisted state of a suspended run: written when a step calls `StepContext.suspend()`, read\n * back by `Workflow.resume()`. Callers never construct one — the type is exported so a host can\n * inspect what the persistence backend wrote.\n *\n * Snapshots are single-shot. `resume()` deletes the snapshot before re-entering the executor, so the\n * same one cannot be resumed twice; a second attempt raises\n * {@link WorkflowSnapshotNotFoundError}.\n *\n * Everything reachable from here must survive `JSON.stringify` — the store serializes on save even\n * for the memory backend, and raises `WorkflowNotSerializableError` rather than letting a `TypeError`\n * escape. That rules out BigInt, circular references and class instances in step outputs, in\n * `accumulatedInput` and in `state`.\n *\n * `currentStepId` is the suspending step, and resume continues from the step AFTER it. A workflow\n * definition edited between suspend and resume therefore either fails with\n * `WorkflowResumeStepNotFoundError` (the id is gone) or resumes at a position the author did not\n * intend (the id moved).\n */\nexport interface WorkflowSnapshot {\n /** v1 = pre-SE29 (no `state`); v2 = SE29 (carries `state`). Resume reads both. */\n readonly _schemaVersion: 1 | 2;\n readonly runId: string;\n readonly workflowName: string;\n readonly currentStepId: string;\n readonly suspendedPayload?: unknown;\n readonly stepResults: ReadonlyArray<StepResult>;\n readonly accumulatedInput: unknown;\n /** SE29 — shared state captured at suspend (v2). Absent on a v1 snapshot. */\n readonly state?: unknown;\n readonly suspendedAt: number;\n}\n\n/* ─── SE28 — streaming ─── */\n\n/**\n * SE28 — a step-level workflow event emitted by `Workflow.stream()` as top-level\n * steps run. Coarse-grained (one event per top-level step; nested\n * parallel/branch/foreach emit as their single wrapping step), distinct from the\n * token-delta agent stream. Discriminate on `type`.\n *\n * @public\n */\nexport type WorkflowEvent =\n | { readonly type: \"step_started\"; readonly stepId: string }\n | { readonly type: \"step_completed\"; readonly stepId: string; readonly output: unknown }\n | {\n readonly type: \"step_failed\";\n readonly stepId: string;\n readonly error: { readonly name: string; readonly message: string };\n }\n | { readonly type: \"workflow_suspended\"; readonly stepId: string }\n | { readonly type: \"workflow_completed\" };\n\n/**\n * SE28 — the async iterator returned by `Workflow.stream()`. Yields\n * {@link WorkflowEvent}s in execution order; `result` resolves to the same\n * terminal {@link WorkflowRun} the `run()` path returns (the authoritative\n * outcome — the stream ends when the run terminates).\n *\n * @public\n */\nexport type WorkflowStream<TOutput = unknown> = AsyncIterableIterator<WorkflowEvent> & {\n readonly result: Promise<WorkflowRun<TOutput>>;\n};\n\n/* ─── Options ─── */\n\n/**\n * Where suspend snapshots are kept. Omitting `WorkflowOptions.persistence` selects the same store\n * `backend: \"memory\"` selects explicitly.\n *\n * `\"memory\"` is one process-wide map shared by every workflow, so a run suspended under it can only\n * be resumed by the process that suspended it, and only until it exits. `\"json\"` writes one\n * `{runId}.json` per snapshot into `dir` through an atomic write and survives a restart. Any suspend\n * point that waits on a human or an external system needs `\"json\"`; `\"memory\"` is for tests and for\n * suspends resolved within the same process.\n *\n * `dir` is required when `backend` is `\"json\"` and ignored otherwise — `Workflow.create()` rejects\n * the options up front when it is missing or empty, rather than failing at the first suspend.\n */\nexport interface WorkflowPersistenceOptions {\n readonly backend: \"memory\" | \"json\";\n /** Required for `backend: \"json\"`. */\n readonly dir?: string;\n}\n\n/**\n * Configuration for `Workflow.create()`, validated by Zod before the builder is handed back: a `name`\n * outside 1..128 characters, or `persistence.backend: \"json\"` without a `dir`, throws there rather\n * than at run time.\n *\n * `name` is an observability and error-message label, not an identity. Two workflows may share one;\n * the identity behind the single-flight lock is minted per `.commit()` call, so two separately\n * committed workflows never block each other however they are named.\n *\n * The three schemas are independent and each optional: `inputSchema` guards `run(input)` before step\n * 1, `outputSchema` guards the final value on the completed path only (a suspended or failed run\n * skips it), and `stateSchema` guards `initialState` plus every `StepContext.setState()` call. All\n * three must be synchronous — a schema carrying an async refinement is reported as a validation\n * failure with that explanation, never awaited.\n */\nexport interface WorkflowOptions {\n readonly name: string;\n readonly persistence?: WorkflowPersistenceOptions;\n /**\n * SE27 — Zod schema for the WHOLE workflow's input. When set, `run(input)`\n * validates `input` BEFORE step 1; a mismatch yields `status: \"failed\"` with a\n * typed {@link WorkflowInputError} in `error` (fail-fast, no step runs, no\n * silent coerce). Absent ⇒ no whole-workflow input validation (unchanged).\n */\n readonly inputSchema?: ZodType;\n /**\n * SE27 — Zod schema for the workflow's final output. When set, the terminal\n * `completed` output is validated before `WorkflowRun.output` is populated; a\n * mismatch yields `status: \"failed\"` with a typed {@link WorkflowOutputError}.\n * Only validated on the `completed` path (suspended/failed runs skip it).\n */\n readonly outputSchema?: ZodType;\n /**\n * SE29 — Zod schema for the workflow's shared state (see `StepContext.state` /\n * `setState`). When set, `initialState` and every `setState(next)` are\n * validated against it (a mismatch throws {@link WorkflowStateError}). When\n * `initialState` is absent, `state` starts as `undefined` and validation fires\n * on the first `setState` call.\n */\n readonly stateSchema?: ZodType;\n /**\n * SE29 — the initial shared state, seeded onto `StepContext.state` before\n * step 1. Validated against `stateSchema` when both are set. Persisted across\n * suspend/resume.\n */\n readonly initialState?: unknown;\n /** Internal — minted at `.commit()`. Not user-facing. */\n readonly workflowId?: string;\n}\n\n/**\n * Per-run options for `Workflow.run()` and `Workflow.stream()`.\n *\n * `signal` is combined with the run's internal single-flight signal and reaches every step through\n * `StepContext.signal`. The executor itself checks it at step boundaries, so a step that ignores the\n * signal runs to completion before the run reports `status: \"cancelled\"` — a step doing long I/O\n * should pass `ctx.signal` down to make abort prompt.\n *\n * `runId` is minted per call (`wfr-` plus 8 hex) unless you pass it, which is why concurrent runs of\n * one workflow do not interfere. Pinning it buys a deterministic id for resume, and buys the\n * single-flight lock with it: starting a second run of the same committed workflow under a `runId`\n * that is still in flight throws {@link WorkflowAlreadyRunningError}.\n */\nexport interface WorkflowRunOptions {\n readonly signal?: AbortSignal;\n /** Override run ID for deterministic resume (advanced; default = mintRunId). */\n readonly runId?: string;\n /**\n * Opt-in Task wrapping (ADRs D363, D374). Registers the workflow run\n * as a `Task` (kind=\"workflow\") with a `wf-` namespaced id (D368,\n * EC-5). The task transitions terminal when `Workflow.run` resolves.\n *\n * Auto-id: `wf-{runId}`.\n *\n * @public\n */\n readonly task?: true | { id?: string; meta?: Record<string, unknown> };\n}\n\n/**\n * Arguments for `Workflow.resume()`.\n *\n * `workflow` is typed structurally as `{ run }`, but resume needs more than `run`: it reads the\n * committed steps and options off the instance and throws a plain `Error` — \"Workflow.resume requires\n * an instance from Workflow.create().commit()\" — for anything else. Pass the same committed\n * `Workflow` the suspended run came from, not a stand-in.\n *\n * `runId` selects the snapshot. An id with no snapshot throws\n * {@link WorkflowSnapshotNotFoundError}.\n *\n * `payload` becomes the input of the step after the suspend point, and is parsed against the\n * suspending step's `payloadSchema` first when it declared one (a mismatch throws out of `resume`).\n * Omit it to resume from the accumulated input captured in the snapshot instead — the two are\n * alternatives, not a merge.\n */\nexport interface WorkflowResumeOptions<TI = unknown> {\n readonly runId: string;\n readonly workflow: { run: (input: TI, opts?: WorkflowRunOptions) => Promise<WorkflowRun> };\n readonly payload?: unknown;\n readonly signal?: AbortSignal;\n}\n\n/* ─── Error classes ─── */\n\n/**\n * Thrown by `.commit()` when one step id appears twice anywhere in the workflow — including inside a\n * parallel branch, a branch predicate, the fallback, and the inner step of a `foreach` or `dowhile`.\n *\n * Ids address steps in snapshots and on resume, so this is refused at build time rather than\n * discovered mid-run. Workflows nested with `workflowStep()` are exempt: the child runs in its own\n * executor with its own id-space, so its ids cannot collide with the parent's.\n */\nexport class WorkflowDuplicateStepIdError extends Error {\n override readonly name = \"WorkflowDuplicateStepIdError\";\n constructor(public readonly stepId: string) {\n super(`Duplicate step id \"${stepId}\" in workflow.`);\n }\n}\n\n/**\n * SE27 — the whole-workflow `inputSchema` rejected `run(input)` (before step 1).\n * `detail` is a pre-formatted issues summary (a string, NOT Zod's `ZodIssue[]`).\n */\nexport class WorkflowInputError extends Error {\n override readonly name = \"WorkflowInputError\";\n constructor(\n public readonly workflowName: string,\n public readonly detail: string,\n ) {\n super(`Workflow \"${workflowName}\" input failed schema validation: ${detail}`);\n }\n}\n\n/**\n * SE27 — the whole-workflow `outputSchema` rejected the final output (on `completed`).\n * `detail` is a pre-formatted issues summary (a string, NOT Zod's `ZodIssue[]`).\n */\nexport class WorkflowOutputError extends Error {\n override readonly name = \"WorkflowOutputError\";\n constructor(\n public readonly workflowName: string,\n public readonly detail: string,\n ) {\n super(`Workflow \"${workflowName}\" output failed schema validation: ${detail}`);\n }\n}\n\n/**\n * SE29 — `WorkflowOptions.stateSchema` rejected an `initialState` or a\n * `setState(next)` call. `detail` is a pre-formatted issues summary.\n */\nexport class WorkflowStateError extends Error {\n override readonly name = \"WorkflowStateError\";\n constructor(\n public readonly workflowName: string,\n public readonly detail: string,\n ) {\n super(`Workflow \"${workflowName}\" state failed schema validation: ${detail}`);\n }\n}\n\n/**\n * SE30 — a nested workflow (via `workflowStep`) did not `complete`. A nested\n * `suspended` is NOT resumable in v1 (resume continues AFTER the step, so the\n * child would be skipped) — restructure with a top-level suspend. A nested\n * `failed`/`cancelled` fails the parent step with the child's error attached.\n */\nexport class WorkflowNestedError extends Error {\n override readonly name = \"WorkflowNestedError\";\n constructor(\n public readonly stepId: string,\n public readonly childName: string,\n public readonly childStatus: Exclude<WorkflowRun[\"status\"], \"completed\">,\n public readonly childError?: { name: string; message: string },\n ) {\n super(\n `Nested workflow \"${childName}\" (step \"${stepId}\") ended with status \"${childStatus}\"${\n childStatus === \"suspended\"\n ? \" — nested suspend/resume is not supported in v1 (use a top-level suspend)\"\n : \"\"\n }${childError ? `: ${childError.name}: ${childError.message}` : \"\"}`,\n // Reconstruct a synthetic Error from the serialized child-error shape so\n // debuggers surface the nested cause chain — the original Error instance is\n // lost at the WorkflowRun serialization boundary, so this is the best\n // achievable without changing the run protocol.\n childError\n ? { cause: Object.assign(new Error(childError.message), { name: childError.name }) }\n : undefined,\n );\n }\n}\n\n/**\n * Thrown out of `Workflow.run()` — one of the few workflow failures that rejects instead of arriving\n * as `run.status === \"failed\"` — when the committed workflow already has a run in flight under the\n * same run id.\n *\n * The lock key pairs the id minted at `.commit()` with the run id, not `WorkflowOptions.name`, so\n * two workflows sharing a name are independent and concurrent runs with distinct minted ids never\n * collide. In practice this only fires when a caller pins `WorkflowRunOptions.runId`, or resumes a\n * run id that is still executing. The registry is an in-process map: a crash releases every lock, and\n * it says nothing about runs in other processes.\n */\nexport class WorkflowAlreadyRunningError extends Error {\n override readonly name = \"WorkflowAlreadyRunningError\";\n constructor(\n public readonly workflowName: string,\n public readonly runId: string,\n ) {\n super(`Workflow \"${workflowName}\" run \"${runId}\" already in-flight.`);\n }\n}\n\n/**\n * Thrown by `Workflow.resume()` when no snapshot exists for the given run id.\n *\n * The message suggests configuring persistence, which is the common cause but not the only one. The\n * run may never have suspended; it may have suspended under the default memory backend in a process\n * that has since exited; or the snapshot may already have been consumed, since resume deletes it\n * before re-entering the executor and a second resume of the same run id lands here.\n */\nexport class WorkflowSnapshotNotFoundError extends Error {\n override readonly name = \"WorkflowSnapshotNotFoundError\";\n constructor(public readonly runId: string) {\n super(`No snapshot found for runId \"${runId}\". Configure persistence to enable resume.`);\n }\n}\n\n/**\n * Raised when a `dowhile` step's condition kept returning true past `maxIterations` (default 100).\n *\n * It does not escape `run()`: the step fails, the run ends `status: \"failed\"`, and the error reaches\n * the caller flattened as `run.error` with `name: \"WorkflowMaxIterationsExceededError\"` — match on\n * the name, the instance does not survive. The guard is evaluated before each iteration, so the inner\n * step runs at most `maxIterations` times; raising the ceiling is a `maxIterations` on the step, and\n * there is no global default to change.\n */\nexport class WorkflowMaxIterationsExceededError extends Error {\n override readonly name = \"WorkflowMaxIterationsExceededError\";\n constructor(\n public readonly stepId: string,\n public readonly maxIterations: number,\n ) {\n super(`Step \"${stepId}\" exceeded max iterations (${maxIterations}).`);\n }\n}\n\n/** EC-4 absorbed — JSON.stringify failed on snapshot payload. */\nexport class WorkflowNotSerializableError extends Error {\n override readonly name = \"WorkflowNotSerializableError\";\n constructor(\n public readonly stepId: string,\n public readonly underlying: Error,\n ) {\n super(\n `Workflow snapshot at step \"${stepId}\" failed to serialize as JSON: ${underlying.message}. ` +\n `Persisted snapshots support only JSON-serializable values (no BigInt, no circular refs, no class instances with cycles).`,\n );\n }\n}\n\n/** EC-8 absorbed — `currentStepId` from snapshot not found in resumed workflow. */\nexport class WorkflowResumeStepNotFoundError extends Error {\n override readonly name = \"WorkflowResumeStepNotFoundError\";\n constructor(\n public readonly stepId: string,\n public readonly workflowName: string,\n ) {\n super(\n `Cannot resume: step \"${stepId}\" not found in workflow \"${workflowName}\". ` +\n `The Workflow definition diverged from the snapshot.`,\n );\n }\n}\n\n/** Aggregate failure from parallel branches. */\nexport class WorkflowParallelError extends AggregateError {\n override readonly name = \"WorkflowParallelError\";\n constructor(\n errors: ReadonlyArray<Error>,\n public readonly stepId: string,\n ) {\n super(errors, `${errors.length} branch(es) failed in parallel step \"${stepId}\".`);\n }\n}\n\n/** D238 — saga engine not yet implemented. */\nexport class WorkflowCompensateNotImplementedError extends Error {\n override readonly name = \"WorkflowCompensateNotImplementedError\";\n constructor(public readonly stepId: string) {\n super(\n `Step \"${stepId}\" defines compensate, but saga engine is deferred to v1.2. ` +\n `Remove compensate or implement rollback manually.`,\n );\n }\n}\n","/**\n * Snapshot store interface + InMemory and JsonFile backends (ADR D235).\n *\n * EC-4 absorbed: serialization happens here. `JSON.stringify` failure raises\n * `WorkflowNotSerializableError` instead of letting the underlying `TypeError`\n * leak.\n *\n * @internal\n */\n\nimport { mkdir, readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n WorkflowNotSerializableError,\n type WorkflowOptions,\n type WorkflowSnapshot,\n} from \"../../types/workflow.js\";\nimport { atomicWriteText } from \"../persistence/atomic-write.js\";\n\nexport interface WorkflowSnapshotStore {\n save(snapshot: WorkflowSnapshot): Promise<void>;\n load(runId: string): Promise<WorkflowSnapshot | undefined>;\n delete(runId: string): Promise<void>;\n list(\n workflowName?: string,\n ): Promise<ReadonlyArray<{ runId: string; workflowName: string; suspendedAt: number }>>;\n}\n\n/* ─── InMemory backend (default) ─── */\n\nclass InMemoryWorkflowSnapshotStore implements WorkflowSnapshotStore {\n private readonly map = new Map<string, WorkflowSnapshot>();\n\n async save(snapshot: WorkflowSnapshot): Promise<void> {\n // Verify serializability even in-memory so behavior is consistent with json backend.\n try {\n JSON.stringify(snapshot);\n } catch (err) {\n throw new WorkflowNotSerializableError(\n snapshot.currentStepId,\n err instanceof Error ? err : new Error(String(err)),\n );\n }\n this.map.set(snapshot.runId, snapshot);\n }\n async load(runId: string): Promise<WorkflowSnapshot | undefined> {\n return this.map.get(runId);\n }\n async delete(runId: string): Promise<void> {\n this.map.delete(runId);\n }\n async list(\n workflowName?: string,\n ): Promise<ReadonlyArray<{ runId: string; workflowName: string; suspendedAt: number }>> {\n return [...this.map.values()]\n .filter((s) => workflowName === undefined || s.workflowName === workflowName)\n .map((s) => ({\n runId: s.runId,\n workflowName: s.workflowName,\n suspendedAt: s.suspendedAt,\n }));\n }\n}\n\n/* ─── Json file backend (opt-in) ─── */\n\nclass JsonFileWorkflowSnapshotStore implements WorkflowSnapshotStore {\n constructor(private readonly dir: string) {}\n\n private filePath(runId: string): string {\n return join(this.dir, `${runId}.json`);\n }\n\n async save(snapshot: WorkflowSnapshot): Promise<void> {\n let serialized: string;\n try {\n serialized = JSON.stringify(snapshot);\n } catch (err) {\n throw new WorkflowNotSerializableError(\n snapshot.currentStepId,\n err instanceof Error ? err : new Error(String(err)),\n );\n }\n await mkdir(this.dir, { recursive: true });\n await atomicWriteText(this.filePath(snapshot.runId), serialized);\n }\n\n async load(runId: string): Promise<WorkflowSnapshot | undefined> {\n try {\n const raw = await readFile(this.filePath(runId), \"utf8\");\n return JSON.parse(raw) as WorkflowSnapshot;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw err;\n }\n }\n\n async delete(runId: string): Promise<void> {\n try {\n await (await import(\"node:fs/promises\")).unlink(this.filePath(runId));\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n }\n }\n\n private async readEntriesOrEmpty(): Promise<string[]> {\n try {\n return await readdir(this.dir);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw err;\n }\n }\n\n private async readSnapshotSafe(file: string): Promise<WorkflowSnapshot | undefined> {\n try {\n const raw = await readFile(join(this.dir, file), \"utf8\");\n return JSON.parse(raw) as WorkflowSnapshot;\n } catch {\n return undefined;\n }\n }\n\n async list(\n workflowName?: string,\n ): Promise<ReadonlyArray<{ runId: string; workflowName: string; suspendedAt: number }>> {\n const entries = await this.readEntriesOrEmpty();\n const results: Array<{ runId: string; workflowName: string; suspendedAt: number }> = [];\n for (const file of entries) {\n if (!file.endsWith(\".json\")) continue;\n const snap = await this.readSnapshotSafe(file);\n if (snap === undefined) continue;\n if (workflowName !== undefined && snap.workflowName !== workflowName) continue;\n results.push({\n runId: snap.runId,\n workflowName: snap.workflowName,\n suspendedAt: snap.suspendedAt,\n });\n }\n return results;\n }\n}\n\n/* ─── Resolver: per-Workflow store cache ─── */\n\nconst memoryStore = new InMemoryWorkflowSnapshotStore();\nconst jsonStores = new Map<string, JsonFileWorkflowSnapshotStore>();\n\nexport function getSnapshotStoreFor(options: WorkflowOptions): WorkflowSnapshotStore {\n if (options.persistence?.backend === \"json\") {\n const dir = options.persistence.dir as string; // schema enforces dir is set\n let store = jsonStores.get(dir);\n if (store === undefined) {\n store = new JsonFileWorkflowSnapshotStore(dir);\n jsonStores.set(dir, store);\n }\n return store;\n }\n return memoryStore;\n}\n\n/** Test seam — clear in-memory store between tests. */\nexport function __resetSnapshotStoresForTests(): void {\n jsonStores.clear();\n // memoryStore has private map; reset via assignment.\n // biome-ignore lint/suspicious/noExplicitAny: test-only seam\n (memoryStore as any).map.clear();\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthenticationError } from './chunk-
|
|
1
|
+
import { AuthenticationError } from './chunk-ZZMZWBR6.js';
|
|
2
2
|
import { randomBytes } from 'crypto';
|
|
3
3
|
import { statSync, readFileSync, mkdirSync, chmodSync, openSync, writeFileSync, fsyncSync, closeSync, renameSync, unlinkSync } from 'fs';
|
|
4
4
|
import { join } from 'path';
|
|
@@ -143,5 +143,5 @@ function writeCredential(cred, config, env = {}) {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
export { CredentialError, assertSecureModes, authFilePath, credentialHome, readAuthFile, readStoredOAuth, writeCredential };
|
|
146
|
-
//# sourceMappingURL=chunk-
|
|
147
|
-
//# sourceMappingURL=chunk-
|
|
146
|
+
//# sourceMappingURL=chunk-C3NT3PVE.js.map
|
|
147
|
+
//# sourceMappingURL=chunk-C3NT3PVE.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/auth/credential-store.ts"],"names":[],"mappings":"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","file":"chunk-UQGQFBRL.js","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n closeSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { z } from \"zod\";\n\nimport { AuthenticationError } from \"../../errors.js\";\n\n/**\n * M42 — the SDK credential store. Promoted DOWN from agent-builder's hardened `agents/lib/credentials.ts`\n * (M37), generalized from a closed `openrouter|anthropic|openai` union to an open `provider: string` and\n * driven by a caller-supplied {@link CredentialStoreConfig} (no hardcoded `.agent-builder`/`auth.json` /\n * `AGENT_BUILDER_HOME`). The security-critical file mechanics are ported VERBATIM (ADR D3 of the M42 plan):\n * atomic O_EXCL + rename + fsync write, 0700/0600 mode gates, `env` is always a PARAMETER (never an ambient\n * `process.env` read).\n *\n * The env-precedence + key-prefix-inference + declared-provider rungs of the agent-builder resolver are\n * APP POLICY and deliberately stay UP in the consumer; this module owns only the on-disk store + the\n * `api|oauth` discriminated union. See {@link resolveCredential} (SDK) for the store-read + refresh path.\n *\n * Re-exported from `@theokit/sdk/auth`, and therefore PUBLIC, under semver.\n *\n * NOTE — no internal-visibility tag in this block. `tsconfig.base.json` sets `stripInternal: true`,\n * and TypeScript scans EVERY leading comment range of the declaration that follows, including the\n * import right below this one. The tag that used to sit here deleted that import from the emitted\n * `.d.ts`, leaving the types it binds unresolvable for any consumer running type-aware lint\n * (usetheodev/theokit-sdk#283 records the same trap on a declaration).\n */\nimport type {\n CredentialStoreConfig,\n StoredCredential,\n StoredOAuthCredential,\n} from \"./auth-types.js\";\n\n/** The store directory, honoring an optional `homeEnvVar` override. */\nexport function credentialHome(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const override = config.homeEnvVar !== undefined ? env[config.homeEnvVar]?.trim() : undefined;\n return override !== undefined && override.length > 0\n ? override\n : join(config.home, config.dirName);\n}\n\n/** The credential file path inside the (possibly overridden) store directory. */\nexport function authFilePath(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n return join(credentialHome(config, env), config.fileName);\n}\n\n/**\n * A credential problem the caller can act on. Never carries the key value.\n *\n * M78 — this used to extend bare `Error`, which quietly disabled classification for the entire auth\n * path: `isTransientError` is `err instanceof TheokitAgentError && err.isRetryable === true`\n * (`errors.ts:443`), so a credential failure could never be judged transient OR permanent. The\n * predicate was not \"forgotten\" downstream — it was unusable there by construction.\n *\n * Extending `AuthenticationError` is ADDITIVE: the class still exists, still reports\n * `name: \"CredentialError\"`, and every existing `instanceof CredentialError` stays true. It only\n * gains ancestors. `AuthenticationError` pins `isRetryable: false`, so gaining the ability to be\n * classified does NOT turn a revoked credential into a retry loop.\n *\n * The single reference does the same thing with one root type: Codex routes every domain failure\n * through `CodexErr` with `is_retryable()` as a method (`protocol/src/error.rs:176`), rather than\n * parallel classes extending the language's `Error`.\n */\nexport class CredentialError extends AuthenticationError {\n // Field, not an assignment in the constructor: `AuthenticationError.name` is `override readonly`\n // (`errors.ts:174`), so `this.name = …` does not compile. Caught by `tsc`, not by vitest — the\n // suite was green with the broken assignment because the transpiler strips the type.\n override readonly name: string = \"CredentialError\";\n}\n\n/**\n * The on-disk store — a discriminated union on `type`. A legacy file with NO\n * `type` (or `type: 'api'`) is the API-key variant — read unchanged, no migration. The `oauth` variant\n * carries the token pair + expiry.\n */\nconst apiFileSchema = z\n .object({\n type: z.literal(\"api\").optional(),\n provider: z.string().min(1).optional(),\n api_key: z.string(),\n })\n .strict();\n\nconst oauthFileSchema = z\n .object({\n type: z.literal(\"oauth\"),\n provider: z.string().min(1),\n access: z.string().min(1),\n refresh: z.string().min(1),\n expires: z.number(),\n account_id: z.string().optional(),\n })\n .strict();\n\n// oauth first (it requires `type: 'oauth'`); a legacy `{provider?, api_key}` falls through to api.\nconst fileSchema = z.union([oauthFileSchema, apiFileSchema]);\n\n/**\n * The 0700-dir / 0600-file mode gates (ported verbatim). The DIRECTORY matters as much as the file:\n * `mkdirSync(mode)` applies only at creation, so a pre-existing store dir keeps whatever mode it had, and a\n * writable dir lets an attacker replace the credential file with a symlink to their own 0600 file — the\n * agent then runs on THEIR account.\n */\nexport function assertSecureModes(dirPath: string, path: string): void {\n // Windows has no POSIX mode bits. `statSync().mode` there is SYNTHETIC — 0666 for any writable\n // entry, whatever the ACLs actually say — so `mode & 0o022` was non-zero for every valid store and\n // this gate refused all of them, which made the credential path unreadable on that platform\n // rather than protected. A check that cannot observe the real permission system must not report a\n // verdict about it; ACL enforcement is a separate mechanism and not one this function can fake.\n if (process.platform === \"win32\") return;\n\n const dirMode = statSync(dirPath).mode & 0o777;\n if ((dirMode & 0o022) !== 0) {\n throw new CredentialError(\n `${dirPath} is writable by other users (mode ${dirMode.toString(8)}), so the credential file ` +\n `inside it can be replaced. Fix it with: chmod 700 ${dirPath}`,\n );\n }\n const mode = statSync(path).mode & 0o777;\n if ((mode & 0o077) !== 0) {\n throw new CredentialError(\n `${path} is readable by other users (mode ${mode.toString(8)}). ` +\n `A credential file must not be. Fix it with: chmod 600 ${path}`,\n );\n }\n}\n\n/**\n * A `z.union` reports a generic \"Invalid input\" at the root, hiding WHAT is wrong. Pick the sub-schema the\n * file was CLEARLY aiming at (by its `type` discriminant) and surface that schema's specific issue.\n */\nfunction describeUnionError(parsed: unknown, err: unknown, path: string): CredentialError {\n const looksOAuth =\n typeof parsed === \"object\" &&\n parsed !== null &&\n (parsed as { type?: unknown }).type === \"oauth\";\n const specific = looksOAuth ? oauthFileSchema.safeParse(parsed) : apiFileSchema.safeParse(parsed);\n let issue: z.ZodIssue | undefined;\n if (!specific.success) {\n issue = specific.error.issues[0];\n } else if (err instanceof z.ZodError) {\n issue = err.issues[0];\n }\n return new CredentialError(\n `${path}: ${issue?.message ?? String(err)} [${issue?.path.join(\".\") || \"root\"}]`,\n );\n}\n\n/** Parse the raw file into the store union, surfacing the SPECIFIC sub-schema issue (not a generic union error). */\nfunction parseStoredFile(raw: string, path: string): StoredCredential {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // The parser's message embeds a snippet of the INPUT — up to the raw key when a user pastes the bare\n // key instead of JSON. The position is not actionable anyway, so the expected shape is more useful.\n throw new CredentialError(\n `${path} is not valid JSON. Expected: {\"provider\": \"<name>\", \"api_key\": \"...\"}`,\n );\n }\n try {\n return fileSchema.parse(parsed);\n } catch (err) {\n throw describeUnionError(parsed, err, path);\n }\n}\n\n/**\n * Read the credential file. Absent ⇒ `undefined` (the normal case). Present-but-wrong is a typed error\n * naming the file: a malformed credential store must not surface as a raw parse crash. Enforces the\n * 0700 dir / 0600 file mode gates (ported verbatim — a writable dir lets an attacker swap the file for a\n * symlink to their own account).\n */\nexport function readAuthFile(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredCredential | undefined {\n const path = authFilePath(config, env);\n\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw new CredentialError(`cannot read ${path}: ${(err as Error).message}`);\n }\n\n assertSecureModes(credentialHome(config, env), path);\n return parseStoredFile(raw, path);\n}\n\n/**\n * Read the stored OAuth credential (with its refresh token), or `undefined` when the store is absent or\n * holds an api credential. The oauth engine needs the refresh token, which the resolved bearer does not\n * carry. Enforces the same 0600/0700 gates as every other read.\n */\nexport function readStoredOAuth(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredOAuthCredential | undefined {\n const stored = readAuthFile(config, env);\n return stored !== undefined && stored.type === \"oauth\" ? stored : undefined;\n}\n\n/** Narrows a writable credential to the oauth variant. */\nfunction isOAuthWrite(\n c: { provider: string; apiKey: string } | StoredOAuthCredential,\n): c is StoredOAuthCredential {\n return \"type\" in c && c.type === \"oauth\";\n}\n\n/** Build the on-disk JSON payload for the credential variant, validating non-empty tokens. */\nfunction buildStorePayload(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n): Record<string, unknown> {\n if (isOAuthWrite(cred)) {\n if (cred.access.length === 0 || cred.refresh.length === 0) {\n throw new CredentialError(\n \"refusing to write an oauth credential with an empty access/refresh token\",\n );\n }\n return {\n type: \"oauth\",\n provider: cred.provider,\n access: cred.access,\n refresh: cred.refresh,\n expires: cred.expires,\n ...(cred.account_id !== undefined ? { account_id: cred.account_id } : {}),\n };\n }\n if (typeof cred.apiKey !== \"string\" || cred.apiKey.length === 0) {\n throw new CredentialError(\"refusing to write an empty API key\");\n }\n return { provider: cred.provider, api_key: cred.apiKey };\n}\n\n/**\n * Persist a credential atomically at mode `0600`. Ported VERBATIM (ADR D3): write to a random-named temp\n * file in the same directory with `wx` (O_EXCL), fsync, close, chmod, then `rename` (atomic on POSIX) —\n * so a crash mid-write leaves whatever was there untouched, and a pre-planted symlink cannot capture the\n * key. The api variant persists the unchanged `{provider, api_key}` (back-compat, no `type` key); the\n * oauth variant persists `{type:'oauth', provider, access, refresh, expires, account_id?}`.\n */\nexport function writeCredential(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const payload = buildStorePayload(cred);\n\n const dir = credentialHome(config, env);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n chmodSync(dir, 0o700); // unconditional: mkdirSync's mode applies only at creation\n\n const path = authFilePath(config, env);\n // RANDOM name + `wx` (O_EXCL): a predictable temp name with a plain write follows a pre-planted SYMLINK,\n // landing the key in an attacker's file while reporting success. O_EXCL refuses any pre-existing file or\n // link; the random suffix also removes the pid collision two containers sharing a bind-mounted home make.\n const tmp = `${path}.tmp-${randomBytes(8).toString(\"hex\")}`;\n try {\n const fd = openSync(tmp, \"wx\", 0o600);\n try {\n writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\\n`);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n chmodSync(tmp, 0o600); // explicit: the mode argument is subject to umask\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // the temp file may not exist; its absence is not a failure of the write\n }\n throw new CredentialError(`cannot write ${path}: ${(err as Error).message}`);\n }\n return path;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/auth/credential-store.ts"],"names":[],"mappings":"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","file":"chunk-C3NT3PVE.js","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n closeSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { z } from \"zod\";\n\nimport { AuthenticationError } from \"../../errors.js\";\n\n/**\n * M42 — the SDK credential store. Promoted DOWN from agent-builder's hardened `agents/lib/credentials.ts`\n * (M37), generalized from a closed `openrouter|anthropic|openai` union to an open `provider: string` and\n * driven by a caller-supplied {@link CredentialStoreConfig} (no hardcoded `.agent-builder`/`auth.json` /\n * `AGENT_BUILDER_HOME`). The security-critical file mechanics are ported VERBATIM (ADR D3 of the M42 plan):\n * atomic O_EXCL + rename + fsync write, 0700/0600 mode gates, `env` is always a PARAMETER (never an ambient\n * `process.env` read).\n *\n * The env-precedence + key-prefix-inference + declared-provider rungs of the agent-builder resolver are\n * APP POLICY and deliberately stay UP in the consumer; this module owns only the on-disk store + the\n * `api|oauth` discriminated union. See {@link resolveCredential} (SDK) for the store-read + refresh path.\n *\n * Re-exported from `@theokit/sdk/auth`, and therefore PUBLIC, under semver.\n *\n * NOTE — no internal-visibility tag in this block. `tsconfig.base.json` sets `stripInternal: true`,\n * and TypeScript scans EVERY leading comment range of the declaration that follows, including the\n * import right below this one. The tag that used to sit here deleted that import from the emitted\n * `.d.ts`, leaving the types it binds unresolvable for any consumer running type-aware lint\n * (usetheodev/theokit-sdk#283 records the same trap on a declaration).\n */\nimport type {\n CredentialStoreConfig,\n StoredCredential,\n StoredOAuthCredential,\n} from \"./auth-types.js\";\n\n/** The store directory, honoring an optional `homeEnvVar` override. */\nexport function credentialHome(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const override = config.homeEnvVar !== undefined ? env[config.homeEnvVar]?.trim() : undefined;\n return override !== undefined && override.length > 0\n ? override\n : join(config.home, config.dirName);\n}\n\n/** The credential file path inside the (possibly overridden) store directory. */\nexport function authFilePath(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n return join(credentialHome(config, env), config.fileName);\n}\n\n/**\n * A credential problem the caller can act on. Never carries the key value.\n *\n * M78 — this used to extend bare `Error`, which quietly disabled classification for the entire auth\n * path: `isTransientError` is `err instanceof TheokitAgentError && err.isRetryable === true`\n * (`errors.ts:443`), so a credential failure could never be judged transient OR permanent. The\n * predicate was not \"forgotten\" downstream — it was unusable there by construction.\n *\n * Extending `AuthenticationError` is ADDITIVE: the class still exists, still reports\n * `name: \"CredentialError\"`, and every existing `instanceof CredentialError` stays true. It only\n * gains ancestors. `AuthenticationError` pins `isRetryable: false`, so gaining the ability to be\n * classified does NOT turn a revoked credential into a retry loop.\n *\n * The single reference does the same thing with one root type: Codex routes every domain failure\n * through `CodexErr` with `is_retryable()` as a method (`protocol/src/error.rs:176`), rather than\n * parallel classes extending the language's `Error`.\n */\nexport class CredentialError extends AuthenticationError {\n // Field, not an assignment in the constructor: `AuthenticationError.name` is `override readonly`\n // (`errors.ts:174`), so `this.name = …` does not compile. Caught by `tsc`, not by vitest — the\n // suite was green with the broken assignment because the transpiler strips the type.\n override readonly name: string = \"CredentialError\";\n}\n\n/**\n * The on-disk store — a discriminated union on `type`. A legacy file with NO\n * `type` (or `type: 'api'`) is the API-key variant — read unchanged, no migration. The `oauth` variant\n * carries the token pair + expiry.\n */\nconst apiFileSchema = z\n .object({\n type: z.literal(\"api\").optional(),\n provider: z.string().min(1).optional(),\n api_key: z.string(),\n })\n .strict();\n\nconst oauthFileSchema = z\n .object({\n type: z.literal(\"oauth\"),\n provider: z.string().min(1),\n access: z.string().min(1),\n refresh: z.string().min(1),\n expires: z.number(),\n account_id: z.string().optional(),\n })\n .strict();\n\n// oauth first (it requires `type: 'oauth'`); a legacy `{provider?, api_key}` falls through to api.\nconst fileSchema = z.union([oauthFileSchema, apiFileSchema]);\n\n/**\n * The 0700-dir / 0600-file mode gates (ported verbatim). The DIRECTORY matters as much as the file:\n * `mkdirSync(mode)` applies only at creation, so a pre-existing store dir keeps whatever mode it had, and a\n * writable dir lets an attacker replace the credential file with a symlink to their own 0600 file — the\n * agent then runs on THEIR account.\n */\nexport function assertSecureModes(dirPath: string, path: string): void {\n // Windows has no POSIX mode bits. `statSync().mode` there is SYNTHETIC — 0666 for any writable\n // entry, whatever the ACLs actually say — so `mode & 0o022` was non-zero for every valid store and\n // this gate refused all of them, which made the credential path unreadable on that platform\n // rather than protected. A check that cannot observe the real permission system must not report a\n // verdict about it; ACL enforcement is a separate mechanism and not one this function can fake.\n if (process.platform === \"win32\") return;\n\n const dirMode = statSync(dirPath).mode & 0o777;\n if ((dirMode & 0o022) !== 0) {\n throw new CredentialError(\n `${dirPath} is writable by other users (mode ${dirMode.toString(8)}), so the credential file ` +\n `inside it can be replaced. Fix it with: chmod 700 ${dirPath}`,\n );\n }\n const mode = statSync(path).mode & 0o777;\n if ((mode & 0o077) !== 0) {\n throw new CredentialError(\n `${path} is readable by other users (mode ${mode.toString(8)}). ` +\n `A credential file must not be. Fix it with: chmod 600 ${path}`,\n );\n }\n}\n\n/**\n * A `z.union` reports a generic \"Invalid input\" at the root, hiding WHAT is wrong. Pick the sub-schema the\n * file was CLEARLY aiming at (by its `type` discriminant) and surface that schema's specific issue.\n */\nfunction describeUnionError(parsed: unknown, err: unknown, path: string): CredentialError {\n const looksOAuth =\n typeof parsed === \"object\" &&\n parsed !== null &&\n (parsed as { type?: unknown }).type === \"oauth\";\n const specific = looksOAuth ? oauthFileSchema.safeParse(parsed) : apiFileSchema.safeParse(parsed);\n let issue: z.ZodIssue | undefined;\n if (!specific.success) {\n issue = specific.error.issues[0];\n } else if (err instanceof z.ZodError) {\n issue = err.issues[0];\n }\n return new CredentialError(\n `${path}: ${issue?.message ?? String(err)} [${issue?.path.join(\".\") || \"root\"}]`,\n );\n}\n\n/** Parse the raw file into the store union, surfacing the SPECIFIC sub-schema issue (not a generic union error). */\nfunction parseStoredFile(raw: string, path: string): StoredCredential {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // The parser's message embeds a snippet of the INPUT — up to the raw key when a user pastes the bare\n // key instead of JSON. The position is not actionable anyway, so the expected shape is more useful.\n throw new CredentialError(\n `${path} is not valid JSON. Expected: {\"provider\": \"<name>\", \"api_key\": \"...\"}`,\n );\n }\n try {\n return fileSchema.parse(parsed);\n } catch (err) {\n throw describeUnionError(parsed, err, path);\n }\n}\n\n/**\n * Read the credential file. Absent ⇒ `undefined` (the normal case). Present-but-wrong is a typed error\n * naming the file: a malformed credential store must not surface as a raw parse crash. Enforces the\n * 0700 dir / 0600 file mode gates (ported verbatim — a writable dir lets an attacker swap the file for a\n * symlink to their own account).\n */\nexport function readAuthFile(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredCredential | undefined {\n const path = authFilePath(config, env);\n\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw new CredentialError(`cannot read ${path}: ${(err as Error).message}`);\n }\n\n assertSecureModes(credentialHome(config, env), path);\n return parseStoredFile(raw, path);\n}\n\n/**\n * Read the stored OAuth credential (with its refresh token), or `undefined` when the store is absent or\n * holds an api credential. The oauth engine needs the refresh token, which the resolved bearer does not\n * carry. Enforces the same 0600/0700 gates as every other read.\n */\nexport function readStoredOAuth(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredOAuthCredential | undefined {\n const stored = readAuthFile(config, env);\n return stored !== undefined && stored.type === \"oauth\" ? stored : undefined;\n}\n\n/** Narrows a writable credential to the oauth variant. */\nfunction isOAuthWrite(\n c: { provider: string; apiKey: string } | StoredOAuthCredential,\n): c is StoredOAuthCredential {\n return \"type\" in c && c.type === \"oauth\";\n}\n\n/** Build the on-disk JSON payload for the credential variant, validating non-empty tokens. */\nfunction buildStorePayload(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n): Record<string, unknown> {\n if (isOAuthWrite(cred)) {\n if (cred.access.length === 0 || cred.refresh.length === 0) {\n throw new CredentialError(\n \"refusing to write an oauth credential with an empty access/refresh token\",\n );\n }\n return {\n type: \"oauth\",\n provider: cred.provider,\n access: cred.access,\n refresh: cred.refresh,\n expires: cred.expires,\n ...(cred.account_id !== undefined ? { account_id: cred.account_id } : {}),\n };\n }\n if (typeof cred.apiKey !== \"string\" || cred.apiKey.length === 0) {\n throw new CredentialError(\"refusing to write an empty API key\");\n }\n return { provider: cred.provider, api_key: cred.apiKey };\n}\n\n/**\n * Persist a credential atomically at mode `0600`. Ported VERBATIM (ADR D3): write to a random-named temp\n * file in the same directory with `wx` (O_EXCL), fsync, close, chmod, then `rename` (atomic on POSIX) —\n * so a crash mid-write leaves whatever was there untouched, and a pre-planted symlink cannot capture the\n * key. The api variant persists the unchanged `{provider, api_key}` (back-compat, no `type` key); the\n * oauth variant persists `{type:'oauth', provider, access, refresh, expires, account_id?}`.\n */\nexport function writeCredential(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const payload = buildStorePayload(cred);\n\n const dir = credentialHome(config, env);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n chmodSync(dir, 0o700); // unconditional: mkdirSync's mode applies only at creation\n\n const path = authFilePath(config, env);\n // RANDOM name + `wx` (O_EXCL): a predictable temp name with a plain write follows a pre-planted SYMLINK,\n // landing the key in an attacker's file while reporting success. O_EXCL refuses any pre-existing file or\n // link; the random suffix also removes the pid collision two containers sharing a bind-mounted home make.\n const tmp = `${path}.tmp-${randomBytes(8).toString(\"hex\")}`;\n try {\n const fd = openSync(tmp, \"wx\", 0o600);\n try {\n writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\\n`);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n chmodSync(tmp, 0o600); // explicit: the mode argument is subject to umask\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // the temp file may not exist; its absence is not a failure of the write\n }\n throw new CredentialError(`cannot write ${path}: ${(err as Error).message}`);\n }\n return path;\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSemaphore } from './chunk-
|
|
1
|
+
import { createSemaphore } from './chunk-4QZSA2HJ.js';
|
|
2
2
|
|
|
3
3
|
// src/internal/runtime/concurrency/map-with-concurrency.ts
|
|
4
4
|
var NEVER_ABORT = new AbortController().signal;
|
|
@@ -21,5 +21,5 @@ async function mapWithConcurrency(items, concurrency, fn, options) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export { mapWithConcurrency };
|
|
24
|
-
//# sourceMappingURL=chunk-
|
|
25
|
-
//# sourceMappingURL=chunk-
|
|
24
|
+
//# sourceMappingURL=chunk-C72AZW7J.js.map
|
|
25
|
+
//# sourceMappingURL=chunk-C72AZW7J.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/runtime/concurrency/map-with-concurrency.ts"],"names":[],"mappings":";;;AAcA,IAAM,WAAA,GAA2B,IAAI,eAAA,EAAgB,CAAE,MAAA;AAgBvD,eAAsB,kBAAA,CACpB,KAAA,EACA,WAAA,EACA,EAAA,EACA,OAAA,EACc;AACd,EAAA,MAAM,SAAA,GAAY,gBAAgB,WAAW,CAAA;AAC7C,EAAA,MAAM,MAAA,GAAS,SAAS,MAAA,IAAU,WAAA;AAClC,EAAA,OAAO,OAAA,CAAQ,GAAA;AAAA,IACb,KAAA,CAAM,GAAA,CAAI,OAAO,IAAA,EAAM,KAAA,KAAU;AAC/B,MAAA,MAAM,OAAA,GAAU,MAAM,SAAA,CAAU,OAAA,EAAQ;AACxC,MAAA,IAAI;AACF,QAAA,IAAI,OAAO,OAAA,EAAS;AAClB,UAAA,MAAM,OAAO,MAAA,YAAkB,KAAA,GAC3B,OAAO,MAAA,GACP,IAAI,MAAM,6BAA6B,CAAA;AAAA,QAC7C;AACA,QAAA,OAAO,MAAM,EAAA,CAAG,IAAA,EAAM,KAAA,EAAO,MAAM,CAAA;AAAA,MACrC,CAAA,SAAE;AACA,QAAA,OAAA,EAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,GACH;AACF","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/internal/runtime/concurrency/map-with-concurrency.ts"],"names":[],"mappings":";;;AAcA,IAAM,WAAA,GAA2B,IAAI,eAAA,EAAgB,CAAE,MAAA;AAgBvD,eAAsB,kBAAA,CACpB,KAAA,EACA,WAAA,EACA,EAAA,EACA,OAAA,EACc;AACd,EAAA,MAAM,SAAA,GAAY,gBAAgB,WAAW,CAAA;AAC7C,EAAA,MAAM,MAAA,GAAS,SAAS,MAAA,IAAU,WAAA;AAClC,EAAA,OAAO,OAAA,CAAQ,GAAA;AAAA,IACb,KAAA,CAAM,GAAA,CAAI,OAAO,IAAA,EAAM,KAAA,KAAU;AAC/B,MAAA,MAAM,OAAA,GAAU,MAAM,SAAA,CAAU,OAAA,EAAQ;AACxC,MAAA,IAAI;AACF,QAAA,IAAI,OAAO,OAAA,EAAS;AAClB,UAAA,MAAM,OAAO,MAAA,YAAkB,KAAA,GAC3B,OAAO,MAAA,GACP,IAAI,MAAM,6BAA6B,CAAA;AAAA,QAC7C;AACA,QAAA,OAAO,MAAM,EAAA,CAAG,IAAA,EAAM,KAAA,EAAO,MAAM,CAAA;AAAA,MACrC,CAAA,SAAE;AACA,QAAA,OAAA,EAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,GACH;AACF","file":"chunk-C72AZW7J.js","sourcesContent":["/**\n * Ordered, bounded-concurrency parallel map (plan m0-foundation-expose-primitives, M0-2).\n *\n * Runs `fn` over `items` with at most `concurrency` invocations in flight at\n * once, preserving input order in the result array. Fail-fast: rejects with the\n * first error a task throws (matching the in-house `boundedParallel`/`runBatches`\n * clones this consolidates). Backed by the in-house {@link createSemaphore}\n * (ADR D135 — no `p-limit`/`p-map` dependency).\n *\n * @internal — public via `@theokit/sdk/concurrency`\n */\n\nimport { createSemaphore } from \"./async-semaphore.js\";\n\nconst NEVER_ABORT: AbortSignal = new AbortController().signal;\n\n/**\n * Map `fn` over `items` with bounded concurrency, preserving order.\n *\n * @param items - inputs to process\n * @param concurrency - max in-flight invocations (positive integer; validated)\n * @param fn - async mapper; receives the item, its index, and an abort signal\n * @param options.signal - optional abort signal; once aborted, no new `fn`\n * invocation is started (in-flight ones are not force-cancelled)\n * @returns results in the same order as `items`\n * @throws ConfigurationError when `concurrency` is not a positive integer\n *\n * @example\n * await mapWithConcurrency([1, 2, 3], 2, async (n) => n * 2); // [2, 4, 6]\n */\nexport async function mapWithConcurrency<T, R>(\n items: ReadonlyArray<T>,\n concurrency: number,\n fn: (item: T, index: number, signal: AbortSignal) => Promise<R>,\n options?: { signal?: AbortSignal },\n): Promise<R[]> {\n const semaphore = createSemaphore(concurrency);\n const signal = options?.signal ?? NEVER_ABORT;\n return Promise.all(\n items.map(async (item, index) => {\n const release = await semaphore.acquire();\n try {\n if (signal.aborted) {\n throw signal.reason instanceof Error\n ? signal.reason\n : new Error(\"mapWithConcurrency: aborted\");\n }\n return await fn(item, index, signal);\n } finally {\n release();\n }\n }),\n );\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkAQO3NSRG_cjs = require('./chunk-AQO3NSRG.cjs');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
4
|
+
var chunk4CLOXP6H_cjs = require('./chunk-4CLOXP6H.cjs');
|
|
5
|
+
var chunk4ZHTIJNE_cjs = require('./chunk-4ZHTIJNE.cjs');
|
|
6
|
+
var chunkEG4QM7ZJ_cjs = require('./chunk-EG4QM7ZJ.cjs');
|
|
7
7
|
var promises = require('fs/promises');
|
|
8
8
|
var path = require('path');
|
|
9
9
|
|
|
@@ -50,13 +50,13 @@ async function readProjectSubagents(cwd) {
|
|
|
50
50
|
return subagents;
|
|
51
51
|
}
|
|
52
52
|
async function readSubagentsFrom(root, subagents) {
|
|
53
|
-
const entries = await
|
|
53
|
+
const entries = await chunk4CLOXP6H_cjs.readWorkspaceDir(root, "subagents_read_error", "subagents directory");
|
|
54
54
|
for (const entry of entries) {
|
|
55
55
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
56
56
|
const path$1 = path.join(root, entry.name);
|
|
57
57
|
const raw = await promises.readFile(path$1, "utf8");
|
|
58
58
|
if (!hasFrontmatter(raw)) {
|
|
59
|
-
|
|
59
|
+
chunkEG4QM7ZJ_cjs.diag(`[theokit-sdk] ${entry.name} has no frontmatter \u2014 not an agent declaration, skipping`);
|
|
60
60
|
continue;
|
|
61
61
|
}
|
|
62
62
|
const definition = parseSubagentMarkdown(raw, entry.name);
|
|
@@ -100,7 +100,7 @@ function rejectUnknownFields(fields, filename) {
|
|
|
100
100
|
for (const key of Object.keys(fields)) {
|
|
101
101
|
if (INERT_CLAUDE_CODE_FIELDS.has(key)) continue;
|
|
102
102
|
if (!ACCEPTED_FIELDS.has(key)) {
|
|
103
|
-
throw new
|
|
103
|
+
throw new chunk4ZHTIJNE_cjs.ConfigurationError(
|
|
104
104
|
`Subagent ${filename}: unknown frontmatter field "${key}" (accepted: ${[...ACCEPTED_FIELDS].join(", ")})`,
|
|
105
105
|
{ code: "subagent_unknown_field" }
|
|
106
106
|
);
|
|
@@ -109,7 +109,7 @@ function rejectUnknownFields(fields, filename) {
|
|
|
109
109
|
}
|
|
110
110
|
function rejectMcp(fields, filename) {
|
|
111
111
|
if (fields.mcp !== void 0) {
|
|
112
|
-
throw new
|
|
112
|
+
throw new chunk4ZHTIJNE_cjs.ConfigurationError(
|
|
113
113
|
`Subagent ${filename}: per-subagent "mcp" is not yet supported on the local delegation path; declare MCP servers in .theokit/mcp.json (or the parent) instead`,
|
|
114
114
|
{ code: "subagent_mcp_unsupported_local" }
|
|
115
115
|
);
|
|
@@ -119,7 +119,7 @@ function resolveModel(fields, filename) {
|
|
|
119
119
|
const modelId = asString(fields.model);
|
|
120
120
|
const effort = asString(fields.reasoning_effort);
|
|
121
121
|
if (effort !== void 0 && (modelId === void 0 || modelId === "inherit")) {
|
|
122
|
-
throw new
|
|
122
|
+
throw new chunk4ZHTIJNE_cjs.ConfigurationError(
|
|
123
123
|
`Subagent ${filename}: reasoning_effort requires a concrete model (effort is a model parameter; an absent model or "inherit" cannot carry it)`,
|
|
124
124
|
{ code: "subagent_reasoning_effort_without_model" }
|
|
125
125
|
);
|
|
@@ -131,7 +131,7 @@ function resolveModel(fields, filename) {
|
|
|
131
131
|
function resolveSandbox(fields, filename) {
|
|
132
132
|
if (fields.sandbox === void 0) return void 0;
|
|
133
133
|
if (typeof fields.sandbox !== "boolean") {
|
|
134
|
-
throw new
|
|
134
|
+
throw new chunk4ZHTIJNE_cjs.ConfigurationError(
|
|
135
135
|
`Subagent ${filename}: sandbox must be a boolean (got "${String(fields.sandbox)}"); granular sandbox modes are not supported by the runtime`,
|
|
136
136
|
{ code: "subagent_sandbox_not_boolean" }
|
|
137
137
|
);
|
|
@@ -156,17 +156,17 @@ function hasFrontmatter(raw) {
|
|
|
156
156
|
function splitFrontmatter(raw, filename) {
|
|
157
157
|
const match = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/.exec(raw);
|
|
158
158
|
if (match === null) {
|
|
159
|
-
throw new
|
|
159
|
+
throw new chunk4ZHTIJNE_cjs.ConfigurationError(`Subagent ${filename} is missing frontmatter`, {
|
|
160
160
|
code: "subagent_missing_frontmatter"
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
163
|
return { frontmatter: match[1] ?? "", body: (match[2] ?? "").trim() };
|
|
164
164
|
}
|
|
165
165
|
function parseFrontmatterFields(frontmatter) {
|
|
166
|
-
return
|
|
166
|
+
return chunk4CLOXP6H_cjs.parseSimpleYaml(frontmatter);
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
exports.loadSubagents = loadSubagents;
|
|
170
170
|
exports.pluginBundleDirs = pluginBundleDirs;
|
|
171
|
-
//# sourceMappingURL=chunk-
|
|
172
|
-
//# sourceMappingURL=chunk-
|
|
171
|
+
//# sourceMappingURL=chunk-CQBXOJ6U.cjs.map
|
|
172
|
+
//# sourceMappingURL=chunk-CQBXOJ6U.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/runtime/plugins/plugin-bundles.ts","../src/internal/runtime/skills/subagents-loader.ts"],"names":["pluginBundleRoots","readdir","join","projectConfigRoots","readWorkspaceDir","path","readFile","diag","ConfigurationError","parseSimpleYaml"],"mappings":"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","file":"chunk-WNTAPVU5.cjs","sourcesContent":["/**\n * Locating the plugin bundles a project carries.\n *\n * Shared by the skills and subagents loaders, which both need the same answer to \"which folders in\n * this project are plugins\" and would otherwise each grow their own copy of the directory walk.\n *\n * @internal\n */\n\nimport type { Dirent } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pluginBundleRoots } from \"../../persistence/paths.js\";\n\n/**\n * Every plugin folder under the project's plugin roots.\n *\n * Returns the FOLDERS, not their contents — what a bundle contributes (`skills/`, `agents/`) is the\n * caller's business, and a loader that also knew the layout would have to change whenever the other\n * one did.\n *\n * A missing root is not an error: most projects carry no plugins, and treating their absence as a\n * failure would make \"none installed\" indistinguishable from \"the directory could not be read\".\n */\nexport async function pluginBundleDirs(cwd: string): Promise<string[]> {\n const dirs: string[] = [];\n for (const root of pluginBundleRoots(cwd)) {\n let entries: Dirent[];\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) dirs.push(join(root, entry.name));\n }\n }\n return dirs;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\nimport type { AgentDefinition } from \"../../../types/agent.js\";\nimport type { ModelSelection } from \"../../../types/agent-prims.js\";\nimport { diag } from \"../../diagnostics.js\";\nimport { projectConfigRoots } from \"../../persistence/paths.js\";\nimport { readWorkspaceDir } from \"../config/workspace-dir.js\";\nimport { type FrontmatterValue, parseSimpleYaml } from \"../context/yaml-frontmatter.js\";\nimport { pluginBundleDirs } from \"../plugins/plugin-bundles.js\";\n\n/**\n * Load file-based subagents from `.theokit/agents/*.md` and merge with\n * inline definitions. Inline overrides file-based on name conflict.\n *\n * Each markdown file has YAML frontmatter (description + optional model)\n * and a body that becomes the subagent prompt.\n *\n * @internal\n */\nexport async function loadSubagents(\n cwd: string,\n settingSourcesIncludeProject: boolean,\n inline: Record<string, AgentDefinition> | undefined,\n): Promise<Record<string, AgentDefinition>> {\n const result: Record<string, AgentDefinition> = {};\n if (settingSourcesIncludeProject) {\n const projectAgents = await readProjectSubagents(cwd);\n for (const [name, definition] of Object.entries(projectAgents)) {\n result[name] = definition;\n }\n }\n if (inline !== undefined) {\n for (const [name, definition] of Object.entries(inline)) {\n result[name] = definition;\n }\n }\n return result;\n}\n\n/**\n * Read agent declarations from every project config root (`.theokit`, then `.claude`).\n *\n * FIRST occurrence of a name wins, which is what makes `projectConfigRoots`' order a contract rather\n * than a detail: a project declaring the same agent in both means the explicit namespace.\n */\nasync function readProjectSubagents(cwd: string): Promise<Record<string, AgentDefinition>> {\n const subagents: Record<string, AgentDefinition> = {};\n for (const configRoot of projectConfigRoots(cwd)) {\n await readSubagentsFrom(join(configRoot, \"agents\"), subagents);\n }\n // A Claude Code plugin is a BUNDLE, and its `agents/` is what it exists to contribute. Read after\n // the project's own, so a project can shadow an agent a plugin ships without editing the plugin.\n for (const bundle of await pluginBundleDirs(cwd)) {\n await readSubagentsFrom(join(bundle, \"agents\"), subagents);\n }\n return subagents;\n}\n\nasync function readSubagentsFrom(\n root: string,\n subagents: Record<string, AgentDefinition>,\n): Promise<void> {\n const entries = await readWorkspaceDir(root, \"subagents_read_error\", \"subagents directory\");\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith(\".md\")) continue;\n const path = join(root, entry.name);\n const raw = await readFile(path, \"utf8\");\n // A markdown file with NO frontmatter is not an agent declaration — a directory of agents\n // written for the Claude Code CLI conventionally carries documentation beside them, and\n // `.claude/agents/README.md` exists in this repository. Throwing on it made ONE such file stop\n // every agent in the directory from loading.\n //\n // Skipped with a warn rather than in silence, and ONLY for the no-frontmatter case: a file that\n // HAS frontmatter and gets it wrong is a broken agent and still fails loudly, which is what\n // keeps a typo'd `sandbox` from returning as a silent gate through this door.\n if (!hasFrontmatter(raw)) {\n diag(`[theokit-sdk] ${entry.name} has no frontmatter — not an agent declaration, skipping`);\n continue;\n }\n const definition = parseSubagentMarkdown(raw, entry.name);\n if (subagents[definition.name] === undefined) {\n subagents[definition.name] = definition.definition;\n }\n }\n}\n\n// The frontmatter keys a disk subagent may declare. Any other key is a typed load\n// error rather than a silent drop — a dropped `sandbox` an operator wrote believing\n// it confines the child is exactly the silent-gate failure class this guards against.\nconst ACCEPTED_FIELDS = new Set([\n \"name\",\n \"description\",\n \"model\",\n \"tools\",\n \"reasoning_effort\",\n \"mcp\",\n \"sandbox\",\n]);\n\n// Fields the Claude Code CLI writes that carry NO behaviour for this runtime. Accepted and ignored,\n// so an agent authored for the CLI loads here unchanged — measured 2026-08-26 across the 59 agent\n// files on one machine, where `color` appeared in 38 of them and made every one of those a\n// `subagent_unknown_field` load error.\n//\n// Named explicitly instead of loosening the check above, because that check's reason is sound: a\n// dropped `sandbox` an operator wrote believing it confines the child is a silent gate. A field that\n// COULD change behaviour must still fail loudly. This set is the difference between \"we know this\n// one and it does nothing\" and \"we have never heard of this\" — two facts a bare allow-everything\n// would collapse into one.\n//\n// Anything added here needs the same justification: inert for THIS runtime, not merely unfamiliar.\nconst INERT_CLAUDE_CODE_FIELDS = new Set([\n /** The CLI's label colour for the agent. Presentation only. */\n \"color\",\n]);\n\nfunction parseSubagentMarkdown(\n raw: string,\n filename: string,\n): { name: string; definition: AgentDefinition } {\n const { frontmatter, body } = splitFrontmatter(raw, filename);\n const fields = parseFrontmatterFields(frontmatter);\n rejectUnknownFields(fields, filename);\n rejectMcp(fields, filename);\n\n const definition: AgentDefinition = {\n description: asString(fields.description) ?? \"\",\n prompt: body,\n };\n const model = resolveModel(fields, filename);\n if (model !== undefined) definition.model = model;\n const tools = toStringList(fields.tools);\n if (tools.length > 0) definition.tools = tools;\n const sandbox = resolveSandbox(fields, filename);\n if (sandbox !== undefined) definition.sandbox = sandbox;\n\n const name = asString(fields.name) ?? filename.replace(/\\.md$/, \"\");\n return { name, definition };\n}\n\nfunction rejectUnknownFields(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): void {\n for (const key of Object.keys(fields)) {\n if (INERT_CLAUDE_CODE_FIELDS.has(key)) continue;\n if (!ACCEPTED_FIELDS.has(key)) {\n throw new ConfigurationError(\n `Subagent ${filename}: unknown frontmatter field \"${key}\" (accepted: ${[...ACCEPTED_FIELDS].join(\", \")})`,\n { code: \"subagent_unknown_field\" },\n );\n }\n }\n}\n\n// mcp: a known field, but not yet honored on the LOCAL delegation path. The frontmatter YAML can only\n// express server NAMES (parseSimpleYaml has no nested-object support), while a child's `Agent.create`\n// needs `mcpServers` as a Record<name, config>; resolving names→config per-subagent in local delegation\n// is its own follow-up. Rather than silently drop it (the M26/M32 silent-gate class), it is a typed load\n// error that names the field and points at the alternative.\nfunction rejectMcp(fields: Record<string, FrontmatterValue | undefined>, filename: string): void {\n if (fields.mcp !== undefined) {\n throw new ConfigurationError(\n `Subagent ${filename}: per-subagent \"mcp\" is not yet supported on the local delegation path; declare MCP servers in .theokit/mcp.json (or the parent) instead`,\n { code: \"subagent_mcp_unsupported_local\" },\n );\n }\n}\n\n// model + reasoning_effort — effort rides inside `model.params[thinking]`, so it requires a concrete\n// model id to attach to (a child inheriting the parent's model cannot carry the parent's provider-\n// specific effort param safely).\nfunction resolveModel(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): ModelSelection | \"inherit\" | undefined {\n const modelId = asString(fields.model);\n const effort = asString(fields.reasoning_effort);\n // reasoning_effort rides in model.params[thinking], so it needs a CONCRETE model id to attach to.\n // Neither an absent model NOR `model: inherit` can carry it (the inherited id is unknown at load), so\n // both are typed errors rather than a silently-dropped effort — the silent-gate class this guards.\n if (effort !== undefined && (modelId === undefined || modelId === \"inherit\")) {\n throw new ConfigurationError(\n `Subagent ${filename}: reasoning_effort requires a concrete model (effort is a model parameter; an absent model or \"inherit\" cannot carry it)`,\n { code: \"subagent_reasoning_effort_without_model\" },\n );\n }\n if (modelId === undefined) return undefined;\n if (modelId === \"inherit\") return \"inherit\";\n return effort !== undefined\n ? { id: modelId, params: [{ id: \"thinking\", value: effort }] }\n : { id: modelId };\n}\n\n// sandbox: boolean only. A granular mode string (read-only/…) is unsupported by the SDK runtime and is\n// a typed error rather than a silent coercion to a boolean.\nfunction resolveSandbox(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): boolean | undefined {\n if (fields.sandbox === undefined) return undefined;\n if (typeof fields.sandbox !== \"boolean\") {\n throw new ConfigurationError(\n `Subagent ${filename}: sandbox must be a boolean (got \"${String(fields.sandbox)}\"); granular sandbox modes are not supported by the runtime`,\n { code: \"subagent_sandbox_not_boolean\" },\n );\n }\n return fields.sandbox;\n}\n\nfunction asString(v: FrontmatterValue | undefined): string | undefined {\n if (typeof v !== \"string\") return undefined;\n // parseSimpleYaml does not strip quotes (documented), and `model`/`reasoning_effort` are fields users\n // habitually quote (`model: \"openai/gpt-4o\"`). Strip a single matching surrounding quote pair so a\n // quoted id/effort does not slip past validation and fail only at the provider.\n const m = /^([\"'])(.*)\\1$/.exec(v);\n return m ? m[2] : v;\n}\n\n/** Accept a YAML list (`string[]`) or a comma/space-separated scalar; trim + drop empties. */\nfunction toStringList(v: FrontmatterValue | undefined): string[] {\n if (Array.isArray(v)) return v.map((t) => t.trim()).filter((t) => t.length > 0);\n if (typeof v === \"string\") {\n return v\n .split(/[\\s,]+/)\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n }\n return [];\n}\n\n/** Does this file open with a frontmatter block at all? Its ABSENCE means \"not an agent\". */\nfunction hasFrontmatter(raw: string): boolean {\n return /^---\\s*\\n/.test(raw);\n}\n\nfunction splitFrontmatter(raw: string, filename: string): { frontmatter: string; body: string } {\n const match = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n([\\s\\S]*)$/.exec(raw);\n if (match === null) {\n throw new ConfigurationError(`Subagent ${filename} is missing frontmatter`, {\n code: \"subagent_missing_frontmatter\",\n });\n }\n return { frontmatter: match[1] ?? \"\", body: (match[2] ?? \"\").trim() };\n}\n\nfunction parseFrontmatterFields(frontmatter: string): Record<string, FrontmatterValue | undefined> {\n // Preserve the rich YAML value types (boolean/number/string[]): `sandbox: true` and\n // `mcp: [a, b]` are meaningful here, so narrowing everything to string (as the\n // pre-M33 loader did) would drop them. Per-field validation happens in parseSubagentMarkdown.\n return parseSimpleYaml(frontmatter);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/runtime/plugins/plugin-bundles.ts","../src/internal/runtime/skills/subagents-loader.ts"],"names":["pluginBundleRoots","readdir","join","projectConfigRoots","readWorkspaceDir","path","readFile","diag","ConfigurationError","parseSimpleYaml"],"mappings":"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","file":"chunk-CQBXOJ6U.cjs","sourcesContent":["/**\n * Locating the plugin bundles a project carries.\n *\n * Shared by the skills and subagents loaders, which both need the same answer to \"which folders in\n * this project are plugins\" and would otherwise each grow their own copy of the directory walk.\n *\n * @internal\n */\n\nimport type { Dirent } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pluginBundleRoots } from \"../../persistence/paths.js\";\n\n/**\n * Every plugin folder under the project's plugin roots.\n *\n * Returns the FOLDERS, not their contents — what a bundle contributes (`skills/`, `agents/`) is the\n * caller's business, and a loader that also knew the layout would have to change whenever the other\n * one did.\n *\n * A missing root is not an error: most projects carry no plugins, and treating their absence as a\n * failure would make \"none installed\" indistinguishable from \"the directory could not be read\".\n */\nexport async function pluginBundleDirs(cwd: string): Promise<string[]> {\n const dirs: string[] = [];\n for (const root of pluginBundleRoots(cwd)) {\n let entries: Dirent[];\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) dirs.push(join(root, entry.name));\n }\n }\n return dirs;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\nimport type { AgentDefinition } from \"../../../types/agent.js\";\nimport type { ModelSelection } from \"../../../types/agent-prims.js\";\nimport { diag } from \"../../diagnostics.js\";\nimport { projectConfigRoots } from \"../../persistence/paths.js\";\nimport { readWorkspaceDir } from \"../config/workspace-dir.js\";\nimport { type FrontmatterValue, parseSimpleYaml } from \"../context/yaml-frontmatter.js\";\nimport { pluginBundleDirs } from \"../plugins/plugin-bundles.js\";\n\n/**\n * Load file-based subagents from `.theokit/agents/*.md` and merge with\n * inline definitions. Inline overrides file-based on name conflict.\n *\n * Each markdown file has YAML frontmatter (description + optional model)\n * and a body that becomes the subagent prompt.\n *\n * @internal\n */\nexport async function loadSubagents(\n cwd: string,\n settingSourcesIncludeProject: boolean,\n inline: Record<string, AgentDefinition> | undefined,\n): Promise<Record<string, AgentDefinition>> {\n const result: Record<string, AgentDefinition> = {};\n if (settingSourcesIncludeProject) {\n const projectAgents = await readProjectSubagents(cwd);\n for (const [name, definition] of Object.entries(projectAgents)) {\n result[name] = definition;\n }\n }\n if (inline !== undefined) {\n for (const [name, definition] of Object.entries(inline)) {\n result[name] = definition;\n }\n }\n return result;\n}\n\n/**\n * Read agent declarations from every project config root (`.theokit`, then `.claude`).\n *\n * FIRST occurrence of a name wins, which is what makes `projectConfigRoots`' order a contract rather\n * than a detail: a project declaring the same agent in both means the explicit namespace.\n */\nasync function readProjectSubagents(cwd: string): Promise<Record<string, AgentDefinition>> {\n const subagents: Record<string, AgentDefinition> = {};\n for (const configRoot of projectConfigRoots(cwd)) {\n await readSubagentsFrom(join(configRoot, \"agents\"), subagents);\n }\n // A Claude Code plugin is a BUNDLE, and its `agents/` is what it exists to contribute. Read after\n // the project's own, so a project can shadow an agent a plugin ships without editing the plugin.\n for (const bundle of await pluginBundleDirs(cwd)) {\n await readSubagentsFrom(join(bundle, \"agents\"), subagents);\n }\n return subagents;\n}\n\nasync function readSubagentsFrom(\n root: string,\n subagents: Record<string, AgentDefinition>,\n): Promise<void> {\n const entries = await readWorkspaceDir(root, \"subagents_read_error\", \"subagents directory\");\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith(\".md\")) continue;\n const path = join(root, entry.name);\n const raw = await readFile(path, \"utf8\");\n // A markdown file with NO frontmatter is not an agent declaration — a directory of agents\n // written for the Claude Code CLI conventionally carries documentation beside them, and\n // `.claude/agents/README.md` exists in this repository. Throwing on it made ONE such file stop\n // every agent in the directory from loading.\n //\n // Skipped with a warn rather than in silence, and ONLY for the no-frontmatter case: a file that\n // HAS frontmatter and gets it wrong is a broken agent and still fails loudly, which is what\n // keeps a typo'd `sandbox` from returning as a silent gate through this door.\n if (!hasFrontmatter(raw)) {\n diag(`[theokit-sdk] ${entry.name} has no frontmatter — not an agent declaration, skipping`);\n continue;\n }\n const definition = parseSubagentMarkdown(raw, entry.name);\n if (subagents[definition.name] === undefined) {\n subagents[definition.name] = definition.definition;\n }\n }\n}\n\n// The frontmatter keys a disk subagent may declare. Any other key is a typed load\n// error rather than a silent drop — a dropped `sandbox` an operator wrote believing\n// it confines the child is exactly the silent-gate failure class this guards against.\nconst ACCEPTED_FIELDS = new Set([\n \"name\",\n \"description\",\n \"model\",\n \"tools\",\n \"reasoning_effort\",\n \"mcp\",\n \"sandbox\",\n]);\n\n// Fields the Claude Code CLI writes that carry NO behaviour for this runtime. Accepted and ignored,\n// so an agent authored for the CLI loads here unchanged — measured 2026-08-26 across the 59 agent\n// files on one machine, where `color` appeared in 38 of them and made every one of those a\n// `subagent_unknown_field` load error.\n//\n// Named explicitly instead of loosening the check above, because that check's reason is sound: a\n// dropped `sandbox` an operator wrote believing it confines the child is a silent gate. A field that\n// COULD change behaviour must still fail loudly. This set is the difference between \"we know this\n// one and it does nothing\" and \"we have never heard of this\" — two facts a bare allow-everything\n// would collapse into one.\n//\n// Anything added here needs the same justification: inert for THIS runtime, not merely unfamiliar.\nconst INERT_CLAUDE_CODE_FIELDS = new Set([\n /** The CLI's label colour for the agent. Presentation only. */\n \"color\",\n]);\n\nfunction parseSubagentMarkdown(\n raw: string,\n filename: string,\n): { name: string; definition: AgentDefinition } {\n const { frontmatter, body } = splitFrontmatter(raw, filename);\n const fields = parseFrontmatterFields(frontmatter);\n rejectUnknownFields(fields, filename);\n rejectMcp(fields, filename);\n\n const definition: AgentDefinition = {\n description: asString(fields.description) ?? \"\",\n prompt: body,\n };\n const model = resolveModel(fields, filename);\n if (model !== undefined) definition.model = model;\n const tools = toStringList(fields.tools);\n if (tools.length > 0) definition.tools = tools;\n const sandbox = resolveSandbox(fields, filename);\n if (sandbox !== undefined) definition.sandbox = sandbox;\n\n const name = asString(fields.name) ?? filename.replace(/\\.md$/, \"\");\n return { name, definition };\n}\n\nfunction rejectUnknownFields(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): void {\n for (const key of Object.keys(fields)) {\n if (INERT_CLAUDE_CODE_FIELDS.has(key)) continue;\n if (!ACCEPTED_FIELDS.has(key)) {\n throw new ConfigurationError(\n `Subagent ${filename}: unknown frontmatter field \"${key}\" (accepted: ${[...ACCEPTED_FIELDS].join(\", \")})`,\n { code: \"subagent_unknown_field\" },\n );\n }\n }\n}\n\n// mcp: a known field, but not yet honored on the LOCAL delegation path. The frontmatter YAML can only\n// express server NAMES (parseSimpleYaml has no nested-object support), while a child's `Agent.create`\n// needs `mcpServers` as a Record<name, config>; resolving names→config per-subagent in local delegation\n// is its own follow-up. Rather than silently drop it (the M26/M32 silent-gate class), it is a typed load\n// error that names the field and points at the alternative.\nfunction rejectMcp(fields: Record<string, FrontmatterValue | undefined>, filename: string): void {\n if (fields.mcp !== undefined) {\n throw new ConfigurationError(\n `Subagent ${filename}: per-subagent \"mcp\" is not yet supported on the local delegation path; declare MCP servers in .theokit/mcp.json (or the parent) instead`,\n { code: \"subagent_mcp_unsupported_local\" },\n );\n }\n}\n\n// model + reasoning_effort — effort rides inside `model.params[thinking]`, so it requires a concrete\n// model id to attach to (a child inheriting the parent's model cannot carry the parent's provider-\n// specific effort param safely).\nfunction resolveModel(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): ModelSelection | \"inherit\" | undefined {\n const modelId = asString(fields.model);\n const effort = asString(fields.reasoning_effort);\n // reasoning_effort rides in model.params[thinking], so it needs a CONCRETE model id to attach to.\n // Neither an absent model NOR `model: inherit` can carry it (the inherited id is unknown at load), so\n // both are typed errors rather than a silently-dropped effort — the silent-gate class this guards.\n if (effort !== undefined && (modelId === undefined || modelId === \"inherit\")) {\n throw new ConfigurationError(\n `Subagent ${filename}: reasoning_effort requires a concrete model (effort is a model parameter; an absent model or \"inherit\" cannot carry it)`,\n { code: \"subagent_reasoning_effort_without_model\" },\n );\n }\n if (modelId === undefined) return undefined;\n if (modelId === \"inherit\") return \"inherit\";\n return effort !== undefined\n ? { id: modelId, params: [{ id: \"thinking\", value: effort }] }\n : { id: modelId };\n}\n\n// sandbox: boolean only. A granular mode string (read-only/…) is unsupported by the SDK runtime and is\n// a typed error rather than a silent coercion to a boolean.\nfunction resolveSandbox(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): boolean | undefined {\n if (fields.sandbox === undefined) return undefined;\n if (typeof fields.sandbox !== \"boolean\") {\n throw new ConfigurationError(\n `Subagent ${filename}: sandbox must be a boolean (got \"${String(fields.sandbox)}\"); granular sandbox modes are not supported by the runtime`,\n { code: \"subagent_sandbox_not_boolean\" },\n );\n }\n return fields.sandbox;\n}\n\nfunction asString(v: FrontmatterValue | undefined): string | undefined {\n if (typeof v !== \"string\") return undefined;\n // parseSimpleYaml does not strip quotes (documented), and `model`/`reasoning_effort` are fields users\n // habitually quote (`model: \"openai/gpt-4o\"`). Strip a single matching surrounding quote pair so a\n // quoted id/effort does not slip past validation and fail only at the provider.\n const m = /^([\"'])(.*)\\1$/.exec(v);\n return m ? m[2] : v;\n}\n\n/** Accept a YAML list (`string[]`) or a comma/space-separated scalar; trim + drop empties. */\nfunction toStringList(v: FrontmatterValue | undefined): string[] {\n if (Array.isArray(v)) return v.map((t) => t.trim()).filter((t) => t.length > 0);\n if (typeof v === \"string\") {\n return v\n .split(/[\\s,]+/)\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n }\n return [];\n}\n\n/** Does this file open with a frontmatter block at all? Its ABSENCE means \"not an agent\". */\nfunction hasFrontmatter(raw: string): boolean {\n return /^---\\s*\\n/.test(raw);\n}\n\nfunction splitFrontmatter(raw: string, filename: string): { frontmatter: string; body: string } {\n const match = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n([\\s\\S]*)$/.exec(raw);\n if (match === null) {\n throw new ConfigurationError(`Subagent ${filename} is missing frontmatter`, {\n code: \"subagent_missing_frontmatter\",\n });\n }\n return { frontmatter: match[1] ?? \"\", body: (match[2] ?? \"\").trim() };\n}\n\nfunction parseFrontmatterFields(frontmatter: string): Record<string, FrontmatterValue | undefined> {\n // Preserve the rich YAML value types (boolean/number/string[]): `sandbox: true` and\n // `mcp: [a, b]` are meaningful here, so narrowing everything to string (as the\n // pre-M33 loader did) would drop them. Per-field validation happens in parseSubagentMarkdown.\n return parseSimpleYaml(frontmatter);\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { diag } from './chunk-
|
|
1
|
+
import { diag } from './chunk-XEQ3TM66.js';
|
|
2
2
|
|
|
3
3
|
// src/internal/env.ts
|
|
4
4
|
var API_KEY_ENV_VAR = "THEOKIT_API_KEY";
|
|
@@ -149,5 +149,5 @@ function redactSecrets(text, opts) {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
export { API_KEY_ENV_VAR, addPattern, maskToken, readEnv, redactSecrets, resolveApiKey };
|
|
152
|
-
//# sourceMappingURL=chunk-
|
|
153
|
-
//# sourceMappingURL=chunk-
|
|
152
|
+
//# sourceMappingURL=chunk-D4CUGAKZ.js.map
|
|
153
|
+
//# sourceMappingURL=chunk-D4CUGAKZ.js.map
|