@remnic/core 9.69.38 → 9.69.40

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 (656) hide show
  1. package/dist/access-admin-ops-surface.d.ts +16 -14
  2. package/dist/access-admin-ops-surface.js +39 -39
  3. package/dist/access-authorization-probe.d.ts +16 -14
  4. package/dist/access-authorization-probe.js +40 -40
  5. package/dist/access-boundary.d.ts +16 -14
  6. package/dist/access-boundary.js +39 -39
  7. package/dist/access-cli.js +107 -105
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-coding-context-resolution.d.ts +1 -1
  10. package/dist/access-extraction-force-flush.d.ts +16 -14
  11. package/dist/access-extraction-force-flush.js +39 -39
  12. package/dist/access-health-types.d.ts +1 -1
  13. package/dist/access-http-briefing.d.ts +16 -14
  14. package/dist/access-http-briefing.js +40 -40
  15. package/dist/access-http-lcm-compaction.d.ts +16 -14
  16. package/dist/access-http-lifecycle-flush.d.ts +16 -14
  17. package/dist/access-http-offline-stream.d.ts +16 -14
  18. package/dist/access-http-query.d.ts +2 -2
  19. package/dist/access-http-query.js +41 -41
  20. package/dist/access-http.d.ts +17 -15
  21. package/dist/access-http.js +58 -58
  22. package/dist/access-identity-continuity-surface.d.ts +13 -12
  23. package/dist/access-identity-continuity-surface.js +39 -39
  24. package/dist/access-lcm-surface.d.ts +16 -14
  25. package/dist/access-lcm-surface.js +39 -39
  26. package/dist/access-mcp.d.ts +16 -14
  27. package/dist/access-mcp.js +47 -47
  28. package/dist/access-memory-search-fanout.d.ts +2 -2
  29. package/dist/{access-namespace-preflight-DY4z6L5X.d.ts → access-namespace-preflight-CKBumJ8W.d.ts} +1 -1
  30. package/dist/access-namespace-preflight.d.ts +3 -3
  31. package/dist/access-namespace-preflight.js +39 -39
  32. package/dist/access-observe-transcript.d.ts +13 -12
  33. package/dist/access-observe-write-category.d.ts +1 -1
  34. package/dist/access-observe-write-category.js +2 -2
  35. package/dist/access-observe-write-surface.d.ts +16 -14
  36. package/dist/access-observe-write-surface.js +39 -39
  37. package/dist/access-offline-manifest.d.ts +37 -13
  38. package/dist/access-offline-manifest.js +7 -3
  39. package/dist/access-operations-batch.js +41 -41
  40. package/dist/access-operations.d.ts +16 -14
  41. package/dist/access-operations.js +46 -46
  42. package/dist/access-recall-concurrency.d.ts +16 -14
  43. package/dist/access-recall-concurrency.js +39 -39
  44. package/dist/access-recall-response.d.ts +16 -14
  45. package/dist/access-recall-response.js +39 -39
  46. package/dist/access-recall-surface.d.ts +16 -14
  47. package/dist/access-recall-surface.js +39 -39
  48. package/dist/access-schema.d.ts +5 -3
  49. package/dist/access-schema.js +1 -1
  50. package/dist/{access-service-gBcdRUHY.d.ts → access-service-DJ3qogNt.d.ts} +8 -8
  51. package/dist/access-service-helpers.d.ts +16 -14
  52. package/dist/access-service.d.ts +16 -14
  53. package/dist/access-service.js +39 -39
  54. package/dist/access-surface-catalog.d.ts +16 -14
  55. package/dist/access-surface-catalog.js +41 -41
  56. package/dist/access-wearables-meetings-surface.d.ts +6 -5
  57. package/dist/action-confidence.d.ts +1 -1
  58. package/dist/active-memory-bridge.d.ts +1 -1
  59. package/dist/active-recall.d.ts +1 -1
  60. package/dist/active-recall.js +6 -5
  61. package/dist/active-recall.js.map +1 -1
  62. package/dist/activity/digest.d.ts +1 -1
  63. package/dist/adapters/index.js +4 -4
  64. package/dist/adapters/registry.js +2 -2
  65. package/dist/ambient-provenance.d.ts +1 -1
  66. package/dist/artifact-search.d.ts +1 -1
  67. package/dist/{auto-sync-RP4C6ZPF.js → auto-sync-D6BAPIJV.js} +5 -5
  68. package/dist/background-generation-config.d.ts +1 -1
  69. package/dist/background-generation-config.js +3 -1
  70. package/dist/background-generation.d.ts +1 -1
  71. package/dist/behavior-learner.d.ts +1 -1
  72. package/dist/behavior-signals.d.ts +1 -1
  73. package/dist/bootstrap.d.ts +13 -12
  74. package/dist/briefing-window.d.ts +2 -2
  75. package/dist/briefing.d.ts +2 -2
  76. package/dist/briefing.js +16 -16
  77. package/dist/buffer-surprise-report.d.ts +1 -1
  78. package/dist/buffer-turn-helpers.d.ts +1 -1
  79. package/dist/buffer.d.ts +2 -2
  80. package/dist/buffer.js +5 -5
  81. package/dist/bulk-import/index.d.ts +3 -3
  82. package/dist/calibration.d.ts +3 -2
  83. package/dist/calibration.js +2 -2
  84. package/dist/capabilities.d.ts +1 -1
  85. package/dist/{catalog-CW87xGx8.d.ts → catalog-BHXkBVhg.d.ts} +1 -1
  86. package/dist/causal-behavior.d.ts +1 -1
  87. package/dist/causal-consolidation.d.ts +1 -1
  88. package/dist/causal-consolidation.js +20 -19
  89. package/dist/causal-consolidation.js.map +1 -1
  90. package/dist/causal-trajectory-graph.d.ts +1 -1
  91. package/dist/{chunk-B36GUU6T.js → chunk-23HFXQ5J.js} +36 -3
  92. package/dist/chunk-23HFXQ5J.js.map +1 -0
  93. package/dist/{chunk-YFTNZMGR.js → chunk-27NO2KVB.js} +31 -8
  94. package/dist/chunk-27NO2KVB.js.map +1 -0
  95. package/dist/{chunk-T32B72QX.js → chunk-2SKMZUOW.js} +2 -2
  96. package/dist/{chunk-VHOSM5G4.js → chunk-2SNCQHJZ.js} +2 -2
  97. package/dist/{chunk-VV4ZVUE6.js → chunk-3QEVOQF5.js} +2 -2
  98. package/dist/{chunk-3N3PBBEH.js → chunk-3XPN7AVY.js} +2 -2
  99. package/dist/{chunk-XN6XT6GR.js → chunk-46Z3VGWF.js} +2 -2
  100. package/dist/{chunk-2PTNJTBE.js → chunk-4CMXI55L.js} +2 -2
  101. package/dist/{chunk-2MT4ADLQ.js → chunk-5LYSEZOF.js} +18 -9
  102. package/dist/chunk-5LYSEZOF.js.map +1 -0
  103. package/dist/{chunk-XWLLFKHM.js → chunk-62HFZNCJ.js} +19 -12
  104. package/dist/chunk-62HFZNCJ.js.map +1 -0
  105. package/dist/{chunk-VELCIWJZ.js → chunk-6L2II3KS.js} +22 -11
  106. package/dist/chunk-6L2II3KS.js.map +1 -0
  107. package/dist/{chunk-A6CKMIPK.js → chunk-7D6SER6A.js} +8 -8
  108. package/dist/{chunk-4B3HBIFX.js → chunk-7Z54NXVS.js} +2 -2
  109. package/dist/{chunk-X2NFFBTO.js → chunk-A7GQBJP5.js} +4 -4
  110. package/dist/{chunk-ACY4ZPF7.js → chunk-AEOOGXMQ.js} +10 -5
  111. package/dist/chunk-AEOOGXMQ.js.map +1 -0
  112. package/dist/{chunk-NWMUSKED.js → chunk-BGRTZOJB.js} +3 -3
  113. package/dist/{chunk-ZEGL7YCC.js → chunk-BXIJSPCL.js} +2 -2
  114. package/dist/{chunk-MLWMR2GE.js → chunk-BYQX4IOG.js} +2 -2
  115. package/dist/{chunk-ULDBGA5W.js → chunk-C5R73BON.js} +2 -2
  116. package/dist/{chunk-BD7JTBYP.js → chunk-D7MAYFQP.js} +2 -2
  117. package/dist/{chunk-V6G2PSXA.js → chunk-DAZANIYU.js} +251 -297
  118. package/dist/chunk-DAZANIYU.js.map +1 -0
  119. package/dist/{chunk-BRZWWUCJ.js → chunk-DFVSJFHK.js} +2 -2
  120. package/dist/{chunk-DPMTLJCT.js → chunk-ES5BUPYB.js} +2 -2
  121. package/dist/{chunk-MVAQ2WM3.js → chunk-G2XZFGYN.js} +6 -2
  122. package/dist/chunk-G2XZFGYN.js.map +1 -0
  123. package/dist/{chunk-TNSCIPBQ.js → chunk-G6NQ3L4T.js} +2 -2
  124. package/dist/{chunk-5N4MZLEH.js → chunk-GO5LOHCD.js} +2 -2
  125. package/dist/{chunk-AECJY3GJ.js → chunk-GSSDHAYH.js} +2 -2
  126. package/dist/{chunk-JA2QJOAX.js → chunk-HJUP3K6L.js} +2 -2
  127. package/dist/{chunk-ZKZFFWLV.js → chunk-ICNJ6J46.js} +2 -2
  128. package/dist/{chunk-6EHM2AV7.js → chunk-IMBQFHRV.js} +2 -2
  129. package/dist/{chunk-6PRY6CLC.js → chunk-IOPIGX7Y.js} +1 -1
  130. package/dist/{chunk-TRHBQVVO.js → chunk-IS2IDFJP.js} +14 -14
  131. package/dist/{chunk-R4VAUNNC.js → chunk-J4WGTN2N.js} +2 -2
  132. package/dist/{chunk-JPOX2AJB.js → chunk-J7FVMLBR.js} +2 -2
  133. package/dist/{chunk-BYZKLEWG.js → chunk-JAJIMTFB.js} +6 -6
  134. package/dist/{chunk-OKO57IXB.js → chunk-JOP7W24J.js} +11 -11
  135. package/dist/{chunk-YUW66UAH.js → chunk-JUDT33RX.js} +2 -2
  136. package/dist/{chunk-QHT7MOUF.js → chunk-K4A6UVPB.js} +22 -11
  137. package/dist/chunk-K4A6UVPB.js.map +1 -0
  138. package/dist/{chunk-UQNYPK7G.js → chunk-K4JKAXMO.js} +2 -2
  139. package/dist/{chunk-BV4ZKIZH.js → chunk-K75A5XWU.js} +3 -2
  140. package/dist/{chunk-3CBI2ZSA.js → chunk-KG2OOAFF.js} +20 -12
  141. package/dist/chunk-KG2OOAFF.js.map +1 -0
  142. package/dist/{chunk-M6HBPLBA.js → chunk-KOTG3RXE.js} +2 -2
  143. package/dist/{chunk-CWTCMZGE.js → chunk-KTOXQMW3.js} +119 -3
  144. package/dist/chunk-KTOXQMW3.js.map +1 -0
  145. package/dist/{chunk-OB3XMWX5.js → chunk-KVO2BTA4.js} +2 -2
  146. package/dist/{chunk-CBFYCDYO.js → chunk-KY236SP5.js} +3 -3
  147. package/dist/{chunk-4BCHFSC7.js → chunk-LFVZD5EC.js} +3 -3
  148. package/dist/{chunk-GGAXFTNH.js → chunk-LKFVVN7R.js} +2 -2
  149. package/dist/{chunk-IYKZJVL5.js → chunk-MDIEES23.js} +1 -1
  150. package/dist/chunk-MDIEES23.js.map +1 -0
  151. package/dist/{chunk-4RX5O34R.js → chunk-MJC7UKH7.js} +2 -2
  152. package/dist/{chunk-7S53BPTU.js → chunk-MVG3KXON.js} +69 -22
  153. package/dist/chunk-MVG3KXON.js.map +1 -0
  154. package/dist/chunk-NETQXOPY.js +221 -0
  155. package/dist/chunk-NETQXOPY.js.map +1 -0
  156. package/dist/{chunk-UZZ7SQT3.js → chunk-NVVZPBKI.js} +2 -2
  157. package/dist/{chunk-BLDBT6HZ.js → chunk-PJRKLB4Z.js} +18 -2
  158. package/dist/chunk-PJRKLB4Z.js.map +1 -0
  159. package/dist/{chunk-TTSJ7WUC.js → chunk-PKUJNICO.js} +2 -2
  160. package/dist/{chunk-QMWKENNK.js → chunk-Q4AUIFUA.js} +4 -4
  161. package/dist/{chunk-G43PMSME.js → chunk-QE6YVNP5.js} +7 -7
  162. package/dist/{chunk-WKDFJXW5.js → chunk-QM2SPLKQ.js} +1 -1
  163. package/dist/chunk-QM2SPLKQ.js.map +1 -0
  164. package/dist/{chunk-GT4ZHOKT.js → chunk-QPVNK2VE.js} +2 -2
  165. package/dist/{chunk-K5DA5TRG.js → chunk-QS5Q5RBV.js} +2 -2
  166. package/dist/{chunk-BX4EOMKT.js → chunk-RDLPFM7I.js} +2 -2
  167. package/dist/{chunk-EY5JAWZC.js → chunk-RJQAP333.js} +2 -2
  168. package/dist/{chunk-5AERZWJD.js → chunk-RLU2Y5GV.js} +4 -4
  169. package/dist/chunk-RLU2Y5GV.js.map +1 -0
  170. package/dist/{chunk-2OGTN37H.js → chunk-ROEFLU37.js} +4 -4
  171. package/dist/{chunk-62QIQEUC.js → chunk-SFHLQPBF.js} +25 -25
  172. package/dist/chunk-SK7D34OL.js +68 -0
  173. package/dist/chunk-SK7D34OL.js.map +1 -0
  174. package/dist/{chunk-HVS7TH2Y.js → chunk-SUEOG2S4.js} +2 -2
  175. package/dist/{chunk-74AHCL56.js → chunk-TEMKBSV6.js} +2 -2
  176. package/dist/{chunk-LQNRVPTV.js → chunk-THTF2W7M.js} +151 -118
  177. package/dist/chunk-THTF2W7M.js.map +1 -0
  178. package/dist/{chunk-KDFDXEXZ.js → chunk-TO36VPZI.js} +2 -2
  179. package/dist/{chunk-BJEJUOGM.js → chunk-TZ44E732.js} +44 -6
  180. package/dist/chunk-TZ44E732.js.map +1 -0
  181. package/dist/{chunk-JXN77SGO.js → chunk-U2VDCFXW.js} +1 -1
  182. package/dist/chunk-U2VDCFXW.js.map +1 -0
  183. package/dist/{chunk-3OYSIVOO.js → chunk-UZ6JYPJ6.js} +611 -289
  184. package/dist/chunk-UZ6JYPJ6.js.map +1 -0
  185. package/dist/{chunk-M3MYMWXG.js → chunk-V2ZA4YWE.js} +2 -2
  186. package/dist/{chunk-UIOIDW3L.js → chunk-VHKXRYQN.js} +2 -2
  187. package/dist/{chunk-GAS7KYC7.js → chunk-VKWFNPBH.js} +2 -2
  188. package/dist/{chunk-6H2G7RFT.js → chunk-VNQRRUNS.js} +11 -10
  189. package/dist/chunk-VNQRRUNS.js.map +1 -0
  190. package/dist/{chunk-XGRXQR6T.js → chunk-VQWBUPSJ.js} +2 -2
  191. package/dist/{chunk-TUKGXQ5T.js → chunk-VQYWKCDR.js} +2 -2
  192. package/dist/{chunk-PPQEP4OH.js → chunk-W23JARAQ.js} +2 -2
  193. package/dist/{chunk-YQNNHLCG.js → chunk-WPGR3RW4.js} +2 -2
  194. package/dist/{chunk-474DL7UB.js → chunk-WZYHPAG5.js} +3 -3
  195. package/dist/{chunk-5HYUUFMQ.js → chunk-XCPNH2MG.js} +259 -10
  196. package/dist/chunk-XCPNH2MG.js.map +1 -0
  197. package/dist/{chunk-GQQVEH6V.js → chunk-XM46Y66S.js} +2 -2
  198. package/dist/{chunk-JNSENHV5.js → chunk-YRIFXXMI.js} +3 -3
  199. package/dist/{chunk-TRLOFIQC.js → chunk-YTK5MVNF.js} +2 -2
  200. package/dist/{chunk-VMNCZ627.js → chunk-YTZN2UZO.js} +2 -2
  201. package/dist/chunk-Z4GUX2M6.js +94 -0
  202. package/dist/chunk-Z4GUX2M6.js.map +1 -0
  203. package/dist/{chunk-6ZMNTRU3.js → chunk-ZAEPD4C2.js} +2 -2
  204. package/dist/{chunk-KQW3YGEN.js → chunk-ZRMMXWYI.js} +2 -2
  205. package/dist/{chunk-P4ZAEYKG.js → chunk-ZX3AYNNV.js} +6 -3
  206. package/dist/chunk-ZX3AYNNV.js.map +1 -0
  207. package/dist/{chunk-MCRVQ5YQ.js → chunk-ZZCR2QYL.js} +2 -2
  208. package/dist/{cli-BNg-TAlz.d.ts → cli-BWri5-am.d.ts} +5 -5
  209. package/dist/cli.d.ts +18 -16
  210. package/dist/cli.js +80 -79
  211. package/dist/coding/export-okf-codegraph.d.ts +1 -1
  212. package/dist/coding/export-okf-codegraph.js +15 -15
  213. package/dist/coding/pre-action-gate.d.ts +1 -1
  214. package/dist/compounding/engine.d.ts +2 -2
  215. package/dist/compounding/engine.js +16 -16
  216. package/dist/compounding/preference-consolidator.d.ts +1 -1
  217. package/dist/compression-optimizer.d.ts +1 -1
  218. package/dist/config.d.ts +1 -1
  219. package/dist/config.js +6 -5
  220. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  221. package/dist/connectors/codex-materialize-runner.js +16 -16
  222. package/dist/connectors/codex-materialize.d.ts +1 -1
  223. package/dist/connectors/index.d.ts +1 -1
  224. package/dist/connectors/index.js +16 -16
  225. package/dist/consolidation-provenance-check.d.ts +2 -2
  226. package/dist/consolidation-undo.d.ts +2 -2
  227. package/dist/contradiction/index.d.ts +6 -5
  228. package/dist/converge-config.d.ts +1 -1
  229. package/dist/convergence-refresh.d.ts +2 -2
  230. package/dist/convergence-refresh.js +18 -18
  231. package/dist/conversation-index/backend.d.ts +1 -1
  232. package/dist/conversation-index/chunker.d.ts +1 -1
  233. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  234. package/dist/conversation-index/indexer.d.ts +1 -1
  235. package/dist/conversation-index/search.d.ts +1 -1
  236. package/dist/corpus-watermark.d.ts +1 -1
  237. package/dist/corpus-watermark.js +18 -18
  238. package/dist/cross-lingual-recall.d.ts +1 -1
  239. package/dist/day-summary.d.ts +1 -1
  240. package/dist/deep-recall-http-glue.d.ts +16 -14
  241. package/dist/deep-recall-http-glue.js +2 -2
  242. package/dist/deep-recall-mcp-tools.d.ts +16 -14
  243. package/dist/deep-recall-policy-llm.d.ts +4 -3
  244. package/dist/deep-recall-policy-llm.js +3 -3
  245. package/dist/deep-recall-seeds.d.ts +1 -1
  246. package/dist/delinearize.d.ts +1 -1
  247. package/dist/dependency-propagation-config.d.ts +1 -1
  248. package/dist/{dependency-propagation-delivery-Cq1ekOwV.d.ts → dependency-propagation-delivery-ueZlKTQB.d.ts} +1 -1
  249. package/dist/direct-answer-wiring.d.ts +1 -1
  250. package/dist/direct-answer.d.ts +1 -1
  251. package/dist/embedding-fallback.d.ts +1 -1
  252. package/dist/enrichment/index.d.ts +1 -1
  253. package/dist/entity-origin-fields.d.ts +1 -1
  254. package/dist/entity-retrieval.d.ts +2 -2
  255. package/dist/entity-retrieval.js +16 -16
  256. package/dist/entity-schema.d.ts +1 -1
  257. package/dist/episodic-context.d.ts +1 -1
  258. package/dist/eval-trajectory-contracts.d.ts +1 -1
  259. package/dist/eval-trajectory-store.d.ts +1 -1
  260. package/dist/eval-trajectory.d.ts +1 -1
  261. package/dist/explicit-capture.d.ts +13 -12
  262. package/dist/external-wiki-access.d.ts +16 -14
  263. package/dist/external-wiki-access.js +40 -40
  264. package/dist/external-wiki-collection-registration.d.ts +1 -1
  265. package/dist/external-wiki-collection.d.ts +1 -1
  266. package/dist/external-wiki-mcp-tools.d.ts +16 -14
  267. package/dist/extraction-error-classification.d.ts +14 -3
  268. package/dist/extraction-error-classification.js +5 -3
  269. package/dist/extraction-faithfulness.d.ts +4 -3
  270. package/dist/extraction-faithfulness.js +3 -3
  271. package/dist/extraction-judge-telemetry.d.ts +4 -3
  272. package/dist/extraction-judge-training.d.ts +4 -3
  273. package/dist/extraction-judge.d.ts +4 -3
  274. package/dist/extraction-judge.js +3 -3
  275. package/dist/extraction-liveness.d.ts +1 -1
  276. package/dist/extraction-normalization.d.ts +1 -1
  277. package/dist/extraction-prompt.d.ts +1 -1
  278. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  279. package/dist/extraction-source-grounding.d.ts +1 -1
  280. package/dist/extraction-span-config.d.ts +1 -1
  281. package/dist/extraction-span-materialize.d.ts +1 -1
  282. package/dist/extraction.d.ts +4 -4
  283. package/dist/extraction.js +26 -24
  284. package/dist/fallback-llm-codex-subscription.d.ts +52 -7
  285. package/dist/fallback-llm-codex-subscription.js +17 -1
  286. package/dist/fallback-llm.d.ts +25 -28
  287. package/dist/fallback-llm.js +4 -3
  288. package/dist/{generic-recall-paths-BcySh_f9.d.ts → generic-recall-paths-CpyVmA88.d.ts} +1 -1
  289. package/dist/graph-append-error.d.ts +1 -1
  290. package/dist/graph-dashboard-diff.d.ts +1 -1
  291. package/dist/graph-dashboard-key.d.ts +1 -1
  292. package/dist/graph-dashboard-parser.d.ts +1 -1
  293. package/dist/graph-edge-reinforcement.d.ts +1 -1
  294. package/dist/graph-jsonl.d.ts +1 -1
  295. package/dist/graph-path-reconstruction.d.ts +1 -1
  296. package/dist/graph-path-scoring.d.ts +1 -1
  297. package/dist/graph-snapshot.d.ts +1 -1
  298. package/dist/graph.d.ts +1 -1
  299. package/dist/harmonic-retrieval.js +1 -1
  300. package/dist/importance.d.ts +1 -1
  301. package/dist/importers/index.d.ts +1 -1
  302. package/dist/importers/test-utils.d.ts +1 -1
  303. package/dist/in-flight-reads.d.ts +1 -1
  304. package/dist/{index-DWOb4wz9.d.ts → index-BvUA4S7M.d.ts} +3 -3
  305. package/dist/index.d.ts +80 -40
  306. package/dist/index.js +140 -115
  307. package/dist/intent.d.ts +1 -1
  308. package/dist/lcm/engine.d.ts +1 -1
  309. package/dist/lcm/engine.js +2 -2
  310. package/dist/lcm/index.d.ts +1 -1
  311. package/dist/lcm/index.js +7 -7
  312. package/dist/lcm/tools.d.ts +1 -1
  313. package/dist/lifecycle.d.ts +1 -1
  314. package/dist/live-connectors-runner.d.ts +1 -1
  315. package/dist/local-llm-BsJGulur.d.ts +247 -0
  316. package/dist/local-llm-config.d.ts +4 -1
  317. package/dist/local-llm-config.js +4 -2
  318. package/dist/local-llm-helpers.d.ts +18 -69
  319. package/dist/local-llm-helpers.js +1 -1
  320. package/dist/local-llm.d.ts +3 -170
  321. package/dist/local-llm.js +2 -2
  322. package/dist/local-model-endpoint.d.ts +1 -1
  323. package/dist/location/index.d.ts +3 -3
  324. package/dist/location/index.js +18 -18
  325. package/dist/maintenance/memory-governance.d.ts +1 -1
  326. package/dist/maintenance/memory-governance.js +16 -16
  327. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  328. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +16 -16
  329. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  330. package/dist/maintenance/rebuild-memory-projection.js +17 -17
  331. package/dist/{maintenance-CW9wCzMP.d.ts → maintenance-CYubtIRr.d.ts} +9 -3
  332. package/dist/mcp-memory-inspector-app.d.ts +16 -14
  333. package/dist/memory-action-policy.d.ts +1 -1
  334. package/dist/memory-cache.d.ts +1 -1
  335. package/dist/memory-controller.d.ts +1 -1
  336. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  337. package/dist/memory-projection-store.d.ts +1 -1
  338. package/dist/memory-provenance.d.ts +1 -1
  339. package/dist/memory-snapshot.d.ts +1 -1
  340. package/dist/memory-subject-cli.d.ts +16 -14
  341. package/dist/memory-subject.d.ts +16 -14
  342. package/dist/memory-worth-outcomes.d.ts +2 -2
  343. package/dist/models-json.d.ts +1 -1
  344. package/dist/namespaces/migrate.d.ts +3 -3
  345. package/dist/namespaces/migrate.js +17 -17
  346. package/dist/namespaces/principal.d.ts +1 -1
  347. package/dist/namespaces/search.d.ts +12 -1
  348. package/dist/namespaces/search.js +9 -9
  349. package/dist/namespaces/storage.d.ts +3 -3
  350. package/dist/namespaces/storage.js +16 -16
  351. package/dist/native-knowledge.d.ts +1 -1
  352. package/dist/offline-sync-impression-drain.d.ts +1 -1
  353. package/dist/operator-doctor-corpus.d.ts +1 -1
  354. package/dist/operator-doctor-corpus.js +19 -19
  355. package/dist/operator-doctor-replica.d.ts +1 -1
  356. package/dist/operator-toolkit.d.ts +3 -3
  357. package/dist/operator-toolkit.js +30 -29
  358. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  359. package/dist/orchestration/maintenance.d.ts +4 -4
  360. package/dist/orchestration/maintenance.js +27 -27
  361. package/dist/{orchestrator-DocO0_hw.d.ts → orchestrator-BWDRJ_0d.d.ts} +37 -13
  362. package/dist/orchestrator.d.ts +13 -12
  363. package/dist/orchestrator.js +110 -106
  364. package/dist/patterns-cli.d.ts +1 -1
  365. package/dist/{pipeline-CiYcqqhl.d.ts → pipeline-7JMn2yMH.d.ts} +1 -1
  366. package/dist/policy-runtime.d.ts +1 -1
  367. package/dist/proactive-contention.d.ts +2 -2
  368. package/dist/provenance.d.ts +1 -1
  369. package/dist/{public-http-C0FoTiL_.d.ts → public-http-CJWs3mo9.d.ts} +1 -1
  370. package/dist/{qmd-qXD4vatU.d.ts → qmd-CxCH9G9m.d.ts} +2 -2
  371. package/dist/qmd-preflight.d.ts +2 -2
  372. package/dist/qmd-recall-cache.d.ts +1 -1
  373. package/dist/qmd.d.ts +2 -2
  374. package/dist/qmd.js +2 -2
  375. package/dist/recall-concurrency-config.d.ts +1 -1
  376. package/dist/recall-disclosure-escalation.d.ts +1 -1
  377. package/dist/recall-explain-renderer.d.ts +1 -1
  378. package/dist/recall-explain-renderer.js +3 -3
  379. package/dist/recall-memory-map.d.ts +1 -1
  380. package/dist/recall-navigate-access.d.ts +1 -1
  381. package/dist/recall-navigate-access.js +2 -2
  382. package/dist/recall-navigate-disclosure.d.ts +1 -1
  383. package/dist/recall-navigate-disclosure.js +1 -1
  384. package/dist/recall-navigate.d.ts +1 -1
  385. package/dist/recall-navigate.js +2 -2
  386. package/dist/recall-planner-llm.d.ts +3 -2
  387. package/dist/recall-planner-llm.js +4 -3
  388. package/dist/recall-planner-llm.js.map +1 -1
  389. package/dist/recall-state-view-admission.d.ts +13 -3
  390. package/dist/recall-state-view-admission.js +8 -8
  391. package/dist/recall-state-view-anchors.d.ts +85 -0
  392. package/dist/recall-state-view-anchors.js +21 -0
  393. package/dist/recall-state-view-anchors.js.map +1 -0
  394. package/dist/recall-state-view-inject.js +2 -2
  395. package/dist/recall-state-view-render.js +2 -2
  396. package/dist/recall-state-view-widen.js +2 -2
  397. package/dist/recall-state-view-wire.js +3 -3
  398. package/dist/recall-state-view.d.ts +38 -1
  399. package/dist/recall-state-view.js +11 -3
  400. package/dist/recall-state.d.ts +1 -1
  401. package/dist/recall-tag-filter.d.ts +1 -1
  402. package/dist/recall-timings.d.ts +1 -1
  403. package/dist/recall-xray-cli.d.ts +1 -1
  404. package/dist/recall-xray-cli.js +4 -4
  405. package/dist/recall-xray-renderer.d.ts +1 -1
  406. package/dist/recall-xray-renderer.js +3 -3
  407. package/dist/recall-xray.d.ts +1 -1
  408. package/dist/recall-xray.js +2 -2
  409. package/dist/reconcile/cursor.d.ts +1 -1
  410. package/dist/reconcile/manifest.d.ts +1 -1
  411. package/dist/reconcile/plan.d.ts +1 -1
  412. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  413. package/dist/replay/normalizers/claude.d.ts +1 -1
  414. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  415. package/dist/replay/normalizers/shared.d.ts +1 -1
  416. package/dist/replay/runner.d.ts +1 -1
  417. package/dist/replay/types.d.ts +1 -1
  418. package/dist/replica-divergence.d.ts +1 -1
  419. package/dist/replica-peers-config.d.ts +1 -1
  420. package/dist/resolve-auth-token.d.ts +1 -1
  421. package/dist/resume-bundles.js +7 -6
  422. package/dist/retrieval-agents.d.ts +2 -2
  423. package/dist/retrieval-tiers.d.ts +1 -1
  424. package/dist/routing/engine.d.ts +1 -1
  425. package/dist/routing/store.d.ts +1 -1
  426. package/dist/salvage-envelope.d.ts +1 -1
  427. package/dist/{scope-profiles-BT9rqC3w.d.ts → scope-profiles-BGAUqhBR.d.ts} +1 -1
  428. package/dist/search/embed-helper.d.ts +1 -1
  429. package/dist/search/factory.d.ts +1 -1
  430. package/dist/search/factory.js +8 -8
  431. package/dist/search/index.d.ts +1 -1
  432. package/dist/search/index.js +12 -12
  433. package/dist/search/lancedb-backend.d.ts +1 -1
  434. package/dist/search/lancedb-backend.js +2 -2
  435. package/dist/search/meilisearch-backend.d.ts +1 -1
  436. package/dist/search/meilisearch-backend.js +2 -2
  437. package/dist/search/noop-backend.d.ts +1 -1
  438. package/dist/search/orama-backend.d.ts +1 -1
  439. package/dist/search/orama-backend.js +2 -2
  440. package/dist/search/port.d.ts +2 -2
  441. package/dist/search/port.js +1 -1
  442. package/dist/search/remote-backend.d.ts +1 -1
  443. package/dist/search/remote-backend.js +2 -2
  444. package/dist/{semantic-consolidation-CmZi7thY.d.ts → semantic-consolidation-CCeRD9pV.d.ts} +1 -1
  445. package/dist/semantic-consolidation.d.ts +2 -2
  446. package/dist/semantic-consolidation.js +17 -17
  447. package/dist/semantic-rule-promotion.js +16 -16
  448. package/dist/semantic-rule-verifier.d.ts +1 -1
  449. package/dist/semantic-rule-verifier.js +16 -16
  450. package/dist/{service-CLkA7AQB.d.ts → service-BwpzRduk.d.ts} +2 -2
  451. package/dist/session-observer-bands.d.ts +1 -1
  452. package/dist/session-observer-state.d.ts +1 -1
  453. package/dist/shared-context/manager.d.ts +1 -1
  454. package/dist/signal.d.ts +1 -1
  455. package/dist/source-agent-qualifier.d.ts +1 -1
  456. package/dist/source-agent-qualifier.js +19 -19
  457. package/dist/standup/build.js +16 -16
  458. package/dist/{storage-wvX01lht.d.ts → storage-BprAGBG0.d.ts} +2 -1
  459. package/dist/storage.d.ts +2 -2
  460. package/dist/storage.js +15 -15
  461. package/dist/subject-config.d.ts +1 -1
  462. package/dist/summarizer.d.ts +1 -1
  463. package/dist/summarizer.js +5 -5
  464. package/dist/summary-snapshot.d.ts +1 -1
  465. package/dist/support-passport/index.d.ts +18 -17
  466. package/dist/support-passport/index.js +42 -42
  467. package/dist/task-llm-config.d.ts +16 -0
  468. package/dist/task-llm-config.js +12 -0
  469. package/dist/task-llm-config.js.map +1 -0
  470. package/dist/temporal-supersession.d.ts +2 -2
  471. package/dist/temporal-timeline-recall.d.ts +1 -1
  472. package/dist/temporal-validity.d.ts +1 -1
  473. package/dist/threading.d.ts +1 -1
  474. package/dist/tier-migration.d.ts +2 -2
  475. package/dist/tier-routing.d.ts +1 -1
  476. package/dist/topics.d.ts +1 -1
  477. package/dist/transcript.d.ts +1 -1
  478. package/dist/transfer/export-okf.d.ts +1 -1
  479. package/dist/transfer/export-okf.js +16 -16
  480. package/dist/trust-score-stage.d.ts +1 -1
  481. package/dist/trust-score.d.ts +1 -1
  482. package/dist/{types-Cyr32ABj.d.ts → types-nJV23pa3.d.ts} +1 -1
  483. package/dist/types.d.ts +1 -1
  484. package/dist/types.js +1 -1
  485. package/dist/utility-runtime.d.ts +1 -1
  486. package/dist/verified-recall.js +16 -16
  487. package/dist/who-knows-cli.d.ts +16 -14
  488. package/dist/who-knows-cli.js +17 -17
  489. package/dist/who-knows.d.ts +16 -14
  490. package/dist/who-knows.js +16 -16
  491. package/dist/write-envelope.d.ts +1 -1
  492. package/package.json +2 -2
  493. package/src/access-category-alias.test.ts +93 -0
  494. package/src/access-offline-manifest.ts +52 -2
  495. package/src/access-schema.ts +9 -4
  496. package/src/activity/config.test.ts +61 -0
  497. package/src/activity/config.ts +40 -1
  498. package/src/activity/timeline/analysis-provider.ts +8 -2
  499. package/src/activity/timeline/analysis-run.test.ts +82 -0
  500. package/src/activity/timeline/publish-cli.test.ts +30 -0
  501. package/src/activity/timeline/publish-cli.ts +7 -0
  502. package/src/activity/timeline/query.ts +8 -1
  503. package/src/activity/timeline/regenerate.test.ts +82 -2
  504. package/src/activity/timeline/regenerate.ts +7 -1
  505. package/src/activity/vault-frontmatter.test.ts +99 -1
  506. package/src/activity/vault-frontmatter.ts +131 -0
  507. package/src/activity/vault-publish.ts +6 -0
  508. package/src/activity/vault-publisher.test.ts +172 -0
  509. package/src/activity/vault-publisher.ts +69 -15
  510. package/src/activity/vault-region.test.ts +7 -2
  511. package/src/activity/vault-region.ts +7 -3
  512. package/src/background-generation-config.ts +32 -6
  513. package/src/background-generation.test.ts +10 -1
  514. package/src/cli/timeline-publish-commands.ts +9 -0
  515. package/src/config.test.ts +170 -43
  516. package/src/config.ts +17 -5
  517. package/src/extraction-error-classification.ts +36 -1
  518. package/src/extraction-timeout.test.ts +110 -1
  519. package/src/extraction.test.ts +19 -1
  520. package/src/extraction.ts +23 -21
  521. package/src/fallback-llm-codex-subscription.ts +193 -7
  522. package/src/fallback-llm-parse-failure.test.ts +156 -0
  523. package/src/fallback-llm.test.ts +58 -0
  524. package/src/fallback-llm.ts +187 -186
  525. package/src/index.ts +1 -0
  526. package/src/local-llm-config.ts +11 -10
  527. package/src/local-llm-headers-timeout.test.ts +30 -0
  528. package/src/local-llm-helpers.ts +28 -0
  529. package/src/local-llm.ts +8 -19
  530. package/src/namespaces/search.test.ts +51 -1
  531. package/src/namespaces/search.ts +48 -3
  532. package/src/orchestration/extraction-persist-promotion.test.ts +228 -2
  533. package/src/orchestration/extraction-persist-promotion.ts +17 -14
  534. package/src/orchestration/orchestrator-helpers.test.ts +104 -0
  535. package/src/orchestration/orchestrator-init.ts +366 -106
  536. package/src/orchestration/recall-internal.ts +85 -74
  537. package/src/orchestration/recall-rerank-coordinator.ts +41 -4
  538. package/src/orchestration/recall-search-pipeline.ts +25 -18
  539. package/src/orchestration/recall-state-view-pipeline.test.ts +89 -0
  540. package/src/orchestration/semantic-merge-promotion-payload.ts +62 -6
  541. package/src/orchestration/startup-collection-checks.ts +85 -0
  542. package/src/orchestrator-flush.test.ts +7 -0
  543. package/src/orchestrator-init.test.ts +1539 -0
  544. package/src/orchestrator.ts +7 -0
  545. package/src/qmd.ts +21 -10
  546. package/src/recall-rerank-coordinator.test.ts +153 -0
  547. package/src/recall-state-view-admission.ts +11 -1
  548. package/src/recall-state-view-anchors.ts +163 -0
  549. package/src/recall-state-view-cron-intent.test.ts +268 -0
  550. package/src/recall-state-view-widen.test.ts +14 -5
  551. package/src/recall-state-view-widen.ts +29 -8
  552. package/src/recall-state-view-zero-diff.test.ts +30 -0
  553. package/src/recall-state-view.test.ts +161 -0
  554. package/src/recall-state-view.ts +211 -37
  555. package/src/reconcile-identity-cache.test.ts +82 -1
  556. package/src/search/port.ts +1 -1
  557. package/src/storage/cas-revision-store.test.ts +4 -0
  558. package/src/storage/cas-revision-store.ts +104 -12
  559. package/src/storage-frontmatter-cas.test.ts +19 -17
  560. package/src/summarizer.ts +5 -1
  561. package/src/task-llm-config.test.ts +124 -0
  562. package/src/task-llm-config.ts +88 -0
  563. package/src/testing/subjects/startup-discovery-lifecycle.test.ts +273 -0
  564. package/src/trust-score-recall-paths.test.ts +1 -1
  565. package/src/types.ts +1 -0
  566. package/dist/chunk-255PC37A.js +0 -120
  567. package/dist/chunk-255PC37A.js.map +0 -1
  568. package/dist/chunk-2MT4ADLQ.js.map +0 -1
  569. package/dist/chunk-3CBI2ZSA.js.map +0 -1
  570. package/dist/chunk-3OYSIVOO.js.map +0 -1
  571. package/dist/chunk-5AERZWJD.js.map +0 -1
  572. package/dist/chunk-5HYUUFMQ.js.map +0 -1
  573. package/dist/chunk-6H2G7RFT.js.map +0 -1
  574. package/dist/chunk-7S53BPTU.js.map +0 -1
  575. package/dist/chunk-ACY4ZPF7.js.map +0 -1
  576. package/dist/chunk-B36GUU6T.js.map +0 -1
  577. package/dist/chunk-BJEJUOGM.js.map +0 -1
  578. package/dist/chunk-BLDBT6HZ.js.map +0 -1
  579. package/dist/chunk-CWTCMZGE.js.map +0 -1
  580. package/dist/chunk-IYKZJVL5.js.map +0 -1
  581. package/dist/chunk-JXN77SGO.js.map +0 -1
  582. package/dist/chunk-LQNRVPTV.js.map +0 -1
  583. package/dist/chunk-MVAQ2WM3.js.map +0 -1
  584. package/dist/chunk-P4ZAEYKG.js.map +0 -1
  585. package/dist/chunk-QHT7MOUF.js.map +0 -1
  586. package/dist/chunk-V6G2PSXA.js.map +0 -1
  587. package/dist/chunk-VELCIWJZ.js.map +0 -1
  588. package/dist/chunk-WKDFJXW5.js.map +0 -1
  589. package/dist/chunk-XWLLFKHM.js.map +0 -1
  590. package/dist/chunk-YFTNZMGR.js.map +0 -1
  591. /package/dist/{auto-sync-RP4C6ZPF.js.map → auto-sync-D6BAPIJV.js.map} +0 -0
  592. /package/dist/{chunk-T32B72QX.js.map → chunk-2SKMZUOW.js.map} +0 -0
  593. /package/dist/{chunk-VHOSM5G4.js.map → chunk-2SNCQHJZ.js.map} +0 -0
  594. /package/dist/{chunk-VV4ZVUE6.js.map → chunk-3QEVOQF5.js.map} +0 -0
  595. /package/dist/{chunk-3N3PBBEH.js.map → chunk-3XPN7AVY.js.map} +0 -0
  596. /package/dist/{chunk-XN6XT6GR.js.map → chunk-46Z3VGWF.js.map} +0 -0
  597. /package/dist/{chunk-2PTNJTBE.js.map → chunk-4CMXI55L.js.map} +0 -0
  598. /package/dist/{chunk-A6CKMIPK.js.map → chunk-7D6SER6A.js.map} +0 -0
  599. /package/dist/{chunk-4B3HBIFX.js.map → chunk-7Z54NXVS.js.map} +0 -0
  600. /package/dist/{chunk-X2NFFBTO.js.map → chunk-A7GQBJP5.js.map} +0 -0
  601. /package/dist/{chunk-NWMUSKED.js.map → chunk-BGRTZOJB.js.map} +0 -0
  602. /package/dist/{chunk-ZEGL7YCC.js.map → chunk-BXIJSPCL.js.map} +0 -0
  603. /package/dist/{chunk-MLWMR2GE.js.map → chunk-BYQX4IOG.js.map} +0 -0
  604. /package/dist/{chunk-ULDBGA5W.js.map → chunk-C5R73BON.js.map} +0 -0
  605. /package/dist/{chunk-BD7JTBYP.js.map → chunk-D7MAYFQP.js.map} +0 -0
  606. /package/dist/{chunk-BRZWWUCJ.js.map → chunk-DFVSJFHK.js.map} +0 -0
  607. /package/dist/{chunk-DPMTLJCT.js.map → chunk-ES5BUPYB.js.map} +0 -0
  608. /package/dist/{chunk-TNSCIPBQ.js.map → chunk-G6NQ3L4T.js.map} +0 -0
  609. /package/dist/{chunk-5N4MZLEH.js.map → chunk-GO5LOHCD.js.map} +0 -0
  610. /package/dist/{chunk-AECJY3GJ.js.map → chunk-GSSDHAYH.js.map} +0 -0
  611. /package/dist/{chunk-JA2QJOAX.js.map → chunk-HJUP3K6L.js.map} +0 -0
  612. /package/dist/{chunk-ZKZFFWLV.js.map → chunk-ICNJ6J46.js.map} +0 -0
  613. /package/dist/{chunk-6EHM2AV7.js.map → chunk-IMBQFHRV.js.map} +0 -0
  614. /package/dist/{chunk-6PRY6CLC.js.map → chunk-IOPIGX7Y.js.map} +0 -0
  615. /package/dist/{chunk-TRHBQVVO.js.map → chunk-IS2IDFJP.js.map} +0 -0
  616. /package/dist/{chunk-R4VAUNNC.js.map → chunk-J4WGTN2N.js.map} +0 -0
  617. /package/dist/{chunk-JPOX2AJB.js.map → chunk-J7FVMLBR.js.map} +0 -0
  618. /package/dist/{chunk-BYZKLEWG.js.map → chunk-JAJIMTFB.js.map} +0 -0
  619. /package/dist/{chunk-OKO57IXB.js.map → chunk-JOP7W24J.js.map} +0 -0
  620. /package/dist/{chunk-YUW66UAH.js.map → chunk-JUDT33RX.js.map} +0 -0
  621. /package/dist/{chunk-UQNYPK7G.js.map → chunk-K4JKAXMO.js.map} +0 -0
  622. /package/dist/{chunk-BV4ZKIZH.js.map → chunk-K75A5XWU.js.map} +0 -0
  623. /package/dist/{chunk-M6HBPLBA.js.map → chunk-KOTG3RXE.js.map} +0 -0
  624. /package/dist/{chunk-OB3XMWX5.js.map → chunk-KVO2BTA4.js.map} +0 -0
  625. /package/dist/{chunk-CBFYCDYO.js.map → chunk-KY236SP5.js.map} +0 -0
  626. /package/dist/{chunk-4BCHFSC7.js.map → chunk-LFVZD5EC.js.map} +0 -0
  627. /package/dist/{chunk-GGAXFTNH.js.map → chunk-LKFVVN7R.js.map} +0 -0
  628. /package/dist/{chunk-4RX5O34R.js.map → chunk-MJC7UKH7.js.map} +0 -0
  629. /package/dist/{chunk-UZZ7SQT3.js.map → chunk-NVVZPBKI.js.map} +0 -0
  630. /package/dist/{chunk-TTSJ7WUC.js.map → chunk-PKUJNICO.js.map} +0 -0
  631. /package/dist/{chunk-QMWKENNK.js.map → chunk-Q4AUIFUA.js.map} +0 -0
  632. /package/dist/{chunk-G43PMSME.js.map → chunk-QE6YVNP5.js.map} +0 -0
  633. /package/dist/{chunk-GT4ZHOKT.js.map → chunk-QPVNK2VE.js.map} +0 -0
  634. /package/dist/{chunk-K5DA5TRG.js.map → chunk-QS5Q5RBV.js.map} +0 -0
  635. /package/dist/{chunk-BX4EOMKT.js.map → chunk-RDLPFM7I.js.map} +0 -0
  636. /package/dist/{chunk-EY5JAWZC.js.map → chunk-RJQAP333.js.map} +0 -0
  637. /package/dist/{chunk-2OGTN37H.js.map → chunk-ROEFLU37.js.map} +0 -0
  638. /package/dist/{chunk-62QIQEUC.js.map → chunk-SFHLQPBF.js.map} +0 -0
  639. /package/dist/{chunk-HVS7TH2Y.js.map → chunk-SUEOG2S4.js.map} +0 -0
  640. /package/dist/{chunk-74AHCL56.js.map → chunk-TEMKBSV6.js.map} +0 -0
  641. /package/dist/{chunk-KDFDXEXZ.js.map → chunk-TO36VPZI.js.map} +0 -0
  642. /package/dist/{chunk-M3MYMWXG.js.map → chunk-V2ZA4YWE.js.map} +0 -0
  643. /package/dist/{chunk-UIOIDW3L.js.map → chunk-VHKXRYQN.js.map} +0 -0
  644. /package/dist/{chunk-GAS7KYC7.js.map → chunk-VKWFNPBH.js.map} +0 -0
  645. /package/dist/{chunk-XGRXQR6T.js.map → chunk-VQWBUPSJ.js.map} +0 -0
  646. /package/dist/{chunk-TUKGXQ5T.js.map → chunk-VQYWKCDR.js.map} +0 -0
  647. /package/dist/{chunk-PPQEP4OH.js.map → chunk-W23JARAQ.js.map} +0 -0
  648. /package/dist/{chunk-YQNNHLCG.js.map → chunk-WPGR3RW4.js.map} +0 -0
  649. /package/dist/{chunk-474DL7UB.js.map → chunk-WZYHPAG5.js.map} +0 -0
  650. /package/dist/{chunk-GQQVEH6V.js.map → chunk-XM46Y66S.js.map} +0 -0
  651. /package/dist/{chunk-JNSENHV5.js.map → chunk-YRIFXXMI.js.map} +0 -0
  652. /package/dist/{chunk-TRLOFIQC.js.map → chunk-YTK5MVNF.js.map} +0 -0
  653. /package/dist/{chunk-VMNCZ627.js.map → chunk-YTZN2UZO.js.map} +0 -0
  654. /package/dist/{chunk-6ZMNTRU3.js.map → chunk-ZAEPD4C2.js.map} +0 -0
  655. /package/dist/{chunk-KQW3YGEN.js.map → chunk-ZRMMXWYI.js.map} +0 -0
  656. /package/dist/{chunk-MCRVQ5YQ.js.map → chunk-ZZCR2QYL.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/summarizer.ts"],"sourcesContent":["import { mkdir, readFile, writeFile, readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { log } from \"./logger.js\";\nimport { LocalLlmClient } from \"./local-llm.js\";\nimport { FallbackLlmClient, fallbackLlmRuntimeContextFromConfig, gatewayTaskChainOptions } from \"./fallback-llm.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { extractJsonCandidates } from \"./json-extract.js\";\nimport {\n completeBackgroundGeneration,\n parseBackgroundGenerationJson,\n} from \"./background-generation.js\";\nimport type { HourlySummary, TranscriptEntry, PluginConfig, GatewayConfig } from \"./types.js\";\nimport type { TranscriptManager } from \"./transcript.js\";\nimport { readSummarySnapshot, upsertSummarySnapshot, writeSummarySnapshot } from \"./summary-snapshot.js\";\nimport { encodeStoragePathSegment, resolveSafeStoragePath } from \"./storage-paths.js\";\nimport { sessionStoragePaths } from \"./session-identity.js\";\nimport { resolveLocalLlmCapabilities } from \"./capabilities.js\";\nimport { resolvePipelineProcessingCapabilities } from \"./capabilities.js\";\n\n// Schema for LLM summary output\nconst HourlySummarySchema = z.object({\n bullets: z.array(z.string().trim().min(1)).min(1).describe(\"3-5 bullet points summarizing the hour's activity\"),\n});\n\ntype HourlySummaryResult = z.infer<typeof HourlySummarySchema>;\n\nconst HourlySummaryExtendedSchema = z.object({\n topics: z.array(z.string()).default([]),\n decisions: z.array(z.string()).default([]),\n actionItems: z.array(z.string()).default([]),\n rejected: z.array(z.string()).default([]),\n});\n\ntype HourlySummaryExtendedResult = z.infer<typeof HourlySummaryExtendedSchema>;\n\ntype HourlySummaryExtendedMeta = {\n userTurns: number;\n assistantTurns: number;\n toolCalls: number;\n toolCounts: Record<string, number>;\n};\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Outcome stats of one `runHourly` pass (issue #2783). The summarizer must\n * not report success on empty work: an empty or stale transcript store is\n * the delegate-mode starvation signature, and callers surface these counts\n * and the staleness flag as a distinct warning instead of a bare ok.\n */\nexport interface HourlySummarizerRunStats {\n sessionsConsidered: number;\n sessionsWithEntries: number;\n summariesWritten: number;\n /** True when the newest transcript entry across the store is older than STALE_STORE_MS. */\n staleStore: boolean;\n /** ISO timestamp of the newest transcript entry seen by the scan, when any exist. */\n newestEntryTimestamp: string | null;\n /** True when the transcript scan itself FAILED (unreadable store) — distinct from an empty store. */\n scanFailed: boolean;\n}\n\n/** A store whose newest entry is older than this is considered stale (starvation signal, issue #2783). */\nconst STALE_STORE_MS = 2 * 60 * 60 * 1000;\n\n/**\n * Interpret one {@link HourlySummarizerRunStats} into the operator-facing\n * message/warning (issue #2783). Every degraded shape — failed scan, empty\n * store, backend-down, stale store — is DISTINCT from success; monitoring\n * alerts on `warning`, never on `ok` (ok only means \"the run completed\").\n */\nexport function summarizeHourlyStatus(stats: HourlySummarizerRunStats): {\n message: string;\n warning?: string;\n} {\n if (stats.scanFailed) {\n return {\n message:\n \"Hourly summarization completed, but the transcript store scan FAILED (unreadable directory or I/O error). Investigate the daemon's memoryDir.\",\n warning: \"transcript store scan failed\",\n };\n }\n if (stats.sessionsConsidered === 0) {\n return {\n message:\n \"Hourly summarization completed, but the transcript store is empty — no sessions found. If turns are ingested via observe, transcript persistence may be disabled or failing.\",\n warning: \"transcript store is empty\",\n };\n }\n if (stats.sessionsWithEntries > 0 && stats.summariesWritten === 0) {\n return {\n message: `Hourly summarization found ${stats.sessionsWithEntries} session(s) with transcript entries but wrote no summaries — the summarizer backend may be down.`,\n warning: \"sessions with entries produced no summaries\",\n };\n }\n if (stats.sessionsWithEntries === 0 && stats.staleStore) {\n return {\n message: `Hourly summarization completed with no transcript entries for the target hour, and the store looks stale (newest entry ${stats.newestEntryTimestamp ?? \"unknown\"}).`,\n warning: \"no transcript entries for the target hour and no new entries recently\",\n };\n }\n return {\n message: `Hourly summarization completed: ${stats.summariesWritten} summar${stats.summariesWritten === 1 ? \"y\" : \"ies\"} written across ${stats.sessionsWithEntries} session${stats.sessionsWithEntries === 1 ? \"\" : \"s\"} with transcript entries.`,\n };\n}\n\nexport class HourlySummarizer {\n private summariesDir: string;\n private config: PluginConfig;\n private localLlm: LocalLlmClient;\n private fallbackLlm: FallbackLlmClient;\n private modelRegistry: ModelRegistry;\n private transcript?: TranscriptManager;\n\n constructor(\n config: PluginConfig,\n gatewayConfig?: GatewayConfig,\n modelRegistry?: ModelRegistry,\n transcript?: TranscriptManager\n ) {\n this.config = config;\n this.summariesDir = path.join(config.memoryDir, \"summaries\", \"hourly\");\n this.modelRegistry = modelRegistry ?? new ModelRegistry(config.memoryDir);\n this.transcript = transcript;\n\n // Initialize local LLM client with shared model registry\n this.localLlm = new LocalLlmClient(config, this.modelRegistry);\n\n // Initialize fallback client with gateway config\n this.fallbackLlm = new FallbackLlmClient(gatewayConfig, fallbackLlmRuntimeContextFromConfig(config));\n\n if (\n !gatewayConfig?.agents?.defaults?.model?.primary &&\n !resolveLocalLlmCapabilities(config).localLlm &&\n config.modelSource !== \"gateway\"\n ) {\n log.warn(\"no gateway default AI and local LLM disabled — hourly summarization disabled\");\n }\n }\n\n private get useGatewayModelSource(): boolean {\n return this.config.modelSource === \"gateway\";\n }\n\n private get shouldUseLocalLlm(): boolean {\n return resolveLocalLlmCapabilities(this.config).localLlm && !this.useGatewayModelSource;\n }\n\n private withGatewayAgent(\n options: import(\"./fallback-llm.js\").FallbackLlmOptions\n ): import(\"./fallback-llm.js\").FallbackLlmOptions {\n if (!this.useGatewayModelSource) return options;\n // Shared resolution (taskModelChain > gatewayAgentId) — gotcha #22. Issue #1365.\n return { ...options, ...gatewayTaskChainOptions(this.config) };\n }\n\n async initialize(): Promise<void> {\n await mkdir(this.summariesDir, { recursive: true });\n log.info(\"hourly summarizer initialized\");\n }\n\n private async summarySessionDir(sessionKey: string): Promise<string> {\n return resolveSafeStoragePath(this.summariesDir, encodeStoragePathSegment(sessionKey, \"session\"));\n }\n\n private async legacySummarySessionDir(sessionKey: string): Promise<string | null> {\n if (sessionKey.includes(\"\\0\")) return null;\n try {\n return await resolveSafeStoragePath(this.summariesDir, sessionKey);\n } catch {\n return null;\n }\n }\n\n private summaryDateString(hour: string): string {\n const dateStr = hour.slice(0, 10);\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(dateStr)) {\n throw new Error(`invalid hourly summary timestamp: ${hour}`);\n }\n return dateStr;\n }\n\n // Generate summary for a specific hour and session\n async generateSummary(\n sessionKey: string,\n hourStart: Date,\n entries: TranscriptEntry[]\n ): Promise<HourlySummary | null> {\n if (entries.length === 0) return null;\n\n // Format entries for the LLM\n const conversation = entries.map((e) => `[${e.role}] ${e.content}`).join(\"\\n\\n\");\n\n if (resolvePipelineProcessingCapabilities(this.config).hourlySummariesExtended) {\n const extended = await this.generateExtended(sessionKey, hourStart, conversation, entries);\n if (!extended) return null;\n const meta: HourlySummaryExtendedMeta = {\n userTurns: entries.filter((e) => e.role === \"user\").length,\n assistantTurns: entries.filter((e) => e.role === \"assistant\").length,\n toolCalls: extended._meta.toolCalls,\n toolCounts: extended._meta.toolCounts,\n };\n // Keep HourlySummary surface stable; encode \"topics\" as bullets for recall injection.\n const base: HourlySummary = {\n hour: hourStart.toISOString(),\n sessionKey,\n bullets: extended.topics.length > 0 ? extended.topics.slice(0, 5) : [\"(summary generated)\"],\n turnCount: entries.length,\n generatedAt: new Date().toISOString(),\n };\n const withExtras = base as any;\n withExtras._extended = extended;\n withExtras._extendedMeta = meta;\n return base;\n }\n\n const hourIso = hourStart.toISOString();\n const startTime = Date.now();\n\n if (this.config.backgroundGeneration) {\n try {\n const text = await completeBackgroundGeneration(this.config, [\n { role: \"system\", content: \"You are a conversation summarization system. Output valid JSON only.\" },\n { role: \"user\", content: `Summarize this conversation:\\n\\n${conversation}` },\n ]);\n const parsed = parseBackgroundGenerationJson(text, (value) => HourlySummarySchema.parse(value));\n if (parsed) {\n return {\n hour: hourIso,\n sessionKey,\n bullets: parsed.bullets,\n turnCount: entries.length,\n generatedAt: new Date().toISOString(),\n };\n }\n } catch {\n log.info(\"summary generation: background generation unavailable, continuing\");\n }\n }\n\n // Try local LLM first if enabled\n if (this.shouldUseLocalLlm) {\n try {\n const localResult = await this.generateWithLocalLlm(conversation);\n if (localResult) {\n const durationMs = Date.now() - startTime;\n log.debug(`generated hourly summary for ${sessionKey} at ${hourIso} in ${durationMs}ms using local LLM`);\n return {\n hour: hourIso,\n sessionKey,\n bullets: localResult.bullets,\n turnCount: entries.length,\n generatedAt: new Date().toISOString(),\n };\n }\n // Local failed, fall back if allowed\n if (!this.config.localLlmFallback) {\n log.warn(\"summary generation: local LLM failed and fallback disabled\");\n return null;\n }\n log.info(\"summary generation: local LLM unavailable, falling back to gateway default AI\");\n } catch (err) {\n if (!this.config.localLlmFallback) {\n log.warn(\"summary generation: local LLM error and fallback disabled:\", err);\n return null;\n }\n log.info(\"summary generation: local LLM error, falling back to gateway default AI:\", err);\n }\n }\n\n // Fall back to gateway's default AI\n log.info(\"summary generation: falling back to gateway default AI\");\n\n try {\n const messages = [\n {\n role: \"system\" as const,\n content: `You are a conversation summarization system. Summarize the following conversation transcript into 3-5 concise bullet points.\n\nGuidelines:\n- Focus on what was accomplished, decided, or discussed\n- Include specific topics, projects, or entities mentioned\n- Note any significant user requests or agent actions\n- Keep bullets brief but informative (1-2 sentences each)\n- Skip trivial greetings or meta-conversation\n- Use present tense for ongoing work, past for completed items\n\nRespond with valid JSON matching this schema:\n{\n \"bullets\": [\"bullet 1\", \"bullet 2\", \"bullet 3\"]\n}`,\n },\n { role: \"user\" as const, content: `Summarize this conversation:\\n\\n${conversation}` },\n ];\n\n const result = await this.fallbackLlm.parseWithSchema(\n messages,\n HourlySummarySchema,\n this.withGatewayAgent({ temperature: 0.3, maxTokens: 8192 })\n );\n\n const durationMs = Date.now() - startTime;\n\n if (result) {\n log.debug(`generated hourly summary for ${sessionKey} at ${hourIso} in ${durationMs}ms via fallback`);\n return {\n hour: hourIso,\n sessionKey,\n bullets: result.bullets,\n turnCount: entries.length,\n generatedAt: new Date().toISOString(),\n };\n }\n\n log.warn(\"summary generation fallback returned no parsed output\");\n return null;\n } catch (err) {\n log.error(\"summary generation fallback failed\", err);\n return null;\n }\n }\n\n private async generateExtended(\n sessionKey: string,\n hourStart: Date,\n conversation: string,\n entries: TranscriptEntry[]\n ): Promise<(HourlySummaryExtendedResult & { _meta: HourlySummaryExtendedMeta }) | null> {\n const hourIso = hourStart.toISOString();\n const startTime = Date.now();\n\n const hourEnd = new Date(hourStart.getTime() + 60 * 60 * 1000);\n let toolCounts: Record<string, number> = {};\n if (this.config.hourlySummariesIncludeToolStats && this.transcript) {\n const uses = await this.transcript.readToolUse(sessionKey, hourStart, hourEnd);\n for (const u of uses) toolCounts[u.tool] = (toolCounts[u.tool] ?? 0) + 1;\n }\n\n const sys = `You are a conversation summarization system.\\n\\nSummarize the hour into structured sections.\\n\\nReturn valid JSON matching:\\n{\\n \\\"topics\\\": [\\\"...\\\"],\\n \\\"decisions\\\": [\\\"...\\\"],\\n \\\"actionItems\\\": [\\\"...\\\"],\\n \\\"rejected\\\": [\\\"...\\\"]\\n}\\n\\nGuidelines:\\n- Prefer concrete topics and decisions.\\n- Action items should be imperative.\\n- Rejected ideas are things that were explicitly discarded or reversed.\\n- If there are none for a section, return an empty array.\\n`;\n\n const toolStatsLine =\n Object.keys(toolCounts).length > 0\n ? `Tools used (counts): ${Object.entries(toolCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([k, v]) => `${k}=${v}`)\n .join(\", \")}\\n\\n`\n : \"\";\n const userTurns = entries.filter((e) => e.role === \"user\").length;\n const assistantTurns = entries.filter((e) => e.role === \"assistant\").length;\n const toolCalls = Object.values(toolCounts).reduce((a, b) => a + b, 0);\n const statsLine = `Stats: userTurns=${userTurns}, assistantTurns=${assistantTurns}, toolCalls=${toolCalls}\\n\\n`;\n\n const user = `Hour: ${hourIso}\\nSession: ${sessionKey}\\n\\n${statsLine}${toolStatsLine}Conversation:\\n${conversation}\\n`;\n\n // Try local LLM first if enabled\n if (this.shouldUseLocalLlm) {\n try {\n const contextSizes = this.modelRegistry.calculateContextSizes(\n this.config.localLlmModel,\n this.config.localLlmMaxContext\n );\n const truncated =\n user.length > contextSizes.maxInputChars\n ? user.slice(0, contextSizes.maxInputChars) + \"\\n\\n[truncated]\"\n : user;\n const response = await this.localLlm.chatCompletion(\n [\n { role: \"system\", content: \"Output valid JSON only.\" },\n { role: \"user\", content: sys + \"\\n\\n\" + truncated },\n ],\n {\n temperature: 0.2,\n maxTokens: contextSizes.maxOutputTokens,\n operation: \"hourly_summary_extended\",\n priority: \"background\",\n }\n );\n if (response?.content) {\n const content = response.content.trim();\n for (const candidate of extractJsonCandidates(content)) {\n try {\n const parsed = JSON.parse(candidate);\n const result = HourlySummaryExtendedSchema.parse(parsed);\n log.debug(\n `generated extended hourly summary for ${sessionKey} at ${hourIso} in ${Date.now() - startTime}ms (local)`\n );\n return { ...result, _meta: { userTurns, assistantTurns, toolCalls, toolCounts } };\n } catch {\n // keep trying candidates\n }\n }\n }\n } catch (err) {\n if (!this.config.localLlmFallback) return null;\n log.info(\"extended summary: local failed, falling back:\", err);\n }\n }\n\n try {\n const result = await this.fallbackLlm.parseWithSchema(\n [\n { role: \"system\" as const, content: sys },\n { role: \"user\" as const, content: user },\n ],\n HourlySummaryExtendedSchema,\n this.withGatewayAgent({ temperature: 0.2, maxTokens: 2048 })\n );\n if (result) {\n log.debug(\n `generated extended hourly summary for ${sessionKey} at ${hourIso} in ${Date.now() - startTime}ms (fallback)`\n );\n return { ...result, _meta: { userTurns, assistantTurns, toolCalls, toolCounts } };\n }\n return null;\n } catch (err) {\n log.error(\"extended summary generation failed\", err);\n return null;\n }\n }\n\n /**\n * Generate summary using local LLM with JSON mode.\n * Uses dynamic context sizing based on model capabilities.\n */\n private async generateWithLocalLlm(conversation: string): Promise<HourlySummaryResult | null> {\n // Get dynamic context sizes based on model capabilities\n const contextSizes = this.modelRegistry.calculateContextSizes(\n this.config.localLlmModel,\n this.config.localLlmMaxContext\n );\n log.debug(`Summarizer model context: ${contextSizes.description}`);\n\n const maxConversationChars = contextSizes.maxInputChars;\n const truncatedConversation =\n conversation.length > maxConversationChars\n ? conversation.slice(0, maxConversationChars) + \"\\n\\n[truncated]\"\n : conversation;\n\n const instructions = `You are a conversation summarization system. Summarize the following conversation transcript into 3-5 concise bullet points.\n\nGuidelines:\n- Focus on what was accomplished, decided, or discussed\n- Include specific topics, projects, or entities mentioned\n- Note any significant user requests or agent actions\n- Keep bullets brief but informative (1-2 sentences each)\n- Skip trivial greetings or meta-conversation\n- Use present tense for ongoing work, past for completed items\n\nRespond with valid JSON matching this schema:\n{\n \"bullets\": [\"bullet 1\", \"bullet 2\", \"bullet 3\"]\n}`;\n\n const fullPrompt = `${instructions}\\n\\nConversation to summarize:\\n${truncatedConversation}`;\n\n const response = await this.localLlm.chatCompletion(\n [\n { role: \"system\", content: \"You are a conversation summarization system. Output valid JSON only.\" },\n { role: \"user\", content: fullPrompt },\n ],\n {\n temperature: 0.3,\n maxTokens: contextSizes.maxOutputTokens,\n operation: \"hourly_summary\",\n priority: \"background\",\n }\n );\n\n if (!response?.content) {\n return null;\n }\n\n try {\n // Parse JSON response\n const content = response.content.trim();\n for (const candidate of extractJsonCandidates(content)) {\n try {\n const parsed = JSON.parse(candidate);\n return HourlySummarySchema.parse(parsed);\n } catch {\n // keep trying candidates\n }\n }\n return null;\n } catch (err) {\n log.warn(\"local LLM summary: failed to parse JSON response:\", err);\n return null;\n }\n }\n\n // Save summary to file\n async saveSummary(summary: HourlySummary): Promise<void> {\n const sessionDir = await this.summarySessionDir(summary.sessionKey);\n await mkdir(sessionDir, { recursive: true });\n\n // Format date as YYYY-MM-DD for the filename\n const dateStr = this.summaryDateString(summary.hour);\n const filePath = await resolveSafeStoragePath(sessionDir, `${dateStr}.md`);\n\n // Format hour as HH:00 for display\n const hourStr = summary.hour.slice(11, 13);\n\n // Build markdown content\n const lines: string[] = [];\n\n // Check if file exists to append or create\n let existingContent = \"\";\n try {\n existingContent = await readFile(filePath, \"utf-8\");\n } catch {\n // File doesn't exist yet, will create new\n }\n\n // Check if this hour already exists (idempotent)\n const hourHeader = `## ${hourStr}:00`;\n if (existingContent.includes(hourHeader)) {\n // Replace existing hour section\n const headerMatch = new RegExp(`(^|\\\\n)${escapeRegExp(hourHeader)}\\\\n`).exec(existingContent);\n const sectionStart = headerMatch\n ? headerMatch.index + headerMatch[1].length\n : existingContent.indexOf(hourHeader);\n const nextHeaderPattern = /\\n## \\d{2}:00\\n/g;\n nextHeaderPattern.lastIndex = sectionStart + hourHeader.length;\n const nextHeader = nextHeaderPattern.exec(existingContent);\n const beforeHour = existingContent.slice(0, sectionStart);\n const afterHour = nextHeader ? existingContent.slice(nextHeader.index + 1) : \"\";\n const newSection = this.formatHourSection(summary, hourHeader);\n existingContent = beforeHour + newSection.trimEnd() + (afterHour ? \"\\n\\n\" + afterHour : \"\\n\");\n\n await writeFile(filePath, existingContent, \"utf-8\");\n log.debug(`updated hourly summary for ${summary.sessionKey} at ${hourStr}:00`);\n } else {\n // Append new hour section\n const newSection = this.formatHourSection(summary, hourHeader);\n\n if (existingContent) {\n // Add to existing file\n await writeFile(filePath, existingContent.trimEnd() + \"\\n\\n\" + newSection, \"utf-8\");\n } else {\n // Create new file with header\n const header = `# Hourly Summaries — ${dateStr}\\n\\n*Session: ${summary.sessionKey}*\\n`;\n await writeFile(filePath, header + \"\\n\" + newSection, \"utf-8\");\n }\n log.debug(`saved hourly summary for ${summary.sessionKey} at ${hourStr}:00`);\n }\n try {\n await upsertSummarySnapshot(this.config.memoryDir, summary);\n } catch (error) {\n log.warn(\n `hourly summarizer: failed to update summary snapshot for ${summary.sessionKey} (fail-open): ${String(error)}`\n );\n }\n }\n\n private formatHourSection(summary: HourlySummary, hourHeader: string): string {\n const ext = (summary as any)._extended as\n | (HourlySummaryExtendedResult & { _meta?: HourlySummaryExtendedMeta })\n | undefined;\n const meta = (summary as any)._extendedMeta as HourlySummaryExtendedMeta | undefined;\n const lines: string[] = [hourHeader, \"\"];\n\n if (resolvePipelineProcessingCapabilities(this.config).hourlySummariesExtended && ext) {\n lines.push(\"### Topics Discussed\");\n for (const t of ext.topics) lines.push(`- ${t}`);\n lines.push(\"\");\n lines.push(\"### Decisions Made\");\n for (const d of ext.decisions) lines.push(`- ${d}`);\n lines.push(\"\");\n lines.push(\"### Action Items\");\n for (const a of ext.actionItems) lines.push(`- ${a}`);\n lines.push(\"\");\n lines.push(\"### Rejected Ideas / Reversals\");\n for (const r of ext.rejected) lines.push(`- ${r}`);\n lines.push(\"\");\n if (meta && Object.keys(meta.toolCounts).length > 0) {\n lines.push(\"### Tools Used\");\n const top = Object.entries(meta.toolCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 12);\n for (const [name, count] of top) lines.push(`- ${name}: ${count}`);\n lines.push(\"\");\n }\n lines.push(\"### Stats\");\n lines.push(`- Turns: ${summary.turnCount}`);\n if (meta) {\n lines.push(`- User turns: ${meta.userTurns}`);\n lines.push(`- Assistant turns: ${meta.assistantTurns}`);\n lines.push(`- Tool calls: ${meta.toolCalls}`);\n }\n lines.push(\"\");\n return lines.join(\"\\n\");\n }\n\n for (const bullet of summary.bullets) lines.push(`- ${bullet}`);\n lines.push(` *(${summary.turnCount} turns)*`);\n lines.push(\"\");\n return lines.join(\"\\n\");\n }\n\n // Read recent summaries for recall injection\n async readRecent(sessionKey: string, hours: number): Promise<HourlySummary[]> {\n try {\n const cutoffTime = Date.now() - hours * 60 * 60 * 1000;\n\n const snapshot = await readSummarySnapshot(this.config.memoryDir, sessionKey);\n if (snapshot) {\n return snapshot\n .filter((s) => new Date(s.hour).getTime() >= cutoffTime)\n .sort((a, b) => new Date(b.hour).getTime() - new Date(a.hour).getTime());\n }\n\n const summaries: HourlySummary[] = [];\n const encodedDir = await this.summarySessionDir(sessionKey);\n const legacyDir = await this.legacySummarySessionDir(sessionKey);\n const seenDirs = new Set<string>();\n\n for (const sessionDir of [encodedDir, legacyDir]) {\n if (!sessionDir || seenDirs.has(sessionDir)) continue;\n seenDirs.add(sessionDir);\n const parsed = await this.readSummaryDir(sessionDir, sessionKey);\n summaries.push(...parsed);\n }\n\n const byHour = new Map<string, HourlySummary>();\n for (const summary of summaries) {\n if (!byHour.has(summary.hour)) byHour.set(summary.hour, summary);\n }\n\n const sortedSummaries = Array.from(byHour.values()).sort(\n (a, b) => new Date(b.hour).getTime() - new Date(a.hour).getTime()\n );\n\n // Filter to recent hours while materializing the full parsed history.\n const recent = sortedSummaries.filter((s) => new Date(s.hour).getTime() >= cutoffTime);\n\n if (sortedSummaries.length > 0) {\n try {\n await writeSummarySnapshot(this.config.memoryDir, sessionKey, sortedSummaries);\n } catch (error) {\n log.warn(\n `hourly summarizer: failed to materialize summary snapshot for ${sessionKey} (fail-open): ${String(error)}`\n );\n }\n }\n\n return recent;\n } catch {\n // Directory doesn't exist or error reading\n return [];\n }\n }\n\n private async readSummaryDir(sessionDir: string, sessionKey: string): Promise<HourlySummary[]> {\n let files: string[];\n try {\n files = await readdir(sessionDir);\n } catch {\n return [];\n }\n\n const summaries: HourlySummary[] = [];\n const mdFiles = files.filter((f) => f.endsWith(\".md\"));\n for (const file of mdFiles) {\n const filePath = await resolveSafeStoragePath(sessionDir, file).catch(() => null);\n if (filePath === null) continue;\n\n try {\n const content = await readFile(filePath, \"utf-8\");\n summaries.push(...this.parseSummaryFile(content, sessionKey, file));\n } catch {\n // Skip unreadable summary files.\n }\n }\n\n return summaries;\n }\n\n private parseSummaryFile(content: string, sessionKey: string, filename: string): HourlySummary[] {\n const summaries: HourlySummary[] = [];\n\n // Extract date from filename (YYYY-MM-DD.md)\n const dateMatch = filename.match(/^(\\d{4}-\\d{2}-\\d{2})\\.md$/);\n if (!dateMatch) return summaries;\n const dateStr = dateMatch[1];\n\n // Split by hour sections\n const hourSections = content.split(/\\n## (\\d{2}):00\\n/);\n\n // First element is the header, skip it\n for (let i = 1; i < hourSections.length; i += 2) {\n const hourStr = hourSections[i];\n const sectionContent = hourSections[i + 1] || \"\";\n\n // Parse bullets\n const bullets: string[] = [];\n const lines = sectionContent.split(\"\\n\");\n let turnCount = 0;\n\n let inTopics = false;\n let sawExtendedTopicsHeader = false;\n for (const line of lines) {\n if (line.startsWith(\"### Topics\")) {\n inTopics = true;\n sawExtendedTopicsHeader = true;\n continue;\n }\n if (line.startsWith(\"### \") && !line.startsWith(\"### Topics\")) {\n inTopics = false;\n }\n const bulletMatch = line.match(/^- (.+)$/);\n if (bulletMatch) {\n // For extended format, only treat topic bullets as recall bullets.\n if (!sawExtendedTopicsHeader || inTopics) bullets.push(bulletMatch[1]);\n }\n const turnMatch = line.match(/\\((\\d+) turns?\\)/);\n if (turnMatch) turnCount = parseInt(turnMatch[1], 10);\n }\n\n if (bullets.length > 0) {\n summaries.push({\n hour: `${dateStr}T${hourStr}:00:00.000Z`,\n sessionKey,\n bullets,\n turnCount,\n generatedAt: \"\", // Not stored in file, not needed for recall\n });\n }\n }\n\n return summaries;\n }\n\n // Format summaries for recall injection\n formatForRecall(summaries: HourlySummary[], maxCount: number): string {\n if (summaries.length === 0) return \"\";\n\n const limited = summaries.slice(0, maxCount);\n const lines: string[] = [`## Recent Activity (last ${limited.length} hours)`];\n\n for (const summary of limited) {\n const hourStr = summary.hour.slice(11, 16); // HH:MM\n for (const bullet of summary.bullets) {\n lines.push(`- ${hourStr}: ${bullet}`);\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n // Main entry point for cron job\n async runHourly(): Promise<HourlySummarizerRunStats> {\n log.debug(\"running hourly summary generation\");\n\n // Get active sessions from transcript. The scan outcome is kept LOCAL to\n // this invocation (review round 2): shared instance state would let two\n // concurrent runHourly calls cross-report each other's timestamps.\n const scan = await this.getActiveSessions();\n const sessions = scan.sessionKeys;\n let sessionsWithEntries = 0;\n let summariesWritten = 0;\n\n for (const sessionKey of sessions) {\n // Calculate the hour we want to summarize (previous hour)\n const now = new Date();\n const hourStart = new Date(now.getTime() - 60 * 60 * 1000);\n hourStart.setMinutes(0, 0, 0);\n const hourEnd = new Date(hourStart.getTime() + 60 * 60 * 1000);\n\n // Get entries for this session in the target hour\n const entries = await this.getTranscriptEntries(sessionKey, hourStart, hourEnd);\n\n if (entries.length === 0) {\n log.debug(`no transcript entries for ${sessionKey} at ${hourStart.toISOString()}`);\n continue;\n }\n sessionsWithEntries += 1;\n\n // Generate and save summary\n const summary = await this.generateSummary(sessionKey, hourStart, entries);\n if (summary) {\n await this.saveSummary(summary);\n summariesWritten += 1;\n log.info(`generated hourly summary for ${sessionKey} (${entries.length} turns)`);\n }\n }\n\n return {\n sessionsConsidered: sessions.length,\n sessionsWithEntries,\n summariesWritten,\n // Staleness signal (issue #2783): newest entry across the whole\n // store, from the same scan getActiveSessions already performs.\n staleStore:\n scan.newestEntryTimestamp !== null &&\n Date.now() - new Date(scan.newestEntryTimestamp).getTime() > STALE_STORE_MS,\n newestEntryTimestamp: scan.newestEntryTimestamp,\n scanFailed: scan.scanFailed,\n };\n }\n\n // Get list of active sessions from the transcript directory, plus the\n // scan bookkeeping runHourly reports: newest entry timestamp (staleness\n // signal) and whether the scan itself FAILED. A failed scan must not be\n // reported as an empty store — those are different incidents (review\n // round 2).\n private async getActiveSessions(): Promise<{\n sessionKeys: string[];\n newestEntryTimestamp: string | null;\n scanFailed: boolean;\n }> {\n const transcriptDir = await resolveSafeStoragePath(this.config.memoryDir, \"transcripts\").catch(() => null);\n if (transcriptDir === null) {\n return { sessionKeys: [], newestEntryTimestamp: null, scanFailed: false };\n }\n\n const sessionKeys = new Set<string>();\n let newestEntryTimestamp: string | null = null;\n let newestEntryTimeMs = Number.NaN;\n let fileReadFailed = false;\n const collect = async (transcriptPath: string): Promise<void> => {\n try {\n const raw = await readFile(transcriptPath, \"utf-8\");\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const entry = JSON.parse(line) as TranscriptEntry;\n if (typeof entry.sessionKey === \"string\" && entry.sessionKey.length > 0) {\n sessionKeys.add(entry.sessionKey);\n }\n // Compare parsed epoch values, never strings: a malformed\n // timestamp in a hand-edited file must not poison the staleness\n // signal with a lexically-maximal garbage value (review).\n if (typeof entry.timestamp === \"string\") {\n const timeMs = new Date(entry.timestamp).getTime();\n if (Number.isFinite(timeMs) && (Number.isNaN(newestEntryTimeMs) || timeMs > newestEntryTimeMs)) {\n newestEntryTimeMs = timeMs;\n newestEntryTimestamp = entry.timestamp;\n }\n }\n } catch {\n // ignore malformed transcript lines\n }\n }\n } catch (err) {\n // ENOENT is a concurrently-deleted file — ignore. Any other read\n // failure (permissions, I/O) means the store is partially UNREADABLE:\n // mark the scan failed so the caller warns instead of reporting an\n // empty store (review round 3).\n if ((err as NodeJS.ErrnoException)?.code !== \"ENOENT\") {\n fileReadFailed = true;\n }\n }\n };\n\n try {\n const typeEntries = await readdir(transcriptDir, { withFileTypes: true });\n for (const typeEnt of typeEntries) {\n if (!typeEnt.isDirectory()) continue;\n const typeDir = await resolveSafeStoragePath(transcriptDir, typeEnt.name).catch(() => null);\n if (typeDir === null) continue;\n const idEntries = await readdir(typeDir, { withFileTypes: true });\n for (const idEnt of idEntries) {\n if (!idEnt.isDirectory()) continue;\n const chanDir = await resolveSafeStoragePath(typeDir, idEnt.name).catch(() => null);\n if (chanDir === null) continue;\n const files = (await readdir(chanDir)).filter((f) => f.endsWith(\".jsonl\")).sort();\n for (const file of files) {\n const transcriptPath = await resolveSafeStoragePath(chanDir, file).catch(() => null);\n if (transcriptPath === null) continue;\n await collect(transcriptPath);\n }\n }\n }\n return {\n sessionKeys: Array.from(sessionKeys),\n newestEntryTimestamp,\n scanFailed: fileReadFailed,\n };\n } catch (err) {\n // ENOENT on the root is a never-written store — an EMPTY store, not a\n // scan failure (those are different incidents).\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code === \"ENOENT\") {\n return { sessionKeys: [], newestEntryTimestamp: null, scanFailed: false };\n }\n log.warn(`transcript scan failed: ${err}`);\n return { sessionKeys: [], newestEntryTimestamp: null, scanFailed: true };\n }\n }\n\n // Get transcript entries for a session within a time range\n private async getTranscriptEntries(sessionKey: string, startTime: Date, endTime: Date): Promise<TranscriptEntry[]> {\n // Shared session-identity layer (issue #1496, rule #22). Arbitrary keys\n // route to `session/<hash>`; legacy `agent:<id>:...` keep their paths. The\n // shared helper also supplies the read-back-only candidate dirs (mirrors\n // TranscriptManager) so legacy `other/default` AND old `parts.length >= 3`\n // data stays discoverable here too.\n const paths = sessionStoragePaths(sessionKey);\n\n try {\n const transcriptRoot = path.join(this.config.memoryDir, \"transcripts\");\n const candidateDirs = new Set(\n [paths.dir, paths.alternateDir, paths.legacyDir, ...paths.readbackDirs].filter(\n (dir): dir is string => typeof dir === \"string\" && dir.length > 0\n )\n );\n const entries: TranscriptEntry[] = [];\n // Dedup identical raw rows that a partially-applied migration may have\n // left in both the primary dir and a read-back dir (issue #1496, cursor\n // review). Exact raw JSONL line is the stable identity.\n const seenRawLines = new Set<string>();\n\n // Read all daily transcript files in the directory\n for (const candidateDir of candidateDirs) {\n const transcriptDir = await resolveSafeStoragePath(transcriptRoot, candidateDir).catch(() => null);\n if (transcriptDir === null) continue;\n\n const files = await readdir(transcriptDir).catch(() => []);\n for (const file of files) {\n if (!file.endsWith(\".jsonl\")) continue;\n\n const transcriptPath = await resolveSafeStoragePath(transcriptDir, file).catch(() => null);\n if (transcriptPath === null) continue;\n\n try {\n const content = await readFile(transcriptPath, \"utf-8\");\n const lines = content.trim().split(\"\\n\");\n\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const entry = JSON.parse(line) as TranscriptEntry;\n const entryTime = new Date(entry.timestamp).getTime();\n\n if (\n entry.sessionKey === sessionKey &&\n entryTime >= startTime.getTime() &&\n entryTime < endTime.getTime() &&\n !seenRawLines.has(line)\n ) {\n seenRawLines.add(line);\n entries.push(entry);\n }\n } catch {\n // Skip malformed lines\n }\n }\n } catch {\n // Skip unreadable files\n }\n }\n }\n\n return entries;\n } catch {\n return [];\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/access-offline-manifest.ts"],"sourcesContent":["import * as nodePath from \"node:path\";\nimport { offlineSyncStorageForSnapshot } from \"./offline-sync-impression-drain.js\";\nimport { iterateOfflineSyncSnapshotFileRecords } from \"./offline-sync.js\";\nimport type { Orchestrator } from \"./orchestrator.js\";\nimport {\n CONTENT_HASH_NORMALIZER_VERSION,\n IDENTITY_RESOLUTION_VERSION,\n RECONCILE_MANIFEST_FORMAT,\n RECONCILE_MANIFEST_SCHEMA_VERSION,\n type ReconcileManifest,\n type ReconcileManifestFile,\n type ReconcileMemoryIdentity,\n type ReconcileMemoryParser,\n buildReconcileManifestFile,\n citationTemplateFingerprint,\n isCachedIdentityReusable,\n isReconcileMemoryIdentity,\n} from \"./reconcile/manifest.js\";\nimport { createPersistedSupportPassportPrivateFileExclusion } from \"./support-passport/card-projection.js\";\n\nexport interface OfflineSyncManifestRequest {\n includeTranscripts?: boolean;\n signal?: AbortSignal;\n}\n\nexport interface OfflineSyncManifestStreamResponse extends Omit<ReconcileManifest, \"files\"> {\n namespace: string;\n files: AsyncIterable<ReconcileManifestFile>;\n}\n\nexport interface ServerIdentityCacheEntry {\n path: string;\n sha256: string;\n memory?: ReconcileMemoryIdentity;\n /** Stamped on sha-only entries so an upgrade re-parses them. */\n normalizerVersion?: number;\n identityResolutionVersion?: number;\n /** Stat identity the exclusion classification was computed against. */\n statIdentity?: string;\n /** Persisted support-passport private-memory classification for statIdentity. */\n excluded?: boolean;\n}\n\n/**\n * Decide what the manifest stream should persist, and whether a write is\n * needed at all.\n *\n * A write is required whenever the persisted set changed — an identity was\n * rebuilt, or an entry was dropped because its file lost its identity — and\n * also when a completed walk leaves entries for paths it never saw, which are\n * files that have since been deleted. Skipping the write in that last case\n * would strand those entries on disk forever.\n *\n * Pruning is gated on the walk completing: an aborted or partially consumed\n * stream has simply not observed the remaining paths, so it may only add.\n */\nexport function planServerIdentityCacheWrite(input: {\n persisted: ReadonlyMap<string, ServerIdentityCacheEntry>;\n yieldedPaths: ReadonlySet<string>;\n streamCompleted: boolean;\n cacheDirty: boolean;\n}): { shouldWrite: boolean; entries: ServerIdentityCacheEntry[] } {\n const entries = input.streamCompleted\n ? [...input.persisted.values()].filter((entry) => input.yieldedPaths.has(entry.path))\n : [...input.persisted.values()];\n return { shouldWrite: input.cacheDirty || entries.length !== input.persisted.size, entries };\n}\n\n/**\n * The cache lives under `.remnic/` rather than `state/`: snapshot enumeration\n * excludes internal `.remnic/` paths structurally (`isInternalRemnicStatePath`),\n * whereas `state/` is only filtered by an allowlist of known node-local\n * artifacts. Under `state/` this node-local cache would be advertised as a peer\n * file, so convergence would transfer the cache itself — and the stream rewrites\n * it during finalization, so the advertised digest could go stale mid-transfer.\n */\nfunction serverIdentityCachePath(storageDir: string): string {\n return nodePath.join(storageDir, \".remnic\", \"state\", \"converge-identity-cache.json\");\n}\n\nasync function loadServerIdentityCache(\n storageDir: string,\n citationTemplate?: string\n): Promise<Map<string, ServerIdentityCacheEntry>> {\n const cache = new Map<string, ServerIdentityCacheEntry>();\n try {\n const raw = JSON.parse(\n await import(\"node:fs/promises\").then((fs) => fs.readFile(serverIdentityCachePath(storageDir), \"utf8\"))\n ) as {\n citationTemplate?: string;\n files?: unknown[];\n };\n // Identities are derived after stripping inline attribution for a specific\n // citation template; entries written under a different one would produce\n // wrong contentHash values for unchanged files.\n if (raw.citationTemplate !== citationTemplateFingerprint(citationTemplate)) return cache;\n for (const candidate of raw.files ?? []) {\n const entry = candidate as Partial<ServerIdentityCacheEntry> | null;\n if (typeof entry?.path !== \"string\" || typeof entry.sha256 !== \"string\") continue;\n if (entry.memory !== undefined && !isReconcileMemoryIdentity(entry.memory)) continue;\n if (entry.statIdentity !== undefined && typeof entry.statIdentity !== \"string\") continue;\n if (entry.excluded !== undefined && typeof entry.excluded !== \"boolean\") continue;\n if (entry.normalizerVersion !== undefined && typeof entry.normalizerVersion !== \"number\") continue;\n if (entry.identityResolutionVersion !== undefined && typeof entry.identityResolutionVersion !== \"number\") {\n continue;\n }\n cache.set(entry.path, {\n path: entry.path,\n sha256: entry.sha256,\n ...(entry.memory ? { memory: entry.memory } : {}),\n ...(entry.memory\n ? {}\n : {\n ...(typeof entry.normalizerVersion === \"number\" ? { normalizerVersion: entry.normalizerVersion } : {}),\n ...(typeof entry.identityResolutionVersion === \"number\"\n ? { identityResolutionVersion: entry.identityResolutionVersion }\n : {}),\n }),\n ...(entry.statIdentity !== undefined && entry.excluded !== undefined\n ? { statIdentity: entry.statIdentity, excluded: entry.excluded }\n : {}),\n });\n }\n } catch {\n // missing or corrupt cache: cold build\n }\n return cache;\n}\n\nconst serverIdentityCacheWriteLocks = new Map<string, Promise<void>>();\n\n/** Serialize cache replacements per path: overlapping manifest streams for one\n * namespace would otherwise each publish a whole-file snapshot, and the slower\n * stream built from older filesystem state would overwrite the newer one. */\nasync function withServerIdentityCacheWriteLock(cachePath: string, write: () => Promise<void>): Promise<void> {\n const previous = serverIdentityCacheWriteLocks.get(cachePath) ?? Promise.resolve();\n const next = previous.then(write, write);\n serverIdentityCacheWriteLocks.set(cachePath, next);\n try {\n await next;\n } finally {\n if (serverIdentityCacheWriteLocks.get(cachePath) === next) {\n serverIdentityCacheWriteLocks.delete(cachePath);\n }\n }\n}\n\n/** Union of the entries being written and the current on-disk set; on conflict\n * the write wins (it reflects the newer run). Callers hold the write lock. */\nasync function mergeServerIdentityCacheEntries(\n fs: typeof import(\"node:fs/promises\"),\n cachePath: string,\n entries: readonly ServerIdentityCacheEntry[],\n citationTemplate: string | undefined,\n dropped: ReadonlySet<string> = new Set()\n): Promise<ServerIdentityCacheEntry[]> {\n const merged = new Map(entries.map((entry) => [entry.path, entry]));\n try {\n const raw = JSON.parse(await fs.readFile(cachePath, \"utf8\")) as {\n citationTemplate?: string;\n files?: unknown[];\n };\n if (raw.citationTemplate === citationTemplateFingerprint(citationTemplate)) {\n for (const candidate of raw.files ?? []) {\n const entry = candidate as Partial<ServerIdentityCacheEntry> | null;\n if (typeof entry?.path !== \"string\" || typeof entry.sha256 !== \"string\") continue;\n if (entry.memory !== undefined && !isReconcileMemoryIdentity(entry.memory)) continue;\n if (dropped.has(entry.path) || merged.has(entry.path)) continue;\n merged.set(entry.path, {\n path: entry.path,\n sha256: entry.sha256,\n ...(entry.memory ? { memory: entry.memory } : {}),\n ...(entry.memory\n ? {}\n : {\n ...(typeof entry.normalizerVersion === \"number\" ? { normalizerVersion: entry.normalizerVersion } : {}),\n ...(typeof entry.identityResolutionVersion === \"number\"\n ? { identityResolutionVersion: entry.identityResolutionVersion }\n : {}),\n }),\n });\n }\n }\n } catch {\n // missing or unreadable current cache: the write set stands alone\n }\n return [...merged.values()];\n}\n\nexport async function createOfflineSyncManifestStream(\n orchestrator: Orchestrator,\n namespace: string,\n userExcludeRegexps: RegExp[],\n options: OfflineSyncManifestRequest,\n parseMemory: ReconcileMemoryParser\n): Promise<OfflineSyncManifestStreamResponse> {\n const storage = await offlineSyncStorageForSnapshot(orchestrator, namespace);\n const citationTemplate = orchestrator.config.inlineSourceAttributionFormat;\n const identityCache = await loadServerIdentityCache(storage.dir, citationTemplate);\n // The exclusion callback runs before every yield; without the persisted\n // classification it would read and parse every candidate file, defeating the\n // warm-cache skip entirely.\n const classificationUpdates = new Map<string, { statIdentity: string; excluded: boolean }>();\n const snapshotFiles = iterateOfflineSyncSnapshotFileRecords({\n root: storage.dir,\n includeContent: false,\n includeTranscripts: options.includeTranscripts !== false,\n readFileDigest: async ({ filePath }) => storage.digestOfflineSyncFile(filePath),\n signal: options.signal,\n userExcludeRegexps,\n excludeFile: createPersistedSupportPassportPrivateFileExclusion(storage, identityCache, classificationUpdates),\n });\n return {\n namespace,\n format: RECONCILE_MANIFEST_FORMAT,\n schemaVersion: RECONCILE_MANIFEST_SCHEMA_VERSION,\n files: (async function* () {\n // Any change to the persisted set, not just a rebuilt identity: a file\n // that lost its identity, or a completed walk that must prune vanished\n // paths, also has to reach disk or the removal is lost forever.\n let cacheDirty = false;\n let streamCompleted = false;\n // Seeded with every previously cached entry so a partially consumed\n // stream (client disconnect, abort) can only add to the cache. Writing\n // just this run's rebuilds would drop every cache hit, so one edit to a\n // large corpus would shrink the cache to that single entry and force a\n // near-cold rebuild on the next request.\n const persistedEntries = new Map(identityCache);\n const yieldedPaths = new Set<string>();\n const flush = async (): Promise<void> => {\n const { shouldWrite, entries } = planServerIdentityCacheWrite({\n persisted: persistedEntries,\n yieldedPaths,\n streamCompleted,\n cacheDirty,\n });\n if (!shouldWrite) return;\n try {\n const fs = await import(\"node:fs/promises\");\n const cachePath = serverIdentityCachePath(storage.dir);\n await withServerIdentityCacheWriteLock(cachePath, async () => {\n // Merge with whatever is on disk NOW: a concurrent stream for the\n // same namespace may have published newer entries after this\n // request loaded its snapshot, and a blind whole-file replace\n // would discard them.\n const written = new Set(entries.map((entry) => entry.path));\n const dropped = streamCompleted\n ? new Set([...identityCache.keys()].filter((pathName) => !written.has(pathName)))\n : new Set<string>();\n const merged = await mergeServerIdentityCacheEntries(\n fs,\n cachePath,\n entries,\n citationTemplate,\n dropped\n );\n await fs.mkdir(nodePath.dirname(cachePath), { recursive: true });\n const tmp = `${cachePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;\n await fs.writeFile(\n tmp,\n JSON.stringify({ citationTemplate: citationTemplateFingerprint(citationTemplate), files: merged })\n );\n await fs.rename(tmp, cachePath);\n });\n } catch {\n // cache persistence is best-effort\n }\n };\n try {\n const applyClassification = (path: string, sha256: string): void => {\n const classification = classificationUpdates.get(path);\n if (classification === undefined) return;\n const entry = persistedEntries.get(path) ?? { path, sha256 };\n if (entry.statIdentity === classification.statIdentity && entry.excluded === classification.excluded) {\n return;\n }\n persistedEntries.set(path, {\n ...entry,\n ...(entry.memory ? { memory: entry.memory } : {}),\n statIdentity: classification.statIdentity,\n excluded: classification.excluded,\n });\n cacheDirty = true;\n };\n for await (const file of snapshotFiles) {\n yieldedPaths.add(file.path);\n const cached = identityCache.get(file.path);\n if (\n cached !== undefined &&\n cached.sha256.toLowerCase() === file.sha256.toLowerCase() &&\n isCachedIdentityReusable(cached)\n ) {\n applyClassification(file.path, file.sha256);\n yield {\n ...file,\n ...(cached.memory\n ? { memory: cached.memory }\n : {\n normalizerVersion: cached.normalizerVersion,\n identityResolutionVersion: cached.identityResolutionVersion,\n }),\n };\n continue;\n }\n const built = await buildReconcileManifestFile(\n file,\n async ({ path }) => storage.readOfflineSyncFile(nodePath.join(storage.dir, path)),\n parseMemory,\n citationTemplate\n );\n // Negative results persist too: a memory-shaped file that parses\n // without an identity would otherwise be re-read on every warm run.\n const previous = persistedEntries.get(built.path);\n if (previous?.sha256 !== built.sha256 || (built.memory !== undefined && previous?.memory !== built.memory)) {\n cacheDirty = true;\n }\n if (built.memory === undefined && built.normalizerVersion === undefined) {\n // Read failed: do not persist a negative identity for this SHA.\n yield built;\n continue;\n }\n persistedEntries.set(built.path, {\n path: built.path,\n sha256: built.sha256,\n ...(built.memory !== undefined\n ? { memory: built.memory }\n : {\n normalizerVersion: built.normalizerVersion,\n identityResolutionVersion: built.identityResolutionVersion,\n }),\n });\n applyClassification(built.path, built.sha256);\n yield built;\n }\n streamCompleted = true;\n } finally {\n await flush();\n }\n })(),\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/namespaces/search.ts"],"sourcesContent":["import { resolveNamespaceCapabilities } from \"../capabilities.js\";\nimport path from \"node:path\";\nimport { realpathSync } from \"node:fs\";\nimport type { PluginConfig, QmdSearchResult } from \"../types.js\";\nimport type {\n SearchBackend,\n SearchExecutionOptions,\n SearchQueryOptions,\n} from \"../search/port.js\";\nimport { createSearchBackend } from \"../search/factory.js\";\nimport { namespaceIdentityToken, normalizeNamespaceIdentity } from \"./identity.js\";\nimport { ALL_CATEGORY_DIRS } from \"../utils/category-dir.js\";\n\nconst NESTED_NAMESPACE_FILTER_OVERFETCH_FACTOR = 4;\nconst NESTED_NAMESPACE_FILTER_OVERFETCH_MIN = 50;\n\nexport function namespaceCollectionName(\n baseCollection: string,\n namespace: string,\n options?: {\n defaultNamespace?: string;\n useLegacyDefaultCollection?: boolean;\n },\n): string {\n const trimmed = normalizeNamespaceIdentity(namespace);\n const defaultNamespace = normalizeNamespaceIdentity(options?.defaultNamespace ?? \"\") || \"default\";\n if (\n options?.useLegacyDefaultCollection === true &&\n trimmed === defaultNamespace\n ) {\n return baseCollection;\n }\n\n return `${baseCollection}--${namespaceIdentityToken(trimmed || defaultNamespace)}`;\n}\n\ntype StorageRouterLike = {\n storageFor(namespace: string): Promise<{ dir: string }>;\n};\n\ntype NamespaceBackendRecord = {\n backend: SearchBackend;\n collection: string;\n memoryDir: string;\n available: boolean;\n collectionState: CollectionState;\n filtersNestedNamespaces: boolean;\n};\n\nexport interface NamespaceUpdateResult {\n backendCount: number;\n eligibleNamespaces: string[];\n}\n\nexport type CollectionState = \"present\" | \"missing\" | \"unknown\" | \"skipped\";\n\nexport interface NamespaceSearchHealth {\n collection: string;\n memoryDir: string;\n available: boolean;\n collectionState: CollectionState;\n debugStatus: string;\n installedVersion: string | null;\n supportedVersion: string | null;\n supported: boolean | null;\n upgradeAvailable: boolean | null;\n doctorAvailable: boolean | null;\n daemonMode: boolean | null;\n pendingEmbeddings: number | null;\n oldestPendingAgeMs: number | null;\n embeddingBacklogThreshold: number;\n}\n\ntype NamespaceScopedSearchConfig = PluginConfig & {\n hostEmbeddingProviderScope?: string;\n};\n\ntype BackendRecordOptions = {\n autoCreateCollection: boolean;\n abortAsUnavailable: boolean;\n failOpenMissingGuardedCollection: boolean;\n};\n\nexport class NamespaceSearchRouter {\n private readonly cache = new Map<string, Promise<NamespaceBackendRecord>>();\n\n constructor(\n private readonly config: PluginConfig,\n private readonly storageRouter: StorageRouterLike,\n private readonly createBackend: (config: PluginConfig) => SearchBackend = createSearchBackend,\n ) {}\n\n async collectionForNamespace(namespace: string): Promise<string> {\n return (await this.backendRecordFor(namespace)).collection;\n }\n\n /**\n * Resolve the search backend for a namespace (#2019). Returns `unknown` so\n * callers (e.g. the prioritized-embed path) duck-type for capability like\n * `embedFiles` rather than depending on a concrete QMD shape. Reuses the\n * cached backend record, so this never re-creates a backend. Returns `null`\n * when the namespace backend is unavailable.\n */\n async backendForNamespace(namespace: string): Promise<unknown> {\n const record = await this.backendRecordFor(namespace);\n return record.available ? record.backend : null;\n }\n\n async searchAcrossNamespaces(options: {\n query: string;\n namespaces: string[];\n maxResults?: number;\n mode?: \"search\" | \"hybrid\" | \"bm25\" | \"vector\";\n searchOptions?: SearchQueryOptions;\n execution?: SearchExecutionOptions;\n }): Promise<QmdSearchResult[]> {\n const query = options.query.trim();\n if (!query) return [];\n const maxResults = Math.max(0, Math.floor(options.maxResults ?? this.config.qmdMaxResults));\n if (maxResults === 0) return [];\n\n const method = options.mode ?? \"search\";\n const namespaces = Array.from(new Set(options.namespaces.map((value) => value.trim()).filter(Boolean)));\n if (namespaces.length === 0) return [];\n\n const resultsByNamespace = await Promise.all(\n namespaces.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n if (!record.available || record.collectionState === \"missing\") {\n // A per-namespace backend that is unavailable (or missing its\n // collection) must report like any other QMD skip (#1536): its\n // empty contribution is otherwise indistinguishable from a true\n // no-matches for that namespace (codex round-5 review on #1544).\n try {\n options.execution?.onDegradation?.({\n backend: \"qmd\",\n code: \"backend_unavailable\",\n detail:\n record.collectionState === \"missing\"\n ? `namespace collection missing: ${namespace}`\n : `namespace backend unavailable: ${namespace}`,\n });\n } catch {\n // Observers must never break search.\n }\n return { namespace, results: [] as QmdSearchResult[] };\n }\n const backendLimit = backendSearchLimit(record, maxResults);\n let results: QmdSearchResult[];\n switch (method) {\n case \"hybrid\":\n results = await record.backend.hybridSearch(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n case \"bm25\":\n results = await record.backend.bm25Search(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n case \"vector\":\n results = await record.backend.vectorSearch(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n default:\n results = await record.backend.search(\n query,\n record.collection,\n backendLimit,\n options.searchOptions,\n options.execution,\n );\n break;\n }\n results = filterNamespaceSubtreeResults(record, results)\n .map((result) => ({\n ...result,\n namespace,\n // Resolve to an absolute path so the (namespace, path) identity is\n // globally unique — same-relative-path hits from different namespaces\n // stay distinct across every downstream consumer with no special\n // handling. Display/citation surfaces relativize for portability (#2020).\n path: resolveNamespaceResultPath(record.memoryDir, record.collection, result.path),\n }))\n // Reject hits whose resolved path escapes the queried namespace's\n // storage root (#2077). A stale/corrupt per-namespace collection can\n // return a path owned by another namespace; stamping it would let\n // downstream scope checks (which trust the stamped namespace) and\n // absolute-path resolution surface a foreign-namespace memory.\n .filter((result) => resolvedPathIsInsideNamespaceRoot(record.memoryDir, result.path));\n return { namespace, results };\n }),\n );\n\n return mergeNamespaceSearchResults(resultsByNamespace, maxResults);\n }\n\n /**\n * Update all namespace backends.\n * Returns the number of backends for which an update was attempted\n * (i.e., available and collection present). Callers can treat 0 as a\n * signal that no backend was eligible — useful for success-verification in\n * startup-sync when namespacesEnabled is true.\n */\n async updateNamespaces(\n namespaces: string[],\n execution?: SearchExecutionOptions,\n options?: { strict?: boolean },\n ): Promise<number> {\n return (await this.updateNamespacesDetailed(namespaces, execution, options)).backendCount;\n }\n\n async updateNamespacesDetailed(\n namespaces: string[],\n execution?: SearchExecutionOptions,\n options?: { strict?: boolean },\n ): Promise<NamespaceUpdateResult> {\n const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));\n const eligible = (await Promise.all(\n unique.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n return record.available && record.collectionState !== \"missing\"\n ? { namespace, record }\n : null;\n }),\n )).filter((entry): entry is { namespace: string; record: NamespaceBackendRecord } => entry !== null);\n\n const globalEntry = eligible.find(({ record }) => record.backend.updatesAllCollections?.() === true);\n const scopedEntries = globalEntry\n ? eligible.filter(({ record }) => record.backend.updatesAllCollections?.() !== true)\n : eligible;\n\n await Promise.all([\n globalEntry\n ? updateBackendRecord(globalEntry.record, execution, options)\n : Promise.resolve(),\n ...scopedEntries.map(({ record }) => updateBackendRecord(record, execution, options)),\n ]);\n\n return {\n backendCount: (globalEntry ? 1 : 0) + scopedEntries.length,\n eligibleNamespaces: eligible.map(({ namespace }) => namespace),\n };\n }\n\n async embedNamespaces(namespaces: string[], options?: { strict?: boolean }): Promise<void> {\n const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));\n await Promise.all(\n unique.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n if (!record.available || record.collectionState === \"missing\") return;\n await embedBackendRecord(record, options);\n }),\n );\n }\n\n async ensureNamespaceCollection(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<\"present\" | \"missing\" | \"unknown\" | \"skipped\"> {\n const record = await this.backendRecordFor(namespace, execution);\n return record.collectionState;\n }\n\n async healthForNamespace(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceSearchHealth> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const record = await this.createBackendRecordFor(\n key,\n execution,\n {\n autoCreateCollection: false,\n abortAsUnavailable: true,\n failOpenMissingGuardedCollection: false,\n },\n );\n try {\n const liveRecord = await this.liveCachedRecordForHealth(key, record, execution);\n const diagnosticBackend = liveRecord?.backend ?? record.backend;\n const versionStatus =\n \"getVersionStatus\" in diagnosticBackend &&\n typeof diagnosticBackend.getVersionStatus === \"function\"\n ? diagnosticBackend.getVersionStatus()\n : null;\n const daemonMode = daemonModeForBackend(diagnosticBackend);\n const backendStatus =\n \"status\" in diagnosticBackend &&\n typeof diagnosticBackend.status === \"function\"\n ? await Promise.race([\n diagnosticBackend.status().catch(() => null),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 5_000).unref?.()),\n ])\n : null;\n const collectionState =\n liveRecord?.collectionState === \"missing\"\n ? \"missing\"\n : record.collectionState;\n\n return {\n collection: record.collection,\n memoryDir: record.memoryDir,\n available: liveRecord?.available ?? record.available,\n collectionState,\n debugStatus: diagnosticBackend.debugStatus(),\n installedVersion: versionStatus?.installedVersion ?? null,\n supportedVersion: versionStatus?.supportedVersion ?? null,\n supported: versionStatus?.supported ?? null,\n upgradeAvailable: versionStatus?.upgradeAvailable ?? null,\n doctorAvailable: versionStatus?.capabilities?.doctor ?? null,\n daemonMode,\n pendingEmbeddings: backendStatus?.pendingEmbeddings ?? null,\n oldestPendingAgeMs: backendStatus?.oldestPendingAgeMs ?? null,\n embeddingBacklogThreshold: this.config.qmdEmbeddingBacklogThreshold,\n };\n } finally {\n const dispose = (record.backend as { dispose?: () => void | Promise<void> }).dispose;\n await dispose?.call(record.backend);\n }\n }\n\n private async liveCachedRecordForHealth(\n key: string,\n disposableRecord: NamespaceBackendRecord,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceBackendRecord | null> {\n const pending = this.cache.get(key);\n if (!pending) return null;\n const cachedRecord = await awaitWithAbort(pending, execution?.signal).catch(() => null);\n if (!cachedRecord) return null;\n if (cachedRecord.collection !== disposableRecord.collection) return null;\n if (cachedRecord.memoryDir !== disposableRecord.memoryDir) return null;\n return cachedRecord;\n }\n\n /** Clear cached backend records so the next access re-probes availability. */\n clearCache(): void {\n this.cache.clear();\n }\n\n /** Release any per-namespace backend handles held by cached records. */\n async dispose(): Promise<void> {\n const pendingRecords = Array.from(this.cache.values());\n this.cache.clear();\n const settled = await Promise.allSettled(pendingRecords);\n await Promise.allSettled(\n settled.flatMap((entry) => {\n if (entry.status !== \"fulfilled\") return [];\n const dispose = (entry.value.backend as { dispose?: () => void | Promise<void> }).dispose;\n return dispose ? [dispose.call(entry.value.backend)] : [];\n }),\n );\n }\n\n private async backendRecordFor(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceBackendRecord> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const existing = this.cache.get(key);\n if (existing) return await existing;\n\n const pending = this.createBackendRecordFor(key, execution, {\n autoCreateCollection: true,\n abortAsUnavailable: false,\n failOpenMissingGuardedCollection: true,\n }).catch((error) => {\n this.cache.delete(key);\n throw error;\n });\n\n this.cache.set(key, pending);\n return await pending;\n }\n\n private async createBackendRecordFor(\n namespace: string,\n execution: SearchExecutionOptions | undefined,\n options: BackendRecordOptions,\n ): Promise<NamespaceBackendRecord> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const storage = await this.storageRouter.storageFor(key);\n const useLegacyDefaultCollection =\n key === this.config.defaultNamespace && storage.dir === this.config.memoryDir;\n const filtersNestedNamespaces =\n resolveNamespaceCapabilities(this.config).namespaces === true && useLegacyDefaultCollection;\n const rootHostEmbeddingScope =\n (this.config as NamespaceScopedSearchConfig).hostEmbeddingProviderScope ??\n this.config.memoryDir;\n const scopedConfig: NamespaceScopedSearchConfig = {\n ...this.config,\n memoryDir: storage.dir,\n hostEmbeddingProviderScope: rootHostEmbeddingScope,\n qmdCollection: namespaceCollectionName(this.config.qmdCollection, key, {\n defaultNamespace: this.config.defaultNamespace,\n useLegacyDefaultCollection,\n }),\n };\n\n const backend = this.createBackend(scopedConfig);\n try {\n const availabilityProbe =\n options.autoCreateCollection || typeof backend.checkAvailability !== \"function\"\n ? backend.probe()\n : backend.checkAvailability({ signal: execution?.signal });\n const available = await awaitWithAbort(availabilityProbe, execution?.signal).catch((error) => {\n if (error instanceof NamespaceSearchAbortError && !options.abortAsUnavailable) {\n throw error;\n }\n return false;\n });\n const collectionState = available\n ? await awaitWithAbort(\n // The legacy default namespace at the flat root (`filtersNestedNamespaces`)\n // shares its `memoryDir` with the `namespaces/` container, so its base\n // collection is a \"broad root\" that also indexes nested-namespace files.\n // We STILL auto-create it (issue #1929): the search side already targets\n // this exact base collection and `filterNamespaceSubtreeResults` strips\n // the nested `namespaces/` subtree out of its results, so index and\n // search stay symmetric. Skipping creation left a configured default\n // namespace (e.g. `geek`) with maintenance \"ran\" but no collection and 0\n // recall results. `ensureCollection` is a no-op when the collection is\n // already present, so legacy installs that pre-created the broad root are\n // unaffected.\n this.collectionStateForBackend(backend, storage.dir, scopedConfig.qmdCollection, {\n autoCreate: options.autoCreateCollection,\n failOpenMissingGuardedCollection: options.failOpenMissingGuardedCollection,\n execution,\n }),\n execution?.signal,\n ).catch((error) => {\n if (error instanceof NamespaceSearchAbortError && !options.abortAsUnavailable) {\n throw error;\n }\n return \"unknown\" as const;\n })\n : \"unknown\";\n return {\n backend,\n collection: scopedConfig.qmdCollection,\n memoryDir: storage.dir,\n available,\n collectionState,\n filtersNestedNamespaces,\n };\n } catch (error) {\n const dispose = (backend as { dispose?: () => void | Promise<void> }).dispose;\n if (dispose) {\n await Promise.resolve(dispose.call(backend)).catch(() => {});\n }\n throw error;\n }\n }\n\n private async collectionStateForBackend(\n backend: SearchBackend,\n memoryDir: string,\n collection: string,\n options: {\n autoCreate: boolean;\n failOpenMissingGuardedCollection: boolean;\n execution?: SearchExecutionOptions;\n },\n ): Promise<CollectionState> {\n if (!options.autoCreate) {\n if (!backend.checkCollection) return \"unknown\";\n const collectionState = await backend\n .checkCollection(collection, options.execution)\n .catch(() => \"unknown\" as const);\n return options.failOpenMissingGuardedCollection && collectionState === \"missing\"\n ? \"unknown\"\n : collectionState;\n }\n return await backend.ensureCollection(memoryDir, collection, options.execution).catch(() => \"unknown\" as const);\n }\n}\n\nclass NamespaceSearchAbortError extends Error {\n constructor() {\n super(\"operation aborted\");\n }\n}\n\nfunction awaitWithAbort<T>(operation: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return operation;\n if (signal.aborted) return Promise.reject(new NamespaceSearchAbortError());\n\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(new NamespaceSearchAbortError());\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n operation.then(resolve, reject).finally(() => {\n signal.removeEventListener(\"abort\", onAbort);\n });\n });\n}\n\nfunction filterNamespaceSubtreeResults(\n record: NamespaceBackendRecord,\n results: QmdSearchResult[],\n): QmdSearchResult[] {\n if (!record.filtersNestedNamespaces) return results;\n return results.filter((result) =>\n !pathIsInsideNamespaceSubtree(record.memoryDir, record.collection, result.path)\n );\n}\n\nfunction backendSearchLimit(\n record: NamespaceBackendRecord,\n maxResults: number,\n): number {\n if (!record.filtersNestedNamespaces) return maxResults;\n return Math.max(\n maxResults,\n maxResults * NESTED_NAMESPACE_FILTER_OVERFETCH_FACTOR,\n NESTED_NAMESPACE_FILTER_OVERFETCH_MIN,\n );\n}\n\nasync function updateBackendRecord(\n record: NamespaceBackendRecord,\n execution?: SearchExecutionOptions,\n options?: { strict?: boolean },\n): Promise<void> {\n if (options?.strict === true) {\n if (\n record.backend.updatesAllCollections?.() === true &&\n typeof record.backend.updateStrict === \"function\"\n ) {\n await record.backend.updateStrict(execution);\n return;\n }\n if (typeof record.backend.updateCollectionStrict === \"function\") {\n await record.backend.updateCollectionStrict(record.collection, execution);\n return;\n }\n }\n await record.backend.update(execution);\n}\n\nasync function embedBackendRecord(\n record: NamespaceBackendRecord,\n options?: { strict?: boolean },\n): Promise<void> {\n if (options?.strict === true) {\n if (typeof record.backend.embedCollectionStrict === \"function\") {\n await record.backend.embedCollectionStrict(record.collection);\n return;\n }\n if (typeof record.backend.embedStrict === \"function\") {\n await record.backend.embedStrict();\n return;\n }\n }\n if (typeof record.backend.embedCollection === \"function\") {\n await record.backend.embedCollection(record.collection);\n return;\n }\n await record.backend.embed();\n}\n\nfunction daemonModeForBackend(backend: SearchBackend): boolean | null {\n return \"isDaemonMode\" in backend && typeof backend.isDaemonMode === \"function\"\n ? backend.isDaemonMode() === true\n : null;\n}\n\nfunction isContainedPath(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\n}\n\nfunction pathIsInsideNamespaceSubtree(\n memoryDir: string,\n collection: string,\n resultPath: string | undefined,\n): boolean {\n if (!resultPath) return false;\n const normalizedResultPath = normalizeQmdResultPath(resultPath, collection);\n const memoryRoot = path.resolve(memoryDir);\n const namespacesRoot = path.join(memoryRoot, \"namespaces\");\n const candidate = path.isAbsolute(normalizedResultPath)\n ? path.normalize(normalizedResultPath)\n : path.resolve(memoryRoot, normalizedResultPath);\n return isContainedPath(namespacesRoot, candidate);\n}\n\n/**\n * Reject a QMD hit whose resolved path escapes the queried namespace's storage\n * root (#2077). `resolvedPath` is the already-resolved value produced by\n * `resolveNamespaceResultPath`; a stale/corrupt per-namespace collection can\n * yield an absolute path owned by another namespace, and stamping it with the\n * queried namespace would surface a foreign-namespace memory downstream.\n *\n * Lexical containment runs first — it is cheap and the only check possible when\n * the file is not yet on disk (a stale collection may cite a since-deleted\n * path). When both root and candidate exist, their filesystem realpaths are\n * canonicalized and re-checked so a symlink planted inside the namespace root\n * cannot resolve into another namespace or outside storage. An unresolved path\n * (ENOENT) keeps the lexical result rather than rejecting the stale-collection\n * case this guard targets.\n */\nfunction resolvedPathIsInsideNamespaceRoot(memoryDir: string, resolvedPath: string): boolean {\n const root = path.resolve(memoryDir);\n const candidate = path.isAbsolute(resolvedPath)\n ? path.normalize(resolvedPath)\n : path.resolve(root, resolvedPath);\n if (!isContainedPath(root, candidate)) return false;\n try {\n return isContainedPath(realpathSync.native(root), realpathSync.native(candidate));\n } catch {\n return true;\n }\n}\nexport function normalizeQmdResultPath(resultPath: string, collection: string): string {\n let value = resultPath.trim();\n if (value.startsWith(\"qmd://\")) {\n try {\n const parsed = new URL(value);\n if (parsed.protocol === \"qmd:\" && parsed.hostname === collection) {\n value = decodeURIComponent(parsed.pathname.replace(/^\\/+/, \"\"));\n }\n } catch {\n const remainder = value.slice(\"qmd://\".length);\n const slashIndex = remainder.indexOf(\"/\");\n if (slashIndex !== -1) {\n value = remainder.slice(slashIndex + 1);\n }\n }\n }\n\n // Only strip a genuine QMD collection prefix — never when the collection name\n // collides with a memory category dir (e.g. qmdCollection == \"facts\"), or a\n // bare \"facts/<id>.md\" hit would be corrupted to \"<id>.md\" and fail namespace\n // reads/access tracking (#2020).\n const collectionPrefix = `${collection}/`;\n if (value.startsWith(collectionPrefix) && !ALL_CATEGORY_DIRS.includes(collection)) {\n value = value.slice(collectionPrefix.length);\n }\n return value;\n}\nfunction resolveNamespaceResultPath(\n memoryDir: string,\n collection: string,\n resultPath: string,\n): string {\n const normalized = normalizeQmdResultPath(resultPath, collection);\n if (path.isAbsolute(normalized)) return normalized;\n const root = path.resolve(memoryDir);\n const resolved = path.resolve(root, normalized);\n const relative = path.relative(root, resolved);\n if (relative === \"\" || relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n return resultPath;\n }\n return resolved;\n}\nfunction mergeNamespaceSearchResults(\n lists: Array<{ namespace: string; results: QmdSearchResult[] }>,\n maxResults: number,\n): QmdSearchResult[] {\n const merged = new Map<string, QmdSearchResult>();\n\n for (const { namespace, results } of lists) {\n for (const result of results) {\n const key = `${namespace}\\0${result.path || result.docid}`;\n const existing = merged.get(key);\n if (!existing) {\n merged.set(key, { ...result, namespace });\n continue;\n }\n if (result.score > existing.score) {\n merged.set(key, {\n ...result,\n namespace,\n snippet: existing.snippet || result.snippet || \"\",\n });\n }\n }\n }\n\n return [...merged.values()]\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults);\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/extraction-error-classification.ts"],"sourcesContent":["import type { ExtractionFailureClass } from \"./types.js\";\nimport { isTransientHttpError } from \"./connectors/live/transient-errors.js\";\n\n/**\n * Read a numeric HTTP status off a thrown error without re-implementing the\n * shared transient classifier. Uses `in`/typeof narrowing (no inline casts).\n */\nfunction httpStatusFromError(err: unknown): number | undefined {\n if (!err || typeof err !== \"object\") return undefined;\n if (\"status\" in err && typeof err.status === \"number\" && Number.isFinite(err.status)) return err.status;\n if (\"statusCode\" in err && typeof err.statusCode === \"number\" && Number.isFinite(err.statusCode)) {\n return err.statusCode;\n }\n return undefined;\n}\n\n/**\n * Map a thrown extraction error to a coarse failure class for the retry/breaker\n * layer. 401/403 → `auth_config` (misconfigured provider, open the breaker);\n * transient (429/5xx/network, per the shared `isTransientHttpError`) → back off;\n * anything else defaults to `provider_retryable` (fail-open toward retry, but\n * capped by the per-fingerprint attempt budget). Never throws.\n */\nexport function classifyExtractionThrownError(err: unknown): ExtractionFailureClass {\n try {\n const status = httpStatusFromError(err);\n if (status === 401 || status === 403) return \"auth_config\";\n if (isTransientHttpError(err)) return \"provider_retryable\";\n return \"provider_retryable\";\n } catch {\n return \"provider_retryable\";\n }\n}\n\n/**\n * Map the gateway fallback's discriminated parse-failure reason to a coarse\n * extraction failure class. \"no models configured\" is an auth/config problem;\n * an HTTP/transport failure backs off; an unparseable-but-present response is a\n * genuine empty-parse.\n */\nexport function classifyFallbackParseFailure(\n reason: \"no_models\" | \"empty\" | \"http_error\",\n): ExtractionFailureClass {\n switch (reason) {\n case \"no_models\":\n return \"auth_config\";\n case \"http_error\":\n return \"provider_retryable\";\n case \"empty\":\n return \"parse_empty\";\n }\n}\n"],"mappings":";;;;;AAOA,SAAS,oBAAoB,KAAkC;AAC7D,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,MAAI,YAAY,OAAO,OAAO,IAAI,WAAW,YAAY,OAAO,SAAS,IAAI,MAAM,EAAG,QAAO,IAAI;AACjG,MAAI,gBAAgB,OAAO,OAAO,IAAI,eAAe,YAAY,OAAO,SAAS,IAAI,UAAU,GAAG;AAChG,WAAO,IAAI;AAAA,EACb;AACA,SAAO;AACT;AASO,SAAS,8BAA8B,KAAsC;AAClF,MAAI;AACF,UAAM,SAAS,oBAAoB,GAAG;AACtC,QAAI,WAAW,OAAO,WAAW,IAAK,QAAO;AAC7C,QAAI,qBAAqB,GAAG,EAAG,QAAO;AACtC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQO,SAAS,6BACd,QACwB;AACxB,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/providers/codex-subscription.ts","../src/fallback-llm-codex-subscription.ts"],"sourcesContent":["/**\n * Codex subscription extraction provider (issue #2784).\n *\n * Routes extraction/consolidation LLM calls through the `codex` CLI so the\n * operator's Codex subscription (ChatGPT OAuth login) authenticates the\n * request — no OpenAI API key and no codex-openai-proxy. Credentials stay in\n * the CLI's own auth store; this module never reads, accepts, or logs tokens.\n *\n * Transport contract mirrors `packages/bench/src/providers/codex-cli.ts`\n * (`codex exec --json --output-last-message`, env allowlist, login-status\n * precheck) but lives in core so the standalone daemon and host plugins get\n * a working `api: \"codex-cli\"` transport without importing the optional\n * bench package. Registered through the existing\n * `setCodexCliFallbackRunnerForProcess` seam, and only when no host or\n * benchmark runner has claimed it first.\n */\n\nimport { mkdir, mkdtemp, readFile, rm, stat } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nimport type {\n CodexCliFallbackConfig,\n CodexCliFallbackMessage,\n CodexCliFallbackRequest,\n CodexCliFallbackResult,\n CodexCliFallbackRunner,\n} from \"../cli-fallback.js\";\nimport { getCodexCliFallbackRunnerForProcess, isCodexCliFallbackRunnerRegistered, normalizeCodexCliTimeoutMs, setCodexCliFallbackRunnerForProcess } from \"../cli-fallback.js\";\nimport { log } from \"../logger.js\";\nimport { launchProcess } from \"../runtime/child-process.js\";\nimport type { CodexCliReasoningEffort, ModelProviderConfig } from \"../types.js\";\nimport { expandTildePath } from \"../utils/path.js\";\n\nexport const CODEX_SUBSCRIPTION_PROVIDER_ID = \"codex-subscription\";\n\n/** Env var overriding the codex executable (mirrors the bench provider). */\nconst CODEX_EXECUTABLE_ENV = \"REMNIC_CODEX_EXECUTABLE\";\n\nconst DEFAULT_REASONING_EFFORT: CodexCliReasoningEffort = \"medium\";\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst LOGIN_STATUS_TIMEOUT_MS = 10_000;\nconst LOGIN_STATUS_CACHE_TTL_MS = 10 * 60_000;\nconst STDIO_LIMIT = 64_000;\nconst OUTPUT_SUMMARY_LIMIT = 500;\n/**\n * Env keys whose value is a filesystem path. Relative values resolve against\n * the original process cwd before either child launches, because the exec\n * child runs with cwd = the ephemeral workspace (same rule as executables).\n */\nconst PATH_BEARING_ENV_KEYS: Readonly<Record<string, true>> = Object.freeze({ CODEX_HOME: true, HOME: true, USERPROFILE: true });\n\n/**\n * Environment keys forwarded to the codex child. Everything else — including\n * ambient `OPENAI_API_KEY` / `OPENAI_BASE_URL` — is stripped so the CLI cannot\n * silently fall back to metered API-key auth instead of the subscription\n * login. Mirrors the bench provider's allowlist.\n */\nconst CODEX_RUNTIME_ENV_ALLOWLIST: Readonly<Record<string, true>> = Object.freeze({\n ALL_PROXY: true,\n APPDATA: true,\n CODEX_HOME: true,\n COLORTERM: true,\n COMSPEC: true,\n FORCE_COLOR: true,\n HOME: true,\n HOMEDRIVE: true,\n HOMEPATH: true,\n LANG: true,\n LOCALAPPDATA: true,\n LOGNAME: true,\n NO_COLOR: true,\n NODE_EXTRA_CA_CERTS: true,\n NO_PROXY: true,\n NUMBER_OF_PROCESSORS: true,\n OS: true,\n PATH: true,\n PATHEXT: true,\n PROGRAMDATA: true,\n PROCESSOR_ARCHITECTURE: true,\n HTTP_PROXY: true,\n HTTPS_PROXY: true,\n SHELL: true,\n SSL_CERT_DIR: true,\n SSL_CERT_FILE: true,\n SYSTEMDRIVE: true,\n SYSTEMROOT: true,\n TEMP: true,\n TERM: true,\n TMP: true,\n TMPDIR: true,\n USER: true,\n USERNAME: true,\n USERPROFILE: true,\n WINDIR: true,\n XDG_CACHE_HOME: true,\n XDG_CONFIG_HOME: true,\n XDG_DATA_HOME: true,\n XDG_RUNTIME_DIR: true,\n});\n\nconst LOGIN_OK_PATTERN = /logged in using chatgpt/i;\nconst LOGIN_API_KEY_PATTERN = /api key/i;\n/** CLI output shapes that mean the subscription session was rejected. */\nconst AUTH_FAILURE_PATTERN =\n /\\b401\\b|\\b403\\b|unauthorized|forbidden|not logged in|no active|re-?authenticat|token expired|session expired|please log ?in/i;\nconst TIMEOUT_PATTERN = /timed out after \\d+ms/i;\n/** Secret shapes a codex CLI could echo into errors; replaced before surfacing. */\nconst SECRET_ECHO_PATTERNS: readonly RegExp[] = [\n /sk-[A-Za-z0-9_-]{8,}/g,\n /Bearer\\s+[A-Za-z0-9._-]{8,}/g,\n /eyJ[A-Za-z0-9._-]{10,}/g,\n];\n\n/**\n * Built-in provider entry so `\"codex-subscription/<model>\"` chains resolve\n * with no models.json and no apiKey — the transport owns authentication.\n */\nexport function codexSubscriptionBuiltinProviderConfig(): ModelProviderConfig {\n return {\n baseUrl: \"codex-cli://subscription\",\n api: \"codex-cli\",\n models: [],\n };\n}\n\nexport type CodexSubscriptionAuthReason = \"unauthenticated\" | \"expired_or_revoked\";\n\n/** Login/authorization failure with actionable re-auth guidance. */\nexport class CodexSubscriptionAuthError extends Error {\n readonly reason: CodexSubscriptionAuthReason;\n\n constructor(reason: CodexSubscriptionAuthReason, message: string) {\n super(message);\n this.name = \"CodexSubscriptionAuthError\";\n this.reason = reason;\n }\n}\n\n/** Provider config violated the no-raw-credentials contract. */\nexport class CodexSubscriptionConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CodexSubscriptionConfigError\";\n }\n}\n\n/** Request exceeded its deadline. Abort-driven cancellations rethrow the\n * caller's own abort reason instead, preserving the AbortError contract. */\nexport class CodexSubscriptionTimeoutError extends Error {\n constructor(timeoutMs: number) {\n super(`codex-subscription request timed out after ${timeoutMs}ms`);\n this.name = \"TimeoutError\";\n }\n}\n\nexport interface CodexSubscriptionExecRequest {\n executable: string;\n args: string[];\n input: string;\n env: NodeJS.ProcessEnv;\n outputPath: string;\n workspacePath: string;\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\nexport interface CodexSubscriptionExecResult {\n status: number | null;\n signal?: NodeJS.Signals | null;\n stdout: string;\n stderr: string;\n outputText: string;\n}\n\nexport interface CodexSubscriptionRunnerDeps {\n /** Runs `codex exec`. Default: isolated subprocess via launchProcess. */\n runCodexExec?: (request: CodexSubscriptionExecRequest) => Promise<CodexSubscriptionExecResult>;\n /** Runs `codex login status`. Default: isolated subprocess. Receives the\n * login-status timeout budget (capped by the request deadline) and the\n * shared-check abort signal (fires when the last waiter leaves). */\n runLoginStatus?: (\n executable: string,\n env: NodeJS.ProcessEnv,\n timeoutMs: number,\n signal?: AbortSignal\n ) => Promise<{ status: number | null; stdout: string; stderr: string }>;\n /** Environment the isolated child env is filtered from. Tests inject fakes. */\n env?: NodeJS.ProcessEnv;\n tmpdir?: () => string;\n now?: () => number;\n}\n\ninterface CommandOutput {\n status: number | null;\n signal?: NodeJS.Signals | null;\n stdout: string;\n stderr: string;\n}\n\ninterface LoginStatusCacheEntry {\n at: number;\n promise: Promise<void>;\n /** Auth-store fingerprint at check time; a mismatch invalidates the entry. */\n fingerprint: string | null;\n /** Live waiters. The in-flight check aborts when the last waiter leaves. */\n waiters: number;\n settled: boolean;\n controller: AbortController;\n}\n\nconst loginStatusCache = new Map<string, LoginStatusCacheEntry>();\nconst childrenByRunner = new WeakMap<CodexCliFallbackRunner, Set<number>>();\nconst runnerByOwner = new WeakMap<object, CodexCliFallbackRunner>();\nconst shutdownByRunner = new WeakMap<CodexCliFallbackRunner, AbortController>();\nlet defaultRegisteredRunner: CodexCliFallbackRunner | undefined;\nlet coreRunnerRegistered = false;\n\nexport function createCodexSubscriptionRunner(deps: CodexSubscriptionRunnerDeps = {}): CodexCliFallbackRunner {\n const envSource = deps.env ?? process.env;\n const children = new Set<number>();\n const shutdown = new AbortController();\n const runnerDeps: CodexSubscriptionRunnerDeps = {\n ...deps,\n runCodexExec: deps.runCodexExec ?? ((request) => runCodexExecSubprocess(request, children)),\n runLoginStatus:\n deps.runLoginStatus ??\n ((executable, env, timeoutMs, signal) =>\n runLoginStatusSubprocess(executable, env, timeoutMs, signal, children)),\n };\n const runner: CodexCliFallbackRunner = (request) => {\n const signal = request.options.signal\n ? AbortSignal.any([request.options.signal, shutdown.signal])\n : shutdown.signal;\n if (signal.aborted) {\n return Promise.reject(abortErrorOf(signal));\n }\n return runCodexSubscriptionRequest(\n { ...request, options: { ...request.options, signal } },\n runnerDeps,\n envSource,\n );\n };\n childrenByRunner.set(runner, children);\n shutdownByRunner.set(runner, shutdown);\n return runner;\n}\n\n/** One runner per owning runtime/config object so teardown cannot cross instances. */\nexport function getCodexSubscriptionRunnerForOwner(owner: object): CodexCliFallbackRunner {\n let runner = runnerByOwner.get(owner);\n const shutdown = runner ? shutdownByRunner.get(runner) : undefined;\n if (!runner || shutdown?.signal.aborted) {\n runner = createCodexSubscriptionRunner();\n runnerByOwner.set(owner, runner);\n }\n return runner;\n}\n\n/** Shutdown signal for the owning runner, if this function is a core runner. */\nexport function getCodexSubscriptionShutdownSignal(\n runner: CodexCliFallbackRunner,\n): AbortSignal | undefined {\n return shutdownByRunner.get(runner)?.signal;\n}\n\n/**\n * Registers the core subprocess transport on the codex-cli seam, but only\n * when no runner is registered yet — a host or benchmark runner that claimed\n * the seam first always wins. If the seam was cleared afterwards\n * (setCodexCliFallbackRunnerForProcess(undefined)), the core runner is\n * re-registered so the next call still routes. Idempotent.\n */\nexport function ensureCodexSubscriptionRunnerRegistered(deps: CodexSubscriptionRunnerDeps = {}): boolean {\n if (isCodexCliFallbackRunnerRegistered()) return false;\n defaultRegisteredRunner = createCodexSubscriptionRunner(deps);\n setCodexCliFallbackRunnerForProcess(defaultRegisteredRunner);\n coreRunnerRegistered = true;\n return true;\n}\n\n/** True when the process seam still holds the core default runner. */\nexport function isDefaultRegisteredCodexSubscriptionRunner(): boolean {\n return defaultRegisteredRunner !== undefined\n && getCodexCliFallbackRunnerForProcess() === defaultRegisteredRunner;\n}\n\n/** Host shutdown hook: terminate this runtime's detached Codex children. Does not exit. */\nexport function terminateActiveCodexSubscriptionChildren(\n signal: NodeJS.Signals = \"SIGTERM\",\n runner?: CodexCliFallbackRunner,\n): void {\n const target = runner ?? defaultRegisteredRunner;\n if (!target) return;\n const shutdown = shutdownByRunner.get(target);\n if (shutdown && !shutdown.signal.aborted) {\n shutdown.abort(new DOMException(\"The operation was aborted.\", \"AbortError\"));\n }\n const pids = childrenByRunner.get(target);\n if (!pids) return;\n for (const pid of pids) {\n terminateCodexChildPid(pid, signal);\n }\n}\n\n/** SIGTERM now, SIGKILL after a bound, even if the caller later awaits drain. */\nexport function beginCodexSubscriptionShutdown(\n runner?: CodexCliFallbackRunner,\n forceKillAfterMs = 1_000,\n): () => void {\n terminateActiveCodexSubscriptionChildren(\"SIGTERM\", runner);\n const timer = setTimeout(() => {\n terminateActiveCodexSubscriptionChildren(\"SIGKILL\", runner);\n }, forceKillAfterMs);\n timer.unref();\n return () => {\n clearTimeout(timer);\n terminateActiveCodexSubscriptionChildren(\"SIGKILL\", runner);\n };\n}\nasync function runCodexSubscriptionRequest(\n request: CodexCliFallbackRequest,\n deps: CodexSubscriptionRunnerDeps,\n envSource: NodeJS.ProcessEnv\n): Promise<CodexCliFallbackResult> {\n const { config } = request;\n assertNoApiKeyConfig(config);\n const executable = resolveExecutable(config, envSource);\n const env = buildIsolatedEnv(envSource);\n\n const providerTimeoutMs = config.retryOptions?.timeoutMs !== undefined\n ? normalizeCodexCliTimeoutMs(config.retryOptions.timeoutMs)\n : undefined;\n const timeoutMs = request.options.timeoutMs ?? providerTimeoutMs ?? DEFAULT_TIMEOUT_MS;\n // The effective deadline starts BEFORE the login-status precheck: login\n // consumes the same call/provider timeout budget, it is not additive.\n const now = deps.now ?? Date.now;\n const deadlineStartedAt = now();\n if (request.options.signal?.aborted) {\n throw abortErrorOf(request.options.signal);\n }\n await assertSubscriptionLogin(executable, env, deps, {\n loginStatusTimeoutMs: Math.min(LOGIN_STATUS_TIMEOUT_MS, timeoutMs),\n callerTimeoutMs: timeoutMs,\n deadlineStartedAt,\n signal: request.options.signal,\n });\n\n if (request.options.signal?.aborted) {\n throw abortErrorOf(request.options.signal);\n }\n\n const remainingTimeoutMs = timeoutMs - (now() - deadlineStartedAt);\n if (remainingTimeoutMs <= 0) {\n throw new CodexSubscriptionTimeoutError(timeoutMs);\n }\n let tempDir: string | undefined;\n try {\n tempDir = await mkdtemp(path.join(deps.tmpdir?.() ?? os.tmpdir(), \"remnic-codex-sub-\"));\n const workspacePath = path.join(tempDir, \"workspace\");\n const outputPath = path.join(tempDir, \"last-message.txt\");\n await mkdir(workspacePath, { recursive: true });\n\n const runCodexExec = deps.runCodexExec!;\n const result = await runCodexExec({\n executable,\n args: buildExecArgs(request.modelId, config, workspacePath, outputPath),\n input: buildPrompt(request.messages),\n env,\n outputPath,\n workspacePath,\n timeoutMs: remainingTimeoutMs,\n signal: request.options.signal,\n });\n\n if (result.status !== 0) {\n const failure = execFailureError(result, remainingTimeoutMs, executable, env);\n if (failure instanceof CodexSubscriptionTimeoutError) {\n throw failure;\n }\n if (request.options.signal?.aborted) {\n throw abortErrorOf(request.options.signal);\n }\n throw failure;\n }\n if (request.options.signal?.aborted) {\n throw abortErrorOf(request.options.signal);\n }\n\n const content = result.outputText.trim();\n if (content.length === 0) {\n throw new Error(\n `codex-subscription: codex exec returned no final message (${summarizeOutput(result.stderr, result.stdout)})`\n );\n }\n return { content, ...usageFrom(result) };\n } finally {\n if (tempDir) {\n await rm(tempDir, { force: true, recursive: true }).catch(() => {});\n }\n }\n}\n\n/**\n * This provider authenticates exclusively through the codex CLI login, so a\n * configured apiKey is a configuration mistake — reject it without echoing\n * the value.\n */\nexport function assertNoApiKeyConfig(config: CodexCliFallbackConfig): void {\n if (config.apiKey !== undefined && config.apiKey !== \"\") {\n throw new CodexSubscriptionConfigError(\n `${CODEX_SUBSCRIPTION_PROVIDER_ID} does not accept apiKey configuration: it authenticates through the Codex CLI login. Remove the apiKey field and run \\`codex login\\` with a ChatGPT account instead.`\n );\n }\n}\n\nfunction resolveExecutable(config: CodexCliFallbackConfig, env: NodeJS.ProcessEnv): string {\n const configured = config.codexCliExecutable ?? config.executable ?? env[CODEX_EXECUTABLE_ENV] ?? \"codex\";\n const expanded = expandTildePath(String(configured).trim());\n if (expanded.trim().length === 0) {\n throw new CodexSubscriptionConfigError(`${CODEX_EXECUTABLE_ENV} / executable must not be empty`);\n }\n // The exec child runs with cwd = the temp workspace, and spawn resolves a\n // relative executable against the CHILD cwd. Resolve relative paths against\n // the original process cwd now so `./codex` stays valid; bare names keep\n // PATH lookup.\n if (expanded.includes(\"/\") || expanded.includes(\"\\\\\")) {\n return path.resolve(expanded);\n }\n return expanded;\n}\n\nfunction buildIsolatedEnv(source: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = {};\n for (const [key, value] of Object.entries(source)) {\n if (value !== undefined && isAllowedEnvKey(key)) {\n env[key] = PATH_BEARING_ENV_KEYS[key.toUpperCase()] === true\n ? normalizePathEnvValue(value)\n : value;\n }\n }\n return env;\n}\n\n/**\n * The exec child runs with cwd = the ephemeral workspace while the login\n * child runs with cwd = this process, so a relative HOME/CODEX_HOME would\n * resolve differently per child. Anchor both to the original process cwd.\n */\nfunction normalizePathEnvValue(value: string): string {\n const trimmed = value.trim();\n if (trimmed.length === 0) {\n return value;\n }\n const expanded = expandTildePath(trimmed);\n return path.isAbsolute(expanded) ? expanded : path.resolve(expanded);\n}\nfunction isAllowedEnvKey(key: string): boolean {\n const normalized = key.toUpperCase();\n return CODEX_RUNTIME_ENV_ALLOWLIST[normalized] === true || normalized.startsWith(\"LC_\");\n}\n\ninterface LoginCheckContext {\n /** Budget for the login-status subprocess itself. */\n loginStatusTimeoutMs: number;\n /** The caller's overall effective deadline (login + exec). */\n callerTimeoutMs: number;\n deadlineStartedAt: number;\n signal?: AbortSignal;\n}\n\n/**\n * Verifies the operator's Codex subscription login via `codex login status`.\n * Success is cached briefly; failures are never cached so a re-login takes\n * effect on the next request. A cached success is also invalidated when the\n * auth store changes on disk (e.g. another process switches the same Codex\n * home from a ChatGPT login to an API key), so the cache can never mask a\n * later non-subscription login mode.\n */\nasync function assertSubscriptionLogin(\n executable: string,\n env: NodeJS.ProcessEnv,\n deps: CodexSubscriptionRunnerDeps,\n ctx: LoginCheckContext\n): Promise<void> {\n const now = deps.now ?? Date.now;\n const cacheKey = `${executable}\\0${resolveCodexAuthHome(env) ?? \"\"}`;\n const cached = loginStatusCache.get(cacheKey);\n if (cached && now() - cached.at < LOGIN_STATUS_CACHE_TTL_MS) {\n if (!cached.settled || (await authStoreFingerprint(env)) === cached.fingerprint) {\n await waitForLoginEntry(cached, cacheKey, ctx, now);\n return;\n }\n }\n loginStatusCache.delete(cacheKey);\n if (ctx.signal?.aborted) {\n throw abortErrorOf(ctx.signal);\n }\n const entry: LoginStatusCacheEntry = {\n at: now(),\n fingerprint: null,\n waiters: 0,\n settled: false,\n controller: new AbortController(),\n promise: Promise.resolve(undefined),\n };\n entry.promise = runLoginStatusCheck(executable, env, deps, ctx, entry);\n entry.promise.then(\n () => {\n entry.settled = true;\n },\n () => {\n entry.settled = true;\n if (loginStatusCache.get(cacheKey) === entry) {\n loginStatusCache.delete(cacheKey);\n }\n }\n );\n loginStatusCache.set(cacheKey, entry);\n await waitForLoginEntry(entry, cacheKey, ctx, now);\n}\n\nasync function runLoginStatusCheck(\n executable: string,\n env: NodeJS.ProcessEnv,\n deps: CodexSubscriptionRunnerDeps,\n ctx: LoginCheckContext,\n entry: LoginStatusCacheEntry\n): Promise<void> {\n const runLoginStatus = deps.runLoginStatus!;\n const result = await runLoginStatus(executable, env, ctx.loginStatusTimeoutMs, entry.controller.signal);\n const output = `${result.stdout}\\n${result.stderr}`.trim();\n if (TIMEOUT_PATTERN.test(output)) {\n // A login-status subprocess timeout is a deadline expiry, not an auth\n // failure — never report it as \"unauthenticated\".\n throw new CodexSubscriptionTimeoutError(ctx.loginStatusTimeoutMs);\n }\n if (result.status === 0 && LOGIN_OK_PATTERN.test(output)) {\n entry.fingerprint = await authStoreFingerprint(env);\n return;\n }\n const apiKeyNote = LOGIN_API_KEY_PATTERN.test(output)\n ? \" The CLI currently reports an API-key login; subscription extraction needs a ChatGPT login.\"\n : \"\";\n throw new CodexSubscriptionAuthError(\n \"unauthenticated\",\n `codex-subscription: no ChatGPT-backed Codex login found. Run \\`codex login\\` and choose the ChatGPT account option, then retry.${apiKeyNote}`\n );\n}\n\n/**\n * Waits on a shared login check with this caller's own budget. A deadline or\n * caller abort rejects immediately — without cancelling the shared check\n * while other callers still wait on it. When the LAST waiter leaves an\n * in-flight check, the subprocess is aborted and the entry dropped so a later\n * caller starts a fresh check.\n */\nasync function waitForLoginEntry(\n entry: LoginStatusCacheEntry,\n cacheKey: string,\n ctx: LoginCheckContext,\n now: () => number\n): Promise<void> {\n const remainingMs = ctx.callerTimeoutMs - (now() - ctx.deadlineStartedAt);\n if (remainingMs <= 0) {\n throw new CodexSubscriptionTimeoutError(ctx.callerTimeoutMs);\n }\n const signal = ctx.signal;\n let rejectOnAbort!: (reason?: unknown) => void;\n const abortWait = new Promise<never>((_resolve, reject) => {\n rejectOnAbort = reject;\n });\n // Identity matters: the same reference is removed in the finally below.\n const onAbort = (): void => {\n if (signal === undefined) return;\n rejectOnAbort(abortErrorOf(signal));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n entry.waiters++;\n // The deadline timer intentionally holds the event loop: this caller's\n // await is backed by nothing else while the shared check is in flight.\n let deadlineTimer: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n entry.promise,\n abortWait,\n new Promise<never>((_resolve, reject) => {\n deadlineTimer = setTimeout(\n () => reject(new CodexSubscriptionTimeoutError(ctx.callerTimeoutMs)),\n remainingMs\n );\n }),\n ]);\n } catch (err) {\n if (signal?.aborted) {\n throw abortErrorOf(signal);\n }\n throw err;\n } finally {\n clearTimeout(deadlineTimer);\n signal?.removeEventListener(\"abort\", onAbort);\n entry.waiters--;\n if (entry.waiters <= 0 && !entry.settled) {\n entry.controller.abort();\n if (loginStatusCache.get(cacheKey) === entry) {\n loginStatusCache.delete(cacheKey);\n }\n }\n }\n}\n\n/**\n * `mtimeMs:size` of the Codex auth store, read as metadata only — the\n * provider never reads the store's contents. A change between the cached\n * check and now invalidates the cached login mode.\n */\nasync function authStoreFingerprint(env: NodeJS.ProcessEnv): Promise<string | null> {\n const home = resolveCodexAuthHome(env);\n if (!home) {\n return null;\n }\n try {\n const stats = await stat(path.join(home, \"auth.json\"));\n return `${stats.mtimeMs}:${stats.size}`;\n } catch {\n return null;\n }\n}\n\nfunction resolveCodexAuthHome(env: NodeJS.ProcessEnv): string | undefined {\n if (env.CODEX_HOME) return env.CODEX_HOME;\n const profile = env.HOME ?? env.USERPROFILE;\n return profile ? path.join(profile, \".codex\") : undefined;\n}\n\n/**\n * Args mirror the bench provider: fully sandboxed, ephemeral, no tools/hooks/\n * plugins/memories — extraction must behave as a plain completion endpoint.\n */\nfunction buildExecArgs(\n modelId: string,\n config: CodexCliFallbackConfig,\n workspacePath: string,\n outputPath: string\n): string[] {\n const reasoningEffort = readReasoningEffort(config) ?? DEFAULT_REASONING_EFFORT;\n return [\n \"exec\",\n \"--strict-config\",\n \"--model\",\n modelId,\n \"--config\",\n `model_reasoning_effort=${JSON.stringify(reasoningEffort)}`,\n \"--config\",\n 'approval_policy=\"never\"',\n \"--config\",\n 'web_search=\"disabled\"',\n \"--disable\",\n \"hooks\",\n \"--disable\",\n \"shell_tool\",\n \"--disable\",\n \"unified_exec\",\n \"--disable\",\n \"apps\",\n \"--disable\",\n \"plugins\",\n \"--disable\",\n \"remote_plugin\",\n \"--disable\",\n \"multi_agent\",\n \"--disable\",\n \"browser_use\",\n \"--disable\",\n \"browser_use_external\",\n \"--disable\",\n \"computer_use\",\n \"--disable\",\n \"image_generation\",\n \"--disable\",\n \"in_app_browser\",\n \"--disable\",\n \"goals\",\n \"--disable\",\n \"memories\",\n \"--disable\",\n \"chronicle\",\n \"--disable\",\n \"tool_suggest\",\n \"--disable\",\n \"workspace_dependencies\",\n \"--disable\",\n \"shell_snapshot\",\n \"--ephemeral\",\n \"--ignore-user-config\",\n \"--ignore-rules\",\n \"--sandbox\",\n \"read-only\",\n \"--cd\",\n workspacePath,\n \"--skip-git-repo-check\",\n \"--json\",\n \"--output-last-message\",\n outputPath,\n \"-\",\n ];\n}\n\nfunction readReasoningEffort(config: CodexCliFallbackConfig): CodexCliReasoningEffort | undefined {\n for (const value of [config.codexCliReasoningEffort, config.reasoningEffort]) {\n if (typeof value === \"string\") {\n const normalized = value.trim().toLowerCase();\n if (normalized === \"low\" || normalized === \"medium\" || normalized === \"high\" || normalized === \"xhigh\") {\n return normalized;\n }\n throw new CodexSubscriptionConfigError(\n \"codex-subscription reasoningEffort must be one of low, medium, high, xhigh (got unrecognized value)\"\n );\n }\n }\n return undefined;\n}\n\n/**\n * One JSON object per message: role boundaries are structural (JSON string\n * escaping), so literal `[system]`/role-marker text inside message content\n * can never forge another role's turn. Content stays model-visible verbatim.\n */\nfunction buildPrompt(messages: readonly CodexCliFallbackMessage[]): string {\n const transcript = messages\n .map((message) => JSON.stringify({ role: message.role, content: message.content }))\n .join(\"\\n\");\n return [\n \"You are acting as an LLM completion endpoint for a memory-extraction pipeline, not as a coding agent.\",\n \"Answer the request in the transcript below. Do not inspect files, run commands, browse, or use tools.\",\n \"Return only the final answer text. If the request asks for JSON, return raw JSON only.\",\n \"\",\n 'TRANSCRIPT (JSON Lines: one {\"role\":\"...\",\"content\":\"...\"} object per message; newlines inside content are escaped):',\n transcript,\n ].join(\"\\n\");\n}\n\nfunction execFailureError(\n result: CodexSubscriptionExecResult,\n timeoutMs: number,\n executable: string,\n env: NodeJS.ProcessEnv\n): Error {\n const combined = `${result.stderr}\\n${result.stdout}`;\n // The authoritative timeout marker wins over auth-pattern text: a timed-out\n // exec may have already printed model/diagnostic output containing 401/403\n // before the deadline fired (issue #2833).\n if (TIMEOUT_PATTERN.test(combined)) {\n return new CodexSubscriptionTimeoutError(timeoutMs);\n }\n if (AUTH_FAILURE_PATTERN.test(combined)) {\n // Re-check login on the next request; the cached status is now stale.\n loginStatusCache.delete(`${executable}\\0${env.CODEX_HOME ?? env.HOME ?? \"\"}`);\n return new CodexSubscriptionAuthError(\n \"expired_or_revoked\",\n \"codex-subscription: the Codex CLI rejected the request as unauthenticated \" +\n \"(session expired or revoked). Run `codex login` again to re-authenticate, then retry.\"\n );\n }\n\n const exitLabel = result.signal ? `signal ${result.signal}` : `exit ${result.status ?? \"unknown\"}`;\n return new Error(\n `codex-subscription: codex exec failed (${exitLabel}): ${summarizeOutput(result.stderr, result.stdout)}`\n );\n}\n\n/** Secret-redacted, then bounded tail of child output — the only child text\n * that ever reaches a thrown error. Redaction runs BEFORE bounding so a\n * secret straddling the cutoff cannot survive as an unmatchable fragment. */\nfunction summarizeOutput(stderr: string, stdout: string): string {\n const summary = [stderr.trim(), stdout.trim()].filter((part) => part.length > 0).join(\"\\n\");\n if (summary.length === 0) {\n return \"no process output\";\n }\n return redactSecretEchoes(summary).slice(-OUTPUT_SUMMARY_LIMIT);\n}\n\nexport function redactSecretEchoes(value: string): string {\n let redacted = value;\n for (const pattern of SECRET_ECHO_PATTERNS) {\n redacted = redacted.replace(pattern, \"[redacted]\");\n }\n return redacted;\n}\ntype CodexSubscriptionUsage = Pick<CodexCliFallbackResult, \"usage\">;\n\nfunction usageFrom(result: CodexSubscriptionExecResult): CodexSubscriptionUsage {\n const usage = parseCodexJsonlUsage(`${result.stdout}\\n${result.stderr}`);\n if (!usage) {\n return {};\n }\n return {\n usage: {\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n totalTokens: usage.inputTokens + usage.outputTokens,\n },\n };\n}\n\nexport function parseCodexJsonlUsage(output: string): { inputTokens: number; outputTokens: number } | undefined {\n let usage: { inputTokens: number; outputTokens: number } | undefined;\n for (const line of output.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"{\")) continue;\n try {\n const event = JSON.parse(trimmed) as {\n type?: unknown;\n usage?: Record<string, unknown>;\n };\n if (event.type !== \"turn.completed\" || !event.usage) continue;\n const inputTokens = readCounter(event.usage.input_tokens);\n const outputTokens = readCounter(event.usage.output_tokens);\n if (inputTokens !== undefined && outputTokens !== undefined) {\n usage = { inputTokens, outputTokens };\n }\n } catch {\n // codex exec prints non-JSON status text alongside JSONL; ignore it\n }\n }\n return usage;\n}\n\nfunction readCounter(value: unknown): number | undefined {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n return undefined;\n }\n return value;\n}\n\nfunction abortErrorOf(signal: AbortSignal): Error {\n if (signal.reason instanceof CodexSubscriptionTimeoutError) return signal.reason;\n const reason =\n signal.reason instanceof Error\n ? signal.reason\n : signal.reason !== undefined\n ? new Error(String(signal.reason))\n : new DOMException(\"The operation was aborted.\", \"AbortError\");\n const match = /fallback LLM timed out after (\\d+)ms/i.exec(reason.message);\n if (match) {\n return new CodexSubscriptionTimeoutError(Number(match[1]));\n }\n return reason;\n}\n\n/** Bounds streamed child output to STDIO_LIMIT, keeping the TAIL — codex\n * prints its final error or turn.completed result last. Secrets are redacted\n * BEFORE bounding so one straddling the cutoff cannot leak a fragment. */\nfunction appendBounded(existing: string, next: string): string {\n const redacted = redactSecretEchoes(existing + next);\n return redacted.length > STDIO_LIMIT ? redacted.slice(-STDIO_LIMIT) : redacted;\n}\n\nasync function runLoginStatusSubprocess(\n executable: string,\n env: NodeJS.ProcessEnv,\n timeoutMs: number,\n signal: AbortSignal | undefined,\n children: Set<number>,\n): Promise<{ status: number | null; stdout: string; stderr: string }> {\n return await runSubprocess(executable, [\"login\", \"status\"], {\n env,\n stdin: undefined,\n timeoutMs,\n timeoutLabel: \"login status\",\n signal,\n children,\n });\n}\n\nasync function runCodexExecSubprocess(\n request: CodexSubscriptionExecRequest,\n children: Set<number>,\n): Promise<CodexSubscriptionExecResult> {\n const result = await runSubprocess(request.executable, request.args, {\n env: request.env,\n stdin: request.input,\n timeoutMs: request.timeoutMs,\n timeoutLabel: \"exec\",\n signal: request.signal,\n cwd: request.workspacePath,\n children,\n });\n if (result.status === 124) return { ...result, outputText: \"\" };\n let outputText = \"\";\n try {\n outputText = (await readFile(request.outputPath, \"utf8\")).trim();\n } catch {\n // Missing output file surfaces as the no-final-message error path.\n }\n return { ...result, outputText };\n}\n\ninterface SubprocessOptions {\n env: NodeJS.ProcessEnv;\n stdin?: string;\n timeoutMs?: number;\n timeoutLabel: string;\n signal?: AbortSignal;\n cwd?: string;\n children: Set<number>;\n}\n\nasync function runSubprocess(executable: string, args: string[], options: SubprocessOptions): Promise<CommandOutput> {\n return await new Promise<CommandOutput>((resolve, reject) => {\n if (options.signal?.aborted) {\n reject(abortErrorOf(options.signal));\n return;\n }\n const child = launchProcess(executable, args, {\n ...(options.cwd ? { cwd: options.cwd } : {}),\n env: options.env,\n stdio: [options.stdin === undefined ? \"ignore\" : \"pipe\", \"pipe\", \"pipe\"],\n detached: process.platform !== \"win32\",\n windowsHide: true,\n });\n registerActiveCodexChild(child.pid, options.children);\n let stdout = \"\";\n let stderr = \"\";\n let timedOut = false;\n let settled = false;\n let killTimeout: ReturnType<typeof setTimeout> | undefined;\n const clearKillTimeout = (): void => {\n if (killTimeout) {\n clearTimeout(killTimeout);\n killTimeout = undefined;\n }\n };\n const terminate = (signal: NodeJS.Signals): void => {\n if (child.pid && process.platform !== \"win32\") {\n try {\n process.kill(-child.pid, signal);\n return;\n } catch {\n // fall through to killing the direct child\n }\n }\n child.kill(signal);\n };\n const scheduleForcedKill = (): void => {\n clearKillTimeout();\n killTimeout = setTimeout(() => terminate(\"SIGKILL\"), 1_000);\n killTimeout.unref();\n };\n const finish = (fn: () => void): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n options.signal?.removeEventListener(\"abort\", onAbort);\n fn();\n };\n const settleTimeout = (): void => {\n timedOut = true;\n stderr = appendBounded(\n stderr,\n `\\ncodex-subscription: ${options.timeoutLabel} timed out after ${options.timeoutMs}ms.`\n );\n finish(() => {\n resolve({\n status: 124,\n signal: \"SIGTERM\",\n stdout,\n stderr,\n });\n });\n };\n const onAbort = (): void => {\n const reasonText =\n options.signal?.reason instanceof Error\n ? options.signal.reason.message\n : String(options.signal?.reason ?? \"\");\n terminate(\"SIGTERM\");\n scheduleForcedKill();\n if (/fallback LLM timed out after \\d+ms/i.test(reasonText)) {\n settleTimeout();\n return;\n }\n finish(() => reject(abortErrorOf(options.signal!)));\n };\n options.signal?.addEventListener(\"abort\", onAbort, { once: true });\n const timeout = options.timeoutMs\n ? setTimeout(() => {\n terminate(\"SIGTERM\");\n scheduleForcedKill();\n settleTimeout();\n }, options.timeoutMs)\n : undefined;\n timeout?.unref();\n child.stdout?.setEncoding(\"utf8\");\n child.stderr?.setEncoding(\"utf8\");\n child.stdout?.on(\"data\", (chunk: string) => {\n stdout = appendBounded(stdout, chunk);\n });\n child.stderr?.on(\"data\", (chunk: string) => {\n stderr = appendBounded(stderr, chunk);\n });\n child.stdin?.on(\"error\", (error: NodeJS.ErrnoException) => {\n stderr = appendBounded(stderr, `\\ncodex-subscription: stdin error: ${error.code ?? error.message}`);\n });\n child.on(\"error\", (error) => {\n unregisterActiveCodexChild(child.pid, options.children);\n finish(() => {\n reject(\n child.pid\n ? new Error(`codex-subscription: codex CLI failed after start: ${safeMessage(error)}`, { cause: error })\n : new CodexSubscriptionAuthError(\n \"unauthenticated\",\n `codex-subscription: codex CLI not found at \\`${executable}\\` — install the Codex CLI and run \\`codex login\\` with a ChatGPT account, then retry.`\n )\n );\n });\n });\n child.on(\"close\", (status, signal) => {\n clearKillTimeout();\n unregisterActiveCodexChild(child.pid, options.children);\n finish(() => {\n resolve({\n status: timedOut ? (status === null || status === 0 ? 124 : status) : status,\n signal: timedOut ? (signal ?? \"SIGTERM\") : signal,\n stdout,\n stderr,\n });\n });\n });\n if (options.stdin !== undefined) {\n try {\n child.stdin?.end(options.stdin);\n } catch (error) {\n log.debug(`codex-subscription: failed writing prompt to stdin: ${safeMessage(error)}`);\n }\n }\n });\n}\n\nfunction safeMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport const __codexSubscriptionTestHooks = {\n activeCodexChildCount: (runner?: CodexCliFallbackRunner): number => {\n const target = runner ?? defaultRegisteredRunner;\n return target ? (childrenByRunner.get(target)?.size ?? 0) : 0;\n },\n appendBounded,\n resetLoginStatusCache: (): void => {\n loginStatusCache.clear();\n },\n isCoreRunnerRegistered: (): boolean => coreRunnerRegistered,\n resetCoreRunnerRegistered: (): void => {\n coreRunnerRegistered = false;\n defaultRegisteredRunner = undefined;\n },\n};\n\nfunction registerActiveCodexChild(pid: number | undefined, children: Set<number>): void {\n if (pid === undefined) return;\n children.add(pid);\n}\n\nfunction unregisterActiveCodexChild(pid: number | undefined, children: Set<number>): void {\n if (pid === undefined) return;\n children.delete(pid);\n}\n\nfunction terminateCodexChildPid(pid: number, signal: NodeJS.Signals): void {\n if (process.platform !== \"win32\") {\n try {\n process.kill(-pid, signal);\n return;\n } catch {\n // Fall back to killing the direct child below.\n }\n }\n\n try {\n process.kill(pid, signal);\n } catch {\n // The child may already have exited.\n }\n}\n","/**\n * Codex-subscription helpers for FallbackLlmClient (issue #2833).\n *\n * Terminal error classification, the `api: \"codex-cli\"` provider attempt,\n * and Codex runner/lifecycle helpers live here so fallback-llm.ts stays\n * generic chain orchestration.\n */\n\nimport { raceAbort } from \"./abort-error.js\";\nimport { callCodexCliFallback, isCodexCliFallbackRunnerRegistered } from \"./cli-fallback.js\";\nimport type { CodexCliFallbackRunner } from \"./cli-fallback.js\";\nimport {\n CODEX_SUBSCRIPTION_PROVIDER_ID,\n CodexSubscriptionAuthError,\n CodexSubscriptionConfigError,\n CodexSubscriptionTimeoutError,\n assertNoApiKeyConfig,\n ensureCodexSubscriptionRunnerRegistered,\n getCodexSubscriptionShutdownSignal,\n isDefaultRegisteredCodexSubscriptionRunner,\n} from \"./providers/codex-subscription.js\";\nimport type { ModelProviderConfig } from \"./types.js\";\n\ntype CodexSubscriptionAttemptResult = {\n content: string;\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n };\n};\n\n/**\n * Terminal codex-subscription failures (timeout, auth, config contract).\n * These carry documented caller guidance (`TimeoutError` name, `codex login`\n * steps), so they must survive the chain instead of collapsing into a\n * generic empty/http_error result (issue #2833).\n */\nexport function isTerminalCodexSubscriptionError(error: unknown): boolean {\n return (\n error instanceof CodexSubscriptionTimeoutError ||\n error instanceof CodexSubscriptionAuthError ||\n error instanceof CodexSubscriptionConfigError\n );\n}\n\n/**\n * Settle a fallback-LLM chain at the caller deadline. Abort the in-flight\n * work, return immediately, and observe the abandoned promise so a late\n * rejection cannot become unhandled.\n */\nexport async function raceFallbackLlmDeadline<T>(\n work: Promise<T>,\n timeoutMs: number,\n abortOnTimeout: () => void,\n): Promise<{ timedOut: true } | { timedOut: false; value: T }> {\n const deadline = new AbortController();\n const timer = setTimeout(() => deadline.abort(), timeoutMs);\n deadline.signal.addEventListener(\"abort\", abortOnTimeout, { once: true });\n try {\n const value = await raceAbort(\n work,\n deadline.signal,\n `fallback LLM timed out after ${timeoutMs}ms`,\n );\n return { timedOut: false, value };\n } catch (error) {\n if (!deadline.signal.aborted) throw error;\n const afterAbort = await Promise.race([\n work.then(\n (value) => ({ state: \"value\" as const, value }),\n (lateError) => ({ state: \"error\" as const, error: lateError }),\n ),\n new Promise<{ state: \"pending\" }>((resolve) => {\n setImmediate(() => resolve({ state: \"pending\" }));\n }),\n ]);\n if (afterAbort.state === \"value\") return { timedOut: false, value: afterAbort.value };\n if (afterAbort.state === \"error\") throw afterAbort.error;\n void work.then(\n () => undefined,\n () => undefined,\n );\n return { timedOut: true };\n } finally {\n clearTimeout(timer);\n deadline.signal.removeEventListener(\"abort\", abortOnTimeout);\n }\n}\n\n/**\n * Attempt the Codex CLI / subscription provider. Returns `undefined` when the\n * model is not `api: \"codex-cli\"` so the generic FallbackLlmClient path runs.\n *\n * Subscription ids reject a configured apiKey before generic secret resolution\n * — otherwise an unresolvable ref throws a generic error and the provider's\n * `codex login` guidance never surfaces (issue #2833). Other `codex-cli`\n * providers still resolve a configured key. Runtime auth is skipped: the CLI\n * login is the credential.\n */\nexport async function tryCodexSubscriptionProvider(\n model: {\n providerId: string;\n modelId: string;\n providerConfig: ModelProviderConfig;\n },\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: { timeoutMs?: number; signal?: AbortSignal },\n resolveFallbackApiKey: () => Promise<string | undefined>,\n runner?: CodexCliFallbackRunner,\n): Promise<CodexSubscriptionAttemptResult | undefined> {\n if (model.providerConfig.api !== \"codex-cli\") return undefined;\n\n if (model.providerId === CODEX_SUBSCRIPTION_PROVIDER_ID) {\n assertNoApiKeyConfig(model.providerConfig);\n }\n\n const resolvedApiKey =\n model.providerConfig.apiKey === undefined ? undefined : await resolveFallbackApiKey();\n const rawKey = model.providerConfig.apiKey;\n const needsResolution =\n rawKey === \"secretref-managed\" || (typeof rawKey === \"object\" && rawKey !== null);\n if (needsResolution && !resolvedApiKey) {\n throw new Error(`API key for provider \"${model.providerId}\" could not be resolved from secret ref`);\n }\n\n const effectiveConfig: ModelProviderConfig = {\n ...model.providerConfig,\n ...(resolvedApiKey ? { apiKey: resolvedApiKey } : {}),\n };\n\n // Let the provider surface its typed timeout before the generic outer deadline.\n const callOptions = {\n timeoutMs: options.timeoutMs === undefined\n ? undefined\n : Math.max(1, options.timeoutMs - Math.min(100, Math.max(5, Math.floor(options.timeoutMs / 5)))),\n signal: options.signal,\n };\n // A host/benchmark runner on the process seam still wins. The core\n // default runner does not: prefer the owning runtime so shutdown\n // terminates the request that runtime started.\n if (isCodexCliFallbackRunnerRegistered() && !(runner && isDefaultRegisteredCodexSubscriptionRunner())) {\n return await callCodexCliFallback(effectiveConfig, model.modelId, messages, callOptions);\n }\n if (runner) {\n return await callCodexCliFallback(effectiveConfig, model.modelId, messages, callOptions, runner);\n }\n ensureCodexSubscriptionRunnerRegistered();\n return await callCodexCliFallback(effectiveConfig, model.modelId, messages, callOptions);\n}\n\nexport function abortReason(signal: AbortSignal | undefined): Error {\n const reason = signal?.reason;\n return reason instanceof Error ? reason : new Error(\"fallback LLM request aborted\");\n}\n\nexport function withCodexRuntimeShutdown<T extends { signal?: AbortSignal }>(\n options: T,\n runner: CodexCliFallbackRunner | undefined,\n): T {\n if (!runner) return options;\n const shutdown = getCodexSubscriptionShutdownSignal(runner);\n if (!shutdown) return options;\n return {\n ...options,\n signal: options.signal ? AbortSignal.any([options.signal, shutdown]) : shutdown,\n };\n}\n"],"mappings":"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","names":[]}