@remnic/core 9.19.0 → 9.20.0

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 (306) hide show
  1. package/dist/access-admin-ops-surface.d.ts +8 -8
  2. package/dist/access-admin-ops-surface.js +8 -8
  3. package/dist/access-boundary.d.ts +8 -8
  4. package/dist/access-boundary.js +8 -8
  5. package/dist/access-cli.js +32 -32
  6. package/dist/access-http.d.ts +8 -8
  7. package/dist/access-http.js +12 -12
  8. package/dist/access-identity-continuity-surface.d.ts +6 -6
  9. package/dist/access-identity-continuity-surface.js +8 -8
  10. package/dist/access-lcm-surface.d.ts +8 -8
  11. package/dist/access-lcm-surface.js +8 -8
  12. package/dist/access-mcp.d.ts +8 -8
  13. package/dist/access-mcp.js +11 -11
  14. package/dist/access-memory-search-fanout.d.ts +2 -2
  15. package/dist/{access-namespace-preflight-BsawJa-L.d.ts → access-namespace-preflight-tmwQgCT6.d.ts} +1 -1
  16. package/dist/access-namespace-preflight.d.ts +3 -3
  17. package/dist/access-namespace-preflight.js +8 -8
  18. package/dist/access-observe-write-surface.d.ts +8 -8
  19. package/dist/access-observe-write-surface.js +8 -8
  20. package/dist/access-operations-batch.js +9 -9
  21. package/dist/access-operations.d.ts +8 -8
  22. package/dist/access-operations.js +10 -10
  23. package/dist/access-recall-concurrency.d.ts +8 -8
  24. package/dist/access-recall-concurrency.js +8 -8
  25. package/dist/access-recall-response.d.ts +8 -8
  26. package/dist/access-recall-response.js +8 -8
  27. package/dist/access-recall-surface.d.ts +8 -8
  28. package/dist/access-recall-surface.js +8 -8
  29. package/dist/{access-service-DLuVnV6a.d.ts → access-service-BqUii7LY.d.ts} +6 -6
  30. package/dist/access-service.d.ts +8 -8
  31. package/dist/access-service.js +8 -8
  32. package/dist/access-surface-catalog.d.ts +8 -8
  33. package/dist/action-confidence.d.ts +1 -1
  34. package/dist/active-memory-bridge.d.ts +1 -1
  35. package/dist/active-recall.d.ts +1 -1
  36. package/dist/active-recall.js +1 -1
  37. package/dist/{auto-sync-IH3G25MT.js → auto-sync-UPTUVE4X.js} +3 -3
  38. package/dist/behavior-learner.d.ts +1 -1
  39. package/dist/behavior-signals.d.ts +1 -1
  40. package/dist/bootstrap.d.ts +6 -6
  41. package/dist/briefing.d.ts +2 -2
  42. package/dist/briefing.js +4 -4
  43. package/dist/buffer-surprise-report.d.ts +1 -1
  44. package/dist/buffer.d.ts +2 -2
  45. package/dist/bulk-import/index.d.ts +3 -3
  46. package/dist/calibration.d.ts +1 -1
  47. package/dist/capabilities.d.ts +1 -1
  48. package/dist/{catalog-O6P8694A.d.ts → catalog-iWvWz61I.d.ts} +1 -1
  49. package/dist/causal-behavior.d.ts +1 -1
  50. package/dist/causal-consolidation.d.ts +1 -1
  51. package/dist/causal-consolidation.js +5 -5
  52. package/dist/causal-trajectory-graph.d.ts +1 -1
  53. package/dist/{chunk-YUWFASAK.js → chunk-275ENJDK.js} +2 -2
  54. package/dist/{chunk-EZFVVEQG.js → chunk-3ZUY2VQF.js} +2 -2
  55. package/dist/{chunk-HRREDJSL.js → chunk-4F6AANKS.js} +3 -3
  56. package/dist/{chunk-U7D5HWNG.js → chunk-4PYLBXX6.js} +2 -2
  57. package/dist/{chunk-3LZSS77C.js → chunk-53WDAG7X.js} +2 -2
  58. package/dist/{chunk-QEEMLGCO.js → chunk-5IXPWEQB.js} +5 -5
  59. package/dist/{chunk-VSVX777Y.js → chunk-5JQLAQUZ.js} +2 -2
  60. package/dist/{chunk-DR65EEXG.js → chunk-62QM5MKY.js} +7 -7
  61. package/dist/{chunk-WYL5ODHJ.js → chunk-6NZ7U4R4.js} +1 -1
  62. package/dist/chunk-6NZ7U4R4.js.map +1 -0
  63. package/dist/{chunk-OFQUY5NZ.js → chunk-7M6APKJL.js} +331 -5
  64. package/dist/chunk-7M6APKJL.js.map +1 -0
  65. package/dist/{chunk-OOJQ6ID5.js → chunk-AT3TDN6O.js} +1017 -296
  66. package/dist/chunk-AT3TDN6O.js.map +1 -0
  67. package/dist/{chunk-DQCUBRTZ.js → chunk-B7C3TF5H.js} +2 -2
  68. package/dist/{chunk-RPOOJPMB.js → chunk-EILX7SQR.js} +3 -3
  69. package/dist/{chunk-D5H3B36B.js → chunk-EXU5IQ3S.js} +2 -2
  70. package/dist/{chunk-KUF7OIFK.js → chunk-EZKKHVFY.js} +2 -2
  71. package/dist/{chunk-S5HCKQ7Q.js → chunk-GEUDRENF.js} +2 -2
  72. package/dist/{chunk-X7GOH7Y6.js → chunk-HJEEAO4O.js} +2 -2
  73. package/dist/{chunk-FL7MNSH3.js → chunk-HPOY2PHQ.js} +3 -3
  74. package/dist/{chunk-Q55XM4SU.js → chunk-JFDEYXF7.js} +2 -2
  75. package/dist/{chunk-UVSDFM7R.js → chunk-JN3IUA2Q.js} +2 -2
  76. package/dist/{chunk-PLRDZ2OO.js → chunk-JWMYVQAM.js} +2 -2
  77. package/dist/{chunk-KOFVOVJG.js → chunk-KHRKEELC.js} +17 -17
  78. package/dist/{chunk-Y4JHE2ML.js → chunk-LI4ZOFHW.js} +2 -2
  79. package/dist/{chunk-MLW3J7IC.js → chunk-LMHDFOVV.js} +3 -3
  80. package/dist/{chunk-X6E5WAGX.js → chunk-N7EVMKP6.js} +6 -6
  81. package/dist/{chunk-HCNG42P3.js → chunk-Q3FWRDCP.js} +2 -2
  82. package/dist/{chunk-5MFHOX5T.js → chunk-QO2KODU6.js} +2 -2
  83. package/dist/{chunk-W3DJOT22.js → chunk-TCZWBJBO.js} +2 -2
  84. package/dist/{chunk-B3ABVQ36.js → chunk-UHVXE24Y.js} +2 -1
  85. package/dist/{chunk-UX3ZXN34.js → chunk-UV72DEZD.js} +2 -2
  86. package/dist/{chunk-OZSL2QZC.js → chunk-V5TSUGRB.js} +5 -5
  87. package/dist/{chunk-CH3BRJ3P.js → chunk-X5QS5C2O.js} +2 -2
  88. package/dist/{cli-0dQHR6e6.d.ts → cli-DPEhq0Cp.d.ts} +5 -5
  89. package/dist/cli.d.ts +10 -10
  90. package/dist/cli.js +25 -25
  91. package/dist/compounding/engine.d.ts +2 -2
  92. package/dist/compounding/engine.js +4 -4
  93. package/dist/compounding/preference-consolidator.d.ts +1 -1
  94. package/dist/compression-optimizer.d.ts +1 -1
  95. package/dist/config.d.ts +1 -1
  96. package/dist/config.js +1 -1
  97. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  98. package/dist/connectors/codex-materialize-runner.js +4 -4
  99. package/dist/connectors/codex-materialize.d.ts +1 -1
  100. package/dist/connectors/index.d.ts +1 -1
  101. package/dist/connectors/index.js +4 -4
  102. package/dist/consolidation-provenance-check.d.ts +2 -2
  103. package/dist/consolidation-undo.d.ts +2 -2
  104. package/dist/contradiction/index.d.ts +2 -2
  105. package/dist/conversation-index/backend.d.ts +1 -1
  106. package/dist/conversation-index/chunker.d.ts +1 -1
  107. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  108. package/dist/conversation-index/indexer.d.ts +1 -1
  109. package/dist/conversation-index/search.d.ts +1 -1
  110. package/dist/day-summary.d.ts +1 -1
  111. package/dist/delinearize.d.ts +1 -1
  112. package/dist/direct-answer-wiring.d.ts +1 -1
  113. package/dist/direct-answer.d.ts +1 -1
  114. package/dist/embedding-fallback.d.ts +1 -1
  115. package/dist/enrichment/index.d.ts +1 -1
  116. package/dist/entity-retrieval.d.ts +2 -2
  117. package/dist/entity-retrieval.js +4 -4
  118. package/dist/entity-schema.d.ts +1 -1
  119. package/dist/explicit-capture.d.ts +6 -6
  120. package/dist/extraction-faithfulness.d.ts +1 -1
  121. package/dist/extraction-judge-telemetry.d.ts +1 -1
  122. package/dist/extraction-judge-training.d.ts +1 -1
  123. package/dist/extraction-judge.d.ts +1 -1
  124. package/dist/extraction.d.ts +1 -1
  125. package/dist/fallback-llm.d.ts +1 -1
  126. package/dist/graph-dashboard-diff.d.ts +1 -1
  127. package/dist/graph-dashboard-key.d.ts +1 -1
  128. package/dist/graph-dashboard-parser.d.ts +1 -1
  129. package/dist/graph-edge-reinforcement.d.ts +1 -1
  130. package/dist/graph-snapshot.d.ts +1 -1
  131. package/dist/graph.d.ts +1 -1
  132. package/dist/importance.d.ts +1 -1
  133. package/dist/importers/index.d.ts +1 -1
  134. package/dist/in-flight-reads.d.ts +1 -1
  135. package/dist/index.d.ts +468 -88
  136. package/dist/index.js +66 -36
  137. package/dist/intent.d.ts +1 -1
  138. package/dist/lcm/engine.d.ts +1 -1
  139. package/dist/lcm/index.d.ts +1 -1
  140. package/dist/lcm/tools.d.ts +1 -1
  141. package/dist/lifecycle.d.ts +1 -1
  142. package/dist/live-connectors-runner.d.ts +1 -1
  143. package/dist/local-llm.d.ts +1 -1
  144. package/dist/local-model-endpoint.d.ts +1 -1
  145. package/dist/maintenance/memory-governance.d.ts +1 -1
  146. package/dist/maintenance/memory-governance.js +4 -4
  147. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  148. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +4 -4
  149. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  150. package/dist/maintenance/rebuild-memory-projection.js +5 -5
  151. package/dist/mcp-memory-inspector-app.d.ts +8 -8
  152. package/dist/memory-action-policy.d.ts +1 -1
  153. package/dist/memory-cache.d.ts +1 -1
  154. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  155. package/dist/memory-projection-store.d.ts +1 -1
  156. package/dist/memory-provenance.d.ts +1 -1
  157. package/dist/memory-worth-outcomes.d.ts +2 -2
  158. package/dist/models-json.d.ts +1 -1
  159. package/dist/namespaces/migrate.d.ts +3 -3
  160. package/dist/namespaces/migrate.js +5 -5
  161. package/dist/namespaces/principal.d.ts +1 -1
  162. package/dist/namespaces/search.d.ts +1 -1
  163. package/dist/namespaces/storage.d.ts +3 -3
  164. package/dist/namespaces/storage.js +4 -4
  165. package/dist/native-knowledge.d.ts +1 -1
  166. package/dist/offline-sync-impression-drain.d.ts +1 -1
  167. package/dist/operator-toolkit.d.ts +2 -2
  168. package/dist/operator-toolkit.js +9 -9
  169. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  170. package/dist/orchestration/maintenance.d.ts +3 -3
  171. package/dist/orchestration/maintenance.js +9 -9
  172. package/dist/{orchestrator-B8ickLkd.d.ts → orchestrator-DB93S48I.d.ts} +5 -5
  173. package/dist/orchestrator.d.ts +6 -6
  174. package/dist/orchestrator.js +32 -32
  175. package/dist/patterns-cli.d.ts +1 -1
  176. package/dist/{pipeline-B669unGm.d.ts → pipeline-DmGc-H66.d.ts} +1 -1
  177. package/dist/policy-runtime.d.ts +1 -1
  178. package/dist/proactive-contention.d.ts +1 -1
  179. package/dist/provenance.d.ts +1 -1
  180. package/dist/{qmd-D0PVXmea.d.ts → qmd-cJT0crkF.d.ts} +1 -1
  181. package/dist/qmd-preflight.d.ts +2 -2
  182. package/dist/qmd-recall-cache.d.ts +1 -1
  183. package/dist/qmd.d.ts +2 -2
  184. package/dist/recall-concurrency-config.d.ts +1 -1
  185. package/dist/recall-disclosure-escalation.d.ts +1 -1
  186. package/dist/recall-explain-renderer.d.ts +1 -1
  187. package/dist/recall-explain-renderer.js +3 -3
  188. package/dist/recall-memory-map.d.ts +1 -1
  189. package/dist/recall-planner-llm.d.ts +1 -1
  190. package/dist/recall-state.d.ts +1 -1
  191. package/dist/recall-tag-filter.d.ts +1 -1
  192. package/dist/recall-timings.d.ts +1 -1
  193. package/dist/recall-xray-cli.d.ts +1 -1
  194. package/dist/recall-xray-cli.js +4 -4
  195. package/dist/recall-xray-renderer.d.ts +1 -1
  196. package/dist/recall-xray-renderer.js +3 -3
  197. package/dist/recall-xray.d.ts +1 -1
  198. package/dist/recall-xray.js +2 -2
  199. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  200. package/dist/replay/normalizers/claude.d.ts +1 -1
  201. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  202. package/dist/replay/normalizers/shared.d.ts +1 -1
  203. package/dist/replay/runner.d.ts +1 -1
  204. package/dist/replay/types.d.ts +1 -1
  205. package/dist/resolve-auth-token.d.ts +1 -1
  206. package/dist/resume-bundles.js +2 -2
  207. package/dist/retrieval-agents.d.ts +2 -2
  208. package/dist/retrieval-tiers.d.ts +1 -1
  209. package/dist/routing/engine.d.ts +1 -1
  210. package/dist/routing/store.d.ts +1 -1
  211. package/dist/salvage-envelope.d.ts +1 -1
  212. package/dist/{scope-profiles-BOp3gSzp.d.ts → scope-profiles-KG2nODX7.d.ts} +1 -1
  213. package/dist/search/embed-helper.d.ts +1 -1
  214. package/dist/search/factory.d.ts +1 -1
  215. package/dist/search/index.d.ts +1 -1
  216. package/dist/search/lancedb-backend.d.ts +1 -1
  217. package/dist/search/meilisearch-backend.d.ts +1 -1
  218. package/dist/search/noop-backend.d.ts +1 -1
  219. package/dist/search/orama-backend.d.ts +1 -1
  220. package/dist/search/port.d.ts +1 -1
  221. package/dist/search/remote-backend.d.ts +1 -1
  222. package/dist/{semantic-consolidation-C7SZNzUJ.d.ts → semantic-consolidation-BaZlg0D8.d.ts} +1 -1
  223. package/dist/semantic-consolidation.d.ts +2 -2
  224. package/dist/semantic-consolidation.js +5 -5
  225. package/dist/semantic-rule-promotion.js +4 -4
  226. package/dist/semantic-rule-verifier.d.ts +1 -1
  227. package/dist/semantic-rule-verifier.js +4 -4
  228. package/dist/session-observer-bands.d.ts +1 -1
  229. package/dist/session-observer-state.d.ts +1 -1
  230. package/dist/shared-context/manager.d.ts +1 -1
  231. package/dist/signal.d.ts +1 -1
  232. package/dist/{storage-CJ_Fia4H.d.ts → storage-BKhHHnRo.d.ts} +2 -221
  233. package/dist/storage.d.ts +2 -2
  234. package/dist/storage.js +3 -3
  235. package/dist/summarizer.d.ts +1 -1
  236. package/dist/summary-snapshot.d.ts +1 -1
  237. package/dist/temporal-supersession.d.ts +2 -2
  238. package/dist/temporal-timeline-recall.d.ts +1 -1
  239. package/dist/temporal-validity.d.ts +1 -1
  240. package/dist/threading.d.ts +1 -1
  241. package/dist/tier-migration.d.ts +2 -2
  242. package/dist/tier-routing.d.ts +1 -1
  243. package/dist/topics.d.ts +1 -1
  244. package/dist/transcript.d.ts +1 -1
  245. package/dist/trust-score-stage.d.ts +1 -1
  246. package/dist/trust-score.d.ts +1 -1
  247. package/dist/{types-GeWGXq9E.d.ts → types-GBQZuT7l.d.ts} +395 -1
  248. package/dist/types.d.ts +1 -1
  249. package/dist/types.js +1 -1
  250. package/dist/utility-runtime.d.ts +1 -1
  251. package/dist/verified-recall.js +4 -4
  252. package/dist/write-envelope.d.ts +1 -1
  253. package/package.json +2 -2
  254. package/src/config.ts +3 -3
  255. package/src/meetings/build.test.ts +646 -0
  256. package/src/meetings/build.ts +365 -0
  257. package/src/meetings/cli.test.ts +276 -0
  258. package/src/meetings/cli.ts +242 -0
  259. package/src/meetings/config.test.ts +72 -0
  260. package/src/meetings/config.ts +183 -0
  261. package/src/meetings/errors.ts +13 -0
  262. package/src/meetings/fuse.test.ts +208 -0
  263. package/src/meetings/fuse.ts +297 -0
  264. package/src/meetings/index.ts +11 -1
  265. package/src/meetings/memory-generator.ts +116 -0
  266. package/src/meetings/recall-exclusion.test.ts +88 -0
  267. package/src/meetings/store.test.ts +232 -0
  268. package/src/meetings/store.ts +465 -0
  269. package/src/meetings/types.ts +111 -0
  270. package/src/orchestration/orchestrator-helpers.ts +23 -3
  271. package/src/orchestration/recall-search-pipeline.test.ts +182 -0
  272. package/src/orchestration/recall-search-pipeline.ts +36 -15
  273. package/src/types.ts +6 -0
  274. package/dist/chunk-OFQUY5NZ.js.map +0 -1
  275. package/dist/chunk-OOJQ6ID5.js.map +0 -1
  276. package/dist/chunk-WYL5ODHJ.js.map +0 -1
  277. /package/dist/{auto-sync-IH3G25MT.js.map → auto-sync-UPTUVE4X.js.map} +0 -0
  278. /package/dist/{chunk-YUWFASAK.js.map → chunk-275ENJDK.js.map} +0 -0
  279. /package/dist/{chunk-EZFVVEQG.js.map → chunk-3ZUY2VQF.js.map} +0 -0
  280. /package/dist/{chunk-HRREDJSL.js.map → chunk-4F6AANKS.js.map} +0 -0
  281. /package/dist/{chunk-U7D5HWNG.js.map → chunk-4PYLBXX6.js.map} +0 -0
  282. /package/dist/{chunk-3LZSS77C.js.map → chunk-53WDAG7X.js.map} +0 -0
  283. /package/dist/{chunk-QEEMLGCO.js.map → chunk-5IXPWEQB.js.map} +0 -0
  284. /package/dist/{chunk-VSVX777Y.js.map → chunk-5JQLAQUZ.js.map} +0 -0
  285. /package/dist/{chunk-DR65EEXG.js.map → chunk-62QM5MKY.js.map} +0 -0
  286. /package/dist/{chunk-DQCUBRTZ.js.map → chunk-B7C3TF5H.js.map} +0 -0
  287. /package/dist/{chunk-RPOOJPMB.js.map → chunk-EILX7SQR.js.map} +0 -0
  288. /package/dist/{chunk-D5H3B36B.js.map → chunk-EXU5IQ3S.js.map} +0 -0
  289. /package/dist/{chunk-KUF7OIFK.js.map → chunk-EZKKHVFY.js.map} +0 -0
  290. /package/dist/{chunk-S5HCKQ7Q.js.map → chunk-GEUDRENF.js.map} +0 -0
  291. /package/dist/{chunk-X7GOH7Y6.js.map → chunk-HJEEAO4O.js.map} +0 -0
  292. /package/dist/{chunk-FL7MNSH3.js.map → chunk-HPOY2PHQ.js.map} +0 -0
  293. /package/dist/{chunk-Q55XM4SU.js.map → chunk-JFDEYXF7.js.map} +0 -0
  294. /package/dist/{chunk-UVSDFM7R.js.map → chunk-JN3IUA2Q.js.map} +0 -0
  295. /package/dist/{chunk-PLRDZ2OO.js.map → chunk-JWMYVQAM.js.map} +0 -0
  296. /package/dist/{chunk-KOFVOVJG.js.map → chunk-KHRKEELC.js.map} +0 -0
  297. /package/dist/{chunk-Y4JHE2ML.js.map → chunk-LI4ZOFHW.js.map} +0 -0
  298. /package/dist/{chunk-MLW3J7IC.js.map → chunk-LMHDFOVV.js.map} +0 -0
  299. /package/dist/{chunk-X6E5WAGX.js.map → chunk-N7EVMKP6.js.map} +0 -0
  300. /package/dist/{chunk-HCNG42P3.js.map → chunk-Q3FWRDCP.js.map} +0 -0
  301. /package/dist/{chunk-5MFHOX5T.js.map → chunk-QO2KODU6.js.map} +0 -0
  302. /package/dist/{chunk-W3DJOT22.js.map → chunk-TCZWBJBO.js.map} +0 -0
  303. /package/dist/{chunk-B3ABVQ36.js.map → chunk-UHVXE24Y.js.map} +0 -0
  304. /package/dist/{chunk-UX3ZXN34.js.map → chunk-UV72DEZD.js.map} +0 -0
  305. /package/dist/{chunk-OZSL2QZC.js.map → chunk-V5TSUGRB.js.map} +0 -0
  306. /package/dist/{chunk-CH3BRJ3P.js.map → chunk-X5QS5C2O.js.map} +0 -0
@@ -6,13 +6,13 @@ import {
6
6
  loadSyncState,
7
7
  syncWearableSource,
8
8
  wearableSourceLabel
9
- } from "./chunk-UX3ZXN34.js";
9
+ } from "./chunk-UV72DEZD.js";
10
10
  import {
11
11
  CompressionGuidelineCoordinator
12
12
  } from "./chunk-B7GROTXD.js";
13
13
  import {
14
14
  MaintenanceScheduler
15
- } from "./chunk-OZSL2QZC.js";
15
+ } from "./chunk-V5TSUGRB.js";
16
16
  import {
17
17
  runPeerProfileReasoner
18
18
  } from "./chunk-I74SUMNI.js";
@@ -28,7 +28,7 @@ import {
28
28
  import {
29
29
  CompoundingEngine,
30
30
  defaultTierMigrationCycleBudget
31
- } from "./chunk-EZFVVEQG.js";
31
+ } from "./chunk-3ZUY2VQF.js";
32
32
  import {
33
33
  SharedContextManager
34
34
  } from "./chunk-JGUXPJUQ.js";
@@ -210,7 +210,7 @@ import {
210
210
  buildEntityRecallSection,
211
211
  entityRecentTranscriptLookbackHours,
212
212
  readRecentEntityTranscriptEntries
213
- } from "./chunk-KUF7OIFK.js";
213
+ } from "./chunk-EZKKHVFY.js";
214
214
  import {
215
215
  normalizeReplaySessionKey
216
216
  } from "./chunk-AJVLDJU6.js";
@@ -220,14 +220,14 @@ import {
220
220
  import {
221
221
  compareVerifiedEpisodeResults,
222
222
  searchVerifiedEpisodes
223
- } from "./chunk-VSVX777Y.js";
223
+ } from "./chunk-5JQLAQUZ.js";
224
224
  import {
225
225
  ThreadingManager
226
226
  } from "./chunk-OJP3N7UK.js";
227
227
  import {
228
228
  compareVerifiedSemanticRuleResults,
229
229
  searchVerifiedSemanticRules
230
- } from "./chunk-D5H3B36B.js";
230
+ } from "./chunk-EXU5IQ3S.js";
231
231
  import {
232
232
  searchWorkProductLedgerEntries
233
233
  } from "./chunk-ZRWB5D4H.js";
@@ -240,14 +240,14 @@ import {
240
240
  import {
241
241
  runNamespaceMaintenanceFanout,
242
242
  summarizeNamespaceMaintenanceHealth
243
- } from "./chunk-X6E5WAGX.js";
243
+ } from "./chunk-N7EVMKP6.js";
244
244
  import {
245
245
  NamespaceCatalog,
246
246
  planNamespaceMaintenance
247
- } from "./chunk-YUWFASAK.js";
247
+ } from "./chunk-275ENJDK.js";
248
248
  import {
249
249
  NamespaceStorageRouter
250
- } from "./chunk-5MFHOX5T.js";
250
+ } from "./chunk-QO2KODU6.js";
251
251
  import {
252
252
  searchHarmonicRetrieval
253
253
  } from "./chunk-AV5ZEH4M.js";
@@ -282,7 +282,7 @@ import {
282
282
  materializeAfterSemanticConsolidation,
283
283
  parseConsolidationResponse,
284
284
  parseOperatorAwareConsolidationResponse
285
- } from "./chunk-3LZSS77C.js";
285
+ } from "./chunk-53WDAG7X.js";
286
286
  import {
287
287
  BootstrapEngine
288
288
  } from "./chunk-MYVPLJOO.js";
@@ -301,6 +301,9 @@ import {
301
301
  import {
302
302
  isDisagreementPrompt
303
303
  } from "./chunk-H3FZVNRN.js";
304
+ import {
305
+ detectMeetings
306
+ } from "./chunk-7M6APKJL.js";
304
307
  import {
305
308
  compileCorrectionRule,
306
309
  correctionsFilePath,
@@ -334,7 +337,7 @@ import {
334
337
  clusterByKey,
335
338
  createCorrectionService,
336
339
  detectPassiveCorrections
337
- } from "./chunk-DR65EEXG.js";
340
+ } from "./chunk-62QM5MKY.js";
338
341
  import {
339
342
  importCapsule
340
343
  } from "./chunk-7CPOZH6Y.js";
@@ -354,7 +357,7 @@ import {
354
357
  } from "./chunk-JGSKJHF7.js";
355
358
  import {
356
359
  buildXraySnapshot
357
- } from "./chunk-Q55XM4SU.js";
360
+ } from "./chunk-JFDEYXF7.js";
358
361
  import {
359
362
  NamespaceSearchRouter
360
363
  } from "./chunk-SB4OKS6C.js";
@@ -400,7 +403,7 @@ import {
400
403
  } from "./chunk-W4FBGYGK.js";
401
404
  import {
402
405
  buildChainFollowupGenerator
403
- } from "./chunk-HCNG42P3.js";
406
+ } from "./chunk-Q3FWRDCP.js";
404
407
  import {
405
408
  ContentHashIndex,
406
409
  QmdResultResolver,
@@ -408,6 +411,7 @@ import {
408
411
  compareEntityTimestamps,
409
412
  composeFusionDayMeta,
410
413
  fingerprintEntityStructuredFacts,
414
+ fuseCluster,
411
415
  fuseDay,
412
416
  hashFusionBody,
413
417
  parseEntityFile,
@@ -417,17 +421,18 @@ import {
417
421
  reconstructFusionInputs,
418
422
  selfDeps,
419
423
  serializeFusionDay
420
- } from "./chunk-HRREDJSL.js";
424
+ } from "./chunk-4F6AANKS.js";
421
425
  import {
422
426
  bodyIsEscaped,
423
427
  decodeTranscriptBody,
424
428
  escapeSegmentText,
429
+ escapeSpeakerLabel,
425
430
  isValidTranscriptDate,
426
431
  loadSpeakerRegistry,
427
432
  parseDayTranscript,
428
433
  saveSpeakerRegistry,
429
434
  speakerRegistryKey
430
- } from "./chunk-B3ABVQ36.js";
435
+ } from "./chunk-UHVXE24Y.js";
431
436
  import {
432
437
  buildRetiredFactTombstoneInputs
433
438
  } from "./chunk-2QMKMVHH.js";
@@ -448,14 +453,15 @@ import {
448
453
  } from "./chunk-J6A3CX5N.js";
449
454
  import {
450
455
  confidenceTier
451
- } from "./chunk-WYL5ODHJ.js";
456
+ } from "./chunk-6NZ7U4R4.js";
452
457
  import {
453
458
  namespaceIdentityFromToken,
454
459
  namespaceIdentityToken,
455
460
  normalizeNamespaceIdentity
456
461
  } from "./chunk-EGGE52UU.js";
457
462
  import {
458
- assertPathInsideRoot
463
+ assertPathInsideRoot,
464
+ pathIsInside
459
465
  } from "./chunk-GCASGYIO.js";
460
466
  import {
461
467
  inferMemoryStatus,
@@ -868,8 +874,8 @@ var ExtractionQueueCoordinator = class {
868
874
  log.warn(`waitForExtractionIdle timed out after ${timeoutMs}ms`);
869
875
  return false;
870
876
  }
871
- const { promise, resolve } = Promise.withResolvers();
872
- setTimeout(resolve, 50);
877
+ const { promise, resolve: resolve2 } = Promise.withResolvers();
878
+ setTimeout(resolve2, 50);
873
879
  await promise;
874
880
  }
875
881
  return true;
@@ -1009,20 +1015,20 @@ var SemanticConsolidationCoordinator = class {
1009
1015
  result.errors++;
1010
1016
  continue;
1011
1017
  }
1012
- let canonicalContent;
1018
+ let canonicalContent2;
1013
1019
  let operator;
1014
1020
  if (operatorAwareEnabled) {
1015
1021
  const parsed = parseOperatorAwareConsolidationResponse(
1016
1022
  response.content,
1017
1023
  cluster
1018
1024
  );
1019
- canonicalContent = parsed.output;
1025
+ canonicalContent2 = parsed.output;
1020
1026
  operator = parsed.operator;
1021
1027
  } else {
1022
- canonicalContent = parseConsolidationResponse(response.content);
1028
+ canonicalContent2 = parseConsolidationResponse(response.content);
1023
1029
  operator = chooseConsolidationOperator(cluster);
1024
1030
  }
1025
- cluster.canonicalContent = canonicalContent;
1031
+ cluster.canonicalContent = canonicalContent2;
1026
1032
  const sorted = [...cluster.memories].sort(
1027
1033
  (a, b) => new Date(b.frontmatter.created).getTime() - new Date(a.frontmatter.created).getTime()
1028
1034
  );
@@ -1036,7 +1042,7 @@ var SemanticConsolidationCoordinator = class {
1036
1042
  }
1037
1043
  const canonicalEnvelope = composeMemoryEnvelope(
1038
1044
  {
1039
- content: canonicalContent,
1045
+ content: canonicalContent2,
1040
1046
  category: newest.frontmatter.category,
1041
1047
  confidence: newest.frontmatter.confidence,
1042
1048
  tags: [
@@ -2080,7 +2086,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
2080
2086
  namespaces,
2081
2087
  {
2082
2088
  readNamespaceMemories: async (ns) => (await this.getStorage(ns)).readAllMemories(),
2083
- readMemoryFrontmatter: async (path31, preferredNamespace) => {
2089
+ readMemoryFrontmatter: async (path32, preferredNamespace) => {
2084
2090
  if (!fallbackReader) {
2085
2091
  for (const ns of namespaces) {
2086
2092
  try {
@@ -2092,7 +2098,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
2092
2098
  }
2093
2099
  if (!fallbackReader) return null;
2094
2100
  const memory = await this.readQmdResultMemory(
2095
- path31,
2101
+ path32,
2096
2102
  fallbackReader,
2097
2103
  namespaces,
2098
2104
  preferredNamespace
@@ -2837,8 +2843,8 @@ function utcDateKeysForLocalDay(date, timeZone) {
2837
2843
  const hourMs = 36e5;
2838
2844
  const scanStart = date.getTime() - 48 * hourMs;
2839
2845
  const scanEnd = date.getTime() + 48 * hourMs;
2840
- for (let ms2 = scanStart; ms2 <= scanEnd; ms2 += hourMs) {
2841
- const candidate = new Date(ms2);
2846
+ for (let ms = scanStart; ms <= scanEnd; ms += hourMs) {
2847
+ const candidate = new Date(ms);
2842
2848
  if (formatDateInTimeZone(candidate, timeZone) === targetLocalDate) {
2843
2849
  keys.add(utcDateKey(candidate));
2844
2850
  }
@@ -2883,14 +2889,14 @@ async function qmdStartupCollectionCheckWithTimeout(promise, controller, label)
2883
2889
  const timeoutMs = qmdStartupCollectionCheckTimeoutMs();
2884
2890
  let timer;
2885
2891
  let settled = false;
2886
- const timeoutPromise = new Promise((resolve) => {
2892
+ const timeoutPromise = new Promise((resolve2) => {
2887
2893
  timer = setTimeout(() => {
2888
2894
  if (settled) return;
2889
2895
  controller.abort();
2890
2896
  log.warn(
2891
2897
  `QMD startup collection check for ${label} timed out after ${timeoutMs}ms; keeping search enabled fail-open`
2892
2898
  );
2893
- resolve("unknown");
2899
+ resolve2("unknown");
2894
2900
  }, timeoutMs);
2895
2901
  timer.unref?.();
2896
2902
  });
@@ -2995,17 +3001,20 @@ function splitTurnsBySourceValidAt(turns, options = {}) {
2995
3001
  function isArtifactMemoryPath(filePath) {
2996
3002
  return /(?:^|[\\/])artifacts(?:[\\/]|$)/i.test(filePath);
2997
3003
  }
3004
+ function isMeetingRecordPath(filePath) {
3005
+ return /(?:^|[\\/])meetings[\\/]\d{4}-\d{2}-\d{2}[\\/]mtg-\d{4}-\d{2}-\d{2}-[0-9a-f]{8}\.md$/i.test(filePath);
3006
+ }
2998
3007
  var ACTIVITY_DIGEST_TOPLEVEL = /^activity[\\/]\d{4}-\d{2}-\d{2}\.md$/i;
2999
3008
  var ACTIVITY_DIGEST_ANYWHERE = /(?:^|[\\/])activity[\\/]\d{4}-\d{2}-\d{2}\.md$/i;
3000
3009
  function isActivityDigestPath(filePath, memoryRoot) {
3001
3010
  if (memoryRoot !== void 0 && memoryRoot.length > 0) {
3002
- const relative = path4.relative(memoryRoot, path4.resolve(memoryRoot, filePath));
3003
- return ACTIVITY_DIGEST_TOPLEVEL.test(relative);
3011
+ const relative2 = path4.relative(memoryRoot, path4.resolve(memoryRoot, filePath));
3012
+ return ACTIVITY_DIGEST_TOPLEVEL.test(relative2);
3004
3013
  }
3005
3014
  return ACTIVITY_DIGEST_ANYWHERE.test(filePath);
3006
3015
  }
3007
3016
  function isGenericRecallExcludedPath(filePath, memoryRoot) {
3008
- return isArtifactMemoryPath(filePath) || isActivityDigestPath(filePath, memoryRoot);
3017
+ return isArtifactMemoryPath(filePath) || isActivityDigestPath(filePath, memoryRoot) || isMeetingRecordPath(filePath);
3009
3018
  }
3010
3019
  function buildCompressionGuidelinesMarkdown2(events, generatedAtIso = (/* @__PURE__ */ new Date()).toISOString()) {
3011
3020
  return buildCompressionGuidelinesMarkdown(events, generatedAtIso);
@@ -7818,9 +7827,9 @@ ${rows.join("\n")}
7818
7827
  }
7819
7828
  return merged.sort(compareVerifiedEpisodeResults).slice(0, maxResults);
7820
7829
  }),
7821
- new Promise((resolve) => {
7830
+ new Promise((resolve2) => {
7822
7831
  timeoutHandle = setTimeout(
7823
- () => resolve([]),
7832
+ () => resolve2([]),
7824
7833
  VERIFIED_RECALL_TIMEOUT_MS
7825
7834
  );
7826
7835
  })
@@ -7898,9 +7907,9 @@ ${rows.join("\n")}
7898
7907
  }
7899
7908
  return merged.sort(compareVerifiedSemanticRuleResults).slice(0, maxResults);
7900
7909
  }),
7901
- new Promise((resolve) => {
7910
+ new Promise((resolve2) => {
7902
7911
  rulesTimeoutHandle = setTimeout(
7903
- () => resolve([]),
7912
+ () => resolve2([]),
7904
7913
  VERIFIED_RULES_TIMEOUT_MS
7905
7914
  );
7906
7915
  })
@@ -8626,7 +8635,7 @@ ${formatted}`;
8626
8635
  );
8627
8636
  const results = await Promise.race([
8628
8637
  this.deps.searchConversationRecallResults(retrievalQuery, topK),
8629
- new Promise((resolve) => setTimeout(() => resolve([]), timeoutMs))
8638
+ new Promise((resolve2) => setTimeout(() => resolve2([]), timeoutMs))
8630
8639
  ]).catch(() => []);
8631
8640
  const durationMs = Date.now() - startedAtMs;
8632
8641
  if (durationMs >= timeoutMs) {
@@ -8840,9 +8849,9 @@ ${formatted}`;
8840
8849
  }
8841
8850
  const outcome = await (timeoutMs !== null ? Promise.race([
8842
8851
  promise,
8843
- new Promise((resolve) => {
8852
+ new Promise((resolve2) => {
8844
8853
  timeoutHandle = setTimeout(
8845
- () => resolve({ status: "timed_out" }),
8854
+ () => resolve2({ status: "timed_out" }),
8846
8855
  timeoutMs
8847
8856
  );
8848
8857
  })
@@ -8878,9 +8887,9 @@ ${formatted}`;
8878
8887
  try {
8879
8888
  const result = await (timeoutMs !== null ? Promise.race([
8880
8889
  task(stepSignal),
8881
- new Promise((resolve) => {
8890
+ new Promise((resolve2) => {
8882
8891
  timeoutHandle = setTimeout(
8883
- () => resolve({ status: "timed_out" }),
8892
+ () => resolve2({ status: "timed_out" }),
8884
8893
  timeoutMs
8885
8894
  );
8886
8895
  })
@@ -10692,8 +10701,8 @@ var ArchiveScoringWorkerPool = class {
10692
10701
  const idle = this.idle.pop();
10693
10702
  if (idle) return idle;
10694
10703
  if (this.workers.length < this.targetSize) return this.spawn();
10695
- return new Promise((resolve, reject) => {
10696
- const entry = { resolve, reject };
10704
+ return new Promise((resolve2, reject) => {
10705
+ const entry = { resolve: resolve2, reject };
10697
10706
  this.waiters.push(entry);
10698
10707
  if (!abortSignal) return;
10699
10708
  const onAbort = () => {
@@ -10734,7 +10743,7 @@ var ArchiveScoringWorkerPool = class {
10734
10743
  return worker;
10735
10744
  }
10736
10745
  dispatch(worker, task, abortSignal, onAbandon) {
10737
- return new Promise((resolve, reject) => {
10746
+ return new Promise((resolve2, reject) => {
10738
10747
  let settled = false;
10739
10748
  const timer = setTimeout(() => {
10740
10749
  if (settled) return;
@@ -10748,7 +10757,7 @@ var ArchiveScoringWorkerPool = class {
10748
10757
  if (settled) return;
10749
10758
  settled = true;
10750
10759
  cleanup();
10751
- if (reply.ok) resolve(reply.results);
10760
+ if (reply.ok) resolve2(reply.results);
10752
10761
  else reject(new Error(reply.error));
10753
10762
  };
10754
10763
  const onError = (err) => {
@@ -10770,7 +10779,7 @@ var ArchiveScoringWorkerPool = class {
10770
10779
  settled = true;
10771
10780
  cleanup();
10772
10781
  onAbandon();
10773
- resolve([]);
10782
+ resolve2([]);
10774
10783
  };
10775
10784
  const cleanup = () => {
10776
10785
  clearTimeout(timer);
@@ -10977,9 +10986,17 @@ var RecallSearchPipelineCoordinator = class {
10977
10986
  const scopedSeedResults = queryAwarePrefilter.candidatePaths?.size ? await this.deps.searchScopedMemoryCandidates(
10978
10987
  queryAwarePrefilter.candidatePaths,
10979
10988
  prompt,
10980
- qmdFetchLimit,
10989
+ // Overfetch the FULL scoped candidate set BEFORE the generic-recall
10990
+ // exclusion `filterRecallCandidates` applies below (L464). Capping to
10991
+ // `qmdFetchLimit` here lets excluded paths (artifacts, activity digests,
10992
+ // meeting records) consume the caller's budget and drop legitimate hits
10993
+ // with no refill — the hot-path mirror of the archive-fallback fix. The
10994
+ // candidate set is an already-bounded prefilter, so its size is the
10995
+ // natural ceiling; the post-exclusion cap is applied by filterRecallCandidates.
10996
+ queryAwarePrefilter.candidatePaths.size,
10981
10997
  { allowArchived: options.collection !== void 0 }
10982
10998
  ) : [];
10999
+ const recallable = (r) => !isGenericRecallExcludedPath(r.path, this.deps.config.memoryDir);
10983
11000
  let fetchLimit = Math.max(qmdFetchLimit, qmdHybridFetchLimit);
10984
11001
  const maxFetchLimit = Math.min(
10985
11002
  320,
@@ -11104,7 +11121,7 @@ var RecallSearchPipelineCoordinator = class {
11104
11121
  [...primaryResults, ...hybridResults],
11105
11122
  this.deps.namespaceFromPath,
11106
11123
  fetchLimit,
11107
- { transportFallback: "hybrid" }
11124
+ { transportFallback: "hybrid", filter: recallable }
11108
11125
  );
11109
11126
  }
11110
11127
  }
@@ -11113,7 +11130,8 @@ var RecallSearchPipelineCoordinator = class {
11113
11130
  mergedResults = dedupeResultsByNamespace(
11114
11131
  [...scopedSeedResults, ...mergedResults],
11115
11132
  this.deps.namespaceFromPath,
11116
- fetchLimit
11133
+ fetchLimit,
11134
+ { filter: recallable }
11117
11135
  );
11118
11136
  }
11119
11137
  const filteredResults = filterRecallCandidates(mergedResults, {
@@ -11177,14 +11195,22 @@ var RecallSearchPipelineCoordinator = class {
11177
11195
  const cappedLimit = Math.max(0, limit);
11178
11196
  if (cappedLimit === 0) return [];
11179
11197
  if (queryAwarePrefilter?.candidatePaths?.size === 0) return [];
11180
- const scopedSeedResults = queryAwarePrefilter?.candidatePaths?.size ? await this.deps.searchScopedMemoryCandidates(
11181
- queryAwarePrefilter.candidatePaths,
11198
+ const candidatePaths = queryAwarePrefilter?.candidatePaths;
11199
+ const scopedSeedResults = (candidatePaths?.size ? await this.deps.searchScopedMemoryCandidates(
11200
+ candidatePaths,
11182
11201
  prompt,
11183
- cappedLimit,
11202
+ // Overfetch the FULL scoped candidate set BEFORE the generic-recall
11203
+ // exclusion below. Capping to `cappedLimit` first lets excluded paths
11204
+ // (artifacts, activity digests, meeting records) consume the caller's
11205
+ // budget and drop legitimate hits with no refill — e.g. a prefilter of
11206
+ // [meetingRecord, facts/a.md] at limit 1 would return nothing. The
11207
+ // candidate set is an already-bounded prefilter, so its size is the
11208
+ // natural ceiling; the post-exclusion cap is applied below.
11209
+ candidatePaths.size,
11184
11210
  { allowArchived: true }
11185
- ) : [];
11211
+ ) : []).filter((result) => !isGenericRecallExcludedPath(result.path, this.deps.config.memoryDir));
11186
11212
  if (scopedSeedResults.length >= cappedLimit) {
11187
- return scopedSeedResults.filter((result) => !isGenericRecallExcludedPath(result.path, this.deps.config.memoryDir)).slice(0, cappedLimit);
11213
+ return scopedSeedResults.slice(0, cappedLimit);
11188
11214
  }
11189
11215
  const tokens = Array.from(new Set(tokenizeRecallQuery(prompt)));
11190
11216
  if (tokens.length === 0) return scopedSeedResults;
@@ -11246,11 +11272,11 @@ var RecallSearchPipelineCoordinator = class {
11246
11272
  try {
11247
11273
  return await Promise.race([
11248
11274
  taskPromise,
11249
- new Promise((resolve) => {
11275
+ new Promise((resolve2) => {
11250
11276
  timeoutHandle = setTimeout(() => {
11251
11277
  timedOut = true;
11252
11278
  abandonToDeadline();
11253
- resolve(fallback);
11279
+ resolve2(fallback);
11254
11280
  }, remainingMs);
11255
11281
  })
11256
11282
  ]);
@@ -11416,9 +11442,9 @@ var RecallSearchPipelineCoordinator = class {
11416
11442
  boostInput.memoryByPath,
11417
11443
  { allowLifecycleFiltered: true, asOfMs: options.asOfMs }
11418
11444
  ),
11419
- new Promise((resolve) => {
11445
+ new Promise((resolve2) => {
11420
11446
  timeoutHandle = setTimeout(
11421
- () => resolve({ status: "timed_out" }),
11447
+ () => resolve2({ status: "timed_out" }),
11422
11448
  boostTimeoutMs
11423
11449
  );
11424
11450
  })
@@ -11995,7 +12021,7 @@ var TurnIngestionCoordinator = class {
11995
12021
  if (a.order === b.order) return 0;
11996
12022
  return a.order < b.order ? -1 : 1;
11997
12023
  }).map(
11998
- ({ bufferKey, turns: sessionSlice }) => new Promise((resolve, reject) => {
12024
+ ({ bufferKey, turns: sessionSlice }) => new Promise((resolve2, reject) => {
11999
12025
  void this.deps.queueBufferedExtraction(sessionSlice, "trigger_mode", {
12000
12026
  skipDedupeCheck: true,
12001
12027
  forceExtractionAttempt: true,
@@ -12007,7 +12033,7 @@ var TurnIngestionCoordinator = class {
12007
12033
  abortSignal: options.abortSignal,
12008
12034
  writeNamespaceOverride: options.writeNamespaceOverride,
12009
12035
  principalOverride: options.principalOverride,
12010
- onTaskSettled: (err) => err ? reject(err) : resolve()
12036
+ onTaskSettled: (err) => err ? reject(err) : resolve2()
12011
12037
  }).catch(reject);
12012
12038
  })
12013
12039
  );
@@ -12136,7 +12162,7 @@ var TurnIngestionCoordinator = class {
12136
12162
  for (const sessionSlice of sessionSlices) {
12137
12163
  try {
12138
12164
  const result = await new Promise(
12139
- (resolve, reject) => {
12165
+ (resolve2, reject) => {
12140
12166
  void this.deps.queueBufferedExtraction(sessionSlice, "trigger_mode", {
12141
12167
  skipDedupeCheck: true,
12142
12168
  forceExtractionAttempt: true,
@@ -12147,7 +12173,7 @@ var TurnIngestionCoordinator = class {
12147
12173
  extractionDeadlineMs: options.deadlineMs,
12148
12174
  failOnExtractionFailure: options.failOnExtractionFailure === true,
12149
12175
  writeNamespaceOverride: this.deps.bulkImportWriteNamespace(),
12150
- onTaskSettled: (err, result2) => err ? reject(err) : resolve(
12176
+ onTaskSettled: (err, result2) => err ? reject(err) : resolve2(
12151
12177
  result2 ?? {
12152
12178
  status: "skipped",
12153
12179
  reason: "missing_extraction_result",
@@ -12896,8 +12922,8 @@ var RecallIntrospectionCoordinator = class {
12896
12922
  async waitForDirectAnswerObservationIdle(timeoutMs = 6e4) {
12897
12923
  let timeoutHandle = null;
12898
12924
  try {
12899
- const timeoutPromise = new Promise((resolve) => {
12900
- timeoutHandle = setTimeout(() => resolve("timeout"), timeoutMs);
12925
+ const timeoutPromise = new Promise((resolve2) => {
12926
+ timeoutHandle = setTimeout(() => resolve2("timeout"), timeoutMs);
12901
12927
  });
12902
12928
  const result = await Promise.race([
12903
12929
  this.deps.directAnswerObservationChain.then(() => "ok"),
@@ -13113,8 +13139,8 @@ var OrchestratorInitCoordinator = class {
13113
13139
  }
13114
13140
  deps;
13115
13141
  async initialize() {
13116
- this.deps.deferredReady = new Promise((resolve) => {
13117
- this.deps.resolveDeferredReady = resolve;
13142
+ this.deps.deferredReady = new Promise((resolve2) => {
13143
+ this.deps.resolveDeferredReady = resolve2;
13118
13144
  });
13119
13145
  try {
13120
13146
  await migrateFromEngram({
@@ -13420,7 +13446,7 @@ var OrchestratorInitCoordinator = class {
13420
13446
  if (signal.aborted) return;
13421
13447
  if (!this.deps.wearablesAutoSyncHandle && this.deps.config.wearables.enabled && this.deps.config.wearables.autoSyncEnabled && Object.values(this.deps.config.wearables.sources).some((source) => source.enabled)) {
13422
13448
  try {
13423
- const { startWearablesAutoSync } = await import("./auto-sync-IH3G25MT.js");
13449
+ const { startWearablesAutoSync } = await import("./auto-sync-UPTUVE4X.js");
13424
13450
  if (signal.aborted) return;
13425
13451
  this.deps.wearablesAutoSyncHandle = startWearablesAutoSync(
13426
13452
  {
@@ -15703,14 +15729,14 @@ var RecallEntryCoordinator = class {
15703
15729
  if (this.deps.initPromise) {
15704
15730
  const gateResult = await Promise.race([
15705
15731
  this.deps.initPromise.then(() => "ok"),
15706
- new Promise((resolve) => {
15732
+ new Promise((resolve2) => {
15707
15733
  initGateTimeoutHandle = setTimeout(
15708
- () => resolve("timeout"),
15734
+ () => resolve2("timeout"),
15709
15735
  this.deps.config.initGateTimeoutMs
15710
15736
  );
15711
15737
  }),
15712
- abortController.signal.aborted ? Promise.resolve("aborted") : new Promise((resolve) => {
15713
- onInitGateAbort = () => resolve("aborted");
15738
+ abortController.signal.aborted ? Promise.resolve("aborted") : new Promise((resolve2) => {
15739
+ onInitGateAbort = () => resolve2("aborted");
15714
15740
  abortController.signal.addEventListener(
15715
15741
  "abort",
15716
15742
  onInitGateAbort,
@@ -16035,9 +16061,9 @@ var SessionContextCoordinator = class {
16035
16061
  try {
16036
16062
  await Promise.race([
16037
16063
  this.deps.initPromise.catch(() => void 0),
16038
- new Promise((resolve) => {
16064
+ new Promise((resolve2) => {
16039
16065
  initGateTimeoutHandle = setTimeout(
16040
- resolve,
16066
+ resolve2,
16041
16067
  this.deps.config.initGateTimeoutMs
16042
16068
  );
16043
16069
  })
@@ -16058,14 +16084,14 @@ var SessionContextCoordinator = class {
16058
16084
  for (const bufferKey of bufferKeys) {
16059
16085
  const turns = this.deps.buffer.getTurns(bufferKey);
16060
16086
  if (turns.length === 0) continue;
16061
- await new Promise((resolve, reject) => {
16087
+ await new Promise((resolve2, reject) => {
16062
16088
  void this.deps.queueBufferedExtraction(turns, "trigger_mode", {
16063
16089
  bufferKey,
16064
16090
  clearBufferAfterExtraction: true,
16065
16091
  skipDedupeCheck: true,
16066
16092
  forceExtractionAttempt: true,
16067
16093
  abortSignal: options.abortSignal,
16068
- onTaskSettled: (error) => error ? reject(error) : resolve()
16094
+ onTaskSettled: (error) => error ? reject(error) : resolve2()
16069
16095
  }).catch(reject);
16070
16096
  });
16071
16097
  }
@@ -16149,8 +16175,8 @@ var XrayCaptureQueue = class {
16149
16175
  const previous = this.tail;
16150
16176
  let release = () => {
16151
16177
  };
16152
- this.tail = new Promise((resolve) => {
16153
- release = resolve;
16178
+ this.tail = new Promise((resolve2) => {
16179
+ release = resolve2;
16154
16180
  });
16155
16181
  try {
16156
16182
  await this.waitForTurn(previous, signal);
@@ -17111,8 +17137,8 @@ var Orchestrator = class {
17111
17137
  };
17112
17138
  this.lcmEngine = new LcmEngine(config, summarizeFn);
17113
17139
  }
17114
- this.initPromise = new Promise((resolve) => {
17115
- this.resolveInit = resolve;
17140
+ this.initPromise = new Promise((resolve2) => {
17141
+ this.resolveInit = resolve2;
17116
17142
  });
17117
17143
  }
17118
17144
  /** Get or create a BoxBuilder for the given namespace storage root (namespace-isolated). */
@@ -17416,7 +17442,7 @@ ${doc.content}` : doc.content,
17416
17442
  log.warn(`waitForConsolidationIdle timed out after ${timeoutMs}ms`);
17417
17443
  return false;
17418
17444
  }
17419
- await new Promise((resolve) => setTimeout(resolve, 50));
17445
+ await new Promise((resolve2) => setTimeout(resolve2, 50));
17420
17446
  }
17421
17447
  return true;
17422
17448
  }
@@ -19184,9 +19210,9 @@ function readStructuralSymbol(entry) {
19184
19210
  const rec = entry;
19185
19211
  const symbol = typeof rec.symbol === "string" ? rec.symbol.trim() : "";
19186
19212
  if (!symbol) return null;
19187
- const path31 = typeof rec.path === "string" && rec.path.length > 0 ? rec.path : void 0;
19213
+ const path32 = typeof rec.path === "string" && rec.path.length > 0 ? rec.path : void 0;
19188
19214
  const kind = typeof rec.kind === "string" && rec.kind.length > 0 ? rec.kind : void 0;
19189
- const item = path31 !== void 0 && kind !== void 0 ? { symbol, path: path31, kind } : path31 !== void 0 ? { symbol, path: path31 } : kind !== void 0 ? { symbol, kind } : { symbol };
19215
+ const item = path32 !== void 0 && kind !== void 0 ? { symbol, path: path32, kind } : path32 !== void 0 ? { symbol, path: path32 } : kind !== void 0 ? { symbol, kind } : { symbol };
19190
19216
  return item;
19191
19217
  }
19192
19218
  function classifySpawnError(err) {
@@ -19272,15 +19298,15 @@ var FilesystemBackend = class {
19272
19298
  }
19273
19299
  resolveRemotePath(remotePath) {
19274
19300
  const resolved = path17.isAbsolute(remotePath) ? path17.resolve(remotePath) : path17.resolve(this.basePath, remotePath);
19275
- const relative = path17.relative(this.basePath, resolved);
19276
- if (relative === ".." || relative.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative)) {
19301
+ const relative2 = path17.relative(this.basePath, resolved);
19302
+ if (relative2 === ".." || relative2.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative2)) {
19277
19303
  throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);
19278
19304
  }
19279
19305
  return resolved;
19280
19306
  }
19281
19307
  isInsideBase(candidate, realBase) {
19282
- const relative = path17.relative(realBase, candidate);
19283
- return relative === "" || relative !== ".." && !relative.startsWith(`..${path17.sep}`) && !path17.isAbsolute(relative);
19308
+ const relative2 = path17.relative(realBase, candidate);
19309
+ return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${path17.sep}`) && !path17.isAbsolute(relative2);
19284
19310
  }
19285
19311
  async realBasePathIfExists() {
19286
19312
  try {
@@ -19630,8 +19656,8 @@ function resolveManifestAssetPath(memoryDir, originalPath) {
19630
19656
  }
19631
19657
  const memoryRoot = path20.resolve(memoryDir);
19632
19658
  const fullPath = path20.resolve(memoryRoot, originalPath);
19633
- const relative = path20.relative(memoryRoot, fullPath);
19634
- if (relative === "" || relative === ".." || relative.startsWith(`..${path20.sep}`) || path20.isAbsolute(relative)) {
19659
+ const relative2 = path20.relative(memoryRoot, fullPath);
19660
+ if (relative2 === "" || relative2 === ".." || relative2.startsWith(`..${path20.sep}`) || path20.isAbsolute(relative2)) {
19635
19661
  return null;
19636
19662
  }
19637
19663
  return fullPath;
@@ -20166,8 +20192,8 @@ async function generateContextTree(options) {
20166
20192
  };
20167
20193
  }
20168
20194
  function isPathInside(root, candidate) {
20169
- const relative = path21.relative(root, candidate);
20170
- return relative === "" || !relative.startsWith("..") && !path21.isAbsolute(relative);
20195
+ const relative2 = path21.relative(root, candidate);
20196
+ return relative2 === "" || !relative2.startsWith("..") && !path21.isAbsolute(relative2);
20171
20197
  }
20172
20198
  function assertNotSymlink(targetPath, label) {
20173
20199
  try {
@@ -20204,11 +20230,11 @@ function assertSafeInputRoot(realMemoryDir, targetPath, label) {
20204
20230
  }
20205
20231
  function assertSafeOutputTarget(realOutputDir, outputPath) {
20206
20232
  let current = realOutputDir;
20207
- const relative = path21.relative(realOutputDir, outputPath);
20208
- if (relative.startsWith("..") || path21.isAbsolute(relative)) {
20233
+ const relative2 = path21.relative(realOutputDir, outputPath);
20234
+ if (relative2.startsWith("..") || path21.isAbsolute(relative2)) {
20209
20235
  throw new Error(`context tree output path escapes outputDir: ${outputPath}`);
20210
20236
  }
20211
- for (const segment of relative.split(path21.sep).filter(Boolean)) {
20237
+ for (const segment of relative2.split(path21.sep).filter(Boolean)) {
20212
20238
  current = path21.join(current, segment);
20213
20239
  try {
20214
20240
  const stat5 = fs.lstatSync(current);
@@ -20240,8 +20266,8 @@ function validateProjectionCategories(categories) {
20240
20266
  }
20241
20267
  function resolveContainedOutputPath(outputRoot, ...segments) {
20242
20268
  const resolved = path21.resolve(outputRoot, ...segments);
20243
- const relative = path21.relative(outputRoot, resolved);
20244
- if (relative === "" || !relative.startsWith("..") && !path21.isAbsolute(relative)) {
20269
+ const relative2 = path21.relative(outputRoot, resolved);
20270
+ if (relative2 === "" || !relative2.startsWith("..") && !path21.isAbsolute(relative2)) {
20245
20271
  return resolved;
20246
20272
  }
20247
20273
  throw new Error(`context tree output path escapes outputDir: ${segments.join("/")}`);
@@ -21345,8 +21371,8 @@ function realMemoryRoot(memoryDir) {
21345
21371
  }
21346
21372
  }
21347
21373
  function isPathInside2(rootReal, candidateReal) {
21348
- const relative = path25.relative(rootReal, candidateReal);
21349
- return relative === "" || !!relative && !relative.startsWith("..") && !path25.isAbsolute(relative);
21374
+ const relative2 = path25.relative(rootReal, candidateReal);
21375
+ return relative2 === "" || !!relative2 && !relative2.startsWith("..") && !path25.isAbsolute(relative2);
21350
21376
  }
21351
21377
  function isSafeDirectory(rootReal, dir) {
21352
21378
  try {
@@ -22222,8 +22248,8 @@ function isProcessAlive(pid) {
22222
22248
  return true;
22223
22249
  }
22224
22250
  }
22225
- function sleepSync(ms2) {
22226
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms2);
22251
+ function sleepSync(ms) {
22252
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
22227
22253
  }
22228
22254
  function createPersonalSpace(baseDir, memoryDirOverride) {
22229
22255
  const homeDir = baseDir ?? resolveHomeDir();
@@ -22608,8 +22634,8 @@ function safeRealpath(filePath) {
22608
22634
  }
22609
22635
  }
22610
22636
  function isPathInsideRoot(candidatePath, rootPath) {
22611
- const relative = path27.relative(rootPath, candidatePath);
22612
- return relative === "" || !relative.startsWith("..") && !path27.isAbsolute(relative);
22637
+ const relative2 = path27.relative(rootPath, candidatePath);
22638
+ return relative2 === "" || !relative2.startsWith("..") && !path27.isAbsolute(relative2);
22613
22639
  }
22614
22640
  function parseSimpleFrontmatter(content) {
22615
22641
  const match = content.match(/^---\n([\s\S]*?)\n---/);
@@ -23187,187 +23213,873 @@ async function generateActivityMemories(date, digestBody, config, deps) {
23187
23213
  return result;
23188
23214
  }
23189
23215
 
23190
- // src/meetings/detect.ts
23191
- import { createHash as createHash9 } from "crypto";
23192
- var DEFAULT_MEETING_APP_PATTERNS = [
23193
- "zoom.us",
23194
- "Zoom",
23195
- "Microsoft Teams",
23196
- "teams.microsoft.com",
23197
- "meet.google.com",
23198
- "Webex",
23199
- "Slack",
23200
- // huddle windows
23201
- "FaceTime"
23202
- ];
23203
- var DEFAULT_MEETINGS_DETECTION_CONFIG = {
23204
- appPatterns: [...DEFAULT_MEETING_APP_PATTERNS],
23205
- minOverlapMinutes: 2,
23206
- audioOnlyMinMinutes: 15,
23207
- mergeGapMinutes: 2
23216
+ // src/meetings/errors.ts
23217
+ var MeetingsInputError = class extends Error {
23218
+ constructor(message) {
23219
+ super(message);
23220
+ this.name = "MeetingsInputError";
23221
+ }
23208
23222
  };
23209
- function ms(iso) {
23210
- if (typeof iso !== "string") return Number.NaN;
23211
- if (!Number.isFinite(Date.parse(iso))) return Number.NaN;
23212
- const m = iso.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|[+-](?:0\d:[0-5]\d|1[0-3]:[0-5]\d|14:00))$/);
23213
- if (m === null) return Number.NaN;
23214
- const [year, month, day, hour, minute, second] = m.slice(1).map(Number);
23215
- const daysInMonth = month >= 1 && month <= 12 ? new Date(Date.UTC(year, month, 0)).getUTCDate() : 0;
23216
- if (day < 1 || day > daysInMonth || hour > 23 || minute > 59 || second > 59) return Number.NaN;
23217
- return Date.parse(iso);
23223
+
23224
+ // src/meetings/fuse.ts
23225
+ var SORT_STR = (a, b) => a < b ? -1 : a > b ? 1 : 0;
23226
+ function formatClockUtc(ms) {
23227
+ return new Date(ms).toISOString().slice(11, 16);
23218
23228
  }
23219
23229
  function overlapMs(aStart, aEnd, bStart, bEnd) {
23220
- const start = Math.max(aStart, bStart);
23221
- const end = Math.min(aEnd, bEnd);
23222
- return end > start ? end - start : 0;
23223
- }
23224
- function meetingId(date, startUtc) {
23225
- if (!isValidDay(date)) {
23226
- throw new RangeError(`meetings: invalid day "${date}" for a meeting id; expected a real YYYY-MM-DD.`);
23227
- }
23228
- const startMs = ms(startUtc);
23229
- if (Number.isNaN(startMs)) {
23230
- throw new RangeError(`meetings: invalid meeting start "${startUtc}" for a meeting id.`);
23231
- }
23232
- const anchor = new Date(startMs).toISOString();
23233
- const hash = createHash9("sha256").update(`${date}|${anchor}`, "utf8").digest("hex").slice(0, 8);
23234
- return `mtg-${date}-${hash}`;
23235
- }
23236
- function isFinitePair(a, b) {
23237
- return Number.isFinite(a) && Number.isFinite(b) && b > a;
23238
- }
23239
- function combineDetection(a, b) {
23240
- if (a === "app+audio" || b === "app+audio") return "app+audio";
23241
- if (a === "provider" || b === "provider") return "provider";
23242
- return "audio";
23243
- }
23244
- function buildCandidates(audioWindows, appSpans, config) {
23245
- const minOverlapMs = config.minOverlapMinutes * 6e4;
23246
- const audioOnlyMs = config.audioOnlyMinMinutes * 6e4;
23247
- const candidates = [];
23248
- for (const window of audioWindows) {
23249
- const startMs = ms(window.startUtc);
23250
- const endMs = ms(window.endUtc);
23251
- if (!isFinitePair(startMs, endMs)) continue;
23252
- if (window.providerMeeting === true) {
23253
- candidates.push({
23254
- startMs,
23255
- endMs,
23256
- detectionSource: "provider",
23257
- sources: [window.source],
23258
- ...window.title !== void 0 ? { title: window.title } : {}
23230
+ return Math.max(0, Math.min(aEnd, bEnd) - Math.max(aStart, bStart));
23231
+ }
23232
+ function segmentInWindow(seg, windowStartMs, windowEndMs) {
23233
+ const startMs = seg.startIso === void 0 ? NaN : Date.parse(seg.startIso);
23234
+ if (Number.isNaN(startMs)) return null;
23235
+ const endParsed = seg.endIso === void 0 ? NaN : Date.parse(seg.endIso);
23236
+ const endMs = Number.isNaN(endParsed) ? startMs : endParsed;
23237
+ if (endMs === startMs) return startMs >= windowStartMs && startMs < windowEndMs;
23238
+ return overlapMs(startMs, endMs, windowStartMs, windowEndMs) > 0;
23239
+ }
23240
+ function clipConversation(conv, windowStartMs, windowEndMs) {
23241
+ const convStart = Date.parse(conv.startIso);
23242
+ const convEnd = conv.endIso === void 0 ? convStart : Date.parse(conv.endIso);
23243
+ const convOverlaps = Number.isFinite(convStart) && overlapMs(convStart, Number.isFinite(convEnd) ? convEnd : convStart, windowStartMs, windowEndMs) > 0;
23244
+ const kept = [];
23245
+ let earliestStart;
23246
+ let earliestIso;
23247
+ let latestEnd;
23248
+ let latestIso;
23249
+ for (const seg of conv.segments) {
23250
+ const decision = segmentInWindow(seg, windowStartMs, windowEndMs);
23251
+ if (decision === false || decision === null && !convOverlaps) continue;
23252
+ kept.push(seg);
23253
+ if (seg.startIso !== void 0) {
23254
+ const s = Date.parse(seg.startIso);
23255
+ if (Number.isFinite(s) && (earliestStart === void 0 || s < earliestStart)) {
23256
+ earliestStart = s;
23257
+ earliestIso = seg.startIso;
23258
+ }
23259
+ const endIso = seg.endIso ?? seg.startIso;
23260
+ const e = Date.parse(endIso);
23261
+ if (Number.isFinite(e) && (latestEnd === void 0 || e > latestEnd)) {
23262
+ latestEnd = e;
23263
+ latestIso = endIso;
23264
+ }
23265
+ }
23266
+ }
23267
+ if (kept.length === 0) return null;
23268
+ return {
23269
+ source: conv.source,
23270
+ conversationId: conv.conversationId,
23271
+ ...conv.title !== void 0 ? { title: conv.title } : {},
23272
+ ...conv.summary !== void 0 ? { summary: conv.summary } : {},
23273
+ startIso: earliestIso ?? conv.startIso,
23274
+ ...latestIso !== void 0 ? { endIso: latestIso } : conv.endIso !== void 0 ? { endIso: conv.endIso } : {},
23275
+ segments: kept
23276
+ };
23277
+ }
23278
+ function shortenUrl(url) {
23279
+ return url.replace(/^[a-z]+:\/\//i, "");
23280
+ }
23281
+ function contextLabel(snap) {
23282
+ if (snap.url !== void 0 && snap.url.length > 0) return `${snap.app}: ${shortenUrl(snap.url)}`;
23283
+ if (snap.title !== void 0 && snap.title.length > 0) return `${snap.app}: ${snap.title}`;
23284
+ return snap.app;
23285
+ }
23286
+ function isMeetingAppSnapshot(snap, meetingApp, appPatterns) {
23287
+ const hay = `${snap.app} ${snap.title ?? ""} ${snap.url ?? ""}`.toLowerCase();
23288
+ if (meetingApp !== void 0 && meetingApp.length > 0 && hay.includes(meetingApp.toLowerCase())) {
23289
+ return true;
23290
+ }
23291
+ for (const pattern of appPatterns) {
23292
+ if (pattern.length > 0 && hay.includes(pattern.toLowerCase())) return true;
23293
+ }
23294
+ return false;
23295
+ }
23296
+ var MEETING_APP_KEY = "\0meeting-app";
23297
+ function buildScreenContext(activity, windowStartMs, windowEndMs, meetingApp, config) {
23298
+ const win = activity.map((snap) => ({ snap, ms: Date.parse(snap.tsUtc) })).filter((entry) => Number.isFinite(entry.ms) && entry.ms >= windowStartMs && entry.ms < windowEndMs).sort((a, b) => a.ms - b.ms || SORT_STR(a.snap.app, b.snap.app));
23299
+ const keyOf = (snap) => isMeetingAppSnapshot(snap, meetingApp, config.appPatterns) ? MEETING_APP_KEY : `${snap.app}\0${snap.url ?? snap.title ?? ""}`;
23300
+ const events = [];
23301
+ const includedText = [];
23302
+ let runStartIdx = 0;
23303
+ while (runStartIdx < win.length) {
23304
+ const key = keyOf(win[runStartIdx].snap);
23305
+ let runEndIdx = runStartIdx + 1;
23306
+ while (runEndIdx < win.length && keyOf(win[runEndIdx].snap) === key) runEndIdx++;
23307
+ const runStartMs = win[runStartIdx].ms;
23308
+ const runEndMs = runEndIdx < win.length ? win[runEndIdx].ms : win[runEndIdx - 1].ms;
23309
+ const dwellSeconds = Math.floor((runEndMs - runStartMs) / 1e3);
23310
+ const head = win[runStartIdx].snap;
23311
+ const isMeetingApp = key === MEETING_APP_KEY;
23312
+ if (isMeetingApp) {
23313
+ for (let i = runStartIdx; i < runEndIdx; i++) {
23314
+ const text = win[i].snap.text;
23315
+ if (text !== void 0 && text.trim().length > 0) includedText.push(text.trim());
23316
+ }
23317
+ } else if (dwellSeconds >= config.contextDwellSeconds) {
23318
+ events.push({
23319
+ tsUtc: new Date(runStartMs).toISOString(),
23320
+ clock: formatClockUtc(runStartMs),
23321
+ app: head.app,
23322
+ label: contextLabel(head),
23323
+ dwellSeconds
23259
23324
  });
23260
- continue;
23325
+ for (let i = runStartIdx; i < runEndIdx; i++) {
23326
+ const text = win[i].snap.text;
23327
+ if (text !== void 0 && text.trim().length > 0) includedText.push(text.trim());
23328
+ }
23261
23329
  }
23262
- let bestApp;
23263
- for (const span of appSpans) {
23264
- const spanStart = ms(span.startUtc);
23265
- const spanEnd = ms(span.endUtc);
23266
- if (!isFinitePair(spanStart, spanEnd)) continue;
23267
- const overlap = overlapMs(startMs, endMs, spanStart, spanEnd);
23268
- if (overlap <= 0 || overlap < minOverlapMs) continue;
23269
- if (bestApp === void 0 || overlap > bestApp.overlap) {
23270
- bestApp = { span, overlap };
23271
- } else if (overlap === bestApp.overlap) {
23272
- const bestStart = ms(bestApp.span.startUtc);
23273
- const better = spanStart < bestStart || spanStart === bestStart && (span.app < bestApp.span.app || span.app === bestApp.span.app && spanEnd < ms(bestApp.span.endUtc));
23274
- if (better) bestApp = { span, overlap };
23275
- }
23276
- }
23277
- if (bestApp !== void 0) {
23278
- candidates.push({
23279
- startMs,
23280
- endMs,
23281
- app: bestApp.span.app,
23282
- detectionSource: "app+audio",
23283
- sources: [window.source],
23284
- ...window.title !== void 0 ? { title: window.title } : {}
23285
- });
23330
+ runStartIdx = runEndIdx;
23331
+ }
23332
+ const excerpts = [];
23333
+ const seen = /* @__PURE__ */ new Set();
23334
+ let used = 0;
23335
+ for (const text of includedText) {
23336
+ if (seen.has(text)) continue;
23337
+ if (used + text.length > config.maxContextChars) break;
23338
+ seen.add(text);
23339
+ excerpts.push(text);
23340
+ used += text.length;
23341
+ }
23342
+ return { events, excerpts, snapshotCount: win.length };
23343
+ }
23344
+ function fuseMeeting(input, config, options = {}) {
23345
+ const windowStartMs = Date.parse(input.meeting.startUtc);
23346
+ const windowEndMs = Date.parse(input.meeting.endUtc);
23347
+ if (!Number.isFinite(windowStartMs) || !Number.isFinite(windowEndMs) || windowEndMs <= windowStartMs) {
23348
+ throw new RangeError(
23349
+ `meetings: meeting ${input.meeting.id} has an invalid window [${input.meeting.startUtc}, ${input.meeting.endUtc}).`
23350
+ );
23351
+ }
23352
+ const clipped = [];
23353
+ for (const conv of input.conversations) {
23354
+ const clip = clipConversation(conv, windowStartMs, windowEndMs);
23355
+ if (clip !== null) clipped.push(clip);
23356
+ }
23357
+ const fused = clipped.length > 0 ? fuseCluster(clipped, {
23358
+ ...options.sourceTrust !== void 0 ? { sourceTrust: options.sourceTrust } : {},
23359
+ ...options.windowToleranceMs !== void 0 ? { windowToleranceMs: options.windowToleranceMs } : {}
23360
+ }) : { sources: [], speakers: [], segments: [], disagreements: [], startIso: input.meeting.startUtc };
23361
+ const corroborated = /* @__PURE__ */ new Set();
23362
+ for (const segment of fused.segments) {
23363
+ for (const alt of segment.provenance.alternatives) {
23364
+ if (alt.source === segment.provenance.source) continue;
23365
+ corroborated.add(alt.source);
23366
+ }
23367
+ }
23368
+ const attendees = /* @__PURE__ */ new Set();
23369
+ for (const speaker of fused.speakers) {
23370
+ if (!speaker.isSelf) attendees.add(speaker.label);
23371
+ }
23372
+ const screen = buildScreenContext(
23373
+ input.activity ?? [],
23374
+ windowStartMs,
23375
+ windowEndMs,
23376
+ input.meeting.app,
23377
+ config
23378
+ );
23379
+ return {
23380
+ attendees: [...attendees].sort(SORT_STR),
23381
+ sources: [...fused.sources].sort(SORT_STR),
23382
+ corroboratedBy: [...corroborated].sort(SORT_STR),
23383
+ screenContext: screen.events,
23384
+ contextExcerpts: screen.excerpts,
23385
+ transcript: fused.segments,
23386
+ speakers: fused.speakers,
23387
+ snapshotCount: screen.snapshotCount
23388
+ };
23389
+ }
23390
+
23391
+ // src/meetings/store.ts
23392
+ import { createHash as createHash9 } from "crypto";
23393
+ import * as path29 from "path";
23394
+ var MEETINGS_DIR_NAME = "meetings";
23395
+ var MEETING_KIND = "meeting";
23396
+ var MEETING_FORMAT_VERSION = 1;
23397
+ var MEETING_ID_PATTERN = /^mtg-(\d{4}-\d{2}-\d{2})-[0-9a-f]{8}$/;
23398
+ function meetingIdDate(id) {
23399
+ const match = MEETING_ID_PATTERN.exec(id);
23400
+ return match === null ? null : match[1];
23401
+ }
23402
+ function canonicalContent(base, fused) {
23403
+ return JSON.stringify({
23404
+ formatVersion: MEETING_FORMAT_VERSION,
23405
+ id: base.id,
23406
+ date: base.date,
23407
+ startUtc: base.startUtc,
23408
+ endUtc: base.endUtc,
23409
+ app: base.app ?? null,
23410
+ detectionSource: base.detectionSource,
23411
+ title: base.title ?? null,
23412
+ attendees: fused.attendees,
23413
+ sources: fused.sources,
23414
+ corroboratedBy: fused.corroboratedBy,
23415
+ screenContext: fused.screenContext,
23416
+ contextExcerpts: fused.contextExcerpts,
23417
+ transcript: fused.transcript,
23418
+ speakers: fused.speakers,
23419
+ snapshotCount: fused.snapshotCount
23420
+ });
23421
+ }
23422
+ function composeMeetingRecord(base, fused) {
23423
+ const contentHash = createHash9("sha256").update(canonicalContent(base, fused), "utf-8").digest("hex");
23424
+ return {
23425
+ ...base,
23426
+ ...fused,
23427
+ contentHash,
23428
+ formatVersion: MEETING_FORMAT_VERSION
23429
+ };
23430
+ }
23431
+ function formatClockUtc2(iso) {
23432
+ const ms = Date.parse(iso);
23433
+ if (Number.isNaN(ms)) return "--:--";
23434
+ return new Date(ms).toISOString().slice(11, 16);
23435
+ }
23436
+ function renderTranscriptLine(segment) {
23437
+ const clock = formatClockUtc2(segment.startIso ?? "");
23438
+ return `**${escapeSpeakerLabel(segment.speaker)}** [${clock}]: ${escapeSegmentText(segment.text)}`;
23439
+ }
23440
+ function frontmatterList(key, values) {
23441
+ if (values.length === 0) return [`${key}: []`];
23442
+ const lines = [`${key}:`];
23443
+ for (const value of values) lines.push(` - ${JSON.stringify(value)}`);
23444
+ return lines;
23445
+ }
23446
+ function serializeMeetingRecord(record) {
23447
+ const lines = ["---"];
23448
+ lines.push(`kind: ${MEETING_KIND}`);
23449
+ lines.push(`formatVersion: ${record.formatVersion}`);
23450
+ lines.push(`id: ${JSON.stringify(record.id)}`);
23451
+ lines.push(`date: ${JSON.stringify(record.date)}`);
23452
+ lines.push(`startUtc: ${JSON.stringify(record.startUtc)}`);
23453
+ lines.push(`endUtc: ${JSON.stringify(record.endUtc)}`);
23454
+ if (record.app !== void 0) lines.push(`app: ${JSON.stringify(record.app)}`);
23455
+ lines.push(`detectionSource: ${JSON.stringify(record.detectionSource)}`);
23456
+ if (record.title !== void 0) lines.push(`title: ${JSON.stringify(record.title)}`);
23457
+ lines.push(...frontmatterList("attendees", record.attendees));
23458
+ lines.push(...frontmatterList("sources", record.sources));
23459
+ lines.push(...frontmatterList("corroboratedBy", record.corroboratedBy));
23460
+ lines.push(`snapshotCount: ${record.snapshotCount}`);
23461
+ lines.push(`contentHash: ${JSON.stringify(record.contentHash)}`);
23462
+ lines.push("---");
23463
+ lines.push("");
23464
+ const heading = record.title !== void 0 && record.title.length > 0 ? ` \xB7 ${record.title}` : "";
23465
+ lines.push(`# Meeting ${record.id}${heading}`);
23466
+ lines.push("");
23467
+ lines.push("## Attendees");
23468
+ lines.push("");
23469
+ if (record.attendees.length === 0) {
23470
+ lines.push("_None resolved._");
23471
+ } else {
23472
+ for (const attendee of record.attendees) lines.push(`- ${attendee}`);
23473
+ }
23474
+ lines.push("");
23475
+ if (record.screenContext.length > 0 || record.contextExcerpts.length > 0) {
23476
+ lines.push("## Screen context");
23477
+ lines.push("");
23478
+ for (const event of record.screenContext) {
23479
+ lines.push(`- [${event.clock}] ${event.label}`);
23480
+ }
23481
+ if (record.contextExcerpts.length > 0) {
23482
+ if (record.screenContext.length > 0) lines.push("");
23483
+ lines.push("Notable excerpts:");
23484
+ lines.push("");
23485
+ for (const excerpt of record.contextExcerpts) lines.push(`> ${excerpt.replace(/\n/g, " ")}`);
23486
+ }
23487
+ lines.push("");
23488
+ }
23489
+ lines.push("## Transcript");
23490
+ lines.push("");
23491
+ if (record.transcript.length === 0) {
23492
+ lines.push("_No transcript segments in this window._");
23493
+ } else {
23494
+ for (const segment of record.transcript) lines.push(renderTranscriptLine(segment));
23495
+ }
23496
+ lines.push("");
23497
+ return `${lines.join("\n")}`;
23498
+ }
23499
+ function parseScalar(value) {
23500
+ const trimmed = value.trim();
23501
+ if (trimmed.startsWith('"')) {
23502
+ try {
23503
+ return JSON.parse(trimmed);
23504
+ } catch {
23505
+ return trimmed;
23506
+ }
23507
+ }
23508
+ return trimmed;
23509
+ }
23510
+ function parseMeetingRecordSummary(raw) {
23511
+ if (!raw.startsWith("---\n")) return null;
23512
+ const closeIndex = raw.indexOf("\n---\n", 4);
23513
+ if (closeIndex === -1) return null;
23514
+ const frontmatter = raw.slice(4, closeIndex).split("\n");
23515
+ const scalars = {};
23516
+ const lists = {};
23517
+ let currentList = null;
23518
+ for (const line of frontmatter) {
23519
+ const listItem = /^ {2}- (.*)$/.exec(line);
23520
+ if (listItem !== null && currentList !== null) {
23521
+ lists[currentList].push(parseScalar(listItem[1]));
23286
23522
  continue;
23287
23523
  }
23288
- if (endMs - startMs >= audioOnlyMs && Number.isInteger(window.distinctNonWearerSpeakers) && window.distinctNonWearerSpeakers >= 2) {
23289
- candidates.push({
23290
- startMs,
23291
- endMs,
23292
- detectionSource: "audio",
23293
- sources: [window.source],
23294
- ...window.title !== void 0 ? { title: window.title } : {}
23295
- });
23524
+ const kv = /^([A-Za-z][A-Za-z0-9]*):\s*(.*)$/.exec(line);
23525
+ if (kv === null) continue;
23526
+ const key = kv[1];
23527
+ const value = kv[2];
23528
+ if (value === "") {
23529
+ currentList = key;
23530
+ lists[key] = [];
23531
+ } else if (value === "[]") {
23532
+ currentList = null;
23533
+ lists[key] = [];
23534
+ } else {
23535
+ currentList = null;
23536
+ scalars[key] = value;
23296
23537
  }
23297
23538
  }
23298
- return candidates;
23539
+ if (scalars.kind !== void 0 && parseScalar(scalars.kind) !== MEETING_KIND) return null;
23540
+ const id = scalars.id !== void 0 ? parseScalar(scalars.id) : void 0;
23541
+ const contentHash = scalars.contentHash !== void 0 ? parseScalar(scalars.contentHash) : void 0;
23542
+ if (id === void 0 || contentHash === void 0) return null;
23543
+ return {
23544
+ id,
23545
+ date: scalars.date !== void 0 ? parseScalar(scalars.date) : "",
23546
+ startUtc: scalars.startUtc !== void 0 ? parseScalar(scalars.startUtc) : "",
23547
+ endUtc: scalars.endUtc !== void 0 ? parseScalar(scalars.endUtc) : "",
23548
+ ...scalars.app !== void 0 ? { app: parseScalar(scalars.app) } : {},
23549
+ detectionSource: scalars.detectionSource !== void 0 ? parseScalar(scalars.detectionSource) : "",
23550
+ ...scalars.title !== void 0 ? { title: parseScalar(scalars.title) } : {},
23551
+ attendees: lists.attendees ?? [],
23552
+ sources: lists.sources ?? [],
23553
+ corroboratedBy: lists.corroboratedBy ?? [],
23554
+ snapshotCount: scalars.snapshotCount !== void 0 ? Number(scalars.snapshotCount) || 0 : 0,
23555
+ contentHash
23556
+ };
23299
23557
  }
23300
- var DETECTION_RANK = {
23301
- "app+audio": 0,
23302
- provider: 1,
23303
- audio: 2
23558
+ var MeetingRecordStore = class {
23559
+ constructor(memoryDir, io) {
23560
+ this.memoryDir = memoryDir;
23561
+ this.io = io;
23562
+ this.meetingsDir = path29.join(memoryDir, MEETINGS_DIR_NAME);
23563
+ }
23564
+ memoryDir;
23565
+ io;
23566
+ meetingsDir;
23567
+ recordPath(date, id) {
23568
+ if (!isValidTranscriptDate(date)) {
23569
+ throw new Error(`invalid meeting date '${String(date)}' \u2014 expected YYYY-MM-DD`);
23570
+ }
23571
+ const idDate = meetingIdDate(id);
23572
+ if (idDate === null) {
23573
+ throw new Error(`invalid meeting id '${String(id)}' \u2014 expected mtg-YYYY-MM-DD-<hash>`);
23574
+ }
23575
+ if (idDate !== date) {
23576
+ throw new Error(`meeting id '${id}' does not belong to date '${date}'`);
23577
+ }
23578
+ return path29.join(this.meetingsDir, date, `${id}.md`);
23579
+ }
23580
+ /** Idempotently persist a record: skip the write when contentHash is unchanged. */
23581
+ async saveMeetingRecord(record) {
23582
+ const filePath = this.recordPath(record.date, record.id);
23583
+ await this.assertPathContained(filePath);
23584
+ const existing = await this.readRaw(filePath);
23585
+ if (existing !== null) {
23586
+ const summary = parseMeetingRecordSummary(existing);
23587
+ if (summary !== null && summary.contentHash === record.contentHash) {
23588
+ return { path: filePath, written: false, contentHash: record.contentHash };
23589
+ }
23590
+ }
23591
+ await this.io.writeFile(filePath, serializeMeetingRecord(record));
23592
+ return { path: filePath, written: true, contentHash: record.contentHash };
23593
+ }
23594
+ /** Read a stored record's raw markdown; null when absent. */
23595
+ async readMeetingRecord(date, id) {
23596
+ const filePath = this.recordPath(date, id);
23597
+ await this.assertPathContained(filePath);
23598
+ return this.readRaw(filePath);
23599
+ }
23600
+ /**
23601
+ * Read + parse every stored record for a day exactly ONCE, sorted by start
23602
+ * time (ascending, id tiebreak). The single day-read path both `listMeetingIds`
23603
+ * and `listMeetingSummaries` derive from — no record is read twice.
23604
+ */
23605
+ async readDaySummaries(date) {
23606
+ if (!isValidTranscriptDate(date)) {
23607
+ throw new Error(`invalid meeting date '${String(date)}' \u2014 expected YYYY-MM-DD`);
23608
+ }
23609
+ const dayDir = path29.join(this.meetingsDir, date);
23610
+ await this.assertPathContained(dayDir);
23611
+ let entries;
23612
+ try {
23613
+ entries = await this.io.readDir(dayDir);
23614
+ } catch (err) {
23615
+ if (err.code === "ENOENT") return [];
23616
+ throw err;
23617
+ }
23618
+ const summaries = [];
23619
+ for (const entry of entries) {
23620
+ if (!entry.endsWith(".md")) continue;
23621
+ const id = entry.slice(0, -3);
23622
+ if (meetingIdDate(id) !== date) continue;
23623
+ const raw = await this.readMeetingRecord(date, id);
23624
+ if (raw === null) continue;
23625
+ const summary = parseMeetingRecordSummary(raw);
23626
+ if (summary !== null) summaries.push(summary);
23627
+ }
23628
+ summaries.sort((a, b) => a.startUtc < b.startUtc ? -1 : a.startUtc > b.startUtc ? 1 : SORT_STR2(a.id, b.id));
23629
+ return summaries;
23630
+ }
23631
+ /** List meeting ids stored for a day, sorted by start time (ascending). */
23632
+ async listMeetingIds(date) {
23633
+ return (await this.readDaySummaries(date)).map((summary) => summary.id);
23634
+ }
23635
+ /** Read parsed summaries for a day, sorted by start time. */
23636
+ async listMeetingSummaries(date) {
23637
+ return this.readDaySummaries(date);
23638
+ }
23639
+ /** List dates that have at least one stored meeting record, newest first. */
23640
+ async listMeetingDates() {
23641
+ await this.assertPathContained(this.meetingsDir);
23642
+ let entries;
23643
+ try {
23644
+ entries = await this.io.readDir(this.meetingsDir);
23645
+ } catch (err) {
23646
+ if (err.code === "ENOENT") return [];
23647
+ throw err;
23648
+ }
23649
+ const dates = entries.filter((entry) => isValidTranscriptDate(entry));
23650
+ dates.sort((a, b) => a > b ? -1 : a < b ? 1 : 0);
23651
+ return dates;
23652
+ }
23653
+ /** Remove a stored record. Idempotent: a no-op when already absent. */
23654
+ async deleteMeetingRecord(date, id) {
23655
+ const filePath = this.recordPath(date, id);
23656
+ await this.assertPathContained(filePath);
23657
+ try {
23658
+ await this.io.deleteFile(filePath);
23659
+ } catch (err) {
23660
+ if (err.code === "ENOENT") return;
23661
+ throw err;
23662
+ }
23663
+ }
23664
+ async readRaw(filePath) {
23665
+ try {
23666
+ return await this.io.readFile(filePath);
23667
+ } catch (err) {
23668
+ if (err.code === "ENOENT") return null;
23669
+ throw err;
23670
+ }
23671
+ }
23672
+ async assertPathContained(targetPath) {
23673
+ let rootReal;
23674
+ try {
23675
+ rootReal = await this.io.realpath(this.memoryDir);
23676
+ } catch {
23677
+ rootReal = path29.resolve(this.memoryDir);
23678
+ }
23679
+ await this.assertNoEscape(rootReal, this.meetingsDir);
23680
+ await this.assertNoEscape(rootReal, path29.dirname(targetPath));
23681
+ await this.assertNoEscape(rootReal, targetPath);
23682
+ await this.assertNotSymlink(this.meetingsDir, "directory");
23683
+ const dayDir = this.dayDirWithin(targetPath);
23684
+ if (dayDir !== null) await this.assertNotSymlink(dayDir, "directory");
23685
+ if (targetPath.endsWith(".md")) await this.assertNotSymlink(targetPath, "record file");
23686
+ }
23687
+ /** The `<meetings>/<date>` directory on the path to `targetPath`, or null when
23688
+ * `targetPath` is the meetings root itself. */
23689
+ dayDirWithin(targetPath) {
23690
+ const rel = path29.relative(this.meetingsDir, targetPath);
23691
+ if (rel === "" || rel.startsWith("..") || path29.isAbsolute(rel)) return null;
23692
+ const first = rel.split(path29.sep)[0];
23693
+ if (first === void 0 || first.length === 0) return null;
23694
+ return path29.join(this.meetingsDir, first);
23695
+ }
23696
+ async assertNotSymlink(target, kind) {
23697
+ let stat5;
23698
+ try {
23699
+ stat5 = await this.io.lstat(target);
23700
+ } catch (err) {
23701
+ if (err.code === "ENOENT") return;
23702
+ throw err;
23703
+ }
23704
+ if (stat5.isSymbolicLink) {
23705
+ const label = path29.relative(this.memoryDir, target) || MEETINGS_DIR_NAME;
23706
+ throw new Error(
23707
+ `meetings ${kind} '${label}' is a symbolic link \u2014 refusing to follow it even when it resolves inside the memory dir (AGENTS.md pattern #3)`
23708
+ );
23709
+ }
23710
+ }
23711
+ async assertNoEscape(rootReal, candidate) {
23712
+ let candidateReal;
23713
+ try {
23714
+ candidateReal = await this.io.realpath(candidate);
23715
+ } catch {
23716
+ return;
23717
+ }
23718
+ if (!pathIsInside(rootReal, candidateReal)) {
23719
+ throw new Error(
23720
+ "meeting record path resolves outside the memory dir \u2014 refusing to follow a symlink/traversal (AGENTS.md pattern #3)"
23721
+ );
23722
+ }
23723
+ }
23304
23724
  };
23305
- function candidateOrder(a, b) {
23306
- return a.startMs - b.startMs || a.endMs - b.endMs || DETECTION_RANK[a.detectionSource] - DETECTION_RANK[b.detectionSource] || (a.app ?? "").localeCompare(b.app ?? "") || (a.title ?? "").localeCompare(b.title ?? "") || (a.sources[0] ?? "").localeCompare(b.sources[0] ?? "");
23307
- }
23308
- function mergeCandidates(candidates, mergeGapMs) {
23309
- const sorted = [...candidates].sort(candidateOrder);
23310
- const merged = [];
23311
- for (const candidate of sorted) {
23312
- const prev = merged[merged.length - 1];
23313
- const overlaps = prev !== void 0 && candidate.startMs < prev.endMs;
23314
- const sameAppAdjacent = prev !== void 0 && prev.app !== void 0 && prev.app === candidate.app && candidate.startMs - prev.endMs <= mergeGapMs;
23315
- if (prev !== void 0 && (overlaps || sameAppAdjacent)) {
23316
- prev.endMs = Math.max(prev.endMs, candidate.endMs);
23317
- prev.app = prev.app ?? candidate.app;
23318
- prev.detectionSource = combineDetection(prev.detectionSource, candidate.detectionSource);
23319
- prev.sources = [.../* @__PURE__ */ new Set([...prev.sources, ...candidate.sources])];
23320
- prev.title = prev.title ?? candidate.title;
23725
+ var SORT_STR2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
23726
+
23727
+ // src/meetings/build.ts
23728
+ function buildMeetingRecordsForDay(data, config, options = {}, resolveMeetingId = (meeting) => meeting.id) {
23729
+ const meetings = detectMeetings(data.detection, {
23730
+ appPatterns: config.appPatterns,
23731
+ minOverlapMinutes: config.minOverlapMinutes,
23732
+ audioOnlyMinMinutes: config.audioOnlyMinMinutes,
23733
+ mergeGapMinutes: config.mergeGapMinutes
23734
+ });
23735
+ return meetings.map((meeting) => {
23736
+ const fused = fuseMeeting(
23737
+ { meeting, conversations: data.conversations, ...data.activity !== void 0 ? { activity: data.activity } : {} },
23738
+ config,
23739
+ options
23740
+ );
23741
+ return composeMeetingRecord(
23742
+ {
23743
+ id: resolveMeetingId(meeting),
23744
+ date: meeting.date,
23745
+ startUtc: meeting.startUtc,
23746
+ endUtc: meeting.endUtc,
23747
+ ...meeting.app !== void 0 ? { app: meeting.app } : {},
23748
+ detectionSource: meeting.detectionSource,
23749
+ ...meeting.title !== void 0 ? { title: meeting.title } : {}
23750
+ },
23751
+ fused
23752
+ );
23753
+ });
23754
+ }
23755
+ var MeetingsBuilder = class {
23756
+ constructor(opts) {
23757
+ this.opts = opts;
23758
+ }
23759
+ opts;
23760
+ async buildDay(date) {
23761
+ if (!this.opts.config.enabled) {
23762
+ return { date, enabled: false, meetings: [], built: 0, skipped: 0, removed: [] };
23763
+ }
23764
+ const data = await this.opts.source.loadDayData(date);
23765
+ if (data.detection.date !== date) {
23766
+ throw new RangeError(
23767
+ `meetings: day source returned detection.date "${data.detection.date}" for requested day "${date}".`
23768
+ );
23769
+ }
23770
+ const existing = await this.opts.store.listMeetingSummaries(date);
23771
+ const claimed = /* @__PURE__ */ new Set();
23772
+ const resolveMeetingId = (meeting) => this.adoptExistingId(meeting, existing, claimed);
23773
+ const records = buildMeetingRecordsForDay(
23774
+ data,
23775
+ this.opts.config,
23776
+ this.opts.fusionOptions ?? {},
23777
+ resolveMeetingId
23778
+ );
23779
+ const meetings = [];
23780
+ let built = 0;
23781
+ let skipped = 0;
23782
+ const builtIds = /* @__PURE__ */ new Set();
23783
+ const priorIds = new Set(existing.map((summary2) => summary2.id));
23784
+ const unchangedIds = [];
23785
+ const updatedIds = [];
23786
+ for (const record of records) {
23787
+ const save = await this.opts.store.saveMeetingRecord(record);
23788
+ if (save.written) {
23789
+ built++;
23790
+ if (priorIds.has(record.id)) updatedIds.push(record.id);
23791
+ } else {
23792
+ skipped++;
23793
+ unchangedIds.push(record.id);
23794
+ }
23795
+ builtIds.add(record.id);
23796
+ meetings.push({
23797
+ id: record.id,
23798
+ startUtc: record.startUtc,
23799
+ endUtc: record.endUtc,
23800
+ detectionSource: record.detectionSource,
23801
+ sources: record.sources,
23802
+ attendees: record.attendees,
23803
+ snapshotCount: record.snapshotCount,
23804
+ written: save.written
23805
+ });
23806
+ }
23807
+ const removed = [];
23808
+ for (const existingId of await this.opts.store.listMeetingIds(date)) {
23809
+ if (builtIds.has(existingId)) continue;
23810
+ await this.opts.store.deleteMeetingRecord(date, existingId);
23811
+ removed.push(existingId);
23812
+ }
23813
+ const summary = { date, enabled: true, meetings, built, skipped, removed };
23814
+ let outcome;
23815
+ if (this.opts.memoryGenerator !== void 0) {
23816
+ try {
23817
+ outcome = await this.opts.memoryGenerator.onRecordsBuilt({
23818
+ built: records,
23819
+ removedIds: removed,
23820
+ unchangedIds,
23821
+ updatedIds
23822
+ });
23823
+ } catch (err) {
23824
+ log.error("meetings: memory generation failed after records were persisted", err);
23825
+ summary.memoryWarning = "memory generation failed after records were persisted; see logs for detail";
23826
+ }
23827
+ }
23828
+ if (outcome?.episodes !== void 0) summary.episodes = outcome.episodes;
23829
+ if (outcome?.facts !== void 0) summary.facts = outcome.facts;
23830
+ if (outcome?.warnings !== void 0 && outcome.warnings.length > 0) {
23831
+ summary.memoryWarning = outcome.warnings.join("; ");
23832
+ }
23833
+ if (built > 0 || removed.length > 0 || (outcome?.reindexNeeded ?? false)) {
23834
+ try {
23835
+ await this.opts.hooks?.reindex?.(summary);
23836
+ } catch (err) {
23837
+ log.error("meetings: reindex hook failed after records were persisted", err);
23838
+ summary.reindexWarning = "reindex hook failed after records were persisted; see logs for detail";
23839
+ }
23840
+ }
23841
+ return summary;
23842
+ }
23843
+ /**
23844
+ * Pick the existing same-day record whose window best overlaps `meeting` and
23845
+ * reuse its id — but ONLY when adoption is safe: the windows substantially
23846
+ * coincide (overlap covers a majority of the shorter window), OR a corroborating
23847
+ * identity signal (same app, same title, or a shared transcript source) is
23848
+ * BACKED by a non-marginal overlap (>= a quarter of the shorter window). Coarse
23849
+ * identity signals alone never license adoption across a thin sliver of overlap,
23850
+ * or two genuinely different back-to-back same-app meetings would overwrite each
23851
+ * other's record and `show <old-id>` would point at the wrong meeting. Candidate
23852
+ * selection is deterministic (max overlap, then earliest start, then id).
23853
+ * Returns the detector's fresh id when nothing qualifies.
23854
+ */
23855
+ adoptExistingId(meeting, existing, claimed) {
23856
+ const dStart = Date.parse(meeting.startUtc);
23857
+ const dEnd = Date.parse(meeting.endUtc);
23858
+ if (!Number.isFinite(dStart) || !Number.isFinite(dEnd)) return meeting.id;
23859
+ let best;
23860
+ for (const record of existing) {
23861
+ if (claimed.has(record.id)) continue;
23862
+ const eStart = Date.parse(record.startUtc);
23863
+ const eEnd = Date.parse(record.endUtc);
23864
+ if (!Number.isFinite(eStart) || !Number.isFinite(eEnd)) continue;
23865
+ const overlap = Math.min(dEnd, eEnd) - Math.max(dStart, eStart);
23866
+ if (overlap <= 0) continue;
23867
+ const better = best === void 0 || overlap > best.overlap || overlap === best.overlap && (record.startUtc < best.record.startUtc || record.startUtc === best.record.startUtc && record.id < best.record.id);
23868
+ if (better) best = { record, overlap, existingDurationMs: eEnd - eStart };
23869
+ }
23870
+ if (best === void 0) return meeting.id;
23871
+ const shorterWindowMs = Math.min(dEnd - dStart, best.existingDurationMs);
23872
+ if (shorterWindowMs <= 0) return meeting.id;
23873
+ const substantial = best.overlap * 2 >= shorterWindowMs;
23874
+ const sharedSource = meeting.sources.some((source) => best.record.sources.includes(source));
23875
+ const sameApp = meeting.app !== void 0 && best.record.app !== void 0 && meeting.app.toLowerCase() === best.record.app.toLowerCase();
23876
+ const meetingTitle = meeting.title?.trim() ?? "";
23877
+ const sameTitle = meetingTitle.length > 0 && meetingTitle === (best.record.title?.trim() ?? "");
23878
+ const hasIdentitySignal = sharedSource || sameApp || sameTitle;
23879
+ const nonMarginalOverlap = best.overlap * 4 >= shorterWindowMs;
23880
+ if (!substantial && !(hasIdentitySignal && nonMarginalOverlap)) return meeting.id;
23881
+ claimed.add(best.record.id);
23882
+ return best.record.id;
23883
+ }
23884
+ };
23885
+
23886
+ // src/meetings/cli.ts
23887
+ var USAGE = `Usage: meetings <command> [options]
23888
+
23889
+ Commands:
23890
+ list [--date <YYYY-MM-DD>] List meeting records (all days, or one day)
23891
+ show <meeting-id> Print a stored meeting record
23892
+ build --date <YYYY-MM-DD> Detect + fuse + store the day's meetings
23893
+
23894
+ Add --json to list/build for machine-readable output.
23895
+ `;
23896
+ var VALUE_FLAGS = { "--date": true };
23897
+ var BOOLEAN_FLAGS = { "--json": true };
23898
+ function parseFlags(args) {
23899
+ const flags = /* @__PURE__ */ new Map();
23900
+ const positional = [];
23901
+ for (let i = 0; i < args.length; i++) {
23902
+ const arg = args[i];
23903
+ if (!arg.startsWith("--")) {
23904
+ positional.push(arg);
23905
+ continue;
23906
+ }
23907
+ if (VALUE_FLAGS[arg] === true) {
23908
+ const value = args[i + 1];
23909
+ if (value === void 0 || value.startsWith("--")) {
23910
+ throw new MeetingsInputError(`flag ${arg} requires a value`);
23911
+ }
23912
+ flags.set(arg, value);
23913
+ i++;
23914
+ continue;
23915
+ }
23916
+ if (BOOLEAN_FLAGS[arg] === true) {
23917
+ flags.set(arg, true);
23321
23918
  continue;
23322
23919
  }
23323
- merged.push({ ...candidate, sources: [...candidate.sources] });
23920
+ const known = [...Object.keys(VALUE_FLAGS), ...Object.keys(BOOLEAN_FLAGS)].sort().join(", ");
23921
+ throw new MeetingsInputError(`unknown flag ${arg} (valid: ${known})`);
23324
23922
  }
23325
- return merged;
23923
+ return { flags, positional };
23326
23924
  }
23327
- function assertFiniteNonNegative(name, value) {
23328
- if (!Number.isFinite(value) || value < 0) {
23329
- throw new RangeError(`meetings config "${name}" must be a finite, non-negative number (got ${value}).`);
23330
- }
23331
- }
23332
- function isValidDay(date) {
23333
- const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(date);
23334
- if (m === null) return false;
23335
- const [, year, month, day] = m.map(Number);
23336
- const daysInMonth = month >= 1 && month <= 12 ? new Date(Date.UTC(year, month, 0)).getUTCDate() : 0;
23337
- return day >= 1 && day <= daysInMonth;
23338
- }
23339
- function validateConfig(config) {
23340
- assertFiniteNonNegative("minOverlapMinutes", config.minOverlapMinutes);
23341
- assertFiniteNonNegative("audioOnlyMinMinutes", config.audioOnlyMinMinutes);
23342
- assertFiniteNonNegative("mergeGapMinutes", config.mergeGapMinutes);
23343
- }
23344
- function detectMeetings(input, config = DEFAULT_MEETINGS_DETECTION_CONFIG) {
23345
- validateConfig(config);
23346
- if (!isValidDay(input.date)) {
23347
- throw new RangeError(`meetings: invalid day "${input.date}"; expected a real YYYY-MM-DD.`);
23348
- }
23349
- const candidates = buildCandidates(input.audioWindows, input.appSpans, config);
23350
- const merged = mergeCandidates(candidates, config.mergeGapMinutes * 6e4);
23351
- return merged.map((candidate) => {
23352
- const startUtc = new Date(candidate.startMs).toISOString();
23353
- const endUtc = new Date(candidate.endMs).toISOString();
23354
- return {
23355
- id: meetingId(input.date, startUtc),
23356
- date: input.date,
23357
- startUtc,
23358
- endUtc,
23359
- ...candidate.app !== void 0 ? { app: candidate.app } : {},
23360
- detectionSource: candidate.detectionSource,
23361
- sources: [...candidate.sources].sort((a, b) => a < b ? -1 : a > b ? 1 : 0),
23362
- ...candidate.title !== void 0 ? { title: candidate.title } : {}
23363
- };
23364
- });
23925
+ function requireDate(parsed) {
23926
+ const value = parsed.flags.get("--date");
23927
+ if (typeof value !== "string") {
23928
+ throw new MeetingsInputError("--date <YYYY-MM-DD> is required");
23929
+ }
23930
+ if (!isValidTranscriptDate(value)) {
23931
+ throw new MeetingsInputError(`--date must be a real YYYY-MM-DD; got '${value}'`);
23932
+ }
23933
+ return value;
23934
+ }
23935
+ function renderSummaryLine(summary) {
23936
+ const attendees = summary.attendees.length > 0 ? summary.attendees.join(", ") : "(none)";
23937
+ const sources = summary.sources.length > 0 ? summary.sources.join("+") : "(none)";
23938
+ const corroborated = summary.corroboratedBy.length > 0 ? ` corroborated=${summary.corroboratedBy.join("+")}` : "";
23939
+ return ` ${summary.id} ${summary.startUtc}\u2013${summary.endUtc} [${summary.detectionSource}] sources=${sources}${corroborated} attendees=${attendees} snapshots=${summary.snapshotCount}`;
23940
+ }
23941
+ function renderBuildSummary(summary) {
23942
+ if (!summary.enabled) {
23943
+ return `meetings disabled \u2014 set meetings.enabled=true to build (${summary.date})`;
23944
+ }
23945
+ const lines = [
23946
+ `${summary.date}: ${summary.meetings.length} meeting${summary.meetings.length === 1 ? "" : "s"} (${summary.built} written, ${summary.skipped} unchanged, ${summary.removed.length} removed)`
23947
+ ];
23948
+ for (const meeting of summary.meetings) {
23949
+ const sources = meeting.sources.length > 0 ? meeting.sources.join("+") : "(none)";
23950
+ lines.push(
23951
+ ` ${meeting.id} ${meeting.startUtc}\u2013${meeting.endUtc} [${meeting.detectionSource}] sources=${sources} snapshots=${meeting.snapshotCount} ${meeting.written ? "written" : "unchanged"}`
23952
+ );
23953
+ }
23954
+ if (summary.reindexWarning !== void 0) {
23955
+ lines.push(` warning: ${summary.reindexWarning}`);
23956
+ }
23957
+ if (summary.memoryWarning !== void 0) {
23958
+ lines.push(` warning: ${summary.memoryWarning}`);
23959
+ }
23960
+ return lines.join("\n");
23961
+ }
23962
+ async function runMeetingsCliCommand(deps, args, io) {
23963
+ const [command, ...rest] = args;
23964
+ try {
23965
+ switch (command) {
23966
+ case void 0:
23967
+ case "help":
23968
+ case "--help": {
23969
+ io.stdout.write(USAGE);
23970
+ return command === void 0 ? 1 : 0;
23971
+ }
23972
+ case "list": {
23973
+ const parsed = parseFlags(rest);
23974
+ const json = parsed.flags.has("--json");
23975
+ const dateFlag = parsed.flags.get("--date");
23976
+ if (typeof dateFlag === "string" && !isValidTranscriptDate(dateFlag)) {
23977
+ throw new MeetingsInputError(`--date must be a real YYYY-MM-DD; got '${dateFlag}'`);
23978
+ }
23979
+ if (!deps.config.enabled) {
23980
+ if (json) {
23981
+ io.stdout.write(typeof dateFlag === "string" ? "[]\n" : "{}\n");
23982
+ } else {
23983
+ io.stdout.write("meetings disabled \u2014 set meetings.enabled=true to build\n");
23984
+ }
23985
+ return 0;
23986
+ }
23987
+ if (typeof dateFlag === "string") {
23988
+ const summaries = await deps.store.listMeetingSummaries(dateFlag);
23989
+ if (json) {
23990
+ io.stdout.write(`${JSON.stringify(summaries, null, 2)}
23991
+ `);
23992
+ return 0;
23993
+ }
23994
+ if (summaries.length === 0) {
23995
+ io.stdout.write(`No meetings for ${dateFlag}.
23996
+ `);
23997
+ return 0;
23998
+ }
23999
+ io.stdout.write(`${dateFlag}:
24000
+ `);
24001
+ for (const summary of summaries) io.stdout.write(`${renderSummaryLine(summary)}
24002
+ `);
24003
+ return 0;
24004
+ }
24005
+ const dates = await deps.store.listMeetingDates();
24006
+ if (json) {
24007
+ const out = {};
24008
+ for (const date of dates) out[date] = await deps.store.listMeetingSummaries(date);
24009
+ io.stdout.write(`${JSON.stringify(out, null, 2)}
24010
+ `);
24011
+ return 0;
24012
+ }
24013
+ if (dates.length === 0) {
24014
+ io.stdout.write("No meetings recorded.\n");
24015
+ return 0;
24016
+ }
24017
+ for (const date of dates) {
24018
+ const summaries = await deps.store.listMeetingSummaries(date);
24019
+ io.stdout.write(`${date}:
24020
+ `);
24021
+ for (const summary of summaries) io.stdout.write(`${renderSummaryLine(summary)}
24022
+ `);
24023
+ }
24024
+ return 0;
24025
+ }
24026
+ case "show": {
24027
+ const parsed = parseFlags(rest);
24028
+ if (!deps.config.enabled) {
24029
+ io.stdout.write("meetings disabled \u2014 set meetings.enabled=true to build\n");
24030
+ return 0;
24031
+ }
24032
+ const id = parsed.positional[0];
24033
+ if (id === void 0) {
24034
+ throw new MeetingsInputError("show requires a meeting id");
24035
+ }
24036
+ const date = meetingIdDate(id);
24037
+ if (date === null) {
24038
+ throw new MeetingsInputError(`invalid meeting id '${id}' \u2014 expected mtg-YYYY-MM-DD-<hash>`);
24039
+ }
24040
+ if (!isValidTranscriptDate(date)) {
24041
+ throw new MeetingsInputError(`invalid meeting id '${id}' \u2014 '${date}' is not a real calendar date`);
24042
+ }
24043
+ const raw = await deps.store.readMeetingRecord(date, id);
24044
+ if (raw === null) {
24045
+ throw new MeetingsInputError(`meeting '${id}' not found`);
24046
+ }
24047
+ io.stdout.write(raw.endsWith("\n") ? raw : `${raw}
24048
+ `);
24049
+ return 0;
24050
+ }
24051
+ case "build": {
24052
+ const parsed = parseFlags(rest);
24053
+ const date = requireDate(parsed);
24054
+ const summary = await deps.builder.buildDay(date);
24055
+ if (parsed.flags.has("--json")) {
24056
+ io.stdout.write(`${JSON.stringify(summary, null, 2)}
24057
+ `);
24058
+ return 0;
24059
+ }
24060
+ io.stdout.write(`${renderBuildSummary(summary)}
24061
+ `);
24062
+ return 0;
24063
+ }
24064
+ default:
24065
+ throw new MeetingsInputError(`unknown meetings command '${command}'
24066
+
24067
+ ${USAGE}`);
24068
+ }
24069
+ } catch (err) {
24070
+ if (err instanceof MeetingsInputError) {
24071
+ io.stderr.write(`meetings: ${err.message}
24072
+ `);
24073
+ return 1;
24074
+ }
24075
+ throw err;
24076
+ }
23365
24077
  }
23366
24078
 
23367
24079
  // src/session-summaries/index.ts
23368
24080
  import { createHash as createHash10 } from "crypto";
23369
24081
  import { lstat as lstat2, mkdir as mkdir7, readFile as readFile6, readdir as readdir4, rename, rm, stat as stat4, writeFile as writeFile7 } from "fs/promises";
23370
- import path29 from "path";
24082
+ import path30 from "path";
23371
24083
 
23372
24084
  // src/session-summaries/adapters.ts
23373
24085
  var VALID_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "tool", "system", "other"]);
@@ -23872,7 +24584,7 @@ function shortHash(value, length = 16) {
23872
24584
  async function listTranscriptFiles(root, maxFiles) {
23873
24585
  const out = [];
23874
24586
  let truncated = false;
23875
- const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${path29.sep}` : entryName;
24587
+ const entrySortKey = (entryName, isDirectory) => isDirectory ? `${entryName}${path30.sep}` : entryName;
23876
24588
  async function visit(dir) {
23877
24589
  if (truncated) return;
23878
24590
  const entries = (await readdir4(dir, { withFileTypes: true })).sort(
@@ -23882,13 +24594,13 @@ async function listTranscriptFiles(root, maxFiles) {
23882
24594
  if (truncated) return;
23883
24595
  if (entry.name.startsWith(".")) continue;
23884
24596
  if (entry.isSymbolicLink()) continue;
23885
- const fullPath = path29.join(dir, entry.name);
24597
+ const fullPath = path30.join(dir, entry.name);
23886
24598
  if (entry.isDirectory()) {
23887
24599
  await visit(fullPath);
23888
24600
  continue;
23889
24601
  }
23890
24602
  if (!entry.isFile()) continue;
23891
- const ext = path29.extname(entry.name).toLowerCase();
24603
+ const ext = path30.extname(entry.name).toLowerCase();
23892
24604
  if (!SUPPORTED_EXTENSIONS.has(ext)) continue;
23893
24605
  out.push(fullPath);
23894
24606
  if (out.length > maxFiles) {
@@ -23915,7 +24627,7 @@ function normalizeInputDir(inputDir) {
23915
24627
  if (typeof inputDir !== "string" || inputDir.trim().length === 0) {
23916
24628
  throw new Error("inputDir must be a non-empty string");
23917
24629
  }
23918
- return path29.resolve(expandTildePath(inputDir.trim()));
24630
+ return path30.resolve(expandTildePath(inputDir.trim()));
23919
24631
  }
23920
24632
  function initRoleCounts() {
23921
24633
  return {
@@ -24072,11 +24784,11 @@ async function collectLocalSessionSummaries(options) {
24072
24784
  continue;
24073
24785
  }
24074
24786
  seenFileHashes.add(fileHash);
24075
- const fileExtension = path29.extname(filePath).toLowerCase();
24787
+ const fileExtension = path30.extname(filePath).toLowerCase();
24076
24788
  const parsed = await adapter.parseFile(
24077
24789
  {
24078
24790
  content,
24079
- fileName: path29.basename(filePath),
24791
+ fileName: path30.basename(filePath),
24080
24792
  fileExtension,
24081
24793
  fileRef: fileHash
24082
24794
  },
@@ -24132,7 +24844,7 @@ async function collectLocalSessionSummaries(options) {
24132
24844
  }
24133
24845
  async function readRedactionConfig(pathLike) {
24134
24846
  if (!pathLike) return void 0;
24135
- const raw = await readFile6(path29.resolve(expandTildePath(pathLike)), "utf-8");
24847
+ const raw = await readFile6(path30.resolve(expandTildePath(pathLike)), "utf-8");
24136
24848
  const parsed = JSON.parse(raw);
24137
24849
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
24138
24850
  throw new Error("redaction config must be a JSON object");
@@ -24145,15 +24857,15 @@ function toJsonl(drafts) {
24145
24857
  }
24146
24858
  function defaultDraftOutputPath(memoryDir, generatedAt) {
24147
24859
  const stamp = generatedAt.replace(/[:.]/g, "-");
24148
- return path29.join(
24149
- path29.resolve(expandTildePath(memoryDir)),
24860
+ return path30.join(
24861
+ path30.resolve(expandTildePath(memoryDir)),
24150
24862
  "state",
24151
24863
  "session-summary-drafts",
24152
24864
  `session-summaries-${stamp}.jsonl`
24153
24865
  );
24154
24866
  }
24155
24867
  async function writeDrafts(filePath, drafts) {
24156
- await mkdir7(path29.dirname(filePath), { recursive: true });
24868
+ await mkdir7(path30.dirname(filePath), { recursive: true });
24157
24869
  const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
24158
24870
  try {
24159
24871
  await writeFile7(tempPath, toJsonl(drafts), "utf-8");
@@ -24171,7 +24883,7 @@ async function runLocalSessionSummaryCliCommand(options) {
24171
24883
  });
24172
24884
  const wroteFiles = [];
24173
24885
  if (options.output) {
24174
- const outputPath = path29.resolve(expandTildePath(options.output));
24886
+ const outputPath = path30.resolve(expandTildePath(options.output));
24175
24887
  await writeDrafts(outputPath, report.drafts);
24176
24888
  wroteFiles.push(outputPath);
24177
24889
  }
@@ -24206,19 +24918,19 @@ async function runLocalSessionSummaryCliCommand(options) {
24206
24918
 
24207
24919
  // src/transfer/capsule-fork.ts
24208
24920
  import { lstat as lstat3, mkdir as mkdir8, readFile as readFile7, realpath as realpath2, writeFile as writeFile8 } from "fs/promises";
24209
- import path30 from "path";
24921
+ import path31 from "path";
24210
24922
  async function forkCapsule(opts) {
24211
24923
  validateForkId(opts.forkId);
24212
- const rootAbs = path30.resolve(opts.targetRoot);
24924
+ const rootAbs = path31.resolve(opts.targetRoot);
24213
24925
  await assertIsDirectoryNotSymlink(rootAbs, "forkCapsule", "targetRoot");
24214
- const forkDirAbs = path30.join(rootAbs, "forks", opts.forkId);
24926
+ const forkDirAbs = path31.join(rootAbs, "forks", opts.forkId);
24215
24927
  const forkEntryExists = await pathEntryExists(forkDirAbs);
24216
24928
  if (forkEntryExists) {
24217
24929
  throw new Error(
24218
24930
  `forkCapsule: fork path already exists \u2014 forkId "${opts.forkId}" is already in use at: ${forkDirAbs}`
24219
24931
  );
24220
24932
  }
24221
- const archiveAbs = path30.resolve(opts.sourceArchive);
24933
+ const archiveAbs = path31.resolve(opts.sourceArchive);
24222
24934
  const importResult = await importCapsule({
24223
24935
  archivePath: archiveAbs,
24224
24936
  root: rootAbs,
@@ -24240,10 +24952,10 @@ async function forkCapsule(opts) {
24240
24952
  importedRecords: importResult.imported.length,
24241
24953
  skippedRecords: importResult.skipped.length
24242
24954
  };
24243
- const lineagePath = path30.join(forkDirAbs, "lineage.json");
24955
+ const lineagePath = path31.join(forkDirAbs, "lineage.json");
24244
24956
  const rootReal = await realpath2(rootAbs);
24245
24957
  await assertRealpathInsideRoot(rootReal, lineagePath, `forks/${opts.forkId}/lineage.json`, "forkCapsule");
24246
- await mkdir8(path30.dirname(lineagePath), { recursive: true });
24958
+ await mkdir8(path31.dirname(lineagePath), { recursive: true });
24247
24959
  await writeFile8(lineagePath, JSON.stringify(lineage, null, 2) + "\n", "utf-8");
24248
24960
  return {
24249
24961
  archivePath: archiveAbs,
@@ -24257,11 +24969,11 @@ async function readForkLineage(targetRoot, forkId) {
24257
24969
  if (typeof forkId !== "string" || forkId.length === 0 || forkId.length > 64 || !CAPSULE_ID_PATTERN.test(forkId)) {
24258
24970
  return null;
24259
24971
  }
24260
- const rootAbs = path30.resolve(targetRoot);
24972
+ const rootAbs = path31.resolve(targetRoot);
24261
24973
  const rootReal = await realpath2(rootAbs).catch(() => rootAbs);
24262
- const lineagePath = path30.join(rootReal, "forks", forkId, "lineage.json");
24263
- const rel = path30.relative(rootReal, lineagePath);
24264
- if (rel.startsWith("..") || path30.isAbsolute(rel)) {
24974
+ const lineagePath = path31.join(rootReal, "forks", forkId, "lineage.json");
24975
+ const rel = path31.relative(rootReal, lineagePath);
24976
+ if (rel.startsWith("..") || path31.isAbsolute(rel)) {
24265
24977
  return null;
24266
24978
  }
24267
24979
  if (!await isLineagePathContained(rootReal, lineagePath)) {
@@ -24302,19 +25014,19 @@ async function pathEntryExists(absPath) {
24302
25014
  async function isLineagePathContained(rootReal, lineagePath) {
24303
25015
  let existing = lineagePath;
24304
25016
  const suffix = [];
24305
- while (existing !== path30.dirname(existing)) {
25017
+ while (existing !== path31.dirname(existing)) {
24306
25018
  const st = await lstat3(existing).catch(() => null);
24307
25019
  if (st !== null) break;
24308
- suffix.unshift(path30.basename(existing));
24309
- existing = path30.dirname(existing);
25020
+ suffix.unshift(path31.basename(existing));
25021
+ existing = path31.dirname(existing);
24310
25022
  }
24311
25023
  const existingReal = await realpath2(existing).catch(() => existing);
24312
- const targetReal = suffix.length > 0 ? path30.join(existingReal, ...suffix) : existingReal;
24313
- const rel = path30.relative(rootReal, targetReal);
25024
+ const targetReal = suffix.length > 0 ? path31.join(existingReal, ...suffix) : existingReal;
25025
+ const rel = path31.relative(rootReal, targetReal);
24314
25026
  if (rel === "") return true;
24315
25027
  if (rel === "..") return false;
24316
- if (rel.startsWith(`..${path30.sep}`)) return false;
24317
- if (path30.isAbsolute(rel)) return false;
25028
+ if (rel.startsWith(`..${path31.sep}`)) return false;
25029
+ if (path31.isAbsolute(rel)) return false;
24318
25030
  return true;
24319
25031
  }
24320
25032
 
@@ -24443,10 +25155,19 @@ export {
24443
25155
  locateTranscriptPath,
24444
25156
  isEligibleActivityFact,
24445
25157
  generateActivityMemories,
24446
- DEFAULT_MEETING_APP_PATTERNS,
24447
- DEFAULT_MEETINGS_DETECTION_CONFIG,
24448
- meetingId,
24449
- detectMeetings,
25158
+ MeetingsInputError,
25159
+ fuseMeeting,
25160
+ MEETINGS_DIR_NAME,
25161
+ MEETING_KIND,
25162
+ MEETING_FORMAT_VERSION,
25163
+ meetingIdDate,
25164
+ composeMeetingRecord,
25165
+ serializeMeetingRecord,
25166
+ parseMeetingRecordSummary,
25167
+ MeetingRecordStore,
25168
+ buildMeetingRecordsForDay,
25169
+ MeetingsBuilder,
25170
+ runMeetingsCliCommand,
24450
25171
  registerLocalSessionSourceAdapter,
24451
25172
  getLocalSessionSourceAdapter,
24452
25173
  listLocalSessionSourceAdapters,
@@ -24462,4 +25183,4 @@ export {
24462
25183
  blendGraphExpandedRecallScore,
24463
25184
  Orchestrator
24464
25185
  };
24465
- //# sourceMappingURL=chunk-OOJQ6ID5.js.map
25186
+ //# sourceMappingURL=chunk-AT3TDN6O.js.map