@remnic/core 10.0.59 → 10.0.60

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 (300) hide show
  1. package/dist/access-admin-ops-surface.js +49 -47
  2. package/dist/access-authorization-probe.js +50 -48
  3. package/dist/access-boundary.js +49 -47
  4. package/dist/access-cli.js +136 -134
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-extraction-force-flush.js +49 -47
  7. package/dist/access-http-briefing.js +50 -48
  8. package/dist/access-http-query.js +51 -49
  9. package/dist/access-http.js +72 -70
  10. package/dist/access-identity-continuity-surface.js +49 -47
  11. package/dist/access-lcm-surface.js +49 -47
  12. package/dist/access-mcp.js +60 -58
  13. package/dist/access-namespace-preflight.js +49 -47
  14. package/dist/access-observe-write-category.js +8 -8
  15. package/dist/access-observe-write-surface.js +49 -47
  16. package/dist/access-offline-manifest.js +7 -7
  17. package/dist/access-operations-batch.js +52 -50
  18. package/dist/access-operations.js +59 -57
  19. package/dist/access-recall-concurrency.js +49 -47
  20. package/dist/access-recall-response.js +49 -47
  21. package/dist/access-recall-surface.js +49 -47
  22. package/dist/access-schema.js +7 -7
  23. package/dist/access-service.js +49 -47
  24. package/dist/access-surface-catalog.js +51 -49
  25. package/dist/access-surface-catalog.js.map +1 -1
  26. package/dist/active-recall.js +23 -21
  27. package/dist/active-recall.js.map +1 -1
  28. package/dist/adapters/index.js +7 -7
  29. package/dist/adapters/registry.js +3 -3
  30. package/dist/briefing.js +15 -13
  31. package/dist/buffer.js +5 -5
  32. package/dist/causal-behavior.js +2 -2
  33. package/dist/causal-chain.js +2 -2
  34. package/dist/causal-consolidation.js +18 -16
  35. package/dist/causal-consolidation.js.map +1 -1
  36. package/dist/causal-retrieval.js +2 -2
  37. package/dist/causal-trajectory-graph.js +2 -2
  38. package/dist/causal-trajectory.js +1 -1
  39. package/dist/{chunk-XDKEHZUC.js → chunk-264B57GV.js} +2 -2
  40. package/dist/{chunk-5U2BBF7E.js → chunk-2EJAPJ5G.js} +20 -10
  41. package/dist/chunk-2EJAPJ5G.js.map +1 -0
  42. package/dist/{chunk-6BO27AWQ.js → chunk-2HVCTFKG.js} +2 -2
  43. package/dist/{chunk-3E3Z6UA3.js → chunk-3DG2YAAX.js} +86 -86
  44. package/dist/chunk-4LZ7SVKM.js +211 -0
  45. package/dist/chunk-4LZ7SVKM.js.map +1 -0
  46. package/dist/{chunk-2IVK5IDY.js → chunk-4O4VAEWH.js} +2 -2
  47. package/dist/{chunk-NRGQ5HJO.js → chunk-4P4VLPGB.js} +1 -1
  48. package/dist/{chunk-GIRWNTMV.js → chunk-4PG5R6BJ.js} +2 -2
  49. package/dist/{chunk-PM4PKC3Y.js → chunk-5XY46Z2W.js} +3 -3
  50. package/dist/{chunk-52II7PB6.js → chunk-645WOU5I.js} +4 -4
  51. package/dist/{chunk-RG3I2663.js → chunk-64JLBFCQ.js} +2 -2
  52. package/dist/{chunk-G3T6YMBO.js → chunk-64S6X4IU.js} +7 -7
  53. package/dist/{chunk-FB4JQEFS.js → chunk-66CC6L6R.js} +2 -2
  54. package/dist/{chunk-TYSD7UQO.js → chunk-6BKSUA6P.js} +2 -2
  55. package/dist/{chunk-6AEKSOWV.js → chunk-6I6DFULH.js} +8 -8
  56. package/dist/{chunk-OL7A7NKH.js → chunk-74Z2BYEK.js} +2 -2
  57. package/dist/{chunk-JD5F5MYN.js → chunk-7DHNBABU.js} +3 -3
  58. package/dist/{chunk-JZRQY7ZQ.js → chunk-ADK5TMQL.js} +2 -2
  59. package/dist/{chunk-EJFOGYF3.js → chunk-AWKADEMO.js} +3 -3
  60. package/dist/{chunk-VV73XT3A.js → chunk-BJLCV2P3.js} +2 -2
  61. package/dist/{chunk-Y5KESB7T.js → chunk-C5GTIRIO.js} +38 -38
  62. package/dist/{chunk-LLG5VNK7.js → chunk-DF4SYU4Z.js} +2 -2
  63. package/dist/{chunk-WBN66HPI.js → chunk-ELHJK7LM.js} +6 -6
  64. package/dist/{chunk-YDDLSGYE.js → chunk-F3GX76LV.js} +2 -2
  65. package/dist/{chunk-AAANTXCQ.js → chunk-FZVZYU5C.js} +2 -2
  66. package/dist/{chunk-ON77FQXH.js → chunk-G6GMZJQ4.js} +2 -2
  67. package/dist/{chunk-37VTMUAL.js → chunk-GGHX4YHM.js} +2 -2
  68. package/dist/{chunk-JY2BGCYN.js → chunk-GJF337YM.js} +2 -2
  69. package/dist/{chunk-GDYLZ6FR.js → chunk-HJ3UTGIW.js} +3 -3
  70. package/dist/{chunk-FXWX7VD3.js → chunk-HL643H2F.js} +12 -12
  71. package/dist/{chunk-CCL2OXFO.js → chunk-HSHLDSPX.js} +3 -3
  72. package/dist/{chunk-WXBVGKS6.js → chunk-I6UTOUBK.js} +35 -79
  73. package/dist/chunk-I6UTOUBK.js.map +1 -0
  74. package/dist/{chunk-MLUPSZFK.js → chunk-IA3XZG4V.js} +2 -2
  75. package/dist/{chunk-ISNPYOXR.js → chunk-IJFX4JRI.js} +7 -7
  76. package/dist/{chunk-RTJJPW3C.js → chunk-ILMB3X4X.js} +5 -5
  77. package/dist/{chunk-USNU3BEQ.js → chunk-J53IBVMF.js} +2 -2
  78. package/dist/{chunk-JEX2JL3U.js → chunk-JEDS2QYV.js} +2 -2
  79. package/dist/{chunk-RFT4OPYI.js → chunk-JFRO5HJY.js} +2 -2
  80. package/dist/{chunk-WZYAXOGO.js → chunk-JM2WJBP7.js} +2 -2
  81. package/dist/{chunk-DJFULNXK.js → chunk-JRY55I6Z.js} +2 -2
  82. package/dist/{chunk-YZNTAOPZ.js → chunk-KXDUSGPM.js} +2 -2
  83. package/dist/{chunk-YJHOVA42.js → chunk-L5RMURVI.js} +2 -2
  84. package/dist/{chunk-R4BR62UO.js → chunk-LGLLCWA2.js} +2 -2
  85. package/dist/{chunk-AMKIIRLL.js → chunk-M3GOWG2P.js} +2 -2
  86. package/dist/{chunk-4G2A7MH3.js → chunk-M7KAJBO2.js} +3 -3
  87. package/dist/{chunk-UGTYADB4.js → chunk-MHSUEA32.js} +3 -3
  88. package/dist/{chunk-ERMT5WQM.js → chunk-MKE5DP3S.js} +2 -2
  89. package/dist/{chunk-EH46DHBU.js → chunk-MOB4JHG6.js} +2 -2
  90. package/dist/{chunk-IQSRVR6Z.js → chunk-N5H22V75.js} +2 -2
  91. package/dist/{chunk-WASVDS6G.js → chunk-NF5EHQTJ.js} +4 -4
  92. package/dist/{chunk-RYB553SS.js → chunk-NJZY5LOC.js} +2 -2
  93. package/dist/{chunk-BPIAXMGC.js → chunk-PIVSUPF2.js} +2 -2
  94. package/dist/{chunk-2S6JADBB.js → chunk-PJLJN23N.js} +2 -2
  95. package/dist/{chunk-ZAZZOQAQ.js → chunk-PRSF7DWT.js} +2 -2
  96. package/dist/{chunk-QY24FSXT.js → chunk-PTJWUN4H.js} +45 -45
  97. package/dist/{chunk-GFAEKSFR.js → chunk-QBK3IM6W.js} +5 -5
  98. package/dist/{chunk-KRAMCBIW.js → chunk-QKXPOLQD.js} +4 -4
  99. package/dist/{chunk-VCLNU6MY.js → chunk-QWURVT5Z.js} +2 -2
  100. package/dist/{chunk-YDT3OEYF.js → chunk-R4ZHF4K2.js} +2 -2
  101. package/dist/{chunk-KMJDH4KX.js → chunk-RSYFSCKL.js} +16 -16
  102. package/dist/{chunk-UHH67NLU.js → chunk-T4SMMTGY.js} +2 -2
  103. package/dist/{chunk-DJR37Q37.js → chunk-TIS6T6UP.js} +2 -2
  104. package/dist/{chunk-RKRX4C4H.js → chunk-TPKB7T6Z.js} +2 -2
  105. package/dist/{chunk-JZCBMKR5.js → chunk-TUCEP2LS.js} +5 -5
  106. package/dist/{chunk-OMWQO7H6.js → chunk-UEDC2VGP.js} +2 -2
  107. package/dist/{chunk-KBOQQEVC.js → chunk-UIX4JLVV.js} +2 -2
  108. package/dist/{chunk-NGH74LDV.js → chunk-UP2Q7U4G.js} +9 -9
  109. package/dist/{chunk-HQUYENKK.js → chunk-UY67YP6Q.js} +2 -2
  110. package/dist/{chunk-U2A56LLF.js → chunk-VQ6H4DL6.js} +11 -11
  111. package/dist/{chunk-RHJ5VGB3.js → chunk-W37MS6SX.js} +2 -2
  112. package/dist/{chunk-KAL5SXPP.js → chunk-WJC5KGYC.js} +6 -6
  113. package/dist/{chunk-G6A3SGCE.js → chunk-WVEEVYMH.js} +8 -25
  114. package/dist/chunk-WVEEVYMH.js.map +1 -0
  115. package/dist/{chunk-4B73TQQV.js → chunk-X2TZWVCC.js} +2 -2
  116. package/dist/{chunk-UQBOPCDK.js → chunk-X4PAATLA.js} +2 -2
  117. package/dist/{chunk-24SIB3EW.js → chunk-XWE3EOWX.js} +2 -2
  118. package/dist/{chunk-Y77FXULH.js → chunk-XWXBXBOX.js} +2 -2
  119. package/dist/{chunk-VKQI47DJ.js → chunk-Y7427SL7.js} +4 -4
  120. package/dist/{chunk-TEH5MDX5.js → chunk-YH7HJNWV.js} +22 -22
  121. package/dist/chunk-YHTG64XV.js +117 -0
  122. package/dist/chunk-YHTG64XV.js.map +1 -0
  123. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  124. package/dist/{chunk-2M36PR7R.js → chunk-Z2T5BPOZ.js} +2 -2
  125. package/dist/{chunk-7NT3FKAF.js → chunk-Z4EH5TSO.js} +2 -2
  126. package/dist/{chunk-ZE5N4JSY.js → chunk-ZRDEOC4X.js} +2 -2
  127. package/dist/{chunk-IEW6NDHX.js → chunk-ZXEPLZUQ.js} +9 -9
  128. package/dist/cli.js +94 -92
  129. package/dist/coding/export-okf-codegraph.js +14 -12
  130. package/dist/coding/export-okf-codegraph.js.map +1 -1
  131. package/dist/coding/pre-action-gate.js +2 -2
  132. package/dist/compounding/engine.js +16 -14
  133. package/dist/config.js +23 -21
  134. package/dist/connectors/codex-materialize-runner.js +15 -13
  135. package/dist/connectors/index.js +15 -13
  136. package/dist/convergence-refresh.js +17 -15
  137. package/dist/corpus-scan-worker-host.d.ts +109 -0
  138. package/dist/corpus-scan-worker-host.d.ts.map +1 -0
  139. package/dist/corpus-scan-worker-host.js +15 -0
  140. package/dist/corpus-scan-worker.entry.d.ts +21 -0
  141. package/dist/corpus-scan-worker.entry.d.ts.map +1 -0
  142. package/dist/corpus-scan-worker.entry.js +60 -0
  143. package/dist/corpus-scan-worker.entry.js.map +1 -0
  144. package/dist/corpus-scan-worker.entry.mjs +176 -0
  145. package/dist/corpus-scan.d.ts +71 -0
  146. package/dist/corpus-scan.d.ts.map +1 -0
  147. package/dist/corpus-scan.js +16 -0
  148. package/dist/corpus-watermark.d.ts.map +1 -1
  149. package/dist/corpus-watermark.js +17 -15
  150. package/dist/dashboard-runtime.js +2 -2
  151. package/dist/deep-recall-http-glue.js +8 -8
  152. package/dist/embedding-fallback.js +2 -2
  153. package/dist/{entity-canonical-id-migration-F3JVG6K6.js → entity-canonical-id-migration-CUDCKWPF.js} +4 -2
  154. package/dist/entity-canonical-id-migration-CUDCKWPF.js.map +1 -0
  155. package/dist/entity-retrieval.js +17 -15
  156. package/dist/event-order-recall.js +3 -3
  157. package/dist/external-wiki-access.js +50 -48
  158. package/dist/extraction.js +20 -18
  159. package/dist/{graph-edge-decay-IU75NV42.js → graph-edge-decay-2BZTY2IM.js} +5 -5
  160. package/dist/graph-edge-decay-2BZTY2IM.js.map +1 -0
  161. package/dist/graph-jsonl.js +3 -3
  162. package/dist/graph-snapshot.js +3 -3
  163. package/dist/graph.js +2 -2
  164. package/dist/harmonic-retrieval.js +15 -13
  165. package/dist/index.js +164 -162
  166. package/dist/lcm/engine.js +2 -2
  167. package/dist/lcm/index.js +5 -5
  168. package/dist/location/index.js +17 -15
  169. package/dist/maintenance/memory-governance.js +15 -13
  170. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +15 -13
  171. package/dist/maintenance/rebuild-memory-projection-runner.js +17 -15
  172. package/dist/maintenance/rebuild-memory-projection.js +16 -14
  173. package/dist/memory-browse-operations.js +50 -48
  174. package/dist/memory-browse.js +5 -5
  175. package/dist/namespaces/migrate.js +16 -14
  176. package/dist/namespaces/search.js +8 -8
  177. package/dist/namespaces/storage.js +15 -13
  178. package/dist/offline-sync-changeset-generations.js +4 -4
  179. package/dist/offline-sync-embedding-generation.js +3 -3
  180. package/dist/offline-sync-snapshot-stream.js +7 -7
  181. package/dist/offline-sync.js +6 -6
  182. package/dist/operator-doctor-corpus.js +18 -16
  183. package/dist/operator-toolkit.js +34 -32
  184. package/dist/orchestration/maintenance.js +25 -23
  185. package/dist/orchestrator.js +136 -134
  186. package/dist/qmd.js +4 -4
  187. package/dist/recall-navigation-operations.js +50 -48
  188. package/dist/recall-navigation.js +49 -47
  189. package/dist/recall-state-view-admission.js +5 -5
  190. package/dist/recall-why-service.js +5 -5
  191. package/dist/resume-bundles.js +24 -22
  192. package/dist/search/factory.js +7 -7
  193. package/dist/search/index.js +15 -15
  194. package/dist/semantic-consolidation.js +16 -14
  195. package/dist/semantic-rule-promotion.js +15 -13
  196. package/dist/semantic-rule-verifier.js +15 -13
  197. package/dist/source-agent-qualifier.js +18 -16
  198. package/dist/standup/build.js +15 -13
  199. package/dist/storage/entity-canonical-id-migration.d.ts.map +1 -1
  200. package/dist/storage/memory-read-store.d.ts +5 -9
  201. package/dist/storage/memory-read-store.d.ts.map +1 -1
  202. package/dist/storage.js +16 -14
  203. package/dist/support-passport/index.js +52 -50
  204. package/dist/transfer/export-okf.js +15 -13
  205. package/dist/verified-recall.js +15 -13
  206. package/dist/who-knows-cli.js +16 -14
  207. package/dist/who-knows.js +15 -13
  208. package/package.json +2 -2
  209. package/scripts/build-with-heap.mjs +8 -0
  210. package/src/corpus-scan-worker-host.ts +314 -0
  211. package/src/corpus-scan-worker.entry.mjs +176 -0
  212. package/src/corpus-scan-worker.entry.ts +95 -0
  213. package/src/corpus-scan.ts +215 -0
  214. package/src/corpus-watermark.ts +28 -12
  215. package/src/storage/entity-canonical-id-migration.ts +4 -26
  216. package/src/storage/memory-read-store.ts +17 -99
  217. package/dist/chunk-5U2BBF7E.js.map +0 -1
  218. package/dist/chunk-G6A3SGCE.js.map +0 -1
  219. package/dist/chunk-WXBVGKS6.js.map +0 -1
  220. /package/dist/{chunk-XDKEHZUC.js.map → chunk-264B57GV.js.map} +0 -0
  221. /package/dist/{chunk-6BO27AWQ.js.map → chunk-2HVCTFKG.js.map} +0 -0
  222. /package/dist/{chunk-3E3Z6UA3.js.map → chunk-3DG2YAAX.js.map} +0 -0
  223. /package/dist/{chunk-2IVK5IDY.js.map → chunk-4O4VAEWH.js.map} +0 -0
  224. /package/dist/{chunk-NRGQ5HJO.js.map → chunk-4P4VLPGB.js.map} +0 -0
  225. /package/dist/{chunk-GIRWNTMV.js.map → chunk-4PG5R6BJ.js.map} +0 -0
  226. /package/dist/{chunk-PM4PKC3Y.js.map → chunk-5XY46Z2W.js.map} +0 -0
  227. /package/dist/{chunk-52II7PB6.js.map → chunk-645WOU5I.js.map} +0 -0
  228. /package/dist/{chunk-RG3I2663.js.map → chunk-64JLBFCQ.js.map} +0 -0
  229. /package/dist/{chunk-G3T6YMBO.js.map → chunk-64S6X4IU.js.map} +0 -0
  230. /package/dist/{chunk-FB4JQEFS.js.map → chunk-66CC6L6R.js.map} +0 -0
  231. /package/dist/{chunk-TYSD7UQO.js.map → chunk-6BKSUA6P.js.map} +0 -0
  232. /package/dist/{chunk-6AEKSOWV.js.map → chunk-6I6DFULH.js.map} +0 -0
  233. /package/dist/{chunk-OL7A7NKH.js.map → chunk-74Z2BYEK.js.map} +0 -0
  234. /package/dist/{chunk-JD5F5MYN.js.map → chunk-7DHNBABU.js.map} +0 -0
  235. /package/dist/{chunk-JZRQY7ZQ.js.map → chunk-ADK5TMQL.js.map} +0 -0
  236. /package/dist/{chunk-EJFOGYF3.js.map → chunk-AWKADEMO.js.map} +0 -0
  237. /package/dist/{chunk-VV73XT3A.js.map → chunk-BJLCV2P3.js.map} +0 -0
  238. /package/dist/{chunk-Y5KESB7T.js.map → chunk-C5GTIRIO.js.map} +0 -0
  239. /package/dist/{chunk-LLG5VNK7.js.map → chunk-DF4SYU4Z.js.map} +0 -0
  240. /package/dist/{chunk-WBN66HPI.js.map → chunk-ELHJK7LM.js.map} +0 -0
  241. /package/dist/{chunk-YDDLSGYE.js.map → chunk-F3GX76LV.js.map} +0 -0
  242. /package/dist/{chunk-AAANTXCQ.js.map → chunk-FZVZYU5C.js.map} +0 -0
  243. /package/dist/{chunk-ON77FQXH.js.map → chunk-G6GMZJQ4.js.map} +0 -0
  244. /package/dist/{chunk-37VTMUAL.js.map → chunk-GGHX4YHM.js.map} +0 -0
  245. /package/dist/{chunk-JY2BGCYN.js.map → chunk-GJF337YM.js.map} +0 -0
  246. /package/dist/{chunk-GDYLZ6FR.js.map → chunk-HJ3UTGIW.js.map} +0 -0
  247. /package/dist/{chunk-FXWX7VD3.js.map → chunk-HL643H2F.js.map} +0 -0
  248. /package/dist/{chunk-CCL2OXFO.js.map → chunk-HSHLDSPX.js.map} +0 -0
  249. /package/dist/{chunk-MLUPSZFK.js.map → chunk-IA3XZG4V.js.map} +0 -0
  250. /package/dist/{chunk-ISNPYOXR.js.map → chunk-IJFX4JRI.js.map} +0 -0
  251. /package/dist/{chunk-RTJJPW3C.js.map → chunk-ILMB3X4X.js.map} +0 -0
  252. /package/dist/{chunk-USNU3BEQ.js.map → chunk-J53IBVMF.js.map} +0 -0
  253. /package/dist/{chunk-JEX2JL3U.js.map → chunk-JEDS2QYV.js.map} +0 -0
  254. /package/dist/{chunk-RFT4OPYI.js.map → chunk-JFRO5HJY.js.map} +0 -0
  255. /package/dist/{chunk-WZYAXOGO.js.map → chunk-JM2WJBP7.js.map} +0 -0
  256. /package/dist/{chunk-DJFULNXK.js.map → chunk-JRY55I6Z.js.map} +0 -0
  257. /package/dist/{chunk-YZNTAOPZ.js.map → chunk-KXDUSGPM.js.map} +0 -0
  258. /package/dist/{chunk-YJHOVA42.js.map → chunk-L5RMURVI.js.map} +0 -0
  259. /package/dist/{chunk-R4BR62UO.js.map → chunk-LGLLCWA2.js.map} +0 -0
  260. /package/dist/{chunk-AMKIIRLL.js.map → chunk-M3GOWG2P.js.map} +0 -0
  261. /package/dist/{chunk-4G2A7MH3.js.map → chunk-M7KAJBO2.js.map} +0 -0
  262. /package/dist/{chunk-UGTYADB4.js.map → chunk-MHSUEA32.js.map} +0 -0
  263. /package/dist/{chunk-ERMT5WQM.js.map → chunk-MKE5DP3S.js.map} +0 -0
  264. /package/dist/{chunk-EH46DHBU.js.map → chunk-MOB4JHG6.js.map} +0 -0
  265. /package/dist/{chunk-IQSRVR6Z.js.map → chunk-N5H22V75.js.map} +0 -0
  266. /package/dist/{chunk-WASVDS6G.js.map → chunk-NF5EHQTJ.js.map} +0 -0
  267. /package/dist/{chunk-RYB553SS.js.map → chunk-NJZY5LOC.js.map} +0 -0
  268. /package/dist/{chunk-BPIAXMGC.js.map → chunk-PIVSUPF2.js.map} +0 -0
  269. /package/dist/{chunk-2S6JADBB.js.map → chunk-PJLJN23N.js.map} +0 -0
  270. /package/dist/{chunk-ZAZZOQAQ.js.map → chunk-PRSF7DWT.js.map} +0 -0
  271. /package/dist/{chunk-QY24FSXT.js.map → chunk-PTJWUN4H.js.map} +0 -0
  272. /package/dist/{chunk-GFAEKSFR.js.map → chunk-QBK3IM6W.js.map} +0 -0
  273. /package/dist/{chunk-KRAMCBIW.js.map → chunk-QKXPOLQD.js.map} +0 -0
  274. /package/dist/{chunk-VCLNU6MY.js.map → chunk-QWURVT5Z.js.map} +0 -0
  275. /package/dist/{chunk-YDT3OEYF.js.map → chunk-R4ZHF4K2.js.map} +0 -0
  276. /package/dist/{chunk-KMJDH4KX.js.map → chunk-RSYFSCKL.js.map} +0 -0
  277. /package/dist/{chunk-UHH67NLU.js.map → chunk-T4SMMTGY.js.map} +0 -0
  278. /package/dist/{chunk-DJR37Q37.js.map → chunk-TIS6T6UP.js.map} +0 -0
  279. /package/dist/{chunk-RKRX4C4H.js.map → chunk-TPKB7T6Z.js.map} +0 -0
  280. /package/dist/{chunk-JZCBMKR5.js.map → chunk-TUCEP2LS.js.map} +0 -0
  281. /package/dist/{chunk-OMWQO7H6.js.map → chunk-UEDC2VGP.js.map} +0 -0
  282. /package/dist/{chunk-KBOQQEVC.js.map → chunk-UIX4JLVV.js.map} +0 -0
  283. /package/dist/{chunk-NGH74LDV.js.map → chunk-UP2Q7U4G.js.map} +0 -0
  284. /package/dist/{chunk-HQUYENKK.js.map → chunk-UY67YP6Q.js.map} +0 -0
  285. /package/dist/{chunk-U2A56LLF.js.map → chunk-VQ6H4DL6.js.map} +0 -0
  286. /package/dist/{chunk-RHJ5VGB3.js.map → chunk-W37MS6SX.js.map} +0 -0
  287. /package/dist/{chunk-KAL5SXPP.js.map → chunk-WJC5KGYC.js.map} +0 -0
  288. /package/dist/{chunk-4B73TQQV.js.map → chunk-X2TZWVCC.js.map} +0 -0
  289. /package/dist/{chunk-UQBOPCDK.js.map → chunk-X4PAATLA.js.map} +0 -0
  290. /package/dist/{chunk-24SIB3EW.js.map → chunk-XWE3EOWX.js.map} +0 -0
  291. /package/dist/{chunk-Y77FXULH.js.map → chunk-XWXBXBOX.js.map} +0 -0
  292. /package/dist/{chunk-VKQI47DJ.js.map → chunk-Y7427SL7.js.map} +0 -0
  293. /package/dist/{chunk-TEH5MDX5.js.map → chunk-YH7HJNWV.js.map} +0 -0
  294. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  295. /package/dist/{chunk-2M36PR7R.js.map → chunk-Z2T5BPOZ.js.map} +0 -0
  296. /package/dist/{chunk-7NT3FKAF.js.map → chunk-Z4EH5TSO.js.map} +0 -0
  297. /package/dist/{chunk-ZE5N4JSY.js.map → chunk-ZRDEOC4X.js.map} +0 -0
  298. /package/dist/{chunk-IEW6NDHX.js.map → chunk-ZXEPLZUQ.js.map} +0 -0
  299. /package/dist/{entity-canonical-id-migration-F3JVG6K6.js.map → corpus-scan-worker-host.js.map} +0 -0
  300. /package/dist/{graph-edge-decay-IU75NV42.js.map → corpus-scan.js.map} +0 -0
@@ -0,0 +1,314 @@
1
+ /**
2
+ * Corpus-scan worker host (main-thread starvation fix).
3
+ *
4
+ * The periodic corpus maintenance scans are pure, read-only filesystem work
5
+ * whose volume scales with the corpus (hundreds of thousands of files on a
6
+ * large deployment). Running them on the daemon's main thread starves observe,
7
+ * recall and the extraction queue: every awaited syscall is a main-thread
8
+ * continuation.
9
+ *
10
+ * This host runs the scans in ONE `worker_threads` worker so the main thread
11
+ * stays free. The worker entry is plain JavaScript
12
+ * (`corpus-scan-worker.entry.mjs`, generated from the TypeScript source), so
13
+ * it loads on every runtime the package supports — no TypeScript loader is
14
+ * needed inside a worker thread.
15
+ *
16
+ * Lifecycle:
17
+ * - lazy spawn on the first job; `unref()`ed, so it never keeps the process
18
+ * alive;
19
+ * - a cancelled job is rejected on the main thread immediately and the
20
+ * worker is told to stop the walk at its next checkpoint;
21
+ * - a worker that cannot start (or dies before answering) makes the host run
22
+ * the SAME implementation inline, so the scan still happens;
23
+ * - `close()` terminates the worker and rejects in-flight jobs.
24
+ */
25
+
26
+ import { existsSync } from "node:fs";
27
+ import { fileURLToPath } from "node:url";
28
+ import { Worker } from "node:worker_threads";
29
+ import { abortError } from "./abort-error.js";
30
+ import { log } from "./logger.js";
31
+ import {
32
+ collectContainedMarkdownPaths,
33
+ fingerprintEntityEntries,
34
+ statMtimes,
35
+ } from "./corpus-scan.js";
36
+
37
+ /** The scans the worker can run. */
38
+ export type CorpusScanJobKind = "walk" | "entity-entries-fingerprint" | "stat-mtimes";
39
+
40
+ /** Job payloads, one per kind. */
41
+ export type CorpusScanPayload =
42
+ | { kind: "walk"; baseDir: string; startDirs: string[]; propagateReadErrors: boolean }
43
+ | { kind: "entity-entries-fingerprint"; entitiesDir: string }
44
+ | { kind: "stat-mtimes"; paths: string[] };
45
+
46
+ /** Result shape per job kind. */
47
+ export interface CorpusScanResults {
48
+ walk: string[];
49
+ "entity-entries-fingerprint": string;
50
+ "stat-mtimes": Array<number | null>;
51
+ }
52
+
53
+ /** Every result shape the worker can return, in one union. */
54
+ export type CorpusScanResult = string[] | string | Array<number | null>;
55
+
56
+ /** A worker-side failure, flattened for the thread boundary. */
57
+ export interface CorpusScanErrorPayload {
58
+ name: string;
59
+ message: string;
60
+ code?: string;
61
+ }
62
+
63
+ /** A message posted back from the worker. */
64
+ export interface CorpusScanReply {
65
+ id: number;
66
+ ok: boolean;
67
+ result?: CorpusScanResult;
68
+ error?: CorpusScanErrorPayload;
69
+ }
70
+
71
+ /** Completed-job counters per kind. */
72
+ export interface CorpusScanStats {
73
+ jobs: number;
74
+ byKind: Record<string, number>;
75
+ }
76
+
77
+ interface PendingJob {
78
+ kind: CorpusScanJobKind;
79
+ resolve: (value: CorpusScanResult) => void;
80
+ reject: (error: Error) => void;
81
+ cleanup?: () => void;
82
+ }
83
+
84
+ /**
85
+ * Resolve the worker entry beside THIS module: the source tree keeps the
86
+ * generated JavaScript entry at `src/corpus-scan-worker.entry.mjs` and the
87
+ * built package copies it next to the bundled host, so the same relative path
88
+ * works in both.
89
+ */
90
+ function resolveWorkerEntryUrl(): URL {
91
+ const candidates = [
92
+ "./corpus-scan-worker.entry.mjs",
93
+ "../corpus-scan-worker.entry.mjs",
94
+ ];
95
+ for (const candidate of candidates) {
96
+ const url = new URL(candidate, import.meta.url);
97
+ if (existsSync(fileURLToPath(url))) return url;
98
+ }
99
+ throw new Error(`corpus scan worker entry not found (looked for ${candidates.join(", ")})`);
100
+ }
101
+
102
+ function toError(payload: CorpusScanErrorPayload, fallback: string): Error {
103
+ const error = new Error(payload.message === "" ? fallback : payload.message);
104
+ error.name = payload.name;
105
+ if (payload.code !== undefined) {
106
+ // SAFETY: the errno `code` is an optional string on an Error, and the
107
+ // worker only forwards a code it read off a filesystem rejection.
108
+ const errno = error as NodeJS.ErrnoException;
109
+ errno.code = payload.code;
110
+ }
111
+ return error;
112
+ }
113
+
114
+ /** Run the same scan inline (the fallback when no worker is available). */
115
+ async function runInline(payload: CorpusScanPayload, checkCancelled?: () => void): Promise<CorpusScanResult> {
116
+ switch (payload.kind) {
117
+ case "walk":
118
+ return await collectContainedMarkdownPaths({
119
+ baseDir: payload.baseDir,
120
+ startDirs: payload.startDirs,
121
+ propagateReadErrors: payload.propagateReadErrors,
122
+ checkCancelled,
123
+ });
124
+ case "entity-entries-fingerprint":
125
+ return await fingerprintEntityEntries(payload.entitiesDir);
126
+ case "stat-mtimes":
127
+ return await statMtimes(payload.paths);
128
+ }
129
+ }
130
+
131
+ export class CorpusScanWorkerHost {
132
+ private worker: Worker | null = null;
133
+ private readonly pending = new Map<number, PendingJob>();
134
+ private nextId = 1;
135
+ private readonly jobCounts = new Map<CorpusScanJobKind, number>();
136
+ private attached = false;
137
+ private workerUnavailable = false;
138
+
139
+ /** Completed jobs per kind — observability for tests and diagnostics. */
140
+ public stats(): CorpusScanStats {
141
+ const byKind: Record<string, number> = {};
142
+ let jobs = 0;
143
+ for (const [kind, count] of this.jobCounts) {
144
+ byKind[kind] = count;
145
+ jobs += count;
146
+ }
147
+ return { jobs, byKind };
148
+ }
149
+
150
+ /**
151
+ * Run one scan. It executes in the worker; when no worker can run it, the
152
+ * same implementation runs inline. Rejects with the job's error (errno code
153
+ * preserved) or an AbortError when `signal` fires first.
154
+ */
155
+ public async request<P extends CorpusScanPayload>(
156
+ payload: P,
157
+ signal?: AbortSignal,
158
+ ): Promise<CorpusScanResults[P["kind"]]> {
159
+ if (signal?.aborted) throw abortError("corpus read aborted");
160
+ const result = await this.runInWorker(payload, signal);
161
+ // SAFETY: the worker answers with the result type of the job it was given,
162
+ // and the kind is part of the request, so the pair holds.
163
+ return result as CorpusScanResults[P["kind"]];
164
+ }
165
+
166
+ private async runInWorker(payload: CorpusScanPayload, signal?: AbortSignal): Promise<CorpusScanResult> {
167
+ if (this.workerUnavailable) {
168
+ return await runInline(payload, this.cancellationCheck(signal));
169
+ }
170
+ let worker: Worker;
171
+ try {
172
+ worker = this.ensureWorker();
173
+ } catch (error) {
174
+ // No worker available (missing entry, unsupported runtime): the scan
175
+ // still happens, on this thread. Report the fallback once: every later
176
+ // scan would otherwise run inline silently.
177
+ this.disableWorker(error instanceof Error ? error : new Error(String(error)));
178
+ return await runInline(payload, this.cancellationCheck(signal));
179
+ }
180
+ const id = this.nextId++;
181
+ // Keep the process alive while a job is in flight; release it when the
182
+ // queue drains so an idle worker never holds the event loop open.
183
+ this.setAttached(true);
184
+ try {
185
+ return await new Promise<CorpusScanResult>((resolve, reject) => {
186
+ const job: PendingJob = { kind: payload.kind, resolve, reject };
187
+ if (signal) {
188
+ const onAbort = (): void => {
189
+ this.cancelJob(id);
190
+ // Drop the job now: the worker's late reply is ignored, and the
191
+ // queue must not stay "busy" for a job nobody awaits.
192
+ this.pending.delete(id);
193
+ if (this.pending.size === 0) this.setAttached(false);
194
+ reject(abortError("corpus read aborted"));
195
+ };
196
+ signal.addEventListener("abort", onAbort, { once: true });
197
+ job.cleanup = () => signal.removeEventListener("abort", onAbort);
198
+ }
199
+ this.pending.set(id, job);
200
+ worker.postMessage({ id, payload });
201
+ });
202
+ } catch (error) {
203
+ // A worker that died before answering leaves the scan undone: run it
204
+ // inline so the caller still gets its result.
205
+ if (!this.pending.has(id) && this.workerUnavailable) {
206
+ return await runInline(payload, this.cancellationCheck(signal));
207
+ }
208
+ throw error;
209
+ }
210
+ }
211
+
212
+ private cancellationCheck(signal?: AbortSignal): (() => void) | undefined {
213
+ if (!signal) return undefined;
214
+ return () => {
215
+ if (signal.aborted) throw abortError("corpus read aborted");
216
+ };
217
+ }
218
+
219
+ /** Tell the worker to abandon a job (its next checkpoint stops the walk). */
220
+ private cancelJob(id: number): void {
221
+ this.worker?.postMessage({ id, cancel: true });
222
+ }
223
+
224
+ /**
225
+ * Attach/detach the worker's message listener. A worker with a `message`
226
+ * listener keeps the parent's event loop alive (the port stays ref'd), so an
227
+ * idle worker is detached: the daemon must be able to exit with a warm
228
+ * corpus-scan worker in memory.
229
+ */
230
+ private setAttached(attached: boolean): void {
231
+ const worker = this.worker;
232
+ if (!worker) return;
233
+ if (attached) {
234
+ if (!this.attached) {
235
+ worker.on("message", this.onMessage);
236
+ this.attached = true;
237
+ }
238
+ worker.ref();
239
+ } else {
240
+ if (this.attached) {
241
+ worker.removeAllListeners("message");
242
+ this.attached = false;
243
+ }
244
+ worker.unref();
245
+ }
246
+ }
247
+
248
+ private readonly onMessage = (message: CorpusScanReply): void => {
249
+ const job = this.pending.get(message.id);
250
+ if (!job) return;
251
+ this.pending.delete(message.id);
252
+ job.cleanup?.();
253
+ this.jobCounts.set(job.kind, (this.jobCounts.get(job.kind) ?? 0) + 1);
254
+ if (message.ok && message.result !== undefined) job.resolve(message.result);
255
+ else job.reject(toError(message.error ?? { name: "Error", message: "corpus scan worker job failed" }, "corpus scan worker job failed"));
256
+ if (this.pending.size === 0) this.setAttached(false);
257
+ };
258
+
259
+ /**
260
+ * Disable the worker and say why, exactly once: after this, every corpus
261
+ * scan runs inline on the main thread, which is the starvation this module
262
+ * exists to avoid. Silence here would hide the regression.
263
+ */
264
+ private disableWorker(error: Error): void {
265
+ if (this.workerUnavailable) return;
266
+ this.workerUnavailable = true;
267
+ log.warn("corpus scan worker unavailable; falling back to inline scans", error);
268
+ }
269
+
270
+ private ensureWorker(): Worker {
271
+ if (this.worker) return this.worker;
272
+ const worker = new Worker(resolveWorkerEntryUrl());
273
+ worker.unref();
274
+ // Events from a worker that is no longer current (closed, replaced) must
275
+ // not touch jobs that belong to its successor: `exit` is delivered after
276
+ // `terminate()` resolves, by which time a new worker may own the queue.
277
+ worker.on("error", (error: Error) => {
278
+ if (this.worker !== worker) return;
279
+ this.failAll(error);
280
+ this.disableWorker(error);
281
+ });
282
+ worker.on("exit", () => {
283
+ if (this.worker !== worker) return;
284
+ this.worker = null;
285
+ this.attached = false;
286
+ this.failAll(new Error("corpus scan worker exited"));
287
+ });
288
+ this.worker = worker;
289
+ return worker;
290
+ }
291
+
292
+ private failAll(error: Error): void {
293
+ for (const [id, job] of [...this.pending]) {
294
+ this.pending.delete(id);
295
+ job.cleanup?.();
296
+ job.reject(error);
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Terminate the worker and reject in-flight jobs. The next request spawns a
302
+ * fresh worker, so a shutdown (or a test teardown) leaves no handle behind.
303
+ */
304
+ public close(): void {
305
+ const worker = this.worker;
306
+ this.worker = null;
307
+ this.attached = false;
308
+ this.failAll(new Error("corpus scan worker closed"));
309
+ void worker?.terminate();
310
+ }
311
+ }
312
+
313
+ /** Process-wide corpus-scan worker. */
314
+ export const corpusScanWorker = new CorpusScanWorkerHost();
@@ -0,0 +1,176 @@
1
+ // GENERATED FILE — do not edit.
2
+ // Source: packages/remnic-core/src/corpus-scan-worker.entry.ts
3
+ // Regenerate: npm run sync:corpus-scan-worker
4
+
5
+
6
+ // packages/remnic-core/src/corpus-scan-worker.entry.ts
7
+ import { parentPort } from "node:worker_threads";
8
+
9
+ // packages/remnic-core/src/abort-error.ts
10
+ function abortError(message) {
11
+ const err = new Error(message);
12
+ Object.defineProperty(err, "name", { value: "AbortError" });
13
+ return err;
14
+ }
15
+
16
+ // packages/remnic-core/src/corpus-scan.ts
17
+ import { createHash } from "node:crypto";
18
+ import { lstat, readdir, realpath, stat } from "node:fs/promises";
19
+ import path from "node:path";
20
+
21
+ // packages/remnic-core/src/utils/errno.ts
22
+ function isErrnoCode(error, code) {
23
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
24
+ }
25
+
26
+ // packages/remnic-core/src/utils/macos-replication-junk.ts
27
+ function isMacOsReplicationJunkBasename(basename) {
28
+ return basename === ".DS_Store" || basename.startsWith("._");
29
+ }
30
+
31
+ // packages/remnic-core/src/corpus-scan.ts
32
+ function isPropagatableReadError(error) {
33
+ return error.code !== void 0 && error.code !== "ENOENT";
34
+ }
35
+ async function collectContainedMarkdownPaths(options) {
36
+ const { baseDir, startDirs, propagateReadErrors = false, checkCancelled } = options;
37
+ const filePaths = [];
38
+ try {
39
+ await realpath(baseDir);
40
+ } catch (error) {
41
+ const failure = error;
42
+ if (propagateReadErrors && isPropagatableReadError(failure)) throw error;
43
+ return filePaths;
44
+ }
45
+ const collectPaths = async (dir) => {
46
+ checkCancelled?.();
47
+ let dirStat;
48
+ try {
49
+ dirStat = await lstat(dir);
50
+ } catch (error) {
51
+ const failure = error;
52
+ if (propagateReadErrors && isPropagatableReadError(failure)) throw error;
53
+ return;
54
+ }
55
+ if (dirStat.isSymbolicLink()) return;
56
+ if (!dirStat.isDirectory()) {
57
+ if (propagateReadErrors) {
58
+ throw new Error(`corpus scan: expected a directory but found a non-directory at ${dir}`);
59
+ }
60
+ return;
61
+ }
62
+ let entries;
63
+ try {
64
+ entries = await readdir(dir, { withFileTypes: true });
65
+ } catch (error) {
66
+ const failure = error;
67
+ if (propagateReadErrors && isPropagatableReadError(failure)) throw error;
68
+ return;
69
+ }
70
+ const subdirs = [];
71
+ for (const entry of entries) {
72
+ checkCancelled?.();
73
+ if (entry.isSymbolicLink()) continue;
74
+ if (isMacOsReplicationJunkBasename(entry.name)) continue;
75
+ const fullPath = path.join(dir, entry.name);
76
+ if (entry.isDirectory()) {
77
+ subdirs.push(fullPath);
78
+ } else if (entry.name.endsWith(".md")) {
79
+ filePaths.push(fullPath);
80
+ }
81
+ }
82
+ for (const subdir of subdirs) {
83
+ await collectPaths(subdir);
84
+ }
85
+ };
86
+ for (const dir of startDirs) {
87
+ await collectPaths(dir);
88
+ }
89
+ checkCancelled?.();
90
+ return filePaths;
91
+ }
92
+ async function fingerprintEntityEntries(entitiesDir) {
93
+ let names;
94
+ try {
95
+ names = (await readdir(entitiesDir)).filter((name) => path.extname(name) === ".md" && !isMacOsReplicationJunkBasename(name)).sort();
96
+ } catch (error) {
97
+ if (isErrnoCode(error, "ENOENT")) return "missing";
98
+ throw error;
99
+ }
100
+ const hash = createHash("sha256");
101
+ for (const name of names) {
102
+ hash.update(`${name.length}:${name}:`);
103
+ try {
104
+ const entry = await lstat(path.join(entitiesDir, name), { bigint: true });
105
+ hash.update(`${entry.dev}:${entry.ino}:${entry.size}:${entry.mtimeNs}:${entry.ctimeNs}`);
106
+ } catch (error) {
107
+ if (!isErrnoCode(error, "ENOENT")) throw error;
108
+ hash.update("missing");
109
+ }
110
+ hash.update("\n");
111
+ }
112
+ return hash.digest("hex");
113
+ }
114
+ async function statMtimes(paths) {
115
+ const results = new Array(paths.length).fill(null);
116
+ const STAT_BATCH_SIZE = 256;
117
+ for (let start = 0; start < paths.length; start += STAT_BATCH_SIZE) {
118
+ await Promise.all(paths.slice(start, start + STAT_BATCH_SIZE).map(async (filePath, offset) => {
119
+ try {
120
+ const entry = await stat(filePath);
121
+ results[start + offset] = entry.mtimeMs;
122
+ } catch (error) {
123
+ if (isErrnoCode(error, "ENOENT")) return;
124
+ throw error;
125
+ }
126
+ }));
127
+ }
128
+ return results;
129
+ }
130
+
131
+ // packages/remnic-core/src/corpus-scan-worker.entry.ts
132
+ if (!parentPort) throw new Error("corpus scan worker must run as a worker thread");
133
+ var port = parentPort;
134
+ var cancelled = /* @__PURE__ */ new Set();
135
+ function serializeError(error) {
136
+ const payload = {
137
+ name: error.name,
138
+ message: error instanceof Error ? error.message : String(error)
139
+ };
140
+ if (error.code !== void 0) payload.code = error.code;
141
+ return payload;
142
+ }
143
+ async function runJob(id, payload) {
144
+ const checkCancelled = () => {
145
+ if (cancelled.has(id)) throw abortError("corpus read aborted");
146
+ };
147
+ switch (payload.kind) {
148
+ case "walk":
149
+ return await collectContainedMarkdownPaths({
150
+ baseDir: payload.baseDir,
151
+ startDirs: payload.startDirs,
152
+ propagateReadErrors: payload.propagateReadErrors,
153
+ checkCancelled
154
+ });
155
+ case "entity-entries-fingerprint":
156
+ return await fingerprintEntityEntries(payload.entitiesDir);
157
+ case "stat-mtimes":
158
+ return await statMtimes(payload.paths);
159
+ }
160
+ }
161
+ port.on("message", (message) => {
162
+ if (message.cancel) {
163
+ cancelled.add(message.id);
164
+ return;
165
+ }
166
+ const { id } = message;
167
+ const payload = message.payload;
168
+ if (!payload) return;
169
+ void runJob(id, payload).then((result) => {
170
+ port.postMessage({ id, ok: true, result });
171
+ }).catch((error) => {
172
+ port.postMessage({ id, ok: false, error: serializeError(error) });
173
+ }).finally(() => {
174
+ cancelled.delete(id);
175
+ });
176
+ });
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Corpus-scan worker entry (TypeScript source of the generated worker).
3
+ *
4
+ * The worker runs the daemon's pure, read-only corpus scans off the main event
5
+ * loop: the recall-corpus path walk, the entity-entry fingerprint, and the
6
+ * watermark's freshness stat. Every job carries its own inputs and returns its
7
+ * own results, so the worker holds no state.
8
+ *
9
+ * This file is BUNDLED into `src/corpus-scan-worker.entry.mjs` (plain
10
+ * JavaScript) by scripts/sync-corpus-scan-worker.mjs: a worker thread does not
11
+ * inherit the TypeScript loader the source tree runs under, so the worker
12
+ * entry must be JavaScript on every runtime the package supports. The bundled
13
+ * file is committed and checked for drift by
14
+ * scripts/check-corpus-scan-worker-sync.mjs.
15
+ *
16
+ * Protocol: the host posts `{ id, payload }`; the worker answers
17
+ * `{ id, ok: true, result }` or `{ id, ok: false, error }`. A posted
18
+ * `{ id, cancel: true }` abandons that job at its next checkpoint.
19
+ */
20
+
21
+ import { parentPort } from "node:worker_threads";
22
+ import { abortError } from "./abort-error.js";
23
+ import {
24
+ collectContainedMarkdownPaths,
25
+ fingerprintEntityEntries,
26
+ statMtimes,
27
+ } from "./corpus-scan.js";
28
+ import type {
29
+ CorpusScanErrorPayload,
30
+ CorpusScanPayload,
31
+ CorpusScanResult,
32
+ } from "./corpus-scan-worker-host.js";
33
+
34
+ if (!parentPort) throw new Error("corpus scan worker must run as a worker thread");
35
+
36
+ const port = parentPort;
37
+ const cancelled = new Set<number>();
38
+
39
+ /** A thrown value from the scan code: an Error, optionally errno-coded. */
40
+ type ScanFailure = Error & { code?: string };
41
+
42
+ /** A message the host posts to the worker. */
43
+ interface CorpusScanRequestMessage {
44
+ id: number;
45
+ payload?: CorpusScanPayload;
46
+ cancel?: boolean;
47
+ }
48
+
49
+ function serializeError(error: ScanFailure): CorpusScanErrorPayload {
50
+ const payload: CorpusScanErrorPayload = {
51
+ name: error.name,
52
+ message: error instanceof Error ? error.message : String(error),
53
+ };
54
+ if (error.code !== undefined) payload.code = error.code;
55
+ return payload;
56
+ }
57
+
58
+ async function runJob(id: number, payload: CorpusScanPayload): Promise<CorpusScanResult> {
59
+ const checkCancelled = (): void => {
60
+ if (cancelled.has(id)) throw abortError("corpus read aborted");
61
+ };
62
+ switch (payload.kind) {
63
+ case "walk":
64
+ return await collectContainedMarkdownPaths({
65
+ baseDir: payload.baseDir,
66
+ startDirs: payload.startDirs,
67
+ propagateReadErrors: payload.propagateReadErrors,
68
+ checkCancelled,
69
+ });
70
+ case "entity-entries-fingerprint":
71
+ return await fingerprintEntityEntries(payload.entitiesDir);
72
+ case "stat-mtimes":
73
+ return await statMtimes(payload.paths);
74
+ }
75
+ }
76
+
77
+ port.on("message", (message: CorpusScanRequestMessage) => {
78
+ if (message.cancel) {
79
+ cancelled.add(message.id);
80
+ return;
81
+ }
82
+ const { id } = message;
83
+ const payload = message.payload;
84
+ if (!payload) return;
85
+ void runJob(id, payload)
86
+ .then((result) => {
87
+ port.postMessage({ id, ok: true, result });
88
+ })
89
+ .catch((error: ScanFailure) => {
90
+ port.postMessage({ id, ok: false, error: serializeError(error) });
91
+ })
92
+ .finally(() => {
93
+ cancelled.delete(id);
94
+ });
95
+ });