@theokit/sdk 4.53.1 → 4.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (694) hide show
  1. package/CHANGELOG.md +1184 -0
  2. package/README.md +9 -4
  3. package/dist/a2a/agent-mailbox.d.cts +27 -0
  4. package/dist/a2a/agent-mailbox.d.ts +27 -0
  5. package/dist/a2a/index.cjs +9 -4
  6. package/dist/a2a/index.cjs.map +1 -1
  7. package/dist/a2a/index.js +7 -2
  8. package/dist/a2a/index.js.map +1 -1
  9. package/dist/a2a/message-bus.d.cts +39 -0
  10. package/dist/a2a/message-bus.d.ts +39 -0
  11. package/dist/a2a/subagent.d.cts +68 -7
  12. package/dist/a2a/subagent.d.ts +68 -7
  13. package/dist/a2a/types.d.cts +26 -0
  14. package/dist/a2a/types.d.ts +26 -0
  15. package/dist/{agent-B9HXlwID.d.ts → agent-D3Xr_-6Z.d.cts} +245 -850
  16. package/dist/{agent-nLqeXKIX.d.cts → agent-DIu6FooJ.d.ts} +245 -850
  17. package/dist/agent-HDEVVUBS.js +52 -0
  18. package/dist/{agent-FFVV4U5N.js.map → agent-HDEVVUBS.js.map} +1 -1
  19. package/dist/agent-R2HOJFZJ.cjs +61 -0
  20. package/dist/{agent-YLAHVHEH.cjs.map → agent-R2HOJFZJ.cjs.map} +1 -1
  21. package/dist/agent-builder.d.ts +19 -0
  22. package/dist/agent-session-store-P6V3FINW.js +7 -0
  23. package/dist/{agent-session-store-TNCGL5RN.js.map → agent-session-store-P6V3FINW.js.map} +1 -1
  24. package/dist/agent-session-store-ZJ3JSRS4.cjs +24 -0
  25. package/dist/{agent-session-store-DUGBAX5V.cjs.map → agent-session-store-ZJ3JSRS4.cjs.map} +1 -1
  26. package/dist/agent.d.ts +9 -6
  27. package/dist/auth/index.cjs +52 -35
  28. package/dist/auth/index.cjs.map +1 -1
  29. package/dist/auth/index.js +26 -9
  30. package/dist/auth/index.js.map +1 -1
  31. package/dist/{batch-UPKN4SG6.js → batch-2TGJMNCJ.js} +14 -13
  32. package/dist/batch-2TGJMNCJ.js.map +1 -0
  33. package/dist/{batch-ZEFN5SO7.cjs → batch-ND32UKZS.cjs} +31 -30
  34. package/dist/batch-ND32UKZS.cjs.map +1 -0
  35. package/dist/{chunk-TTJ54H3E.cjs → chunk-2ADR2GSO.cjs} +8 -8
  36. package/dist/chunk-2ADR2GSO.cjs.map +1 -0
  37. package/dist/chunk-2BDH744Z.js +15 -0
  38. package/dist/chunk-2BDH744Z.js.map +1 -0
  39. package/dist/{chunk-VGPXHHF3.cjs → chunk-2C72DXQF.cjs} +63 -27
  40. package/dist/chunk-2C72DXQF.cjs.map +1 -0
  41. package/dist/{chunk-4Q4K4WB5.js → chunk-2D34UTDC.js} +20 -4
  42. package/dist/chunk-2D34UTDC.js.map +1 -0
  43. package/dist/{chunk-UFIXH26P.js → chunk-2QKTVKH3.js} +4 -4
  44. package/dist/{chunk-UFIXH26P.js.map → chunk-2QKTVKH3.js.map} +1 -1
  45. package/dist/{chunk-GBBDINFK.js → chunk-3E77SX4H.js} +4 -4
  46. package/dist/{chunk-GBBDINFK.js.map → chunk-3E77SX4H.js.map} +1 -1
  47. package/dist/{chunk-VYHJZVL5.cjs → chunk-3EE6LVWT.cjs} +2 -2
  48. package/dist/chunk-3EE6LVWT.cjs.map +1 -0
  49. package/dist/{chunk-5NBUH3NO.js → chunk-3OR54XG4.js} +2 -2
  50. package/dist/{chunk-C6Y6CWYD.cjs.map → chunk-3OR54XG4.js.map} +1 -1
  51. package/dist/{chunk-ZN2DGEY3.cjs → chunk-3YJNUKYN.cjs} +15 -15
  52. package/dist/{chunk-ZN2DGEY3.cjs.map → chunk-3YJNUKYN.cjs.map} +1 -1
  53. package/dist/{chunk-POWRZSK4.js → chunk-44JAAH4X.js} +3 -3
  54. package/dist/{chunk-POWRZSK4.js.map → chunk-44JAAH4X.js.map} +1 -1
  55. package/dist/{chunk-SSDD676S.js → chunk-44MBDIHG.js} +4 -4
  56. package/dist/{chunk-SSDD676S.js.map → chunk-44MBDIHG.js.map} +1 -1
  57. package/dist/{chunk-OY7O3Q6R.js → chunk-4ERPXIVB.js} +5 -5
  58. package/dist/{chunk-OY7O3Q6R.js.map → chunk-4ERPXIVB.js.map} +1 -1
  59. package/dist/{chunk-3BK6YR5P.cjs → chunk-4I55V454.cjs} +4 -4
  60. package/dist/{chunk-3BK6YR5P.cjs.map → chunk-4I55V454.cjs.map} +1 -1
  61. package/dist/{chunk-B4YA6BRS.cjs → chunk-4O5TGQBW.cjs} +30 -7
  62. package/dist/chunk-4O5TGQBW.cjs.map +1 -0
  63. package/dist/{chunk-4JBHSLQO.cjs → chunk-4OTIXDMU.cjs} +2 -2
  64. package/dist/{chunk-4JBHSLQO.cjs.map → chunk-4OTIXDMU.cjs.map} +1 -1
  65. package/dist/{chunk-C6Y6CWYD.cjs → chunk-52NKC5HT.cjs} +2 -2
  66. package/dist/chunk-52NKC5HT.cjs.map +1 -0
  67. package/dist/{chunk-665SFFFR.cjs → chunk-53CBTBWO.cjs} +11 -11
  68. package/dist/{chunk-665SFFFR.cjs.map → chunk-53CBTBWO.cjs.map} +1 -1
  69. package/dist/{chunk-FFM3SJTQ.js → chunk-5JLFFPCH.js} +4 -4
  70. package/dist/{chunk-FFM3SJTQ.js.map → chunk-5JLFFPCH.js.map} +1 -1
  71. package/dist/{chunk-34XOCZJO.js → chunk-5PHVENFV.js} +3 -3
  72. package/dist/chunk-5PHVENFV.js.map +1 -0
  73. package/dist/{chunk-BDTVFIPB.cjs → chunk-5UOVYM3P.cjs} +36 -31
  74. package/dist/chunk-5UOVYM3P.cjs.map +1 -0
  75. package/dist/{chunk-VF7X6HDR.cjs → chunk-5USCYPPI.cjs} +15 -15
  76. package/dist/{chunk-VF7X6HDR.cjs.map → chunk-5USCYPPI.cjs.map} +1 -1
  77. package/dist/chunk-6HTXPPHK.cjs +18 -0
  78. package/dist/chunk-6HTXPPHK.cjs.map +1 -0
  79. package/dist/{chunk-D24WJWN2.js → chunk-AEOZTXVW.js} +3 -3
  80. package/dist/{chunk-D24WJWN2.js.map → chunk-AEOZTXVW.js.map} +1 -1
  81. package/dist/{chunk-DGOG5NXR.js → chunk-AG5JPQIY.js} +3 -3
  82. package/dist/{chunk-DGOG5NXR.js.map → chunk-AG5JPQIY.js.map} +1 -1
  83. package/dist/{chunk-BFYGJGC5.js → chunk-AQLGBKNT.js} +3 -3
  84. package/dist/chunk-AQLGBKNT.js.map +1 -0
  85. package/dist/{chunk-7W7ZWMLQ.js → chunk-AWO27VRZ.js} +3 -3
  86. package/dist/chunk-AWO27VRZ.js.map +1 -0
  87. package/dist/{chunk-VYCKUKPA.cjs → chunk-B2J4ZMZL.cjs} +3 -2
  88. package/dist/chunk-B2J4ZMZL.cjs.map +1 -0
  89. package/dist/{chunk-BERBYXFH.js → chunk-BMAZLQQ4.js} +3 -3
  90. package/dist/{chunk-BERBYXFH.js.map → chunk-BMAZLQQ4.js.map} +1 -1
  91. package/dist/{chunk-5YKNEMXR.cjs → chunk-BVZW2B5V.cjs} +4 -4
  92. package/dist/chunk-BVZW2B5V.cjs.map +1 -0
  93. package/dist/{chunk-MSFLYJDY.js → chunk-CQ2TQ32Y.js} +4 -4
  94. package/dist/chunk-CQ2TQ32Y.js.map +1 -0
  95. package/dist/{chunk-C5DEO6OI.cjs → chunk-CQGYNZ3K.cjs} +4 -4
  96. package/dist/{chunk-C5DEO6OI.cjs.map → chunk-CQGYNZ3K.cjs.map} +1 -1
  97. package/dist/{chunk-D75S2X6I.cjs → chunk-CTCGWIUD.cjs} +5 -5
  98. package/dist/{chunk-D75S2X6I.cjs.map → chunk-CTCGWIUD.cjs.map} +1 -1
  99. package/dist/{chunk-NZL4BNFQ.js → chunk-CV7XMBHP.js} +4 -4
  100. package/dist/chunk-CV7XMBHP.js.map +1 -0
  101. package/dist/{chunk-SEL2ZQMT.js → chunk-DAPSQZT4.js} +15 -10
  102. package/dist/chunk-DAPSQZT4.js.map +1 -0
  103. package/dist/{chunk-SVO5WPZX.cjs → chunk-DQKERTND.cjs} +11 -11
  104. package/dist/{chunk-SVO5WPZX.cjs.map → chunk-DQKERTND.cjs.map} +1 -1
  105. package/dist/{chunk-N5CR3TJZ.js → chunk-DZBSJX6J.js} +4 -4
  106. package/dist/{chunk-N5CR3TJZ.js.map → chunk-DZBSJX6J.js.map} +1 -1
  107. package/dist/{chunk-RAHSWE5C.cjs → chunk-EI2Q7SJ5.cjs} +12 -12
  108. package/dist/chunk-EI2Q7SJ5.cjs.map +1 -0
  109. package/dist/{chunk-UCFONJBG.js → chunk-EPSICJLZ.js} +2 -2
  110. package/dist/{chunk-UCFONJBG.js.map → chunk-EPSICJLZ.js.map} +1 -1
  111. package/dist/{chunk-3X6PM7DU.cjs → chunk-F3YZMOAU.cjs} +8 -8
  112. package/dist/{chunk-3X6PM7DU.cjs.map → chunk-F3YZMOAU.cjs.map} +1 -1
  113. package/dist/{chunk-F77UENR6.cjs → chunk-F5WMX4EA.cjs} +586 -398
  114. package/dist/chunk-F5WMX4EA.cjs.map +1 -0
  115. package/dist/{chunk-HE4BIAOS.js → chunk-F7AQV62G.js} +5 -4
  116. package/dist/chunk-F7AQV62G.js.map +1 -0
  117. package/dist/{chunk-2RW7K6FN.cjs → chunk-GHX4P3V2.cjs} +2 -2
  118. package/dist/chunk-GHX4P3V2.cjs.map +1 -0
  119. package/dist/{chunk-B6HOIWQ6.js → chunk-GJ6RK75E.js} +5 -5
  120. package/dist/chunk-GJ6RK75E.js.map +1 -0
  121. package/dist/{chunk-FOXKFTVZ.cjs → chunk-GNT35C5U.cjs} +13 -13
  122. package/dist/chunk-GNT35C5U.cjs.map +1 -0
  123. package/dist/{chunk-4NAKHID5.js → chunk-GTKFV7O5.js} +2 -2
  124. package/dist/chunk-GTKFV7O5.js.map +1 -0
  125. package/dist/{chunk-ELKO4ZLR.cjs → chunk-GWC3HADL.cjs} +4 -4
  126. package/dist/{chunk-ELKO4ZLR.cjs.map → chunk-GWC3HADL.cjs.map} +1 -1
  127. package/dist/{chunk-OXNYIMZZ.js → chunk-H73MEMQB.js} +2 -2
  128. package/dist/chunk-H73MEMQB.js.map +1 -0
  129. package/dist/{chunk-E7FJOO4G.cjs → chunk-HJBMA5MB.cjs} +11 -11
  130. package/dist/{chunk-E7FJOO4G.cjs.map → chunk-HJBMA5MB.cjs.map} +1 -1
  131. package/dist/{chunk-2FYEVT2B.cjs → chunk-HLPSLDGL.cjs} +275 -160
  132. package/dist/chunk-HLPSLDGL.cjs.map +1 -0
  133. package/dist/{chunk-VW6M4B3Z.cjs → chunk-HY57ULY2.cjs} +5 -5
  134. package/dist/{chunk-VW6M4B3Z.cjs.map → chunk-HY57ULY2.cjs.map} +1 -1
  135. package/dist/{chunk-CAH3G4IS.js → chunk-HY66GLM6.js} +2 -2
  136. package/dist/chunk-HY66GLM6.js.map +1 -0
  137. package/dist/{chunk-G3JWXOGY.js → chunk-I5BE5M5L.js} +310 -122
  138. package/dist/chunk-I5BE5M5L.js.map +1 -0
  139. package/dist/{chunk-C4H6PB5J.cjs → chunk-I6TGFUCO.cjs} +4 -4
  140. package/dist/{chunk-C4H6PB5J.cjs.map → chunk-I6TGFUCO.cjs.map} +1 -1
  141. package/dist/{chunk-U4UJHOSH.js → chunk-IDCKSLYH.js} +3 -3
  142. package/dist/{chunk-U4UJHOSH.js.map → chunk-IDCKSLYH.js.map} +1 -1
  143. package/dist/{chunk-WQ53UQL4.cjs → chunk-ILCGLTSA.cjs} +4 -4
  144. package/dist/{chunk-WQ53UQL4.cjs.map → chunk-ILCGLTSA.cjs.map} +1 -1
  145. package/dist/{chunk-QBTVATSF.cjs → chunk-ITSSOVOB.cjs} +44 -47
  146. package/dist/chunk-ITSSOVOB.cjs.map +1 -0
  147. package/dist/{chunk-V6HWJQQV.js → chunk-IVNNSANC.js} +27 -30
  148. package/dist/chunk-IVNNSANC.js.map +1 -0
  149. package/dist/{chunk-SZHU7A5B.cjs → chunk-IWBGCBR6.cjs} +4 -4
  150. package/dist/{chunk-SZHU7A5B.cjs.map → chunk-IWBGCBR6.cjs.map} +1 -1
  151. package/dist/{chunk-Q4RESANI.cjs → chunk-J24VJOH3.cjs} +20 -4
  152. package/dist/chunk-J24VJOH3.cjs.map +1 -0
  153. package/dist/{chunk-Y4AXQOT4.cjs → chunk-JHPGF3FP.cjs} +8 -8
  154. package/dist/{chunk-Y4AXQOT4.cjs.map → chunk-JHPGF3FP.cjs.map} +1 -1
  155. package/dist/{chunk-BM6N4KHO.cjs → chunk-JTB5Q42C.cjs} +6 -22
  156. package/dist/chunk-JTB5Q42C.cjs.map +1 -0
  157. package/dist/{chunk-LPVIRJVF.cjs → chunk-K3FW2XZD.cjs} +9 -9
  158. package/dist/{chunk-LPVIRJVF.cjs.map → chunk-K3FW2XZD.cjs.map} +1 -1
  159. package/dist/{chunk-LS3LMQ23.js → chunk-MVAPK2BX.js} +162 -49
  160. package/dist/chunk-MVAPK2BX.js.map +1 -0
  161. package/dist/{chunk-XPR366DL.cjs → chunk-NGESVVJN.cjs} +17 -17
  162. package/dist/chunk-NGESVVJN.cjs.map +1 -0
  163. package/dist/{chunk-VUKQL3L2.cjs → chunk-NIRE5CNO.cjs} +20 -13
  164. package/dist/chunk-NIRE5CNO.cjs.map +1 -0
  165. package/dist/{chunk-VC5ABJXC.js → chunk-NLTVXLGT.js} +3 -3
  166. package/dist/{chunk-VC5ABJXC.js.map → chunk-NLTVXLGT.js.map} +1 -1
  167. package/dist/chunk-NUKRL3I6.cjs +23 -0
  168. package/dist/chunk-NUKRL3I6.cjs.map +1 -0
  169. package/dist/{chunk-R5YZACGK.js → chunk-OC4NTGMN.js} +3 -3
  170. package/dist/{chunk-R5YZACGK.js.map → chunk-OC4NTGMN.js.map} +1 -1
  171. package/dist/{chunk-GOVJO4YE.js → chunk-OHBIUXKM.js} +6 -6
  172. package/dist/chunk-OHBIUXKM.js.map +1 -0
  173. package/dist/{chunk-FPYT5WZP.cjs → chunk-P6A3M6VD.cjs} +10 -10
  174. package/dist/{chunk-FPYT5WZP.cjs.map → chunk-P6A3M6VD.cjs.map} +1 -1
  175. package/dist/{chunk-OKLYRPKL.cjs → chunk-Q47R5E2X.cjs} +8 -8
  176. package/dist/chunk-Q47R5E2X.cjs.map +1 -0
  177. package/dist/{chunk-HSQ5Q3I5.js → chunk-Q4CMI2LP.js} +12 -5
  178. package/dist/chunk-Q4CMI2LP.js.map +1 -0
  179. package/dist/{chunk-2XLKLVVR.js → chunk-Q5EWJPRY.js} +2 -2
  180. package/dist/chunk-Q5EWJPRY.js.map +1 -0
  181. package/dist/{chunk-SK4QLUBK.js → chunk-QARJGQSA.js} +16 -7
  182. package/dist/chunk-QARJGQSA.js.map +1 -0
  183. package/dist/{chunk-CZ2GKKYL.cjs → chunk-QDED6YO6.cjs} +5 -5
  184. package/dist/{chunk-CZ2GKKYL.cjs.map → chunk-QDED6YO6.cjs.map} +1 -1
  185. package/dist/{chunk-VK7MAV65.cjs → chunk-QKLOP4VC.cjs} +2 -2
  186. package/dist/{chunk-VK7MAV65.cjs.map → chunk-QKLOP4VC.cjs.map} +1 -1
  187. package/dist/{chunk-FIOCJYLA.js → chunk-QRSUA2CV.js} +3 -3
  188. package/dist/{chunk-FIOCJYLA.js.map → chunk-QRSUA2CV.js.map} +1 -1
  189. package/dist/{chunk-ZT57WTUJ.cjs → chunk-R3UPQFKK.cjs} +21 -12
  190. package/dist/chunk-R3UPQFKK.cjs.map +1 -0
  191. package/dist/{chunk-X2FR4OIT.js → chunk-R7WIIPUR.js} +2 -2
  192. package/dist/chunk-R7WIIPUR.js.map +1 -0
  193. package/dist/{chunk-RP5HQVLD.js → chunk-RNB4APBZ.js} +30 -7
  194. package/dist/chunk-RNB4APBZ.js.map +1 -0
  195. package/dist/{chunk-GD63JPGC.cjs → chunk-ROYPRJH4.cjs} +9 -9
  196. package/dist/{chunk-GD63JPGC.cjs.map → chunk-ROYPRJH4.cjs.map} +1 -1
  197. package/dist/{chunk-V26QVGUG.js → chunk-RUDY2GTT.js} +59 -23
  198. package/dist/chunk-RUDY2GTT.js.map +1 -0
  199. package/dist/{chunk-JIQRXKTA.cjs → chunk-SKXBJ2NU.cjs} +7 -7
  200. package/dist/chunk-SKXBJ2NU.cjs.map +1 -0
  201. package/dist/{chunk-XROIW6BH.js → chunk-SUKXXLWD.js} +6 -6
  202. package/dist/chunk-SUKXXLWD.js.map +1 -0
  203. package/dist/{chunk-LTSTGCL6.js → chunk-T73NA43R.js} +3 -3
  204. package/dist/{chunk-LTSTGCL6.js.map → chunk-T73NA43R.js.map} +1 -1
  205. package/dist/chunk-T7O6K6PX.js +20 -0
  206. package/dist/chunk-T7O6K6PX.js.map +1 -0
  207. package/dist/{chunk-5F5NWKPN.js → chunk-T7XEKOVW.js} +5 -20
  208. package/dist/chunk-T7XEKOVW.js.map +1 -0
  209. package/dist/{chunk-HAWE74GQ.cjs → chunk-U2AC6JUP.cjs} +8 -8
  210. package/dist/chunk-U2AC6JUP.cjs.map +1 -0
  211. package/dist/{chunk-3WVMJY7F.js → chunk-UC3HT2S4.js} +3 -3
  212. package/dist/{chunk-3WVMJY7F.js.map → chunk-UC3HT2S4.js.map} +1 -1
  213. package/dist/{chunk-PBZ7HMBP.js → chunk-UPRJR6IP.js} +4 -4
  214. package/dist/chunk-UPRJR6IP.js.map +1 -0
  215. package/dist/{chunk-3V7UJLQT.js → chunk-UQGQFBRL.js} +3 -3
  216. package/dist/chunk-UQGQFBRL.js.map +1 -0
  217. package/dist/{chunk-2D43RD5D.cjs → chunk-V2UUGUY4.cjs} +27 -27
  218. package/dist/chunk-V2UUGUY4.cjs.map +1 -0
  219. package/dist/{chunk-6AZDM6LK.js → chunk-VF7EWVDG.js} +3 -3
  220. package/dist/{chunk-6AZDM6LK.js.map → chunk-VF7EWVDG.js.map} +1 -1
  221. package/dist/{chunk-PNVDQL5Y.cjs → chunk-VTYY7XL5.cjs} +2 -2
  222. package/dist/chunk-VTYY7XL5.cjs.map +1 -0
  223. package/dist/{chunk-Y4I4EQFK.js → chunk-WKRSH2VR.js} +3 -3
  224. package/dist/{chunk-Y4I4EQFK.js.map → chunk-WKRSH2VR.js.map} +1 -1
  225. package/dist/{chunk-4QEC4CCS.js → chunk-WTMU7J4U.js} +2 -2
  226. package/dist/{chunk-4QEC4CCS.js.map → chunk-WTMU7J4U.js.map} +1 -1
  227. package/dist/{chunk-KSWHTR54.js → chunk-XN7NOENA.js} +6 -6
  228. package/dist/chunk-XN7NOENA.js.map +1 -0
  229. package/dist/{chunk-ADLLFY3H.cjs → chunk-XSX2UU6Y.cjs} +10 -9
  230. package/dist/chunk-XSX2UU6Y.cjs.map +1 -0
  231. package/dist/{chunk-LD4MOBFX.js → chunk-XV4IZNV4.js} +9 -9
  232. package/dist/chunk-XV4IZNV4.js.map +1 -0
  233. package/dist/{chunk-EZ2YEF4F.cjs → chunk-XWL6O3SW.cjs} +4 -4
  234. package/dist/chunk-XWL6O3SW.cjs.map +1 -0
  235. package/dist/{chunk-PGP7IOJ2.js → chunk-YMA4S2WO.js} +4 -4
  236. package/dist/{chunk-PGP7IOJ2.js.map → chunk-YMA4S2WO.js.map} +1 -1
  237. package/dist/{chunk-OUOXM36O.cjs → chunk-YPJ5NH5N.cjs} +11 -11
  238. package/dist/chunk-YPJ5NH5N.cjs.map +1 -0
  239. package/dist/{chunk-YLQQX5W2.cjs → chunk-ZF2LDKQQ.cjs} +2 -2
  240. package/dist/chunk-ZF2LDKQQ.cjs.map +1 -0
  241. package/dist/{chunk-L5YO6PWL.cjs → chunk-ZNW6V4Y6.cjs} +2 -2
  242. package/dist/chunk-ZNW6V4Y6.cjs.map +1 -0
  243. package/dist/client/index.cjs.map +1 -1
  244. package/dist/client/index.js.map +1 -1
  245. package/dist/client/theokit-client.d.cts +36 -0
  246. package/dist/client/theokit-client.d.ts +36 -0
  247. package/dist/client/types.d.cts +30 -0
  248. package/dist/client/types.d.ts +30 -0
  249. package/dist/compact-session-FUJDVF7B.js +22 -0
  250. package/dist/{compact-session-4MNKNMO2.js.map → compact-session-FUJDVF7B.js.map} +1 -1
  251. package/dist/compact-session-LEWF554G.cjs +59 -0
  252. package/dist/{compact-session-EPFBQ46Z.cjs.map → compact-session-LEWF554G.cjs.map} +1 -1
  253. package/dist/compaction.cjs +17 -16
  254. package/dist/compaction.d.cts +13 -13
  255. package/dist/compaction.d.ts +13 -13
  256. package/dist/compaction.js +4 -3
  257. package/dist/concurrency.cjs +7 -6
  258. package/dist/concurrency.cjs.map +1 -1
  259. package/dist/concurrency.js +5 -4
  260. package/dist/concurrency.js.map +1 -1
  261. package/dist/context/index.cjs +7 -7
  262. package/dist/context/index.js +3 -3
  263. package/dist/context-FDOON2DB.js +6 -0
  264. package/dist/{context-ENXZNF6J.js.map → context-FDOON2DB.js.map} +1 -1
  265. package/dist/context-VMIE4BMD.cjs +23 -0
  266. package/dist/{context-7USNN6LP.cjs.map → context-VMIE4BMD.cjs.map} +1 -1
  267. package/dist/cron-BcWmzWzT.d.cts +240 -0
  268. package/dist/cron-De6hzWCF.d.ts +240 -0
  269. package/dist/cron.cjs +43 -41
  270. package/dist/cron.d.cts +5 -3
  271. package/dist/cron.d.ts +5 -3
  272. package/dist/cron.js +42 -40
  273. package/dist/define-tool.d.ts +14 -6
  274. package/dist/{errors-BSoXcl3F.d.cts → errors-BgJH9PHi.d.cts} +39 -24
  275. package/dist/{errors-CHllybaU.d.ts → errors-C5fJUqLk.d.ts} +39 -24
  276. package/dist/errors.cjs +22 -21
  277. package/dist/errors.d.cts +2 -2
  278. package/dist/errors.d.ts +2 -2
  279. package/dist/errors.js +3 -2
  280. package/dist/eval.cjs +61 -58
  281. package/dist/eval.cjs.map +1 -1
  282. package/dist/eval.d.cts +38 -0
  283. package/dist/eval.d.ts +38 -0
  284. package/dist/eval.js +51 -48
  285. package/dist/eval.js.map +1 -1
  286. package/dist/event-bus.d.ts +16 -0
  287. package/dist/{executor-2Z6XJJJG.js → executor-BMEHFOXZ.js} +8 -7
  288. package/dist/executor-BMEHFOXZ.js.map +1 -0
  289. package/dist/{executor-2Z3LGG3I.cjs → executor-ZERJ3DGN.cjs} +25 -24
  290. package/dist/executor-ZERJ3DGN.cjs.map +1 -0
  291. package/dist/filesystem/index.cjs +8 -7
  292. package/dist/filesystem/index.cjs.map +1 -1
  293. package/dist/filesystem/index.js +4 -3
  294. package/dist/filesystem/index.js.map +1 -1
  295. package/dist/filesystem/local-filesystem.d.cts +18 -0
  296. package/dist/filesystem/local-filesystem.d.ts +18 -0
  297. package/dist/filesystem/types.d.cts +12 -0
  298. package/dist/filesystem/types.d.ts +12 -0
  299. package/dist/fs-session-store-3MOJQGP2.cjs +20 -0
  300. package/dist/{fs-session-store-VVY2AHWG.cjs.map → fs-session-store-3MOJQGP2.cjs.map} +1 -1
  301. package/dist/fs-session-store-IN7JTTXD.js +11 -0
  302. package/dist/{fs-session-store-R5FD3EN6.js.map → fs-session-store-IN7JTTXD.js.map} +1 -1
  303. package/dist/generate-object-N5MDZUJI.js +8 -0
  304. package/dist/{generate-object-WQRCXFD2.js.map → generate-object-N5MDZUJI.js.map} +1 -1
  305. package/dist/generate-object-PGSP5U7N.cjs +21 -0
  306. package/dist/{generate-object-AVXOJK2I.cjs.map → generate-object-PGSP5U7N.cjs.map} +1 -1
  307. package/dist/generate-object.d.ts +20 -0
  308. package/dist/index-manager-NG5YENWO.cjs +22 -0
  309. package/dist/{index-manager-VRU3A2YL.cjs.map → index-manager-NG5YENWO.cjs.map} +1 -1
  310. package/dist/index-manager-ZMRJ6ZII.js +13 -0
  311. package/dist/{index-manager-WS7TVKUW.js.map → index-manager-ZMRJ6ZII.js.map} +1 -1
  312. package/dist/index.cjs +169 -155
  313. package/dist/index.cjs.map +1 -1
  314. package/dist/index.d.cts +702 -54
  315. package/dist/index.d.ts +702 -54
  316. package/dist/index.js +61 -58
  317. package/dist/index.js.map +1 -1
  318. package/dist/{inject-session-GMBMJVNZ.js → inject-session-BJMJH5BX.js} +9 -8
  319. package/dist/inject-session-BJMJH5BX.js.map +1 -0
  320. package/dist/inject-session-WQGGMCQY.cjs +29 -0
  321. package/dist/inject-session-WQGGMCQY.cjs.map +1 -0
  322. package/dist/internal/auth/auth-types.d.ts +83 -1
  323. package/dist/internal/auth/credential-store.d.ts +34 -6
  324. package/dist/internal/auth/oauth-device.d.ts +0 -1
  325. package/dist/internal/auth/resolve-credential.d.ts +40 -0
  326. package/dist/internal/budget/tracker/budget.d.ts +12 -14
  327. package/dist/internal/budget/usage-accumulator.d.ts +15 -0
  328. package/dist/internal/llm/anthropic-shared.d.ts +8 -4
  329. package/dist/internal/llm/model-identifier.d.ts +26 -0
  330. package/dist/internal/llm/openai.d.ts +8 -0
  331. package/dist/internal/llm/prompt-cache-key.d.ts +1 -0
  332. package/dist/internal/llm/responses.d.ts +67 -1
  333. package/dist/internal/llm/router.d.ts +8 -0
  334. package/dist/internal/llm/types.d.ts +27 -1
  335. package/dist/internal/local-agent/real-local-run-provider.d.ts +8 -3
  336. package/dist/internal/local-agent/real-local-run-tools.d.ts +23 -4
  337. package/dist/internal/mcp/oauth.d.ts +5 -0
  338. package/dist/internal/mcp/token-storage.d.ts +34 -0
  339. package/dist/internal/memory/adapters/index.cjs +12 -11
  340. package/dist/internal/memory/adapters/index.d.cts +3 -1
  341. package/dist/internal/memory/adapters/index.d.ts +3 -1
  342. package/dist/internal/memory/adapters/index.js +9 -8
  343. package/dist/internal/memory/adapters/openai-compatible.d.cts +45 -0
  344. package/dist/internal/memory/adapters/openai-compatible.d.ts +45 -0
  345. package/dist/internal/memory/embedding-cache.d.ts +42 -1
  346. package/dist/internal/memory/escape-like-pattern.d.ts +22 -0
  347. package/dist/internal/memory/sqlite-vec-loader.d.ts +1 -3
  348. package/dist/internal/memory/storage/markdown-store.d.ts +0 -5
  349. package/dist/internal/persistence/cwd-mutex.d.cts +34 -0
  350. package/dist/internal/persistence/cwd-mutex.d.ts +34 -0
  351. package/dist/internal/persistence/exclusive-create.d.cts +31 -0
  352. package/dist/internal/persistence/exclusive-create.d.ts +31 -0
  353. package/dist/internal/persistence/file-lock.d.cts +28 -0
  354. package/dist/internal/persistence/file-lock.d.ts +28 -0
  355. package/dist/internal/persistence/fs-session-store.d.cts +3 -0
  356. package/dist/internal/persistence/fs-session-store.d.ts +3 -0
  357. package/dist/internal/persistence/fts5-sanitize.d.cts +20 -0
  358. package/dist/internal/persistence/fts5-sanitize.d.ts +20 -0
  359. package/dist/internal/persistence/index.cjs +40 -39
  360. package/dist/internal/persistence/index.cjs.map +1 -1
  361. package/dist/internal/persistence/index.d.cts +6 -1
  362. package/dist/internal/persistence/index.d.ts +6 -1
  363. package/dist/internal/persistence/index.js +9 -8
  364. package/dist/internal/persistence/index.js.map +1 -1
  365. package/dist/internal/persistence/paths.d.cts +54 -1
  366. package/dist/internal/persistence/paths.d.ts +54 -1
  367. package/dist/internal/persistence/persistence-schema.d.cts +9 -1
  368. package/dist/internal/persistence/persistence-schema.d.ts +9 -1
  369. package/dist/internal/persistence/schema-version.d.cts +215 -1
  370. package/dist/internal/persistence/schema-version.d.ts +215 -1
  371. package/dist/internal/persistence/session-writer.d.cts +7 -7
  372. package/dist/internal/persistence/session-writer.d.ts +7 -7
  373. package/dist/internal/persistence/sqlite-cas.d.cts +37 -1
  374. package/dist/internal/persistence/sqlite-cas.d.ts +37 -1
  375. package/dist/internal/persistence/sqlite-open.d.cts +14 -0
  376. package/dist/internal/persistence/sqlite-open.d.ts +14 -0
  377. package/dist/internal/persistence/sqlite-wal.d.cts +45 -0
  378. package/dist/internal/persistence/sqlite-wal.d.ts +45 -0
  379. package/dist/internal/persistence/transcript-ops.d.cts +7 -1
  380. package/dist/internal/persistence/transcript-ops.d.ts +7 -1
  381. package/dist/internal/plugins/types.d.cts +1 -1
  382. package/dist/internal/plugins/types.d.ts +1 -1
  383. package/dist/internal/providers/builtin/openai-chatgpt.d.ts +12 -0
  384. package/dist/internal/providers/catalog-loader.d.ts +8 -0
  385. package/dist/internal/providers/catalog-schema.d.ts +55 -0
  386. package/dist/internal/providers/catalog-source-models-dev.d.ts +36 -0
  387. package/dist/internal/runtime/concurrency/delegation-depth.d.ts +27 -0
  388. package/dist/internal/runtime/concurrency/subagent-credentials.d.ts +33 -1
  389. package/dist/internal/runtime/context/context-discovery-runner.d.ts +44 -0
  390. package/dist/internal/runtime/context/context-discovery.d.ts +58 -0
  391. package/dist/internal/runtime/context/context-rules-frontmatter.d.ts +70 -1
  392. package/dist/internal/runtime/fixtures/fixture-mode.d.ts +15 -1
  393. package/dist/internal/runtime/lifecycle/post-run-lifecycle.d.ts +15 -0
  394. package/dist/internal/runtime/registry/agent-registry-store.d.ts +12 -0
  395. package/dist/internal/runtime/registry/live-agent-registry.d.ts +37 -0
  396. package/dist/internal/scorers/llm-judge.d.ts +6 -1
  397. package/dist/internal/security/index.cjs +14 -13
  398. package/dist/internal/security/index.d.cts +4 -1
  399. package/dist/internal/security/index.d.ts +4 -1
  400. package/dist/internal/security/index.js +4 -3
  401. package/dist/internal/security/path-guard.d.cts +46 -0
  402. package/dist/internal/security/path-guard.d.ts +46 -0
  403. package/dist/internal/security/redact.d.cts +71 -0
  404. package/dist/internal/security/redact.d.ts +71 -0
  405. package/dist/internal/session/agent-session.d.ts +15 -4
  406. package/dist/internal/session/session-cache.d.ts +5 -0
  407. package/dist/internal/task/store.d.ts +91 -5
  408. package/dist/internal/telemetry/span-names.d.ts +0 -1
  409. package/dist/internal/telemetry/tracer.d.ts +14 -0
  410. package/dist/job-queue.d.ts +18 -0
  411. package/dist/judge-call-DWHAJATE.js +6 -0
  412. package/dist/{judge-call-MDIPTBJI.js.map → judge-call-DWHAJATE.js.map} +1 -1
  413. package/dist/judge-call-EGYRC2RE.cjs +23 -0
  414. package/dist/{judge-call-G5SGV2M2.cjs.map → judge-call-EGYRC2RE.cjs.map} +1 -1
  415. package/dist/mcp-auth.cjs +41 -25
  416. package/dist/mcp-auth.cjs.map +1 -1
  417. package/dist/mcp-auth.js +34 -18
  418. package/dist/mcp-auth.js.map +1 -1
  419. package/dist/models.cjs +42 -27
  420. package/dist/models.cjs.map +1 -1
  421. package/dist/models.js +25 -10
  422. package/dist/models.js.map +1 -1
  423. package/dist/oauth-transaction-store-BT4GLTLK.cjs +36 -0
  424. package/dist/{oauth-transaction-store-7CKHPQRN.cjs.map → oauth-transaction-store-BT4GLTLK.cjs.map} +1 -1
  425. package/dist/oauth-transaction-store-W52KVHQ4.js +3 -0
  426. package/dist/{oauth-transaction-store-W74I6EFD.js.map → oauth-transaction-store-W52KVHQ4.js.map} +1 -1
  427. package/dist/path-safety.cjs +11 -10
  428. package/dist/path-safety.js +4 -3
  429. package/dist/permission-engine.d.ts +55 -0
  430. package/dist/persistence.cjs +43 -42
  431. package/dist/persistence.cjs.map +1 -1
  432. package/dist/persistence.js +13 -12
  433. package/dist/persistence.js.map +1 -1
  434. package/dist/project.cjs +9 -8
  435. package/dist/project.cjs.map +1 -1
  436. package/dist/project.js +5 -4
  437. package/dist/project.js.map +1 -1
  438. package/dist/providers.cjs +23 -0
  439. package/dist/providers.cjs.map +1 -0
  440. package/dist/providers.d.cts +29 -0
  441. package/dist/providers.d.ts +29 -0
  442. package/dist/providers.js +10 -0
  443. package/dist/providers.js.map +1 -0
  444. package/dist/registry-VFKX7WOP.cjs +47 -0
  445. package/dist/{registry-63ASMXT4.cjs.map → registry-VFKX7WOP.cjs.map} +1 -1
  446. package/dist/registry-VFP3WWQP.js +10 -0
  447. package/dist/{registry-O7FJ2MPM.js.map → registry-VFP3WWQP.js.map} +1 -1
  448. package/dist/retry.cjs +5 -4
  449. package/dist/retry.js +4 -3
  450. package/dist/{run-C8FBAC8o.d.cts → run-BYSHf58D.d.cts} +185 -33
  451. package/dist/{run-C8FBAC8o.d.ts → run-BYSHf58D.d.ts} +185 -33
  452. package/dist/{run-to-completion-JDPIUKSH.js → run-to-completion-DRO77625.js} +3 -3
  453. package/dist/{run-to-completion-JDPIUKSH.js.map → run-to-completion-DRO77625.js.map} +1 -1
  454. package/dist/{run-to-completion-J73I6IY4.cjs → run-to-completion-X4OWM673.cjs} +13 -13
  455. package/dist/{run-to-completion-J73I6IY4.cjs.map → run-to-completion-X4OWM673.cjs.map} +1 -1
  456. package/dist/sandbox/bwrap.d.cts +27 -13
  457. package/dist/sandbox/bwrap.d.ts +27 -13
  458. package/dist/sandbox/index.cjs +20 -19
  459. package/dist/sandbox/index.cjs.map +1 -1
  460. package/dist/sandbox/index.js +5 -4
  461. package/dist/sandbox/index.js.map +1 -1
  462. package/dist/sandbox/linux-sandbox.d.cts +72 -0
  463. package/dist/sandbox/linux-sandbox.d.ts +72 -0
  464. package/dist/sandbox/local-sandbox.d.cts +41 -0
  465. package/dist/sandbox/local-sandbox.d.ts +41 -0
  466. package/dist/sandbox/seccomp.d.cts +6 -0
  467. package/dist/sandbox/seccomp.d.ts +6 -0
  468. package/dist/sandbox/types.d.cts +64 -0
  469. package/dist/sandbox/types.d.ts +64 -0
  470. package/dist/scorers.d.ts +38 -7
  471. package/dist/sdk-agent-D8qJVkuV.d.ts +860 -0
  472. package/dist/sdk-agent-DEoKhA8a.d.cts +860 -0
  473. package/dist/server/auth/errors.d.cts +1 -1
  474. package/dist/server/auth/errors.d.ts +1 -1
  475. package/dist/server/auth/index.cjs +29 -21
  476. package/dist/server/auth/index.cjs.map +1 -1
  477. package/dist/server/auth/index.d.cts +25 -15
  478. package/dist/server/auth/index.d.ts +25 -15
  479. package/dist/server/auth/index.js +15 -7
  480. package/dist/server/auth/index.js.map +1 -1
  481. package/dist/server/auth/oauth-transaction-store.d.cts +13 -1
  482. package/dist/server/auth/oauth-transaction-store.d.ts +13 -1
  483. package/dist/server/auth/orchestrator.d.cts +1 -1
  484. package/dist/server/auth/orchestrator.d.ts +1 -1
  485. package/dist/server/auth/types.d.cts +1 -1
  486. package/dist/server/auth/types.d.ts +1 -1
  487. package/dist/server/auth/validate-return-to.d.cts +21 -11
  488. package/dist/server/auth/validate-return-to.d.ts +21 -11
  489. package/dist/server/errors-envelope.cjs +15 -14
  490. package/dist/server/errors-envelope.cjs.map +1 -1
  491. package/dist/server/errors-envelope.d.cts +4 -4
  492. package/dist/server/errors-envelope.d.ts +4 -4
  493. package/dist/server/errors-envelope.js +4 -3
  494. package/dist/server/errors-envelope.js.map +1 -1
  495. package/dist/session-transcript-AKDYYGXQ.js +6 -0
  496. package/dist/{session-transcript-RAKEK76V.js.map → session-transcript-AKDYYGXQ.js.map} +1 -1
  497. package/dist/session-transcript-JXHFTB7G.cjs +51 -0
  498. package/dist/{session-transcript-DOM3UTXR.cjs.map → session-transcript-JXHFTB7G.cjs.map} +1 -1
  499. package/dist/skills.cjs +8 -7
  500. package/dist/skills.js +6 -5
  501. package/dist/stream-object-BUCF5PHO.cjs +21 -0
  502. package/dist/{stream-object-L3Q7PBMF.cjs.map → stream-object-BUCF5PHO.cjs.map} +1 -1
  503. package/dist/stream-object-L57K4OFS.js +8 -0
  504. package/dist/{stream-object-ZYXWS4B2.js.map → stream-object-L57K4OFS.js.map} +1 -1
  505. package/dist/{stream-to-completion-DFJ5T3BK.js → stream-to-completion-QV5HCL3J.js} +3 -3
  506. package/dist/{stream-to-completion-DFJ5T3BK.js.map → stream-to-completion-QV5HCL3J.js.map} +1 -1
  507. package/dist/{stream-to-completion-H2MHISSK.cjs → stream-to-completion-SRISU5AB.cjs} +10 -10
  508. package/dist/{stream-to-completion-H2MHISSK.cjs.map → stream-to-completion-SRISU5AB.cjs.map} +1 -1
  509. package/dist/subagents-loader-AZIXJ7D3.cjs +16 -0
  510. package/dist/{subagents-loader-VRW73QQT.cjs.map → subagents-loader-AZIXJ7D3.cjs.map} +1 -1
  511. package/dist/subagents-loader-J54ESLDV.js +7 -0
  512. package/dist/{subagents-loader-I56GSKAQ.js.map → subagents-loader-J54ESLDV.js.map} +1 -1
  513. package/dist/subagents-loader.cjs +7 -6
  514. package/dist/subagents-loader.cjs.map +1 -1
  515. package/dist/subagents-loader.d.cts +3 -2
  516. package/dist/subagents-loader.d.ts +3 -2
  517. package/dist/subagents-loader.js +5 -4
  518. package/dist/subagents-loader.js.map +1 -1
  519. package/dist/subscription/define-subscription.d.cts +1 -1
  520. package/dist/subscription/define-subscription.d.ts +1 -1
  521. package/dist/subscription/index.cjs +22 -9
  522. package/dist/subscription/index.cjs.map +1 -1
  523. package/dist/subscription/index.d.cts +1 -1
  524. package/dist/subscription/index.d.ts +1 -1
  525. package/dist/subscription/index.js +21 -8
  526. package/dist/subscription/index.js.map +1 -1
  527. package/dist/subscription/internal/adapter-types.d.cts +1 -1
  528. package/dist/subscription/internal/adapter-types.d.ts +1 -1
  529. package/dist/subscription/internal/server-integration.d.cts +1 -1
  530. package/dist/subscription/internal/server-integration.d.ts +1 -1
  531. package/dist/subscription/internal/sse-encoder.d.cts +1 -1
  532. package/dist/subscription/internal/sse-encoder.d.ts +1 -1
  533. package/dist/subscription/internal/sse-parser.d.cts +1 -1
  534. package/dist/subscription/internal/sse-parser.d.ts +1 -1
  535. package/dist/subscription/internal/subscription-runtime.d.cts +1 -1
  536. package/dist/subscription/internal/subscription-runtime.d.ts +1 -1
  537. package/dist/subscription/internal/ws-adapter-node.d.cts +1 -1
  538. package/dist/subscription/internal/ws-adapter-node.d.ts +1 -1
  539. package/dist/subscription/theokit-subscribe.d.cts +14 -1
  540. package/dist/subscription/theokit-subscribe.d.ts +14 -1
  541. package/dist/subscription/types.d.cts +19 -1
  542. package/dist/subscription/types.d.ts +19 -1
  543. package/dist/task-store.cjs +8 -7
  544. package/dist/task-store.js +5 -4
  545. package/dist/types/agent-prims.d.ts +14 -0
  546. package/dist/types/agent.d.ts +92 -11
  547. package/dist/types/batch.d.ts +7 -1
  548. package/dist/types/conversation.d.ts +18 -5
  549. package/dist/types/goal-events.d.ts +4 -8
  550. package/dist/types/memory-adapter.d.ts +12 -1
  551. package/dist/types/plugin.d.ts +101 -0
  552. package/dist/types/provider-profile.d.ts +32 -0
  553. package/dist/types/run-events.d.ts +28 -1
  554. package/dist/types/run.d.ts +35 -23
  555. package/dist/types/sdk-agent.d.ts +14 -0
  556. package/dist/types/session-record.d.ts +18 -1
  557. package/dist/types/task.d.ts +15 -1
  558. package/dist/types/theokit.d.ts +10 -1
  559. package/dist/types/updates.d.ts +35 -4
  560. package/dist/types/workflow.d.ts +155 -0
  561. package/dist/workflow.cjs +29 -28
  562. package/dist/workflow.d.cts +666 -17
  563. package/dist/workflow.d.ts +666 -17
  564. package/dist/workflow.js +8 -7
  565. package/docs/error-codes.md +215 -0
  566. package/docs/harness-capability-map.md +1358 -0
  567. package/package.json +29 -16
  568. package/bin/init-claude.mjs +0 -68
  569. package/claude-template/AGENTS.md +0 -157
  570. package/claude-template/CLAUDE.md +0 -66
  571. package/claude-template/dot-claude/rules/theokit-conventions.md +0 -32
  572. package/claude-template/dot-claude/settings.json +0 -16
  573. package/claude-template/dot-claude/skills/theokit-agent-core/SKILL.md +0 -209
  574. package/claude-template/dot-claude/skills/theokit-auth/SKILL.md +0 -102
  575. package/claude-template/dot-claude/skills/theokit-budget/SKILL.md +0 -176
  576. package/claude-template/dot-claude/skills/theokit-client/SKILL.md +0 -58
  577. package/claude-template/dot-claude/skills/theokit-compaction/SKILL.md +0 -102
  578. package/claude-template/dot-claude/skills/theokit-concurrency/SKILL.md +0 -68
  579. package/claude-template/dot-claude/skills/theokit-config/SKILL.md +0 -139
  580. package/claude-template/dot-claude/skills/theokit-cron/SKILL.md +0 -148
  581. package/claude-template/dot-claude/skills/theokit-di/SKILL.md +0 -233
  582. package/claude-template/dot-claude/skills/theokit-di-agent/SKILL.md +0 -294
  583. package/claude-template/dot-claude/skills/theokit-errors/SKILL.md +0 -172
  584. package/claude-template/dot-claude/skills/theokit-eval/SKILL.md +0 -179
  585. package/claude-template/dot-claude/skills/theokit-filesystem/SKILL.md +0 -74
  586. package/claude-template/dot-claude/skills/theokit-gateways/SKILL.md +0 -209
  587. package/claude-template/dot-claude/skills/theokit-memory/SKILL.md +0 -176
  588. package/claude-template/dot-claude/skills/theokit-messages/SKILL.md +0 -58
  589. package/claude-template/dot-claude/skills/theokit-models/SKILL.md +0 -79
  590. package/claude-template/dot-claude/skills/theokit-path-safety/SKILL.md +0 -60
  591. package/claude-template/dot-claude/skills/theokit-persistence/SKILL.md +0 -85
  592. package/claude-template/dot-claude/skills/theokit-project/SKILL.md +0 -55
  593. package/claude-template/dot-claude/skills/theokit-retry/SKILL.md +0 -50
  594. package/claude-template/dot-claude/skills/theokit-sandbox/SKILL.md +0 -93
  595. package/claude-template/dot-claude/skills/theokit-sanitize/SKILL.md +0 -66
  596. package/claude-template/dot-claude/skills/theokit-skills/SKILL.md +0 -68
  597. package/claude-template/dot-claude/skills/theokit-streaming/SKILL.md +0 -156
  598. package/claude-template/dot-claude/skills/theokit-subagents/SKILL.md +0 -109
  599. package/claude-template/dot-claude/skills/theokit-subscriptions/SKILL.md +0 -148
  600. package/claude-template/dot-claude/skills/theokit-task-store/SKILL.md +0 -75
  601. package/claude-template/dot-claude/skills/theokit-tools/SKILL.md +0 -170
  602. package/claude-template/dot-claude/skills/theokit-workflows/SKILL.md +0 -218
  603. package/dist/agent-FFVV4U5N.js +0 -50
  604. package/dist/agent-YLAHVHEH.cjs +0 -59
  605. package/dist/agent-session-store-DUGBAX5V.cjs +0 -23
  606. package/dist/agent-session-store-TNCGL5RN.js +0 -6
  607. package/dist/batch-UPKN4SG6.js.map +0 -1
  608. package/dist/batch-ZEFN5SO7.cjs.map +0 -1
  609. package/dist/chunk-2D43RD5D.cjs.map +0 -1
  610. package/dist/chunk-2FYEVT2B.cjs.map +0 -1
  611. package/dist/chunk-2RW7K6FN.cjs.map +0 -1
  612. package/dist/chunk-2XLKLVVR.js.map +0 -1
  613. package/dist/chunk-34XOCZJO.js.map +0 -1
  614. package/dist/chunk-3V7UJLQT.js.map +0 -1
  615. package/dist/chunk-4NAKHID5.js.map +0 -1
  616. package/dist/chunk-4Q4K4WB5.js.map +0 -1
  617. package/dist/chunk-5F5NWKPN.js.map +0 -1
  618. package/dist/chunk-5NBUH3NO.js.map +0 -1
  619. package/dist/chunk-5YKNEMXR.cjs.map +0 -1
  620. package/dist/chunk-7W7ZWMLQ.js.map +0 -1
  621. package/dist/chunk-ADLLFY3H.cjs.map +0 -1
  622. package/dist/chunk-B4YA6BRS.cjs.map +0 -1
  623. package/dist/chunk-B6HOIWQ6.js.map +0 -1
  624. package/dist/chunk-BDTVFIPB.cjs.map +0 -1
  625. package/dist/chunk-BFYGJGC5.js.map +0 -1
  626. package/dist/chunk-BM6N4KHO.cjs.map +0 -1
  627. package/dist/chunk-CAH3G4IS.js.map +0 -1
  628. package/dist/chunk-EZ2YEF4F.cjs.map +0 -1
  629. package/dist/chunk-F77UENR6.cjs.map +0 -1
  630. package/dist/chunk-FOXKFTVZ.cjs.map +0 -1
  631. package/dist/chunk-G3JWXOGY.js.map +0 -1
  632. package/dist/chunk-GOVJO4YE.js.map +0 -1
  633. package/dist/chunk-HAWE74GQ.cjs.map +0 -1
  634. package/dist/chunk-HE4BIAOS.js.map +0 -1
  635. package/dist/chunk-HSQ5Q3I5.js.map +0 -1
  636. package/dist/chunk-JIQRXKTA.cjs.map +0 -1
  637. package/dist/chunk-KSWHTR54.js.map +0 -1
  638. package/dist/chunk-L5YO6PWL.cjs.map +0 -1
  639. package/dist/chunk-LD4MOBFX.js.map +0 -1
  640. package/dist/chunk-LS3LMQ23.js.map +0 -1
  641. package/dist/chunk-MSFLYJDY.js.map +0 -1
  642. package/dist/chunk-NZL4BNFQ.js.map +0 -1
  643. package/dist/chunk-OKLYRPKL.cjs.map +0 -1
  644. package/dist/chunk-OUOXM36O.cjs.map +0 -1
  645. package/dist/chunk-OXNYIMZZ.js.map +0 -1
  646. package/dist/chunk-PBZ7HMBP.js.map +0 -1
  647. package/dist/chunk-PNVDQL5Y.cjs.map +0 -1
  648. package/dist/chunk-Q4RESANI.cjs.map +0 -1
  649. package/dist/chunk-QBTVATSF.cjs.map +0 -1
  650. package/dist/chunk-RAHSWE5C.cjs.map +0 -1
  651. package/dist/chunk-RP5HQVLD.js.map +0 -1
  652. package/dist/chunk-SEL2ZQMT.js.map +0 -1
  653. package/dist/chunk-SK4QLUBK.js.map +0 -1
  654. package/dist/chunk-TTJ54H3E.cjs.map +0 -1
  655. package/dist/chunk-V26QVGUG.js.map +0 -1
  656. package/dist/chunk-V6HWJQQV.js.map +0 -1
  657. package/dist/chunk-VGPXHHF3.cjs.map +0 -1
  658. package/dist/chunk-VUKQL3L2.cjs.map +0 -1
  659. package/dist/chunk-VYCKUKPA.cjs.map +0 -1
  660. package/dist/chunk-VYHJZVL5.cjs.map +0 -1
  661. package/dist/chunk-X2FR4OIT.js.map +0 -1
  662. package/dist/chunk-XPR366DL.cjs.map +0 -1
  663. package/dist/chunk-XROIW6BH.js.map +0 -1
  664. package/dist/chunk-YLQQX5W2.cjs.map +0 -1
  665. package/dist/chunk-ZT57WTUJ.cjs.map +0 -1
  666. package/dist/compact-session-4MNKNMO2.js +0 -21
  667. package/dist/compact-session-EPFBQ46Z.cjs +0 -58
  668. package/dist/context-7USNN6LP.cjs +0 -22
  669. package/dist/context-ENXZNF6J.js +0 -5
  670. package/dist/cron-BMjgFH-_.d.ts +0 -631
  671. package/dist/cron-DFDdCdMM.d.cts +0 -631
  672. package/dist/executor-2Z3LGG3I.cjs.map +0 -1
  673. package/dist/executor-2Z6XJJJG.js.map +0 -1
  674. package/dist/fs-session-store-R5FD3EN6.js +0 -10
  675. package/dist/fs-session-store-VVY2AHWG.cjs +0 -19
  676. package/dist/generate-object-AVXOJK2I.cjs +0 -20
  677. package/dist/generate-object-WQRCXFD2.js +0 -7
  678. package/dist/index-manager-VRU3A2YL.cjs +0 -21
  679. package/dist/index-manager-WS7TVKUW.js +0 -12
  680. package/dist/inject-session-AUQLBDRS.cjs +0 -28
  681. package/dist/inject-session-AUQLBDRS.cjs.map +0 -1
  682. package/dist/inject-session-GMBMJVNZ.js.map +0 -1
  683. package/dist/judge-call-G5SGV2M2.cjs +0 -22
  684. package/dist/judge-call-MDIPTBJI.js +0 -5
  685. package/dist/oauth-transaction-store-7CKHPQRN.cjs +0 -32
  686. package/dist/oauth-transaction-store-W74I6EFD.js +0 -3
  687. package/dist/registry-63ASMXT4.cjs +0 -46
  688. package/dist/registry-O7FJ2MPM.js +0 -9
  689. package/dist/session-transcript-DOM3UTXR.cjs +0 -50
  690. package/dist/session-transcript-RAKEK76V.js +0 -5
  691. package/dist/stream-object-L3Q7PBMF.cjs +0 -20
  692. package/dist/stream-object-ZYXWS4B2.js +0 -7
  693. package/dist/subagents-loader-I56GSKAQ.js +0 -6
  694. package/dist/subagents-loader-VRW73QQT.cjs +0 -15
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/memory/embedding-cache.ts"],"names":[],"mappings":";;;AAQO,IAAM,oBAAN,MAAkD;AAAA,EAGvD,WAAA,CAA6B,WAAmB,GAAA,EAAM;AAAzB,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AAAA,EAA0B;AAAA,EAA1B,QAAA;AAAA,EAFZ,GAAA,uBAAU,GAAA,EAAsB;AAAA,EAIjD,IAAI,GAAA,EAAmC;AACrC,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAC9B,IAAA,IAAI,KAAA,KAAU,QAAW,OAAO,MAAA;AAEhC,IAAA,IAAA,CAAK,GAAA,CAAI,OAAO,GAAG,CAAA;AACnB,IAAA,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AACvB,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEA,GAAA,CAAI,KAAa,KAAA,EAAuB;AACtC,IAAA,IAAI,IAAA,CAAK,IAAI,GAAA,CAAI,GAAG,GAAG,IAAA,CAAK,GAAA,CAAI,OAAO,GAAG,CAAA;AAAA,SAAA,IACjC,IAAA,CAAK,GAAA,CAAI,IAAA,IAAQ,IAAA,CAAK,QAAA,EAAU;AAEvC,MAAA,MAAM,SAAS,IAAA,CAAK,GAAA,CAAI,IAAA,EAAK,CAAE,MAAK,CAAE,KAAA;AACtC,MAAA,IAAI,MAAA,KAAW,MAAA,EAAW,IAAA,CAAK,GAAA,CAAI,OAAO,MAAM,CAAA;AAAA,IAClD;AACA,IAAA,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,EACzB;AAAA,EAEA,IAAA,GAAe;AACb,IAAA,OAAO,KAAK,GAAA,CAAI,IAAA;AAAA,EAClB;AACF;AAsBO,IAAM,oBAAA,GAAuC,IAAI,iBAAA","file":"chunk-2RW7K6FN.cjs","sourcesContent":["import type { EmbeddingCache } from \"./embedding-adapter.js\";\n\n/**\n * Bounded in-memory LRU cache for embeddings, keyed by `sha256(text)` (or any\n * stable key the caller chooses).\n *\n * @internal\n */\nexport class LruEmbeddingCache implements EmbeddingCache {\n private readonly map = new Map<string, number[]>();\n\n constructor(private readonly capacity: number = 5000) {}\n\n get(key: string): number[] | undefined {\n const value = this.map.get(key);\n if (value === undefined) return undefined;\n // Move to most-recent by re-inserting.\n this.map.delete(key);\n this.map.set(key, value);\n return value;\n }\n\n set(key: string, value: number[]): void {\n if (this.map.has(key)) this.map.delete(key);\n else if (this.map.size >= this.capacity) {\n // Evict the oldest entry — Map preserves insertion order.\n const oldest = this.map.keys().next().value;\n if (oldest !== undefined) this.map.delete(oldest);\n }\n this.map.set(key, value);\n }\n\n size(): number {\n return this.map.size;\n }\n}\n\n/**\n * T4.4 — Process-wide singleton embedding cache (DR4 finding #4).\n *\n * Pre-T4.4 each adapter / index-manager constructed its own\n * `LruEmbeddingCache` — a consumer with 3 Memory.openIndex calls\n * got 3 independent caches with no cross-index deduplication. The\n * same text embedded identically across indexes re-computed the\n * embedding each time.\n *\n * The singleton shares the cache process-wide so hit rate goes up\n * dramatically. The LRU eviction (default 5000 entries) bounds\n * memory usage even with the shared surface.\n *\n * Consumers who need isolation (e.g., multi-tenant with different\n * embedding models) should construct their own `LruEmbeddingCache`\n * and pass it explicitly — the singleton is the DEFAULT, not the\n * only option.\n *\n * @internal\n */\nexport const globalEmbeddingCache: EmbeddingCache = new LruEmbeddingCache();\n\n/**\n * T4.4 — Test seam: reset the global singleton between tests.\n * NOT included in the public barrel.\n *\n * @internal\n */\nexport function __TESTING__resetGlobalEmbeddingCache(): void {\n const cache = globalEmbeddingCache as LruEmbeddingCache;\n // Clear all entries — the capacity stays unchanged.\n (cache as unknown as { map: Map<string, number[]> }).map.clear();\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/persistence/cwd-mutex.ts"],"names":[],"mappings":";AAqBA,IAAM,KAAA,uBAAY,GAAA,EAA8B;AAEzC,SAAS,YAAA,CAAgB,KAAa,EAAA,EAAkC;AAC7E,EAAA,MAAM,OAAO,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA,IAAK,QAAQ,OAAA,EAAQ;AAC/C,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,EAAA,EAAI,EAAE,CAAA;AAG7B,EAAA,KAAA,CAAM,GAAA;AAAA,IACJ,GAAA;AAAA,IACA,IAAA,CAAK,IAAA;AAAA,MACH,MAAM,MAAA;AAAA,MACN,MAAM;AAAA;AACR,GACF;AACA,EAAA,OAAO,IAAA;AACT","file":"chunk-2XLKLVVR.js","sourcesContent":["/**\n * Per-key serialization. Returns a promise that resolves after the previous\n * `withCwdMutex(key, fn)` call for the same key has completed. Prevents\n * read-modify-write races on `MEMORY.md` within a single process.\n *\n * Multi-process safety is NOT covered (would need OS file locks — see\n * `withFileLock` in `./file-lock.ts`).\n *\n * **Public utility (SDK 2.0 Phase 2 physical-survey unblock — see ADR-008).**\n * Extracted packages (`@theokit/sdk-budget`, `@theokit/sdk-memory`) consume\n * this via `import { withCwdMutex } from \"@theokit/sdk\"` to ensure the\n * cross-package mutex Map IS the same process-level registry (single source\n * of truth) — duplicating the impl per package would defeat the purpose\n * (each package would have its own Map; concurrent writes from different\n * packages would race).\n *\n * Stability guarantee: signature + semantics will not change before sdk-core\n * v3.0. The mutex Map is module-scoped — restart-on-import resets state.\n *\n * @public\n */\nconst tails = new Map<string, Promise<unknown>>();\n\nexport function withCwdMutex<T>(key: string, fn: () => Promise<T>): Promise<T> {\n const prev = tails.get(key) ?? Promise.resolve();\n const next = prev.then(fn, fn); // run fn whether prev fulfilled or rejected\n // Save the new tail. Store the .then() chain that swallows the result so a\n // failure here doesn't poison subsequent waiters.\n tails.set(\n key,\n next.then(\n () => undefined,\n () => undefined,\n ),\n );\n return next;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/runtime/context/context-loaders.ts","../src/internal/runtime/context/context-import-resolver.ts","../src/internal/runtime/context/context-glob.ts","../src/internal/runtime/context/context-yaml-lite.ts","../src/internal/runtime/context/context-rules-frontmatter.ts","../src/internal/runtime/context/context-mdc-parser.ts","../src/internal/runtime/context/context-discovery-runner.ts"],"names":["resolvePath","z","dirname","readFile"],"mappings":"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","file":"chunk-34XOCZJO.js","sourcesContent":["/**\n * Context file loaders + truncation (T1.2, ADRs D154 / D155 / D159).\n *\n * Reads context source files from disk, applies the per-file size cap\n * with 70%/20% head/tail truncation, and emits the\n * `context_files_truncated` telemetry counter when the cap fires.\n * Pure (no I/O) for `truncateWithMarker` — testable in isolation.\n *\n * @internal\n */\n\nimport { readFile } from \"node:fs/promises\";\n\nconst HEAD_RATIO = 0.7;\nconst TAIL_RATIO = 0.2;\nconst MARKER = \"\\n\\n…[truncated by theokit]\\n\\n\";\n\n/** Default per-file cap (40k chars ≈ 10k tokens). D155. */\nexport const DEFAULT_MAX_BYTES_PER_FILE = 40_000;\n\nexport interface LoadedSource {\n /** Absolute path the content came from. */\n readonly source: string;\n readonly content: string;\n readonly originalBytes: number;\n readonly truncated: boolean;\n}\n\nexport interface TruncateResult {\n readonly truncated: boolean;\n readonly finalContent: string;\n}\n\n/**\n * Cap `content` at `max` characters with 70%/20% head/tail truncation\n * and an explicit marker. Pure — no I/O, no telemetry.\n *\n * EC-C: when `max <= MARKER.length`, skip the marker entirely and\n * return a head-only slice. Without this guard, `budget = max -\n * MARKER.length` would go negative and `content.slice(-tailBytes)`\n * would slice from the END of the string rather than truncating.\n *\n * EC-H: codepoint integrity — `String.slice()` operates on UTF-16\n * code units, which can split surrogate pairs. We accept that\n * trailing/leading replacement chars (U+FFFD) may appear at boundaries.\n * Modern LLMs tolerate them; byte-exact safety would require Buffer\n * slicing + TextDecoder with `fatal: true` retry, which adds complexity\n * without value.\n *\n * @public\n */\nexport function truncateWithMarker(content: string, max: number): TruncateResult {\n if (content.length <= max) {\n return { truncated: false, finalContent: content };\n }\n // EC-C: max too small to fit even the marker — return head-only slice.\n if (max <= MARKER.length) {\n return { truncated: true, finalContent: content.slice(0, max) };\n }\n const budget = max - MARKER.length;\n const headBytes = Math.floor(budget * (HEAD_RATIO / (HEAD_RATIO + TAIL_RATIO)));\n const tailBytes = budget - headBytes;\n return {\n truncated: true,\n finalContent: content.slice(0, headBytes) + MARKER + content.slice(-tailBytes),\n };\n}\n\n/**\n * Read a file from disk and apply the per-file cap. Emits telemetry\n * counter when truncation fires.\n *\n * EC-G: file deleted between discovery and read (FS race) → returns\n * `undefined`, never throws.\n *\n * @internal\n */\nexport async function loadPlainMarkdown(\n absPath: string,\n opts: { maxBytesPerFile?: number } = {},\n): Promise<LoadedSource | undefined> {\n const max = opts.maxBytesPerFile ?? DEFAULT_MAX_BYTES_PER_FILE;\n let content: string;\n try {\n content = await readFile(absPath, \"utf8\");\n } catch {\n // EC-G: ENOENT / EACCES / etc → caller treats as missing.\n return undefined;\n }\n const { truncated, finalContent } = truncateWithMarker(content, max);\n if (truncated) {\n emitTruncationCounter(absPath);\n }\n return {\n source: absPath,\n content: finalContent,\n originalBytes: content.length,\n truncated,\n };\n}\n\n/**\n * EC-L: telemetry no-op when OTel is not imported. We import the tracer\n * lazily and use `safeCall` so the lookup never throws and never pulls\n * OTel into the import graph for users without `@opentelemetry/api`\n * installed.\n *\n * @internal\n */\nfunction emitTruncationCounter(source: string): void {\n // Lazy resolution via globalThis avoids static import of telemetry/tracer.\n // Tests can spy via the same path; production users without OTel see no-op.\n const tracer = (\n globalThis as { __theokit_tracer?: { inc?: (k: string, attrs: unknown) => void } }\n ).__theokit_tracer;\n if (tracer?.inc === undefined) return;\n try {\n tracer.inc(\"context_files_truncated\", { file: source });\n } catch {\n // Telemetry must never break the loader.\n }\n}\n","/**\n * `@path/to/file` import resolver (T2.1, ADR D156).\n *\n * Anthropic/Gemini convention: lines that are EXACTLY `@path` get\n * replaced with the imported file's content, recursively (5-hop cap),\n * with cycle detection. Inline `see @x.md, also @y.md` references are\n * NOT resolved (EC-Q — own-line only, mirrors Anthropic's actual\n * behavior).\n *\n * EC-D fix: every imported file is itself capped at `maxBytesPerFile`\n * via `loadPlainMarkdown` BEFORE concatenation. Prevents a CLAUDE.md\n * with 5 imports of 30k each from ballooning to 150k of imported\n * content before the outer cap fires.\n *\n * @internal\n */\n\nimport { homedir } from \"node:os\";\nimport { dirname, isAbsolute, join, resolve as resolvePath } from \"node:path\";\n\nimport { loadPlainMarkdown } from \"./context-loaders.js\";\nimport { insideRoot } from \"./path-containment.js\";\n\n/** EC-Q: line-anchored. `@path` must be alone on its line. */\nconst IMPORT_RE = /^@(\\S+)\\s*$/gm;\nconst MAX_HOPS = 5;\n\nexport interface ResolveImportsOptions {\n /** Absolute paths already resolved (cycle detection). */\n readonly visited: Set<string>;\n /** Current recursion depth — caps at MAX_HOPS. */\n readonly depth: number;\n /** Per-import file cap (EC-D). Forwarded to loadPlainMarkdown. */\n readonly maxBytesPerFile: number;\n /**\n * The directory an import may not escape. When set, a target resolving outside it is\n * refused and replaced with a placeholder.\n *\n * The file carrying the import is REPOSITORY-CONTROLLED — `CLAUDE.md` and `GEMINI.md`\n * are the two default specs with `followImports: true`, and both are found by\n * `git-root-walk` inside the tree the agent was pointed at. Without a root, a cloned\n * repository could name `@~/.ssh/id_rsa` or any absolute path and have its contents\n * inlined into the system prompt, and from there sent to the model provider. The\n * traversal guard that already existed (`isSafePattern`) guards the discovery PATTERN,\n * not the import TARGET, so it never saw this.\n *\n * OPTIONAL, so a caller outside the discovery path keeps the previous behaviour rather\n * than breaking on an upgrade. `runDiscovery` always supplies `gitRoot ?? cwd` — the\n * same value it already uses to keep absolute paths out of `<source name=\"\">`.\n */\n readonly projectRoot?: string;\n}\n\n/**\n * Resolve `@path` directives in `content`. Each match is replaced with\n * the imported file content (already cap-truncated per EC-D), and\n * recursion continues on the resolved content until MAX_HOPS or cycle.\n *\n * Failure modes (placeholders, never throws):\n * - file not found → `[@import not found: <path>]`\n * - cycle detected → `[@import cycle detected: <path>]`\n * - depth exceeded → trailing `\\n\\n…[@import depth limit 5 reached]\\n\\n`\n *\n * @internal\n */\nexport async function resolveImports(\n content: string,\n basePath: string,\n opts: ResolveImportsOptions,\n): Promise<string> {\n if (opts.depth >= MAX_HOPS) {\n return `${content}\\n\\n…[@import depth limit ${MAX_HOPS} reached]\\n\\n`;\n }\n const baseDir = dirname(basePath);\n return replaceAsync(content, IMPORT_RE, async (raw) => {\n const absolute = resolveImportPath(raw, baseDir);\n // Containment BEFORE the read. Reporting the refusal after loading the file would\n // already have put the bytes in memory, and the placeholder names the path the author\n // wrote rather than the resolved one — echoing `/home/<user>/.ssh/id_rsa` back into the\n // prompt would leak the layout of the machine to the same untrusted document.\n if (opts.projectRoot !== undefined && !insideRoot(absolute, opts.projectRoot)) {\n return `[@import outside the project root, refused: ${raw}]`;\n }\n if (opts.visited.has(absolute)) {\n return `[@import cycle detected: ${raw}]`;\n }\n opts.visited.add(absolute);\n const loaded = await loadPlainMarkdown(absolute, { maxBytesPerFile: opts.maxBytesPerFile });\n if (loaded === undefined) {\n return `[@import not found: ${raw}]`;\n }\n // Recurse with same visited set + incremented depth. `projectRoot` is FORWARDED: an\n // imported file is repository-controlled too, so a root that applied only at depth 0\n // would be escapable in one extra hop.\n return resolveImports(loaded.content, absolute, {\n visited: opts.visited,\n depth: opts.depth + 1,\n maxBytesPerFile: opts.maxBytesPerFile,\n ...(opts.projectRoot === undefined ? {} : { projectRoot: opts.projectRoot }),\n });\n });\n}\n\nfunction resolveImportPath(raw: string, baseDir: string): string {\n if (raw.startsWith(\"~/\")) {\n return resolvePath(join(homedir(), raw.slice(2)));\n }\n if (isAbsolute(raw)) {\n return resolvePath(raw);\n }\n return resolvePath(join(baseDir, raw));\n}\n\n/**\n * Async equivalent of `String.prototype.replace` — sequential. Returns\n * `content` with every `re` match replaced by `await replacer(match)`.\n *\n * @internal\n */\nasync function replaceAsync(\n content: string,\n re: RegExp,\n replacer: (raw: string) => Promise<string>,\n): Promise<string> {\n const matches: Array<{ match: string; raw: string; index: number }> = [];\n // Reset lastIndex; clone the regex to avoid stateful traps.\n const localRe = new RegExp(re.source, re.flags);\n let m: RegExpExecArray | null;\n // biome-ignore lint/suspicious/noAssignInExpressions: idiomatic regex loop\n while ((m = localRe.exec(content)) !== null) {\n matches.push({ match: m[0], raw: m[1] ?? \"\", index: m.index });\n if (m.index === localRe.lastIndex) localRe.lastIndex += 1;\n }\n if (matches.length === 0) return content;\n let result = \"\";\n let cursor = 0;\n for (const entry of matches) {\n result += content.slice(cursor, entry.index);\n result += await replacer(entry.raw);\n cursor = entry.index + entry.match.length;\n }\n result += content.slice(cursor);\n return result;\n}\n","/**\n * Shared glob → RegExp compiler for context discovery (extracted from the\n * MDC parser so the `.cursor/rules/*.mdc` and `.theokit/rules/*.md` parsers\n * share ONE implementation — DRY, no new dependency).\n *\n * Supports `**` (any depth), `*` (single path segment, no `/`), `?` (single\n * non-separator char). Sufficient for the patterns Cursor and Claude Code\n * themselves recommend.\n *\n * @internal\n */\nexport function globToRegex(glob: string): RegExp {\n // Support **/ (zero-or-more path segments), ** (any depth), * (single\n // segment), ? (single non-separator char). `**/` collapses so `src/**/*.ts`\n // matches `src/foo.ts` AND `src/a/b/foo.ts` — the semantics Cursor and Claude\n // Code document (\"src/**/* → all files under src/\"). `*` and `?` never cross a\n // `/` (strict glob segment semantics). Escape other regex metas.\n const compiled = glob\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*\\//g, \"::GLOBSTAR_SLASH::\")\n .replace(/\\*\\*/g, \"::GLOBSTAR::\")\n .replace(/\\*/g, \"[^/]*\")\n .replace(/\\?/g, \"[^/]\")\n .replace(/::GLOBSTAR_SLASH::/g, \"(?:.*/)?\")\n .replace(/::GLOBSTAR::/g, \".*\");\n return new RegExp(`^${compiled}$`);\n}\n\n/**\n * True when any of `patterns` glob-matches any of `paths`. Central helper so\n * both rule parsers agree on activation semantics.\n *\n * @internal\n */\nexport function anyGlobMatches(\n patterns: ReadonlyArray<string>,\n paths: ReadonlyArray<string>,\n): boolean {\n if (patterns.length === 0 || paths.length === 0) return false;\n const res = patterns.map(globToRegex);\n return paths.some((p) => res.some((re) => re.test(p)));\n}\n","/**\n * Minimal YAML-subset frontmatter parsing shared by the `.cursor/rules/*.mdc`\n * and `.theokit/rules/*.md` parsers (extracted for DRY — one parser, one set\n * of edge-case behaviours, no new dependency).\n *\n * Handles `key: value` lines (string scalars, booleans, integers) and `key:`\n * followed by indented `- item` arrays or inline `[a, b]` arrays. Sufficient\n * for the small, fixed frontmatter field sets these rule files use. Throws on\n * a truly malformed line (no colon).\n *\n * NOTE — distinct from the sibling `yaml-frontmatter.ts` `parseSimpleYaml` on\n * purpose: that one parses INLINE arrays only (`key: [a, b]`), whereas rule\n * files (`.cursor/rules/*.mdc`, `.theokit/rules/*.md`) use MULTI-LINE `- item`\n * lists (`paths:` / `globs:`), which this parser adds. Unifying onto the inline\n * parser would drop multi-line list support; unifying the other way would touch\n * the skills/subagents/persistence loaders that depend on the inline one. The\n * two intentionally coexist until a shared parser handles both shapes.\n *\n * @internal\n */\n\nconst FRONTMATTER_RE = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n([\\s\\S]*)$/;\n\nexport interface FrontmatterSplit {\n /** Raw YAML block between the `---` fences, or undefined when absent. */\n readonly yaml: string | undefined;\n /** The markdown body after the frontmatter (or the whole content). */\n readonly body: string;\n}\n\n/**\n * Split `---`-fenced frontmatter from the body. When no frontmatter fence is\n * present, `yaml` is undefined and `body` is the whole content.\n *\n * @internal\n */\nexport function splitFrontmatter(content: string): FrontmatterSplit {\n const m = FRONTMATTER_RE.exec(content);\n if (m === null) return { yaml: undefined, body: content };\n return { yaml: m[1] ?? \"\", body: m[2] ?? \"\" };\n}\n\n/**\n * Parse the minimal YAML subset. Throws on a line without a colon (malformed).\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: YAML-subset parser handles scalars + multi-line arrays + inline arrays in a single pass; extracting helpers fragments the line-state machine.\nexport function parseSimpleYaml(yaml: string): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n const lines = yaml.split(/\\r?\\n/);\n let i = 0;\n while (i < lines.length) {\n const line = lines[i];\n i += 1;\n if (line === undefined) continue;\n const trimmed = line.trim();\n if (trimmed === \"\" || trimmed.startsWith(\"#\")) continue;\n const colon = trimmed.indexOf(\":\");\n if (colon === -1) throw new Error(`Invalid YAML line: ${trimmed}`);\n const key = trimmed.slice(0, colon).trim();\n const rest = trimmed.slice(colon + 1).trim();\n if (rest === \"\") {\n // Possible array; collect indented `- item` lines.\n const items: string[] = [];\n while (i < lines.length) {\n const next = lines[i];\n if (next === undefined) break;\n const nextTrim = next.trim();\n if (nextTrim.startsWith(\"- \")) {\n items.push(parseScalar(nextTrim.slice(2).trim()) as string);\n i += 1;\n } else if (nextTrim === \"\") {\n i += 1;\n } else {\n break;\n }\n }\n out[key] = items;\n } else if (rest.startsWith(\"[\") && rest.endsWith(\"]\")) {\n // Inline array `globs: [\"**/*.ts\", \"**/*.tsx\"]`\n const inner = rest.slice(1, -1).trim();\n out[key] =\n inner === \"\"\n ? []\n : inner.split(\",\").map((s) => parseScalar(s.trim().replace(/^[\"']|[\"']$/g, \"\")));\n } else {\n out[key] = parseScalar(rest);\n }\n }\n return out;\n}\n\nfunction parseScalar(s: string): string | boolean | number {\n if (s === \"true\") return true;\n if (s === \"false\") return false;\n if (/^-?\\d+$/.test(s)) return parseInt(s, 10);\n // Strip surrounding quotes if present.\n return s.replace(/^[\"']|[\"']$/g, \"\");\n}\n","/**\n * Parser for `.theokit/rules/*.md` — theokit-native path-scoped rules,\n * mirroring Claude Code's `.claude/rules/`.\n *\n * Frontmatter fields:\n * - `paths` — glob-pattern array (Claude Code parity: `.claude/rules` uses `paths:`).\n * - `globs` — glob-pattern array (Cursor-compatible alias; unioned with `paths`).\n * - `alwaysApply` — activate unconditionally (no scope needed).\n * - `enabled` — set `false` to disable the rule entirely (wins over everything).\n * - `description` — human note; not used for activation in v1.\n *\n * Activation (`shouldActivateRule`):\n * - `enabled: false` → never activates.\n * - `alwaysApply: true` → always activates.\n * - otherwise → activates iff a `paths`/`globs` pattern matches an in-scope\n * file (the caller's `agent.send(..., { contextPaths })`). With no in-scope\n * files, a scoped rule stays dormant (parity with Cursor `.mdc`).\n *\n * A file with no `---` frontmatter is treated as an unconditional rule\n * (`alwaysApply: true`). Malformed YAML → `undefined` (caller drops + counts).\n *\n * Glob + YAML subset are shared with the MDC parser (DRY, no new dependency).\n *\n * @internal\n */\n\nimport { z } from \"zod\";\n\nimport { anyGlobMatches } from \"./context-glob.js\";\nimport { parseSimpleYaml, splitFrontmatter } from \"./context-yaml-lite.js\";\n\n/** YAML frontmatter schema for `.theokit/rules/*.md` files. @internal */\nexport const RulesFrontmatterSchema = z.object({\n description: z.string().optional(),\n paths: z.array(z.string()).optional(),\n globs: z.array(z.string()).optional(),\n alwaysApply: z.boolean().optional(),\n enabled: z.boolean().optional(),\n});\n\nexport type RulesFrontmatter = z.infer<typeof RulesFrontmatterSchema>;\n\nexport interface RulesParseResult {\n readonly frontmatter: RulesFrontmatter;\n readonly body: string;\n}\n\n/**\n * Parse `.theokit/rules/*.md` content into frontmatter + body. No frontmatter\n * fence → unconditional rule. Malformed YAML → `undefined`.\n *\n * @internal\n */\nexport function parseRules(content: string): RulesParseResult | undefined {\n const { yaml, body } = splitFrontmatter(content);\n if (yaml === undefined) {\n return { frontmatter: { alwaysApply: true }, body: content };\n }\n try {\n const parsed = parseSimpleYaml(yaml);\n const validated = RulesFrontmatterSchema.safeParse(parsed);\n if (!validated.success) return undefined;\n return { frontmatter: validated.data, body };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Decide whether a rule activates given the in-scope files. `paths` and\n * `globs` are unioned; both are glob patterns matched against the caller's\n * declared scope.\n *\n * @internal\n */\nexport function shouldActivateRule(\n fm: RulesFrontmatter,\n inScopePaths: ReadonlyArray<string>,\n): boolean {\n if (fm.enabled === false) return false;\n if (fm.alwaysApply === true) return true;\n const patterns = [...(fm.paths ?? []), ...(fm.globs ?? [])];\n if (patterns.length === 0) return false;\n return anyGlobMatches(patterns, inScopePaths);\n}\n","/**\n * MDC (Markdown Cursor) parser for `.cursor/rules/*.mdc` (T3.1, ADR D154).\n *\n * Parses YAML frontmatter with `description` / `globs` / `alwaysApply`\n * fields. Honors activation per Cursor's docs:\n * - `alwaysApply: true` → activates unconditionally.\n * - `alwaysApply: false` + matching glob in `touchedFiles` → activates.\n * - `alwaysApply: false` + no glob match → skipped.\n *\n * **EC-I (v1 semantic):** at `agent.send()` time, `touchedFiles` is empty\n * UNLESS the caller passes `contextPaths` (the in-scope file set). When\n * `contextPaths` is provided, per-glob activation fires; otherwise only\n * `alwaysApply: true` rules activate. Description-based \"agent requested\"\n * classification is out of scope.\n *\n * Glob matching + the YAML subset are shared with the `.theokit/rules/*.md`\n * parser via `context-glob.ts` / `context-yaml-lite.ts` (DRY, no new dep).\n *\n * @internal\n */\n\nimport { z } from \"zod\";\n\nimport { anyGlobMatches } from \"./context-glob.js\";\nimport { parseSimpleYaml, splitFrontmatter } from \"./context-yaml-lite.js\";\n\n/** YAML frontmatter schema for MDC files. @internal */\nexport const McdFrontmatterSchema = z.object({\n description: z.string().optional(),\n globs: z.array(z.string()).optional(),\n alwaysApply: z.boolean().optional(),\n});\n\nexport type McdFrontmatter = z.infer<typeof McdFrontmatterSchema>;\n\nexport interface McdParseResult {\n readonly frontmatter: McdFrontmatter;\n readonly body: string;\n}\n\n/**\n * Parse `.mdc` content. Returns frontmatter + body. EC-18: when the\n * file has no `---` frontmatter, returns `frontmatter: {alwaysApply:\n * true}` so the body is treated as an unconditional rule.\n *\n * On YAML parse error, returns `undefined` and the caller emits a\n * telemetry counter (EC-21).\n *\n * @internal\n */\nexport function parseMdc(content: string): McdParseResult | undefined {\n const { yaml, body } = splitFrontmatter(content);\n if (yaml === undefined) {\n // EC-18: no frontmatter — treat as alwaysApply\n return { frontmatter: { alwaysApply: true }, body: content };\n }\n try {\n const parsed = parseSimpleYaml(yaml);\n const validated = McdFrontmatterSchema.safeParse(parsed);\n if (!validated.success) return undefined;\n return { frontmatter: validated.data, body };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Decide whether an MDC rule activates given the currently-touched\n * files. EC-I: empty `touchedFiles` → only `alwaysApply: true`\n * activates.\n *\n * @internal\n */\nexport function shouldActivate(fm: McdFrontmatter, touchedFiles: ReadonlyArray<string>): boolean {\n if (fm.alwaysApply === true) return true;\n if (fm.globs === undefined || fm.globs.length === 0) return false;\n return anyGlobMatches(fm.globs, touchedFiles);\n}\n","/**\n * Multi-format context discovery runner (T5.1, ADRs D150-D156).\n *\n * Walks `DEFAULT_DISCOVERY_SPECS` (or caller override), loads each\n * spec via the appropriate parser, applies `@import` resolution where\n * declared, and returns a flat list of `AggregatorSource[]` ready for\n * the aggregate cap.\n *\n * **EC-E privacy fix:** source disambiguation uses\n * `relative(gitRoot ?? cwd, ...)` — NEVER absolute paths in\n * `<source name=\"\">`.\n *\n * @internal\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, relative } from \"node:path\";\n\nimport type { AggregatorSource } from \"./context-aggregator.js\";\nimport {\n DEFAULT_DISCOVERY_SPECS,\n type DiscoverySpec,\n findGitRoot,\n walkUpForFile,\n walkUpForGlob,\n} from \"./context-discovery.js\";\nimport { resolveImports } from \"./context-import-resolver.js\";\nimport { loadPlainMarkdown } from \"./context-loaders.js\";\nimport { parseMdc, shouldActivate } from \"./context-mdc-parser.js\";\nimport { parseRules, shouldActivateRule } from \"./context-rules-frontmatter.js\";\n\nexport interface DiscoveryRunnerOptions {\n /** Workspace root passed to all discovery scopes. */\n readonly cwd: string;\n /** Per-file truncation cap (D155). */\n readonly maxBytesPerFile: number;\n /** Optional override of the default registry. */\n readonly specs?: ReadonlyArray<DiscoverySpec>;\n /** Cursor MDC: file paths the LLM has touched this turn (EC-I: empty at send-time). */\n readonly touchedFiles?: ReadonlyArray<string>;\n /** When true, skip `theokit-context` spec — caller already handles the legacy path. */\n readonly skipLegacyTheokitContext?: boolean;\n /**\n * The root an `@import` may not escape. Defaults to `gitRoot ?? cwd` — the same value\n * this runner already uses to keep absolute paths out of `<source name=\"\">`.\n *\n * Present so an embedder with a trust boundary narrower than the repository can declare\n * it. Absent, the repository IS the boundary, which is the honest default for a document\n * discovered by walking the repository.\n */\n readonly importRoot?: string;\n}\n\n/**\n * Run discovery + loading across all specs. Returns sources ready for\n * the aggregator (priority + content fields populated).\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: per-spec dispatch ladder + cross-spec dedup is a flat orchestrator; splitting would obscure the priority-merge invariant.\nexport async function runDiscovery(opts: DiscoveryRunnerOptions): Promise<AggregatorSource[]> {\n const gitRoot = findGitRoot(opts.cwd);\n const specs = opts.specs ?? DEFAULT_DISCOVERY_SPECS;\n const out: AggregatorSource[] = [];\n const seenReal = new Set<string>();\n\n for (const spec of specs) {\n if (opts.skipLegacyTheokitContext && spec.id === \"theokit-context\") continue;\n const paths = await resolvePathsForSpec(spec, opts.cwd, gitRoot);\n for (const path of paths) {\n if (seenReal.has(path)) continue;\n seenReal.add(path);\n const source = await loadOneSource(spec, path, opts, gitRoot);\n if (source !== undefined) out.push(source);\n }\n }\n return out;\n}\n\nasync function resolvePathsForSpec(\n spec: DiscoverySpec,\n cwd: string,\n gitRoot: string | undefined,\n): Promise<string[]> {\n if (spec.scope === \"cwd-only\") {\n return walkUpForFile(cwd, spec.pattern, cwd);\n }\n if (spec.scope === \"git-root-walk\") {\n return walkUpForFile(cwd, spec.pattern, gitRoot ?? cwd);\n }\n // globbed\n return walkUpForGlob(cwd, spec.pattern);\n}\n\nasync function loadOneSource(\n spec: DiscoverySpec,\n path: string,\n opts: DiscoveryRunnerOptions,\n gitRoot: string | undefined,\n): Promise<AggregatorSource | undefined> {\n // EC-E privacy: name uses relative-to-git-root for disambiguation;\n // NEVER absolute paths in the public `<source name=\"\">` attribute.\n // For cwd-only specs (THEO.md), no disambiguation is needed because\n // the scope can only ever match a single file.\n const relPath = relative(gitRoot ?? opts.cwd, dirname(path));\n const needsSuffix = spec.scope !== \"cwd-only\" && relPath !== \"\" && relPath !== \".\";\n const id = needsSuffix ? `${spec.id}@${relPath}` : spec.id;\n\n if (spec.parser === \"mdc\") {\n return loadMdcSource(spec, path, id, opts);\n }\n if (spec.parser === \"rules-frontmatter\") {\n return loadRulesSource(spec, path, id, opts);\n }\n if (spec.parser === \"frontmatter-zod\") {\n // Legacy `.theokit/context/*.md` — handled by `loadContextConfig` in\n // `context-manager.ts` for backward compat. We skip here unless caller\n // explicitly wants us to load it (currently always skipped).\n return undefined;\n }\n // plain-markdown\n return loadPlainMarkdownSource(spec, path, id, opts, gitRoot);\n}\n\n/**\n * Shared read → parse → activation-gate → source pipeline for the frontmatter\n * discovery parsers (mdc, rules). Binds the parser + the activation predicate so\n * the mdc and rules loaders differ only in those two, not in the surrounding\n * read/guard/shape boilerplate (DRY).\n */\nasync function loadParsedSource<F>(\n spec: DiscoverySpec,\n path: string,\n id: string,\n parse: (raw: string) => { frontmatter: F; body: string } | undefined,\n isActive: (frontmatter: F) => boolean,\n): Promise<AggregatorSource | undefined> {\n let raw: string;\n try {\n raw = await readFile(path, \"utf8\");\n } catch {\n return undefined;\n }\n const parsed = parse(raw);\n if (parsed === undefined || !isActive(parsed.frontmatter)) return undefined;\n return { id, source: path, content: parsed.body, priority: spec.priority, truncated: false };\n}\n\nfunction loadMdcSource(\n spec: DiscoverySpec,\n path: string,\n id: string,\n opts: DiscoveryRunnerOptions,\n): Promise<AggregatorSource | undefined> {\n return loadParsedSource(spec, path, id, parseMdc, (fm) =>\n shouldActivate(fm, opts.touchedFiles ?? []),\n );\n}\n\nfunction loadRulesSource(\n spec: DiscoverySpec,\n path: string,\n id: string,\n opts: DiscoveryRunnerOptions,\n): Promise<AggregatorSource | undefined> {\n return loadParsedSource(spec, path, id, parseRules, (fm) =>\n shouldActivateRule(fm, opts.touchedFiles ?? []),\n );\n}\n\nasync function loadPlainMarkdownSource(\n spec: DiscoverySpec,\n path: string,\n id: string,\n opts: DiscoveryRunnerOptions,\n gitRoot: string | undefined,\n): Promise<AggregatorSource | undefined> {\n const loaded = await loadPlainMarkdown(path, { maxBytesPerFile: opts.maxBytesPerFile });\n if (loaded === undefined) return undefined;\n let content = loaded.content;\n if (spec.followImports) {\n content = await resolveImports(content, path, {\n visited: new Set([path]),\n depth: 0,\n maxBytesPerFile: opts.maxBytesPerFile,\n // The document carrying the import is repository-controlled, so the repository is the\n // boundary it may not cross. Without this, `CLAUDE.md` / `GEMINI.md` — the two specs\n // with `followImports: true` — could name any absolute or `~/` path and have it\n // inlined into the system prompt.\n projectRoot: opts.importRoot ?? gitRoot ?? opts.cwd,\n });\n }\n return {\n id,\n source: path,\n content,\n priority: spec.priority,\n truncated: loaded.truncated,\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/auth/credential-store.ts"],"names":[],"mappings":"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","file":"chunk-3V7UJLQT.js","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n closeSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { z } from \"zod\";\n\nimport { AuthenticationError } from \"../../errors.js\";\n\n/**\n * M42 — the SDK credential store. Promoted DOWN from agent-builder's hardened `agents/lib/credentials.ts`\n * (M37), generalized from a closed `openrouter|anthropic|openai` union to an open `provider: string` and\n * driven by a caller-supplied {@link CredentialStoreConfig} (no hardcoded `.agent-builder`/`auth.json` /\n * `AGENT_BUILDER_HOME`). The security-critical file mechanics are ported VERBATIM (ADR D3 of the M42 plan):\n * atomic O_EXCL + rename + fsync write, 0700/0600 mode gates, `env` is always a PARAMETER (never an ambient\n * `process.env` read).\n *\n * The env-precedence + key-prefix-inference + declared-provider rungs of the agent-builder resolver are\n * APP POLICY and deliberately stay UP in the consumer; this module owns only the on-disk store + the\n * `api|oauth` discriminated union. See {@link resolveCredential} (SDK) for the store-read + refresh path.\n *\n * @internal\n */\nimport type {\n CredentialStoreConfig,\n StoredCredential,\n StoredOAuthCredential,\n} from \"./auth-types.js\";\n\n/** The store directory, honoring an optional `homeEnvVar` override. */\nexport function credentialHome(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const override = config.homeEnvVar !== undefined ? env[config.homeEnvVar]?.trim() : undefined;\n return override !== undefined && override.length > 0\n ? override\n : join(config.home, config.dirName);\n}\n\n/** The credential file path inside the (possibly overridden) store directory. */\nexport function authFilePath(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n return join(credentialHome(config, env), config.fileName);\n}\n\n/**\n * A credential problem the caller can act on. Never carries the key value.\n *\n * M78 — this used to extend bare `Error`, which quietly disabled classification for the entire auth\n * path: `isTransientError` is `err instanceof TheokitAgentError && err.isRetryable === true`\n * (`errors.ts:443`), so a credential failure could never be judged transient OR permanent. The\n * predicate was not \"forgotten\" downstream — it was unusable there by construction.\n *\n * Extending `AuthenticationError` is ADDITIVE: the class still exists, still reports\n * `name: \"CredentialError\"`, and every existing `instanceof CredentialError` stays true. It only\n * gains ancestors. `AuthenticationError` pins `isRetryable: false`, so gaining the ability to be\n * classified does NOT turn a revoked credential into a retry loop.\n *\n * The single reference does the same thing with one root type: Codex routes every domain failure\n * through `CodexErr` with `is_retryable()` as a method (`protocol/src/error.rs:176`), rather than\n * parallel classes extending the language's `Error`.\n */\nexport class CredentialError extends AuthenticationError {\n // Field, not an assignment in the constructor: `AuthenticationError.name` is `override readonly`\n // (`errors.ts:174`), so `this.name = …` does not compile. Caught by `tsc`, not by vitest — the\n // suite was green with the broken assignment because the transpiler strips the type.\n override readonly name: string = \"CredentialError\";\n}\n\n/**\n * The on-disk store — a discriminated union on `type`. A legacy file with NO\n * `type` (or `type: 'api'`) is the API-key variant — read unchanged, no migration. The `oauth` variant\n * carries the token pair + expiry.\n */\nconst apiFileSchema = z\n .object({\n type: z.literal(\"api\").optional(),\n provider: z.string().min(1).optional(),\n api_key: z.string(),\n })\n .strict();\n\nconst oauthFileSchema = z\n .object({\n type: z.literal(\"oauth\"),\n provider: z.string().min(1),\n access: z.string().min(1),\n refresh: z.string().min(1),\n expires: z.number(),\n account_id: z.string().optional(),\n })\n .strict();\n\n// oauth first (it requires `type: 'oauth'`); a legacy `{provider?, api_key}` falls through to api.\nconst fileSchema = z.union([oauthFileSchema, apiFileSchema]);\n\n/**\n * Read the credential file. Absent ⇒ `undefined` (the normal case). Present-but-wrong is a typed error\n * naming the file: a malformed credential store must not surface as a raw parse crash. Enforces the\n * 0700 dir / 0600 file mode gates (ported verbatim — a writable dir lets an attacker swap the file for a\n * symlink to their own account).\n */\n/**\n * The 0700-dir / 0600-file mode gates (ported verbatim). The DIRECTORY matters as much as the file:\n * `mkdirSync(mode)` applies only at creation, so a pre-existing store dir keeps whatever mode it had, and a\n * writable dir lets an attacker replace the credential file with a symlink to their own 0600 file — the\n * agent then runs on THEIR account.\n */\nexport function assertSecureModes(dirPath: string, path: string): void {\n // Windows has no POSIX mode bits. `statSync().mode` there is SYNTHETIC — 0666 for any writable\n // entry, whatever the ACLs actually say — so `mode & 0o022` was non-zero for every valid store and\n // this gate refused all of them, which made the credential path unreadable on that platform\n // rather than protected. A check that cannot observe the real permission system must not report a\n // verdict about it; ACL enforcement is a separate mechanism and not one this function can fake.\n if (process.platform === \"win32\") return;\n\n const dirMode = statSync(dirPath).mode & 0o777;\n if ((dirMode & 0o022) !== 0) {\n throw new CredentialError(\n `${dirPath} is writable by other users (mode ${dirMode.toString(8)}), so the credential file ` +\n `inside it can be replaced. Fix it with: chmod 700 ${dirPath}`,\n );\n }\n const mode = statSync(path).mode & 0o777;\n if ((mode & 0o077) !== 0) {\n throw new CredentialError(\n `${path} is readable by other users (mode ${mode.toString(8)}). ` +\n `A credential file must not be. Fix it with: chmod 600 ${path}`,\n );\n }\n}\n\n/**\n * A `z.union` reports a generic \"Invalid input\" at the root, hiding WHAT is wrong. Pick the sub-schema the\n * file was CLEARLY aiming at (by its `type` discriminant) and surface that schema's specific issue.\n */\nfunction describeUnionError(parsed: unknown, err: unknown, path: string): CredentialError {\n const looksOAuth =\n typeof parsed === \"object\" &&\n parsed !== null &&\n (parsed as { type?: unknown }).type === \"oauth\";\n const specific = looksOAuth ? oauthFileSchema.safeParse(parsed) : apiFileSchema.safeParse(parsed);\n let issue: z.ZodIssue | undefined;\n if (!specific.success) {\n issue = specific.error.issues[0];\n } else if (err instanceof z.ZodError) {\n issue = err.issues[0];\n }\n return new CredentialError(\n `${path}: ${issue?.message ?? String(err)} [${issue?.path.join(\".\") || \"root\"}]`,\n );\n}\n\n/** Parse the raw file into the store union, surfacing the SPECIFIC sub-schema issue (not a generic union error). */\nfunction parseStoredFile(raw: string, path: string): StoredCredential {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // The parser's message embeds a snippet of the INPUT — up to the raw key when a user pastes the bare\n // key instead of JSON. The position is not actionable anyway, so the expected shape is more useful.\n throw new CredentialError(\n `${path} is not valid JSON. Expected: {\"provider\": \"<name>\", \"api_key\": \"...\"}`,\n );\n }\n try {\n return fileSchema.parse(parsed);\n } catch (err) {\n throw describeUnionError(parsed, err, path);\n }\n}\n\nexport function readAuthFile(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredCredential | undefined {\n const path = authFilePath(config, env);\n\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw new CredentialError(`cannot read ${path}: ${(err as Error).message}`);\n }\n\n assertSecureModes(credentialHome(config, env), path);\n return parseStoredFile(raw, path);\n}\n\n/**\n * Read the stored OAuth credential (with its refresh token), or `undefined` when the store is absent or\n * holds an api credential. The oauth engine needs the refresh token, which the resolved bearer does not\n * carry. Enforces the same 0600/0700 gates as every other read.\n */\nexport function readStoredOAuth(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredOAuthCredential | undefined {\n const stored = readAuthFile(config, env);\n return stored !== undefined && stored.type === \"oauth\" ? stored : undefined;\n}\n\n/** Narrows a writable credential to the oauth variant. */\nfunction isOAuthWrite(\n c: { provider: string; apiKey: string } | StoredOAuthCredential,\n): c is StoredOAuthCredential {\n return \"type\" in c && c.type === \"oauth\";\n}\n\n/**\n * Persist a credential atomically at mode `0600`. Ported VERBATIM (ADR D3): write to a random-named temp\n * file in the same directory with `wx` (O_EXCL), fsync, close, chmod, then `rename` (atomic on POSIX) —\n * so a crash mid-write leaves whatever was there untouched, and a pre-planted symlink cannot capture the\n * key. The api variant persists the unchanged `{provider, api_key}` (back-compat, no `type` key); the\n * oauth variant persists `{type:'oauth', provider, access, refresh, expires, account_id?}`.\n */\n/** Build the on-disk JSON payload for the credential variant, validating non-empty tokens. */\nfunction buildStorePayload(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n): Record<string, unknown> {\n if (isOAuthWrite(cred)) {\n if (cred.access.length === 0 || cred.refresh.length === 0) {\n throw new CredentialError(\n \"refusing to write an oauth credential with an empty access/refresh token\",\n );\n }\n return {\n type: \"oauth\",\n provider: cred.provider,\n access: cred.access,\n refresh: cred.refresh,\n expires: cred.expires,\n ...(cred.account_id !== undefined ? { account_id: cred.account_id } : {}),\n };\n }\n if (typeof cred.apiKey !== \"string\" || cred.apiKey.length === 0) {\n throw new CredentialError(\"refusing to write an empty API key\");\n }\n return { provider: cred.provider, api_key: cred.apiKey };\n}\n\nexport function writeCredential(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const payload = buildStorePayload(cred);\n\n const dir = credentialHome(config, env);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n chmodSync(dir, 0o700); // unconditional: mkdirSync's mode applies only at creation\n\n const path = authFilePath(config, env);\n // RANDOM name + `wx` (O_EXCL): a predictable temp name with a plain write follows a pre-planted SYMLINK,\n // landing the key in an attacker's file while reporting success. O_EXCL refuses any pre-existing file or\n // link; the random suffix also removes the pid collision two containers sharing a bind-mounted home make.\n const tmp = `${path}.tmp-${randomBytes(8).toString(\"hex\")}`;\n try {\n const fd = openSync(tmp, \"wx\", 0o600);\n try {\n writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\\n`);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n chmodSync(tmp, 0o600); // explicit: the mode argument is subject to umask\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // the temp file may not exist; its absence is not a failure of the write\n }\n throw new CredentialError(`cannot write ${path}: ${(err as Error).message}`);\n }\n return path;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/runtime/context/context-discovery.ts"],"names":[],"mappings":"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","file":"chunk-4NAKHID5.js","sourcesContent":["/**\n * Context file discovery (T1.1, ADRs D150 / D151).\n *\n * Discovers context files via three scopes:\n * - `cwd-only` — single dir, single path lookup\n * - `git-root-walk` — walk cwd → git-root, collect every directory's match\n * (nearest-first ordering)\n * - `globbed` — glob pattern relative to cwd (e.g. `.cursor/rules/*.mdc`)\n *\n * Pure `existsSync` checks — **no `.gitignore` parsing** (EC-A, KISS) and\n * **no invented `.theokitignore`** (EC-B). Paths normalized via\n * `realpath` to dedup symlink chains pointing to the same physical file\n * (EC-F). Git worktrees work transparently because `.git` exists as a\n * file in that case (EC-N).\n *\n * @internal\n */\n\nimport { existsSync, realpathSync } from \"node:fs\";\nimport { glob } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\n\n/** Single filename (\"AGENTS.md\") or relative glob (\".cursor/rules/*.mdc\"). */\nexport type DiscoveryScope = \"cwd-only\" | \"git-root-walk\" | \"globbed\";\n\n/** Parser to apply once file is read. */\nexport type DiscoveryParser = \"plain-markdown\" | \"mdc\" | \"frontmatter-zod\" | \"rules-frontmatter\";\n\n/**\n * Specification for one discoverable context source. The default registry\n * `DEFAULT_DISCOVERY_SPECS` covers the 2026 industry-standard set.\n *\n * @internal\n */\nexport interface DiscoverySpec {\n /** Stable identifier — used as `<source name=\"\">` and telemetry key. */\n readonly id: string;\n /** Priority for merge (lower = earlier in prompt). */\n readonly priority: number;\n /** Filename (cwd-only/git-root-walk) or glob (globbed). */\n readonly pattern: string;\n readonly scope: DiscoveryScope;\n readonly parser: DiscoveryParser;\n /** Whether to follow `@path` import directives (CLAUDE.md / GEMINI.md). */\n readonly followImports: boolean;\n}\n\n/**\n * 2026 industry-standard context file registry. Sorted by priority\n * ascending — earlier in prompt = more general, last-writer-wins on\n * conflict (D152 concat-by-priority).\n *\n * @internal\n */\nexport const DEFAULT_DISCOVERY_SPECS: ReadonlyArray<DiscoverySpec> = [\n {\n id: \"AGENTS.md\",\n pattern: \"AGENTS.md\",\n scope: \"git-root-walk\",\n parser: \"plain-markdown\",\n followImports: false,\n priority: 10,\n },\n {\n id: \"GEMINI.md\",\n pattern: \"GEMINI.md\",\n scope: \"git-root-walk\",\n parser: \"plain-markdown\",\n followImports: true,\n priority: 20,\n },\n {\n id: \"CLAUDE.md\",\n pattern: \"CLAUDE.md\",\n scope: \"git-root-walk\",\n parser: \"plain-markdown\",\n followImports: true,\n priority: 30,\n },\n {\n id: \"cursor-rules\",\n pattern: \".cursor/rules/*.mdc\",\n scope: \"globbed\",\n parser: \"mdc\",\n followImports: false,\n priority: 40,\n },\n {\n id: \"theokit-rules\",\n pattern: \".theokit/rules/*.md\",\n scope: \"globbed\",\n parser: \"rules-frontmatter\",\n followImports: false,\n priority: 45,\n },\n {\n id: \"theokit-context\",\n pattern: \".theokit/context/*.md\",\n scope: \"globbed\",\n parser: \"frontmatter-zod\",\n followImports: false,\n priority: 50,\n },\n {\n id: \"THEO.md\",\n pattern: \".theokit/THEO.md\",\n scope: \"cwd-only\",\n parser: \"plain-markdown\",\n followImports: false,\n priority: 60,\n },\n];\n\nconst SAFE_FILENAME = /^[a-zA-Z0-9_.\\-/*]+$/;\nconst TRAVERSAL_RE = /(^|\\/)\\.\\.(\\/|$)/;\n\n/**\n * Reject patterns that contain path traversal (`..`) or non-allowed\n * characters (D81 parity, EC-4).\n *\n * @internal\n */\nexport function isSafePattern(pattern: string): boolean {\n if (typeof pattern !== \"string\" || pattern.length === 0) return false;\n if (TRAVERSAL_RE.test(pattern)) return false;\n if (isAbsolute(pattern)) return false;\n return SAFE_FILENAME.test(pattern);\n}\n\n/**\n * Walk upward from `cwd` looking for the closest directory containing\n * a `.git` entry (file OR directory — worktrees use a `.git` FILE,\n * EC-N). Returns the absolute path of that directory, or `undefined`\n * when no git root exists at or above `cwd`.\n *\n * @internal\n */\nexport function findGitRoot(cwd: string): string | undefined {\n if (typeof cwd !== \"string\" || cwd.length === 0) return undefined;\n let current = resolve(cwd);\n // Guard against infinite loops on weird filesystems.\n for (let i = 0; i < 64; i += 1) {\n if (existsSync(join(current, \".git\"))) return current;\n const parent = dirname(current);\n if (parent === current) return undefined;\n current = parent;\n }\n return undefined;\n}\n\n/**\n * Walk `cwd` upward to `stopDir` (inclusive) collecting every existing\n * occurrence of `filename`. Returns absolute, realpath-deduped paths in\n * nearest-first order (innermost dir first).\n *\n * No `.gitignore` parsing (EC-A). Realpath collapses symlink chains\n * pointing to the same physical file (EC-F). Filesystem races (file\n * deleted mid-walk) are skipped silently (EC-5).\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: walk-up loop combines validation + realpath dedup + FS-race handling + stopDir guard in a single bounded loop; splitting fragments the dedup invariant.\nexport function walkUpForFile(\n cwd: string,\n filename: string,\n stopDir: string | undefined,\n): string[] {\n if (!isSafePattern(filename)) {\n return [];\n }\n const start = resolve(cwd);\n const stop = stopDir !== undefined ? resolve(stopDir) : undefined;\n const found: string[] = [];\n const seenReal = new Set<string>();\n let current = start;\n // 64-level depth cap.\n for (let i = 0; i < 64; i += 1) {\n const candidate = join(current, filename);\n if (existsSync(candidate)) {\n let real: string;\n try {\n real = realpathSync(candidate);\n } catch {\n // FS race (deleted mid-walk) — skip.\n real = candidate;\n }\n if (!seenReal.has(real)) {\n seenReal.add(real);\n found.push(real);\n }\n }\n if (stop !== undefined && current === stop) break;\n const parent = dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return found;\n}\n\n/**\n * Glob-style discovery under `cwd` (e.g. `.cursor/rules/*.mdc`, `.theokit/rules/**\\/*.md`).\n * Returns absolute, lex-sorted paths.\n *\n * `*` matches within one path segment and `**` spans any depth, including zero — so\n * `.theokit/rules/**\\/*.md` finds `rules/top.md` as well as `rules/deep/nested/inner.md`, while\n * `.theokit/rules/*.md` keeps its flat meaning and finds only the first. That distinction is the\n * compatibility contract: every existing spec uses a single `*`, and widening it would silently\n * start absorbing nested files nobody chose to expose.\n *\n * ## Why this used to be flat, and what changed (B-119)\n *\n * The previous implementation split the pattern at its LAST `/`, treated the prefix as a literal\n * directory and did one `readdir` — documented as \"nested directories deferred to v2\" (EC-R). The\n * deferral was deliberate; what made it a defect was measured from a consumer. TheoCode's own rule\n * loader descends recursively, so migrating it onto the `theokit-rules` spec would have silently\n * dropped every nested rule — on the path that decides whether a repository's hooks execute. And a\n * pattern written to say so, `.theokit/rules/**\\/*.md`, resolved its directory part to a literal\n * `**` and matched NOTHING, not even the top-level file it matched before the globstar was added.\n *\n * ## Why the stdlib rather than a walker\n *\n * `fs.promises.glob` (Node ≥ 22, and this package requires ≥ 22.12) implements exactly these\n * semantics, verified against a fixture before adoption: `**\\/*.md` returns all three depths,\n * `*.md` returns one, and it emits no experimental warning. Writing a recursive walker here would\n * have been a third implementation of matching inside one package — the same duplication that let\n * the enumerator and the compiler in `context-glob.ts` disagree in the first place. `globToRegex`\n * stays where it belongs: deciding whether a rule APPLIES to a set of paths, which is a different\n * question from which files exist.\n *\n * `isSafePattern` still runs first and is unchanged, so `..` is refused before any I/O.\n *\n * @internal\n */\nexport async function walkUpForGlob(cwd: string, pattern: string): Promise<string[]> {\n if (!isSafePattern(pattern)) return [];\n const found: string[] = [];\n try {\n for await (const entry of glob(pattern, { cwd })) {\n found.push(resolve(cwd, entry));\n }\n } catch {\n // A pattern whose directory does not exist is the ordinary case — most projects have no\n // `.cursor/rules/`. Same outcome as matching nothing.\n return [];\n }\n // Sorted, because discovery order becomes prompt order and must not vary with the filesystem.\n //\n // The comparator is explicit and deliberately NOT `localeCompare`, which is the usual suggestion\n // for a bare `.sort()`. `localeCompare` orders by the machine's locale, so the same tree would\n // assemble a different prompt on a differently-configured machine — trading one source of\n // non-determinism for a subtler one. Code-unit ordering is what a bare `.sort()` already does for\n // strings; writing it out states the intent and keeps the result machine-independent.\n return found.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/sandbox/shell-escape.ts","../src/sandbox/types.ts","../src/sandbox/local-sandbox.ts"],"names":["fsWriteFile"],"mappings":"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","file":"chunk-4Q4K4WB5.js","sourcesContent":["/**\n * POSIX shell escaping for values interpolated into a `SandboxBackend.execute`\n * command string. `execute` runs via `/bin/sh -c`, so any untrusted value\n * (repo URL, ref, path) MUST be quoted to prevent command injection.\n *\n * @internal\n */\n\n/** Wrap `arg` in single quotes, escaping embedded single quotes (`'\\''`). */\nexport function shellEscapePosix(arg: string): string {\n return `'${arg.replace(/'/g, \"'\\\\''\")}'`;\n}\n","/**\n * Sandbox backend protocol — pluggable execution environment for agent tools.\n *\n * Per ADR D1: only 2 abstract methods (`execute` + `uploadFile`). All\n * higher-level operations are derived on the base class. New backends\n * (Docker, Firecracker, E2B) only implement those 2 methods.\n *\n * @public\n */\n\nimport type { EnvPolicy } from \"../types/env-policy.js\";\nimport { shellEscapePosix } from \"./shell-escape.js\";\n\nexport interface ExecuteResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n timedOut: boolean;\n}\n\nexport interface SandboxConfig {\n workDir?: string;\n timeoutMs?: number;\n maxOutputBytes?: number;\n /**\n * #54 — env inherit/scrub policy for the executed command's child process.\n * Defaults to `\"inherit-scrubbed\"` (drop secret-like vars: `*KEY*`, `*SECRET*`,\n * `*TOKEN*`, `*PASSWORD*`, `*_AUTH*`). Pass `\"all\"` to restore full inheritance\n * or `\"core\"` for a minimal safe allowlist.\n */\n env?: EnvPolicy;\n}\n\nexport class SandboxSecurityError extends Error {\n readonly code = \"sandbox_security\" as const;\n constructor(message: string) {\n super(message);\n this.name = \"SandboxSecurityError\";\n }\n}\n\nexport class SandboxNotAvailableError extends Error {\n readonly code = \"sandbox_not_available\" as const;\n constructor(message: string) {\n super(message);\n this.name = \"SandboxNotAvailableError\";\n }\n}\n\nexport abstract class SandboxBackend {\n protected config: SandboxConfig;\n\n constructor(config: SandboxConfig = {}) {\n this.config = {\n workDir: config.workDir ?? \"/tmp\",\n timeoutMs: config.timeoutMs ?? 30_000,\n maxOutputBytes: config.maxOutputBytes ?? 5 * 1024 * 1024,\n // #54 — preserve the env policy so backends can scrub secrets.\n env: config.env ?? \"inherit-scrubbed\",\n };\n }\n\n abstract execute(command: string, opts?: { timeoutMs?: number }): Promise<ExecuteResult>;\n\n abstract uploadFile(path: string, content: string | Buffer): Promise<void>;\n\n async readFile(path: string): Promise<string> {\n const result = await this.execute(`cat ${this.shellEscape(path)}`);\n if (result.exitCode !== 0) {\n throw new Error(`readFile failed: ${result.stderr}`);\n }\n return result.stdout;\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n await this.uploadFile(path, content);\n }\n\n async glob(pattern: string, cwd?: string): Promise<string[]> {\n const dir = cwd ?? this.config.workDir ?? \".\";\n const result = await this.execute(\n `find ${this.shellEscape(dir)} -name ${this.shellEscape(pattern)} -type f 2>/dev/null`,\n );\n if (result.exitCode !== 0) return [];\n return result.stdout.trim().split(\"\\n\").filter(Boolean);\n }\n\n async grep(pattern: string, path?: string): Promise<string[]> {\n const target = path ?? \".\";\n const result = await this.execute(\n `grep -rn ${this.shellEscape(pattern)} ${this.shellEscape(target)} 2>/dev/null`,\n );\n if (result.exitCode !== 0) return [];\n return result.stdout.trim().split(\"\\n\").filter(Boolean);\n }\n\n async listDir(path: string): Promise<string[]> {\n const result = await this.execute(`ls -1 ${this.shellEscape(path)}`);\n if (result.exitCode !== 0) return [];\n return result.stdout.trim().split(\"\\n\").filter(Boolean);\n }\n\n protected truncateOutput(output: string): string {\n const max = this.config.maxOutputBytes ?? 5 * 1024 * 1024;\n if (Buffer.byteLength(output) > max) {\n return `${output.slice(0, max)}\\n...(truncated)`;\n }\n return output;\n }\n\n private shellEscape(arg: string): string {\n return shellEscapePosix(arg);\n }\n}\n\n/**\n * A backend OR a per-request resolver of one — mirrors `FilesystemProvider` / `InteractiveProvider`.\n * A resolver runs at tool-execution time (request scope), so a multi-tenant / multi-role agent gets a\n * distinct sandbox per request without a shared mutable one. This is how a tool takes execution as an\n * INJECTED capability: the same tool runs on a local sandbox, a container/E2B backend (cluster/web), or\n * any future backend, with no direct `child_process` import.\n *\n * @public\n */\nexport type SandboxProvider<Ctx = unknown> =\n | SandboxBackend\n | ((ctx: Ctx) => SandboxBackend | Promise<SandboxBackend>);\n\n/** Resolve a {@link SandboxProvider} to a concrete backend for `ctx`. */\nexport async function resolveSandbox<Ctx>(\n provider: SandboxProvider<Ctx>,\n ctx: Ctx,\n): Promise<SandboxBackend> {\n return provider instanceof SandboxBackend ? provider : provider(ctx);\n}\n","/**\n * LocalSandbox — subprocess-based execution. **This is NOT an isolation\n * boundary.** It runs the command via `/bin/sh -c` in the SAME OS as the host\n * with the host's filesystem and network fully reachable — it provides NO\n * process, filesystem, or network isolation. Its only safety affordances are:\n * - a wall-clock timeout (kills a runaway command),\n * - an output-size cap (bounds memory), and\n * - env scrubbing (#54): secret-like parent env vars (`*KEY*`/`*SECRET*`/\n * `*TOKEN*`/`*PASSWORD*`/`*_AUTH*`) are dropped from the child by default\n * (`SandboxConfig.env`), so a shell tool cannot exfiltrate host secrets via\n * the environment.\n *\n * For real isolation (untrusted code), use a container/VM backend — NOT this.\n *\n * @public\n */\n\nimport { execFile } from \"node:child_process\";\nimport { writeFile as fsWriteFile, mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { resolveChildEnv } from \"../internal/runtime/lifecycle/env-policy.js\";\nimport { type ExecuteResult, SandboxBackend, type SandboxConfig } from \"./types.js\";\n\nexport class LocalSandbox extends SandboxBackend {\n constructor(config: SandboxConfig = {}) {\n super(config);\n }\n\n async execute(command: string, opts?: { timeoutMs?: number }): Promise<ExecuteResult> {\n const timeout = opts?.timeoutMs ?? this.config.timeoutMs ?? 30_000;\n const max = this.config.maxOutputBytes ?? 5 * 1024 * 1024;\n\n return new Promise<ExecuteResult>((resolve) => {\n const child = execFile(\n \"/bin/sh\",\n [\"-c\", command],\n {\n cwd: this.config.workDir,\n timeout,\n maxBuffer: max,\n encoding: \"utf-8\",\n // #54 — scrub secret-like host env vars from the child by default.\n env: resolveChildEnv({ policy: this.config.env }),\n },\n (error, stdout, stderr) => {\n resolve(this.buildResult(error, stdout ?? \"\", stderr ?? \"\"));\n },\n );\n\n // Safety: if child somehow doesn't callback\n child.on(\"error\", () => {\n resolve({ stdout: \"\", stderr: \"spawn error\", exitCode: 1, timedOut: false });\n });\n });\n }\n\n private buildResult(error: Error | null, stdout: string, stderr: string): ExecuteResult {\n const timedOut = error !== null && \"killed\" in error && (error as { killed: boolean }).killed;\n return {\n stdout: this.truncateOutput(stdout),\n stderr: this.truncateOutput(stderr),\n exitCode: timedOut ? 124 : error ? 1 : 0,\n timedOut,\n };\n }\n\n async uploadFile(path: string, content: string | Buffer): Promise<void> {\n const fullPath = path.startsWith(\"/\") ? path : `${this.config.workDir}/${path}`;\n await mkdir(dirname(fullPath), { recursive: true });\n await fsWriteFile(fullPath, content, \"utf-8\");\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/env.ts","../src/internal/diagnostics.ts","../src/internal/security/redact.ts"],"names":[],"mappings":";AAKO,IAAM,eAAA,GAAkB,iBAAA;AAoBxB,SAAS,QAAQ,IAAA,EAAkC;AACxD,EAAA,OAAO,UAAA,CAAW,OAAA,EAAS,GAAA,GAAM,IAAI,CAAA;AACvC;AAYO,SAAS,cAAc,QAAA,EAAuC;AACnE,EAAA,IAAI,QAAA,KAAa,MAAA,IAAa,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG;AACjD,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,MAAM,OAAA,GAAU,QAAQ,eAAe,CAAA;AACvC,EAAA,IAAI,OAAA,KAAY,MAAA,IAAa,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AAC/C,IAAA,OAAO,OAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAA;AACT;;;ACoBA,IAAM,SAAA,mBAAY,MAAA,CAAO,GAAA,CAAI,iCAAiC,CAAA;AAI9D,SAAS,WAAA,GAA2C;AAClD,EAAA,OAAQ,WAAqC,SAAS,CAAA;AACxD;AASO,SAAS,mBAAmB,IAAA,EAAyC;AAC1E,EAAC,UAAA,CAAqC,SAAS,CAAA,GAAI,IAAA;AACrD;AAQO,SAAS,KAAK,OAAA,EAAuB;AAG1C,EAAA,MAAM,OAAO,WAAA,EAAY;AACzB,EAAA,IAAI,SAAS,MAAA,EAAW;AACxB,EAAA,IAAI;AACF,IAAA,IAAA,CAAK,OAAO,CAAA;AAAA,EACd,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;;;AC9EA,IAAI,iBAA0B,WAAA,EAAY;AAE1C,SAAS,WAAA,GAAuB;AAG9B,EAAA,MAAM,GAAA,GAAM,QAAQ,wBAAwB,CAAA;AAC5C,EAAA,IAAI,GAAA,KAAQ,QAAW,OAAO,IAAA;AAC9B,EAAA,OAAO,CAAC,KAAK,MAAA,EAAQ,KAAA,EAAO,IAAI,CAAA,CAAE,QAAA,CAAS,GAAA,CAAI,WAAA,EAAa,CAAA;AAC9D;AAGA,IAAI,YAAA,GAAe,KAAA;AACnB,IAAI,CAAC,cAAA,IAAkB,CAAC,YAAA,EAAc;AACpC,EAAA,IAAA;AAAA,IACE;AAAA,GAEF;AACA,EAAA,YAAA,GAAe,IAAA;AACjB;AASA,IAAM,gBAAA,GAAsC;AAAA;AAAA;AAAA;AAAA;AAAA,EAK1C,iJAAA;AAAA;AAAA;AAAA,EAGA,gEAAA;AAAA;AAAA,EAEA,mCAAA;AAAA;AAAA,EAEA,oCAAA;AAAA;AAAA,EACA,4BAAA;AAAA;AAAA;AAAA,EAEA,6BAAA;AAAA;AAAA,EACA,wBAAA;AAAA;AAAA;AAAA,EAEA,wBAAA;AAAA;AAAA,EACA,mBAAA;AAAA;AAAA,EACA,sBAAA;AAAA;AAAA,EACA,0BAAA;AAAA;AAAA,EACA,sBAAA;AAAA;AAAA,EACA,8BAAA;AAAA;AAAA,EACA,uBAAA;AAAA;AAAA,EACA,sBAAA;AAAA;AAAA,EACA,0BAAA;AAAA;AAAA,EACA,0BAAA;AAAA;AAAA,EACA,0BAAA;AAAA;AAAA,EACA,wBAAA;AAAA;AAAA,EACA,2BAAA;AAAA;AAAA,EACA,2BAAA;AAAA;AAAA,EACA,0BAAA;AAAA;AAAA,EACA,yBAAA;AAAA;AAAA,EACA,+BAAA;AAAA;AAAA;AAAA,EAEA,sBAAA;AAAA;AAAA,EACA,2CAAA;AAAA;AAAA,EACA,wBAAA;AAAA;AAAA,EACA,uBAAA;AAAA;AAAA,EACA,2DAAA;AAAA;AAAA,EACA;AAAA;AACF,CAAA;AAKA,IAAM,cAAA,GAAiB,wCAAA;AAoBvB,IAAM,aAAA,GACJ,4NAAA;AAEF,IAAM,iBAA2B,EAAC;AAS3B,SAAS,WAAW,EAAA,EAAkB;AAC3C,EAAA,IAAI,CAAC,GAAG,MAAA,EAAQ;AACd,IAAA,MAAM,IAAI,MAAM,wEAAwE,CAAA;AAAA,EAC1F;AACA,EAAA,cAAA,CAAe,KAAK,EAAE,CAAA;AACxB;AAYO,SAAS,UAAU,KAAA,EAAuB;AAC/C,EAAA,IAAI,KAAA,CAAM,MAAA,GAAS,EAAA,EAAI,OAAO,KAAA;AAC9B,EAAA,OAAO,CAAA,EAAG,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,GAAA,EAAM,KAAA,CAAM,KAAA,CAAM,EAAE,CAAC,CAAA,CAAA;AAClD;AAKA,IAAM,UAAA,GAAa,mBAAA;AAoBnB,SAAS,eAAe,KAAA,EAA+B;AACrD,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW,OAAO,IAAA;AAClD,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,IAAI;AACF,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AAC9B,MAAA,OAAO,CAAA,KAAM,SAAY,IAAA,GAAO,CAAA;AAAA,IAClC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,0BAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,OAAO,KAAK,CAAA;AACrB;AAEO,SAAS,aAAA,CAAc,MAAe,IAAA,EAAuC;AAClF,EAAA,MAAM,OAAA,GAAU,eAAe,IAAI,CAAA;AACnC,EAAA,IAAI,OAAA,KAAY,MAAM,OAAO,EAAA;AAC7B,EAAA,IAAI,CAAC,gBAAgB,OAAO,OAAA;AAE5B,EAAA,IAAI,CAAA,GAAI,OAAA;AACR,EAAA,KAAA,MAAW,MAAM,gBAAA,EAAkB;AACjC,IAAA,CAAA,GAAI,EAAE,OAAA,CAAQ,EAAA,EAAI,CAAC,CAAA,KAAM,SAAA,CAAU,CAAC,CAAC,CAAA;AAAA,EACvC;AACA,EAAA,KAAA,MAAW,MAAM,cAAA,EAAgB;AAC/B,IAAA,CAAA,GAAI,EAAE,OAAA,CAAQ,EAAA,EAAI,CAAC,CAAA,KAAM,SAAA,CAAU,CAAC,CAAC,CAAA;AAAA,EACvC;AACA,EAAA,IAAI,CAAC,MAAM,QAAA,EAAU;AAInB,IAAA,CAAA,GAAI,CAAA,CAAE,QAAQ,cAAA,EAAgB,CAAC,GAAG,MAAA,KAAmB,CAAA,EAAG,MAAM,CAAA,GAAA,CAAK,CAAA;AAInE,IAAA,CAAA,GAAI,EAAE,OAAA,CAAQ,aAAA,EAAe,CAAC,KAAA,EAAO,QAAgB,KAAA,KAAkB;AAOrE,MAAA,IAAI,UAAA,CAAW,IAAA,CAAK,KAAK,CAAA,EAAG,OAAO,KAAA;AACnC,MAAA,OAAO,GAAG,MAAM,CAAA,GAAA,CAAA;AAAA,IAClB,CAAC,CAAA;AAAA,EACH;AACA,EAAA,OAAO,CAAA;AACT","file":"chunk-5F5NWKPN.js","sourcesContent":["/**\n * Environment variable used to provide the default API key.\n *\n * @internal\n */\nexport const API_KEY_ENV_VAR = \"THEOKIT_API_KEY\";\n\n/**\n * Read an environment variable without assuming `process` exists.\n *\n * Parts of this package legitimately reach a browser: `errors.ts` is imported by the client\n * bindings that framework consumers ship to the front end, and it in turn pulls in the redaction\n * and retry modules. `process` is a Node global — a bare `process.env` in any of them throws\n * `ReferenceError: process is not defined` while the module graph is still evaluating, before a\n * single component renders. The page goes blank with one console error that names no cause.\n *\n * `globalThis.process?.env?.[name]` degrades instead: on the server it reads the variable, and in\n * a browser it yields `undefined`, which every caller here already treats as \"not set\". Bundlers\n * that inline `process.env.X` at build time keep working, because they replace the expression\n * before it ever runs.\n *\n * This is the same pattern the sibling design system uses for `NODE_ENV`, for the same reason.\n *\n * @internal\n */\nexport function readEnv(name: string): string | undefined {\n return globalThis.process?.env?.[name];\n}\n\n/**\n * Resolve the API key with the documented precedence:\n *\n * 1. Explicit `apiKey` argument.\n * 2. The `THEOKIT_API_KEY` environment variable.\n *\n * Returns `undefined` when neither is set.\n *\n * @internal\n */\nexport function resolveApiKey(explicit?: string): string | undefined {\n if (explicit !== undefined && explicit.length > 0) {\n return explicit;\n }\n const fromEnv = readEnv(API_KEY_ENV_VAR);\n if (fromEnv !== undefined && fromEnv.length > 0) {\n return fromEnv;\n }\n return undefined;\n}\n","/**\n * The library's single diagnostics channel — silent by default (#147).\n *\n * ## The problem\n *\n * The SDK wrote diagnostics straight to `process.stderr` from hot paths — 92 sites across 51\n * files under `internal/`. In a TUI host (Ink, alternate screen), those writes interleave with the\n * render and **corrupt the frame**. And the host had no way to intercept them: there was no\n * injectable logger. One consumer went as far as installing `proper-lockfile` just to silence ONE\n * of them.\n *\n * A library cannot assume `stdout`/`stderr` are free sinks. The application owns the terminal, not\n * the dependency.\n *\n * ## The contract\n *\n * - **`setDiagnosticsSink(fn)`** hands the messages to the application, which decides where to put\n * them (a status line, a file, a panel). It is what was missing for a TUI to coexist with the SDK.\n * - **With no sink, nothing is emitted.** A library does not own the host's terminal.\n *\n * ## Silent by default, and how 36 suites survived the flip\n *\n * The default WAS `stderr`, and 36 test files spy on `process.stderr.write` to assert a given\n * warning is emitted. That contract is real and had to survive; migrating all 36 by hand, across\n * four different spy styles, is how you weaken 36 suites in one commit.\n *\n * So the flip happened at the default, and `vitest.setup.ts` installs a sink that FORWARDS to\n * `stderr` for the duration of every test. Those assertions still test what they always tested —\n * \"this condition emits a diagnostic\" — through the channel a host would use, while production\n * emits nothing unless asked.\n *\n * The cost is stated rather than hidden: no test observes the production default by accident, so\n * `tests/diagnostics-public-entry.test.ts` pins it explicitly by clearing the sink first.\n *\n * ## Coverage is the whole guarantee\n *\n * The first sweep migrated the 92 sites under `internal/` and left `src/`'s own modules —\n * `event-bus.ts`, `batch.ts`, `compaction.ts`, `internal/workflow/step-branch.ts`. A host could\n * therefore install a sink and still have its frame corrupted by a batch run, which is the reported\n * defect with a smaller blast radius. Those are routed here too, and\n * `tests/lint/no-direct-terminal-write.test.ts` is what keeps the next hot path from\n * reintroducing one. \"Mostly interceptable\" is not interceptable.\n *\n * The remaining direct writers are allowlisted there with a reason, and every one of them is a seam\n * whose destination the CALLER already chooses (`opts.warn`, `opts.logger`, the Workflow logger).\n *\n * ## What this is NOT\n *\n * It is not a logger with levels, formatting or multiple destinations. It is the minimum that\n * resolves the reported blocker; a full logger here would be inventing a requirement nobody asked\n * for.\n */\n\n/** Receives each diagnostic message already formatted, with the trailing `\\n`. */\nexport type DiagnosticsSink = (message: string) => void;\n\n/**\n * The registry lives on `globalThis`, not in a module-level `let` (theokit#173).\n *\n * A module-level binding is a per-INSTANCE singleton, and a package manager will install two\n * physical copies of the same version whenever two dependents resolve different peer sets. Measured:\n * `@theokit/sdk@4.39.1` existed under two pnpm store hashes in the theokit workspace, so a sink\n * installed through `@theokit/agents` landed in a different registry than the emitter writes to.\n *\n * The failure mode is the quiet one — the re-export resolves, the function is callable, nothing\n * throws, and no diagnostic ever arrives. `Symbol.for` gives every copy in the process the same\n * slot; the `v1` suffix leaves room to change the shape without colliding with an older copy.\n */\nconst SINK_SLOT = Symbol.for(\"theokit.sdk.diagnostics.sink.v1\");\n\ntype SinkHolder = Record<symbol, DiagnosticsSink | undefined>;\n\nfunction currentSink(): DiagnosticsSink | undefined {\n return (globalThis as unknown as SinkHolder)[SINK_SLOT];\n}\n\n/**\n * Installs (or removes, by passing `undefined`) the diagnostics destination.\n *\n * When a sink is present it is the ONLY destination — `stderr` gets no copy. Duplicating\n * destinations would hand the problem back to the TUI that installed the sink precisely to get the\n * messages out of the terminal.\n */\nexport function setDiagnosticsSink(next: DiagnosticsSink | undefined): void {\n (globalThis as unknown as SinkHolder)[SINK_SLOT] = next;\n}\n\n/**\n * Emits a library diagnostic message.\n *\n * Replaces `process.stderr.write` on internal paths. Never throws: a faulty sink must not\n * must not take down the run it merely observes.\n */\nexport function diag(message: string): void {\n // Silent by default (#147): with no sink installed the message is dropped. A library must not\n // assume the host's stdout/stderr are free-form log sinks — in a TUI they are the render surface.\n const sink = currentSink();\n if (sink === undefined) return;\n try {\n sink(message);\n } catch {\n // Observability never breaks the run — same principle as `emitRunEvent`.\n }\n}\n\n/**\n * Emits a diagnostic that reports a USER-VISIBLE FAILURE, and is never silently dropped.\n *\n * `diag` is silent with no sink installed, and that is right for chatter: a library must not assume\n * the host's stderr is a free-form log, because in a TUI it is the render surface. A failure is a\n * different message. `theokit-sdk#189` is the record of the difference — an MCP server failed to\n * start, the only report went to `diag()`, the embedding UI never read it, and the user saw an\n * agent with missing tools and no reason given.\n *\n * The two failure modes are not symmetric, which is the whole decision: a corrupted frame is\n * visible and recoverable, while a silently dropped failure is neither. So this falls back to\n * stderr rather than to silence.\n *\n * A sink still takes precedence — the host installed it precisely to keep these off the terminal —\n * EXCEPT when the sink throws. A broken sink swallowing the one report of a failure is the same\n * defect one layer further in.\n *\n * @internal\n */\nexport function diagFailure(message: string): void {\n const sink = currentSink();\n if (sink !== undefined) {\n try {\n sink(message);\n return;\n } catch {\n // Fall through: the sink is broken, and this message is too important to drop with it.\n }\n }\n try {\n // `globalThis.process?.stderr` rather than a bare `process`: in a browser the bare form is a\n // ReferenceError that the catch below would swallow — working by accident, on an exception used\n // as ordinary control flow. Optional chaining states the intent: write to stderr where one\n // exists, stay silent where none does.\n globalThis.process?.stderr?.write(`${message}\\n`);\n } catch {\n // Nothing left to try. Observability never breaks the run.\n }\n}\n","import { diag } from \"../diagnostics.js\";\nimport { readEnv } from \"../env.js\";\n\n/**\n * Canonical secret redaction module (ADRs D68-D73).\n *\n * Single source of truth for credential pattern masking across the SDK.\n * Wired at output boundaries: `ErrorMetadata.raw` (mappers/shared.ts),\n * telemetry span attributes (telemetry/tracer.ts), transcript JSONL\n * appends (agent-session-store.ts), migration logger output\n * (memory/migrate-sqlite-to-lance.ts).\n *\n * - D68: central module, single source of truth (replaces 2 duplicates)\n * - D69: env snapshot at module init (prompt-injection defense)\n * - D70: ON by default, warn on opt-out\n * - D71: two-bucket masking — short fully masked, long preserves prefix+suffix\n * - D72: `codeFile` opt-out for legitimate prefix-shaped content\n * - D73: redact at OUTPUT boundaries, not at storage\n *\n * @internal\n */\n\n// D69: env snapshot captured at module load. Subsequent mutations of\n// process.env.THEOKIT_REDACT_SECRETS are ignored — defends against\n// prompt injection that tries to disable redaction mid-run.\nlet REDACT_ENABLED: boolean = readEnvOnce();\n\nfunction readEnvOnce(): boolean {\n // `readEnv` rather than `process.env`: this module reaches the browser through `errors.ts`, and\n // a bare `process` there is a ReferenceError at module scope — a blank page, not a warning.\n const raw = readEnv(\"THEOKIT_REDACT_SECRETS\");\n if (raw === undefined) return true; // D70: default ON\n return [\"1\", \"true\", \"yes\", \"on\"].includes(raw.toLowerCase());\n}\n\n// D70: warn once on opt-out so the user knows they're vulnerable.\nlet warnedOptOut = false;\nif (!REDACT_ENABLED && !warnedOptOut) {\n diag(\n \"[theokit-sdk] Secret redaction is DISABLED via THEOKIT_REDACT_SECRETS. \" +\n \"Credentials may leak into errors, telemetry, logs, transcripts.\\n\",\n );\n warnedOptOut = true;\n}\n\n/**\n * Built-in credential patterns. Order matters — more specific prefixes\n * must come before generic ones (e.g., `sk-ant-` before `sk-`). Quantifiers\n * are all bounded `{n,m}` or applied to char classes — linear time, no ReDoS.\n *\n * @internal\n */\nconst BUILTIN_PATTERNS: readonly RegExp[] = [\n // T5.4: 30+ vendor prefixes (was 12 pre-T5.4). Order matters — more\n // specific prefixes precede generic ones (e.g., sk-ant-admin01 before\n // sk-ant-, sk-proj- before sk-). PEM block deliberately first so its\n // multi-line span runs before any per-line patterns can fire.\n /-----BEGIN[ ]+(?:RSA |EC |DSA |OPENSSH |ENCRYPTED |)PRIVATE KEY-----[\\s\\S]+?-----END[ ]+(?:RSA |EC |DSA |OPENSSH |ENCRYPTED |)PRIVATE KEY-----/g,\n // JWT — exact 3-segment base64url. Dotted; the body floor of 4 chars per\n // segment matches the minimum legal payload while skipping `a.b.c` noise.\n /eyJ[A-Za-z0-9_-]{4,}\\.eyJ[A-Za-z0-9_-]{4,}\\.[A-Za-z0-9_-]{4,}/g,\n // Azure Storage SAS — match the sig= component (URL-encoded base64).\n /(?<=[?&]sig=)[A-Za-z0-9%+/]{20,}/g,\n // Anthropic\n /sk-ant-admin01-[A-Za-z0-9_-]{10,}/g, // Anthropic admin keys (must precede sk-ant-)\n /sk-ant-[A-Za-z0-9_-]{10,}/g, // Anthropic regular\n // OpenAI family + clones (sk- generic must come AFTER all sk-foo- variants)\n /sk-proj-[A-Za-z0-9_-]{10,}/g, // OpenAI project key (must precede sk- generic)\n /sk-[A-Za-z0-9_-]{10,}/g, // OpenAI / OpenRouter / DeepInfra / Together / DeepSeek\n // Provider prefixes (alphabetized for maintainability)\n /AIza[A-Za-z0-9_-]{35}/g, // Google API key\n /AKIA[A-Z0-9]{16}/g, // AWS access key\n /fw_[A-Za-z0-9]{20,}/g, // Fireworks\n /glpat-[A-Za-z0-9_-]{20}/g, // GitLab PAT\n /ghp_[A-Za-z0-9]{36}/g, // GitHub PAT classic\n /github_pat_[A-Za-z0-9_]{82}/g, // GitHub PAT fine-grained\n /gsk_[A-Za-z0-9]{20,}/g, // Groq\n /hf_[A-Za-z0-9]{20,}/g, // HuggingFace\n /\\bpa-[A-Za-z0-9_-]{20,}/g, // Voyage AI (word-boundary to skip CSS / kebab IDs)\n /pcsk_[A-Za-z0-9_-]{20,}/g, // Pinecone\n /pplx-[A-Za-z0-9_-]{20,}/g, // Perplexity\n /r8_[A-Za-z0-9_-]{20,}/g, // Replicate\n /rk_live_[A-Za-z0-9]{20,}/g, // Stripe restricted\n /sk_live_[A-Za-z0-9]{20,}/g, // Stripe secret\n /sntrys_[A-Za-z0-9]{40,}/g, // Sentry user auth\n /xai-[A-Za-z0-9_-]{20,}/g, // xAI (Grok)\n /xox[bpasr]-[A-Za-z0-9-]{10,}/g, //Slack tokens\n // Additional unique-prefix tokens with low false-positive risk\n /npm_[A-Za-z0-9]{36}/g, // npm access token\n /SG\\.[A-Za-z0-9_-]{22}\\.[A-Za-z0-9_-]{43}/g, // SendGrid\n /\\bSK[A-Za-z0-9]{32}\\b/g, // Twilio API SID (word-boundary to skip CSS class noise)\n /\\bkey-[a-f0-9]{32}\\b/g, // Mailgun (hex-only narrows false positives)\n /MT[A-Za-z0-9_-]{23}\\.[A-Za-z0-9_-]{6}\\.[A-Za-z0-9_-]{27}/g, // Discord bot\n /\\b(?:sdk|mob)-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\\b/g, // LaunchDarkly\n];\n\n// `Bearer <token>` matched as its own first-class pattern so PARAM_PATTERN\n// doesn't have to handle the unusual `Authorization: Bearer xxx` shape\n// (no `:` or `=` between \"Bearer\" and the value — bare whitespace).\nconst BEARER_PATTERN = /\\b(Bearer\\s+)([A-Za-z0-9_\\-.+/=]{8,})/g;\n\n// Parametric: matches `key=value` and `key: value` (with optional quote\n// between the key and the separator, to handle JSON: `\"api_key\": \"...\"`)\n// in URLs, query strings, JSON-like bodies, HTTP headers. Captures the\n// prefix so we keep it visible while masking the value.\n//\n// `authorization` deliberately excluded — BEARER_PATTERN handles the\n// common `Authorization: Bearer xxx` shape. Including it here causes\n// double-masking (\"Authorization: *** ***\") after Bearer fires.\n// T5.4: keyword set expanded from 6 → 16 to cover the OAuth / JWT / generic\n// credential vocabulary surfaced by DR6 finding #4. `authorization`,\n// `auth`, `bearer` stay excluded — BEARER_PATTERN handles the\n// `Authorization: Bearer xxx` shape and including these here would\n// re-catch the post-BUILTIN-masked form (D71 prefix-preservation\n// contract) and double-mask to `***`.\n//\n// Value class includes `.` so JWT / `.env` / dotted base64url values\n// match; the callback skips already-masked values (containing the\n// `...` D71 separator) to preserve the BUILTIN prefix-mask result.\nconst PARAM_PATTERN =\n /(\\b(?:access_token|api_key|api-key|client_secret|credential|credentials|id_token|jwt|password|private_key|refresh_token|secret|service_account|session_token|token|x-api-key)\\b[\"']?\\s*[:=]\\s*[\"']?)([A-Za-z0-9_\\-.+/]+)/gi;\n\nconst _extraPatterns: RegExp[] = [];\n\n/**\n * Add a user-defined redaction pattern. Additive — never removes builtins.\n * Throws if the regex lacks the `/g` flag (without `/g`, `.replace` only\n * substitutes the first match and the rest leaks).\n *\n * @internal — exposed publicly via `Security.addPattern` in `src/security.ts`.\n */\nexport function addPattern(re: RegExp): void {\n if (!re.global) {\n throw new Error(\"Security.addPattern: regex must have /g flag for replace-all semantics\");\n }\n _extraPatterns.push(re);\n}\n\n/**\n * Two-bucket masking (D71):\n * - tokens shorter than 18 chars → fully masked as `***`\n * - tokens >= 18 chars → keep first 6 + `...` + last 4\n *\n * Rationale: long tokens are unique per-account; prefix+suffix preserves\n * debuggability without revealing the secret middle.\n *\n * @internal\n */\nexport function maskToken(token: string): string {\n if (token.length < 18) return \"***\";\n return `${token.slice(0, 6)}...${token.slice(-4)}`;\n}\n\n// issue #117 — the EXACT shape of a `maskToken` output (`slice(0,6)+\"...\"+slice(-4)`\n// = 6 chars, literal `...`, 4 chars). Used to detect a value PARAM_PATTERN would\n// otherwise re-mask, WITHOUT skipping a raw secret that merely contains `...`.\nconst MASK_SHAPE = /^.{6}\\.\\.\\..{4}$/s;\n\n/**\n * Redact known credential patterns from `text`. Default behavior masks\n * builtins + extras + parametric `key=value` sinks.\n *\n * With `{ codeFile: true }` (D72), skips PARAM_PATTERN to avoid mangling\n * `.env.example`, schema JSON, or test fixtures that legitimately contain\n * prefix-like strings.\n *\n * Returns the redacted string. Coerces non-strings via JSON.stringify;\n * EC-7 fix (edge-case review): wraps in try/catch so circular references\n * never propagate — returns sentinel `\"[unredactable: circular]\"`.\n *\n * @internal\n */\n// Coerce arbitrary input to a string for redaction. Returns `null`\n// sentinel when the value is null/undefined/non-stringifiable, so the\n// caller can short-circuit with `\"\"`. EC-7 fix: circular refs go through\n// the try/catch and produce the sentinel marker, never throwing.\nfunction coerceToString(value: unknown): string | null {\n if (typeof value === \"string\") return value;\n if (value === null || value === undefined) return null;\n if (typeof value === \"object\") {\n try {\n const s = JSON.stringify(value);\n return s === undefined ? null : s;\n } catch {\n return \"[unredactable: circular]\";\n }\n }\n return String(value);\n}\n\nexport function redactSecrets(text: unknown, opts?: { codeFile?: boolean }): string {\n const coerced = coerceToString(text);\n if (coerced === null) return \"\";\n if (!REDACT_ENABLED) return coerced;\n\n let s = coerced;\n for (const re of BUILTIN_PATTERNS) {\n s = s.replace(re, (m) => maskToken(m));\n }\n for (const re of _extraPatterns) {\n s = s.replace(re, (m) => maskToken(m));\n }\n if (!opts?.codeFile) {\n // Bearer first (preserves \"Bearer \" prefix, masks the token after).\n // Must run before PARAM_PATTERN so the bare-whitespace shape doesn't\n // get mis-handled as a value.\n s = s.replace(BEARER_PATTERN, (_, prefix: string) => `${prefix}***`);\n // T5.4: skip if value already contains the D71 bucket-mask separator\n // (`...`) — BUILTIN ran first and produced a prefix-preserved mask;\n // re-masking would lose the prefix and degrade debuggability.\n s = s.replace(PARAM_PATTERN, (whole, prefix: string, value: string) => {\n // issue #117 — skip ONLY when the value is already a mask that a BUILTIN\n // pattern produced (maskToken's exact `6chars...4chars` shape), so we don't\n // re-mask and lose the prefix. The old `value.includes(\"...\")` was too broad:\n // a REAL secret that happens to contain `...` (e.g. `L_-cxw-.2UI_..._`) was\n // skipped and LEAKED. The mask shape is exact (maskToken: slice(0,6)+\"...\"+\n // slice(-4)), so a raw secret with `...` elsewhere is now masked.\n if (MASK_SHAPE.test(value)) return whole;\n return `${prefix}***`;\n });\n }\n return s;\n}\n\n/**\n * Test-only helper exported for `_test-reset.ts`. NOT included in the\n * `index.ts` barrel — vitest setup imports the dedicated module via\n * explicit path to discourage production callers.\n *\n * @internal\n */\nexport function _resetForTests(opts: { enabled?: boolean; clearExtras?: boolean }): void {\n if (opts.enabled !== undefined) REDACT_ENABLED = opts.enabled;\n if (opts.clearExtras === true) _extraPatterns.length = 0;\n}\n\n/**\n * T5.4 — Test-only count of BUILTIN_PATTERNS. Exposed so the count-floor\n * assertion can run without re-deriving the array shape in test land.\n * NOT included in the public barrel.\n *\n * @internal\n */\nexport function __TESTING__BUILTIN_PATTERN_COUNT(): number {\n return BUILTIN_PATTERNS.length;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/auth/errors.ts"],"names":[],"mappings":";AAUO,IAAM,eAAA,GAAN,cAA8B,KAAA,CAAM;AAAA,EACvB,IAAA,GAAO,iBAAA;AAAA,EAChB,IAAA;AAAA,EAET,WAAA,CAAY,MAAc,OAAA,EAAiB;AACzC,IAAA,KAAA,CAAM,CAAA,CAAA,EAAI,IAAI,CAAA,EAAA,EAAK,OAAO,CAAA,CAAE,CAAA;AAC5B,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AACF;AAMO,IAAM,yBAAA,GAAN,cAAwC,KAAA,CAAM;AAAA,EACjC,IAAA,GAAO,2BAAA;AAAA,EAChB,YAAA;AAAA,EAET,YAAY,YAAA,EAAsB;AAChC,IAAA,KAAA;AAAA,MACE,6BAA6B,YAAY,CAAA,mDAAA;AAAA,KAC3C;AACA,IAAA,IAAA,CAAK,YAAA,GAAe,YAAA;AAAA,EACtB;AACF;AAcO,IAAM,iBAAA,GAAN,cAAgC,KAAA,CAAM;AAAA,EACzB,IAAA,GAAe,mBAAA;AAAA,EACxB,IAAA;AAAA,EAET,WAAA,CAAY,MAAc,OAAA,EAAkB;AAC1C,IAAA,KAAA,CAAM,OAAA,IAAW,CAAA,sBAAA,EAAyB,IAAI,CAAA,CAAE,CAAA;AAChD,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AACF;AAUO,IAAM,kBAAA,GAAN,cAAiC,iBAAA,CAAkB;AAAA,EACtC,IAAA,GAAe,oBAAA;AAAA,EACxB,gBAAA;AAAA,EAET,YAAY,gBAAA,EAA2B;AACrC,IAAA,KAAA,CAAM,uBAAA,EAAyB,oBAAoB,mCAAmC,CAAA;AACtF,IAAA,IAAA,CAAK,gBAAA,GAAmB,gBAAA;AAAA,EAC1B;AACF","file":"chunk-5NBUH3NO.js","sourcesContent":["/**\n * @theokit/sdk/server/auth — typed error classes\n *\n * Plan T1.2 + v1.1 EC-1 (AuthCancelledError for OAuth provider error response RFC 6749 §4.1.2.1).\n */\n\n/**\n * Thrown at `defineAuth()` time when configuration is invalid\n * (e.g., duplicate provider name, invalid email shape per EC-V1-12).\n */\nexport class AuthConfigError extends Error {\n override readonly name = \"AuthConfigError\";\n readonly code: string;\n\n constructor(code: string, message: string) {\n super(`[${code}] ${message}`);\n this.code = code;\n }\n}\n\n/**\n * Thrown at `startSignIn(providerName, ...)` or `finishSignIn(providerName, ...)`\n * when the named provider is not registered in `providers[]`.\n */\nexport class AuthProviderNotFoundError extends Error {\n override readonly name = \"AuthProviderNotFoundError\";\n readonly providerName: string;\n\n constructor(providerName: string) {\n super(\n `Auth provider not found: '${providerName}'. Register it in defineAuth({ providers: [...] }).`,\n );\n this.providerName = providerName;\n }\n}\n\n/**\n * Thrown during OAuth callback handling for state mismatches, expired\n * transactions, missing query params, or provider 4xx/5xx errors.\n *\n * Typed `code` field lets consumers branch on cause:\n * - 'oauth_transaction_expired' — cookie tx > 10min old (per ADR D5)\n * - 'oauth_state_mismatch' — query state ≠ cookie state (CSRF defense per RFC 6749 §10.12)\n * - 'oauth_provider_error' — non-access_denied error in callback URL\n * - 'oauth_token_exchange_failed' — provider rejected code-for-tokens swap\n * - 'oauth_userinfo_failed' — userinfo endpoint returned error\n * - 'oauth_missing_code_or_state' — required query params absent\n */\nexport class AuthCallbackError extends Error {\n override readonly name: string = \"AuthCallbackError\";\n readonly code: string;\n\n constructor(code: string, message?: string) {\n super(message ?? `OAuth callback error: ${code}`);\n this.code = code;\n }\n}\n\n/**\n * Per v1.1 EC-1 MUST FIX — typed subclass of AuthCallbackError for the\n * specific case where user declined consent at provider screen.\n *\n * OAuth 2.0 RFC 6749 §4.1.2.1: provider redirects with `?error=access_denied`.\n * Apps can catch this distinctly from network/server errors to render\n * \"Login cancelled — try again\" UX instead of opaque \"callback failed\".\n */\nexport class AuthCancelledError extends AuthCallbackError {\n override readonly name: string = \"AuthCancelledError\";\n readonly errorDescription?: string;\n\n constructor(errorDescription?: string) {\n super(\"user_declined_consent\", errorDescription ?? \"User declined consent at provider\");\n this.errorDescription = errorDescription;\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/auth/credential-store.ts"],"names":["join","AuthenticationError","z","statSync","readFileSync","mkdirSync","chmodSync","randomBytes","openSync","writeFileSync","fsyncSync","closeSync","renameSync","unlinkSync"],"mappings":"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","file":"chunk-5YKNEMXR.cjs","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n closeSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { z } from \"zod\";\n\nimport { AuthenticationError } from \"../../errors.js\";\n\n/**\n * M42 — the SDK credential store. Promoted DOWN from agent-builder's hardened `agents/lib/credentials.ts`\n * (M37), generalized from a closed `openrouter|anthropic|openai` union to an open `provider: string` and\n * driven by a caller-supplied {@link CredentialStoreConfig} (no hardcoded `.agent-builder`/`auth.json` /\n * `AGENT_BUILDER_HOME`). The security-critical file mechanics are ported VERBATIM (ADR D3 of the M42 plan):\n * atomic O_EXCL + rename + fsync write, 0700/0600 mode gates, `env` is always a PARAMETER (never an ambient\n * `process.env` read).\n *\n * The env-precedence + key-prefix-inference + declared-provider rungs of the agent-builder resolver are\n * APP POLICY and deliberately stay UP in the consumer; this module owns only the on-disk store + the\n * `api|oauth` discriminated union. See {@link resolveCredential} (SDK) for the store-read + refresh path.\n *\n * @internal\n */\nimport type {\n CredentialStoreConfig,\n StoredCredential,\n StoredOAuthCredential,\n} from \"./auth-types.js\";\n\n/** The store directory, honoring an optional `homeEnvVar` override. */\nexport function credentialHome(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const override = config.homeEnvVar !== undefined ? env[config.homeEnvVar]?.trim() : undefined;\n return override !== undefined && override.length > 0\n ? override\n : join(config.home, config.dirName);\n}\n\n/** The credential file path inside the (possibly overridden) store directory. */\nexport function authFilePath(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n return join(credentialHome(config, env), config.fileName);\n}\n\n/**\n * A credential problem the caller can act on. Never carries the key value.\n *\n * M78 — this used to extend bare `Error`, which quietly disabled classification for the entire auth\n * path: `isTransientError` is `err instanceof TheokitAgentError && err.isRetryable === true`\n * (`errors.ts:443`), so a credential failure could never be judged transient OR permanent. The\n * predicate was not \"forgotten\" downstream — it was unusable there by construction.\n *\n * Extending `AuthenticationError` is ADDITIVE: the class still exists, still reports\n * `name: \"CredentialError\"`, and every existing `instanceof CredentialError` stays true. It only\n * gains ancestors. `AuthenticationError` pins `isRetryable: false`, so gaining the ability to be\n * classified does NOT turn a revoked credential into a retry loop.\n *\n * The single reference does the same thing with one root type: Codex routes every domain failure\n * through `CodexErr` with `is_retryable()` as a method (`protocol/src/error.rs:176`), rather than\n * parallel classes extending the language's `Error`.\n */\nexport class CredentialError extends AuthenticationError {\n // Field, not an assignment in the constructor: `AuthenticationError.name` is `override readonly`\n // (`errors.ts:174`), so `this.name = …` does not compile. Caught by `tsc`, not by vitest — the\n // suite was green with the broken assignment because the transpiler strips the type.\n override readonly name: string = \"CredentialError\";\n}\n\n/**\n * The on-disk store — a discriminated union on `type`. A legacy file with NO\n * `type` (or `type: 'api'`) is the API-key variant — read unchanged, no migration. The `oauth` variant\n * carries the token pair + expiry.\n */\nconst apiFileSchema = z\n .object({\n type: z.literal(\"api\").optional(),\n provider: z.string().min(1).optional(),\n api_key: z.string(),\n })\n .strict();\n\nconst oauthFileSchema = z\n .object({\n type: z.literal(\"oauth\"),\n provider: z.string().min(1),\n access: z.string().min(1),\n refresh: z.string().min(1),\n expires: z.number(),\n account_id: z.string().optional(),\n })\n .strict();\n\n// oauth first (it requires `type: 'oauth'`); a legacy `{provider?, api_key}` falls through to api.\nconst fileSchema = z.union([oauthFileSchema, apiFileSchema]);\n\n/**\n * Read the credential file. Absent ⇒ `undefined` (the normal case). Present-but-wrong is a typed error\n * naming the file: a malformed credential store must not surface as a raw parse crash. Enforces the\n * 0700 dir / 0600 file mode gates (ported verbatim — a writable dir lets an attacker swap the file for a\n * symlink to their own account).\n */\n/**\n * The 0700-dir / 0600-file mode gates (ported verbatim). The DIRECTORY matters as much as the file:\n * `mkdirSync(mode)` applies only at creation, so a pre-existing store dir keeps whatever mode it had, and a\n * writable dir lets an attacker replace the credential file with a symlink to their own 0600 file — the\n * agent then runs on THEIR account.\n */\nexport function assertSecureModes(dirPath: string, path: string): void {\n // Windows has no POSIX mode bits. `statSync().mode` there is SYNTHETIC — 0666 for any writable\n // entry, whatever the ACLs actually say — so `mode & 0o022` was non-zero for every valid store and\n // this gate refused all of them, which made the credential path unreadable on that platform\n // rather than protected. A check that cannot observe the real permission system must not report a\n // verdict about it; ACL enforcement is a separate mechanism and not one this function can fake.\n if (process.platform === \"win32\") return;\n\n const dirMode = statSync(dirPath).mode & 0o777;\n if ((dirMode & 0o022) !== 0) {\n throw new CredentialError(\n `${dirPath} is writable by other users (mode ${dirMode.toString(8)}), so the credential file ` +\n `inside it can be replaced. Fix it with: chmod 700 ${dirPath}`,\n );\n }\n const mode = statSync(path).mode & 0o777;\n if ((mode & 0o077) !== 0) {\n throw new CredentialError(\n `${path} is readable by other users (mode ${mode.toString(8)}). ` +\n `A credential file must not be. Fix it with: chmod 600 ${path}`,\n );\n }\n}\n\n/**\n * A `z.union` reports a generic \"Invalid input\" at the root, hiding WHAT is wrong. Pick the sub-schema the\n * file was CLEARLY aiming at (by its `type` discriminant) and surface that schema's specific issue.\n */\nfunction describeUnionError(parsed: unknown, err: unknown, path: string): CredentialError {\n const looksOAuth =\n typeof parsed === \"object\" &&\n parsed !== null &&\n (parsed as { type?: unknown }).type === \"oauth\";\n const specific = looksOAuth ? oauthFileSchema.safeParse(parsed) : apiFileSchema.safeParse(parsed);\n let issue: z.ZodIssue | undefined;\n if (!specific.success) {\n issue = specific.error.issues[0];\n } else if (err instanceof z.ZodError) {\n issue = err.issues[0];\n }\n return new CredentialError(\n `${path}: ${issue?.message ?? String(err)} [${issue?.path.join(\".\") || \"root\"}]`,\n );\n}\n\n/** Parse the raw file into the store union, surfacing the SPECIFIC sub-schema issue (not a generic union error). */\nfunction parseStoredFile(raw: string, path: string): StoredCredential {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // The parser's message embeds a snippet of the INPUT — up to the raw key when a user pastes the bare\n // key instead of JSON. The position is not actionable anyway, so the expected shape is more useful.\n throw new CredentialError(\n `${path} is not valid JSON. Expected: {\"provider\": \"<name>\", \"api_key\": \"...\"}`,\n );\n }\n try {\n return fileSchema.parse(parsed);\n } catch (err) {\n throw describeUnionError(parsed, err, path);\n }\n}\n\nexport function readAuthFile(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredCredential | undefined {\n const path = authFilePath(config, env);\n\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw new CredentialError(`cannot read ${path}: ${(err as Error).message}`);\n }\n\n assertSecureModes(credentialHome(config, env), path);\n return parseStoredFile(raw, path);\n}\n\n/**\n * Read the stored OAuth credential (with its refresh token), or `undefined` when the store is absent or\n * holds an api credential. The oauth engine needs the refresh token, which the resolved bearer does not\n * carry. Enforces the same 0600/0700 gates as every other read.\n */\nexport function readStoredOAuth(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredOAuthCredential | undefined {\n const stored = readAuthFile(config, env);\n return stored !== undefined && stored.type === \"oauth\" ? stored : undefined;\n}\n\n/** Narrows a writable credential to the oauth variant. */\nfunction isOAuthWrite(\n c: { provider: string; apiKey: string } | StoredOAuthCredential,\n): c is StoredOAuthCredential {\n return \"type\" in c && c.type === \"oauth\";\n}\n\n/**\n * Persist a credential atomically at mode `0600`. Ported VERBATIM (ADR D3): write to a random-named temp\n * file in the same directory with `wx` (O_EXCL), fsync, close, chmod, then `rename` (atomic on POSIX) —\n * so a crash mid-write leaves whatever was there untouched, and a pre-planted symlink cannot capture the\n * key. The api variant persists the unchanged `{provider, api_key}` (back-compat, no `type` key); the\n * oauth variant persists `{type:'oauth', provider, access, refresh, expires, account_id?}`.\n */\n/** Build the on-disk JSON payload for the credential variant, validating non-empty tokens. */\nfunction buildStorePayload(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n): Record<string, unknown> {\n if (isOAuthWrite(cred)) {\n if (cred.access.length === 0 || cred.refresh.length === 0) {\n throw new CredentialError(\n \"refusing to write an oauth credential with an empty access/refresh token\",\n );\n }\n return {\n type: \"oauth\",\n provider: cred.provider,\n access: cred.access,\n refresh: cred.refresh,\n expires: cred.expires,\n ...(cred.account_id !== undefined ? { account_id: cred.account_id } : {}),\n };\n }\n if (typeof cred.apiKey !== \"string\" || cred.apiKey.length === 0) {\n throw new CredentialError(\"refusing to write an empty API key\");\n }\n return { provider: cred.provider, api_key: cred.apiKey };\n}\n\nexport function writeCredential(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const payload = buildStorePayload(cred);\n\n const dir = credentialHome(config, env);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n chmodSync(dir, 0o700); // unconditional: mkdirSync's mode applies only at creation\n\n const path = authFilePath(config, env);\n // RANDOM name + `wx` (O_EXCL): a predictable temp name with a plain write follows a pre-planted SYMLINK,\n // landing the key in an attacker's file while reporting success. O_EXCL refuses any pre-existing file or\n // link; the random suffix also removes the pid collision two containers sharing a bind-mounted home make.\n const tmp = `${path}.tmp-${randomBytes(8).toString(\"hex\")}`;\n try {\n const fd = openSync(tmp, \"wx\", 0o600);\n try {\n writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\\n`);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n chmodSync(tmp, 0o600); // explicit: the mode argument is subject to umask\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // the temp file may not exist; its absence is not a failure of the write\n }\n throw new CredentialError(`cannot write ${path}: ${(err as Error).message}`);\n }\n return path;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/auth/oauth-transaction-store.ts"],"names":[],"mappings":"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","file":"chunk-7W7ZWMLQ.js","sourcesContent":["/**\n * @theokit/sdk/server/auth — encrypted OAuth transaction cookie store\n *\n * Per ADR D5 — cookie-state pattern (no Redis/db dependency in core).\n *\n * Stores OAuthTransaction (state + pkceVerifier + returnTo + expiry) in a\n * single signed+encrypted HttpOnly cookie. Stateless, works in edge/serverless.\n *\n * Cookie name: `__Host-theo_oauth_tx` (T5.3 — RFC 6265bis prefix)\n * Lifetime: 10 minutes (per D5 invariant)\n * Encryption: AES-256-GCM via Node's webcrypto subtle API\n *\n * Note: this is a minimal in-package implementation. Production deployments\n * may prefer using `theokit/server/auth/crypto`'s encrypt/decrypt helpers\n * via the SessionManager's existing secret rotation chain. For T1.2 we keep\n * it self-contained to avoid cross-package peer-dep complexity; T2+ may\n * refactor to share SessionManager's encrypt path.\n */\n\nimport { Buffer } from \"node:buffer\";\nimport { webcrypto } from \"node:crypto\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { OAuthTransaction } from \"./types.js\";\n\n// T5.3 — `__Host-` prefix per RFC 6265bis. Browsers enforce that any\n// cookie with this prefix MUST be set with `Secure`, MUST NOT carry a\n// `Domain` attribute, and MUST have `Path=/`. This blocks the\n// subdomain-fixation vector where a malicious page on\n// `evil.example.com` could plant a same-name cookie that the parent\n// app at `example.com` would happily decrypt.\nconst COOKIE_NAME = \"__Host-theo_oauth_tx\";\nconst TX_LIFETIME_MS = 10 * 60 * 1000; // 10 minutes per D5\n\n// T5.1 — HKDF info string fixed per plan; bump version (v1 → v2) only when\n// the AES-GCM derivation contract itself changes (which would invalidate\n// all in-flight cookies).\nconst HKDF_INFO = \"theokit:oauth-tx-v1\";\n\n/**\n * T5.1 — Derive a 32-byte AES-256-GCM key from `secret` via HKDF-SHA256\n * (RFC 5869). Replaces the pre-T5.1 zero-padding scheme that was NOT a\n * KDF and produced near-identical keys for near-identical secrets.\n *\n * Contract:\n * - `secret` MUST be ≥ 32 bytes (256 bits) — throws otherwise.\n * - Salt is sourced from `THEOKIT_OAUTH_TX_SALT` env (UTF-8 string);\n * when unset, RFC 5869's zero-string fallback is used and operators\n * accept the default cross-app collision risk.\n * - `info` is fixed at \"theokit:oauth-tx-v1\" so v1 cookies decrypt\n * forever even if a future v2 derivation ships alongside.\n *\n * Throws `AuthSecretTooShortError` (typed) when secret < 32 bytes.\n *\n * @internal\n */\nasync function deriveKey(secret: string): Promise<webcrypto.CryptoKey> {\n const secretBytes = new TextEncoder().encode(secret);\n if (secretBytes.byteLength < 32) {\n throw new AuthSecretTooShortError(secretBytes.byteLength);\n }\n const saltRaw = process.env.THEOKIT_OAUTH_TX_SALT ?? \"\";\n const salt = new TextEncoder().encode(saltRaw);\n // Import the raw secret as HKDF input keying material.\n const ikm = await webcrypto.subtle.importKey(\"raw\", secretBytes, \"HKDF\", false, [\"deriveBits\"]);\n // Derive 256 bits via HKDF-SHA256.\n const derived = await webcrypto.subtle.deriveBits(\n { name: \"HKDF\", hash: \"SHA-256\", salt, info: new TextEncoder().encode(HKDF_INFO) },\n ikm,\n 256,\n );\n // Wrap the derived bits as an AES-GCM key.\n return webcrypto.subtle.importKey(\"raw\", derived, { name: \"AES-GCM\" }, true, [\n \"encrypt\",\n \"decrypt\",\n ]);\n}\n\n/**\n * T5.1 — Typed error thrown when an OAuth tx-cookie secret has < 32\n * bytes of entropy. Surfaces the actual byte length so operators can\n * diagnose mis-configured env vars without leaking the secret itself.\n *\n * @public\n */\nexport class AuthSecretTooShortError extends Error {\n override readonly name = \"AuthSecretTooShortError\";\n constructor(actualBytes: number) {\n super(\n `OAuth transaction secret must be at least 32 bytes (got ${actualBytes}). ` +\n \"Generate a fresh value with: openssl rand -base64 33\",\n );\n }\n}\n\n/**\n * T5.1 — Test seam for the HKDF derivation. NOT included in the public\n * barrel — exposed only so unit tests can assert avalanche / determinism\n * properties without round-tripping through encodeTransaction.\n *\n * @internal\n */\nexport async function __TESTING__deriveKey(secret: string): Promise<webcrypto.CryptoKey> {\n return deriveKey(secret);\n}\n\nexport async function encodeTransaction(tx: OAuthTransaction, secret: string): Promise<string> {\n const key = await deriveKey(secret);\n const iv = webcrypto.getRandomValues(new Uint8Array(12));\n const plaintext = new TextEncoder().encode(JSON.stringify(tx));\n const ciphertext = await webcrypto.subtle.encrypt({ name: \"AES-GCM\", iv }, key, plaintext);\n const combined = new Uint8Array(iv.length + ciphertext.byteLength);\n combined.set(iv, 0);\n combined.set(new Uint8Array(ciphertext), iv.length);\n return Buffer.from(combined).toString(\"base64url\");\n}\n\nasync function decodeTransaction(\n encoded: string,\n secret: string,\n): Promise<OAuthTransaction | null> {\n try {\n const key = await deriveKey(secret);\n const combined = Buffer.from(encoded, \"base64url\");\n const iv = combined.slice(0, 12);\n const ciphertext = combined.slice(12);\n const plaintext = await webcrypto.subtle.decrypt({ name: \"AES-GCM\", iv }, key, ciphertext);\n const tx = JSON.parse(new TextDecoder().decode(plaintext)) as OAuthTransaction;\n return tx;\n } catch {\n return null;\n }\n}\n\nfunction getCookie(req: IncomingMessage, name: string): string | null {\n const header = req.headers.cookie;\n if (!header) return null;\n for (const part of header.split(\";\")) {\n const [k, ...v] = part.trim().split(\"=\");\n if (k === name) return v.join(\"=\");\n }\n return null;\n}\n\nfunction setCookie(res: ServerResponse, name: string, value: string): void {\n const existing = res.getHeader(\"Set-Cookie\");\n const cookie = `${name}=${value}; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=${TX_LIFETIME_MS / 1000}`;\n if (Array.isArray(existing)) {\n res.setHeader(\"Set-Cookie\", [...existing, cookie]);\n } else if (typeof existing === \"string\") {\n res.setHeader(\"Set-Cookie\", [existing, cookie]);\n } else {\n res.setHeader(\"Set-Cookie\", cookie);\n }\n}\n\n/**\n * T5.3 — Clear the tx cookie deterministically. Emits exactly ONE\n * Set-Cookie line for `name` (filtering any prior occurrences of the\n * same name from a pre-existing Set-Cookie header) with:\n *\n * - empty value\n * - `Max-Age=0` (modern browsers — immediate delete)\n * - `Expires=Thu, 01 Jan 1970 00:00:00 GMT` (legacy fallback)\n * - `HttpOnly`, `Secure`, `SameSite=Lax`, `Path=/` — preserved so the\n * `__Host-` prefix contract is honored even on the clear path\n *\n * Pre-T5.3 this function called setCookie() with an empty value (which\n * still carried `Max-Age=600`) AND then issued a second explicit\n * `Max-Age=0` clear into the Set-Cookie header. The double-write\n * produced a duplicate response header that some legacy clients did\n * not handle deterministically.\n */\nfunction clearCookie(res: ServerResponse, name: string): void {\n const clear = `${name}=; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT`;\n const existing = res.getHeader(\"Set-Cookie\");\n const preserved = Array.isArray(existing)\n ? existing.filter((c) => !c.startsWith(`${name}=`))\n : typeof existing === \"string\" && !existing.startsWith(`${name}=`)\n ? [existing]\n : [];\n res.setHeader(\"Set-Cookie\", [...preserved, clear]);\n}\n\nasync function _setTransaction(\n res: ServerResponse,\n tx: OAuthTransaction,\n secret: string,\n): Promise<void> {\n const encoded = await encodeTransaction(tx, secret);\n setCookie(res, COOKIE_NAME, encoded);\n}\n// Reserved internal helper — not currently invoked (drop-in for future T2.x refactor that consolidates SessionManager + tx-store crypto paths). Underscore prefix per biome noUnusedVariables documented escape.\nvoid _setTransaction;\n\nexport async function getTransaction(\n req: IncomingMessage,\n secret: string,\n): Promise<OAuthTransaction | null> {\n const raw = getCookie(req, COOKIE_NAME);\n if (!raw) return null;\n const tx = await decodeTransaction(raw, secret);\n if (!tx) return null;\n // Check expiry\n if (tx.expiresAt < Date.now()) return null;\n return tx;\n}\n\nexport function clearTransaction(res: ServerResponse): void {\n clearCookie(res, COOKIE_NAME);\n}\n\nexport function newTransaction(opts: {\n state: string;\n pkceVerifier?: string;\n returnTo?: string;\n}): OAuthTransaction {\n const now = Date.now();\n return {\n state: opts.state,\n pkceVerifier: opts.pkceVerifier,\n returnTo: opts.returnTo,\n createdAt: now,\n expiresAt: now + TX_LIFETIME_MS,\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/runtime/compression/compression-helpers.ts","../src/compaction.ts"],"names":["TheokitAgentError","diag","redactSecrets"],"mappings":"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","file":"chunk-ADLLFY3H.cjs","sourcesContent":["/**\n * Compression helpers (T2.3, ADR D92).\n *\n * Scaffold for future compression LLM integration:\n * - `selectCompressionWindow` — splits messages into compress/preserve halves\n * - `assertCompressionReduced` — 10% reduction floor to detect \"compression placebo\"\n *\n * The compression LLM call itself is out of scope for this plan (requires\n * an auxiliary-model ADR). These helpers are used by `Agent.send` when a\n * future iteration adds compression.\n *\n * @internal\n */\n\nexport interface CompressionWindow<M> {\n toCompress: M[];\n toPreserve: M[];\n}\n\n/**\n * Split `messages` into the half to compress (older) and the half to\n * preserve verbatim (recent). When `messages.length <= preserveLast`,\n * everything is preserved.\n *\n * @internal\n */\nexport function selectCompressionWindow<M>(\n messages: readonly M[],\n preserveLast = 6,\n): CompressionWindow<M> {\n if (messages.length <= preserveLast) {\n return { toCompress: [], toPreserve: [...messages] };\n }\n return {\n toCompress: messages.slice(0, -preserveLast),\n toPreserve: messages.slice(-preserveLast),\n };\n}\n\nexport interface CompressionCheck {\n reduced: boolean;\n reductionPct: number;\n reason?: string;\n}\n\n/**\n * Check that compression actually reduced token count by at least `minPct`\n * (default 10%). Returns `{ reduced: false }` for spirals-in-formation\n * (compression LLM outputs that grow or barely shrink).\n *\n * @internal\n */\nexport function assertCompressionReduced(\n before: number,\n after: number,\n minPct = 10,\n): CompressionCheck {\n if (before <= 0) {\n return { reduced: false, reductionPct: 0, reason: \"before count was zero\" };\n }\n const reductionPct = ((before - after) / before) * 100;\n if (reductionPct >= minPct) {\n return { reduced: true, reductionPct };\n }\n return {\n reduced: false,\n reductionPct,\n reason: `compression reduced ${reductionPct.toFixed(1)}% (< ${minPct}% min). Spiral likely.`,\n };\n}\n","/**\n * Public compaction / context-management helpers (M2-1, extended V3-3).\n *\n * Promotes the SDK's compaction capability to a public surface so consumers can\n * compact a transcript, mark/filter conversation checkpoints, and detect\n * context-overflow — without reaching into `internal/`.\n *\n * Two recent-window modes (V3-3):\n * - `keepRecent` (turn-count, default) — keeps the last N turns verbatim and\n * always preserves leading system PROMPTS; reuses the internal\n * `selectCompressionWindow` (no second algorithm).\n * - `keepTokens` (token-budget) — keeps the trailing turns whose accumulated\n * `estimateTokens` fits the budget (theocode `splitTranscript` semantics). In\n * this mode leading system prompts are NOT special-cased (D6).\n *\n * Summarization is delegated to a caller-supplied callback (which receives the\n * older window + the summary template). With `failSafe`, a thrown summarizer\n * returns the ORIGINAL transcript + a structured warn (compaction is an\n * optimization, never a cause of data loss); without it, the error propagates.\n *\n * Public from the `@theokit/sdk/compaction` sub-path.\n */\n\nimport { TheokitAgentError } from \"./errors.js\";\nimport { diag } from \"./internal/diagnostics.js\";\nimport { selectCompressionWindow } from \"./internal/runtime/compression/compression-helpers.js\";\nimport { redactSecrets } from \"./internal/security/redact.js\";\n\n/**\n * Minimal message shape for compaction/compression input. THE canonical public origin (leaf type —\n * rollup-plugin-dts cannot re-export types from internal modules into entry bundles; M42 lesson).\n *\n * @public\n */\nexport interface CompressibleMessage {\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n}\n\n/**\n * Sentinel prefix marking a conversation checkpoint turn. A visible, structured,\n * prose-unlikely token (no invisible/control bytes — safe to persist and to read\n * in source). Only {@link buildCheckpoint} should produce content beginning with it.\n */\nexport const CHECKPOINT_MARKER = \"[[theokit:checkpoint]] \";\n\n/**\n * The 7-section summary template handed to the `summarize` callback (theocode\n * parity shape). Every header is always present so the summarizer cannot silently\n * drop a category; the model is told to preserve file paths, commands, and error\n * text verbatim. Override per-call via {@link CompactTranscriptOptions.summaryTemplate}.\n */\nexport const SUMMARY_TEMPLATE = `Summarize the conversation so far into these sections (keep every header even if empty):\n\n## Goal\nWhat the user is ultimately trying to achieve.\n\n## Constraints\nHard requirements, conventions, and rules stated.\n\n## Progress\nWhat has been done so far.\n\n## Decisions\nChoices made and their rationale.\n\n## Next\nThe immediate next steps.\n\n## Critical\nAnything that MUST NOT be forgotten (preserve verbatim: error messages, exact values).\n\n## Files\nFile paths touched or referenced (verbatim).`;\n\n/** Reject an empty marker — it would match every turn via `startsWith(\"\")` (EC-3). */\nfunction assertMarker(marker: string): void {\n if (marker === \"\") {\n throw new TheokitAgentError(\"compaction marker must be non-empty\", {\n code: \"invalid_argument\",\n });\n }\n}\n\n/** True for a real system prompt — a `system` turn that is NOT a checkpoint marker. */\nfunction isSystemPrompt(message: CompressibleMessage, marker: string): boolean {\n return message.role === \"system\" && !message.content.startsWith(marker);\n}\n\n/** Carried split: leading system prompts (preserved), the older window, the verbatim tail. */\ninterface TranscriptSplit {\n systemPrompts: CompressibleMessage[];\n head: CompressibleMessage[];\n recent: CompressibleMessage[];\n}\n\n/**\n * Token-budget split (theocode `splitTranscript`): walk from the END accumulating\n * `estimateTokens` until `keepTokens` is exceeded; everything older is the head.\n * Always keeps ≥ 1 recent turn. No system-prompt special-casing (D6).\n */\nfunction selectByTokenBudget(\n messages: CompressibleMessage[],\n keepTokens: number,\n): { head: CompressibleMessage[]; recent: CompressibleMessage[] } {\n let acc = 0;\n let splitIndex = messages.length;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n acc += estimateTokens(messages[i]?.content ?? \"\");\n if (acc > keepTokens && i < messages.length - 1) {\n splitIndex = i + 1;\n break;\n }\n splitIndex = i;\n }\n return { head: messages.slice(0, splitIndex), recent: messages.slice(splitIndex) };\n}\n\n/** Turn-count split (M2): preserve leading system prompts; window the rest by `keepRecent`. */\nfunction splitByRecent(\n messages: CompressibleMessage[],\n keepRecent: number,\n marker: string,\n): TranscriptSplit {\n const systemPrompts = messages.filter((m) => isSystemPrompt(m, marker));\n const rest = messages.filter((m) => !isSystemPrompt(m, marker));\n const { toCompress, toPreserve } = selectCompressionWindow(rest, keepRecent);\n return { systemPrompts, head: toCompress, recent: toPreserve };\n}\n\n/** Options for {@link compactTranscript}. */\nexport interface CompactTranscriptOptions {\n /** Trailing turns preserved verbatim by COUNT (default 6). Ignored when `keepTokens` is set. */\n keepRecent?: number;\n /**\n * Trailing turns preserved verbatim by TOKEN BUDGET (theocode mode). When set,\n * takes precedence over `keepRecent` and disables system-prompt preservation (D6).\n */\n keepTokens?: number;\n /** Checkpoint marker (default {@link CHECKPOINT_MARKER}). Must be non-empty. */\n marker?: string;\n /** Summary template passed to `summarize` (default {@link SUMMARY_TEMPLATE}). */\n summaryTemplate?: string;\n /** Summarize the older window into one turn; if omitted, the older window is dropped. */\n summarize?: (older: CompressibleMessage[], template: string) => Promise<CompressibleMessage>;\n /**\n * When true, a thrown `summarize` returns the ORIGINAL transcript + a structured\n * warn (compaction never loses data). Default false: the error propagates.\n */\n failSafe?: boolean;\n}\n\n/** Sentinel returned by {@link runSummarize} when fail-safe swallowed a throw. */\nconst FAILSAFE_ABORT = Symbol(\"failsafe-abort\");\n\n/** Run the summarizer; on throw, either propagate or (fail-safe) warn + signal abort. */\nasync function runSummarize(\n summarize: NonNullable<CompactTranscriptOptions[\"summarize\"]>,\n head: CompressibleMessage[],\n template: string,\n failSafe: boolean,\n): Promise<CompressibleMessage | typeof FAILSAFE_ABORT> {\n try {\n return await summarize(head, template);\n } catch (err) {\n if (!failSafe) throw err;\n // Unbreakable Rule 8 — never fail silently. The breadcrumb points at the root\n // cause when a summarizer fails every turn and context grows unchecked. The\n // summarizer is caller-supplied, so its error text is routed through\n // `redactSecrets` (ADR D68 — no unredacted output sink in src/).\n // theokit#147 — through the interceptable channel. A summarizer failing every turn is exactly\n // the breadcrumb a TUI host wants in its own panel, not smeared across its alternate screen.\n diag(\n `[compaction] summarizer failed — proceeding uncompacted: ${redactSecrets(err instanceof Error ? err.message : String(err))}\\n`,\n );\n return FAILSAFE_ABORT;\n }\n}\n\n/**\n * Compact a transcript. In `keepRecent` mode (default) the last `keepRecent` turns\n * are kept verbatim and leading system PROMPTS preserved; in `keepTokens` mode the\n * trailing turns within the token budget are kept (no system special-casing, D6).\n * The older window is summarized (via `summarize`, receiving the template) or\n * dropped. Never mutates the input.\n */\nexport async function compactTranscript(\n messages: CompressibleMessage[],\n options: CompactTranscriptOptions = {},\n): Promise<CompressibleMessage[]> {\n const marker = options.marker ?? CHECKPOINT_MARKER;\n assertMarker(marker);\n const split =\n options.keepTokens != null\n ? { systemPrompts: [], ...selectByTokenBudget(messages, options.keepTokens) }\n : splitByRecent(messages, options.keepRecent ?? 6, marker);\n if (split.head.length === 0) {\n return [...messages];\n }\n if (!options.summarize) {\n return [...split.systemPrompts, ...split.recent];\n }\n const template = options.summaryTemplate ?? SUMMARY_TEMPLATE;\n const summary = await runSummarize(\n options.summarize,\n split.head,\n template,\n options.failSafe ?? false,\n );\n if (summary === FAILSAFE_ABORT) {\n return [...messages];\n }\n return [...split.systemPrompts, summary, ...split.recent];\n}\n\n/**\n * Build a checkpoint marker turn (a `system` turn whose content starts with\n * `marker`, default {@link CHECKPOINT_MARKER}). `marker` must be non-empty.\n */\nexport function buildCheckpoint(\n label?: string,\n marker: string = CHECKPOINT_MARKER,\n): CompressibleMessage {\n assertMarker(marker);\n return { role: \"system\", content: marker + (label ?? \"\") };\n}\n\n/** Options for {@link filterFromLatestCheckpoint}. */\nexport interface FilterCheckpointOptions {\n /** Marker to scan for (default {@link CHECKPOINT_MARKER}). */\n marker?: string;\n /**\n * `'after'` (default, M2) returns turns AFTER the latest marker (exclusive);\n * `'from'` (theocode) returns turns FROM the latest marker (inclusive).\n */\n include?: \"after\" | \"from\";\n}\n\n/**\n * Return the turns relative to the most recent checkpoint marker (all turns if\n * none). `include: 'after'` (default) excludes the checkpoint; `'from'` includes\n * it (the summary stands in for the pruned head). Never mutates the input.\n */\nexport function filterFromLatestCheckpoint(\n messages: CompressibleMessage[],\n options: FilterCheckpointOptions = {},\n): CompressibleMessage[] {\n const marker = options.marker ?? CHECKPOINT_MARKER;\n const offset = options.include === \"from\" ? 0 : 1;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n if (messages[i]?.content.startsWith(marker)) {\n return messages.slice(i + offset);\n }\n }\n return [...messages];\n}\n\n/**\n * True iff `err` is a {@link TheokitAgentError} (or subclass) reporting a\n * context-window-exceeded condition (the typed `context_too_long` code). Reads\n * both `code` (set by provider mappers) and `metadata.code` (the preferred field)\n * — never a brittle message regex.\n */\nexport function isContextOverflowError(err: unknown): boolean {\n return (\n err instanceof TheokitAgentError &&\n (err.code === \"context_too_long\" || err.metadata?.code === \"context_too_long\")\n );\n}\n\n/**\n * M77 — the margin is outside `(0, 1]`. Typed, because a margin > 1 would GROW the assumed window,\n * which is the unsafe direction: `shouldCompact` is monotonically decreasing in `contextWindow`, so\n * overestimating it makes the trigger fire too late and the context overflow.\n */\nexport class ContextWindowMarginError extends TheokitAgentError {\n constructor(readonly margin: number) {\n super(\n `context-window margin must be in (0, 1], got ${String(margin)}. ` +\n `A margin above 1 grows the assumed window and delays compaction past the real limit.`,\n { code: \"invalid_context_window_margin\" },\n );\n }\n}\n\n/**\n * M77 — default safety margin on the context window.\n *\n * `0.95` is not a guess: it is the single reference's value. Codex ships\n * `effective_context_window_percent: 95` (`models-manager/src/model_info.rs:158`) and never budgets\n * against 100% of a window. Being MULTIPLICATIVE, it stays conservative at any window size, which a\n * fixed subtraction would not.\n */\nexport const CONTEXT_WINDOW_MARGIN = 0.95;\n\n/**\n * M77 — the floor used ONLY when neither the catalog nor the caller knows the window.\n *\n * Honest about its own weakness. This number has **one** source (the M77 milestone text); the search\n * for a second one failed, because the reference has no fallback at all — Codex returns `Option` and\n * its callers early-return (`core/src/session/turn_context.rs:213`, `core/src/compact_remote.rs:374`).\n *\n * It is conservative only UPWARD. For a model whose real window is larger, budgeting against 128k\n * compacts early — wasteful but safe. For a model whose real window is SMALLER (an 8k or 32k model\n * absent from the catalog), it compacts too late and the context still overflows. That residual risk\n * is real and is why {@link resolveEffectiveContextWindow} never lets this floor compete with a known\n * catalog value, and why the `compaction_fallback` event exists: a surface can show that the budget is\n * a guess instead of the user finding out when the provider rejects the request.\n */\nexport const CONTEXT_WINDOW_FLOOR = 128_000;\n\n/** Where the effective window came from — carried into the M77 structured event. */\nexport type ContextWindowSource = \"override\" | \"catalog\" | \"fallback\";\n\n/** Input to {@link resolveEffectiveContextWindow}. */\nexport interface EffectiveContextWindowInput {\n /** Caller-supplied window, in tokens. Clamped by `catalog` when both are present. */\n readonly override?: number | undefined;\n /** The model's window from the catalog, in tokens. Absent when the model is unknown. */\n readonly catalog?: number | undefined;\n /** Safety margin in `(0, 1]`. Codex uses 0.95 (`model_info.rs:158`). */\n readonly margin: number;\n /** Conservative floor used ONLY when neither `override` nor `catalog` is available. */\n readonly floor?: number | undefined;\n}\n\n/** Result of {@link resolveEffectiveContextWindow}. */\nexport interface EffectiveContextWindow {\n /** The window to budget against, after clamp and margin. */\n readonly window: number;\n /** Which input won — `\"fallback\"` means neither override nor catalog was available. */\n readonly source: ContextWindowSource;\n /** `true` when an `override` above the catalog window was clamped down to it. */\n readonly clamped: boolean;\n}\n\n/**\n * Resolve the window to budget against — the fail-SAFE replacement for reading the catalog directly.\n *\n * Today `post-run-lifecycle.ts` reads `getCatalogModelInfo(model)?.limit?.context` and, when that is\n * `undefined`, auto-compaction simply never fires. That is fail-OPEN: the context grows until the\n * provider rejects the request. (The comment there calls it \"fail-safe\" — M77 corrects it.)\n *\n * Three techniques, two of them borrowed from the single reference:\n *\n * 1. **Override, CLAMPED by the catalog** — Codex `models-manager/src/model_info.rs:26-31` lets\n * config override the window but limits it with `context_window.min(max_context_window)`.\n * Without the clamp, declaring 999k on a 200k model reopens the overflow through another door.\n * 2. **Multiplicative margin** — Codex `model_info.rs:158` (`effective_context_window_percent: 95`)\n * never budgets against 100% of the window. Being multiplicative, it is conservative for ANY\n * window size.\n * 3. **Floor, only when nothing is known** — deliberately NOT a blanket default. A fixed floor is\n * conservative only upward: applied to a small model it would inflate the assumed window and\n * reproduce the very fail-open this function exists to close. Hence the floor never competes\n * with a known catalog value.\n *\n * Pure — no catalog lookup, no I/O. The caller supplies the numbers, mirroring `shouldCompact`.\n */\n/**\n * Absolute cap on a declared context window, applied when no catalog entry exists to compare against.\n *\n * **10M**, not 2M. The first version used 2M on the rationale that it sat \"comfortably above the\n * largest published window\" — adversarial review measured the opposite: Llama 4 Scout publishes\n * **10M**, and it arrives precisely via OpenRouter, the provider **without** a catalog, which is the\n * case this cap exists to cover. The user would have silently lost 80% of the declared window.\n *\n * The cap still serves what motivates it — one extra zero on 400k gives 4M, which passes; two zeros\n * give 40M, which does not. A limit that rejects legitimate configuration is worse than no limit,\n * because failing OPEN is visible when it happens and silently losing 80% is not.\n */\nexport const ABSOLUTE_CONTEXT_WINDOW_CAP = 10_000_000;\n\nexport function resolveEffectiveContextWindow(\n input: EffectiveContextWindowInput,\n): EffectiveContextWindow {\n if (!(input.margin > 0) || input.margin > 1) {\n throw new ContextWindowMarginError(input.margin);\n }\n\n const withMargin = (raw: number): number => Math.floor(raw * input.margin);\n\n if (input.override !== undefined) {\n // The catalog is the preferred cap; without it the ABSOLUTE cap applies.\n //\n // M95 (adversarial review of M94) — the previous version clamped **only** when a catalog entry\n // existed, and the whole reason the `contextWindow` key exists is the model that has NO entry\n // (OpenRouter has zero). So the clamp was missing in exactly the case that justifies the\n // feature, while the documentation — including an already-published CHANGELOG — stated without\n // qualification that \"declaring 10M does not blow past the provider\".\n //\n // The concrete scenario is one extra zero: `context_window = 4000000`. The only guard was a\n // `.positive().int()`, which sets no upper bound. The agent would never compact until the\n // provider refused the turn — the silent fail-OPEN that M77 exists to prevent.\n const cap = input.catalog ?? ABSOLUTE_CONTEXT_WINDOW_CAP;\n const clamped = input.override > cap;\n return { window: withMargin(clamped ? cap : input.override), source: \"override\", clamped };\n }\n\n if (input.catalog !== undefined) {\n return { window: withMargin(input.catalog), source: \"catalog\", clamped: false };\n }\n\n return { window: withMargin(input.floor ?? 0), source: \"fallback\", clamped: false };\n}\n\n/** Input to {@link shouldCompact}: an estimate, the model's window, and reserved headroom. */\nexport interface ShouldCompactInput {\n /** Estimated token count of the next request (e.g. from {@link estimateTokens}). */\n readonly estimated: number;\n /** The model's total context window, in tokens. */\n readonly contextWindow: number;\n /** Tokens to reserve as headroom (output + safety margin). */\n readonly buffer: number;\n /**\n * Tokens reserved for the model's response generation, SEPARATE from `buffer`.\n * Default 0 — omitting it preserves the legacy\n * `estimated >= contextWindow - buffer` result.\n */\n readonly maxOutput?: number;\n}\n\n/**\n * Tokenizer-free token estimate via the conventional ~4-chars-per-token\n * heuristic: `ceil(text.length / 4)`. `\"\"` → 0; any non-empty text → ≥ 1.\n * A cheap PRE-CALL gate for {@link shouldCompact} — NOT exact tokenization\n * (a consumer needing exactness supplies their own tokenizer). Uses UTF-16\n * `.length` (code units), so multibyte text is approximate.\n */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n/**\n * Decide BEFORE sending whether to compact: `true` when the `estimated` token\n * count leaves less than `buffer` headroom in the `contextWindow`\n * (`estimated >= contextWindow - buffer`). A `buffer >= contextWindow`\n * (non-positive threshold) always returns `true`. Pure — the caller supplies\n * the window (e.g. from `resolveModelCapabilities`), keeping this decoupled\n * from the per-model catalog.\n */\nexport function shouldCompact(input: ShouldCompactInput): boolean {\n return input.estimated >= input.contextWindow - input.buffer - (input.maxOutput ?? 0);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/runtime/concurrency/subagent-credentials.ts","../src/a2a/subagent.ts"],"names":["AsyncLocalStorage","getAgentFacade","z"],"mappings":"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","file":"chunk-B4YA6BRS.cjs","sourcesContent":["/**\n * theokit#148 — the parent's credentials, delivered through the CALL, not through the tool object.\n *\n * ## The class of bug this replaces\n *\n * Credential inheritance used to ride a property installed on the subagent tool object — first a\n * unique `Symbol()`, then `Symbol.for` after #143. Both are the same shape of contract: \"this\n * object will reach the dispatcher with an extra property intact\". Nothing enforces that, and it\n * broke twice for two different reasons:\n *\n * - **Module duplication** (#142/#143): `tsup splitting: false` inlined a separate copy of the\n * module into each public entry, so the two copies disagreed on a unique `Symbol()` key. Fixed at\n * the build level by M78's `splitting: true`, but the fragile contract remained.\n * - **Object normalization** (#148): any layer that rebuilds the tool from its known fields drops\n * the property. `@theokit/agents`' `toCompiledTool` does exactly that, and had to add an explicit\n * `Object.getOwnPropertySymbols` copy loop to compensate — a band-aid the SDK's contract forced\n * onto a consumer. A named field would have been dropped by the same four-field rebuild, which is\n * why \"make it a typed field\" alone does not close this.\n *\n * ## Why the async scope closes it\n *\n * What survives a rebuild is not the object — it is the CALL. A normalizing wrapper builds a new\n * object but still invokes the original handler, inside the parent run's async context. So\n * credentials published on that context reach the handler regardless of what the tool object looks\n * like by then. There is no property left for a layer to drop.\n *\n * It also fixes a defect the per-object slot could not: credentials were stored per tool INSTANCE,\n * so one subagent tool shared by two agents got last-writer-wins. The scope is per run.\n *\n * Nothing is exposed to third-party tool code: the store is module-private, credentials never touch\n * a handler's `ctx`, and `currentInheritedSubAgentCredentials` is `@internal`.\n *\n * @internal\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { ModelSelection } from \"../../../types/agent-prims.js\";\nimport type { Plugin } from \"../../plugins/types.js\";\n\n/**\n * Credentials a parent agent hands down to its subagent tools so the child inherits the parent's\n * auth (and, absent an explicit `spec.model`, its model).\n *\n * Declared here rather than in `a2a/subagent.ts` so the delivery mechanism owns the payload shape\n * and the dependency runs one way (`a2a/subagent` -> this module). `a2a/subagent.ts` briefly\n * re-exported it \"for back-compat\"; knip proved there was no back-compat surface to preserve — the\n * type was never in the public barrel nor the exports map — so the re-export was deleted.\n *\n * @internal\n */\nexport interface InheritedCredentials {\n readonly apiKey?: string;\n readonly model?: ModelSelection;\n /**\n * The parent's shell-sandbox posture (`local.sandboxOptions.enabled`), handed down so a delegated\n * child of a sandboxed parent stays sandboxed unless its role explicitly opts out. Without this a\n * child ran unsandboxed whenever its role omitted `sandbox` — a default-open the sandbox wiring\n * exists to prevent.\n */\n readonly sandbox?: boolean;\n /**\n * #55 — the parent's code-registered plugins (e.g. a `PermissionPlugin`) handed down so the child\n * runs under the SAME policy. Without this, a delegated child's inner tool calls escape the\n * parent's argument-level permission gate. First-party delegation path only — never exposed to\n * third-party tool `ctx`.\n */\n readonly plugins?: readonly Plugin[];\n}\n\nconst credentialsStore = new AsyncLocalStorage<InheritedCredentials>();\n\n/**\n * Run `fn` with `credentials` published as the delegation credentials of the current run.\n *\n * Nested scopes shadow the outer one and the outer is restored on return, so a delegated child that\n * itself delegates hands down ITS credentials, not its parent's.\n *\n * @internal\n */\nexport async function withInheritedSubAgentCredentials<T>(\n credentials: InheritedCredentials,\n fn: () => Promise<T>,\n): Promise<T> {\n return credentialsStore.run(credentials, fn);\n}\n\n/**\n * The delegation credentials of the current run, or `undefined` outside a run scope.\n *\n * `undefined` is deliberately NOT a fallback to some previous run's value: a subagent dispatched\n * with no parent context must create its child without an inherited key rather than reuse a\n * credential that belonged to someone else.\n *\n * @internal\n */\nexport function currentInheritedSubAgentCredentials(): InheritedCredentials | undefined {\n return credentialsStore.getStore();\n}\n","/**\n * Subagent delegation — declarative child agent invocable as a tool.\n *\n * Per ADR D2: `defineSubAgent(spec)` returns a `CustomTool` that, when\n * invoked by the LLM, creates a child agent and sends the input as a\n * message. EC-2: delegation depth tracked to prevent infinite recursion.\n *\n * SE10 — the handler forwards the parent run's `AbortSignal` to the child.\n * SE11 — optional `onDelegationStart` / `onDelegationComplete` lifecycle hooks\n * let the caller reject, rewrite, observe, or annotate a delegation.\n *\n * @public\n */\n\nimport { z } from \"zod\";\nimport {\n currentInheritedSubAgentCredentials,\n type InheritedCredentials,\n} from \"../internal/runtime/concurrency/subagent-credentials.js\";\nimport { getAgentFacade } from \"../internal/runtime/registry/agent-factory-registry.js\";\nimport type {\n AgentDefinition,\n AgentOptions,\n CustomTool,\n ToolContextMessage,\n} from \"../types/agent.js\";\nimport type { ModelSelection } from \"../types/agent-prims.js\";\nimport type { Run } from \"../types/run.js\";\n\n/** Arguments passed to {@link SubAgentSpec.messageFilter} (SE12). */\nexport interface MessageFilterArgs {\n /** The supervisor transcript (read-only text projection) available to this delegation. */\n messages: readonly ToolContextMessage[];\n /** The prompt about to be delegated (after any `onDelegationStart` rewrite). */\n input: string;\n /** The subagent's name. */\n name: string;\n}\n\n/** Context passed to {@link SubAgentSpec.onDelegationStart} before the child runs. */\nexport interface DelegationStartContext {\n input: string;\n name: string;\n /**\n * SE15 — 1-based count of times THIS subagent tool has been invoked (a\n * per-`defineSubAgent`-instance counter). Incremented before this hook runs;\n * a rejected delegation still counts. Enables reject-after-N patterns.\n */\n iteration: number;\n}\n\n/**\n * Decision returned from {@link SubAgentSpec.onDelegationStart}. Discriminated on\n * `proceed` so a rejection (`proceed: false` + `rejectionReason`) and an approval\n * (`modifiedInput`) cannot be mixed into one nonsensical object.\n */\nexport type DelegationStartDecision =\n | { proceed: false; rejectionReason?: string }\n | {\n proceed?: true;\n modifiedInput?: string;\n /** SE13 — cap the child's iteration count (forwarded as `SendOptions.maxIterations`). */\n modifiedMaxSteps?: number;\n };\n\n/** Context passed to {@link SubAgentSpec.onDelegationComplete} after the child settles. */\nexport interface DelegationCompleteContext {\n input: string;\n name: string;\n /** The child's text result (present on success). */\n result?: string;\n /** The error the child threw (present on failure); the error is still re-thrown. */\n error?: unknown;\n /** SE15 — the same 1-based iteration this delegation's `onDelegationStart` saw. */\n iteration: number;\n}\n\n/**\n * The return of a delegation hook: a decision, a promise of one, or nothing —\n * `void` lets a side-effect-only callback (`(ctx) => { log(ctx) }`) type-check,\n * which is the common case (mirrors a peer framework's `async ctx => { ... }` hooks).\n */\n// biome-ignore lint/suspicious/noConfusingVoidType: `void` is the idiomatic return for an optional-return callback; the rule false-positives on callback return unions.\ntype DelegationHookResult<T> = T | void | Promise<T | void>;\n\n/** Decision returned from {@link SubAgentSpec.onDelegationComplete}. */\nexport interface DelegationCompleteDecision {\n /** Appended to the child's result string. */\n feedback?: string;\n}\n\nexport interface SubAgentSpec {\n name: string;\n description: string;\n instructions: string;\n /**\n * A bare id string (back-compat) OR a full {@link ModelSelection} carrying\n * `params` (e.g. `[{ id: \"thinking\", value: \"low\" }]` for reasoning effort). The\n * object form is required for per-subagent reasoning effort to survive to the child\n * — the pre-M33 path took only `.id` and dropped params.\n */\n model?: string | ModelSelection;\n tools?: CustomTool[];\n /** Per-subagent shell sandbox toggle (M33). `true` ⇒ child `local.sandboxOptions.enabled`. */\n sandbox?: boolean;\n maxDelegationDepth?: number;\n /**\n * SE11 — called before the supervisor delegates. Return `{ proceed: false }`\n * to reject (the child never runs and `rejectionReason` becomes the tool\n * result), or `{ modifiedInput }` to rewrite the delegated prompt. A throwing\n * hook surfaces (never silently swallowed).\n */\n onDelegationStart?: (\n ctx: DelegationStartContext,\n ) => DelegationHookResult<DelegationStartDecision>;\n /**\n * SE11 — called after the delegation settles. On success `ctx.result` is set\n * and an optional `{ feedback }` is appended to it. On failure `ctx.error` is\n * set and the original error is ALWAYS re-thrown after this hook runs — a throw\n * from this hook on the error path is suppressed so it cannot mask the\n * delegation's real failure (on the success path a throw does propagate).\n */\n onDelegationComplete?: (\n ctx: DelegationCompleteContext,\n ) => DelegationHookResult<DelegationCompleteDecision>;\n /**\n * SE12 — opt-in parent-context forwarding. When set, the supervisor transcript\n * (`ctx.messages`, a read-only text projection) is passed to this filter and the\n * returned subset is forwarded to the child as a role-tagged context preamble\n * prepended to the delegated input. When ABSENT the child runs input-only —\n * memory isolation stays the default. A filter returning `[]` forwards nothing.\n * A throwing filter propagates (fail-fast, never swallowed — same contract as\n * `onDelegationStart`); the delegation surfaces as a tool error.\n */\n messageFilter?: (args: MessageFilterArgs) => readonly ToolContextMessage[];\n /**\n * SE14 — opt-in subagent result-context control. When `true`, the child's\n * completed tool-call results (name + result) are appended to the delegation\n * payload returned to the supervisor, inside a `<subagent-tool-results>` block.\n * When absent/`false` the delegation returns the child's final text only —\n * text-only stays the default (a peer framework's scoped posture). See ADR 0006.\n */\n includeToolResults?: boolean;\n}\n\nexport class MaxDelegationDepthError extends Error {\n readonly code = \"max_delegation_depth\" as const;\n constructor(\n public readonly currentDepth: number,\n public readonly maxDepth: number,\n ) {\n super(`Max delegation depth ${maxDepth} exceeded (current: ${currentDepth})`);\n this.name = \"MaxDelegationDepthError\";\n }\n}\n\n/**\n * Run the `onDelegationStart` hook; returns either a rejection or the (possibly\n * rewritten) input plus the optional SE13 `maxSteps` cap.\n */\nasync function applyDelegationStart(\n spec: SubAgentSpec,\n input: string,\n iteration: number,\n): Promise<{ reject: string } | { input: string; maxSteps?: number }> {\n if (spec.onDelegationStart === undefined) return { input };\n const decision = await spec.onDelegationStart({ input, name: spec.name, iteration });\n if (decision === undefined) return { input };\n if (decision.proceed === false)\n return { reject: decision.rejectionReason ?? \"(delegation rejected)\" };\n return {\n input: decision.modifiedInput ?? input,\n ...(decision.modifiedMaxSteps !== undefined ? { maxSteps: decision.modifiedMaxSteps } : {}),\n };\n}\n\n/**\n * SE14 — replay the child run's stream (a safe post-`wait()` idiom — the run buffers\n * events, `stream()` replays them) and collect every completed tool-call result into\n * a delimited block. Returns `\"\"` when the child ran no completed tool calls. See ADR 0006.\n */\nasync function collectChildToolResults(run: Run): Promise<string> {\n const lines: string[] = [];\n for await (const event of run.stream()) {\n if (event.type === \"tool_call\" && event.status === \"completed\") {\n const rendered =\n typeof event.result === \"string\" ? event.result : JSON.stringify(event.result ?? null);\n lines.push(`${event.name}: ${rendered}`);\n }\n }\n if (lines.length === 0) return \"\";\n return `\\n\\n<subagent-tool-results>\\n${lines.join(\"\\n\")}\\n</subagent-tool-results>`;\n}\n\n/**\n * Create the transient child agent and send the input, composing every forwarded\n * `SendOptions` onto ONE `send` call — SE10 `signal` + SE13 `maxIterations`. Absent\n * every option ⇒ the pre-SE10 single-arg `send(input)` shape. SE14 — when\n * `includeToolResults` is set, append the child's completed tool results. Dispose in `finally`.\n */\n/**\n * Build the child agent's `Agent.create` options: the child inherits the parent's\n * apiKey (else `Agent.create` throws \"Missing API key\"), its model (unless the spec\n * overrides it), and — #55 — the parent's plugins (permission gate/guards) so the\n * child's inner tool calls run under the same policy.\n */\nexport function buildChildCreateOptions(\n spec: SubAgentSpec,\n inherited: InheritedCredentials | undefined,\n): AgentOptions {\n // M33 — carry the WHOLE model (a bare id becomes `{ id }`; a ModelSelection with\n // `params` keeps its reasoning effort). The pre-M33 path wrapped `spec.model` as\n // `{ id: spec.model }`, which only worked because spec.model was a string and\n // silently dropped reasoning params.\n const model: string | ModelSelection | undefined =\n spec.model !== undefined\n ? typeof spec.model === \"string\"\n ? { id: spec.model }\n : spec.model\n : inherited?.model;\n // M33 — the role's own `sandbox` wins; when it omits the field, inherit the parent's posture. A role's\n // explicit `sandbox: false` therefore confines-OFF a child of a sandboxed parent (distinct from absent).\n const sandbox = spec.sandbox ?? inherited?.sandbox;\n return {\n ...(inherited?.apiKey !== undefined ? { apiKey: inherited.apiKey } : {}),\n ...(model !== undefined ? { model } : {}),\n ...(sandbox !== undefined ? { local: { sandboxOptions: { enabled: sandbox } } } : {}),\n ...(inherited?.plugins !== undefined ? { plugins: inherited.plugins } : {}),\n systemPrompt: spec.instructions,\n tools: spec.tools ?? [],\n };\n}\n\nasync function runChildAgent(\n spec: SubAgentSpec,\n input: string,\n signal: AbortSignal | undefined,\n maxSteps: number | undefined,\n inherited: InheritedCredentials | undefined,\n): Promise<string> {\n // SE45 cycle 3 — use the registered Agent facade via the DIP seam\n // (agent-factory-registry) instead of a dynamic `import(\"../agent.js\")`.\n // This removes the last madge cycle (a2a/subagent -> agent -> ... -> real-local-run-tools\n // -> a2a/subagent): the facade registers itself at module-init via setAgentFacade,\n // so subagent depends only on the registry port, never on the facade module.\n const agent = await getAgentFacade().create(buildChildCreateOptions(spec, inherited));\n try {\n const sendOptions: {\n signal?: AbortSignal;\n maxIterations?: number;\n origin?: import(\"../types/run.js\").MessageOrigin;\n } = {\n ...(signal !== undefined ? { signal } : {}),\n ...(maxSteps !== undefined ? { maxIterations: maxSteps } : {}),\n // SE3 — a delegated child's turn is initiated by the coordinating parent.\n origin: { kind: \"coordinator\" },\n };\n const run = await agent.send(input, sendOptions);\n const result = await run.wait();\n // Fail-fast, don't swallow (Rule 8): a child that ended in error must surface — otherwise a real\n // failure (e.g. `provider_unresolved`) is hidden behind \"(no response)\" and the parent loops on it.\n if (result.status === \"error\") {\n const cause = (result as { error?: { message?: string } }).error;\n throw new Error(\n `subagent \"${spec.name}\" run failed: ${cause?.message ?? \"unknown error\"}`,\n cause !== undefined ? { cause } : undefined,\n );\n }\n const text = result.result ?? \"(no response)\";\n // SE14 — text-only by default; opt-in appends the child's tool results.\n return spec.includeToolResults === true ? text + (await collectChildToolResults(run)) : text;\n } finally {\n agent.dispose();\n }\n}\n\n/**\n * Best-effort error-path notification: run `onDelegationComplete` with the child's\n * error so the caller can observe the failure. The observer's own throw (sync or\n * async) is suppressed here so it cannot mask the delegation's real error, which the\n * handler re-throws next.\n */\nasync function notifyDelegationError(\n spec: SubAgentSpec,\n input: string,\n error: unknown,\n iteration: number,\n): Promise<void> {\n if (spec.onDelegationComplete === undefined) return;\n try {\n await spec.onDelegationComplete({ input, name: spec.name, error, iteration });\n } catch {\n // Subordinate to `error`; the child's real cause wins.\n }\n}\n\n/**\n * SE12 — apply `messageFilter` (if set) and prepend the filtered supervisor\n * transcript to the delegated input as a role-tagged context preamble. Absent\n * filter OR no messages OR an empty filtered subset ⇒ the original input\n * (isolation-by-default preserved).\n */\nfunction applyMessageFilter(\n spec: SubAgentSpec,\n input: string,\n messages: readonly ToolContextMessage[] | undefined,\n): string {\n if (spec.messageFilter === undefined || messages === undefined) return input;\n const filtered = spec.messageFilter({ messages, input, name: spec.name });\n if (filtered.length === 0) return input;\n const preamble = filtered.map((m) => `${m.role}: ${m.content}`).join(\"\\n\");\n return `Prior conversation:\\n${preamble}\\n\\nTask:\\n${input}`;\n}\n\n/** Run the success-path `onDelegationComplete` hook; appends its `feedback` to the result. */\nasync function applyDelegationComplete(\n spec: SubAgentSpec,\n input: string,\n result: string,\n iteration: number,\n): Promise<string> {\n if (spec.onDelegationComplete === undefined) return result;\n const completion = await spec.onDelegationComplete({ input, name: spec.name, result, iteration });\n return completion?.feedback !== undefined ? result + completion.feedback : result;\n}\n\nfunction defineSubAgent(spec: SubAgentSpec, _parentDepth = 0): CustomTool {\n const currentDepth = _parentDepth + 1;\n const maxDepth = spec.maxDelegationDepth ?? 3;\n\n if (currentDepth > maxDepth) {\n throw new MaxDelegationDepthError(currentDepth, maxDepth);\n }\n\n // Zod for RUNTIME validation of the tool_use input …\n const inputZod = z.object({\n input: z.string().describe(\"Task for the subagent\"),\n });\n // … and a real Draft-7 JSON Schema for the LLM. `CustomTool.inputSchema` is sent\n // to the model verbatim; a raw Zod object would serialize to garbage, so the\n // model emits malformed input that fails `inputZod.parse` and the delegation\n // never runs (the previous bug — the schema and the validator are now distinct).\n const inputSchema: Record<string, unknown> = {\n type: \"object\",\n properties: {\n input: { type: \"string\", description: \"Task for the subagent\" },\n },\n required: [\"input\"],\n additionalProperties: false,\n };\n\n // SE15 — per-instance delegation counter, surfaced as `iteration` on the hook\n // contexts. Incremented once per handler invocation before onDelegationStart.\n let iteration = 0;\n\n const tool: CustomTool = {\n name: spec.name,\n description: spec.description,\n inputSchema,\n handler: async (\n rawInput: Record<string, unknown>,\n ctx?: {\n signal?: AbortSignal;\n context?: unknown;\n messages?: readonly ToolContextMessage[];\n },\n ): Promise<string> => {\n const { input: parsed } = inputZod.parse(rawInput);\n // theokit#148 — read the parent's credentials from the RUN's async scope, at dispatch time.\n // They used to be stashed on this tool object by the runtime, which meant any layer that\n // rebuilt the object (e.g. `@theokit/agents`' `toCompiledTool`) silently dropped them and the\n // child failed with `provider_unresolved`. The scope travels with the call, so nothing about\n // the object's shape matters — and two concurrent runs sharing one tool each read their own.\n const inherited = currentInheritedSubAgentCredentials();\n iteration += 1; // SE15 — before onDelegationStart; a rejected delegation still counts.\n // Pin THIS invocation's iteration before any await so a concurrent invocation\n // bumping the shared counter cannot change the value onDelegationComplete /\n // notifyDelegationError observe — they see the same iteration onDelegationStart did.\n const capturedIteration = iteration;\n\n const start = await applyDelegationStart(spec, parsed, capturedIteration);\n if (\"reject\" in start) return start.reject;\n // SE12 — opt-in: forward the filtered supervisor transcript as a preamble.\n const input = applyMessageFilter(spec, start.input, ctx?.messages);\n\n let result: string;\n try {\n // SE13 — apply the optional onDelegationStart maxSteps cap on the child send.\n result = await runChildAgent(spec, input, ctx?.signal, start.maxSteps, inherited);\n } catch (error) {\n // SE11 — notify the completion hook of the failure (best-effort observer),\n // then re-throw the ORIGINAL error (Rule 8: never swallow the delegation's\n // own failure).\n await notifyDelegationError(spec, input, error, capturedIteration);\n throw error;\n }\n return applyDelegationComplete(spec, input, result, capturedIteration);\n },\n };\n\n // theokit#148 — nothing is installed on the tool. The credentials arrive through the run's async\n // scope (see `internal/runtime/concurrency/subagent-credentials.ts`), so there is no extra\n // property for a normalizing layer to drop.\n return tool;\n}\n\n/** SE36 — `SubAgent.create` replaces `defineSubAgent` (ADR 0015). @public */\nexport class SubAgent {\n private constructor() {}\n static create(spec: SubAgentSpec, parentDepth = 0): CustomTool {\n return defineSubAgent(spec, parentDepth);\n }\n}\n\n/**\n * Convert a parent's declarative `agents` map ({@link AgentDefinition} per key)\n * into delegation tools for the LOCAL runtime — the counterpart of the\n * cloud/fixture subagent wiring. Each child inherits the parent's `apiKey`/model\n * via {@link inheritSubAgentCredentials}; `def.model` overrides the model\n * (`\"inherit\"` keeps the parent's), and `def.tools` scopes the child to that\n * subset of the parent's tools (absent → the parent's full toolset, per the\n * `AgentDefinition.tools` contract).\n *\n * M33 — per-subagent `model` (with reasoning `params`) and `sandbox` are now wired\n * into local delegation: each is carried onto the {@link SubAgentSpec} and applied to\n * the child in {@link buildChildCreateOptions}. `\"inherit\"` (or an absent field) keeps\n * the parent's value. Per-subagent `mcp` is rejected at load (see subagents-loader) —\n * resolving server names→config on the local path is a follow-up.\n *\n * @internal\n */\nexport function subAgentToolsFromDefinitions(\n agents: Record<string, AgentDefinition>,\n parentTools: readonly CustomTool[],\n): CustomTool[] {\n return Object.entries(agents).map(([name, def]) => {\n const whitelist =\n Array.isArray(def.tools) && def.tools.length > 0 ? new Set(def.tools) : undefined;\n const childTools = whitelist ? parentTools.filter((t) => whitelist.has(t.name)) : parentTools;\n return defineSubAgent({\n name,\n description: def.description,\n instructions: def.prompt,\n // Carry the FULL ModelSelection (id + reasoning params), not just the id, so\n // per-subagent reasoning effort survives to buildChildCreateOptions.\n ...(def.model !== undefined && def.model !== \"inherit\" ? { model: def.model } : {}),\n ...(def.sandbox !== undefined ? { sandbox: def.sandbox } : {}),\n tools: [...childTools],\n });\n });\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/persistence/fs-session-store.ts"],"names":[],"mappings":"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","file":"chunk-B6HOIWQ6.js","sourcesContent":["/**\n * SE41 — `FsSessionStore`, the DEFAULT reference implementation of the pluggable\n * {@link SessionStore} seam. It reads and append-writes the native Claude-shaped\n * `.jsonl` transcript at `<baseDir>/projects/<encoded-cwd>/<agentId>.jsonl` — the\n * exact on-disk format SE40 introduced (the file the Claude Code CLI can\n * `--continue`). Omitting `local.sessionStore` resolves to this store, so the\n * default persistence path is byte-identical to SE40 behavior.\n *\n * `readRecords` is `readTranscript(transcriptPath(...))` (a missing session →\n * `[]`, not an error — a fresh agent has no history). `appendRecords` is a TRUE\n * append: it reads the prior records, concatenates the new-turn delta, and\n * rewrites the whole line set atomically under the SE40 cross-process file lock\n * (`writeTranscript` never shrinks — the native format is an append-only\n * `parentUuid` DAG). The parent dir is created BEFORE acquiring the lock because\n * the lock's companion `<path>.lock` file needs an existing parent dir (the SE40\n * `mkdir(dirname)`-before-lock fix).\n *\n * @internal\n */\n\nimport { mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { SessionStore } from \"../../types/session-store.js\";\nimport { withFileLock } from \"./file-lock.js\";\nimport { appendJsonl } from \"./jsonl.js\";\nimport { readTranscript, type SessionRecord, transcriptPath } from \"./session-transcript.js\";\nimport { acquireSessionWriter, type SessionWriterLease } from \"./session-writer.js\";\n\n/** Options identifying the on-disk transcript location for the FS default store. */\nexport interface FsSessionStoreOptions {\n /** Transcript base dir (`~/.theokit` default, `~/.claude` for CLI interop) — already `~`-expanded. */\n baseDir: string;\n /** The workspace cwd whose encoded form is the transcript project dir. */\n cwd: string;\n}\n\n/**\n * The default `SessionStore` — reads/append-writes the native `.jsonl` transcript.\n *\n * @internal\n */\n/**\n * Reference-counted leases, shared per path.\n *\n * `acquireSessionWriter` is STRICT on purpose: two concurrent acquisitions of the same path, and\n * exactly one wins — \"a lease that let both through would be decorative\" (the M81 test says exactly\n * that, and it is right). That is the primitive's contract, and it does not change.\n *\n * But within ONE process it is normal to have more than one store over the same session: the golden\n * compaction tests and the concurrent-send tests do exactly that, and they record real runtime\n * behavior. Applying the raw primitive there would turn a legitimate pattern into a\n * `SessionBusyError`.\n *\n * The reconciliation belongs here, in the primitive's consumer: the process takes ONE lease per path\n * and counts how many stores use it. The last to release actually frees it. Cross-process stays\n * strict — which is the problem M81 states (\"`exec resume --last` can write into the TUI's live\n * session\").\n */\nconst sharedLeases = new Map<string, { lease: SessionWriterLease; refs: number }>();\n\nasync function acquireShared(path: string): Promise<SessionWriterLease> {\n const existing = sharedLeases.get(path);\n if (existing !== undefined) {\n existing.refs++;\n return createProxy(path);\n }\n const lease = await acquireSessionWriter(path);\n sharedLeases.set(path, { lease, refs: 1 });\n return createProxy(path);\n}\n\n/** A handle that decrements the count; the last to release frees the real lease. */\nfunction createProxy(path: string): SessionWriterLease {\n let released = false;\n return {\n sessionPath: path,\n // The proxy forwards the renewal to the ONE real lease this path shares. Renewing through any\n // holder is correct and is the point: the record must say \"someone in this process is still\n // writing\", and the refcount already guarantees they are all the same owner.\n renew: (): void => {\n if (released) return;\n sharedLeases.get(path)?.lease.renew();\n },\n release: async (): Promise<void> => {\n if (released) return;\n released = true;\n const entry = sharedLeases.get(path);\n if (entry === undefined) return;\n entry.refs--;\n if (entry.refs > 0) return;\n sharedLeases.delete(path);\n await entry.lease.release();\n },\n };\n}\n\nexport class FsSessionStore implements SessionStore {\n readonly #baseDir: string;\n readonly #cwd: string;\n /** One lease per `agentId` — a store serves more than one session over the process lifetime. */\n readonly #leases = new Map<string, SessionWriterLease>();\n\n constructor(options: FsSessionStoreOptions) {\n this.#baseDir = options.baseDir;\n this.#cwd = options.cwd;\n }\n\n async readRecords(agentId: string): Promise<SessionRecord[]> {\n return readTranscript(transcriptPath(this.#baseDir, this.#cwd, agentId));\n }\n\n async appendRecords(agentId: string, records: readonly SessionRecord[]): Promise<void> {\n // Empty delta → nothing to persist (avoids an unnecessary lock + rewrite).\n if (records.length === 0) return;\n const path = transcriptPath(this.#baseDir, this.#cwd, agentId);\n // mkdir BEFORE the lock: withFileLock's companion `<path>.lock` needs the parent dir.\n await mkdir(dirname(path), { recursive: true });\n\n await withFileLock(path, async () => {\n // M93 — appends the DELTA instead of rewriting the whole file.\n //\n // Before: `readTranscript` + `writeTranscript` of everything, per turn. O(n) of I/O **and** of\n // parsing on every turn, O(n^2) per session — the consumer note in\n // `agents/lib/session/backtrack.ts` records 1.4 MB / 3000 lines over 200 turns.\n //\n // Correct because the format **is already append-only**: the `parentUuid` DAG does not depend\n // on line order, and every record carries its own parent. `appendJsonl` **already existed in\n // the package** and had a single caller (`eval/runner.ts`) — the primitive was there, it was\n // the store that ignored it (rung 4).\n //\n // `withFileLock` stays — but the earlier claim that \"it is what serializes two concurrent\n // `appendRecords`\" was too strong, and M93's adversarial review measured it: removing it fails\n // no test. The reason is the paragraph above — the `parentUuid` DAG does not depend on line\n // order, so two interleaved batches reconstruct identically. The work the lock was doing\n // (protecting a read-modify-write) disappeared along with the rewrite.\n //\n // What it still covers is the TOCTOU window in `needsLineBreakBefore` (read the last byte,\n // then write): without it, two processes can both conclude \"a \\n is missing\" and produce a\n // blank line — which the reader discards, i.e. benign. It stays as a **declared, not\n // mechanized** defense (the discipline in `error-handling.md` § 4: enumerate the residue\n // rather than let a missing test pass for coverage).\n //\n // `writeTranscript` still exists for **compaction**, the one operation that legitimately\n // rewrites the file.\n for (const record of records) appendJsonl(path, record);\n });\n }\n\n /**\n * Takes the session's writer lease. Throws `SessionBusyError` when another process holds it.\n *\n * **Explicit, and NOT inside `appendRecords`** — M95's adversarial review measured why that\n * matters: the `SessionStore` contract states that \"an `appendRecords` rejection is logged to\n * stderr, NOT thrown to the caller (best-effort write)\". Acquiring there made the\n * `SessionBusyError` get **swallowed**, and the result was worse than the original problem:\n * instead of two writers interleaving lines, the loser **lost the turn silently** — nothing on\n * disk, a stderr warning invisible under the TUI, and no way for the caller to react.\n *\n * At init the error reaches someone who can act: `exec` forks to a new id, which is exactly what\n * the error message itself prescribes. It is the difference between failing where a decision is\n * possible and failing where only loss is.\n */\n async acquire(agentId: string): Promise<void> {\n if (this.#leases.has(agentId)) return;\n const path = transcriptPath(this.#baseDir, this.#cwd, agentId);\n await mkdir(dirname(path), { recursive: true });\n this.#leases.set(agentId, await acquireShared(path));\n }\n\n /**\n * Releases ONE agent's lease.\n *\n * It exists because `dispose()` releases **every** lease the store holds, and a store injected by\n * the consumer may serve several agents: an init that fails for agent B must not free agent A's\n * lease, which is still live and writing.\n */\n async release(agentId: string): Promise<void> {\n const lease = this.#leases.get(agentId);\n if (lease === undefined) return;\n this.#leases.delete(agentId);\n await lease.release();\n }\n\n /**\n * Releases every lease this store holds.\n *\n * Without it the `.writer.lock` outlives the process and the next open would have to wait out the\n * heartbeat window — recoverable, but 30 s of waiting after a CLEAN shutdown would be an avoidable\n * defect. Idempotent: calling it twice is not an error.\n */\n async dispose(): Promise<void> {\n const leases = [...this.#leases.values()];\n this.#leases.clear();\n for (const lease of leases) await lease.release();\n }\n}\n"]}