@theokit/sdk 4.62.0 → 4.63.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/dist/a2a/index.cjs +2 -2
  3. package/dist/a2a/index.js +1 -1
  4. package/dist/{agent-DIu6FooJ.d.ts → agent-BFno7Sfn.d.ts} +36 -21
  5. package/dist/agent-WK7MKIMH.cjs +66 -0
  6. package/dist/{agent-VYPUO4UB.cjs.map → agent-WK7MKIMH.cjs.map} +1 -1
  7. package/dist/{agent-D3Xr_-6Z.d.cts → agent-X0DKA943.d.cts} +36 -21
  8. package/dist/agent-YWMBM7LX.js +57 -0
  9. package/dist/{agent-NVBFTY5H.js.map → agent-YWMBM7LX.js.map} +1 -1
  10. package/dist/agent-session-store-6EL5NPA4.cjs +24 -0
  11. package/dist/{agent-session-store-WAKLOKWK.cjs.map → agent-session-store-6EL5NPA4.cjs.map} +1 -1
  12. package/dist/agent-session-store-OPGRB4XM.js +7 -0
  13. package/dist/{agent-session-store-G2BMUZQV.js.map → agent-session-store-OPGRB4XM.js.map} +1 -1
  14. package/dist/auth/index.cjs +18 -18
  15. package/dist/auth/index.js +6 -6
  16. package/dist/{batch-ND32UKZS.cjs → batch-BXYTW2DP.cjs} +27 -27
  17. package/dist/{batch-ND32UKZS.cjs.map → batch-BXYTW2DP.cjs.map} +1 -1
  18. package/dist/{batch-2TGJMNCJ.js → batch-L4ZXS46M.js} +10 -10
  19. package/dist/{batch-2TGJMNCJ.js.map → batch-L4ZXS46M.js.map} +1 -1
  20. package/dist/{chunk-VF7EWVDG.js → chunk-2GUYQR5P.js} +3 -3
  21. package/dist/{chunk-VF7EWVDG.js.map → chunk-2GUYQR5P.js.map} +1 -1
  22. package/dist/{chunk-J2UROOIG.cjs → chunk-2HVF2WJY.cjs} +8 -8
  23. package/dist/{chunk-J2UROOIG.cjs.map → chunk-2HVF2WJY.cjs.map} +1 -1
  24. package/dist/{chunk-44MBDIHG.js → chunk-2QDYBS2A.js} +3 -3
  25. package/dist/{chunk-44MBDIHG.js.map → chunk-2QDYBS2A.js.map} +1 -1
  26. package/dist/{chunk-NGESVVJN.cjs → chunk-3FFAEAUJ.cjs} +17 -17
  27. package/dist/{chunk-NGESVVJN.cjs.map → chunk-3FFAEAUJ.cjs.map} +1 -1
  28. package/dist/{chunk-GWC3HADL.cjs → chunk-3NSS2OIZ.cjs} +4 -4
  29. package/dist/{chunk-GWC3HADL.cjs.map → chunk-3NSS2OIZ.cjs.map} +1 -1
  30. package/dist/{chunk-CV7XMBHP.js → chunk-3O42QOMJ.js} +3 -3
  31. package/dist/{chunk-CV7XMBHP.js.map → chunk-3O42QOMJ.js.map} +1 -1
  32. package/dist/{chunk-IWBGCBR6.cjs → chunk-4CLOXP6H.cjs} +4 -4
  33. package/dist/{chunk-IWBGCBR6.cjs.map → chunk-4CLOXP6H.cjs.map} +1 -1
  34. package/dist/{chunk-YEXA3PGR.js → chunk-4FFBAUFS.js} +5 -5
  35. package/dist/{chunk-YEXA3PGR.js.map → chunk-4FFBAUFS.js.map} +1 -1
  36. package/dist/{chunk-HY57ULY2.cjs → chunk-4PYZ5AX3.cjs} +5 -5
  37. package/dist/{chunk-HY57ULY2.cjs.map → chunk-4PYZ5AX3.cjs.map} +1 -1
  38. package/dist/{chunk-OC4NTGMN.js → chunk-4QZSA2HJ.js} +3 -3
  39. package/dist/{chunk-OC4NTGMN.js.map → chunk-4QZSA2HJ.js.map} +1 -1
  40. package/dist/{chunk-K3FW2XZD.cjs → chunk-4ZHTIJNE.cjs} +9 -9
  41. package/dist/{chunk-K3FW2XZD.cjs.map → chunk-4ZHTIJNE.cjs.map} +1 -1
  42. package/dist/{chunk-BUIK7GUA.cjs → chunk-5HEG4CQH.cjs} +8 -8
  43. package/dist/{chunk-BUIK7GUA.cjs.map → chunk-5HEG4CQH.cjs.map} +1 -1
  44. package/dist/{chunk-SKXBJ2NU.cjs → chunk-5VB22SYX.cjs} +7 -54
  45. package/dist/chunk-5VB22SYX.cjs.map +1 -0
  46. package/dist/{chunk-5USCYPPI.cjs → chunk-6HKGLTJI.cjs} +8 -8
  47. package/dist/{chunk-5USCYPPI.cjs.map → chunk-6HKGLTJI.cjs.map} +1 -1
  48. package/dist/chunk-6RKUO7AW.cjs +864 -0
  49. package/dist/chunk-6RKUO7AW.cjs.map +1 -0
  50. package/dist/{chunk-5JLFFPCH.js → chunk-7YGCPMGB.js} +4 -4
  51. package/dist/{chunk-5JLFFPCH.js.map → chunk-7YGCPMGB.js.map} +1 -1
  52. package/dist/{chunk-SUKXXLWD.js → chunk-A46SWMIF.js} +6 -6
  53. package/dist/{chunk-SUKXXLWD.js.map → chunk-A46SWMIF.js.map} +1 -1
  54. package/dist/{chunk-F7AQV62G.js → chunk-A4JVILQU.js} +5 -5
  55. package/dist/{chunk-F7AQV62G.js.map → chunk-A4JVILQU.js.map} +1 -1
  56. package/dist/chunk-A4RAL2ER.cjs +51 -0
  57. package/dist/chunk-A4RAL2ER.cjs.map +1 -0
  58. package/dist/{chunk-44JAAH4X.js → chunk-B3IMEBOA.js} +3 -3
  59. package/dist/{chunk-44JAAH4X.js.map → chunk-B3IMEBOA.js.map} +1 -1
  60. package/dist/{chunk-QDED6YO6.cjs → chunk-B4EOJWOY.cjs} +5 -5
  61. package/dist/{chunk-QDED6YO6.cjs.map → chunk-B4EOJWOY.cjs.map} +1 -1
  62. package/dist/{chunk-YJDH3CKG.js → chunk-BP46RJ5X.js} +5 -5
  63. package/dist/{chunk-YJDH3CKG.js.map → chunk-BP46RJ5X.js.map} +1 -1
  64. package/dist/{chunk-QRSUA2CV.js → chunk-BU4KFWXF.js} +3 -3
  65. package/dist/{chunk-QRSUA2CV.js.map → chunk-BU4KFWXF.js.map} +1 -1
  66. package/dist/{chunk-IBYRA5PM.js → chunk-BVJJ3DRV.js} +6 -6
  67. package/dist/{chunk-IBYRA5PM.js.map → chunk-BVJJ3DRV.js.map} +1 -1
  68. package/dist/{chunk-AQLGBKNT.js → chunk-BZRFXJHA.js} +3 -3
  69. package/dist/{chunk-AQLGBKNT.js.map → chunk-BZRFXJHA.js.map} +1 -1
  70. package/dist/{chunk-UQGQFBRL.js → chunk-C3NT3PVE.js} +3 -3
  71. package/dist/{chunk-UQGQFBRL.js.map → chunk-C3NT3PVE.js.map} +1 -1
  72. package/dist/{chunk-UC3HT2S4.js → chunk-C72AZW7J.js} +3 -3
  73. package/dist/{chunk-UC3HT2S4.js.map → chunk-C72AZW7J.js.map} +1 -1
  74. package/dist/{chunk-WNTAPVU5.cjs → chunk-CQBXOJ6U.cjs} +13 -13
  75. package/dist/{chunk-WNTAPVU5.cjs.map → chunk-CQBXOJ6U.cjs.map} +1 -1
  76. package/dist/{chunk-T7XEKOVW.js → chunk-D4CUGAKZ.js} +3 -3
  77. package/dist/{chunk-T7XEKOVW.js.map → chunk-D4CUGAKZ.js.map} +1 -1
  78. package/dist/chunk-DKD3MH6A.js +194 -0
  79. package/dist/chunk-DKD3MH6A.js.map +1 -0
  80. package/dist/{chunk-YXGAW7BB.js → chunk-DN2PACRI.js} +10 -10
  81. package/dist/{chunk-YXGAW7BB.js.map → chunk-DN2PACRI.js.map} +1 -1
  82. package/dist/{chunk-XSX2UU6Y.cjs → chunk-DXGZ2NUG.cjs} +10 -10
  83. package/dist/{chunk-XSX2UU6Y.cjs.map → chunk-DXGZ2NUG.cjs.map} +1 -1
  84. package/dist/{chunk-NUKRL3I6.cjs → chunk-EG4QM7ZJ.cjs} +18 -2
  85. package/dist/chunk-EG4QM7ZJ.cjs.map +1 -0
  86. package/dist/chunk-GEEXBYFL.js +831 -0
  87. package/dist/chunk-GEEXBYFL.js.map +1 -0
  88. package/dist/chunk-GKEFRLU7.cjs +21 -0
  89. package/dist/chunk-GKEFRLU7.cjs.map +1 -0
  90. package/dist/{chunk-NIRE5CNO.cjs → chunk-HCZD23VS.cjs} +13 -13
  91. package/dist/{chunk-NIRE5CNO.cjs.map → chunk-HCZD23VS.cjs.map} +1 -1
  92. package/dist/chunk-HOXVQ5FR.cjs +201 -0
  93. package/dist/chunk-HOXVQ5FR.cjs.map +1 -0
  94. package/dist/{chunk-QARJGQSA.js → chunk-HS7AVXTF.js} +3 -3
  95. package/dist/{chunk-QARJGQSA.js.map → chunk-HS7AVXTF.js.map} +1 -1
  96. package/dist/{chunk-4I55V454.cjs → chunk-I6HGWHPU.cjs} +4 -4
  97. package/dist/{chunk-4I55V454.cjs.map → chunk-I6HGWHPU.cjs.map} +1 -1
  98. package/dist/{chunk-T73NA43R.js → chunk-IPYYKCRC.js} +3 -3
  99. package/dist/{chunk-T73NA43R.js.map → chunk-IPYYKCRC.js.map} +1 -1
  100. package/dist/{chunk-6OBIWHDR.cjs → chunk-ITYQ6VBP.cjs} +24 -365
  101. package/dist/chunk-ITYQ6VBP.cjs.map +1 -0
  102. package/dist/chunk-JPBKYL3B.cjs +18 -0
  103. package/dist/{chunk-6HTXPPHK.cjs.map → chunk-JPBKYL3B.cjs.map} +1 -1
  104. package/dist/{chunk-MZ2FGBLZ.js → chunk-K5OJUYSZ.js} +4 -4
  105. package/dist/{chunk-MZ2FGBLZ.js.map → chunk-K5OJUYSZ.js.map} +1 -1
  106. package/dist/{chunk-SKOCYA55.js → chunk-KIH6IZ43.js} +90 -88
  107. package/dist/chunk-KIH6IZ43.js.map +1 -0
  108. package/dist/{chunk-EI2Q7SJ5.cjs → chunk-KQ7TS7WW.cjs} +10 -10
  109. package/dist/{chunk-EI2Q7SJ5.cjs.map → chunk-KQ7TS7WW.cjs.map} +1 -1
  110. package/dist/{chunk-RUDY2GTT.js → chunk-KQRW2GPZ.js} +5 -5
  111. package/dist/{chunk-RUDY2GTT.js.map → chunk-KQRW2GPZ.js.map} +1 -1
  112. package/dist/{chunk-P5LCASTC.cjs → chunk-KYAJINUI.cjs} +125 -125
  113. package/dist/{chunk-P5LCASTC.cjs.map → chunk-KYAJINUI.cjs.map} +1 -1
  114. package/dist/{chunk-CQ2TQ32Y.js → chunk-LWGSI6M3.js} +5 -50
  115. package/dist/chunk-LWGSI6M3.js.map +1 -0
  116. package/dist/{chunk-ZHPWGIUX.js → chunk-LXI4XZEC.js} +5 -5
  117. package/dist/{chunk-ZHPWGIUX.js.map → chunk-LXI4XZEC.js.map} +1 -1
  118. package/dist/{chunk-AG5JPQIY.js → chunk-LXQ6HKPS.js} +3 -3
  119. package/dist/{chunk-AG5JPQIY.js.map → chunk-LXQ6HKPS.js.map} +1 -1
  120. package/dist/{chunk-ROYPRJH4.cjs → chunk-LYRDF5TQ.cjs} +9 -9
  121. package/dist/{chunk-ROYPRJH4.cjs.map → chunk-LYRDF5TQ.cjs.map} +1 -1
  122. package/dist/{chunk-G24KZRSA.js → chunk-N2U4AZGB.js} +3 -3
  123. package/dist/{chunk-G24KZRSA.js.map → chunk-N2U4AZGB.js.map} +1 -1
  124. package/dist/{chunk-4ERPXIVB.js → chunk-O73J46PV.js} +5 -5
  125. package/dist/{chunk-4ERPXIVB.js.map → chunk-O73J46PV.js.map} +1 -1
  126. package/dist/{chunk-F3YZMOAU.cjs → chunk-O7DK5PBJ.cjs} +4 -4
  127. package/dist/{chunk-F3YZMOAU.cjs.map → chunk-O7DK5PBJ.cjs.map} +1 -1
  128. package/dist/{chunk-Z4BCLVTI.cjs → chunk-O7LZFG6O.cjs} +5 -5
  129. package/dist/{chunk-Z4BCLVTI.cjs.map → chunk-O7LZFG6O.cjs.map} +1 -1
  130. package/dist/{chunk-3YJNUKYN.cjs → chunk-OHLDPWTA.cjs} +15 -15
  131. package/dist/{chunk-3YJNUKYN.cjs.map → chunk-OHLDPWTA.cjs.map} +1 -1
  132. package/dist/{chunk-FUL2I7G5.js → chunk-OSEG74VJ.js} +8 -8
  133. package/dist/{chunk-FUL2I7G5.js.map → chunk-OSEG74VJ.js.map} +1 -1
  134. package/dist/{chunk-UCBJBJ27.js → chunk-PUAEFLYK.js} +4 -4
  135. package/dist/{chunk-UCBJBJ27.js.map → chunk-PUAEFLYK.js.map} +1 -1
  136. package/dist/{chunk-CWHTMNNK.cjs → chunk-Q7LPTOD6.cjs} +24 -24
  137. package/dist/{chunk-CWHTMNNK.cjs.map → chunk-Q7LPTOD6.cjs.map} +1 -1
  138. package/dist/{chunk-2C72DXQF.cjs → chunk-RFMBZPOW.cjs} +9 -9
  139. package/dist/{chunk-2C72DXQF.cjs.map → chunk-RFMBZPOW.cjs.map} +1 -1
  140. package/dist/{chunk-NLTVXLGT.js → chunk-RFXWMRFC.js} +3 -3
  141. package/dist/{chunk-NLTVXLGT.js.map → chunk-RFXWMRFC.js.map} +1 -1
  142. package/dist/{chunk-2DG7KW4L.cjs → chunk-RMWTPV3M.cjs} +8 -8
  143. package/dist/{chunk-2DG7KW4L.cjs.map → chunk-RMWTPV3M.cjs.map} +1 -1
  144. package/dist/{chunk-P6A3M6VD.cjs → chunk-SZVR77EJ.cjs} +10 -10
  145. package/dist/{chunk-P6A3M6VD.cjs.map → chunk-SZVR77EJ.cjs.map} +1 -1
  146. package/dist/{chunk-3E77SX4H.js → chunk-TAZVKYWJ.js} +3 -3
  147. package/dist/{chunk-3E77SX4H.js.map → chunk-TAZVKYWJ.js.map} +1 -1
  148. package/dist/{chunk-WKRSH2VR.js → chunk-U6IFHFWK.js} +3 -3
  149. package/dist/{chunk-WKRSH2VR.js.map → chunk-U6IFHFWK.js.map} +1 -1
  150. package/dist/{chunk-I6TGFUCO.cjs → chunk-UALX2J2Q.cjs} +4 -4
  151. package/dist/{chunk-I6TGFUCO.cjs.map → chunk-UALX2J2Q.cjs.map} +1 -1
  152. package/dist/{chunk-XN7NOENA.js → chunk-UBDMVMBZ.js} +5 -5
  153. package/dist/{chunk-XN7NOENA.js.map → chunk-UBDMVMBZ.js.map} +1 -1
  154. package/dist/{chunk-QEKI3YKI.js → chunk-UEXIJTLC.js} +14 -349
  155. package/dist/chunk-UEXIJTLC.js.map +1 -0
  156. package/dist/{chunk-DQKERTND.cjs → chunk-UGT7GK7I.cjs} +11 -11
  157. package/dist/{chunk-DQKERTND.cjs.map → chunk-UGT7GK7I.cjs.map} +1 -1
  158. package/dist/{chunk-FKMUFNQE.js → chunk-UMP6OJIM.js} +4 -4
  159. package/dist/{chunk-FKMUFNQE.js.map → chunk-UMP6OJIM.js.map} +1 -1
  160. package/dist/{chunk-AEOZTXVW.js → chunk-UNYXQ4M5.js} +3 -3
  161. package/dist/{chunk-AEOZTXVW.js.map → chunk-UNYXQ4M5.js.map} +1 -1
  162. package/dist/{chunk-2BDH744Z.js → chunk-UTSRIDKZ.js} +3 -3
  163. package/dist/{chunk-2BDH744Z.js.map → chunk-UTSRIDKZ.js.map} +1 -1
  164. package/dist/{chunk-2ADR2GSO.cjs → chunk-UU36SHFY.cjs} +5 -5
  165. package/dist/{chunk-2ADR2GSO.cjs.map → chunk-UU36SHFY.cjs.map} +1 -1
  166. package/dist/{chunk-R3UPQFKK.cjs → chunk-V2BOS4WF.cjs} +9 -9
  167. package/dist/{chunk-R3UPQFKK.cjs.map → chunk-V2BOS4WF.cjs.map} +1 -1
  168. package/dist/chunk-WE22OXQA.js +48 -0
  169. package/dist/chunk-WE22OXQA.js.map +1 -0
  170. package/dist/{chunk-Q4CMI2LP.js → chunk-WLQNMXQE.js} +5 -5
  171. package/dist/{chunk-Q4CMI2LP.js.map → chunk-WLQNMXQE.js.map} +1 -1
  172. package/dist/{chunk-XWL6O3SW.cjs → chunk-WNO3C3N2.cjs} +4 -4
  173. package/dist/{chunk-XWL6O3SW.cjs.map → chunk-WNO3C3N2.cjs.map} +1 -1
  174. package/dist/{chunk-T7O6K6PX.js → chunk-XEQ3TM66.js} +18 -3
  175. package/dist/chunk-XEQ3TM66.js.map +1 -0
  176. package/dist/{chunk-BVZW2B5V.cjs → chunk-XJCXEKMD.cjs} +4 -4
  177. package/dist/{chunk-BVZW2B5V.cjs.map → chunk-XJCXEKMD.cjs.map} +1 -1
  178. package/dist/{chunk-JTB5Q42C.cjs → chunk-XL7Q7HB2.cjs} +4 -4
  179. package/dist/{chunk-JTB5Q42C.cjs.map → chunk-XL7Q7HB2.cjs.map} +1 -1
  180. package/dist/chunk-XO4SOZN6.js +19 -0
  181. package/dist/chunk-XO4SOZN6.js.map +1 -0
  182. package/dist/{chunk-CQGYNZ3K.cjs → chunk-XWTLIGO3.cjs} +4 -4
  183. package/dist/{chunk-CQGYNZ3K.cjs.map → chunk-XWTLIGO3.cjs.map} +1 -1
  184. package/dist/{chunk-6SBW4QR2.cjs → chunk-YML4ME27.cjs} +11 -11
  185. package/dist/{chunk-6SBW4QR2.cjs.map → chunk-YML4ME27.cjs.map} +1 -1
  186. package/dist/{chunk-P6H23T43.cjs → chunk-ZCIRZE37.cjs} +11 -11
  187. package/dist/{chunk-P6H23T43.cjs.map → chunk-ZCIRZE37.cjs.map} +1 -1
  188. package/dist/{chunk-QI7WE46I.cjs → chunk-ZLQSWSJ2.cjs} +11 -11
  189. package/dist/{chunk-QI7WE46I.cjs.map → chunk-ZLQSWSJ2.cjs.map} +1 -1
  190. package/dist/{chunk-AH6WD7JR.cjs → chunk-ZMRD5DZQ.cjs} +362 -360
  191. package/dist/chunk-ZMRD5DZQ.cjs.map +1 -0
  192. package/dist/{chunk-ILCGLTSA.cjs → chunk-ZSWPZ23K.cjs} +4 -4
  193. package/dist/{chunk-ILCGLTSA.cjs.map → chunk-ZSWPZ23K.cjs.map} +1 -1
  194. package/dist/{chunk-IDCKSLYH.js → chunk-ZZMZWBR6.js} +3 -3
  195. package/dist/{chunk-IDCKSLYH.js.map → chunk-ZZMZWBR6.js.map} +1 -1
  196. package/dist/compact-session-QV57KR66.cjs +59 -0
  197. package/dist/{compact-session-GJXJD73F.cjs.map → compact-session-QV57KR66.cjs.map} +1 -1
  198. package/dist/compact-session-RIGOWC4Y.js +22 -0
  199. package/dist/{compact-session-TSMQOIHO.js.map → compact-session-RIGOWC4Y.js.map} +1 -1
  200. package/dist/compaction.cjs +17 -17
  201. package/dist/compaction.js +4 -4
  202. package/dist/concurrency.cjs +7 -7
  203. package/dist/concurrency.js +5 -5
  204. package/dist/context-AGQ3DIZU.cjs +24 -0
  205. package/dist/{context-LCKNH2XI.cjs.map → context-AGQ3DIZU.cjs.map} +1 -1
  206. package/dist/context-GQRFBCLP.js +7 -0
  207. package/dist/{context-MZSKGKYR.js.map → context-GQRFBCLP.js.map} +1 -1
  208. package/dist/{cron-BcWmzWzT.d.cts → cron-BuiRPrvt.d.cts} +1 -1
  209. package/dist/{cron-De6hzWCF.d.ts → cron-C2SIi31n.d.ts} +1 -1
  210. package/dist/cron.cjs +37 -35
  211. package/dist/cron.d.cts +2 -2
  212. package/dist/cron.d.ts +2 -2
  213. package/dist/cron.js +36 -34
  214. package/dist/errors.cjs +22 -22
  215. package/dist/errors.js +3 -3
  216. package/dist/eval.cjs +42 -40
  217. package/dist/eval.cjs.map +1 -1
  218. package/dist/eval.js +36 -34
  219. package/dist/eval.js.map +1 -1
  220. package/dist/{executor-ZERJ3DGN.cjs → executor-6CYCA7MI.cjs} +25 -25
  221. package/dist/{executor-ZERJ3DGN.cjs.map → executor-6CYCA7MI.cjs.map} +1 -1
  222. package/dist/{executor-BMEHFOXZ.js → executor-QSEC3MRH.js} +8 -8
  223. package/dist/{executor-BMEHFOXZ.js.map → executor-QSEC3MRH.js.map} +1 -1
  224. package/dist/filesystem/index.cjs +8 -8
  225. package/dist/filesystem/index.js +4 -4
  226. package/dist/fs-session-store-4PIHT5UX.cjs +20 -0
  227. package/dist/{fs-session-store-XZ7ZTB3A.cjs.map → fs-session-store-4PIHT5UX.cjs.map} +1 -1
  228. package/dist/fs-session-store-NM6YSTE2.js +11 -0
  229. package/dist/{fs-session-store-4BHGIWRE.js.map → fs-session-store-NM6YSTE2.js.map} +1 -1
  230. package/dist/generate-object-GUNAUVBX.js +8 -0
  231. package/dist/{generate-object-N5MDZUJI.js.map → generate-object-GUNAUVBX.js.map} +1 -1
  232. package/dist/generate-object-R7HTMW7F.cjs +21 -0
  233. package/dist/{generate-object-PGSP5U7N.cjs.map → generate-object-R7HTMW7F.cjs.map} +1 -1
  234. package/dist/index-manager-RBDHP3PM.js +17 -0
  235. package/dist/{index-manager-AHAYJ33H.js.map → index-manager-RBDHP3PM.js.map} +1 -1
  236. package/dist/index-manager-UZBF22BJ.cjs +26 -0
  237. package/dist/{index-manager-RHPFVFSC.cjs.map → index-manager-UZBF22BJ.cjs.map} +1 -1
  238. package/dist/index.cjs +146 -319
  239. package/dist/index.cjs.map +1 -1
  240. package/dist/index.d.cts +8 -3
  241. package/dist/index.d.ts +8 -3
  242. package/dist/index.js +62 -235
  243. package/dist/index.js.map +1 -1
  244. package/dist/{inject-session-ZCQUB3IT.js → inject-session-DAR7OUCW.js} +8 -8
  245. package/dist/{inject-session-ZCQUB3IT.js.map → inject-session-DAR7OUCW.js.map} +1 -1
  246. package/dist/{inject-session-PPSO2IDD.cjs → inject-session-WQKMC3GR.cjs} +10 -10
  247. package/dist/{inject-session-PPSO2IDD.cjs.map → inject-session-WQKMC3GR.cjs.map} +1 -1
  248. package/dist/internal/memory/active-memory.d.ts +8 -1
  249. package/dist/internal/memory/adapters/index.cjs +9 -9
  250. package/dist/internal/memory/adapters/index.js +8 -8
  251. package/dist/internal/memory/dreaming/diary.d.ts +39 -2
  252. package/dist/internal/memory/index-db.d.ts +44 -1
  253. package/dist/internal/memory/index-manager-contract.d.ts +10 -0
  254. package/dist/internal/memory/index-manager-helpers.d.ts +20 -1
  255. package/dist/internal/memory/index-manager.d.ts +1 -1
  256. package/dist/internal/memory/lance-index.d.ts +15 -1
  257. package/dist/internal/memory/migrate-sqlite-to-lance.d.ts +43 -0
  258. package/dist/internal/memory/storage/index.cjs +101 -18
  259. package/dist/internal/memory/storage/index.d.cts +11 -1
  260. package/dist/internal/memory/storage/index.d.ts +11 -1
  261. package/dist/internal/memory/storage/index.js +10 -7
  262. package/dist/internal/memory/storage/markdown-store.d.cts +13 -42
  263. package/dist/internal/memory/storage/markdown-store.d.ts +13 -42
  264. package/dist/internal/memory/storage/memory-root.d.cts +93 -0
  265. package/dist/internal/memory/storage/memory-root.d.ts +93 -0
  266. package/dist/internal/memory/storage/session-loader.d.cts +35 -1
  267. package/dist/internal/memory/storage/session-loader.d.ts +35 -1
  268. package/dist/internal/memory/storage/session-summary-writer.d.cts +50 -2
  269. package/dist/internal/memory/storage/session-summary-writer.d.ts +50 -2
  270. package/dist/internal/memory/storage/transcript-store.d.cts +38 -1
  271. package/dist/internal/memory/storage/transcript-store.d.ts +38 -1
  272. package/dist/internal/memory/storage/wiki-loader.d.cts +27 -2
  273. package/dist/internal/memory/storage/wiki-loader.d.ts +27 -2
  274. package/dist/internal/memory/tools.d.ts +8 -1
  275. package/dist/internal/memory/types.d.ts +5 -0
  276. package/dist/internal/persistence/index.cjs +29 -28
  277. package/dist/internal/persistence/index.cjs.map +1 -1
  278. package/dist/internal/persistence/index.js +8 -7
  279. package/dist/internal/persistence/index.js.map +1 -1
  280. package/dist/internal/persistence/session-dir.d.cts +0 -15
  281. package/dist/internal/persistence/session-dir.d.ts +0 -15
  282. package/dist/internal/runtime/memory/memory-store.d.ts +2 -2
  283. package/dist/internal/security/index.cjs +14 -14
  284. package/dist/internal/security/index.js +4 -4
  285. package/dist/judge-call-LAHMBJ57.cjs +23 -0
  286. package/dist/{judge-call-EGYRC2RE.cjs.map → judge-call-LAHMBJ57.cjs.map} +1 -1
  287. package/dist/judge-call-LVXABPS3.js +6 -0
  288. package/dist/{judge-call-DWHAJATE.js.map → judge-call-LVXABPS3.js.map} +1 -1
  289. package/dist/mcp-auth.cjs +15 -15
  290. package/dist/mcp-auth.js +5 -5
  291. package/dist/models.cjs +22 -22
  292. package/dist/models.js +7 -7
  293. package/dist/path-safety.cjs +11 -11
  294. package/dist/path-safety.js +4 -4
  295. package/dist/persistence.cjs +33 -32
  296. package/dist/persistence.cjs.map +1 -1
  297. package/dist/persistence.js +10 -9
  298. package/dist/persistence.js.map +1 -1
  299. package/dist/project.cjs +6 -6
  300. package/dist/project.js +4 -4
  301. package/dist/providers.cjs +9 -9
  302. package/dist/providers.js +7 -7
  303. package/dist/registry-75W33OGL.js +10 -0
  304. package/dist/{registry-VFP3WWQP.js.map → registry-75W33OGL.js.map} +1 -1
  305. package/dist/registry-V7BDQ6QB.cjs +47 -0
  306. package/dist/{registry-VFKX7WOP.cjs.map → registry-V7BDQ6QB.cjs.map} +1 -1
  307. package/dist/retry.cjs +5 -5
  308. package/dist/retry.js +4 -4
  309. package/dist/sandbox/index.cjs +7 -7
  310. package/dist/sandbox/index.js +3 -3
  311. package/dist/server/errors-envelope.cjs +15 -15
  312. package/dist/server/errors-envelope.js +4 -4
  313. package/dist/session-transcript-6WNITKRE.cjs +63 -0
  314. package/dist/{session-transcript-HF5GEU5M.cjs.map → session-transcript-6WNITKRE.cjs.map} +1 -1
  315. package/dist/session-transcript-XAEKW6P7.js +6 -0
  316. package/dist/{session-transcript-P462ZRHX.js.map → session-transcript-XAEKW6P7.js.map} +1 -1
  317. package/dist/skills.cjs +8 -8
  318. package/dist/skills.js +6 -6
  319. package/dist/stream-object-UF4QRQRU.js +8 -0
  320. package/dist/{stream-object-L57K4OFS.js.map → stream-object-UF4QRQRU.js.map} +1 -1
  321. package/dist/stream-object-ZJTQNKY3.cjs +21 -0
  322. package/dist/{stream-object-BUCF5PHO.cjs.map → stream-object-ZJTQNKY3.cjs.map} +1 -1
  323. package/dist/subagents-loader-CRT5LLL3.js +8 -0
  324. package/dist/{subagents-loader-6ATCDEKN.js.map → subagents-loader-CRT5LLL3.js.map} +1 -1
  325. package/dist/subagents-loader-YEUFFPAL.cjs +17 -0
  326. package/dist/{subagents-loader-X5QKODCL.cjs.map → subagents-loader-YEUFFPAL.cjs.map} +1 -1
  327. package/dist/subagents-loader.cjs +7 -7
  328. package/dist/subagents-loader.d.cts +1 -1
  329. package/dist/subagents-loader.d.ts +1 -1
  330. package/dist/subagents-loader.js +5 -5
  331. package/dist/subscription/index.cjs +4 -4
  332. package/dist/subscription/index.js +3 -3
  333. package/dist/task-store.cjs +8 -8
  334. package/dist/task-store.js +5 -5
  335. package/dist/types/agent.d.ts +11 -0
  336. package/dist/types/memory-provider.d.ts +8 -0
  337. package/dist/workflow.cjs +28 -28
  338. package/dist/workflow.js +7 -7
  339. package/docs/error-codes.md +10 -9
  340. package/docs/harness-capability-map.md +57 -17
  341. package/docs/memory-decisions.md +44 -7
  342. package/package.json +1 -1
  343. package/dist/agent-NVBFTY5H.js +0 -55
  344. package/dist/agent-VYPUO4UB.cjs +0 -64
  345. package/dist/agent-session-store-G2BMUZQV.js +0 -7
  346. package/dist/agent-session-store-WAKLOKWK.cjs +0 -24
  347. package/dist/chunk-2UCFUSPW.cjs +0 -468
  348. package/dist/chunk-2UCFUSPW.cjs.map +0 -1
  349. package/dist/chunk-6HTXPPHK.cjs +0 -18
  350. package/dist/chunk-6OBIWHDR.cjs.map +0 -1
  351. package/dist/chunk-AH6WD7JR.cjs.map +0 -1
  352. package/dist/chunk-CQ2TQ32Y.js.map +0 -1
  353. package/dist/chunk-NUKRL3I6.cjs.map +0 -1
  354. package/dist/chunk-QEKI3YKI.js.map +0 -1
  355. package/dist/chunk-SKOCYA55.js.map +0 -1
  356. package/dist/chunk-SKXBJ2NU.cjs.map +0 -1
  357. package/dist/chunk-T7O6K6PX.js.map +0 -1
  358. package/dist/chunk-WCLDJSMY.js +0 -456
  359. package/dist/chunk-WCLDJSMY.js.map +0 -1
  360. package/dist/compact-session-GJXJD73F.cjs +0 -59
  361. package/dist/compact-session-TSMQOIHO.js +0 -22
  362. package/dist/context-LCKNH2XI.cjs +0 -24
  363. package/dist/context-MZSKGKYR.js +0 -7
  364. package/dist/fs-session-store-4BHGIWRE.js +0 -11
  365. package/dist/fs-session-store-XZ7ZTB3A.cjs +0 -20
  366. package/dist/generate-object-N5MDZUJI.js +0 -8
  367. package/dist/generate-object-PGSP5U7N.cjs +0 -21
  368. package/dist/index-manager-AHAYJ33H.js +0 -16
  369. package/dist/index-manager-RHPFVFSC.cjs +0 -25
  370. package/dist/judge-call-DWHAJATE.js +0 -6
  371. package/dist/judge-call-EGYRC2RE.cjs +0 -23
  372. package/dist/registry-VFKX7WOP.cjs +0 -47
  373. package/dist/registry-VFP3WWQP.js +0 -10
  374. package/dist/session-transcript-HF5GEU5M.cjs +0 -63
  375. package/dist/session-transcript-P462ZRHX.js +0 -6
  376. package/dist/stream-object-BUCF5PHO.cjs +0 -21
  377. package/dist/stream-object-L57K4OFS.js +0 -8
  378. package/dist/subagents-loader-6ATCDEKN.js +0 -8
  379. package/dist/subagents-loader-X5QKODCL.cjs +0 -17
@@ -1,21 +1,21 @@
1
1
  'use strict';
2
2
 
3
- var chunkNGESVVJN_cjs = require('./chunk-NGESVVJN.cjs');
3
+ var chunk3FFAEAUJ_cjs = require('./chunk-3FFAEAUJ.cjs');
4
4
  require('./chunk-BUUUWQMB.cjs');
5
- var chunkF3YZMOAU_cjs = require('./chunk-F3YZMOAU.cjs');
6
- var chunkCQGYNZ3K_cjs = require('./chunk-CQGYNZ3K.cjs');
5
+ var chunkO7DK5PBJ_cjs = require('./chunk-O7DK5PBJ.cjs');
6
+ var chunkXWTLIGO3_cjs = require('./chunk-XWTLIGO3.cjs');
7
7
  require('./chunk-ZF2LDKQQ.cjs');
8
- require('./chunk-2C72DXQF.cjs');
9
- require('./chunk-I6TGFUCO.cjs');
10
- var chunkK3FW2XZD_cjs = require('./chunk-K3FW2XZD.cjs');
11
- require('./chunk-JTB5Q42C.cjs');
12
- var chunkNUKRL3I6_cjs = require('./chunk-NUKRL3I6.cjs');
8
+ require('./chunk-RFMBZPOW.cjs');
9
+ require('./chunk-UALX2J2Q.cjs');
10
+ var chunk4ZHTIJNE_cjs = require('./chunk-4ZHTIJNE.cjs');
11
+ require('./chunk-XL7Q7HB2.cjs');
12
+ var chunkEG4QM7ZJ_cjs = require('./chunk-EG4QM7ZJ.cjs');
13
13
  var crypto = require('crypto');
14
14
 
15
15
  function validateBatchInput(prompts, options) {
16
16
  const { concurrency } = options;
17
17
  if (concurrency !== void 0 && (!Number.isInteger(concurrency) || concurrency < 1)) {
18
- throw new chunkK3FW2XZD_cjs.ConfigurationError(
18
+ throw new chunk4ZHTIJNE_cjs.ConfigurationError(
19
19
  `Agent.batch concurrency must be a positive integer, got ${concurrency}`,
20
20
  { code: "invalid_concurrency" }
21
21
  );
@@ -24,7 +24,7 @@ function validateBatchInput(prompts, options) {
24
24
  const item = prompts[i];
25
25
  const prompt = typeof item === "string" ? item : item?.prompt;
26
26
  if (typeof prompt !== "string" || prompt.length === 0) {
27
- throw new chunkK3FW2XZD_cjs.ConfigurationError(`Agent.batch prompt at index ${i} must be a non-empty string`, {
27
+ throw new chunk4ZHTIJNE_cjs.ConfigurationError(`Agent.batch prompt at index ${i} must be a non-empty string`, {
28
28
  code: "invalid_batch_item"
29
29
  });
30
30
  }
@@ -38,7 +38,7 @@ async function batchImpl(prompts, options, deps) {
38
38
  options.providers?.credentialPoolStrategy
39
39
  );
40
40
  const exec = () => runBatch(prompts, options, deps);
41
- const withPool = () => sharedPools.size > 0 ? chunkF3YZMOAU_cjs.withCredentialPool(sharedPools, exec) : exec();
41
+ const withPool = () => sharedPools.size > 0 ? chunkO7DK5PBJ_cjs.withCredentialPool(sharedPools, exec) : exec();
42
42
  if (options.task !== void 0) {
43
43
  return wrapBatchAsTask(prompts.length, options.task, withPool);
44
44
  }
@@ -52,7 +52,7 @@ async function wrapBatchAsTask(total, taskOpt, exec) {
52
52
  ...opts.meta ?? {}
53
53
  };
54
54
  let results = [];
55
- await chunkNGESVVJN_cjs.submit({
55
+ await chunk3FFAEAUJ_cjs.submit({
56
56
  kind: "batch",
57
57
  work: async (ctx) => {
58
58
  results = await exec();
@@ -66,7 +66,7 @@ async function wrapBatchAsTask(total, taskOpt, exec) {
66
66
  allowReservedPrefix: true
67
67
  });
68
68
  for (let i = 0; i < 5e3; i++) {
69
- const h = await chunkNGESVVJN_cjs.get(id);
69
+ const h = await chunk3FFAEAUJ_cjs.get(id);
70
70
  if (h?.state === "finished" || h?.state === "error" || h?.state === "cancelled") break;
71
71
  await new Promise((r) => setTimeout(r, 5));
72
72
  }
@@ -75,7 +75,7 @@ async function wrapBatchAsTask(total, taskOpt, exec) {
75
75
  async function runBatch(prompts, options, deps) {
76
76
  const requested = options.concurrency ?? 4;
77
77
  const effective = Math.min(requested, prompts.length);
78
- const semaphore = chunkCQGYNZ3K_cjs.createSemaphore(effective);
78
+ const semaphore = chunkXWTLIGO3_cjs.createSemaphore(effective);
79
79
  const items = prompts.map(normalizeItem);
80
80
  const results = new Array(items.length);
81
81
  const counters = { completed: 0, failed: 0 };
@@ -135,7 +135,7 @@ async function runOne(item, index, options, deps) {
135
135
  try {
136
136
  await agent.dispose();
137
137
  } catch (disposeErr) {
138
- chunkNUKRL3I6_cjs.diag(
138
+ chunkEG4QM7ZJ_cjs.diag(
139
139
  `[theokit-sdk] batch: agent.dispose failed for prompt ${index}: ${disposeErr instanceof Error ? disposeErr.message : String(disposeErr)}
140
140
  `
141
141
  );
@@ -173,15 +173,15 @@ function normalizeItem(promptOrItem) {
173
173
  }
174
174
  function abortResult(item, index, signal) {
175
175
  let error;
176
- if (signal?.reason instanceof chunkK3FW2XZD_cjs.TheokitAgentError) {
176
+ if (signal?.reason instanceof chunk4ZHTIJNE_cjs.TheokitAgentError) {
177
177
  error = signal.reason;
178
178
  } else if (signal?.reason instanceof Error) {
179
- error = new chunkK3FW2XZD_cjs.TheokitAgentError(signal.reason.message, {
179
+ error = new chunk4ZHTIJNE_cjs.TheokitAgentError(signal.reason.message, {
180
180
  code: "aborted",
181
181
  cause: signal.reason
182
182
  });
183
183
  } else {
184
- error = new chunkK3FW2XZD_cjs.TheokitAgentError("Batch aborted via AbortSignal", { code: "aborted" });
184
+ error = new chunk4ZHTIJNE_cjs.TheokitAgentError("Batch aborted via AbortSignal", { code: "aborted" });
185
185
  }
186
186
  return {
187
187
  ok: false,
@@ -193,18 +193,18 @@ function abortResult(item, index, signal) {
193
193
  };
194
194
  }
195
195
  function toTheokitError(err) {
196
- if (err instanceof chunkK3FW2XZD_cjs.TheokitAgentError) return err;
196
+ if (err instanceof chunk4ZHTIJNE_cjs.TheokitAgentError) return err;
197
197
  if (err instanceof Error) {
198
- return new chunkK3FW2XZD_cjs.TheokitAgentError(err.message, { code: "unknown", cause: err });
198
+ return new chunk4ZHTIJNE_cjs.TheokitAgentError(err.message, { code: "unknown", cause: err });
199
199
  }
200
- return new chunkK3FW2XZD_cjs.TheokitAgentError(String(err), { code: "unknown" });
200
+ return new chunk4ZHTIJNE_cjs.TheokitAgentError(String(err), { code: "unknown" });
201
201
  }
202
202
  async function safeCallResult(cb, result) {
203
203
  if (cb === void 0) return;
204
204
  try {
205
205
  await cb(result);
206
206
  } catch (err) {
207
- chunkNUKRL3I6_cjs.diag(
207
+ chunkEG4QM7ZJ_cjs.diag(
208
208
  `[theokit-sdk] batch: onResult callback threw: ${err instanceof Error ? err.message : String(err)}
209
209
  `
210
210
  );
@@ -215,7 +215,7 @@ function safeCallProgress(cb, progress) {
215
215
  try {
216
216
  cb(progress);
217
217
  } catch (err) {
218
- chunkNUKRL3I6_cjs.diag(
218
+ chunkEG4QM7ZJ_cjs.diag(
219
219
  `[theokit-sdk] batch: onProgress callback threw: ${err instanceof Error ? err.message : String(err)}
220
220
  `
221
221
  );
@@ -229,11 +229,11 @@ function buildPoolsFromApiKeys(apiKeys, strategy) {
229
229
  const filtered = keys.filter((k) => typeof k === "string" && k.length > 0);
230
230
  if (filtered.length < 2) continue;
231
231
  const entries = filtered.map(
232
- (token, i) => chunkF3YZMOAU_cjs.newPooledCredential({ provider, accessToken: token, priority: i, source: "manual" })
232
+ (token, i) => chunkO7DK5PBJ_cjs.newPooledCredential({ provider, accessToken: token, priority: i, source: "manual" })
233
233
  );
234
234
  pools.set(
235
235
  provider,
236
- new chunkF3YZMOAU_cjs.CredentialPool(provider, entries, strategy?.[provider] ?? "fill_first")
236
+ new chunkO7DK5PBJ_cjs.CredentialPool(provider, entries, strategy?.[provider] ?? "fill_first")
237
237
  );
238
238
  }
239
239
  return pools;
@@ -241,5 +241,5 @@ function buildPoolsFromApiKeys(apiKeys, strategy) {
241
241
 
242
242
  exports.batchImpl = batchImpl;
243
243
  exports.validateBatchInput = validateBatchInput;
244
- //# sourceMappingURL=batch-ND32UKZS.cjs.map
245
- //# sourceMappingURL=batch-ND32UKZS.cjs.map
244
+ //# sourceMappingURL=batch-BXYTW2DP.cjs.map
245
+ //# sourceMappingURL=batch-BXYTW2DP.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/batch.ts"],"names":["ConfigurationError","withCredentialPool","randomUUID","submit","get","createSemaphore","diag","TheokitAgentError","newPooledCredential","CredentialPool"],"mappings":"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","file":"batch-ND32UKZS.cjs","sourcesContent":["/**\n * `Agent.batch(prompts, options)` core (ADRs D134-D140).\n *\n * Fans out N prompts via bounded concurrency, isolates failures per-prompt,\n * preserves input order in the result array, supports streaming callbacks\n * + AbortSignal. The credential pool (D131) is shared across all\n * in-flight agents via `withCredentialPool` ALS scope (EC-A fix).\n *\n * @internal\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { ConfigurationError, TheokitAgentError } from \"./errors.js\";\nimport { diag } from \"./internal/diagnostics.js\";\nimport { CredentialPool, newPooledCredential } from \"./internal/llm/credential-pool.js\";\nimport { withCredentialPool } from \"./internal/llm/credential-pool-context.js\";\nimport type { CredentialPoolStrategy } from \"./internal/llm/credential-pool-types.js\";\nimport { createSemaphore } from \"./internal/runtime/concurrency/async-semaphore.js\";\nimport { get as taskRegistryGet, submit as taskRegistrySubmit } from \"./internal/task/registry.js\";\nimport type { AgentOptions, SDKAgent } from \"./types/agent.js\";\nimport type { BatchItem, BatchOptions, BatchProgress, BatchResult } from \"./types/batch.js\";\n\n/** DI contract — keeps batch.ts cycle-free from agent.ts. @internal */\ninterface BatchDeps {\n create: (options: AgentOptions) => Promise<SDKAgent>;\n}\n\n/**\n * Pre-flight boundary validation for `Agent.batch` (arch-review Gap 3).\n *\n * Mirrors the in-repo `validateAgentOptions` / `validateCronExpression`\n * pattern: throws `ConfigurationError` with a stable code on the first\n * violation, returns silently otherwise. Pure — no I/O.\n *\n * Rules:\n * - `concurrency`, when provided, must be a positive integer (rejects\n * 0/negative/non-integer/NaN/Infinity). Previously this was caught only\n * incidentally deep inside `createSemaphore` with a leaky \"permits\"\n * message, AND after task wrapping (dangling Task on invalid input).\n * - every prompt item must carry a non-empty string prompt. Previously\n * `normalizeItem` passed `prompt: \"\"` / non-string straight to\n * `agent.send`. (Whitespace-only strings are intentionally NOT rejected —\n * an empty string is a structural error; judging content is not this\n * validator's job, and the repo's property tests treat any length>=1\n * string as a valid prompt.)\n *\n * @internal\n */\nexport function validateBatchInput(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n): void {\n const { concurrency } = options;\n if (concurrency !== undefined && (!Number.isInteger(concurrency) || concurrency < 1)) {\n throw new ConfigurationError(\n `Agent.batch concurrency must be a positive integer, got ${concurrency}`,\n { code: \"invalid_concurrency\" },\n );\n }\n for (let i = 0; i < prompts.length; i++) {\n const item = prompts[i];\n const prompt = typeof item === \"string\" ? item : item?.prompt;\n if (typeof prompt !== \"string\" || prompt.length === 0) {\n throw new ConfigurationError(`Agent.batch prompt at index ${i} must be a non-empty string`, {\n code: \"invalid_batch_item\",\n });\n }\n }\n}\n\n/**\n * Run N prompts in parallel with bounded concurrency.\n *\n * @internal\n */\nexport async function batchImpl(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult[]> {\n // EC-1: empty array → no work, no agents created.\n if (prompts.length === 0) return [];\n\n // Pre-flight boundary validation (arch-review Gap 3). MUST run before pool\n // build AND before wrapBatchAsTask so invalid input never registers a\n // dangling Task or builds a credential pool (fail-fast, Rule 8).\n validateBatchInput(prompts, options);\n\n // EC-A fix: build credential pools ONCE and share via AsyncLocalStorage.\n // Without this each Agent.create() would build its own pool from identical\n // apiKeys → 4× rate-limit wastage per concurrency window.\n const sharedPools = buildPoolsFromApiKeys(\n options.providers?.apiKeys,\n options.providers?.credentialPoolStrategy,\n );\n const exec = (): Promise<BatchResult[]> => runBatch(prompts, options, deps);\n const withPool = (): Promise<BatchResult[]> =>\n sharedPools.size > 0 ? withCredentialPool(sharedPools, exec) : exec();\n // T3.3: opt-in Task wrapping (ADRs D363, D374). Register the whole\n // batch as a single Task (kind=\"batch\") with `b-` prefix (D368/EC-5).\n if (options.task !== undefined) {\n return wrapBatchAsTask(prompts.length, options.task, withPool);\n }\n return withPool();\n}\n\nasync function wrapBatchAsTask(\n total: number,\n taskOpt: true | { id?: string; meta?: Record<string, unknown> },\n exec: () => Promise<BatchResult[]>,\n): Promise<BatchResult[]> {\n const opts = taskOpt === true ? {} : taskOpt;\n const id = opts.id ?? `b-${randomUUID()}`;\n const meta: Record<string, unknown> = {\n total,\n ...(opts.meta ?? {}),\n };\n let results: BatchResult[] = [];\n await taskRegistrySubmit({\n kind: \"batch\",\n work: async (ctx) => {\n results = await exec();\n const succeeded = results.filter((r) => r.ok).length;\n const failed = results.length - succeeded;\n ctx.emit({ total: results.length, succeeded, failed });\n return { total: results.length, succeeded, failed };\n },\n id,\n meta,\n allowReservedPrefix: true,\n });\n // submit returns immediately with a queued handle. Wait for terminal.\n for (let i = 0; i < 5000; i++) {\n const h = await taskRegistryGet(id);\n if (h?.state === \"finished\" || h?.state === \"error\" || h?.state === \"cancelled\") break;\n await new Promise((r) => setTimeout(r, 5));\n }\n return results;\n}\n\nasync function runBatch(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult[]> {\n const requested = options.concurrency ?? 4;\n // createSemaphore throws on invalid (EC-2).\n // EC-3: cap to prompts.length to avoid idle workers.\n const effective = Math.min(requested, prompts.length);\n const semaphore = createSemaphore(effective);\n const items = prompts.map(normalizeItem);\n const results: BatchResult[] = new Array(items.length);\n const counters = { completed: 0, failed: 0 };\n let aborted = false;\n\n const onAbort = (): void => {\n aborted = true;\n };\n options.signal?.addEventListener(\"abort\", onAbort);\n // EC-C: pre-aborted signal — treat as already-aborted before any work.\n if (options.signal?.aborted === true) aborted = true;\n\n try {\n await Promise.all(\n items.map(async (item, index) => {\n const release = await semaphore.acquire();\n try {\n if (aborted) {\n results[index] = abortResult(item, index, options.signal);\n } else {\n results[index] = await runOne(item, index, options, deps);\n }\n if (results[index].ok) counters.completed += 1;\n else counters.failed += 1;\n // B-110 (measured 2026-08-19): `onResult` used to run AFTER `release()`, so a caller who\n // asked for `concurrency: 1` still got overlapping `onResult` invocations — the permit was\n // already returned before the callback ran. `concurrency` is documented (`types/batch.ts`)\n // to bound the whole per-item lifecycle, callback included, so the permit is now held\n // until `onResult` finishes: this call moved inside the `try` the `finally` below wraps.\n await safeCallResult(options.onResult, results[index]);\n } finally {\n release();\n }\n safeCallProgress(options.onProgress, {\n total: items.length,\n completed: counters.completed,\n failed: counters.failed,\n inFlight: semaphore.inFlight(),\n pending: Math.max(0, semaphore.pending() - semaphore.inFlight()),\n });\n }),\n );\n } finally {\n options.signal?.removeEventListener(\"abort\", onAbort);\n }\n\n return options.filter ? results.filter(options.filter) : results;\n}\n\nasync function runOne(\n item: BatchItem,\n index: number,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult> {\n const t0 = Date.now();\n const agentOpts = buildAgentOptions(item, options);\n\n try {\n const agent = await deps.create(agentOpts);\n try {\n const run = await agent.send(item.prompt);\n const result = await run.wait();\n return {\n ok: true,\n index,\n prompt: item.prompt,\n result,\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: Date.now() - t0,\n };\n } finally {\n // EC-8: dispose failure → stderr warn, don't fail the result.\n try {\n await agent.dispose();\n } catch (disposeErr) {\n // theokit#147 — the interceptable channel; a batch run must not write onto a TUI's frame.\n diag(\n `[theokit-sdk] batch: agent.dispose failed for prompt ${index}: ${\n disposeErr instanceof Error ? disposeErr.message : String(disposeErr)\n }\\n`,\n );\n }\n }\n } catch (err) {\n return {\n ok: false,\n index,\n prompt: item.prompt,\n error: toTheokitError(err),\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: Date.now() - t0,\n };\n }\n}\n\nfunction buildAgentOptions(item: BatchItem, options: BatchOptions): AgentOptions {\n const {\n concurrency: _c,\n filter: _f,\n onResult: _or,\n onProgress: _op,\n signal: _s,\n task: _t,\n ...rest\n } = options;\n void _c;\n void _f;\n void _or;\n void _op;\n void _s;\n void _t;\n const agentOpts = rest as AgentOptions;\n if (item.systemPrompt !== undefined) {\n return { ...agentOpts, systemPrompt: item.systemPrompt };\n }\n return agentOpts;\n}\n\nfunction normalizeItem(promptOrItem: string | BatchItem): BatchItem {\n return typeof promptOrItem === \"string\" ? { prompt: promptOrItem } : promptOrItem;\n}\n\nfunction abortResult(item: BatchItem, index: number, signal?: AbortSignal): BatchResult {\n // EC-D: propagate signal.reason when set (preserves caller's error).\n let error: TheokitAgentError;\n if (signal?.reason instanceof TheokitAgentError) {\n error = signal.reason;\n } else if (signal?.reason instanceof Error) {\n error = new TheokitAgentError(signal.reason.message, {\n code: \"aborted\",\n cause: signal.reason,\n });\n } else {\n error = new TheokitAgentError(\"Batch aborted via AbortSignal\", { code: \"aborted\" });\n }\n return {\n ok: false,\n index,\n prompt: item.prompt,\n error,\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: 0,\n };\n}\n\nfunction toTheokitError(err: unknown): TheokitAgentError {\n if (err instanceof TheokitAgentError) return err;\n if (err instanceof Error) {\n return new TheokitAgentError(err.message, { code: \"unknown\", cause: err });\n }\n return new TheokitAgentError(String(err), { code: \"unknown\" });\n}\n\nasync function safeCallResult(cb: BatchOptions[\"onResult\"], result: BatchResult): Promise<void> {\n if (cb === undefined) return;\n try {\n await cb(result);\n } catch (err) {\n diag(\n `[theokit-sdk] batch: onResult callback threw: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n}\n\nfunction safeCallProgress(cb: BatchOptions[\"onProgress\"], progress: BatchProgress): void {\n if (cb === undefined) return;\n try {\n cb(progress);\n } catch (err) {\n diag(\n `[theokit-sdk] batch: onProgress callback threw: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n}\n\n/**\n * EC-A: construct shared pools from options.apiKeys. Empty/invalid → empty Map.\n *\n * @internal\n */\nfunction buildPoolsFromApiKeys(\n apiKeys: Record<string, string[]> | undefined,\n strategy: Record<string, CredentialPoolStrategy> | undefined,\n): Map<string, CredentialPool> {\n const pools = new Map<string, CredentialPool>();\n if (apiKeys === undefined) return pools;\n for (const [provider, keys] of Object.entries(apiKeys)) {\n if (!Array.isArray(keys)) continue;\n const filtered = keys.filter((k): k is string => typeof k === \"string\" && k.length > 0);\n if (filtered.length < 2) continue; // 1-key pools aren't pools\n const entries = filtered.map((token, i) =>\n newPooledCredential({ provider, accessToken: token, priority: i, source: \"manual\" }),\n );\n pools.set(\n provider,\n new CredentialPool(provider, entries, strategy?.[provider] ?? \"fill_first\"),\n );\n }\n return pools;\n}\n"]}
1
+ {"version":3,"sources":["../src/batch.ts"],"names":["ConfigurationError","withCredentialPool","randomUUID","submit","get","createSemaphore","diag","TheokitAgentError","newPooledCredential","CredentialPool"],"mappings":"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","file":"batch-BXYTW2DP.cjs","sourcesContent":["/**\n * `Agent.batch(prompts, options)` core (ADRs D134-D140).\n *\n * Fans out N prompts via bounded concurrency, isolates failures per-prompt,\n * preserves input order in the result array, supports streaming callbacks\n * + AbortSignal. The credential pool (D131) is shared across all\n * in-flight agents via `withCredentialPool` ALS scope (EC-A fix).\n *\n * @internal\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { ConfigurationError, TheokitAgentError } from \"./errors.js\";\nimport { diag } from \"./internal/diagnostics.js\";\nimport { CredentialPool, newPooledCredential } from \"./internal/llm/credential-pool.js\";\nimport { withCredentialPool } from \"./internal/llm/credential-pool-context.js\";\nimport type { CredentialPoolStrategy } from \"./internal/llm/credential-pool-types.js\";\nimport { createSemaphore } from \"./internal/runtime/concurrency/async-semaphore.js\";\nimport { get as taskRegistryGet, submit as taskRegistrySubmit } from \"./internal/task/registry.js\";\nimport type { AgentOptions, SDKAgent } from \"./types/agent.js\";\nimport type { BatchItem, BatchOptions, BatchProgress, BatchResult } from \"./types/batch.js\";\n\n/** DI contract — keeps batch.ts cycle-free from agent.ts. @internal */\ninterface BatchDeps {\n create: (options: AgentOptions) => Promise<SDKAgent>;\n}\n\n/**\n * Pre-flight boundary validation for `Agent.batch` (arch-review Gap 3).\n *\n * Mirrors the in-repo `validateAgentOptions` / `validateCronExpression`\n * pattern: throws `ConfigurationError` with a stable code on the first\n * violation, returns silently otherwise. Pure — no I/O.\n *\n * Rules:\n * - `concurrency`, when provided, must be a positive integer (rejects\n * 0/negative/non-integer/NaN/Infinity). Previously this was caught only\n * incidentally deep inside `createSemaphore` with a leaky \"permits\"\n * message, AND after task wrapping (dangling Task on invalid input).\n * - every prompt item must carry a non-empty string prompt. Previously\n * `normalizeItem` passed `prompt: \"\"` / non-string straight to\n * `agent.send`. (Whitespace-only strings are intentionally NOT rejected —\n * an empty string is a structural error; judging content is not this\n * validator's job, and the repo's property tests treat any length>=1\n * string as a valid prompt.)\n *\n * @internal\n */\nexport function validateBatchInput(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n): void {\n const { concurrency } = options;\n if (concurrency !== undefined && (!Number.isInteger(concurrency) || concurrency < 1)) {\n throw new ConfigurationError(\n `Agent.batch concurrency must be a positive integer, got ${concurrency}`,\n { code: \"invalid_concurrency\" },\n );\n }\n for (let i = 0; i < prompts.length; i++) {\n const item = prompts[i];\n const prompt = typeof item === \"string\" ? item : item?.prompt;\n if (typeof prompt !== \"string\" || prompt.length === 0) {\n throw new ConfigurationError(`Agent.batch prompt at index ${i} must be a non-empty string`, {\n code: \"invalid_batch_item\",\n });\n }\n }\n}\n\n/**\n * Run N prompts in parallel with bounded concurrency.\n *\n * @internal\n */\nexport async function batchImpl(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult[]> {\n // EC-1: empty array → no work, no agents created.\n if (prompts.length === 0) return [];\n\n // Pre-flight boundary validation (arch-review Gap 3). MUST run before pool\n // build AND before wrapBatchAsTask so invalid input never registers a\n // dangling Task or builds a credential pool (fail-fast, Rule 8).\n validateBatchInput(prompts, options);\n\n // EC-A fix: build credential pools ONCE and share via AsyncLocalStorage.\n // Without this each Agent.create() would build its own pool from identical\n // apiKeys → 4× rate-limit wastage per concurrency window.\n const sharedPools = buildPoolsFromApiKeys(\n options.providers?.apiKeys,\n options.providers?.credentialPoolStrategy,\n );\n const exec = (): Promise<BatchResult[]> => runBatch(prompts, options, deps);\n const withPool = (): Promise<BatchResult[]> =>\n sharedPools.size > 0 ? withCredentialPool(sharedPools, exec) : exec();\n // T3.3: opt-in Task wrapping (ADRs D363, D374). Register the whole\n // batch as a single Task (kind=\"batch\") with `b-` prefix (D368/EC-5).\n if (options.task !== undefined) {\n return wrapBatchAsTask(prompts.length, options.task, withPool);\n }\n return withPool();\n}\n\nasync function wrapBatchAsTask(\n total: number,\n taskOpt: true | { id?: string; meta?: Record<string, unknown> },\n exec: () => Promise<BatchResult[]>,\n): Promise<BatchResult[]> {\n const opts = taskOpt === true ? {} : taskOpt;\n const id = opts.id ?? `b-${randomUUID()}`;\n const meta: Record<string, unknown> = {\n total,\n ...(opts.meta ?? {}),\n };\n let results: BatchResult[] = [];\n await taskRegistrySubmit({\n kind: \"batch\",\n work: async (ctx) => {\n results = await exec();\n const succeeded = results.filter((r) => r.ok).length;\n const failed = results.length - succeeded;\n ctx.emit({ total: results.length, succeeded, failed });\n return { total: results.length, succeeded, failed };\n },\n id,\n meta,\n allowReservedPrefix: true,\n });\n // submit returns immediately with a queued handle. Wait for terminal.\n for (let i = 0; i < 5000; i++) {\n const h = await taskRegistryGet(id);\n if (h?.state === \"finished\" || h?.state === \"error\" || h?.state === \"cancelled\") break;\n await new Promise((r) => setTimeout(r, 5));\n }\n return results;\n}\n\nasync function runBatch(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult[]> {\n const requested = options.concurrency ?? 4;\n // createSemaphore throws on invalid (EC-2).\n // EC-3: cap to prompts.length to avoid idle workers.\n const effective = Math.min(requested, prompts.length);\n const semaphore = createSemaphore(effective);\n const items = prompts.map(normalizeItem);\n const results: BatchResult[] = new Array(items.length);\n const counters = { completed: 0, failed: 0 };\n let aborted = false;\n\n const onAbort = (): void => {\n aborted = true;\n };\n options.signal?.addEventListener(\"abort\", onAbort);\n // EC-C: pre-aborted signal — treat as already-aborted before any work.\n if (options.signal?.aborted === true) aborted = true;\n\n try {\n await Promise.all(\n items.map(async (item, index) => {\n const release = await semaphore.acquire();\n try {\n if (aborted) {\n results[index] = abortResult(item, index, options.signal);\n } else {\n results[index] = await runOne(item, index, options, deps);\n }\n if (results[index].ok) counters.completed += 1;\n else counters.failed += 1;\n // B-110 (measured 2026-08-19): `onResult` used to run AFTER `release()`, so a caller who\n // asked for `concurrency: 1` still got overlapping `onResult` invocations — the permit was\n // already returned before the callback ran. `concurrency` is documented (`types/batch.ts`)\n // to bound the whole per-item lifecycle, callback included, so the permit is now held\n // until `onResult` finishes: this call moved inside the `try` the `finally` below wraps.\n await safeCallResult(options.onResult, results[index]);\n } finally {\n release();\n }\n safeCallProgress(options.onProgress, {\n total: items.length,\n completed: counters.completed,\n failed: counters.failed,\n inFlight: semaphore.inFlight(),\n pending: Math.max(0, semaphore.pending() - semaphore.inFlight()),\n });\n }),\n );\n } finally {\n options.signal?.removeEventListener(\"abort\", onAbort);\n }\n\n return options.filter ? results.filter(options.filter) : results;\n}\n\nasync function runOne(\n item: BatchItem,\n index: number,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult> {\n const t0 = Date.now();\n const agentOpts = buildAgentOptions(item, options);\n\n try {\n const agent = await deps.create(agentOpts);\n try {\n const run = await agent.send(item.prompt);\n const result = await run.wait();\n return {\n ok: true,\n index,\n prompt: item.prompt,\n result,\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: Date.now() - t0,\n };\n } finally {\n // EC-8: dispose failure → stderr warn, don't fail the result.\n try {\n await agent.dispose();\n } catch (disposeErr) {\n // theokit#147 — the interceptable channel; a batch run must not write onto a TUI's frame.\n diag(\n `[theokit-sdk] batch: agent.dispose failed for prompt ${index}: ${\n disposeErr instanceof Error ? disposeErr.message : String(disposeErr)\n }\\n`,\n );\n }\n }\n } catch (err) {\n return {\n ok: false,\n index,\n prompt: item.prompt,\n error: toTheokitError(err),\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: Date.now() - t0,\n };\n }\n}\n\nfunction buildAgentOptions(item: BatchItem, options: BatchOptions): AgentOptions {\n const {\n concurrency: _c,\n filter: _f,\n onResult: _or,\n onProgress: _op,\n signal: _s,\n task: _t,\n ...rest\n } = options;\n void _c;\n void _f;\n void _or;\n void _op;\n void _s;\n void _t;\n const agentOpts = rest as AgentOptions;\n if (item.systemPrompt !== undefined) {\n return { ...agentOpts, systemPrompt: item.systemPrompt };\n }\n return agentOpts;\n}\n\nfunction normalizeItem(promptOrItem: string | BatchItem): BatchItem {\n return typeof promptOrItem === \"string\" ? { prompt: promptOrItem } : promptOrItem;\n}\n\nfunction abortResult(item: BatchItem, index: number, signal?: AbortSignal): BatchResult {\n // EC-D: propagate signal.reason when set (preserves caller's error).\n let error: TheokitAgentError;\n if (signal?.reason instanceof TheokitAgentError) {\n error = signal.reason;\n } else if (signal?.reason instanceof Error) {\n error = new TheokitAgentError(signal.reason.message, {\n code: \"aborted\",\n cause: signal.reason,\n });\n } else {\n error = new TheokitAgentError(\"Batch aborted via AbortSignal\", { code: \"aborted\" });\n }\n return {\n ok: false,\n index,\n prompt: item.prompt,\n error,\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: 0,\n };\n}\n\nfunction toTheokitError(err: unknown): TheokitAgentError {\n if (err instanceof TheokitAgentError) return err;\n if (err instanceof Error) {\n return new TheokitAgentError(err.message, { code: \"unknown\", cause: err });\n }\n return new TheokitAgentError(String(err), { code: \"unknown\" });\n}\n\nasync function safeCallResult(cb: BatchOptions[\"onResult\"], result: BatchResult): Promise<void> {\n if (cb === undefined) return;\n try {\n await cb(result);\n } catch (err) {\n diag(\n `[theokit-sdk] batch: onResult callback threw: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n}\n\nfunction safeCallProgress(cb: BatchOptions[\"onProgress\"], progress: BatchProgress): void {\n if (cb === undefined) return;\n try {\n cb(progress);\n } catch (err) {\n diag(\n `[theokit-sdk] batch: onProgress callback threw: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n}\n\n/**\n * EC-A: construct shared pools from options.apiKeys. Empty/invalid → empty Map.\n *\n * @internal\n */\nfunction buildPoolsFromApiKeys(\n apiKeys: Record<string, string[]> | undefined,\n strategy: Record<string, CredentialPoolStrategy> | undefined,\n): Map<string, CredentialPool> {\n const pools = new Map<string, CredentialPool>();\n if (apiKeys === undefined) return pools;\n for (const [provider, keys] of Object.entries(apiKeys)) {\n if (!Array.isArray(keys)) continue;\n const filtered = keys.filter((k): k is string => typeof k === \"string\" && k.length > 0);\n if (filtered.length < 2) continue; // 1-key pools aren't pools\n const entries = filtered.map((token, i) =>\n newPooledCredential({ provider, accessToken: token, priority: i, source: \"manual\" }),\n );\n pools.set(\n provider,\n new CredentialPool(provider, entries, strategy?.[provider] ?? \"fill_first\"),\n );\n }\n return pools;\n}\n"]}
@@ -1,13 +1,13 @@
1
- import { submit, get } from './chunk-SUKXXLWD.js';
1
+ import { submit, get } from './chunk-A46SWMIF.js';
2
2
  import './chunk-K2BQQ445.js';
3
- import { newPooledCredential, CredentialPool, withCredentialPool } from './chunk-3E77SX4H.js';
4
- import { createSemaphore } from './chunk-OC4NTGMN.js';
3
+ import { newPooledCredential, CredentialPool, withCredentialPool } from './chunk-TAZVKYWJ.js';
4
+ import { createSemaphore } from './chunk-4QZSA2HJ.js';
5
5
  import './chunk-Q5EWJPRY.js';
6
- import './chunk-RUDY2GTT.js';
7
- import './chunk-VF7EWVDG.js';
8
- import { ConfigurationError, TheokitAgentError } from './chunk-IDCKSLYH.js';
9
- import './chunk-T7XEKOVW.js';
10
- import { diag } from './chunk-T7O6K6PX.js';
6
+ import './chunk-KQRW2GPZ.js';
7
+ import './chunk-2GUYQR5P.js';
8
+ import { ConfigurationError, TheokitAgentError } from './chunk-ZZMZWBR6.js';
9
+ import './chunk-D4CUGAKZ.js';
10
+ import { diag } from './chunk-XEQ3TM66.js';
11
11
  import { randomUUID } from 'crypto';
12
12
 
13
13
  function validateBatchInput(prompts, options) {
@@ -238,5 +238,5 @@ function buildPoolsFromApiKeys(apiKeys, strategy) {
238
238
  }
239
239
 
240
240
  export { batchImpl, validateBatchInput };
241
- //# sourceMappingURL=batch-2TGJMNCJ.js.map
242
- //# sourceMappingURL=batch-2TGJMNCJ.js.map
241
+ //# sourceMappingURL=batch-L4ZXS46M.js.map
242
+ //# sourceMappingURL=batch-L4ZXS46M.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/batch.ts"],"names":[],"mappings":"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","file":"batch-2TGJMNCJ.js","sourcesContent":["/**\n * `Agent.batch(prompts, options)` core (ADRs D134-D140).\n *\n * Fans out N prompts via bounded concurrency, isolates failures per-prompt,\n * preserves input order in the result array, supports streaming callbacks\n * + AbortSignal. The credential pool (D131) is shared across all\n * in-flight agents via `withCredentialPool` ALS scope (EC-A fix).\n *\n * @internal\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { ConfigurationError, TheokitAgentError } from \"./errors.js\";\nimport { diag } from \"./internal/diagnostics.js\";\nimport { CredentialPool, newPooledCredential } from \"./internal/llm/credential-pool.js\";\nimport { withCredentialPool } from \"./internal/llm/credential-pool-context.js\";\nimport type { CredentialPoolStrategy } from \"./internal/llm/credential-pool-types.js\";\nimport { createSemaphore } from \"./internal/runtime/concurrency/async-semaphore.js\";\nimport { get as taskRegistryGet, submit as taskRegistrySubmit } from \"./internal/task/registry.js\";\nimport type { AgentOptions, SDKAgent } from \"./types/agent.js\";\nimport type { BatchItem, BatchOptions, BatchProgress, BatchResult } from \"./types/batch.js\";\n\n/** DI contract — keeps batch.ts cycle-free from agent.ts. @internal */\ninterface BatchDeps {\n create: (options: AgentOptions) => Promise<SDKAgent>;\n}\n\n/**\n * Pre-flight boundary validation for `Agent.batch` (arch-review Gap 3).\n *\n * Mirrors the in-repo `validateAgentOptions` / `validateCronExpression`\n * pattern: throws `ConfigurationError` with a stable code on the first\n * violation, returns silently otherwise. Pure — no I/O.\n *\n * Rules:\n * - `concurrency`, when provided, must be a positive integer (rejects\n * 0/negative/non-integer/NaN/Infinity). Previously this was caught only\n * incidentally deep inside `createSemaphore` with a leaky \"permits\"\n * message, AND after task wrapping (dangling Task on invalid input).\n * - every prompt item must carry a non-empty string prompt. Previously\n * `normalizeItem` passed `prompt: \"\"` / non-string straight to\n * `agent.send`. (Whitespace-only strings are intentionally NOT rejected —\n * an empty string is a structural error; judging content is not this\n * validator's job, and the repo's property tests treat any length>=1\n * string as a valid prompt.)\n *\n * @internal\n */\nexport function validateBatchInput(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n): void {\n const { concurrency } = options;\n if (concurrency !== undefined && (!Number.isInteger(concurrency) || concurrency < 1)) {\n throw new ConfigurationError(\n `Agent.batch concurrency must be a positive integer, got ${concurrency}`,\n { code: \"invalid_concurrency\" },\n );\n }\n for (let i = 0; i < prompts.length; i++) {\n const item = prompts[i];\n const prompt = typeof item === \"string\" ? item : item?.prompt;\n if (typeof prompt !== \"string\" || prompt.length === 0) {\n throw new ConfigurationError(`Agent.batch prompt at index ${i} must be a non-empty string`, {\n code: \"invalid_batch_item\",\n });\n }\n }\n}\n\n/**\n * Run N prompts in parallel with bounded concurrency.\n *\n * @internal\n */\nexport async function batchImpl(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult[]> {\n // EC-1: empty array → no work, no agents created.\n if (prompts.length === 0) return [];\n\n // Pre-flight boundary validation (arch-review Gap 3). MUST run before pool\n // build AND before wrapBatchAsTask so invalid input never registers a\n // dangling Task or builds a credential pool (fail-fast, Rule 8).\n validateBatchInput(prompts, options);\n\n // EC-A fix: build credential pools ONCE and share via AsyncLocalStorage.\n // Without this each Agent.create() would build its own pool from identical\n // apiKeys → 4× rate-limit wastage per concurrency window.\n const sharedPools = buildPoolsFromApiKeys(\n options.providers?.apiKeys,\n options.providers?.credentialPoolStrategy,\n );\n const exec = (): Promise<BatchResult[]> => runBatch(prompts, options, deps);\n const withPool = (): Promise<BatchResult[]> =>\n sharedPools.size > 0 ? withCredentialPool(sharedPools, exec) : exec();\n // T3.3: opt-in Task wrapping (ADRs D363, D374). Register the whole\n // batch as a single Task (kind=\"batch\") with `b-` prefix (D368/EC-5).\n if (options.task !== undefined) {\n return wrapBatchAsTask(prompts.length, options.task, withPool);\n }\n return withPool();\n}\n\nasync function wrapBatchAsTask(\n total: number,\n taskOpt: true | { id?: string; meta?: Record<string, unknown> },\n exec: () => Promise<BatchResult[]>,\n): Promise<BatchResult[]> {\n const opts = taskOpt === true ? {} : taskOpt;\n const id = opts.id ?? `b-${randomUUID()}`;\n const meta: Record<string, unknown> = {\n total,\n ...(opts.meta ?? {}),\n };\n let results: BatchResult[] = [];\n await taskRegistrySubmit({\n kind: \"batch\",\n work: async (ctx) => {\n results = await exec();\n const succeeded = results.filter((r) => r.ok).length;\n const failed = results.length - succeeded;\n ctx.emit({ total: results.length, succeeded, failed });\n return { total: results.length, succeeded, failed };\n },\n id,\n meta,\n allowReservedPrefix: true,\n });\n // submit returns immediately with a queued handle. Wait for terminal.\n for (let i = 0; i < 5000; i++) {\n const h = await taskRegistryGet(id);\n if (h?.state === \"finished\" || h?.state === \"error\" || h?.state === \"cancelled\") break;\n await new Promise((r) => setTimeout(r, 5));\n }\n return results;\n}\n\nasync function runBatch(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult[]> {\n const requested = options.concurrency ?? 4;\n // createSemaphore throws on invalid (EC-2).\n // EC-3: cap to prompts.length to avoid idle workers.\n const effective = Math.min(requested, prompts.length);\n const semaphore = createSemaphore(effective);\n const items = prompts.map(normalizeItem);\n const results: BatchResult[] = new Array(items.length);\n const counters = { completed: 0, failed: 0 };\n let aborted = false;\n\n const onAbort = (): void => {\n aborted = true;\n };\n options.signal?.addEventListener(\"abort\", onAbort);\n // EC-C: pre-aborted signal — treat as already-aborted before any work.\n if (options.signal?.aborted === true) aborted = true;\n\n try {\n await Promise.all(\n items.map(async (item, index) => {\n const release = await semaphore.acquire();\n try {\n if (aborted) {\n results[index] = abortResult(item, index, options.signal);\n } else {\n results[index] = await runOne(item, index, options, deps);\n }\n if (results[index].ok) counters.completed += 1;\n else counters.failed += 1;\n // B-110 (measured 2026-08-19): `onResult` used to run AFTER `release()`, so a caller who\n // asked for `concurrency: 1` still got overlapping `onResult` invocations — the permit was\n // already returned before the callback ran. `concurrency` is documented (`types/batch.ts`)\n // to bound the whole per-item lifecycle, callback included, so the permit is now held\n // until `onResult` finishes: this call moved inside the `try` the `finally` below wraps.\n await safeCallResult(options.onResult, results[index]);\n } finally {\n release();\n }\n safeCallProgress(options.onProgress, {\n total: items.length,\n completed: counters.completed,\n failed: counters.failed,\n inFlight: semaphore.inFlight(),\n pending: Math.max(0, semaphore.pending() - semaphore.inFlight()),\n });\n }),\n );\n } finally {\n options.signal?.removeEventListener(\"abort\", onAbort);\n }\n\n return options.filter ? results.filter(options.filter) : results;\n}\n\nasync function runOne(\n item: BatchItem,\n index: number,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult> {\n const t0 = Date.now();\n const agentOpts = buildAgentOptions(item, options);\n\n try {\n const agent = await deps.create(agentOpts);\n try {\n const run = await agent.send(item.prompt);\n const result = await run.wait();\n return {\n ok: true,\n index,\n prompt: item.prompt,\n result,\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: Date.now() - t0,\n };\n } finally {\n // EC-8: dispose failure → stderr warn, don't fail the result.\n try {\n await agent.dispose();\n } catch (disposeErr) {\n // theokit#147 — the interceptable channel; a batch run must not write onto a TUI's frame.\n diag(\n `[theokit-sdk] batch: agent.dispose failed for prompt ${index}: ${\n disposeErr instanceof Error ? disposeErr.message : String(disposeErr)\n }\\n`,\n );\n }\n }\n } catch (err) {\n return {\n ok: false,\n index,\n prompt: item.prompt,\n error: toTheokitError(err),\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: Date.now() - t0,\n };\n }\n}\n\nfunction buildAgentOptions(item: BatchItem, options: BatchOptions): AgentOptions {\n const {\n concurrency: _c,\n filter: _f,\n onResult: _or,\n onProgress: _op,\n signal: _s,\n task: _t,\n ...rest\n } = options;\n void _c;\n void _f;\n void _or;\n void _op;\n void _s;\n void _t;\n const agentOpts = rest as AgentOptions;\n if (item.systemPrompt !== undefined) {\n return { ...agentOpts, systemPrompt: item.systemPrompt };\n }\n return agentOpts;\n}\n\nfunction normalizeItem(promptOrItem: string | BatchItem): BatchItem {\n return typeof promptOrItem === \"string\" ? { prompt: promptOrItem } : promptOrItem;\n}\n\nfunction abortResult(item: BatchItem, index: number, signal?: AbortSignal): BatchResult {\n // EC-D: propagate signal.reason when set (preserves caller's error).\n let error: TheokitAgentError;\n if (signal?.reason instanceof TheokitAgentError) {\n error = signal.reason;\n } else if (signal?.reason instanceof Error) {\n error = new TheokitAgentError(signal.reason.message, {\n code: \"aborted\",\n cause: signal.reason,\n });\n } else {\n error = new TheokitAgentError(\"Batch aborted via AbortSignal\", { code: \"aborted\" });\n }\n return {\n ok: false,\n index,\n prompt: item.prompt,\n error,\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: 0,\n };\n}\n\nfunction toTheokitError(err: unknown): TheokitAgentError {\n if (err instanceof TheokitAgentError) return err;\n if (err instanceof Error) {\n return new TheokitAgentError(err.message, { code: \"unknown\", cause: err });\n }\n return new TheokitAgentError(String(err), { code: \"unknown\" });\n}\n\nasync function safeCallResult(cb: BatchOptions[\"onResult\"], result: BatchResult): Promise<void> {\n if (cb === undefined) return;\n try {\n await cb(result);\n } catch (err) {\n diag(\n `[theokit-sdk] batch: onResult callback threw: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n}\n\nfunction safeCallProgress(cb: BatchOptions[\"onProgress\"], progress: BatchProgress): void {\n if (cb === undefined) return;\n try {\n cb(progress);\n } catch (err) {\n diag(\n `[theokit-sdk] batch: onProgress callback threw: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n}\n\n/**\n * EC-A: construct shared pools from options.apiKeys. Empty/invalid → empty Map.\n *\n * @internal\n */\nfunction buildPoolsFromApiKeys(\n apiKeys: Record<string, string[]> | undefined,\n strategy: Record<string, CredentialPoolStrategy> | undefined,\n): Map<string, CredentialPool> {\n const pools = new Map<string, CredentialPool>();\n if (apiKeys === undefined) return pools;\n for (const [provider, keys] of Object.entries(apiKeys)) {\n if (!Array.isArray(keys)) continue;\n const filtered = keys.filter((k): k is string => typeof k === \"string\" && k.length > 0);\n if (filtered.length < 2) continue; // 1-key pools aren't pools\n const entries = filtered.map((token, i) =>\n newPooledCredential({ provider, accessToken: token, priority: i, source: \"manual\" }),\n );\n pools.set(\n provider,\n new CredentialPool(provider, entries, strategy?.[provider] ?? \"fill_first\"),\n );\n }\n return pools;\n}\n"]}
1
+ {"version":3,"sources":["../src/batch.ts"],"names":[],"mappings":"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","file":"batch-L4ZXS46M.js","sourcesContent":["/**\n * `Agent.batch(prompts, options)` core (ADRs D134-D140).\n *\n * Fans out N prompts via bounded concurrency, isolates failures per-prompt,\n * preserves input order in the result array, supports streaming callbacks\n * + AbortSignal. The credential pool (D131) is shared across all\n * in-flight agents via `withCredentialPool` ALS scope (EC-A fix).\n *\n * @internal\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { ConfigurationError, TheokitAgentError } from \"./errors.js\";\nimport { diag } from \"./internal/diagnostics.js\";\nimport { CredentialPool, newPooledCredential } from \"./internal/llm/credential-pool.js\";\nimport { withCredentialPool } from \"./internal/llm/credential-pool-context.js\";\nimport type { CredentialPoolStrategy } from \"./internal/llm/credential-pool-types.js\";\nimport { createSemaphore } from \"./internal/runtime/concurrency/async-semaphore.js\";\nimport { get as taskRegistryGet, submit as taskRegistrySubmit } from \"./internal/task/registry.js\";\nimport type { AgentOptions, SDKAgent } from \"./types/agent.js\";\nimport type { BatchItem, BatchOptions, BatchProgress, BatchResult } from \"./types/batch.js\";\n\n/** DI contract — keeps batch.ts cycle-free from agent.ts. @internal */\ninterface BatchDeps {\n create: (options: AgentOptions) => Promise<SDKAgent>;\n}\n\n/**\n * Pre-flight boundary validation for `Agent.batch` (arch-review Gap 3).\n *\n * Mirrors the in-repo `validateAgentOptions` / `validateCronExpression`\n * pattern: throws `ConfigurationError` with a stable code on the first\n * violation, returns silently otherwise. Pure — no I/O.\n *\n * Rules:\n * - `concurrency`, when provided, must be a positive integer (rejects\n * 0/negative/non-integer/NaN/Infinity). Previously this was caught only\n * incidentally deep inside `createSemaphore` with a leaky \"permits\"\n * message, AND after task wrapping (dangling Task on invalid input).\n * - every prompt item must carry a non-empty string prompt. Previously\n * `normalizeItem` passed `prompt: \"\"` / non-string straight to\n * `agent.send`. (Whitespace-only strings are intentionally NOT rejected —\n * an empty string is a structural error; judging content is not this\n * validator's job, and the repo's property tests treat any length>=1\n * string as a valid prompt.)\n *\n * @internal\n */\nexport function validateBatchInput(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n): void {\n const { concurrency } = options;\n if (concurrency !== undefined && (!Number.isInteger(concurrency) || concurrency < 1)) {\n throw new ConfigurationError(\n `Agent.batch concurrency must be a positive integer, got ${concurrency}`,\n { code: \"invalid_concurrency\" },\n );\n }\n for (let i = 0; i < prompts.length; i++) {\n const item = prompts[i];\n const prompt = typeof item === \"string\" ? item : item?.prompt;\n if (typeof prompt !== \"string\" || prompt.length === 0) {\n throw new ConfigurationError(`Agent.batch prompt at index ${i} must be a non-empty string`, {\n code: \"invalid_batch_item\",\n });\n }\n }\n}\n\n/**\n * Run N prompts in parallel with bounded concurrency.\n *\n * @internal\n */\nexport async function batchImpl(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult[]> {\n // EC-1: empty array → no work, no agents created.\n if (prompts.length === 0) return [];\n\n // Pre-flight boundary validation (arch-review Gap 3). MUST run before pool\n // build AND before wrapBatchAsTask so invalid input never registers a\n // dangling Task or builds a credential pool (fail-fast, Rule 8).\n validateBatchInput(prompts, options);\n\n // EC-A fix: build credential pools ONCE and share via AsyncLocalStorage.\n // Without this each Agent.create() would build its own pool from identical\n // apiKeys → 4× rate-limit wastage per concurrency window.\n const sharedPools = buildPoolsFromApiKeys(\n options.providers?.apiKeys,\n options.providers?.credentialPoolStrategy,\n );\n const exec = (): Promise<BatchResult[]> => runBatch(prompts, options, deps);\n const withPool = (): Promise<BatchResult[]> =>\n sharedPools.size > 0 ? withCredentialPool(sharedPools, exec) : exec();\n // T3.3: opt-in Task wrapping (ADRs D363, D374). Register the whole\n // batch as a single Task (kind=\"batch\") with `b-` prefix (D368/EC-5).\n if (options.task !== undefined) {\n return wrapBatchAsTask(prompts.length, options.task, withPool);\n }\n return withPool();\n}\n\nasync function wrapBatchAsTask(\n total: number,\n taskOpt: true | { id?: string; meta?: Record<string, unknown> },\n exec: () => Promise<BatchResult[]>,\n): Promise<BatchResult[]> {\n const opts = taskOpt === true ? {} : taskOpt;\n const id = opts.id ?? `b-${randomUUID()}`;\n const meta: Record<string, unknown> = {\n total,\n ...(opts.meta ?? {}),\n };\n let results: BatchResult[] = [];\n await taskRegistrySubmit({\n kind: \"batch\",\n work: async (ctx) => {\n results = await exec();\n const succeeded = results.filter((r) => r.ok).length;\n const failed = results.length - succeeded;\n ctx.emit({ total: results.length, succeeded, failed });\n return { total: results.length, succeeded, failed };\n },\n id,\n meta,\n allowReservedPrefix: true,\n });\n // submit returns immediately with a queued handle. Wait for terminal.\n for (let i = 0; i < 5000; i++) {\n const h = await taskRegistryGet(id);\n if (h?.state === \"finished\" || h?.state === \"error\" || h?.state === \"cancelled\") break;\n await new Promise((r) => setTimeout(r, 5));\n }\n return results;\n}\n\nasync function runBatch(\n prompts: ReadonlyArray<string | BatchItem>,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult[]> {\n const requested = options.concurrency ?? 4;\n // createSemaphore throws on invalid (EC-2).\n // EC-3: cap to prompts.length to avoid idle workers.\n const effective = Math.min(requested, prompts.length);\n const semaphore = createSemaphore(effective);\n const items = prompts.map(normalizeItem);\n const results: BatchResult[] = new Array(items.length);\n const counters = { completed: 0, failed: 0 };\n let aborted = false;\n\n const onAbort = (): void => {\n aborted = true;\n };\n options.signal?.addEventListener(\"abort\", onAbort);\n // EC-C: pre-aborted signal — treat as already-aborted before any work.\n if (options.signal?.aborted === true) aborted = true;\n\n try {\n await Promise.all(\n items.map(async (item, index) => {\n const release = await semaphore.acquire();\n try {\n if (aborted) {\n results[index] = abortResult(item, index, options.signal);\n } else {\n results[index] = await runOne(item, index, options, deps);\n }\n if (results[index].ok) counters.completed += 1;\n else counters.failed += 1;\n // B-110 (measured 2026-08-19): `onResult` used to run AFTER `release()`, so a caller who\n // asked for `concurrency: 1` still got overlapping `onResult` invocations — the permit was\n // already returned before the callback ran. `concurrency` is documented (`types/batch.ts`)\n // to bound the whole per-item lifecycle, callback included, so the permit is now held\n // until `onResult` finishes: this call moved inside the `try` the `finally` below wraps.\n await safeCallResult(options.onResult, results[index]);\n } finally {\n release();\n }\n safeCallProgress(options.onProgress, {\n total: items.length,\n completed: counters.completed,\n failed: counters.failed,\n inFlight: semaphore.inFlight(),\n pending: Math.max(0, semaphore.pending() - semaphore.inFlight()),\n });\n }),\n );\n } finally {\n options.signal?.removeEventListener(\"abort\", onAbort);\n }\n\n return options.filter ? results.filter(options.filter) : results;\n}\n\nasync function runOne(\n item: BatchItem,\n index: number,\n options: BatchOptions,\n deps: BatchDeps,\n): Promise<BatchResult> {\n const t0 = Date.now();\n const agentOpts = buildAgentOptions(item, options);\n\n try {\n const agent = await deps.create(agentOpts);\n try {\n const run = await agent.send(item.prompt);\n const result = await run.wait();\n return {\n ok: true,\n index,\n prompt: item.prompt,\n result,\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: Date.now() - t0,\n };\n } finally {\n // EC-8: dispose failure → stderr warn, don't fail the result.\n try {\n await agent.dispose();\n } catch (disposeErr) {\n // theokit#147 — the interceptable channel; a batch run must not write onto a TUI's frame.\n diag(\n `[theokit-sdk] batch: agent.dispose failed for prompt ${index}: ${\n disposeErr instanceof Error ? disposeErr.message : String(disposeErr)\n }\\n`,\n );\n }\n }\n } catch (err) {\n return {\n ok: false,\n index,\n prompt: item.prompt,\n error: toTheokitError(err),\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: Date.now() - t0,\n };\n }\n}\n\nfunction buildAgentOptions(item: BatchItem, options: BatchOptions): AgentOptions {\n const {\n concurrency: _c,\n filter: _f,\n onResult: _or,\n onProgress: _op,\n signal: _s,\n task: _t,\n ...rest\n } = options;\n void _c;\n void _f;\n void _or;\n void _op;\n void _s;\n void _t;\n const agentOpts = rest as AgentOptions;\n if (item.systemPrompt !== undefined) {\n return { ...agentOpts, systemPrompt: item.systemPrompt };\n }\n return agentOpts;\n}\n\nfunction normalizeItem(promptOrItem: string | BatchItem): BatchItem {\n return typeof promptOrItem === \"string\" ? { prompt: promptOrItem } : promptOrItem;\n}\n\nfunction abortResult(item: BatchItem, index: number, signal?: AbortSignal): BatchResult {\n // EC-D: propagate signal.reason when set (preserves caller's error).\n let error: TheokitAgentError;\n if (signal?.reason instanceof TheokitAgentError) {\n error = signal.reason;\n } else if (signal?.reason instanceof Error) {\n error = new TheokitAgentError(signal.reason.message, {\n code: \"aborted\",\n cause: signal.reason,\n });\n } else {\n error = new TheokitAgentError(\"Batch aborted via AbortSignal\", { code: \"aborted\" });\n }\n return {\n ok: false,\n index,\n prompt: item.prompt,\n error,\n ...(item.metadata !== undefined ? { metadata: item.metadata } : {}),\n durationMs: 0,\n };\n}\n\nfunction toTheokitError(err: unknown): TheokitAgentError {\n if (err instanceof TheokitAgentError) return err;\n if (err instanceof Error) {\n return new TheokitAgentError(err.message, { code: \"unknown\", cause: err });\n }\n return new TheokitAgentError(String(err), { code: \"unknown\" });\n}\n\nasync function safeCallResult(cb: BatchOptions[\"onResult\"], result: BatchResult): Promise<void> {\n if (cb === undefined) return;\n try {\n await cb(result);\n } catch (err) {\n diag(\n `[theokit-sdk] batch: onResult callback threw: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n}\n\nfunction safeCallProgress(cb: BatchOptions[\"onProgress\"], progress: BatchProgress): void {\n if (cb === undefined) return;\n try {\n cb(progress);\n } catch (err) {\n diag(\n `[theokit-sdk] batch: onProgress callback threw: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n}\n\n/**\n * EC-A: construct shared pools from options.apiKeys. Empty/invalid → empty Map.\n *\n * @internal\n */\nfunction buildPoolsFromApiKeys(\n apiKeys: Record<string, string[]> | undefined,\n strategy: Record<string, CredentialPoolStrategy> | undefined,\n): Map<string, CredentialPool> {\n const pools = new Map<string, CredentialPool>();\n if (apiKeys === undefined) return pools;\n for (const [provider, keys] of Object.entries(apiKeys)) {\n if (!Array.isArray(keys)) continue;\n const filtered = keys.filter((k): k is string => typeof k === \"string\" && k.length > 0);\n if (filtered.length < 2) continue; // 1-key pools aren't pools\n const entries = filtered.map((token, i) =>\n newPooledCredential({ provider, accessToken: token, priority: i, source: \"manual\" }),\n );\n pools.set(\n provider,\n new CredentialPool(provider, entries, strategy?.[provider] ?? \"fill_first\"),\n );\n }\n return pools;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { diag } from './chunk-T7O6K6PX.js';
1
+ import { diag } from './chunk-XEQ3TM66.js';
2
2
  import { randomBytes } from 'crypto';
3
3
  import { open, rename, unlink, mkdir, statfs } from 'fs/promises';
4
4
  import { dirname } from 'path';
@@ -72,5 +72,5 @@ async function atomicWriteText(filePath, content) {
72
72
  }
73
73
 
74
74
  export { atomicWriteJson, atomicWriteTempTarget, atomicWriteText, replaceFileAtomic };
75
- //# sourceMappingURL=chunk-VF7EWVDG.js.map
76
- //# sourceMappingURL=chunk-VF7EWVDG.js.map
75
+ //# sourceMappingURL=chunk-2GUYQR5P.js.map
76
+ //# sourceMappingURL=chunk-2GUYQR5P.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/persistence/atomic-write.ts"],"names":[],"mappings":"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","file":"chunk-VF7EWVDG.js","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { mkdir, open, rename, statfs, unlink } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { diag } from \"../diagnostics.js\";\n\n// T5.8 — Linux filesystem magic numbers (from `<linux/magic.h>`).\n// Used by `detectNetworkFsName` to identify the parent directory's\n// filesystem type from a `statfs()` return value. The four entries\n// below cover the network/FUSE cases where `rename()` is best-effort\n// rather than strictly atomic; everything else is treated as local.\nconst NETWORK_FS_MAGIC: ReadonlyMap<number, string> = new Map([\n [0x6969, \"nfs\"],\n [0x517b, \"smb\"],\n [0xff534d42, \"cifs\"],\n [0x65735546, \"fuse\"],\n]);\n\n/**\n * T5.8 — Map a `statfs().type` magic number to a network-FS label, or\n * `null` for local filesystems. Pure function — exported via the\n * `__TESTING__` seam so unit tests can drive the parse logic without\n * needing a network mount.\n *\n * @internal\n */\nfunction detectNetworkFsName(typeMagic: number): string | null {\n return NETWORK_FS_MAGIC.get(typeMagic) ?? null;\n}\n\nconst warnedNfsDirs = new Set<string>();\n\n/**\n * T5.8 — Best-effort one-shot stderr warning when `dirPath` lives on a\n * network/FUSE filesystem. Silent no-op on local filesystems, on\n * statfs failure (Windows / Node < 18.15 / EACCES), or after the\n * first warning per (dir + label) pair. Mirrors the `sqlite-wal.ts`\n * warn-once-per-label pattern (D63).\n *\n * @internal\n */\nasync function warnOnNetworkFsOnce(dirPath: string, label: string): Promise<void> {\n const key = `${dirPath}\\0${label}`;\n if (warnedNfsDirs.has(key)) return;\n warnedNfsDirs.add(key);\n try {\n const info = await statfs(dirPath);\n const fsName = detectNetworkFsName(info.type);\n if (fsName === null) return;\n diag(\n `[theokit-sdk] ${label}: detected network fs (${fsName}) at ${dirPath} — ` +\n \"rename() atomicity guarantees may be weaker than expected.\\n\",\n );\n } catch {\n // statfs unavailable (Windows / Node < 18.15) or unreadable —\n // silent fallback. The warning is purely informational.\n }\n}\n\n/**\n * T5.8 — Test seam exposing the pure detection function so unit tests\n * can assert magic-number coverage without spinning up a network FS.\n * NOT included in the public barrel.\n *\n * @internal\n */\nexport function __TESTING__detectNetworkFsName(typeMagic: number): string | null {\n return detectNetworkFsName(typeMagic);\n}\n\n/**\n * T5.8 — Test seam: clear the per-directory warn-once registry between\n * tests so warning-emission tests stay deterministic.\n *\n * @internal\n */\nexport function __TESTING__resetNfsWarnings(): void {\n warnedNfsDirs.clear();\n}\n\n/**\n * M107 — temp-file creation control, shared by `replaceFileAtomic`,\n * `atomicWriteJson` e `atomicWriteText`.\n *\n * Both fields are OPTIONAL and the default is byte-identical to the behavior\n * before M107. See `replaceFileAtomic` for why the mode reassertion\n * is conditional.\n *\n */\nexport interface AtomicWriteFileOptions {\n /**\n * Permission bits of the created file. Default: `0o600`, the previous fixed\n * literal — filtered by the `umask`, as it always was. When provided, the mode is\n * reasserted on the descriptor, so the `umask` cannot silently\n * clearing bits the caller asked for.\n */\n mode?: number;\n /**\n * Create the temp file with `wx` (exclusive creation) instead of `w`. Default:\n * `false` — the previous flag. With `true`, a pre-existing temp file becomes\n * `EEXIST` instead of being truncated.\n */\n exclusive?: boolean;\n}\n\n/** The one place the temp-path format is written. `atomicWriteTempTarget` reverses it. */\nfunction atomicWriteTempPath(filePath: string, pid: number, suffix: string): string {\n return `${filePath}.${String(pid)}.${suffix}.tmp`;\n}\n\n/** Reverses {@link atomicWriteTempPath}: `<file>.<pid>.<hex>.tmp` → `<file>`. */\nconst TEMP_PATTERN = /^(.+)\\.\\d+\\.[0-9a-f]{16}\\.tmp$/;\n\n/**\n * U-9 — the file a leftover temp was replacing, or `undefined` if this is not one of ours.\n *\n * A crash between the open and the rename leaves `<file>.<pid>.<hex>.tmp` behind, and nothing here\n * collects it: this module creates temps and has no opinion about sweeping them. A consumer that\n * wants to has to know the format — which lived only in the implementation, so one copied it out of\n * a compiled chunk as a regex. That copy would have gone on reporting \"nothing to collect\" the day\n * the format changed, which is the quietest possible way for a cleanup to stop working.\n *\n * Deliberately strict: the pid must be digits and the suffix exactly 16 hex characters. Matching any\n * `.tmp` would claim editors' swap files and other tools' scratch, on a path whose purpose is\n * deleting them.\n */\nexport function atomicWriteTempTarget(name: string): string | undefined {\n return TEMP_PATTERN.exec(name)?.[1];\n}\n\n/**\n * Atomic file replacement: write content to a per-call unique tmp path,\n * fsync, then rename over the target. Crash mid-write leaves either the old\n * file intact or the new file complete — never a half-written file.\n *\n * The tmp suffix is `<pid>.<rand>.tmp` so parallel processes (and concurrent\n * burst writes within one process) never collide on the same tmp path — a\n * race that would manifest as `ENOENT` on `rename` after the rival process\n * already moved its tmp into place.\n *\n * Mirrors peer-project's `replaceFileAtomic` from\n * `reference/peer-project/packages/memory-host-sdk/src/host/fs-utils.ts` with\n * the multi-writer robustness fix.\n *\n * ## M107 — `options` is optional, and the default is byte-identical\n *\n * The third parameter is additive: every earlier caller still compiles and\n * writing exactly the same bytes, with the same mode, to the same path.\n *\n * The mode reassertion (`handle.chmod`) is **conditional on `mode !== undefined`**,\n * and that is not cosmetic. `open`'s mode argument is filtered by the `umask`,\n * which only CLEARS bits — measured in this codebase before the change:\n *\n * ```\n * umask 0o002 -> 0o600 umask 0o022 -> 0o600 umask 0o200 -> 0o400\n * ```\n *\n * An unconditional `chmod` would take the third case from `0o400` to `0o600` — a\n * an on-disk change for every caller that asked for nothing, including external\n * consumers. When the caller DOES ask for a mode, however, letting the `umask` decide\n * silently is the defect this parameter exists to close; hence the reassertion.\n *\n * It goes on the DESCRIPTOR, before the `rename`, never after: chmod-ing the final\n * final one would leave a window where it carries the `umask`'s mode — a known anti-pattern.\n * The chosen shape passes the mode as an `open` argument.\n *\n */\nexport async function replaceFileAtomic(\n filePath: string,\n content: string,\n options?: AtomicWriteFileOptions,\n): Promise<void> {\n // T5.8 — warn once per parent directory if it lives on a network /\n // FUSE filesystem where `rename()` atomicity is best-effort. The\n // write proceeds unchanged; the warning is purely informational so\n // operators can spot the case in stderr / log aggregators.\n await warnOnNetworkFsOnce(dirname(filePath), \"atomic-write\");\n // T5.7 — crypto-random tmp suffix (CSPRNG, 64 bits of entropy)\n // replaces the predictable `Math.random().toString(36)` source. An\n // attacker observing the process can no longer predict the next\n // tmp path and pre-stage a hostile file to be renamed into place.\n const suffix = randomBytes(8).toString(\"hex\");\n const tmp = atomicWriteTempPath(filePath, process.pid, suffix);\n // T5.7 — mode 0o600 on the tmp file (owner read+write only). The\n // tmp file holds the FULL in-flight content (credential snapshots,\n // OAuth tokens) before the rename. World-readable default would\n // expose secrets during the ms-window between open and rename\n // (TOCTOU). On modern Linux the post-rename target inherits the\n // tmp's permission bits, so the final file is also 0o600.\n const handle = await open(tmp, options?.exclusive === true ? \"wx\" : \"w\", options?.mode ?? 0o600);\n try {\n await handle.writeFile(content, \"utf8\");\n await handle.sync();\n // Conditional by measurement, not by taste — see this function's docblock.\n if (options?.mode !== undefined) await handle.chmod(options.mode);\n } finally {\n await handle.close();\n }\n try {\n await rename(tmp, filePath);\n } catch (cause) {\n // Cleanup tmp on rename failure so we don't leak stale .tmp files.\n await unlink(tmp).catch(() => undefined);\n throw cause;\n }\n}\n\n/**\n * Options for `atomicWriteJson`.\n *\n */\nexport interface AtomicWriteJsonOptions extends AtomicWriteFileOptions {\n /** Indent passed to `JSON.stringify`. Default: 2. */\n indent?: number;\n /** Whether to append a trailing newline (POSIX convention). Default: true. */\n trailingNewline?: boolean;\n}\n\n/**\n * Typed JSON atomic write helper.\n *\n * Serializes `data` to JSON, then delegates to `replaceFileAtomic`. The\n * parent directory is auto-created (recursive `mkdir`) to make this helper\n * safe for callers who haven't ensured the directory exists (EC-4 in the\n * persistence-state-hardening plan).\n *\n * Throws `TypeError` on circular refs or `undefined` data (propagates from\n * `JSON.stringify`).\n *\n */\nexport async function atomicWriteJson<T>(\n filePath: string,\n data: T,\n options?: AtomicWriteJsonOptions,\n): Promise<void> {\n const indent = options?.indent ?? 2;\n const trailingNewline = options?.trailingNewline ?? true;\n const json = JSON.stringify(data, null, indent);\n if (json === undefined) {\n throw new TypeError(\"atomicWriteJson: cannot serialize undefined\");\n }\n const content = trailingNewline ? `${json}\\n` : json;\n await mkdir(dirname(filePath), { recursive: true });\n await replaceFileAtomic(filePath, content, options);\n}\n\n/**\n * Atomic text write. Same crash-safety guarantees as `replaceFileAtomic` +\n * auto-mkdir of the parent directory. Used by `theokit-migrate-config`\n * (T4.1, EC-2 MUST FIX) so a crash mid-migration leaves previous MD files\n * intact rather than corrupting them.\n *\n */\nexport async function atomicWriteText(filePath: string, content: string): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true });\n await replaceFileAtomic(filePath, content);\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/persistence/atomic-write.ts"],"names":[],"mappings":"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","file":"chunk-2GUYQR5P.js","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { mkdir, open, rename, statfs, unlink } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { diag } from \"../diagnostics.js\";\n\n// T5.8 — Linux filesystem magic numbers (from `<linux/magic.h>`).\n// Used by `detectNetworkFsName` to identify the parent directory's\n// filesystem type from a `statfs()` return value. The four entries\n// below cover the network/FUSE cases where `rename()` is best-effort\n// rather than strictly atomic; everything else is treated as local.\nconst NETWORK_FS_MAGIC: ReadonlyMap<number, string> = new Map([\n [0x6969, \"nfs\"],\n [0x517b, \"smb\"],\n [0xff534d42, \"cifs\"],\n [0x65735546, \"fuse\"],\n]);\n\n/**\n * T5.8 — Map a `statfs().type` magic number to a network-FS label, or\n * `null` for local filesystems. Pure function — exported via the\n * `__TESTING__` seam so unit tests can drive the parse logic without\n * needing a network mount.\n *\n * @internal\n */\nfunction detectNetworkFsName(typeMagic: number): string | null {\n return NETWORK_FS_MAGIC.get(typeMagic) ?? null;\n}\n\nconst warnedNfsDirs = new Set<string>();\n\n/**\n * T5.8 — Best-effort one-shot stderr warning when `dirPath` lives on a\n * network/FUSE filesystem. Silent no-op on local filesystems, on\n * statfs failure (Windows / Node < 18.15 / EACCES), or after the\n * first warning per (dir + label) pair. Mirrors the `sqlite-wal.ts`\n * warn-once-per-label pattern (D63).\n *\n * @internal\n */\nasync function warnOnNetworkFsOnce(dirPath: string, label: string): Promise<void> {\n const key = `${dirPath}\\0${label}`;\n if (warnedNfsDirs.has(key)) return;\n warnedNfsDirs.add(key);\n try {\n const info = await statfs(dirPath);\n const fsName = detectNetworkFsName(info.type);\n if (fsName === null) return;\n diag(\n `[theokit-sdk] ${label}: detected network fs (${fsName}) at ${dirPath} — ` +\n \"rename() atomicity guarantees may be weaker than expected.\\n\",\n );\n } catch {\n // statfs unavailable (Windows / Node < 18.15) or unreadable —\n // silent fallback. The warning is purely informational.\n }\n}\n\n/**\n * T5.8 — Test seam exposing the pure detection function so unit tests\n * can assert magic-number coverage without spinning up a network FS.\n * NOT included in the public barrel.\n *\n * @internal\n */\nexport function __TESTING__detectNetworkFsName(typeMagic: number): string | null {\n return detectNetworkFsName(typeMagic);\n}\n\n/**\n * T5.8 — Test seam: clear the per-directory warn-once registry between\n * tests so warning-emission tests stay deterministic.\n *\n * @internal\n */\nexport function __TESTING__resetNfsWarnings(): void {\n warnedNfsDirs.clear();\n}\n\n/**\n * M107 — temp-file creation control, shared by `replaceFileAtomic`,\n * `atomicWriteJson` e `atomicWriteText`.\n *\n * Both fields are OPTIONAL and the default is byte-identical to the behavior\n * before M107. See `replaceFileAtomic` for why the mode reassertion\n * is conditional.\n *\n */\nexport interface AtomicWriteFileOptions {\n /**\n * Permission bits of the created file. Default: `0o600`, the previous fixed\n * literal — filtered by the `umask`, as it always was. When provided, the mode is\n * reasserted on the descriptor, so the `umask` cannot silently\n * clearing bits the caller asked for.\n */\n mode?: number;\n /**\n * Create the temp file with `wx` (exclusive creation) instead of `w`. Default:\n * `false` — the previous flag. With `true`, a pre-existing temp file becomes\n * `EEXIST` instead of being truncated.\n */\n exclusive?: boolean;\n}\n\n/** The one place the temp-path format is written. `atomicWriteTempTarget` reverses it. */\nfunction atomicWriteTempPath(filePath: string, pid: number, suffix: string): string {\n return `${filePath}.${String(pid)}.${suffix}.tmp`;\n}\n\n/** Reverses {@link atomicWriteTempPath}: `<file>.<pid>.<hex>.tmp` → `<file>`. */\nconst TEMP_PATTERN = /^(.+)\\.\\d+\\.[0-9a-f]{16}\\.tmp$/;\n\n/**\n * U-9 — the file a leftover temp was replacing, or `undefined` if this is not one of ours.\n *\n * A crash between the open and the rename leaves `<file>.<pid>.<hex>.tmp` behind, and nothing here\n * collects it: this module creates temps and has no opinion about sweeping them. A consumer that\n * wants to has to know the format — which lived only in the implementation, so one copied it out of\n * a compiled chunk as a regex. That copy would have gone on reporting \"nothing to collect\" the day\n * the format changed, which is the quietest possible way for a cleanup to stop working.\n *\n * Deliberately strict: the pid must be digits and the suffix exactly 16 hex characters. Matching any\n * `.tmp` would claim editors' swap files and other tools' scratch, on a path whose purpose is\n * deleting them.\n */\nexport function atomicWriteTempTarget(name: string): string | undefined {\n return TEMP_PATTERN.exec(name)?.[1];\n}\n\n/**\n * Atomic file replacement: write content to a per-call unique tmp path,\n * fsync, then rename over the target. Crash mid-write leaves either the old\n * file intact or the new file complete — never a half-written file.\n *\n * The tmp suffix is `<pid>.<rand>.tmp` so parallel processes (and concurrent\n * burst writes within one process) never collide on the same tmp path — a\n * race that would manifest as `ENOENT` on `rename` after the rival process\n * already moved its tmp into place.\n *\n * Mirrors peer-project's `replaceFileAtomic` from\n * `reference/peer-project/packages/memory-host-sdk/src/host/fs-utils.ts` with\n * the multi-writer robustness fix.\n *\n * ## M107 — `options` is optional, and the default is byte-identical\n *\n * The third parameter is additive: every earlier caller still compiles and\n * writing exactly the same bytes, with the same mode, to the same path.\n *\n * The mode reassertion (`handle.chmod`) is **conditional on `mode !== undefined`**,\n * and that is not cosmetic. `open`'s mode argument is filtered by the `umask`,\n * which only CLEARS bits — measured in this codebase before the change:\n *\n * ```\n * umask 0o002 -> 0o600 umask 0o022 -> 0o600 umask 0o200 -> 0o400\n * ```\n *\n * An unconditional `chmod` would take the third case from `0o400` to `0o600` — a\n * an on-disk change for every caller that asked for nothing, including external\n * consumers. When the caller DOES ask for a mode, however, letting the `umask` decide\n * silently is the defect this parameter exists to close; hence the reassertion.\n *\n * It goes on the DESCRIPTOR, before the `rename`, never after: chmod-ing the final\n * final one would leave a window where it carries the `umask`'s mode — a known anti-pattern.\n * The chosen shape passes the mode as an `open` argument.\n *\n */\nexport async function replaceFileAtomic(\n filePath: string,\n content: string,\n options?: AtomicWriteFileOptions,\n): Promise<void> {\n // T5.8 — warn once per parent directory if it lives on a network /\n // FUSE filesystem where `rename()` atomicity is best-effort. The\n // write proceeds unchanged; the warning is purely informational so\n // operators can spot the case in stderr / log aggregators.\n await warnOnNetworkFsOnce(dirname(filePath), \"atomic-write\");\n // T5.7 — crypto-random tmp suffix (CSPRNG, 64 bits of entropy)\n // replaces the predictable `Math.random().toString(36)` source. An\n // attacker observing the process can no longer predict the next\n // tmp path and pre-stage a hostile file to be renamed into place.\n const suffix = randomBytes(8).toString(\"hex\");\n const tmp = atomicWriteTempPath(filePath, process.pid, suffix);\n // T5.7 — mode 0o600 on the tmp file (owner read+write only). The\n // tmp file holds the FULL in-flight content (credential snapshots,\n // OAuth tokens) before the rename. World-readable default would\n // expose secrets during the ms-window between open and rename\n // (TOCTOU). On modern Linux the post-rename target inherits the\n // tmp's permission bits, so the final file is also 0o600.\n const handle = await open(tmp, options?.exclusive === true ? \"wx\" : \"w\", options?.mode ?? 0o600);\n try {\n await handle.writeFile(content, \"utf8\");\n await handle.sync();\n // Conditional by measurement, not by taste — see this function's docblock.\n if (options?.mode !== undefined) await handle.chmod(options.mode);\n } finally {\n await handle.close();\n }\n try {\n await rename(tmp, filePath);\n } catch (cause) {\n // Cleanup tmp on rename failure so we don't leak stale .tmp files.\n await unlink(tmp).catch(() => undefined);\n throw cause;\n }\n}\n\n/**\n * Options for `atomicWriteJson`.\n *\n */\nexport interface AtomicWriteJsonOptions extends AtomicWriteFileOptions {\n /** Indent passed to `JSON.stringify`. Default: 2. */\n indent?: number;\n /** Whether to append a trailing newline (POSIX convention). Default: true. */\n trailingNewline?: boolean;\n}\n\n/**\n * Typed JSON atomic write helper.\n *\n * Serializes `data` to JSON, then delegates to `replaceFileAtomic`. The\n * parent directory is auto-created (recursive `mkdir`) to make this helper\n * safe for callers who haven't ensured the directory exists (EC-4 in the\n * persistence-state-hardening plan).\n *\n * Throws `TypeError` on circular refs or `undefined` data (propagates from\n * `JSON.stringify`).\n *\n */\nexport async function atomicWriteJson<T>(\n filePath: string,\n data: T,\n options?: AtomicWriteJsonOptions,\n): Promise<void> {\n const indent = options?.indent ?? 2;\n const trailingNewline = options?.trailingNewline ?? true;\n const json = JSON.stringify(data, null, indent);\n if (json === undefined) {\n throw new TypeError(\"atomicWriteJson: cannot serialize undefined\");\n }\n const content = trailingNewline ? `${json}\\n` : json;\n await mkdir(dirname(filePath), { recursive: true });\n await replaceFileAtomic(filePath, content, options);\n}\n\n/**\n * Atomic text write. Same crash-safety guarantees as `replaceFileAtomic` +\n * auto-mkdir of the parent directory. Used by `theokit-migrate-config`\n * (T4.1, EC-2 MUST FIX) so a crash mid-migration leaves previous MD files\n * intact rather than corrupting them.\n *\n */\nexport async function atomicWriteText(filePath: string, content: string): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true });\n await replaceFileAtomic(filePath, content);\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkI6TGFUCO_cjs = require('./chunk-I6TGFUCO.cjs');
4
- var chunkNUKRL3I6_cjs = require('./chunk-NUKRL3I6.cjs');
3
+ var chunkUALX2J2Q_cjs = require('./chunk-UALX2J2Q.cjs');
4
+ var chunkEG4QM7ZJ_cjs = require('./chunk-EG4QM7ZJ.cjs');
5
5
  var promises = require('fs/promises');
6
6
 
7
7
  function migrateSchema(opts) {
@@ -44,10 +44,10 @@ async function readVersionedJson(opts) {
44
44
  const asidePath = `${path}.corrupt.${Date.now()}`;
45
45
  try {
46
46
  await promises.rename(path, asidePath);
47
- chunkNUKRL3I6_cjs.diag(`[theokit-sdk] ${path} is corrupt; moved to ${asidePath}. Using default value.
47
+ chunkEG4QM7ZJ_cjs.diag(`[theokit-sdk] ${path} is corrupt; moved to ${asidePath}. Using default value.
48
48
  `);
49
49
  } catch {
50
- chunkNUKRL3I6_cjs.diag(`[theokit-sdk] ${path} is corrupt; using default value.
50
+ chunkEG4QM7ZJ_cjs.diag(`[theokit-sdk] ${path} is corrupt; using default value.
51
51
  `);
52
52
  }
53
53
  return defaultValue();
@@ -62,7 +62,7 @@ async function readVersionedJson(opts) {
62
62
  return file.data;
63
63
  }
64
64
  if (stored > currentVersion) {
65
- chunkNUKRL3I6_cjs.diag(
65
+ chunkEG4QM7ZJ_cjs.diag(
66
66
  `[theokit-sdk] ${path} schema version ${stored} > current ${currentVersion}; using default value (forward-only).
67
67
  `
68
68
  );
@@ -75,11 +75,11 @@ async function writeVersionedJson(path, data, currentVersion) {
75
75
  _schemaVersion: currentVersion,
76
76
  data
77
77
  };
78
- await chunkI6TGFUCO_cjs.atomicWriteJson(path, file);
78
+ await chunkUALX2J2Q_cjs.atomicWriteJson(path, file);
79
79
  }
80
80
 
81
81
  exports.migrateSchema = migrateSchema;
82
82
  exports.readVersionedJson = readVersionedJson;
83
83
  exports.writeVersionedJson = writeVersionedJson;
84
- //# sourceMappingURL=chunk-J2UROOIG.cjs.map
85
- //# sourceMappingURL=chunk-J2UROOIG.cjs.map
84
+ //# sourceMappingURL=chunk-2HVF2WJY.cjs.map
85
+ //# sourceMappingURL=chunk-2HVF2WJY.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/persistence/schema-version.ts"],"names":["readFile","rename","diag","atomicWriteJson"],"mappings":"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","file":"chunk-J2UROOIG.cjs","sourcesContent":["/**\n * Schema versioning helpers (ADR D62).\n *\n * Two parallel APIs:\n * - `migrateSchema` — SQLite via `PRAGMA user_version` + ordered forward-only migrations.\n * - `readVersionedJson` / `writeVersionedJson` — JSON files with `_schemaVersion` field.\n *\n * Forward-only: never deletes data, never downgrades. Migration callbacks\n * own the transformation; this module owns the bookkeeping.\n *\n * @internal\n */\n\nimport { readFile, rename } from \"node:fs/promises\";\nimport { diag } from \"../diagnostics.js\";\nimport { atomicWriteJson } from \"./atomic-write.js\";\n\n// ────────────────────── SQLite migrations ──────────────────────\n\n/**\n * The three `better-sqlite3` methods this module actually uses, declared structurally so nothing\n * here imports the driver.\n *\n * A real `better-sqlite3` `Database` satisfies it. `pragma` is called both to read\n * (`pragma(\"user_version\", { simple: true })`, which must return the number itself rather than a\n * row array) and to write (`pragma(\"user_version = N\")`). `transaction` must return a function\n * that, when called, runs the wrapped body inside a real SQLite transaction and rolls it back if\n * the body throws — a stub that merely calls through gives `migrateSchema` no atomicity, and a\n * half-applied migration is exactly what it exists to prevent.\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 */\nexport interface SqliteLike {\n pragma: (statement: string, options?: { simple?: boolean }) => unknown;\n exec: (sql: string) => void;\n transaction: <Args extends unknown[], R>(fn: (...args: Args) => R) => (...args: Args) => R;\n}\n\n/**\n * One forward migration step.\n *\n * `up` runs inside the shared transaction and must be self-contained: it may not commit, and any\n * error it throws aborts the whole run and rolls back every step in it, including the ones that\n * already succeeded. `user_version` is set to `toVersion` immediately after `up` returns, inside\n * the same transaction, so version and schema move together or not at all.\n *\n * `toVersion` is the version the database reaches, not the one it starts from. Steps are ordered\n * by it, gaps are allowed, and two steps sharing a `toVersion` both run — nothing deduplicates\n * them.\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 */\nexport interface Migration {\n toVersion: number;\n up: (db: SqliteLike) => void;\n}\n\n/**\n * Arguments to `migrateSchema`.\n *\n * `currentVersion` is the version the code expects, and it is the ceiling: a migration whose\n * `toVersion` exceeds it is left unapplied for a later release. `migrations` may be given in any\n * order and may contain steps already applied — both are filtered and sorted here. `label` only\n * ever appears in the downgrade error message.\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 */\nexport interface MigrateSchemaOptions {\n db: SqliteLike;\n currentVersion: number;\n migrations: ReadonlyArray<Migration>;\n /** For log/error context (e.g., \"memory-index\", \"registry\"). */\n label?: string;\n}\n\n/**\n * What `migrateSchema` did.\n *\n * `from` is the `user_version` found on the database, `to` is the version it holds afterwards,\n * and `ran` is how many steps executed. When nothing was pending, `to === from` and `ran === 0`.\n *\n * `to` is the `toVersion` of the last step applied, NOT `currentVersion`. A database at version 3\n * against `currentVersion: 5` with no migration in that range comes back as\n * `{ from: 3, to: 3, ran: 0 }` — the gap is reported, not closed. Comparing `to` with\n * `currentVersion` is how a caller notices that the migration list is missing a step.\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 */\nexport interface MigrateSchemaResult {\n from: number;\n to: number;\n ran: number;\n}\n\n/**\n * Bring a SQLite database's `user_version` up to `currentVersion` by running the steps that sit\n * between the two.\n *\n * Steps are sorted ascending by `toVersion` and filtered to `> stored && <= currentVersion`, then\n * run in that order inside ONE transaction: each `up` is followed immediately by the matching\n * `user_version` write. Either every step in the run commits or none does — a step that throws\n * aborts the transaction, propagates the error, and leaves the database at the version it started\n * from. There is no partially-migrated state and no resume point.\n *\n * Forward-only. When the stored version is greater than `currentVersion` — an older build opening\n * a database a newer one already migrated — this throws immediately, before touching anything,\n * with a message naming both versions and `label`. Nothing downgrades, and no data is deleted on\n * any path here; what a step does is the step's own business.\n *\n * A stored version equal to `currentVersion` returns without opening a transaction. A `user_version`\n * that is absent or not a number is read as 0, so a fresh database runs every step.\n *\n * Concurrency: the SQLite transaction is the only serialization. This takes no file lock, so two\n * processes migrating the same file at once are arbitrated by SQLite's own write lock — the loser\n * gets a busy or locked error from the driver, not a queued turn. Wrap the call in `withFileLock`\n * if that matters.\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 */\nexport function migrateSchema(opts: MigrateSchemaOptions): MigrateSchemaResult {\n const { db, currentVersion, migrations, label = \"db\" } = opts;\n const storedRaw = db.pragma(\"user_version\", { simple: true });\n const stored = typeof storedRaw === \"number\" ? storedRaw : 0;\n\n if (stored > currentVersion) {\n throw new Error(\n `[${label}] schema version ${stored} > current ${currentVersion}; ` +\n \"did you downgrade the SDK? Forward-only migrations only.\",\n );\n }\n\n if (stored === currentVersion) {\n return { from: stored, to: stored, ran: 0 };\n }\n\n const pending = [...migrations]\n .sort((a, b) => a.toVersion - b.toVersion)\n .filter((m) => m.toVersion > stored && m.toVersion <= currentVersion);\n\n let ran = 0;\n let lastApplied = stored;\n\n db.transaction(() => {\n for (const m of pending) {\n m.up(db);\n db.pragma(`user_version = ${m.toVersion}`);\n lastApplied = m.toVersion;\n ran += 1;\n }\n })();\n\n return { from: stored, to: lastApplied, ran };\n}\n\n// ────────────────────── JSON versioned files ──────────────────────\n\n/**\n * The on-disk envelope: the payload under `data`, its schema version alongside it.\n *\n * `writeVersionedJson` always produces this shape. `readVersionedJson` reads it, but tolerates a\n * file that is not in it — a legacy object with no `_schemaVersion` is treated as version 0 and\n * handed to the migrate callback whole, so this type describes what is written, not everything\n * that can be read.\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 */\nexport interface VersionedJsonFile<T> {\n _schemaVersion: number;\n data: T;\n}\n\n/**\n * Upgrade callback for `readVersionedJson`, invoked only when the stored version is BELOW the\n * current one.\n *\n * `parsed` is the whole parsed JSON value, not `parsed.data`. That is deliberate: a legacy file\n * predating the envelope has its fields at the top level, and a callback handed only `.data`\n * would receive `undefined` for exactly the files that need migrating. It is typed `unknown`\n * because nothing has validated it — narrow before reading.\n *\n * `fromVersion` is the `_schemaVersion` found on disk, or 0 when the field is missing or not a\n * number.\n *\n * The return value is used as-is and is NOT written back; the file on disk still holds the old\n * shape until someone calls `writeVersionedJson`. Throwing here propagates out of\n * `readVersionedJson`, which otherwise never throws — return the default value instead if an\n * unmigratable file should be survivable.\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 */\nexport type VersionedJsonMigrate<T> = (parsed: unknown, fromVersion: number) => T;\n\n/**\n * Arguments to `readVersionedJson`.\n *\n * `defaultValue` is a factory rather than a value because it is called on several paths and each\n * caller must get its own object — returning a shared mutable default would let one caller's\n * edits appear in another's. It is called for a missing file, an unreadable one, a corrupt one,\n * a non-object payload, and a file written by a newer version.\n *\n * `migrate` is called only for a stored version strictly below `currentVersion`.\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 */\nexport interface ReadVersionedJsonOptions<T> {\n path: string;\n currentVersion: number;\n migrate: VersionedJsonMigrate<T>;\n defaultValue: () => T;\n}\n\n/**\n * Read a versioned JSON file, migrating or falling back rather than failing.\n *\n * What comes back, by case:\n *\n * - version matches `currentVersion` — the file's `data` field, returned as `T` WITHOUT\n * validation. A file whose envelope is right but whose payload is not gets through.\n * - version below `currentVersion` — whatever `migrate(parsed, stored)` returns. The migrated\n * value is not persisted; the file is untouched.\n * - version above `currentVersion` — `defaultValue()`, plus a warning. Forward-only: a file\n * written by a newer build is left alone rather than downgraded.\n * - file missing, or unreadable for any other reason (permissions, a directory in its place) —\n * `defaultValue()`, silently. Absence and denial are not distinguished.\n * - file present but not valid JSON — `defaultValue()`, and the file is RENAMED to\n * `<path>.corrupt.<epoch-ms>` so the next run starts clean and the bad bytes stay available.\n * A rename that itself fails is warned about and the read still returns the default, which\n * means the same corrupt file will be met again next time.\n * - JSON that parses to a non-object (a number, a string, `null`) — `defaultValue()`, silently\n * and without moving the file aside.\n *\n * The only ways this throws are through the callbacks you supply: `migrate` or `defaultValue`\n * raising. Nothing else here rejects.\n *\n * There is no locking. A concurrent `writeVersionedJson` on the same path is atomic at the rename,\n * so a reader sees either the old file or the new one, never a half-written one — but a\n * read-modify-write built from this pair is NOT atomic across the two calls, and needs\n * `withFileLock` around both.\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 */\nexport async function readVersionedJson<T>(opts: ReadVersionedJsonOptions<T>): Promise<T> {\n const { path, currentVersion, migrate, defaultValue } = opts;\n\n let raw: string;\n try {\n raw = await readFile(path, \"utf-8\");\n } catch {\n return defaultValue();\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // T5.10 — move corrupt file aside so (a) user can investigate and\n // (b) next run starts fresh instead of hitting the same warning loop.\n const asidePath = `${path}.corrupt.${Date.now()}`;\n try {\n await rename(path, asidePath);\n diag(`[theokit-sdk] ${path} is corrupt; moved to ${asidePath}. Using default value.\\n`);\n } catch {\n diag(`[theokit-sdk] ${path} is corrupt; using default value.\\n`);\n }\n return defaultValue();\n }\n\n if (typeof parsed !== \"object\" || parsed === null) {\n return defaultValue();\n }\n\n const file = parsed as { _schemaVersion?: unknown; data?: unknown };\n const storedRaw = file._schemaVersion;\n const stored = typeof storedRaw === \"number\" ? storedRaw : 0;\n\n if (stored === currentVersion) {\n return file.data as T;\n }\n\n if (stored > currentVersion) {\n diag(\n `[theokit-sdk] ${path} schema version ${stored} > current ${currentVersion}; ` +\n \"using default value (forward-only).\\n\",\n );\n return defaultValue();\n }\n\n // EC-2 fix: pass the FULL parsed object to migrate, not just `file.data`.\n // Legacy shapes (e.g., `{ schemaVersion: \"1.0\", agents: {...} }` without\n // a `data` field) need to inspect the whole thing.\n return migrate(parsed, stored);\n}\n\n/**\n * Write `data` wrapped in the version envelope, replacing the file atomically.\n *\n * The bytes go to a temp file in the same directory and are moved into place with `rename`, so a\n * crash or a concurrent reader never observes a partial file: the path holds either the previous\n * content or the complete new content. Parent directories are created as needed, and the file is\n * created with mode 0600 (subject to the process umask), formatted with two-space indentation and\n * a trailing newline.\n *\n * `currentVersion` is stamped verbatim as `_schemaVersion`; nothing checks it against what was\n * already on disk, so this will happily overwrite a newer file with an older version. Read first\n * if that matters.\n *\n * Rejects when `data` cannot be serialized — a circular reference, or a `toJSON` that throws.\n * Serialization happens before any filesystem call, so on that path no directory is created, no\n * temp file exists, and the file already on disk is untouched.\n *\n * Atomicity is the rename's, so it is as strong as the filesystem's: on NFS, SMB or FUSE the\n * underlying writer emits a one-shot warning that the guarantee is weaker there.\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 */\nexport async function writeVersionedJson<T>(\n path: string,\n data: T,\n currentVersion: number,\n): Promise<void> {\n const file: VersionedJsonFile<T> = {\n _schemaVersion: currentVersion,\n data,\n };\n await atomicWriteJson(path, file);\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/persistence/schema-version.ts"],"names":["readFile","rename","diag","atomicWriteJson"],"mappings":"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","file":"chunk-2HVF2WJY.cjs","sourcesContent":["/**\n * Schema versioning helpers (ADR D62).\n *\n * Two parallel APIs:\n * - `migrateSchema` — SQLite via `PRAGMA user_version` + ordered forward-only migrations.\n * - `readVersionedJson` / `writeVersionedJson` — JSON files with `_schemaVersion` field.\n *\n * Forward-only: never deletes data, never downgrades. Migration callbacks\n * own the transformation; this module owns the bookkeeping.\n *\n * @internal\n */\n\nimport { readFile, rename } from \"node:fs/promises\";\nimport { diag } from \"../diagnostics.js\";\nimport { atomicWriteJson } from \"./atomic-write.js\";\n\n// ────────────────────── SQLite migrations ──────────────────────\n\n/**\n * The three `better-sqlite3` methods this module actually uses, declared structurally so nothing\n * here imports the driver.\n *\n * A real `better-sqlite3` `Database` satisfies it. `pragma` is called both to read\n * (`pragma(\"user_version\", { simple: true })`, which must return the number itself rather than a\n * row array) and to write (`pragma(\"user_version = N\")`). `transaction` must return a function\n * that, when called, runs the wrapped body inside a real SQLite transaction and rolls it back if\n * the body throws — a stub that merely calls through gives `migrateSchema` no atomicity, and a\n * half-applied migration is exactly what it exists to prevent.\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 */\nexport interface SqliteLike {\n pragma: (statement: string, options?: { simple?: boolean }) => unknown;\n exec: (sql: string) => void;\n transaction: <Args extends unknown[], R>(fn: (...args: Args) => R) => (...args: Args) => R;\n}\n\n/**\n * One forward migration step.\n *\n * `up` runs inside the shared transaction and must be self-contained: it may not commit, and any\n * error it throws aborts the whole run and rolls back every step in it, including the ones that\n * already succeeded. `user_version` is set to `toVersion` immediately after `up` returns, inside\n * the same transaction, so version and schema move together or not at all.\n *\n * `toVersion` is the version the database reaches, not the one it starts from. Steps are ordered\n * by it, gaps are allowed, and two steps sharing a `toVersion` both run — nothing deduplicates\n * them.\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 */\nexport interface Migration {\n toVersion: number;\n up: (db: SqliteLike) => void;\n}\n\n/**\n * Arguments to `migrateSchema`.\n *\n * `currentVersion` is the version the code expects, and it is the ceiling: a migration whose\n * `toVersion` exceeds it is left unapplied for a later release. `migrations` may be given in any\n * order and may contain steps already applied — both are filtered and sorted here. `label` only\n * ever appears in the downgrade error message.\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 */\nexport interface MigrateSchemaOptions {\n db: SqliteLike;\n currentVersion: number;\n migrations: ReadonlyArray<Migration>;\n /** For log/error context (e.g., \"memory-index\", \"registry\"). */\n label?: string;\n}\n\n/**\n * What `migrateSchema` did.\n *\n * `from` is the `user_version` found on the database, `to` is the version it holds afterwards,\n * and `ran` is how many steps executed. When nothing was pending, `to === from` and `ran === 0`.\n *\n * `to` is the `toVersion` of the last step applied, NOT `currentVersion`. A database at version 3\n * against `currentVersion: 5` with no migration in that range comes back as\n * `{ from: 3, to: 3, ran: 0 }` — the gap is reported, not closed. Comparing `to` with\n * `currentVersion` is how a caller notices that the migration list is missing a step.\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 */\nexport interface MigrateSchemaResult {\n from: number;\n to: number;\n ran: number;\n}\n\n/**\n * Bring a SQLite database's `user_version` up to `currentVersion` by running the steps that sit\n * between the two.\n *\n * Steps are sorted ascending by `toVersion` and filtered to `> stored && <= currentVersion`, then\n * run in that order inside ONE transaction: each `up` is followed immediately by the matching\n * `user_version` write. Either every step in the run commits or none does — a step that throws\n * aborts the transaction, propagates the error, and leaves the database at the version it started\n * from. There is no partially-migrated state and no resume point.\n *\n * Forward-only. When the stored version is greater than `currentVersion` — an older build opening\n * a database a newer one already migrated — this throws immediately, before touching anything,\n * with a message naming both versions and `label`. Nothing downgrades, and no data is deleted on\n * any path here; what a step does is the step's own business.\n *\n * A stored version equal to `currentVersion` returns without opening a transaction. A `user_version`\n * that is absent or not a number is read as 0, so a fresh database runs every step.\n *\n * Concurrency: the SQLite transaction is the only serialization. This takes no file lock, so two\n * processes migrating the same file at once are arbitrated by SQLite's own write lock — the loser\n * gets a busy or locked error from the driver, not a queued turn. Wrap the call in `withFileLock`\n * if that matters.\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 */\nexport function migrateSchema(opts: MigrateSchemaOptions): MigrateSchemaResult {\n const { db, currentVersion, migrations, label = \"db\" } = opts;\n const storedRaw = db.pragma(\"user_version\", { simple: true });\n const stored = typeof storedRaw === \"number\" ? storedRaw : 0;\n\n if (stored > currentVersion) {\n throw new Error(\n `[${label}] schema version ${stored} > current ${currentVersion}; ` +\n \"did you downgrade the SDK? Forward-only migrations only.\",\n );\n }\n\n if (stored === currentVersion) {\n return { from: stored, to: stored, ran: 0 };\n }\n\n const pending = [...migrations]\n .sort((a, b) => a.toVersion - b.toVersion)\n .filter((m) => m.toVersion > stored && m.toVersion <= currentVersion);\n\n let ran = 0;\n let lastApplied = stored;\n\n db.transaction(() => {\n for (const m of pending) {\n m.up(db);\n db.pragma(`user_version = ${m.toVersion}`);\n lastApplied = m.toVersion;\n ran += 1;\n }\n })();\n\n return { from: stored, to: lastApplied, ran };\n}\n\n// ────────────────────── JSON versioned files ──────────────────────\n\n/**\n * The on-disk envelope: the payload under `data`, its schema version alongside it.\n *\n * `writeVersionedJson` always produces this shape. `readVersionedJson` reads it, but tolerates a\n * file that is not in it — a legacy object with no `_schemaVersion` is treated as version 0 and\n * handed to the migrate callback whole, so this type describes what is written, not everything\n * that can be read.\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 */\nexport interface VersionedJsonFile<T> {\n _schemaVersion: number;\n data: T;\n}\n\n/**\n * Upgrade callback for `readVersionedJson`, invoked only when the stored version is BELOW the\n * current one.\n *\n * `parsed` is the whole parsed JSON value, not `parsed.data`. That is deliberate: a legacy file\n * predating the envelope has its fields at the top level, and a callback handed only `.data`\n * would receive `undefined` for exactly the files that need migrating. It is typed `unknown`\n * because nothing has validated it — narrow before reading.\n *\n * `fromVersion` is the `_schemaVersion` found on disk, or 0 when the field is missing or not a\n * number.\n *\n * The return value is used as-is and is NOT written back; the file on disk still holds the old\n * shape until someone calls `writeVersionedJson`. Throwing here propagates out of\n * `readVersionedJson`, which otherwise never throws — return the default value instead if an\n * unmigratable file should be survivable.\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 */\nexport type VersionedJsonMigrate<T> = (parsed: unknown, fromVersion: number) => T;\n\n/**\n * Arguments to `readVersionedJson`.\n *\n * `defaultValue` is a factory rather than a value because it is called on several paths and each\n * caller must get its own object — returning a shared mutable default would let one caller's\n * edits appear in another's. It is called for a missing file, an unreadable one, a corrupt one,\n * a non-object payload, and a file written by a newer version.\n *\n * `migrate` is called only for a stored version strictly below `currentVersion`.\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 */\nexport interface ReadVersionedJsonOptions<T> {\n path: string;\n currentVersion: number;\n migrate: VersionedJsonMigrate<T>;\n defaultValue: () => T;\n}\n\n/**\n * Read a versioned JSON file, migrating or falling back rather than failing.\n *\n * What comes back, by case:\n *\n * - version matches `currentVersion` — the file's `data` field, returned as `T` WITHOUT\n * validation. A file whose envelope is right but whose payload is not gets through.\n * - version below `currentVersion` — whatever `migrate(parsed, stored)` returns. The migrated\n * value is not persisted; the file is untouched.\n * - version above `currentVersion` — `defaultValue()`, plus a warning. Forward-only: a file\n * written by a newer build is left alone rather than downgraded.\n * - file missing, or unreadable for any other reason (permissions, a directory in its place) —\n * `defaultValue()`, silently. Absence and denial are not distinguished.\n * - file present but not valid JSON — `defaultValue()`, and the file is RENAMED to\n * `<path>.corrupt.<epoch-ms>` so the next run starts clean and the bad bytes stay available.\n * A rename that itself fails is warned about and the read still returns the default, which\n * means the same corrupt file will be met again next time.\n * - JSON that parses to a non-object (a number, a string, `null`) — `defaultValue()`, silently\n * and without moving the file aside.\n *\n * The only ways this throws are through the callbacks you supply: `migrate` or `defaultValue`\n * raising. Nothing else here rejects.\n *\n * There is no locking. A concurrent `writeVersionedJson` on the same path is atomic at the rename,\n * so a reader sees either the old file or the new one, never a half-written one — but a\n * read-modify-write built from this pair is NOT atomic across the two calls, and needs\n * `withFileLock` around both.\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 */\nexport async function readVersionedJson<T>(opts: ReadVersionedJsonOptions<T>): Promise<T> {\n const { path, currentVersion, migrate, defaultValue } = opts;\n\n let raw: string;\n try {\n raw = await readFile(path, \"utf-8\");\n } catch {\n return defaultValue();\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // T5.10 — move corrupt file aside so (a) user can investigate and\n // (b) next run starts fresh instead of hitting the same warning loop.\n const asidePath = `${path}.corrupt.${Date.now()}`;\n try {\n await rename(path, asidePath);\n diag(`[theokit-sdk] ${path} is corrupt; moved to ${asidePath}. Using default value.\\n`);\n } catch {\n diag(`[theokit-sdk] ${path} is corrupt; using default value.\\n`);\n }\n return defaultValue();\n }\n\n if (typeof parsed !== \"object\" || parsed === null) {\n return defaultValue();\n }\n\n const file = parsed as { _schemaVersion?: unknown; data?: unknown };\n const storedRaw = file._schemaVersion;\n const stored = typeof storedRaw === \"number\" ? storedRaw : 0;\n\n if (stored === currentVersion) {\n return file.data as T;\n }\n\n if (stored > currentVersion) {\n diag(\n `[theokit-sdk] ${path} schema version ${stored} > current ${currentVersion}; ` +\n \"using default value (forward-only).\\n\",\n );\n return defaultValue();\n }\n\n // EC-2 fix: pass the FULL parsed object to migrate, not just `file.data`.\n // Legacy shapes (e.g., `{ schemaVersion: \"1.0\", agents: {...} }` without\n // a `data` field) need to inspect the whole thing.\n return migrate(parsed, stored);\n}\n\n/**\n * Write `data` wrapped in the version envelope, replacing the file atomically.\n *\n * The bytes go to a temp file in the same directory and are moved into place with `rename`, so a\n * crash or a concurrent reader never observes a partial file: the path holds either the previous\n * content or the complete new content. Parent directories are created as needed, and the file is\n * created with mode 0600 (subject to the process umask), formatted with two-space indentation and\n * a trailing newline.\n *\n * `currentVersion` is stamped verbatim as `_schemaVersion`; nothing checks it against what was\n * already on disk, so this will happily overwrite a newer file with an older version. Read first\n * if that matters.\n *\n * Rejects when `data` cannot be serialized — a circular reference, or a `toJSON` that throws.\n * Serialization happens before any filesystem call, so on that path no directory is created, no\n * temp file exists, and the file already on disk is untouched.\n *\n * Atomicity is the rename's, so it is as strong as the filesystem's: on NFS, SMB or FUSE the\n * underlying writer emits a one-shot warning that the guarantee is weaker there.\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 */\nexport async function writeVersionedJson<T>(\n path: string,\n data: T,\n currentVersion: number,\n): Promise<void> {\n const file: VersionedJsonFile<T> = {\n _schemaVersion: currentVersion,\n data,\n };\n await atomicWriteJson(path, file);\n}\n"]}