@theokit/sdk 4.39.0 → 4.39.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/dist/agent-KGKKAGXY.js +46 -0
  3. package/dist/{agent-KKZYLY5D.js.map → agent-KGKKAGXY.js.map} +1 -1
  4. package/dist/agent-TOWHPM7B.cjs +55 -0
  5. package/dist/{agent-I3EZZR6S.cjs.map → agent-TOWHPM7B.cjs.map} +1 -1
  6. package/dist/agent-session-store-EGTTYSKS.js +6 -0
  7. package/dist/{agent-session-store-RHMHP5DG.js.map → agent-session-store-EGTTYSKS.js.map} +1 -1
  8. package/dist/agent-session-store-RHTLZ5OX.cjs +23 -0
  9. package/dist/{agent-session-store-N4TVKHBU.cjs.map → agent-session-store-RHTLZ5OX.cjs.map} +1 -1
  10. package/dist/auth/index.cjs +15 -15
  11. package/dist/auth/index.js +4 -4
  12. package/dist/{batch-X6JKGDPK.cjs → batch-FO2KZN7W.cjs} +26 -26
  13. package/dist/{batch-X6JKGDPK.cjs.map → batch-FO2KZN7W.cjs.map} +1 -1
  14. package/dist/{batch-6KQM3EBA.js → batch-WX2HLXX2.js} +9 -9
  15. package/dist/{batch-6KQM3EBA.js.map → batch-WX2HLXX2.js.map} +1 -1
  16. package/dist/{chunk-ECHGWE47.cjs → chunk-27E4EMR6.cjs} +4 -4
  17. package/dist/{chunk-ECHGWE47.cjs.map → chunk-27E4EMR6.cjs.map} +1 -1
  18. package/dist/{chunk-DGLLVCNB.cjs → chunk-33B2BSME.cjs} +4 -4
  19. package/dist/{chunk-DGLLVCNB.cjs.map → chunk-33B2BSME.cjs.map} +1 -1
  20. package/dist/{chunk-KE6XKRLQ.js → chunk-3CAQCFVZ.js} +3 -3
  21. package/dist/{chunk-KE6XKRLQ.js.map → chunk-3CAQCFVZ.js.map} +1 -1
  22. package/dist/{chunk-XYOHKCYG.cjs → chunk-3LK3ZDL5.cjs} +5 -5
  23. package/dist/{chunk-XYOHKCYG.cjs.map → chunk-3LK3ZDL5.cjs.map} +1 -1
  24. package/dist/{chunk-I53ZQHU6.cjs → chunk-4E3HLSYE.cjs} +4 -4
  25. package/dist/{chunk-I53ZQHU6.cjs.map → chunk-4E3HLSYE.cjs.map} +1 -1
  26. package/dist/{chunk-AR5MQZ3J.js → chunk-4GGXF7YM.js} +3 -3
  27. package/dist/{chunk-AR5MQZ3J.js.map → chunk-4GGXF7YM.js.map} +1 -1
  28. package/dist/{chunk-4JSZYSGW.js → chunk-4H2DCO6P.js} +3 -3
  29. package/dist/{chunk-4JSZYSGW.js.map → chunk-4H2DCO6P.js.map} +1 -1
  30. package/dist/{chunk-75DSEWTJ.cjs → chunk-4H2QARXM.cjs} +7 -7
  31. package/dist/{chunk-75DSEWTJ.cjs.map → chunk-4H2QARXM.cjs.map} +1 -1
  32. package/dist/{chunk-JZUPMTJY.js → chunk-4HKAZRTC.js} +3 -3
  33. package/dist/{chunk-JZUPMTJY.js.map → chunk-4HKAZRTC.js.map} +1 -1
  34. package/dist/{chunk-CEIHCKTO.cjs → chunk-5COPO3H4.cjs} +4 -4
  35. package/dist/{chunk-CEIHCKTO.cjs.map → chunk-5COPO3H4.cjs.map} +1 -1
  36. package/dist/{chunk-KX7JV5KM.js → chunk-5XPKYDK7.js} +3 -3
  37. package/dist/{chunk-KX7JV5KM.js.map → chunk-5XPKYDK7.js.map} +1 -1
  38. package/dist/{chunk-E2FFG33C.js → chunk-7HP6N5X3.js} +5 -5
  39. package/dist/{chunk-E2FFG33C.js.map → chunk-7HP6N5X3.js.map} +1 -1
  40. package/dist/{chunk-3I4B3OIX.js → chunk-7PBAJ2WA.js} +3 -3
  41. package/dist/{chunk-3I4B3OIX.js.map → chunk-7PBAJ2WA.js.map} +1 -1
  42. package/dist/{chunk-KGRIHEDT.js → chunk-7WXT5M6P.js} +5 -5
  43. package/dist/{chunk-KGRIHEDT.js.map → chunk-7WXT5M6P.js.map} +1 -1
  44. package/dist/{chunk-BCQ3E2ZG.cjs → chunk-A76OFN2B.cjs} +8 -4
  45. package/dist/chunk-A76OFN2B.cjs.map +1 -0
  46. package/dist/{chunk-TOTP24P6.js → chunk-AFJAQ5JV.js} +4 -4
  47. package/dist/{chunk-TOTP24P6.js.map → chunk-AFJAQ5JV.js.map} +1 -1
  48. package/dist/{chunk-DKFGUOWL.js → chunk-AKMPQJPX.js} +3 -3
  49. package/dist/{chunk-DKFGUOWL.js.map → chunk-AKMPQJPX.js.map} +1 -1
  50. package/dist/{chunk-HIQFVHC6.cjs → chunk-ALDFVGQQ.cjs} +9 -9
  51. package/dist/{chunk-HIQFVHC6.cjs.map → chunk-ALDFVGQQ.cjs.map} +1 -1
  52. package/dist/{chunk-INSFS5GT.cjs → chunk-AYDSWY35.cjs} +293 -293
  53. package/dist/{chunk-INSFS5GT.cjs.map → chunk-AYDSWY35.cjs.map} +1 -1
  54. package/dist/{chunk-YRXY2A5L.js → chunk-BBMN4O6E.js} +4 -4
  55. package/dist/{chunk-YRXY2A5L.js.map → chunk-BBMN4O6E.js.map} +1 -1
  56. package/dist/{chunk-6EEYRFJC.js → chunk-BM7VYZED.js} +5 -5
  57. package/dist/{chunk-6EEYRFJC.js.map → chunk-BM7VYZED.js.map} +1 -1
  58. package/dist/{chunk-ML5A5DOJ.js → chunk-C64E2EJS.js} +4 -4
  59. package/dist/{chunk-ML5A5DOJ.js.map → chunk-C64E2EJS.js.map} +1 -1
  60. package/dist/{chunk-E4IUN3JB.cjs → chunk-CJHBSSAF.cjs} +15 -15
  61. package/dist/{chunk-E4IUN3JB.cjs.map → chunk-CJHBSSAF.cjs.map} +1 -1
  62. package/dist/{chunk-IHFNRNTJ.cjs → chunk-E7WWIX34.cjs} +8 -8
  63. package/dist/{chunk-IHFNRNTJ.cjs.map → chunk-E7WWIX34.cjs.map} +1 -1
  64. package/dist/{chunk-C7OP3FAK.cjs → chunk-EJNFZET4.cjs} +11 -11
  65. package/dist/{chunk-C7OP3FAK.cjs.map → chunk-EJNFZET4.cjs.map} +1 -1
  66. package/dist/{chunk-ECW2MLEW.cjs → chunk-ELYGL52R.cjs} +4 -4
  67. package/dist/{chunk-ECW2MLEW.cjs.map → chunk-ELYGL52R.cjs.map} +1 -1
  68. package/dist/{chunk-GIRD3RWH.js → chunk-ERBH54V3.js} +35 -35
  69. package/dist/{chunk-GIRD3RWH.js.map → chunk-ERBH54V3.js.map} +1 -1
  70. package/dist/{chunk-JRLXEYR4.js → chunk-EYUZZXHZ.js} +4 -4
  71. package/dist/{chunk-JRLXEYR4.js.map → chunk-EYUZZXHZ.js.map} +1 -1
  72. package/dist/{chunk-PI4RO4GR.js → chunk-F4SQTWVR.js} +3 -3
  73. package/dist/{chunk-PI4RO4GR.js.map → chunk-F4SQTWVR.js.map} +1 -1
  74. package/dist/{chunk-LALG2K33.cjs → chunk-FMDZZRYE.cjs} +8 -8
  75. package/dist/{chunk-LALG2K33.cjs.map → chunk-FMDZZRYE.cjs.map} +1 -1
  76. package/dist/{chunk-SCFW5MJZ.js → chunk-FUP3ZA5T.js} +4 -4
  77. package/dist/{chunk-SCFW5MJZ.js.map → chunk-FUP3ZA5T.js.map} +1 -1
  78. package/dist/{chunk-DWY25VLP.cjs → chunk-H2V6CXM7.cjs} +9 -9
  79. package/dist/{chunk-DWY25VLP.cjs.map → chunk-H2V6CXM7.cjs.map} +1 -1
  80. package/dist/{chunk-DU7DE543.js → chunk-HCRCNI7A.js} +3 -3
  81. package/dist/{chunk-DU7DE543.js.map → chunk-HCRCNI7A.js.map} +1 -1
  82. package/dist/{chunk-QKE556YD.js → chunk-HJMFPIRM.js} +5 -5
  83. package/dist/{chunk-QKE556YD.js.map → chunk-HJMFPIRM.js.map} +1 -1
  84. package/dist/{chunk-J3UK2GMN.js → chunk-IEKSEAIV.js} +3 -3
  85. package/dist/{chunk-J3UK2GMN.js.map → chunk-IEKSEAIV.js.map} +1 -1
  86. package/dist/{chunk-DMTZ3FII.cjs → chunk-JERO4TP6.cjs} +5 -5
  87. package/dist/{chunk-DMTZ3FII.cjs.map → chunk-JERO4TP6.cjs.map} +1 -1
  88. package/dist/{chunk-6LGQECT7.cjs → chunk-K6TWHNT4.cjs} +11 -11
  89. package/dist/{chunk-6LGQECT7.cjs.map → chunk-K6TWHNT4.cjs.map} +1 -1
  90. package/dist/{chunk-4F7JQZOX.js → chunk-KRPEPZQY.js} +7 -7
  91. package/dist/{chunk-4F7JQZOX.js.map → chunk-KRPEPZQY.js.map} +1 -1
  92. package/dist/{chunk-CN6UX5EV.cjs → chunk-LNTQRD23.cjs} +26 -26
  93. package/dist/{chunk-CN6UX5EV.cjs.map → chunk-LNTQRD23.cjs.map} +1 -1
  94. package/dist/{chunk-W4WKVOOQ.cjs → chunk-LOTWA65Z.cjs} +11 -11
  95. package/dist/{chunk-W4WKVOOQ.cjs.map → chunk-LOTWA65Z.cjs.map} +1 -1
  96. package/dist/{chunk-BPN5ONSW.cjs → chunk-LR3VKB7A.cjs} +124 -120
  97. package/dist/chunk-LR3VKB7A.cjs.map +1 -0
  98. package/dist/{chunk-ET6PHZRX.js → chunk-LWVKI75U.js} +3 -3
  99. package/dist/{chunk-ET6PHZRX.js.map → chunk-LWVKI75U.js.map} +1 -1
  100. package/dist/{chunk-G2Q3ZC6C.cjs → chunk-LY4KEOOY.cjs} +4 -4
  101. package/dist/{chunk-G2Q3ZC6C.cjs.map → chunk-LY4KEOOY.cjs.map} +1 -1
  102. package/dist/{chunk-42IFCKQZ.js → chunk-LYD3ALDT.js} +5 -5
  103. package/dist/{chunk-42IFCKQZ.js.map → chunk-LYD3ALDT.js.map} +1 -1
  104. package/dist/{chunk-KWUNN5J2.js → chunk-MDN44YMZ.js} +5 -5
  105. package/dist/{chunk-KWUNN5J2.js.map → chunk-MDN44YMZ.js.map} +1 -1
  106. package/dist/{chunk-HWNVAUK4.js → chunk-MI3OKONE.js} +3 -3
  107. package/dist/{chunk-HWNVAUK4.js.map → chunk-MI3OKONE.js.map} +1 -1
  108. package/dist/{chunk-VJYSQXN6.cjs → chunk-MM2JKFQV.cjs} +10 -10
  109. package/dist/{chunk-VJYSQXN6.cjs.map → chunk-MM2JKFQV.cjs.map} +1 -1
  110. package/dist/{chunk-74D7KSBP.cjs → chunk-MWVLE5RY.cjs} +11 -11
  111. package/dist/{chunk-74D7KSBP.cjs.map → chunk-MWVLE5RY.cjs.map} +1 -1
  112. package/dist/{chunk-V2RBCCN5.js → chunk-NHXPQN44.js} +3 -3
  113. package/dist/{chunk-V2RBCCN5.js.map → chunk-NHXPQN44.js.map} +1 -1
  114. package/dist/{chunk-Z2CUEBXV.cjs → chunk-NJVV5OAV.cjs} +8 -8
  115. package/dist/{chunk-Z2CUEBXV.cjs.map → chunk-NJVV5OAV.cjs.map} +1 -1
  116. package/dist/{chunk-J6T5LWJ4.cjs → chunk-OVGNXGCK.cjs} +9 -9
  117. package/dist/{chunk-J6T5LWJ4.cjs.map → chunk-OVGNXGCK.cjs.map} +1 -1
  118. package/dist/{chunk-TIMPJL5V.cjs → chunk-PDOLUFGY.cjs} +4 -4
  119. package/dist/{chunk-TIMPJL5V.cjs.map → chunk-PDOLUFGY.cjs.map} +1 -1
  120. package/dist/{chunk-FWBSDQZ7.cjs → chunk-PIBXDEZM.cjs} +5 -5
  121. package/dist/{chunk-FWBSDQZ7.cjs.map → chunk-PIBXDEZM.cjs.map} +1 -1
  122. package/dist/{chunk-USZTVNUQ.cjs → chunk-PY7G7YWK.cjs} +5 -5
  123. package/dist/{chunk-USZTVNUQ.cjs.map → chunk-PY7G7YWK.cjs.map} +1 -1
  124. package/dist/{chunk-N475ETD6.cjs → chunk-QMIG7TKG.cjs} +17 -17
  125. package/dist/{chunk-N475ETD6.cjs.map → chunk-QMIG7TKG.cjs.map} +1 -1
  126. package/dist/{chunk-D7IULBF2.js → chunk-RA2UZBYP.js} +3 -3
  127. package/dist/{chunk-D7IULBF2.js.map → chunk-RA2UZBYP.js.map} +1 -1
  128. package/dist/{chunk-7OLG7VI4.cjs → chunk-RHQJX3EI.cjs} +4 -4
  129. package/dist/{chunk-7OLG7VI4.cjs.map → chunk-RHQJX3EI.cjs.map} +1 -1
  130. package/dist/{chunk-YP67XZES.js → chunk-RMCHJZNZ.js} +4 -4
  131. package/dist/{chunk-YP67XZES.js.map → chunk-RMCHJZNZ.js.map} +1 -1
  132. package/dist/{chunk-ZYB6B7QJ.js → chunk-RMO7HAIF.js} +13 -9
  133. package/dist/chunk-RMO7HAIF.js.map +1 -0
  134. package/dist/{chunk-IVSD7L22.js → chunk-RNCN2TTP.js} +8 -4
  135. package/dist/chunk-RNCN2TTP.js.map +1 -0
  136. package/dist/{chunk-BQDUEG4C.js → chunk-RTDT2UMT.js} +3 -3
  137. package/dist/{chunk-BQDUEG4C.js.map → chunk-RTDT2UMT.js.map} +1 -1
  138. package/dist/{chunk-FRUBE44B.cjs → chunk-TZ47DTM2.cjs} +24 -24
  139. package/dist/{chunk-FRUBE44B.cjs.map → chunk-TZ47DTM2.cjs.map} +1 -1
  140. package/dist/{chunk-6YNYA7GD.cjs → chunk-U53AYSHS.cjs} +11 -11
  141. package/dist/{chunk-6YNYA7GD.cjs.map → chunk-U53AYSHS.cjs.map} +1 -1
  142. package/dist/{chunk-G4XUXSRN.cjs → chunk-UDSGSPUY.cjs} +12 -12
  143. package/dist/{chunk-G4XUXSRN.cjs.map → chunk-UDSGSPUY.cjs.map} +1 -1
  144. package/dist/{chunk-LJX2SQV2.js → chunk-UIPTINIF.js} +6 -6
  145. package/dist/{chunk-LJX2SQV2.js.map → chunk-UIPTINIF.js.map} +1 -1
  146. package/dist/{chunk-6NEHIHFU.cjs → chunk-V7CA3CX5.cjs} +4 -4
  147. package/dist/{chunk-6NEHIHFU.cjs.map → chunk-V7CA3CX5.cjs.map} +1 -1
  148. package/dist/{chunk-SG5ZWT6C.js → chunk-VQ33XLC6.js} +3 -3
  149. package/dist/{chunk-SG5ZWT6C.js.map → chunk-VQ33XLC6.js.map} +1 -1
  150. package/dist/{chunk-AECV3G5Z.js → chunk-VTDQRUAJ.js} +4 -4
  151. package/dist/{chunk-AECV3G5Z.js.map → chunk-VTDQRUAJ.js.map} +1 -1
  152. package/dist/{chunk-MC5EINBV.js → chunk-WJOLIPEM.js} +8 -8
  153. package/dist/{chunk-MC5EINBV.js.map → chunk-WJOLIPEM.js.map} +1 -1
  154. package/dist/{chunk-7U2HAAWB.cjs → chunk-X2LDDKFM.cjs} +10 -10
  155. package/dist/{chunk-7U2HAAWB.cjs.map → chunk-X2LDDKFM.cjs.map} +1 -1
  156. package/dist/{chunk-LGILIGV3.js → chunk-XKGOIGTJ.js} +3 -3
  157. package/dist/{chunk-LGILIGV3.js.map → chunk-XKGOIGTJ.js.map} +1 -1
  158. package/dist/{chunk-65ONFZWM.js → chunk-XZ7PO2FM.js} +4 -4
  159. package/dist/{chunk-65ONFZWM.js.map → chunk-XZ7PO2FM.js.map} +1 -1
  160. package/dist/{chunk-DCXRHCZJ.cjs → chunk-Z5DYGBPV.cjs} +8 -8
  161. package/dist/{chunk-DCXRHCZJ.cjs.map → chunk-Z5DYGBPV.cjs.map} +1 -1
  162. package/dist/{chunk-7YBJZS5P.cjs → chunk-ZAKTZ5B4.cjs} +8 -8
  163. package/dist/{chunk-7YBJZS5P.cjs.map → chunk-ZAKTZ5B4.cjs.map} +1 -1
  164. package/dist/compact-session-FCEFK2CG.cjs +55 -0
  165. package/dist/{compact-session-VVT6IBJG.cjs.map → compact-session-FCEFK2CG.cjs.map} +1 -1
  166. package/dist/compact-session-KPYRNTQN.js +18 -0
  167. package/dist/{compact-session-PYEC3NZV.js.map → compact-session-KPYRNTQN.js.map} +1 -1
  168. package/dist/compaction.cjs +16 -16
  169. package/dist/compaction.js +3 -3
  170. package/dist/concurrency.cjs +6 -6
  171. package/dist/concurrency.js +4 -4
  172. package/dist/context-DNFT4B5D.cjs +22 -0
  173. package/dist/{context-2FZSC6VQ.cjs.map → context-DNFT4B5D.cjs.map} +1 -1
  174. package/dist/context-LYE6TJL5.js +5 -0
  175. package/dist/{context-ATJJAFOS.js.map → context-LYE6TJL5.js.map} +1 -1
  176. package/dist/cron.cjs +31 -31
  177. package/dist/cron.js +30 -30
  178. package/dist/errors.cjs +21 -21
  179. package/dist/errors.js +2 -2
  180. package/dist/eval.cjs +36 -36
  181. package/dist/eval.js +30 -30
  182. package/dist/{executor-T65PPOPT.js → executor-PCRX3533.js} +7 -7
  183. package/dist/{executor-T65PPOPT.js.map → executor-PCRX3533.js.map} +1 -1
  184. package/dist/{executor-BMRICN46.cjs → executor-TQ3FSZ7F.cjs} +24 -24
  185. package/dist/{executor-BMRICN46.cjs.map → executor-TQ3FSZ7F.cjs.map} +1 -1
  186. package/dist/filesystem/index.cjs +7 -7
  187. package/dist/filesystem/index.js +3 -3
  188. package/dist/fs-session-store-V32XJ63Z.cjs +19 -0
  189. package/dist/{fs-session-store-J5MCFFUM.cjs.map → fs-session-store-V32XJ63Z.cjs.map} +1 -1
  190. package/dist/fs-session-store-YPZIOLJM.js +10 -0
  191. package/dist/{fs-session-store-O6FNHECD.js.map → fs-session-store-YPZIOLJM.js.map} +1 -1
  192. package/dist/generate-object-DLHT5RXH.js +7 -0
  193. package/dist/{generate-object-XDCBYVK3.js.map → generate-object-DLHT5RXH.js.map} +1 -1
  194. package/dist/generate-object-QILSGTEJ.cjs +20 -0
  195. package/dist/{generate-object-UF6WIZLF.cjs.map → generate-object-QILSGTEJ.cjs.map} +1 -1
  196. package/dist/index-manager-LEMQ73A7.cjs +20 -0
  197. package/dist/{index-manager-N7RQYUKT.cjs.map → index-manager-LEMQ73A7.cjs.map} +1 -1
  198. package/dist/index-manager-SXF3FAQV.js +11 -0
  199. package/dist/{index-manager-ZVZUHPP7.js.map → index-manager-SXF3FAQV.js.map} +1 -1
  200. package/dist/index.cjs +129 -129
  201. package/dist/index.js +43 -43
  202. package/dist/{inject-session-LFCYVSLJ.cjs → inject-session-BIVVFWGL.cjs} +9 -9
  203. package/dist/{inject-session-LFCYVSLJ.cjs.map → inject-session-BIVVFWGL.cjs.map} +1 -1
  204. package/dist/{inject-session-GQMTDZUN.js → inject-session-OLWZ2NJN.js} +7 -7
  205. package/dist/{inject-session-GQMTDZUN.js.map → inject-session-OLWZ2NJN.js.map} +1 -1
  206. package/dist/internal/memory/adapters/index.cjs +8 -8
  207. package/dist/internal/memory/adapters/index.js +7 -7
  208. package/dist/internal/persistence/index.cjs +25 -25
  209. package/dist/internal/persistence/index.js +6 -6
  210. package/dist/internal/security/index.cjs +13 -13
  211. package/dist/internal/security/index.js +3 -3
  212. package/dist/judge-call-AIT3EULV.cjs +22 -0
  213. package/dist/{judge-call-U2D33JOW.cjs.map → judge-call-AIT3EULV.cjs.map} +1 -1
  214. package/dist/judge-call-NPRU7JIQ.js +5 -0
  215. package/dist/{judge-call-NA2G6ZMJ.js.map → judge-call-NPRU7JIQ.js.map} +1 -1
  216. package/dist/models.cjs +20 -20
  217. package/dist/models.js +5 -5
  218. package/dist/path-safety.cjs +10 -10
  219. package/dist/path-safety.js +3 -3
  220. package/dist/persistence.cjs +26 -26
  221. package/dist/persistence.js +7 -7
  222. package/dist/project.cjs +5 -5
  223. package/dist/project.js +3 -3
  224. package/dist/registry-AXQXPLFH.js +9 -0
  225. package/dist/{registry-CAS6Y5ZY.js.map → registry-AXQXPLFH.js.map} +1 -1
  226. package/dist/registry-VKDFTK6L.cjs +46 -0
  227. package/dist/{registry-JSDI4WKA.cjs.map → registry-VKDFTK6L.cjs.map} +1 -1
  228. package/dist/retry.cjs +4 -4
  229. package/dist/retry.js +3 -3
  230. package/dist/sandbox/index.cjs +6 -6
  231. package/dist/sandbox/index.js +2 -2
  232. package/dist/server/errors-envelope.cjs +14 -14
  233. package/dist/server/errors-envelope.js +3 -3
  234. package/dist/session-transcript-SLQRKQ72.cjs +50 -0
  235. package/dist/{session-transcript-H7NUFXXM.cjs.map → session-transcript-SLQRKQ72.cjs.map} +1 -1
  236. package/dist/session-transcript-X3UMSVL2.js +5 -0
  237. package/dist/{session-transcript-3B52DKTG.js.map → session-transcript-X3UMSVL2.js.map} +1 -1
  238. package/dist/skills.cjs +7 -7
  239. package/dist/skills.js +5 -5
  240. package/dist/stream-object-3HEUGMQY.cjs +20 -0
  241. package/dist/{stream-object-4FDU76YW.cjs.map → stream-object-3HEUGMQY.cjs.map} +1 -1
  242. package/dist/stream-object-VWYW7FJ2.js +7 -0
  243. package/dist/{stream-object-HWDEEQN4.js.map → stream-object-VWYW7FJ2.js.map} +1 -1
  244. package/dist/subagents-loader-F52ARQ62.cjs +15 -0
  245. package/dist/{subagents-loader-A4W6C3QP.cjs.map → subagents-loader-F52ARQ62.cjs.map} +1 -1
  246. package/dist/subagents-loader-QUIK6GMV.js +6 -0
  247. package/dist/{subagents-loader-X33KH2SZ.js.map → subagents-loader-QUIK6GMV.js.map} +1 -1
  248. package/dist/subagents-loader.cjs +6 -6
  249. package/dist/subagents-loader.js +4 -4
  250. package/dist/subscription/index.cjs +3 -3
  251. package/dist/subscription/index.js +2 -2
  252. package/dist/task-store.cjs +7 -7
  253. package/dist/task-store.js +4 -4
  254. package/dist/workflow.cjs +27 -27
  255. package/dist/workflow.js +6 -6
  256. package/package.json +1 -1
  257. package/dist/agent-I3EZZR6S.cjs +0 -55
  258. package/dist/agent-KKZYLY5D.js +0 -46
  259. package/dist/agent-session-store-N4TVKHBU.cjs +0 -23
  260. package/dist/agent-session-store-RHMHP5DG.js +0 -6
  261. package/dist/chunk-BCQ3E2ZG.cjs.map +0 -1
  262. package/dist/chunk-BPN5ONSW.cjs.map +0 -1
  263. package/dist/chunk-IVSD7L22.js.map +0 -1
  264. package/dist/chunk-ZYB6B7QJ.js.map +0 -1
  265. package/dist/compact-session-PYEC3NZV.js +0 -18
  266. package/dist/compact-session-VVT6IBJG.cjs +0 -55
  267. package/dist/context-2FZSC6VQ.cjs +0 -22
  268. package/dist/context-ATJJAFOS.js +0 -5
  269. package/dist/fs-session-store-J5MCFFUM.cjs +0 -19
  270. package/dist/fs-session-store-O6FNHECD.js +0 -10
  271. package/dist/generate-object-UF6WIZLF.cjs +0 -20
  272. package/dist/generate-object-XDCBYVK3.js +0 -7
  273. package/dist/index-manager-N7RQYUKT.cjs +0 -20
  274. package/dist/index-manager-ZVZUHPP7.js +0 -11
  275. package/dist/judge-call-NA2G6ZMJ.js +0 -5
  276. package/dist/judge-call-U2D33JOW.cjs +0 -22
  277. package/dist/registry-CAS6Y5ZY.js +0 -9
  278. package/dist/registry-JSDI4WKA.cjs +0 -46
  279. package/dist/session-transcript-3B52DKTG.js +0 -5
  280. package/dist/session-transcript-H7NUFXXM.cjs +0 -50
  281. package/dist/stream-object-4FDU76YW.cjs +0 -20
  282. package/dist/stream-object-HWDEEQN4.js +0 -7
  283. package/dist/subagents-loader-A4W6C3QP.cjs +0 -15
  284. package/dist/subagents-loader-X33KH2SZ.js +0 -6
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stream-object.ts"],"names":[],"mappings":"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","file":"chunk-DU7DE543.js","sourcesContent":["import type { z as ZodNamespace, ZodType } from \"zod\";\n\nimport {\n buildToolPrompt,\n buildTransientAgentOptions,\n disposeAndDeleteTransient,\n extractUsage,\n makeOutputTool,\n setupStructuredOutput,\n} from \"./internal/structured-output-helpers.js\";\nimport type { AgentOptions, LocalOptions, ModelSelection, SDKAgent } from \"./types/agent.js\";\nimport type { ProviderRoutingSettings } from \"./types/providers.js\";\n\n/**\n * Options accepted by {@link Agent.streamObject}. Same shape as\n * `Agent.generateObject` with the addition that the result is an\n * `AsyncIterator<StreamObjectEvent<T>>` rather than a single Promise. See ADR D39.\n *\n * @public\n */\nexport interface StreamObjectOptions<T extends ZodType> {\n schema: T;\n prompt: string;\n systemPrompt?: string;\n /** SE8 — accepts a bare-string id shorthand or a {@link ModelSelection}. */\n model: string | ModelSelection;\n apiKey?: string;\n local: LocalOptions;\n maxRetries?: number;\n /**\n * Optional provider routing forwarded to the transient agent. Required when\n * `model.id` uses a prefix (e.g. `openai/gpt-4o-mini`) but the credential is\n * for a unified gateway (e.g. OpenRouter). Without this, the SDK infers\n * provider from the prefix and may fail with `provider_unresolved` even\n * when the right env key is set under a different provider name.\n */\n providers?: ProviderRoutingSettings;\n}\n\n/**\n * Recursive partial — `T` where every nested field becomes optional.\n *\n * @public\n */\nexport type DeepPartial<T> = T extends (infer U)[]\n ? Array<DeepPartial<U>>\n : T extends object\n ? { [K in keyof T]?: DeepPartial<T[K]> }\n : T;\n\n/**\n * Event emitted by {@link Agent.streamObject}. Discriminate on `type`.\n *\n * - `partial` events fire zero or more times with monotonically increasing\n * `attempt`, carrying best-effort schema-parsed snapshots of the model's\n * accumulating output.\n * - `complete` fires exactly once at the end, carrying the fully Zod-parsed\n * object alongside usage and finishReason — semantically identical to a\n * successful `Agent.generateObject()` return.\n *\n * @public\n */\nexport type StreamObjectEvent<T> =\n | { type: \"partial\"; partial: DeepPartial<T>; attempt: number }\n | {\n type: \"complete\";\n object: T;\n raw: unknown;\n usage: { inputTokens: number; outputTokens: number };\n finishReason: \"tool_use\" | \"error\";\n };\n\n/**\n * Error thrown by {@link Agent.streamObject} when the model refuses to call\n * the synthetic `output` tool or when all retries fail to produce a\n * schema-valid object. Same code taxonomy as `GenerateObjectError`.\n *\n * @public\n */\nexport class StreamObjectError extends Error {\n override readonly name = \"StreamObjectError\";\n readonly code: \"no_tool_call\" | \"parse_failed\";\n override readonly cause?: unknown;\n constructor(code: \"no_tool_call\" | \"parse_failed\", message: string, cause?: unknown) {\n super(message);\n this.code = code;\n if (cause !== undefined) this.cause = cause;\n }\n}\n\ninterface StreamObjectDeps {\n create: (options: AgentOptions) => Promise<SDKAgent>;\n delete: (agentId: string) => Promise<void>;\n}\n\n/**\n * Implementation of `Agent.streamObject` as an async generator. Mirrors the\n * synthetic-forced-tool pattern from `generate-object.ts` (ADR D33) with the\n * addition of intermediate `partial` events emitted from incremental parsing\n * of accumulating text deltas during the agent loop.\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: streaming loop interleaves text-delta accumulation, partial-parse attempts, retries, and final dispose — splitting harms locality of the iterator contract.\nexport async function* streamObjectImpl<T extends ZodType>(\n options: StreamObjectOptions<T>,\n deps: StreamObjectDeps,\n): AsyncGenerator<StreamObjectEvent<ZodNamespace.infer<T>>, void, void> {\n const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(\n options.schema,\n options.maxRetries,\n );\n let capturedRaw: unknown;\n let lastUsage = initialUsage;\n\n const outputTool = makeOutputTool(jsonSchema, (input) => {\n // EC-6: first capture wins (parallel tool use in Claude 3.5+).\n if (capturedRaw === undefined) {\n capturedRaw = input;\n }\n return JSON.stringify({ ok: true });\n });\n\n const agentOptions: AgentOptions = buildTransientAgentOptions({\n model: options.model,\n local: options.local,\n outputTool,\n ...(options.systemPrompt !== undefined ? { systemPrompt: options.systemPrompt } : {}),\n ...(options.apiKey !== undefined ? { apiKey: options.apiKey } : {}),\n ...(options.providers !== undefined ? { providers: options.providers } : {}),\n });\n const agent = await deps.create(agentOptions);\n const userMessage = buildToolPrompt(options.prompt);\n\n try {\n let lastParseError: unknown;\n let attemptCounter = 0;\n\n for (let attempt = 0; attempt <= maxRetries; attempt += 1) {\n capturedRaw = undefined;\n const run = await agent.send(userMessage);\n\n // Buffer text deltas during streaming; try partial-parse on each.\n let textBuffer = \"\";\n for await (const msg of run.stream()) {\n if (msg.type === \"assistant\") {\n const newText = msg.message.content\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\");\n if (newText.length > 0) {\n textBuffer += newText;\n const partial = bestEffortPartialParse(textBuffer, options.schema);\n if (partial !== undefined) {\n attemptCounter += 1;\n yield {\n type: \"partial\",\n partial: partial as DeepPartial<ZodNamespace.infer<T>>,\n attempt: attemptCounter,\n };\n }\n }\n }\n }\n const result = await run.wait();\n lastUsage = extractUsage(result);\n\n if (capturedRaw === undefined) {\n // EC: when the underlying run errored (e.g. provider_unresolved),\n // surface the original cause instead of the misleading \"model\n // returned text\" message — there was no model call at all.\n if (result.status === \"error\" && result.error !== undefined) {\n throw new StreamObjectError(\n \"no_tool_call\",\n `Agent run failed before the model could reply: ${result.error.message ?? \"unknown error\"} [${result.error.code ?? \"?\"}]`,\n result.error,\n );\n }\n if (attempt === maxRetries) {\n throw new StreamObjectError(\n \"no_tool_call\",\n \"The model returned text instead of calling the `output` tool.\",\n );\n }\n continue;\n }\n\n const parsed = options.schema.safeParse(capturedRaw);\n if (parsed.success) {\n yield {\n type: \"complete\",\n object: parsed.data,\n raw: capturedRaw,\n usage: lastUsage,\n finishReason: \"tool_use\",\n };\n return;\n }\n lastParseError = parsed.error;\n }\n\n throw new StreamObjectError(\n \"parse_failed\",\n \"Schema parse failed after all retries.\",\n lastParseError,\n );\n } finally {\n // EC-4: even if consumer calls iter.return() mid-stream, this finally\n // runs — transient agent is disposed AND removed from registry.\n await disposeAndDeleteTransient(agent, deps.delete);\n }\n}\n\n/**\n * Try to extract a partial JSON object from a possibly-incomplete text\n * buffer and parse it via the schema in lenient mode. Returns `undefined`\n * if nothing parseable is found yet.\n *\n * Strategy: find the first `{`, find the LAST balanced `}` (greedy), parse\n * the substring as JSON, then `safeParse` against `schema.partial()` if the\n * schema supports it, else against the original schema.\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: stateful JSON-balancing scanner — string/brace/escape state must be co-located for the parser to remain correct.\nfunction bestEffortPartialParse<T extends ZodType>(text: string, schema: T): unknown | undefined {\n const start = text.indexOf(\"{\");\n if (start < 0) return undefined;\n // Find the longest balanced JSON object from `start`.\n let depth = 0;\n let inString = false;\n let isEscaped = false;\n let end = -1;\n for (let i = start; i < text.length; i += 1) {\n const ch = text[i];\n if (isEscaped) {\n isEscaped = false;\n continue;\n }\n if (ch === \"\\\\\" && inString) {\n isEscaped = true;\n continue;\n }\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) continue;\n if (ch === \"{\") depth += 1;\n else if (ch === \"}\") {\n depth -= 1;\n if (depth === 0) end = i;\n }\n }\n if (end < 0) return undefined;\n const candidate = text.slice(start, end + 1);\n let parsed: unknown;\n try {\n parsed = JSON.parse(candidate);\n } catch {\n return undefined;\n }\n // Try schema.partial() if available (Zod objects support it); else fall\n // back to the original schema (loose match).\n const maybePartial = (schema as unknown as { partial?: () => ZodType }).partial;\n const looseSchema = typeof maybePartial === \"function\" ? maybePartial.call(schema) : schema;\n const result = looseSchema.safeParse(parsed);\n return result.success ? result.data : undefined;\n}\n"]}
1
+ {"version":3,"sources":["../src/stream-object.ts"],"names":[],"mappings":";;;AA+EO,IAAM,iBAAA,GAAN,cAAgC,KAAA,CAAM;AAAA,EACzB,IAAA,GAAO,mBAAA;AAAA,EAChB,IAAA;AAAA,EACS,KAAA;AAAA,EAClB,WAAA,CAAY,IAAA,EAAuC,OAAA,EAAiB,KAAA,EAAiB;AACnF,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAI,KAAA,KAAU,MAAA,EAAW,IAAA,CAAK,KAAA,GAAQ,KAAA;AAAA,EACxC;AACF;AAgBA,gBAAuB,gBAAA,CACrB,SACA,IAAA,EACsE;AACtE,EAAA,MAAM,EAAE,UAAA,EAAY,UAAA,EAAY,YAAA,EAAa,GAAI,qBAAA;AAAA,IAC/C,OAAA,CAAQ,MAAA;AAAA,IACR,OAAA,CAAQ;AAAA,GACV;AACA,EAAA,IAAI,WAAA;AACJ,EAAA,IAAI,SAAA,GAAY,YAAA;AAEhB,EAAA,MAAM,UAAA,GAAa,cAAA,CAAe,UAAA,EAAY,CAAC,KAAA,KAAU;AAEvD,IAAA,IAAI,gBAAgB,MAAA,EAAW;AAC7B,MAAA,WAAA,GAAc,KAAA;AAAA,IAChB;AACA,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,EACpC,CAAC,CAAA;AAED,EAAA,MAAM,eAA6B,0BAAA,CAA2B;AAAA,IAC5D,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,UAAA;AAAA,IACA,GAAI,QAAQ,YAAA,KAAiB,MAAA,GAAY,EAAE,YAAA,EAAc,OAAA,CAAQ,YAAA,EAAa,GAAI,EAAC;AAAA,IACnF,GAAI,QAAQ,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAO,GAAI,EAAC;AAAA,IACjE,GAAI,QAAQ,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,EAAW,OAAA,CAAQ,SAAA,EAAU,GAAI;AAAC,GAC3E,CAAA;AACD,EAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,MAAA,CAAO,YAAY,CAAA;AAC5C,EAAA,MAAM,WAAA,GAAc,eAAA,CAAgB,OAAA,CAAQ,MAAM,CAAA;AAElD,EAAA,IAAI;AACF,IAAA,IAAI,cAAA;AACJ,IAAA,IAAI,cAAA,GAAiB,CAAA;AAErB,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,UAAA,EAAY,WAAW,CAAA,EAAG;AACzD,MAAA,WAAA,GAAc,KAAA,CAAA;AACd,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,IAAA,CAAK,WAAW,CAAA;AAGxC,MAAA,IAAI,UAAA,GAAa,EAAA;AACjB,MAAA,WAAA,MAAiB,GAAA,IAAO,GAAA,CAAI,MAAA,EAAO,EAAG;AACpC,QAAA,IAAI,GAAA,CAAI,SAAS,WAAA,EAAa;AAC5B,UAAA,MAAM,UAAU,GAAA,CAAI,OAAA,CAAQ,QACzB,MAAA,CAAO,CAAC,MAA2C,CAAA,CAAE,IAAA,KAAS,MAAM,CAAA,CACpE,IAAI,CAAC,CAAA,KAAM,EAAE,IAAI,CAAA,CACjB,KAAK,EAAE,CAAA;AACV,UAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,YAAA,UAAA,IAAc,OAAA;AACd,YAAA,MAAM,OAAA,GAAU,sBAAA,CAAuB,UAAA,EAAY,OAAA,CAAQ,MAAM,CAAA;AACjE,YAAA,IAAI,YAAY,KAAA,CAAA,EAAW;AACzB,cAAA,cAAA,IAAkB,CAAA;AAClB,cAAA,MAAM;AAAA,gBACJ,IAAA,EAAM,SAAA;AAAA,gBACN,OAAA;AAAA,gBACA,OAAA,EAAS;AAAA,eACX;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,MAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,IAAA,EAAK;AAC9B,MAAA,SAAA,GAAY,aAAa,MAAM,CAAA;AAE/B,MAAA,IAAI,gBAAgB,KAAA,CAAA,EAAW;AAI7B,QAAA,IAAI,MAAA,CAAO,MAAA,KAAW,OAAA,IAAW,MAAA,CAAO,UAAU,KAAA,CAAA,EAAW;AAC3D,UAAA,MAAM,IAAI,iBAAA;AAAA,YACR,cAAA;AAAA,YACA,CAAA,+CAAA,EAAkD,OAAO,KAAA,CAAM,OAAA,IAAW,eAAe,CAAA,EAAA,EAAK,MAAA,CAAO,KAAA,CAAM,IAAA,IAAQ,GAAG,CAAA,CAAA,CAAA;AAAA,YACtH,MAAA,CAAO;AAAA,WACT;AAAA,QACF;AACA,QAAA,IAAI,YAAY,UAAA,EAAY;AAC1B,UAAA,MAAM,IAAI,iBAAA;AAAA,YACR,cAAA;AAAA,YACA;AAAA,WACF;AAAA,QACF;AACA,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,CAAO,SAAA,CAAU,WAAW,CAAA;AACnD,MAAA,IAAI,OAAO,OAAA,EAAS;AAClB,QAAA,MAAM;AAAA,UACJ,IAAA,EAAM,UAAA;AAAA,UACN,QAAQ,MAAA,CAAO,IAAA;AAAA,UACf,GAAA,EAAK,WAAA;AAAA,UACL,KAAA,EAAO,SAAA;AAAA,UACP,YAAA,EAAc;AAAA,SAChB;AACA,QAAA;AAAA,MACF;AACA,MAAA,cAAA,GAAiB,MAAA,CAAO,KAAA;AAAA,IAC1B;AAEA,IAAA,MAAM,IAAI,iBAAA;AAAA,MACR,cAAA;AAAA,MACA,wCAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,CAAA,SAAE;AAGA,IAAA,MAAM,yBAAA,CAA0B,KAAA,EAAO,IAAA,CAAK,MAAM,CAAA;AAAA,EACpD;AACF;AAcA,SAAS,sBAAA,CAA0C,MAAc,MAAA,EAAgC;AAC/F,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC9B,EAAA,IAAI,KAAA,GAAQ,GAAG,OAAO,MAAA;AAEtB,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,IAAI,SAAA,GAAY,KAAA;AAChB,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,KAAA,IAAS,IAAI,KAAA,EAAO,CAAA,GAAI,IAAA,CAAK,MAAA,EAAQ,KAAK,CAAA,EAAG;AAC3C,IAAA,MAAM,EAAA,GAAK,KAAK,CAAC,CAAA;AACjB,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,SAAA,GAAY,KAAA;AACZ,MAAA;AAAA,IACF;AACA,IAAA,IAAI,EAAA,KAAO,QAAQ,QAAA,EAAU;AAC3B,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,GAAA,EAAK;AACd,MAAA,QAAA,GAAW,CAAC,QAAA;AACZ,MAAA;AAAA,IACF;AACA,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,IAAI,EAAA,KAAO,KAAK,KAAA,IAAS,CAAA;AAAA,SAAA,IAChB,OAAO,GAAA,EAAK;AACnB,MAAA,KAAA,IAAS,CAAA;AACT,MAAA,IAAI,KAAA,KAAU,GAAG,GAAA,GAAM,CAAA;AAAA,IACzB;AAAA,EACF;AACA,EAAA,IAAI,GAAA,GAAM,GAAG,OAAO,MAAA;AACpB,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,KAAA,EAAO,MAAM,CAAC,CAAA;AAC3C,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA,EAC/B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AAGA,EAAA,MAAM,eAAgB,MAAA,CAAkD,OAAA;AACxE,EAAA,MAAM,cAAc,OAAO,YAAA,KAAiB,aAAa,YAAA,CAAa,IAAA,CAAK,MAAM,CAAA,GAAI,MAAA;AACrF,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,SAAA,CAAU,MAAM,CAAA;AAC3C,EAAA,OAAO,MAAA,CAAO,OAAA,GAAU,MAAA,CAAO,IAAA,GAAO,MAAA;AACxC","file":"chunk-HCRCNI7A.js","sourcesContent":["import type { z as ZodNamespace, ZodType } from \"zod\";\n\nimport {\n buildToolPrompt,\n buildTransientAgentOptions,\n disposeAndDeleteTransient,\n extractUsage,\n makeOutputTool,\n setupStructuredOutput,\n} from \"./internal/structured-output-helpers.js\";\nimport type { AgentOptions, LocalOptions, ModelSelection, SDKAgent } from \"./types/agent.js\";\nimport type { ProviderRoutingSettings } from \"./types/providers.js\";\n\n/**\n * Options accepted by {@link Agent.streamObject}. Same shape as\n * `Agent.generateObject` with the addition that the result is an\n * `AsyncIterator<StreamObjectEvent<T>>` rather than a single Promise. See ADR D39.\n *\n * @public\n */\nexport interface StreamObjectOptions<T extends ZodType> {\n schema: T;\n prompt: string;\n systemPrompt?: string;\n /** SE8 — accepts a bare-string id shorthand or a {@link ModelSelection}. */\n model: string | ModelSelection;\n apiKey?: string;\n local: LocalOptions;\n maxRetries?: number;\n /**\n * Optional provider routing forwarded to the transient agent. Required when\n * `model.id` uses a prefix (e.g. `openai/gpt-4o-mini`) but the credential is\n * for a unified gateway (e.g. OpenRouter). Without this, the SDK infers\n * provider from the prefix and may fail with `provider_unresolved` even\n * when the right env key is set under a different provider name.\n */\n providers?: ProviderRoutingSettings;\n}\n\n/**\n * Recursive partial — `T` where every nested field becomes optional.\n *\n * @public\n */\nexport type DeepPartial<T> = T extends (infer U)[]\n ? Array<DeepPartial<U>>\n : T extends object\n ? { [K in keyof T]?: DeepPartial<T[K]> }\n : T;\n\n/**\n * Event emitted by {@link Agent.streamObject}. Discriminate on `type`.\n *\n * - `partial` events fire zero or more times with monotonically increasing\n * `attempt`, carrying best-effort schema-parsed snapshots of the model's\n * accumulating output.\n * - `complete` fires exactly once at the end, carrying the fully Zod-parsed\n * object alongside usage and finishReason — semantically identical to a\n * successful `Agent.generateObject()` return.\n *\n * @public\n */\nexport type StreamObjectEvent<T> =\n | { type: \"partial\"; partial: DeepPartial<T>; attempt: number }\n | {\n type: \"complete\";\n object: T;\n raw: unknown;\n usage: { inputTokens: number; outputTokens: number };\n finishReason: \"tool_use\" | \"error\";\n };\n\n/**\n * Error thrown by {@link Agent.streamObject} when the model refuses to call\n * the synthetic `output` tool or when all retries fail to produce a\n * schema-valid object. Same code taxonomy as `GenerateObjectError`.\n *\n * @public\n */\nexport class StreamObjectError extends Error {\n override readonly name = \"StreamObjectError\";\n readonly code: \"no_tool_call\" | \"parse_failed\";\n override readonly cause?: unknown;\n constructor(code: \"no_tool_call\" | \"parse_failed\", message: string, cause?: unknown) {\n super(message);\n this.code = code;\n if (cause !== undefined) this.cause = cause;\n }\n}\n\ninterface StreamObjectDeps {\n create: (options: AgentOptions) => Promise<SDKAgent>;\n delete: (agentId: string) => Promise<void>;\n}\n\n/**\n * Implementation of `Agent.streamObject` as an async generator. Mirrors the\n * synthetic-forced-tool pattern from `generate-object.ts` (ADR D33) with the\n * addition of intermediate `partial` events emitted from incremental parsing\n * of accumulating text deltas during the agent loop.\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: streaming loop interleaves text-delta accumulation, partial-parse attempts, retries, and final dispose — splitting harms locality of the iterator contract.\nexport async function* streamObjectImpl<T extends ZodType>(\n options: StreamObjectOptions<T>,\n deps: StreamObjectDeps,\n): AsyncGenerator<StreamObjectEvent<ZodNamespace.infer<T>>, void, void> {\n const { jsonSchema, maxRetries, initialUsage } = setupStructuredOutput(\n options.schema,\n options.maxRetries,\n );\n let capturedRaw: unknown;\n let lastUsage = initialUsage;\n\n const outputTool = makeOutputTool(jsonSchema, (input) => {\n // EC-6: first capture wins (parallel tool use in Claude 3.5+).\n if (capturedRaw === undefined) {\n capturedRaw = input;\n }\n return JSON.stringify({ ok: true });\n });\n\n const agentOptions: AgentOptions = buildTransientAgentOptions({\n model: options.model,\n local: options.local,\n outputTool,\n ...(options.systemPrompt !== undefined ? { systemPrompt: options.systemPrompt } : {}),\n ...(options.apiKey !== undefined ? { apiKey: options.apiKey } : {}),\n ...(options.providers !== undefined ? { providers: options.providers } : {}),\n });\n const agent = await deps.create(agentOptions);\n const userMessage = buildToolPrompt(options.prompt);\n\n try {\n let lastParseError: unknown;\n let attemptCounter = 0;\n\n for (let attempt = 0; attempt <= maxRetries; attempt += 1) {\n capturedRaw = undefined;\n const run = await agent.send(userMessage);\n\n // Buffer text deltas during streaming; try partial-parse on each.\n let textBuffer = \"\";\n for await (const msg of run.stream()) {\n if (msg.type === \"assistant\") {\n const newText = msg.message.content\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\");\n if (newText.length > 0) {\n textBuffer += newText;\n const partial = bestEffortPartialParse(textBuffer, options.schema);\n if (partial !== undefined) {\n attemptCounter += 1;\n yield {\n type: \"partial\",\n partial: partial as DeepPartial<ZodNamespace.infer<T>>,\n attempt: attemptCounter,\n };\n }\n }\n }\n }\n const result = await run.wait();\n lastUsage = extractUsage(result);\n\n if (capturedRaw === undefined) {\n // EC: when the underlying run errored (e.g. provider_unresolved),\n // surface the original cause instead of the misleading \"model\n // returned text\" message — there was no model call at all.\n if (result.status === \"error\" && result.error !== undefined) {\n throw new StreamObjectError(\n \"no_tool_call\",\n `Agent run failed before the model could reply: ${result.error.message ?? \"unknown error\"} [${result.error.code ?? \"?\"}]`,\n result.error,\n );\n }\n if (attempt === maxRetries) {\n throw new StreamObjectError(\n \"no_tool_call\",\n \"The model returned text instead of calling the `output` tool.\",\n );\n }\n continue;\n }\n\n const parsed = options.schema.safeParse(capturedRaw);\n if (parsed.success) {\n yield {\n type: \"complete\",\n object: parsed.data,\n raw: capturedRaw,\n usage: lastUsage,\n finishReason: \"tool_use\",\n };\n return;\n }\n lastParseError = parsed.error;\n }\n\n throw new StreamObjectError(\n \"parse_failed\",\n \"Schema parse failed after all retries.\",\n lastParseError,\n );\n } finally {\n // EC-4: even if consumer calls iter.return() mid-stream, this finally\n // runs — transient agent is disposed AND removed from registry.\n await disposeAndDeleteTransient(agent, deps.delete);\n }\n}\n\n/**\n * Try to extract a partial JSON object from a possibly-incomplete text\n * buffer and parse it via the schema in lenient mode. Returns `undefined`\n * if nothing parseable is found yet.\n *\n * Strategy: find the first `{`, find the LAST balanced `}` (greedy), parse\n * the substring as JSON, then `safeParse` against `schema.partial()` if the\n * schema supports it, else against the original schema.\n *\n * @internal\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: stateful JSON-balancing scanner — string/brace/escape state must be co-located for the parser to remain correct.\nfunction bestEffortPartialParse<T extends ZodType>(text: string, schema: T): unknown | undefined {\n const start = text.indexOf(\"{\");\n if (start < 0) return undefined;\n // Find the longest balanced JSON object from `start`.\n let depth = 0;\n let inString = false;\n let isEscaped = false;\n let end = -1;\n for (let i = start; i < text.length; i += 1) {\n const ch = text[i];\n if (isEscaped) {\n isEscaped = false;\n continue;\n }\n if (ch === \"\\\\\" && inString) {\n isEscaped = true;\n continue;\n }\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) continue;\n if (ch === \"{\") depth += 1;\n else if (ch === \"}\") {\n depth -= 1;\n if (depth === 0) end = i;\n }\n }\n if (end < 0) return undefined;\n const candidate = text.slice(start, end + 1);\n let parsed: unknown;\n try {\n parsed = JSON.parse(candidate);\n } catch {\n return undefined;\n }\n // Try schema.partial() if available (Zod objects support it); else fall\n // back to the original schema (loose match).\n const maybePartial = (schema as unknown as { partial?: () => ZodType }).partial;\n const looseSchema = typeof maybePartial === \"function\" ? maybePartial.call(schema) : schema;\n const result = looseSchema.safeParse(parsed);\n return result.success ? result.data : undefined;\n}\n"]}
@@ -1,7 +1,7 @@
1
- import { mapOpenAICompatibleError } from './chunk-SCFW5MJZ.js';
1
+ import { mapOpenAICompatibleError } from './chunk-FUP3ZA5T.js';
2
2
  import { globalEmbeddingCache } from './chunk-OXNYIMZZ.js';
3
- import { mapWithConcurrency } from './chunk-LGILIGV3.js';
4
- import { AuthenticationError, ConfigurationError, NetworkError } from './chunk-SG5ZWT6C.js';
3
+ import { mapWithConcurrency } from './chunk-XKGOIGTJ.js';
4
+ import { AuthenticationError, ConfigurationError, NetworkError } from './chunk-VQ33XLC6.js';
5
5
  import { createHash } from 'crypto';
6
6
 
7
7
  var MAX_BATCH = 100;
@@ -193,5 +193,5 @@ function sleep(ms) {
193
193
  }
194
194
 
195
195
  export { createOpenAiCompatibleRuntime };
196
- //# sourceMappingURL=chunk-QKE556YD.js.map
197
- //# sourceMappingURL=chunk-QKE556YD.js.map
196
+ //# sourceMappingURL=chunk-HJMFPIRM.js.map
197
+ //# sourceMappingURL=chunk-HJMFPIRM.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/memory/adapters/openai-compatible.ts"],"names":[],"mappings":"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","file":"chunk-QKE556YD.js","sourcesContent":["import { createHash } from \"node:crypto\";\n\nimport { AuthenticationError, ConfigurationError, NetworkError } from \"../../../errors.js\";\nimport { mapOpenAICompatibleError } from \"../../error-mappers/openai-compatible.js\";\nimport { mapWithConcurrency } from \"../../runtime/concurrency/map-with-concurrency.js\";\nimport type {\n CreateAdapterOptions,\n EmbeddingRuntime,\n EmbeddingRuntimeStats,\n} from \"../embedding-adapter.js\";\nimport { globalEmbeddingCache } from \"../embedding-cache.js\";\n\n/**\n * Shared factory for OpenAI-compatible embedding providers (OpenAI, Mistral,\n * DeepInfra, and anything else exposing `POST /v1/embeddings` with the\n * `{ model, input }` request shape and `{ data: [{ embedding }] }` response).\n *\n * Mirrors the inner mechanics of peer-project's batch embedding runtime.\n *\n * @internal\n */\n\nconst MAX_BATCH = 100;\nconst MAX_RETRIES = 2;\n\nexport interface OpenAiCompatibleConfig {\n id: string;\n defaultBaseUrl: string;\n apiKeyEnv: string;\n baseUrlEnv?: string;\n defaultModel: string;\n /**\n * Dimension hint by model id. The chosen model MUST be in this table —\n * unknown models throw `ConfigurationError(code: \"embedding_unknown_model\")`\n * (EC-4 fix). This prevents vec0 virtual-table dimension mismatches that\n * surface as cryptic errors downstream.\n */\n dimensionByModel: Record<string, number>;\n /**\n * Path component appended to `baseUrl` for the embeddings endpoint.\n * Default `\"/v1/embeddings\"` (OpenAI canonical). REPLACES the default —\n * does NOT concatenate. Used by DeepInfra (`\"/v1/openai/embeddings\"`),\n * etc. (EC-2 fix).\n */\n embeddingsPath?: string;\n /**\n * theokit#159 — per-provider deviations from the OpenAI wire.\n *\n * The runtime was rigidly OpenAI-shaped: one auth header, one body, one response shape. Three of\n * the ten catalog providers do not speak it, so every call they made was rejected — Azure\n * authenticates with an `api-key` header and puts the deployment in the path, Cohere's `/v2/embed`\n * takes `texts` and answers `{embeddings:{float}}`. Advertising a provider that cannot work is\n * worse than not advertising it.\n *\n * Every hook is optional and its default is exactly the previous behaviour, so the seven\n * providers that DO speak OpenAI are untouched.\n */\n dialect?: EmbeddingDialect;\n}\n\n/**\n * theokit#159 — the three points where a provider may deviate from the OpenAI embedding wire.\n *\n * Deliberately three narrow hooks rather than a general \"transform the request\" seam: these are the\n * only axes on which the supported providers actually differ, and a wider seam would invite\n * per-provider logic that belongs in the adapter.\n */\nexport interface EmbeddingDialect {\n /** Replaces `authorization: Bearer <key>`. */\n authHeaders?: (apiKey: string) => Record<string, string>;\n /** Replaces the `{ model, input }` request body. */\n body?: (model: string, inputs: ReadonlyArray<string>) => Record<string, unknown>;\n /** Replaces reading vectors from `json.data[].embedding`. Return `undefined` when unparseable. */\n vectors?: (json: unknown) => number[][] | undefined;\n}\n\nexport async function createOpenAiCompatibleRuntime(\n cfg: OpenAiCompatibleConfig,\n options: CreateAdapterOptions,\n): Promise<EmbeddingRuntime> {\n const model = options.model ?? cfg.defaultModel;\n const apiKey = options.apiKey ?? process.env[cfg.apiKeyEnv];\n if (apiKey === undefined || apiKey.length === 0) {\n throw new AuthenticationError(`${cfg.apiKeyEnv} missing`, {\n code: \"embedding_missing_api_key\",\n });\n }\n const envBaseUrl = cfg.baseUrlEnv !== undefined ? process.env[cfg.baseUrlEnv] : undefined;\n const baseUrl = options.baseUrl ?? envBaseUrl ?? cfg.defaultBaseUrl;\n const fetchImpl = options.fetch ?? fetch;\n // T4.4 — default to process-wide singleton (was per-adapter instance).\n const cache = options.cache ?? globalEmbeddingCache;\n // EC-4: refuse unknown models to prevent vec0 dimension mismatches downstream.\n const dimension = cfg.dimensionByModel[model];\n if (dimension === undefined) {\n throw new ConfigurationError(\n `${cfg.id} adapter: model \"${model}\" is not in the dimension table. Use one of: ${Object.keys(cfg.dimensionByModel).join(\", \")}. To add it, update dimensionByModel in the adapter source.`,\n { code: \"embedding_unknown_model\" },\n );\n }\n // theokit#128: `{model}` is substituted, because Azure OpenAI addresses the deployment IN THE\n // PATH (`/openai/deployments/{model}/embeddings`) rather than in the body. Without this the URL\n // carried the literal placeholder and every Azure request 404'd. A path with no placeholder —\n // every other provider — is passed through untouched.\n const embeddingsPath = (cfg.embeddingsPath ?? \"/v1/embeddings\").replace(\n \"{model}\",\n encodeURIComponent(model),\n );\n\n const stats: EmbeddingRuntimeStats = {\n cacheHits: 0,\n cacheMisses: 0,\n httpCalls: 0,\n retries: 0,\n };\n\n return {\n id: cfg.id,\n model,\n dimension,\n stats: () => ({ ...stats }),\n embed: (texts) =>\n embedTexts({\n texts,\n cache,\n stats,\n model,\n dimension,\n apiKey,\n baseUrl,\n embeddingsPath,\n fetchImpl,\n providerId: cfg.id,\n dialect: cfg.dialect ?? {},\n }),\n };\n}\n\ninterface EmbedTextsInput {\n texts: ReadonlyArray<string>;\n cache: NonNullable<CreateAdapterOptions[\"cache\"]>;\n stats: EmbeddingRuntimeStats;\n model: string;\n dimension: number;\n apiKey: string;\n baseUrl: string;\n embeddingsPath: string;\n fetchImpl: typeof fetch;\n providerId: string;\n dialect: EmbeddingDialect;\n}\n\nasync function embedTexts(input: EmbedTextsInput): Promise<number[][]> {\n const { texts, cache, stats, model, dimension } = input;\n const results = new Array<number[] | undefined>(texts.length);\n const pending: Array<{ index: number; text: string; key: string }> = [];\n for (let i = 0; i < texts.length; i++) {\n classifyEntry({\n index: i,\n text: texts[i] ?? \"\",\n model,\n dimension,\n cache,\n stats,\n results,\n pending,\n });\n }\n await embedInBoundedBatches(input, pending, results);\n return results.map((v) => v ?? new Array(dimension).fill(0));\n}\n\ninterface ClassifyEntryArgs {\n index: number;\n text: string;\n model: string;\n dimension: number;\n cache: NonNullable<CreateAdapterOptions[\"cache\"]>;\n stats: EmbeddingRuntimeStats;\n results: Array<number[] | undefined>;\n pending: Array<{ index: number; text: string; key: string }>;\n}\n\nfunction classifyEntry(args: ClassifyEntryArgs): void {\n if (args.text.trim().length === 0) {\n args.results[args.index] = new Array(args.dimension).fill(0);\n return;\n }\n const key = hashKey(args.model, args.text);\n const cached = args.cache.get(key);\n if (cached !== undefined) {\n args.stats.cacheHits += 1;\n args.results[args.index] = cached;\n return;\n }\n args.stats.cacheMisses += 1;\n args.pending.push({ index: args.index, text: args.text, key });\n}\n\n// T4.3 — max concurrent embedding API requests per embed() call.\n// 3 is enough to saturate most embedding APIs without triggering\n// rate limits (each batch is already up to MAX_BATCH=100 texts).\nconst MAX_CONCURRENT_BATCHES = 3;\n\n/**\n * T4.3 — parallel embed batches (DR4 finding #3).\n *\n * Pre-T4.3 this was a serial `for` loop — each batch of 100 texts\n * awaited before the next HTTP request started. With 500 texts the\n * serial path took 5 × RTT; parallel takes max(RTT) × ceil(5/3).\n *\n * Uses bounded-concurrency `Promise.all` capped at 3 concurrent\n * HTTP requests to avoid overwhelming the embedding API.\n */\nasync function embedInBoundedBatches(\n input: EmbedTextsInput,\n pending: ReadonlyArray<{ index: number; text: string; key: string }>,\n results: Array<number[] | undefined>,\n): Promise<void> {\n const batches: Array<ReadonlyArray<{ index: number; text: string; key: string }>> = [];\n for (let offset = 0; offset < pending.length; offset += MAX_BATCH) {\n batches.push(pending.slice(offset, offset + MAX_BATCH));\n }\n // M0-2: bounded parallel via the shared ordered pool (was an inline\n // acquire/release clone — see plan m0-foundation-expose-primitives).\n await mapWithConcurrency(batches, MAX_CONCURRENT_BATCHES, (batch) =>\n processBatch(input, batch, results),\n );\n}\n\nasync function processBatch(\n input: EmbedTextsInput,\n batch: ReadonlyArray<{ index: number; text: string; key: string }>,\n results: Array<number[] | undefined>,\n): Promise<void> {\n const vectors = await embedBatch({\n apiKey: input.apiKey,\n baseUrl: input.baseUrl,\n embeddingsPath: input.embeddingsPath,\n model: input.model,\n inputs: batch.map((b) => b.text),\n fetchImpl: input.fetchImpl,\n stats: input.stats,\n providerId: input.providerId,\n dialect: input.dialect,\n });\n for (let j = 0; j < batch.length; j++) {\n const slot = batch[j];\n const vector = vectors[j];\n if (slot === undefined || vector === undefined) continue;\n results[slot.index] = vector;\n input.cache.set(slot.key, vector);\n }\n}\n\ninterface BatchOptions {\n apiKey: string;\n baseUrl: string;\n embeddingsPath: string;\n model: string;\n inputs: ReadonlyArray<string>;\n fetchImpl: typeof fetch;\n stats: EmbeddingRuntimeStats;\n providerId: string;\n dialect: EmbeddingDialect;\n}\n\nasync function embedBatch(opts: BatchOptions): Promise<number[][]> {\n // EC-2: embeddingsPath REPLACES the suffix; never concatenates.\n const url = `${opts.baseUrl.replace(/\\/$/, \"\")}${opts.embeddingsPath}`;\n let attempt = 0;\n while (true) {\n opts.stats.httpCalls += 1;\n const response = await postEmbedRequest(opts, url);\n if (response.ok)\n return await parseEmbedResponse(response, opts.providerId, opts.embeddingsPath, opts.dialect);\n if (isRetryable(response.status) && attempt < MAX_RETRIES) {\n attempt += 1;\n opts.stats.retries += 1;\n await sleep(linearBackoffMs(attempt));\n continue;\n }\n // Read body (best-effort) so the mapper has access to provider error code.\n const text = await response.text().catch(() => \"\");\n let body: unknown = text;\n try {\n body = JSON.parse(text);\n } catch {\n // not JSON — keep as string\n }\n throw mapOpenAICompatibleError({\n providerId: opts.providerId,\n status: response.status,\n body,\n headers: response.headers,\n endpoint: opts.embeddingsPath,\n });\n }\n}\n\nasync function postEmbedRequest(opts: BatchOptions, url: string): Promise<Response> {\n return opts.fetchImpl(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n ...(opts.dialect.authHeaders?.(opts.apiKey) ?? { authorization: `Bearer ${opts.apiKey}` }),\n },\n body: JSON.stringify(\n opts.dialect.body?.(opts.model, opts.inputs) ?? { model: opts.model, input: opts.inputs },\n ),\n });\n}\n\nasync function parseEmbedResponse(\n response: Response,\n providerId: string,\n endpoint: string,\n dialect?: EmbeddingDialect,\n): Promise<number[][]> {\n const json = (await response.json()) as { data?: Array<{ embedding: number[] }> };\n // theokit#159 — a provider whose response is not OpenAI-shaped supplies its own reader.\n const viaDialect = dialect?.vectors?.(json);\n if (viaDialect !== undefined) return viaDialect;\n if (!Array.isArray(json.data)) {\n throw new NetworkError(`${providerId} ${endpoint} returned no data`, {\n code: \"embedding_invalid_response\",\n metadata: {\n provider: providerId,\n endpoint,\n code: \"invalid_request\",\n raw: json,\n },\n });\n }\n return json.data.map((d) => d.embedding);\n}\n\nfunction isRetryable(status: number): boolean {\n return status === 429 || (status >= 500 && status < 600);\n}\n\nfunction hashKey(model: string, text: string): string {\n return createHash(\"sha256\").update(`${model} ${text}`).digest(\"hex\");\n}\n\nfunction linearBackoffMs(attempt: number): number {\n return 50 * attempt;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/memory/adapters/openai-compatible.ts"],"names":[],"mappings":"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","file":"chunk-HJMFPIRM.js","sourcesContent":["import { createHash } from \"node:crypto\";\n\nimport { AuthenticationError, ConfigurationError, NetworkError } from \"../../../errors.js\";\nimport { mapOpenAICompatibleError } from \"../../error-mappers/openai-compatible.js\";\nimport { mapWithConcurrency } from \"../../runtime/concurrency/map-with-concurrency.js\";\nimport type {\n CreateAdapterOptions,\n EmbeddingRuntime,\n EmbeddingRuntimeStats,\n} from \"../embedding-adapter.js\";\nimport { globalEmbeddingCache } from \"../embedding-cache.js\";\n\n/**\n * Shared factory for OpenAI-compatible embedding providers (OpenAI, Mistral,\n * DeepInfra, and anything else exposing `POST /v1/embeddings` with the\n * `{ model, input }` request shape and `{ data: [{ embedding }] }` response).\n *\n * Mirrors the inner mechanics of peer-project's batch embedding runtime.\n *\n * @internal\n */\n\nconst MAX_BATCH = 100;\nconst MAX_RETRIES = 2;\n\nexport interface OpenAiCompatibleConfig {\n id: string;\n defaultBaseUrl: string;\n apiKeyEnv: string;\n baseUrlEnv?: string;\n defaultModel: string;\n /**\n * Dimension hint by model id. The chosen model MUST be in this table —\n * unknown models throw `ConfigurationError(code: \"embedding_unknown_model\")`\n * (EC-4 fix). This prevents vec0 virtual-table dimension mismatches that\n * surface as cryptic errors downstream.\n */\n dimensionByModel: Record<string, number>;\n /**\n * Path component appended to `baseUrl` for the embeddings endpoint.\n * Default `\"/v1/embeddings\"` (OpenAI canonical). REPLACES the default —\n * does NOT concatenate. Used by DeepInfra (`\"/v1/openai/embeddings\"`),\n * etc. (EC-2 fix).\n */\n embeddingsPath?: string;\n /**\n * theokit#159 — per-provider deviations from the OpenAI wire.\n *\n * The runtime was rigidly OpenAI-shaped: one auth header, one body, one response shape. Three of\n * the ten catalog providers do not speak it, so every call they made was rejected — Azure\n * authenticates with an `api-key` header and puts the deployment in the path, Cohere's `/v2/embed`\n * takes `texts` and answers `{embeddings:{float}}`. Advertising a provider that cannot work is\n * worse than not advertising it.\n *\n * Every hook is optional and its default is exactly the previous behaviour, so the seven\n * providers that DO speak OpenAI are untouched.\n */\n dialect?: EmbeddingDialect;\n}\n\n/**\n * theokit#159 — the three points where a provider may deviate from the OpenAI embedding wire.\n *\n * Deliberately three narrow hooks rather than a general \"transform the request\" seam: these are the\n * only axes on which the supported providers actually differ, and a wider seam would invite\n * per-provider logic that belongs in the adapter.\n */\nexport interface EmbeddingDialect {\n /** Replaces `authorization: Bearer <key>`. */\n authHeaders?: (apiKey: string) => Record<string, string>;\n /** Replaces the `{ model, input }` request body. */\n body?: (model: string, inputs: ReadonlyArray<string>) => Record<string, unknown>;\n /** Replaces reading vectors from `json.data[].embedding`. Return `undefined` when unparseable. */\n vectors?: (json: unknown) => number[][] | undefined;\n}\n\nexport async function createOpenAiCompatibleRuntime(\n cfg: OpenAiCompatibleConfig,\n options: CreateAdapterOptions,\n): Promise<EmbeddingRuntime> {\n const model = options.model ?? cfg.defaultModel;\n const apiKey = options.apiKey ?? process.env[cfg.apiKeyEnv];\n if (apiKey === undefined || apiKey.length === 0) {\n throw new AuthenticationError(`${cfg.apiKeyEnv} missing`, {\n code: \"embedding_missing_api_key\",\n });\n }\n const envBaseUrl = cfg.baseUrlEnv !== undefined ? process.env[cfg.baseUrlEnv] : undefined;\n const baseUrl = options.baseUrl ?? envBaseUrl ?? cfg.defaultBaseUrl;\n const fetchImpl = options.fetch ?? fetch;\n // T4.4 — default to process-wide singleton (was per-adapter instance).\n const cache = options.cache ?? globalEmbeddingCache;\n // EC-4: refuse unknown models to prevent vec0 dimension mismatches downstream.\n const dimension = cfg.dimensionByModel[model];\n if (dimension === undefined) {\n throw new ConfigurationError(\n `${cfg.id} adapter: model \"${model}\" is not in the dimension table. Use one of: ${Object.keys(cfg.dimensionByModel).join(\", \")}. To add it, update dimensionByModel in the adapter source.`,\n { code: \"embedding_unknown_model\" },\n );\n }\n // theokit#128: `{model}` is substituted, because Azure OpenAI addresses the deployment IN THE\n // PATH (`/openai/deployments/{model}/embeddings`) rather than in the body. Without this the URL\n // carried the literal placeholder and every Azure request 404'd. A path with no placeholder —\n // every other provider — is passed through untouched.\n const embeddingsPath = (cfg.embeddingsPath ?? \"/v1/embeddings\").replace(\n \"{model}\",\n encodeURIComponent(model),\n );\n\n const stats: EmbeddingRuntimeStats = {\n cacheHits: 0,\n cacheMisses: 0,\n httpCalls: 0,\n retries: 0,\n };\n\n return {\n id: cfg.id,\n model,\n dimension,\n stats: () => ({ ...stats }),\n embed: (texts) =>\n embedTexts({\n texts,\n cache,\n stats,\n model,\n dimension,\n apiKey,\n baseUrl,\n embeddingsPath,\n fetchImpl,\n providerId: cfg.id,\n dialect: cfg.dialect ?? {},\n }),\n };\n}\n\ninterface EmbedTextsInput {\n texts: ReadonlyArray<string>;\n cache: NonNullable<CreateAdapterOptions[\"cache\"]>;\n stats: EmbeddingRuntimeStats;\n model: string;\n dimension: number;\n apiKey: string;\n baseUrl: string;\n embeddingsPath: string;\n fetchImpl: typeof fetch;\n providerId: string;\n dialect: EmbeddingDialect;\n}\n\nasync function embedTexts(input: EmbedTextsInput): Promise<number[][]> {\n const { texts, cache, stats, model, dimension } = input;\n const results = new Array<number[] | undefined>(texts.length);\n const pending: Array<{ index: number; text: string; key: string }> = [];\n for (let i = 0; i < texts.length; i++) {\n classifyEntry({\n index: i,\n text: texts[i] ?? \"\",\n model,\n dimension,\n cache,\n stats,\n results,\n pending,\n });\n }\n await embedInBoundedBatches(input, pending, results);\n return results.map((v) => v ?? new Array(dimension).fill(0));\n}\n\ninterface ClassifyEntryArgs {\n index: number;\n text: string;\n model: string;\n dimension: number;\n cache: NonNullable<CreateAdapterOptions[\"cache\"]>;\n stats: EmbeddingRuntimeStats;\n results: Array<number[] | undefined>;\n pending: Array<{ index: number; text: string; key: string }>;\n}\n\nfunction classifyEntry(args: ClassifyEntryArgs): void {\n if (args.text.trim().length === 0) {\n args.results[args.index] = new Array(args.dimension).fill(0);\n return;\n }\n const key = hashKey(args.model, args.text);\n const cached = args.cache.get(key);\n if (cached !== undefined) {\n args.stats.cacheHits += 1;\n args.results[args.index] = cached;\n return;\n }\n args.stats.cacheMisses += 1;\n args.pending.push({ index: args.index, text: args.text, key });\n}\n\n// T4.3 — max concurrent embedding API requests per embed() call.\n// 3 is enough to saturate most embedding APIs without triggering\n// rate limits (each batch is already up to MAX_BATCH=100 texts).\nconst MAX_CONCURRENT_BATCHES = 3;\n\n/**\n * T4.3 — parallel embed batches (DR4 finding #3).\n *\n * Pre-T4.3 this was a serial `for` loop — each batch of 100 texts\n * awaited before the next HTTP request started. With 500 texts the\n * serial path took 5 × RTT; parallel takes max(RTT) × ceil(5/3).\n *\n * Uses bounded-concurrency `Promise.all` capped at 3 concurrent\n * HTTP requests to avoid overwhelming the embedding API.\n */\nasync function embedInBoundedBatches(\n input: EmbedTextsInput,\n pending: ReadonlyArray<{ index: number; text: string; key: string }>,\n results: Array<number[] | undefined>,\n): Promise<void> {\n const batches: Array<ReadonlyArray<{ index: number; text: string; key: string }>> = [];\n for (let offset = 0; offset < pending.length; offset += MAX_BATCH) {\n batches.push(pending.slice(offset, offset + MAX_BATCH));\n }\n // M0-2: bounded parallel via the shared ordered pool (was an inline\n // acquire/release clone — see plan m0-foundation-expose-primitives).\n await mapWithConcurrency(batches, MAX_CONCURRENT_BATCHES, (batch) =>\n processBatch(input, batch, results),\n );\n}\n\nasync function processBatch(\n input: EmbedTextsInput,\n batch: ReadonlyArray<{ index: number; text: string; key: string }>,\n results: Array<number[] | undefined>,\n): Promise<void> {\n const vectors = await embedBatch({\n apiKey: input.apiKey,\n baseUrl: input.baseUrl,\n embeddingsPath: input.embeddingsPath,\n model: input.model,\n inputs: batch.map((b) => b.text),\n fetchImpl: input.fetchImpl,\n stats: input.stats,\n providerId: input.providerId,\n dialect: input.dialect,\n });\n for (let j = 0; j < batch.length; j++) {\n const slot = batch[j];\n const vector = vectors[j];\n if (slot === undefined || vector === undefined) continue;\n results[slot.index] = vector;\n input.cache.set(slot.key, vector);\n }\n}\n\ninterface BatchOptions {\n apiKey: string;\n baseUrl: string;\n embeddingsPath: string;\n model: string;\n inputs: ReadonlyArray<string>;\n fetchImpl: typeof fetch;\n stats: EmbeddingRuntimeStats;\n providerId: string;\n dialect: EmbeddingDialect;\n}\n\nasync function embedBatch(opts: BatchOptions): Promise<number[][]> {\n // EC-2: embeddingsPath REPLACES the suffix; never concatenates.\n const url = `${opts.baseUrl.replace(/\\/$/, \"\")}${opts.embeddingsPath}`;\n let attempt = 0;\n while (true) {\n opts.stats.httpCalls += 1;\n const response = await postEmbedRequest(opts, url);\n if (response.ok)\n return await parseEmbedResponse(response, opts.providerId, opts.embeddingsPath, opts.dialect);\n if (isRetryable(response.status) && attempt < MAX_RETRIES) {\n attempt += 1;\n opts.stats.retries += 1;\n await sleep(linearBackoffMs(attempt));\n continue;\n }\n // Read body (best-effort) so the mapper has access to provider error code.\n const text = await response.text().catch(() => \"\");\n let body: unknown = text;\n try {\n body = JSON.parse(text);\n } catch {\n // not JSON — keep as string\n }\n throw mapOpenAICompatibleError({\n providerId: opts.providerId,\n status: response.status,\n body,\n headers: response.headers,\n endpoint: opts.embeddingsPath,\n });\n }\n}\n\nasync function postEmbedRequest(opts: BatchOptions, url: string): Promise<Response> {\n return opts.fetchImpl(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n ...(opts.dialect.authHeaders?.(opts.apiKey) ?? { authorization: `Bearer ${opts.apiKey}` }),\n },\n body: JSON.stringify(\n opts.dialect.body?.(opts.model, opts.inputs) ?? { model: opts.model, input: opts.inputs },\n ),\n });\n}\n\nasync function parseEmbedResponse(\n response: Response,\n providerId: string,\n endpoint: string,\n dialect?: EmbeddingDialect,\n): Promise<number[][]> {\n const json = (await response.json()) as { data?: Array<{ embedding: number[] }> };\n // theokit#159 — a provider whose response is not OpenAI-shaped supplies its own reader.\n const viaDialect = dialect?.vectors?.(json);\n if (viaDialect !== undefined) return viaDialect;\n if (!Array.isArray(json.data)) {\n throw new NetworkError(`${providerId} ${endpoint} returned no data`, {\n code: \"embedding_invalid_response\",\n metadata: {\n provider: providerId,\n endpoint,\n code: \"invalid_request\",\n raw: json,\n },\n });\n }\n return json.data.map((d) => d.embedding);\n}\n\nfunction isRetryable(status: number): boolean {\n return status === 429 || (status >= 500 && status < 600);\n}\n\nfunction hashKey(model: string, text: string): string {\n return createHash(\"sha256\").update(`${model} ${text}`).digest(\"hex\");\n}\n\nfunction linearBackoffMs(attempt: number): number {\n return 50 * attempt;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { ConfigurationError } from './chunk-SG5ZWT6C.js';
1
+ import { ConfigurationError } from './chunk-VQ33XLC6.js';
2
2
  import { createHash } from 'crypto';
3
3
  import { realpathSync, lstatSync, readlinkSync } from 'fs';
4
4
  import { resolve, dirname, sep } from 'path';
@@ -210,5 +210,5 @@ function safeFilenameForId(id, options) {
210
210
  }
211
211
 
212
212
  export { ForbiddenPathError, PathTraversalError, assertNoSymlinkEscape, isForbiddenPath, safeFilenameForId, safePathJoin, sanitizeIdentifier, validateArtifactPath };
213
- //# sourceMappingURL=chunk-J3UK2GMN.js.map
214
- //# sourceMappingURL=chunk-J3UK2GMN.js.map
213
+ //# sourceMappingURL=chunk-IEKSEAIV.js.map
214
+ //# sourceMappingURL=chunk-IEKSEAIV.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/security/path-guard.ts"],"names":[],"mappings":"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","file":"chunk-J3UK2GMN.js","sourcesContent":["/**\n * Canonical path-guard module (ADRs D79-D81).\n *\n * Three primitives + one typed error:\n * - `safePathJoin(base, ...parts)` — resolve THEN prefix-check (ADR D80).\n * - `assertNoSymlinkEscape(path, base)` — `realpathSync` resolves entire\n * symlink chain (EC-1 fix; Hermes v0.2 #386, #61).\n * - `sanitizeIdentifier(input, { maxLen })` — strict grammar\n * `^[a-z0-9][a-z0-9-_]*$` (ADR D81; case-insensitive on input,\n * lowercase on output).\n * - `PathTraversalError` — extends ConfigurationError with code\n * `path_traversal` (ADR D65: no new hierarchy).\n *\n * Wire at all sites where user input becomes a path. CI lint gate\n * `tests/lint/no-unguarded-path-input.test.ts` prevents regression\n * (ADR D85).\n *\n * @internal\n */\n\nimport { createHash } from \"node:crypto\";\nimport { lstatSync, readlinkSync, realpathSync, type Stats } from \"node:fs\";\nimport { dirname, resolve, sep } from \"node:path\";\n\nimport { ConfigurationError } from \"../../errors.js\";\n\n/**\n * Thrown when a path operation would escape its allowed base directory.\n * Extends `ConfigurationError` (no new error hierarchy per ADR D65).\n *\n * @internal\n */\nexport class PathTraversalError extends ConfigurationError {\n override readonly name: string = \"PathTraversalError\";\n\n constructor(input: string, resolvedPath: string) {\n super(`Path traversal attempt: ${input} → ${resolvedPath}`, {\n code: \"path_traversal\",\n });\n }\n}\n\n/**\n * Thrown when an agent tool is asked to read or write a sensitive path\n * that the blocklist forbids (`.env`, `.git/`, `node_modules/`, `.theo/`,\n * lock files). Distinct from `PathTraversalError` because the path is\n * lexically inside the project — it is just sensitive.\n *\n * Extends `ConfigurationError` (no new error hierarchy per ADR D65).\n *\n * @public\n */\nexport class ForbiddenPathError extends ConfigurationError {\n override readonly name: string = \"ForbiddenPathError\";\n\n constructor(path: string) {\n super(\n `Path '${path}' is in the sensitive-file blocklist (.env, .git/, node_modules/, .theo/, lock files)`,\n {\n code: \"forbidden_path\",\n },\n );\n }\n}\n\n/**\n * Is `target` the same as `base`, or strictly under it?\n *\n * The prefix must not double the separator. `resolve` strips a trailing `sep` from every base\n * EXCEPT the filesystem root, where `resolve(sep) === sep`; there `base + sep` would be `//`, which\n * no absolute path starts with, so a root base rejected EVERY path (#149). Only the root takes that\n * branch — for any other base the prefix is unchanged, so containment is not weakened.\n *\n * Both containment checks in this module go through here: they had the same defect and were fixed\n * one at a time, which is exactly how the two drifted apart in the first place.\n *\n * Both arguments MUST already be resolved absolute paths.\n */\nfunction isInside(target: string, base: string): boolean {\n if (target === base) return true;\n const prefix = base.endsWith(sep) ? base : base + sep;\n return target.startsWith(prefix);\n}\n\n/**\n * Join `base` with `...parts` and ensure the resolved absolute path stays\n * under `base`. Resolves FIRST, then prefix-checks (ADR D80) — prevents\n * normalized-escape bypasses like `subdir/.\\\\./bar`.\n *\n * Returns the safe absolute path. Throws `PathTraversalError` if escape.\n *\n * @internal\n */\nexport function safePathJoin(base: string, ...parts: string[]): string {\n if (base === \"\") {\n throw new Error(\"safePathJoin: base must be non-empty\");\n }\n // T5.5 — NUL byte + C0/DEL control char rejection at the boundary.\n // Apply before path resolution so a malicious input never reaches\n // `resolve` (which on some platforms behaved unexpectedly with NUL\n // and in N-API callers historically silently truncated).\n rejectNulAndControlChars(base, \"base\");\n for (const part of parts) {\n rejectNulAndControlChars(part, \"path segment\");\n }\n const baseResolved = resolve(base);\n const target = resolve(base, ...parts);\n if (!isInside(target, baseResolved)) {\n throw new PathTraversalError(parts.join(\"/\"), target);\n }\n return target;\n}\n\n/**\n * T5.5 — Reject NUL (`\\x00`) and C0/DEL control characters\n * (`\\x01-\\x1F`, `\\x7F`) in any path-shaped or identifier-shaped input.\n * Centralizes the check so every public path-guard / sanitize entrypoint\n * shares the same defense.\n *\n * Throws `PathTraversalError` (the same shape as other path-shape\n * rejections) so callers don't need to learn a new error class.\n *\n * @internal\n */\nfunction rejectNulAndControlChars(input: string, role: string): void {\n for (let i = 0; i < input.length; i++) {\n const code = input.charCodeAt(i);\n if (code === 0x00 || (code >= 0x01 && code <= 0x1f) || code === 0x7f) {\n const label = code === 0x00 ? \"<nul-byte>\" : `<control-char-0x${code.toString(16)}>`;\n throw new PathTraversalError(`${role}: ${input}`, label);\n }\n }\n}\n\n/**\n * Assert that `path` — including every directory component in the chain —\n * stays under `base` after symlink resolution. No-op when nothing on the\n * path exists yet.\n *\n * Two-bug history:\n * 1. **EC-1** (original fix, kept): a multi-level symlink chain A → B → C\n * must be resolved end-to-end. `realpathSync` does this in 1 syscall.\n * 2. **Defence-in-depth** (added v1.x): the previous implementation only\n * called `lstatSync(path)` on the terminal component. If an INTERMEDIATE\n * directory was a symlink (`base/inner-symlink → /outside`), `lstat` on\n * `base/inner-symlink/file.txt` followed the symlink and reported the\n * regular file — escape went undetected. Fix: walk up to the nearest\n * existing ancestor and `realpath` THAT, then re-attach the suffix and\n * check the result against the canonical base.\n *\n * @internal\n */\nexport function assertNoSymlinkEscape(path: string, base: string): void {\n // T5.5 — reject NUL / control chars before any FS call (a NUL byte\n // in the path used to silently truncate at the C boundary on legacy\n // libc — defense in depth even on modern Node).\n rejectNulAndControlChars(path, \"path\");\n rejectNulAndControlChars(base, \"base\");\n // Canonical base — symlinks in the base path itself are absorbed once here.\n let baseResolved: string;\n try {\n baseResolved = realpathSync(base);\n } catch {\n // base doesn't exist as a real directory yet — fall back to lexical resolve.\n baseResolved = resolve(base);\n }\n\n // Find the deepest ancestor of `path` that exists, then realpath it.\n // Anything from there onward is \"not yet on disk\" and contributes only\n // its lexical suffix. This covers three cases:\n // - path exists (regular file or symlink at any depth) → realpath the full path\n // - path doesn't exist but intermediate dir is a symlink → realpath the ancestor\n // - nothing on the path exists → no escape risk (return)\n const resolved = realpathOfDeepestExisting(path);\n if (resolved === undefined) return; // path has no existing prefix — nothing to attack\n\n if (!isInside(resolved, baseResolved)) {\n throw new PathTraversalError(`symlink ${path}`, resolved);\n }\n}\n\n/**\n * Find the deepest ancestor of `path` that exists on disk, resolve all\n * symlinks in that ancestor via `realpathSync`, and re-attach the\n * lexical suffix. Returns `undefined` when no ancestor exists.\n *\n * Handles dangling symlinks: if the terminal IS a symlink but its target\n * is missing, we still detect escape via `readlinkSync` + parent resolve.\n */\nfunction realpathOfDeepestExisting(path: string): string | undefined {\n // First try the full path — the common case.\n try {\n return realpathSync(path);\n } catch {\n // Not resolvable. Two sub-cases.\n }\n\n // Sub-case A: terminal is a dangling symlink.\n try {\n const stat: Stats = lstatSync(path);\n if (stat.isSymbolicLink()) {\n const target = readlinkSync(path);\n // Resolve target relative to the REAL parent dir, so intermediate\n // symlinks in the parent chain are absorbed.\n const parentReal = realpathOfDeepestExisting(dirname(path));\n const parentBase = parentReal ?? dirname(path);\n return resolve(parentBase, target);\n }\n } catch {\n // lstat failed too — terminal doesn't exist at all.\n }\n\n // Sub-case B: walk up to the nearest existing ancestor, then re-attach\n // the suffix lexically.\n let cursor = dirname(path);\n let suffix = path.slice(cursor.length);\n while (cursor !== dirname(cursor)) {\n try {\n const real = realpathSync(cursor);\n // Reconstruct: ancestor's realpath + remaining (still-lexical) suffix\n return resolve(real, `.${suffix}`);\n } catch {\n suffix = path.slice(dirname(cursor).length);\n cursor = dirname(cursor);\n }\n }\n // Reached filesystem root without finding any existing ancestor.\n return undefined;\n}\n\nconst LOCK_FILES = new Set([\"pnpm-lock.yaml\", \"package-lock.json\", \"yarn.lock\", \"bun.lockb\"]);\n\n// T5.6 — top-level credential dot-dirs / dot-files. Matching against\n// the FIRST path segment (lowercase). Adding any entry here costs a\n// CHANGELOG note + an explicit case-fold test (entries are lowercased\n// at module load).\nconst SENSITIVE_FIRST_SEGMENTS = new Set([\n \".ssh\",\n \".aws\",\n \".docker\",\n \".kube\",\n \".npmrc\",\n \".netrc\",\n \".pgpass\",\n]);\n\n// T5.6 — credential basenames blocked at ANY depth (lowercase). Catches\n// the developer-laptop case where an agent recurses into a subdir.\nconst SENSITIVE_BASENAMES = new Set([\n \"id_rsa\",\n \"id_ed25519\",\n \"id_ecdsa\",\n \"id_dsa\",\n \"authorized_keys\",\n \"known_hosts\",\n \".npmrc\",\n \".netrc\",\n \".pgpass\",\n]);\n\n// T5.6 — extension suffixes blocked at ANY depth (lowercase). Covers\n// the entire `*.pem` / `*.key` private-material family.\nconst SENSITIVE_SUFFIXES = [\".pem\", \".key\", \".p12\", \".pfx\"];\n\n/**\n * Decide whether a project-relative path points to a known-sensitive file\n * that a coding agent must not read or write.\n *\n * Universal blocklist (works for any agent operating on a project tree):\n *\n * - `.env`, `.env.<anything>` — except `.env.example` (template safe to read)\n * - `.git/` — version control internals\n * - `node_modules/` — dependency cache (changes don't belong to the user)\n * - `.theo/` — TheoKit build artefacts / state\n * - Lock files at any depth: `pnpm-lock.yaml`, `package-lock.json`,\n * `yarn.lock`, `bun.lockb`\n *\n * Operates on path segments (forward-slash normalized). Cross-platform safe.\n *\n * Use together with `safePathJoin` + `assertNoSymlinkEscape`: the former two\n * defeat traversal, this one defeats reading a file that is lexically inside\n * the project but should not be agent-visible.\n *\n * @public\n */\nexport function isForbiddenPath(input: string): boolean {\n // T5.6 — lowercase normalization defeats case-only bypass on\n // case-insensitive filesystems (Windows/macOS-default) where `.ENV`\n // and `.env` map to the same inode but a case-sensitive string\n // check passes the former.\n const normalized = input.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").toLowerCase();\n if (normalized.length === 0) return false;\n\n const segments = normalized.split(\"/\").filter((s) => s.length > 0);\n if (segments.length === 0) return false;\n\n if (isForbiddenFirstSegment(segments[0]!)) return true;\n if (isForbiddenBasename(segments[segments.length - 1]!)) return true;\n return false;\n}\n\nfunction isForbiddenFirstSegment(first: string): boolean {\n // .env.example is explicitly allowlisted (template safe to read)\n if (first === \".env.example\") return false;\n if (first === \".env\") return true;\n if (/^\\.env\\./.test(first)) return true;\n if (first === \".git\" || first === \"node_modules\" || first === \".theo\") return true;\n return SENSITIVE_FIRST_SEGMENTS.has(first);\n}\n\nfunction isForbiddenBasename(basename: string): boolean {\n if (LOCK_FILES.has(basename)) return true;\n if (SENSITIVE_BASENAMES.has(basename)) return true;\n for (const suffix of SENSITIVE_SUFFIXES) {\n if (basename.endsWith(suffix)) return true;\n }\n return false;\n}\n\nconst IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9\\-_]*$/i;\n\n/**\n * Validate that `input` is a safe path component (skill name, agent ID,\n * namespace, etc.) and return its lowercase form. Strict grammar\n * `^[a-z0-9][a-z0-9-_]*$` rejects path separators, dots, null bytes,\n * whitespace, unicode invisible chars, and any leading `-`/`_`.\n *\n * @param input - User-supplied identifier candidate.\n * @param options.maxLen - Maximum allowed length (default 64).\n * @returns Lowercase form of `input`.\n * @throws `ConfigurationError` with code `invalid_identifier` on rejection.\n *\n * @internal\n */\n/**\n * T1.4 — validate a relative artifact path string BEFORE it is used to look\n * up a fixture or to fetch from PaaS. Rejects every well-known traversal\n * vector at the boundary, throwing `PathTraversalError`.\n *\n * Vectors rejected:\n * - classic `..` parent-directory traversal (any segment).\n * - backslash separators (Windows-style `..\\\\windows`).\n * - URL-encoded `%2e%2e` / `%2E%2E` (double-decoded traversal).\n * - NUL byte injection (`\\x00`).\n * - Windows drive letter prefix (`C:`, `D:\\\\...`).\n * - Home-tilde expansion (`~/`, `~root/...`).\n * - Absolute paths starting with `/`.\n *\n * Does NOT touch the filesystem — the call is shape-only. Live symlink\n * traversal protection happens via `assertNoSymlinkEscape` at the FS-resolve\n * boundary.\n *\n * @param input - Caller-supplied artifact path.\n * @throws `PathTraversalError` on any rejection.\n *\n * @internal\n */\nexport function validateArtifactPath(input: string): void {\n rejectKnownPrefixVectors(input);\n const normalized = decodeAndNormalize(input);\n rejectParentTraversal(input, normalized);\n}\n\nfunction rejectKnownPrefixVectors(input: string): void {\n if (input.includes(\"\\x00\")) {\n throw new PathTraversalError(input, \"<nul-byte>\");\n }\n if (input.startsWith(\"/\") || input.startsWith(\"~\")) {\n throw new PathTraversalError(input, input);\n }\n if (/^[A-Za-z]:[\\\\/]?/.test(input)) {\n throw new PathTraversalError(input, input);\n }\n}\n\nfunction decodeAndNormalize(input: string): string {\n // URL-encoded traversal — 2 passes catches `%252e%252e`.\n // Malformed sequences (decodeURIComponent throws) are themselves a rejection.\n let decoded = input;\n for (let i = 0; i < 2; i += 1) {\n try {\n const next = decodeURIComponent(decoded);\n if (next === decoded) break;\n decoded = next;\n } catch {\n throw new PathTraversalError(input, \"<malformed-url-encoding>\");\n }\n }\n // Normalize backslash to forward slash before segment-walking.\n return decoded.replace(/\\\\/g, \"/\");\n}\n\nfunction rejectParentTraversal(input: string, normalized: string): void {\n for (const segment of normalized.split(\"/\")) {\n if (segment === \"..\" || segment === \"..%00\") {\n throw new PathTraversalError(input, normalized);\n }\n }\n // Defense in depth: literal `..` anywhere in the normalized string.\n if (normalized.includes(\"..\")) {\n throw new PathTraversalError(input, normalized);\n }\n}\n\nexport function sanitizeIdentifier(input: string, options?: { maxLen?: number }): string {\n const maxLen = options?.maxLen ?? 64;\n if (input.length === 0 || input.length > maxLen) {\n throw new ConfigurationError(`Identifier length out of range (1-${maxLen}): \"${input}\"`, {\n code: \"invalid_identifier\",\n });\n }\n // T5.5 — explicit NUL / control char rejection ahead of the generic\n // pattern check. The IDENTIFIER_PATTERN regex already excludes these\n // (they are not in `[a-z0-9\\-_]`), but routing them through the same\n // helper used by safePathJoin gives operators a precise diagnostic\n // (\"nul-byte\" / \"control-char-0x..\") instead of the generic\n // \"invalid characters\" message — making prompt-injection traces\n // legible per Unbreakable Rule 3.\n rejectNulAndControlChars(input, \"identifier\");\n if (!IDENTIFIER_PATTERN.test(input)) {\n throw new ConfigurationError(`Identifier contains invalid characters: \"${input}\"`, {\n code: \"invalid_identifier\",\n });\n }\n return input.toLowerCase();\n}\n\n/**\n * Convert ANY opaque id (agent id, run id, conversation id, namespace, email,\n * arbitrary string) into a deterministic, filesystem-safe filename component.\n *\n * Unlike {@link sanitizeIdentifier} (which THROWS on non-conforming input),\n * this is a total function: it NEVER throws on a non-empty string. It returns\n * the lowercased id verbatim when it already matches the safe grammar\n * `^[a-z0-9][a-z0-9-_]*$` and fits `maxLen` (so UUIDs, hashes, and slugs stay\n * human-readable), otherwise a deterministic `h-<16 hex>` sha256 token\n * (collision-resistant and always a valid filename). The output charset is\n * always `[a-z0-9_-]`, safe as a literal path segment on every filesystem.\n *\n * @param id - any opaque identifier (must be a non-empty string)\n * @param options.maxLen - max length for the passthrough branch (default 128).\n * Ids longer than this are hashed; the hash token itself is always short.\n * @throws ConfigurationError (code `invalid_filename_id`) only on empty input.\n *\n * @example\n * safeFilenameForId(\"550e8400-e29b-41d4-a716-446655440000\") // passthrough\n * safeFilenameForId(\"user@example.com\") // \"h-<16hex>\"\n *\n * @internal — public via `@theokit/sdk/path-safety`\n */\nexport function safeFilenameForId(id: string, options?: { maxLen?: number }): string {\n if (id.length === 0) {\n throw new ConfigurationError(\"Filename id must be a non-empty string\", {\n code: \"invalid_filename_id\",\n });\n }\n const maxLen = options?.maxLen ?? 128;\n const lower = id.toLowerCase();\n if (lower.length <= maxLen && IDENTIFIER_PATTERN.test(lower)) {\n return lower;\n }\n return `h-${createHash(\"sha256\").update(id).digest(\"hex\").slice(0, 16)}`;\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/security/path-guard.ts"],"names":[],"mappings":"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","file":"chunk-IEKSEAIV.js","sourcesContent":["/**\n * Canonical path-guard module (ADRs D79-D81).\n *\n * Three primitives + one typed error:\n * - `safePathJoin(base, ...parts)` — resolve THEN prefix-check (ADR D80).\n * - `assertNoSymlinkEscape(path, base)` — `realpathSync` resolves entire\n * symlink chain (EC-1 fix; Hermes v0.2 #386, #61).\n * - `sanitizeIdentifier(input, { maxLen })` — strict grammar\n * `^[a-z0-9][a-z0-9-_]*$` (ADR D81; case-insensitive on input,\n * lowercase on output).\n * - `PathTraversalError` — extends ConfigurationError with code\n * `path_traversal` (ADR D65: no new hierarchy).\n *\n * Wire at all sites where user input becomes a path. CI lint gate\n * `tests/lint/no-unguarded-path-input.test.ts` prevents regression\n * (ADR D85).\n *\n * @internal\n */\n\nimport { createHash } from \"node:crypto\";\nimport { lstatSync, readlinkSync, realpathSync, type Stats } from \"node:fs\";\nimport { dirname, resolve, sep } from \"node:path\";\n\nimport { ConfigurationError } from \"../../errors.js\";\n\n/**\n * Thrown when a path operation would escape its allowed base directory.\n * Extends `ConfigurationError` (no new error hierarchy per ADR D65).\n *\n * @internal\n */\nexport class PathTraversalError extends ConfigurationError {\n override readonly name: string = \"PathTraversalError\";\n\n constructor(input: string, resolvedPath: string) {\n super(`Path traversal attempt: ${input} → ${resolvedPath}`, {\n code: \"path_traversal\",\n });\n }\n}\n\n/**\n * Thrown when an agent tool is asked to read or write a sensitive path\n * that the blocklist forbids (`.env`, `.git/`, `node_modules/`, `.theo/`,\n * lock files). Distinct from `PathTraversalError` because the path is\n * lexically inside the project — it is just sensitive.\n *\n * Extends `ConfigurationError` (no new error hierarchy per ADR D65).\n *\n * @public\n */\nexport class ForbiddenPathError extends ConfigurationError {\n override readonly name: string = \"ForbiddenPathError\";\n\n constructor(path: string) {\n super(\n `Path '${path}' is in the sensitive-file blocklist (.env, .git/, node_modules/, .theo/, lock files)`,\n {\n code: \"forbidden_path\",\n },\n );\n }\n}\n\n/**\n * Is `target` the same as `base`, or strictly under it?\n *\n * The prefix must not double the separator. `resolve` strips a trailing `sep` from every base\n * EXCEPT the filesystem root, where `resolve(sep) === sep`; there `base + sep` would be `//`, which\n * no absolute path starts with, so a root base rejected EVERY path (#149). Only the root takes that\n * branch — for any other base the prefix is unchanged, so containment is not weakened.\n *\n * Both containment checks in this module go through here: they had the same defect and were fixed\n * one at a time, which is exactly how the two drifted apart in the first place.\n *\n * Both arguments MUST already be resolved absolute paths.\n */\nfunction isInside(target: string, base: string): boolean {\n if (target === base) return true;\n const prefix = base.endsWith(sep) ? base : base + sep;\n return target.startsWith(prefix);\n}\n\n/**\n * Join `base` with `...parts` and ensure the resolved absolute path stays\n * under `base`. Resolves FIRST, then prefix-checks (ADR D80) — prevents\n * normalized-escape bypasses like `subdir/.\\\\./bar`.\n *\n * Returns the safe absolute path. Throws `PathTraversalError` if escape.\n *\n * @internal\n */\nexport function safePathJoin(base: string, ...parts: string[]): string {\n if (base === \"\") {\n throw new Error(\"safePathJoin: base must be non-empty\");\n }\n // T5.5 — NUL byte + C0/DEL control char rejection at the boundary.\n // Apply before path resolution so a malicious input never reaches\n // `resolve` (which on some platforms behaved unexpectedly with NUL\n // and in N-API callers historically silently truncated).\n rejectNulAndControlChars(base, \"base\");\n for (const part of parts) {\n rejectNulAndControlChars(part, \"path segment\");\n }\n const baseResolved = resolve(base);\n const target = resolve(base, ...parts);\n if (!isInside(target, baseResolved)) {\n throw new PathTraversalError(parts.join(\"/\"), target);\n }\n return target;\n}\n\n/**\n * T5.5 — Reject NUL (`\\x00`) and C0/DEL control characters\n * (`\\x01-\\x1F`, `\\x7F`) in any path-shaped or identifier-shaped input.\n * Centralizes the check so every public path-guard / sanitize entrypoint\n * shares the same defense.\n *\n * Throws `PathTraversalError` (the same shape as other path-shape\n * rejections) so callers don't need to learn a new error class.\n *\n * @internal\n */\nfunction rejectNulAndControlChars(input: string, role: string): void {\n for (let i = 0; i < input.length; i++) {\n const code = input.charCodeAt(i);\n if (code === 0x00 || (code >= 0x01 && code <= 0x1f) || code === 0x7f) {\n const label = code === 0x00 ? \"<nul-byte>\" : `<control-char-0x${code.toString(16)}>`;\n throw new PathTraversalError(`${role}: ${input}`, label);\n }\n }\n}\n\n/**\n * Assert that `path` — including every directory component in the chain —\n * stays under `base` after symlink resolution. No-op when nothing on the\n * path exists yet.\n *\n * Two-bug history:\n * 1. **EC-1** (original fix, kept): a multi-level symlink chain A → B → C\n * must be resolved end-to-end. `realpathSync` does this in 1 syscall.\n * 2. **Defence-in-depth** (added v1.x): the previous implementation only\n * called `lstatSync(path)` on the terminal component. If an INTERMEDIATE\n * directory was a symlink (`base/inner-symlink → /outside`), `lstat` on\n * `base/inner-symlink/file.txt` followed the symlink and reported the\n * regular file — escape went undetected. Fix: walk up to the nearest\n * existing ancestor and `realpath` THAT, then re-attach the suffix and\n * check the result against the canonical base.\n *\n * @internal\n */\nexport function assertNoSymlinkEscape(path: string, base: string): void {\n // T5.5 — reject NUL / control chars before any FS call (a NUL byte\n // in the path used to silently truncate at the C boundary on legacy\n // libc — defense in depth even on modern Node).\n rejectNulAndControlChars(path, \"path\");\n rejectNulAndControlChars(base, \"base\");\n // Canonical base — symlinks in the base path itself are absorbed once here.\n let baseResolved: string;\n try {\n baseResolved = realpathSync(base);\n } catch {\n // base doesn't exist as a real directory yet — fall back to lexical resolve.\n baseResolved = resolve(base);\n }\n\n // Find the deepest ancestor of `path` that exists, then realpath it.\n // Anything from there onward is \"not yet on disk\" and contributes only\n // its lexical suffix. This covers three cases:\n // - path exists (regular file or symlink at any depth) → realpath the full path\n // - path doesn't exist but intermediate dir is a symlink → realpath the ancestor\n // - nothing on the path exists → no escape risk (return)\n const resolved = realpathOfDeepestExisting(path);\n if (resolved === undefined) return; // path has no existing prefix — nothing to attack\n\n if (!isInside(resolved, baseResolved)) {\n throw new PathTraversalError(`symlink ${path}`, resolved);\n }\n}\n\n/**\n * Find the deepest ancestor of `path` that exists on disk, resolve all\n * symlinks in that ancestor via `realpathSync`, and re-attach the\n * lexical suffix. Returns `undefined` when no ancestor exists.\n *\n * Handles dangling symlinks: if the terminal IS a symlink but its target\n * is missing, we still detect escape via `readlinkSync` + parent resolve.\n */\nfunction realpathOfDeepestExisting(path: string): string | undefined {\n // First try the full path — the common case.\n try {\n return realpathSync(path);\n } catch {\n // Not resolvable. Two sub-cases.\n }\n\n // Sub-case A: terminal is a dangling symlink.\n try {\n const stat: Stats = lstatSync(path);\n if (stat.isSymbolicLink()) {\n const target = readlinkSync(path);\n // Resolve target relative to the REAL parent dir, so intermediate\n // symlinks in the parent chain are absorbed.\n const parentReal = realpathOfDeepestExisting(dirname(path));\n const parentBase = parentReal ?? dirname(path);\n return resolve(parentBase, target);\n }\n } catch {\n // lstat failed too — terminal doesn't exist at all.\n }\n\n // Sub-case B: walk up to the nearest existing ancestor, then re-attach\n // the suffix lexically.\n let cursor = dirname(path);\n let suffix = path.slice(cursor.length);\n while (cursor !== dirname(cursor)) {\n try {\n const real = realpathSync(cursor);\n // Reconstruct: ancestor's realpath + remaining (still-lexical) suffix\n return resolve(real, `.${suffix}`);\n } catch {\n suffix = path.slice(dirname(cursor).length);\n cursor = dirname(cursor);\n }\n }\n // Reached filesystem root without finding any existing ancestor.\n return undefined;\n}\n\nconst LOCK_FILES = new Set([\"pnpm-lock.yaml\", \"package-lock.json\", \"yarn.lock\", \"bun.lockb\"]);\n\n// T5.6 — top-level credential dot-dirs / dot-files. Matching against\n// the FIRST path segment (lowercase). Adding any entry here costs a\n// CHANGELOG note + an explicit case-fold test (entries are lowercased\n// at module load).\nconst SENSITIVE_FIRST_SEGMENTS = new Set([\n \".ssh\",\n \".aws\",\n \".docker\",\n \".kube\",\n \".npmrc\",\n \".netrc\",\n \".pgpass\",\n]);\n\n// T5.6 — credential basenames blocked at ANY depth (lowercase). Catches\n// the developer-laptop case where an agent recurses into a subdir.\nconst SENSITIVE_BASENAMES = new Set([\n \"id_rsa\",\n \"id_ed25519\",\n \"id_ecdsa\",\n \"id_dsa\",\n \"authorized_keys\",\n \"known_hosts\",\n \".npmrc\",\n \".netrc\",\n \".pgpass\",\n]);\n\n// T5.6 — extension suffixes blocked at ANY depth (lowercase). Covers\n// the entire `*.pem` / `*.key` private-material family.\nconst SENSITIVE_SUFFIXES = [\".pem\", \".key\", \".p12\", \".pfx\"];\n\n/**\n * Decide whether a project-relative path points to a known-sensitive file\n * that a coding agent must not read or write.\n *\n * Universal blocklist (works for any agent operating on a project tree):\n *\n * - `.env`, `.env.<anything>` — except `.env.example` (template safe to read)\n * - `.git/` — version control internals\n * - `node_modules/` — dependency cache (changes don't belong to the user)\n * - `.theo/` — TheoKit build artefacts / state\n * - Lock files at any depth: `pnpm-lock.yaml`, `package-lock.json`,\n * `yarn.lock`, `bun.lockb`\n *\n * Operates on path segments (forward-slash normalized). Cross-platform safe.\n *\n * Use together with `safePathJoin` + `assertNoSymlinkEscape`: the former two\n * defeat traversal, this one defeats reading a file that is lexically inside\n * the project but should not be agent-visible.\n *\n * @public\n */\nexport function isForbiddenPath(input: string): boolean {\n // T5.6 — lowercase normalization defeats case-only bypass on\n // case-insensitive filesystems (Windows/macOS-default) where `.ENV`\n // and `.env` map to the same inode but a case-sensitive string\n // check passes the former.\n const normalized = input.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").toLowerCase();\n if (normalized.length === 0) return false;\n\n const segments = normalized.split(\"/\").filter((s) => s.length > 0);\n if (segments.length === 0) return false;\n\n if (isForbiddenFirstSegment(segments[0]!)) return true;\n if (isForbiddenBasename(segments[segments.length - 1]!)) return true;\n return false;\n}\n\nfunction isForbiddenFirstSegment(first: string): boolean {\n // .env.example is explicitly allowlisted (template safe to read)\n if (first === \".env.example\") return false;\n if (first === \".env\") return true;\n if (/^\\.env\\./.test(first)) return true;\n if (first === \".git\" || first === \"node_modules\" || first === \".theo\") return true;\n return SENSITIVE_FIRST_SEGMENTS.has(first);\n}\n\nfunction isForbiddenBasename(basename: string): boolean {\n if (LOCK_FILES.has(basename)) return true;\n if (SENSITIVE_BASENAMES.has(basename)) return true;\n for (const suffix of SENSITIVE_SUFFIXES) {\n if (basename.endsWith(suffix)) return true;\n }\n return false;\n}\n\nconst IDENTIFIER_PATTERN = /^[a-z0-9][a-z0-9\\-_]*$/i;\n\n/**\n * Validate that `input` is a safe path component (skill name, agent ID,\n * namespace, etc.) and return its lowercase form. Strict grammar\n * `^[a-z0-9][a-z0-9-_]*$` rejects path separators, dots, null bytes,\n * whitespace, unicode invisible chars, and any leading `-`/`_`.\n *\n * @param input - User-supplied identifier candidate.\n * @param options.maxLen - Maximum allowed length (default 64).\n * @returns Lowercase form of `input`.\n * @throws `ConfigurationError` with code `invalid_identifier` on rejection.\n *\n * @internal\n */\n/**\n * T1.4 — validate a relative artifact path string BEFORE it is used to look\n * up a fixture or to fetch from PaaS. Rejects every well-known traversal\n * vector at the boundary, throwing `PathTraversalError`.\n *\n * Vectors rejected:\n * - classic `..` parent-directory traversal (any segment).\n * - backslash separators (Windows-style `..\\\\windows`).\n * - URL-encoded `%2e%2e` / `%2E%2E` (double-decoded traversal).\n * - NUL byte injection (`\\x00`).\n * - Windows drive letter prefix (`C:`, `D:\\\\...`).\n * - Home-tilde expansion (`~/`, `~root/...`).\n * - Absolute paths starting with `/`.\n *\n * Does NOT touch the filesystem — the call is shape-only. Live symlink\n * traversal protection happens via `assertNoSymlinkEscape` at the FS-resolve\n * boundary.\n *\n * @param input - Caller-supplied artifact path.\n * @throws `PathTraversalError` on any rejection.\n *\n * @internal\n */\nexport function validateArtifactPath(input: string): void {\n rejectKnownPrefixVectors(input);\n const normalized = decodeAndNormalize(input);\n rejectParentTraversal(input, normalized);\n}\n\nfunction rejectKnownPrefixVectors(input: string): void {\n if (input.includes(\"\\x00\")) {\n throw new PathTraversalError(input, \"<nul-byte>\");\n }\n if (input.startsWith(\"/\") || input.startsWith(\"~\")) {\n throw new PathTraversalError(input, input);\n }\n if (/^[A-Za-z]:[\\\\/]?/.test(input)) {\n throw new PathTraversalError(input, input);\n }\n}\n\nfunction decodeAndNormalize(input: string): string {\n // URL-encoded traversal — 2 passes catches `%252e%252e`.\n // Malformed sequences (decodeURIComponent throws) are themselves a rejection.\n let decoded = input;\n for (let i = 0; i < 2; i += 1) {\n try {\n const next = decodeURIComponent(decoded);\n if (next === decoded) break;\n decoded = next;\n } catch {\n throw new PathTraversalError(input, \"<malformed-url-encoding>\");\n }\n }\n // Normalize backslash to forward slash before segment-walking.\n return decoded.replace(/\\\\/g, \"/\");\n}\n\nfunction rejectParentTraversal(input: string, normalized: string): void {\n for (const segment of normalized.split(\"/\")) {\n if (segment === \"..\" || segment === \"..%00\") {\n throw new PathTraversalError(input, normalized);\n }\n }\n // Defense in depth: literal `..` anywhere in the normalized string.\n if (normalized.includes(\"..\")) {\n throw new PathTraversalError(input, normalized);\n }\n}\n\nexport function sanitizeIdentifier(input: string, options?: { maxLen?: number }): string {\n const maxLen = options?.maxLen ?? 64;\n if (input.length === 0 || input.length > maxLen) {\n throw new ConfigurationError(`Identifier length out of range (1-${maxLen}): \"${input}\"`, {\n code: \"invalid_identifier\",\n });\n }\n // T5.5 — explicit NUL / control char rejection ahead of the generic\n // pattern check. The IDENTIFIER_PATTERN regex already excludes these\n // (they are not in `[a-z0-9\\-_]`), but routing them through the same\n // helper used by safePathJoin gives operators a precise diagnostic\n // (\"nul-byte\" / \"control-char-0x..\") instead of the generic\n // \"invalid characters\" message — making prompt-injection traces\n // legible per Unbreakable Rule 3.\n rejectNulAndControlChars(input, \"identifier\");\n if (!IDENTIFIER_PATTERN.test(input)) {\n throw new ConfigurationError(`Identifier contains invalid characters: \"${input}\"`, {\n code: \"invalid_identifier\",\n });\n }\n return input.toLowerCase();\n}\n\n/**\n * Convert ANY opaque id (agent id, run id, conversation id, namespace, email,\n * arbitrary string) into a deterministic, filesystem-safe filename component.\n *\n * Unlike {@link sanitizeIdentifier} (which THROWS on non-conforming input),\n * this is a total function: it NEVER throws on a non-empty string. It returns\n * the lowercased id verbatim when it already matches the safe grammar\n * `^[a-z0-9][a-z0-9-_]*$` and fits `maxLen` (so UUIDs, hashes, and slugs stay\n * human-readable), otherwise a deterministic `h-<16 hex>` sha256 token\n * (collision-resistant and always a valid filename). The output charset is\n * always `[a-z0-9_-]`, safe as a literal path segment on every filesystem.\n *\n * @param id - any opaque identifier (must be a non-empty string)\n * @param options.maxLen - max length for the passthrough branch (default 128).\n * Ids longer than this are hashed; the hash token itself is always short.\n * @throws ConfigurationError (code `invalid_filename_id`) only on empty input.\n *\n * @example\n * safeFilenameForId(\"550e8400-e29b-41d4-a716-446655440000\") // passthrough\n * safeFilenameForId(\"user@example.com\") // \"h-<16hex>\"\n *\n * @internal — public via `@theokit/sdk/path-safety`\n */\nexport function safeFilenameForId(id: string, options?: { maxLen?: number }): string {\n if (id.length === 0) {\n throw new ConfigurationError(\"Filename id must be a non-empty string\", {\n code: \"invalid_filename_id\",\n });\n }\n const maxLen = options?.maxLen ?? 128;\n const lower = id.toLowerCase();\n if (lower.length <= maxLen && IDENTIFIER_PATTERN.test(lower)) {\n return lower;\n }\n return `h-${createHash(\"sha256\").update(id).digest(\"hex\").slice(0, 16)}`;\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkYLQQX5W2_cjs = require('./chunk-YLQQX5W2.cjs');
4
- var chunkBCQ3E2ZG_cjs = require('./chunk-BCQ3E2ZG.cjs');
4
+ var chunkA76OFN2B_cjs = require('./chunk-A76OFN2B.cjs');
5
5
  var fs = require('fs');
6
6
  var path = require('path');
7
7
 
@@ -16,7 +16,7 @@ async function getProperLockfile() {
16
16
  if (!validateLockModule(mod)) {
17
17
  if (!warnedStructural) {
18
18
  warnedStructural = true;
19
- chunkBCQ3E2ZG_cjs.diag(
19
+ chunkA76OFN2B_cjs.diag(
20
20
  "[theokit-sdk] proper-lockfile: imported module does NOT expose the expected `lock`/`unlock` API surface. This may indicate a supply-chain compromise or an incompatible major version. Falling back to in-process mutex (no cross-process safety). Reinstall with: pnpm add proper-lockfile@^11\n"
21
21
  );
22
22
  }
@@ -39,7 +39,7 @@ async function withFileLock(path, fn, options) {
39
39
  if (lib === null) {
40
40
  if (!warnedMissing) {
41
41
  warnedMissing = true;
42
- chunkBCQ3E2ZG_cjs.diag(
42
+ chunkA76OFN2B_cjs.diag(
43
43
  "[theokit-sdk] proper-lockfile not installed; cross-process file lock unavailable. Install with: pnpm add proper-lockfile\n"
44
44
  );
45
45
  }
@@ -166,5 +166,5 @@ exports.appendJsonl = appendJsonl;
166
166
  exports.loadJsonl = loadJsonl;
167
167
  exports.readJsonlIds = readJsonlIds;
168
168
  exports.withFileLock = withFileLock;
169
- //# sourceMappingURL=chunk-DMTZ3FII.cjs.map
170
- //# sourceMappingURL=chunk-DMTZ3FII.cjs.map
169
+ //# sourceMappingURL=chunk-JERO4TP6.cjs.map
170
+ //# sourceMappingURL=chunk-JERO4TP6.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/persistence/file-lock.ts","../src/internal/persistence/jsonl.ts"],"names":["diag","withCwdMutex","readFileSync","path","mkdirSync","dirname","openSync","writeSync","closeSync","fstatSync","readSync"],"mappings":"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","file":"chunk-DMTZ3FII.cjs","sourcesContent":["/**\n * Cross-process file lock helper (ADR D61).\n *\n * Uses `proper-lockfile` (optional peer dep) for cross-process locks. When\n * the peer dep is absent, falls back to `withCwdMutex` (in-process only)\n * with a one-shot stderr warning.\n *\n * EC-1 fix: uses a companion `<path>.lock` file with `realpath: false` so\n * `withFileLock` works even when the target `path` does not exist yet.\n * Without this, fresh installs that lock-then-create would crash with ENOENT.\n *\n * @internal\n */\n\nimport { diag } from \"../diagnostics.js\";\nimport { withCwdMutex } from \"./cwd-mutex.js\";\n\ninterface ProperLockfileModule {\n lock: (file: string, options: ProperLockfileOptions) => Promise<() => Promise<void>>;\n}\n\ninterface ProperLockfileOptions {\n lockfilePath?: string;\n realpath?: boolean;\n stale?: number;\n retries?: {\n retries: number;\n factor?: number;\n minTimeout?: number;\n maxTimeout?: number;\n };\n}\n\nlet cached: ProperLockfileModule | null | undefined;\nlet warnedMissing = false;\nlet warnedStructural = false;\n\nasync function getProperLockfile(): Promise<ProperLockfileModule | null> {\n if (cached !== undefined) return cached;\n try {\n const mod = await import(\"proper-lockfile\");\n // T5.9 — supply-chain hardening: validate the imported module\n // exposes the API surface we depend on BEFORE caching it. A\n // tampered or incompatible version that lacks `lock`/`unlock`\n // functions gets treated as \"not installed\" with an advisory\n // warning — never silently used.\n if (!validateLockModule(mod)) {\n if (!warnedStructural) {\n warnedStructural = true;\n diag(\n \"[theokit-sdk] proper-lockfile: imported module does NOT expose \" +\n \"the expected `lock`/`unlock` API surface. This may indicate a \" +\n \"supply-chain compromise or an incompatible major version. \" +\n \"Falling back to in-process mutex (no cross-process safety). \" +\n \"Reinstall with: pnpm add proper-lockfile@^11\\n\",\n );\n }\n cached = null;\n return cached;\n }\n cached = mod as ProperLockfileModule;\n } catch {\n cached = null;\n }\n return cached;\n}\n\n/**\n * T5.9 — Structural validation of the dynamically-imported\n * `proper-lockfile` module. Verifies the API surface we depend on\n * (`lock` and `unlock` as functions) is present. Pure function —\n * never throws, never mutates, never performs I/O.\n *\n * Exported via `__TESTING__validateLockModule` seam so unit tests\n * can drive the check without spinning up the dynamic import.\n *\n * @internal\n */\nfunction validateLockModule(mod: unknown): boolean {\n if (mod === null || mod === undefined || typeof mod !== \"object\") return false;\n const m = mod as Record<string, unknown>;\n return typeof m.lock === \"function\" && typeof m.unlock === \"function\";\n}\n\n/**\n * T5.9 — Test seam: expose the structural validator for unit tests.\n * NOT included in the public barrel.\n *\n * @internal\n */\nexport function __TESTING__validateLockModule(mod: unknown): boolean {\n return validateLockModule(mod);\n}\n\n/**\n * T5.9 — Test seam: reset the module cache + warning flags between\n * tests so each test starts fresh. NOT included in the public barrel.\n *\n * @internal\n */\nexport function __TESTING__resetFileLockCache(): void {\n cached = undefined;\n warnedMissing = false;\n warnedStructural = false;\n}\n\n/**\n * Options for `withFileLock`.\n *\n * @internal\n */\nexport interface FileLockOptions {\n /** Stale lock timeout in ms. Default 30_000 (30s). */\n stale?: number;\n /** Max retries on busy lock. Default 5. */\n retries?: number;\n /** Backoff factor between retries. Default 1.5. */\n retryFactor?: number;\n}\n\n/**\n * Run `fn` while holding an OS-level cross-process lock on `path`.\n *\n * If `proper-lockfile` is installed, uses it with a companion `<path>.lock`\n * file (`realpath: false`, so target file does NOT need to exist yet).\n * Otherwise falls back to in-process `withCwdMutex` and prints a one-shot\n * stderr warning telling the user to install `proper-lockfile` for\n * cross-process safety.\n *\n * The lock is released even when `fn` throws.\n *\n * @internal\n */\nexport async function withFileLock<T>(\n path: string,\n fn: () => Promise<T>,\n options?: FileLockOptions,\n): Promise<T> {\n const lib = await getProperLockfile();\n\n if (lib === null) {\n if (!warnedMissing) {\n warnedMissing = true;\n diag(\n \"[theokit-sdk] proper-lockfile not installed; \" +\n \"cross-process file lock unavailable. \" +\n \"Install with: pnpm add proper-lockfile\\n\",\n );\n }\n return withCwdMutex(`file-lock:${path}`, fn);\n }\n\n // proper-lockfile errors immediately on same-process concurrent acquire\n // (\"Lock file is already being held\"). Wrap with cwd-mutex first so\n // in-process callers queue and only ONE thread at a time enters the\n // cross-process acquire path. Combined: full in-process + cross-process\n // serialization.\n return withCwdMutex(`file-lock:${path}`, async () => {\n const release = await lib.lock(path, {\n // EC-1: companion lockfile, target path may not exist yet.\n lockfilePath: `${path}.lock`,\n realpath: false,\n stale: options?.stale ?? 30_000,\n retries: {\n retries: options?.retries ?? 5,\n factor: options?.retryFactor ?? 1.5,\n minTimeout: 100,\n maxTimeout: 5_000,\n },\n });\n\n try {\n return await fn();\n } finally {\n await release();\n }\n });\n}\n\n/**\n * Test helper — resets the cached proper-lockfile module + warning flag.\n * Allows tests to simulate \"module absent\" by clearing cache then\n * monkey-patching the dynamic import resolution.\n *\n * @internal\n */\nexport function _resetFileLockCacheForTesting(): void {\n cached = undefined;\n warnedMissing = false;\n}\n","/**\n * Durable JSONL primitives shared by the eval harness (M6).\n *\n * - `loadJsonl` — generic dataset reader (split/trim/skip-blank/parse) with a\n * line-numbered {@link JsonlParseError}. The dataset SCHEMA is the caller's\n * concern via `map` (M6 ADR D3) — this module owns only the parse.\n * - `appendJsonl` / `readJsonlIds` — crash-durable, resumable batch persistence\n * (M6 ADR D1): each record is appended as one whole `\\n`-terminated line the\n * instant it is produced, and a re-run resumes by skipping already-keyed rows.\n *\n * referencia: knowledge-base/references/theocode-eval/lib/swebench-dataset.ts:82\n * (parseJsonl + line-N error) and swebench-batch.ts:113,205 (resume + per-line\n * flush).\n *\n * @internal\n */\nimport {\n closeSync,\n fstatSync,\n mkdirSync,\n openSync,\n readFileSync,\n readSync,\n writeSync,\n} from \"node:fs\";\nimport { dirname } from \"node:path\";\n\n/** Raised when a JSONL line is not valid JSON or is not a JSON object. Carries the 1-based line number. */\nexport class JsonlParseError extends Error {\n constructor(\n message: string,\n readonly line: number,\n ) {\n super(message);\n this.name = \"JsonlParseError\";\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Parse a single trimmed line to a plain object, or `undefined` if blank / invalid / non-object. */\nfunction tryParseObjectLine(line: string): Record<string, unknown> | undefined {\n if (line.length === 0) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n return undefined;\n }\n return isPlainObject(parsed) ? parsed : undefined;\n}\n\n/**\n * Parse a JSONL file into rows. Blank lines are skipped. A malformed or\n * non-object line throws {@link JsonlParseError} naming the 1-based line. When\n * `map` is provided, each raw object is mapped to the typed row (the SWE-bench\n * schema lives in the caller's `map`, per M6 ADR D3).\n */\nexport function loadJsonl<T = Record<string, unknown>>(\n path: string,\n opts: {\n map?: (raw: Record<string, unknown>, lineNumber: number) => T;\n /**\n * M81 — tolerate a truncated LAST line (a crash artifact: the process died mid-write).\n *\n * Opt-in on purpose. As a default it would also swallow corruption in the MIDDLE of the file,\n * turning loud data loss into silent data loss — the wrong trade for a session store.\n */\n tolerateTrailingPartialLine?: boolean;\n } = {},\n): T[] {\n const lines = readFileSync(path, \"utf8\").split(\"\\n\");\n const out: T[] = [];\n for (let i = 0; i < lines.length; i += 1) {\n const lineNumber = i + 1;\n const line = (lines[i] ?? \"\").trim();\n if (line.length === 0) continue;\n // M81 — `undefined` = a tolerated invalid line (the last one, truncated by a crash). Any other\n // invalid line has already thrown inside `parseLine`.\n const parsed = parseLine(\n line,\n lineNumber,\n opts.tolerateTrailingPartialLine === true && lineNumber === lines.length,\n );\n if (parsed === undefined) break;\n out.push(opts.map ? opts.map(parsed, lineNumber) : (parsed as unknown as T));\n }\n return out;\n}\n\n/**\n * Parses ONE line, returning `undefined` when it is a tolerated truncated last line.\n *\n * Extracted because `loadJsonl` went over the cognitive-complexity ceiling once it gained the\n * tolerance — and because parsing a line and iterating a file are two responsibilities that were\n * only together out of habit.\n */\nfunction parseLine(\n line: string,\n lineNumber: number,\n tolerate: boolean,\n): Record<string, unknown> | undefined {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n if (tolerate) return undefined;\n throw new JsonlParseError(`line ${lineNumber}: invalid JSON`, lineNumber);\n }\n if (!isPlainObject(parsed)) {\n throw new JsonlParseError(`line ${lineNumber}: not a JSON object`, lineNumber);\n }\n return parsed;\n}\n\n/**\n * Append one record as a whole `\\n`-terminated JSON line. Creates the parent dir\n * if missing. `appendFileSync` is synchronous, so within a single Node process\n * the event loop serializes writes and each call writes its line atomically —\n * interleave-safe for the bounded-concurrency batch runner.\n *\n * referencia: swebench-batch.ts:192 (mkdir-before-append), :205 (per-line flush).\n */\nexport function appendJsonl(path: string, record: unknown): void {\n mkdirSync(dirname(path), { recursive: true });\n const prefix = needsLineBreakBefore(path) ? \"\\n\" : \"\";\n // M93 (adversarial review, H1) — `0o600`. `appendFileSync` takes no `mode`, so the permission came\n // from the umask: under `umask 022` the transcript was born `0664`, world-readable. The previous\n // path (`replaceFileAtomic`) pinned `0o600` on purpose — \"holds the FULL in-flight content\n // (credential snapshots, OAuth tokens)\" (`atomic-write.ts:107`) — and switching to append lost\n // that silently. The same class had already been caught in the consumer (`atomic-sync.ts`, M88\n // HIGH-1).\n //\n // `mode` only applies on CREATION; a pre-existing file keeps whatever permission it already has.\n const fd = openSync(path, \"a\", 0o600);\n try {\n writeSync(fd, `${prefix}${JSON.stringify(record)}\\n`);\n } finally {\n closeSync(fd);\n }\n}\n\n/**\n * Does the file end without a `\\n`? Then the last line is truncated — a crash mid-append.\n *\n * Without this check the next append **glues** itself onto the middle of the broken line, producing\n * an invalid line the reader discards: the NEW record disappears along with the partial one. The\n * previous path (read-modify-write) self-healed from this because it rewrote the whole file.\n * Measured in M93's adversarial review (H2): after an append over a truncated file, the\n * just-written record was no longer readable.\n *\n * Reads **one byte**, not the file.\n */\nfunction needsLineBreakBefore(path: string): boolean {\n let fd: number;\n try {\n fd = openSync(path, \"r\");\n } catch {\n return false; // the file does not exist yet: nothing to splice onto\n }\n try {\n const size = fstatSync(fd).size;\n if (size === 0) return false;\n const buf = Buffer.alloc(1);\n readSync(fd, buf, 0, 1, size - 1);\n return buf[0] !== 0x0a;\n } finally {\n closeSync(fd);\n }\n}\n\n/**\n * Read the set of keys from an existing JSONL file for which `keyFn(parsed)`\n * returns a non-empty string. Used to resume a crashed batch by skipping rows\n * already persisted with a successful result. A trailing partial line from an\n * interrupted append is tolerated (skipped, not thrown), and a missing file\n * yields an empty set.\n *\n * referencia: swebench-batch.ts:113 (readDoneIds), :129 (success-only),\n * :131 (tolerate partial line).\n */\nexport function readJsonlIds(\n path: string,\n keyFn: (parsed: Record<string, unknown>) => string | undefined,\n): Set<string> {\n const done = new Set<string>();\n let text: string;\n try {\n text = readFileSync(path, \"utf8\");\n } catch {\n return done; // no file yet → nothing done\n }\n for (const rawLine of text.split(\"\\n\")) {\n // A trailing partial line from an interrupted run parses to undefined → skipped.\n const parsed = tryParseObjectLine(rawLine.trim());\n if (parsed === undefined) continue;\n const key = keyFn(parsed);\n if (typeof key === \"string\" && key.length > 0) done.add(key);\n }\n return done;\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/persistence/file-lock.ts","../src/internal/persistence/jsonl.ts"],"names":["diag","withCwdMutex","readFileSync","path","mkdirSync","dirname","openSync","writeSync","closeSync","fstatSync","readSync"],"mappings":"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","file":"chunk-JERO4TP6.cjs","sourcesContent":["/**\n * Cross-process file lock helper (ADR D61).\n *\n * Uses `proper-lockfile` (optional peer dep) for cross-process locks. When\n * the peer dep is absent, falls back to `withCwdMutex` (in-process only)\n * with a one-shot stderr warning.\n *\n * EC-1 fix: uses a companion `<path>.lock` file with `realpath: false` so\n * `withFileLock` works even when the target `path` does not exist yet.\n * Without this, fresh installs that lock-then-create would crash with ENOENT.\n *\n * @internal\n */\n\nimport { diag } from \"../diagnostics.js\";\nimport { withCwdMutex } from \"./cwd-mutex.js\";\n\ninterface ProperLockfileModule {\n lock: (file: string, options: ProperLockfileOptions) => Promise<() => Promise<void>>;\n}\n\ninterface ProperLockfileOptions {\n lockfilePath?: string;\n realpath?: boolean;\n stale?: number;\n retries?: {\n retries: number;\n factor?: number;\n minTimeout?: number;\n maxTimeout?: number;\n };\n}\n\nlet cached: ProperLockfileModule | null | undefined;\nlet warnedMissing = false;\nlet warnedStructural = false;\n\nasync function getProperLockfile(): Promise<ProperLockfileModule | null> {\n if (cached !== undefined) return cached;\n try {\n const mod = await import(\"proper-lockfile\");\n // T5.9 — supply-chain hardening: validate the imported module\n // exposes the API surface we depend on BEFORE caching it. A\n // tampered or incompatible version that lacks `lock`/`unlock`\n // functions gets treated as \"not installed\" with an advisory\n // warning — never silently used.\n if (!validateLockModule(mod)) {\n if (!warnedStructural) {\n warnedStructural = true;\n diag(\n \"[theokit-sdk] proper-lockfile: imported module does NOT expose \" +\n \"the expected `lock`/`unlock` API surface. This may indicate a \" +\n \"supply-chain compromise or an incompatible major version. \" +\n \"Falling back to in-process mutex (no cross-process safety). \" +\n \"Reinstall with: pnpm add proper-lockfile@^11\\n\",\n );\n }\n cached = null;\n return cached;\n }\n cached = mod as ProperLockfileModule;\n } catch {\n cached = null;\n }\n return cached;\n}\n\n/**\n * T5.9 — Structural validation of the dynamically-imported\n * `proper-lockfile` module. Verifies the API surface we depend on\n * (`lock` and `unlock` as functions) is present. Pure function —\n * never throws, never mutates, never performs I/O.\n *\n * Exported via `__TESTING__validateLockModule` seam so unit tests\n * can drive the check without spinning up the dynamic import.\n *\n * @internal\n */\nfunction validateLockModule(mod: unknown): boolean {\n if (mod === null || mod === undefined || typeof mod !== \"object\") return false;\n const m = mod as Record<string, unknown>;\n return typeof m.lock === \"function\" && typeof m.unlock === \"function\";\n}\n\n/**\n * T5.9 — Test seam: expose the structural validator for unit tests.\n * NOT included in the public barrel.\n *\n * @internal\n */\nexport function __TESTING__validateLockModule(mod: unknown): boolean {\n return validateLockModule(mod);\n}\n\n/**\n * T5.9 — Test seam: reset the module cache + warning flags between\n * tests so each test starts fresh. NOT included in the public barrel.\n *\n * @internal\n */\nexport function __TESTING__resetFileLockCache(): void {\n cached = undefined;\n warnedMissing = false;\n warnedStructural = false;\n}\n\n/**\n * Options for `withFileLock`.\n *\n * @internal\n */\nexport interface FileLockOptions {\n /** Stale lock timeout in ms. Default 30_000 (30s). */\n stale?: number;\n /** Max retries on busy lock. Default 5. */\n retries?: number;\n /** Backoff factor between retries. Default 1.5. */\n retryFactor?: number;\n}\n\n/**\n * Run `fn` while holding an OS-level cross-process lock on `path`.\n *\n * If `proper-lockfile` is installed, uses it with a companion `<path>.lock`\n * file (`realpath: false`, so target file does NOT need to exist yet).\n * Otherwise falls back to in-process `withCwdMutex` and prints a one-shot\n * stderr warning telling the user to install `proper-lockfile` for\n * cross-process safety.\n *\n * The lock is released even when `fn` throws.\n *\n * @internal\n */\nexport async function withFileLock<T>(\n path: string,\n fn: () => Promise<T>,\n options?: FileLockOptions,\n): Promise<T> {\n const lib = await getProperLockfile();\n\n if (lib === null) {\n if (!warnedMissing) {\n warnedMissing = true;\n diag(\n \"[theokit-sdk] proper-lockfile not installed; \" +\n \"cross-process file lock unavailable. \" +\n \"Install with: pnpm add proper-lockfile\\n\",\n );\n }\n return withCwdMutex(`file-lock:${path}`, fn);\n }\n\n // proper-lockfile errors immediately on same-process concurrent acquire\n // (\"Lock file is already being held\"). Wrap with cwd-mutex first so\n // in-process callers queue and only ONE thread at a time enters the\n // cross-process acquire path. Combined: full in-process + cross-process\n // serialization.\n return withCwdMutex(`file-lock:${path}`, async () => {\n const release = await lib.lock(path, {\n // EC-1: companion lockfile, target path may not exist yet.\n lockfilePath: `${path}.lock`,\n realpath: false,\n stale: options?.stale ?? 30_000,\n retries: {\n retries: options?.retries ?? 5,\n factor: options?.retryFactor ?? 1.5,\n minTimeout: 100,\n maxTimeout: 5_000,\n },\n });\n\n try {\n return await fn();\n } finally {\n await release();\n }\n });\n}\n\n/**\n * Test helper — resets the cached proper-lockfile module + warning flag.\n * Allows tests to simulate \"module absent\" by clearing cache then\n * monkey-patching the dynamic import resolution.\n *\n * @internal\n */\nexport function _resetFileLockCacheForTesting(): void {\n cached = undefined;\n warnedMissing = false;\n}\n","/**\n * Durable JSONL primitives shared by the eval harness (M6).\n *\n * - `loadJsonl` — generic dataset reader (split/trim/skip-blank/parse) with a\n * line-numbered {@link JsonlParseError}. The dataset SCHEMA is the caller's\n * concern via `map` (M6 ADR D3) — this module owns only the parse.\n * - `appendJsonl` / `readJsonlIds` — crash-durable, resumable batch persistence\n * (M6 ADR D1): each record is appended as one whole `\\n`-terminated line the\n * instant it is produced, and a re-run resumes by skipping already-keyed rows.\n *\n * referencia: knowledge-base/references/theocode-eval/lib/swebench-dataset.ts:82\n * (parseJsonl + line-N error) and swebench-batch.ts:113,205 (resume + per-line\n * flush).\n *\n * @internal\n */\nimport {\n closeSync,\n fstatSync,\n mkdirSync,\n openSync,\n readFileSync,\n readSync,\n writeSync,\n} from \"node:fs\";\nimport { dirname } from \"node:path\";\n\n/** Raised when a JSONL line is not valid JSON or is not a JSON object. Carries the 1-based line number. */\nexport class JsonlParseError extends Error {\n constructor(\n message: string,\n readonly line: number,\n ) {\n super(message);\n this.name = \"JsonlParseError\";\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Parse a single trimmed line to a plain object, or `undefined` if blank / invalid / non-object. */\nfunction tryParseObjectLine(line: string): Record<string, unknown> | undefined {\n if (line.length === 0) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n return undefined;\n }\n return isPlainObject(parsed) ? parsed : undefined;\n}\n\n/**\n * Parse a JSONL file into rows. Blank lines are skipped. A malformed or\n * non-object line throws {@link JsonlParseError} naming the 1-based line. When\n * `map` is provided, each raw object is mapped to the typed row (the SWE-bench\n * schema lives in the caller's `map`, per M6 ADR D3).\n */\nexport function loadJsonl<T = Record<string, unknown>>(\n path: string,\n opts: {\n map?: (raw: Record<string, unknown>, lineNumber: number) => T;\n /**\n * M81 — tolerate a truncated LAST line (a crash artifact: the process died mid-write).\n *\n * Opt-in on purpose. As a default it would also swallow corruption in the MIDDLE of the file,\n * turning loud data loss into silent data loss — the wrong trade for a session store.\n */\n tolerateTrailingPartialLine?: boolean;\n } = {},\n): T[] {\n const lines = readFileSync(path, \"utf8\").split(\"\\n\");\n const out: T[] = [];\n for (let i = 0; i < lines.length; i += 1) {\n const lineNumber = i + 1;\n const line = (lines[i] ?? \"\").trim();\n if (line.length === 0) continue;\n // M81 — `undefined` = a tolerated invalid line (the last one, truncated by a crash). Any other\n // invalid line has already thrown inside `parseLine`.\n const parsed = parseLine(\n line,\n lineNumber,\n opts.tolerateTrailingPartialLine === true && lineNumber === lines.length,\n );\n if (parsed === undefined) break;\n out.push(opts.map ? opts.map(parsed, lineNumber) : (parsed as unknown as T));\n }\n return out;\n}\n\n/**\n * Parses ONE line, returning `undefined` when it is a tolerated truncated last line.\n *\n * Extracted because `loadJsonl` went over the cognitive-complexity ceiling once it gained the\n * tolerance — and because parsing a line and iterating a file are two responsibilities that were\n * only together out of habit.\n */\nfunction parseLine(\n line: string,\n lineNumber: number,\n tolerate: boolean,\n): Record<string, unknown> | undefined {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n if (tolerate) return undefined;\n throw new JsonlParseError(`line ${lineNumber}: invalid JSON`, lineNumber);\n }\n if (!isPlainObject(parsed)) {\n throw new JsonlParseError(`line ${lineNumber}: not a JSON object`, lineNumber);\n }\n return parsed;\n}\n\n/**\n * Append one record as a whole `\\n`-terminated JSON line. Creates the parent dir\n * if missing. `appendFileSync` is synchronous, so within a single Node process\n * the event loop serializes writes and each call writes its line atomically —\n * interleave-safe for the bounded-concurrency batch runner.\n *\n * referencia: swebench-batch.ts:192 (mkdir-before-append), :205 (per-line flush).\n */\nexport function appendJsonl(path: string, record: unknown): void {\n mkdirSync(dirname(path), { recursive: true });\n const prefix = needsLineBreakBefore(path) ? \"\\n\" : \"\";\n // M93 (adversarial review, H1) — `0o600`. `appendFileSync` takes no `mode`, so the permission came\n // from the umask: under `umask 022` the transcript was born `0664`, world-readable. The previous\n // path (`replaceFileAtomic`) pinned `0o600` on purpose — \"holds the FULL in-flight content\n // (credential snapshots, OAuth tokens)\" (`atomic-write.ts:107`) — and switching to append lost\n // that silently. The same class had already been caught in the consumer (`atomic-sync.ts`, M88\n // HIGH-1).\n //\n // `mode` only applies on CREATION; a pre-existing file keeps whatever permission it already has.\n const fd = openSync(path, \"a\", 0o600);\n try {\n writeSync(fd, `${prefix}${JSON.stringify(record)}\\n`);\n } finally {\n closeSync(fd);\n }\n}\n\n/**\n * Does the file end without a `\\n`? Then the last line is truncated — a crash mid-append.\n *\n * Without this check the next append **glues** itself onto the middle of the broken line, producing\n * an invalid line the reader discards: the NEW record disappears along with the partial one. The\n * previous path (read-modify-write) self-healed from this because it rewrote the whole file.\n * Measured in M93's adversarial review (H2): after an append over a truncated file, the\n * just-written record was no longer readable.\n *\n * Reads **one byte**, not the file.\n */\nfunction needsLineBreakBefore(path: string): boolean {\n let fd: number;\n try {\n fd = openSync(path, \"r\");\n } catch {\n return false; // the file does not exist yet: nothing to splice onto\n }\n try {\n const size = fstatSync(fd).size;\n if (size === 0) return false;\n const buf = Buffer.alloc(1);\n readSync(fd, buf, 0, 1, size - 1);\n return buf[0] !== 0x0a;\n } finally {\n closeSync(fd);\n }\n}\n\n/**\n * Read the set of keys from an existing JSONL file for which `keyFn(parsed)`\n * returns a non-empty string. Used to resume a crashed batch by skipping rows\n * already persisted with a successful result. A trailing partial line from an\n * interrupted append is tolerated (skipped, not thrown), and a missing file\n * yields an empty set.\n *\n * referencia: swebench-batch.ts:113 (readDoneIds), :129 (success-only),\n * :131 (tolerate partial line).\n */\nexport function readJsonlIds(\n path: string,\n keyFn: (parsed: Record<string, unknown>) => string | undefined,\n): Set<string> {\n const done = new Set<string>();\n let text: string;\n try {\n text = readFileSync(path, \"utf8\");\n } catch {\n return done; // no file yet → nothing done\n }\n for (const rawLine of text.split(\"\\n\")) {\n // A trailing partial line from an interrupted run parses to undefined → skipped.\n const parsed = tryParseObjectLine(rawLine.trim());\n if (parsed === undefined) continue;\n const key = keyFn(parsed);\n if (typeof key === \"string\" && key.length > 0) done.add(key);\n }\n return done;\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkIHFNRNTJ_cjs = require('./chunk-IHFNRNTJ.cjs');
4
- var chunkBCQ3E2ZG_cjs = require('./chunk-BCQ3E2ZG.cjs');
3
+ var chunkE7WWIX34_cjs = require('./chunk-E7WWIX34.cjs');
4
+ var chunkA76OFN2B_cjs = require('./chunk-A76OFN2B.cjs');
5
5
  var async_hooks = require('async_hooks');
6
6
  var fs = require('fs');
7
7
  var promises = require('fs/promises');
@@ -17,7 +17,7 @@ var warned = /* @__PURE__ */ new Set();
17
17
  function warnOnce(key, message) {
18
18
  if (warned.has(key)) return;
19
19
  warned.add(key);
20
- chunkBCQ3E2ZG_cjs.diag(`${message}
20
+ chunkA76OFN2B_cjs.diag(`${message}
21
21
  `);
22
22
  }
23
23
  async function loadHookConfig(cwd) {
@@ -35,7 +35,7 @@ async function loadHookConfig(cwd) {
35
35
  try {
36
36
  raw = await promises.readFile(jsonPath, "utf8");
37
37
  } catch (cause) {
38
- throw new chunkIHFNRNTJ_cjs.ConfigurationError(`Failed to read hooks config: ${jsonPath}`, {
38
+ throw new chunkE7WWIX34_cjs.ConfigurationError(`Failed to read hooks config: ${jsonPath}`, {
39
39
  code: "hooks_read_error",
40
40
  cause
41
41
  });
@@ -44,7 +44,7 @@ async function loadHookConfig(cwd) {
44
44
  try {
45
45
  parsed = JSON.parse(raw);
46
46
  } catch (cause) {
47
- throw new chunkIHFNRNTJ_cjs.ConfigurationError(`Invalid JSON in hooks config: ${jsonPath}`, {
47
+ throw new chunkE7WWIX34_cjs.ConfigurationError(`Invalid JSON in hooks config: ${jsonPath}`, {
48
48
  code: "hooks_json_invalid",
49
49
  cause
50
50
  });
@@ -53,7 +53,7 @@ async function loadHookConfig(cwd) {
53
53
  }
54
54
  function asRecord(value, path, where) {
55
55
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
56
- throw new chunkIHFNRNTJ_cjs.ConfigurationError(`hooks: expected an object at ${where} in ${path}`, {
56
+ throw new chunkE7WWIX34_cjs.ConfigurationError(`hooks: expected an object at ${where} in ${path}`, {
57
57
  code: "hooks_json_invalid"
58
58
  });
59
59
  }
@@ -61,7 +61,7 @@ function asRecord(value, path, where) {
61
61
  }
62
62
  function asArray(value, path, where) {
63
63
  if (!Array.isArray(value)) {
64
- throw new chunkIHFNRNTJ_cjs.ConfigurationError(`hooks: expected an array at ${where} in ${path}`, {
64
+ throw new chunkE7WWIX34_cjs.ConfigurationError(`hooks: expected an array at ${where} in ${path}`, {
65
65
  code: "hooks_json_invalid"
66
66
  });
67
67
  }
@@ -99,13 +99,13 @@ function flattenEventGroups(groups, path, ccEvent) {
99
99
  function parseClaudeCodeCommand(raw, matcher, path, ccEvent) {
100
100
  const cmd = asRecord(raw, path, `hooks.${ccEvent}[].hooks[]`);
101
101
  if (cmd.type !== "command") {
102
- throw new chunkIHFNRNTJ_cjs.ConfigurationError(
102
+ throw new chunkE7WWIX34_cjs.ConfigurationError(
103
103
  `hooks: only { "type": "command" } is supported (got ${JSON.stringify(cmd.type)}) in ${path}`,
104
104
  { code: "hooks_unsupported_type" }
105
105
  );
106
106
  }
107
107
  if (typeof cmd.command !== "string" || cmd.command.length === 0) {
108
- throw new chunkIHFNRNTJ_cjs.ConfigurationError(`hooks: "command" must be a non-empty string in ${path}`, {
108
+ throw new chunkE7WWIX34_cjs.ConfigurationError(`hooks: "command" must be a non-empty string in ${path}`, {
109
109
  code: "hooks_invalid_command"
110
110
  });
111
111
  }
@@ -137,5 +137,5 @@ exports.loadHookConfig = loadHookConfig;
137
137
  exports.warnOnce = warnOnce;
138
138
  exports.warnPersonalitySwitchInsideFork = warnPersonalitySwitchInsideFork;
139
139
  exports.withPersonalityContext = withPersonalityContext;
140
- //# sourceMappingURL=chunk-6LGQECT7.cjs.map
141
- //# sourceMappingURL=chunk-6LGQECT7.cjs.map
140
+ //# sourceMappingURL=chunk-K6TWHNT4.cjs.map
141
+ //# sourceMappingURL=chunk-K6TWHNT4.cjs.map