@theokit/sdk 5.15.1 → 5.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/a2a/index.cjs +3 -3
  3. package/dist/a2a/index.js +1 -1
  4. package/dist/agent-D6WBBNGR.cjs +72 -0
  5. package/dist/{agent-CB27KF6O.cjs.map → agent-D6WBBNGR.cjs.map} +1 -1
  6. package/dist/agent-QRIFX2SY.js +63 -0
  7. package/dist/{agent-66U5QCPF.js.map → agent-QRIFX2SY.js.map} +1 -1
  8. package/dist/agent-session-store-2LQEPS4H.js +6 -0
  9. package/dist/{agent-session-store-22GKA7O4.js.map → agent-session-store-2LQEPS4H.js.map} +1 -1
  10. package/dist/agent-session-store-IOH6BREF.cjs +23 -0
  11. package/dist/{agent-session-store-WP6NGDVX.cjs.map → agent-session-store-IOH6BREF.cjs.map} +1 -1
  12. package/dist/auth/index.cjs +15 -15
  13. package/dist/auth/index.js +3 -3
  14. package/dist/{batch-N2XDYZED.js → batch-7IGV2OKA.js} +8 -8
  15. package/dist/{batch-N2XDYZED.js.map → batch-7IGV2OKA.js.map} +1 -1
  16. package/dist/{batch-VFR2MAUE.cjs → batch-FIWQZ3JD.cjs} +14 -14
  17. package/dist/{batch-VFR2MAUE.cjs.map → batch-FIWQZ3JD.cjs.map} +1 -1
  18. package/dist/{chunk-AT2PESXB.cjs → chunk-2UYAL4N7.cjs} +5 -5
  19. package/dist/chunk-2UYAL4N7.cjs.map +1 -0
  20. package/dist/{chunk-K2BQQ445.js → chunk-3GQYMKVJ.js} +3 -3
  21. package/dist/{chunk-K2BQQ445.js.map → chunk-3GQYMKVJ.js.map} +1 -1
  22. package/dist/{chunk-YSTXFWQE.cjs → chunk-3HL43XBD.cjs} +4 -4
  23. package/dist/{chunk-YSTXFWQE.cjs.map → chunk-3HL43XBD.cjs.map} +1 -1
  24. package/dist/{chunk-XESYJ4JC.js → chunk-3VX7JHJI.js} +7 -7
  25. package/dist/{chunk-XESYJ4JC.js.map → chunk-3VX7JHJI.js.map} +1 -1
  26. package/dist/{chunk-6XQLTQB6.cjs → chunk-3YCNBOX7.cjs} +3 -3
  27. package/dist/{chunk-6XQLTQB6.cjs.map → chunk-3YCNBOX7.cjs.map} +1 -1
  28. package/dist/{chunk-CHKV2L2Y.cjs → chunk-46YYJIHL.cjs} +30 -30
  29. package/dist/chunk-46YYJIHL.cjs.map +1 -0
  30. package/dist/{chunk-73IITAF7.js → chunk-4C37ELQL.js} +9 -9
  31. package/dist/{chunk-73IITAF7.js.map → chunk-4C37ELQL.js.map} +1 -1
  32. package/dist/{chunk-AGO5S5WD.js → chunk-4E4D6H77.js} +3 -3
  33. package/dist/{chunk-AGO5S5WD.js.map → chunk-4E4D6H77.js.map} +1 -1
  34. package/dist/{chunk-R35ZJAYT.cjs → chunk-4JF52NED.cjs} +12 -12
  35. package/dist/{chunk-R35ZJAYT.cjs.map → chunk-4JF52NED.cjs.map} +1 -1
  36. package/dist/{chunk-INVEGVGO.js → chunk-4TA47IK4.js} +8 -8
  37. package/dist/{chunk-INVEGVGO.js.map → chunk-4TA47IK4.js.map} +1 -1
  38. package/dist/{chunk-MLGETTYX.js → chunk-4YUIYSZO.js} +6 -6
  39. package/dist/{chunk-MLGETTYX.js.map → chunk-4YUIYSZO.js.map} +1 -1
  40. package/dist/{chunk-RZL2W4C3.js → chunk-5L7S2VOL.js} +5 -5
  41. package/dist/{chunk-RZL2W4C3.js.map → chunk-5L7S2VOL.js.map} +1 -1
  42. package/dist/{chunk-3WKWBYPO.cjs → chunk-6EHOJLJ3.cjs} +20 -20
  43. package/dist/chunk-6EHOJLJ3.cjs.map +1 -0
  44. package/dist/{chunk-XOU3CL7S.cjs → chunk-6HQFPX7N.cjs} +28 -28
  45. package/dist/chunk-6HQFPX7N.cjs.map +1 -0
  46. package/dist/{chunk-3E3VSMB6.cjs → chunk-6XT5LAZG.cjs} +58 -58
  47. package/dist/chunk-6XT5LAZG.cjs.map +1 -0
  48. package/dist/{chunk-R427EOZE.cjs → chunk-7EFT6N5C.cjs} +13 -13
  49. package/dist/{chunk-R427EOZE.cjs.map → chunk-7EFT6N5C.cjs.map} +1 -1
  50. package/dist/{chunk-L7V4DDIE.cjs → chunk-7VNFOGRD.cjs} +12 -12
  51. package/dist/chunk-7VNFOGRD.cjs.map +1 -0
  52. package/dist/{chunk-YKNBTHMD.js → chunk-AQ23NII7.js} +3 -3
  53. package/dist/{chunk-YKNBTHMD.js.map → chunk-AQ23NII7.js.map} +1 -1
  54. package/dist/{chunk-O2RCS3SJ.js → chunk-ATGSV4GS.js} +4 -4
  55. package/dist/{chunk-O2RCS3SJ.js.map → chunk-ATGSV4GS.js.map} +1 -1
  56. package/dist/{chunk-H7HD6RXO.cjs → chunk-AW72G4TC.cjs} +5 -5
  57. package/dist/{chunk-H7HD6RXO.cjs.map → chunk-AW72G4TC.cjs.map} +1 -1
  58. package/dist/{chunk-M4U24U6G.js → chunk-AZK3QM36.js} +5 -5
  59. package/dist/{chunk-M4U24U6G.js.map → chunk-AZK3QM36.js.map} +1 -1
  60. package/dist/{chunk-QK2ERTO3.js → chunk-BH6M2DGV.js} +4 -4
  61. package/dist/{chunk-QK2ERTO3.js.map → chunk-BH6M2DGV.js.map} +1 -1
  62. package/dist/{chunk-26UQG242.cjs → chunk-BTGYRM4J.cjs} +264 -264
  63. package/dist/chunk-BTGYRM4J.cjs.map +1 -0
  64. package/dist/{chunk-ZQWRUJHE.js → chunk-CG64VPPU.js} +50 -50
  65. package/dist/{chunk-ZQWRUJHE.js.map → chunk-CG64VPPU.js.map} +1 -1
  66. package/dist/{chunk-CBBT42VX.js → chunk-CMDM4VF6.js} +3 -3
  67. package/dist/{chunk-CBBT42VX.js.map → chunk-CMDM4VF6.js.map} +1 -1
  68. package/dist/{chunk-OLJOI4LK.js → chunk-CN732Z5C.js} +4 -4
  69. package/dist/{chunk-OLJOI4LK.js.map → chunk-CN732Z5C.js.map} +1 -1
  70. package/dist/{chunk-SETHRLQS.cjs → chunk-D3BL3EEB.cjs} +9 -9
  71. package/dist/chunk-D3BL3EEB.cjs.map +1 -0
  72. package/dist/{chunk-LCCT5ZXJ.js → chunk-DB5RYCXX.js} +13 -13
  73. package/dist/{chunk-LCCT5ZXJ.js.map → chunk-DB5RYCXX.js.map} +1 -1
  74. package/dist/{chunk-SV63WTA2.js → chunk-DBH2WA2U.js} +4 -4
  75. package/dist/{chunk-SV63WTA2.js.map → chunk-DBH2WA2U.js.map} +1 -1
  76. package/dist/{chunk-XE3CAY6Z.cjs → chunk-DEHPRORL.cjs} +4 -4
  77. package/dist/{chunk-XE3CAY6Z.cjs.map → chunk-DEHPRORL.cjs.map} +1 -1
  78. package/dist/{chunk-UKMBRMGT.js → chunk-DGO4LPLP.js} +4 -4
  79. package/dist/{chunk-UKMBRMGT.js.map → chunk-DGO4LPLP.js.map} +1 -1
  80. package/dist/{chunk-RS7YQR4X.cjs → chunk-EBX6XUN7.cjs} +7 -7
  81. package/dist/{chunk-RS7YQR4X.cjs.map → chunk-EBX6XUN7.cjs.map} +1 -1
  82. package/dist/chunk-EDIYR4VR.cjs +18 -0
  83. package/dist/{chunk-SPEN7RJU.cjs.map → chunk-EDIYR4VR.cjs.map} +1 -1
  84. package/dist/{chunk-QGDPMM3C.js → chunk-EF5IONLL.js} +5 -5
  85. package/dist/{chunk-QGDPMM3C.js.map → chunk-EF5IONLL.js.map} +1 -1
  86. package/dist/{chunk-MSW7LB2V.cjs → chunk-EOWIUDKG.cjs} +5 -5
  87. package/dist/{chunk-MSW7LB2V.cjs.map → chunk-EOWIUDKG.cjs.map} +1 -1
  88. package/dist/{chunk-L7JPXZ2C.cjs → chunk-ER3BF23R.cjs} +19 -19
  89. package/dist/{chunk-L7JPXZ2C.cjs.map → chunk-ER3BF23R.cjs.map} +1 -1
  90. package/dist/{chunk-BNEUB52I.cjs → chunk-ERBKPA2N.cjs} +4 -4
  91. package/dist/{chunk-BNEUB52I.cjs.map → chunk-ERBKPA2N.cjs.map} +1 -1
  92. package/dist/{chunk-4QCJAJAG.js → chunk-F54PXZIA.js} +5 -5
  93. package/dist/{chunk-4QCJAJAG.js.map → chunk-F54PXZIA.js.map} +1 -1
  94. package/dist/{chunk-2XWAYCFM.cjs → chunk-FBT2SF2S.cjs} +12 -12
  95. package/dist/{chunk-2XWAYCFM.cjs.map → chunk-FBT2SF2S.cjs.map} +1 -1
  96. package/dist/{chunk-AUH2EVWY.cjs → chunk-FZSPVIFK.cjs} +16 -16
  97. package/dist/chunk-FZSPVIFK.cjs.map +1 -0
  98. package/dist/{chunk-CYWOJA6B.js → chunk-GA27FFT5.js} +3 -3
  99. package/dist/{chunk-CYWOJA6B.js.map → chunk-GA27FFT5.js.map} +1 -1
  100. package/dist/{chunk-HWMGR3HA.js → chunk-GEQLHBJM.js} +6 -6
  101. package/dist/{chunk-HWMGR3HA.js.map → chunk-GEQLHBJM.js.map} +1 -1
  102. package/dist/{chunk-IJ7M6GOG.cjs → chunk-GKERJ52A.cjs} +4 -4
  103. package/dist/{chunk-IJ7M6GOG.cjs.map → chunk-GKERJ52A.cjs.map} +1 -1
  104. package/dist/{chunk-NEH3BPFD.cjs → chunk-HI5TJWQE.cjs} +19 -19
  105. package/dist/{chunk-NEH3BPFD.cjs.map → chunk-HI5TJWQE.cjs.map} +1 -1
  106. package/dist/{chunk-ZOFRNNZD.cjs → chunk-IZV72OEI.cjs} +11 -11
  107. package/dist/chunk-IZV72OEI.cjs.map +1 -0
  108. package/dist/{chunk-KU5O7WPK.js → chunk-JD3EKKKB.js} +4 -4
  109. package/dist/{chunk-KU5O7WPK.js.map → chunk-JD3EKKKB.js.map} +1 -1
  110. package/dist/{chunk-DFBWYETS.js → chunk-JRP2W2DR.js} +3 -3
  111. package/dist/{chunk-DFBWYETS.js.map → chunk-JRP2W2DR.js.map} +1 -1
  112. package/dist/{chunk-26GI3OYA.js → chunk-JRQJMZKY.js} +13 -13
  113. package/dist/{chunk-26GI3OYA.js.map → chunk-JRQJMZKY.js.map} +1 -1
  114. package/dist/{chunk-YQ3XC6C2.cjs → chunk-JVH3NNJ3.cjs} +13 -13
  115. package/dist/chunk-JVH3NNJ3.cjs.map +1 -0
  116. package/dist/{chunk-VWYFGE27.cjs → chunk-KC2HKUPT.cjs} +56 -56
  117. package/dist/chunk-KC2HKUPT.cjs.map +1 -0
  118. package/dist/{chunk-PDOXYXWX.cjs → chunk-KDJTECE6.cjs} +4 -4
  119. package/dist/{chunk-PDOXYXWX.cjs.map → chunk-KDJTECE6.cjs.map} +1 -1
  120. package/dist/{chunk-QD6B6W6I.js → chunk-L2KC2G7H.js} +5 -5
  121. package/dist/{chunk-QD6B6W6I.js.map → chunk-L2KC2G7H.js.map} +1 -1
  122. package/dist/{chunk-3BBTHFGJ.js → chunk-L5B7EWWH.js} +5 -5
  123. package/dist/{chunk-3BBTHFGJ.js.map → chunk-L5B7EWWH.js.map} +1 -1
  124. package/dist/{chunk-X7CE7Y5W.js → chunk-LG4JCJEI.js} +11 -11
  125. package/dist/{chunk-X7CE7Y5W.js.map → chunk-LG4JCJEI.js.map} +1 -1
  126. package/dist/{chunk-2HXTNVLM.js → chunk-LSURFRJA.js} +6 -6
  127. package/dist/{chunk-2HXTNVLM.js.map → chunk-LSURFRJA.js.map} +1 -1
  128. package/dist/{chunk-55LLQFHW.cjs → chunk-MJGY3E3C.cjs} +4 -4
  129. package/dist/{chunk-55LLQFHW.cjs.map → chunk-MJGY3E3C.cjs.map} +1 -1
  130. package/dist/{chunk-EQ5IDL6W.cjs → chunk-MKS5FFH5.cjs} +15 -15
  131. package/dist/chunk-MKS5FFH5.cjs.map +1 -0
  132. package/dist/{chunk-WM646HEN.js → chunk-MTNCJ7MQ.js} +6 -6
  133. package/dist/{chunk-WM646HEN.js.map → chunk-MTNCJ7MQ.js.map} +1 -1
  134. package/dist/{chunk-SA6K24NB.cjs → chunk-MXJJMP4U.cjs} +7 -7
  135. package/dist/chunk-MXJJMP4U.cjs.map +1 -0
  136. package/dist/{chunk-FTXY4D44.cjs → chunk-N2ORTDSO.cjs} +20 -20
  137. package/dist/chunk-N2ORTDSO.cjs.map +1 -0
  138. package/dist/{chunk-7YUPSBDV.cjs → chunk-NDXZXGVP.cjs} +6 -6
  139. package/dist/{chunk-7YUPSBDV.cjs.map → chunk-NDXZXGVP.cjs.map} +1 -1
  140. package/dist/{chunk-3UMPP553.cjs → chunk-NMRNE6QX.cjs} +11 -11
  141. package/dist/{chunk-3UMPP553.cjs.map → chunk-NMRNE6QX.cjs.map} +1 -1
  142. package/dist/{chunk-PKRPV3R7.js → chunk-NO6AG22P.js} +6 -6
  143. package/dist/{chunk-PKRPV3R7.js.map → chunk-NO6AG22P.js.map} +1 -1
  144. package/dist/{chunk-NK5EOTDY.js → chunk-OIOSY5G6.js} +3 -3
  145. package/dist/{chunk-NK5EOTDY.js.map → chunk-OIOSY5G6.js.map} +1 -1
  146. package/dist/{chunk-RGVMJU57.js → chunk-P7B64NFK.js} +8 -8
  147. package/dist/{chunk-RGVMJU57.js.map → chunk-P7B64NFK.js.map} +1 -1
  148. package/dist/{chunk-TDED5XES.js → chunk-PCPYTBVV.js} +6 -6
  149. package/dist/chunk-PCPYTBVV.js.map +1 -0
  150. package/dist/{chunk-FBIDOOJM.cjs → chunk-PDFSLD5P.cjs} +6 -6
  151. package/dist/{chunk-FBIDOOJM.cjs.map → chunk-PDFSLD5P.cjs.map} +1 -1
  152. package/dist/{chunk-YMVTUV5K.js → chunk-PISZRLES.js} +5 -5
  153. package/dist/{chunk-YMVTUV5K.js.map → chunk-PISZRLES.js.map} +1 -1
  154. package/dist/{chunk-BUUUWQMB.cjs → chunk-PNL63WDP.cjs} +4 -4
  155. package/dist/{chunk-BUUUWQMB.cjs.map → chunk-PNL63WDP.cjs.map} +1 -1
  156. package/dist/{chunk-VNRNZ3WI.js → chunk-PSMWZYW6.js} +4 -4
  157. package/dist/{chunk-VNRNZ3WI.js.map → chunk-PSMWZYW6.js.map} +1 -1
  158. package/dist/{chunk-5645PMVU.cjs → chunk-PXYINWBC.cjs} +20 -20
  159. package/dist/chunk-PXYINWBC.cjs.map +1 -0
  160. package/dist/{chunk-RTDVSHJR.cjs → chunk-Q4UOCMAO.cjs} +5 -5
  161. package/dist/{chunk-RTDVSHJR.cjs.map → chunk-Q4UOCMAO.cjs.map} +1 -1
  162. package/dist/{chunk-5IRDK5BC.js → chunk-QH6MWGOA.js} +4 -4
  163. package/dist/{chunk-5IRDK5BC.js.map → chunk-QH6MWGOA.js.map} +1 -1
  164. package/dist/{chunk-3LMVJTNJ.js → chunk-QPUKIZOT.js} +3 -3
  165. package/dist/{chunk-3LMVJTNJ.js.map → chunk-QPUKIZOT.js.map} +1 -1
  166. package/dist/{chunk-SWALPLFQ.cjs → chunk-RTCO3USA.cjs} +16 -16
  167. package/dist/chunk-RTCO3USA.cjs.map +1 -0
  168. package/dist/{chunk-SAGRF4IB.js → chunk-S2CMEJ5F.js} +3 -3
  169. package/dist/{chunk-SAGRF4IB.js.map → chunk-S2CMEJ5F.js.map} +1 -1
  170. package/dist/{chunk-VZGE7NAI.js → chunk-S5ERB3CH.js} +3 -3
  171. package/dist/{chunk-VZGE7NAI.js.map → chunk-S5ERB3CH.js.map} +1 -1
  172. package/dist/{chunk-XJ3WU5CZ.js → chunk-S7IZEVXX.js} +6 -6
  173. package/dist/{chunk-XJ3WU5CZ.js.map → chunk-S7IZEVXX.js.map} +1 -1
  174. package/dist/{chunk-Q7UG242V.js → chunk-TIYQDJFK.js} +3 -3
  175. package/dist/{chunk-Q7UG242V.js.map → chunk-TIYQDJFK.js.map} +1 -1
  176. package/dist/{chunk-POBZXULR.cjs → chunk-TTNJOM5W.cjs} +16 -16
  177. package/dist/{chunk-POBZXULR.cjs.map → chunk-TTNJOM5W.cjs.map} +1 -1
  178. package/dist/{chunk-VCQ37TC5.js → chunk-TTXRNCXY.js} +3 -3
  179. package/dist/{chunk-VCQ37TC5.js.map → chunk-TTXRNCXY.js.map} +1 -1
  180. package/dist/{chunk-3HA7N2BB.cjs → chunk-TYKBAKAS.cjs} +5 -5
  181. package/dist/{chunk-3HA7N2BB.cjs.map → chunk-TYKBAKAS.cjs.map} +1 -1
  182. package/dist/{chunk-A77UMVMD.cjs → chunk-UMCCYXFZ.cjs} +8 -8
  183. package/dist/{chunk-A77UMVMD.cjs.map → chunk-UMCCYXFZ.cjs.map} +1 -1
  184. package/dist/{chunk-3GTN4HOO.js → chunk-UNP4NCMZ.js} +3 -3
  185. package/dist/{chunk-3GTN4HOO.js.map → chunk-UNP4NCMZ.js.map} +1 -1
  186. package/dist/{chunk-BPL5CVZ5.js → chunk-VFT63FJF.js} +3 -3
  187. package/dist/{chunk-BPL5CVZ5.js.map → chunk-VFT63FJF.js.map} +1 -1
  188. package/dist/{chunk-3KIUY67P.cjs → chunk-VHY6NVCJ.cjs} +30 -30
  189. package/dist/chunk-VHY6NVCJ.cjs.map +1 -0
  190. package/dist/{chunk-TRPRTZEH.cjs → chunk-VT3NWHFH.cjs} +6 -6
  191. package/dist/{chunk-TRPRTZEH.cjs.map → chunk-VT3NWHFH.cjs.map} +1 -1
  192. package/dist/{chunk-FJWQP6EE.js → chunk-WJ6OGKAO.js} +3 -3
  193. package/dist/{chunk-FJWQP6EE.js.map → chunk-WJ6OGKAO.js.map} +1 -1
  194. package/dist/{chunk-FLDHYF5C.cjs → chunk-X2XLSE2N.cjs} +9 -9
  195. package/dist/chunk-X2XLSE2N.cjs.map +1 -0
  196. package/dist/{chunk-UDAKAE4Z.cjs → chunk-X4ZYEZPD.cjs} +12 -12
  197. package/dist/chunk-X4ZYEZPD.cjs.map +1 -0
  198. package/dist/{chunk-QG4SXZ2A.cjs → chunk-XR6O6G3B.cjs} +27 -27
  199. package/dist/chunk-XR6O6G3B.cjs.map +1 -0
  200. package/dist/{chunk-BWYC7RZG.cjs → chunk-XTQWTVVI.cjs} +11 -11
  201. package/dist/chunk-XTQWTVVI.cjs.map +1 -0
  202. package/dist/{chunk-MLJDW2YK.js → chunk-YSGS57DA.js} +4 -4
  203. package/dist/{chunk-MLJDW2YK.js.map → chunk-YSGS57DA.js.map} +1 -1
  204. package/dist/{chunk-KCM3RMKR.js → chunk-YUQNHLKN.js} +8 -8
  205. package/dist/{chunk-KCM3RMKR.js.map → chunk-YUQNHLKN.js.map} +1 -1
  206. package/dist/{chunk-P7QYG4RZ.cjs → chunk-Z5MB2HAN.cjs} +8 -8
  207. package/dist/{chunk-P7QYG4RZ.cjs.map → chunk-Z5MB2HAN.cjs.map} +1 -1
  208. package/dist/{chunk-HJ2LV464.js → chunk-ZUWVO442.js} +4 -4
  209. package/dist/{chunk-HJ2LV464.js.map → chunk-ZUWVO442.js.map} +1 -1
  210. package/dist/{compact-session-CHBJOYWP.cjs → compact-session-5DWFHMW4.cjs} +21 -21
  211. package/dist/{compact-session-CHBJOYWP.cjs.map → compact-session-5DWFHMW4.cjs.map} +1 -1
  212. package/dist/{compact-session-F3J3FMEU.js → compact-session-AL65PEMX.js} +12 -12
  213. package/dist/{compact-session-F3J3FMEU.js.map → compact-session-AL65PEMX.js.map} +1 -1
  214. package/dist/context/index.cjs +11 -11
  215. package/dist/context/index.js +6 -6
  216. package/dist/context-4XSD2V3G.js +7 -0
  217. package/dist/{context-7EBZST3L.js.map → context-4XSD2V3G.js.map} +1 -1
  218. package/dist/context-ZX2VBGSX.cjs +24 -0
  219. package/dist/{context-4RSI3AXT.cjs.map → context-ZX2VBGSX.cjs.map} +1 -1
  220. package/dist/cron.cjs +40 -40
  221. package/dist/cron.js +39 -39
  222. package/dist/eval.cjs +51 -51
  223. package/dist/eval.cjs.map +1 -1
  224. package/dist/eval.js +41 -41
  225. package/dist/{executor-THUXNAFR.js → executor-ZHIUSHRV.js} +7 -7
  226. package/dist/{executor-THUXNAFR.js.map → executor-ZHIUSHRV.js.map} +1 -1
  227. package/dist/{executor-5QL5AXIZ.cjs → executor-ZTLJZ5LK.cjs} +24 -24
  228. package/dist/{executor-5QL5AXIZ.cjs.map → executor-ZTLJZ5LK.cjs.map} +1 -1
  229. package/dist/filesystem/index.cjs +14 -14
  230. package/dist/filesystem/index.cjs.map +1 -1
  231. package/dist/filesystem/index.js +4 -4
  232. package/dist/{fork-agent-S2EPIML7.js → fork-agent-BHVTALT5.js} +3 -3
  233. package/dist/{fork-agent-S2EPIML7.js.map → fork-agent-BHVTALT5.js.map} +1 -1
  234. package/dist/{fork-agent-WAEQI2DL.cjs → fork-agent-DCOPPXM2.cjs} +4 -4
  235. package/dist/{fork-agent-WAEQI2DL.cjs.map → fork-agent-DCOPPXM2.cjs.map} +1 -1
  236. package/dist/fs-session-store-EZ32TFGB.js +11 -0
  237. package/dist/{fs-session-store-MYQEVUFL.js.map → fs-session-store-EZ32TFGB.js.map} +1 -1
  238. package/dist/fs-session-store-G664LDDN.cjs +20 -0
  239. package/dist/{fs-session-store-CYNTEPJZ.cjs.map → fs-session-store-G664LDDN.cjs.map} +1 -1
  240. package/dist/generate-object-JFZTK567.cjs +20 -0
  241. package/dist/{generate-object-A5F576IT.cjs.map → generate-object-JFZTK567.cjs.map} +1 -1
  242. package/dist/{generate-object-TBDOBBYW.js → generate-object-RPBXY2U3.js} +4 -4
  243. package/dist/{generate-object-TBDOBBYW.js.map → generate-object-RPBXY2U3.js.map} +1 -1
  244. package/dist/index-manager-2MJEEN2O.js +18 -0
  245. package/dist/{index-manager-NF2WRLOU.js.map → index-manager-2MJEEN2O.js.map} +1 -1
  246. package/dist/index-manager-CT6MMG7S.cjs +27 -0
  247. package/dist/{index-manager-2KH75BRW.cjs.map → index-manager-CT6MMG7S.cjs.map} +1 -1
  248. package/dist/index.cjs +130 -130
  249. package/dist/index.cjs.map +1 -1
  250. package/dist/index.js +56 -56
  251. package/dist/{inject-session-LC2TROHM.js → inject-session-E2SZ4A35.js} +6 -6
  252. package/dist/{inject-session-LC2TROHM.js.map → inject-session-E2SZ4A35.js.map} +1 -1
  253. package/dist/{inject-session-T4RXANG3.cjs → inject-session-QZULG65O.cjs} +8 -8
  254. package/dist/{inject-session-T4RXANG3.cjs.map → inject-session-QZULG65O.cjs.map} +1 -1
  255. package/dist/internal/memory/adapters/index.cjs +4 -4
  256. package/dist/internal/memory/adapters/index.js +3 -3
  257. package/dist/internal/memory/storage/index.cjs +45 -45
  258. package/dist/internal/memory/storage/index.js +9 -9
  259. package/dist/internal/persistence/index.cjs +22 -22
  260. package/dist/internal/persistence/index.js +6 -6
  261. package/dist/internal/security/index.cjs +9 -9
  262. package/dist/internal/security/index.js +2 -2
  263. package/dist/mcp-auth.cjs +8 -8
  264. package/dist/mcp-auth.js +3 -3
  265. package/dist/models.cjs +30 -30
  266. package/dist/models.cjs.map +1 -1
  267. package/dist/models.js +8 -8
  268. package/dist/{oauth-transaction-store-U34YLEGP.js → oauth-transaction-store-QQBWGNE2.js} +3 -3
  269. package/dist/{oauth-transaction-store-U34YLEGP.js.map → oauth-transaction-store-QQBWGNE2.js.map} +1 -1
  270. package/dist/{oauth-transaction-store-OMX436YB.cjs → oauth-transaction-store-YF7WOA6B.cjs} +10 -10
  271. package/dist/{oauth-transaction-store-OMX436YB.cjs.map → oauth-transaction-store-YF7WOA6B.cjs.map} +1 -1
  272. package/dist/path-safety.cjs +9 -9
  273. package/dist/path-safety.js +2 -2
  274. package/dist/persistence.cjs +41 -41
  275. package/dist/persistence.cjs.map +1 -1
  276. package/dist/persistence.js +11 -11
  277. package/dist/project.cjs +7 -7
  278. package/dist/project.cjs.map +1 -1
  279. package/dist/project.js +4 -4
  280. package/dist/providers.cjs +6 -6
  281. package/dist/providers.js +4 -4
  282. package/dist/{registry-5TDAF7RK.js → registry-DOYBR237.js} +6 -6
  283. package/dist/{registry-5TDAF7RK.js.map → registry-DOYBR237.js.map} +1 -1
  284. package/dist/{registry-W7TSCLQO.cjs → registry-PB7JFVUJ.cjs} +14 -14
  285. package/dist/{registry-W7TSCLQO.cjs.map → registry-PB7JFVUJ.cjs.map} +1 -1
  286. package/dist/sandbox/index.cjs +41 -41
  287. package/dist/sandbox/index.cjs.map +1 -1
  288. package/dist/sandbox/index.js +7 -7
  289. package/dist/sanitize/index.cjs +2 -2
  290. package/dist/sanitize/index.js +1 -1
  291. package/dist/server/auth/index.cjs +9 -9
  292. package/dist/server/auth/index.cjs.map +1 -1
  293. package/dist/server/auth/index.js +4 -4
  294. package/dist/{session-transcript-7TZ6HXSX.cjs → session-transcript-EBVGLZ6B.cjs} +17 -17
  295. package/dist/{session-transcript-7TZ6HXSX.cjs.map → session-transcript-EBVGLZ6B.cjs.map} +1 -1
  296. package/dist/{session-transcript-BSHZYYY6.js → session-transcript-GU2VE7JX.js} +4 -4
  297. package/dist/{session-transcript-BSHZYYY6.js.map → session-transcript-GU2VE7JX.js.map} +1 -1
  298. package/dist/skills.cjs +7 -7
  299. package/dist/skills.js +4 -4
  300. package/dist/stream-object-3AU7QDHT.js +7 -0
  301. package/dist/{stream-object-EKM4WGTI.js.map → stream-object-3AU7QDHT.js.map} +1 -1
  302. package/dist/stream-object-SLGR2KIA.cjs +20 -0
  303. package/dist/{stream-object-AS4YYM4B.cjs.map → stream-object-SLGR2KIA.cjs.map} +1 -1
  304. package/dist/subagents-loader-4PQS7ULK.cjs +16 -0
  305. package/dist/{subagents-loader-KLWF4QPD.cjs.map → subagents-loader-4PQS7ULK.cjs.map} +1 -1
  306. package/dist/subagents-loader-CPFVLWLH.js +7 -0
  307. package/dist/{subagents-loader-SXETS2F2.js.map → subagents-loader-CPFVLWLH.js.map} +1 -1
  308. package/dist/subagents-loader.cjs +4 -4
  309. package/dist/subagents-loader.js +3 -3
  310. package/dist/subagents.cjs +2 -2
  311. package/dist/subagents.js +1 -1
  312. package/dist/task-store.cjs +5 -5
  313. package/dist/task-store.js +2 -2
  314. package/dist/workflow.cjs +28 -28
  315. package/dist/workflow.js +5 -5
  316. package/package.json +1 -1
  317. package/dist/agent-66U5QCPF.js +0 -63
  318. package/dist/agent-CB27KF6O.cjs +0 -72
  319. package/dist/agent-session-store-22GKA7O4.js +0 -6
  320. package/dist/agent-session-store-WP6NGDVX.cjs +0 -23
  321. package/dist/chunk-26UQG242.cjs.map +0 -1
  322. package/dist/chunk-3E3VSMB6.cjs.map +0 -1
  323. package/dist/chunk-3KIUY67P.cjs.map +0 -1
  324. package/dist/chunk-3WKWBYPO.cjs.map +0 -1
  325. package/dist/chunk-5645PMVU.cjs.map +0 -1
  326. package/dist/chunk-AT2PESXB.cjs.map +0 -1
  327. package/dist/chunk-AUH2EVWY.cjs.map +0 -1
  328. package/dist/chunk-BWYC7RZG.cjs.map +0 -1
  329. package/dist/chunk-CHKV2L2Y.cjs.map +0 -1
  330. package/dist/chunk-EQ5IDL6W.cjs.map +0 -1
  331. package/dist/chunk-FLDHYF5C.cjs.map +0 -1
  332. package/dist/chunk-FTXY4D44.cjs.map +0 -1
  333. package/dist/chunk-L7V4DDIE.cjs.map +0 -1
  334. package/dist/chunk-QG4SXZ2A.cjs.map +0 -1
  335. package/dist/chunk-SA6K24NB.cjs.map +0 -1
  336. package/dist/chunk-SETHRLQS.cjs.map +0 -1
  337. package/dist/chunk-SPEN7RJU.cjs +0 -18
  338. package/dist/chunk-SWALPLFQ.cjs.map +0 -1
  339. package/dist/chunk-TDED5XES.js.map +0 -1
  340. package/dist/chunk-UDAKAE4Z.cjs.map +0 -1
  341. package/dist/chunk-VWYFGE27.cjs.map +0 -1
  342. package/dist/chunk-XOU3CL7S.cjs.map +0 -1
  343. package/dist/chunk-YQ3XC6C2.cjs.map +0 -1
  344. package/dist/chunk-ZOFRNNZD.cjs.map +0 -1
  345. package/dist/context-4RSI3AXT.cjs +0 -24
  346. package/dist/context-7EBZST3L.js +0 -7
  347. package/dist/fs-session-store-CYNTEPJZ.cjs +0 -20
  348. package/dist/fs-session-store-MYQEVUFL.js +0 -11
  349. package/dist/generate-object-A5F576IT.cjs +0 -20
  350. package/dist/index-manager-2KH75BRW.cjs +0 -27
  351. package/dist/index-manager-NF2WRLOU.js +0 -18
  352. package/dist/stream-object-AS4YYM4B.cjs +0 -20
  353. package/dist/stream-object-EKM4WGTI.js +0 -7
  354. package/dist/subagents-loader-KLWF4QPD.cjs +0 -16
  355. package/dist/subagents-loader-SXETS2F2.js +0 -7
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/security/path-guard.ts"],"names":["ConfigurationError","atOrInsideRoot","resolve","path","realpathSync","lstatSync","readlinkSync","dirname","createHash"],"mappings":"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","file":"chunk-3KIUY67P.cjs","sourcesContent":["/**\n * Canonical path-guard module (ADRs D79-D81).\n *\n * Three primitives + one typed error:\n * - `safePathJoin(base, ...parts)` — resolve THEN prefix-check (ADR D80).\n * - `assertNoSymlinkEscape(path, base)` — `realpathSync` resolves entire\n * symlink chain (EC-1 fix; Hermes v0.2 #386, #61).\n * - `sanitizeIdentifier(input, { maxLen })` — strict grammar\n * `^[a-z0-9][a-z0-9-_]*$` (ADR D81; case-insensitive on input,\n * lowercase on output).\n * - `PathTraversalError` — extends ConfigurationError with code\n * `path_traversal` (ADR D65: no new hierarchy).\n *\n * Wire at all sites where user input becomes a path. CI lint gate\n * `tests/lint/no-unguarded-path-input.test.ts` prevents regression\n * (ADR D85).\n *\n * @internal\n */\n\nimport { createHash } from \"node:crypto\";\nimport { lstatSync, readlinkSync, realpathSync, type Stats } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\n\nimport { ConfigurationError } from \"../../errors.js\";\nimport { atOrInsideRoot } from \"./path-containment.js\";\n\n/**\n * Thrown when a path operation would escape its allowed base directory.\n * Extends `ConfigurationError` (no new error hierarchy per ADR D65).\n *\n */\nexport class PathTraversalError extends ConfigurationError {\n override readonly name: string = \"PathTraversalError\";\n\n constructor(input: string, resolvedPath: string) {\n super(`Path traversal attempt: ${input} → ${resolvedPath}`, {\n code: \"path_traversal\",\n });\n }\n}\n\n/**\n * Thrown when an agent tool is asked to read or write a sensitive path\n * that the blocklist forbids (`.env`, `.git/`, `node_modules/`, `.theo/`,\n * lock files). Distinct from `PathTraversalError` because the path is\n * lexically inside the project — it is just sensitive.\n *\n * Extends `ConfigurationError` (no new error hierarchy per ADR D65).\n *\n * @public\n */\nexport class ForbiddenPathError extends ConfigurationError {\n override readonly name: string = \"ForbiddenPathError\";\n\n constructor(path: string) {\n super(\n `Path '${path}' is in the sensitive-file blocklist (.env, .git/, node_modules/, .theo/, lock files)`,\n {\n code: \"forbidden_path\",\n },\n );\n }\n}\n\n/**\n * Is `target` the same as `base`, or strictly under it?\n *\n * The prefix must not double the separator. `resolve` strips a trailing `sep` from every base\n * EXCEPT the filesystem root, where `resolve(sep) === sep`; there `base + sep` would be `//`, which\n * no absolute path starts with, so a root base rejected EVERY path (#149). Only the root takes that\n * branch — for any other base the prefix is unchanged, so containment is not weakened.\n *\n * Both containment checks in this module go through here: they had the same defect and were fixed\n * one at a time, which is exactly how the two drifted apart in the first place.\n *\n * Both arguments MUST already be resolved absolute paths.\n */\nfunction isInside(target: string, base: string): boolean {\n // B-117 — compared after symlink resolution, via the shared rule. A prefix test judges a link by\n // its NAME: `<base>/link/x` where `link` points outside is lexically inside and physically not.\n // Measured reachable from the plugin manager and the MCP client before this was changed.\n //\n // The root itself stays allowed, which `insideRoot` alone does not answer: it returns false for\n // `target === base` (correct for its own caller, wrong here, where `safePathJoin(base)` with no\n // parts must return `base`). Kept as an explicit second clause rather than by weakening the\n // shared rule for everyone.\n return atOrInsideRoot(target, base);\n}\n\n/**\n * Join `base` with `...parts` and ensure the resolved absolute path stays\n * under `base`. Resolves FIRST, then prefix-checks (ADR D80) — prevents\n * normalized-escape bypasses like `subdir/.\\\\./bar`.\n *\n * Returns the safe absolute path. Throws `PathTraversalError` if escape.\n *\n */\nexport function safePathJoin(base: string, ...parts: string[]): string {\n if (base === \"\") {\n throw new Error(\"safePathJoin: base must be non-empty\");\n }\n // T5.5 — NUL byte + C0/DEL control char rejection at the boundary.\n // Apply before path resolution so a malicious input never reaches\n // `resolve` (which on some platforms behaved unexpectedly with NUL\n // and in N-API callers historically silently truncated).\n rejectNulAndControlChars(base, \"base\");\n for (const part of parts) {\n rejectNulAndControlChars(part, \"path segment\");\n }\n const baseResolved = resolve(base);\n const target = resolve(base, ...parts);\n if (!isInside(target, baseResolved)) {\n throw new PathTraversalError(parts.join(\"/\"), target);\n }\n return target;\n}\n\n/**\n * T5.5 — the operator-legible label for the first NUL (`\\x00`), C0 control char (`\\x01-\\x1F`) or\n * DEL (`\\x7F`) in `input`, or `undefined` when it carries none. Centralizes the scan so every\n * public path-guard / sanitize entrypoint shares one definition of \"control character\".\n *\n * Detection is separated from the throw so the two callers can share the scan and the precise\n * diagnostic while each raising the error ITS OWN contract documents (#368) — a path guard reports\n * a traversal, an identifier validator reports an invalid identifier. Before that split both threw\n * `PathTraversalError`, which made an identifier validator's error class depend on the bytes of the\n * input it was handed.\n *\n * @internal\n */\nfunction firstControlCharLabel(input: string): string | undefined {\n for (let i = 0; i < input.length; i++) {\n const code = input.charCodeAt(i);\n if (code === 0x00 || (code >= 0x01 && code <= 0x1f) || code === 0x7f) {\n return code === 0x00 ? \"<nul-byte>\" : `<control-char-0x${code.toString(16)}>`;\n }\n }\n return undefined;\n}\n\n/**\n * Reject any path-shaped input carrying a NUL or control character, as `PathTraversalError` — the\n * same shape as every other path-shape rejection, so callers do not learn a second error class.\n *\n * @internal\n */\nfunction rejectNulAndControlChars(input: string, role: string): void {\n const label = firstControlCharLabel(input);\n if (label !== undefined) throw new PathTraversalError(`${role}: ${input}`, label);\n}\n\n/**\n * Assert that `path` — including every directory component in the chain —\n * stays under `base` after symlink resolution. No-op when nothing on the\n * path exists yet.\n *\n * Two-bug history:\n * 1. **EC-1** (original fix, kept): a multi-level symlink chain A → B → C\n * must be resolved end-to-end. `realpathSync` does this in 1 syscall.\n * 2. **Defence-in-depth** (added v1.x): the previous implementation only\n * called `lstatSync(path)` on the terminal component. If an INTERMEDIATE\n * directory was a symlink (`base/inner-symlink → /outside`), `lstat` on\n * `base/inner-symlink/file.txt` followed the symlink and reported the\n * regular file — escape went undetected. Fix: walk up to the nearest\n * existing ancestor and `realpath` THAT, then re-attach the suffix and\n * check the result against the canonical base.\n *\n */\nexport function assertNoSymlinkEscape(path: string, base: string): void {\n // T5.5 — reject NUL / control chars before any FS call (a NUL byte\n // in the path used to silently truncate at the C boundary on legacy\n // libc — defense in depth even on modern Node).\n rejectNulAndControlChars(path, \"path\");\n rejectNulAndControlChars(base, \"base\");\n // Canonical base — symlinks in the base path itself are absorbed once here.\n let baseResolved: string;\n try {\n baseResolved = realpathSync(base);\n } catch {\n // base doesn't exist as a real directory yet — fall back to lexical resolve.\n baseResolved = resolve(base);\n }\n\n // Find the deepest ancestor of `path` that exists, then realpath it.\n // Anything from there onward is \"not yet on disk\" and contributes only\n // its lexical suffix. This covers three cases:\n // - path exists (regular file or symlink at any depth) → realpath the full path\n // - path doesn't exist but intermediate dir is a symlink → realpath the ancestor\n // - nothing on the path exists → no escape risk (return)\n const resolved = realpathOfDeepestExisting(path);\n if (resolved === undefined) return; // path has no existing prefix — nothing to attack\n\n if (!isInside(resolved, baseResolved)) {\n throw new PathTraversalError(`symlink ${path}`, resolved);\n }\n}\n\n/**\n * Find the deepest ancestor of `path` that exists on disk, resolve all\n * symlinks in that ancestor via `realpathSync`, and re-attach the\n * lexical suffix. Returns `undefined` when no ancestor exists.\n *\n * Handles dangling symlinks: if the terminal IS a symlink but its target\n * is missing, we still detect escape via `readlinkSync` + parent resolve.\n */\nfunction realpathOfDeepestExisting(path: string): string | undefined {\n // First try the full path — the common case.\n try {\n return realpathSync(path);\n } catch {\n // Not resolvable. Two sub-cases.\n }\n\n // Sub-case A: terminal is a dangling symlink.\n try {\n const stat: Stats = lstatSync(path);\n if (stat.isSymbolicLink()) {\n const target = readlinkSync(path);\n // Resolve target relative to the REAL parent dir, so intermediate\n // symlinks in the parent chain are absorbed.\n const parentReal = realpathOfDeepestExisting(dirname(path));\n const parentBase = parentReal ?? dirname(path);\n return resolve(parentBase, target);\n }\n } catch {\n // lstat failed too — terminal doesn't exist at all.\n }\n\n // Sub-case B: walk up to the nearest existing ancestor, then re-attach\n // the suffix lexically.\n let cursor = dirname(path);\n let suffix = path.slice(cursor.length);\n while (cursor !== dirname(cursor)) {\n try {\n const real = realpathSync(cursor);\n // Reconstruct: ancestor's realpath + remaining (still-lexical) suffix\n return resolve(real, `.${suffix}`);\n } catch {\n suffix = path.slice(dirname(cursor).length);\n cursor = dirname(cursor);\n }\n }\n // Reached filesystem root without finding any existing ancestor.\n return undefined;\n}\n\nconst LOCK_FILES = new Set([\"pnpm-lock.yaml\", \"package-lock.json\", \"yarn.lock\", \"bun.lockb\"]);\n\n// T5.6 — top-level credential dot-dirs / dot-files. Matching against\n// the FIRST path segment (lowercase). Adding any entry here costs a\n// CHANGELOG note + an explicit case-fold test (entries are lowercased\n// at module load).\nconst SENSITIVE_FIRST_SEGMENTS = new Set([\n \".ssh\",\n \".aws\",\n \".docker\",\n \".kube\",\n \".npmrc\",\n \".netrc\",\n \".pgpass\",\n]);\n\n// T5.6 — credential basenames blocked at ANY depth (lowercase). Catches\n// the developer-laptop case where an agent recurses into a subdir.\nconst SENSITIVE_BASENAMES = new Set([\n \"id_rsa\",\n \"id_ed25519\",\n \"id_ecdsa\",\n \"id_dsa\",\n \"authorized_keys\",\n \"known_hosts\",\n \".npmrc\",\n \".netrc\",\n \".pgpass\",\n]);\n\n// T5.6 — extension suffixes blocked at ANY depth (lowercase). Covers\n// the entire `*.pem` / `*.key` private-material family.\nconst SENSITIVE_SUFFIXES = [\".pem\", \".key\", \".p12\", \".pfx\"];\n\n/**\n * Decide whether a project-relative path points to a known-sensitive file\n * that a coding agent must not read or write.\n *\n * Universal blocklist (works for any agent operating on a project tree):\n *\n * - `.env`, `.env.<anything>` — except `.env.example` (template safe to read)\n * - `.git/` — version control internals\n * - `node_modules/` — dependency cache (changes don't belong to the user)\n * - `.theo/` — TheoKit build artefacts / state\n * - Lock files at any depth: `pnpm-lock.yaml`, `package-lock.json`,\n * `yarn.lock`, `bun.lockb`\n *\n * Operates on path segments (forward-slash normalized). Cross-platform safe.\n *\n * Use together with `safePathJoin` + `assertNoSymlinkEscape`: the former two\n * defeat traversal, this one defeats reading a file that is lexically inside\n * the project but should not be agent-visible.\n *\n * @public\n */\nexport function isForbiddenPath(input: string): boolean {\n // T5.6 — lowercase normalization defeats case-only bypass on\n // case-insensitive filesystems (Windows/macOS-default) where `.ENV`\n // and `.env` map to the same inode but a case-sensitive string\n // check passes the former.\n const normalized = input.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").toLowerCase();\n if (normalized.length === 0) return false;\n\n const segments = normalized.split(\"/\").filter((s) => s.length > 0);\n if (segments.length === 0) return false;\n\n if (isForbiddenFirstSegment(segments[0]!)) return true;\n if (isForbiddenBasename(segments[segments.length - 1]!)) return true;\n return false;\n}\n\nfunction isForbiddenFirstSegment(first: string): boolean {\n // .env.example is explicitly allowlisted (template safe to read)\n if (first === \".env.example\") return false;\n if (first === \".env\") return true;\n if (/^\\.env\\./.test(first)) return true;\n if (first === \".git\" || first === \"node_modules\" || first === \".theo\") return true;\n return SENSITIVE_FIRST_SEGMENTS.has(first);\n}\n\nfunction isForbiddenBasename(basename: string): boolean {\n if (LOCK_FILES.has(basename)) return true;\n if (SENSITIVE_BASENAMES.has(basename)) return true;\n for (const suffix of SENSITIVE_SUFFIXES) {\n if (basename.endsWith(suffix)) return true;\n }\n return false;\n}\n\nconst IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9\\-_]*$/i;\n\n/**\n * T1.4 — validate a relative artifact path string BEFORE it is used to look\n * up a fixture or to fetch from PaaS. Rejects every well-known traversal\n * vector at the boundary, throwing `PathTraversalError`.\n *\n * Vectors rejected:\n * - classic `..` parent-directory traversal (any segment).\n * - backslash separators (Windows-style `..\\\\windows`).\n * - URL-encoded `%2e%2e` / `%2E%2E` (double-decoded traversal).\n * - NUL byte injection (`\\x00`).\n * - Windows drive letter prefix (`C:`, `D:\\\\...`).\n * - Home-tilde expansion (`~/`, `~root/...`).\n * - Absolute paths starting with `/`.\n *\n * Does NOT touch the filesystem — the call is shape-only. Live symlink\n * traversal protection happens via `assertNoSymlinkEscape` at the FS-resolve\n * boundary.\n *\n * @param input - Caller-supplied artifact path.\n * @throws `PathTraversalError` on any rejection.\n *\n * Semver-exempt: reachable via the `@theokit/sdk/internal/security` sub-path, which the package\n * declares in `exports` but does NOT cover with its semver contract.\n */\nexport function validateArtifactPath(input: string): void {\n rejectKnownPrefixVectors(input);\n const normalized = decodeAndNormalize(input);\n rejectParentTraversal(input, normalized);\n}\n\nfunction rejectKnownPrefixVectors(input: string): void {\n if (input.includes(\"\\x00\")) {\n throw new PathTraversalError(input, \"<nul-byte>\");\n }\n if (input.startsWith(\"/\") || input.startsWith(\"~\")) {\n throw new PathTraversalError(input, input);\n }\n if (/^[A-Za-z]:[\\\\/]?/.test(input)) {\n throw new PathTraversalError(input, input);\n }\n}\n\nfunction decodeAndNormalize(input: string): string {\n // URL-encoded traversal — 2 passes catches `%252e%252e`.\n // Malformed sequences (decodeURIComponent throws) are themselves a rejection.\n let decoded = input;\n for (let i = 0; i < 2; i += 1) {\n try {\n const next = decodeURIComponent(decoded);\n if (next === decoded) break;\n decoded = next;\n } catch {\n throw new PathTraversalError(input, \"<malformed-url-encoding>\");\n }\n }\n // Normalize backslash to forward slash before segment-walking.\n return decoded.replace(/\\\\/g, \"/\");\n}\n\nfunction rejectParentTraversal(input: string, normalized: string): void {\n for (const segment of normalized.split(\"/\")) {\n if (segment === \"..\" || segment === \"..%00\") {\n throw new PathTraversalError(input, normalized);\n }\n }\n // Defense in depth: literal `..` anywhere in the normalized string.\n if (normalized.includes(\"..\")) {\n throw new PathTraversalError(input, normalized);\n }\n}\n\n/**\n * Validate that `input` is a safe path component (skill name, agent ID,\n * namespace, etc.) and return its lowercase form. Strict grammar\n * `^[a-z0-9][a-z0-9-_]*$` rejects path separators, dots, null bytes,\n * whitespace, unicode invisible chars, and any leading `-`/`_`.\n *\n * ONE error class leaves this function: `ConfigurationError` with code\n * `invalid_identifier`, for every rejection — length out of range, a path\n * separator, `..`, a space, a leading `-`, and a NUL / C0 control char / DEL\n * alike. A caller can branch on that code and know it has covered the whole\n * rejection surface.\n *\n * Before #368 the control-char branch threw `PathTraversalError` instead, which\n * made the error CLASS a function of the attacker's bytes; the message still names\n * the offending byte, which is the part that was worth keeping.\n *\n * @param input - User-supplied identifier candidate.\n * @param options.maxLen - Maximum allowed length (default 64).\n * @returns Lowercase form of `input`.\n * @throws `ConfigurationError` with code `invalid_identifier` on every rejection.\n */\nexport function sanitizeIdentifier(input: string, options?: { maxLen?: number }): string {\n const maxLen = options?.maxLen ?? 64;\n if (input.length === 0 || input.length > maxLen) {\n throw new ConfigurationError(`Identifier length out of range (1-${maxLen}): \"${input}\"`, {\n code: \"invalid_identifier\",\n });\n }\n // T5.5 — explicit NUL / control char rejection ahead of the generic pattern check. The\n // IDENTIFIER_PATTERN regex already excludes these (they are not in `[a-z0-9\\-_]`); naming the\n // offending byte gives operators a precise diagnostic instead of the generic \"invalid characters\"\n // message, which is what makes a prompt-injection trace legible (Rule 3).\n //\n // #368 — the diagnostic used to arrive as a `PathTraversalError`, because the branch reused\n // `safePathJoin`'s thrower. That made the error CLASS a function of the attacker's bytes: a\n // caller branching on the documented `invalid_identifier` rethrew for any input carrying a\n // control char, so a rejection surfaced as a 500 and the 400/500 split became an oracle. The\n // detection is shared; the error each contract documents is not.\n const controlChar = firstControlCharLabel(input);\n if (controlChar !== undefined) {\n throw new ConfigurationError(`Identifier contains ${controlChar}: \"${input}\"`, {\n code: \"invalid_identifier\",\n });\n }\n if (!IDENTIFIER_PATTERN.test(input)) {\n throw new ConfigurationError(`Identifier contains invalid characters: \"${input}\"`, {\n code: \"invalid_identifier\",\n });\n }\n return input.toLowerCase();\n}\n\n/**\n * Convert ANY opaque id (agent id, run id, conversation id, namespace, email,\n * arbitrary string) into a deterministic, filesystem-safe filename component.\n *\n * Unlike {@link sanitizeIdentifier} (which THROWS on non-conforming input),\n * this is a total function: it NEVER throws on a non-empty string. It returns\n * the lowercased id verbatim when it already matches the safe grammar\n * `^[a-z0-9][a-z0-9-_]*$` and fits `maxLen` (so UUIDs, hashes, and slugs stay\n * human-readable), otherwise a deterministic `h-<16 hex>` sha256 token\n * (collision-resistant and always a valid filename). The output charset is\n * always `[a-z0-9_-]`, safe as a literal path segment on every filesystem.\n *\n * @param id - any opaque identifier (must be a non-empty string)\n * @param options.maxLen - max length for the passthrough branch (default 128).\n * Ids longer than this are hashed; the hash token itself is always short.\n * @throws ConfigurationError (code `invalid_filename_id`) only on empty input.\n *\n * @example\n * safeFilenameForId(\"550e8400-e29b-41d4-a716-446655440000\") // passthrough\n * safeFilenameForId(\"user@example.com\") // \"h-<16hex>\"\n *\n */\nexport function safeFilenameForId(id: string, options?: { maxLen?: number }): string {\n if (id.length === 0) {\n throw new ConfigurationError(\"Filename id must be a non-empty string\", {\n code: \"invalid_filename_id\",\n });\n }\n const maxLen = options?.maxLen ?? 128;\n const lower = id.toLowerCase();\n if (lower.length <= maxLen && IDENTIFIER_PATTERN.test(lower)) {\n return lower;\n }\n return `h-${createHash(\"sha256\").update(id).digest(\"hex\").slice(0, 16)}`;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/persistence/session-transcript.ts"],"names":["redactSecrets","randomUUID","join","homedir","createHash","path","mkdir","dirname","replaceFileAtomic","readFile","diag"],"mappings":";;;;;;;;;AAmDO,SAAS,iBAAiB,GAAA,EAAqB;AACpD,EAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,eAAA,EAAiB,GAAG,CAAA;AACzC;AAGO,SAAS,cAAc,EAAA,EAAoB;AAChD,EAAA,OAAO,EAAA,CAAG,OAAA,CAAQ,iBAAA,EAAmB,GAAG,CAAA;AAC1C;AAEA,IAAM,GAAA,GAAM,CAAC,CAAA,KAAsBA,+BAAA,CAAc,CAAC,CAAA;AAGlD,SAAS,YAAY,KAAA,EAAyB;AAC5C,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,MAAMA,+BAAA,CAAc,IAAA,CAAK,UAAU,KAAA,IAAS,IAAI,CAAC,CAAC,CAAA;AAAA,EAChE,CAAA,CAAA,MAAQ;AACN,IAAA,OAAOA,+BAAA,CAAc,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,EACpC;AACF;AAWO,IAAM,iBAAA,GAAN,MAAM,kBAAA,CAAkB;AAAA,EAC7B,WAA4B,EAAC;AAAA,EAC7B,KAAA,GAAuB,IAAA;AAAA,EACvB,KAAA;AAAA,EAEA,YAAY,IAAA,EAAgC;AAC1C,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,WAAA,CACL,KAAA,EACA,IAAA,EACmB;AACnB,IAAA,MAAM,CAAA,GAAI,IAAI,kBAAA,CAAkB,IAAI,CAAA;AACpC,IAAA,CAAA,CAAE,QAAA,GAAW,CAAC,GAAG,KAAK,CAAA;AACtB,IAAA,CAAA,CAAE,KAAA,GAAQ,KAAA,CAAM,MAAA,GAAS,CAAA,GAAK,KAAA,CAAM,MAAM,MAAA,GAAS,CAAC,CAAA,EAAG,IAAA,IAAQ,IAAA,GAAQ,IAAA;AACvE,IAAA,OAAO,CAAA;AAAA,EACT;AAAA,EAEA,MACE,GAAA,EACe;AACf,IAAA,MAAM,IAAA,GAAsB;AAAA,MAC1B,GAAG,GAAA;AAAA,MACH,MAAMC,iBAAA,EAAW;AAAA,MACjB,YAAY,IAAA,CAAK,KAAA;AAAA,MACjB,SAAA,EAAW,KAAK,KAAA,CAAM,SAAA;AAAA,MACtB,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAClC,WAAA,EAAa,KAAA;AAAA,MACb,QAAA,EAAU,UAAA;AAAA,MACV,GAAA,EAAK,KAAK,KAAA,CAAM,GAAA;AAAA,MAChB,OAAA,EAAS,IAAA,CAAK,KAAA,CAAM,OAAA,IAAW;AAAA,KACjC;AACA,IAAA,IAAA,CAAK,QAAA,CAAS,KAAK,IAAI,CAAA;AACvB,IAAA,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAA;AAClB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,eAAe,IAAA,EAA6B;AAC1C,IAAA,OAAO,KAAK,KAAA,CAAM;AAAA,MAChB,IAAA,EAAM,MAAA;AAAA,MACN,OAAA,EAAS,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,GAAA,CAAI,IAAI,CAAA,EAAG,CAAA;AAAE,KACvE,CAAA;AAAA,EACH;AAAA,EAEA,oBAAoB,IAAA,EAAoC;AACtD,IAAA,MAAM,UAAmB,EAAC;AAC1B,IAAA,IAAI,KAAK,QAAA,EAAU;AAYjB,MAAA,MAAM,gBAAA,GAAmB,GAAA,CAAI,IAAA,CAAK,QAAQ,CAAA;AAC1C,MAAA,MAAM,mBAAA,GACJ,IAAA,CAAK,iBAAA,KAAsB,MAAA,IAAa,qBAAqB,IAAA,CAAK,QAAA;AACpE,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,IAAA,EAAM,UAAA;AAAA,QACN,QAAA,EAAU,gBAAA;AAAA,QACV,GAAI,mBAAA,GAAsB,EAAE,WAAW,IAAA,CAAK,iBAAA,KAAsB;AAAC,OACpE,CAAA;AAAA,IACH;AACA,IAAA,IAAI,IAAA,CAAK,IAAA,EAAM,OAAA,CAAQ,IAAA,CAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG,CAAA;AAClE,IAAA,KAAA,MAAW,CAAA,IAAK,IAAA,CAAK,SAAA,IAAa,EAAC,EAAG;AACpC,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,IAAA,EAAM,UAAA,EAAY,IAAI,CAAA,CAAE,EAAA,EAAI,IAAA,EAAM,CAAA,CAAE,MAAM,KAAA,EAAO,WAAA,CAAY,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,IACxF;AACA,IAAA,OAAO,KAAK,KAAA,CAAM;AAAA,MAChB,IAAA,EAAM,WAAA;AAAA,MACN,OAAA,EAAS;AAAA,QACP,IAAIA,iBAAA,EAAW;AAAA,QACf,IAAA,EAAM,SAAA;AAAA,QACN,IAAA,EAAM,WAAA;AAAA,QACN,KAAA,EAAO,KAAK,KAAA,CAAM,KAAA;AAAA,QAClB;AAAA;AACF,KACD,CAAA;AAAA,EACH;AAAA,EAEA,kBACE,OAAA,EACe;AACf,IAAA,MAAM,OAAA,GAAmB,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MAC3C,IAAA,EAAM,aAAA;AAAA,MACN,aAAa,CAAA,CAAE,SAAA;AAAA,MACf,OAAA,EAAS,GAAA,CAAI,CAAA,CAAE,OAAO,CAAA;AAAA,MACtB,QAAA,EAAU,EAAE,OAAA,KAAY;AAAA,KAC1B,CAAE,CAAA;AACF,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAQ,EAAG,CAAA;AAAA,EACxE;AAAA;AAAA,EAGA,sBAAsB,IAAA,EAA6D;AACjF,IAAA,MAAM,GAAA,GAAqB;AAAA,MACzB,IAAA,EAAM,QAAA;AAAA,MACN,MAAMA,iBAAA,EAAW;AAAA,MACjB,UAAA,EAAY,IAAA;AAAA,MACZ,SAAA,EAAW,KAAK,KAAA,CAAM,SAAA;AAAA,MACtB,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAClC,OAAA,EAAS,kBAAA;AAAA,MACT,eAAA,EAAiB,IAAA;AAAA,MACjB,WAAA,EAAa,KAAA;AAAA,MACb,QAAA,EAAU,UAAA;AAAA,MACV,GAAA,EAAK,KAAK,KAAA,CAAM,GAAA;AAAA,MAChB,OAAA,EAAS,IAAA,CAAK,KAAA,CAAM,OAAA,IAAW;AAAA,KACjC;AACA,IAAA,IAAA,CAAK,QAAA,CAAS,KAAK,GAAG,CAAA;AACtB,IAAA,IAAA,CAAK,QAAQ,GAAA,CAAI,IAAA;AACjB,IAAA,OAAO,GAAA;AAAA,EACT;AAAA,EAEA,OAAA,GAAoC;AAClC,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd;AACF;AAKA,SAAS,uBAAuB,OAAA,EAAwD;AACtF,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAoB;AACtC,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,MAAM,GAAA,GAAM,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,SAAS,CAAA;AACjC,IAAA,IAAI,GAAA,KAAQ,MAAA,IAAa,CAAA,CAAE,SAAA,GAAY,GAAA,QAAW,GAAA,CAAI,CAAA,CAAE,SAAA,EAAW,CAAA,CAAE,SAAS,CAAA;AAAA,EAChF;AACA,EAAA,OAAO,KAAA;AACT;AAGA,SAAS,YAAY,OAAA,EAA+D;AAClF,EAAA,MAAM,OAAA,GAAU,uBAAuB,OAAO,CAAA;AAC9C,EAAA,MAAM,MAAA,uBAAa,GAAA,EAA2B;AAC9C,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,IAAI,CAAA;AAClC,IAAA,MAAM,IAAA,GACJ,QAAA,KAAa,MAAA,IAAA,CACZ,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,SAAS,CAAA,IAAK,EAAA,KAAO,OAAA,CAAQ,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA,IAAK,EAAA,CAAA;AACzE,IAAA,IAAI,IAAA,EAAM,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,MAAM,CAAC,CAAA;AAAA,EAChC;AACA,EAAA,OAAO,MAAA;AACT;AAUA,SAAS,oBAAoB,CAAA,EAAyD;AACpF,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,IAAA,EAAM,MAAA,CAAO,CAAA,CAAE,QAAA,IAAY,EAAE,CAAA;AAAA,IAC7B,GAAI,CAAA,CAAE,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,EAAW,MAAA,CAAO,CAAA,CAAE,SAAS,CAAA,EAAE,GAAI;AAAC,GACxE;AACF;AAEA,SAAS,YAAY,CAAA,EAAsC;AACzD,EAAA,IAAI,CAAA,CAAE,IAAA,KAAS,MAAA,EAAQ,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,MAAA,CAAO,CAAA,CAAE,IAAA,IAAQ,EAAE,CAAA,EAAE;AACzE,EAAA,IAAI,CAAA,CAAE,IAAA,KAAS,UAAA,EAAY,OAAO,oBAAoB,CAAC,CAAA;AACvD,EAAA,IAAI,CAAA,CAAE,SAAS,UAAA,EAAY;AACzB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,UAAA;AAAA,MACN,EAAA,EAAI,MAAA,CAAO,CAAA,CAAE,EAAE,CAAA;AAAA,MACf,IAAA,EAAM,MAAA,CAAO,CAAA,CAAE,IAAI,CAAA;AAAA,MACnB,KAAA,EAAQ,CAAA,CAAE,KAAA,IAAqC;AAAC,KAClD;AAAA,EACF;AACA,EAAA,IAAI,CAAA,CAAE,SAAS,aAAA,EAAe;AAC5B,IAAA,MAAM,EAAA,GAAwB;AAAA,MAC5B,IAAA,EAAM,aAAA;AAAA,MACN,SAAA,EAAW,MAAA,CAAO,CAAA,CAAE,WAAW,CAAA;AAAA,MAC/B,OAAA,EAAS,OAAO,CAAA,CAAE,OAAA,KAAY,QAAA,GAAW,EAAE,OAAA,GAAU,IAAA,CAAK,SAAA,CAAU,CAAA,CAAE,OAAO,CAAA;AAAA,MAC7E,OAAA,EAAS,EAAE,QAAA,KAAa;AAAA,KAC1B;AACA,IAAA,OAAO,EAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAA;AACT;AAGA,SAAS,gBAAgB,GAAA,EAA4C;AACnE,EAAA,IAAI,IAAI,IAAA,KAAS,MAAA,IAAU,GAAA,CAAI,IAAA,KAAS,aAAa,OAAO,MAAA;AAC5D,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,OAAA,EAAS,OAAA,IAAW,EAAC;AACxC,EAAA,MAAM,KAAA,GAAQ,OAAO,GAAA,CAAI,WAAW,EAAE,MAAA,CAAO,CAAC,CAAA,KAA2B,CAAA,KAAM,MAAS,CAAA;AACxF,EAAA,OAAO,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAM,SAAS,KAAA,EAAM;AAC1C;AAGA,SAAS,cAAA,CACP,OAAA,EACA,MAAA,EACA,OAAA,EAC2B;AAC3B,EAAA,IAAI,IAAA;AACJ,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,IAAI,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,IAAI,CAAA,KAAM,CAAA,IAAK,CAAC,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,IAAI,CAAA,EAAG,IAAA,GAAO,CAAA;AAAA,EAC/D;AACA,EAAA,OAAO,IAAA;AACT;AAGA,SAAS,UAAA,CAAW,MAAqB,MAAA,EAAqD;AAC5F,EAAA,MAAM,QAAyB,EAAC;AAChC,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,IAAI,GAAA,GAAiC,IAAA;AACrC,EAAA,OAAO,QAAQ,MAAA,IAAa,CAAC,KAAK,GAAA,CAAI,GAAA,CAAI,IAAI,CAAA,EAAG;AAC/C,IAAA,IAAA,CAAK,GAAA,CAAI,IAAI,IAAI,CAAA;AACjB,IAAA,KAAA,CAAM,KAAK,GAAG,CAAA;AACd,IAAA,GAAA,GAAM,IAAI,UAAA,KAAe,IAAA,GAAO,OAAO,GAAA,CAAI,GAAA,CAAI,UAAU,CAAA,GAAI,MAAA;AAAA,EAC/D;AACA,EAAA,OAAO,MAAM,OAAA,EAAQ;AACvB;AAOO,SAAS,oBAAoB,OAAA,EAAiD;AACnF,EAAA,MAAM,MAAA,GAAS,YAAY,OAAO,CAAA;AAClC,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,MAAA,EAAO,EAAG,IAAI,EAAE,UAAA,EAAY,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,UAAU,CAAA;AAC3E,EAAA,MAAM,IAAA,GAAO,cAAA,CAAe,OAAA,EAAS,MAAA,EAAQ,OAAO,CAAA;AACpD,EAAA,IAAI,IAAA,KAAS,MAAA,EAAW,OAAO,EAAC;AAEhC,EAAA,MAAM,OAAqB,EAAC;AAC5B,EAAA,KAAA,MAAW,GAAA,IAAO,UAAA,CAAW,IAAA,EAAM,MAAM,CAAA,EAAG;AAC1C,IAAA,MAAM,CAAA,GAAI,gBAAgB,GAAG,CAAA;AAC7B,IAAA,IAAI,CAAA,KAAM,MAAA,EAAW,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA;AAAA,EAClC;AACA,EAAA,OAAO,IAAA;AACT;AAeO,SAAS,cAAA,GAAyB;AACvC,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,CAAI,YAAA,EAAc,IAAA,EAAK;AAChD,EAAA,IAAI,QAAA,KAAa,MAAA,IAAa,QAAA,CAAS,MAAA,GAAS,GAAG,OAAO,QAAA;AAC1D,EAAA,OAAOC,SAAA,CAAKC,UAAA,EAAQ,EAAG,UAAU,CAAA;AACnC;AAGO,SAAS,cAAA,GAAyB;AACvC,EAAA,OAAO,cAAA,EAAe;AACxB;AAQO,SAAS,YAAY,CAAA,EAAmB;AAC7C,EAAA,IAAI,CAAA,KAAM,GAAA,EAAK,OAAOA,UAAA,EAAQ;AAC9B,EAAA,IAAI,CAAA,CAAE,UAAA,CAAW,IAAI,CAAA,EAAG,OAAOD,SAAA,CAAKC,UAAA,EAAQ,EAAG,CAAA,CAAE,KAAA,CAAM,CAAC,CAAC,CAAA;AACzD,EAAA,OAAO,CAAA;AACT;AASA,IAAM,iBAAA,GAAoB,MAAA,CAAO,IAAA,CAAK,kCAAA,EAAoC,KAAK,CAAA;AAE/E,IAAM,UAAA,GAAa,iEAAA;AAGZ,SAAS,cAAc,EAAA,EAAqB;AACjD,EAAA,OAAO,UAAA,CAAW,KAAK,EAAE,CAAA;AAC3B;AA8BO,SAAS,eAAe,EAAA,EAAoB;AACjD,EAAA,IAAI,aAAA,CAAc,EAAE,CAAA,EAAG,OAAO,GAAG,WAAA,EAAY;AAC7C,EAAA,MAAM,OAAOC,iBAAA,CAAW,QAAQ,CAAA,CAC7B,MAAA,CAAO,OAAO,MAAA,CAAO,CAAC,iBAAA,EAAmB,MAAA,CAAO,KAAK,EAAA,EAAI,MAAM,CAAC,CAAC,CAAC,EAClE,MAAA,EAAO;AACV,EAAA,MAAM,QAAQ,MAAA,CAAO,IAAA,CAAK,KAAK,QAAA,CAAS,CAAA,EAAG,EAAE,CAAC,CAAA;AAC9C,EAAA,KAAA,CAAM,CAAC,CAAA,GAAM,KAAA,CAAM,CAAC,IAAe,EAAA,GAAQ,GAAA;AAC3C,EAAA,KAAA,CAAM,CAAC,CAAA,GAAM,KAAA,CAAM,CAAC,IAAe,EAAA,GAAQ,GAAA;AAC3C,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,QAAA,CAAS,KAAK,CAAA;AAChC,EAAA,OAAO,CAAA,EAAG,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA,EAAI,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA,EAAI,GAAA,CAAI,KAAA,CAAM,EAAA,EAAI,EAAE,CAAC,CAAA,CAAA,EAAI,GAAA,CAAI,KAAA,CAAM,EAAA,EAAI,EAAE,CAAC,CAAA,CAAA,EAAI,GAAA,CAAI,KAAA,CAAM,EAAE,CAAC,CAAA,CAAA;AAC1G;AAGO,SAAS,cAAA,CAAe,OAAA,EAAiB,GAAA,EAAa,SAAA,EAA2B;AACtF,EAAA,OAAOF,SAAA,CAAK,OAAA,EAAS,UAAA,EAAY,gBAAA,CAAiB,GAAG,GAAG,CAAA,EAAG,cAAA,CAAe,SAAS,CAAC,CAAA,MAAA,CAAQ,CAAA;AAC9F;AASO,SAAS,oBAAA,CAAqB,OAAA,EAAiB,GAAA,EAAa,SAAA,EAA2B;AAC5F,EAAA,OAAOA,SAAA,CAAK,OAAA,EAAS,UAAA,EAAY,gBAAA,CAAiB,GAAG,GAAG,CAAA,EAAG,aAAA,CAAc,SAAS,CAAC,CAAA,MAAA,CAAQ,CAAA;AAC7F;AAGA,eAAsB,eAAA,CACpBG,QACA,OAAA,EACiB;AACjB,EAAA,MAAMC,eAAMC,YAAA,CAAQF,MAAI,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAC9C,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,IAAA,CAAK,SAAA,CAAU,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAC5D,EAAA,MAAMG,oCAAkBH,MAAA,EAAM,OAAA,CAAQ,MAAA,GAAS,CAAA,GAAI,GAAG,IAAI;AAAA,CAAA,GAAO,EAAE,CAAA;AACnE,EAAA,OAAOA,MAAA;AACT;AAGA,SAAS,gBAAgB,IAAA,EAAyC;AAChE,EAAA,MAAM,OAAA,GAAU,KAAK,IAAA,EAAK;AAC1B,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AACjC,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA;AAC9B,IAAA,OAAO,OAAO,IAAI,IAAA,KAAS,QAAA,IAAY,OAAO,GAAA,CAAI,IAAA,KAAS,WAAW,GAAA,GAAM,KAAA,CAAA;AAAA,EAC9E,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAGA,eAAsB,eAAe,IAAA,EAAwC;AAC3E,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,MAAMI,iBAAA,CAAS,IAAA,EAAM,MAAM,CAAA;AAAA,EACnC,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,OAAQ,KAAA,CAAgC,IAAA;AAE9C,IAAA,IAAI,IAAA,KAAS,QAAA,EAAU,OAAO,EAAC;AAc/B,IAAA,IAAI,SAAS,MAAA,EAAW;AACtB,MAAAC,sBAAA;AAAA,QACE,yFACE,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CACvD;AAAA;AAAA,OACF;AACA,MAAA,OAAO,EAAC;AAAA,IACV;AACA,IAAA,MAAM,KAAA;AAAA,EACR;AACA,EAAA,OAAO,GAAA,CACJ,KAAA,CAAM,IAAI,CAAA,CACV,GAAA,CAAI,eAAe,CAAA,CACnB,MAAA,CAAO,CAAC,CAAA,KAA0B,CAAA,KAAM,MAAS,CAAA;AACtD","file":"chunk-3WKWBYPO.cjs","sourcesContent":["/**\n * SE40 — native session transcript (Claude-Code-compatible on-disk shape, theokit-native names).\n *\n * The theokit session format IS the Claude Code record shape (a `uuid`/`parentUuid` DAG of records with\n * structured `text`/`tool_use`/`tool_result`/`thinking` blocks) — so the ecosystem's read-side tools\n * parse our sessions AND, pointed at `~/.claude`, the Claude Code CLI can `--continue` them. This module\n * is the PURE core: append-per-turn record builders + the DAG reader that rebuilds `LlmMessage[]` for\n * resume. File I/O + loop wiring + append-only compaction live in the FS store.\n *\n * Reader mirrors `claude-code-log` dag.py: leaf = a uuid never used as a parentUuid; walk parentUuid to a\n * root (cycle-break); dedup a uuid across sessions keeping the earliest; a `compact_boundary` root\n * terminates the walk so a resume-after-compaction replays only the post-boundary continuation.\n *\n * reference: knowledge-base/references/claude-code-log/claude_code_log/dag.py + models.py\n */\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { mkdir, readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport type { SessionRecord, TranscriptBlock } from \"../../types/session-record.js\";\nimport { diag } from \"../diagnostics.js\";\nimport type { LlmContentPart, LlmMessage, LlmToolResultPart } from \"../llm/types.js\";\nimport { redactSecrets } from \"../security/redact.js\";\nimport { replaceFileAtomic } from \"./atomic-write.js\";\n\n// The `SessionRecord` contract now lives in the domain `types/` layer (SE46 DIP\n// direction). Re-exported here so existing importers of this DAG-core module\n// keep resolving the same name.\nexport type { SessionRecord } from \"../../types/session-record.js\";\n\nexport interface SessionTranscriptOptions {\n cwd: string;\n sessionId: string;\n model: string;\n version?: string;\n}\n\nexport interface AssistantTurn {\n text?: string;\n thinking?: string;\n /**\n * theokit#122 — the provider's signature for the thinking block. Written into the `thinking`\n * record block (`Block` already declared `signature?`), so a resumed session can replay the block\n * exactly as the provider issued it.\n */\n thinkingSignature?: string;\n toolCalls?: Array<{ id: string; name: string; input: Record<string, unknown> }>;\n}\n\n/** Claude Code path convention: cwd with every non-alphanumeric replaced by `-`. */\nexport function encodeProjectDir(cwd: string): string {\n return cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n}\n\n/** Make a caller-supplied session id safe as a path component (no traversal). */\nexport function safeSessionId(id: string): string {\n return id.replace(/[^a-zA-Z0-9_-]/g, \"-\");\n}\n\nconst red = (s: string): string => redactSecrets(s);\n\n/** Deep-redact a structured value (tool input) preserving object shape. */\nfunction redactValue(value: unknown): unknown {\n try {\n return JSON.parse(redactSecrets(JSON.stringify(value ?? null)));\n } catch {\n return redactSecrets(String(value));\n }\n}\n\n// M94 — it was `Record<string, unknown>`. The published type describes the same shape this file\n// has always produced; the local alias now points at it so writer and reader cannot\n// diverge silently.\ntype Block = TranscriptBlock;\n\n/**\n * Builds a session transcript append-by-append, maintaining the `parentUuid` chain. Each turn mints a\n * fresh `uuid` and parents on the previous record; `appendCompactBoundary` starts a NEW ROOT.\n */\nexport class SessionTranscript {\n #records: SessionRecord[] = [];\n #last: string | null = null;\n #opts: SessionTranscriptOptions;\n\n constructor(opts: SessionTranscriptOptions) {\n this.#opts = opts;\n }\n\n /**\n * Seed a transcript from records already on disk so a subsequent append parents\n * on the existing DAG leaf (the last record in file order). Prior records are\n * re-emitted verbatim by {@link records}, so the whole file rewrites atomically\n * as one append-only line set — never shrinking (SE40 compaction is append-only).\n */\n static fromRecords(\n prior: readonly SessionRecord[],\n opts: SessionTranscriptOptions,\n ): SessionTranscript {\n const t = new SessionTranscript(opts);\n t.#records = [...prior];\n t.#last = prior.length > 0 ? (prior[prior.length - 1]?.uuid ?? null) : null;\n return t;\n }\n\n #push(\n rec: Omit<SessionRecord, \"uuid\" | \"parentUuid\" | \"sessionId\" | \"timestamp\">,\n ): SessionRecord {\n const full: SessionRecord = {\n ...rec,\n uuid: randomUUID(),\n parentUuid: this.#last,\n sessionId: this.#opts.sessionId,\n timestamp: new Date().toISOString(),\n isSidechain: false,\n userType: \"external\",\n cwd: this.#opts.cwd,\n version: this.#opts.version ?? \"1.0.0-theokit\",\n };\n this.#records.push(full);\n this.#last = full.uuid;\n return full;\n }\n\n appendUserTurn(text: string): SessionRecord {\n return this.#push({\n type: \"user\",\n message: { role: \"user\", content: [{ type: \"text\", text: red(text) }] },\n });\n }\n\n appendAssistantTurn(turn: AssistantTurn): SessionRecord {\n const content: Block[] = [];\n if (turn.thinking) {\n // theokit#122 — the signature is computed by the provider over the ORIGINAL text, so it is\n // only valid while the text is byte-identical. Redaction rewrites the text; keeping the\n // signature next to a masked body persists a pair that Anthropic rejects with\n // `400 \"thinking blocks cannot be modified\"` — the very failure this issue exists to remove.\n //\n // So redaction WINS and the signature is dropped. The block survives as display-only history\n // (`thinkingToWireBlock` already refuses to replay an unsigned block), which loses one block\n // of context; keeping a signature that cannot verify would lose the whole turn.\n //\n // The signature itself is never redacted — it is an opaque provider token with no user\n // content — but that was only half the reasoning the first version of this fix wrote down.\n const redactedThinking = red(turn.thinking);\n const signatureStillValid =\n turn.thinkingSignature !== undefined && redactedThinking === turn.thinking;\n content.push({\n type: \"thinking\",\n thinking: redactedThinking,\n ...(signatureStillValid ? { signature: turn.thinkingSignature } : {}),\n });\n }\n if (turn.text) content.push({ type: \"text\", text: red(turn.text) });\n for (const c of turn.toolCalls ?? []) {\n content.push({ type: \"tool_use\", id: c.id, name: c.name, input: redactValue(c.input) });\n }\n return this.#push({\n type: \"assistant\",\n message: {\n id: randomUUID(),\n type: \"message\",\n role: \"assistant\",\n model: this.#opts.model,\n content,\n },\n });\n }\n\n appendToolResults(\n results: Array<{ toolUseId: string; content: string; isError?: boolean }>,\n ): SessionRecord {\n const content: Block[] = results.map((r) => ({\n type: \"tool_result\",\n tool_use_id: r.toolUseId,\n content: red(r.content),\n is_error: r.isError === true,\n }));\n return this.#push({ type: \"user\", message: { role: \"user\", content } });\n }\n\n /** Append-only compaction: a `compact_boundary` system record becomes a NEW ROOT (parentUuid null). */\n appendCompactBoundary(meta: { preTokens: number; trigger: string }): SessionRecord {\n const rec: SessionRecord = {\n type: \"system\",\n uuid: randomUUID(),\n parentUuid: null,\n sessionId: this.#opts.sessionId,\n timestamp: new Date().toISOString(),\n subtype: \"compact_boundary\",\n compactMetadata: meta,\n isSidechain: false,\n userType: \"external\",\n cwd: this.#opts.cwd,\n version: this.#opts.version ?? \"1.0.0-theokit\",\n };\n this.#records.push(rec);\n this.#last = rec.uuid;\n return rec;\n }\n\n records(): readonly SessionRecord[] {\n return this.#records;\n }\n}\n\n// ─── Reader (DAG → LlmMessage[]) ──────────────────────────────────────────────────────────────────\n\n/** Earliest timestamp seen per session id. */\nfunction sessionFirstTimestamps(records: readonly SessionRecord[]): Map<string, string> {\n const first = new Map<string, string>();\n for (const r of records) {\n const cur = first.get(r.sessionId);\n if (cur === undefined || r.timestamp < cur) first.set(r.sessionId, r.timestamp);\n }\n return first;\n}\n\n/** Dedup a uuid across sessions: keep the record whose session's earliest timestamp is smallest. */\nfunction dedupByUuid(records: readonly SessionRecord[]): Map<string, SessionRecord> {\n const firstTs = sessionFirstTimestamps(records);\n const byUuid = new Map<string, SessionRecord>();\n for (const r of records) {\n const existing = byUuid.get(r.uuid);\n const wins =\n existing === undefined ||\n (firstTs.get(r.sessionId) ?? \"\") < (firstTs.get(existing.sessionId) ?? \"\");\n if (wins) byUuid.set(r.uuid, r);\n }\n return byUuid;\n}\n\n/**\n * Map one structured block to an `LlmContentPart`.\n *\n * theokit#122 — thinking blocks used to be DROPPED here, which is why an extended-thinking session\n * could not be resumed: the block never made it back into the replayed messages, so the provider saw\n * a conversation whose assistant turn had lost its thinking. They are now reconstructed with their\n * signature; the Anthropic wire re-serializes signed blocks and skips unsigned ones.\n */\nfunction thinkingBlockToPart(b: Extract<Block, { type: \"thinking\" }>): LlmContentPart {\n return {\n type: \"thinking\",\n text: String(b.thinking ?? \"\"),\n ...(b.signature !== undefined ? { signature: String(b.signature) } : {}),\n };\n}\n\nfunction blockToPart(b: Block): LlmContentPart | undefined {\n if (b.type === \"text\") return { type: \"text\", text: String(b.text ?? \"\") };\n if (b.type === \"thinking\") return thinkingBlockToPart(b);\n if (b.type === \"tool_use\") {\n return {\n type: \"tool_use\",\n id: String(b.id),\n name: String(b.name),\n input: (b.input as Record<string, unknown>) ?? {},\n };\n }\n if (b.type === \"tool_result\") {\n const tr: LlmToolResultPart = {\n type: \"tool_result\",\n toolUseId: String(b.tool_use_id),\n content: typeof b.content === \"string\" ? b.content : JSON.stringify(b.content),\n isError: b.is_error === true,\n };\n return tr;\n }\n return undefined;\n}\n\n/** Map one record to an LlmMessage; `undefined` for non-conversational (system) records. */\nfunction recordToMessage(rec: SessionRecord): LlmMessage | undefined {\n if (rec.type !== \"user\" && rec.type !== \"assistant\") return undefined;\n const blocks = rec.message?.content ?? [];\n const parts = blocks.map(blockToPart).filter((p): p is LlmContentPart => p !== undefined);\n return { role: rec.type, content: parts };\n}\n\n/** The most-recent leaf: the LAST record (in input order) whose uuid is never used as a parentUuid. */\nfunction findLatestLeaf(\n records: readonly SessionRecord[],\n byUuid: Map<string, SessionRecord>,\n parents: Set<string>,\n): SessionRecord | undefined {\n let leaf: SessionRecord | undefined;\n for (const r of records) {\n if (byUuid.get(r.uuid) === r && !parents.has(r.uuid)) leaf = r;\n }\n return leaf;\n}\n\n/** Walk parentUuid from a leaf to a root (cycle-safe), returning root→leaf order. */\nfunction walkToRoot(leaf: SessionRecord, byUuid: Map<string, SessionRecord>): SessionRecord[] {\n const chain: SessionRecord[] = [];\n const seen = new Set<string>();\n let cur: SessionRecord | undefined = leaf;\n while (cur !== undefined && !seen.has(cur.uuid)) {\n seen.add(cur.uuid);\n chain.push(cur);\n cur = cur.parentUuid !== null ? byUuid.get(cur.parentUuid) : undefined;\n }\n return chain.reverse();\n}\n\n/**\n * Rebuild the resumable `LlmMessage[]` from transcript records: dedup → find the most-recent leaf →\n * walk `parentUuid` to a root (a `compact_boundary` root terminates the walk) → map to LlmMessages.\n * Returns them in root→leaf (chronological replay) order.\n */\nexport function reconstructMessages(records: readonly SessionRecord[]): LlmMessage[] {\n const byUuid = dedupByUuid(records);\n const parents = new Set<string>();\n for (const r of byUuid.values()) if (r.parentUuid) parents.add(r.parentUuid);\n const leaf = findLatestLeaf(records, byUuid, parents);\n if (leaf === undefined) return [];\n\n const msgs: LlmMessage[] = [];\n for (const rec of walkToRoot(leaf, byUuid)) {\n const m = recordToMessage(rec);\n if (m !== undefined) msgs.push(m);\n }\n return msgs;\n}\n\n// ─── File I/O (the on-disk Claude layout) ─────────────────────────────────────────────────────────\n\n/**\n * Root of the transcript state.\n *\n * `THEOKIT_HOME` wins; the fallback is `~/.theokit`. Home-anchored on purpose, and NOT\n * `paths.ts`'s `getTheokitHome(cwd)`: that one falls back to `<cwd>/.theokit`, and switching\n * by it would move the transcript of everyone who does **not** set the variable. The sibling with the\n * right shape is `catalog-source-models-dev.ts` (M94 ADR-2).\n *\n * Before M94 this function ignored the env var, so whoever set it had their state split in\n * two silently — sessions stayed in `~/.theokit` while the rest of the SDK migrated.\n */\nexport function transcriptRoot(): string {\n const override = process.env.THEOKIT_HOME?.trim();\n if (override !== undefined && override.length > 0) return override;\n return join(homedir(), \".theokit\");\n}\n\n/** @deprecated Use {@link transcriptRoot}. Kept as an alias — same value. */\nexport function defaultBaseDir(): string {\n return transcriptRoot();\n}\n\n/**\n * Expand a leading `~` / `~/` to the user's home dir. `node:path` does NOT expand `~`, so a\n * `baseDir: \"~/.claude\"` (the documented Claude Code CLI interop path) would otherwise resolve to a\n * literal `./~/.claude` under cwd and the CLI would never find the session. Absolute or relative\n * paths without a leading tilde pass through untouched.\n */\nexport function expandTilde(p: string): string {\n if (p === \"~\") return homedir();\n if (p.startsWith(\"~/\")) return join(homedir(), p.slice(2));\n return p;\n}\n\n/**\n * The fixed namespace for deriving a session UUID from an agent id (RFC 9562 § 5.8, version 8).\n *\n * A constant, because the derivation must be STABLE FOREVER: it is what lets the SDK find the\n * session it wrote last week without storing an id-to-filename map anywhere. Changing this value\n * orphans every transcript ever written.\n */\nconst SESSION_NAMESPACE = Buffer.from(\"b7a1f0c94e3d4a1b8f26d05c3a91e7d2\", \"hex\");\n\nconst UUID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/** Is this id already a canonical UUID, and therefore usable as a filename verbatim? */\nexport function isSessionUuid(id: string): boolean {\n return UUID_SHAPE.test(id);\n}\n\n/**\n * The transcript filename for an agent id — always a UUID.\n *\n * #400: the Claude Code CLI resumes a transcript ONLY when its basename is a UUID. Measured against\n * CLI 2.1.236: `<uuid>.jsonl` resumes; `agent-<uuid>.jsonl` and `billing-bot.jsonl` are both ignored,\n * with no error — the session simply is not offered. So a session written under a human-readable\n * agent id was invisible to `claude --continue`, which is the interoperability this project claims\n * as its difference from a proprietary session store.\n *\n * An id that is ALREADY a UUID passes through verbatim, so a transcript Claude Code wrote keeps its\n * own name and the two directions stay symmetric. Anything else is derived with a UUIDv8, which is\n * deterministic: the same agent id always yields the same filename, so nothing has to be persisted\n * to map one back to the other.\n *\n * A DERIVED name is version 8 — RFC 9562's slot for a UUID whose bits come from an\n * implementation-defined scheme, which is exactly what this is. The obvious alternative was v5, but\n * RFC 4122 fixes v5's hash to SHA-1, and reaching for SHA-1 in 2026 means either shipping a weak\n * primitive or arguing with every scanner that flags it, forever. v8 lets the hash be SHA-256 and\n * lets the version nibble say honestly that this is our scheme rather than a standard one.\n *\n * There is no security claim here either way — no secret, no signature, and nothing an attacker\n * gains by colliding two agent ids inside one consumer's own directory. The hash is a naming\n * function. The point of preferring SHA-256 is not that SHA-1 was exploitable here; it is that a\n * weak primitive in the tree costs a permanent argument with every scanner that sees it.\n *\n * The version nibble was measured, not assumed: CLI 2.1.236 resumes a v8-named transcript exactly as\n * it does a v4 one.\n */\nexport function sessionUuidFor(id: string): string {\n if (isSessionUuid(id)) return id.toLowerCase();\n const hash = createHash(\"sha256\")\n .update(Buffer.concat([SESSION_NAMESPACE, Buffer.from(id, \"utf8\")]))\n .digest();\n const bytes = Buffer.from(hash.subarray(0, 16));\n bytes[6] = ((bytes[6] as number) & 0x0f) | 0x80; // version 8 — RFC 9562 custom\n bytes[8] = ((bytes[8] as number) & 0x3f) | 0x80; // RFC 9562 variant\n const hex = bytes.toString(\"hex\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/** The `.jsonl` path for a session: `<baseDir>/projects/<encoded-cwd>/<session-uuid>.jsonl`. */\nexport function transcriptPath(baseDir: string, cwd: string, sessionId: string): string {\n return join(baseDir, \"projects\", encodeProjectDir(cwd), `${sessionUuidFor(sessionId)}.jsonl`);\n}\n\n/**\n * The path this session used BEFORE #400 made transcript filenames UUIDs.\n *\n * Kept so an existing transcript is never orphaned: {@link FsSessionStore} prefers this file when it\n * exists, so history written under the old scheme keeps accumulating in the same file instead of\n * being silently abandoned for a fresh one under the new name.\n */\nexport function legacyTranscriptPath(baseDir: string, cwd: string, sessionId: string): string {\n return join(baseDir, \"projects\", encodeProjectDir(cwd), `${safeSessionId(sessionId)}.jsonl`);\n}\n\n/** Write records as one JSONL line each (atomic; parent dir created). Returns the path. */\nexport async function writeTranscript(\n path: string,\n records: readonly SessionRecord[],\n): Promise<string> {\n await mkdir(dirname(path), { recursive: true });\n const body = records.map((r) => JSON.stringify(r)).join(\"\\n\");\n await replaceFileAtomic(path, records.length > 0 ? `${body}\\n` : \"\");\n return path;\n}\n\n/** Parse one JSONL line to a record; `undefined` for blank/torn/invalid lines (skipped on read). */\nfunction parseRecordLine(line: string): SessionRecord | undefined {\n const trimmed = line.trim();\n if (trimmed.length === 0) return undefined;\n try {\n const rec = JSON.parse(trimmed) as SessionRecord;\n return typeof rec.uuid === \"string\" && typeof rec.type === \"string\" ? rec : undefined;\n } catch {\n return undefined; // a torn last line (crash mid-write) — the rest of the DAG still reconstructs\n }\n}\n\n/** Parse a transcript `.jsonl` into records; a missing file yields `[]`; malformed lines are skipped. */\nexport async function readTranscript(path: string): Promise<SessionRecord[]> {\n let raw: string;\n try {\n raw = await readFile(path, \"utf8\");\n } catch (cause) {\n const code = (cause as NodeJS.ErrnoException).code;\n // An absent file is an empty transcript — a first turn has none, so this is the common case.\n if (code === \"ENOENT\") return [];\n // And so is a runtime with no filesystem. The only call inside this `try` is `readFile`, and a\n // real filesystem failure ALWAYS carries a code: ENOENT, EACCES, EISDIR, EMFILE. An error with\n // no code did not come from a filesystem; it came from the absence of one — `unenv`'s\n // `createNotImplementedError` returns a plain `new Error(…)`, so there is nothing else to key on\n // and no message to match without depending on another package's wording.\n //\n // Measured 2026-09-28: every turn on Cloudflare Workers failed during `LocalAgent.initialize`,\n // because `hydrateSession` reached for a transcript the platform has no way to hold. Before the\n // model, before a token, on a session that never existed.\n //\n // NOT a bare `catch { return [] }`, which would report EACCES on a real transcript as an empty\n // history — a permissions problem read as \"no messages\", which is the silent-corruption shape\n // `error-handling.md` refuses. A test pins EACCES, EISDIR and EMFILE still throwing.\n if (code === undefined) {\n diag(\n `[theokit-sdk] no filesystem for the session transcript, continuing with an empty one: ${\n cause instanceof Error ? cause.message : String(cause)\n }\\n`,\n );\n return [];\n }\n throw cause;\n }\n return raw\n .split(\"\\n\")\n .map(parseRecordLine)\n .filter((r): r is SessionRecord => r !== undefined);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/auth/credential-store.ts"],"names":["join","AuthenticationError","z","statSync","readFileSync","mkdirSync","chmodSync","randomBytes","openSync","writeFileSync","fsyncSync","closeSync","renameSync","unlinkSync"],"mappings":"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","file":"chunk-5645PMVU.cjs","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n closeSync,\n fsyncSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { z } from \"zod\";\n\nimport { AuthenticationError } from \"../../errors.js\";\n\n/**\n * M42 — the SDK credential store. Promoted DOWN from agent-builder's hardened `agents/lib/credentials.ts`\n * (M37), generalized from a closed `openrouter|anthropic|openai` union to an open `provider: string` and\n * driven by a caller-supplied {@link CredentialStoreConfig} (no hardcoded `.agent-builder`/`auth.json` /\n * `AGENT_BUILDER_HOME`). The security-critical file mechanics are ported VERBATIM (ADR D3 of the M42 plan):\n * atomic O_EXCL + rename + fsync write, 0700/0600 mode gates, `env` is always a PARAMETER (never an ambient\n * `process.env` read).\n *\n * The env-precedence + key-prefix-inference + declared-provider rungs of the agent-builder resolver are\n * APP POLICY and deliberately stay UP in the consumer; this module owns only the on-disk store + the\n * `api|oauth` discriminated union. See {@link resolveCredential} (SDK) for the store-read + refresh path.\n *\n * Re-exported from `@theokit/sdk/auth`, and therefore PUBLIC, under semver.\n *\n * NOTE — no internal-visibility tag in this block. `tsconfig.base.json` sets `stripInternal: true`,\n * and TypeScript scans EVERY leading comment range of the declaration that follows, including the\n * import right below this one. The tag that used to sit here deleted that import from the emitted\n * `.d.ts`, leaving the types it binds unresolvable for any consumer running type-aware lint\n * (usetheodev/theokit-sdk#283 records the same trap on a declaration).\n */\nimport type { CredentialStoreConfig, StoredCredential, StoredOAuthCredential } from \"./types.js\";\n\n/** The store directory, honoring an optional `homeEnvVar` override. */\nexport function credentialHome(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const override = config.homeEnvVar !== undefined ? env[config.homeEnvVar]?.trim() : undefined;\n return override !== undefined && override.length > 0\n ? override\n : join(config.home, config.dirName);\n}\n\n/** The credential file path inside the (possibly overridden) store directory. */\nexport function authFilePath(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n return join(credentialHome(config, env), config.fileName);\n}\n\n/**\n * A credential problem the caller can act on. Never carries the key value.\n *\n * M78 — this used to extend bare `Error`, which quietly disabled classification for the entire auth\n * path: `isTransientError` is `err instanceof TheokitAgentError && err.isRetryable === true`\n * (`errors.ts:443`), so a credential failure could never be judged transient OR permanent. The\n * predicate was not \"forgotten\" downstream — it was unusable there by construction.\n *\n * Extending `AuthenticationError` is ADDITIVE: the class still exists, still reports\n * `name: \"CredentialError\"`, and every existing `instanceof CredentialError` stays true. It only\n * gains ancestors. `AuthenticationError` pins `isRetryable: false`, so gaining the ability to be\n * classified does NOT turn a revoked credential into a retry loop.\n *\n * The single reference does the same thing with one root type: Codex routes every domain failure\n * through `CodexErr` with `is_retryable()` as a method (`protocol/src/error.rs:176`), rather than\n * parallel classes extending the language's `Error`.\n */\nexport class CredentialError extends AuthenticationError {\n // Field, not an assignment in the constructor: `AuthenticationError.name` is `override readonly`\n // (`errors.ts:174`), so `this.name = …` does not compile. Caught by `tsc`, not by vitest — the\n // suite was green with the broken assignment because the transpiler strips the type.\n override readonly name: string = \"CredentialError\";\n}\n\n/**\n * The on-disk store — a discriminated union on `type`. A legacy file with NO\n * `type` (or `type: 'api'`) is the API-key variant — read unchanged, no migration. The `oauth` variant\n * carries the token pair + expiry.\n */\nconst apiFileSchema = z\n .object({\n type: z.literal(\"api\").optional(),\n provider: z.string().min(1).optional(),\n api_key: z.string(),\n })\n .strict();\n\nconst oauthFileSchema = z\n .object({\n type: z.literal(\"oauth\"),\n provider: z.string().min(1),\n access: z.string().min(1),\n refresh: z.string().min(1),\n expires: z.number(),\n account_id: z.string().optional(),\n id_token: z.string().min(1).optional(),\n })\n .strict();\n\n// oauth first (it requires `type: 'oauth'`); a legacy `{provider?, api_key}` falls through to api.\nconst fileSchema = z.union([oauthFileSchema, apiFileSchema]);\n\n/**\n * The 0700-dir / 0600-file mode gates (ported verbatim). The DIRECTORY matters as much as the file:\n * `mkdirSync(mode)` applies only at creation, so a pre-existing store dir keeps whatever mode it had, and a\n * writable dir lets an attacker replace the credential file with a symlink to their own 0600 file — the\n * agent then runs on THEIR account.\n */\nexport function assertSecureModes(dirPath: string, path: string): void {\n // Windows has no POSIX mode bits. `statSync().mode` there is SYNTHETIC — 0666 for any writable\n // entry, whatever the ACLs actually say — so `mode & 0o022` was non-zero for every valid store and\n // this gate refused all of them, which made the credential path unreadable on that platform\n // rather than protected. A check that cannot observe the real permission system must not report a\n // verdict about it; ACL enforcement is a separate mechanism and not one this function can fake.\n if (process.platform === \"win32\") return;\n\n const dirMode = statSync(dirPath).mode & 0o777;\n if ((dirMode & 0o022) !== 0) {\n throw new CredentialError(\n `${dirPath} is writable by other users (mode ${dirMode.toString(8)}), so the credential file ` +\n `inside it can be replaced. Fix it with: chmod 700 ${dirPath}`,\n );\n }\n const mode = statSync(path).mode & 0o777;\n if ((mode & 0o077) !== 0) {\n throw new CredentialError(\n `${path} is readable by other users (mode ${mode.toString(8)}). ` +\n `A credential file must not be. Fix it with: chmod 600 ${path}`,\n );\n }\n}\n\n/**\n * A `z.union` reports a generic \"Invalid input\" at the root, hiding WHAT is wrong. Pick the sub-schema the\n * file was CLEARLY aiming at (by its `type` discriminant) and surface that schema's specific issue.\n */\nfunction describeUnionError(parsed: unknown, err: unknown, path: string): CredentialError {\n const looksOAuth =\n typeof parsed === \"object\" &&\n parsed !== null &&\n (parsed as { type?: unknown }).type === \"oauth\";\n const specific = looksOAuth ? oauthFileSchema.safeParse(parsed) : apiFileSchema.safeParse(parsed);\n let issue: z.ZodIssue | undefined;\n if (!specific.success) {\n issue = specific.error.issues[0];\n } else if (err instanceof z.ZodError) {\n issue = err.issues[0];\n }\n return new CredentialError(\n `${path}: ${issue?.message ?? String(err)} [${issue?.path.join(\".\") || \"root\"}]`,\n );\n}\n\n/** Parse the raw file into the store union, surfacing the SPECIFIC sub-schema issue (not a generic union error). */\nfunction parseStoredFile(raw: string, path: string): StoredCredential {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // The parser's message embeds a snippet of the INPUT — up to the raw key when a user pastes the bare\n // key instead of JSON. The position is not actionable anyway, so the expected shape is more useful.\n throw new CredentialError(\n `${path} is not valid JSON. Expected: {\"provider\": \"<name>\", \"api_key\": \"...\"}`,\n );\n }\n try {\n return fileSchema.parse(parsed);\n } catch (err) {\n throw describeUnionError(parsed, err, path);\n }\n}\n\n/**\n * Read the credential file. Absent ⇒ `undefined` (the normal case). Present-but-wrong is a typed error\n * naming the file: a malformed credential store must not surface as a raw parse crash. Enforces the\n * 0700 dir / 0600 file mode gates (ported verbatim — a writable dir lets an attacker swap the file for a\n * symlink to their own account).\n */\nexport function readAuthFile(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredCredential | undefined {\n const path = authFilePath(config, env);\n\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw new CredentialError(`cannot read ${path}: ${(err as Error).message}`);\n }\n\n assertSecureModes(credentialHome(config, env), path);\n return parseStoredFile(raw, path);\n}\n\n/**\n * Read the stored OAuth credential (with its refresh token), or `undefined` when the store is absent or\n * holds an api credential. The oauth engine needs the refresh token, which the resolved bearer does not\n * carry. Enforces the same 0600/0700 gates as every other read.\n */\nexport function readStoredOAuth(\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): StoredOAuthCredential | undefined {\n const stored = readAuthFile(config, env);\n return stored !== undefined && stored.type === \"oauth\" ? stored : undefined;\n}\n\n/** Narrows a writable credential to the oauth variant. */\nfunction isOAuthWrite(\n c: { provider: string; apiKey: string } | StoredOAuthCredential,\n): c is StoredOAuthCredential {\n return \"type\" in c && c.type === \"oauth\";\n}\n\n/** Build the on-disk JSON payload for the credential variant, validating non-empty tokens. */\nfunction buildStorePayload(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n): Record<string, unknown> {\n if (isOAuthWrite(cred)) {\n if (cred.access.length === 0 || cred.refresh.length === 0) {\n throw new CredentialError(\n \"refusing to write an oauth credential with an empty access/refresh token\",\n );\n }\n return {\n type: \"oauth\",\n provider: cred.provider,\n access: cred.access,\n refresh: cred.refresh,\n expires: cred.expires,\n ...(cred.account_id !== undefined ? { account_id: cred.account_id } : {}),\n ...(cred.id_token !== undefined ? { id_token: cred.id_token } : {}),\n };\n }\n if (typeof cred.apiKey !== \"string\" || cred.apiKey.length === 0) {\n throw new CredentialError(\"refusing to write an empty API key\");\n }\n return { provider: cred.provider, api_key: cred.apiKey };\n}\n\n/**\n * Persist a credential atomically at mode `0600`. Ported VERBATIM (ADR D3): write to a random-named temp\n * file in the same directory with `wx` (O_EXCL), fsync, close, chmod, then `rename` (atomic on POSIX) —\n * so a crash mid-write leaves whatever was there untouched, and a pre-planted symlink cannot capture the\n * key. The api variant persists the unchanged `{provider, api_key}` (back-compat, no `type` key); the\n * oauth variant persists `{type:'oauth', provider, access, refresh, expires, account_id?, id_token?}`.\n */\nexport function writeCredential(\n cred: { provider: string; apiKey: string } | StoredOAuthCredential,\n config: CredentialStoreConfig,\n env: Record<string, string | undefined> = {},\n): string {\n const payload = buildStorePayload(cred);\n\n const dir = credentialHome(config, env);\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n chmodSync(dir, 0o700); // unconditional: mkdirSync's mode applies only at creation\n\n const path = authFilePath(config, env);\n // RANDOM name + `wx` (O_EXCL): a predictable temp name with a plain write follows a pre-planted SYMLINK,\n // landing the key in an attacker's file while reporting success. O_EXCL refuses any pre-existing file or\n // link; the random suffix also removes the pid collision two containers sharing a bind-mounted home make.\n const tmp = `${path}.tmp-${randomBytes(8).toString(\"hex\")}`;\n try {\n const fd = openSync(tmp, \"wx\", 0o600);\n try {\n writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\\n`);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n chmodSync(tmp, 0o600); // explicit: the mode argument is subject to umask\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // the temp file may not exist; its absence is not a failure of the write\n }\n throw new CredentialError(`cannot write ${path}: ${(err as Error).message}`);\n }\n return path;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/persistence/sqlite-wal.ts","../src/internal/persistence/sqlite-open.ts"],"names":["diag","mkdir","dirname","ConfigurationError","rename"],"mappings":"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","file":"chunk-AT2PESXB.cjs","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 // Reached by `sqlite-vec`'s own `load()`, not by anything in this package — see the member's\n // docblock on `MemoryDb`. `loadSqliteVecExtension` catches this and re-throws it as a\n // ConfigurationError with code `sqlite_vec_unavailable`, so a bare Error never escapes.\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 +0,0 @@
1
- {"version":3,"sources":["../src/internal/runtime/plugin-loader/plugin-bundles.ts","../src/internal/runtime/skills/subagents-loader.ts"],"names":["pluginBundleRoots","readdir","join","projectConfigRoots","ConfigurationError","diag","readWorkspaceDir","path","readFile","parseSimpleYaml"],"mappings":"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","file":"chunk-AUH2EVWY.cjs","sourcesContent":["/**\n * Locating the plugin bundles a project carries.\n *\n * Shared by the skills and subagents loaders, which both need the same answer to \"which folders in\n * this project are plugins\" and would otherwise each grow their own copy of the directory walk.\n *\n * @internal\n */\n\nimport type { Dirent } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pluginBundleRoots } from \"../../persistence/paths.js\";\nimport type { CompatSourceDeclaration } from \"../compat/foreign-config-sources.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(\n cwd: string,\n /** Declared foreign dialects (#524). Empty reads `.theokit/plugins` only. */\n compatSources: readonly CompatSourceDeclaration[] = [],\n): Promise<string[]> {\n const dirs: string[] = [];\n for (const root of pluginBundleRoots(cwd, compatSources)) {\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 type { CompatSourceDeclaration } from \"../compat/foreign-config-sources.js\";\nimport { readWorkspaceDir } from \"../config/workspace-dir.js\";\nimport { type FrontmatterValue, parseSimpleYaml } from \"../context/yaml-frontmatter.js\";\nimport { pluginBundleDirs } from \"../plugin-loader/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 /** Declared foreign dialects (#524). Empty reads `.theokit/` only. */\n compatSources: readonly CompatSourceDeclaration[] = [],\n): Promise<Record<string, AgentDefinition>> {\n const result: Record<string, AgentDefinition> = {};\n if (settingSourcesIncludeProject) {\n const projectAgents = await readProjectSubagents(cwd, compatSources);\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(\n cwd: string,\n compatSources: readonly CompatSourceDeclaration[],\n): Promise<Record<string, AgentDefinition>> {\n const subagents: Record<string, AgentDefinition> = {};\n for (const configRoot of projectConfigRoots(cwd, compatSources, \"subagents\")) {\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, compatSources)) {\n await readSubagentsFrom(join(bundle, \"agents\"), subagents);\n }\n return subagents;\n}\n\n/**\n * Parse an agent file, or return null when it was written for another runtime.\n *\n * ## What this changed, and what it deliberately did not\n *\n * The failure used to take the whole directory, and that was a decision rather than an oversight:\n * \"a file that HAS frontmatter and gets it wrong is a broken agent and still fails loudly, which is\n * what keeps a typo'd `sandbox` from returning as a silent gate through this door. Isolating the\n * failure per file would hand that risk back.\"\n *\n * The risk named there is real and is NOT handed back, because the isolation is narrower than the\n * one that argument refuses. Only `KNOWN_CLAUDE_CODE_FIELDS` takes this door — the set that already\n * encodes \"this key belongs to another runtime and carries no behaviour here\". A misspelling of one\n * of OUR keys carries `subagent_unknown_field` and still propagates, so `sandboxx` remains fatal\n * and cannot return as a silent gate. `a-claude-code-field-names-itself.test.ts` pins both halves.\n *\n * What moved the decision was the cost, measured in a live TUI on 2026-09-15: one ported\n * `.claude/agents/*.md` carrying `memory:` stopped every sibling agent from loading and the turn\n * produced no answer at all — on an agent the task never used. Beside it, on the same prompt and\n * the same project, another runtime answered normally. The diagnosis fix this file shipped tells a\n * user which key is foreign; it does not give them back the turn.\n *\n * The loader already draws exactly this line for a file with no frontmatter, and for the same\n * stated reason: one of them must not stop every agent in the directory from loading.\n */\nfunction parseOrSkipForeignRuntime(\n raw: string,\n filename: string,\n): { name: string; definition: AgentDefinition } | null {\n try {\n return parseSubagentMarkdown(raw, filename);\n } catch (error) {\n if (error instanceof ConfigurationError && error.code === \"subagent_foreign_runtime_field\") {\n diag(`[theokit-sdk] ${filename}: ${error.message} — skipping this agent`);\n return null;\n }\n throw error;\n }\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 = parseOrSkipForeignRuntime(raw, entry.name);\n if (definition === null) continue;\n if (subagents[definition.name] === undefined) {\n // `path` is computed above to read the file and was then dropped. Keeping it is the whole\n // visibility fix (#524): without it a listing cannot say which root an agent came from.\n subagents[definition.name] = { ...definition.definition, source: path };\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 \"memory\",\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 // Carried unjudged — see `AgentDefinition.memory`. Which root a scope names, and whether the\n // name is one at all, is `@theokit/agents`' decision and refusing it twice means two lists.\n const memory = asString(fields.memory);\n if (memory !== undefined) definition.memory = memory;\n\n const name = asString(fields.name) ?? filename.replace(/\\.md$/, \"\");\n return { name, definition };\n}\n\n/**\n * Frontmatter keys that Claude Code documents for a subagent and this runtime does not accept.\n *\n * Not an allow-list — every one of these still fails the load. It exists so the FAILURE can say\n * which kind of unknown it met. A user migrating a `.claude/agents/` tree used to learn one key per\n * round trip: fix `memory`, meet `permissionMode`, fix that, meet `maxTurns` — with nothing saying\n * the set was finite or that the tree was simply written for another runtime.\n *\n * The distinction this file already draws for `INERT_CLAUDE_CODE_FIELDS` is the same one: \"the\n * difference between 'we know this one and it does nothing' and 'we have never heard of this' — two\n * facts a bare allow-everything would collapse into one.\" This is the third fact beside them —\n * \"another runtime's field\" — and it changes only the message, never the verdict.\n */\nconst KNOWN_CLAUDE_CODE_FIELDS = new Set([\n \"disallowedTools\",\n \"permissionMode\",\n \"maxTurns\",\n \"skills\",\n \"background\",\n \"effort\",\n \"isolation\",\n \"initialPrompt\",\n \"hooks\",\n \"experimental\",\n \"mcpServers\",\n]);\n\n/**\n * The typed error for a key we do not accept. Built here rather than inline so `rejectUnknownFields`\n * stays a plain loop: the message has two shapes and the code has two values, and computing all four\n * at the throw site is what pushed that function past the cognitive-complexity gate.\n */\nfunction unknownFieldError(key: string, filename: string): ConfigurationError {\n const foreign = KNOWN_CLAUDE_CODE_FIELDS.has(key);\n const siblings = [...KNOWN_CLAUDE_CODE_FIELDS].filter((f) => f !== key);\n const origin = foreign\n ? ` — \"${key}\" is a Claude Code subagent field that this runtime does not support. ` +\n `The same applies to: ${siblings.join(\", \")}. Removing them one at a time will meet each ` +\n `in turn; the tree is written for another runtime`\n : \"\";\n // The two codes are written as LITERALS, one per branch, rather than as a ternary inside the\n // options object. `tools/generate-error-codes.mjs` walks the source for the literal assigned to\n // `code:`, so a ternary there is not a literal and it extracted NEITHER — measured 2026-09-15,\n // when `quality:docs-errors` went red and the regenerated reference had lost\n // `subagent_unknown_field` without ever gaining `subagent_foreign_runtime_field`. Two real,\n // throwable codes were absent from the published error reference, which is the one place a\n // consumer looks to find out what they can catch.\n if (foreign)\n return new ConfigurationError(\n `Subagent ${filename}: unknown frontmatter field \"${key}\" (accepted: ${[...ACCEPTED_FIELDS].join(\", \")})${origin}`,\n { code: \"subagent_foreign_runtime_field\" },\n );\n return new ConfigurationError(\n `Subagent ${filename}: unknown frontmatter field \"${key}\" (accepted: ${[...ACCEPTED_FIELDS].join(\", \")})${origin}`,\n { code: \"subagent_unknown_field\" },\n );\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)) throw unknownFieldError(key, filename);\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 // An empty/blank effort (`reasoning_effort: \"\"`) names nothing: treated as absent, never as a\n // `{ id: \"thinking\", value: \"\" }` param the provider would drop or reject.\n const rawEffort = asString(fields.reasoning_effort)?.trim();\n const effort = rawEffort === \"\" ? undefined : rawEffort;\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 +0,0 @@
1
- {"version":3,"sources":["../src/internal/task/task-id.ts","../src/internal/task/store.ts"],"names":["InvalidTaskIdError","mkdirSync","join","atomicWriteText","readFile","diag","readdirSync","unlink"],"mappings":"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","file":"chunk-BWYC7RZG.cjs","sourcesContent":["/**\n * Task-id grammar (D368) — runtime, deliberately NOT in `types/`.\n *\n * It lived in `types/task.ts`, which `types/index.ts` re-exports with `export type *`. That star\n * cannot carry a value, so the only reason `isValidTaskId` ever reached a consumer is that the DTS\n * rollup hoists the declaration while the runtime bundle emits nothing — exactly the shape of #279,\n * where the import typechecked and was `undefined` at the call site. `src/index.ts` re-exports both\n * names from here, so the public API is unchanged.\n *\n * @internal\n */\n\n/**\n * Grammar for user-supplied task IDs (D368).\n * `crypto.randomUUID()` outputs do NOT match this (UUIDs have dashes\n * AND uppercase letters in their canonical form on some Node versions),\n * but the registry normalizes auto-generated IDs to lowercase before\n * insertion, so they pass the same regex.\n */\nconst TASK_ID_GRAMMAR = /^[a-z0-9][a-z0-9_-]*$/;\n\n/** Reserved prefixes for adapter-generated IDs (D368, EC-5). */\nconst RESERVED_PREFIXES = [\"wf-\", \"b-\", \"cron-\"] as const;\n\n/**\n * Validates a task ID against the public grammar + reserved prefixes.\n * Throws `InvalidTaskIdError` from `../errors.js` on rejection.\n *\n * Adapter callers (workflow/batch/cron) MUST set `allowReserved: true`\n * to register their own IDs; user-facing surfaces (`Task.submit`,\n * `agent.send({ task: { id } })`) leave it false.\n */\nexport function isValidTaskId(id: string, allowReserved: boolean): boolean {\n if (!TASK_ID_GRAMMAR.test(id)) return false;\n if (allowReserved) return true;\n for (const prefix of RESERVED_PREFIXES) {\n if (id.startsWith(prefix)) return false;\n }\n return true;\n}\n\n/** Re-exported for adapter implementations + tests. */\nexport const TASK_RESERVED_PREFIXES: readonly string[] = RESERVED_PREFIXES;\n","/**\n * `TaskStore` interface + 2 implementations (ADR D364).\n *\n * - `InMemoryTaskStore` — default, transient, single-process.\n * - `JsonFileTaskStore` — opt-in, one JSON file per task under a\n * dedicated dir; single-process invariant (EC-15 documented).\n *\n * Edge cases absorbed:\n * - EC-1: constructor auto-creates dir (mkdirSync recursive idempotent).\n * - EC-2: every method validates the task id against the public\n * grammar (D368) BEFORE doing any path I/O — path-traversal defense.\n * - EC-6: `list()` returns `[]` on ENOENT (fresh install path).\n * - EC-8: `list()` skips `.tmp.*` orphan files left by interrupted\n * atomic writes.\n * - EC-14 (DOCUMENT): `list()` JSDoc documents the 256-row hard cap.\n * It no longer advertises `submittedBefore` as a way to page past it:\n * the cap is applied to the raw directory listing before any filter, so\n * paging beyond 256 files is not reachable through this interface.\n * - EC-15 (DOCUMENT): `JsonFileTaskStore` JSDoc documents the\n * single-process invariant; v0.2 SQLite covers cross-process.\n *\n * @internal\n */\n\nimport { mkdirSync, readdirSync } from \"node:fs\";\nimport { readFile, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { InvalidTaskIdError } from \"../../errors.js\";\nimport type { TaskFilter, TaskHandle, TaskState, TaskStoreOptions } from \"../../types/task.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { atomicWriteText } from \"../persistence/atomic-write.js\";\nimport { isValidTaskId } from \"./task-id.js\";\n\nconst JSON_LOAD_CAP = 256;\nconst DEFAULT_LIST_LIMIT = 100;\n\n/** Storage interface used by `TaskRegistry`. */\nexport interface TaskStore {\n insert(handle: TaskHandle): Promise<void>;\n update(id: string, mutate: (h: TaskHandle) => TaskHandle): Promise<TaskHandle | undefined>;\n get(id: string): Promise<TaskHandle | undefined>;\n /**\n * Returns at most `filter.limit ?? 100` matching handles.\n *\n * `JsonFileTaskStore` returns them newest-first and considers every task in its\n * directory, reading at most 256 files concurrently (#362 — that number bounds\n * I/O, not which tasks are visible). Walk past `limit` by passing the oldest\n * `submittedAt` of a page as the next call's `submittedBefore`; the ordering is\n * what makes that a cursor rather than a re-roll of an arbitrary subset.\n * `InMemoryTaskStore` applies the same filters but does not order its result.\n */\n list(filter: TaskFilter): Promise<TaskHandle[]>;\n delete(id: string): Promise<boolean>;\n /** Removes terminal handles whose terminal-timestamp is older than `epochMs`. */\n evictTerminalOlderThan(epochMs: number): Promise<number>;\n}\n\nfunction assertValidIdForStore(id: string): void {\n if (!isValidTaskId(id, /* allowReserved */ true)) {\n throw new InvalidTaskIdError(`store rejects invalid task id: ${id}`, id);\n }\n}\n\nfunction terminalTimestamp(h: TaskHandle): number | undefined {\n if (h.state === \"finished\") return h.finishedAt;\n if (h.state === \"error\") return h.erroredAt;\n if (h.state === \"cancelled\") return h.cancelledAt;\n return undefined;\n}\n\nfunction isTerminal(state: TaskState): boolean {\n return state === \"finished\" || state === \"error\" || state === \"cancelled\";\n}\n\nfunction matchesState(h: TaskHandle, filter: TaskFilter): boolean {\n if (filter.state === undefined) return true;\n const states = Array.isArray(filter.state) ? filter.state : [filter.state];\n return states.includes(h.state);\n}\nfunction matchesKind(h: TaskHandle, filter: TaskFilter): boolean {\n if (filter.kind === undefined) return true;\n const kinds = Array.isArray(filter.kind) ? filter.kind : [filter.kind];\n return kinds.includes(h.kind);\n}\nfunction matchesTime(h: TaskHandle, filter: TaskFilter): boolean {\n if (filter.submittedAfter !== undefined && h.submittedAt <= filter.submittedAfter) return false;\n if (filter.submittedBefore !== undefined && h.submittedAt >= filter.submittedBefore) return false;\n return true;\n}\nfunction matchesFilter(h: TaskHandle, filter: TaskFilter): boolean {\n return matchesState(h, filter) && matchesKind(h, filter) && matchesTime(h, filter);\n}\n\n/** The states `evictTerminalOlderThan` considers terminal. */\nconst TERMINAL_STATES: readonly TaskState[] = [\"finished\", \"error\", \"cancelled\"];\n\n/**\n * Where `submittedAt` belongs in a newest-first list — the first index whose entry is older.\n *\n * Linear rather than binary: the list is bounded by the caller's `limit` (100 by default) and the\n * scan runs once per MATCHING handle, so the comparison count is dwarfed by the file read that\n * produced the handle. A binary search here would trade a real cost for an imagined one.\n */\nfunction insertionIndex(newestFirst: readonly TaskHandle[], submittedAt: number): number {\n for (let i = 0; i < newestFirst.length; i++) {\n const entry = newestFirst[i];\n if (entry !== undefined && entry.submittedAt < submittedAt) return i;\n }\n return newestFirst.length;\n}\n\nfunction applyFilter(values: Iterable<TaskHandle>, filter: TaskFilter): TaskHandle[] {\n const limit = filter.limit ?? DEFAULT_LIST_LIMIT;\n const out: TaskHandle[] = [];\n for (const h of values) {\n if (matchesFilter(h, filter)) {\n out.push(h);\n if (out.length >= limit) break;\n }\n }\n return out;\n}\n\n/* ─── InMemory ─── */\n\n/**\n * Default `TaskStore` — a plain `Map` living in the current process.\n *\n * Nothing reaches disk and nothing survives the process, so a task recorded here\n * is invisible to a reader in another process (`theokit tasks`). Select it with\n * `getTaskStoreFor({ backend: \"memory\" })`.\n *\n * How it fails: every id-taking method validates against the task-id grammar\n * (`^[a-z0-9][a-z0-9_-]*$`; reserved `wf-`/`b-`/`cron-` prefixes are permitted\n * here) and throws `InvalidTaskIdError` before touching the map. A missing id is\n * reported by returning `undefined` (`get`, `update`) or `false` (`delete`), never\n * by throwing.\n *\n * Traps:\n * - `insert()` is a `Map.set`: an existing id is overwritten silently, not\n * rejected.\n * - `list()` walks in INSERTION order and stops as soon as `filter.limit ?? 100`\n * matches are collected. It never sorts, so the limit truncates an\n * oldest-first scan rather than returning the most recent tasks.\n * - Nothing evicts on its own; terminal handles accumulate until a caller invokes\n * `evictTerminalOlderThan`.\n */\nexport class InMemoryTaskStore implements TaskStore {\n private readonly map = new Map<string, TaskHandle>();\n\n async insert(handle: TaskHandle): Promise<void> {\n assertValidIdForStore(handle.id);\n this.map.set(handle.id, handle);\n }\n\n async update(id: string, mutate: (h: TaskHandle) => TaskHandle): Promise<TaskHandle | undefined> {\n assertValidIdForStore(id);\n const existing = this.map.get(id);\n if (existing === undefined) return undefined;\n const next = mutate(existing);\n this.map.set(id, next);\n return next;\n }\n\n async get(id: string): Promise<TaskHandle | undefined> {\n assertValidIdForStore(id);\n return this.map.get(id);\n }\n\n async list(filter: TaskFilter): Promise<TaskHandle[]> {\n return applyFilter(this.map.values(), filter);\n }\n\n async delete(id: string): Promise<boolean> {\n assertValidIdForStore(id);\n return this.map.delete(id);\n }\n\n async evictTerminalOlderThan(epochMs: number): Promise<number> {\n let count = 0;\n for (const [id, h] of this.map.entries()) {\n if (!isTerminal(h.state)) continue;\n const ts = terminalTimestamp(h);\n if (ts !== undefined && ts < epochMs) {\n this.map.delete(id);\n count++;\n }\n }\n return count;\n }\n}\n\n/* ─── JsonFile (opt-in) ───\n *\n * IMPORTANT (EC-15): `JsonFileTaskStore` is **single-process**.\n * Concurrent writers from multiple Node processes against the same\n * directory may corrupt entries (atomic-write protects per-file, but\n * the `list()` scan + `update()` read-modify-write cycle is not\n * serialised across processes). Use only when the `TaskRegistry`\n * runs in exactly one process. v0.2 will add a SQLite backend with\n * the same interface for cross-process scenarios (D364 + D61).\n */\n/**\n * Opt-in `TaskStore` that keeps one JSON file per task under `dir`, so another\n * process can read the registry off disk.\n *\n * const store = new JsonFileTaskStore(\"/var/lib/theokit/tasks\");\n *\n * Two calls are synchronous, and both are deliberate: the constructor creates `dir`\n * recursively (`mkdirSync`), and `list()` scans it with `readdirSync` before awaiting\n * anything. Every other operation is async — `get` uses `readFile`, `delete` uses\n * `unlink`, and every write goes through an atomic temp-file-plus-rename.\n *\n * SINGLE-PROCESS ONLY — see the note above. Per-file atomicity does not make\n * `update()` safe: it is a read-modify-write, so two writers that both `get`\n * before either writes lose one of the two mutations. That is true within one\n * process as well as across processes.\n *\n * How it fails:\n * - An invalid id throws `InvalidTaskIdError` BEFORE any path is constructed.\n * That ordering is the path-traversal defence, and it is why ids are validated\n * rather than escaped.\n * - A missing task is `undefined` from `get` and `false` from `delete`.\n * - A file that exists but does not parse is NOT surfaced as an error: `get`\n * writes to the diagnostics channel and returns `undefined`, so a corrupted\n * task also silently vanishes from `list()`.\n * - `list()` returns `[]` when `dir` does not exist; any other `readdir` failure\n * (for example a permission error) throws.\n *\n * Traps:\n * - `list()` reads every task file in the directory (256 at a time) to apply the\n * filter, because `state`, `kind` and `submittedAt` live inside the files. On a\n * large directory that is a lot of I/O for one call; the memory it holds is\n * bounded by `limit`, the time is not.\n * - `list()` is `async`, but its directory scan is not: `readdirSync` blocks the event\n * loop for the whole listing before the first `await`. Only the per-file reads that\n * follow it are concurrent.\n * - Files whose name contains `.tmp` are skipped as orphans of an interrupted\n * write, and nothing ever removes them.\n */\nexport class JsonFileTaskStore implements TaskStore {\n constructor(private readonly dir: string) {\n // EC-1: idempotent mkdir; ignore EEXIST.\n try {\n mkdirSync(dir, { recursive: true });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") throw err;\n }\n }\n\n private filePath(id: string): string {\n return join(this.dir, `${id}.json`);\n }\n\n async insert(handle: TaskHandle): Promise<void> {\n assertValidIdForStore(handle.id);\n await atomicWriteText(this.filePath(handle.id), JSON.stringify(handle));\n }\n\n async update(id: string, mutate: (h: TaskHandle) => TaskHandle): Promise<TaskHandle | undefined> {\n assertValidIdForStore(id);\n const existing = await this.get(id);\n if (existing === undefined) return undefined;\n const next = mutate(existing);\n await atomicWriteText(this.filePath(id), JSON.stringify(next));\n return next;\n }\n\n async get(id: string): Promise<TaskHandle | undefined> {\n assertValidIdForStore(id);\n try {\n const raw = await readFile(this.filePath(id), \"utf8\");\n return JSON.parse(raw) as TaskHandle;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") return undefined;\n // Corrupt JSON or other I/O error — log + degrade gracefully (D50/EC-7 cache pattern).\n diag(`[task-store] failed to read ${id}: ${(err as Error).message}\\n`);\n return undefined;\n }\n }\n\n /**\n * Task ids backed by a file in `dir`, in readdir order.\n *\n * EC-8: orphan `.tmp` files left by an interrupted atomic write are skipped, as is any name\n * outside the id grammar. EC-6: a missing directory lists as empty; any other `readdir` failure\n * (a permission error, say) throws rather than being reported as \"no tasks\".\n */\n private candidateIds(): string[] {\n let entries: string[];\n try {\n entries = readdirSync(this.dir);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return []; // EC-6\n throw err;\n }\n return entries\n .filter((name) => name.endsWith(\".json\") && !name.includes(\".tmp\"))\n .map((name) => name.slice(0, -\".json\".length))\n .filter((id) => isValidTaskId(id, true));\n }\n\n /**\n * Read every task in `ids`, handing each loaded handle to `visit`, at most `JSON_LOAD_CAP` file\n * reads in flight.\n *\n * #362 — the cap used to be applied to the directory listing, which made it a bound on WHICH\n * tasks were visible rather than on how much I/O ran at once. Every filter then ran on that\n * arbitrary readdir-ordered prefix. As a concurrency bound it does the job it was named for\n * without deciding what the caller gets to see; the caller's own bound on memory is whatever\n * `visit` chooses to retain.\n */\n private async forEachHandle(\n ids: readonly string[],\n visit: (handle: TaskHandle) => void | Promise<void>,\n ): Promise<void> {\n for (let start = 0; start < ids.length; start += JSON_LOAD_CAP) {\n const batch = ids.slice(start, start + JSON_LOAD_CAP);\n const loaded = await Promise.all(batch.map(async (id) => this.get(id)));\n for (const handle of loaded) {\n if (handle !== undefined) await visit(handle);\n }\n }\n }\n\n async list(filter: TaskFilter): Promise<TaskHandle[]> {\n const limit = filter.limit ?? DEFAULT_LIST_LIMIT;\n // Newest-first, keeping at most `limit` handles in memory regardless of how many match. The\n // order is what makes `submittedBefore` a real cursor: with the previous readdir order, a page\n // was an arbitrary subset, so a caller walking the timeline skipped every task that happened\n // to fall outside its window and could never come back for them.\n const newest: TaskHandle[] = [];\n await this.forEachHandle(this.candidateIds(), (handle) => {\n if (!matchesFilter(handle, filter)) return;\n const at = insertionIndex(newest, handle.submittedAt);\n if (at >= limit) return; // older than everything already held, and the page is full\n newest.splice(at, 0, handle);\n if (newest.length > limit) newest.pop();\n });\n return newest;\n }\n\n async delete(id: string): Promise<boolean> {\n assertValidIdForStore(id);\n try {\n await unlink(this.filePath(id));\n return true;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw err;\n }\n }\n\n async evictTerminalOlderThan(epochMs: number): Promise<number> {\n // #362 — eviction scans the directory itself rather than borrowing `list()`. Sharing that path\n // made one call incomplete twice over: it saw only a 256-file window, and it wanted the OLDEST\n // handles while `list()` is ordered newest-first — so on a large directory it could delete\n // nothing while thousands of eligible handles sat just outside the page. Sweeping every\n // candidate is what lets one call mean \"everything eligible is gone\".\n let count = 0;\n await this.forEachHandle(this.candidateIds(), async (handle) => {\n if (!TERMINAL_STATES.includes(handle.state)) return;\n const ts = terminalTimestamp(handle);\n if (ts === undefined || ts >= epochMs) return;\n if (await this.delete(handle.id)) count++;\n });\n return count;\n }\n}\n\n/** Factory used by `TaskRegistry.configure` (D364). */\nexport function getTaskStoreFor(options: TaskStoreOptions): TaskStore {\n if (options.backend === \"memory\") return new InMemoryTaskStore();\n return new JsonFileTaskStore(options.dir);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/memory/dreaming/diary.ts","../src/internal/memory/dreaming/phases.ts","../src/internal/memory/dreaming/run.ts","../src/internal/memory/migrate-sqlite-to-lance.ts"],"names":["join","readFile","replaceFileAtomic","createHash","kept","withCwdMutex","resolveMemoryRoot","readFactsFromMarkdown","diag","mkdir","defaultIndexPath","existsSync","openMemoryDb","ConfigurationError","lanceStoragePath","redactSecrets","rmSync","mkdirSync","LanceIndex","renameSync"],"mappings":"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","file":"chunk-CHKV2L2Y.cjs","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { replaceFileAtomic } from \"../../persistence/atomic-write.js\";\nimport type { MemoryRoot } from \"../storage/memory-root.js\";\n\n/**\n * Dream-diary append (ADR D7).\n *\n * Diary lives at `.theokit/memory/dream-diary.md` and grows with one entry\n * per sweep. Each entry is content-hashed so the same input produces the\n * same entry — idempotency contract.\n *\n * Writes go through `replaceFileAtomic` (EC-3 of edge-case review) so a\n * crash mid-write can never leave a half-written diary.\n *\n * Shared with `@theokit/sdk-memory`; see the memory-store barrel.\n */\n\nexport interface DiaryEntry {\n timestampMs: number;\n factsBefore: number;\n factsAfter: number;\n duplicatesRemoved: number;\n clustersCreated: number;\n notesWritten: number;\n}\n\n/** `<memory root>/dream-diary.md`. Takes the RESOLVED ROOT — see `storage/memory-root.ts` (#463). */\nexport function diaryPath(root: MemoryRoot): string {\n return join(root, \"dream-diary.md\");\n}\n\n/**\n * One diary entry as the markdown that gets appended: a timestamp heading, the short entry hash,\n * and the counts the sweep produced. The hash is what makes a re-run recognisable as the same\n * sweep rather than a new one.\n */\nexport function renderDiaryEntry(entry: DiaryEntry): string {\n const stamp = new Date(entry.timestampMs).toISOString();\n const hash = entryHash(entry).slice(0, 8);\n return [\n `## ${stamp}`,\n \"\",\n `- entry-hash: ${hash}`,\n `- facts before: ${entry.factsBefore}`,\n `- facts after: ${entry.factsAfter}`,\n `- duplicates removed: ${entry.duplicatesRemoved}`,\n `- clusters created: ${entry.clustersCreated}`,\n `- notes written: ${entry.notesWritten}`,\n \"\",\n ].join(\"\\n\");\n}\n\n/**\n * Append one sweep's entry to `<memory root>/dream-diary.md`, creating the file with its header\n * when this is the first sweep. The diary is a human-readable record of what dreaming changed —\n * consolidations are otherwise invisible, because they alter the notes rather than announce\n * themselves.\n */\nexport async function appendDiaryEntry(root: MemoryRoot, entry: DiaryEntry): Promise<void> {\n const path = diaryPath(root);\n let raw = \"\";\n try {\n raw = await readFile(path, \"utf8\");\n } catch {\n raw = \"# Dream Diary\\n\\n\";\n }\n const next = `${raw.endsWith(\"\\n\") ? raw : `${raw}\\n`}${renderDiaryEntry(entry)}`;\n await replaceFileAtomic(path, next);\n}\n\n/**\n * A stable hash of one entry's counts, so two sweeps that did the same work read as the same work.\n * Rendered truncated in the entry; the full value is what callers compare.\n */\nexport function entryHash(entry: DiaryEntry): string {\n return createHash(\"sha256\")\n .update(\n [\n entry.factsBefore,\n entry.factsAfter,\n entry.duplicatesRemoved,\n entry.clustersCreated,\n entry.notesWritten,\n ].join(\"|\"),\n )\n .digest(\"hex\");\n}\n","import type { EmbeddingRuntime } from \"../embedding-adapter.js\";\nimport type { MemoryFact, MemoryKind } from \"../types.js\";\n\n/**\n * Dreaming/REM phase logic.\n *\n * Three phases:\n * - **light** — drop near-duplicate facts (cosine similarity > 0.95).\n * - **REM** — cluster thematically related facts (cosine ≥ 0.75).\n * - **deep** — pick a representative bullet per cluster (longest text\n * wins) and emit consolidated markdown notes.\n */\n\nexport interface DedupResult {\n kept: MemoryFact[];\n duplicatesRemoved: number;\n}\n\n/** A group of semantically similar facts, with the text chosen to represent them. */\nexport interface Cluster {\n representativeText: string;\n members: ReadonlyArray<MemoryFact>;\n}\n\n/** What clustering produced: the clusters and how many facts the per-sweep cap left out. */\nexport interface ClusterResult {\n clusters: Cluster[];\n /** How many input facts past the per-sweep cap were not clustered; 0 when none were. */\n factsLeftOut: number;\n}\n\nconst DEFAULT_DEDUP_THRESHOLD = 0.95;\nconst DEFAULT_CLUSTER_THRESHOLD = 0.75;\n\n/**\n * Kinds a sweep may consolidate. ADR-14 partitions the vocabulary into three buckets and only\n * this one is a merge candidate; the rest are protected for a reason that survives the sweep\n * being non-destructive.\n *\n * `user`, `feedback` and `reference` are ATOMIC: there is nothing to merge and the loss is\n * irreversible. Two corrections a user gave on different days can read alike and are not the\n * same correction. An untyped fact is protected too — a kind that nobody declared is not a\n * licence to treat it as consolidatable.\n *\n * Why this matters even though nothing is deleted: dedup drops the near-duplicate from the\n * CLUSTERING INPUT, and the cluster's representative is what the search index returns. The\n * source file survives; the artefact the agent reads does not. That is ADR-14's third rule —\n * the invariant is about what the agent reads, not what survives on disk.\n */\n// Typed against `MemoryKind` rather than `string`, so the compiler checks these against the vocabulary\n// they mirror. They were `Set<string>` and CONSOLIDATABLE_KINDS held \"session\" — not a member of\n// `MemoryKind`, and rejected by `markdown-store.assertWritable` before any fact is written, so no\n// fact reaching this policy could ever carry it. The arm read as though sessions were consolidatable\n// while no session could exist. Adding a member to either set is now a type error unless `MemoryKind`\n// gains it deliberately.\nconst CONSOLIDATABLE_KINDS: ReadonlySet<MemoryKind> = new Set([\"project\"]);\nconst ATOMIC_KINDS: ReadonlySet<MemoryKind> = new Set([\"user\", \"feedback\", \"reference\"]);\n\n/**\n * Three levels, graded by how much the store knows about the entry. The middle one exists\n * because the first draft of this filter did not have it and broke the common case.\n *\n * - ATOMIC (`user`, `feedback`, `reference`) — never deduplicated. Two corrections given on\n * different days can read alike and are not the same correction.\n * - CONSOLIDATABLE (`project`, `session`) — near-duplicate dedup at the similarity threshold.\n * Overlapping project facts are exactly what a sweep is for.\n * - UNTYPED — EXACT duplicates only. A hand-written bullet under `## Facts` carries no kind,\n * and the store's own header invites editing those by hand, so untyped is the common case\n * rather than an edge one. Treating it as atomic would disable the sweep for most stores;\n * treating it as consolidatable would let a near-duplicate of an untyped correction be\n * dropped. Exact-match is the only claim the store can make without inferring a kind, which\n * is the rule this codebase already applies one field over.\n */\ntype DedupPolicy = \"never\" | \"exact\" | \"similar\";\n\nfunction dedupPolicy(fact: MemoryFact): DedupPolicy {\n if (fact.kind === undefined) return \"exact\";\n if (ATOMIC_KINDS.has(fact.kind)) return \"never\";\n return CONSOLIDATABLE_KINDS.has(fact.kind) ? \"similar\" : \"never\";\n}\n\n/** Whitespace and case collapsed; nothing else. Not a similarity measure — an identity one. */\nfunction normalizeForExactMatch(text: string): string {\n return text\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, \" \")\n .replace(/[.!?]+$/, \"\");\n}\n\n/**\n * Light phase — drop facts whose embedding is too similar to one already kept.\n *\n * Protected kinds bypass deduplication entirely and are returned untouched, so a sweep can\n * never conflate two of them into one representative.\n *\n * \"Drop\" here means DROPPED FROM THE RETURNED LIST. Nothing on disk is deleted, by any phase of\n * this sweep, today.\n *\n * BEFORE YOU ADD PRUNING HERE, READ THIS. The security contract for this store requires a backup\n * to precede any destructive operation (SOP-06-05 step 7). That requirement is currently LATENT\n * — not satisfied, not waived — precisely because the sweep only ever adds notes and filters a\n * list. There is no backup implementation in this package, and an audit that looked for one\n * recorded its absence as having no present consequence.\n *\n * The first commit that makes this sweep delete a file from disk is the commit that makes the\n * gap real, and it is also the commit whose author will have no reason to know this line exists.\n * That is why the trigger is written beside the code that would trip it rather than in the audit\n * that found it: a gap recorded in a reviewer's file reappears as a surprise; a gap recorded\n * here stops the person adding pruning.\n */\nexport async function lightPhase(\n facts: ReadonlyArray<MemoryFact>,\n embedding: EmbeddingRuntime,\n threshold: number = DEFAULT_DEDUP_THRESHOLD,\n): Promise<DedupResult> {\n if (facts.length <= 1) return { kept: [...facts], duplicatesRemoved: 0 };\n const never = facts.filter((f) => dedupPolicy(f) === \"never\");\n const exact = facts.filter((f) => dedupPolicy(f) === \"exact\");\n const similar = facts.filter((f) => dedupPolicy(f) === \"similar\");\n\n // Exact pass: identity, not similarity. No embedding call, no threshold, no judgement.\n const seen = new Set<string>();\n const exactKept: MemoryFact[] = [];\n let removed = 0;\n for (const f of exact) {\n const key = normalizeForExactMatch(f.text);\n if (seen.has(key)) {\n removed += 1;\n continue;\n }\n seen.add(key);\n exactKept.push(f);\n }\n\n const sim =\n similar.length > 1\n ? await dedupCandidates(similar, embedding, threshold)\n : { kept: [...similar], duplicatesRemoved: 0 };\n\n // Protected facts keep their original relative position at the front: they were never in\n // the running, and putting them back through the sort would imply they had been judged.\n return {\n kept: [...never, ...exactKept, ...sim.kept],\n duplicatesRemoved: removed + sim.duplicatesRemoved,\n };\n}\n\nasync function dedupCandidates(\n facts: ReadonlyArray<MemoryFact>,\n embedding: EmbeddingRuntime,\n threshold: number,\n): Promise<DedupResult> {\n if (facts.length <= 1) return { kept: [...facts], duplicatesRemoved: 0 };\n const vectors = await embedding.embed(facts.map((f) => f.text));\n const keptIdx: number[] = [];\n const keptVecs: number[][] = [];\n for (let i = 0; i < facts.length; i++) {\n const vec = vectors[i] ?? [];\n const isDup = keptVecs.some((kept) => cosineSimilarity(vec, kept) >= threshold);\n if (isDup) continue;\n keptIdx.push(i);\n keptVecs.push(vec);\n }\n const kept = keptIdx.map((i) => facts[i] as MemoryFact);\n return { kept, duplicatesRemoved: facts.length - kept.length };\n}\n\n// T4.6 — cap facts per sweep to prevent O(N²) blowup. 500 facts →\n// 125K comparisons (acceptable). 5000 facts → 12.5M (unacceptable).\n// When facts exceed the cap, a deterministic subsample is taken so the\n// sweep is bounded. The remaining facts are carried to the next sweep.\nconst DEFAULT_MAX_FACTS_PER_SWEEP = 500;\n\n/** REM phase — single-link agglomerative clustering by cosine similarity. */\nexport async function remPhase(\n facts: ReadonlyArray<MemoryFact>,\n embedding: EmbeddingRuntime,\n threshold: number = DEFAULT_CLUSTER_THRESHOLD,\n maxFactsPerSweep: number = DEFAULT_MAX_FACTS_PER_SWEEP,\n): Promise<ClusterResult> {\n // KNOWN GAP, deliberately not closed here. Protected kinds are excluded from DEDUP — a\n // near-duplicate correction is never dropped — but they still reach CLUSTERING, and a cluster\n // carries one representative into the consolidated note.\n //\n // Filtering them out here too was tried and reverted: untyped is the common case (hand-written\n // bullets carry no kind), so excluding it disables consolidation for most stores, and it broke\n // three existing golden tests. The damage is also smaller than in the dedup case — the source\n // files survive and remain readable, so what a cluster costs is nuance in an ADDITIONAL\n // artefact rather than a lost entry.\n //\n // It becomes real damage only if recall serves notes INSTEAD of sources. That depends on what\n // the index covers, which is not settled here. Recorded rather than silently accepted.\n if (facts.length === 0) return { clusters: [], factsLeftOut: 0 };\n // T4.6 — cap: subsample when facts exceed budget. Deterministic\n // sort by text hash so the same input always picks the same subset.\n const capped = facts.length > maxFactsPerSweep ? facts.slice(0, maxFactsPerSweep) : facts;\n const vectors = await embedding.embed(capped.map((f) => f.text));\n const clusterOfIdx = unionFindByPairs(vectors, threshold);\n const groups = bucketFactsByClusterRoot(capped, clusterOfIdx);\n return {\n clusters: [...groups.values()].map(buildClusterFromMembers),\n factsLeftOut: facts.length - capped.length,\n };\n}\n\nfunction unionFindByPairs(\n vectors: ReadonlyArray<ReadonlyArray<number>>,\n threshold: number,\n): number[] {\n const clusterOfIdx = vectors.map((_, i) => i);\n for (let i = 0; i < vectors.length; i++) {\n for (let j = i + 1; j < vectors.length; j++) {\n if (cosineSimilarity(vectors[i] ?? [], vectors[j] ?? []) >= threshold) {\n unifyClusters(clusterOfIdx, i, j);\n }\n }\n }\n return clusterOfIdx;\n}\n\nfunction bucketFactsByClusterRoot(\n facts: ReadonlyArray<MemoryFact>,\n clusterOfIdx: number[],\n): Map<number, MemoryFact[]> {\n const groups = new Map<number, MemoryFact[]>();\n for (let i = 0; i < facts.length; i++) {\n const root = findRoot(clusterOfIdx, i);\n const list = groups.get(root) ?? [];\n list.push(facts[i] as MemoryFact);\n groups.set(root, list);\n }\n return groups;\n}\n\nfunction buildClusterFromMembers(members: ReadonlyArray<MemoryFact>): Cluster {\n const sorted = [...members].sort((a, b) => b.text.length - a.text.length);\n return { representativeText: sorted[0]?.text ?? \"\", members };\n}\n\n/** Deep phase — render consolidated markdown for the dreamed note. */\nexport function deepPhase(clusters: ReadonlyArray<Cluster>, timestampMs: number): string {\n if (clusters.length === 0) return \"\";\n const isoStamp = new Date(timestampMs).toISOString();\n const lines: string[] = [`# Dreamed ${isoStamp}`, \"\"];\n for (let i = 0; i < clusters.length; i++) {\n const c = clusters[i];\n if (c === undefined) continue;\n lines.push(`## Cluster ${i + 1}: ${c.representativeText}`);\n lines.push(\"\");\n for (const member of c.members) lines.push(`- ${member.text}`);\n lines.push(\"\");\n }\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction cosineSimilarity(a: ReadonlyArray<number>, b: ReadonlyArray<number>): number {\n if (a.length === 0 || b.length === 0 || a.length !== b.length) return 0;\n let dot = 0;\n let aNorm = 0;\n let bNorm = 0;\n for (let i = 0; i < a.length; i++) {\n const ai = a[i] ?? 0;\n const bi = b[i] ?? 0;\n dot += ai * bi;\n aNorm += ai * ai;\n bNorm += bi * bi;\n }\n const denom = Math.sqrt(aNorm) * Math.sqrt(bNorm);\n return denom === 0 ? 0 : dot / denom;\n}\n\nfunction findRoot(parents: number[], i: number): number {\n let root = i;\n while (parents[root] !== root) {\n const next = parents[root] ?? root;\n if (next === root) break;\n root = next;\n }\n parents[i] = root;\n return root;\n}\n\nfunction unifyClusters(parents: number[], a: number, b: number): void {\n const rootA = findRoot(parents, a);\n const rootB = findRoot(parents, b);\n if (rootA !== rootB) parents[rootB] = rootA;\n}\n","import { mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { diag } from \"../../diagnostics.js\";\nimport { replaceFileAtomic } from \"../../persistence/atomic-write.js\";\nimport { withCwdMutex } from \"../../persistence/cwd-mutex.js\";\nimport type { EmbeddingRuntime } from \"../embedding-adapter.js\";\nimport { readFactsFromMarkdown } from \"../storage/markdown-store.js\";\nimport { type MemoryRoot, resolveMemoryRoot } from \"../storage/memory-root.js\";\nimport { appendDiaryEntry } from \"./diary.js\";\nimport { deepPhase, lightPhase, remPhase } from \"./phases.js\";\n\n/**\n * Dreaming sweep orchestrator (ADR D7 of memory-system-peer-project-parity).\n *\n * Phases:\n * 1. **light** — drop near-duplicate facts via cosine similarity.\n * 2. **REM** — cluster thematically related facts.\n * 3. **deep** — write a `notes/dreamed-<ts>.md` per sweep with consolidated\n * clusters; append a diary entry.\n *\n * All file writes go through `replaceFileAtomic` (EC-3) and the entire sweep\n * holds the per-cwd mutex so a `Remember:` append can't race it.\n */\n\nexport interface DreamingOptions {\n cwd: string;\n /**\n * The memory root to sweep. Defaults to the project store — right for a caller with no\n * `memory.directory`, and wrong for one that has it, which is why it is passable (#463).\n */\n memoryRoot?: MemoryRoot;\n embedding: EmbeddingRuntime;\n dedupThreshold?: number;\n clusterThreshold?: number;\n /** Test hook — fixed timestamp for the run. */\n now?: () => number;\n}\n\n/** Outcome of one dreaming sweep: counts before and after, and the note written. */\nexport interface DreamingResult {\n status: \"ok\" | \"skipped\" | \"error\";\n factsBefore: number;\n factsAfter: number;\n duplicatesRemoved: number;\n clustersCreated: number;\n notesWritten: number;\n diaryEntryHash: string | undefined;\n /**\n * Deduplicated facts past the per-sweep cap that were not clustered. Set on `\"ok\"`, 0 on\n * `\"skipped\"`, and absent on `\"error\"`, where the sweep cannot say how many it left out.\n */\n factsLeftOut?: number;\n}\n\n/** Run one dreaming sweep (dedupe, cluster, write a consolidated note), serialised per `cwd`. */\nexport function runDreamingSweep(options: DreamingOptions): Promise<DreamingResult> {\n return withCwdMutex(`dream:${options.cwd}`, () => runInner(options));\n}\n\nasync function runInner(options: DreamingOptions): Promise<DreamingResult> {\n const now = options.now ?? Date.now;\n const timestampMs = now();\n try {\n const root = options.memoryRoot ?? resolveMemoryRoot(options.cwd);\n const facts = await readFactsFromMarkdown(\n options.cwd,\n options.memoryRoot ? { directory: options.memoryRoot } : undefined,\n );\n if (facts.length === 0) {\n return emptyResult(\"skipped\");\n }\n const dedup = await lightPhase(facts, options.embedding, options.dedupThreshold);\n const rem = await remPhase(dedup.kept, options.embedding, options.clusterThreshold);\n const notesWritten = await writeConsolidatedNotes(root, rem.clusters, timestampMs);\n const result: DreamingResult = {\n status: \"ok\",\n factsBefore: facts.length,\n factsAfter: dedup.kept.length,\n duplicatesRemoved: dedup.duplicatesRemoved,\n clustersCreated: rem.clusters.length,\n notesWritten,\n diaryEntryHash: undefined,\n factsLeftOut: rem.factsLeftOut,\n };\n await appendDiaryEntry(root, {\n timestampMs,\n factsBefore: result.factsBefore,\n factsAfter: result.factsAfter,\n duplicatesRemoved: result.duplicatesRemoved,\n clustersCreated: result.clustersCreated,\n notesWritten: result.notesWritten,\n });\n return result;\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : String(cause);\n diag(`[theokit-sdk] dreaming sweep failed: ${message}\\n`);\n return emptyResult(\"error\");\n }\n}\n\nasync function writeConsolidatedNotes(\n root: MemoryRoot,\n clusters: ReadonlyArray<{ representativeText: string; members: ReadonlyArray<{ text: string }> }>,\n timestampMs: number,\n): Promise<number> {\n if (clusters.length === 0) return 0;\n const notesDir = join(root, \"notes\");\n await mkdir(notesDir, { recursive: true });\n const isoSlug = new Date(timestampMs).toISOString().replace(/[^\\dT]/g, \"-\");\n const file = join(notesDir, `dreamed-${isoSlug}.md`);\n const body = deepPhase(clusters, timestampMs);\n await replaceFileAtomic(file, body);\n return 1;\n}\n\nfunction emptyResult(status: \"skipped\" | \"error\"): DreamingResult {\n const result: DreamingResult = {\n status,\n factsBefore: 0,\n factsAfter: 0,\n duplicatesRemoved: 0,\n clustersCreated: 0,\n notesWritten: 0,\n diaryEntryHash: undefined,\n };\n // An empty store left nothing out; a failed sweep cannot say, so it reports no count.\n return status === \"skipped\" ? { ...result, factsLeftOut: 0 } : result;\n}\n","import { existsSync, mkdirSync, renameSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { ConfigurationError } from \"../../errors.js\";\nimport { redactSecrets } from \"../security/index.js\";\nimport { defaultIndexPath, openMemoryDb } from \"./index-db.js\";\nimport { LanceIndex, lanceStoragePath } from \"./lance-index.js\";\nimport { type MemoryRoot, resolveMemoryRoot } from \"./storage/memory-root.js\";\n\n/**\n * Migrate Memory.index from SQLite to LanceDB (ADR D44).\n *\n * EC-3 MUST FIX: validation uses NFC unicode normalization on both sides.\n *\n * Shared with `@theokit/sdk-memory` through the memory-store barrel (#463).\n */\n\nexport interface MigrateOptions {\n cwd: string;\n /**\n * Absolute path (or `~/`-prefixed) of the memory root to migrate, when the agent that wrote it\n * set `memory.directory`. Defaults to `<cwd>/.theokit/memory` (#463).\n */\n directory?: string;\n dryRun?: boolean;\n batchSize?: number;\n /** Inject for tests; defaults to console.log. */\n logger?: (msg: string) => void;\n}\n\nexport interface MigrateResult {\n countSqlite: number;\n countLance: number;\n /** Set when validation succeeded (or dryRun); false on validation failure. */\n validated: boolean;\n /** Per-fact compare results (size = sample count, up to 10). */\n sampleComparisons: ReadonlyArray<{ id: string; match: boolean }>;\n /** Lance storage location (final, after migration). */\n lancePath: string;\n /** Was the migration committed (false for dry-run). */\n committed: boolean;\n}\n\n/**\n * One row of the SQLite memory index, as the Lance migration reads it: the chunk plus the tenant\n * columns the target table needs. Shared with `@theokit/sdk-memory`, which migrates the same table.\n */\nexport interface SqliteFactRow {\n id: string;\n path: string;\n source: \"memory\" | \"sessions\" | \"wiki\";\n start_line: number;\n end_line: number;\n text: string;\n namespace?: string | null;\n scope?: string | null;\n user_id?: string | null;\n}\n\n/**\n * Read all facts from the SQLite memory index. Returns empty array if the\n * SQLite db file does not exist (workspace never used Memory).\n *\n * Shared with `@theokit/sdk-memory` through the memory-store barrel, so it carries no visibility\n * tag — naming that tag in this block would delete the function below it (#463).\n */\nexport async function readAllSqliteFacts(root: MemoryRoot): Promise<SqliteFactRow[]> {\n const dbPath = defaultIndexPath(root);\n if (!existsSync(dbPath)) return [];\n const db = await openMemoryDb({ filePath: dbPath });\n try {\n // SQLite schema: chunks table holds the facts. Schema may vary; we\n // probe column existence and fall back to safe defaults.\n const stmt = db.prepare(\"SELECT id, path, source, start_line, end_line, text FROM chunks\");\n const rows = stmt.all() as Array<{\n id: string;\n path: string;\n source: \"memory\" | \"sessions\" | \"wiki\";\n start_line: number;\n end_line: number;\n text: string;\n }>;\n return rows.map((r) => ({\n ...r,\n namespace: \"default\",\n scope: \"agent\",\n user_id: \"default\",\n }));\n } finally {\n db.close();\n }\n}\n\n/**\n * Compare two strings via NFC normalization (EC-3 MUST FIX). Required\n * because SQLite/Lance native bindings can normalize unicode differently\n * (NFC vs NFD), producing false negatives on facts with accents/emojis.\n *\n * @internal\n */\nfunction nfcEqual(a: string, b: string): boolean {\n return a.normalize(\"NFC\") === b.normalize(\"NFC\");\n}\n\n/**\n * Refuse a `batchSize` the loop below cannot make progress with, before anything is migrated.\n *\n * The loop is `for (let i = 0; i < facts.length; i += batchSize)`, so the three ways this goes wrong\n * are all silent and all different:\n *\n * - 0 or negative: `i` never advances past the guard. The migration SPINS FOREVER, calling\n * `addFacts([])` and writing a \"Migrated x/y\" line every iteration — a hang with unbounded output,\n * which is the worst shape a failure can take because it looks like work.\n * - NaN (`Number(\"abc\")`): `i += NaN` makes the guard false on the first check, zero facts move, and\n * the caller is told \"Validation FAILED. SQLite preserved.\" A typo in an argument is reported as a\n * migration failure.\n * - a fraction: `slice` truncates and the loop still terminates, but the batch boundaries stop\n * matching the number the caller asked for.\n *\n * Validated HERE rather than only in the CLI that motivated the finding, because the CLI is a wrapper\n * over this function and a programmatic caller reaches it with no wrapper at all.\n *\n * @internal\n */\nfunction assertUsableBatchSize(batchSize: number | undefined): void {\n if (batchSize === undefined) return;\n if (!Number.isInteger(batchSize) || batchSize < 1) {\n throw new ConfigurationError(\n `migrateSqliteToLance: batchSize must be a whole number of at least 1; received ${String(batchSize)}.`,\n { code: \"invalid_batch_size\" },\n );\n }\n}\n\n/**\n * Run the migration. Writes Lance to `<cwd>/.theokit/memory/lance-new/`\n * first, validates round-trip, then renames to `lance/` on success.\n * SQLite db is preserved (CLI prompts user to delete).\n *\n * @internal\n */\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: migration is a single transaction (read → write → validate → commit-or-rollback); splitting harms atomicity reasoning.\nexport async function migrateSqliteToLance(opts: MigrateOptions): Promise<MigrateResult> {\n assertUsableBatchSize(opts.batchSize);\n const cwd = opts.cwd;\n // One resolution, reused by every path this migration touches (#463).\n const memoryRoot = resolveMemoryRoot(cwd, { directory: opts.directory });\n const finalPath = lanceStoragePath(memoryRoot);\n const newPath = join(memoryRoot, \"lance-new\");\n // T1.4 (ADR D68): wrap logger so any fact text containing secrets is\n // masked before reaching the destination (console or user-supplied sink).\n // Caller-supplied loggers cannot bypass — by design (D70).\n const rawLog = opts.logger ?? ((m: string) => console.log(m));\n const log = (m: string) => rawLog(redactSecrets(m));\n\n // EC: destination exists → typed error.\n if (existsSync(finalPath)) {\n throw new ConfigurationError(\n `Destination already exists: ${finalPath}. Remove it manually (\\`rm -rf ${finalPath}\\`) and re-run.`,\n { code: \"migration_destination_exists\" },\n );\n }\n if (existsSync(newPath)) {\n // Leftover from a previous failed/interrupted migration. Safe to delete.\n log(`Removing stale ${newPath} from a previous run...`);\n rmSync(newPath, { recursive: true, force: true });\n }\n\n log(`Reading SQLite facts from ${cwd}/.theokit/memory/index.sqlite ...`);\n const sqliteFacts = await readAllSqliteFacts(memoryRoot);\n log(`SQLite has ${sqliteFacts.length} facts.`);\n if (sqliteFacts.length === 0) {\n return {\n countSqlite: 0,\n countLance: 0,\n validated: true,\n sampleComparisons: [],\n lancePath: finalPath,\n committed: false,\n };\n }\n\n // Reuse the embedding runtime configured in the workspace? For v1.2 we\n // require the caller to pass embedding explicitly via env. The migration\n // path is documented as: \"set OPENAI_API_KEY (or similar) before running.\"\n // Here we ship a placeholder embedder that uses a deterministic\n // content-hash — sufficient for migration validation; consumers should\n // re-embed on first real query after migration if needed.\n const placeholderEmbedding = {\n id: \"migration-placeholder\",\n model: \"deterministic-hash\",\n dimension: 8,\n embed: async (texts: ReadonlyArray<string>) => {\n // Simple deterministic hash → 8-dim vector (migration validation only).\n return texts.map((t) => {\n const arr = new Array(8).fill(0);\n for (let i = 0; i < t.length; i += 1) {\n arr[i % 8] += t.charCodeAt(i);\n }\n return arr.map((x) => x / 1000);\n });\n },\n stats: () => ({ cacheHits: 0, cacheMisses: 0, httpCalls: 0, retries: 0 }),\n };\n\n mkdirSync(newPath, { recursive: true });\n log(`Writing Lance index to ${newPath} ...`);\n\n const lance = await LanceIndex.open({\n cwd,\n embedding: placeholderEmbedding,\n storagePath: newPath,\n });\n\n const batchSize = opts.batchSize ?? 100;\n for (let i = 0; i < sqliteFacts.length; i += batchSize) {\n const batch = sqliteFacts.slice(i, i + batchSize).map((f) => ({\n id: f.id,\n text: f.text,\n source: f.source,\n namespace: f.namespace ?? \"default\",\n scope: f.scope ?? \"agent\",\n user_id: f.user_id ?? \"default\",\n timestamp: 0,\n }));\n await lance.addFacts(batch);\n log(` Migrated ${Math.min(i + batchSize, sqliteFacts.length)}/${sqliteFacts.length}`);\n }\n\n // Validation: count + sample compare (10 random) with NFC normalization.\n const lanceCount = await lance.countFacts(\"default\");\n log(`Lance has ${lanceCount} facts (expected ${sqliteFacts.length}).`);\n\n const sampleSize = Math.min(10, sqliteFacts.length);\n const sampleComparisons: { id: string; match: boolean }[] = [];\n for (let i = 0; i < sampleSize; i += 1) {\n const sqliteFact = sqliteFacts[Math.floor((i * sqliteFacts.length) / sampleSize)];\n if (sqliteFact === undefined) continue;\n // Search Lance for this fact's text — best-effort round-trip.\n const hits = await lance.search(sqliteFact.text, {\n namespace: sqliteFact.namespace ?? \"default\",\n limit: 1,\n });\n // EC-3: compare with NFC normalization.\n const hit = hits[0];\n const match = hit !== undefined && nfcEqual(hit.text, sqliteFact.text);\n sampleComparisons.push({ id: sqliteFact.id, match });\n }\n\n const allMatch = sampleComparisons.every((c) => c.match);\n const countMatch = lanceCount === sqliteFacts.length;\n const validated = allMatch && countMatch;\n\n await lance.close();\n\n if (opts.dryRun === true) {\n log(\"Dry-run mode — discarding Lance staging dir.\");\n rmSync(newPath, { recursive: true, force: true });\n return {\n countSqlite: sqliteFacts.length,\n countLance: lanceCount,\n validated,\n sampleComparisons,\n lancePath: finalPath,\n committed: false,\n };\n }\n\n if (!validated) {\n log(\"Validation FAILED — leaving SQLite intact, removing Lance staging dir.\");\n rmSync(newPath, { recursive: true, force: true });\n return {\n countSqlite: sqliteFacts.length,\n countLance: lanceCount,\n validated: false,\n sampleComparisons,\n lancePath: finalPath,\n committed: false,\n };\n }\n\n // Atomic commit via rename.\n renameSync(newPath, finalPath);\n log(`Migration committed to ${finalPath}.`);\n return {\n countSqlite: sqliteFacts.length,\n countLance: lanceCount,\n validated: true,\n sampleComparisons,\n lancePath: finalPath,\n committed: true,\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/internal/persistence/session-writer.ts"],"names":["TheokitAgentError","hostname","openSync","writeSync","fchmodSync","closeSync","readFileSync","existsSync","rmSync"],"mappings":"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","file":"chunk-EQ5IDL6W.cjs","sourcesContent":["/**\n * M81 — single-writer lease for a session transcript.\n *\n * ## The problem\n *\n * Nothing stops two processes appending to the same JSONL transcript. The concrete case: `exec\n * resume --last` can write into the TUI's live session. Two interleaved appends to an append-only\n * file produce lines that are each individually valid and whose SEQUENCE is fiction — and nothing\n * reports it, because every line parses.\n *\n * ## Why an exclusive lockfile rather than `withFileLock`\n *\n * The plan's ADR D2 said to compose `withFileLock`, and that was the right instinct — do not build a\n * second lock mechanism. It turned out not to fit the SHAPE: `withFileLock(path, fn)` is\n * scope-based — it holds the lock for the duration of a callback. A session lease is **held across\n * turns**, for as long as the process owns the session, with an explicit `release()`. Wrapping the\n * whole session lifetime in a callback would invert control of the entire agent loop.\n *\n * So this uses the same underlying primitive `withFileLock` uses (an exclusive-create lockfile,\n * `wx`) with lease semantics on top. That keeps the mechanism single — the file-existence lock —\n * while giving it the lifetime the caller needs. The deviation from D2 is recorded here because the\n * plan's rationale (no second mechanism) still holds; only its shape assumption did not.\n *\n * ## Fail fast, never wait\n *\n * A second writer that WAITED would block `exec` behind a TUI session that can last hours. The typed\n * error lets the caller choose: fork to a new id, or give up with a real diagnosis.\n *\n * @internal\n */\n\nimport {\n closeSync,\n existsSync,\n fchmodSync,\n openSync,\n readFileSync,\n rmSync,\n writeSync,\n} from \"node:fs\";\nimport { hostname } from \"node:os\";\n\nimport { TheokitAgentError } from \"../../errors.js\";\n\n/**\n * M81 — another process already holds the writer lease for this session.\n *\n * Carries `sessionPath` because knowing WHICH session is busy is what lets the caller decide between\n * forking and waiting for the user to close the TUI (`rules/error-handling.md § 2` — context enough\n * to act on).\n */\nexport class SessionBusyError extends TheokitAgentError {\n override readonly name = \"SessionBusyError\";\n\n constructor(readonly sessionPath: string) {\n super(\n `another process is already writing this session: ${sessionPath}. ` +\n \"Fork it to a new id instead of appending — two writers interleave lines into a sequence \" +\n \"that parses but is not what either process wrote.\",\n { code: \"session_busy\", isRetryable: false },\n );\n }\n}\n\n/** A held writer lease. `release()` is idempotent. */\nexport interface SessionWriterLease {\n readonly sessionPath: string;\n release(): Promise<void>;\n /**\n * Re-stamp the ownership record, so a **live** owner never crosses the staleness window.\n *\n * Idempotent and cheap: one `write` of a ~80-byte JSON. Call it on the path that already writes to\n * the session — appending a turn — and the cross-host window stops being a lie about liveness.\n *\n * A no-op after `release()`: renewing a lease you no longer hold would re-create the lock file and\n * hand this process ownership it gave up. That is the one direction of this API that could\n * *create* the double-writer it exists to prevent.\n */\n renew(): void;\n}\n\n/**\n * Staleness window **between machines** — and only between them.\n *\n * 30 s from ACQUISITION. Calling it a \"heartbeat\" would be a lie: the record is written once, when\n * the lease is taken, and is **not** renewed on every write. An earlier version of this comment\n * claimed \"the owner touches the file on every acquisition, so a live process never crosses the\n * window\" — false twice over, and adversarial review measured both.\n *\n * On the **same host** this does not matter: `reclaimable` decides by `pid`, which is exact, and age\n * never enters the calculation. Across hosts it does matter, and it is a real limit: a **live**\n * remote owner loses the lease after 30 s, because there is no way to ask another machine whether\n * its process still exists.\n *\n * **The residue is now closable by the caller** (`agent-builder#118`). `SessionWriterLease.renew()`\n * re-stamps the record; calling it on the path that already writes to the session — appending a turn\n * — keeps a live owner from ever crossing the window. It costs one `write` of ~80 bytes on a file\n * that was previously written once per session.\n *\n * It is `renew()` and not an internal timer on purpose. A timer inside the lease would keep the event\n * loop alive (or need `unref` plus its own teardown), and it would renew a lease belonging to a\n * process that is hung rather than working — which is precisely the state the window exists to\n * detect. Tying the renewal to a real write means the record tracks **progress**, not mere existence.\n */\nexport const HEARTBEAT_WINDOW_MS = 30_000;\n\n/** Who holds the lock. Written as JSON into `.writer.lock`. */\ninterface LockOwner {\n pid: number;\n hostname: string;\n mtime: number;\n}\n\n/** The ownership record for THIS process, stamped now. One place, so acquire and renew cannot drift. */\nfunction ownerNow(): LockOwner {\n return { pid: process.pid, hostname: hostname(), mtime: Date.now() };\n}\n\n/**\n * Writes the owner with user-only permissions.\n *\n * `0600` because the lock is an assertion of OWNERSHIP: with the `0664` the usual umask produces,\n * another user in the same group can overwrite the file and forge ownership of the session — and\n * from then on it is the legitimate owner who starts receiving `SessionBusyError`. The content\n * (`pid`, `hostname`) is low-sensitivity; what the permission protects is the signal's\n * **integrity**, not its secrecy.\n */\nfunction writeOwner(lockPath: string, owner: LockOwner): void {\n const fd = openSync(lockPath, \"w\", 0o600);\n try {\n writeSync(fd, JSON.stringify(owner));\n // `open`'s `mode` only applies on CREATION. A `.writer.lock` inherited from an earlier version —\n // or left behind by a process with a different umask — would stay `0664` after being reclaimed,\n // and the forgery window the mode closes for new locks would remain open for old ones.\n fchmodSync(fd, 0o600);\n } finally {\n closeSync(fd);\n }\n}\n\n/** Reads the lock's owner. `undefined` when the file vanished or the content is unreadable. */\nfunction readOwner(lockPath: string): LockOwner | undefined {\n let raw: string;\n try {\n raw = readFileSync(lockPath, \"utf8\");\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n // `ENOENT` — vanished between the `EEXIST` and the read. Benign race: the lock is gone.\n if (code === \"ENOENT\") return undefined;\n // `EISDIR` — the lock path is a DIRECTORY. No process in this library creates one; it is debris\n // from something else, and it will never become a readable lock. Failing closed here would lock\n // the session out forever. Treated as owner-less: acquisition proceeds and fails with the real\n // FS error, which says what is wrong — instead of a permanent SessionBusyError that says\n // nothing. It is NOT \"reclaimable\": the lock is not removed, and the caller proceeds without a\n // lease.\n if (code === \"EISDIR\") return undefined;\n // Any other read failure (`EACCES` in a shared directory, `EIO`) differs in kind: the lock\n // **exists** and it is we who cannot read the owner. Treating it as free would let two writers\n // coexist — precisely what the lease exists to prevent — and the `0600` that protects the lock\n // against forgery WIDENS that surface: in a shared directory, another user's lock is unreadable\n // by design.\n //\n // Not knowing who the owner is differs from there being no owner. Fail closed.\n throw new SessionBusyError(lockPath.replace(/\\.writer\\.lock$/, \"\"));\n }\n try {\n const d = JSON.parse(raw) as Partial<LockOwner>;\n if (\n typeof d.pid !== \"number\" ||\n typeof d.hostname !== \"string\" ||\n typeof d.mtime !== \"number\"\n ) {\n return undefined;\n }\n return { pid: d.pid, hostname: d.hostname, mtime: d.mtime };\n } catch {\n // Unreadable JSON: a lock nobody can interpret must not lock the session out forever. Treating\n // it as stale is the recoverable choice; the cost is the same as that of an old lock.\n return undefined;\n }\n}\n\n/** Does the process exist? `signal 0` sends nothing — it only queries permission/existence. */\nfunction processAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n // EPERM means it EXISTS and belongs to another user.\n return (err as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n\n/**\n * Can the lock be taken from whoever holds it?\n *\n * ADR-2 of the plan: reclaiming by `pid` alone has a false positive across machines — the same\n * number exists on another host, pointing at an unrelated process. So:\n *\n * - **same host:** the `pid` is authoritative, and it **alone**. Dead process => reclaimable at\n * once; live process => never, however old the lock is.\n * - **other host:** the `pid` says nothing here. Only the heartbeat window counts, because it is\n * the one signal that does not lie across machines.\n *\n * ## Why age does NOT count on the same host\n *\n * The first version did `stale || !processAlive(pid)`, and that was a serious defect: `mtime` is\n * written at **acquisition** and is not touched on each append, so any session lasting longer than\n * the window — that is, **every real session** — became stealable by another process. Two writers\n * on the same transcript is exactly what the lease exists to prevent.\n *\n * On the same host the question \"does the owner still exist?\" has an exact answer, and age adds no\n * information to it — only a way to be wrong. Keeping the window there would be heuristic layered\n * on top of a fact.\n */\nfunction reclaimable(owner: LockOwner | undefined): boolean {\n if (owner === undefined) return true; // unreadable or vanished\n if (owner.hostname !== hostname()) {\n return Date.now() - owner.mtime > HEARTBEAT_WINDOW_MS;\n }\n return !processAlive(owner.pid);\n}\n\n/**\n * Does the session have a writer **right now**? A query that does NOT take the lease.\n *\n * M95 — it exists because asking by taking creates the very contention it meant to detect: two\n * processes querying a **free** session at the same time made one of them lose, and the consumer\n * forked for no reason. Measured in adversarial review: `RACE: spurious forks = 1`.\n *\n * It is a snapshot, not a guarantee: between the query and the real acquisition someone may take\n * the session. Callers needing the guarantee use {@link acquireSessionWriter}; callers needing to\n * **decide an id before opening anything** use this, and handle the race where it shows up.\n *\n */\nexport function sessionHasWriter(sessionPath: string): boolean {\n const lockPath = `${sessionPath}.writer.lock`;\n if (!existsSync(lockPath)) return false;\n try {\n return !reclaimable(readOwner(lockPath));\n } catch {\n // `readOwner` throws when the lock exists and cannot be read — fail closed, for the same reason\n // as there: not knowing who the owner is differs from there being no owner.\n return true;\n }\n}\n\n/**\n * Take the exclusive writer lease for `sessionPath`, or reject with {@link SessionBusyError}.\n *\n * The lock is a sibling `.lock` file created with `wx` — the same file-existence primitive the\n * SDK's `withFileLock` builds on. Exclusivity comes from the filesystem, so it holds across\n * processes, not just across async tasks in one process.\n */\nexport async function acquireSessionWriter(sessionPath: string): Promise<SessionWriterLease> {\n // M95 — `.writer.lock`, NOT `.lock`.\n //\n // `withFileLock(path, fn)` already uses `<path>.lock` as its companion. While the lease was called\n // from nowhere (the defect this milestone fixes) the collision was theoretical; wiring it to the\n // same file would make the long-lived lease block every short critical section on the same path.\n //\n // Two files because they are two things: `withFileLock` protects a section with a start and an\n // end; the lease is OWNERSHIP, held across turns, with an explicit `release()` — the distinction\n // the M81 docstring above already explains.\n const lockPath = `${sessionPath}.writer.lock`;\n const mine: LockOwner = ownerNow();\n let fd: number;\n try {\n // The mode applies on CREATION — the `w` in `writeOwner` does not alter an existing file.\n fd = openSync(lockPath, \"wx\", 0o600);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") throw err;\n // M95 — the lock exists. Until now that alone was enough to refuse, and that was the defect: a\n // TUI killed by SIGKILL locked the user out of their own session PERMANENTLY, with no documented\n // recovery path. Now the lock says who the owner is, and a dead owner yields its place.\n if (!reclaimable(readOwner(lockPath))) throw new SessionBusyError(sessionPath);\n writeOwner(lockPath, mine);\n return createLease(sessionPath, lockPath);\n }\n closeSync(fd);\n writeOwner(lockPath, mine);\n\n return createLease(sessionPath, lockPath);\n}\n\n/** The lease itself — idempotent `release()`. Extracted because acquisition has two exit paths. */\nfunction createLease(sessionPath: string, lockPath: string): SessionWriterLease {\n let released = false;\n return {\n sessionPath,\n release: async (): Promise<void> => {\n if (released) return;\n released = true;\n rmSync(lockPath, { force: true });\n },\n renew: (): void => {\n // A released lease does not own the lock. Re-stamping here would RE-CREATE the file and give\n // this process ownership it explicitly gave up — the one way this method could manufacture the\n // double-writer the lease exists to prevent.\n if (released) return;\n writeOwner(lockPath, ownerNow());\n },\n };\n}\n"]}