@theokit/sdk 4.63.4 → 5.0.0-next.2
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 +847 -23
- package/dist/a2a/index.cjs +29 -13
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.d.cts +1 -1
- package/dist/a2a/index.d.ts +1 -1
- package/dist/a2a/index.js +26 -11
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/message-bus.d.cts +26 -3
- package/dist/a2a/message-bus.d.ts +26 -3
- package/dist/a2a/subagent.d.cts +8 -3
- package/dist/a2a/subagent.d.ts +8 -3
- package/dist/{agent-X0DKA943.d.cts → agent-C3KO5LKm.d.cts} +251 -36
- package/dist/{agent-BFno7Sfn.d.ts → agent-CvmTR9uf.d.ts} +251 -36
- package/dist/agent-GPV2JWZG.cjs +67 -0
- package/dist/{agent-UX7WFI6B.cjs.map → agent-GPV2JWZG.cjs.map} +1 -1
- package/dist/agent-Y24I5JBM.js +58 -0
- package/dist/{agent-A5XMIVNP.js.map → agent-Y24I5JBM.js.map} +1 -1
- package/dist/agent-session-store-AFML3AXC.js +6 -0
- package/dist/{agent-session-store-OPGRB4XM.js.map → agent-session-store-AFML3AXC.js.map} +1 -1
- package/dist/agent-session-store-MTSIY3MH.cjs +23 -0
- package/dist/{agent-session-store-6EL5NPA4.cjs.map → agent-session-store-MTSIY3MH.cjs.map} +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/auth/index.cjs +33 -34
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.js +6 -7
- package/dist/auth/index.js.map +1 -1
- package/dist/{batch-BXYTW2DP.cjs → batch-I6T6MXZO.cjs} +58 -40
- package/dist/batch-I6T6MXZO.cjs.map +1 -0
- package/dist/{batch-L4ZXS46M.js → batch-US4F6WPK.js} +42 -24
- package/dist/batch-US4F6WPK.js.map +1 -0
- package/dist/chunk-24MGQDK3.js +31 -0
- package/dist/chunk-24MGQDK3.js.map +1 -0
- package/dist/{chunk-UGT7GK7I.cjs → chunk-24SYBZPL.cjs} +36 -18
- package/dist/chunk-24SYBZPL.cjs.map +1 -0
- package/dist/{chunk-KYAJINUI.cjs → chunk-2HPNT6HH.cjs} +581 -401
- package/dist/chunk-2HPNT6HH.cjs.map +1 -0
- package/dist/{chunk-VLVVJLDH.cjs → chunk-2NE7DTOK.cjs} +234 -193
- package/dist/chunk-2NE7DTOK.cjs.map +1 -0
- package/dist/{chunk-N2U4AZGB.js → chunk-2WXHA33T.js} +3 -3
- package/dist/chunk-2WXHA33T.js.map +1 -0
- package/dist/chunk-2XC6KDJM.js +22 -0
- package/dist/chunk-2XC6KDJM.js.map +1 -0
- package/dist/{chunk-L3MTL4NA.js → chunk-2ZLVT7H3.js} +223 -182
- package/dist/chunk-2ZLVT7H3.js.map +1 -0
- package/dist/{chunk-2GUYQR5P.js → chunk-3JHIFQ4I.js} +39 -13
- package/dist/chunk-3JHIFQ4I.js.map +1 -0
- package/dist/{chunk-BU4KFWXF.js → chunk-44I6UYVH.js} +8 -17
- package/dist/chunk-44I6UYVH.js.map +1 -0
- package/dist/{chunk-UNYXQ4M5.js → chunk-47TF32NQ.js} +10 -5
- package/dist/chunk-47TF32NQ.js.map +1 -0
- package/dist/{chunk-WNO3C3N2.cjs → chunk-4A3SKJ53.cjs} +56 -27
- package/dist/chunk-4A3SKJ53.cjs.map +1 -0
- package/dist/{chunk-YML4ME27.cjs → chunk-4HS6FFGL.cjs} +55 -46
- package/dist/chunk-4HS6FFGL.cjs.map +1 -0
- package/dist/{chunk-C72AZW7J.js → chunk-4MMWFSCD.js} +4 -4
- package/dist/chunk-4MMWFSCD.js.map +1 -0
- package/dist/{chunk-6HKGLTJI.cjs → chunk-4NLCWGH7.cjs} +15 -15
- package/dist/chunk-4NLCWGH7.cjs.map +1 -0
- package/dist/{chunk-LKBEROHN.js → chunk-4S5TWFIZ.js} +14 -14
- package/dist/chunk-4S5TWFIZ.js.map +1 -0
- package/dist/{chunk-UBDMVMBZ.js → chunk-55GB6JYQ.js} +33 -22
- package/dist/chunk-55GB6JYQ.js.map +1 -0
- package/dist/{chunk-U6IFHFWK.js → chunk-5WKQDIGO.js} +8 -17
- package/dist/chunk-5WKQDIGO.js.map +1 -0
- package/dist/chunk-67ADYSTW.js +120 -0
- package/dist/chunk-67ADYSTW.js.map +1 -0
- package/dist/{chunk-XL7Q7HB2.cjs → chunk-6LHQPOMI.cjs} +39 -6
- package/dist/chunk-6LHQPOMI.cjs.map +1 -0
- package/dist/{chunk-A4JVILQU.js → chunk-6M2OIS4Y.js} +7 -7
- package/dist/chunk-6M2OIS4Y.js.map +1 -0
- package/dist/{chunk-LWGSI6M3.js → chunk-6PWOWXMC.js} +4 -4
- package/dist/{chunk-LWGSI6M3.js.map → chunk-6PWOWXMC.js.map} +1 -1
- package/dist/{chunk-RNB4APBZ.js → chunk-6WAKKTBO.js} +9 -5
- package/dist/chunk-6WAKKTBO.js.map +1 -0
- package/dist/{chunk-V2BOS4WF.cjs → chunk-7A6535RA.cjs} +11 -11
- package/dist/chunk-7A6535RA.cjs.map +1 -0
- package/dist/{chunk-ZLQSWSJ2.cjs → chunk-7FDKWDA2.cjs} +11 -11
- package/dist/{chunk-ZLQSWSJ2.cjs.map → chunk-7FDKWDA2.cjs.map} +1 -1
- package/dist/{chunk-4VPXM6UU.js → chunk-7I5Z3UBJ.js} +3 -3
- package/dist/{chunk-4VPXM6UU.js.map → chunk-7I5Z3UBJ.js.map} +1 -1
- package/dist/{chunk-B4EOJWOY.cjs → chunk-7JJ3A6AT.cjs} +13 -7
- package/dist/chunk-7JJ3A6AT.cjs.map +1 -0
- package/dist/{chunk-WJVHMTKB.cjs → chunk-AA27GEYS.cjs} +3 -3
- package/dist/{chunk-WJVHMTKB.cjs.map → chunk-AA27GEYS.cjs.map} +1 -1
- package/dist/{chunk-BP46RJ5X.js → chunk-AAEZSPTC.js} +5 -5
- package/dist/{chunk-BP46RJ5X.js.map → chunk-AAEZSPTC.js.map} +1 -1
- package/dist/chunk-AGACYRJ2.js +11 -0
- package/dist/chunk-AGACYRJ2.js.map +1 -0
- package/dist/{chunk-ZZMZWBR6.js → chunk-ALUN2B4W.js} +81 -58
- package/dist/chunk-ALUN2B4W.js.map +1 -0
- package/dist/chunk-ANMJJD6D.cjs +18 -0
- package/dist/chunk-ANMJJD6D.cjs.map +1 -0
- package/dist/{chunk-DXGZ2NUG.cjs → chunk-ATT276RD.cjs} +12 -11
- package/dist/chunk-ATT276RD.cjs.map +1 -0
- package/dist/{chunk-4FFBAUFS.js → chunk-AWINL3ZC.js} +6 -6
- package/dist/chunk-AWINL3ZC.js.map +1 -0
- package/dist/{chunk-UU36SHFY.cjs → chunk-BJUJT5ED.cjs} +9 -8
- package/dist/chunk-BJUJT5ED.cjs.map +1 -0
- package/dist/{chunk-D4CUGAKZ.js → chunk-CZJ6Q7CW.js} +36 -6
- package/dist/chunk-CZJ6Q7CW.js.map +1 -0
- package/dist/{chunk-KQ7TS7WW.cjs → chunk-D6POWE7E.cjs} +37 -26
- package/dist/chunk-D6POWE7E.cjs.map +1 -0
- package/dist/{chunk-AWO27VRZ.js → chunk-DMRT67Y6.js} +6 -5
- package/dist/chunk-DMRT67Y6.js.map +1 -0
- package/dist/{chunk-5VB22SYX.cjs → chunk-DQZU7JK6.cjs} +7 -7
- package/dist/{chunk-5VB22SYX.cjs.map → chunk-DQZU7JK6.cjs.map} +1 -1
- package/dist/{chunk-3NSS2OIZ.cjs → chunk-DRL7URI4.cjs} +6 -6
- package/dist/{chunk-3NSS2OIZ.cjs.map → chunk-DRL7URI4.cjs.map} +1 -1
- package/dist/{chunk-RFXWMRFC.js → chunk-EFMFILPG.js} +14 -6
- package/dist/chunk-EFMFILPG.js.map +1 -0
- package/dist/{chunk-HS7AVXTF.js → chunk-EH6XD3FY.js} +4 -4
- package/dist/chunk-EH6XD3FY.js.map +1 -0
- package/dist/{chunk-KQRW2GPZ.js → chunk-EIQFAOFD.js} +6 -6
- package/dist/chunk-EIQFAOFD.js.map +1 -0
- package/dist/{chunk-XJCXEKMD.cjs → chunk-EXTRW7GW.cjs} +4 -4
- package/dist/chunk-EXTRW7GW.cjs.map +1 -0
- package/dist/{chunk-U54XCYG3.js → chunk-FJWQP6EE.js} +12 -6
- package/dist/chunk-FJWQP6EE.js.map +1 -0
- package/dist/{chunk-O7DK5PBJ.cjs → chunk-FUSDYC2B.cjs} +26 -42
- package/dist/chunk-FUSDYC2B.cjs.map +1 -0
- package/dist/{chunk-4QZSA2HJ.js → chunk-G7BLGBRN.js} +4 -4
- package/dist/chunk-G7BLGBRN.js.map +1 -0
- package/dist/{chunk-BZRFXJHA.js → chunk-GBCVPKHE.js} +55 -26
- package/dist/chunk-GBCVPKHE.js.map +1 -0
- package/dist/chunk-GGZ5GPE3.cjs +130 -0
- package/dist/chunk-GGZ5GPE3.cjs.map +1 -0
- package/dist/{chunk-5HEG4CQH.cjs → chunk-GZV6AVRL.cjs} +8 -8
- package/dist/{chunk-5HEG4CQH.cjs.map → chunk-GZV6AVRL.cjs.map} +1 -1
- package/dist/{chunk-VCLBZAZU.cjs → chunk-H6YM3PV6.cjs} +17 -17
- package/dist/chunk-H6YM3PV6.cjs.map +1 -0
- package/dist/{chunk-RFMBZPOW.cjs → chunk-HCT4HPCL.cjs} +10 -10
- package/dist/chunk-HCT4HPCL.cjs.map +1 -0
- package/dist/{chunk-OSEG74VJ.js → chunk-HFEJE7AC.js} +52 -43
- package/dist/chunk-HFEJE7AC.js.map +1 -0
- package/dist/{chunk-52NKC5HT.cjs → chunk-HUFSABUZ.cjs} +12 -8
- package/dist/chunk-HUFSABUZ.cjs.map +1 -0
- package/dist/{chunk-4CLOXP6H.cjs → chunk-HW7SEELD.cjs} +4 -4
- package/dist/{chunk-4CLOXP6H.cjs.map → chunk-HW7SEELD.cjs.map} +1 -1
- package/dist/{chunk-ZSWPZ23K.cjs → chunk-I2PWY7VM.cjs} +5 -5
- package/dist/chunk-I2PWY7VM.cjs.map +1 -0
- package/dist/{chunk-VJ26EKGJ.cjs → chunk-IJ7M6GOG.cjs} +3 -3
- package/dist/chunk-IJ7M6GOG.cjs.map +1 -0
- package/dist/{chunk-SAVIWMZB.js → chunk-ILGZ2ZZV.js} +3 -3
- package/dist/chunk-ILGZ2ZZV.js.map +1 -0
- package/dist/{chunk-4ZHTIJNE.cjs → chunk-J7J7J2GN.cjs} +87 -63
- package/dist/chunk-J7J7J2GN.cjs.map +1 -0
- package/dist/{chunk-UALX2J2Q.cjs → chunk-JLRLCBJ4.cjs} +38 -11
- package/dist/chunk-JLRLCBJ4.cjs.map +1 -0
- package/dist/{chunk-2QDYBS2A.js → chunk-JMDDYA22.js} +4 -4
- package/dist/chunk-JMDDYA22.js.map +1 -0
- package/dist/{chunk-LXQ6HKPS.js → chunk-JNAA4G4H.js} +3 -3
- package/dist/{chunk-LXQ6HKPS.js.map → chunk-JNAA4G4H.js.map} +1 -1
- package/dist/{chunk-UMP6OJIM.js → chunk-JOFVLOFY.js} +4 -4
- package/dist/{chunk-UMP6OJIM.js.map → chunk-JOFVLOFY.js.map} +1 -1
- package/dist/{chunk-A46SWMIF.js → chunk-K2VMFZQ5.js} +7 -7
- package/dist/chunk-K2VMFZQ5.js.map +1 -0
- package/dist/{chunk-DN2PACRI.js → chunk-K3NH62DG.js} +461 -282
- package/dist/chunk-K3NH62DG.js.map +1 -0
- package/dist/{chunk-LYTOXSRH.js → chunk-KDR53EO7.js} +1939 -1864
- package/dist/chunk-KDR53EO7.js.map +1 -0
- package/dist/{chunk-XWTLIGO3.cjs → chunk-KTTHHYEW.cjs} +5 -5
- package/dist/chunk-KTTHHYEW.cjs.map +1 -0
- package/dist/{chunk-3FFAEAUJ.cjs → chunk-KVSAY6NZ.cjs} +18 -18
- package/dist/chunk-KVSAY6NZ.cjs.map +1 -0
- package/dist/{chunk-IAHZCGBE.cjs → chunk-LHSWHYF3.cjs} +120 -146
- package/dist/chunk-LHSWHYF3.cjs.map +1 -0
- package/dist/{chunk-3OR54XG4.js → chunk-NJWYQWDL.js} +12 -8
- package/dist/chunk-NJWYQWDL.js.map +1 -0
- package/dist/chunk-NVXXWAU7.cjs +13 -0
- package/dist/chunk-NVXXWAU7.cjs.map +1 -0
- package/dist/{chunk-2D34UTDC.js → chunk-O6USDERH.js} +31 -11
- package/dist/chunk-O6USDERH.js.map +1 -0
- package/dist/{chunk-XO4SOZN6.js → chunk-OR6XIWLB.js} +4 -4
- package/dist/{chunk-XO4SOZN6.js.map → chunk-OR6XIWLB.js.map} +1 -1
- package/dist/{chunk-4PYZ5AX3.cjs → chunk-PRZ3BES7.cjs} +16 -8
- package/dist/chunk-PRZ3BES7.cjs.map +1 -0
- package/dist/{chunk-HCZD23VS.cjs → chunk-QC55H6RJ.cjs} +65 -39
- package/dist/chunk-QC55H6RJ.cjs.map +1 -0
- package/dist/{chunk-4O5TGQBW.cjs → chunk-QME6FDFG.cjs} +9 -5
- package/dist/chunk-QME6FDFG.cjs.map +1 -0
- package/dist/chunk-QOGNZMHD.cjs +34 -0
- package/dist/chunk-QOGNZMHD.cjs.map +1 -0
- package/dist/{chunk-7VT4P3Z4.cjs → chunk-QUAEOKDW.cjs} +1642 -1567
- package/dist/chunk-QUAEOKDW.cjs.map +1 -0
- package/dist/{chunk-B2J4ZMZL.cjs → chunk-QWD3CZWE.cjs} +6 -5
- package/dist/chunk-QWD3CZWE.cjs.map +1 -0
- package/dist/{chunk-SZVR77EJ.cjs → chunk-QWD4RDZ3.cjs} +15 -24
- package/dist/chunk-QWD4RDZ3.cjs.map +1 -0
- package/dist/{chunk-7BG5UH3T.cjs → chunk-RHZ6HP23.cjs} +4 -4
- package/dist/chunk-RHZ6HP23.cjs.map +1 -0
- package/dist/{chunk-2HVF2WJY.cjs → chunk-RQMCOFAI.cjs} +8 -8
- package/dist/{chunk-2HVF2WJY.cjs.map → chunk-RQMCOFAI.cjs.map} +1 -1
- package/dist/{chunk-VKJ7V7EB.cjs → chunk-SA6K24NB.cjs} +3 -3
- package/dist/chunk-SA6K24NB.cjs.map +1 -0
- package/dist/{chunk-7AD3ZTZL.js → chunk-SAGRF4IB.js} +3 -3
- package/dist/chunk-SAGRF4IB.js.map +1 -0
- package/dist/{chunk-PUAEFLYK.js → chunk-SVQIW5RJ.js} +4 -4
- package/dist/{chunk-PUAEFLYK.js.map → chunk-SVQIW5RJ.js.map} +1 -1
- package/dist/{chunk-43ZQRWAP.cjs → chunk-SYVWE64W.cjs} +22 -22
- package/dist/chunk-SYVWE64W.cjs.map +1 -0
- package/dist/{chunk-3O42QOMJ.js → chunk-TA3K7SBK.js} +7 -6
- package/dist/chunk-TA3K7SBK.js.map +1 -0
- package/dist/{chunk-LYRDF5TQ.cjs → chunk-TFG5IBZS.cjs} +14 -23
- package/dist/chunk-TFG5IBZS.cjs.map +1 -0
- package/dist/{chunk-GKEFRLU7.cjs → chunk-TMKTSYDS.cjs} +6 -6
- package/dist/{chunk-GKEFRLU7.cjs.map → chunk-TMKTSYDS.cjs.map} +1 -1
- package/dist/{chunk-J24VJOH3.cjs → chunk-UADQJBHR.cjs} +31 -11
- package/dist/chunk-UADQJBHR.cjs.map +1 -0
- package/dist/{chunk-TAZVKYWJ.js → chunk-UBR5PWD7.js} +26 -40
- package/dist/chunk-UBR5PWD7.js.map +1 -0
- package/dist/{chunk-IPYYKCRC.js → chunk-UFPUHJWS.js} +5 -5
- package/dist/{chunk-IPYYKCRC.js.map → chunk-UFPUHJWS.js.map} +1 -1
- package/dist/{chunk-OHLDPWTA.cjs → chunk-UGRS7ZA7.cjs} +15 -15
- package/dist/{chunk-OHLDPWTA.cjs.map → chunk-UGRS7ZA7.cjs.map} +1 -1
- package/dist/{chunk-RIAM53CP.js → chunk-UKMBRMGT.js} +3 -3
- package/dist/chunk-UKMBRMGT.js.map +1 -0
- package/dist/{chunk-L4BDVXIM.js → chunk-UNK4HNJH.js} +97 -123
- package/dist/chunk-UNK4HNJH.js.map +1 -0
- package/dist/{chunk-C3NT3PVE.js → chunk-V22DZIXO.js} +3 -3
- package/dist/chunk-V22DZIXO.js.map +1 -0
- package/dist/{chunk-OFRFZRQ4.cjs → chunk-V6ZY4AX6.cjs} +24 -14
- package/dist/chunk-V6ZY4AX6.cjs.map +1 -0
- package/dist/{chunk-B3IMEBOA.js → chunk-VE6DFSKU.js} +3 -3
- package/dist/{chunk-B3IMEBOA.js.map → chunk-VE6DFSKU.js.map} +1 -1
- package/dist/{chunk-WLQNMXQE.js → chunk-VWUXIVEI.js} +53 -26
- package/dist/chunk-VWUXIVEI.js.map +1 -0
- package/dist/{chunk-GMLBYDW4.cjs → chunk-VXDEKILY.cjs} +108 -109
- package/dist/chunk-VXDEKILY.cjs.map +1 -0
- package/dist/{chunk-ACDLHN3W.js → chunk-WJXOICRC.js} +16 -6
- package/dist/chunk-WJXOICRC.js.map +1 -0
- package/dist/{chunk-7YGCPMGB.js → chunk-XB4GI5RZ.js} +27 -12
- package/dist/chunk-XB4GI5RZ.js.map +1 -0
- package/dist/{chunk-O73J46PV.js → chunk-XDANGA2C.js} +5 -5
- package/dist/{chunk-O73J46PV.js.map → chunk-XDANGA2C.js.map} +1 -1
- package/dist/{chunk-NDGGJQTZ.js → chunk-XJZEBGXD.js} +10 -10
- package/dist/chunk-XJZEBGXD.js.map +1 -0
- package/dist/{chunk-UTSRIDKZ.js → chunk-XYFGKVZ7.js} +3 -3
- package/dist/chunk-XYFGKVZ7.js.map +1 -0
- package/dist/{chunk-RMWTPV3M.cjs → chunk-Y2KYR2ED.cjs} +27 -27
- package/dist/chunk-Y2KYR2ED.cjs.map +1 -0
- package/dist/{chunk-O7LZFG6O.cjs → chunk-YIFFF23U.cjs} +5 -5
- package/dist/chunk-YIFFF23U.cjs.map +1 -0
- package/dist/{chunk-4OTIXDMU.cjs → chunk-YJNYDJ2T.cjs} +12 -4
- package/dist/chunk-YJNYDJ2T.cjs.map +1 -0
- package/dist/{chunk-6JSIEDKL.cjs → chunk-YSTXFWQE.cjs} +13 -7
- package/dist/chunk-YSTXFWQE.cjs.map +1 -0
- package/dist/{chunk-I6HGWHPU.cjs → chunk-Z3NTRKIC.cjs} +4 -4
- package/dist/{chunk-I6HGWHPU.cjs.map → chunk-Z3NTRKIC.cjs.map} +1 -1
- package/dist/{chunk-32WTYBUH.js → chunk-ZH26RNQA.js} +91 -92
- package/dist/chunk-ZH26RNQA.js.map +1 -0
- package/dist/compact-session-BHTPCIHA.cjs +61 -0
- package/dist/{compact-session-QV57KR66.cjs.map → compact-session-BHTPCIHA.cjs.map} +1 -1
- package/dist/compact-session-W4WLJTHA.js +24 -0
- package/dist/{compact-session-RIGOWC4Y.js.map → compact-session-W4WLJTHA.js.map} +1 -1
- package/dist/compaction.cjs +20 -17
- package/dist/compaction.d.cts +15 -1
- package/dist/compaction.d.ts +15 -1
- package/dist/compaction.js +3 -4
- package/dist/concurrency.cjs +6 -7
- package/dist/concurrency.cjs.map +1 -1
- package/dist/concurrency.d.cts +6 -3
- package/dist/concurrency.d.ts +6 -3
- package/dist/concurrency.js +4 -5
- package/dist/concurrency.js.map +1 -1
- package/dist/context/index.cjs +6 -6
- package/dist/context/index.js +3 -3
- package/dist/context-NI33FS2R.cjs +23 -0
- package/dist/{context-WFLTTMK3.cjs.map → context-NI33FS2R.cjs.map} +1 -1
- package/dist/context-Y7B7SI5X.js +6 -0
- package/dist/{context-WI2DFG7V.js.map → context-Y7B7SI5X.js.map} +1 -1
- package/dist/create-skill.d.ts +4 -1
- package/dist/{cron-BuiRPrvt.d.cts → cron-C3PhZED0.d.cts} +8 -2
- package/dist/{cron-C2SIi31n.d.ts → cron-crfMMdAw.d.ts} +8 -2
- package/dist/cron.cjs +46 -45
- package/dist/cron.d.cts +5 -4
- package/dist/cron.d.ts +5 -4
- package/dist/cron.js +45 -44
- package/dist/{errors-BgJH9PHi.d.cts → errors-CLOAyuiv.d.ts} +133 -95
- package/dist/{errors-C5fJUqLk.d.ts → errors-DrDEgyz1.d.cts} +133 -95
- package/dist/errors-base-B5g01neU.d.cts +75 -0
- package/dist/errors-base-B5g01neU.d.ts +75 -0
- package/dist/errors-base.d.ts +73 -0
- package/dist/errors.cjs +25 -22
- package/dist/errors.d.cts +3 -2
- package/dist/errors.d.ts +3 -2
- package/dist/errors.js +2 -3
- package/dist/eval.cjs +74 -78
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +64 -68
- package/dist/eval.js.map +1 -1
- package/dist/{executor-6CYCA7MI.cjs → executor-XQAOQOHD.cjs} +60 -54
- package/dist/executor-XQAOQOHD.cjs.map +1 -0
- package/dist/{executor-QSEC3MRH.js → executor-ZNDQDX6Q.js} +43 -37
- package/dist/executor-ZNDQDX6Q.js.map +1 -0
- package/dist/filesystem/index.cjs +24 -26
- package/dist/filesystem/index.cjs.map +1 -1
- package/dist/filesystem/index.js +20 -22
- package/dist/filesystem/index.js.map +1 -1
- package/dist/filesystem/types.d.cts +11 -5
- package/dist/filesystem/types.d.ts +11 -5
- package/dist/{fork-agent-RSV4E3EA.js → fork-agent-S2EPIML7.js} +3 -3
- package/dist/fork-agent-S2EPIML7.js.map +1 -0
- package/dist/{fork-agent-Y2IK2RYU.cjs → fork-agent-WAEQI2DL.cjs} +4 -4
- package/dist/fork-agent-WAEQI2DL.cjs.map +1 -0
- package/dist/fs-session-store-77JU46UZ.js +10 -0
- package/dist/{fs-session-store-NM6YSTE2.js.map → fs-session-store-77JU46UZ.js.map} +1 -1
- package/dist/fs-session-store-E4U3P56L.cjs +19 -0
- package/dist/{fs-session-store-4PIHT5UX.cjs.map → fs-session-store-E4U3P56L.cjs.map} +1 -1
- package/dist/generate-object-BXV7BZRP.js +7 -0
- package/dist/{generate-object-GUNAUVBX.js.map → generate-object-BXV7BZRP.js.map} +1 -1
- package/dist/generate-object-YBI2TDJ3.cjs +20 -0
- package/dist/{generate-object-R7HTMW7F.cjs.map → generate-object-YBI2TDJ3.cjs.map} +1 -1
- package/dist/generate-object.d.ts +2 -4
- package/dist/index-manager-DXR2RSFI.cjs +26 -0
- package/dist/{index-manager-2SRX45WJ.cjs.map → index-manager-DXR2RSFI.cjs.map} +1 -1
- package/dist/index-manager-QH6OXEV5.js +17 -0
- package/dist/{index-manager-SP4ISSDX.js.map → index-manager-QH6OXEV5.js.map} +1 -1
- package/dist/index.cjs +234 -194
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +243 -41
- package/dist/index.d.ts +243 -41
- package/dist/index.js +140 -102
- package/dist/index.js.map +1 -1
- package/dist/{inject-session-DAR7OUCW.js → inject-session-SUM6TDJF.js} +9 -9
- package/dist/{inject-session-DAR7OUCW.js.map → inject-session-SUM6TDJF.js.map} +1 -1
- package/dist/inject-session-W6A46J3E.cjs +29 -0
- package/dist/{inject-session-WQKMC3GR.cjs.map → inject-session-W6A46J3E.cjs.map} +1 -1
- package/dist/interactive/index.cjs +12 -6
- package/dist/interactive/index.cjs.map +1 -1
- package/dist/interactive/index.js +12 -6
- package/dist/interactive/index.js.map +1 -1
- package/dist/interactive/types.d.cts +14 -4
- package/dist/interactive/types.d.ts +14 -4
- package/dist/internal/agent-loop/loop-context-init.d.ts +1 -1
- package/dist/internal/agent-loop/loop-finalize.d.ts +25 -0
- package/dist/internal/agent-loop/loop.d.ts +1 -1
- package/dist/internal/agent-loop/message-builders.d.ts +1 -1
- package/dist/internal/agent-loop/tool-dispatch.d.ts +2 -2
- package/dist/internal/agent-loop/usage-and-cost.d.ts +1 -1
- package/dist/internal/auth/credential-availability.d.ts +61 -0
- package/dist/internal/auth/credential-store.d.ts +1 -1
- package/dist/internal/auth/oauth-device.d.ts +1 -1
- package/dist/internal/auth/oauth-engine.d.ts +1 -1
- package/dist/internal/auth/resolve-credential.d.ts +1 -1
- package/dist/internal/base-url.d.ts +14 -0
- package/dist/internal/cloud-agent/cloud-config-serializer.d.ts +1 -1
- package/dist/internal/{runtime/concurrency → concurrency}/subagent-credentials.d.ts +2 -2
- package/dist/internal/emit-run-event.d.ts +16 -0
- package/dist/internal/error-mappers/shared.d.ts +14 -1
- package/dist/internal/eval/assert.d.ts +2 -1
- package/dist/internal/eval/single-flight.d.ts +2 -1
- package/dist/internal/global-singleton.d.ts +6 -3
- package/dist/internal/llm/responses.d.ts +10 -0
- package/dist/internal/local-agent/local-agent-bootstrap.d.ts +5 -3
- package/dist/internal/local-agent/local-agent-capabilities.d.ts +38 -0
- package/dist/internal/local-agent/local-agent-dispatch.d.ts +2 -2
- package/dist/internal/local-agent/local-agent-memory-provider.d.ts +1 -1
- package/dist/internal/local-agent/local-agent-personality-extensions.d.ts +25 -1
- package/dist/internal/local-agent/local-agent-send.d.ts +42 -1
- package/dist/internal/local-agent/real-local-run-mcp.d.ts +26 -0
- package/dist/internal/local-agent/real-local-run-options.d.ts +26 -0
- package/dist/internal/local-agent/real-local-run-tools.d.ts +21 -4
- package/dist/internal/local-agent/real-local-run.d.ts +2 -2
- package/dist/internal/mcp/handshake-timeout.d.ts +53 -0
- package/dist/internal/memory/active-memory.d.ts +1 -1
- package/dist/internal/memory/adapters/index.cjs +10 -10
- package/dist/internal/memory/adapters/index.js +9 -9
- package/dist/internal/memory/adapters/openai-embedding.d.cts +10 -0
- package/dist/internal/memory/adapters/openai-embedding.d.ts +10 -0
- package/dist/internal/memory/corpus-sync.d.ts +23 -0
- package/dist/internal/memory/index-db.d.ts +15 -1
- package/dist/internal/memory/index-manager-contract.d.ts +12 -0
- package/dist/internal/memory/index-manager.d.ts +4 -10
- package/dist/internal/memory/index-repository.d.ts +58 -0
- package/dist/internal/memory/lance-memory-adapter.d.ts +16 -14
- package/dist/internal/memory/memory-index.d.ts +15 -0
- package/dist/internal/memory/sdk-memory-peer-loader.d.ts +54 -1
- package/dist/internal/memory/storage/index.cjs +39 -40
- package/dist/internal/memory/storage/index.js +10 -11
- package/dist/internal/memory/storage/memory-root.d.cts +2 -3
- package/dist/internal/memory/storage/memory-root.d.ts +2 -3
- package/dist/internal/persistence/atomic-write.d.cts +4 -4
- package/dist/internal/persistence/atomic-write.d.ts +4 -4
- package/dist/internal/persistence/index.cjs +24 -25
- package/dist/internal/persistence/index.cjs.map +1 -1
- package/dist/internal/persistence/index.js +7 -8
- package/dist/internal/persistence/index.js.map +1 -1
- package/dist/internal/persistence/jsonl.d.cts +3 -1
- package/dist/internal/persistence/jsonl.d.ts +3 -1
- package/dist/internal/persistence/paths.d.cts +25 -12
- package/dist/internal/persistence/paths.d.ts +25 -12
- package/dist/internal/persistence/transcript-ops.d.cts +11 -2
- package/dist/internal/persistence/transcript-ops.d.ts +11 -2
- package/dist/internal/plugins/context.d.cts +0 -10
- package/dist/internal/plugins/context.d.ts +0 -10
- package/dist/internal/plugins/types.d.cts +1 -1
- package/dist/internal/plugins/types.d.ts +1 -1
- package/dist/internal/providers/catalog-schema.d.ts +94 -0
- package/dist/internal/providers/catalog-source-models-dev.d.ts +11 -0
- package/dist/internal/runtime/compat/compat-config-file.d.ts +31 -0
- package/dist/internal/runtime/compat/foreign-config-sources.d.ts +58 -34
- package/dist/internal/runtime/compression/compression-model-registry.d.ts +1 -1
- package/dist/internal/runtime/compression/compression-summarizer.d.ts +5 -1
- package/dist/internal/runtime/fixtures/fixture-events.d.ts +1 -1
- package/dist/internal/runtime/fixtures/fixture-mode.d.ts +8 -14
- package/dist/internal/runtime/fixtures/fixture-run-base.d.ts +1 -1
- package/dist/internal/runtime/fixtures/fixture-scripts.d.ts +2 -2
- package/dist/internal/runtime/hooks/hooks-executor.d.ts +6 -1
- package/dist/internal/runtime/lifecycle/wrap-completion-check-run.d.ts +1 -1
- package/dist/internal/runtime/{memory → memory-glue}/memory-provider.d.ts +1 -1
- package/dist/internal/runtime/{plugins → plugin-loader}/plugin-bundles.d.ts +4 -1
- package/dist/internal/runtime/processors/wrap-output-run.d.ts +1 -1
- package/dist/internal/runtime/registry/live-agent-registry.d.ts +9 -1
- package/dist/internal/runtime/system-prompt/local-assembly.d.ts +2 -1
- package/dist/internal/scorers/llm-judge.d.ts +12 -0
- package/dist/internal/security/index.cjs +14 -15
- package/dist/internal/security/index.d.cts +6 -1
- package/dist/internal/security/index.d.ts +6 -1
- package/dist/internal/security/index.js +4 -5
- package/dist/internal/security/path-containment.d.ts +24 -0
- package/dist/internal/session/agent-session-store.d.ts +1 -1
- package/dist/internal/session/agent-session.d.ts +1 -1
- package/dist/internal/session/index.d.ts +1 -1
- package/dist/internal/session/session-cache.d.ts +9 -3
- package/dist/internal/task/registry.d.ts +1 -1
- package/dist/internal/task/store.d.ts +1 -1
- package/dist/internal/task/subscribe.d.ts +1 -1
- package/dist/internal/task/task-id.d.ts +22 -0
- package/dist/internal/telemetry/adapter-registry.d.ts +12 -2
- package/dist/internal/telemetry/adapters/braintrust.d.ts +6 -1
- package/dist/internal/telemetry/adapters/langsmith.d.ts +6 -1
- package/dist/internal/workflow/executor.d.ts +2 -1
- package/dist/internal/workflow/snapshot-store.d.ts +1 -1
- package/dist/internal/workflow/step-branch.d.ts +2 -2
- package/dist/internal/workflow/step-dowhile.d.ts +2 -2
- package/dist/internal/workflow/step-execution.d.ts +25 -0
- package/dist/internal/workflow/step-foreach.d.ts +2 -2
- package/dist/internal/workflow/step-parallel.d.ts +2 -2
- package/dist/judge-call-6MVARKU2.js +5 -0
- package/dist/{judge-call-LVXABPS3.js.map → judge-call-6MVARKU2.js.map} +1 -1
- package/dist/judge-call-I3P4D5QR.cjs +22 -0
- package/dist/{judge-call-LAHMBJ57.cjs.map → judge-call-I3P4D5QR.cjs.map} +1 -1
- package/dist/mcp-auth.cjs +14 -15
- package/dist/mcp-auth.cjs.map +1 -1
- package/dist/mcp-auth.d.cts +2 -0
- package/dist/mcp-auth.d.ts +2 -0
- package/dist/mcp-auth.js +4 -5
- package/dist/mcp-auth.js.map +1 -1
- package/dist/models.cjs +52 -42
- package/dist/models.cjs.map +1 -1
- package/dist/models.js +39 -29
- package/dist/models.js.map +1 -1
- package/dist/oauth-transaction-store-5RIR6D5C.js +5 -0
- package/dist/{oauth-transaction-store-W52KVHQ4.js.map → oauth-transaction-store-5RIR6D5C.js.map} +1 -1
- package/dist/oauth-transaction-store-SXIE57OD.cjs +38 -0
- package/dist/{oauth-transaction-store-BT4GLTLK.cjs.map → oauth-transaction-store-SXIE57OD.cjs.map} +1 -1
- package/dist/path-safety.cjs +11 -12
- package/dist/path-safety.d.cts +2 -0
- package/dist/path-safety.d.ts +2 -0
- package/dist/path-safety.js +4 -5
- package/dist/permission-engine.d.ts +10 -17
- package/dist/persistence.cjs +31 -31
- package/dist/persistence.cjs.map +1 -1
- package/dist/persistence.d.cts +9 -1
- package/dist/persistence.d.ts +9 -1
- package/dist/persistence.js +12 -13
- package/dist/persistence.js.map +1 -1
- package/dist/project.cjs +5 -6
- package/dist/project.cjs.map +1 -1
- package/dist/project.js +3 -4
- package/dist/project.js.map +1 -1
- package/dist/providers.cjs +10 -10
- package/dist/providers.d.cts +2 -0
- package/dist/providers.d.ts +2 -0
- package/dist/providers.js +8 -8
- package/dist/registry-BZQFYRTL.cjs +46 -0
- package/dist/{registry-V7BDQ6QB.cjs.map → registry-BZQFYRTL.cjs.map} +1 -1
- package/dist/registry-DMWCJKRF.js +9 -0
- package/dist/{registry-75W33OGL.js.map → registry-DMWCJKRF.js.map} +1 -1
- package/dist/retry.cjs +4 -5
- package/dist/retry.d.cts +20 -5
- package/dist/retry.d.ts +20 -5
- package/dist/retry.js +3 -4
- package/dist/{run-BYSHf58D.d.ts → run-CTAdRU3U.d.cts} +120 -152
- package/dist/{run-BYSHf58D.d.cts → run-CTAdRU3U.d.ts} +120 -152
- package/dist/{run-until-HEQOUVU6.js → run-until-6D6TQ4JN.js} +27 -59
- package/dist/run-until-6D6TQ4JN.js.map +1 -0
- package/dist/{run-until-U2B5FJJI.cjs → run-until-DG2KXWB2.cjs} +27 -59
- package/dist/run-until-DG2KXWB2.cjs.map +1 -0
- package/dist/sandbox/bwrap.d.cts +11 -1
- package/dist/sandbox/bwrap.d.ts +11 -1
- package/dist/sandbox/index.cjs +26 -30
- package/dist/sandbox/index.cjs.map +1 -1
- package/dist/sandbox/index.d.cts +8 -1
- package/dist/sandbox/index.d.ts +8 -1
- package/dist/sandbox/index.js +10 -14
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/linux-sandbox.d.cts +20 -4
- package/dist/sandbox/linux-sandbox.d.ts +20 -4
- package/dist/sandbox/types.d.cts +18 -2
- package/dist/sandbox/types.d.ts +18 -2
- package/dist/sanitize/index.cjs +2 -2
- package/dist/sanitize/index.js +1 -1
- package/dist/sanitize/types.d.cts +15 -2
- package/dist/sanitize/types.d.ts +15 -2
- package/dist/{sdk-agent-D8qJVkuV.d.ts → sdk-agent-BOiKqOgL.d.cts} +197 -117
- package/dist/{sdk-agent-DEoKhA8a.d.cts → sdk-agent-D4a_BR_6.d.ts} +197 -117
- package/dist/server/auth/errors.d.cts +4 -3
- package/dist/server/auth/errors.d.ts +4 -3
- package/dist/server/auth/index.cjs +28 -28
- package/dist/server/auth/index.cjs.map +1 -1
- package/dist/server/auth/index.d.cts +28 -5
- package/dist/server/auth/index.d.ts +28 -5
- package/dist/server/auth/index.js +13 -13
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/auth/oauth-transaction-store.d.cts +2 -1
- package/dist/server/auth/oauth-transaction-store.d.ts +2 -1
- package/dist/server/auth/orchestrator.d.cts +4 -1
- package/dist/server/auth/orchestrator.d.ts +4 -1
- package/dist/server/auth/types.d.cts +18 -0
- package/dist/server/auth/types.d.ts +18 -0
- package/dist/server/errors-envelope.cjs +14 -15
- package/dist/server/errors-envelope.cjs.map +1 -1
- package/dist/server/errors-envelope.d.cts +3 -3
- package/dist/server/errors-envelope.d.ts +3 -3
- package/dist/server/errors-envelope.js +3 -4
- package/dist/server/errors-envelope.js.map +1 -1
- package/dist/session-transcript-LGHSNVY5.cjs +62 -0
- package/dist/{session-transcript-6WNITKRE.cjs.map → session-transcript-LGHSNVY5.cjs.map} +1 -1
- package/dist/session-transcript-VTBTCGQX.js +5 -0
- package/dist/{session-transcript-XAEKW6P7.js.map → session-transcript-VTBTCGQX.js.map} +1 -1
- package/dist/skills.cjs +8 -9
- package/dist/skills.js +6 -7
- package/dist/stream-object-HBFMIZLD.js +7 -0
- package/dist/{stream-object-UF4QRQRU.js.map → stream-object-HBFMIZLD.js.map} +1 -1
- package/dist/stream-object-QSKHISDJ.cjs +20 -0
- package/dist/{stream-object-ZJTQNKY3.cjs.map → stream-object-QSKHISDJ.cjs.map} +1 -1
- package/dist/stream-object.d.ts +2 -4
- package/dist/subagents-loader-TPZLTXYZ.cjs +16 -0
- package/dist/{subagents-loader-UCNO7FUH.cjs.map → subagents-loader-TPZLTXYZ.cjs.map} +1 -1
- package/dist/subagents-loader-Y6JFYXAY.js +7 -0
- package/dist/{subagents-loader-XP5ERVDZ.js.map → subagents-loader-Y6JFYXAY.js.map} +1 -1
- package/dist/subagents-loader.cjs +7 -8
- package/dist/subagents-loader.cjs.map +1 -1
- package/dist/subagents-loader.d.cts +5 -3
- package/dist/subagents-loader.d.ts +5 -3
- package/dist/subagents-loader.js +5 -6
- package/dist/subagents-loader.js.map +1 -1
- package/dist/subagents.cjs +2 -2
- package/dist/subagents.cjs.map +1 -1
- package/dist/subagents.js +1 -1
- package/dist/subagents.js.map +1 -1
- package/dist/subscription/define-subscription.d.cts +4 -1
- package/dist/subscription/define-subscription.d.ts +4 -1
- package/dist/subscription/index.cjs +4 -5
- package/dist/subscription/index.cjs.map +1 -1
- package/dist/subscription/index.d.cts +2 -0
- package/dist/subscription/index.d.ts +2 -0
- package/dist/subscription/index.js +3 -4
- package/dist/subscription/index.js.map +1 -1
- package/dist/subscription/internal/server-integration.d.cts +5 -0
- package/dist/subscription/internal/server-integration.d.ts +5 -0
- package/dist/subscription/internal/subscription-runtime.d.cts +13 -1
- package/dist/subscription/internal/subscription-runtime.d.ts +13 -1
- package/dist/task-errors.d.ts +58 -0
- package/dist/task-store.cjs +7 -8
- package/dist/task-store.d.cts +2 -0
- package/dist/task-store.d.ts +2 -0
- package/dist/task-store.js +4 -5
- package/dist/types/agent-prims.d.ts +21 -0
- package/dist/types/agent.d.ts +109 -15
- package/dist/types/batch.d.ts +3 -0
- package/dist/types/budget-tracker.d.ts +3 -0
- package/dist/types/budget.d.ts +12 -3
- package/dist/types/content-blocks.d.ts +3 -0
- package/dist/types/context.d.ts +3 -0
- package/dist/types/conversation.d.ts +5 -0
- package/dist/types/cron.d.ts +5 -0
- package/dist/types/env-policy.d.ts +3 -0
- package/dist/types/eval.d.ts +3 -0
- package/dist/types/fork.d.ts +3 -0
- package/dist/types/goal-events.d.ts +3 -0
- package/dist/types/mcp.d.ts +5 -0
- package/dist/types/memory-adapter.d.ts +3 -0
- package/dist/types/memory-provider.d.ts +44 -5
- package/dist/types/messages-base.d.ts +4 -0
- package/dist/types/messages.d.ts +5 -0
- package/dist/types/plugin.d.ts +32 -4
- package/dist/types/processors.d.ts +3 -0
- package/dist/types/provider-profile.d.ts +3 -0
- package/dist/types/providers.d.ts +3 -0
- package/dist/types/run-events.d.ts +36 -9
- package/dist/types/run.d.ts +29 -2
- package/dist/types/sdk-agent.d.ts +71 -1
- package/dist/types/session-message.d.ts +3 -0
- package/dist/types/session-record.d.ts +3 -0
- package/dist/types/session-store.d.ts +45 -0
- package/dist/types/task.d.ts +3 -11
- package/dist/types/theokit.d.ts +3 -0
- package/dist/types/trajectory.d.ts +3 -0
- package/dist/types/updates.d.ts +5 -0
- package/dist/types/usage.d.ts +4 -1
- package/dist/types/workflow.d.ts +13 -135
- package/dist/workflow-as-tool.d.ts +66 -0
- package/dist/workflow-errors.d.ts +164 -0
- package/dist/workflow.cjs +29 -30
- package/dist/workflow.d.cts +135 -74
- package/dist/workflow.d.ts +135 -74
- package/dist/workflow.js +8 -9
- package/docs/adr/README.md +2604 -0
- package/docs/error-codes.md +139 -105
- package/docs/harness-capability-map.md +32 -20
- package/docs/memory-decisions.md +1 -1
- package/package.json +3 -7
- package/bin/theokit-migrate-config.mjs +0 -278
- package/bin/theokit-migrate-memory.mjs +0 -116
- package/dist/agent-A5XMIVNP.js +0 -57
- package/dist/agent-UX7WFI6B.cjs +0 -66
- package/dist/agent-session-store-6EL5NPA4.cjs +0 -24
- package/dist/agent-session-store-OPGRB4XM.js +0 -7
- package/dist/batch-BXYTW2DP.cjs.map +0 -1
- package/dist/batch-L4ZXS46M.js.map +0 -1
- package/dist/chunk-247ZTLNU.js +0 -73
- package/dist/chunk-247ZTLNU.js.map +0 -1
- package/dist/chunk-2D34UTDC.js.map +0 -1
- package/dist/chunk-2GUYQR5P.js.map +0 -1
- package/dist/chunk-2QDYBS2A.js.map +0 -1
- package/dist/chunk-32WTYBUH.js.map +0 -1
- package/dist/chunk-3FFAEAUJ.cjs.map +0 -1
- package/dist/chunk-3O42QOMJ.js.map +0 -1
- package/dist/chunk-3OR54XG4.js.map +0 -1
- package/dist/chunk-43ZQRWAP.cjs.map +0 -1
- package/dist/chunk-4FFBAUFS.js.map +0 -1
- package/dist/chunk-4O5TGQBW.cjs.map +0 -1
- package/dist/chunk-4OTIXDMU.cjs.map +0 -1
- package/dist/chunk-4PYZ5AX3.cjs.map +0 -1
- package/dist/chunk-4QZSA2HJ.js.map +0 -1
- package/dist/chunk-4ZHTIJNE.cjs.map +0 -1
- package/dist/chunk-52NKC5HT.cjs.map +0 -1
- package/dist/chunk-6HKGLTJI.cjs.map +0 -1
- package/dist/chunk-6JSIEDKL.cjs.map +0 -1
- package/dist/chunk-7AD3ZTZL.js.map +0 -1
- package/dist/chunk-7BG5UH3T.cjs.map +0 -1
- package/dist/chunk-7VT4P3Z4.cjs.map +0 -1
- package/dist/chunk-7YGCPMGB.js.map +0 -1
- package/dist/chunk-A46SWMIF.js.map +0 -1
- package/dist/chunk-A4JVILQU.js.map +0 -1
- package/dist/chunk-ACDLHN3W.js.map +0 -1
- package/dist/chunk-AKJP2STZ.cjs +0 -81
- package/dist/chunk-AKJP2STZ.cjs.map +0 -1
- package/dist/chunk-AWO27VRZ.js.map +0 -1
- package/dist/chunk-B2J4ZMZL.cjs.map +0 -1
- package/dist/chunk-B4EOJWOY.cjs.map +0 -1
- package/dist/chunk-BU4KFWXF.js.map +0 -1
- package/dist/chunk-BZRFXJHA.js.map +0 -1
- package/dist/chunk-C3NT3PVE.js.map +0 -1
- package/dist/chunk-C72AZW7J.js.map +0 -1
- package/dist/chunk-D4CUGAKZ.js.map +0 -1
- package/dist/chunk-DN2PACRI.js.map +0 -1
- package/dist/chunk-DXGZ2NUG.cjs.map +0 -1
- package/dist/chunk-EG4QM7ZJ.cjs +0 -39
- package/dist/chunk-EG4QM7ZJ.cjs.map +0 -1
- package/dist/chunk-GMLBYDW4.cjs.map +0 -1
- package/dist/chunk-HCZD23VS.cjs.map +0 -1
- package/dist/chunk-HS7AVXTF.js.map +0 -1
- package/dist/chunk-IAHZCGBE.cjs.map +0 -1
- package/dist/chunk-J24VJOH3.cjs.map +0 -1
- package/dist/chunk-JPBKYL3B.cjs +0 -18
- package/dist/chunk-JPBKYL3B.cjs.map +0 -1
- package/dist/chunk-KQ7TS7WW.cjs.map +0 -1
- package/dist/chunk-KQRW2GPZ.js.map +0 -1
- package/dist/chunk-KYAJINUI.cjs.map +0 -1
- package/dist/chunk-L3MTL4NA.js.map +0 -1
- package/dist/chunk-L4BDVXIM.js.map +0 -1
- package/dist/chunk-LKBEROHN.js.map +0 -1
- package/dist/chunk-LYRDF5TQ.cjs.map +0 -1
- package/dist/chunk-LYTOXSRH.js.map +0 -1
- package/dist/chunk-N2U4AZGB.js.map +0 -1
- package/dist/chunk-NDGGJQTZ.js.map +0 -1
- package/dist/chunk-O7DK5PBJ.cjs.map +0 -1
- package/dist/chunk-O7LZFG6O.cjs.map +0 -1
- package/dist/chunk-OFRFZRQ4.cjs.map +0 -1
- package/dist/chunk-OSEG74VJ.js.map +0 -1
- package/dist/chunk-RFMBZPOW.cjs.map +0 -1
- package/dist/chunk-RFXWMRFC.js.map +0 -1
- package/dist/chunk-RIAM53CP.js.map +0 -1
- package/dist/chunk-RMWTPV3M.cjs.map +0 -1
- package/dist/chunk-RNB4APBZ.js.map +0 -1
- package/dist/chunk-SAVIWMZB.js.map +0 -1
- package/dist/chunk-SZVR77EJ.cjs.map +0 -1
- package/dist/chunk-TAZVKYWJ.js.map +0 -1
- package/dist/chunk-U54XCYG3.js.map +0 -1
- package/dist/chunk-U6IFHFWK.js.map +0 -1
- package/dist/chunk-UALX2J2Q.cjs.map +0 -1
- package/dist/chunk-UBDMVMBZ.js.map +0 -1
- package/dist/chunk-UGT7GK7I.cjs.map +0 -1
- package/dist/chunk-UNYXQ4M5.js.map +0 -1
- package/dist/chunk-UTSRIDKZ.js.map +0 -1
- package/dist/chunk-UU36SHFY.cjs.map +0 -1
- package/dist/chunk-V2BOS4WF.cjs.map +0 -1
- package/dist/chunk-VCLBZAZU.cjs.map +0 -1
- package/dist/chunk-VJ26EKGJ.cjs.map +0 -1
- package/dist/chunk-VKJ7V7EB.cjs.map +0 -1
- package/dist/chunk-VLVVJLDH.cjs.map +0 -1
- package/dist/chunk-WLQNMXQE.js.map +0 -1
- package/dist/chunk-WNO3C3N2.cjs.map +0 -1
- package/dist/chunk-WTMU7J4U.js +0 -14
- package/dist/chunk-WTMU7J4U.js.map +0 -1
- package/dist/chunk-XEQ3TM66.js +0 -35
- package/dist/chunk-XEQ3TM66.js.map +0 -1
- package/dist/chunk-XJCXEKMD.cjs.map +0 -1
- package/dist/chunk-XL7Q7HB2.cjs.map +0 -1
- package/dist/chunk-XWTLIGO3.cjs.map +0 -1
- package/dist/chunk-YML4ME27.cjs.map +0 -1
- package/dist/chunk-ZSWPZ23K.cjs.map +0 -1
- package/dist/chunk-ZZMZWBR6.js.map +0 -1
- package/dist/compact-session-QV57KR66.cjs +0 -59
- package/dist/compact-session-RIGOWC4Y.js +0 -22
- package/dist/context-WFLTTMK3.cjs +0 -24
- package/dist/context-WI2DFG7V.js +0 -7
- package/dist/executor-6CYCA7MI.cjs.map +0 -1
- package/dist/executor-QSEC3MRH.js.map +0 -1
- package/dist/fork-agent-RSV4E3EA.js.map +0 -1
- package/dist/fork-agent-Y2IK2RYU.cjs.map +0 -1
- package/dist/fs-session-store-4PIHT5UX.cjs +0 -20
- package/dist/fs-session-store-NM6YSTE2.js +0 -11
- package/dist/generate-object-GUNAUVBX.js +0 -8
- package/dist/generate-object-R7HTMW7F.cjs +0 -21
- package/dist/index-manager-2SRX45WJ.cjs +0 -27
- package/dist/index-manager-SP4ISSDX.js +0 -18
- package/dist/inject-session-WQKMC3GR.cjs +0 -29
- package/dist/internal/persistence/credential-pool-store.d.cts +0 -32
- package/dist/internal/persistence/credential-pool-store.d.ts +0 -32
- package/dist/internal/runtime/memory/memory-path-selector.d.ts +0 -73
- package/dist/judge-call-LAHMBJ57.cjs +0 -23
- package/dist/judge-call-LVXABPS3.js +0 -6
- package/dist/oauth-transaction-store-BT4GLTLK.cjs +0 -36
- package/dist/oauth-transaction-store-W52KVHQ4.js +0 -3
- package/dist/registry-75W33OGL.js +0 -10
- package/dist/registry-V7BDQ6QB.cjs +0 -47
- package/dist/run-until-HEQOUVU6.js.map +0 -1
- package/dist/run-until-U2B5FJJI.cjs.map +0 -1
- package/dist/server/adapter/express.d.cts +0 -9
- package/dist/server/adapter/express.d.ts +0 -9
- package/dist/server/adapter/fastify.d.cts +0 -9
- package/dist/server/adapter/fastify.d.ts +0 -9
- package/dist/server/adapter/hono.d.cts +0 -9
- package/dist/server/adapter/hono.d.ts +0 -9
- package/dist/server/adapter/shared-handler.d.cts +0 -9
- package/dist/server/adapter/shared-handler.d.ts +0 -9
- package/dist/server/adapter/types.d.cts +0 -33
- package/dist/server/adapter/types.d.ts +0 -33
- package/dist/session-transcript-6WNITKRE.cjs +0 -63
- package/dist/session-transcript-XAEKW6P7.js +0 -6
- package/dist/stream-object-UF4QRQRU.js +0 -8
- package/dist/stream-object-ZJTQNKY3.cjs +0 -21
- package/dist/subagents-loader-UCNO7FUH.cjs +0 -17
- package/dist/subagents-loader-XP5ERVDZ.js +0 -8
- /package/dist/{batch.d.ts → internal/agent/batch.d.ts} +0 -0
- /package/dist/{agent-helpers.d.ts → internal/agent/helpers.d.ts} +0 -0
- /package/dist/internal/agent-loop/{loop-types.d.ts → types.d.ts} +0 -0
- /package/dist/internal/auth/{auth-types.d.ts → types.d.ts} +0 -0
- /package/dist/internal/cloud-agent/{cloud-payload-types.d.ts → types.d.ts} +0 -0
- /package/dist/internal/{runtime/concurrency → concurrency}/abort-utils.d.ts +0 -0
- /package/dist/internal/{runtime/concurrency → concurrency}/async-local-storage.d.ts +0 -0
- /package/dist/internal/{runtime/concurrency → concurrency}/async-semaphore.d.ts +0 -0
- /package/dist/internal/{runtime/concurrency → concurrency}/delegation-depth.d.ts +0 -0
- /package/dist/internal/{runtime/concurrency → concurrency}/map-with-concurrency.d.ts +0 -0
- /package/dist/internal/{runtime/retry → error-mappers}/default-retriable.d.ts +0 -0
- /package/dist/internal/{runtime/fixtures/fixture-types.d.ts → memory/storage/list-markdown.d.cts} +0 -0
- /package/dist/internal/{runtime/plugins/plugins-manager.d.ts → memory/storage/list-markdown.d.ts} +0 -0
- /package/dist/internal/{resilience → retry}/circuit-breaker.d.ts +0 -0
- /package/dist/internal/{runtime/retry → retry}/with-retry.d.ts +0 -0
- /package/dist/internal/{security/secret-redactor.d.cts → runtime/fixtures/types.d.ts} +0 -0
- /package/dist/internal/runtime/{memory → memory-glue}/memory-store.d.ts +0 -0
- /package/dist/internal/runtime/{memory → memory-glue}/select-facts.d.ts +0 -0
- /package/dist/internal/runtime/{plugins → plugin-loader}/plugin-frontmatter.d.ts +0 -0
- /package/dist/internal/{security/secret-redactor.d.ts → runtime/plugin-loader/plugins-manager.d.ts} +0 -0
- /package/dist/internal/runtime/{reasoning → system-prompt}/native-reasoning.d.ts +0 -0
- /package/dist/internal/{runtime/context/path-containment.d.ts → security/path-containment.d.cts} +0 -0
- /package/dist/internal/session/{session-types.d.ts → types.d.ts} +0 -0
- /package/dist/internal/{zod/to-json-schema.d.ts → zod-to-json-schema.d.ts} +0 -0
- /package/dist/subscription/internal/{adapter-types.d.cts → types.d.cts} +0 -0
- /package/dist/subscription/internal/{adapter-types.d.ts → types.d.ts} +0 -0
package/dist/mcp-auth.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/mcp/token-storage.ts","../src/internal/mcp/oauth.ts"],"names":["join","homedir","mkdirSync","chmodSync","createRequire","diag","existsSync","readFileSync","atomicWriteJson","assertSecureModes","dirname","randomBytes","createHash","ConfigurationError","createServer","createInterface"],"mappings":"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","file":"mcp-auth.cjs","sourcesContent":["import { chmodSync, existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { assertSecureModes } from \"../auth/credential-store.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { atomicWriteJson } from \"../persistence/atomic-write.js\";\n\n/**\n * The OAuth tokens held for one MCP server. See ADR D41.\n *\n * Persisted per server name by `setTokens` and returned unchanged by `getTokens`. Where it lands\n * depends on what is installed: `keytar` puts the serialized bundle in the OS keychain, and\n * without it the bundle is written to a JSON file at mode 0600 inside a 0700 directory — in\n * PLAINTEXT, keyed by server name alongside every other server's tokens. Nothing here encrypts it.\n *\n * `refreshToken` is the field that matters most and the field that is optional. When present it\n * outlives `accessToken` and can mint new ones, so a leaked store is a persistent compromise of\n * the account rather than a temporary one. When absent, an expired access token means re-running\n * the authorization flow.\n *\n * `expiresAt` and `obtainedAt` are both epoch milliseconds and both describe the ACCESS token —\n * when it stops working, and when this bundle was issued. Nothing records when the refresh token\n * expires, so a refresh rejected because the grant itself lapsed is only discovered at the token\n * endpoint.\n *\n * The value is not validated on read: whatever JSON was stored is cast to this shape, so a\n * hand-edited or truncated store yields an object whose fields may be missing rather than an\n * error.\n *\n * `scope` records what the token was granted, as the server returned it. It is stored for\n * inspection; nothing in this module enforces it.\n *\n * @public — re-exported from `@theokit/sdk/mcp-auth`, and therefore under semver.\n */\nexport interface OAuthTokens {\n accessToken: string;\n refreshToken?: string;\n expiresAt: number; // ms epoch\n scope?: string;\n obtainedAt: number; // ms epoch\n}\n\nconst KEYTAR_SERVICE = \"theokit-mcp\";\n/**\n * Resolve the store path on every call instead of binding it once at module load.\n *\n * This used to be `const FILE_PATH = join(homedir(), ...)`. A module-level constant captures\n * ambient global state at IMPORT, so the store kept writing to whichever HOME was set when the\n * module first loaded and never noticed a later change. In production that is invisible, because\n * HOME does not move mid-process — but it made the module's correctness a property of *when* it was\n * imported, which is not a property a credential store should have.\n *\n * The environment variable is read FIRST and `homedir()` is the fallback, and the variable READ IS\n * PER PLATFORM because `os.homedir()` itself is: on POSIX it prefers `$HOME`, on Windows it reads\n * `USERPROFILE` and never consults `HOME`. Mirroring that split is what keeps this a pure\n * binding-time fix instead of a behaviour change.\n *\n * A previous revision read `process.env.HOME` on every platform. Review caught it: under Git Bash,\n * MSYS2 or Cygwin `HOME` IS set, to a POSIX-shaped path, and `path.win32.join(\"/c/Users/N\", ...)`\n * yields `\\c\\Users\\N\\.theokit\\...` where `USERPROFILE` would have given\n * `C:\\Users\\N\\.theokit\\...`. That would have hidden every existing token on those setups and\n * written a new credential file to a drive-relative path. It was published as \"on Windows HOME is\n * typically unset\" — an untested platform claim, and the same defect class it was written to fix.\n *\n * Why read the env at all: inside a worker thread `process.env` is a JS-level copy while\n * `os.homedir()` is a native call reading the real process environment, so code that moves the home\n * inside a worker is invisible to `homedir()`. Reading the env first makes this module independent\n * of the execution model, not just of the import moment.\n *\n * The empty/whitespace guard falls through to `homedir()`, and it buys LESS than two earlier\n * revisions of this comment claimed. Measured on POSIX: `homedir()` with `HOME=\"\"` returns `\"\"` and\n * with `HOME=\" \"` returns `\" \"` untrimmed, so the fallback hands back the same value the guard\n * rejected — close to a no-op. `path.join(\"\", \".theokit\", ...)` yields a CWD-RELATIVE\n * `.theokit/mcp-tokens.json`, never `/.theokit`; an earlier revision named that as the hazard and it\n * does not exist.\n *\n * On Windows it is UNKNOWN rather than load-bearing: the fallback reads the same `USERPROFILE`, so\n * whether the guard changes anything depends on whether an empty variable is reported as absent\n * there, which is untested and not asserted here. The one case where the guard is genuinely\n * load-bearing is a worker thread whose environment copy was blanked.\n *\n * The OS is UNTESTED here: every POSIX-mode test in `mcp-token-store-modes.test.ts` is\n * `it.skipIf(!POSIX)` and CI runs ubuntu only, so nothing exercises real Windows chmod semantics or\n * libuv's `USERPROFILE` lookup. The BRANCH SELECTION is tested — `process.platform` is spy-able, and\n * `test_the_store_reads_USERPROFILE_and_not_HOME_on_win32` pins all three legs.\n *\n * The split is reasoned from `os.homedir()`'s documented per-platform source. A previous revision\n * also cited `internal/runtime/fixtures/fixture-mode.ts:119` as support; that citation was WRONG and\n * is removed rather than quietly dropped. That line reads `process.env.HOME ?? process.env.USERPROFILE`\n * — HOME-first on every platform, which is the exact shape this split exists to avoid. It supports\n * the rejected alternative, not this one. (That the two modules now resolve different homes under\n * Git Bash is real and is filed separately; `fixture-mode` only probes for `~/.aws/credentials`.)\n *\n * Measured cost, not asserted: `homedir()` is 151 ns/op against 13 382 for the read this path\n * performs and 97 079 for the write (89x and 645x). The resolution is free relative to the I/O it\n * precedes.\n *\n * B-089. `packages/sdk/tests/mcp-token-store-modes.test.ts` pins it: import once, move HOME, write,\n * assert the write followed — and it must hold under `--pool=threads`, not only under the repo's\n * configured `forks`.\n *\n * B-090 — `THEOKIT_HOME` now WINS over the home-anchored default, and the reason is not tidiness.\n * `vitest.setup.ts` isolates every test in this package by pointing `THEOKIT_HOME` at a fresh\n * tmpdir; it backs `HOME` up and never sets it. A home-anchored module that ignored the variable\n * therefore resolved to the developer's REAL `~` while the suite believed it was isolated — and it\n * did: a default-config run deposited four refresh-token entries (`test-srv`, `srv-2`, `srv-race`,\n * `srv-roundtrip`) into `~/.theokit/mcp-tokens.json` from `tests/golden/mcp/oauth.golden.test.ts`.\n * A suite that is wrong about its own isolation is a false green about the one property the rest of\n * its greens rest on.\n *\n * **This is the code catching up to a contract the SDK already published**, not a new policy.\n * `src/project-env.ts:47-49` documents `THEOKIT_HOME` as \"Locates the SDK home — sessions, AND THE\n * CREDENTIAL STORE BENEATH IT\", and it is listed there as a sovereign key precisely because it\n * governs where credentials live. The public contract already said the store sits under the\n * variable; this module was the half that disagreed.\n *\n * The resolver adopted is `transcriptRoot()`'s (`internal/persistence/session-transcript.ts`), NOT\n * `paths.ts`'s `getTheokitHome(cwd)`. The transcript is the sibling with the right SHAPE: home-anchored\n * default, `THEOKIT_HOME` override, trimmed, empty-guarded — and its docstring records that before M94\n * it ignored the variable, so \"whoever set it had their state split in two silently\", which is this\n * defect verbatim. M94 ADR-2 already accepted that migration for identically-shaped state.\n * `getTheokitHome(cwd)` falls back to `<cwd>/.theokit`, so adopting IT would move the token file of\n * everyone who does not set the variable — and to a DIFFERENT place per working directory, making\n * whether you are logged in a property of which folder you launched from.\n *\n * **The migration this does carry**, stated rather than buried: a user who already holds\n * `~/.theokit/mcp-tokens.json` AND sets `THEOKIT_HOME` stops seeing those tokens. `getTokens` returns\n * `undefined`, which the caller surfaces as \"not logged in\", and the OAuth flow re-runs. Nothing is\n * deleted and nothing is overwritten — the old file stays where it is and is picked up again the\n * moment the variable is unset. No migration step is performed on the user's behalf, because\n * silently moving a credential file is a worse failure than a re-auth. Users who do NOT set\n * `THEOKIT_HOME` — the default — see no change at all.\n *\n * **Two further consequences for those who DO set it**, both on the directory-mode path rather than\n * on the path resolution, and both spelled out at {@link ensurePrivateStoreDir}: the store no longer\n * re-permissions a `$THEOKIT_HOME` it did not create, and `getTokens` REFUSES — typed, loud — to read\n * out of a group- or world-writable one instead of returning `undefined`.\n */\nfunction storeFilePath(): string {\n return storeLocation().file;\n}\n\n/**\n * Where the store lives, and whether that directory is OURS.\n *\n * `ours` is not bookkeeping — it decides whether this module is entitled to change the directory's\n * permissions. `<home>/.theokit` is a directory the SDK creates and owns; a `THEOKIT_HOME` root is\n * one the operator chose and may share with other state. See {@link ensurePrivateStoreDir}.\n */\ninterface StoreLocation {\n readonly dir: string;\n readonly file: string;\n readonly ours: boolean;\n}\n\n/**\n * The directory the token file lives in: `THEOKIT_HOME` when usable, `<home>/.theokit` otherwise.\n *\n * The empty/whitespace guard on the override is load-bearing in a way the HOME guard below is not:\n * `THEOKIT_HOME=\"\"` with no guard resolves the store to a CWD-RELATIVE `mcp-tokens.json`, and\n * `THEOKIT_HOME=\" \"` to a directory literally named three spaces. Neither falls back to anything;\n * both are new locations invented from an unusable value. `transcriptRoot()` guards it for the same\n * reason.\n */\nfunction storeLocation(): StoreLocation {\n const override = process.env.THEOKIT_HOME?.trim();\n if (override !== undefined && override.length > 0) {\n return { dir: override, file: join(override, \"mcp-tokens.json\"), ours: false };\n }\n // Mirrors `os.homedir()`'s own per-platform source: USERPROFILE on Windows, HOME elsewhere.\n const fromEnv =\n process.platform === \"win32\" ? process.env.USERPROFILE?.trim() : process.env.HOME?.trim();\n const home = fromEnv !== undefined && fromEnv.length > 0 ? fromEnv : homedir();\n const dir = join(home, \".theokit\");\n return { dir, file: join(dir, \"mcp-tokens.json\"), ours: true };\n}\n\n/**\n * Make the directory private BEFORE anything is written into it.\n *\n * `atomicWriteJson` auto-creates the parent with a bare recursive `mkdir`, so under the common umask\n * 002 `~/.theokit` was born 0775 — and the `chmod 600` applied to the file afterwards protects the\n * wrong thing. Write permission on a DIRECTORY is permission to unlink and recreate its contents, so\n * a 0600 file inside a group-writable directory can be replaced wholesale by another local user. The\n * secret here is a REFRESH TOKEN: replacing it swaps which account the agent authenticates as.\n *\n * **The retro-fix `chmod` is scoped to directories we own, and B-090 is why.** It was written\n * unconditional for a specific reason: `mkdir`'s mode applies only at CREATION, so every machine\n * that already ran an older build has a loose `~/.theokit` sitting there, and a fix that only covers\n * fresh installs does not reach the population that has the problem. That reasoning names its own\n * population — directories THIS MODULE created in an older build. Once `THEOKIT_HOME` is honoured,\n * an unconditional `chmod` also reaches a root the operator chose, which we never created and which\n * `paths.ts` documents as a multi-tenant deployment knob. Measured: it silently demoted a 0775\n * `$THEOKIT_HOME` to 0700, taking the sessions, transcripts, personality and credential-pool state\n * that share that root with it. No other consumer of the variable imposes a mode on it.\n *\n * So: always `mkdir` at 0700 (a directory WE create is born private wherever it is), and `chmod` an\n * existing one only when it is `<home>/.theokit`.\n *\n * The `chmod` deliberately does NOT also cover \"we just created it\". A first draft guarded it with\n * `ours || created !== undefined`; mutating that to plain `ours` killed no test, and the reason is\n * that the disjunct cannot make a difference: a umask only CLEARS bits, and 0700 carries none in the\n * group/other range, so `mkdir(0700)` is private for every possible umask. The redundant clause was\n * removed rather than pinned with a test written to justify it.\n *\n * **What that leaves, stated rather than left to be discovered.** A pre-existing group-writable\n * `$THEOKIT_HOME` is no longer repaired, so the next {@link getTokens} throws `CredentialError` from\n * `assertSecureModes` naming the directory and the `chmod 700` that fixes it. That is the intended\n * end state: a refresh token under a directory any local user can replace files in is not safe to\n * return, and the two available alternatives are worse. Silently tightening the operator's root\n * breaks their deployment to protect them from a choice they may have made deliberately; silently\n * returning the token hands the caller a credential that may already have been swapped. A loud,\n * actionable refusal is the only option that neither mutates someone else's directory nor lies about\n * what it read.\n *\n * The asymmetry that remains is real and is NOT fixed here: the write path has no such gate, so\n * `setTokens` will happily write into that directory and the following `getTokens` refuses it.\n * Adding a write-side gate is a separate behaviour change on a path that currently always succeeds.\n */\nfunction ensurePrivateStoreDir({ dir, ours }: StoreLocation): void {\n try {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n if (ours) chmodSync(dir, 0o700);\n } catch {\n // Windows: chmod is a no-op and the mode argument is meaningless. Same posture as the file\n // chmod below — documented in ADR D41 / EC-14.\n }\n}\n\ninterface KeytarLike {\n setPassword: (service: string, account: string, password: string) => Promise<void>;\n getPassword: (service: string, account: string) => Promise<string | null>;\n deletePassword: (service: string, account: string) => Promise<boolean>;\n}\n\nlet keytarWarned = false;\nlet cachedKeytar: KeytarLike | undefined | null;\nfunction tryRequireKeytar(): KeytarLike | null {\n if (cachedKeytar !== undefined) return cachedKeytar;\n try {\n const r = createRequire(import.meta.url);\n cachedKeytar = r(\"keytar\") as KeytarLike;\n } catch {\n if (!keytarWarned) {\n // The path is RESOLVED rather than spelled `~/.theokit/mcp-tokens.json`. That literal was\n // correct until B-090 made `THEOKIT_HOME` win, at which point a message naming a fixed\n // location would send anyone who sets the variable to look at a file the store no longer\n // writes — a diagnostic that lies costs more than one that is absent.\n diag(\n `[theokit-sdk] keytar not installed; MCP OAuth tokens will be stored in ${storeFilePath()} (chmod 600 where POSIX). Install \\`keytar\\` for OS keychain storage.\\n`,\n );\n keytarWarned = true;\n }\n cachedKeytar = null;\n }\n return cachedKeytar;\n}\n\n// EC-9 (race): serialize concurrent refreshes per server. Each key maps to\n// the in-flight refresh Promise; subsequent callers await the same promise.\nconst inflightRefresh = new Map<string, Promise<OAuthTokens>>();\n\n/**\n * Persist tokens for `serverName`. Tries keychain first, falls back to file\n * with chmod 600 (POSIX). Idempotent.\n *\n */\nexport async function setTokens(serverName: string, tokens: OAuthTokens): Promise<void> {\n const kt = tryRequireKeytar();\n const payload = JSON.stringify(tokens);\n if (kt !== null && kt !== undefined) {\n await kt.setPassword(KEYTAR_SERVICE, serverName, payload);\n return;\n }\n // File fallback. The directory is locked down first — see `ensurePrivateStoreDir`.\n // Resolved once for the whole operation and PASSED DOWN. Resolving per use would let a read and\n // the write that follows it disagree if HOME moved in between — and `ensurePrivateStoreDir`\n // resolving its own copy would let the directory be locked down under one home while the token\n // lands under another. Today those two statements are adjacent and synchronous so they cannot\n // diverge, but that is incidental; passing the path makes the invariant structural.\n const location = storeLocation();\n const filePath = location.file;\n ensurePrivateStoreDir(location);\n let allTokens: Record<string, OAuthTokens> = {};\n if (existsSync(filePath)) {\n try {\n allTokens = JSON.parse(readFileSync(filePath, \"utf8\")) as Record<string, OAuthTokens>;\n } catch {\n // corrupt file — start fresh\n allTokens = {};\n }\n }\n allTokens[serverName] = tokens;\n await atomicWriteJson(filePath, allTokens);\n try {\n chmodSync(filePath, 0o600);\n } catch {\n // Windows: chmod is a no-op. Documented in ADR D41 / EC-14.\n }\n}\n\n/**\n * Retrieve tokens for `serverName`. Returns undefined if absent.\n *\n */\nexport async function getTokens(serverName: string): Promise<OAuthTokens | undefined> {\n const kt = tryRequireKeytar();\n if (kt !== null && kt !== undefined) {\n const value = await kt.getPassword(KEYTAR_SERVICE, serverName);\n if (typeof value !== \"string\") return undefined;\n try {\n return JSON.parse(value) as OAuthTokens;\n } catch {\n return undefined;\n }\n }\n const filePath = storeFilePath();\n if (!existsSync(filePath)) return undefined;\n // The same gate the credential file gets, and deliberately the same implementation rather than a\n // second one: a refresh token is a credential, and `assertSecureModes` already carries the attack\n // it defends against in its docstring. It is called OUTSIDE the try/catch on purpose — the catch\n // below exists to treat a corrupt file as absent, and letting it swallow this would turn \"someone\n // else can replace your token\" into a silent `undefined`, which reads as \"not logged in\".\n assertSecureModes(dirname(filePath), filePath);\n try {\n const all = JSON.parse(readFileSync(filePath, \"utf8\")) as Record<string, OAuthTokens>;\n return all[serverName];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Serialize concurrent refresh attempts per server (EC-9). If a refresh is\n * already in flight for the same `serverName`, the second caller awaits\n * the same Promise.\n *\n */\nexport function lockedRefresh(\n serverName: string,\n refreshFn: () => Promise<OAuthTokens>,\n): Promise<OAuthTokens> {\n const existing = inflightRefresh.get(serverName);\n if (existing !== undefined) return existing;\n const promise = (async () => {\n try {\n return await refreshFn();\n } finally {\n inflightRefresh.delete(serverName);\n }\n })();\n inflightRefresh.set(serverName, promise);\n return promise;\n}\n\n/**\n * Reset all cached state. Test-only helper.\n *\n * @internal\n */\nexport function _resetForTests(): void {\n inflightRefresh.clear();\n cachedKeytar = undefined;\n keytarWarned = false;\n}\n","/**\n * OAuth 2.1 PKCE flow runner for MCP HTTP servers. See ADR D41.\n *\n * @internal\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { createInterface } from \"node:readline/promises\";\n\nimport { ConfigurationError } from \"../../errors.js\";\nimport type { McpOAuthConfig } from \"../../types/mcp.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { type OAuthTokens, setTokens } from \"./token-storage.js\";\n\n/**\n * Generate a random base64url-encoded string. Used for both code_verifier\n * (43-128 chars) and state (CSRF protection).\n */\nfunction base64url(n: number): string {\n return randomBytes(n).toString(\"base64url\");\n}\n\n/**\n * Compute PKCE code_challenge = base64url(SHA256(code_verifier)).\n */\nfunction challengeFor(verifier: string): string {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\");\n}\n\n/**\n * Refresh an access token using `refresh_token`. Throws on failure.\n *\n */\nexport async function refreshAccessToken(\n serverName: string,\n clientId: string,\n refreshToken: string,\n oauth: McpOAuthConfig,\n): Promise<OAuthTokens> {\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: clientId,\n });\n const response = await fetch(oauth.tokenEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n if (!response.ok) {\n throw new ConfigurationError(`OAuth refresh failed: HTTP ${response.status}`, {\n code: \"oauth_refresh_failed\",\n });\n }\n const data = (await response.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n scope?: string;\n };\n const obtainedAt = Date.now();\n const tokens: OAuthTokens = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? refreshToken,\n // EC-10: default conservative 3600s if expires_in missing.\n expiresAt: obtainedAt + (data.expires_in ?? 3600) * 1000,\n obtainedAt,\n ...(data.scope !== undefined ? { scope: data.scope } : {}),\n };\n await setTokens(serverName, tokens);\n return tokens;\n}\n\n/**\n * Run the full PKCE flow. Generates verifier+challenge+state, opens the\n * authorization URL (browser or manual print), waits for the callback\n * (localhost or stdin), exchanges code for tokens.\n *\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: PKCE flow is a linear protocol step (verifier → challenge → state → URL → wait → exchange); refactoring fragments the RFC 7636 narrative.\nexport async function runPkceFlow(\n serverName: string,\n clientId: string,\n scopes: string[] | undefined,\n oauth: McpOAuthConfig,\n): Promise<OAuthTokens> {\n const verifier = base64url(48);\n const challenge = challengeFor(verifier);\n const state = base64url(16);\n const timeoutMs = oauth.timeoutMs ?? 300_000;\n\n let redirectUri: string;\n let codeWaiter: Promise<{ code: string; state: string }>;\n let cleanup: () => void = () => {};\n\n if (oauth.redirectMode === \"localhost\") {\n const result = await openLocalhostCallback(state, timeoutMs);\n redirectUri = result.redirectUri;\n codeWaiter = result.waitFor;\n cleanup = result.close;\n } else {\n redirectUri = \"urn:ietf:wg:oauth:2.0:oob\";\n codeWaiter = readCodeFromStdin(state, timeoutMs);\n }\n\n try {\n const authUrl = new URL(oauth.authorizationEndpoint);\n authUrl.searchParams.set(\"response_type\", \"code\");\n authUrl.searchParams.set(\"client_id\", clientId);\n authUrl.searchParams.set(\"redirect_uri\", redirectUri);\n if (scopes !== undefined && scopes.length > 0) {\n authUrl.searchParams.set(\"scope\", scopes.join(\" \"));\n }\n authUrl.searchParams.set(\"code_challenge\", challenge);\n authUrl.searchParams.set(\"code_challenge_method\", \"S256\");\n authUrl.searchParams.set(\"state\", state);\n\n diag(\n `\\n[theokit-sdk] OAuth required for MCP server \"${serverName}\".\\n` +\n `Open this URL to authenticate:\\n ${authUrl.toString()}\\n\\n`,\n );\n\n const { code, state: returnedState } = await codeWaiter;\n // EC-2 MUST FIX: validate state.\n if (returnedState !== state) {\n throw new ConfigurationError(\n \"OAuth state mismatch — possible CSRF attempt; aborting token exchange.\",\n { code: \"oauth_state_mismatch\" },\n );\n }\n\n // Exchange code for tokens.\n const tokenBody = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n client_id: clientId,\n code_verifier: verifier,\n redirect_uri: redirectUri,\n });\n const response = await fetch(oauth.tokenEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: tokenBody.toString(),\n });\n if (!response.ok) {\n const errText = await response.text();\n throw new ConfigurationError(\n `OAuth token exchange failed: HTTP ${response.status}: ${errText.slice(0, 200)}`,\n { code: \"oauth_token_exchange_failed\" },\n );\n }\n const data = (await response.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n scope?: string;\n };\n const obtainedAt = Date.now();\n return {\n accessToken: data.access_token,\n ...(data.refresh_token !== undefined ? { refreshToken: data.refresh_token } : {}),\n // EC-10: default 3600s when expires_in absent.\n expiresAt: obtainedAt + (data.expires_in ?? 3600) * 1000,\n obtainedAt,\n ...(data.scope !== undefined ? { scope: data.scope } : {}),\n };\n } finally {\n cleanup();\n }\n}\n\n/**\n * Start a localhost HTTP server on a free port; return the redirect URI,\n * a promise that resolves with the code+state from the first valid request,\n * and a close handle.\n *\n * @internal\n */\nasync function openLocalhostCallback(\n expectedState: string,\n timeoutMs: number,\n): Promise<{\n redirectUri: string;\n waitFor: Promise<{ code: string; state: string }>;\n close: () => void;\n}> {\n let resolveCode: ((value: { code: string; state: string }) => void) | undefined;\n let rejectCode: ((reason: unknown) => void) | undefined;\n const waitFor = new Promise<{ code: string; state: string }>((res, rej) => {\n resolveCode = res;\n rejectCode = rej;\n });\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url ?? \"/\", \"http://127.0.0.1\");\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n if (typeof code !== \"string\" || typeof state !== \"string\") {\n res.statusCode = 400;\n res.end(\"Missing code or state\");\n return;\n }\n // EC-2: state must match the one we generated. We DO NOT trust any\n // localhost GET — only the one carrying our exact state.\n if (state !== expectedState) {\n res.statusCode = 400;\n res.end(\"State mismatch — request rejected.\");\n return;\n }\n res.statusCode = 200;\n res.end(\"Authentication successful. You can close this tab and return to the terminal.\");\n resolveCode?.({ code, state });\n });\n server.listen(0, \"127.0.0.1\");\n const timeoutHandle = setTimeout(() => {\n rejectCode?.(new ConfigurationError(\"OAuth flow timed out\", { code: \"oauth_timeout\" }));\n }, timeoutMs);\n // Wait for server.listen to bind so we can read the port.\n await new Promise<void>((r) => {\n if (server.listening) r();\n else server.once(\"listening\", () => r());\n });\n const address = server.address();\n if (typeof address !== \"object\" || address === null) {\n server.close();\n throw new ConfigurationError(\"OAuth localhost callback failed to bind\", {\n code: \"oauth_bind_failed\",\n });\n }\n const port = address.port;\n return {\n redirectUri: `http://127.0.0.1:${port}/callback`,\n waitFor,\n close: () => {\n clearTimeout(timeoutHandle);\n server.close();\n },\n };\n}\n\n/**\n * Read `code` (and `state`) from stdin (manual mode). User pastes the\n * full callback URL or just the code value.\n *\n * @internal\n */\nasync function readCodeFromStdin(\n expectedState: string,\n timeoutMs: number,\n): Promise<{ code: string; state: string }> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n const promise = new Promise<{ code: string; state: string }>((resolve, reject) => {\n rl.question(\"Paste the full callback URL (or just the code): \")\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: stdin reader handles 2 input formats (full URL vs raw code) inline; splitting fragments the manual-mode UX.\n .then((answer) => {\n rl.close();\n const trimmed = answer.trim();\n // Try to parse as URL first.\n if (trimmed.includes(\"?\")) {\n try {\n const parsed = new URL(trimmed);\n const code = parsed.searchParams.get(\"code\");\n const state = parsed.searchParams.get(\"state\") ?? \"\";\n if (typeof code === \"string\") {\n resolve({ code, state });\n return;\n }\n } catch {\n // not a URL — fall through\n }\n }\n // Treat the entire input as the code. State validation will fail\n // unless the user also provided state — but in manual mode they\n // typically paste the URL with state baked in.\n resolve({ code: trimmed, state: expectedState });\n })\n .catch(reject);\n setTimeout(() => {\n rl.close();\n reject(new ConfigurationError(\"OAuth manual input timed out\", { code: \"oauth_timeout\" }));\n }, timeoutMs);\n });\n return promise;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/mcp/token-storage.ts","../src/internal/mcp/oauth.ts"],"names":["join","homedir","mkdirSync","chmodSync","createRequire","diag","existsSync","readFileSync","atomicWriteJson","assertSecureModes","dirname","randomBytes","createHash","ConfigurationError","createServer","createInterface"],"mappings":"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","file":"mcp-auth.cjs","sourcesContent":["import { chmodSync, existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { assertSecureModes } from \"../auth/credential-store.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { atomicWriteJson } from \"../persistence/atomic-write.js\";\n\n/**\n * The OAuth tokens held for one MCP server. See ADR D41.\n *\n * Persisted per server name by `setTokens` and returned unchanged by `getTokens`. Where it lands\n * depends on what is installed: `keytar` puts the serialized bundle in the OS keychain, and\n * without it the bundle is written to a JSON file at mode 0600 inside a 0700 directory — in\n * PLAINTEXT, keyed by server name alongside every other server's tokens. Nothing here encrypts it.\n *\n * `refreshToken` is the field that matters most and the field that is optional. When present it\n * outlives `accessToken` and can mint new ones, so a leaked store is a persistent compromise of\n * the account rather than a temporary one. When absent, an expired access token means re-running\n * the authorization flow.\n *\n * `expiresAt` and `obtainedAt` are both epoch milliseconds and both describe the ACCESS token —\n * when it stops working, and when this bundle was issued. Nothing records when the refresh token\n * expires, so a refresh rejected because the grant itself lapsed is only discovered at the token\n * endpoint.\n *\n * The value is not validated on read: whatever JSON was stored is cast to this shape, so a\n * hand-edited or truncated store yields an object whose fields may be missing rather than an\n * error.\n *\n * `scope` records what the token was granted, as the server returned it. It is stored for\n * inspection; nothing in this module enforces it.\n *\n * @public — re-exported from `@theokit/sdk/mcp-auth`, and therefore under semver.\n */\nexport interface OAuthTokens {\n accessToken: string;\n refreshToken?: string;\n expiresAt: number; // ms epoch\n scope?: string;\n obtainedAt: number; // ms epoch\n}\n\nconst KEYTAR_SERVICE = \"theokit-mcp\";\n/**\n * Resolve the store path on every call instead of binding it once at module load.\n *\n * This used to be `const FILE_PATH = join(homedir(), ...)`. A module-level constant captures\n * ambient global state at IMPORT, so the store kept writing to whichever HOME was set when the\n * module first loaded and never noticed a later change. In production that is invisible, because\n * HOME does not move mid-process — but it made the module's correctness a property of *when* it was\n * imported, which is not a property a credential store should have.\n *\n * The environment variable is read FIRST and `homedir()` is the fallback, and the variable READ IS\n * PER PLATFORM because `os.homedir()` itself is: on POSIX it prefers `$HOME`, on Windows it reads\n * `USERPROFILE` and never consults `HOME`. Mirroring that split is what keeps this a pure\n * binding-time fix instead of a behaviour change.\n *\n * A previous revision read `process.env.HOME` on every platform. Review caught it: under Git Bash,\n * MSYS2 or Cygwin `HOME` IS set, to a POSIX-shaped path, and `path.win32.join(\"/c/Users/N\", ...)`\n * yields `\\c\\Users\\N\\.theokit\\...` where `USERPROFILE` would have given\n * `C:\\Users\\N\\.theokit\\...`. That would have hidden every existing token on those setups and\n * written a new credential file to a drive-relative path. It was published as \"on Windows HOME is\n * typically unset\" — an untested platform claim, and the same defect class it was written to fix.\n *\n * Why read the env at all: inside a worker thread `process.env` is a JS-level copy while\n * `os.homedir()` is a native call reading the real process environment, so code that moves the home\n * inside a worker is invisible to `homedir()`. Reading the env first makes this module independent\n * of the execution model, not just of the import moment.\n *\n * The empty/whitespace guard falls through to `homedir()`, and it buys LESS than two earlier\n * revisions of this comment claimed. Measured on POSIX: `homedir()` with `HOME=\"\"` returns `\"\"` and\n * with `HOME=\" \"` returns `\" \"` untrimmed, so the fallback hands back the same value the guard\n * rejected — close to a no-op. `path.join(\"\", \".theokit\", ...)` yields a CWD-RELATIVE\n * `.theokit/mcp-tokens.json`, never `/.theokit`; an earlier revision named that as the hazard and it\n * does not exist.\n *\n * On Windows it is UNKNOWN rather than load-bearing: the fallback reads the same `USERPROFILE`, so\n * whether the guard changes anything depends on whether an empty variable is reported as absent\n * there, which is untested and not asserted here. The one case where the guard is genuinely\n * load-bearing is a worker thread whose environment copy was blanked.\n *\n * The OS is UNTESTED here: every POSIX-mode test in `mcp/token-store-modes.test.ts` is\n * `it.skipIf(!POSIX)` and CI runs ubuntu only, so nothing exercises real Windows chmod semantics or\n * libuv's `USERPROFILE` lookup. The BRANCH SELECTION is tested — `process.platform` is spy-able, and\n * `test_the_store_reads_USERPROFILE_and_not_HOME_on_win32` pins all three legs.\n *\n * The split is reasoned from `os.homedir()`'s documented per-platform source. A previous revision\n * also cited `internal/runtime/fixtures/fixture-mode.ts:119` as support; that citation was WRONG and\n * is removed rather than quietly dropped. That line reads `process.env.HOME ?? process.env.USERPROFILE`\n * — HOME-first on every platform, which is the exact shape this split exists to avoid. It supports\n * the rejected alternative, not this one. (That the two modules now resolve different homes under\n * Git Bash is real and is filed separately; `fixture-mode` only probes for `~/.aws/credentials`.)\n *\n * Measured cost, not asserted: `homedir()` is 151 ns/op against 13 382 for the read this path\n * performs and 97 079 for the write (89x and 645x). The resolution is free relative to the I/O it\n * precedes.\n *\n * B-089. `packages/sdk/tests/mcp/token-store-modes.test.ts` pins it: import once, move HOME, write,\n * assert the write followed — and it must hold under `--pool=threads`, not only under the repo's\n * configured `forks`.\n *\n * B-090 — `THEOKIT_HOME` now WINS over the home-anchored default, and the reason is not tidiness.\n * `vitest.setup.ts` isolates every test in this package by pointing `THEOKIT_HOME` at a fresh\n * tmpdir; it backs `HOME` up and never sets it. A home-anchored module that ignored the variable\n * therefore resolved to the developer's REAL `~` while the suite believed it was isolated — and it\n * did: a default-config run deposited four refresh-token entries (`test-srv`, `srv-2`, `srv-race`,\n * `srv-roundtrip`) into `~/.theokit/mcp-tokens.json` from `tests/golden/mcp/oauth.golden.test.ts`.\n * A suite that is wrong about its own isolation is a false green about the one property the rest of\n * its greens rest on.\n *\n * **This is the code catching up to a contract the SDK already published**, not a new policy.\n * `src/project-env.ts:47-49` documents `THEOKIT_HOME` as \"Locates the SDK home — sessions, AND THE\n * CREDENTIAL STORE BENEATH IT\", and it is listed there as a sovereign key precisely because it\n * governs where credentials live. The public contract already said the store sits under the\n * variable; this module was the half that disagreed.\n *\n * The resolver adopted is `transcriptRoot()`'s (`internal/persistence/session-transcript.ts`), NOT\n * `paths.ts`'s `getTheokitHome(cwd)`. The transcript is the sibling with the right SHAPE: home-anchored\n * default, `THEOKIT_HOME` override, trimmed, empty-guarded — and its docstring records that before M94\n * it ignored the variable, so \"whoever set it had their state split in two silently\", which is this\n * defect verbatim. M94 ADR-2 already accepted that migration for identically-shaped state.\n * `getTheokitHome(cwd)` falls back to `<cwd>/.theokit`, so adopting IT would move the token file of\n * everyone who does not set the variable — and to a DIFFERENT place per working directory, making\n * whether you are logged in a property of which folder you launched from.\n *\n * **The migration this does carry**, stated rather than buried: a user who already holds\n * `~/.theokit/mcp-tokens.json` AND sets `THEOKIT_HOME` stops seeing those tokens. `getTokens` returns\n * `undefined`, which the caller surfaces as \"not logged in\", and the OAuth flow re-runs. Nothing is\n * deleted and nothing is overwritten — the old file stays where it is and is picked up again the\n * moment the variable is unset. No migration step is performed on the user's behalf, because\n * silently moving a credential file is a worse failure than a re-auth. Users who do NOT set\n * `THEOKIT_HOME` — the default — see no change at all.\n *\n * **Two further consequences for those who DO set it**, both on the directory-mode path rather than\n * on the path resolution, and both spelled out at {@link ensurePrivateStoreDir}: the store no longer\n * re-permissions a `$THEOKIT_HOME` it did not create, and `getTokens` REFUSES — typed, loud — to read\n * out of a group- or world-writable one instead of returning `undefined`.\n */\nfunction storeFilePath(): string {\n return storeLocation().file;\n}\n\n/**\n * Where the store lives, and whether that directory is OURS.\n *\n * `ours` is not bookkeeping — it decides whether this module is entitled to change the directory's\n * permissions. `<home>/.theokit` is a directory the SDK creates and owns; a `THEOKIT_HOME` root is\n * one the operator chose and may share with other state. See {@link ensurePrivateStoreDir}.\n */\ninterface StoreLocation {\n readonly dir: string;\n readonly file: string;\n readonly ours: boolean;\n}\n\n/**\n * The directory the token file lives in: `THEOKIT_HOME` when usable, `<home>/.theokit` otherwise.\n *\n * The empty/whitespace guard on the override is load-bearing in a way the HOME guard below is not:\n * `THEOKIT_HOME=\"\"` with no guard resolves the store to a CWD-RELATIVE `mcp-tokens.json`, and\n * `THEOKIT_HOME=\" \"` to a directory literally named three spaces. Neither falls back to anything;\n * both are new locations invented from an unusable value. `transcriptRoot()` guards it for the same\n * reason.\n */\nfunction storeLocation(): StoreLocation {\n const override = process.env.THEOKIT_HOME?.trim();\n if (override !== undefined && override.length > 0) {\n return { dir: override, file: join(override, \"mcp-tokens.json\"), ours: false };\n }\n // Mirrors `os.homedir()`'s own per-platform source: USERPROFILE on Windows, HOME elsewhere.\n const fromEnv =\n process.platform === \"win32\" ? process.env.USERPROFILE?.trim() : process.env.HOME?.trim();\n const home = fromEnv !== undefined && fromEnv.length > 0 ? fromEnv : homedir();\n const dir = join(home, \".theokit\");\n return { dir, file: join(dir, \"mcp-tokens.json\"), ours: true };\n}\n\n/**\n * Make the directory private BEFORE anything is written into it.\n *\n * `atomicWriteJson` auto-creates the parent with a bare recursive `mkdir`, so under the common umask\n * 002 `~/.theokit` was born 0775 — and the `chmod 600` applied to the file afterwards protects the\n * wrong thing. Write permission on a DIRECTORY is permission to unlink and recreate its contents, so\n * a 0600 file inside a group-writable directory can be replaced wholesale by another local user. The\n * secret here is a REFRESH TOKEN: replacing it swaps which account the agent authenticates as.\n *\n * **The retro-fix `chmod` is scoped to directories we own, and B-090 is why.** It was written\n * unconditional for a specific reason: `mkdir`'s mode applies only at CREATION, so every machine\n * that already ran an older build has a loose `~/.theokit` sitting there, and a fix that only covers\n * fresh installs does not reach the population that has the problem. That reasoning names its own\n * population — directories THIS MODULE created in an older build. Once `THEOKIT_HOME` is honoured,\n * an unconditional `chmod` also reaches a root the operator chose, which we never created and which\n * `paths.ts` documents as a multi-tenant deployment knob. Measured: it silently demoted a 0775\n * `$THEOKIT_HOME` to 0700, taking the sessions, transcripts, personality and credential-pool state\n * that share that root with it. No other consumer of the variable imposes a mode on it.\n *\n * So: always `mkdir` at 0700 (a directory WE create is born private wherever it is), and `chmod` an\n * existing one only when it is `<home>/.theokit`.\n *\n * The `chmod` deliberately does NOT also cover \"we just created it\". A first draft guarded it with\n * `ours || created !== undefined`; mutating that to plain `ours` killed no test, and the reason is\n * that the disjunct cannot make a difference: a umask only CLEARS bits, and 0700 carries none in the\n * group/other range, so `mkdir(0700)` is private for every possible umask. The redundant clause was\n * removed rather than pinned with a test written to justify it.\n *\n * **What that leaves, stated rather than left to be discovered.** A pre-existing group-writable\n * `$THEOKIT_HOME` is no longer repaired, so the next {@link getTokens} throws `CredentialError` from\n * `assertSecureModes` naming the directory and the `chmod 700` that fixes it. That is the intended\n * end state: a refresh token under a directory any local user can replace files in is not safe to\n * return, and the two available alternatives are worse. Silently tightening the operator's root\n * breaks their deployment to protect them from a choice they may have made deliberately; silently\n * returning the token hands the caller a credential that may already have been swapped. A loud,\n * actionable refusal is the only option that neither mutates someone else's directory nor lies about\n * what it read.\n *\n * The asymmetry that remains is real and is NOT fixed here: the write path has no such gate, so\n * `setTokens` will happily write into that directory and the following `getTokens` refuses it.\n * Adding a write-side gate is a separate behaviour change on a path that currently always succeeds.\n */\nfunction ensurePrivateStoreDir({ dir, ours }: StoreLocation): void {\n try {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n if (ours) chmodSync(dir, 0o700);\n } catch {\n // Windows: chmod is a no-op and the mode argument is meaningless. Same posture as the file\n // chmod below — documented in ADR D41 / EC-14.\n }\n}\n\ninterface KeytarLike {\n setPassword: (service: string, account: string, password: string) => Promise<void>;\n getPassword: (service: string, account: string) => Promise<string | null>;\n deletePassword: (service: string, account: string) => Promise<boolean>;\n}\n\nlet keytarWarned = false;\nlet cachedKeytar: KeytarLike | undefined | null;\nfunction tryRequireKeytar(): KeytarLike | null {\n if (cachedKeytar !== undefined) return cachedKeytar;\n try {\n const r = createRequire(import.meta.url);\n cachedKeytar = r(\"keytar\") as KeytarLike;\n } catch {\n if (!keytarWarned) {\n // The path is RESOLVED rather than spelled `~/.theokit/mcp-tokens.json`. That literal was\n // correct until B-090 made `THEOKIT_HOME` win, at which point a message naming a fixed\n // location would send anyone who sets the variable to look at a file the store no longer\n // writes — a diagnostic that lies costs more than one that is absent.\n diag(\n `[theokit-sdk] keytar not installed; MCP OAuth tokens will be stored in ${storeFilePath()} (chmod 600 where POSIX). Install \\`keytar\\` for OS keychain storage.\\n`,\n );\n keytarWarned = true;\n }\n cachedKeytar = null;\n }\n return cachedKeytar;\n}\n\n// EC-9 (race): serialize concurrent refreshes per server. Each key maps to\n// the in-flight refresh Promise; subsequent callers await the same promise.\nconst inflightRefresh = new Map<string, Promise<OAuthTokens>>();\n\n/**\n * Persist tokens for `serverName`. Tries keychain first, falls back to file\n * with chmod 600 (POSIX). Idempotent.\n *\n */\nexport async function setTokens(serverName: string, tokens: OAuthTokens): Promise<void> {\n const kt = tryRequireKeytar();\n const payload = JSON.stringify(tokens);\n if (kt !== null && kt !== undefined) {\n await kt.setPassword(KEYTAR_SERVICE, serverName, payload);\n return;\n }\n // File fallback. The directory is locked down first — see `ensurePrivateStoreDir`.\n // Resolved once for the whole operation and PASSED DOWN. Resolving per use would let a read and\n // the write that follows it disagree if HOME moved in between — and `ensurePrivateStoreDir`\n // resolving its own copy would let the directory be locked down under one home while the token\n // lands under another. Today those two statements are adjacent and synchronous so they cannot\n // diverge, but that is incidental; passing the path makes the invariant structural.\n const location = storeLocation();\n const filePath = location.file;\n ensurePrivateStoreDir(location);\n let allTokens: Record<string, OAuthTokens> = {};\n if (existsSync(filePath)) {\n try {\n allTokens = JSON.parse(readFileSync(filePath, \"utf8\")) as Record<string, OAuthTokens>;\n } catch {\n // corrupt file — start fresh\n allTokens = {};\n }\n }\n allTokens[serverName] = tokens;\n await atomicWriteJson(filePath, allTokens);\n try {\n chmodSync(filePath, 0o600);\n } catch {\n // Windows: chmod is a no-op. Documented in ADR D41 / EC-14.\n }\n}\n\n/**\n * Retrieve tokens for `serverName`. Returns undefined if absent.\n *\n */\nexport async function getTokens(serverName: string): Promise<OAuthTokens | undefined> {\n const kt = tryRequireKeytar();\n if (kt !== null && kt !== undefined) {\n const value = await kt.getPassword(KEYTAR_SERVICE, serverName);\n if (typeof value !== \"string\") return undefined;\n try {\n return JSON.parse(value) as OAuthTokens;\n } catch {\n return undefined;\n }\n }\n const filePath = storeFilePath();\n if (!existsSync(filePath)) return undefined;\n // The same gate the credential file gets, and deliberately the same implementation rather than a\n // second one: a refresh token is a credential, and `assertSecureModes` already carries the attack\n // it defends against in its docstring. It is called OUTSIDE the try/catch on purpose — the catch\n // below exists to treat a corrupt file as absent, and letting it swallow this would turn \"someone\n // else can replace your token\" into a silent `undefined`, which reads as \"not logged in\".\n assertSecureModes(dirname(filePath), filePath);\n try {\n const all = JSON.parse(readFileSync(filePath, \"utf8\")) as Record<string, OAuthTokens>;\n return all[serverName];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Serialize concurrent refresh attempts per server (EC-9). If a refresh is\n * already in flight for the same `serverName`, the second caller awaits\n * the same Promise.\n *\n */\nexport function lockedRefresh(\n serverName: string,\n refreshFn: () => Promise<OAuthTokens>,\n): Promise<OAuthTokens> {\n const existing = inflightRefresh.get(serverName);\n if (existing !== undefined) return existing;\n const promise = (async () => {\n try {\n return await refreshFn();\n } finally {\n inflightRefresh.delete(serverName);\n }\n })();\n inflightRefresh.set(serverName, promise);\n return promise;\n}\n\n/**\n * Reset all cached state. Test-only helper.\n *\n * @internal\n */\nexport function _resetForTests(): void {\n inflightRefresh.clear();\n cachedKeytar = undefined;\n keytarWarned = false;\n}\n","/**\n * OAuth 2.1 PKCE flow runner for MCP HTTP servers. See ADR D41.\n *\n * @internal\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { createInterface } from \"node:readline/promises\";\n\nimport { ConfigurationError } from \"../../errors.js\";\nimport type { McpOAuthConfig } from \"../../types/mcp.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { type OAuthTokens, setTokens } from \"./token-storage.js\";\n\n/**\n * Generate a random base64url-encoded string. Used for both code_verifier\n * (43-128 chars) and state (CSRF protection).\n */\nfunction base64url(n: number): string {\n return randomBytes(n).toString(\"base64url\");\n}\n\n/**\n * Compute PKCE code_challenge = base64url(SHA256(code_verifier)).\n */\nfunction challengeFor(verifier: string): string {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\");\n}\n\n/**\n * Refresh an access token using `refresh_token`. Throws on failure.\n *\n */\nexport async function refreshAccessToken(\n serverName: string,\n clientId: string,\n refreshToken: string,\n oauth: McpOAuthConfig,\n): Promise<OAuthTokens> {\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: clientId,\n });\n const response = await fetch(oauth.tokenEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n if (!response.ok) {\n throw new ConfigurationError(`OAuth refresh failed: HTTP ${response.status}`, {\n code: \"oauth_refresh_failed\",\n });\n }\n const data = (await response.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n scope?: string;\n };\n const obtainedAt = Date.now();\n const tokens: OAuthTokens = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? refreshToken,\n // EC-10: default conservative 3600s if expires_in missing.\n expiresAt: obtainedAt + (data.expires_in ?? 3600) * 1000,\n obtainedAt,\n ...(data.scope !== undefined ? { scope: data.scope } : {}),\n };\n await setTokens(serverName, tokens);\n return tokens;\n}\n\n/**\n * Run the full PKCE flow. Generates verifier+challenge+state, opens the\n * authorization URL (browser or manual print), waits for the callback\n * (localhost or stdin), exchanges code for tokens.\n *\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: PKCE flow is a linear protocol step (verifier → challenge → state → URL → wait → exchange); refactoring fragments the RFC 7636 narrative.\nexport async function runPkceFlow(\n serverName: string,\n clientId: string,\n scopes: string[] | undefined,\n oauth: McpOAuthConfig,\n): Promise<OAuthTokens> {\n const verifier = base64url(48);\n const challenge = challengeFor(verifier);\n const state = base64url(16);\n const timeoutMs = oauth.timeoutMs ?? 300_000;\n\n let redirectUri: string;\n let codeWaiter: Promise<{ code: string; state: string }>;\n let cleanup: () => void = () => {};\n\n if (oauth.redirectMode === \"localhost\") {\n const result = await openLocalhostCallback(state, timeoutMs);\n redirectUri = result.redirectUri;\n codeWaiter = result.waitFor;\n cleanup = result.close;\n } else {\n redirectUri = \"urn:ietf:wg:oauth:2.0:oob\";\n codeWaiter = readCodeFromStdin(state, timeoutMs);\n }\n\n try {\n const authUrl = new URL(oauth.authorizationEndpoint);\n authUrl.searchParams.set(\"response_type\", \"code\");\n authUrl.searchParams.set(\"client_id\", clientId);\n authUrl.searchParams.set(\"redirect_uri\", redirectUri);\n if (scopes !== undefined && scopes.length > 0) {\n authUrl.searchParams.set(\"scope\", scopes.join(\" \"));\n }\n authUrl.searchParams.set(\"code_challenge\", challenge);\n authUrl.searchParams.set(\"code_challenge_method\", \"S256\");\n authUrl.searchParams.set(\"state\", state);\n\n diag(\n `\\n[theokit-sdk] OAuth required for MCP server \"${serverName}\".\\n` +\n `Open this URL to authenticate:\\n ${authUrl.toString()}\\n\\n`,\n );\n\n const { code, state: returnedState } = await codeWaiter;\n // EC-2 MUST FIX: validate state.\n if (returnedState !== state) {\n throw new ConfigurationError(\n \"OAuth state mismatch — possible CSRF attempt; aborting token exchange.\",\n { code: \"oauth_state_mismatch\" },\n );\n }\n\n // Exchange code for tokens.\n const tokenBody = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n client_id: clientId,\n code_verifier: verifier,\n redirect_uri: redirectUri,\n });\n const response = await fetch(oauth.tokenEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: tokenBody.toString(),\n });\n if (!response.ok) {\n const errText = await response.text();\n throw new ConfigurationError(\n `OAuth token exchange failed: HTTP ${response.status}: ${errText.slice(0, 200)}`,\n { code: \"oauth_token_exchange_failed\" },\n );\n }\n const data = (await response.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n scope?: string;\n };\n const obtainedAt = Date.now();\n return {\n accessToken: data.access_token,\n ...(data.refresh_token !== undefined ? { refreshToken: data.refresh_token } : {}),\n // EC-10: default 3600s when expires_in absent.\n expiresAt: obtainedAt + (data.expires_in ?? 3600) * 1000,\n obtainedAt,\n ...(data.scope !== undefined ? { scope: data.scope } : {}),\n };\n } finally {\n cleanup();\n }\n}\n\n/**\n * Start a localhost HTTP server on a free port; return the redirect URI,\n * a promise that resolves with the code+state from the first valid request,\n * and a close handle.\n *\n * @internal\n */\nasync function openLocalhostCallback(\n expectedState: string,\n timeoutMs: number,\n): Promise<{\n redirectUri: string;\n waitFor: Promise<{ code: string; state: string }>;\n close: () => void;\n}> {\n let resolveCode: ((value: { code: string; state: string }) => void) | undefined;\n let rejectCode: ((reason: unknown) => void) | undefined;\n const waitFor = new Promise<{ code: string; state: string }>((res, rej) => {\n resolveCode = res;\n rejectCode = rej;\n });\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url ?? \"/\", \"http://127.0.0.1\");\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n if (typeof code !== \"string\" || typeof state !== \"string\") {\n res.statusCode = 400;\n res.end(\"Missing code or state\");\n return;\n }\n // EC-2: state must match the one we generated. We DO NOT trust any\n // localhost GET — only the one carrying our exact state.\n if (state !== expectedState) {\n res.statusCode = 400;\n res.end(\"State mismatch — request rejected.\");\n return;\n }\n res.statusCode = 200;\n res.end(\"Authentication successful. You can close this tab and return to the terminal.\");\n resolveCode?.({ code, state });\n });\n server.listen(0, \"127.0.0.1\");\n const timeoutHandle = setTimeout(() => {\n rejectCode?.(new ConfigurationError(\"OAuth flow timed out\", { code: \"oauth_timeout\" }));\n }, timeoutMs);\n // Wait for server.listen to bind so we can read the port.\n await new Promise<void>((r) => {\n if (server.listening) r();\n else server.once(\"listening\", () => r());\n });\n const address = server.address();\n if (typeof address !== \"object\" || address === null) {\n server.close();\n throw new ConfigurationError(\"OAuth localhost callback failed to bind\", {\n code: \"oauth_bind_failed\",\n });\n }\n const port = address.port;\n return {\n redirectUri: `http://127.0.0.1:${port}/callback`,\n waitFor,\n close: () => {\n clearTimeout(timeoutHandle);\n server.close();\n },\n };\n}\n\n/**\n * Read `code` (and `state`) from stdin (manual mode). User pastes the\n * full callback URL or just the code value.\n *\n * @internal\n */\nasync function readCodeFromStdin(\n expectedState: string,\n timeoutMs: number,\n): Promise<{ code: string; state: string }> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n const promise = new Promise<{ code: string; state: string }>((resolve, reject) => {\n rl.question(\"Paste the full callback URL (or just the code): \")\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: stdin reader handles 2 input formats (full URL vs raw code) inline; splitting fragments the manual-mode UX.\n .then((answer) => {\n rl.close();\n const trimmed = answer.trim();\n // Try to parse as URL first.\n if (trimmed.includes(\"?\")) {\n try {\n const parsed = new URL(trimmed);\n const code = parsed.searchParams.get(\"code\");\n const state = parsed.searchParams.get(\"state\") ?? \"\";\n if (typeof code === \"string\") {\n resolve({ code, state });\n return;\n }\n } catch {\n // not a URL — fall through\n }\n }\n // Treat the entire input as the code. State validation will fail\n // unless the user also provided state — but in manual mode they\n // typically paste the URL with state baked in.\n resolve({ code: trimmed, state: expectedState });\n })\n .catch(reject);\n setTimeout(() => {\n rl.close();\n reject(new ConfigurationError(\"OAuth manual input timed out\", { code: \"oauth_timeout\" }));\n }, timeoutMs);\n });\n return promise;\n}\n"]}
|
package/dist/mcp-auth.d.cts
CHANGED
package/dist/mcp-auth.d.ts
CHANGED
package/dist/mcp-auth.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { atomicWriteJson } from './chunk-
|
|
2
|
-
import { assertSecureModes } from './chunk-
|
|
3
|
-
import { ConfigurationError } from './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import { diag } from './chunk-XEQ3TM66.js';
|
|
1
|
+
import { atomicWriteJson } from './chunk-3JHIFQ4I.js';
|
|
2
|
+
import { assertSecureModes } from './chunk-V22DZIXO.js';
|
|
3
|
+
import { ConfigurationError } from './chunk-ALUN2B4W.js';
|
|
4
|
+
import { diag } from './chunk-CZJ6Q7CW.js';
|
|
6
5
|
import { randomBytes, createHash } from 'crypto';
|
|
7
6
|
import { createServer } from 'http';
|
|
8
7
|
import { createInterface } from 'readline/promises';
|
package/dist/mcp-auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/mcp/token-storage.ts","../src/internal/mcp/oauth.ts"],"names":[],"mappings":"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","file":"mcp-auth.js","sourcesContent":["import { chmodSync, existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { assertSecureModes } from \"../auth/credential-store.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { atomicWriteJson } from \"../persistence/atomic-write.js\";\n\n/**\n * The OAuth tokens held for one MCP server. See ADR D41.\n *\n * Persisted per server name by `setTokens` and returned unchanged by `getTokens`. Where it lands\n * depends on what is installed: `keytar` puts the serialized bundle in the OS keychain, and\n * without it the bundle is written to a JSON file at mode 0600 inside a 0700 directory — in\n * PLAINTEXT, keyed by server name alongside every other server's tokens. Nothing here encrypts it.\n *\n * `refreshToken` is the field that matters most and the field that is optional. When present it\n * outlives `accessToken` and can mint new ones, so a leaked store is a persistent compromise of\n * the account rather than a temporary one. When absent, an expired access token means re-running\n * the authorization flow.\n *\n * `expiresAt` and `obtainedAt` are both epoch milliseconds and both describe the ACCESS token —\n * when it stops working, and when this bundle was issued. Nothing records when the refresh token\n * expires, so a refresh rejected because the grant itself lapsed is only discovered at the token\n * endpoint.\n *\n * The value is not validated on read: whatever JSON was stored is cast to this shape, so a\n * hand-edited or truncated store yields an object whose fields may be missing rather than an\n * error.\n *\n * `scope` records what the token was granted, as the server returned it. It is stored for\n * inspection; nothing in this module enforces it.\n *\n * @public — re-exported from `@theokit/sdk/mcp-auth`, and therefore under semver.\n */\nexport interface OAuthTokens {\n accessToken: string;\n refreshToken?: string;\n expiresAt: number; // ms epoch\n scope?: string;\n obtainedAt: number; // ms epoch\n}\n\nconst KEYTAR_SERVICE = \"theokit-mcp\";\n/**\n * Resolve the store path on every call instead of binding it once at module load.\n *\n * This used to be `const FILE_PATH = join(homedir(), ...)`. A module-level constant captures\n * ambient global state at IMPORT, so the store kept writing to whichever HOME was set when the\n * module first loaded and never noticed a later change. In production that is invisible, because\n * HOME does not move mid-process — but it made the module's correctness a property of *when* it was\n * imported, which is not a property a credential store should have.\n *\n * The environment variable is read FIRST and `homedir()` is the fallback, and the variable READ IS\n * PER PLATFORM because `os.homedir()` itself is: on POSIX it prefers `$HOME`, on Windows it reads\n * `USERPROFILE` and never consults `HOME`. Mirroring that split is what keeps this a pure\n * binding-time fix instead of a behaviour change.\n *\n * A previous revision read `process.env.HOME` on every platform. Review caught it: under Git Bash,\n * MSYS2 or Cygwin `HOME` IS set, to a POSIX-shaped path, and `path.win32.join(\"/c/Users/N\", ...)`\n * yields `\\c\\Users\\N\\.theokit\\...` where `USERPROFILE` would have given\n * `C:\\Users\\N\\.theokit\\...`. That would have hidden every existing token on those setups and\n * written a new credential file to a drive-relative path. It was published as \"on Windows HOME is\n * typically unset\" — an untested platform claim, and the same defect class it was written to fix.\n *\n * Why read the env at all: inside a worker thread `process.env` is a JS-level copy while\n * `os.homedir()` is a native call reading the real process environment, so code that moves the home\n * inside a worker is invisible to `homedir()`. Reading the env first makes this module independent\n * of the execution model, not just of the import moment.\n *\n * The empty/whitespace guard falls through to `homedir()`, and it buys LESS than two earlier\n * revisions of this comment claimed. Measured on POSIX: `homedir()` with `HOME=\"\"` returns `\"\"` and\n * with `HOME=\" \"` returns `\" \"` untrimmed, so the fallback hands back the same value the guard\n * rejected — close to a no-op. `path.join(\"\", \".theokit\", ...)` yields a CWD-RELATIVE\n * `.theokit/mcp-tokens.json`, never `/.theokit`; an earlier revision named that as the hazard and it\n * does not exist.\n *\n * On Windows it is UNKNOWN rather than load-bearing: the fallback reads the same `USERPROFILE`, so\n * whether the guard changes anything depends on whether an empty variable is reported as absent\n * there, which is untested and not asserted here. The one case where the guard is genuinely\n * load-bearing is a worker thread whose environment copy was blanked.\n *\n * The OS is UNTESTED here: every POSIX-mode test in `mcp-token-store-modes.test.ts` is\n * `it.skipIf(!POSIX)` and CI runs ubuntu only, so nothing exercises real Windows chmod semantics or\n * libuv's `USERPROFILE` lookup. The BRANCH SELECTION is tested — `process.platform` is spy-able, and\n * `test_the_store_reads_USERPROFILE_and_not_HOME_on_win32` pins all three legs.\n *\n * The split is reasoned from `os.homedir()`'s documented per-platform source. A previous revision\n * also cited `internal/runtime/fixtures/fixture-mode.ts:119` as support; that citation was WRONG and\n * is removed rather than quietly dropped. That line reads `process.env.HOME ?? process.env.USERPROFILE`\n * — HOME-first on every platform, which is the exact shape this split exists to avoid. It supports\n * the rejected alternative, not this one. (That the two modules now resolve different homes under\n * Git Bash is real and is filed separately; `fixture-mode` only probes for `~/.aws/credentials`.)\n *\n * Measured cost, not asserted: `homedir()` is 151 ns/op against 13 382 for the read this path\n * performs and 97 079 for the write (89x and 645x). The resolution is free relative to the I/O it\n * precedes.\n *\n * B-089. `packages/sdk/tests/mcp-token-store-modes.test.ts` pins it: import once, move HOME, write,\n * assert the write followed — and it must hold under `--pool=threads`, not only under the repo's\n * configured `forks`.\n *\n * B-090 — `THEOKIT_HOME` now WINS over the home-anchored default, and the reason is not tidiness.\n * `vitest.setup.ts` isolates every test in this package by pointing `THEOKIT_HOME` at a fresh\n * tmpdir; it backs `HOME` up and never sets it. A home-anchored module that ignored the variable\n * therefore resolved to the developer's REAL `~` while the suite believed it was isolated — and it\n * did: a default-config run deposited four refresh-token entries (`test-srv`, `srv-2`, `srv-race`,\n * `srv-roundtrip`) into `~/.theokit/mcp-tokens.json` from `tests/golden/mcp/oauth.golden.test.ts`.\n * A suite that is wrong about its own isolation is a false green about the one property the rest of\n * its greens rest on.\n *\n * **This is the code catching up to a contract the SDK already published**, not a new policy.\n * `src/project-env.ts:47-49` documents `THEOKIT_HOME` as \"Locates the SDK home — sessions, AND THE\n * CREDENTIAL STORE BENEATH IT\", and it is listed there as a sovereign key precisely because it\n * governs where credentials live. The public contract already said the store sits under the\n * variable; this module was the half that disagreed.\n *\n * The resolver adopted is `transcriptRoot()`'s (`internal/persistence/session-transcript.ts`), NOT\n * `paths.ts`'s `getTheokitHome(cwd)`. The transcript is the sibling with the right SHAPE: home-anchored\n * default, `THEOKIT_HOME` override, trimmed, empty-guarded — and its docstring records that before M94\n * it ignored the variable, so \"whoever set it had their state split in two silently\", which is this\n * defect verbatim. M94 ADR-2 already accepted that migration for identically-shaped state.\n * `getTheokitHome(cwd)` falls back to `<cwd>/.theokit`, so adopting IT would move the token file of\n * everyone who does not set the variable — and to a DIFFERENT place per working directory, making\n * whether you are logged in a property of which folder you launched from.\n *\n * **The migration this does carry**, stated rather than buried: a user who already holds\n * `~/.theokit/mcp-tokens.json` AND sets `THEOKIT_HOME` stops seeing those tokens. `getTokens` returns\n * `undefined`, which the caller surfaces as \"not logged in\", and the OAuth flow re-runs. Nothing is\n * deleted and nothing is overwritten — the old file stays where it is and is picked up again the\n * moment the variable is unset. No migration step is performed on the user's behalf, because\n * silently moving a credential file is a worse failure than a re-auth. Users who do NOT set\n * `THEOKIT_HOME` — the default — see no change at all.\n *\n * **Two further consequences for those who DO set it**, both on the directory-mode path rather than\n * on the path resolution, and both spelled out at {@link ensurePrivateStoreDir}: the store no longer\n * re-permissions a `$THEOKIT_HOME` it did not create, and `getTokens` REFUSES — typed, loud — to read\n * out of a group- or world-writable one instead of returning `undefined`.\n */\nfunction storeFilePath(): string {\n return storeLocation().file;\n}\n\n/**\n * Where the store lives, and whether that directory is OURS.\n *\n * `ours` is not bookkeeping — it decides whether this module is entitled to change the directory's\n * permissions. `<home>/.theokit` is a directory the SDK creates and owns; a `THEOKIT_HOME` root is\n * one the operator chose and may share with other state. See {@link ensurePrivateStoreDir}.\n */\ninterface StoreLocation {\n readonly dir: string;\n readonly file: string;\n readonly ours: boolean;\n}\n\n/**\n * The directory the token file lives in: `THEOKIT_HOME` when usable, `<home>/.theokit` otherwise.\n *\n * The empty/whitespace guard on the override is load-bearing in a way the HOME guard below is not:\n * `THEOKIT_HOME=\"\"` with no guard resolves the store to a CWD-RELATIVE `mcp-tokens.json`, and\n * `THEOKIT_HOME=\" \"` to a directory literally named three spaces. Neither falls back to anything;\n * both are new locations invented from an unusable value. `transcriptRoot()` guards it for the same\n * reason.\n */\nfunction storeLocation(): StoreLocation {\n const override = process.env.THEOKIT_HOME?.trim();\n if (override !== undefined && override.length > 0) {\n return { dir: override, file: join(override, \"mcp-tokens.json\"), ours: false };\n }\n // Mirrors `os.homedir()`'s own per-platform source: USERPROFILE on Windows, HOME elsewhere.\n const fromEnv =\n process.platform === \"win32\" ? process.env.USERPROFILE?.trim() : process.env.HOME?.trim();\n const home = fromEnv !== undefined && fromEnv.length > 0 ? fromEnv : homedir();\n const dir = join(home, \".theokit\");\n return { dir, file: join(dir, \"mcp-tokens.json\"), ours: true };\n}\n\n/**\n * Make the directory private BEFORE anything is written into it.\n *\n * `atomicWriteJson` auto-creates the parent with a bare recursive `mkdir`, so under the common umask\n * 002 `~/.theokit` was born 0775 — and the `chmod 600` applied to the file afterwards protects the\n * wrong thing. Write permission on a DIRECTORY is permission to unlink and recreate its contents, so\n * a 0600 file inside a group-writable directory can be replaced wholesale by another local user. The\n * secret here is a REFRESH TOKEN: replacing it swaps which account the agent authenticates as.\n *\n * **The retro-fix `chmod` is scoped to directories we own, and B-090 is why.** It was written\n * unconditional for a specific reason: `mkdir`'s mode applies only at CREATION, so every machine\n * that already ran an older build has a loose `~/.theokit` sitting there, and a fix that only covers\n * fresh installs does not reach the population that has the problem. That reasoning names its own\n * population — directories THIS MODULE created in an older build. Once `THEOKIT_HOME` is honoured,\n * an unconditional `chmod` also reaches a root the operator chose, which we never created and which\n * `paths.ts` documents as a multi-tenant deployment knob. Measured: it silently demoted a 0775\n * `$THEOKIT_HOME` to 0700, taking the sessions, transcripts, personality and credential-pool state\n * that share that root with it. No other consumer of the variable imposes a mode on it.\n *\n * So: always `mkdir` at 0700 (a directory WE create is born private wherever it is), and `chmod` an\n * existing one only when it is `<home>/.theokit`.\n *\n * The `chmod` deliberately does NOT also cover \"we just created it\". A first draft guarded it with\n * `ours || created !== undefined`; mutating that to plain `ours` killed no test, and the reason is\n * that the disjunct cannot make a difference: a umask only CLEARS bits, and 0700 carries none in the\n * group/other range, so `mkdir(0700)` is private for every possible umask. The redundant clause was\n * removed rather than pinned with a test written to justify it.\n *\n * **What that leaves, stated rather than left to be discovered.** A pre-existing group-writable\n * `$THEOKIT_HOME` is no longer repaired, so the next {@link getTokens} throws `CredentialError` from\n * `assertSecureModes` naming the directory and the `chmod 700` that fixes it. That is the intended\n * end state: a refresh token under a directory any local user can replace files in is not safe to\n * return, and the two available alternatives are worse. Silently tightening the operator's root\n * breaks their deployment to protect them from a choice they may have made deliberately; silently\n * returning the token hands the caller a credential that may already have been swapped. A loud,\n * actionable refusal is the only option that neither mutates someone else's directory nor lies about\n * what it read.\n *\n * The asymmetry that remains is real and is NOT fixed here: the write path has no such gate, so\n * `setTokens` will happily write into that directory and the following `getTokens` refuses it.\n * Adding a write-side gate is a separate behaviour change on a path that currently always succeeds.\n */\nfunction ensurePrivateStoreDir({ dir, ours }: StoreLocation): void {\n try {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n if (ours) chmodSync(dir, 0o700);\n } catch {\n // Windows: chmod is a no-op and the mode argument is meaningless. Same posture as the file\n // chmod below — documented in ADR D41 / EC-14.\n }\n}\n\ninterface KeytarLike {\n setPassword: (service: string, account: string, password: string) => Promise<void>;\n getPassword: (service: string, account: string) => Promise<string | null>;\n deletePassword: (service: string, account: string) => Promise<boolean>;\n}\n\nlet keytarWarned = false;\nlet cachedKeytar: KeytarLike | undefined | null;\nfunction tryRequireKeytar(): KeytarLike | null {\n if (cachedKeytar !== undefined) return cachedKeytar;\n try {\n const r = createRequire(import.meta.url);\n cachedKeytar = r(\"keytar\") as KeytarLike;\n } catch {\n if (!keytarWarned) {\n // The path is RESOLVED rather than spelled `~/.theokit/mcp-tokens.json`. That literal was\n // correct until B-090 made `THEOKIT_HOME` win, at which point a message naming a fixed\n // location would send anyone who sets the variable to look at a file the store no longer\n // writes — a diagnostic that lies costs more than one that is absent.\n diag(\n `[theokit-sdk] keytar not installed; MCP OAuth tokens will be stored in ${storeFilePath()} (chmod 600 where POSIX). Install \\`keytar\\` for OS keychain storage.\\n`,\n );\n keytarWarned = true;\n }\n cachedKeytar = null;\n }\n return cachedKeytar;\n}\n\n// EC-9 (race): serialize concurrent refreshes per server. Each key maps to\n// the in-flight refresh Promise; subsequent callers await the same promise.\nconst inflightRefresh = new Map<string, Promise<OAuthTokens>>();\n\n/**\n * Persist tokens for `serverName`. Tries keychain first, falls back to file\n * with chmod 600 (POSIX). Idempotent.\n *\n */\nexport async function setTokens(serverName: string, tokens: OAuthTokens): Promise<void> {\n const kt = tryRequireKeytar();\n const payload = JSON.stringify(tokens);\n if (kt !== null && kt !== undefined) {\n await kt.setPassword(KEYTAR_SERVICE, serverName, payload);\n return;\n }\n // File fallback. The directory is locked down first — see `ensurePrivateStoreDir`.\n // Resolved once for the whole operation and PASSED DOWN. Resolving per use would let a read and\n // the write that follows it disagree if HOME moved in between — and `ensurePrivateStoreDir`\n // resolving its own copy would let the directory be locked down under one home while the token\n // lands under another. Today those two statements are adjacent and synchronous so they cannot\n // diverge, but that is incidental; passing the path makes the invariant structural.\n const location = storeLocation();\n const filePath = location.file;\n ensurePrivateStoreDir(location);\n let allTokens: Record<string, OAuthTokens> = {};\n if (existsSync(filePath)) {\n try {\n allTokens = JSON.parse(readFileSync(filePath, \"utf8\")) as Record<string, OAuthTokens>;\n } catch {\n // corrupt file — start fresh\n allTokens = {};\n }\n }\n allTokens[serverName] = tokens;\n await atomicWriteJson(filePath, allTokens);\n try {\n chmodSync(filePath, 0o600);\n } catch {\n // Windows: chmod is a no-op. Documented in ADR D41 / EC-14.\n }\n}\n\n/**\n * Retrieve tokens for `serverName`. Returns undefined if absent.\n *\n */\nexport async function getTokens(serverName: string): Promise<OAuthTokens | undefined> {\n const kt = tryRequireKeytar();\n if (kt !== null && kt !== undefined) {\n const value = await kt.getPassword(KEYTAR_SERVICE, serverName);\n if (typeof value !== \"string\") return undefined;\n try {\n return JSON.parse(value) as OAuthTokens;\n } catch {\n return undefined;\n }\n }\n const filePath = storeFilePath();\n if (!existsSync(filePath)) return undefined;\n // The same gate the credential file gets, and deliberately the same implementation rather than a\n // second one: a refresh token is a credential, and `assertSecureModes` already carries the attack\n // it defends against in its docstring. It is called OUTSIDE the try/catch on purpose — the catch\n // below exists to treat a corrupt file as absent, and letting it swallow this would turn \"someone\n // else can replace your token\" into a silent `undefined`, which reads as \"not logged in\".\n assertSecureModes(dirname(filePath), filePath);\n try {\n const all = JSON.parse(readFileSync(filePath, \"utf8\")) as Record<string, OAuthTokens>;\n return all[serverName];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Serialize concurrent refresh attempts per server (EC-9). If a refresh is\n * already in flight for the same `serverName`, the second caller awaits\n * the same Promise.\n *\n */\nexport function lockedRefresh(\n serverName: string,\n refreshFn: () => Promise<OAuthTokens>,\n): Promise<OAuthTokens> {\n const existing = inflightRefresh.get(serverName);\n if (existing !== undefined) return existing;\n const promise = (async () => {\n try {\n return await refreshFn();\n } finally {\n inflightRefresh.delete(serverName);\n }\n })();\n inflightRefresh.set(serverName, promise);\n return promise;\n}\n\n/**\n * Reset all cached state. Test-only helper.\n *\n * @internal\n */\nexport function _resetForTests(): void {\n inflightRefresh.clear();\n cachedKeytar = undefined;\n keytarWarned = false;\n}\n","/**\n * OAuth 2.1 PKCE flow runner for MCP HTTP servers. See ADR D41.\n *\n * @internal\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { createInterface } from \"node:readline/promises\";\n\nimport { ConfigurationError } from \"../../errors.js\";\nimport type { McpOAuthConfig } from \"../../types/mcp.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { type OAuthTokens, setTokens } from \"./token-storage.js\";\n\n/**\n * Generate a random base64url-encoded string. Used for both code_verifier\n * (43-128 chars) and state (CSRF protection).\n */\nfunction base64url(n: number): string {\n return randomBytes(n).toString(\"base64url\");\n}\n\n/**\n * Compute PKCE code_challenge = base64url(SHA256(code_verifier)).\n */\nfunction challengeFor(verifier: string): string {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\");\n}\n\n/**\n * Refresh an access token using `refresh_token`. Throws on failure.\n *\n */\nexport async function refreshAccessToken(\n serverName: string,\n clientId: string,\n refreshToken: string,\n oauth: McpOAuthConfig,\n): Promise<OAuthTokens> {\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: clientId,\n });\n const response = await fetch(oauth.tokenEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n if (!response.ok) {\n throw new ConfigurationError(`OAuth refresh failed: HTTP ${response.status}`, {\n code: \"oauth_refresh_failed\",\n });\n }\n const data = (await response.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n scope?: string;\n };\n const obtainedAt = Date.now();\n const tokens: OAuthTokens = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? refreshToken,\n // EC-10: default conservative 3600s if expires_in missing.\n expiresAt: obtainedAt + (data.expires_in ?? 3600) * 1000,\n obtainedAt,\n ...(data.scope !== undefined ? { scope: data.scope } : {}),\n };\n await setTokens(serverName, tokens);\n return tokens;\n}\n\n/**\n * Run the full PKCE flow. Generates verifier+challenge+state, opens the\n * authorization URL (browser or manual print), waits for the callback\n * (localhost or stdin), exchanges code for tokens.\n *\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: PKCE flow is a linear protocol step (verifier → challenge → state → URL → wait → exchange); refactoring fragments the RFC 7636 narrative.\nexport async function runPkceFlow(\n serverName: string,\n clientId: string,\n scopes: string[] | undefined,\n oauth: McpOAuthConfig,\n): Promise<OAuthTokens> {\n const verifier = base64url(48);\n const challenge = challengeFor(verifier);\n const state = base64url(16);\n const timeoutMs = oauth.timeoutMs ?? 300_000;\n\n let redirectUri: string;\n let codeWaiter: Promise<{ code: string; state: string }>;\n let cleanup: () => void = () => {};\n\n if (oauth.redirectMode === \"localhost\") {\n const result = await openLocalhostCallback(state, timeoutMs);\n redirectUri = result.redirectUri;\n codeWaiter = result.waitFor;\n cleanup = result.close;\n } else {\n redirectUri = \"urn:ietf:wg:oauth:2.0:oob\";\n codeWaiter = readCodeFromStdin(state, timeoutMs);\n }\n\n try {\n const authUrl = new URL(oauth.authorizationEndpoint);\n authUrl.searchParams.set(\"response_type\", \"code\");\n authUrl.searchParams.set(\"client_id\", clientId);\n authUrl.searchParams.set(\"redirect_uri\", redirectUri);\n if (scopes !== undefined && scopes.length > 0) {\n authUrl.searchParams.set(\"scope\", scopes.join(\" \"));\n }\n authUrl.searchParams.set(\"code_challenge\", challenge);\n authUrl.searchParams.set(\"code_challenge_method\", \"S256\");\n authUrl.searchParams.set(\"state\", state);\n\n diag(\n `\\n[theokit-sdk] OAuth required for MCP server \"${serverName}\".\\n` +\n `Open this URL to authenticate:\\n ${authUrl.toString()}\\n\\n`,\n );\n\n const { code, state: returnedState } = await codeWaiter;\n // EC-2 MUST FIX: validate state.\n if (returnedState !== state) {\n throw new ConfigurationError(\n \"OAuth state mismatch — possible CSRF attempt; aborting token exchange.\",\n { code: \"oauth_state_mismatch\" },\n );\n }\n\n // Exchange code for tokens.\n const tokenBody = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n client_id: clientId,\n code_verifier: verifier,\n redirect_uri: redirectUri,\n });\n const response = await fetch(oauth.tokenEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: tokenBody.toString(),\n });\n if (!response.ok) {\n const errText = await response.text();\n throw new ConfigurationError(\n `OAuth token exchange failed: HTTP ${response.status}: ${errText.slice(0, 200)}`,\n { code: \"oauth_token_exchange_failed\" },\n );\n }\n const data = (await response.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n scope?: string;\n };\n const obtainedAt = Date.now();\n return {\n accessToken: data.access_token,\n ...(data.refresh_token !== undefined ? { refreshToken: data.refresh_token } : {}),\n // EC-10: default 3600s when expires_in absent.\n expiresAt: obtainedAt + (data.expires_in ?? 3600) * 1000,\n obtainedAt,\n ...(data.scope !== undefined ? { scope: data.scope } : {}),\n };\n } finally {\n cleanup();\n }\n}\n\n/**\n * Start a localhost HTTP server on a free port; return the redirect URI,\n * a promise that resolves with the code+state from the first valid request,\n * and a close handle.\n *\n * @internal\n */\nasync function openLocalhostCallback(\n expectedState: string,\n timeoutMs: number,\n): Promise<{\n redirectUri: string;\n waitFor: Promise<{ code: string; state: string }>;\n close: () => void;\n}> {\n let resolveCode: ((value: { code: string; state: string }) => void) | undefined;\n let rejectCode: ((reason: unknown) => void) | undefined;\n const waitFor = new Promise<{ code: string; state: string }>((res, rej) => {\n resolveCode = res;\n rejectCode = rej;\n });\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url ?? \"/\", \"http://127.0.0.1\");\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n if (typeof code !== \"string\" || typeof state !== \"string\") {\n res.statusCode = 400;\n res.end(\"Missing code or state\");\n return;\n }\n // EC-2: state must match the one we generated. We DO NOT trust any\n // localhost GET — only the one carrying our exact state.\n if (state !== expectedState) {\n res.statusCode = 400;\n res.end(\"State mismatch — request rejected.\");\n return;\n }\n res.statusCode = 200;\n res.end(\"Authentication successful. You can close this tab and return to the terminal.\");\n resolveCode?.({ code, state });\n });\n server.listen(0, \"127.0.0.1\");\n const timeoutHandle = setTimeout(() => {\n rejectCode?.(new ConfigurationError(\"OAuth flow timed out\", { code: \"oauth_timeout\" }));\n }, timeoutMs);\n // Wait for server.listen to bind so we can read the port.\n await new Promise<void>((r) => {\n if (server.listening) r();\n else server.once(\"listening\", () => r());\n });\n const address = server.address();\n if (typeof address !== \"object\" || address === null) {\n server.close();\n throw new ConfigurationError(\"OAuth localhost callback failed to bind\", {\n code: \"oauth_bind_failed\",\n });\n }\n const port = address.port;\n return {\n redirectUri: `http://127.0.0.1:${port}/callback`,\n waitFor,\n close: () => {\n clearTimeout(timeoutHandle);\n server.close();\n },\n };\n}\n\n/**\n * Read `code` (and `state`) from stdin (manual mode). User pastes the\n * full callback URL or just the code value.\n *\n * @internal\n */\nasync function readCodeFromStdin(\n expectedState: string,\n timeoutMs: number,\n): Promise<{ code: string; state: string }> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n const promise = new Promise<{ code: string; state: string }>((resolve, reject) => {\n rl.question(\"Paste the full callback URL (or just the code): \")\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: stdin reader handles 2 input formats (full URL vs raw code) inline; splitting fragments the manual-mode UX.\n .then((answer) => {\n rl.close();\n const trimmed = answer.trim();\n // Try to parse as URL first.\n if (trimmed.includes(\"?\")) {\n try {\n const parsed = new URL(trimmed);\n const code = parsed.searchParams.get(\"code\");\n const state = parsed.searchParams.get(\"state\") ?? \"\";\n if (typeof code === \"string\") {\n resolve({ code, state });\n return;\n }\n } catch {\n // not a URL — fall through\n }\n }\n // Treat the entire input as the code. State validation will fail\n // unless the user also provided state — but in manual mode they\n // typically paste the URL with state baked in.\n resolve({ code: trimmed, state: expectedState });\n })\n .catch(reject);\n setTimeout(() => {\n rl.close();\n reject(new ConfigurationError(\"OAuth manual input timed out\", { code: \"oauth_timeout\" }));\n }, timeoutMs);\n });\n return promise;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/mcp/token-storage.ts","../src/internal/mcp/oauth.ts"],"names":[],"mappings":"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","file":"mcp-auth.js","sourcesContent":["import { chmodSync, existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { assertSecureModes } from \"../auth/credential-store.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { atomicWriteJson } from \"../persistence/atomic-write.js\";\n\n/**\n * The OAuth tokens held for one MCP server. See ADR D41.\n *\n * Persisted per server name by `setTokens` and returned unchanged by `getTokens`. Where it lands\n * depends on what is installed: `keytar` puts the serialized bundle in the OS keychain, and\n * without it the bundle is written to a JSON file at mode 0600 inside a 0700 directory — in\n * PLAINTEXT, keyed by server name alongside every other server's tokens. Nothing here encrypts it.\n *\n * `refreshToken` is the field that matters most and the field that is optional. When present it\n * outlives `accessToken` and can mint new ones, so a leaked store is a persistent compromise of\n * the account rather than a temporary one. When absent, an expired access token means re-running\n * the authorization flow.\n *\n * `expiresAt` and `obtainedAt` are both epoch milliseconds and both describe the ACCESS token —\n * when it stops working, and when this bundle was issued. Nothing records when the refresh token\n * expires, so a refresh rejected because the grant itself lapsed is only discovered at the token\n * endpoint.\n *\n * The value is not validated on read: whatever JSON was stored is cast to this shape, so a\n * hand-edited or truncated store yields an object whose fields may be missing rather than an\n * error.\n *\n * `scope` records what the token was granted, as the server returned it. It is stored for\n * inspection; nothing in this module enforces it.\n *\n * @public — re-exported from `@theokit/sdk/mcp-auth`, and therefore under semver.\n */\nexport interface OAuthTokens {\n accessToken: string;\n refreshToken?: string;\n expiresAt: number; // ms epoch\n scope?: string;\n obtainedAt: number; // ms epoch\n}\n\nconst KEYTAR_SERVICE = \"theokit-mcp\";\n/**\n * Resolve the store path on every call instead of binding it once at module load.\n *\n * This used to be `const FILE_PATH = join(homedir(), ...)`. A module-level constant captures\n * ambient global state at IMPORT, so the store kept writing to whichever HOME was set when the\n * module first loaded and never noticed a later change. In production that is invisible, because\n * HOME does not move mid-process — but it made the module's correctness a property of *when* it was\n * imported, which is not a property a credential store should have.\n *\n * The environment variable is read FIRST and `homedir()` is the fallback, and the variable READ IS\n * PER PLATFORM because `os.homedir()` itself is: on POSIX it prefers `$HOME`, on Windows it reads\n * `USERPROFILE` and never consults `HOME`. Mirroring that split is what keeps this a pure\n * binding-time fix instead of a behaviour change.\n *\n * A previous revision read `process.env.HOME` on every platform. Review caught it: under Git Bash,\n * MSYS2 or Cygwin `HOME` IS set, to a POSIX-shaped path, and `path.win32.join(\"/c/Users/N\", ...)`\n * yields `\\c\\Users\\N\\.theokit\\...` where `USERPROFILE` would have given\n * `C:\\Users\\N\\.theokit\\...`. That would have hidden every existing token on those setups and\n * written a new credential file to a drive-relative path. It was published as \"on Windows HOME is\n * typically unset\" — an untested platform claim, and the same defect class it was written to fix.\n *\n * Why read the env at all: inside a worker thread `process.env` is a JS-level copy while\n * `os.homedir()` is a native call reading the real process environment, so code that moves the home\n * inside a worker is invisible to `homedir()`. Reading the env first makes this module independent\n * of the execution model, not just of the import moment.\n *\n * The empty/whitespace guard falls through to `homedir()`, and it buys LESS than two earlier\n * revisions of this comment claimed. Measured on POSIX: `homedir()` with `HOME=\"\"` returns `\"\"` and\n * with `HOME=\" \"` returns `\" \"` untrimmed, so the fallback hands back the same value the guard\n * rejected — close to a no-op. `path.join(\"\", \".theokit\", ...)` yields a CWD-RELATIVE\n * `.theokit/mcp-tokens.json`, never `/.theokit`; an earlier revision named that as the hazard and it\n * does not exist.\n *\n * On Windows it is UNKNOWN rather than load-bearing: the fallback reads the same `USERPROFILE`, so\n * whether the guard changes anything depends on whether an empty variable is reported as absent\n * there, which is untested and not asserted here. The one case where the guard is genuinely\n * load-bearing is a worker thread whose environment copy was blanked.\n *\n * The OS is UNTESTED here: every POSIX-mode test in `mcp/token-store-modes.test.ts` is\n * `it.skipIf(!POSIX)` and CI runs ubuntu only, so nothing exercises real Windows chmod semantics or\n * libuv's `USERPROFILE` lookup. The BRANCH SELECTION is tested — `process.platform` is spy-able, and\n * `test_the_store_reads_USERPROFILE_and_not_HOME_on_win32` pins all three legs.\n *\n * The split is reasoned from `os.homedir()`'s documented per-platform source. A previous revision\n * also cited `internal/runtime/fixtures/fixture-mode.ts:119` as support; that citation was WRONG and\n * is removed rather than quietly dropped. That line reads `process.env.HOME ?? process.env.USERPROFILE`\n * — HOME-first on every platform, which is the exact shape this split exists to avoid. It supports\n * the rejected alternative, not this one. (That the two modules now resolve different homes under\n * Git Bash is real and is filed separately; `fixture-mode` only probes for `~/.aws/credentials`.)\n *\n * Measured cost, not asserted: `homedir()` is 151 ns/op against 13 382 for the read this path\n * performs and 97 079 for the write (89x and 645x). The resolution is free relative to the I/O it\n * precedes.\n *\n * B-089. `packages/sdk/tests/mcp/token-store-modes.test.ts` pins it: import once, move HOME, write,\n * assert the write followed — and it must hold under `--pool=threads`, not only under the repo's\n * configured `forks`.\n *\n * B-090 — `THEOKIT_HOME` now WINS over the home-anchored default, and the reason is not tidiness.\n * `vitest.setup.ts` isolates every test in this package by pointing `THEOKIT_HOME` at a fresh\n * tmpdir; it backs `HOME` up and never sets it. A home-anchored module that ignored the variable\n * therefore resolved to the developer's REAL `~` while the suite believed it was isolated — and it\n * did: a default-config run deposited four refresh-token entries (`test-srv`, `srv-2`, `srv-race`,\n * `srv-roundtrip`) into `~/.theokit/mcp-tokens.json` from `tests/golden/mcp/oauth.golden.test.ts`.\n * A suite that is wrong about its own isolation is a false green about the one property the rest of\n * its greens rest on.\n *\n * **This is the code catching up to a contract the SDK already published**, not a new policy.\n * `src/project-env.ts:47-49` documents `THEOKIT_HOME` as \"Locates the SDK home — sessions, AND THE\n * CREDENTIAL STORE BENEATH IT\", and it is listed there as a sovereign key precisely because it\n * governs where credentials live. The public contract already said the store sits under the\n * variable; this module was the half that disagreed.\n *\n * The resolver adopted is `transcriptRoot()`'s (`internal/persistence/session-transcript.ts`), NOT\n * `paths.ts`'s `getTheokitHome(cwd)`. The transcript is the sibling with the right SHAPE: home-anchored\n * default, `THEOKIT_HOME` override, trimmed, empty-guarded — and its docstring records that before M94\n * it ignored the variable, so \"whoever set it had their state split in two silently\", which is this\n * defect verbatim. M94 ADR-2 already accepted that migration for identically-shaped state.\n * `getTheokitHome(cwd)` falls back to `<cwd>/.theokit`, so adopting IT would move the token file of\n * everyone who does not set the variable — and to a DIFFERENT place per working directory, making\n * whether you are logged in a property of which folder you launched from.\n *\n * **The migration this does carry**, stated rather than buried: a user who already holds\n * `~/.theokit/mcp-tokens.json` AND sets `THEOKIT_HOME` stops seeing those tokens. `getTokens` returns\n * `undefined`, which the caller surfaces as \"not logged in\", and the OAuth flow re-runs. Nothing is\n * deleted and nothing is overwritten — the old file stays where it is and is picked up again the\n * moment the variable is unset. No migration step is performed on the user's behalf, because\n * silently moving a credential file is a worse failure than a re-auth. Users who do NOT set\n * `THEOKIT_HOME` — the default — see no change at all.\n *\n * **Two further consequences for those who DO set it**, both on the directory-mode path rather than\n * on the path resolution, and both spelled out at {@link ensurePrivateStoreDir}: the store no longer\n * re-permissions a `$THEOKIT_HOME` it did not create, and `getTokens` REFUSES — typed, loud — to read\n * out of a group- or world-writable one instead of returning `undefined`.\n */\nfunction storeFilePath(): string {\n return storeLocation().file;\n}\n\n/**\n * Where the store lives, and whether that directory is OURS.\n *\n * `ours` is not bookkeeping — it decides whether this module is entitled to change the directory's\n * permissions. `<home>/.theokit` is a directory the SDK creates and owns; a `THEOKIT_HOME` root is\n * one the operator chose and may share with other state. See {@link ensurePrivateStoreDir}.\n */\ninterface StoreLocation {\n readonly dir: string;\n readonly file: string;\n readonly ours: boolean;\n}\n\n/**\n * The directory the token file lives in: `THEOKIT_HOME` when usable, `<home>/.theokit` otherwise.\n *\n * The empty/whitespace guard on the override is load-bearing in a way the HOME guard below is not:\n * `THEOKIT_HOME=\"\"` with no guard resolves the store to a CWD-RELATIVE `mcp-tokens.json`, and\n * `THEOKIT_HOME=\" \"` to a directory literally named three spaces. Neither falls back to anything;\n * both are new locations invented from an unusable value. `transcriptRoot()` guards it for the same\n * reason.\n */\nfunction storeLocation(): StoreLocation {\n const override = process.env.THEOKIT_HOME?.trim();\n if (override !== undefined && override.length > 0) {\n return { dir: override, file: join(override, \"mcp-tokens.json\"), ours: false };\n }\n // Mirrors `os.homedir()`'s own per-platform source: USERPROFILE on Windows, HOME elsewhere.\n const fromEnv =\n process.platform === \"win32\" ? process.env.USERPROFILE?.trim() : process.env.HOME?.trim();\n const home = fromEnv !== undefined && fromEnv.length > 0 ? fromEnv : homedir();\n const dir = join(home, \".theokit\");\n return { dir, file: join(dir, \"mcp-tokens.json\"), ours: true };\n}\n\n/**\n * Make the directory private BEFORE anything is written into it.\n *\n * `atomicWriteJson` auto-creates the parent with a bare recursive `mkdir`, so under the common umask\n * 002 `~/.theokit` was born 0775 — and the `chmod 600` applied to the file afterwards protects the\n * wrong thing. Write permission on a DIRECTORY is permission to unlink and recreate its contents, so\n * a 0600 file inside a group-writable directory can be replaced wholesale by another local user. The\n * secret here is a REFRESH TOKEN: replacing it swaps which account the agent authenticates as.\n *\n * **The retro-fix `chmod` is scoped to directories we own, and B-090 is why.** It was written\n * unconditional for a specific reason: `mkdir`'s mode applies only at CREATION, so every machine\n * that already ran an older build has a loose `~/.theokit` sitting there, and a fix that only covers\n * fresh installs does not reach the population that has the problem. That reasoning names its own\n * population — directories THIS MODULE created in an older build. Once `THEOKIT_HOME` is honoured,\n * an unconditional `chmod` also reaches a root the operator chose, which we never created and which\n * `paths.ts` documents as a multi-tenant deployment knob. Measured: it silently demoted a 0775\n * `$THEOKIT_HOME` to 0700, taking the sessions, transcripts, personality and credential-pool state\n * that share that root with it. No other consumer of the variable imposes a mode on it.\n *\n * So: always `mkdir` at 0700 (a directory WE create is born private wherever it is), and `chmod` an\n * existing one only when it is `<home>/.theokit`.\n *\n * The `chmod` deliberately does NOT also cover \"we just created it\". A first draft guarded it with\n * `ours || created !== undefined`; mutating that to plain `ours` killed no test, and the reason is\n * that the disjunct cannot make a difference: a umask only CLEARS bits, and 0700 carries none in the\n * group/other range, so `mkdir(0700)` is private for every possible umask. The redundant clause was\n * removed rather than pinned with a test written to justify it.\n *\n * **What that leaves, stated rather than left to be discovered.** A pre-existing group-writable\n * `$THEOKIT_HOME` is no longer repaired, so the next {@link getTokens} throws `CredentialError` from\n * `assertSecureModes` naming the directory and the `chmod 700` that fixes it. That is the intended\n * end state: a refresh token under a directory any local user can replace files in is not safe to\n * return, and the two available alternatives are worse. Silently tightening the operator's root\n * breaks their deployment to protect them from a choice they may have made deliberately; silently\n * returning the token hands the caller a credential that may already have been swapped. A loud,\n * actionable refusal is the only option that neither mutates someone else's directory nor lies about\n * what it read.\n *\n * The asymmetry that remains is real and is NOT fixed here: the write path has no such gate, so\n * `setTokens` will happily write into that directory and the following `getTokens` refuses it.\n * Adding a write-side gate is a separate behaviour change on a path that currently always succeeds.\n */\nfunction ensurePrivateStoreDir({ dir, ours }: StoreLocation): void {\n try {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n if (ours) chmodSync(dir, 0o700);\n } catch {\n // Windows: chmod is a no-op and the mode argument is meaningless. Same posture as the file\n // chmod below — documented in ADR D41 / EC-14.\n }\n}\n\ninterface KeytarLike {\n setPassword: (service: string, account: string, password: string) => Promise<void>;\n getPassword: (service: string, account: string) => Promise<string | null>;\n deletePassword: (service: string, account: string) => Promise<boolean>;\n}\n\nlet keytarWarned = false;\nlet cachedKeytar: KeytarLike | undefined | null;\nfunction tryRequireKeytar(): KeytarLike | null {\n if (cachedKeytar !== undefined) return cachedKeytar;\n try {\n const r = createRequire(import.meta.url);\n cachedKeytar = r(\"keytar\") as KeytarLike;\n } catch {\n if (!keytarWarned) {\n // The path is RESOLVED rather than spelled `~/.theokit/mcp-tokens.json`. That literal was\n // correct until B-090 made `THEOKIT_HOME` win, at which point a message naming a fixed\n // location would send anyone who sets the variable to look at a file the store no longer\n // writes — a diagnostic that lies costs more than one that is absent.\n diag(\n `[theokit-sdk] keytar not installed; MCP OAuth tokens will be stored in ${storeFilePath()} (chmod 600 where POSIX). Install \\`keytar\\` for OS keychain storage.\\n`,\n );\n keytarWarned = true;\n }\n cachedKeytar = null;\n }\n return cachedKeytar;\n}\n\n// EC-9 (race): serialize concurrent refreshes per server. Each key maps to\n// the in-flight refresh Promise; subsequent callers await the same promise.\nconst inflightRefresh = new Map<string, Promise<OAuthTokens>>();\n\n/**\n * Persist tokens for `serverName`. Tries keychain first, falls back to file\n * with chmod 600 (POSIX). Idempotent.\n *\n */\nexport async function setTokens(serverName: string, tokens: OAuthTokens): Promise<void> {\n const kt = tryRequireKeytar();\n const payload = JSON.stringify(tokens);\n if (kt !== null && kt !== undefined) {\n await kt.setPassword(KEYTAR_SERVICE, serverName, payload);\n return;\n }\n // File fallback. The directory is locked down first — see `ensurePrivateStoreDir`.\n // Resolved once for the whole operation and PASSED DOWN. Resolving per use would let a read and\n // the write that follows it disagree if HOME moved in between — and `ensurePrivateStoreDir`\n // resolving its own copy would let the directory be locked down under one home while the token\n // lands under another. Today those two statements are adjacent and synchronous so they cannot\n // diverge, but that is incidental; passing the path makes the invariant structural.\n const location = storeLocation();\n const filePath = location.file;\n ensurePrivateStoreDir(location);\n let allTokens: Record<string, OAuthTokens> = {};\n if (existsSync(filePath)) {\n try {\n allTokens = JSON.parse(readFileSync(filePath, \"utf8\")) as Record<string, OAuthTokens>;\n } catch {\n // corrupt file — start fresh\n allTokens = {};\n }\n }\n allTokens[serverName] = tokens;\n await atomicWriteJson(filePath, allTokens);\n try {\n chmodSync(filePath, 0o600);\n } catch {\n // Windows: chmod is a no-op. Documented in ADR D41 / EC-14.\n }\n}\n\n/**\n * Retrieve tokens for `serverName`. Returns undefined if absent.\n *\n */\nexport async function getTokens(serverName: string): Promise<OAuthTokens | undefined> {\n const kt = tryRequireKeytar();\n if (kt !== null && kt !== undefined) {\n const value = await kt.getPassword(KEYTAR_SERVICE, serverName);\n if (typeof value !== \"string\") return undefined;\n try {\n return JSON.parse(value) as OAuthTokens;\n } catch {\n return undefined;\n }\n }\n const filePath = storeFilePath();\n if (!existsSync(filePath)) return undefined;\n // The same gate the credential file gets, and deliberately the same implementation rather than a\n // second one: a refresh token is a credential, and `assertSecureModes` already carries the attack\n // it defends against in its docstring. It is called OUTSIDE the try/catch on purpose — the catch\n // below exists to treat a corrupt file as absent, and letting it swallow this would turn \"someone\n // else can replace your token\" into a silent `undefined`, which reads as \"not logged in\".\n assertSecureModes(dirname(filePath), filePath);\n try {\n const all = JSON.parse(readFileSync(filePath, \"utf8\")) as Record<string, OAuthTokens>;\n return all[serverName];\n } catch {\n return undefined;\n }\n}\n\n/**\n * Serialize concurrent refresh attempts per server (EC-9). If a refresh is\n * already in flight for the same `serverName`, the second caller awaits\n * the same Promise.\n *\n */\nexport function lockedRefresh(\n serverName: string,\n refreshFn: () => Promise<OAuthTokens>,\n): Promise<OAuthTokens> {\n const existing = inflightRefresh.get(serverName);\n if (existing !== undefined) return existing;\n const promise = (async () => {\n try {\n return await refreshFn();\n } finally {\n inflightRefresh.delete(serverName);\n }\n })();\n inflightRefresh.set(serverName, promise);\n return promise;\n}\n\n/**\n * Reset all cached state. Test-only helper.\n *\n * @internal\n */\nexport function _resetForTests(): void {\n inflightRefresh.clear();\n cachedKeytar = undefined;\n keytarWarned = false;\n}\n","/**\n * OAuth 2.1 PKCE flow runner for MCP HTTP servers. See ADR D41.\n *\n * @internal\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { createInterface } from \"node:readline/promises\";\n\nimport { ConfigurationError } from \"../../errors.js\";\nimport type { McpOAuthConfig } from \"../../types/mcp.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { type OAuthTokens, setTokens } from \"./token-storage.js\";\n\n/**\n * Generate a random base64url-encoded string. Used for both code_verifier\n * (43-128 chars) and state (CSRF protection).\n */\nfunction base64url(n: number): string {\n return randomBytes(n).toString(\"base64url\");\n}\n\n/**\n * Compute PKCE code_challenge = base64url(SHA256(code_verifier)).\n */\nfunction challengeFor(verifier: string): string {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\");\n}\n\n/**\n * Refresh an access token using `refresh_token`. Throws on failure.\n *\n */\nexport async function refreshAccessToken(\n serverName: string,\n clientId: string,\n refreshToken: string,\n oauth: McpOAuthConfig,\n): Promise<OAuthTokens> {\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: clientId,\n });\n const response = await fetch(oauth.tokenEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n if (!response.ok) {\n throw new ConfigurationError(`OAuth refresh failed: HTTP ${response.status}`, {\n code: \"oauth_refresh_failed\",\n });\n }\n const data = (await response.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n scope?: string;\n };\n const obtainedAt = Date.now();\n const tokens: OAuthTokens = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? refreshToken,\n // EC-10: default conservative 3600s if expires_in missing.\n expiresAt: obtainedAt + (data.expires_in ?? 3600) * 1000,\n obtainedAt,\n ...(data.scope !== undefined ? { scope: data.scope } : {}),\n };\n await setTokens(serverName, tokens);\n return tokens;\n}\n\n/**\n * Run the full PKCE flow. Generates verifier+challenge+state, opens the\n * authorization URL (browser or manual print), waits for the callback\n * (localhost or stdin), exchanges code for tokens.\n *\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: PKCE flow is a linear protocol step (verifier → challenge → state → URL → wait → exchange); refactoring fragments the RFC 7636 narrative.\nexport async function runPkceFlow(\n serverName: string,\n clientId: string,\n scopes: string[] | undefined,\n oauth: McpOAuthConfig,\n): Promise<OAuthTokens> {\n const verifier = base64url(48);\n const challenge = challengeFor(verifier);\n const state = base64url(16);\n const timeoutMs = oauth.timeoutMs ?? 300_000;\n\n let redirectUri: string;\n let codeWaiter: Promise<{ code: string; state: string }>;\n let cleanup: () => void = () => {};\n\n if (oauth.redirectMode === \"localhost\") {\n const result = await openLocalhostCallback(state, timeoutMs);\n redirectUri = result.redirectUri;\n codeWaiter = result.waitFor;\n cleanup = result.close;\n } else {\n redirectUri = \"urn:ietf:wg:oauth:2.0:oob\";\n codeWaiter = readCodeFromStdin(state, timeoutMs);\n }\n\n try {\n const authUrl = new URL(oauth.authorizationEndpoint);\n authUrl.searchParams.set(\"response_type\", \"code\");\n authUrl.searchParams.set(\"client_id\", clientId);\n authUrl.searchParams.set(\"redirect_uri\", redirectUri);\n if (scopes !== undefined && scopes.length > 0) {\n authUrl.searchParams.set(\"scope\", scopes.join(\" \"));\n }\n authUrl.searchParams.set(\"code_challenge\", challenge);\n authUrl.searchParams.set(\"code_challenge_method\", \"S256\");\n authUrl.searchParams.set(\"state\", state);\n\n diag(\n `\\n[theokit-sdk] OAuth required for MCP server \"${serverName}\".\\n` +\n `Open this URL to authenticate:\\n ${authUrl.toString()}\\n\\n`,\n );\n\n const { code, state: returnedState } = await codeWaiter;\n // EC-2 MUST FIX: validate state.\n if (returnedState !== state) {\n throw new ConfigurationError(\n \"OAuth state mismatch — possible CSRF attempt; aborting token exchange.\",\n { code: \"oauth_state_mismatch\" },\n );\n }\n\n // Exchange code for tokens.\n const tokenBody = new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n client_id: clientId,\n code_verifier: verifier,\n redirect_uri: redirectUri,\n });\n const response = await fetch(oauth.tokenEndpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: tokenBody.toString(),\n });\n if (!response.ok) {\n const errText = await response.text();\n throw new ConfigurationError(\n `OAuth token exchange failed: HTTP ${response.status}: ${errText.slice(0, 200)}`,\n { code: \"oauth_token_exchange_failed\" },\n );\n }\n const data = (await response.json()) as {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n scope?: string;\n };\n const obtainedAt = Date.now();\n return {\n accessToken: data.access_token,\n ...(data.refresh_token !== undefined ? { refreshToken: data.refresh_token } : {}),\n // EC-10: default 3600s when expires_in absent.\n expiresAt: obtainedAt + (data.expires_in ?? 3600) * 1000,\n obtainedAt,\n ...(data.scope !== undefined ? { scope: data.scope } : {}),\n };\n } finally {\n cleanup();\n }\n}\n\n/**\n * Start a localhost HTTP server on a free port; return the redirect URI,\n * a promise that resolves with the code+state from the first valid request,\n * and a close handle.\n *\n * @internal\n */\nasync function openLocalhostCallback(\n expectedState: string,\n timeoutMs: number,\n): Promise<{\n redirectUri: string;\n waitFor: Promise<{ code: string; state: string }>;\n close: () => void;\n}> {\n let resolveCode: ((value: { code: string; state: string }) => void) | undefined;\n let rejectCode: ((reason: unknown) => void) | undefined;\n const waitFor = new Promise<{ code: string; state: string }>((res, rej) => {\n resolveCode = res;\n rejectCode = rej;\n });\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url ?? \"/\", \"http://127.0.0.1\");\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n if (typeof code !== \"string\" || typeof state !== \"string\") {\n res.statusCode = 400;\n res.end(\"Missing code or state\");\n return;\n }\n // EC-2: state must match the one we generated. We DO NOT trust any\n // localhost GET — only the one carrying our exact state.\n if (state !== expectedState) {\n res.statusCode = 400;\n res.end(\"State mismatch — request rejected.\");\n return;\n }\n res.statusCode = 200;\n res.end(\"Authentication successful. You can close this tab and return to the terminal.\");\n resolveCode?.({ code, state });\n });\n server.listen(0, \"127.0.0.1\");\n const timeoutHandle = setTimeout(() => {\n rejectCode?.(new ConfigurationError(\"OAuth flow timed out\", { code: \"oauth_timeout\" }));\n }, timeoutMs);\n // Wait for server.listen to bind so we can read the port.\n await new Promise<void>((r) => {\n if (server.listening) r();\n else server.once(\"listening\", () => r());\n });\n const address = server.address();\n if (typeof address !== \"object\" || address === null) {\n server.close();\n throw new ConfigurationError(\"OAuth localhost callback failed to bind\", {\n code: \"oauth_bind_failed\",\n });\n }\n const port = address.port;\n return {\n redirectUri: `http://127.0.0.1:${port}/callback`,\n waitFor,\n close: () => {\n clearTimeout(timeoutHandle);\n server.close();\n },\n };\n}\n\n/**\n * Read `code` (and `state`) from stdin (manual mode). User pastes the\n * full callback URL or just the code value.\n *\n * @internal\n */\nasync function readCodeFromStdin(\n expectedState: string,\n timeoutMs: number,\n): Promise<{ code: string; state: string }> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n const promise = new Promise<{ code: string; state: string }>((resolve, reject) => {\n rl.question(\"Paste the full callback URL (or just the code): \")\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: stdin reader handles 2 input formats (full URL vs raw code) inline; splitting fragments the manual-mode UX.\n .then((answer) => {\n rl.close();\n const trimmed = answer.trim();\n // Try to parse as URL first.\n if (trimmed.includes(\"?\")) {\n try {\n const parsed = new URL(trimmed);\n const code = parsed.searchParams.get(\"code\");\n const state = parsed.searchParams.get(\"state\") ?? \"\";\n if (typeof code === \"string\") {\n resolve({ code, state });\n return;\n }\n } catch {\n // not a URL — fall through\n }\n }\n // Treat the entire input as the code. State validation will fail\n // unless the user also provided state — but in manual mode they\n // typically paste the URL with state baked in.\n resolve({ code: trimmed, state: expectedState });\n })\n .catch(reject);\n setTimeout(() => {\n rl.close();\n reject(new ConfigurationError(\"OAuth manual input timed out\", { code: \"oauth_timeout\" }));\n }, timeoutMs);\n });\n return promise;\n}\n"]}
|
package/dist/models.cjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkPRZ3BES7_cjs = require('./chunk-PRZ3BES7.cjs');
|
|
4
4
|
var chunk3EE6LVWT_cjs = require('./chunk-3EE6LVWT.cjs');
|
|
5
|
-
var
|
|
6
|
-
require('./chunk-
|
|
7
|
-
require('./chunk-
|
|
8
|
-
require('./chunk-
|
|
9
|
-
require('./chunk-
|
|
10
|
-
require('./chunk-
|
|
11
|
-
var
|
|
5
|
+
var chunkQC55H6RJ_cjs = require('./chunk-QC55H6RJ.cjs');
|
|
6
|
+
require('./chunk-NVXXWAU7.cjs');
|
|
7
|
+
require('./chunk-4NLCWGH7.cjs');
|
|
8
|
+
require('./chunk-EXTRW7GW.cjs');
|
|
9
|
+
require('./chunk-HUFSABUZ.cjs');
|
|
10
|
+
require('./chunk-J7J7J2GN.cjs');
|
|
11
|
+
var chunk6LHQPOMI_cjs = require('./chunk-6LHQPOMI.cjs');
|
|
12
12
|
var crypto = require('crypto');
|
|
13
13
|
var fs = require('fs');
|
|
14
14
|
var os = require('os');
|
|
@@ -36,11 +36,11 @@ function capsFromCatalog(m) {
|
|
|
36
36
|
}
|
|
37
37
|
function resolveModelCapabilities(modelId) {
|
|
38
38
|
const bare = stripVariantSuffix(stripRoutingPrefix(modelId));
|
|
39
|
-
const fromIndex =
|
|
39
|
+
const fromIndex = chunkQC55H6RJ_cjs.getCatalogModelInfo(bare);
|
|
40
40
|
if (fromIndex !== void 0) return capsFromCatalog(fromIndex);
|
|
41
41
|
const withVendor = inferVendorPrefix(bare);
|
|
42
42
|
if (withVendor !== bare) {
|
|
43
|
-
const vendored =
|
|
43
|
+
const vendored = chunkQC55H6RJ_cjs.getCatalogModelInfo(withVendor);
|
|
44
44
|
if (vendored !== void 0) return capsFromCatalog(vendored);
|
|
45
45
|
}
|
|
46
46
|
return CONSERVATIVE_DEFAULTS;
|
|
@@ -132,7 +132,7 @@ function catalogTargets() {
|
|
|
132
132
|
if (_catalogTargets !== void 0) return _catalogTargets;
|
|
133
133
|
_catalogTargets = /* @__PURE__ */ new Map();
|
|
134
134
|
try {
|
|
135
|
-
for (const entry of Object.values(
|
|
135
|
+
for (const entry of Object.values(chunkQC55H6RJ_cjs.loadProviderCatalog())) {
|
|
136
136
|
const keys = [entry.id, ...entry.aliases ?? []];
|
|
137
137
|
for (const k of keys) {
|
|
138
138
|
if (!_catalogTargets.has(k)) _catalogTargets.set(k, { keys });
|
|
@@ -146,7 +146,7 @@ function resolvePatchKeys(externalId) {
|
|
|
146
146
|
const mapped = MODELS_DEV_ID_MAP[externalId] ?? externalId;
|
|
147
147
|
const fromCatalog = catalogTargets().get(mapped);
|
|
148
148
|
if (fromCatalog !== void 0) return fromCatalog.keys;
|
|
149
|
-
const profile =
|
|
149
|
+
const profile = chunkQC55H6RJ_cjs.getProviderProfile(mapped);
|
|
150
150
|
if (profile !== void 0) return [profile.name, ...profile.aliases ?? []];
|
|
151
151
|
return void 0;
|
|
152
152
|
}
|
|
@@ -163,14 +163,14 @@ function patchIndexFromApiJson(raw) {
|
|
|
163
163
|
continue;
|
|
164
164
|
}
|
|
165
165
|
for (const [modelId, rawModel] of Object.entries(models)) {
|
|
166
|
-
const parsed =
|
|
166
|
+
const parsed = chunkQC55H6RJ_cjs.catalogModelSchema.safeParse(rawModel);
|
|
167
167
|
if (!parsed.success) continue;
|
|
168
|
-
for (const key of keys)
|
|
168
|
+
for (const key of keys) chunkQC55H6RJ_cjs.patchModelInfo(`${key}/${modelId}`, parsed.data);
|
|
169
169
|
patched++;
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
if (skipped.length > 0) {
|
|
173
|
-
|
|
173
|
+
chunk6LHQPOMI_cjs.diag(
|
|
174
174
|
`[theokit-sdk] WARN: models-dev refresh skipped ${skipped.length} unknown provider(s) (e.g. ${skipped.slice(0, 3).join(", ")})
|
|
175
175
|
`
|
|
176
176
|
);
|
|
@@ -193,40 +193,33 @@ function loadCacheIntoIndex(url = DEFAULT_URL) {
|
|
|
193
193
|
fs.unlinkSync(path);
|
|
194
194
|
} catch {
|
|
195
195
|
}
|
|
196
|
-
|
|
196
|
+
chunk6LHQPOMI_cjs.diag(`[theokit-sdk] WARN: corrupt models-dev cache deleted (${path})
|
|
197
197
|
`);
|
|
198
198
|
return 0;
|
|
199
199
|
}
|
|
200
200
|
try {
|
|
201
201
|
return patchIndexFromApiJson(parsed);
|
|
202
202
|
} catch (err) {
|
|
203
|
-
|
|
203
|
+
chunk6LHQPOMI_cjs.diag(`[theokit-sdk] WARN: models-dev cache patch failed (${err.message})
|
|
204
204
|
`);
|
|
205
205
|
return 0;
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
|
-
|
|
209
|
-
chunkHCZD23VS_cjs.registerBuiltins();
|
|
208
|
+
function fetchDisabledByEnv() {
|
|
210
209
|
const kill = process.env.THEOKIT_DISABLE_MODELS_FETCH;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
try {
|
|
219
|
-
const age = now() - fs.statSync(path).mtimeMs;
|
|
220
|
-
if (age < TTL_MS) {
|
|
221
|
-
return { source: "cache", models: loadCacheIntoIndex(url) };
|
|
222
|
-
}
|
|
223
|
-
} catch {
|
|
224
|
-
}
|
|
210
|
+
return kill !== void 0 && kill !== "" && kill !== "0" && kill.toLowerCase() !== "false";
|
|
211
|
+
}
|
|
212
|
+
function servedFromFreshCache(url, path, now) {
|
|
213
|
+
try {
|
|
214
|
+
if (now() - fs.statSync(path).mtimeMs >= TTL_MS) return void 0;
|
|
215
|
+
} catch {
|
|
216
|
+
return void 0;
|
|
225
217
|
}
|
|
226
|
-
|
|
227
|
-
|
|
218
|
+
return { source: "cache", models: loadCacheIntoIndex(url) };
|
|
219
|
+
}
|
|
220
|
+
async function fetchCatalogBody(url, fetchImpl) {
|
|
228
221
|
try {
|
|
229
|
-
const res = await
|
|
222
|
+
const res = await chunkPRZ3BES7_cjs.Retry.run(
|
|
230
223
|
async () => {
|
|
231
224
|
const r = await fetchImpl(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
|
|
232
225
|
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
@@ -240,36 +233,53 @@ async function refreshModelCatalog(opts = {}) {
|
|
|
240
233
|
if (Number.isFinite(declaredLength) && declaredLength > MAX_CATALOG_BYTES) {
|
|
241
234
|
throw new Error(`catalog too large: ${declaredLength} bytes declared`);
|
|
242
235
|
}
|
|
243
|
-
body = await res.text();
|
|
236
|
+
const body = await res.text();
|
|
244
237
|
if (body.length > MAX_CATALOG_BYTES) {
|
|
245
238
|
throw new Error(`catalog too large: ${body.length} bytes received`);
|
|
246
239
|
}
|
|
247
240
|
JSON.parse(body);
|
|
241
|
+
return body;
|
|
248
242
|
} catch (err) {
|
|
249
|
-
|
|
243
|
+
chunk6LHQPOMI_cjs.diag(
|
|
250
244
|
`[theokit-sdk] WARN: models-dev refresh failed (${err.message}) \u2014 serving existing data
|
|
251
245
|
`
|
|
252
246
|
);
|
|
253
|
-
return
|
|
247
|
+
return void 0;
|
|
254
248
|
}
|
|
249
|
+
}
|
|
250
|
+
function persistAndPatch(path, body) {
|
|
255
251
|
try {
|
|
256
252
|
writeCacheAtomic(path, body);
|
|
257
253
|
} catch (err) {
|
|
258
|
-
|
|
254
|
+
chunk6LHQPOMI_cjs.diag(`[theokit-sdk] WARN: models-dev cache write failed (${err.message})
|
|
259
255
|
`);
|
|
260
256
|
}
|
|
261
257
|
try {
|
|
262
258
|
return { source: "network", models: patchIndexFromApiJson(JSON.parse(body)) };
|
|
263
259
|
} catch (err) {
|
|
264
|
-
|
|
260
|
+
chunk6LHQPOMI_cjs.diag(
|
|
265
261
|
`[theokit-sdk] WARN: models-dev patch failed (${err.message}) \u2014 serving existing data
|
|
266
262
|
`
|
|
267
263
|
);
|
|
268
264
|
return { source: "cache", models: 0 };
|
|
269
265
|
}
|
|
270
266
|
}
|
|
267
|
+
async function refreshModelCatalog(opts = {}) {
|
|
268
|
+
chunkQC55H6RJ_cjs.registerBuiltins();
|
|
269
|
+
if (fetchDisabledByEnv()) return { source: "skipped", models: 0 };
|
|
270
|
+
const url = opts.url ?? process.env.THEOKIT_MODELS_URL ?? DEFAULT_URL;
|
|
271
|
+
const path = cachePathFor(url);
|
|
272
|
+
const now = opts.deps?.now ?? (() => Date.now());
|
|
273
|
+
if (opts.force !== true) {
|
|
274
|
+
const cached = servedFromFreshCache(url, path, now);
|
|
275
|
+
if (cached !== void 0) return cached;
|
|
276
|
+
}
|
|
277
|
+
const body = await fetchCatalogBody(url, opts.deps?.fetch ?? fetch);
|
|
278
|
+
if (body === void 0) return { source: "cache", models: loadCacheIntoIndex(url) };
|
|
279
|
+
return persistAndPatch(path, body);
|
|
280
|
+
}
|
|
271
281
|
function getModelInfo(modelId) {
|
|
272
|
-
return
|
|
282
|
+
return chunkQC55H6RJ_cjs.getCatalogModelInfo(modelId);
|
|
273
283
|
}
|
|
274
284
|
|
|
275
285
|
Object.defineProperty(exports, "parseModelId", {
|