@theokit/sdk 4.63.0 → 4.63.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/a2a/index.cjs +2 -2
  3. package/dist/a2a/index.js +1 -1
  4. package/dist/agent-WK7MKIMH.cjs +66 -0
  5. package/dist/{agent-5KYMG63I.cjs.map → agent-WK7MKIMH.cjs.map} +1 -1
  6. package/dist/agent-YWMBM7LX.js +57 -0
  7. package/dist/{agent-536OOESZ.js.map → agent-YWMBM7LX.js.map} +1 -1
  8. package/dist/agent-session-store-6EL5NPA4.cjs +24 -0
  9. package/dist/{agent-session-store-WAKLOKWK.cjs.map → agent-session-store-6EL5NPA4.cjs.map} +1 -1
  10. package/dist/agent-session-store-OPGRB4XM.js +7 -0
  11. package/dist/{agent-session-store-G2BMUZQV.js.map → agent-session-store-OPGRB4XM.js.map} +1 -1
  12. package/dist/auth/index.cjs +18 -18
  13. package/dist/auth/index.js +6 -6
  14. package/dist/{batch-ND32UKZS.cjs → batch-BXYTW2DP.cjs} +27 -27
  15. package/dist/{batch-ND32UKZS.cjs.map → batch-BXYTW2DP.cjs.map} +1 -1
  16. package/dist/{batch-2TGJMNCJ.js → batch-L4ZXS46M.js} +10 -10
  17. package/dist/{batch-2TGJMNCJ.js.map → batch-L4ZXS46M.js.map} +1 -1
  18. package/dist/{chunk-VF7EWVDG.js → chunk-2GUYQR5P.js} +3 -3
  19. package/dist/{chunk-VF7EWVDG.js.map → chunk-2GUYQR5P.js.map} +1 -1
  20. package/dist/{chunk-J2UROOIG.cjs → chunk-2HVF2WJY.cjs} +8 -8
  21. package/dist/{chunk-J2UROOIG.cjs.map → chunk-2HVF2WJY.cjs.map} +1 -1
  22. package/dist/{chunk-44MBDIHG.js → chunk-2QDYBS2A.js} +3 -3
  23. package/dist/{chunk-44MBDIHG.js.map → chunk-2QDYBS2A.js.map} +1 -1
  24. package/dist/{chunk-NGESVVJN.cjs → chunk-3FFAEAUJ.cjs} +17 -17
  25. package/dist/{chunk-NGESVVJN.cjs.map → chunk-3FFAEAUJ.cjs.map} +1 -1
  26. package/dist/{chunk-GWC3HADL.cjs → chunk-3NSS2OIZ.cjs} +4 -4
  27. package/dist/{chunk-GWC3HADL.cjs.map → chunk-3NSS2OIZ.cjs.map} +1 -1
  28. package/dist/{chunk-CV7XMBHP.js → chunk-3O42QOMJ.js} +3 -3
  29. package/dist/{chunk-CV7XMBHP.js.map → chunk-3O42QOMJ.js.map} +1 -1
  30. package/dist/{chunk-IWBGCBR6.cjs → chunk-4CLOXP6H.cjs} +4 -4
  31. package/dist/{chunk-IWBGCBR6.cjs.map → chunk-4CLOXP6H.cjs.map} +1 -1
  32. package/dist/{chunk-YEXA3PGR.js → chunk-4FFBAUFS.js} +5 -5
  33. package/dist/{chunk-YEXA3PGR.js.map → chunk-4FFBAUFS.js.map} +1 -1
  34. package/dist/{chunk-HY57ULY2.cjs → chunk-4PYZ5AX3.cjs} +5 -5
  35. package/dist/{chunk-HY57ULY2.cjs.map → chunk-4PYZ5AX3.cjs.map} +1 -1
  36. package/dist/{chunk-OC4NTGMN.js → chunk-4QZSA2HJ.js} +3 -3
  37. package/dist/{chunk-OC4NTGMN.js.map → chunk-4QZSA2HJ.js.map} +1 -1
  38. package/dist/{chunk-K3FW2XZD.cjs → chunk-4ZHTIJNE.cjs} +9 -9
  39. package/dist/{chunk-K3FW2XZD.cjs.map → chunk-4ZHTIJNE.cjs.map} +1 -1
  40. package/dist/{chunk-BUIK7GUA.cjs → chunk-5HEG4CQH.cjs} +8 -8
  41. package/dist/{chunk-BUIK7GUA.cjs.map → chunk-5HEG4CQH.cjs.map} +1 -1
  42. package/dist/{chunk-NXH4GPAQ.cjs → chunk-5VB22SYX.cjs} +7 -7
  43. package/dist/{chunk-NXH4GPAQ.cjs.map → chunk-5VB22SYX.cjs.map} +1 -1
  44. package/dist/{chunk-5USCYPPI.cjs → chunk-6HKGLTJI.cjs} +8 -8
  45. package/dist/{chunk-5USCYPPI.cjs.map → chunk-6HKGLTJI.cjs.map} +1 -1
  46. package/dist/{chunk-EHJEZAOO.cjs → chunk-6RKUO7AW.cjs} +32 -32
  47. package/dist/{chunk-EHJEZAOO.cjs.map → chunk-6RKUO7AW.cjs.map} +1 -1
  48. package/dist/{chunk-5JLFFPCH.js → chunk-7YGCPMGB.js} +4 -4
  49. package/dist/{chunk-5JLFFPCH.js.map → chunk-7YGCPMGB.js.map} +1 -1
  50. package/dist/{chunk-SUKXXLWD.js → chunk-A46SWMIF.js} +6 -6
  51. package/dist/{chunk-SUKXXLWD.js.map → chunk-A46SWMIF.js.map} +1 -1
  52. package/dist/{chunk-F7AQV62G.js → chunk-A4JVILQU.js} +5 -5
  53. package/dist/{chunk-F7AQV62G.js.map → chunk-A4JVILQU.js.map} +1 -1
  54. package/dist/{chunk-44JAAH4X.js → chunk-B3IMEBOA.js} +3 -3
  55. package/dist/{chunk-44JAAH4X.js.map → chunk-B3IMEBOA.js.map} +1 -1
  56. package/dist/{chunk-QDED6YO6.cjs → chunk-B4EOJWOY.cjs} +5 -5
  57. package/dist/{chunk-QDED6YO6.cjs.map → chunk-B4EOJWOY.cjs.map} +1 -1
  58. package/dist/{chunk-YJDH3CKG.js → chunk-BP46RJ5X.js} +5 -5
  59. package/dist/{chunk-YJDH3CKG.js.map → chunk-BP46RJ5X.js.map} +1 -1
  60. package/dist/{chunk-QRSUA2CV.js → chunk-BU4KFWXF.js} +3 -3
  61. package/dist/{chunk-QRSUA2CV.js.map → chunk-BU4KFWXF.js.map} +1 -1
  62. package/dist/{chunk-MG3SOM3M.js → chunk-BVJJ3DRV.js} +6 -6
  63. package/dist/{chunk-MG3SOM3M.js.map → chunk-BVJJ3DRV.js.map} +1 -1
  64. package/dist/{chunk-AQLGBKNT.js → chunk-BZRFXJHA.js} +3 -3
  65. package/dist/{chunk-AQLGBKNT.js.map → chunk-BZRFXJHA.js.map} +1 -1
  66. package/dist/{chunk-UQGQFBRL.js → chunk-C3NT3PVE.js} +3 -3
  67. package/dist/{chunk-UQGQFBRL.js.map → chunk-C3NT3PVE.js.map} +1 -1
  68. package/dist/{chunk-UC3HT2S4.js → chunk-C72AZW7J.js} +3 -3
  69. package/dist/{chunk-UC3HT2S4.js.map → chunk-C72AZW7J.js.map} +1 -1
  70. package/dist/{chunk-WNTAPVU5.cjs → chunk-CQBXOJ6U.cjs} +13 -13
  71. package/dist/{chunk-WNTAPVU5.cjs.map → chunk-CQBXOJ6U.cjs.map} +1 -1
  72. package/dist/{chunk-T7XEKOVW.js → chunk-D4CUGAKZ.js} +3 -3
  73. package/dist/{chunk-T7XEKOVW.js.map → chunk-D4CUGAKZ.js.map} +1 -1
  74. package/dist/{chunk-R6TA2DRJ.js → chunk-DKD3MH6A.js} +6 -6
  75. package/dist/{chunk-R6TA2DRJ.js.map → chunk-DKD3MH6A.js.map} +1 -1
  76. package/dist/{chunk-YXGAW7BB.js → chunk-DN2PACRI.js} +10 -10
  77. package/dist/{chunk-YXGAW7BB.js.map → chunk-DN2PACRI.js.map} +1 -1
  78. package/dist/{chunk-XSX2UU6Y.cjs → chunk-DXGZ2NUG.cjs} +10 -10
  79. package/dist/{chunk-XSX2UU6Y.cjs.map → chunk-DXGZ2NUG.cjs.map} +1 -1
  80. package/dist/{chunk-NUKRL3I6.cjs → chunk-EG4QM7ZJ.cjs} +18 -2
  81. package/dist/chunk-EG4QM7ZJ.cjs.map +1 -0
  82. package/dist/{chunk-C7QPML3L.js → chunk-GEEXBYFL.js} +9 -9
  83. package/dist/{chunk-C7QPML3L.js.map → chunk-GEEXBYFL.js.map} +1 -1
  84. package/dist/{chunk-A4VHSE56.cjs → chunk-GKEFRLU7.cjs} +6 -6
  85. package/dist/{chunk-A4VHSE56.cjs.map → chunk-GKEFRLU7.cjs.map} +1 -1
  86. package/dist/{chunk-NIRE5CNO.cjs → chunk-HCZD23VS.cjs} +13 -13
  87. package/dist/{chunk-NIRE5CNO.cjs.map → chunk-HCZD23VS.cjs.map} +1 -1
  88. package/dist/{chunk-IRCJ7EHV.cjs → chunk-HOXVQ5FR.cjs} +14 -14
  89. package/dist/{chunk-IRCJ7EHV.cjs.map → chunk-HOXVQ5FR.cjs.map} +1 -1
  90. package/dist/{chunk-QARJGQSA.js → chunk-HS7AVXTF.js} +3 -3
  91. package/dist/{chunk-QARJGQSA.js.map → chunk-HS7AVXTF.js.map} +1 -1
  92. package/dist/{chunk-4I55V454.cjs → chunk-I6HGWHPU.cjs} +4 -4
  93. package/dist/{chunk-4I55V454.cjs.map → chunk-I6HGWHPU.cjs.map} +1 -1
  94. package/dist/{chunk-T73NA43R.js → chunk-IPYYKCRC.js} +3 -3
  95. package/dist/{chunk-T73NA43R.js.map → chunk-IPYYKCRC.js.map} +1 -1
  96. package/dist/{chunk-UUP3MUZ6.cjs → chunk-ITYQ6VBP.cjs} +18 -18
  97. package/dist/{chunk-UUP3MUZ6.cjs.map → chunk-ITYQ6VBP.cjs.map} +1 -1
  98. package/dist/chunk-JPBKYL3B.cjs +18 -0
  99. package/dist/{chunk-6HTXPPHK.cjs.map → chunk-JPBKYL3B.cjs.map} +1 -1
  100. package/dist/{chunk-MZ2FGBLZ.js → chunk-K5OJUYSZ.js} +4 -4
  101. package/dist/{chunk-MZ2FGBLZ.js.map → chunk-K5OJUYSZ.js.map} +1 -1
  102. package/dist/{chunk-CHKH5452.js → chunk-KIH6IZ43.js} +60 -45
  103. package/dist/chunk-KIH6IZ43.js.map +1 -0
  104. package/dist/{chunk-EI2Q7SJ5.cjs → chunk-KQ7TS7WW.cjs} +10 -10
  105. package/dist/{chunk-EI2Q7SJ5.cjs.map → chunk-KQ7TS7WW.cjs.map} +1 -1
  106. package/dist/{chunk-RUDY2GTT.js → chunk-KQRW2GPZ.js} +5 -5
  107. package/dist/{chunk-RUDY2GTT.js.map → chunk-KQRW2GPZ.js.map} +1 -1
  108. package/dist/{chunk-P5LCASTC.cjs → chunk-KYAJINUI.cjs} +125 -125
  109. package/dist/{chunk-P5LCASTC.cjs.map → chunk-KYAJINUI.cjs.map} +1 -1
  110. package/dist/{chunk-AMFXSENK.js → chunk-LWGSI6M3.js} +4 -4
  111. package/dist/{chunk-AMFXSENK.js.map → chunk-LWGSI6M3.js.map} +1 -1
  112. package/dist/{chunk-ZHPWGIUX.js → chunk-LXI4XZEC.js} +5 -5
  113. package/dist/{chunk-ZHPWGIUX.js.map → chunk-LXI4XZEC.js.map} +1 -1
  114. package/dist/{chunk-AG5JPQIY.js → chunk-LXQ6HKPS.js} +3 -3
  115. package/dist/{chunk-AG5JPQIY.js.map → chunk-LXQ6HKPS.js.map} +1 -1
  116. package/dist/{chunk-ROYPRJH4.cjs → chunk-LYRDF5TQ.cjs} +9 -9
  117. package/dist/{chunk-ROYPRJH4.cjs.map → chunk-LYRDF5TQ.cjs.map} +1 -1
  118. package/dist/{chunk-G24KZRSA.js → chunk-N2U4AZGB.js} +3 -3
  119. package/dist/{chunk-G24KZRSA.js.map → chunk-N2U4AZGB.js.map} +1 -1
  120. package/dist/{chunk-4ERPXIVB.js → chunk-O73J46PV.js} +5 -5
  121. package/dist/{chunk-4ERPXIVB.js.map → chunk-O73J46PV.js.map} +1 -1
  122. package/dist/{chunk-F3YZMOAU.cjs → chunk-O7DK5PBJ.cjs} +4 -4
  123. package/dist/{chunk-F3YZMOAU.cjs.map → chunk-O7DK5PBJ.cjs.map} +1 -1
  124. package/dist/{chunk-Z4BCLVTI.cjs → chunk-O7LZFG6O.cjs} +5 -5
  125. package/dist/{chunk-Z4BCLVTI.cjs.map → chunk-O7LZFG6O.cjs.map} +1 -1
  126. package/dist/{chunk-3YJNUKYN.cjs → chunk-OHLDPWTA.cjs} +15 -15
  127. package/dist/{chunk-3YJNUKYN.cjs.map → chunk-OHLDPWTA.cjs.map} +1 -1
  128. package/dist/{chunk-FUL2I7G5.js → chunk-OSEG74VJ.js} +8 -8
  129. package/dist/{chunk-FUL2I7G5.js.map → chunk-OSEG74VJ.js.map} +1 -1
  130. package/dist/{chunk-UCBJBJ27.js → chunk-PUAEFLYK.js} +4 -4
  131. package/dist/{chunk-UCBJBJ27.js.map → chunk-PUAEFLYK.js.map} +1 -1
  132. package/dist/{chunk-CASUEY42.cjs → chunk-Q7LPTOD6.cjs} +24 -24
  133. package/dist/{chunk-CASUEY42.cjs.map → chunk-Q7LPTOD6.cjs.map} +1 -1
  134. package/dist/{chunk-2C72DXQF.cjs → chunk-RFMBZPOW.cjs} +9 -9
  135. package/dist/{chunk-2C72DXQF.cjs.map → chunk-RFMBZPOW.cjs.map} +1 -1
  136. package/dist/{chunk-NLTVXLGT.js → chunk-RFXWMRFC.js} +3 -3
  137. package/dist/{chunk-NLTVXLGT.js.map → chunk-RFXWMRFC.js.map} +1 -1
  138. package/dist/{chunk-2DG7KW4L.cjs → chunk-RMWTPV3M.cjs} +8 -8
  139. package/dist/{chunk-2DG7KW4L.cjs.map → chunk-RMWTPV3M.cjs.map} +1 -1
  140. package/dist/{chunk-P6A3M6VD.cjs → chunk-SZVR77EJ.cjs} +10 -10
  141. package/dist/{chunk-P6A3M6VD.cjs.map → chunk-SZVR77EJ.cjs.map} +1 -1
  142. package/dist/{chunk-3E77SX4H.js → chunk-TAZVKYWJ.js} +3 -3
  143. package/dist/{chunk-3E77SX4H.js.map → chunk-TAZVKYWJ.js.map} +1 -1
  144. package/dist/{chunk-WKRSH2VR.js → chunk-U6IFHFWK.js} +3 -3
  145. package/dist/{chunk-WKRSH2VR.js.map → chunk-U6IFHFWK.js.map} +1 -1
  146. package/dist/{chunk-I6TGFUCO.cjs → chunk-UALX2J2Q.cjs} +4 -4
  147. package/dist/{chunk-I6TGFUCO.cjs.map → chunk-UALX2J2Q.cjs.map} +1 -1
  148. package/dist/{chunk-XN7NOENA.js → chunk-UBDMVMBZ.js} +5 -5
  149. package/dist/{chunk-XN7NOENA.js.map → chunk-UBDMVMBZ.js.map} +1 -1
  150. package/dist/{chunk-YTR3RBUZ.js → chunk-UEXIJTLC.js} +4 -4
  151. package/dist/{chunk-YTR3RBUZ.js.map → chunk-UEXIJTLC.js.map} +1 -1
  152. package/dist/{chunk-DQKERTND.cjs → chunk-UGT7GK7I.cjs} +11 -11
  153. package/dist/{chunk-DQKERTND.cjs.map → chunk-UGT7GK7I.cjs.map} +1 -1
  154. package/dist/{chunk-FKMUFNQE.js → chunk-UMP6OJIM.js} +4 -4
  155. package/dist/{chunk-FKMUFNQE.js.map → chunk-UMP6OJIM.js.map} +1 -1
  156. package/dist/{chunk-AEOZTXVW.js → chunk-UNYXQ4M5.js} +3 -3
  157. package/dist/{chunk-AEOZTXVW.js.map → chunk-UNYXQ4M5.js.map} +1 -1
  158. package/dist/{chunk-2BDH744Z.js → chunk-UTSRIDKZ.js} +3 -3
  159. package/dist/{chunk-2BDH744Z.js.map → chunk-UTSRIDKZ.js.map} +1 -1
  160. package/dist/{chunk-2ADR2GSO.cjs → chunk-UU36SHFY.cjs} +5 -5
  161. package/dist/{chunk-2ADR2GSO.cjs.map → chunk-UU36SHFY.cjs.map} +1 -1
  162. package/dist/{chunk-R3UPQFKK.cjs → chunk-V2BOS4WF.cjs} +9 -9
  163. package/dist/{chunk-R3UPQFKK.cjs.map → chunk-V2BOS4WF.cjs.map} +1 -1
  164. package/dist/{chunk-Q4CMI2LP.js → chunk-WLQNMXQE.js} +5 -5
  165. package/dist/{chunk-Q4CMI2LP.js.map → chunk-WLQNMXQE.js.map} +1 -1
  166. package/dist/{chunk-XWL6O3SW.cjs → chunk-WNO3C3N2.cjs} +4 -4
  167. package/dist/{chunk-XWL6O3SW.cjs.map → chunk-WNO3C3N2.cjs.map} +1 -1
  168. package/dist/{chunk-T7O6K6PX.js → chunk-XEQ3TM66.js} +18 -3
  169. package/dist/chunk-XEQ3TM66.js.map +1 -0
  170. package/dist/{chunk-BVZW2B5V.cjs → chunk-XJCXEKMD.cjs} +4 -4
  171. package/dist/{chunk-BVZW2B5V.cjs.map → chunk-XJCXEKMD.cjs.map} +1 -1
  172. package/dist/{chunk-JTB5Q42C.cjs → chunk-XL7Q7HB2.cjs} +4 -4
  173. package/dist/{chunk-JTB5Q42C.cjs.map → chunk-XL7Q7HB2.cjs.map} +1 -1
  174. package/dist/{chunk-LW7G5DYW.js → chunk-XO4SOZN6.js} +4 -4
  175. package/dist/{chunk-LW7G5DYW.js.map → chunk-XO4SOZN6.js.map} +1 -1
  176. package/dist/{chunk-CQGYNZ3K.cjs → chunk-XWTLIGO3.cjs} +4 -4
  177. package/dist/{chunk-CQGYNZ3K.cjs.map → chunk-XWTLIGO3.cjs.map} +1 -1
  178. package/dist/{chunk-6SBW4QR2.cjs → chunk-YML4ME27.cjs} +11 -11
  179. package/dist/{chunk-6SBW4QR2.cjs.map → chunk-YML4ME27.cjs.map} +1 -1
  180. package/dist/{chunk-P6H23T43.cjs → chunk-ZCIRZE37.cjs} +11 -11
  181. package/dist/{chunk-P6H23T43.cjs.map → chunk-ZCIRZE37.cjs.map} +1 -1
  182. package/dist/{chunk-QI7WE46I.cjs → chunk-ZLQSWSJ2.cjs} +11 -11
  183. package/dist/{chunk-QI7WE46I.cjs.map → chunk-ZLQSWSJ2.cjs.map} +1 -1
  184. package/dist/{chunk-NLXOGBRJ.cjs → chunk-ZMRD5DZQ.cjs} +338 -323
  185. package/dist/chunk-ZMRD5DZQ.cjs.map +1 -0
  186. package/dist/{chunk-ILCGLTSA.cjs → chunk-ZSWPZ23K.cjs} +4 -4
  187. package/dist/{chunk-ILCGLTSA.cjs.map → chunk-ZSWPZ23K.cjs.map} +1 -1
  188. package/dist/{chunk-IDCKSLYH.js → chunk-ZZMZWBR6.js} +3 -3
  189. package/dist/{chunk-IDCKSLYH.js.map → chunk-ZZMZWBR6.js.map} +1 -1
  190. package/dist/compact-session-QV57KR66.cjs +59 -0
  191. package/dist/{compact-session-GJXJD73F.cjs.map → compact-session-QV57KR66.cjs.map} +1 -1
  192. package/dist/compact-session-RIGOWC4Y.js +22 -0
  193. package/dist/{compact-session-TSMQOIHO.js.map → compact-session-RIGOWC4Y.js.map} +1 -1
  194. package/dist/compaction.cjs +17 -17
  195. package/dist/compaction.js +4 -4
  196. package/dist/concurrency.cjs +7 -7
  197. package/dist/concurrency.js +5 -5
  198. package/dist/context-AGQ3DIZU.cjs +24 -0
  199. package/dist/{context-LCKNH2XI.cjs.map → context-AGQ3DIZU.cjs.map} +1 -1
  200. package/dist/context-GQRFBCLP.js +7 -0
  201. package/dist/{context-MZSKGKYR.js.map → context-GQRFBCLP.js.map} +1 -1
  202. package/dist/cron.cjs +36 -36
  203. package/dist/cron.js +35 -35
  204. package/dist/errors.cjs +22 -22
  205. package/dist/errors.js +3 -3
  206. package/dist/eval.cjs +41 -41
  207. package/dist/eval.js +35 -35
  208. package/dist/{executor-ZERJ3DGN.cjs → executor-6CYCA7MI.cjs} +25 -25
  209. package/dist/{executor-ZERJ3DGN.cjs.map → executor-6CYCA7MI.cjs.map} +1 -1
  210. package/dist/{executor-BMEHFOXZ.js → executor-QSEC3MRH.js} +8 -8
  211. package/dist/{executor-BMEHFOXZ.js.map → executor-QSEC3MRH.js.map} +1 -1
  212. package/dist/filesystem/index.cjs +8 -8
  213. package/dist/filesystem/index.js +4 -4
  214. package/dist/fs-session-store-4PIHT5UX.cjs +20 -0
  215. package/dist/{fs-session-store-XZ7ZTB3A.cjs.map → fs-session-store-4PIHT5UX.cjs.map} +1 -1
  216. package/dist/fs-session-store-NM6YSTE2.js +11 -0
  217. package/dist/{fs-session-store-4BHGIWRE.js.map → fs-session-store-NM6YSTE2.js.map} +1 -1
  218. package/dist/generate-object-GUNAUVBX.js +8 -0
  219. package/dist/{generate-object-N5MDZUJI.js.map → generate-object-GUNAUVBX.js.map} +1 -1
  220. package/dist/generate-object-R7HTMW7F.cjs +21 -0
  221. package/dist/{generate-object-PGSP5U7N.cjs.map → generate-object-R7HTMW7F.cjs.map} +1 -1
  222. package/dist/index-manager-RBDHP3PM.js +17 -0
  223. package/dist/{index-manager-ACEQG3IJ.js.map → index-manager-RBDHP3PM.js.map} +1 -1
  224. package/dist/index-manager-UZBF22BJ.cjs +26 -0
  225. package/dist/{index-manager-6TEEIWM7.cjs.map → index-manager-UZBF22BJ.cjs.map} +1 -1
  226. package/dist/index.cjs +139 -139
  227. package/dist/index.js +50 -50
  228. package/dist/{inject-session-ZCQUB3IT.js → inject-session-DAR7OUCW.js} +8 -8
  229. package/dist/{inject-session-ZCQUB3IT.js.map → inject-session-DAR7OUCW.js.map} +1 -1
  230. package/dist/{inject-session-PPSO2IDD.cjs → inject-session-WQKMC3GR.cjs} +10 -10
  231. package/dist/{inject-session-PPSO2IDD.cjs.map → inject-session-WQKMC3GR.cjs.map} +1 -1
  232. package/dist/internal/memory/adapters/index.cjs +9 -9
  233. package/dist/internal/memory/adapters/index.js +8 -8
  234. package/dist/internal/memory/storage/index.cjs +39 -39
  235. package/dist/internal/memory/storage/index.js +10 -10
  236. package/dist/internal/persistence/index.cjs +21 -21
  237. package/dist/internal/persistence/index.js +7 -7
  238. package/dist/internal/security/index.cjs +14 -14
  239. package/dist/internal/security/index.js +4 -4
  240. package/dist/judge-call-LAHMBJ57.cjs +23 -0
  241. package/dist/{judge-call-EGYRC2RE.cjs.map → judge-call-LAHMBJ57.cjs.map} +1 -1
  242. package/dist/judge-call-LVXABPS3.js +6 -0
  243. package/dist/{judge-call-DWHAJATE.js.map → judge-call-LVXABPS3.js.map} +1 -1
  244. package/dist/mcp-auth.cjs +15 -15
  245. package/dist/mcp-auth.js +5 -5
  246. package/dist/models.cjs +22 -22
  247. package/dist/models.js +7 -7
  248. package/dist/path-safety.cjs +11 -11
  249. package/dist/path-safety.js +4 -4
  250. package/dist/persistence.cjs +28 -28
  251. package/dist/persistence.js +9 -9
  252. package/dist/project.cjs +6 -6
  253. package/dist/project.js +4 -4
  254. package/dist/providers.cjs +9 -9
  255. package/dist/providers.js +7 -7
  256. package/dist/registry-75W33OGL.js +10 -0
  257. package/dist/{registry-VFP3WWQP.js.map → registry-75W33OGL.js.map} +1 -1
  258. package/dist/registry-V7BDQ6QB.cjs +47 -0
  259. package/dist/{registry-VFKX7WOP.cjs.map → registry-V7BDQ6QB.cjs.map} +1 -1
  260. package/dist/retry.cjs +5 -5
  261. package/dist/retry.js +4 -4
  262. package/dist/sandbox/index.cjs +7 -7
  263. package/dist/sandbox/index.js +3 -3
  264. package/dist/server/errors-envelope.cjs +15 -15
  265. package/dist/server/errors-envelope.js +4 -4
  266. package/dist/session-transcript-6WNITKRE.cjs +63 -0
  267. package/dist/{session-transcript-HF5GEU5M.cjs.map → session-transcript-6WNITKRE.cjs.map} +1 -1
  268. package/dist/session-transcript-XAEKW6P7.js +6 -0
  269. package/dist/{session-transcript-P462ZRHX.js.map → session-transcript-XAEKW6P7.js.map} +1 -1
  270. package/dist/skills.cjs +8 -8
  271. package/dist/skills.js +6 -6
  272. package/dist/stream-object-UF4QRQRU.js +8 -0
  273. package/dist/{stream-object-L57K4OFS.js.map → stream-object-UF4QRQRU.js.map} +1 -1
  274. package/dist/stream-object-ZJTQNKY3.cjs +21 -0
  275. package/dist/{stream-object-BUCF5PHO.cjs.map → stream-object-ZJTQNKY3.cjs.map} +1 -1
  276. package/dist/subagents-loader-CRT5LLL3.js +8 -0
  277. package/dist/{subagents-loader-6ATCDEKN.js.map → subagents-loader-CRT5LLL3.js.map} +1 -1
  278. package/dist/subagents-loader-YEUFFPAL.cjs +17 -0
  279. package/dist/{subagents-loader-X5QKODCL.cjs.map → subagents-loader-YEUFFPAL.cjs.map} +1 -1
  280. package/dist/subagents-loader.cjs +7 -7
  281. package/dist/subagents-loader.js +5 -5
  282. package/dist/subscription/index.cjs +4 -4
  283. package/dist/subscription/index.js +3 -3
  284. package/dist/task-store.cjs +8 -8
  285. package/dist/task-store.js +5 -5
  286. package/dist/workflow.cjs +28 -28
  287. package/dist/workflow.js +7 -7
  288. package/package.json +1 -1
  289. package/dist/agent-536OOESZ.js +0 -57
  290. package/dist/agent-5KYMG63I.cjs +0 -66
  291. package/dist/agent-session-store-G2BMUZQV.js +0 -7
  292. package/dist/agent-session-store-WAKLOKWK.cjs +0 -24
  293. package/dist/chunk-6HTXPPHK.cjs +0 -18
  294. package/dist/chunk-CHKH5452.js.map +0 -1
  295. package/dist/chunk-NLXOGBRJ.cjs.map +0 -1
  296. package/dist/chunk-NUKRL3I6.cjs.map +0 -1
  297. package/dist/chunk-T7O6K6PX.js.map +0 -1
  298. package/dist/compact-session-GJXJD73F.cjs +0 -59
  299. package/dist/compact-session-TSMQOIHO.js +0 -22
  300. package/dist/context-LCKNH2XI.cjs +0 -24
  301. package/dist/context-MZSKGKYR.js +0 -7
  302. package/dist/fs-session-store-4BHGIWRE.js +0 -11
  303. package/dist/fs-session-store-XZ7ZTB3A.cjs +0 -20
  304. package/dist/generate-object-N5MDZUJI.js +0 -8
  305. package/dist/generate-object-PGSP5U7N.cjs +0 -21
  306. package/dist/index-manager-6TEEIWM7.cjs +0 -26
  307. package/dist/index-manager-ACEQG3IJ.js +0 -17
  308. package/dist/judge-call-DWHAJATE.js +0 -6
  309. package/dist/judge-call-EGYRC2RE.cjs +0 -23
  310. package/dist/registry-VFKX7WOP.cjs +0 -47
  311. package/dist/registry-VFP3WWQP.js +0 -10
  312. package/dist/session-transcript-HF5GEU5M.cjs +0 -63
  313. package/dist/session-transcript-P462ZRHX.js +0 -6
  314. package/dist/stream-object-BUCF5PHO.cjs +0 -21
  315. package/dist/stream-object-L57K4OFS.js +0 -8
  316. package/dist/subagents-loader-6ATCDEKN.js +0 -8
  317. package/dist/subagents-loader-X5QKODCL.cjs +0 -17
@@ -1,5 +1,5 @@
1
- import { ConfigurationError } from './chunk-IDCKSLYH.js';
2
- import { diag } from './chunk-T7O6K6PX.js';
1
+ import { ConfigurationError } from './chunk-ZZMZWBR6.js';
2
+ import { diag } from './chunk-XEQ3TM66.js';
3
3
  import { mkdir, rename } from 'fs/promises';
4
4
  import { dirname } from 'path';
5
5
 
@@ -117,5 +117,5 @@ async function renameAside(filePath, label) {
117
117
  }
118
118
 
119
119
  export { applyWalWithFallback, isCorruptionError, openSqliteResilient };
120
- //# sourceMappingURL=chunk-AMFXSENK.js.map
121
- //# sourceMappingURL=chunk-AMFXSENK.js.map
120
+ //# sourceMappingURL=chunk-LWGSI6M3.js.map
121
+ //# sourceMappingURL=chunk-LWGSI6M3.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/persistence/sqlite-wal.ts","../src/internal/persistence/sqlite-open.ts"],"names":[],"mappings":";;;;;;AA+CA,IAAM,YAAA,uBAAmB,GAAA,EAAY;AAU9B,SAAS,oBAAA,CAAqB,IAAmB,KAAA,EAA+B;AACrF,EAAA,IAAI;AACF,IAAA,MAAM,SAAS,EAAA,CAAG,MAAA,CAAO,sBAAsB,EAAE,MAAA,EAAQ,MAAM,CAAA;AAC/D,IAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,CAAO,WAAA,OAAkB,KAAA,EAAO;AAChE,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,QAAA,EAAU,KAAA,EAAM;AAAA,IACxC;AACA,IAAA,WAAA,CAAY,KAAA,EAAO,CAAA,KAAA,EAAQ,MAAA,CAAO,MAAM,CAAC,CAAA,kBAAA,CAAoB,CAAA;AAAA,EAC/D,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,MAAM,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAC3D,IAAA,WAAA,CAAY,OAAO,GAAG,CAAA;AAAA,EACxB;AAEA,EAAA,EAAA,CAAG,OAAO,uBAAuB,CAAA;AACjC,EAAA,OAAO,EAAE,IAAA,EAAM,QAAA,EAAU,QAAA,EAAU,IAAA,EAAK;AAC1C;AAEA,SAAS,WAAA,CAAY,OAAe,MAAA,EAAsB;AACxD,EAAA,IAAI,YAAA,CAAa,GAAA,CAAI,KAAK,CAAA,EAAG;AAC7B,EAAA,YAAA,CAAa,IAAI,KAAK,CAAA;AACtB,EAAA,IAAA;AAAA,IACE,CAAA,cAAA,EAAiB,KAAK,CAAA,mBAAA,EAAsB,MAAM,CAAA;AAAA;AAAA,GAEpD;AACF;ACdA,eAAsB,oBACpB,OAAA,EACY;AACZ,EAAA,MAAM,KAAA,CAAM,QAAQ,OAAA,CAAQ,QAAQ,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAC1D,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,aAAa,OAAO,CAAA;AAAA,EACnC,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,OAAA,CAAQ,cAAA,KAAmB,KAAA,IAAS,iBAAA,CAAkB,KAAK,CAAA,EAAG;AAChE,MAAA,MAAM,WAAA,CAAY,OAAA,CAAQ,QAAA,EAAU,OAAA,CAAQ,SAAS,QAAQ,CAAA;AAC7D,MAAA,OAAO,MAAM,aAAa,OAAO,CAAA;AAAA,IACnC;AACA,IAAA,MAAM,KAAA;AAAA,EACR;AACF;AAEA,eAAe,aACb,OAAA,EACY;AACZ,EAAA,MAAM,EAAA,GAAK,MAAM,UAAA,CAAc,OAAA,CAAQ,QAAQ,CAAA;AAG/C,EAAA,oBAAA,CAAqB,EAAA,EAAI,OAAA,CAAQ,KAAA,IAAS,QAAQ,CAAA;AAClD,EAAA,MAAM,OAAA,CAAQ,SAAS,EAAE,CAAA;AACzB,EAAA,OAAO,EAAA;AACT;AAOA,IAAI,qBAAA;AAcJ,SAAS,gBAAgB,EAAA,EAKH;AACpB,EAAA,MAAM,MAAA,GAAS,CAAC,SAAA,EAAmB,OAAA,KAA4C;AAC7E,IAAA,MAAM,IAAA,GAAO,EAAA,CAAG,OAAA,CAAQ,CAAA,OAAA,EAAU,SAAS,CAAA,CAAE,CAAA;AAG7C,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,IAAI,OAAA,EAAS,WAAW,IAAA,EAAM;AAC5B,MAAA,OAAO,QAAQ,MAAA,GAAY,MAAA,GAAY,OAAO,MAAA,CAAO,GAAG,EAAE,CAAC,CAAA;AAAA,IAC7D;AACA,IAAA,OAAO,GAAA,KAAQ,MAAA,GAAY,EAAC,GAAI,CAAC,GAAG,CAAA;AAAA,EACtC,CAAA;AACA,EAAA,OAAO,IAAI,MAAM,EAAA,EAAoC;AAAA,IACnD,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU;AAC1B,MAAA,IAAI,IAAA,KAAS,UAAU,OAAO,MAAA;AAC9B,MAAA,IAAI,IAAA,KAAS,eAAA,IAAmB,OAAO,EAAA,CAAG,kBAAkB,UAAA,EAAY;AACtE,QAAA,OAAO,MAAM;AACX,UAAA,MAAM,IAAI,KAAA;AAAA,YACR;AAAA,WACF;AAAA,QACF,CAAA;AAAA,MACF;AACA,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,MAAM,QAAQ,CAAA;AAChD,MAAA,OAAO,OAAO,KAAA,KAAU,UAAA,GACnB,KAAA,CAAuC,IAAA,CAAK,MAAM,CAAA,GACnD,KAAA;AAAA,IACN;AAAA,GACD,CAAA;AACH;AAOA,eAAe,WAAwC,QAAA,EAA8B;AACnF,EAAA,IAAI,iBAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAM,MAAO,OAAO,qBAAA,EAAuB,aAAA,IAAgB,IAAK,OAAO,gBAAgB,CAAA,CAAA;AAGvF,IAAA,MAAM,IAAA,GAAO,IAAI,OAAA,IAAW,GAAA;AAC5B,IAAA,IAAI,OAAO,SAAS,UAAA,EAAY;AAC9B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gDAAA,EAAmD,OAAO,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,IACnF;AACA,IAAA,OAAO,IAAK,KAAuC,QAAQ,CAAA;AAAA,EAC7D,SAAS,KAAA,EAAO;AACd,IAAA,iBAAA,GAAoB,KAAA;AAAA,EACtB;AAKA,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAO,OAAO,qBAAA,EAAuB,UAAA,QACzC,OAAA,CAAQ,OAAA;AAAA,MACL,OAAA,CAA2D,gBAAA;AAAA,QAC1D;AAAA,YAEC,MAAM;AACL,QAAA,MAAM,IAAI,MAAM,gDAAgD,CAAA;AAAA,MAClE,CAAA;AAAG,KACP,CAAA;AASF,IAAA,OAAO,eAAA,CAAgB,IAAI,GAAA,CAAI,YAAA,CAAa,QAAQ,CAAC,CAAA;AAAA,EACvD,SAAS,eAAA,EAAiB;AACxB,IAAA,MAAM,IACJ,iBAAA,YAA6B,KAAA,GAAQ,iBAAA,CAAkB,OAAA,GAAU,OAAO,iBAAiB,CAAA;AAC3F,IAAA,MAAM,IAAI,eAAA,YAA2B,KAAA,GAAQ,eAAA,CAAgB,OAAA,GAAU,OAAO,eAAe,CAAA;AAC7F,IAAA,MAAM,IAAI,kBAAA;AAAA,MACR,CAAA,4HAAA,EAA+H,CAAC,CAAA,eAAA,EAAkB,CAAC,CAAA,CAAA;AAAA,MACnJ,EAAE,IAAA,EAAM,2BAAA,EAA6B,KAAA,EAAO,eAAA;AAAgB,KAC9D;AAAA,EACF;AACF;AAGO,SAAS,kBAAkB,KAAA,EAAyB;AACzD,EAAA,IAAI,EAAE,KAAA,YAAiB,KAAA,CAAA,EAAQ,OAAO,KAAA;AACtC,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,OAAA,CAAQ,WAAA,EAAY;AACtC,EAAA,OACE,GAAA,CAAI,QAAA,CAAS,WAAW,CAAA,IACxB,IAAI,QAAA,CAAS,gBAAgB,CAAA,IAC7B,GAAA,CAAI,QAAA,CAAS,WAAW,CAAA,IACxB,GAAA,CAAI,SAAS,yBAAyB,CAAA;AAE1C;AAEA,eAAe,WAAA,CAAY,UAAkB,KAAA,EAA8B;AACzE,EAAA,MAAM,YAAY,CAAA,EAAG,QAAQ,CAAA,SAAA,EAAY,IAAA,CAAK,KAAK,CAAA,CAAA;AACnD,EAAA,MAAM,OAAO,QAAA,EAAU,SAAS,CAAA,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AACvD,EAAA,MAAM,MAAA,CAAO,CAAA,EAAG,QAAQ,CAAA,IAAA,CAAA,EAAQ,CAAA,EAAG,SAAS,CAAA,IAAA,CAAM,CAAA,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AACzE,EAAA,MAAM,MAAA,CAAO,CAAA,EAAG,QAAQ,CAAA,IAAA,CAAA,EAAQ,CAAA,EAAG,SAAS,CAAA,IAAA,CAAM,CAAA,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AACzE,EAAA,IAAA;AAAA,IACE,CAAA,cAAA,EAAiB,KAAK,CAAA,oCAAA,EAAuC,SAAS,CAAA;AAAA;AAAA,GACxE;AACF","file":"chunk-AMFXSENK.js","sourcesContent":["/**\n * SQLite WAL mode helper with NFS/SMB/FUSE fallback to DELETE (ADR D63).\n *\n * WAL is faster (concurrent readers + one writer) but unsupported on some\n * network/FUSE filesystems. Try WAL; if the pragma returns something else\n * or throws, fall back to DELETE journal mode. Warn one time per label.\n *\n * This block is the MODULE header and must stay at offset 0. Sitting below the import it became a\n * leading comment of the first declaration instead, which is how its tag deleted `PragmaCapable`\n * from the emitted `.d.ts` while `applyWalWithFallback` — which names it — survived.\n */\n\nimport { diag } from \"../diagnostics.js\";\n\n/**\n * The narrow slice of a SQLite handle this module needs: anything with a `pragma()` method, which\n * `better-sqlite3` satisfies without being named here.\n *\n * Not exported, but it appears in the signature of `applyWalWithFallback`, so it is emitted into\n * the published declarations and a consumer can structurally satisfy it.\n */\ninterface PragmaCapable {\n pragma: (statement: string, options?: { simple?: boolean }) => unknown;\n}\n\n/**\n * What journal mode a connection ended up in after `applyWalWithFallback`.\n *\n * `mode` is the mode actually in effect, never the one that was requested. `fellBack` is `true`\n * only when WAL was attempted and refused — either the pragma threw or it reported a mode other\n * than `wal` — and the connection was put into DELETE instead.\n *\n * `fellBack: true` is normal on NFS, SMB and FUSE, where WAL needs shared memory the filesystem\n * does not provide. It is not an error and nothing further is required of the caller; the\n * consequence is slower concurrent access, since DELETE mode does not allow readers alongside a\n * writer. Treat it as a signal about the storage, not about the database.\n *\n * @public — re-exported from the semver-protected `@theokit/sdk/persistence` barrel, and (for\n * back-compat) from the semver-exempt `@theokit/sdk/internal/persistence` alias.\n */\nexport interface WalApplyResult {\n /** Final journal_mode actually in effect. */\n mode: \"wal\" | \"delete\";\n /** True if we wanted WAL but the filesystem refused. */\n fellBack: boolean;\n}\n\nconst warnedLabels = new Set<string>();\n\n/**\n * Apply WAL mode with DELETE fallback. Idempotent — safe to call multiple\n * times on the same connection.\n *\n * @param db any `pragma()`-capable SQLite handle (e.g., `better-sqlite3`)\n * @param label short identifier used in the warning (e.g., \"memory-index\")\n *\n */\nexport function applyWalWithFallback(db: PragmaCapable, label: string): WalApplyResult {\n try {\n const result = db.pragma(\"journal_mode = WAL\", { simple: true });\n if (typeof result === \"string\" && result.toLowerCase() === \"wal\") {\n return { mode: \"wal\", fellBack: false };\n }\n logFallback(label, `got \"${String(result)}\" instead of \"wal\"`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logFallback(label, msg);\n }\n\n db.pragma(\"journal_mode = DELETE\");\n return { mode: \"delete\", fellBack: true };\n}\n\nfunction logFallback(label: string, reason: string): void {\n if (warnedLabels.has(label)) return;\n warnedLabels.add(label);\n diag(\n `[theokit-sdk] ${label}: WAL unavailable (${reason}); using DELETE journal mode. ` +\n \"This is normal on NFS/SMB/FUSE; expect slightly slower concurrent access.\\n\",\n );\n}\n\n/**\n * Test helper — clears the warn-once registry.\n *\n * @internal\n */\nexport function _resetWalWarnings(): void {\n warnedLabels.clear();\n}\n","/**\n * Resilient SQLite open (plan m0-foundation-expose-primitives, M0-5).\n *\n * Generalizes the driver-load + WAL-apply + corruption-recovery logic that was\n * duplicated (byte-identical) across `sdk/internal/memory/index-db.ts` and\n * `sdk-memory/internal/index/index-db.ts`. Schema-agnostic: the caller applies\n * its own PRAGMA/SCHEMA via the `onOpen` callback.\n *\n * Corruption recovery (EC-7): when opening fails with a \"malformed\" / \"not a\n * database\" / \"encrypted\" error and `recoverCorrupt` is not false, the file is\n * renamed aside to `<path>.corrupt-<ts>` (plus its WAL/SHM siblings) and a fresh\n * DB is opened. The corrupt file is renamed, NOT backed up — the timestamped\n * `.corrupt-*` file is kept for manual recovery.\n *\n * @internal — public via `@theokit/sdk/internal/persistence` (semver-exempt)\n */\n\nimport { mkdir, rename } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { ConfigurationError } from \"../../errors.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { applyWalWithFallback } from \"./sqlite-wal.js\";\n\n/** Minimal SQLite handle surface every driver (`better-sqlite3`) exposes. */\nexport interface ResilientSqliteDb {\n /** SQLite `pragma()` access (used by `applyWalWithFallback`). */\n pragma(statement: string, options?: { simple?: boolean }): unknown;\n exec(sql: string): void;\n close(): void;\n}\n\n/**\n * Input to {@link openSqliteResilient}.\n *\n * The trap is `recoverCorrupt`, whose default is ON. When the driver reports a corrupt or encrypted\n * database, the file is renamed aside and a FRESH one is opened — so the call SUCCEEDS and hands\n * back an EMPTY database. The old bytes survive on disk under the renamed path, but a caller that\n * treats a resolved promise as \"my data is here\" is wrong exactly when it matters. Pass\n * `recoverCorrupt: false` to get the corruption error thrown instead.\n *\n * Semver-exempt: reachable via the '@theokit/sdk/internal/persistence' sub-path, which the package\n * declares in 'exports' but does NOT cover with its semver contract.\n *\n * @typeParam T - the concrete DB handle the driver returns; defaults to {@link ResilientSqliteDb}\n */\nexport interface OpenSqliteResilientOptions<T extends ResilientSqliteDb> {\n /** Absolute path to the SQLite file. Parent directories are created. */\n filePath: string;\n /**\n * Called after the driver is open and WAL is applied, before the handle is\n * returned. Apply PRAGMA/SCHEMA statements here. Errors propagate.\n */\n onOpen?: (db: T) => void | Promise<void>;\n /** Label used in the WAL-fallback warning and corruption-recovery log. Default \"sqlite\". */\n label?: string;\n /** When true (default) a corruption error renames the file aside and rebuilds. */\n recoverCorrupt?: boolean;\n}\n\n/**\n * Open a SQLite file with WAL (+ DELETE fallback) and corruption recovery.\n *\n * @typeParam T - the concrete DB handle type the driver returns (defaults to the\n * minimal {@link ResilientSqliteDb} surface)\n */\nexport async function openSqliteResilient<T extends ResilientSqliteDb = ResilientSqliteDb>(\n options: OpenSqliteResilientOptions<T>,\n): Promise<T> {\n await mkdir(dirname(options.filePath), { recursive: true });\n try {\n return await openConcrete(options);\n } catch (cause) {\n if (options.recoverCorrupt !== false && isCorruptionError(cause)) {\n await renameAside(options.filePath, options.label ?? \"sqlite\");\n return await openConcrete(options);\n }\n throw cause;\n }\n}\n\nasync function openConcrete<T extends ResilientSqliteDb>(\n options: OpenSqliteResilientOptions<T>,\n): Promise<T> {\n const db = await loadDriver<T>(options.filePath);\n // Apply WAL with NFS/SMB/FUSE fallback BEFORE schema so the journal mode is\n // set for the whole session.\n applyWalWithFallback(db, options.label ?? \"sqlite\");\n await options.onOpen?.(db);\n return db;\n}\n\n/** Injectable driver loaders (tests simulate a consumer env without better-sqlite3). */\ninterface DriverLoaders {\n betterSqlite3?: () => Promise<unknown>;\n nodeSqlite?: () => Promise<unknown>;\n}\nlet driverLoaderOverrides: DriverLoaders | undefined;\n\n/** Test-only. @internal */\nexport function _setDriverLoadersForTests(overrides: DriverLoaders | undefined): void {\n driverLoaderOverrides = overrides;\n}\n\n/**\n * Adapt `node:sqlite`'s `DatabaseSync` to the better-sqlite3 surface this module's callers use\n * (`prepare/get/all/run`, `exec`, `close`, `pragma`, `loadExtension`). The error message below has\n * ALWAYS promised this fallback (\"or run on Node 22.5+ for built-in node:sqlite\") — before the\n * flicker-bug fix the promise was fabricated: only better-sqlite3 was ever tried, so every consumer\n * without the optional native dep lost memory tools AND got a per-turn stderr WARN.\n */\nfunction adaptNodeSqlite(db: {\n prepare(sql: string): unknown;\n exec(sql: string): void;\n close(): void;\n loadExtension?: (path: string) => void;\n}): ResilientSqliteDb {\n const pragma = (statement: string, options?: { simple?: boolean }): unknown => {\n const stmt = db.prepare(`PRAGMA ${statement}`) as {\n get(): Record<string, unknown> | undefined;\n };\n const row = stmt.get();\n if (options?.simple === true) {\n return row === undefined ? undefined : Object.values(row)[0];\n }\n return row === undefined ? [] : [row];\n };\n return new Proxy(db as unknown as ResilientSqliteDb, {\n get(target, prop, receiver) {\n if (prop === \"pragma\") return pragma;\n if (prop === \"loadExtension\" && typeof db.loadExtension !== \"function\") {\n return () => {\n throw new Error(\n \"SQLite extension loading is unavailable on the node:sqlite fallback — install better-sqlite3 for sqlite-vec\",\n );\n };\n }\n const value = Reflect.get(target, prop, receiver) as unknown;\n return typeof value === \"function\"\n ? (value as (...a: unknown[]) => unknown).bind(target)\n : value;\n },\n });\n}\n\n// PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n// sweeping these files (a nested root under refactor/). It is not new code and was not touched\n// by M75; refactoring SDK internals without review would trade a visible problem for a diff\n// risky. Tracked in usetheodev/theokit-sdk#151.\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: see the reason just above\nasync function loadDriver<T extends ResilientSqliteDb>(filePath: string): Promise<T> {\n let betterSqliteCause: unknown;\n try {\n const mod = (await (driverLoaderOverrides?.betterSqlite3?.() ?? import(\"better-sqlite3\"))) as {\n default?: unknown;\n };\n const Ctor = mod.default ?? mod;\n if (typeof Ctor !== \"function\") {\n throw new Error(`better-sqlite3 export is not a constructor (got ${typeof Ctor})`);\n }\n return new (Ctor as new (path: string) => unknown)(filePath) as T;\n } catch (cause) {\n betterSqliteCause = cause;\n }\n // Fallback: the Node 22.5+ built-in driver (the path the error message documents).\n // `process.getBuiltinModule` (Node 22.3+) instead of `import(\"node:sqlite\")` — bundlers that\n // predate the sqlite builtin rewrite the import specifier to a bare \"sqlite\" package (proven in\n // the published dist: \"Cannot find package 'sqlite'\"), while getBuiltinModule is opaque to them.\n try {\n const mod = (await (driverLoaderOverrides?.nodeSqlite?.() ??\n Promise.resolve(\n (process as { getBuiltinModule?: (id: string) => unknown }).getBuiltinModule?.(\n \"node:sqlite\",\n ) ??\n (() => {\n throw new Error(\"node:sqlite built-in unavailable (Node < 22.3)\");\n })(),\n ))) as {\n DatabaseSync: new (\n path: string,\n ) => {\n prepare(sql: string): unknown;\n exec(sql: string): void;\n close(): void;\n };\n };\n return adaptNodeSqlite(new mod.DatabaseSync(filePath)) as T;\n } catch (nodeSqliteCause) {\n const b =\n betterSqliteCause instanceof Error ? betterSqliteCause.message : String(betterSqliteCause);\n const n = nodeSqliteCause instanceof Error ? nodeSqliteCause.message : String(nodeSqliteCause);\n throw new ConfigurationError(\n `Failed to load SQLite driver. Install \\`better-sqlite3\\` or run on Node 22.5+ for built-in \\`node:sqlite\\`. better-sqlite3: ${b}; node:sqlite: ${n}`,\n { code: \"sqlite_driver_unavailable\", cause: nodeSqliteCause },\n );\n }\n}\n\n/** True when an open error indicates an unreadable / corrupt database file. */\nexport function isCorruptionError(cause: unknown): boolean {\n if (!(cause instanceof Error)) return false;\n const msg = cause.message.toLowerCase();\n return (\n msg.includes(\"malformed\") ||\n msg.includes(\"not a database\") ||\n msg.includes(\"encrypted\") ||\n msg.includes(\"disk image is malformed\")\n );\n}\n\nasync function renameAside(filePath: string, label: string): Promise<void> {\n const asidePath = `${filePath}.corrupt-${Date.now()}`;\n await rename(filePath, asidePath).catch(() => undefined);\n await rename(`${filePath}-wal`, `${asidePath}-wal`).catch(() => undefined);\n await rename(`${filePath}-shm`, `${asidePath}-shm`).catch(() => undefined);\n diag(\n `[theokit-sdk] ${label} database corrupt; renamed aside to ${asidePath} and rebuilt schema\\n`,\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/persistence/sqlite-wal.ts","../src/internal/persistence/sqlite-open.ts"],"names":[],"mappings":"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","file":"chunk-LWGSI6M3.js","sourcesContent":["/**\n * SQLite WAL mode helper with NFS/SMB/FUSE fallback to DELETE (ADR D63).\n *\n * WAL is faster (concurrent readers + one writer) but unsupported on some\n * network/FUSE filesystems. Try WAL; if the pragma returns something else\n * or throws, fall back to DELETE journal mode. Warn one time per label.\n *\n * This block is the MODULE header and must stay at offset 0. Sitting below the import it became a\n * leading comment of the first declaration instead, which is how its tag deleted `PragmaCapable`\n * from the emitted `.d.ts` while `applyWalWithFallback` — which names it — survived.\n */\n\nimport { diag } from \"../diagnostics.js\";\n\n/**\n * The narrow slice of a SQLite handle this module needs: anything with a `pragma()` method, which\n * `better-sqlite3` satisfies without being named here.\n *\n * Not exported, but it appears in the signature of `applyWalWithFallback`, so it is emitted into\n * the published declarations and a consumer can structurally satisfy it.\n */\ninterface PragmaCapable {\n pragma: (statement: string, options?: { simple?: boolean }) => unknown;\n}\n\n/**\n * What journal mode a connection ended up in after `applyWalWithFallback`.\n *\n * `mode` is the mode actually in effect, never the one that was requested. `fellBack` is `true`\n * only when WAL was attempted and refused — either the pragma threw or it reported a mode other\n * than `wal` — and the connection was put into DELETE instead.\n *\n * `fellBack: true` is normal on NFS, SMB and FUSE, where WAL needs shared memory the filesystem\n * does not provide. It is not an error and nothing further is required of the caller; the\n * consequence is slower concurrent access, since DELETE mode does not allow readers alongside a\n * writer. Treat it as a signal about the storage, not about the database.\n *\n * @public — re-exported from the semver-protected `@theokit/sdk/persistence` barrel, and (for\n * back-compat) from the semver-exempt `@theokit/sdk/internal/persistence` alias.\n */\nexport interface WalApplyResult {\n /** Final journal_mode actually in effect. */\n mode: \"wal\" | \"delete\";\n /** True if we wanted WAL but the filesystem refused. */\n fellBack: boolean;\n}\n\nconst warnedLabels = new Set<string>();\n\n/**\n * Apply WAL mode with DELETE fallback. Idempotent — safe to call multiple\n * times on the same connection.\n *\n * @param db any `pragma()`-capable SQLite handle (e.g., `better-sqlite3`)\n * @param label short identifier used in the warning (e.g., \"memory-index\")\n *\n */\nexport function applyWalWithFallback(db: PragmaCapable, label: string): WalApplyResult {\n try {\n const result = db.pragma(\"journal_mode = WAL\", { simple: true });\n if (typeof result === \"string\" && result.toLowerCase() === \"wal\") {\n return { mode: \"wal\", fellBack: false };\n }\n logFallback(label, `got \"${String(result)}\" instead of \"wal\"`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logFallback(label, msg);\n }\n\n db.pragma(\"journal_mode = DELETE\");\n return { mode: \"delete\", fellBack: true };\n}\n\nfunction logFallback(label: string, reason: string): void {\n if (warnedLabels.has(label)) return;\n warnedLabels.add(label);\n diag(\n `[theokit-sdk] ${label}: WAL unavailable (${reason}); using DELETE journal mode. ` +\n \"This is normal on NFS/SMB/FUSE; expect slightly slower concurrent access.\\n\",\n );\n}\n\n/**\n * Test helper — clears the warn-once registry.\n *\n * @internal\n */\nexport function _resetWalWarnings(): void {\n warnedLabels.clear();\n}\n","/**\n * Resilient SQLite open (plan m0-foundation-expose-primitives, M0-5).\n *\n * Generalizes the driver-load + WAL-apply + corruption-recovery logic that was\n * duplicated (byte-identical) across `sdk/internal/memory/index-db.ts` and\n * `sdk-memory/internal/index/index-db.ts`. Schema-agnostic: the caller applies\n * its own PRAGMA/SCHEMA via the `onOpen` callback.\n *\n * Corruption recovery (EC-7): when opening fails with a \"malformed\" / \"not a\n * database\" / \"encrypted\" error and `recoverCorrupt` is not false, the file is\n * renamed aside to `<path>.corrupt-<ts>` (plus its WAL/SHM siblings) and a fresh\n * DB is opened. The corrupt file is renamed, NOT backed up — the timestamped\n * `.corrupt-*` file is kept for manual recovery.\n *\n * @internal — public via `@theokit/sdk/internal/persistence` (semver-exempt)\n */\n\nimport { mkdir, rename } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport { ConfigurationError } from \"../../errors.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { applyWalWithFallback } from \"./sqlite-wal.js\";\n\n/** Minimal SQLite handle surface every driver (`better-sqlite3`) exposes. */\nexport interface ResilientSqliteDb {\n /** SQLite `pragma()` access (used by `applyWalWithFallback`). */\n pragma(statement: string, options?: { simple?: boolean }): unknown;\n exec(sql: string): void;\n close(): void;\n}\n\n/**\n * Input to {@link openSqliteResilient}.\n *\n * The trap is `recoverCorrupt`, whose default is ON. When the driver reports a corrupt or encrypted\n * database, the file is renamed aside and a FRESH one is opened — so the call SUCCEEDS and hands\n * back an EMPTY database. The old bytes survive on disk under the renamed path, but a caller that\n * treats a resolved promise as \"my data is here\" is wrong exactly when it matters. Pass\n * `recoverCorrupt: false` to get the corruption error thrown instead.\n *\n * Semver-exempt: reachable via the '@theokit/sdk/internal/persistence' sub-path, which the package\n * declares in 'exports' but does NOT cover with its semver contract.\n *\n * @typeParam T - the concrete DB handle the driver returns; defaults to {@link ResilientSqliteDb}\n */\nexport interface OpenSqliteResilientOptions<T extends ResilientSqliteDb> {\n /** Absolute path to the SQLite file. Parent directories are created. */\n filePath: string;\n /**\n * Called after the driver is open and WAL is applied, before the handle is\n * returned. Apply PRAGMA/SCHEMA statements here. Errors propagate.\n */\n onOpen?: (db: T) => void | Promise<void>;\n /** Label used in the WAL-fallback warning and corruption-recovery log. Default \"sqlite\". */\n label?: string;\n /** When true (default) a corruption error renames the file aside and rebuilds. */\n recoverCorrupt?: boolean;\n}\n\n/**\n * Open a SQLite file with WAL (+ DELETE fallback) and corruption recovery.\n *\n * @typeParam T - the concrete DB handle type the driver returns (defaults to the\n * minimal {@link ResilientSqliteDb} surface)\n */\nexport async function openSqliteResilient<T extends ResilientSqliteDb = ResilientSqliteDb>(\n options: OpenSqliteResilientOptions<T>,\n): Promise<T> {\n await mkdir(dirname(options.filePath), { recursive: true });\n try {\n return await openConcrete(options);\n } catch (cause) {\n if (options.recoverCorrupt !== false && isCorruptionError(cause)) {\n await renameAside(options.filePath, options.label ?? \"sqlite\");\n return await openConcrete(options);\n }\n throw cause;\n }\n}\n\nasync function openConcrete<T extends ResilientSqliteDb>(\n options: OpenSqliteResilientOptions<T>,\n): Promise<T> {\n const db = await loadDriver<T>(options.filePath);\n // Apply WAL with NFS/SMB/FUSE fallback BEFORE schema so the journal mode is\n // set for the whole session.\n applyWalWithFallback(db, options.label ?? \"sqlite\");\n await options.onOpen?.(db);\n return db;\n}\n\n/** Injectable driver loaders (tests simulate a consumer env without better-sqlite3). */\ninterface DriverLoaders {\n betterSqlite3?: () => Promise<unknown>;\n nodeSqlite?: () => Promise<unknown>;\n}\nlet driverLoaderOverrides: DriverLoaders | undefined;\n\n/** Test-only. @internal */\nexport function _setDriverLoadersForTests(overrides: DriverLoaders | undefined): void {\n driverLoaderOverrides = overrides;\n}\n\n/**\n * Adapt `node:sqlite`'s `DatabaseSync` to the better-sqlite3 surface this module's callers use\n * (`prepare/get/all/run`, `exec`, `close`, `pragma`, `loadExtension`). The error message below has\n * ALWAYS promised this fallback (\"or run on Node 22.5+ for built-in node:sqlite\") — before the\n * flicker-bug fix the promise was fabricated: only better-sqlite3 was ever tried, so every consumer\n * without the optional native dep lost memory tools AND got a per-turn stderr WARN.\n */\nfunction adaptNodeSqlite(db: {\n prepare(sql: string): unknown;\n exec(sql: string): void;\n close(): void;\n loadExtension?: (path: string) => void;\n}): ResilientSqliteDb {\n const pragma = (statement: string, options?: { simple?: boolean }): unknown => {\n const stmt = db.prepare(`PRAGMA ${statement}`) as {\n get(): Record<string, unknown> | undefined;\n };\n const row = stmt.get();\n if (options?.simple === true) {\n return row === undefined ? undefined : Object.values(row)[0];\n }\n return row === undefined ? [] : [row];\n };\n return new Proxy(db as unknown as ResilientSqliteDb, {\n get(target, prop, receiver) {\n if (prop === \"pragma\") return pragma;\n if (prop === \"loadExtension\" && typeof db.loadExtension !== \"function\") {\n return () => {\n throw new Error(\n \"SQLite extension loading is unavailable on the node:sqlite fallback — install better-sqlite3 for sqlite-vec\",\n );\n };\n }\n const value = Reflect.get(target, prop, receiver) as unknown;\n return typeof value === \"function\"\n ? (value as (...a: unknown[]) => unknown).bind(target)\n : value;\n },\n });\n}\n\n// PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n// sweeping these files (a nested root under refactor/). It is not new code and was not touched\n// by M75; refactoring SDK internals without review would trade a visible problem for a diff\n// risky. Tracked in usetheodev/theokit-sdk#151.\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: see the reason just above\nasync function loadDriver<T extends ResilientSqliteDb>(filePath: string): Promise<T> {\n let betterSqliteCause: unknown;\n try {\n const mod = (await (driverLoaderOverrides?.betterSqlite3?.() ?? import(\"better-sqlite3\"))) as {\n default?: unknown;\n };\n const Ctor = mod.default ?? mod;\n if (typeof Ctor !== \"function\") {\n throw new Error(`better-sqlite3 export is not a constructor (got ${typeof Ctor})`);\n }\n return new (Ctor as new (path: string) => unknown)(filePath) as T;\n } catch (cause) {\n betterSqliteCause = cause;\n }\n // Fallback: the Node 22.5+ built-in driver (the path the error message documents).\n // `process.getBuiltinModule` (Node 22.3+) instead of `import(\"node:sqlite\")` — bundlers that\n // predate the sqlite builtin rewrite the import specifier to a bare \"sqlite\" package (proven in\n // the published dist: \"Cannot find package 'sqlite'\"), while getBuiltinModule is opaque to them.\n try {\n const mod = (await (driverLoaderOverrides?.nodeSqlite?.() ??\n Promise.resolve(\n (process as { getBuiltinModule?: (id: string) => unknown }).getBuiltinModule?.(\n \"node:sqlite\",\n ) ??\n (() => {\n throw new Error(\"node:sqlite built-in unavailable (Node < 22.3)\");\n })(),\n ))) as {\n DatabaseSync: new (\n path: string,\n ) => {\n prepare(sql: string): unknown;\n exec(sql: string): void;\n close(): void;\n };\n };\n return adaptNodeSqlite(new mod.DatabaseSync(filePath)) as T;\n } catch (nodeSqliteCause) {\n const b =\n betterSqliteCause instanceof Error ? betterSqliteCause.message : String(betterSqliteCause);\n const n = nodeSqliteCause instanceof Error ? nodeSqliteCause.message : String(nodeSqliteCause);\n throw new ConfigurationError(\n `Failed to load SQLite driver. Install \\`better-sqlite3\\` or run on Node 22.5+ for built-in \\`node:sqlite\\`. better-sqlite3: ${b}; node:sqlite: ${n}`,\n { code: \"sqlite_driver_unavailable\", cause: nodeSqliteCause },\n );\n }\n}\n\n/** True when an open error indicates an unreadable / corrupt database file. */\nexport function isCorruptionError(cause: unknown): boolean {\n if (!(cause instanceof Error)) return false;\n const msg = cause.message.toLowerCase();\n return (\n msg.includes(\"malformed\") ||\n msg.includes(\"not a database\") ||\n msg.includes(\"encrypted\") ||\n msg.includes(\"disk image is malformed\")\n );\n}\n\nasync function renameAside(filePath: string, label: string): Promise<void> {\n const asidePath = `${filePath}.corrupt-${Date.now()}`;\n await rename(filePath, asidePath).catch(() => undefined);\n await rename(`${filePath}-wal`, `${asidePath}-wal`).catch(() => undefined);\n await rename(`${filePath}-shm`, `${asidePath}-shm`).catch(() => undefined);\n diag(\n `[theokit-sdk] ${label} database corrupt; renamed aside to ${asidePath} and rebuilt schema\\n`,\n );\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { pluginBundleRoots, projectConfigRoots } from './chunk-UFLD2HEV.js';
2
- import { readWorkspaceDir, parseSimpleYaml } from './chunk-AG5JPQIY.js';
3
- import { ConfigurationError } from './chunk-IDCKSLYH.js';
4
- import { diag } from './chunk-T7O6K6PX.js';
2
+ import { readWorkspaceDir, parseSimpleYaml } from './chunk-LXQ6HKPS.js';
3
+ import { ConfigurationError } from './chunk-ZZMZWBR6.js';
4
+ import { diag } from './chunk-XEQ3TM66.js';
5
5
  import { readdir, readFile } from 'fs/promises';
6
6
  import { join } from 'path';
7
7
 
@@ -165,5 +165,5 @@ function parseFrontmatterFields(frontmatter) {
165
165
  }
166
166
 
167
167
  export { loadSubagents, pluginBundleDirs };
168
- //# sourceMappingURL=chunk-ZHPWGIUX.js.map
169
- //# sourceMappingURL=chunk-ZHPWGIUX.js.map
168
+ //# sourceMappingURL=chunk-LXI4XZEC.js.map
169
+ //# sourceMappingURL=chunk-LXI4XZEC.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/runtime/plugins/plugin-bundles.ts","../src/internal/runtime/skills/subagents-loader.ts"],"names":["join"],"mappings":"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","file":"chunk-ZHPWGIUX.js","sourcesContent":["/**\n * Locating the plugin bundles a project carries.\n *\n * Shared by the skills and subagents loaders, which both need the same answer to \"which folders in\n * this project are plugins\" and would otherwise each grow their own copy of the directory walk.\n *\n * @internal\n */\n\nimport type { Dirent } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pluginBundleRoots } from \"../../persistence/paths.js\";\n\n/**\n * Every plugin folder under the project's plugin roots.\n *\n * Returns the FOLDERS, not their contents — what a bundle contributes (`skills/`, `agents/`) is the\n * caller's business, and a loader that also knew the layout would have to change whenever the other\n * one did.\n *\n * A missing root is not an error: most projects carry no plugins, and treating their absence as a\n * failure would make \"none installed\" indistinguishable from \"the directory could not be read\".\n */\nexport async function pluginBundleDirs(cwd: string): Promise<string[]> {\n const dirs: string[] = [];\n for (const root of pluginBundleRoots(cwd)) {\n let entries: Dirent[];\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) dirs.push(join(root, entry.name));\n }\n }\n return dirs;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\nimport type { AgentDefinition } from \"../../../types/agent.js\";\nimport type { ModelSelection } from \"../../../types/agent-prims.js\";\nimport { diag } from \"../../diagnostics.js\";\nimport { projectConfigRoots } from \"../../persistence/paths.js\";\nimport { readWorkspaceDir } from \"../config/workspace-dir.js\";\nimport { type FrontmatterValue, parseSimpleYaml } from \"../context/yaml-frontmatter.js\";\nimport { pluginBundleDirs } from \"../plugins/plugin-bundles.js\";\n\n/**\n * Load file-based subagents from `.theokit/agents/*.md` and merge with\n * inline definitions. Inline overrides file-based on name conflict.\n *\n * Each markdown file has YAML frontmatter (description + optional model)\n * and a body that becomes the subagent prompt.\n *\n * @internal\n */\nexport async function loadSubagents(\n cwd: string,\n settingSourcesIncludeProject: boolean,\n inline: Record<string, AgentDefinition> | undefined,\n): Promise<Record<string, AgentDefinition>> {\n const result: Record<string, AgentDefinition> = {};\n if (settingSourcesIncludeProject) {\n const projectAgents = await readProjectSubagents(cwd);\n for (const [name, definition] of Object.entries(projectAgents)) {\n result[name] = definition;\n }\n }\n if (inline !== undefined) {\n for (const [name, definition] of Object.entries(inline)) {\n result[name] = definition;\n }\n }\n return result;\n}\n\n/**\n * Read agent declarations from every project config root (`.theokit`, then `.claude`).\n *\n * FIRST occurrence of a name wins, which is what makes `projectConfigRoots`' order a contract rather\n * than a detail: a project declaring the same agent in both means the explicit namespace.\n */\nasync function readProjectSubagents(cwd: string): Promise<Record<string, AgentDefinition>> {\n const subagents: Record<string, AgentDefinition> = {};\n for (const configRoot of projectConfigRoots(cwd)) {\n await readSubagentsFrom(join(configRoot, \"agents\"), subagents);\n }\n // A Claude Code plugin is a BUNDLE, and its `agents/` is what it exists to contribute. Read after\n // the project's own, so a project can shadow an agent a plugin ships without editing the plugin.\n for (const bundle of await pluginBundleDirs(cwd)) {\n await readSubagentsFrom(join(bundle, \"agents\"), subagents);\n }\n return subagents;\n}\n\nasync function readSubagentsFrom(\n root: string,\n subagents: Record<string, AgentDefinition>,\n): Promise<void> {\n const entries = await readWorkspaceDir(root, \"subagents_read_error\", \"subagents directory\");\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith(\".md\")) continue;\n const path = join(root, entry.name);\n const raw = await readFile(path, \"utf8\");\n // A markdown file with NO frontmatter is not an agent declaration — a directory of agents\n // written for the Claude Code CLI conventionally carries documentation beside them, and\n // `.claude/agents/README.md` exists in this repository. Throwing on it made ONE such file stop\n // every agent in the directory from loading.\n //\n // Skipped with a warn rather than in silence, and ONLY for the no-frontmatter case: a file that\n // HAS frontmatter and gets it wrong is a broken agent and still fails loudly, which is what\n // keeps a typo'd `sandbox` from returning as a silent gate through this door.\n if (!hasFrontmatter(raw)) {\n diag(`[theokit-sdk] ${entry.name} has no frontmatter — not an agent declaration, skipping`);\n continue;\n }\n const definition = parseSubagentMarkdown(raw, entry.name);\n if (subagents[definition.name] === undefined) {\n subagents[definition.name] = definition.definition;\n }\n }\n}\n\n// The frontmatter keys a disk subagent may declare. Any other key is a typed load\n// error rather than a silent drop — a dropped `sandbox` an operator wrote believing\n// it confines the child is exactly the silent-gate failure class this guards against.\nconst ACCEPTED_FIELDS = new Set([\n \"name\",\n \"description\",\n \"model\",\n \"tools\",\n \"reasoning_effort\",\n \"mcp\",\n \"sandbox\",\n]);\n\n// Fields the Claude Code CLI writes that carry NO behaviour for this runtime. Accepted and ignored,\n// so an agent authored for the CLI loads here unchanged — measured 2026-08-26 across the 59 agent\n// files on one machine, where `color` appeared in 38 of them and made every one of those a\n// `subagent_unknown_field` load error.\n//\n// Named explicitly instead of loosening the check above, because that check's reason is sound: a\n// dropped `sandbox` an operator wrote believing it confines the child is a silent gate. A field that\n// COULD change behaviour must still fail loudly. This set is the difference between \"we know this\n// one and it does nothing\" and \"we have never heard of this\" — two facts a bare allow-everything\n// would collapse into one.\n//\n// Anything added here needs the same justification: inert for THIS runtime, not merely unfamiliar.\nconst INERT_CLAUDE_CODE_FIELDS = new Set([\n /** The CLI's label colour for the agent. Presentation only. */\n \"color\",\n]);\n\nfunction parseSubagentMarkdown(\n raw: string,\n filename: string,\n): { name: string; definition: AgentDefinition } {\n const { frontmatter, body } = splitFrontmatter(raw, filename);\n const fields = parseFrontmatterFields(frontmatter);\n rejectUnknownFields(fields, filename);\n rejectMcp(fields, filename);\n\n const definition: AgentDefinition = {\n description: asString(fields.description) ?? \"\",\n prompt: body,\n };\n const model = resolveModel(fields, filename);\n if (model !== undefined) definition.model = model;\n const tools = toStringList(fields.tools);\n if (tools.length > 0) definition.tools = tools;\n const sandbox = resolveSandbox(fields, filename);\n if (sandbox !== undefined) definition.sandbox = sandbox;\n\n const name = asString(fields.name) ?? filename.replace(/\\.md$/, \"\");\n return { name, definition };\n}\n\nfunction rejectUnknownFields(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): void {\n for (const key of Object.keys(fields)) {\n if (INERT_CLAUDE_CODE_FIELDS.has(key)) continue;\n if (!ACCEPTED_FIELDS.has(key)) {\n throw new ConfigurationError(\n `Subagent ${filename}: unknown frontmatter field \"${key}\" (accepted: ${[...ACCEPTED_FIELDS].join(\", \")})`,\n { code: \"subagent_unknown_field\" },\n );\n }\n }\n}\n\n// mcp: a known field, but not yet honored on the LOCAL delegation path. The frontmatter YAML can only\n// express server NAMES (parseSimpleYaml has no nested-object support), while a child's `Agent.create`\n// needs `mcpServers` as a Record<name, config>; resolving names→config per-subagent in local delegation\n// is its own follow-up. Rather than silently drop it (the M26/M32 silent-gate class), it is a typed load\n// error that names the field and points at the alternative.\nfunction rejectMcp(fields: Record<string, FrontmatterValue | undefined>, filename: string): void {\n if (fields.mcp !== undefined) {\n throw new ConfigurationError(\n `Subagent ${filename}: per-subagent \"mcp\" is not yet supported on the local delegation path; declare MCP servers in .theokit/mcp.json (or the parent) instead`,\n { code: \"subagent_mcp_unsupported_local\" },\n );\n }\n}\n\n// model + reasoning_effort — effort rides inside `model.params[thinking]`, so it requires a concrete\n// model id to attach to (a child inheriting the parent's model cannot carry the parent's provider-\n// specific effort param safely).\nfunction resolveModel(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): ModelSelection | \"inherit\" | undefined {\n const modelId = asString(fields.model);\n const effort = asString(fields.reasoning_effort);\n // reasoning_effort rides in model.params[thinking], so it needs a CONCRETE model id to attach to.\n // Neither an absent model NOR `model: inherit` can carry it (the inherited id is unknown at load), so\n // both are typed errors rather than a silently-dropped effort — the silent-gate class this guards.\n if (effort !== undefined && (modelId === undefined || modelId === \"inherit\")) {\n throw new ConfigurationError(\n `Subagent ${filename}: reasoning_effort requires a concrete model (effort is a model parameter; an absent model or \"inherit\" cannot carry it)`,\n { code: \"subagent_reasoning_effort_without_model\" },\n );\n }\n if (modelId === undefined) return undefined;\n if (modelId === \"inherit\") return \"inherit\";\n return effort !== undefined\n ? { id: modelId, params: [{ id: \"thinking\", value: effort }] }\n : { id: modelId };\n}\n\n// sandbox: boolean only. A granular mode string (read-only/…) is unsupported by the SDK runtime and is\n// a typed error rather than a silent coercion to a boolean.\nfunction resolveSandbox(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): boolean | undefined {\n if (fields.sandbox === undefined) return undefined;\n if (typeof fields.sandbox !== \"boolean\") {\n throw new ConfigurationError(\n `Subagent ${filename}: sandbox must be a boolean (got \"${String(fields.sandbox)}\"); granular sandbox modes are not supported by the runtime`,\n { code: \"subagent_sandbox_not_boolean\" },\n );\n }\n return fields.sandbox;\n}\n\nfunction asString(v: FrontmatterValue | undefined): string | undefined {\n if (typeof v !== \"string\") return undefined;\n // parseSimpleYaml does not strip quotes (documented), and `model`/`reasoning_effort` are fields users\n // habitually quote (`model: \"openai/gpt-4o\"`). Strip a single matching surrounding quote pair so a\n // quoted id/effort does not slip past validation and fail only at the provider.\n const m = /^([\"'])(.*)\\1$/.exec(v);\n return m ? m[2] : v;\n}\n\n/** Accept a YAML list (`string[]`) or a comma/space-separated scalar; trim + drop empties. */\nfunction toStringList(v: FrontmatterValue | undefined): string[] {\n if (Array.isArray(v)) return v.map((t) => t.trim()).filter((t) => t.length > 0);\n if (typeof v === \"string\") {\n return v\n .split(/[\\s,]+/)\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n }\n return [];\n}\n\n/** Does this file open with a frontmatter block at all? Its ABSENCE means \"not an agent\". */\nfunction hasFrontmatter(raw: string): boolean {\n return /^---\\s*\\n/.test(raw);\n}\n\nfunction splitFrontmatter(raw: string, filename: string): { frontmatter: string; body: string } {\n const match = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n([\\s\\S]*)$/.exec(raw);\n if (match === null) {\n throw new ConfigurationError(`Subagent ${filename} is missing frontmatter`, {\n code: \"subagent_missing_frontmatter\",\n });\n }\n return { frontmatter: match[1] ?? \"\", body: (match[2] ?? \"\").trim() };\n}\n\nfunction parseFrontmatterFields(frontmatter: string): Record<string, FrontmatterValue | undefined> {\n // Preserve the rich YAML value types (boolean/number/string[]): `sandbox: true` and\n // `mcp: [a, b]` are meaningful here, so narrowing everything to string (as the\n // pre-M33 loader did) would drop them. Per-field validation happens in parseSubagentMarkdown.\n return parseSimpleYaml(frontmatter);\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/runtime/plugins/plugin-bundles.ts","../src/internal/runtime/skills/subagents-loader.ts"],"names":["join"],"mappings":"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","file":"chunk-LXI4XZEC.js","sourcesContent":["/**\n * Locating the plugin bundles a project carries.\n *\n * Shared by the skills and subagents loaders, which both need the same answer to \"which folders in\n * this project are plugins\" and would otherwise each grow their own copy of the directory walk.\n *\n * @internal\n */\n\nimport type { Dirent } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pluginBundleRoots } from \"../../persistence/paths.js\";\n\n/**\n * Every plugin folder under the project's plugin roots.\n *\n * Returns the FOLDERS, not their contents — what a bundle contributes (`skills/`, `agents/`) is the\n * caller's business, and a loader that also knew the layout would have to change whenever the other\n * one did.\n *\n * A missing root is not an error: most projects carry no plugins, and treating their absence as a\n * failure would make \"none installed\" indistinguishable from \"the directory could not be read\".\n */\nexport async function pluginBundleDirs(cwd: string): Promise<string[]> {\n const dirs: string[] = [];\n for (const root of pluginBundleRoots(cwd)) {\n let entries: Dirent[];\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) dirs.push(join(root, entry.name));\n }\n }\n return dirs;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\nimport type { AgentDefinition } from \"../../../types/agent.js\";\nimport type { ModelSelection } from \"../../../types/agent-prims.js\";\nimport { diag } from \"../../diagnostics.js\";\nimport { projectConfigRoots } from \"../../persistence/paths.js\";\nimport { readWorkspaceDir } from \"../config/workspace-dir.js\";\nimport { type FrontmatterValue, parseSimpleYaml } from \"../context/yaml-frontmatter.js\";\nimport { pluginBundleDirs } from \"../plugins/plugin-bundles.js\";\n\n/**\n * Load file-based subagents from `.theokit/agents/*.md` and merge with\n * inline definitions. Inline overrides file-based on name conflict.\n *\n * Each markdown file has YAML frontmatter (description + optional model)\n * and a body that becomes the subagent prompt.\n *\n * @internal\n */\nexport async function loadSubagents(\n cwd: string,\n settingSourcesIncludeProject: boolean,\n inline: Record<string, AgentDefinition> | undefined,\n): Promise<Record<string, AgentDefinition>> {\n const result: Record<string, AgentDefinition> = {};\n if (settingSourcesIncludeProject) {\n const projectAgents = await readProjectSubagents(cwd);\n for (const [name, definition] of Object.entries(projectAgents)) {\n result[name] = definition;\n }\n }\n if (inline !== undefined) {\n for (const [name, definition] of Object.entries(inline)) {\n result[name] = definition;\n }\n }\n return result;\n}\n\n/**\n * Read agent declarations from every project config root (`.theokit`, then `.claude`).\n *\n * FIRST occurrence of a name wins, which is what makes `projectConfigRoots`' order a contract rather\n * than a detail: a project declaring the same agent in both means the explicit namespace.\n */\nasync function readProjectSubagents(cwd: string): Promise<Record<string, AgentDefinition>> {\n const subagents: Record<string, AgentDefinition> = {};\n for (const configRoot of projectConfigRoots(cwd)) {\n await readSubagentsFrom(join(configRoot, \"agents\"), subagents);\n }\n // A Claude Code plugin is a BUNDLE, and its `agents/` is what it exists to contribute. Read after\n // the project's own, so a project can shadow an agent a plugin ships without editing the plugin.\n for (const bundle of await pluginBundleDirs(cwd)) {\n await readSubagentsFrom(join(bundle, \"agents\"), subagents);\n }\n return subagents;\n}\n\nasync function readSubagentsFrom(\n root: string,\n subagents: Record<string, AgentDefinition>,\n): Promise<void> {\n const entries = await readWorkspaceDir(root, \"subagents_read_error\", \"subagents directory\");\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith(\".md\")) continue;\n const path = join(root, entry.name);\n const raw = await readFile(path, \"utf8\");\n // A markdown file with NO frontmatter is not an agent declaration — a directory of agents\n // written for the Claude Code CLI conventionally carries documentation beside them, and\n // `.claude/agents/README.md` exists in this repository. Throwing on it made ONE such file stop\n // every agent in the directory from loading.\n //\n // Skipped with a warn rather than in silence, and ONLY for the no-frontmatter case: a file that\n // HAS frontmatter and gets it wrong is a broken agent and still fails loudly, which is what\n // keeps a typo'd `sandbox` from returning as a silent gate through this door.\n if (!hasFrontmatter(raw)) {\n diag(`[theokit-sdk] ${entry.name} has no frontmatter — not an agent declaration, skipping`);\n continue;\n }\n const definition = parseSubagentMarkdown(raw, entry.name);\n if (subagents[definition.name] === undefined) {\n subagents[definition.name] = definition.definition;\n }\n }\n}\n\n// The frontmatter keys a disk subagent may declare. Any other key is a typed load\n// error rather than a silent drop — a dropped `sandbox` an operator wrote believing\n// it confines the child is exactly the silent-gate failure class this guards against.\nconst ACCEPTED_FIELDS = new Set([\n \"name\",\n \"description\",\n \"model\",\n \"tools\",\n \"reasoning_effort\",\n \"mcp\",\n \"sandbox\",\n]);\n\n// Fields the Claude Code CLI writes that carry NO behaviour for this runtime. Accepted and ignored,\n// so an agent authored for the CLI loads here unchanged — measured 2026-08-26 across the 59 agent\n// files on one machine, where `color` appeared in 38 of them and made every one of those a\n// `subagent_unknown_field` load error.\n//\n// Named explicitly instead of loosening the check above, because that check's reason is sound: a\n// dropped `sandbox` an operator wrote believing it confines the child is a silent gate. A field that\n// COULD change behaviour must still fail loudly. This set is the difference between \"we know this\n// one and it does nothing\" and \"we have never heard of this\" — two facts a bare allow-everything\n// would collapse into one.\n//\n// Anything added here needs the same justification: inert for THIS runtime, not merely unfamiliar.\nconst INERT_CLAUDE_CODE_FIELDS = new Set([\n /** The CLI's label colour for the agent. Presentation only. */\n \"color\",\n]);\n\nfunction parseSubagentMarkdown(\n raw: string,\n filename: string,\n): { name: string; definition: AgentDefinition } {\n const { frontmatter, body } = splitFrontmatter(raw, filename);\n const fields = parseFrontmatterFields(frontmatter);\n rejectUnknownFields(fields, filename);\n rejectMcp(fields, filename);\n\n const definition: AgentDefinition = {\n description: asString(fields.description) ?? \"\",\n prompt: body,\n };\n const model = resolveModel(fields, filename);\n if (model !== undefined) definition.model = model;\n const tools = toStringList(fields.tools);\n if (tools.length > 0) definition.tools = tools;\n const sandbox = resolveSandbox(fields, filename);\n if (sandbox !== undefined) definition.sandbox = sandbox;\n\n const name = asString(fields.name) ?? filename.replace(/\\.md$/, \"\");\n return { name, definition };\n}\n\nfunction rejectUnknownFields(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): void {\n for (const key of Object.keys(fields)) {\n if (INERT_CLAUDE_CODE_FIELDS.has(key)) continue;\n if (!ACCEPTED_FIELDS.has(key)) {\n throw new ConfigurationError(\n `Subagent ${filename}: unknown frontmatter field \"${key}\" (accepted: ${[...ACCEPTED_FIELDS].join(\", \")})`,\n { code: \"subagent_unknown_field\" },\n );\n }\n }\n}\n\n// mcp: a known field, but not yet honored on the LOCAL delegation path. The frontmatter YAML can only\n// express server NAMES (parseSimpleYaml has no nested-object support), while a child's `Agent.create`\n// needs `mcpServers` as a Record<name, config>; resolving names→config per-subagent in local delegation\n// is its own follow-up. Rather than silently drop it (the M26/M32 silent-gate class), it is a typed load\n// error that names the field and points at the alternative.\nfunction rejectMcp(fields: Record<string, FrontmatterValue | undefined>, filename: string): void {\n if (fields.mcp !== undefined) {\n throw new ConfigurationError(\n `Subagent ${filename}: per-subagent \"mcp\" is not yet supported on the local delegation path; declare MCP servers in .theokit/mcp.json (or the parent) instead`,\n { code: \"subagent_mcp_unsupported_local\" },\n );\n }\n}\n\n// model + reasoning_effort — effort rides inside `model.params[thinking]`, so it requires a concrete\n// model id to attach to (a child inheriting the parent's model cannot carry the parent's provider-\n// specific effort param safely).\nfunction resolveModel(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): ModelSelection | \"inherit\" | undefined {\n const modelId = asString(fields.model);\n const effort = asString(fields.reasoning_effort);\n // reasoning_effort rides in model.params[thinking], so it needs a CONCRETE model id to attach to.\n // Neither an absent model NOR `model: inherit` can carry it (the inherited id is unknown at load), so\n // both are typed errors rather than a silently-dropped effort — the silent-gate class this guards.\n if (effort !== undefined && (modelId === undefined || modelId === \"inherit\")) {\n throw new ConfigurationError(\n `Subagent ${filename}: reasoning_effort requires a concrete model (effort is a model parameter; an absent model or \"inherit\" cannot carry it)`,\n { code: \"subagent_reasoning_effort_without_model\" },\n );\n }\n if (modelId === undefined) return undefined;\n if (modelId === \"inherit\") return \"inherit\";\n return effort !== undefined\n ? { id: modelId, params: [{ id: \"thinking\", value: effort }] }\n : { id: modelId };\n}\n\n// sandbox: boolean only. A granular mode string (read-only/…) is unsupported by the SDK runtime and is\n// a typed error rather than a silent coercion to a boolean.\nfunction resolveSandbox(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): boolean | undefined {\n if (fields.sandbox === undefined) return undefined;\n if (typeof fields.sandbox !== \"boolean\") {\n throw new ConfigurationError(\n `Subagent ${filename}: sandbox must be a boolean (got \"${String(fields.sandbox)}\"); granular sandbox modes are not supported by the runtime`,\n { code: \"subagent_sandbox_not_boolean\" },\n );\n }\n return fields.sandbox;\n}\n\nfunction asString(v: FrontmatterValue | undefined): string | undefined {\n if (typeof v !== \"string\") return undefined;\n // parseSimpleYaml does not strip quotes (documented), and `model`/`reasoning_effort` are fields users\n // habitually quote (`model: \"openai/gpt-4o\"`). Strip a single matching surrounding quote pair so a\n // quoted id/effort does not slip past validation and fail only at the provider.\n const m = /^([\"'])(.*)\\1$/.exec(v);\n return m ? m[2] : v;\n}\n\n/** Accept a YAML list (`string[]`) or a comma/space-separated scalar; trim + drop empties. */\nfunction toStringList(v: FrontmatterValue | undefined): string[] {\n if (Array.isArray(v)) return v.map((t) => t.trim()).filter((t) => t.length > 0);\n if (typeof v === \"string\") {\n return v\n .split(/[\\s,]+/)\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n }\n return [];\n}\n\n/** Does this file open with a frontmatter block at all? Its ABSENCE means \"not an agent\". */\nfunction hasFrontmatter(raw: string): boolean {\n return /^---\\s*\\n/.test(raw);\n}\n\nfunction splitFrontmatter(raw: string, filename: string): { frontmatter: string; body: string } {\n const match = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n([\\s\\S]*)$/.exec(raw);\n if (match === null) {\n throw new ConfigurationError(`Subagent ${filename} is missing frontmatter`, {\n code: \"subagent_missing_frontmatter\",\n });\n }\n return { frontmatter: match[1] ?? \"\", body: (match[2] ?? \"\").trim() };\n}\n\nfunction parseFrontmatterFields(frontmatter: string): Record<string, FrontmatterValue | undefined> {\n // Preserve the rich YAML value types (boolean/number/string[]): `sandbox: true` and\n // `mcp: [a, b]` are meaningful here, so narrowing everything to string (as the\n // pre-M33 loader did) would drop them. Per-field validation happens in parseSubagentMarkdown.\n return parseSimpleYaml(frontmatter);\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { ConfigurationError } from './chunk-IDCKSLYH.js';
1
+ import { ConfigurationError } from './chunk-ZZMZWBR6.js';
2
2
  import { readdir } from 'fs/promises';
3
3
 
4
4
  async function readWorkspaceDir(root, errorCode, describe) {
@@ -39,5 +39,5 @@ function coerce(raw) {
39
39
  }
40
40
 
41
41
  export { parseSimpleYaml, readWorkspaceDir };
42
- //# sourceMappingURL=chunk-AG5JPQIY.js.map
43
- //# sourceMappingURL=chunk-AG5JPQIY.js.map
42
+ //# sourceMappingURL=chunk-LXQ6HKPS.js.map
43
+ //# sourceMappingURL=chunk-LXQ6HKPS.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/runtime/config/workspace-dir.ts","../src/internal/runtime/context/yaml-frontmatter.ts"],"names":[],"mappings":";;;AAyBA,eAAsB,gBAAA,CACpB,IAAA,EACA,SAAA,EACA,QAAA,EAC8B;AAC9B,EAAA,IAAI;AACF,IAAA,OAAQ,MAAM,OAAA,CAAQ,IAAA,EAAM,EAAE,aAAA,EAAe,MAAM,CAAA;AAAA,EACrD,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,GAAA,GAAM,KAAA;AACZ,IAAA,IAAI,GAAA,CAAI,IAAA,KAAS,QAAA,EAAU,OAAO,EAAC;AACnC,IAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,eAAA,EAAkB,QAAQ,CAAA,EAAA,EAAK,IAAI,CAAA,CAAA,EAAI;AAAA,MAClE,IAAA,EAAM,SAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,EACH;AACF;;;AClBO,SAAS,gBAAgB,IAAA,EAA4D;AAC1F,EAAA,MAAM,SAAuD,EAAC;AAC9D,EAAA,KAAA,MAAW,IAAA,IAAQ,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA,EAAG;AACtC,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACnC,IAAA,IAAI,eAAe,EAAA,EAAI;AACvB,IAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,UAAU,EAAE,IAAA,EAAK;AAC3C,IAAA,IAAI,GAAA,CAAI,WAAW,CAAA,EAAG;AACtB,IAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,CAAC,EAAE,IAAA,EAAK;AAC5C,IAAA,MAAA,CAAO,GAAG,CAAA,GAAI,MAAA,CAAO,GAAG,CAAA;AAAA,EAC1B;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,OAAO,GAAA,EAA2C;AAEzD,EAAA,IAAI,GAAA,CAAI,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,IAAI,IAAI,UAAA,CAAW,GAAG,KAAK,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,EAAG;AAC5C,IAAA,OAAO,GAAA,CACJ,MAAM,CAAA,EAAG,EAAE,EACX,KAAA,CAAM,GAAG,EACT,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,IAAA,EAAM,CAAA,CACnB,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,CAAC,CAAA;AAAA,EAC/B;AACA,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAU,GAAA,KAAQ,OAAA,SAAgB,GAAA,KAAQ,MAAA;AACtD,EAAA,MAAM,CAAA,GAAI,OAAO,GAAG,CAAA;AACpB,EAAA,IAAI,MAAA,CAAO,SAAS,CAAC,CAAA,IAAK,QAAQ,MAAA,CAAO,CAAC,GAAG,OAAO,CAAA;AACpD,EAAA,OAAO,GAAA;AACT","file":"chunk-AG5JPQIY.js","sourcesContent":["import { readdir } from \"node:fs/promises\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\n\n/**\n * Entry returned by `readWorkspaceDir`. Mirrors the subset of\n * `fs.Dirent` the file-based loaders use.\n */\nexport interface WorkspaceDirEntry {\n name: string;\n isDirectory(): boolean;\n isFile(): boolean;\n}\n\n/**\n * Read a workspace subdirectory and return its entries. When the directory\n * does not exist (`ENOENT`), returns an empty array — the file-based loaders\n * (skills, plugins, agents) treat a missing directory as \"no entries\"\n * rather than an error.\n *\n * Any other I/O failure is wrapped as `ConfigurationError` so callers can\n * surface a stable error code.\n *\n * @internal\n */\nexport async function readWorkspaceDir(\n root: string,\n errorCode: string,\n describe: string,\n): Promise<WorkspaceDirEntry[]> {\n try {\n return (await readdir(root, { withFileTypes: true })) as WorkspaceDirEntry[];\n } catch (cause) {\n const err = cause as NodeJS.ErrnoException;\n if (err.code === \"ENOENT\") return [];\n throw new ConfigurationError(`Failed to read ${describe}: ${root}`, {\n code: errorCode,\n cause,\n });\n }\n}\n","/**\n * Tiny YAML-frontmatter parser shared by the file-based loaders (skills,\n * subagents, hooks, context, plugins). Supports four scalar shapes:\n *\n * key: bar → \"bar\" (string)\n * key: 42 → 42 (number)\n * key: true → true (boolean)\n * key: [a, b, c] → [\"a\",\"b\",\"c\"](string[])\n * key: → undefined (caller's Zod default kicks in)\n *\n * Limitations (intentional — keep parser tiny, no dep):\n * - No nested objects (use flat keys like `providerId` not `provider.id`).\n * - No quoted strings — `match: \"1\"` becomes the literal 3-char string `\"1\"`.\n * - List values cannot contain a literal comma inside an element; the\n * `tags: [a,b, c]` splitter is greedy on `,`. Use multi-line lists or\n * reword if you need this.\n *\n * @internal\n */\n\nexport type FrontmatterValue = string | number | boolean | string[];\n\nexport function parseSimpleYaml(text: string): Record<string, FrontmatterValue | undefined> {\n const fields: Record<string, FrontmatterValue | undefined> = {};\n for (const line of text.split(/\\r?\\n/)) {\n const colonIndex = line.indexOf(\":\");\n if (colonIndex === -1) continue;\n const key = line.slice(0, colonIndex).trim();\n if (key.length === 0) continue;\n const raw = line.slice(colonIndex + 1).trim();\n fields[key] = coerce(raw);\n }\n return fields;\n}\n\nfunction coerce(raw: string): FrontmatterValue | undefined {\n // EC-3: empty value → undefined so Zod `.optional().default(...)` applies.\n if (raw.length === 0) return undefined;\n if (raw.startsWith(\"[\") && raw.endsWith(\"]\")) {\n return raw\n .slice(1, -1)\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n }\n if (raw === \"true\" || raw === \"false\") return raw === \"true\";\n const n = Number(raw);\n if (Number.isFinite(n) && raw === String(n)) return n;\n return raw;\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/runtime/config/workspace-dir.ts","../src/internal/runtime/context/yaml-frontmatter.ts"],"names":[],"mappings":";;;AAyBA,eAAsB,gBAAA,CACpB,IAAA,EACA,SAAA,EACA,QAAA,EAC8B;AAC9B,EAAA,IAAI;AACF,IAAA,OAAQ,MAAM,OAAA,CAAQ,IAAA,EAAM,EAAE,aAAA,EAAe,MAAM,CAAA;AAAA,EACrD,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,GAAA,GAAM,KAAA;AACZ,IAAA,IAAI,GAAA,CAAI,IAAA,KAAS,QAAA,EAAU,OAAO,EAAC;AACnC,IAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,eAAA,EAAkB,QAAQ,CAAA,EAAA,EAAK,IAAI,CAAA,CAAA,EAAI;AAAA,MAClE,IAAA,EAAM,SAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,EACH;AACF;;;AClBO,SAAS,gBAAgB,IAAA,EAA4D;AAC1F,EAAA,MAAM,SAAuD,EAAC;AAC9D,EAAA,KAAA,MAAW,IAAA,IAAQ,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA,EAAG;AACtC,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACnC,IAAA,IAAI,eAAe,EAAA,EAAI;AACvB,IAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,UAAU,EAAE,IAAA,EAAK;AAC3C,IAAA,IAAI,GAAA,CAAI,WAAW,CAAA,EAAG;AACtB,IAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,CAAC,EAAE,IAAA,EAAK;AAC5C,IAAA,MAAA,CAAO,GAAG,CAAA,GAAI,MAAA,CAAO,GAAG,CAAA;AAAA,EAC1B;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,OAAO,GAAA,EAA2C;AAEzD,EAAA,IAAI,GAAA,CAAI,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,IAAI,IAAI,UAAA,CAAW,GAAG,KAAK,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,EAAG;AAC5C,IAAA,OAAO,GAAA,CACJ,MAAM,CAAA,EAAG,EAAE,EACX,KAAA,CAAM,GAAG,EACT,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,IAAA,EAAM,CAAA,CACnB,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,CAAC,CAAA;AAAA,EAC/B;AACA,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAU,GAAA,KAAQ,OAAA,SAAgB,GAAA,KAAQ,MAAA;AACtD,EAAA,MAAM,CAAA,GAAI,OAAO,GAAG,CAAA;AACpB,EAAA,IAAI,MAAA,CAAO,SAAS,CAAC,CAAA,IAAK,QAAQ,MAAA,CAAO,CAAC,GAAG,OAAO,CAAA;AACpD,EAAA,OAAO,GAAA;AACT","file":"chunk-LXQ6HKPS.js","sourcesContent":["import { readdir } from \"node:fs/promises\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\n\n/**\n * Entry returned by `readWorkspaceDir`. Mirrors the subset of\n * `fs.Dirent` the file-based loaders use.\n */\nexport interface WorkspaceDirEntry {\n name: string;\n isDirectory(): boolean;\n isFile(): boolean;\n}\n\n/**\n * Read a workspace subdirectory and return its entries. When the directory\n * does not exist (`ENOENT`), returns an empty array — the file-based loaders\n * (skills, plugins, agents) treat a missing directory as \"no entries\"\n * rather than an error.\n *\n * Any other I/O failure is wrapped as `ConfigurationError` so callers can\n * surface a stable error code.\n *\n * @internal\n */\nexport async function readWorkspaceDir(\n root: string,\n errorCode: string,\n describe: string,\n): Promise<WorkspaceDirEntry[]> {\n try {\n return (await readdir(root, { withFileTypes: true })) as WorkspaceDirEntry[];\n } catch (cause) {\n const err = cause as NodeJS.ErrnoException;\n if (err.code === \"ENOENT\") return [];\n throw new ConfigurationError(`Failed to read ${describe}: ${root}`, {\n code: errorCode,\n cause,\n });\n }\n}\n","/**\n * Tiny YAML-frontmatter parser shared by the file-based loaders (skills,\n * subagents, hooks, context, plugins). Supports four scalar shapes:\n *\n * key: bar → \"bar\" (string)\n * key: 42 → 42 (number)\n * key: true → true (boolean)\n * key: [a, b, c] → [\"a\",\"b\",\"c\"](string[])\n * key: → undefined (caller's Zod default kicks in)\n *\n * Limitations (intentional — keep parser tiny, no dep):\n * - No nested objects (use flat keys like `providerId` not `provider.id`).\n * - No quoted strings — `match: \"1\"` becomes the literal 3-char string `\"1\"`.\n * - List values cannot contain a literal comma inside an element; the\n * `tags: [a,b, c]` splitter is greedy on `,`. Use multi-line lists or\n * reword if you need this.\n *\n * @internal\n */\n\nexport type FrontmatterValue = string | number | boolean | string[];\n\nexport function parseSimpleYaml(text: string): Record<string, FrontmatterValue | undefined> {\n const fields: Record<string, FrontmatterValue | undefined> = {};\n for (const line of text.split(/\\r?\\n/)) {\n const colonIndex = line.indexOf(\":\");\n if (colonIndex === -1) continue;\n const key = line.slice(0, colonIndex).trim();\n if (key.length === 0) continue;\n const raw = line.slice(colonIndex + 1).trim();\n fields[key] = coerce(raw);\n }\n return fields;\n}\n\nfunction coerce(raw: string): FrontmatterValue | undefined {\n // EC-3: empty value → undefined so Zod `.optional().default(...)` applies.\n if (raw.length === 0) return undefined;\n if (raw.startsWith(\"[\") && raw.endsWith(\"]\")) {\n return raw\n .slice(1, -1)\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n }\n if (raw === \"true\" || raw === \"false\") return raw === \"true\";\n const n = Number(raw);\n if (Number.isFinite(n) && raw === String(n)) return n;\n return raw;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkQDED6YO6_cjs = require('./chunk-QDED6YO6.cjs');
3
+ var chunkB4EOJWOY_cjs = require('./chunk-B4EOJWOY.cjs');
4
4
 
5
5
  // src/stream-object.ts
6
6
  var StreamObjectError = class extends Error {
@@ -14,19 +14,19 @@ var StreamObjectError = class extends Error {
14
14
  }
15
15
  };
16
16
  async function* streamObjectImpl(options, deps) {
17
- const { jsonSchema, maxRetries, initialUsage } = chunkQDED6YO6_cjs.setupStructuredOutput(
17
+ const { jsonSchema, maxRetries, initialUsage } = chunkB4EOJWOY_cjs.setupStructuredOutput(
18
18
  options.schema,
19
19
  options.maxRetries
20
20
  );
21
21
  let capturedRaw;
22
22
  let lastUsage = initialUsage;
23
- const outputTool = chunkQDED6YO6_cjs.makeOutputTool(jsonSchema, (input) => {
23
+ const outputTool = chunkB4EOJWOY_cjs.makeOutputTool(jsonSchema, (input) => {
24
24
  if (capturedRaw === void 0) {
25
25
  capturedRaw = input;
26
26
  }
27
27
  return JSON.stringify({ ok: true });
28
28
  });
29
- const agentOptions = chunkQDED6YO6_cjs.buildTransientAgentOptions({
29
+ const agentOptions = chunkB4EOJWOY_cjs.buildTransientAgentOptions({
30
30
  model: options.model,
31
31
  local: options.local,
32
32
  outputTool,
@@ -35,7 +35,7 @@ async function* streamObjectImpl(options, deps) {
35
35
  ...options.providers !== void 0 ? { providers: options.providers } : {}
36
36
  });
37
37
  const agent = await deps.create(agentOptions);
38
- const userMessage = chunkQDED6YO6_cjs.buildToolPrompt(options.prompt);
38
+ const userMessage = chunkB4EOJWOY_cjs.buildToolPrompt(options.prompt);
39
39
  try {
40
40
  let lastParseError;
41
41
  let attemptCounter = 0;
@@ -61,7 +61,7 @@ async function* streamObjectImpl(options, deps) {
61
61
  }
62
62
  }
63
63
  const result = await run.wait();
64
- lastUsage = chunkQDED6YO6_cjs.extractUsage(result);
64
+ lastUsage = chunkB4EOJWOY_cjs.extractUsage(result);
65
65
  if (capturedRaw === void 0) {
66
66
  if (result.status === "error" && result.error !== void 0) {
67
67
  throw new StreamObjectError(
@@ -97,7 +97,7 @@ async function* streamObjectImpl(options, deps) {
97
97
  lastParseError
98
98
  );
99
99
  } finally {
100
- await chunkQDED6YO6_cjs.disposeAndDeleteTransient(agent, deps.delete);
100
+ await chunkB4EOJWOY_cjs.disposeAndDeleteTransient(agent, deps.delete);
101
101
  }
102
102
  }
103
103
  function bestEffortPartialParse(text, schema) {
@@ -144,5 +144,5 @@ function bestEffortPartialParse(text, schema) {
144
144
 
145
145
  exports.StreamObjectError = StreamObjectError;
146
146
  exports.streamObjectImpl = streamObjectImpl;
147
- //# sourceMappingURL=chunk-ROYPRJH4.cjs.map
148
- //# sourceMappingURL=chunk-ROYPRJH4.cjs.map
147
+ //# sourceMappingURL=chunk-LYRDF5TQ.cjs.map
148
+ //# sourceMappingURL=chunk-LYRDF5TQ.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stream-object.ts"],"names":["setupStructuredOutput","makeOutputTool","buildTransientAgentOptions","buildToolPrompt","extractUsage","disposeAndDeleteTransient"],"mappings":"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","file":"chunk-ROYPRJH4.cjs","sourcesContent":["import type { z as ZodNamespace, ZodType } from \"zod\";\n\nimport {\n buildToolPrompt,\n buildTransientAgentOptions,\n disposeAndDeleteTransient,\n extractUsage,\n makeOutputTool,\n setupStructuredOutput,\n} from \"./internal/structured-output-helpers.js\";\nimport type { AgentOptions, LocalOptions, ModelSelection, SDKAgent } from \"./types/agent.js\";\nimport type { ProviderRoutingSettings } from \"./types/providers.js\";\n\n/**\n * Options accepted by {@link Agent.streamObject}. Same shape as\n * `Agent.generateObject` with the addition that the result is an\n * `AsyncIterator<StreamObjectEvent<T>>` rather than a single Promise. See ADR D39.\n *\n * @public\n */\nexport interface StreamObjectOptions<T extends ZodType> {\n schema: T;\n prompt: string;\n systemPrompt?: string;\n /** SE8 — accepts a bare-string id shorthand or a {@link ModelSelection}. */\n model: string | ModelSelection;\n apiKey?: string;\n local: LocalOptions;\n maxRetries?: number;\n /**\n * Optional provider routing forwarded to the transient agent. Required when\n * `model.id` uses a prefix (e.g. `openai/gpt-4o-mini`) but the credential is\n * for a unified gateway (e.g. OpenRouter). Without this, the SDK infers\n * provider from the prefix and may fail with `provider_unresolved` even\n * when the right env key is set under a different provider name.\n */\n providers?: ProviderRoutingSettings;\n}\n\n/**\n * Recursive partial — `T` where every nested field becomes optional.\n *\n * @public\n */\nexport type DeepPartial<T> = T extends (infer U)[]\n ? Array<DeepPartial<U>>\n : T extends object\n ? { [K in keyof T]?: DeepPartial<T[K]> }\n : T;\n\n/**\n * Event emitted by {@link Agent.streamObject}. Discriminate on `type`.\n *\n * - `partial` events fire zero or more times with monotonically increasing\n * `attempt`, carrying best-effort schema-parsed snapshots of the model's\n * accumulating output.\n * - `complete` fires exactly once at the end, carrying the fully Zod-parsed\n * object alongside usage and finishReason — semantically identical to a\n * successful `Agent.generateObject()` return.\n *\n * @public\n */\nexport type StreamObjectEvent<T> =\n | { type: \"partial\"; partial: DeepPartial<T>; attempt: number }\n | {\n type: \"complete\";\n object: T;\n raw: unknown;\n usage: { inputTokens: number; outputTokens: number };\n finishReason: \"tool_use\" | \"error\";\n };\n\n/**\n * Error thrown by {@link Agent.streamObject} when the model refuses to call\n * the synthetic `output` tool or when all retries fail to produce a\n * schema-valid object. Same code taxonomy as `GenerateObjectError`.\n *\n * @public\n */\nexport class StreamObjectError extends Error {\n override readonly name = \"StreamObjectError\";\n readonly code: \"no_tool_call\" | \"parse_failed\";\n override readonly cause?: unknown;\n constructor(code: \"no_tool_call\" | \"parse_failed\", message: string, cause?: unknown) {\n super(message);\n this.code = code;\n if (cause !== undefined) this.cause = cause;\n }\n}\n\ninterface StreamObjectDeps {\n create: (options: AgentOptions) => Promise<SDKAgent>;\n delete: (agentId: string) => Promise<void>;\n}\n\n/**\n * Implementation of `Agent.streamObject` as an async generator. Mirrors the\n * synthetic-forced-tool pattern from `generate-object.ts` (ADR D33) with the\n * addition of intermediate `partial` events emitted from incremental parsing\n * of accumulating text deltas during the agent loop.\n *\n * REACHED BY DYNAMIC IMPORT — do not delete on a dead-code report (B-140).\n * `agent.ts` loads this module lazily to keep it off the eager path:\n *\n * streamObjectImport ??= import(\"./stream-object.js\");\n * const { streamObjectImpl } = await streamObjectImport;\n *\n * `knip` resolves imports statically and does not follow a destructure off a\n * dynamic-import promise, so it reports this export as unused on every run. It\n * is not: removing it breaks `Agent.streamObject`. That is why this file is\n * named in `knip.json`'s ignore list rather than cleaned up — the entry is a\n * tool limitation, not a suppression of a real finding, and the difference is\n * the whole reason this comment exists.\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: streaming loop interleaves text-delta accumulation, partial-parse attempts, retries, and final dispose — splitting harms locality of the iterator contract.\nexport async function* streamObjectImpl<T extends ZodType>(\n options: StreamObjectOptions<T>,\n deps: StreamObjectDeps,\n): AsyncGenerator<StreamObjectEvent<ZodNamespace.infer<T>>, void, void> {\n const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(\n options.schema,\n options.maxRetries,\n );\n let capturedRaw: unknown;\n let lastUsage = initialUsage;\n\n const outputTool = makeOutputTool(jsonSchema, (input) => {\n // EC-6: first capture wins (parallel tool use in Claude 3.5+).\n if (capturedRaw === undefined) {\n capturedRaw = input;\n }\n return JSON.stringify({ ok: true });\n });\n\n const agentOptions: AgentOptions = buildTransientAgentOptions({\n model: options.model,\n local: options.local,\n outputTool,\n ...(options.systemPrompt !== undefined ? { systemPrompt: options.systemPrompt } : {}),\n ...(options.apiKey !== undefined ? { apiKey: options.apiKey } : {}),\n ...(options.providers !== undefined ? { providers: options.providers } : {}),\n });\n const agent = await deps.create(agentOptions);\n const userMessage = buildToolPrompt(options.prompt);\n\n try {\n let lastParseError: unknown;\n let attemptCounter = 0;\n\n for (let attempt = 0; attempt <= maxRetries; attempt += 1) {\n capturedRaw = undefined;\n const run = await agent.send(userMessage);\n\n // Buffer text deltas during streaming; try partial-parse on each.\n let textBuffer = \"\";\n for await (const msg of run.stream()) {\n if (msg.type === \"assistant\") {\n const newText = msg.message.content\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\");\n if (newText.length > 0) {\n textBuffer += newText;\n const partial = bestEffortPartialParse(textBuffer, options.schema);\n if (partial !== undefined) {\n attemptCounter += 1;\n yield {\n type: \"partial\",\n partial: partial as DeepPartial<ZodNamespace.infer<T>>,\n attempt: attemptCounter,\n };\n }\n }\n }\n }\n const result = await run.wait();\n lastUsage = extractUsage(result);\n\n if (capturedRaw === undefined) {\n // EC: when the underlying run errored (e.g. provider_unresolved),\n // surface the original cause instead of the misleading \"model\n // returned text\" message — there was no model call at all.\n if (result.status === \"error\" && result.error !== undefined) {\n throw new StreamObjectError(\n \"no_tool_call\",\n `Agent run failed before the model could reply: ${result.error.message ?? \"unknown error\"} [${result.error.code ?? \"?\"}]`,\n result.error,\n );\n }\n if (attempt === maxRetries) {\n throw new StreamObjectError(\n \"no_tool_call\",\n \"The model returned text instead of calling the `output` tool.\",\n );\n }\n continue;\n }\n\n const parsed = options.schema.safeParse(capturedRaw);\n if (parsed.success) {\n yield {\n type: \"complete\",\n object: parsed.data,\n raw: capturedRaw,\n usage: lastUsage,\n finishReason: \"tool_use\",\n };\n return;\n }\n lastParseError = parsed.error;\n }\n\n throw new StreamObjectError(\n \"parse_failed\",\n \"Schema parse failed after all retries.\",\n lastParseError,\n );\n } finally {\n // EC-4: even if consumer calls iter.return() mid-stream, this finally\n // runs — transient agent is disposed AND removed from registry.\n await disposeAndDeleteTransient(agent, deps.delete);\n }\n}\n\n/**\n * Try to extract a partial JSON object from a possibly-incomplete text\n * buffer and parse it via the schema in lenient mode. Returns `undefined`\n * if nothing parseable is found yet.\n *\n * Strategy: find the first `{`, find the LAST balanced `}` (greedy), parse\n * the substring as JSON, then `safeParse` against `schema.partial()` if the\n * schema supports it, else against the original schema.\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: stateful JSON-balancing scanner — string/brace/escape state must be co-located for the parser to remain correct.\nfunction bestEffortPartialParse<T extends ZodType>(text: string, schema: T): unknown | undefined {\n const start = text.indexOf(\"{\");\n if (start < 0) return undefined;\n // Find the longest balanced JSON object from `start`.\n let depth = 0;\n let inString = false;\n let isEscaped = false;\n let end = -1;\n for (let i = start; i < text.length; i += 1) {\n const ch = text[i];\n if (isEscaped) {\n isEscaped = false;\n continue;\n }\n if (ch === \"\\\\\" && inString) {\n isEscaped = true;\n continue;\n }\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) continue;\n if (ch === \"{\") depth += 1;\n else if (ch === \"}\") {\n depth -= 1;\n if (depth === 0) end = i;\n }\n }\n if (end < 0) return undefined;\n const candidate = text.slice(start, end + 1);\n let parsed: unknown;\n try {\n parsed = JSON.parse(candidate);\n } catch {\n return undefined;\n }\n // Try schema.partial() if available (Zod objects support it); else fall\n // back to the original schema (loose match).\n const maybePartial = (schema as unknown as { partial?: () => ZodType }).partial;\n const looseSchema = typeof maybePartial === \"function\" ? maybePartial.call(schema) : schema;\n const result = looseSchema.safeParse(parsed);\n return result.success ? result.data : undefined;\n}\n"]}
1
+ {"version":3,"sources":["../src/stream-object.ts"],"names":["setupStructuredOutput","makeOutputTool","buildTransientAgentOptions","buildToolPrompt","extractUsage","disposeAndDeleteTransient"],"mappings":"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","file":"chunk-LYRDF5TQ.cjs","sourcesContent":["import type { z as ZodNamespace, ZodType } from \"zod\";\n\nimport {\n buildToolPrompt,\n buildTransientAgentOptions,\n disposeAndDeleteTransient,\n extractUsage,\n makeOutputTool,\n setupStructuredOutput,\n} from \"./internal/structured-output-helpers.js\";\nimport type { AgentOptions, LocalOptions, ModelSelection, SDKAgent } from \"./types/agent.js\";\nimport type { ProviderRoutingSettings } from \"./types/providers.js\";\n\n/**\n * Options accepted by {@link Agent.streamObject}. Same shape as\n * `Agent.generateObject` with the addition that the result is an\n * `AsyncIterator<StreamObjectEvent<T>>` rather than a single Promise. See ADR D39.\n *\n * @public\n */\nexport interface StreamObjectOptions<T extends ZodType> {\n schema: T;\n prompt: string;\n systemPrompt?: string;\n /** SE8 — accepts a bare-string id shorthand or a {@link ModelSelection}. */\n model: string | ModelSelection;\n apiKey?: string;\n local: LocalOptions;\n maxRetries?: number;\n /**\n * Optional provider routing forwarded to the transient agent. Required when\n * `model.id` uses a prefix (e.g. `openai/gpt-4o-mini`) but the credential is\n * for a unified gateway (e.g. OpenRouter). Without this, the SDK infers\n * provider from the prefix and may fail with `provider_unresolved` even\n * when the right env key is set under a different provider name.\n */\n providers?: ProviderRoutingSettings;\n}\n\n/**\n * Recursive partial — `T` where every nested field becomes optional.\n *\n * @public\n */\nexport type DeepPartial<T> = T extends (infer U)[]\n ? Array<DeepPartial<U>>\n : T extends object\n ? { [K in keyof T]?: DeepPartial<T[K]> }\n : T;\n\n/**\n * Event emitted by {@link Agent.streamObject}. Discriminate on `type`.\n *\n * - `partial` events fire zero or more times with monotonically increasing\n * `attempt`, carrying best-effort schema-parsed snapshots of the model's\n * accumulating output.\n * - `complete` fires exactly once at the end, carrying the fully Zod-parsed\n * object alongside usage and finishReason — semantically identical to a\n * successful `Agent.generateObject()` return.\n *\n * @public\n */\nexport type StreamObjectEvent<T> =\n | { type: \"partial\"; partial: DeepPartial<T>; attempt: number }\n | {\n type: \"complete\";\n object: T;\n raw: unknown;\n usage: { inputTokens: number; outputTokens: number };\n finishReason: \"tool_use\" | \"error\";\n };\n\n/**\n * Error thrown by {@link Agent.streamObject} when the model refuses to call\n * the synthetic `output` tool or when all retries fail to produce a\n * schema-valid object. Same code taxonomy as `GenerateObjectError`.\n *\n * @public\n */\nexport class StreamObjectError extends Error {\n override readonly name = \"StreamObjectError\";\n readonly code: \"no_tool_call\" | \"parse_failed\";\n override readonly cause?: unknown;\n constructor(code: \"no_tool_call\" | \"parse_failed\", message: string, cause?: unknown) {\n super(message);\n this.code = code;\n if (cause !== undefined) this.cause = cause;\n }\n}\n\ninterface StreamObjectDeps {\n create: (options: AgentOptions) => Promise<SDKAgent>;\n delete: (agentId: string) => Promise<void>;\n}\n\n/**\n * Implementation of `Agent.streamObject` as an async generator. Mirrors the\n * synthetic-forced-tool pattern from `generate-object.ts` (ADR D33) with the\n * addition of intermediate `partial` events emitted from incremental parsing\n * of accumulating text deltas during the agent loop.\n *\n * REACHED BY DYNAMIC IMPORT — do not delete on a dead-code report (B-140).\n * `agent.ts` loads this module lazily to keep it off the eager path:\n *\n * streamObjectImport ??= import(\"./stream-object.js\");\n * const { streamObjectImpl } = await streamObjectImport;\n *\n * `knip` resolves imports statically and does not follow a destructure off a\n * dynamic-import promise, so it reports this export as unused on every run. It\n * is not: removing it breaks `Agent.streamObject`. That is why this file is\n * named in `knip.json`'s ignore list rather than cleaned up — the entry is a\n * tool limitation, not a suppression of a real finding, and the difference is\n * the whole reason this comment exists.\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: streaming loop interleaves text-delta accumulation, partial-parse attempts, retries, and final dispose — splitting harms locality of the iterator contract.\nexport async function* streamObjectImpl<T extends ZodType>(\n options: StreamObjectOptions<T>,\n deps: StreamObjectDeps,\n): AsyncGenerator<StreamObjectEvent<ZodNamespace.infer<T>>, void, void> {\n const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(\n options.schema,\n options.maxRetries,\n );\n let capturedRaw: unknown;\n let lastUsage = initialUsage;\n\n const outputTool = makeOutputTool(jsonSchema, (input) => {\n // EC-6: first capture wins (parallel tool use in Claude 3.5+).\n if (capturedRaw === undefined) {\n capturedRaw = input;\n }\n return JSON.stringify({ ok: true });\n });\n\n const agentOptions: AgentOptions = buildTransientAgentOptions({\n model: options.model,\n local: options.local,\n outputTool,\n ...(options.systemPrompt !== undefined ? { systemPrompt: options.systemPrompt } : {}),\n ...(options.apiKey !== undefined ? { apiKey: options.apiKey } : {}),\n ...(options.providers !== undefined ? { providers: options.providers } : {}),\n });\n const agent = await deps.create(agentOptions);\n const userMessage = buildToolPrompt(options.prompt);\n\n try {\n let lastParseError: unknown;\n let attemptCounter = 0;\n\n for (let attempt = 0; attempt <= maxRetries; attempt += 1) {\n capturedRaw = undefined;\n const run = await agent.send(userMessage);\n\n // Buffer text deltas during streaming; try partial-parse on each.\n let textBuffer = \"\";\n for await (const msg of run.stream()) {\n if (msg.type === \"assistant\") {\n const newText = msg.message.content\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\");\n if (newText.length > 0) {\n textBuffer += newText;\n const partial = bestEffortPartialParse(textBuffer, options.schema);\n if (partial !== undefined) {\n attemptCounter += 1;\n yield {\n type: \"partial\",\n partial: partial as DeepPartial<ZodNamespace.infer<T>>,\n attempt: attemptCounter,\n };\n }\n }\n }\n }\n const result = await run.wait();\n lastUsage = extractUsage(result);\n\n if (capturedRaw === undefined) {\n // EC: when the underlying run errored (e.g. provider_unresolved),\n // surface the original cause instead of the misleading \"model\n // returned text\" message — there was no model call at all.\n if (result.status === \"error\" && result.error !== undefined) {\n throw new StreamObjectError(\n \"no_tool_call\",\n `Agent run failed before the model could reply: ${result.error.message ?? \"unknown error\"} [${result.error.code ?? \"?\"}]`,\n result.error,\n );\n }\n if (attempt === maxRetries) {\n throw new StreamObjectError(\n \"no_tool_call\",\n \"The model returned text instead of calling the `output` tool.\",\n );\n }\n continue;\n }\n\n const parsed = options.schema.safeParse(capturedRaw);\n if (parsed.success) {\n yield {\n type: \"complete\",\n object: parsed.data,\n raw: capturedRaw,\n usage: lastUsage,\n finishReason: \"tool_use\",\n };\n return;\n }\n lastParseError = parsed.error;\n }\n\n throw new StreamObjectError(\n \"parse_failed\",\n \"Schema parse failed after all retries.\",\n lastParseError,\n );\n } finally {\n // EC-4: even if consumer calls iter.return() mid-stream, this finally\n // runs — transient agent is disposed AND removed from registry.\n await disposeAndDeleteTransient(agent, deps.delete);\n }\n}\n\n/**\n * Try to extract a partial JSON object from a possibly-incomplete text\n * buffer and parse it via the schema in lenient mode. Returns `undefined`\n * if nothing parseable is found yet.\n *\n * Strategy: find the first `{`, find the LAST balanced `}` (greedy), parse\n * the substring as JSON, then `safeParse` against `schema.partial()` if the\n * schema supports it, else against the original schema.\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: stateful JSON-balancing scanner — string/brace/escape state must be co-located for the parser to remain correct.\nfunction bestEffortPartialParse<T extends ZodType>(text: string, schema: T): unknown | undefined {\n const start = text.indexOf(\"{\");\n if (start < 0) return undefined;\n // Find the longest balanced JSON object from `start`.\n let depth = 0;\n let inString = false;\n let isEscaped = false;\n let end = -1;\n for (let i = start; i < text.length; i += 1) {\n const ch = text[i];\n if (isEscaped) {\n isEscaped = false;\n continue;\n }\n if (ch === \"\\\\\" && inString) {\n isEscaped = true;\n continue;\n }\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) continue;\n if (ch === \"{\") depth += 1;\n else if (ch === \"}\") {\n depth -= 1;\n if (depth === 0) end = i;\n }\n }\n if (end < 0) return undefined;\n const candidate = text.slice(start, end + 1);\n let parsed: unknown;\n try {\n parsed = JSON.parse(candidate);\n } catch {\n return undefined;\n }\n // Try schema.partial() if available (Zod objects support it); else fall\n // back to the original schema (loose match).\n const maybePartial = (schema as unknown as { partial?: () => ZodType }).partial;\n const looseSchema = typeof maybePartial === \"function\" ? maybePartial.call(schema) : schema;\n const result = looseSchema.safeParse(parsed);\n return result.success ? result.data : undefined;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { reconstructMessages, SessionTranscript } from './chunk-FKMUFNQE.js';
1
+ import { reconstructMessages, SessionTranscript } from './chunk-UMP6OJIM.js';
2
2
 
3
3
  // src/internal/session/agent-session-store.ts
4
4
  function seedTranscript(prior, opts) {
@@ -101,5 +101,5 @@ async function appendCompactBoundaryRecord(store, loc, sessionId, meta) {
101
101
  }
102
102
 
103
103
  export { appendCompactBoundaryRecord, persistTurn, readSessionMessages };
104
- //# sourceMappingURL=chunk-G24KZRSA.js.map
105
- //# sourceMappingURL=chunk-G24KZRSA.js.map
104
+ //# sourceMappingURL=chunk-N2U4AZGB.js.map
105
+ //# sourceMappingURL=chunk-N2U4AZGB.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/session/agent-session-store.ts"],"names":[],"mappings":"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","file":"chunk-G24KZRSA.js","sourcesContent":["/**\n * SE40 — native session store over the Claude-shaped `.jsonl` transcript.\n *\n * The theokit session format IS the Claude Code record shape (see\n * `../../persistence/session-transcript.ts`). This module owns the FS lifecycle:\n * read existing records, seed a {@link SessionTranscript}'s parent chain, append\n * the new turn (user + assistant/tool blocks), and write append-only. Compaction\n * appends a `compact_boundary` record (a new root) — it NEVER shrinks the line\n * set (that would break the DAG). Reads reconstruct `LlmMessage[]` via\n * {@link reconstructMessages}, narrowed to the in-memory {@link SessionMessage}.\n *\n * @internal\n */\n\nimport type { ToolResultContentBlock } from \"../../types/content-blocks.js\";\nimport type { ConversationStep, ConversationTurn } from \"../../types/conversation.js\";\nimport type { SessionStore } from \"../../types/session-store.js\";\nimport {\n type AssistantTurn,\n reconstructMessages,\n type SessionRecord,\n SessionTranscript,\n} from \"../persistence/session-transcript.js\";\nimport type { SessionMessage, SessionMessagePart } from \"./session-types.js\";\n\n/**\n * Seed a {@link SessionTranscript} from the already-on-disk records so a new\n * append parents correctly on the existing DAG leaf. The transcript re-emits the\n * seeded records verbatim before the new turn, so the whole file rewrites atomically\n * as one append-only line set. Returns the transcript primed with the prior records.\n */\nfunction seedTranscript(\n prior: readonly SessionRecord[],\n opts: { cwd: string; sessionId: string; model: string },\n): SessionTranscript {\n return SessionTranscript.fromRecords(prior, opts);\n}\n\n/** The turn to persist: the user's text plus the rich per-turn conversation view. */\nexport interface PersistTurnInput {\n userText: string;\n conversation: readonly ConversationTurn[];\n /**\n * M50 — when supplied, size-driven auto-compaction runs in the SAME write chain after the turn\n * persists (usage real vs the model's context window; summarizer injected by the caller).\n */\n autoCompact?: {\n usageTotal?: number | undefined;\n contextWindow?: number | undefined;\n summarize: (\n messages: readonly import(\"../../compaction.js\").CompressibleMessage[],\n ) => Promise<string>;\n };\n}\n\ninterface MappedTurn {\n assistant: AssistantTurn;\n toolResults: Array<{ toolUseId: string; content: string; isError?: boolean }>;\n}\n\n/**\n * theokit#122 — record the turn's thinking block, signature included.\n *\n * The signature is what makes the block replayable: without it the resumed turn is rejected by\n * Anthropic with `400 \"thinking blocks cannot be modified\"`.\n */\nfunction applyThinkingStep(\n assistant: AssistantTurn,\n message: { text: string; signature?: string },\n): void {\n assistant.thinking = message.text;\n if (message.signature !== undefined) assistant.thinkingSignature = message.signature;\n}\n\n/** Fold one agent turn's steps into an assistant record + paired tool results. */\nfunction mapAgentTurn(steps: readonly ConversationStep[]): MappedTurn {\n const assistant: AssistantTurn = {};\n const toolResults: MappedTurn[\"toolResults\"] = [];\n const toolCalls: NonNullable<AssistantTurn[\"toolCalls\"]> = [];\n for (const step of steps) {\n if (step.type === \"thinkingMessage\") applyThinkingStep(assistant, step.message);\n else if (step.type === \"assistantMessage\") assistant.text = step.message.text;\n else if (step.type === \"toolCall\")\n toolCalls.push({\n id: step.message.callId,\n name: step.message.name,\n input: (step.message.args as Record<string, unknown> | undefined) ?? {},\n });\n else\n toolResults.push({\n toolUseId: step.message.callId,\n content: step.message.result,\n isError: step.message.isError,\n });\n }\n if (toolCalls.length > 0) assistant.toolCalls = toolCalls;\n return { assistant, toolResults };\n}\n\n/** True when the assistant record carries any content worth emitting. */\nfunction hasAssistantContent(a: AssistantTurn): boolean {\n return a.text !== undefined || a.thinking !== undefined || (a.toolCalls?.length ?? 0) > 0;\n}\n\n/**\n * Map the rich `ConversationTurn[]` (from `run.conversation()`) into the native\n * assistant/tool records. One transcript turn is: an `assistant` record carrying\n * thinking + text + tool_use blocks, then (when present) a `user` record carrying\n * the paired tool_result blocks. Tool results pair with tool_use by `callId`.\n */\nfunction appendConversation(\n transcript: SessionTranscript,\n conversation: readonly ConversationTurn[],\n): void {\n for (const ct of conversation) {\n if (ct.type !== \"agentConversationTurn\") continue;\n const { assistant, toolResults } = mapAgentTurn(ct.turn.steps);\n if (hasAssistantContent(assistant)) transcript.appendAssistantTurn(assistant);\n if (toolResults.length > 0) transcript.appendToolResults(toolResults);\n }\n}\n\n/**\n * The per-agent transcript metadata used to seed a {@link SessionTranscript}. The\n * actual record I/O goes through the injected {@link SessionStore} (SE41), so this\n * no longer carries a `baseDir` — the store is already bound to its location.\n */\nexport interface TranscriptLocation {\n cwd: string;\n agentId: string;\n model: string;\n}\n\n/**\n * Read the session's records via the {@link SessionStore} and reconstruct the\n * resumable history, narrowed to the in-memory {@link SessionMessage} shape\n * (user/assistant text). Tool turns fold into assistant-role context so resume\n * keeps tool history. Works identically for the FS default and an external store.\n */\nexport async function readSessionMessages(\n store: SessionStore,\n agentId: string,\n): Promise<SessionMessage[]> {\n const records = await store.readRecords(agentId);\n return reconstructMessages(records).map(narrowToSessionMessage);\n}\n\ntype NarrowPart = {\n type: string;\n text?: string;\n content?: unknown;\n name?: string;\n id?: string;\n toolUseId?: string;\n input?: unknown;\n isError?: boolean;\n};\n\n/** Render one reconstructed content part as folded session text. */\nfunction partToText(p: NarrowPart): string {\n if (p.type === \"text\") return p.text ?? \"\";\n if (p.type === \"tool_use\") return `[tool call] ${p.name ?? \"\"}`;\n if (p.type === \"tool_result\") {\n const body = typeof p.content === \"string\" ? p.content : JSON.stringify(p.content);\n return `[tool result] ${body}`;\n }\n return \"\";\n}\n\n/**\n * theokit#146 — the same part, kept as STRUCTURE.\n *\n * `partToText` above is what the model replay wants; a host rendering tool cards needs the call id,\n * the tool name and the arguments, none of which survive `[tool call] NAME`. Both projections are\n * produced from the one reconstructed part, so they cannot drift apart.\n *\n * Returns `undefined` for a part with no display meaning (e.g. an image placeholder the session\n * projection does not model), which the caller filters out.\n */\nfunction partToStructured(p: NarrowPart): SessionMessagePart | undefined {\n if (p.type === \"text\") return { type: \"text\", text: p.text ?? \"\" };\n if (p.type === \"tool_use\") {\n return {\n type: \"tool_use\",\n id: p.id ?? \"\",\n name: p.name ?? \"\",\n input: (p.input ?? {}) as Record<string, unknown>,\n };\n }\n if (p.type === \"tool_result\") {\n return {\n type: \"tool_result\",\n toolUseId: p.toolUseId ?? \"\",\n // Reconstructed tool results carry either a string or the SE7 content blocks; both are\n // already the session shape, so this narrows `unknown` rather than converting anything.\n content: p.content as string | ReadonlyArray<ToolResultContentBlock>,\n ...(p.isError === true ? { isError: true } : {}),\n };\n }\n return undefined;\n}\n\n/** Flatten a reconstructed `LlmMessage` to the narrowed in-memory `SessionMessage`. */\nfunction narrowToSessionMessage(m: {\n role: \"system\" | \"user\" | \"assistant\";\n content: NarrowPart[];\n}): SessionMessage {\n const role = m.role === \"user\" ? \"user\" : \"assistant\";\n const text = m.content\n .map(partToText)\n .filter((s) => s.length > 0)\n .join(\"\\n\");\n const parts = m.content\n .map(partToStructured)\n .filter((p): p is SessionMessagePart => p !== undefined);\n return { role, text, parts };\n}\n\n/** The records appended by the last turn (the delta beyond the seeded prior). */\nfunction deltaRecords(\n transcript: SessionTranscript,\n priorLength: number,\n): readonly SessionRecord[] {\n return transcript.records().slice(priorLength);\n}\n\n/**\n * Persist one conversation turn (user + assistant/tool records) to the session\n * store, append-only. Reads the prior records to seed the parent chain, folds the\n * new turn, and appends ONLY the delta via {@link SessionStore.appendRecords}\n * (the store owns the append atomicity — the FS default serializes under a file\n * lock). Within one process, turns for an agent are already chained upstream, so\n * the read→append is ordered; cross-host ordering is the external store's contract.\n */\nexport async function persistTurn(\n store: SessionStore,\n loc: TranscriptLocation,\n sessionId: string,\n turn: PersistTurnInput,\n): Promise<void> {\n const prior = await store.readRecords(loc.agentId);\n const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });\n transcript.appendUserTurn(turn.userText);\n appendConversation(transcript, turn.conversation);\n await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));\n}\n\n/**\n * Append-only compaction: add a `compact_boundary` system record (a new root) so\n * resume replays only the post-boundary continuation. Appends only the boundary\n * record via the store — NEVER rewrites or shrinks the prior records.\n */\nexport async function appendCompactBoundaryRecord(\n store: SessionStore,\n loc: TranscriptLocation,\n sessionId: string,\n meta: { preTokens: number; trigger: string },\n): Promise<void> {\n const prior = await store.readRecords(loc.agentId);\n const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });\n transcript.appendCompactBoundary(meta);\n await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/session/agent-session-store.ts"],"names":[],"mappings":"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","file":"chunk-N2U4AZGB.js","sourcesContent":["/**\n * SE40 — native session store over the Claude-shaped `.jsonl` transcript.\n *\n * The theokit session format IS the Claude Code record shape (see\n * `../../persistence/session-transcript.ts`). This module owns the FS lifecycle:\n * read existing records, seed a {@link SessionTranscript}'s parent chain, append\n * the new turn (user + assistant/tool blocks), and write append-only. Compaction\n * appends a `compact_boundary` record (a new root) — it NEVER shrinks the line\n * set (that would break the DAG). Reads reconstruct `LlmMessage[]` via\n * {@link reconstructMessages}, narrowed to the in-memory {@link SessionMessage}.\n *\n * @internal\n */\n\nimport type { ToolResultContentBlock } from \"../../types/content-blocks.js\";\nimport type { ConversationStep, ConversationTurn } from \"../../types/conversation.js\";\nimport type { SessionStore } from \"../../types/session-store.js\";\nimport {\n type AssistantTurn,\n reconstructMessages,\n type SessionRecord,\n SessionTranscript,\n} from \"../persistence/session-transcript.js\";\nimport type { SessionMessage, SessionMessagePart } from \"./session-types.js\";\n\n/**\n * Seed a {@link SessionTranscript} from the already-on-disk records so a new\n * append parents correctly on the existing DAG leaf. The transcript re-emits the\n * seeded records verbatim before the new turn, so the whole file rewrites atomically\n * as one append-only line set. Returns the transcript primed with the prior records.\n */\nfunction seedTranscript(\n prior: readonly SessionRecord[],\n opts: { cwd: string; sessionId: string; model: string },\n): SessionTranscript {\n return SessionTranscript.fromRecords(prior, opts);\n}\n\n/** The turn to persist: the user's text plus the rich per-turn conversation view. */\nexport interface PersistTurnInput {\n userText: string;\n conversation: readonly ConversationTurn[];\n /**\n * M50 — when supplied, size-driven auto-compaction runs in the SAME write chain after the turn\n * persists (usage real vs the model's context window; summarizer injected by the caller).\n */\n autoCompact?: {\n usageTotal?: number | undefined;\n contextWindow?: number | undefined;\n summarize: (\n messages: readonly import(\"../../compaction.js\").CompressibleMessage[],\n ) => Promise<string>;\n };\n}\n\ninterface MappedTurn {\n assistant: AssistantTurn;\n toolResults: Array<{ toolUseId: string; content: string; isError?: boolean }>;\n}\n\n/**\n * theokit#122 — record the turn's thinking block, signature included.\n *\n * The signature is what makes the block replayable: without it the resumed turn is rejected by\n * Anthropic with `400 \"thinking blocks cannot be modified\"`.\n */\nfunction applyThinkingStep(\n assistant: AssistantTurn,\n message: { text: string; signature?: string },\n): void {\n assistant.thinking = message.text;\n if (message.signature !== undefined) assistant.thinkingSignature = message.signature;\n}\n\n/** Fold one agent turn's steps into an assistant record + paired tool results. */\nfunction mapAgentTurn(steps: readonly ConversationStep[]): MappedTurn {\n const assistant: AssistantTurn = {};\n const toolResults: MappedTurn[\"toolResults\"] = [];\n const toolCalls: NonNullable<AssistantTurn[\"toolCalls\"]> = [];\n for (const step of steps) {\n if (step.type === \"thinkingMessage\") applyThinkingStep(assistant, step.message);\n else if (step.type === \"assistantMessage\") assistant.text = step.message.text;\n else if (step.type === \"toolCall\")\n toolCalls.push({\n id: step.message.callId,\n name: step.message.name,\n input: (step.message.args as Record<string, unknown> | undefined) ?? {},\n });\n else\n toolResults.push({\n toolUseId: step.message.callId,\n content: step.message.result,\n isError: step.message.isError,\n });\n }\n if (toolCalls.length > 0) assistant.toolCalls = toolCalls;\n return { assistant, toolResults };\n}\n\n/** True when the assistant record carries any content worth emitting. */\nfunction hasAssistantContent(a: AssistantTurn): boolean {\n return a.text !== undefined || a.thinking !== undefined || (a.toolCalls?.length ?? 0) > 0;\n}\n\n/**\n * Map the rich `ConversationTurn[]` (from `run.conversation()`) into the native\n * assistant/tool records. One transcript turn is: an `assistant` record carrying\n * thinking + text + tool_use blocks, then (when present) a `user` record carrying\n * the paired tool_result blocks. Tool results pair with tool_use by `callId`.\n */\nfunction appendConversation(\n transcript: SessionTranscript,\n conversation: readonly ConversationTurn[],\n): void {\n for (const ct of conversation) {\n if (ct.type !== \"agentConversationTurn\") continue;\n const { assistant, toolResults } = mapAgentTurn(ct.turn.steps);\n if (hasAssistantContent(assistant)) transcript.appendAssistantTurn(assistant);\n if (toolResults.length > 0) transcript.appendToolResults(toolResults);\n }\n}\n\n/**\n * The per-agent transcript metadata used to seed a {@link SessionTranscript}. The\n * actual record I/O goes through the injected {@link SessionStore} (SE41), so this\n * no longer carries a `baseDir` — the store is already bound to its location.\n */\nexport interface TranscriptLocation {\n cwd: string;\n agentId: string;\n model: string;\n}\n\n/**\n * Read the session's records via the {@link SessionStore} and reconstruct the\n * resumable history, narrowed to the in-memory {@link SessionMessage} shape\n * (user/assistant text). Tool turns fold into assistant-role context so resume\n * keeps tool history. Works identically for the FS default and an external store.\n */\nexport async function readSessionMessages(\n store: SessionStore,\n agentId: string,\n): Promise<SessionMessage[]> {\n const records = await store.readRecords(agentId);\n return reconstructMessages(records).map(narrowToSessionMessage);\n}\n\ntype NarrowPart = {\n type: string;\n text?: string;\n content?: unknown;\n name?: string;\n id?: string;\n toolUseId?: string;\n input?: unknown;\n isError?: boolean;\n};\n\n/** Render one reconstructed content part as folded session text. */\nfunction partToText(p: NarrowPart): string {\n if (p.type === \"text\") return p.text ?? \"\";\n if (p.type === \"tool_use\") return `[tool call] ${p.name ?? \"\"}`;\n if (p.type === \"tool_result\") {\n const body = typeof p.content === \"string\" ? p.content : JSON.stringify(p.content);\n return `[tool result] ${body}`;\n }\n return \"\";\n}\n\n/**\n * theokit#146 — the same part, kept as STRUCTURE.\n *\n * `partToText` above is what the model replay wants; a host rendering tool cards needs the call id,\n * the tool name and the arguments, none of which survive `[tool call] NAME`. Both projections are\n * produced from the one reconstructed part, so they cannot drift apart.\n *\n * Returns `undefined` for a part with no display meaning (e.g. an image placeholder the session\n * projection does not model), which the caller filters out.\n */\nfunction partToStructured(p: NarrowPart): SessionMessagePart | undefined {\n if (p.type === \"text\") return { type: \"text\", text: p.text ?? \"\" };\n if (p.type === \"tool_use\") {\n return {\n type: \"tool_use\",\n id: p.id ?? \"\",\n name: p.name ?? \"\",\n input: (p.input ?? {}) as Record<string, unknown>,\n };\n }\n if (p.type === \"tool_result\") {\n return {\n type: \"tool_result\",\n toolUseId: p.toolUseId ?? \"\",\n // Reconstructed tool results carry either a string or the SE7 content blocks; both are\n // already the session shape, so this narrows `unknown` rather than converting anything.\n content: p.content as string | ReadonlyArray<ToolResultContentBlock>,\n ...(p.isError === true ? { isError: true } : {}),\n };\n }\n return undefined;\n}\n\n/** Flatten a reconstructed `LlmMessage` to the narrowed in-memory `SessionMessage`. */\nfunction narrowToSessionMessage(m: {\n role: \"system\" | \"user\" | \"assistant\";\n content: NarrowPart[];\n}): SessionMessage {\n const role = m.role === \"user\" ? \"user\" : \"assistant\";\n const text = m.content\n .map(partToText)\n .filter((s) => s.length > 0)\n .join(\"\\n\");\n const parts = m.content\n .map(partToStructured)\n .filter((p): p is SessionMessagePart => p !== undefined);\n return { role, text, parts };\n}\n\n/** The records appended by the last turn (the delta beyond the seeded prior). */\nfunction deltaRecords(\n transcript: SessionTranscript,\n priorLength: number,\n): readonly SessionRecord[] {\n return transcript.records().slice(priorLength);\n}\n\n/**\n * Persist one conversation turn (user + assistant/tool records) to the session\n * store, append-only. Reads the prior records to seed the parent chain, folds the\n * new turn, and appends ONLY the delta via {@link SessionStore.appendRecords}\n * (the store owns the append atomicity — the FS default serializes under a file\n * lock). Within one process, turns for an agent are already chained upstream, so\n * the read→append is ordered; cross-host ordering is the external store's contract.\n */\nexport async function persistTurn(\n store: SessionStore,\n loc: TranscriptLocation,\n sessionId: string,\n turn: PersistTurnInput,\n): Promise<void> {\n const prior = await store.readRecords(loc.agentId);\n const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });\n transcript.appendUserTurn(turn.userText);\n appendConversation(transcript, turn.conversation);\n await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));\n}\n\n/**\n * Append-only compaction: add a `compact_boundary` system record (a new root) so\n * resume replays only the post-boundary continuation. Appends only the boundary\n * record via the store — NEVER rewrites or shrinks the prior records.\n */\nexport async function appendCompactBoundaryRecord(\n store: SessionStore,\n loc: TranscriptLocation,\n sessionId: string,\n meta: { preTokens: number; trigger: string },\n): Promise<void> {\n const prior = await store.readRecords(loc.agentId);\n const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });\n transcript.appendCompactBoundary(meta);\n await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { safePathJoin, assertNoSymlinkEscape } from './chunk-QARJGQSA.js';
2
- import { readWorkspaceDir, parseSimpleYaml } from './chunk-AG5JPQIY.js';
3
- import { ConfigurationError } from './chunk-IDCKSLYH.js';
1
+ import { safePathJoin, assertNoSymlinkEscape } from './chunk-HS7AVXTF.js';
2
+ import { readWorkspaceDir, parseSimpleYaml } from './chunk-LXQ6HKPS.js';
3
+ import { ConfigurationError } from './chunk-ZZMZWBR6.js';
4
4
  import { readFile } from 'fs/promises';
5
5
  import { join } from 'path';
6
6
 
@@ -145,5 +145,5 @@ ${lines.join("\n")}
145
145
  }
146
146
 
147
147
  export { buildSkillsBlock, discoverSkills, escapeBlockBody, stripSkillFrontmatter };
148
- //# sourceMappingURL=chunk-4ERPXIVB.js.map
149
- //# sourceMappingURL=chunk-4ERPXIVB.js.map
148
+ //# sourceMappingURL=chunk-O73J46PV.js.map
149
+ //# sourceMappingURL=chunk-O73J46PV.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/runtime/skills/skill-frontmatter.ts","../src/internal/runtime/skills/discover-skills.ts","../src/internal/runtime/system-prompt/escape.ts","../src/internal/runtime/skills/skills-block.ts"],"names":[],"mappings":";;;;;;;AAMA,SAAS,SAAS,CAAA,EAAqD;AACrE,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,GAAW,CAAA,GAAI,MAAA;AACrC;AAGA,SAAS,eAAe,GAAA,EAAiE;AACvF,EAAA,MAAM,MAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,CAAA,IAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG,GAAA,CAAI,CAAC,CAAA,GAAI,QAAA,CAAS,CAAC,CAAA;AAC7D,EAAA,OAAO,GAAA;AACT;AA8BO,SAAS,qBAAA,CAAsB,KAAa,YAAA,EAAwC;AACzF,EAAA,MAAM,MAAA,GAAS,0BAAA,CAA2B,GAAA,EAAK,YAAY,CAAA;AAC3D,EAAA,MAAM,IAAA,GAAO,WAAA,CAAY,MAAA,EAAQ,YAAY,CAAA;AAC7C,EAAA,oBAAA,CAAqB,QAAQ,IAAI,CAAA;AACjC,EAAA,OAAO,gBAAA,CAAiB,QAAQ,IAAI,CAAA;AACtC;AAOO,SAAS,sBAAsB,GAAA,EAAqB;AACzD,EAAA,MAAM,KAAA,GAAQ,6BAAA,CAA8B,IAAA,CAAK,GAAG,CAAA;AACpD,EAAA,OAAA,CAAQ,KAAA,KAAU,IAAA,GAAO,GAAA,GAAM,GAAA,CAAI,KAAA,CAAM,MAAM,CAAC,CAAA,CAAE,MAAM,CAAA,EAAG,IAAA,EAAK;AAClE;AAEA,SAAS,0BAAA,CAA2B,KAAa,YAAA,EAAoC;AACnF,EAAA,MAAM,KAAA,GAAQ,+BAAA,CAAgC,IAAA,CAAK,GAAG,CAAA;AACtD,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,MAAA,EAAS,YAAY,CAAA,uBAAA,CAAA,EAA2B;AAAA,MAC3E,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AACA,EAAA,MAAM,WAAA,GAAc,KAAA,CAAM,CAAC,CAAA,IAAK,EAAA;AAGhC,EAAA,IAAI;AACF,IAAA,OAAO,cAAA,CAAe,eAAA,CAAgB,WAAW,CAAC,CAAA;AAAA,EACpD,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,SAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACpE,IAAA,MAAM,IAAI,kBAAA;AAAA,MACR,CAAA,MAAA,EAAS,YAAY,CAAA,iCAAA,EAAoC,MAAM,CAAA,CAAA;AAAA,MAC/D,EAAE,IAAA,EAAM,gBAAA,EAAkB,KAAA;AAAM,KAClC;AAAA,EACF;AACF;AAEA,SAAS,WAAA,CAAY,QAAsB,YAAA,EAA8B;AACvE,EAAA,IAAI,UAAA,CAAW,MAAA,CAAO,IAAI,CAAA,SAAU,MAAA,CAAO,IAAA;AAC3C,EAAA,IAAI,UAAA,CAAW,YAAY,CAAA,EAAG,OAAO,YAAA;AACrC,EAAA,MAAM,IAAI,mBAAmB,uDAAA,EAAyD;AAAA,IACpF,IAAA,EAAM;AAAA,GACP,CAAA;AACH;AAEA,SAAS,oBAAA,CAAqB,QAAsB,IAAA,EAAoB;AACtE,EAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,WAAW,CAAA,EAAG;AACnC,IAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,MAAA,EAAS,IAAI,CAAA,uCAAA,CAAA,EAA2C;AAAA,MACnF,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AACF;AAEA,SAAS,gBAAA,CAAiB,QAAsB,IAAA,EAAgC;AAC9E,EAAA,MAAM,cAAc,MAAA,CAAO,WAAA;AAC3B,EAAA,IAAI,gBAAgB,MAAA,EAAW;AAE7B,IAAA,MAAM,IAAI,mBAAmB,CAAA,MAAA,EAAS,IAAI,wBAAwB,EAAE,IAAA,EAAM,kBAAkB,CAAA;AAAA,EAC9F;AACA,EAAA,MAAM,MAAA,GAA2B,EAAE,IAAA,EAAM,WAAA,EAAY;AACrD,EAAA,IAAI,WAAW,MAAA,CAAO,QAAQ,CAAA,EAAG,MAAA,CAAO,WAAW,MAAA,CAAO,QAAA;AAC1D,EAAA,MAAM,IAAA,GAAO,iBAAA,CAAkB,MAAA,CAAO,YAAY,CAAA;AAClD,EAAA,IAAI,IAAA,KAAS,MAAA,EAAW,MAAA,CAAO,YAAA,GAAe,IAAA;AAC9C,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,kBAAkB,GAAA,EAA+C;AACxE,EAAA,IAAI,CAAC,UAAA,CAAW,GAAG,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,MAAM,OAAQ,GAAA,CACX,KAAA,CAAM,GAAG,CAAA,CACT,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAA,CACnB,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,CAAC,CAAA;AAC7B,EAAA,OAAO,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,IAAA,GAAO,MAAA;AAClC;AAEA,SAAS,WAAW,KAAA,EAA4C;AAC9D,EAAA,OAAO,KAAA,KAAU,MAAA,IAAa,KAAA,CAAM,IAAA,GAAO,MAAA,GAAS,CAAA;AACtD;;;AC7CA,eAAsB,cAAA,CACpB,KACA,OAAA,EACkB;AAClB,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAA,GAAU,MAAM,gBAAA,CAAiB,GAAA,EAAK,mBAAA,EAAqB,kBAAkB,CAAA;AAAA,EAC/E,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,SAAkB,EAAC;AACzB,EAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,IAAA,IAAI,CAAC,KAAA,CAAM,WAAA,EAAY,EAAG;AAC1B,IAAA,IAAI,QAAA;AACJ,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,YAAA,CAAa,GAAA,EAAK,KAAA,CAAM,IAAI,CAAA;AACvC,MAAA,qBAAA,CAAsB,UAAU,GAAG,CAAA;AAAA,IACrC,CAAA,CAAA,MAAQ;AACN,MAAA;AAAA,IACF;AACA,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,QAAA,EAAU,UAAU,CAAA;AAC3C,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,QAAA,CAAS,SAAA,EAAW,MAAM,CAAA;AAAA,IACxC,CAAA,CAAA,MAAQ;AAEN,MAAA;AAAA,IACF;AACA,IAAA,MAAM,QAAQ,aAAA,CAAc,GAAA,EAAK,KAAA,CAAM,IAAA,EAAM,WAAW,OAAO,CAAA;AAC/D,IAAA,IAAI,KAAA,KAAU,MAAA,EAAW,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAAA,EAC5C;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,aAAA,CACP,GAAA,EACA,YAAA,EACA,MAAA,EACA,OAAA,EACmB;AACnB,EAAA,IAAI;AACF,IAAA,MAAM,WAAA,GAAc,qBAAA,CAAsB,GAAA,EAAK,YAAY,CAAA;AAC3D,IAAA,MAAM,KAAA,GAAe;AAAA,MACnB,MAAM,WAAA,CAAY,IAAA;AAAA,MAClB,aAAa,WAAA,CAAY,WAAA;AAAA,MACzB;AAAA,KACF;AACA,IAAA,IAAI,WAAA,CAAY,QAAA,KAAa,KAAA,CAAA,EAAW,KAAA,CAAM,WAAW,WAAA,CAAY,QAAA;AACrE,IAAA,IAAI,WAAA,CAAY,YAAA,KAAiB,KAAA,CAAA,EAAW,KAAA,CAAM,eAAe,WAAA,CAAY,YAAA;AAC7E,IAAA,OAAO,KAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,iBAAiB,kBAAA,EAAoB;AACvC,MAAA,OAAA,EAAS,cAAA,GAAiB;AAAA,QACxB,IAAA,EAAM,YAAA;AAAA,QACN,MAAA;AAAA,QACA,IAAA,EAAM,MAAM,IAAA,IAAQ,SAAA;AAAA,QACpB,SAAS,KAAA,CAAM;AAAA,OAChB,CAAA;AACD,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,MAAM,KAAA;AAAA,EACR;AACF;;;ACtIO,IAAM,eAAA,GAAkB,CAAC,CAAA,KAC9B,CAAA,CAAE,QAAQ,IAAA,EAAM,OAAO,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,MAAM,CAAA,CAAE,OAAA,CAAQ,MAAM,MAAM;;;ACO9D,SAAS,iBACd,MAAA,EACoB;AACpB,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAChC,EAAA,MAAM,QAAQ,MAAA,CAAO,GAAA;AAAA,IACnB,CAAC,KAAA,KAAU,CAAA,IAAA,EAAO,eAAA,CAAgB,KAAA,CAAM,IAAI,CAAC,CAAA,EAAA,EAAK,eAAA,CAAgB,KAAA,CAAM,WAAW,CAAC,CAAA;AAAA,GACtF;AACA,EAAA,OAAO,CAAA;AAAA,EAAa,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC;AAAA,SAAA,CAAA;AACtC","file":"chunk-4ERPXIVB.js","sourcesContent":["import { ConfigurationError } from \"../../../errors.js\";\nimport { type FrontmatterValue, parseSimpleYaml } from \"../context/yaml-frontmatter.js\";\n\ntype StringFields = Record<string, string | undefined>;\n\n/** Narrow a FrontmatterValue to string; non-strings + undefined → undefined. */\nfunction asString(v: FrontmatterValue | undefined): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\n\n/** Coerce parser output to legacy string-only shape (skill schema is all-string). */\nfunction toStringFields(raw: Record<string, FrontmatterValue | undefined>): StringFields {\n const out: StringFields = {};\n for (const [k, v] of Object.entries(raw)) out[k] = asString(v);\n return out;\n}\n\n/**\n * Strict skill frontmatter schema (ADR D10).\n *\n * Required: `name`, `description`.\n * Optional: `category`, `dependencies` (comma-separated string in the\n * simple-YAML dialect — parsed to `string[]`).\n *\n * Unknown fields are ignored (forward-compat). Malformed YAML or missing\n * required fields surface as `ConfigurationError` with one of the typed\n * codes below.\n *\n * @internal\n */\nexport interface SkillFrontmatter {\n name: string;\n description: string;\n category?: string;\n dependencies?: string[];\n}\n\n/**\n * Parse a SKILL.md file body into validated frontmatter.\n *\n * @throws ConfigurationError(code: \"missing_frontmatter\") — no `---` block at file head.\n * @throws ConfigurationError(code: \"schema_invalid\") — YAML malformed OR required field missing.\n *\n * @internal\n */\nexport function parseSkillFrontmatter(raw: string, fallbackName: string): SkillFrontmatter {\n const fields = extractAndParseFrontmatter(raw, fallbackName);\n const name = resolveName(fields, fallbackName);\n ensureRequiredFields(fields, name);\n return buildFrontmatter(fields, name);\n}\n\n/**\n * SE20 — return a SKILL.md's BODY (everything after the frontmatter block), trimmed.\n * When there is no frontmatter block, the whole file is the body. Reuses the same\n * frontmatter regex as {@link parseSkillFrontmatter} (DRY).\n */\nexport function stripSkillFrontmatter(raw: string): string {\n const match = /^---\\s*\\n[\\s\\S]*?\\n---\\s*\\n/.exec(raw);\n return (match === null ? raw : raw.slice(match[0].length)).trim();\n}\n\nfunction extractAndParseFrontmatter(raw: string, fallbackName: string): StringFields {\n const match = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n/.exec(raw);\n if (match === null) {\n throw new ConfigurationError(`Skill ${fallbackName} is missing frontmatter`, {\n code: \"missing_frontmatter\",\n });\n }\n const frontmatter = match[1] ?? \"\";\n // EC-5: guard against syntactically invalid frontmatter so the loader\n // surfaces schema_invalid rather than crashing.\n try {\n return toStringFields(parseSimpleYaml(frontmatter));\n } catch (cause) {\n const detail = cause instanceof Error ? cause.message : String(cause);\n throw new ConfigurationError(\n `Skill ${fallbackName} has malformed YAML frontmatter: ${detail}`,\n { code: \"schema_invalid\", cause },\n );\n }\n}\n\nfunction resolveName(fields: StringFields, fallbackName: string): string {\n if (hasContent(fields.name)) return fields.name;\n if (hasContent(fallbackName)) return fallbackName;\n throw new ConfigurationError(\"Skill at unknown path is missing required field: name\", {\n code: \"schema_invalid\",\n });\n}\n\nfunction ensureRequiredFields(fields: StringFields, name: string): void {\n if (!hasContent(fields.description)) {\n throw new ConfigurationError(`Skill ${name} is missing required field: description`, {\n code: \"schema_invalid\",\n });\n }\n}\n\nfunction buildFrontmatter(fields: StringFields, name: string): SkillFrontmatter {\n const description = fields.description;\n if (description === undefined) {\n // ensureRequiredFields already threw; this is unreachable but satisfies TS\n throw new ConfigurationError(`Skill ${name} missing description`, { code: \"schema_invalid\" });\n }\n const result: SkillFrontmatter = { name, description };\n if (hasContent(fields.category)) result.category = fields.category;\n const deps = parseDependencies(fields.dependencies);\n if (deps !== undefined) result.dependencies = deps;\n return result;\n}\n\nfunction parseDependencies(raw: string | undefined): string[] | undefined {\n if (!hasContent(raw)) return undefined;\n const deps = (raw as string)\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return deps.length > 0 ? deps : undefined;\n}\n\nfunction hasContent(value: string | undefined): value is string {\n return value !== undefined && value.trim().length > 0;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\nimport { assertNoSymlinkEscape, safePathJoin } from \"../../security/path-guard.js\";\nimport { readWorkspaceDir } from \"../config/workspace-dir.js\";\nimport { parseSkillFrontmatter } from \"./skill-frontmatter.js\";\n\n/**\n * A discovered skill's metadata. The skill BODY is never included — only the\n * strict frontmatter fields plus the resolved `source` path.\n *\n * Public via `@theokit/sdk/skills`.\n *\n * @public\n */\nexport interface Skill {\n name: string;\n description: string;\n /** Absolute path to the discovered `SKILL.md`. */\n source: string;\n category?: string;\n dependencies?: string[];\n}\n\n/**\n * Information passed to `onInvalidSkill` when a `SKILL.md` is present but its\n * frontmatter is malformed (missing required field or invalid YAML).\n *\n * @public\n */\nexport interface InvalidSkillInfo {\n /** The skill directory name (used as the fallback skill name). */\n name: string;\n /** Absolute path to the offending `SKILL.md`. */\n source: string;\n /** Typed reason: `missing_frontmatter` or `schema_invalid`. */\n code: string;\n message: string;\n}\n\n/**\n * Options for {@link discoverSkills}.\n *\n * @public\n */\nexport interface DiscoverSkillsOptions {\n /**\n * Called once per directory that contains a `SKILL.md` with malformed\n * frontmatter. The skill is excluded from the result; discovery continues\n * (strict-frontmatter ADR / EC-5). A directory WITHOUT a `SKILL.md` is NOT a\n * malformed skill and does not trigger this callback.\n *\n * Default: no-op (a library primitive must not write to the consumer's\n * stderr by default).\n */\n onInvalidSkill?: (info: InvalidSkillInfo) => void;\n}\n\n/**\n * Discover `SKILL.md` skills under an arbitrary directory.\n *\n * For each immediate subdirectory `<dir>/<name>/` containing a `SKILL.md`, the\n * file's strict YAML frontmatter is parsed (`name`/`description` required;\n * `category`/`dependencies` optional). Malformed skills are skipped (optionally\n * reported via {@link DiscoverSkillsOptions.onInvalidSkill}); a subdirectory\n * whose realpath escapes `dir` (via symlink) is skipped (symlink-escape guard,\n * reusing `@theokit/sdk/path-safety`).\n *\n * NEVER throws: a missing, unreadable, or non-directory `dir` yields `[]`.\n *\n * Discovery order follows the filesystem `readdir` order (OS-dependent). Sort\n * the result before {@link buildSkillsBlock} if a stable block order matters.\n *\n * Public via `@theokit/sdk/skills`.\n *\n * @public\n */\nexport async function discoverSkills(\n dir: string,\n options?: DiscoverSkillsOptions,\n): Promise<Skill[]> {\n let entries: Awaited<ReturnType<typeof readWorkspaceDir>>;\n try {\n entries = await readWorkspaceDir(dir, \"skills_read_error\", \"skills directory\");\n } catch {\n // never-throw contract: unreadable / not-a-directory → no skills (EC-1)\n return [];\n }\n\n const skills: Skill[] = [];\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n let skillDir: string;\n try {\n skillDir = safePathJoin(dir, entry.name);\n assertNoSymlinkEscape(skillDir, dir);\n } catch {\n continue;\n }\n const skillPath = join(skillDir, \"SKILL.md\");\n let raw: string;\n try {\n raw = await readFile(skillPath, \"utf8\");\n } catch {\n // no SKILL.md in this subdir → not a skill, not an error (EC-2)\n continue;\n }\n const skill = tryParseSkill(raw, entry.name, skillPath, options);\n if (skill !== undefined) skills.push(skill);\n }\n return skills;\n}\n\nfunction tryParseSkill(\n raw: string,\n fallbackName: string,\n source: string,\n options: DiscoverSkillsOptions | undefined,\n): Skill | undefined {\n try {\n const frontmatter = parseSkillFrontmatter(raw, fallbackName);\n const skill: Skill = {\n name: frontmatter.name,\n description: frontmatter.description,\n source,\n };\n if (frontmatter.category !== undefined) skill.category = frontmatter.category;\n if (frontmatter.dependencies !== undefined) skill.dependencies = frontmatter.dependencies;\n return skill;\n } catch (cause) {\n if (cause instanceof ConfigurationError) {\n options?.onInvalidSkill?.({\n name: fallbackName,\n source,\n code: cause.code ?? \"unknown\",\n message: cause.message,\n });\n return undefined;\n }\n throw cause;\n }\n}\n","/**\n * Block-body XML escape (ADR D9 — prompt-injection defence).\n *\n * Order matters: `&` MUST be escaped first so subsequent `<`/`>` replacements\n * do not double-encode the `&` characters they introduce.\n *\n * @internal\n */\nexport const escapeBlockBody = (s: string): string =>\n s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n","import { escapeBlockBody } from \"../system-prompt/escape.js\";\n\n/**\n * Render the `<skills>` system-prompt block from a skill list.\n *\n * Input is the structural subset `{ name, description }` — the skill BODY is\n * NOT in the type, so it cannot leak into the prompt. Both fields are passed\n * through `escapeBlockBody` to neutralise prompt-injection vectors hidden in\n * user-controlled SKILL.md frontmatter (injection-escape ADR).\n *\n * Returns `undefined` for an empty list so the caller can omit the block.\n *\n * Public via `@theokit/sdk/skills`.\n *\n * @public\n */\nexport function buildSkillsBlock(\n skills: ReadonlyArray<{ name: string; description: string }>,\n): string | undefined {\n if (skills.length === 0) return undefined;\n const lines = skills.map(\n (skill) => ` - ${escapeBlockBody(skill.name)}: ${escapeBlockBody(skill.description)}`,\n );\n return `<skills>\\n${lines.join(\"\\n\")}\\n</skills>`;\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/runtime/skills/skill-frontmatter.ts","../src/internal/runtime/skills/discover-skills.ts","../src/internal/runtime/system-prompt/escape.ts","../src/internal/runtime/skills/skills-block.ts"],"names":[],"mappings":"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","file":"chunk-O73J46PV.js","sourcesContent":["import { ConfigurationError } from \"../../../errors.js\";\nimport { type FrontmatterValue, parseSimpleYaml } from \"../context/yaml-frontmatter.js\";\n\ntype StringFields = Record<string, string | undefined>;\n\n/** Narrow a FrontmatterValue to string; non-strings + undefined → undefined. */\nfunction asString(v: FrontmatterValue | undefined): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\n\n/** Coerce parser output to legacy string-only shape (skill schema is all-string). */\nfunction toStringFields(raw: Record<string, FrontmatterValue | undefined>): StringFields {\n const out: StringFields = {};\n for (const [k, v] of Object.entries(raw)) out[k] = asString(v);\n return out;\n}\n\n/**\n * Strict skill frontmatter schema (ADR D10).\n *\n * Required: `name`, `description`.\n * Optional: `category`, `dependencies` (comma-separated string in the\n * simple-YAML dialect — parsed to `string[]`).\n *\n * Unknown fields are ignored (forward-compat). Malformed YAML or missing\n * required fields surface as `ConfigurationError` with one of the typed\n * codes below.\n *\n * @internal\n */\nexport interface SkillFrontmatter {\n name: string;\n description: string;\n category?: string;\n dependencies?: string[];\n}\n\n/**\n * Parse a SKILL.md file body into validated frontmatter.\n *\n * @throws ConfigurationError(code: \"missing_frontmatter\") — no `---` block at file head.\n * @throws ConfigurationError(code: \"schema_invalid\") — YAML malformed OR required field missing.\n *\n * @internal\n */\nexport function parseSkillFrontmatter(raw: string, fallbackName: string): SkillFrontmatter {\n const fields = extractAndParseFrontmatter(raw, fallbackName);\n const name = resolveName(fields, fallbackName);\n ensureRequiredFields(fields, name);\n return buildFrontmatter(fields, name);\n}\n\n/**\n * SE20 — return a SKILL.md's BODY (everything after the frontmatter block), trimmed.\n * When there is no frontmatter block, the whole file is the body. Reuses the same\n * frontmatter regex as {@link parseSkillFrontmatter} (DRY).\n */\nexport function stripSkillFrontmatter(raw: string): string {\n const match = /^---\\s*\\n[\\s\\S]*?\\n---\\s*\\n/.exec(raw);\n return (match === null ? raw : raw.slice(match[0].length)).trim();\n}\n\nfunction extractAndParseFrontmatter(raw: string, fallbackName: string): StringFields {\n const match = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n/.exec(raw);\n if (match === null) {\n throw new ConfigurationError(`Skill ${fallbackName} is missing frontmatter`, {\n code: \"missing_frontmatter\",\n });\n }\n const frontmatter = match[1] ?? \"\";\n // EC-5: guard against syntactically invalid frontmatter so the loader\n // surfaces schema_invalid rather than crashing.\n try {\n return toStringFields(parseSimpleYaml(frontmatter));\n } catch (cause) {\n const detail = cause instanceof Error ? cause.message : String(cause);\n throw new ConfigurationError(\n `Skill ${fallbackName} has malformed YAML frontmatter: ${detail}`,\n { code: \"schema_invalid\", cause },\n );\n }\n}\n\nfunction resolveName(fields: StringFields, fallbackName: string): string {\n if (hasContent(fields.name)) return fields.name;\n if (hasContent(fallbackName)) return fallbackName;\n throw new ConfigurationError(\"Skill at unknown path is missing required field: name\", {\n code: \"schema_invalid\",\n });\n}\n\nfunction ensureRequiredFields(fields: StringFields, name: string): void {\n if (!hasContent(fields.description)) {\n throw new ConfigurationError(`Skill ${name} is missing required field: description`, {\n code: \"schema_invalid\",\n });\n }\n}\n\nfunction buildFrontmatter(fields: StringFields, name: string): SkillFrontmatter {\n const description = fields.description;\n if (description === undefined) {\n // ensureRequiredFields already threw; this is unreachable but satisfies TS\n throw new ConfigurationError(`Skill ${name} missing description`, { code: \"schema_invalid\" });\n }\n const result: SkillFrontmatter = { name, description };\n if (hasContent(fields.category)) result.category = fields.category;\n const deps = parseDependencies(fields.dependencies);\n if (deps !== undefined) result.dependencies = deps;\n return result;\n}\n\nfunction parseDependencies(raw: string | undefined): string[] | undefined {\n if (!hasContent(raw)) return undefined;\n const deps = (raw as string)\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return deps.length > 0 ? deps : undefined;\n}\n\nfunction hasContent(value: string | undefined): value is string {\n return value !== undefined && value.trim().length > 0;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\nimport { assertNoSymlinkEscape, safePathJoin } from \"../../security/path-guard.js\";\nimport { readWorkspaceDir } from \"../config/workspace-dir.js\";\nimport { parseSkillFrontmatter } from \"./skill-frontmatter.js\";\n\n/**\n * A discovered skill's metadata. The skill BODY is never included — only the\n * strict frontmatter fields plus the resolved `source` path.\n *\n * Public via `@theokit/sdk/skills`.\n *\n * @public\n */\nexport interface Skill {\n name: string;\n description: string;\n /** Absolute path to the discovered `SKILL.md`. */\n source: string;\n category?: string;\n dependencies?: string[];\n}\n\n/**\n * Information passed to `onInvalidSkill` when a `SKILL.md` is present but its\n * frontmatter is malformed (missing required field or invalid YAML).\n *\n * @public\n */\nexport interface InvalidSkillInfo {\n /** The skill directory name (used as the fallback skill name). */\n name: string;\n /** Absolute path to the offending `SKILL.md`. */\n source: string;\n /** Typed reason: `missing_frontmatter` or `schema_invalid`. */\n code: string;\n message: string;\n}\n\n/**\n * Options for {@link discoverSkills}.\n *\n * @public\n */\nexport interface DiscoverSkillsOptions {\n /**\n * Called once per directory that contains a `SKILL.md` with malformed\n * frontmatter. The skill is excluded from the result; discovery continues\n * (strict-frontmatter ADR / EC-5). A directory WITHOUT a `SKILL.md` is NOT a\n * malformed skill and does not trigger this callback.\n *\n * Default: no-op (a library primitive must not write to the consumer's\n * stderr by default).\n */\n onInvalidSkill?: (info: InvalidSkillInfo) => void;\n}\n\n/**\n * Discover `SKILL.md` skills under an arbitrary directory.\n *\n * For each immediate subdirectory `<dir>/<name>/` containing a `SKILL.md`, the\n * file's strict YAML frontmatter is parsed (`name`/`description` required;\n * `category`/`dependencies` optional). Malformed skills are skipped (optionally\n * reported via {@link DiscoverSkillsOptions.onInvalidSkill}); a subdirectory\n * whose realpath escapes `dir` (via symlink) is skipped (symlink-escape guard,\n * reusing `@theokit/sdk/path-safety`).\n *\n * NEVER throws: a missing, unreadable, or non-directory `dir` yields `[]`.\n *\n * Discovery order follows the filesystem `readdir` order (OS-dependent). Sort\n * the result before {@link buildSkillsBlock} if a stable block order matters.\n *\n * Public via `@theokit/sdk/skills`.\n *\n * @public\n */\nexport async function discoverSkills(\n dir: string,\n options?: DiscoverSkillsOptions,\n): Promise<Skill[]> {\n let entries: Awaited<ReturnType<typeof readWorkspaceDir>>;\n try {\n entries = await readWorkspaceDir(dir, \"skills_read_error\", \"skills directory\");\n } catch {\n // never-throw contract: unreadable / not-a-directory → no skills (EC-1)\n return [];\n }\n\n const skills: Skill[] = [];\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n let skillDir: string;\n try {\n skillDir = safePathJoin(dir, entry.name);\n assertNoSymlinkEscape(skillDir, dir);\n } catch {\n continue;\n }\n const skillPath = join(skillDir, \"SKILL.md\");\n let raw: string;\n try {\n raw = await readFile(skillPath, \"utf8\");\n } catch {\n // no SKILL.md in this subdir → not a skill, not an error (EC-2)\n continue;\n }\n const skill = tryParseSkill(raw, entry.name, skillPath, options);\n if (skill !== undefined) skills.push(skill);\n }\n return skills;\n}\n\nfunction tryParseSkill(\n raw: string,\n fallbackName: string,\n source: string,\n options: DiscoverSkillsOptions | undefined,\n): Skill | undefined {\n try {\n const frontmatter = parseSkillFrontmatter(raw, fallbackName);\n const skill: Skill = {\n name: frontmatter.name,\n description: frontmatter.description,\n source,\n };\n if (frontmatter.category !== undefined) skill.category = frontmatter.category;\n if (frontmatter.dependencies !== undefined) skill.dependencies = frontmatter.dependencies;\n return skill;\n } catch (cause) {\n if (cause instanceof ConfigurationError) {\n options?.onInvalidSkill?.({\n name: fallbackName,\n source,\n code: cause.code ?? \"unknown\",\n message: cause.message,\n });\n return undefined;\n }\n throw cause;\n }\n}\n","/**\n * Block-body XML escape (ADR D9 — prompt-injection defence).\n *\n * Order matters: `&` MUST be escaped first so subsequent `<`/`>` replacements\n * do not double-encode the `&` characters they introduce.\n *\n * @internal\n */\nexport const escapeBlockBody = (s: string): string =>\n s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n","import { escapeBlockBody } from \"../system-prompt/escape.js\";\n\n/**\n * Render the `<skills>` system-prompt block from a skill list.\n *\n * Input is the structural subset `{ name, description }` — the skill BODY is\n * NOT in the type, so it cannot leak into the prompt. Both fields are passed\n * through `escapeBlockBody` to neutralise prompt-injection vectors hidden in\n * user-controlled SKILL.md frontmatter (injection-escape ADR).\n *\n * Returns `undefined` for an empty list so the caller can omit the block.\n *\n * Public via `@theokit/sdk/skills`.\n *\n * @public\n */\nexport function buildSkillsBlock(\n skills: ReadonlyArray<{ name: string; description: string }>,\n): string | undefined {\n if (skills.length === 0) return undefined;\n const lines = skills.map(\n (skill) => ` - ${escapeBlockBody(skill.name)}: ${escapeBlockBody(skill.description)}`,\n );\n return `<skills>\\n${lines.join(\"\\n\")}\\n</skills>`;\n}\n"]}