@remnic/core 9.4.2 → 9.6.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.
- package/dist/access-admin-ops-surface.d.ts +6 -6
- package/dist/access-admin-ops-surface.js +28 -28
- package/dist/access-boundary.d.ts +27 -8
- package/dist/access-boundary.js +33 -29
- package/dist/access-cli.js +83 -81
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +52 -6
- package/dist/access-http.js +40 -38
- package/dist/access-identity-continuity-surface.d.ts +5 -5
- package/dist/access-identity-continuity-surface.js +28 -28
- package/dist/access-lcm-surface.d.ts +6 -6
- package/dist/access-lcm-surface.js +28 -28
- package/dist/access-mcp.d.ts +16 -6
- package/dist/access-mcp.js +37 -35
- package/dist/access-observe-write-surface.d.ts +6 -6
- package/dist/access-observe-write-surface.js +28 -28
- package/dist/access-operations-batch.js +33 -32
- package/dist/access-operations.d.ts +9 -9
- package/dist/access-operations.js +35 -34
- package/dist/access-recall-surface.d.ts +6 -6
- package/dist/access-recall-surface.js +28 -28
- package/dist/access-schema.d.ts +4 -4
- package/dist/access-schema.js +4 -4
- package/dist/{access-service-m-2VO_Ig.d.ts → access-service-CXJaql3A.d.ts} +4 -4
- package/dist/access-service.d.ts +6 -6
- package/dist/access-service.js +28 -28
- package/dist/access-surface-catalog.d.ts +6 -6
- package/dist/access-surface-catalog.js +1 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-token-capabilities.d.ts +174 -0
- package/dist/access-token-capabilities.js +33 -0
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +2 -2
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/{auto-sync-HMHQHUAG.js → auto-sync-4A5YBWYO.js} +4 -4
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +5 -5
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +9 -9
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{capsule-crypto-CZJSLEFG.js → capsule-crypto-RAARDY3M.js} +2 -2
- package/dist/capsule-crypto-RAARDY3M.js.map +1 -0
- package/dist/{catalog-BxWokdC2.d.ts → catalog-C9cu67Ig.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +5 -5
- package/dist/causal-chain.js +3 -3
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +13 -13
- package/dist/causal-retrieval.js +3 -3
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-6ZIETXZ2.js → chunk-23JFRB73.js} +2 -2
- package/dist/{chunk-IC6QX5TC.js → chunk-3XIY7MDQ.js} +6 -6
- package/dist/{chunk-FZGGZAAU.js → chunk-4GNEDXDI.js} +146 -2
- package/dist/chunk-4GNEDXDI.js.map +1 -0
- package/dist/{chunk-LOR6ZM5R.js → chunk-4LV23CHK.js} +2 -2
- package/dist/{chunk-E2SPGGUI.js → chunk-4OKLXWDZ.js} +13 -6
- package/dist/chunk-4OKLXWDZ.js.map +1 -0
- package/dist/{chunk-AER6MT24.js → chunk-6SXVCD7W.js} +2 -2
- package/dist/{chunk-OHDJ34CC.js → chunk-72WG5QKN.js} +2 -2
- package/dist/{chunk-CZAZX7JP.js → chunk-7MW3CVLD.js} +4 -4
- package/dist/{chunk-CXLNZXG5.js → chunk-7XGSIUP5.js} +1 -1
- package/dist/{chunk-CZAA5N5S.js → chunk-AYZJID4S.js} +2 -2
- package/dist/{chunk-M7XQSUBB.js → chunk-B3ABVQ36.js} +116 -9
- package/dist/chunk-B3ABVQ36.js.map +1 -0
- package/dist/{chunk-6BISDEN6.js → chunk-BEM4D2QG.js} +14 -14
- package/dist/{chunk-ZPOROUTX.js → chunk-CYWA2CXR.js} +5 -5
- package/dist/{chunk-M5QKGHCR.js → chunk-CYWCKFCL.js} +5 -5
- package/dist/chunk-D7FOKIY5.js +173 -0
- package/dist/chunk-D7FOKIY5.js.map +1 -0
- package/dist/{chunk-4BFRBP45.js → chunk-DEG5ULFJ.js} +2 -2
- package/dist/{chunk-JLR3JSTL.js → chunk-DS7MM2ES.js} +3 -3
- package/dist/{chunk-2BFLDH5F.js → chunk-EEIROWEG.js} +2 -2
- package/dist/{chunk-5QZDMSSN.js → chunk-FKCRGLRD.js} +237 -82
- package/dist/{chunk-5QZDMSSN.js.map → chunk-FKCRGLRD.js.map} +1 -1
- package/dist/{chunk-X4A62ET7.js → chunk-H2DXDQCQ.js} +17 -17
- package/dist/{chunk-27FLVMDC.js → chunk-HLN7RROI.js} +7 -7
- package/dist/chunk-IC2TCZJ2.js +54 -0
- package/dist/chunk-IC2TCZJ2.js.map +1 -0
- package/dist/{chunk-2U2A5HF4.js → chunk-J3XHPFEU.js} +6 -6
- package/dist/{chunk-AKUCU7CI.js → chunk-JI5AVXYO.js} +5 -5
- package/dist/{chunk-KCJ5H6XQ.js → chunk-JSNVWNGX.js} +2 -2
- package/dist/{chunk-7Z2DZNWN.js → chunk-KL4UAXUY.js} +43 -2
- package/dist/{chunk-7Z2DZNWN.js.map → chunk-KL4UAXUY.js.map} +1 -1
- package/dist/{chunk-FLVL4L3L.js → chunk-KTULX4YO.js} +4 -4
- package/dist/{chunk-ILFJ7AVS.js → chunk-LADFWYHY.js} +35 -21
- package/dist/chunk-LADFWYHY.js.map +1 -0
- package/dist/{chunk-437S3G37.js → chunk-LNQUAJNC.js} +1 -1
- package/dist/{chunk-EPGWWCZF.js → chunk-LR5DZ56F.js} +6 -6
- package/dist/{chunk-YDSWRD33.js → chunk-N3JDIRBW.js} +4 -4
- package/dist/{chunk-OUMTBFSQ.js → chunk-NKCPUHCI.js} +5 -5
- package/dist/{chunk-7QWMTOIF.js → chunk-P454KXD6.js} +112 -34
- package/dist/chunk-P454KXD6.js.map +1 -0
- package/dist/{chunk-DR6PEJU3.js → chunk-PCLIWBGD.js} +44 -59
- package/dist/chunk-PCLIWBGD.js.map +1 -0
- package/dist/{chunk-BGTAL46Y.js → chunk-PNLFN2PZ.js} +2 -2
- package/dist/{chunk-P6SYWE4G.js → chunk-PVUJ6WVV.js} +10 -10
- package/dist/{chunk-YPEMNNNY.js → chunk-RGK27ELN.js} +6 -6
- package/dist/{chunk-2QSZNTDO.js → chunk-RKNJBZ55.js} +4 -4
- package/dist/{chunk-66FLU5BT.js → chunk-SIRPLF54.js} +6 -6
- package/dist/{chunk-M7GGMGMZ.js → chunk-SVOHGUMI.js} +1202 -126
- package/dist/chunk-SVOHGUMI.js.map +1 -0
- package/dist/{chunk-HRCACVHL.js → chunk-TLUDFPZL.js} +2 -2
- package/dist/{chunk-2FOD2YY3.js → chunk-UFUKHGZD.js} +236 -103
- package/dist/chunk-UFUKHGZD.js.map +1 -0
- package/dist/{chunk-2MR3MFQB.js → chunk-UPSAT4PY.js} +2 -2
- package/dist/{chunk-4P4626RY.js → chunk-UTRJFDP2.js} +4 -4
- package/dist/{chunk-CGS7UKWM.js → chunk-VCW74PNH.js} +2 -2
- package/dist/{chunk-5GPPACXK.js → chunk-VSMRDBFT.js} +2 -1
- package/dist/{chunk-NG7YBCJO.js → chunk-XCL57M6Q.js} +4 -4
- package/dist/{chunk-CLX5VDNY.js → chunk-Y4RKAQZ7.js} +4 -4
- package/dist/{chunk-DGYCWCQ7.js → chunk-Y7UNNAZD.js} +2 -2
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{chunk-XN3TUUX2.js → chunk-YQB32INI.js} +2 -2
- package/dist/{cli-EiBBOt3r.d.ts → cli-CqdPA6z9.d.ts} +3 -3
- package/dist/cli.d.ts +7 -7
- package/dist/cli.js +61 -59
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +9 -9
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +9 -9
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +13 -11
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/contradiction/index.js +4 -4
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/dashboard-runtime.js +2 -2
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +9 -9
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +5 -5
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-DY6YCRC2.js → first-start-migration-VBJQL6OI.js} +5 -5
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +271 -17
- package/dist/index.js +163 -99
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +2 -2
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +10 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +9 -9
- package/dist/maintenance/rebuild-memory-projection.js +11 -11
- package/dist/mcp-memory-inspector-app.d.ts +6 -6
- package/dist/mcp-read-only-tools.d.ts +16 -0
- package/dist/mcp-read-only-tools.js +8 -0
- package/dist/mcp-read-only-tools.js.map +1 -0
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +19 -19
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +10 -10
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +9 -9
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +2 -2
- package/dist/operator-toolkit.js +25 -25
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +11 -11
- package/dist/{orchestrator-B2Y28Z9t.d.ts → orchestrator-CWFrT8AF.d.ts} +91 -60
- package/dist/orchestrator.d.ts +5 -5
- package/dist/orchestrator.js +85 -83
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{qmd-Db9mOkzB.d.ts → qmd--fnPMK60.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +2 -2
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +4 -4
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/schemas.d.ts +22 -22
- package/dist/search/document-scanner.js +2 -2
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +9 -9
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +13 -13
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/lancedb-backend.js +3 -3
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.js +3 -3
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/orama-backend.js +3 -3
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-BDVIbLRw.d.ts → semantic-consolidation-O5lMZ4LG.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +11 -11
- package/dist/semantic-rule-promotion.js +9 -9
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +10 -10
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/storage-C1maCNbc.d.ts +1591 -0
- package/dist/storage.d.ts +5 -1239
- package/dist/storage.js +8 -8
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/{tier-stats-TG6GUZ6N.js → tier-stats-5XF4UBRQ.js} +4 -4
- package/dist/tokens.d.ts +17 -2
- package/dist/tokens.js +3 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +3 -3
- package/dist/transfer/capsule-import.js +3 -3
- package/dist/transfer/types.d.ts +12 -12
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-ljkd82rn.d.ts → types-CGgcNWCG.d.ts} +31 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +10 -10
- package/package.json +2 -2
- package/src/access-boundary.test.ts +62 -0
- package/src/access-boundary.ts +165 -126
- package/src/access-http.test.ts +781 -0
- package/src/access-http.ts +334 -108
- package/src/access-mcp.test.ts +264 -0
- package/src/access-mcp.ts +45 -70
- package/src/access-operations-batch.ts +35 -12
- package/src/access-surface-catalog.test.ts +22 -14
- package/src/access-surface-catalog.ts +6 -3
- package/src/access-token-capabilities.test.ts +844 -0
- package/src/access-token-capabilities.ts +391 -0
- package/src/chat/chat-mcp.test.ts +232 -0
- package/src/chat/chat-session.ts +34 -0
- package/src/cli-wearables-fuse.test.ts +197 -0
- package/src/cli.ts +25 -0
- package/src/index.ts +14 -0
- package/src/mcp-read-only-tools.ts +61 -0
- package/src/storage.ts +16 -0
- package/src/tokens.ts +32 -3
- package/src/wearables/cli.test.ts +102 -0
- package/src/wearables/cli.ts +65 -0
- package/src/wearables/config.test.ts +32 -0
- package/src/wearables/config.ts +52 -0
- package/src/wearables/day-store.test.ts +246 -0
- package/src/wearables/day-store.ts +272 -3
- package/src/wearables/fusion/cluster.ts +230 -0
- package/src/wearables/fusion/fuse.ts +218 -0
- package/src/wearables/fusion/fusion.test.ts +2575 -0
- package/src/wearables/fusion/index.ts +50 -0
- package/src/wearables/fusion/reconcile.ts +831 -0
- package/src/wearables/fusion/reconstruct.ts +251 -0
- package/src/wearables/fusion/store.ts +480 -0
- package/src/wearables/fusion/types.ts +228 -0
- package/src/wearables/index.ts +41 -0
- package/src/wearables/service.test.ts +1030 -2
- package/src/wearables/service.ts +258 -16
- package/src/wearables/speakers.test.ts +128 -0
- package/src/wearables/speakers.ts +58 -4
- package/src/wearables/storage-io.test.ts +146 -0
- package/src/wearables/types.ts +31 -0
- package/dist/chunk-2FOD2YY3.js.map +0 -1
- package/dist/chunk-7QWMTOIF.js.map +0 -1
- package/dist/chunk-DR6PEJU3.js.map +0 -1
- package/dist/chunk-E2SPGGUI.js.map +0 -1
- package/dist/chunk-FZGGZAAU.js.map +0 -1
- package/dist/chunk-ILFJ7AVS.js.map +0 -1
- package/dist/chunk-M7GGMGMZ.js.map +0 -1
- package/dist/chunk-M7XQSUBB.js.map +0 -1
- /package/dist/{capsule-crypto-CZJSLEFG.js.map → access-token-capabilities.js.map} +0 -0
- /package/dist/{auto-sync-HMHQHUAG.js.map → auto-sync-4A5YBWYO.js.map} +0 -0
- /package/dist/{chunk-6ZIETXZ2.js.map → chunk-23JFRB73.js.map} +0 -0
- /package/dist/{chunk-IC6QX5TC.js.map → chunk-3XIY7MDQ.js.map} +0 -0
- /package/dist/{chunk-LOR6ZM5R.js.map → chunk-4LV23CHK.js.map} +0 -0
- /package/dist/{chunk-AER6MT24.js.map → chunk-6SXVCD7W.js.map} +0 -0
- /package/dist/{chunk-OHDJ34CC.js.map → chunk-72WG5QKN.js.map} +0 -0
- /package/dist/{chunk-CZAZX7JP.js.map → chunk-7MW3CVLD.js.map} +0 -0
- /package/dist/{chunk-CXLNZXG5.js.map → chunk-7XGSIUP5.js.map} +0 -0
- /package/dist/{chunk-CZAA5N5S.js.map → chunk-AYZJID4S.js.map} +0 -0
- /package/dist/{chunk-6BISDEN6.js.map → chunk-BEM4D2QG.js.map} +0 -0
- /package/dist/{chunk-ZPOROUTX.js.map → chunk-CYWA2CXR.js.map} +0 -0
- /package/dist/{chunk-M5QKGHCR.js.map → chunk-CYWCKFCL.js.map} +0 -0
- /package/dist/{chunk-4BFRBP45.js.map → chunk-DEG5ULFJ.js.map} +0 -0
- /package/dist/{chunk-JLR3JSTL.js.map → chunk-DS7MM2ES.js.map} +0 -0
- /package/dist/{chunk-2BFLDH5F.js.map → chunk-EEIROWEG.js.map} +0 -0
- /package/dist/{chunk-X4A62ET7.js.map → chunk-H2DXDQCQ.js.map} +0 -0
- /package/dist/{chunk-27FLVMDC.js.map → chunk-HLN7RROI.js.map} +0 -0
- /package/dist/{chunk-2U2A5HF4.js.map → chunk-J3XHPFEU.js.map} +0 -0
- /package/dist/{chunk-AKUCU7CI.js.map → chunk-JI5AVXYO.js.map} +0 -0
- /package/dist/{chunk-KCJ5H6XQ.js.map → chunk-JSNVWNGX.js.map} +0 -0
- /package/dist/{chunk-FLVL4L3L.js.map → chunk-KTULX4YO.js.map} +0 -0
- /package/dist/{chunk-437S3G37.js.map → chunk-LNQUAJNC.js.map} +0 -0
- /package/dist/{chunk-EPGWWCZF.js.map → chunk-LR5DZ56F.js.map} +0 -0
- /package/dist/{chunk-YDSWRD33.js.map → chunk-N3JDIRBW.js.map} +0 -0
- /package/dist/{chunk-OUMTBFSQ.js.map → chunk-NKCPUHCI.js.map} +0 -0
- /package/dist/{chunk-BGTAL46Y.js.map → chunk-PNLFN2PZ.js.map} +0 -0
- /package/dist/{chunk-P6SYWE4G.js.map → chunk-PVUJ6WVV.js.map} +0 -0
- /package/dist/{chunk-YPEMNNNY.js.map → chunk-RGK27ELN.js.map} +0 -0
- /package/dist/{chunk-2QSZNTDO.js.map → chunk-RKNJBZ55.js.map} +0 -0
- /package/dist/{chunk-66FLU5BT.js.map → chunk-SIRPLF54.js.map} +0 -0
- /package/dist/{chunk-HRCACVHL.js.map → chunk-TLUDFPZL.js.map} +0 -0
- /package/dist/{chunk-2MR3MFQB.js.map → chunk-UPSAT4PY.js.map} +0 -0
- /package/dist/{chunk-4P4626RY.js.map → chunk-UTRJFDP2.js.map} +0 -0
- /package/dist/{chunk-CGS7UKWM.js.map → chunk-VCW74PNH.js.map} +0 -0
- /package/dist/{chunk-5GPPACXK.js.map → chunk-VSMRDBFT.js.map} +0 -0
- /package/dist/{chunk-NG7YBCJO.js.map → chunk-XCL57M6Q.js.map} +0 -0
- /package/dist/{chunk-CLX5VDNY.js.map → chunk-Y4RKAQZ7.js.map} +0 -0
- /package/dist/{chunk-DGYCWCQ7.js.map → chunk-Y7UNNAZD.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{chunk-XN3TUUX2.js.map → chunk-YQB32INI.js.map} +0 -0
- /package/dist/{first-start-migration-DY6YCRC2.js.map → first-start-migration-VBJQL6OI.js.map} +0 -0
- /package/dist/{tier-stats-TG6GUZ6N.js.map → tier-stats-5XF4UBRQ.js.map} +0 -0
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
WEARABLES_DIR_NAME,
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
hasSelfMarker,
|
|
4
|
+
isValidTranscriptDate,
|
|
5
|
+
parseTranscriptSegmentLine,
|
|
6
|
+
resolveSpeaker,
|
|
7
|
+
unescapeSegmentText,
|
|
8
|
+
unescapeSpeakerLabel
|
|
9
|
+
} from "./chunk-B3ABVQ36.js";
|
|
5
10
|
import {
|
|
6
11
|
TombstoneStore,
|
|
7
12
|
buildRetiredFactTombstoneInputs,
|
|
@@ -11,14 +16,12 @@ import {
|
|
|
11
16
|
isErrnoCode
|
|
12
17
|
} from "./chunk-5UZXUTVO.js";
|
|
13
18
|
import {
|
|
14
|
-
assertPathInsideRoot
|
|
15
|
-
|
|
19
|
+
assertPathInsideRoot,
|
|
20
|
+
pathIsInside
|
|
21
|
+
} from "./chunk-VSMRDBFT.js";
|
|
16
22
|
import {
|
|
17
23
|
supersessionKeysForFact
|
|
18
24
|
} from "./chunk-EHK6KZHK.js";
|
|
19
|
-
import {
|
|
20
|
-
stripAttributesSuffix
|
|
21
|
-
} from "./chunk-SVOZFLIQ.js";
|
|
22
25
|
import {
|
|
23
26
|
DEFAULT_CITATION_FORMAT,
|
|
24
27
|
hasCitation,
|
|
@@ -28,10 +31,21 @@ import {
|
|
|
28
31
|
assertMemoryFrontmatterId,
|
|
29
32
|
warnProjectionFallback
|
|
30
33
|
} from "./chunk-4KJLYTLS.js";
|
|
34
|
+
import {
|
|
35
|
+
stripAttributesSuffix
|
|
36
|
+
} from "./chunk-SVOZFLIQ.js";
|
|
31
37
|
import {
|
|
32
38
|
SPECULATIVE_TTL_DAYS,
|
|
33
39
|
confidenceTier
|
|
34
40
|
} from "./chunk-JS2HKKOK.js";
|
|
41
|
+
import {
|
|
42
|
+
markProjectedMemoryPathInvalid,
|
|
43
|
+
readProjectedGovernanceRecord,
|
|
44
|
+
readProjectedMemoryBrowse,
|
|
45
|
+
readProjectedMemoryState,
|
|
46
|
+
readProjectedMemoryTimeline,
|
|
47
|
+
updateProjectedMemoryPath
|
|
48
|
+
} from "./chunk-RHOZ5LLO.js";
|
|
35
49
|
import {
|
|
36
50
|
getCachedEntities,
|
|
37
51
|
invalidateAllForDir,
|
|
@@ -47,14 +61,6 @@ import {
|
|
|
47
61
|
normalizeProjectionPreview,
|
|
48
62
|
normalizeProjectionTags
|
|
49
63
|
} from "./chunk-SCU65EZI.js";
|
|
50
|
-
import {
|
|
51
|
-
markProjectedMemoryPathInvalid,
|
|
52
|
-
readProjectedGovernanceRecord,
|
|
53
|
-
readProjectedMemoryBrowse,
|
|
54
|
-
readProjectedMemoryState,
|
|
55
|
-
readProjectedMemoryTimeline,
|
|
56
|
-
updateProjectedMemoryPath
|
|
57
|
-
} from "./chunk-RHOZ5LLO.js";
|
|
58
64
|
import {
|
|
59
65
|
rotateMarkdownFileToArchive
|
|
60
66
|
} from "./chunk-DM2T26WE.js";
|
|
@@ -88,14 +94,14 @@ import {
|
|
|
88
94
|
reconcileProvenanceRead,
|
|
89
95
|
serializeProvenanceFields
|
|
90
96
|
} from "./chunk-OEHCMALU.js";
|
|
91
|
-
import {
|
|
92
|
-
sanitizeMemoryContent
|
|
93
|
-
} from "./chunk-5GKPFL3S.js";
|
|
94
97
|
import {
|
|
95
98
|
matchEntitySchemaSection,
|
|
96
99
|
normalizeEntityStructuredSection,
|
|
97
100
|
sortStructuredSectionsBySchema
|
|
98
101
|
} from "./chunk-4DJQYKMN.js";
|
|
102
|
+
import {
|
|
103
|
+
sanitizeMemoryContent
|
|
104
|
+
} from "./chunk-5GKPFL3S.js";
|
|
99
105
|
import {
|
|
100
106
|
log
|
|
101
107
|
} from "./chunk-37CTGERM.js";
|
|
@@ -118,10 +124,10 @@ import {
|
|
|
118
124
|
} from "./chunk-VS2IYZRU.js";
|
|
119
125
|
|
|
120
126
|
// src/storage.ts
|
|
121
|
-
import { access, readdir as readdir4, readFile, stat as stat2, writeFile, mkdir, unlink as unlink2, appendFile, open as open2 } from "fs/promises";
|
|
127
|
+
import { access, lstat as lstat2, readdir as readdir4, readFile, realpath as realpath2, stat as stat2, writeFile, mkdir, unlink as unlink2, appendFile, open as open2 } from "fs/promises";
|
|
122
128
|
import { appendFileSync, createReadStream as createReadStream2, mkdirSync, readFileSync, statSync } from "fs";
|
|
123
|
-
import { createHash } from "crypto";
|
|
124
|
-
import
|
|
129
|
+
import { createHash as createHash3 } from "crypto";
|
|
130
|
+
import path5 from "path";
|
|
125
131
|
|
|
126
132
|
// src/storage/memory-read-store.ts
|
|
127
133
|
import { lstat, readdir, realpath, stat } from "fs/promises";
|
|
@@ -1259,6 +1265,1050 @@ var IdentityContinuityStore = class {
|
|
|
1259
1265
|
}
|
|
1260
1266
|
};
|
|
1261
1267
|
|
|
1268
|
+
// src/wearables/fusion/cluster.ts
|
|
1269
|
+
var DEFAULT_PROXIMITY_GAP_MS = 5 * 6e4;
|
|
1270
|
+
function maxSegmentExtent(segments) {
|
|
1271
|
+
let best;
|
|
1272
|
+
for (const seg of segments) {
|
|
1273
|
+
const iso = seg.endIso ?? seg.startIso;
|
|
1274
|
+
if (iso === void 0) continue;
|
|
1275
|
+
const ms = Date.parse(iso);
|
|
1276
|
+
if (!Number.isFinite(ms)) continue;
|
|
1277
|
+
if (best === void 0 || ms > best.ms) {
|
|
1278
|
+
best = { ms, iso };
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
return best;
|
|
1282
|
+
}
|
|
1283
|
+
function effectiveInterval(conversation) {
|
|
1284
|
+
const start = Date.parse(conversation.startIso);
|
|
1285
|
+
const endRaw = conversation.endIso !== void 0 ? Date.parse(conversation.endIso) : NaN;
|
|
1286
|
+
const end = Number.isFinite(endRaw) ? endRaw : maxSegmentExtent(conversation.segments)?.ms ?? start;
|
|
1287
|
+
return { start, end: Math.max(end, start) };
|
|
1288
|
+
}
|
|
1289
|
+
function compareConversation(a, b) {
|
|
1290
|
+
if (a.source !== b.source) return a.source < b.source ? -1 : 1;
|
|
1291
|
+
if (a.conversationId !== b.conversationId) {
|
|
1292
|
+
return a.conversationId < b.conversationId ? -1 : 1;
|
|
1293
|
+
}
|
|
1294
|
+
return 0;
|
|
1295
|
+
}
|
|
1296
|
+
function clusterConversations(inputs, proximityGapMs = DEFAULT_PROXIMITY_GAP_MS) {
|
|
1297
|
+
const finite = [];
|
|
1298
|
+
const noStart = [];
|
|
1299
|
+
for (const conv of inputs) {
|
|
1300
|
+
const interval = effectiveInterval(conv);
|
|
1301
|
+
if (Number.isFinite(interval.start)) {
|
|
1302
|
+
finite.push({ conv, interval });
|
|
1303
|
+
} else {
|
|
1304
|
+
noStart.push(conv);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
finite.sort((a, b) => {
|
|
1308
|
+
if (a.interval.start !== b.interval.start) {
|
|
1309
|
+
return a.interval.start - b.interval.start;
|
|
1310
|
+
}
|
|
1311
|
+
return compareConversation(a.conv, b.conv);
|
|
1312
|
+
});
|
|
1313
|
+
const n = finite.length;
|
|
1314
|
+
const parent = new Array(n);
|
|
1315
|
+
for (let i = 0; i < n; i++) parent[i] = i;
|
|
1316
|
+
const find = (x) => {
|
|
1317
|
+
let root = x;
|
|
1318
|
+
while (parent[root] !== root) root = parent[root];
|
|
1319
|
+
let cur = x;
|
|
1320
|
+
while (parent[cur] !== root) {
|
|
1321
|
+
const next = parent[cur];
|
|
1322
|
+
parent[cur] = root;
|
|
1323
|
+
cur = next;
|
|
1324
|
+
}
|
|
1325
|
+
return root;
|
|
1326
|
+
};
|
|
1327
|
+
const union = (a, b) => {
|
|
1328
|
+
const ra = find(a);
|
|
1329
|
+
const rb = find(b);
|
|
1330
|
+
if (ra !== rb) parent[ra] = rb;
|
|
1331
|
+
};
|
|
1332
|
+
for (let i = 0; i < n; i++) {
|
|
1333
|
+
const endGap = finite[i].interval.end + proximityGapMs;
|
|
1334
|
+
for (let j = i + 1; j < n; j++) {
|
|
1335
|
+
if (finite[j].interval.start > endGap) break;
|
|
1336
|
+
if (finite[i].conv.source === finite[j].conv.source) continue;
|
|
1337
|
+
union(i, j);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
const clusters = [];
|
|
1341
|
+
const rootToCluster = /* @__PURE__ */ new Map();
|
|
1342
|
+
for (let i = 0; i < n; i++) {
|
|
1343
|
+
const root = find(i);
|
|
1344
|
+
let idx = rootToCluster.get(root);
|
|
1345
|
+
if (idx === void 0) {
|
|
1346
|
+
idx = clusters.length;
|
|
1347
|
+
rootToCluster.set(root, idx);
|
|
1348
|
+
clusters.push([]);
|
|
1349
|
+
}
|
|
1350
|
+
clusters[idx].push(finite[i].conv);
|
|
1351
|
+
}
|
|
1352
|
+
noStart.sort(compareConversation);
|
|
1353
|
+
for (const conv of noStart) {
|
|
1354
|
+
clusters.push([conv]);
|
|
1355
|
+
}
|
|
1356
|
+
return clusters;
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
// src/wearables/fusion/reconcile.ts
|
|
1360
|
+
var DEFAULT_WINDOW_TOLERANCE_MS = 3e4;
|
|
1361
|
+
var DEFAULT_SOURCE_TRUST = 0.8;
|
|
1362
|
+
var TRUST_DECISION_EPSILON = 1e-9;
|
|
1363
|
+
var GENERIC_LABEL_PATTERN = /^(Speaker \d+|Unknown speaker|SPEAKER_\d+)$/i;
|
|
1364
|
+
function speakerKey(label, isSelf) {
|
|
1365
|
+
return isSelf ? "self" : label;
|
|
1366
|
+
}
|
|
1367
|
+
function resolveTrust(source, trustMap) {
|
|
1368
|
+
const value = trustMap?.[source];
|
|
1369
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1370
|
+
return Math.min(1, Math.max(0, value));
|
|
1371
|
+
}
|
|
1372
|
+
return DEFAULT_SOURCE_TRUST;
|
|
1373
|
+
}
|
|
1374
|
+
function normalizeWords(text) {
|
|
1375
|
+
return text.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/).filter((word) => word.length > 0);
|
|
1376
|
+
}
|
|
1377
|
+
function wordsEqual(a, b) {
|
|
1378
|
+
if (a.length !== b.length) return false;
|
|
1379
|
+
for (let i = 0; i < a.length; i++) {
|
|
1380
|
+
if (a[i] !== b[i]) return false;
|
|
1381
|
+
}
|
|
1382
|
+
return true;
|
|
1383
|
+
}
|
|
1384
|
+
function isWordPrefix(short, long) {
|
|
1385
|
+
if (short.length === 0 || short.length > long.length) return false;
|
|
1386
|
+
for (let i = 0; i < short.length; i++) {
|
|
1387
|
+
if (short[i] !== long[i]) return false;
|
|
1388
|
+
}
|
|
1389
|
+
return true;
|
|
1390
|
+
}
|
|
1391
|
+
function wordsCorroborate(a, b, allowPrefix) {
|
|
1392
|
+
if (wordsEqual(a, b)) return true;
|
|
1393
|
+
if (!allowPrefix) return false;
|
|
1394
|
+
return isWordPrefix(a, b) || isWordPrefix(b, a);
|
|
1395
|
+
}
|
|
1396
|
+
function clamp01(value) {
|
|
1397
|
+
if (!Number.isFinite(value)) return 0;
|
|
1398
|
+
return Math.min(1, Math.max(0, value));
|
|
1399
|
+
}
|
|
1400
|
+
function fusionInputsFromConversations(sourceId, conversations, registry) {
|
|
1401
|
+
return conversations.map((conversation) => {
|
|
1402
|
+
const segments = conversation.segments.map((raw) => {
|
|
1403
|
+
const resolved = resolveSpeaker(sourceId, raw, registry);
|
|
1404
|
+
return {
|
|
1405
|
+
speaker: resolved.label,
|
|
1406
|
+
isSelf: resolved.isSelf,
|
|
1407
|
+
text: raw.text,
|
|
1408
|
+
...raw.startIso !== void 0 ? { startIso: raw.startIso } : {},
|
|
1409
|
+
...raw.endIso !== void 0 ? { endIso: raw.endIso } : {}
|
|
1410
|
+
};
|
|
1411
|
+
});
|
|
1412
|
+
return {
|
|
1413
|
+
source: sourceId,
|
|
1414
|
+
conversationId: conversation.id,
|
|
1415
|
+
startIso: conversation.startIso,
|
|
1416
|
+
...conversation.endIso !== void 0 ? { endIso: conversation.endIso } : {},
|
|
1417
|
+
...conversation.title !== void 0 ? { title: conversation.title } : {},
|
|
1418
|
+
...conversation.summary !== void 0 ? { summary: conversation.summary } : {},
|
|
1419
|
+
segments
|
|
1420
|
+
};
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
function fuseCluster(cluster, options = {}) {
|
|
1424
|
+
const trustMap = options.sourceTrust;
|
|
1425
|
+
const toleranceMs = options.windowToleranceMs ?? DEFAULT_WINDOW_TOLERANCE_MS;
|
|
1426
|
+
const sources = [];
|
|
1427
|
+
const sourcesSeen = /* @__PURE__ */ new Set();
|
|
1428
|
+
for (const conv of cluster) {
|
|
1429
|
+
if (!sourcesSeen.has(conv.source)) {
|
|
1430
|
+
sourcesSeen.add(conv.source);
|
|
1431
|
+
sources.push(conv.source);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
let startMs = Number.POSITIVE_INFINITY;
|
|
1435
|
+
let endMs = Number.NEGATIVE_INFINITY;
|
|
1436
|
+
let startIso;
|
|
1437
|
+
let endIso;
|
|
1438
|
+
for (const conv of cluster) {
|
|
1439
|
+
const ms = Date.parse(conv.startIso);
|
|
1440
|
+
if (Number.isFinite(ms) && ms < startMs) {
|
|
1441
|
+
startMs = ms;
|
|
1442
|
+
startIso = conv.startIso;
|
|
1443
|
+
}
|
|
1444
|
+
if (conv.endIso !== void 0) {
|
|
1445
|
+
const endM = Date.parse(conv.endIso);
|
|
1446
|
+
if (Number.isFinite(endM) && endM > endMs) {
|
|
1447
|
+
endMs = endM;
|
|
1448
|
+
endIso = conv.endIso;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
const segmentExtent = maxSegmentExtent(
|
|
1453
|
+
cluster.flatMap((conv) => conv.segments)
|
|
1454
|
+
);
|
|
1455
|
+
if (segmentExtent !== void 0 && segmentExtent.ms > endMs) {
|
|
1456
|
+
endMs = segmentExtent.ms;
|
|
1457
|
+
endIso = segmentExtent.iso;
|
|
1458
|
+
}
|
|
1459
|
+
if (endIso !== void 0 && Number.isFinite(startMs) && endMs < startMs) {
|
|
1460
|
+
endIso = startIso;
|
|
1461
|
+
endMs = startMs;
|
|
1462
|
+
}
|
|
1463
|
+
if (startIso === void 0) {
|
|
1464
|
+
startIso = cluster[0]?.startIso ?? (/* @__PURE__ */ new Date(0)).toISOString();
|
|
1465
|
+
}
|
|
1466
|
+
let title;
|
|
1467
|
+
let summary;
|
|
1468
|
+
for (const conv of cluster) {
|
|
1469
|
+
if (title === void 0 && conv.title !== void 0 && conv.title.trim().length > 0) {
|
|
1470
|
+
title = conv.title.trim();
|
|
1471
|
+
}
|
|
1472
|
+
if (summary === void 0 && conv.summary !== void 0 && conv.summary.trim().length > 0) {
|
|
1473
|
+
summary = conv.summary.trim();
|
|
1474
|
+
}
|
|
1475
|
+
if (title !== void 0 && summary !== void 0) break;
|
|
1476
|
+
}
|
|
1477
|
+
const tagged = [];
|
|
1478
|
+
for (const conv of cluster) {
|
|
1479
|
+
const sourceTrust = resolveTrust(conv.source, trustMap);
|
|
1480
|
+
for (const segment of conv.segments) {
|
|
1481
|
+
const startMsValue = segment.startIso !== void 0 ? Date.parse(segment.startIso) : NaN;
|
|
1482
|
+
tagged.push({
|
|
1483
|
+
source: conv.source,
|
|
1484
|
+
conversationId: conv.conversationId,
|
|
1485
|
+
speakerLabel: segment.speaker,
|
|
1486
|
+
isSelf: segment.isSelf,
|
|
1487
|
+
text: segment.text,
|
|
1488
|
+
startMs: Number.isFinite(startMsValue) ? startMsValue : Number.POSITIVE_INFINITY,
|
|
1489
|
+
...segment.startIso !== void 0 ? { startIso: segment.startIso } : {},
|
|
1490
|
+
...segment.endIso !== void 0 ? { endIso: segment.endIso } : {},
|
|
1491
|
+
sourceTrust,
|
|
1492
|
+
originalIndex: tagged.length
|
|
1493
|
+
});
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
tagged.sort((a, b) => {
|
|
1497
|
+
const aFinite = Number.isFinite(a.startMs);
|
|
1498
|
+
const bFinite = Number.isFinite(b.startMs);
|
|
1499
|
+
if (aFinite && bFinite && a.startMs !== b.startMs) return a.startMs - b.startMs;
|
|
1500
|
+
if (aFinite !== bFinite) return aFinite ? -1 : 1;
|
|
1501
|
+
return a.originalIndex - b.originalIndex;
|
|
1502
|
+
});
|
|
1503
|
+
const groups = [];
|
|
1504
|
+
for (const seg of tagged) {
|
|
1505
|
+
const key = speakerKey(seg.speakerLabel, seg.isSelf);
|
|
1506
|
+
const segMissing = !Number.isFinite(seg.startMs);
|
|
1507
|
+
const segWords = normalizeWords(seg.text);
|
|
1508
|
+
const corroborates = (group) => {
|
|
1509
|
+
if (group.members.some((member) => member.source === seg.source)) {
|
|
1510
|
+
return false;
|
|
1511
|
+
}
|
|
1512
|
+
const groupMissing = !Number.isFinite(group.anchorMs);
|
|
1513
|
+
if (groupMissing !== segMissing) return false;
|
|
1514
|
+
if (!groupMissing && Math.abs(seg.startMs - group.anchorMs) > toleranceMs) {
|
|
1515
|
+
return false;
|
|
1516
|
+
}
|
|
1517
|
+
return group.members.some(
|
|
1518
|
+
(member) => wordsCorroborate(normalizeWords(member.text), segWords, !groupMissing)
|
|
1519
|
+
);
|
|
1520
|
+
};
|
|
1521
|
+
const closestCorroborating = (wantSameSpeaker) => {
|
|
1522
|
+
let best;
|
|
1523
|
+
let bestDelta = Infinity;
|
|
1524
|
+
for (const group of groups) {
|
|
1525
|
+
if (group.key === key !== wantSameSpeaker || !corroborates(group)) {
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1528
|
+
const delta = !segMissing && Number.isFinite(group.anchorMs) ? Math.abs(seg.startMs - group.anchorMs) : 0;
|
|
1529
|
+
if (best === void 0 || delta < bestDelta || delta === bestDelta && group.anchorMs < best.anchorMs) {
|
|
1530
|
+
best = group;
|
|
1531
|
+
bestDelta = delta;
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
return best;
|
|
1535
|
+
};
|
|
1536
|
+
let chosen = closestCorroborating(true);
|
|
1537
|
+
if (chosen === void 0) {
|
|
1538
|
+
chosen = closestCorroborating(false);
|
|
1539
|
+
}
|
|
1540
|
+
if (chosen !== void 0) {
|
|
1541
|
+
chosen.members.push(seg);
|
|
1542
|
+
if (seg.originalIndex < chosen.originalIndex) {
|
|
1543
|
+
chosen.originalIndex = seg.originalIndex;
|
|
1544
|
+
}
|
|
1545
|
+
} else {
|
|
1546
|
+
groups.push({
|
|
1547
|
+
key,
|
|
1548
|
+
speakerLabel: seg.speakerLabel,
|
|
1549
|
+
isSelf: seg.isSelf,
|
|
1550
|
+
members: [seg],
|
|
1551
|
+
anchorMs: seg.startMs,
|
|
1552
|
+
// The creating segment is the EARLIEST member (tagged is
|
|
1553
|
+
// time-sorted), so its clock IS the group anchor that groups are
|
|
1554
|
+
// sorted by and that the fused segment must be emitted at.
|
|
1555
|
+
anchorStartIso: seg.startIso,
|
|
1556
|
+
anchorEndIso: seg.endIso,
|
|
1557
|
+
originalIndex: seg.originalIndex
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
groups.sort((a, b) => {
|
|
1562
|
+
const aMissing = !Number.isFinite(a.anchorMs);
|
|
1563
|
+
const bMissing = !Number.isFinite(b.anchorMs);
|
|
1564
|
+
if (aMissing !== bMissing) return aMissing ? 1 : -1;
|
|
1565
|
+
if (!aMissing && a.anchorMs !== b.anchorMs) return a.anchorMs - b.anchorMs;
|
|
1566
|
+
return a.originalIndex - b.originalIndex;
|
|
1567
|
+
});
|
|
1568
|
+
const segments = [];
|
|
1569
|
+
const disagreements = [];
|
|
1570
|
+
for (const group of groups) {
|
|
1571
|
+
const reconciled = reconcileGroup(group);
|
|
1572
|
+
segments.push(reconciled.segment);
|
|
1573
|
+
disagreements.push(...reconciled.disagreements);
|
|
1574
|
+
}
|
|
1575
|
+
const preSortOrder = new Map(segments.map((seg, i) => [seg, i]));
|
|
1576
|
+
segments.sort((a, b) => {
|
|
1577
|
+
const aMs = a.startIso !== void 0 ? Date.parse(a.startIso) : Number.NaN;
|
|
1578
|
+
const bMs = b.startIso !== void 0 ? Date.parse(b.startIso) : Number.NaN;
|
|
1579
|
+
const aFinite = Number.isFinite(aMs);
|
|
1580
|
+
const bFinite = Number.isFinite(bMs);
|
|
1581
|
+
if (aFinite && bFinite) {
|
|
1582
|
+
if (aMs !== bMs) return aMs - bMs;
|
|
1583
|
+
} else if (aFinite !== bFinite) {
|
|
1584
|
+
return aFinite ? -1 : 1;
|
|
1585
|
+
}
|
|
1586
|
+
return (preSortOrder.get(a) ?? 0) - (preSortOrder.get(b) ?? 0);
|
|
1587
|
+
});
|
|
1588
|
+
detectCrossSegmentDisagreements(segments, toleranceMs, disagreements);
|
|
1589
|
+
const result = {
|
|
1590
|
+
sources,
|
|
1591
|
+
speakers: collectSpeakers(tagged),
|
|
1592
|
+
startIso,
|
|
1593
|
+
segments,
|
|
1594
|
+
disagreements
|
|
1595
|
+
};
|
|
1596
|
+
if (endIso !== void 0) result.endIso = endIso;
|
|
1597
|
+
if (title !== void 0) result.title = title;
|
|
1598
|
+
if (summary !== void 0) result.summary = summary;
|
|
1599
|
+
return result;
|
|
1600
|
+
}
|
|
1601
|
+
function reconcileGroup(group) {
|
|
1602
|
+
const members = group.members;
|
|
1603
|
+
const ranked = [...members].sort((a, b) => {
|
|
1604
|
+
if (Math.abs(b.sourceTrust - a.sourceTrust) > TRUST_DECISION_EPSILON) {
|
|
1605
|
+
return b.sourceTrust - a.sourceTrust;
|
|
1606
|
+
}
|
|
1607
|
+
if (b.text.length !== a.text.length) return b.text.length - a.text.length;
|
|
1608
|
+
if (a.source !== b.source) return a.source < b.source ? -1 : 1;
|
|
1609
|
+
if (a.conversationId !== b.conversationId) {
|
|
1610
|
+
return a.conversationId < b.conversationId ? -1 : 1;
|
|
1611
|
+
}
|
|
1612
|
+
return a.originalIndex - b.originalIndex;
|
|
1613
|
+
});
|
|
1614
|
+
const top = ranked[0];
|
|
1615
|
+
const topWords = normalizeWords(top.text);
|
|
1616
|
+
let chosen = top;
|
|
1617
|
+
if (topWords.length > 0) {
|
|
1618
|
+
let bestLen = -1;
|
|
1619
|
+
for (const candidate of ranked) {
|
|
1620
|
+
if (candidate === top) continue;
|
|
1621
|
+
const candidateWords = normalizeWords(candidate.text);
|
|
1622
|
+
if (isWordPrefix(topWords, candidateWords) && candidateWords.length > topWords.length && candidateWords.length > bestLen) {
|
|
1623
|
+
chosen = candidate;
|
|
1624
|
+
bestLen = candidateWords.length;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
const truncatedOverride = chosen !== top;
|
|
1629
|
+
const others = ranked.filter((member) => member !== chosen);
|
|
1630
|
+
const chosenWords = normalizeWords(chosen.text);
|
|
1631
|
+
const reason = members.length === 1 ? "only-source" : truncatedOverride ? "more-complete" : others.some(
|
|
1632
|
+
(r) => chosen.sourceTrust - r.sourceTrust > TRUST_DECISION_EPSILON
|
|
1633
|
+
) ? "higher-trust" : others.some((r) => chosen.text.length - r.text.length > 0) ? "more-complete" : "tie-break";
|
|
1634
|
+
const disagree = [];
|
|
1635
|
+
let conflict = false;
|
|
1636
|
+
for (const candidate of others) {
|
|
1637
|
+
const candidateWords = normalizeWords(candidate.text);
|
|
1638
|
+
if (chosenWords.length === 0 && candidateWords.length === 0) continue;
|
|
1639
|
+
if (wordsEqual(chosenWords, candidateWords)) continue;
|
|
1640
|
+
if (isWordPrefix(candidateWords, chosenWords) || isWordPrefix(chosenWords, candidateWords)) {
|
|
1641
|
+
continue;
|
|
1642
|
+
}
|
|
1643
|
+
conflict = true;
|
|
1644
|
+
disagree.push({ source: candidate.source, value: candidate.text });
|
|
1645
|
+
}
|
|
1646
|
+
const distinctSpeakerKeys = new Set(
|
|
1647
|
+
members.map((m) => speakerKey(m.speakerLabel, m.isSelf))
|
|
1648
|
+
);
|
|
1649
|
+
const speakerConflict = distinctSpeakerKeys.size > 1;
|
|
1650
|
+
const alternatives = others.map((candidate) => ({
|
|
1651
|
+
source: candidate.source,
|
|
1652
|
+
text: candidate.text
|
|
1653
|
+
}));
|
|
1654
|
+
const confidence = conflict || speakerConflict ? clamp01(chosen.sourceTrust * 0.7) : members.length > 1 ? clamp01(chosen.sourceTrust + 0.1 * (members.length - 1)) : clamp01(chosen.sourceTrust);
|
|
1655
|
+
const segment = {
|
|
1656
|
+
speaker: chosen.speakerLabel,
|
|
1657
|
+
isSelf: chosen.isSelf,
|
|
1658
|
+
text: chosen.text,
|
|
1659
|
+
confidence,
|
|
1660
|
+
provenance: {
|
|
1661
|
+
source: chosen.source,
|
|
1662
|
+
conversationId: chosen.conversationId,
|
|
1663
|
+
sourceTrust: chosen.sourceTrust,
|
|
1664
|
+
reason,
|
|
1665
|
+
alternatives,
|
|
1666
|
+
...chosen.startIso !== void 0 ? { sourceStartIso: chosen.startIso } : {},
|
|
1667
|
+
...chosen.endIso !== void 0 ? { sourceEndIso: chosen.endIso } : {}
|
|
1668
|
+
},
|
|
1669
|
+
...group.anchorStartIso !== void 0 ? { startIso: group.anchorStartIso } : {},
|
|
1670
|
+
...group.anchorEndIso !== void 0 ? { endIso: group.anchorEndIso } : {}
|
|
1671
|
+
};
|
|
1672
|
+
const disagreements = [];
|
|
1673
|
+
const anchorIso = group.anchorStartIso ?? (Number.isFinite(group.anchorMs) ? new Date(group.anchorMs).toISOString() : void 0);
|
|
1674
|
+
if (conflict) {
|
|
1675
|
+
disagreements.push({
|
|
1676
|
+
kind: "asr-text",
|
|
1677
|
+
subject: anchorIso ?? "(no timestamp)",
|
|
1678
|
+
candidates: [{ source: chosen.source, value: chosen.text }, ...disagree],
|
|
1679
|
+
provisional: { source: chosen.source, value: chosen.text }
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1682
|
+
if (speakerConflict) {
|
|
1683
|
+
const speakerCandidates = members.map((m) => ({ source: m.source, value: m.speakerLabel })).sort(
|
|
1684
|
+
(a, b) => a.source < b.source ? -1 : a.source > b.source ? 1 : 0
|
|
1685
|
+
);
|
|
1686
|
+
disagreements.push({
|
|
1687
|
+
kind: "speaker",
|
|
1688
|
+
subject: anchorIso ?? "(no timestamp)",
|
|
1689
|
+
candidates: speakerCandidates,
|
|
1690
|
+
provisional: { source: chosen.source, value: chosen.speakerLabel }
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
return { segment, disagreements };
|
|
1694
|
+
}
|
|
1695
|
+
function detectCrossSegmentDisagreements(segments, toleranceMs, out) {
|
|
1696
|
+
const n = segments.length;
|
|
1697
|
+
if (n < 2) return;
|
|
1698
|
+
const claimed = new Array(n).fill(false);
|
|
1699
|
+
for (let i = 0; i < n; i++) {
|
|
1700
|
+
if (claimed[i]) continue;
|
|
1701
|
+
const seed = segments[i];
|
|
1702
|
+
const seedMs = seed.startIso !== void 0 ? Date.parse(seed.startIso) : NaN;
|
|
1703
|
+
if (!Number.isFinite(seedMs)) continue;
|
|
1704
|
+
const seedWords = normalizeWords(seed.text);
|
|
1705
|
+
const clusterIdx = [];
|
|
1706
|
+
for (let j = i + 1; j < n; j++) {
|
|
1707
|
+
if (claimed[j]) continue;
|
|
1708
|
+
const cand = segments[j];
|
|
1709
|
+
if (speakerKey(cand.speaker, cand.isSelf) !== speakerKey(seed.speaker, seed.isSelf)) {
|
|
1710
|
+
continue;
|
|
1711
|
+
}
|
|
1712
|
+
if (cand.provenance.source === seed.provenance.source) continue;
|
|
1713
|
+
const candMs = cand.startIso !== void 0 ? Date.parse(cand.startIso) : NaN;
|
|
1714
|
+
if (!Number.isFinite(candMs)) continue;
|
|
1715
|
+
if (Math.abs(candMs - seedMs) > toleranceMs) continue;
|
|
1716
|
+
if (wordsCorroborate(seedWords, normalizeWords(cand.text), true)) {
|
|
1717
|
+
continue;
|
|
1718
|
+
}
|
|
1719
|
+
clusterIdx.push(j);
|
|
1720
|
+
}
|
|
1721
|
+
if (clusterIdx.length === 0) continue;
|
|
1722
|
+
clusterIdx.unshift(i);
|
|
1723
|
+
for (const idx of clusterIdx) claimed[idx] = true;
|
|
1724
|
+
const involved = clusterIdx.map((idx) => segments[idx]);
|
|
1725
|
+
const involvedOrder = new Map(involved.map((seg, i2) => [seg, i2]));
|
|
1726
|
+
involved.sort((a, b) => {
|
|
1727
|
+
if (Math.abs(b.provenance.sourceTrust - a.provenance.sourceTrust) > TRUST_DECISION_EPSILON) {
|
|
1728
|
+
return b.provenance.sourceTrust - a.provenance.sourceTrust;
|
|
1729
|
+
}
|
|
1730
|
+
if (b.text.length !== a.text.length) return b.text.length - a.text.length;
|
|
1731
|
+
if (a.provenance.source !== b.provenance.source) {
|
|
1732
|
+
return a.provenance.source < b.provenance.source ? -1 : 1;
|
|
1733
|
+
}
|
|
1734
|
+
return involvedOrder.get(a) - involvedOrder.get(b);
|
|
1735
|
+
});
|
|
1736
|
+
const provisional = involved[0];
|
|
1737
|
+
const anchorIso = involved.map((s) => s.startIso).filter((v) => v !== void 0).sort()[0];
|
|
1738
|
+
for (const seg of involved) {
|
|
1739
|
+
seg.confidence = clamp01(seg.provenance.sourceTrust * 0.7);
|
|
1740
|
+
}
|
|
1741
|
+
out.push({
|
|
1742
|
+
kind: "asr-text",
|
|
1743
|
+
subject: anchorIso ?? "(no timestamp)",
|
|
1744
|
+
candidates: involved.map((s) => ({
|
|
1745
|
+
source: s.provenance.source,
|
|
1746
|
+
value: s.text
|
|
1747
|
+
})),
|
|
1748
|
+
provisional: {
|
|
1749
|
+
source: provisional.provenance.source,
|
|
1750
|
+
value: provisional.text
|
|
1751
|
+
}
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
function collectSpeakers(tagged) {
|
|
1756
|
+
const order = [];
|
|
1757
|
+
const acc = /* @__PURE__ */ new Map();
|
|
1758
|
+
for (const seg of tagged) {
|
|
1759
|
+
const key = speakerKey(seg.speakerLabel, seg.isSelf);
|
|
1760
|
+
let entry = acc.get(key);
|
|
1761
|
+
if (entry === void 0) {
|
|
1762
|
+
entry = {
|
|
1763
|
+
label: seg.speakerLabel,
|
|
1764
|
+
isSelf: seg.isSelf,
|
|
1765
|
+
sources: /* @__PURE__ */ new Set(),
|
|
1766
|
+
generic: GENERIC_LABEL_PATTERN.test(seg.speakerLabel)
|
|
1767
|
+
};
|
|
1768
|
+
acc.set(key, entry);
|
|
1769
|
+
order.push(key);
|
|
1770
|
+
}
|
|
1771
|
+
entry.sources.add(seg.source);
|
|
1772
|
+
}
|
|
1773
|
+
return order.map((key) => {
|
|
1774
|
+
const entry = acc.get(key);
|
|
1775
|
+
if (entry === void 0) throw new Error("fusion speaker accumulator miss");
|
|
1776
|
+
const sourceCount = entry.sources.size;
|
|
1777
|
+
const confidence = entry.isSelf ? sourceCount > 1 ? 0.95 : 0.85 : entry.generic ? sourceCount > 1 ? 0.7 : 0.5 : sourceCount > 1 ? 0.9 : 0.7;
|
|
1778
|
+
return {
|
|
1779
|
+
label: entry.label,
|
|
1780
|
+
isSelf: entry.isSelf,
|
|
1781
|
+
confidence,
|
|
1782
|
+
sources: [...entry.sources].sort()
|
|
1783
|
+
};
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
// src/wearables/fusion/fuse.ts
|
|
1788
|
+
import { createHash } from "crypto";
|
|
1789
|
+
var FUSION_ID_PREFIX = "fusion";
|
|
1790
|
+
var FUSION_ALGO_VERSION = "2026-07-12-1";
|
|
1791
|
+
function canonicalInputsKey(date, inputs) {
|
|
1792
|
+
const sorted = [...inputs].sort((a, b) => {
|
|
1793
|
+
if (a.source !== b.source) return a.source < b.source ? -1 : 1;
|
|
1794
|
+
if (a.conversationId !== b.conversationId) {
|
|
1795
|
+
return a.conversationId < b.conversationId ? -1 : 1;
|
|
1796
|
+
}
|
|
1797
|
+
return 0;
|
|
1798
|
+
});
|
|
1799
|
+
const record = [
|
|
1800
|
+
date,
|
|
1801
|
+
sorted.map((conv) => [
|
|
1802
|
+
conv.source,
|
|
1803
|
+
conv.conversationId,
|
|
1804
|
+
conv.startIso,
|
|
1805
|
+
conv.endIso ?? "",
|
|
1806
|
+
conv.title ?? "",
|
|
1807
|
+
conv.summary ?? "",
|
|
1808
|
+
conv.segments.map((segment) => [
|
|
1809
|
+
segment.speaker,
|
|
1810
|
+
segment.isSelf ? "self" : "other",
|
|
1811
|
+
segment.startIso ?? "",
|
|
1812
|
+
segment.endIso ?? "",
|
|
1813
|
+
segment.text
|
|
1814
|
+
])
|
|
1815
|
+
])
|
|
1816
|
+
];
|
|
1817
|
+
return createHash("sha256").update(JSON.stringify(record), "utf-8").digest("hex");
|
|
1818
|
+
}
|
|
1819
|
+
function configFingerprint(options, sources) {
|
|
1820
|
+
const proximityGapMs = options.proximityGapMs ?? DEFAULT_PROXIMITY_GAP_MS;
|
|
1821
|
+
const windowToleranceMs = options.windowToleranceMs ?? DEFAULT_WINDOW_TOLERANCE_MS;
|
|
1822
|
+
const trustMap = options.sourceTrust ?? {};
|
|
1823
|
+
const trustEntries = [...new Set(sources)].sort().map((source) => [source, trustMap[source] ?? DEFAULT_SOURCE_TRUST]);
|
|
1824
|
+
return JSON.stringify([proximityGapMs, windowToleranceMs, trustEntries]);
|
|
1825
|
+
}
|
|
1826
|
+
function canonicalDayKey(date, inputs, options, algoVersion = FUSION_ALGO_VERSION) {
|
|
1827
|
+
const inputsKey = canonicalInputsKey(date, inputs);
|
|
1828
|
+
const fingerprint = configFingerprint(
|
|
1829
|
+
options,
|
|
1830
|
+
inputs.map((conv) => conv.source)
|
|
1831
|
+
);
|
|
1832
|
+
return createHash("sha256").update(inputsKey).update("\n").update(fingerprint).update("\n").update(algoVersion).digest("hex");
|
|
1833
|
+
}
|
|
1834
|
+
function buildProvenance(cluster, proximityGapMs, windowToleranceMs) {
|
|
1835
|
+
return {
|
|
1836
|
+
contributions: cluster.map((conv) => ({
|
|
1837
|
+
source: conv.source,
|
|
1838
|
+
conversationId: conv.conversationId,
|
|
1839
|
+
startIso: conv.startIso,
|
|
1840
|
+
...conv.endIso !== void 0 ? { endIso: conv.endIso } : {},
|
|
1841
|
+
segmentCount: conv.segments.length
|
|
1842
|
+
})),
|
|
1843
|
+
proximityGapMs,
|
|
1844
|
+
windowToleranceMs,
|
|
1845
|
+
method: "time-proximity"
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1848
|
+
function fuseDay(date, inputs, options = {}) {
|
|
1849
|
+
const proximityGapMs = options.proximityGapMs ?? DEFAULT_PROXIMITY_GAP_MS;
|
|
1850
|
+
const windowToleranceMs = options.windowToleranceMs ?? DEFAULT_WINDOW_TOLERANCE_MS;
|
|
1851
|
+
const clusters = clusterConversations(inputs, proximityGapMs);
|
|
1852
|
+
const conversations = clusters.map((cluster) => {
|
|
1853
|
+
const fused = fuseCluster(cluster, {
|
|
1854
|
+
...options,
|
|
1855
|
+
windowToleranceMs
|
|
1856
|
+
});
|
|
1857
|
+
const id = `${FUSION_ID_PREFIX}-${canonicalInputsKey(date, cluster).slice(0, 24)}`;
|
|
1858
|
+
const result = {
|
|
1859
|
+
id,
|
|
1860
|
+
date,
|
|
1861
|
+
startIso: fused.startIso,
|
|
1862
|
+
sources: fused.sources,
|
|
1863
|
+
speakers: fused.speakers,
|
|
1864
|
+
segments: fused.segments,
|
|
1865
|
+
disagreements: fused.disagreements,
|
|
1866
|
+
provenance: buildProvenance(cluster, proximityGapMs, windowToleranceMs)
|
|
1867
|
+
};
|
|
1868
|
+
if (fused.endIso !== void 0) result.endIso = fused.endIso;
|
|
1869
|
+
if (fused.title !== void 0) result.title = fused.title;
|
|
1870
|
+
if (fused.summary !== void 0) result.summary = fused.summary;
|
|
1871
|
+
return result;
|
|
1872
|
+
});
|
|
1873
|
+
const sourcesSeen = /* @__PURE__ */ new Set();
|
|
1874
|
+
const sources = [];
|
|
1875
|
+
for (const conv of conversations) {
|
|
1876
|
+
for (const source of conv.sources) {
|
|
1877
|
+
if (!sourcesSeen.has(source)) {
|
|
1878
|
+
sourcesSeen.add(source);
|
|
1879
|
+
sources.push(source);
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
return {
|
|
1884
|
+
date,
|
|
1885
|
+
conversations,
|
|
1886
|
+
sources,
|
|
1887
|
+
contentHash: canonicalDayKey(date, inputs, options)
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
// src/wearables/fusion/store.ts
|
|
1892
|
+
import { createHash as createHash2 } from "crypto";
|
|
1893
|
+
import * as path4 from "path";
|
|
1894
|
+
var FUSION_KIND = "wearable-fusion";
|
|
1895
|
+
function hashFusionBody(conversations) {
|
|
1896
|
+
return createHash2("sha256").update(JSON.stringify(conversations), "utf-8").digest("hex");
|
|
1897
|
+
}
|
|
1898
|
+
function composeFusionDayMeta(date, conversations, sources, contentHash, fusedAt) {
|
|
1899
|
+
return {
|
|
1900
|
+
kind: FUSION_KIND,
|
|
1901
|
+
date,
|
|
1902
|
+
sourceCount: sources.length,
|
|
1903
|
+
conversationCount: conversations.length,
|
|
1904
|
+
contentHash,
|
|
1905
|
+
bodyHash: hashFusionBody(conversations),
|
|
1906
|
+
fusedAt
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
function serializeFusionDay(meta, conversations) {
|
|
1910
|
+
const lines = ["---"];
|
|
1911
|
+
lines.push(`kind: ${meta.kind}`);
|
|
1912
|
+
lines.push(`date: ${JSON.stringify(meta.date)}`);
|
|
1913
|
+
lines.push(`sourceCount: ${meta.sourceCount}`);
|
|
1914
|
+
lines.push(`conversationCount: ${meta.conversationCount}`);
|
|
1915
|
+
lines.push(`contentHash: ${JSON.stringify(meta.contentHash)}`);
|
|
1916
|
+
lines.push(`bodyHash: ${JSON.stringify(meta.bodyHash)}`);
|
|
1917
|
+
lines.push(`fusedAt: ${JSON.stringify(meta.fusedAt)}`);
|
|
1918
|
+
lines.push("---");
|
|
1919
|
+
lines.push("");
|
|
1920
|
+
return `${lines.join("\n")}
|
|
1921
|
+
${JSON.stringify(conversations, null, 2)}
|
|
1922
|
+
`;
|
|
1923
|
+
}
|
|
1924
|
+
function parseScalar(value) {
|
|
1925
|
+
const trimmed = value.trim();
|
|
1926
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"') && trimmed.length >= 2) {
|
|
1927
|
+
try {
|
|
1928
|
+
const parsed = JSON.parse(trimmed);
|
|
1929
|
+
if (typeof parsed === "string") return parsed;
|
|
1930
|
+
} catch {
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
return trimmed;
|
|
1934
|
+
}
|
|
1935
|
+
function parseNonNegativeInt(value) {
|
|
1936
|
+
if (value === void 0) return 0;
|
|
1937
|
+
const parsed = Number(value);
|
|
1938
|
+
if (!Number.isFinite(parsed) || parsed < 0) return 0;
|
|
1939
|
+
return Math.floor(parsed);
|
|
1940
|
+
}
|
|
1941
|
+
var FUSED_SEGMENT_PICK_REASONS = {
|
|
1942
|
+
"only-source": true,
|
|
1943
|
+
"higher-trust": true,
|
|
1944
|
+
"more-complete": true,
|
|
1945
|
+
"tie-break": true
|
|
1946
|
+
};
|
|
1947
|
+
var FUSED_DISAGREEMENT_KINDS = {
|
|
1948
|
+
"asr-text": true,
|
|
1949
|
+
speaker: true,
|
|
1950
|
+
timestamp: true
|
|
1951
|
+
};
|
|
1952
|
+
function isPlainObject(value) {
|
|
1953
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1954
|
+
}
|
|
1955
|
+
function isStringArray(value) {
|
|
1956
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
1957
|
+
}
|
|
1958
|
+
function isFusedSegmentProvenance(value) {
|
|
1959
|
+
if (!isPlainObject(value)) return false;
|
|
1960
|
+
if (typeof value.source !== "string") return false;
|
|
1961
|
+
if (typeof value.conversationId !== "string") return false;
|
|
1962
|
+
if (typeof value.sourceTrust !== "number") return false;
|
|
1963
|
+
if (typeof value.reason !== "string") return false;
|
|
1964
|
+
if (!(value.reason in FUSED_SEGMENT_PICK_REASONS)) return false;
|
|
1965
|
+
return Array.isArray(value.alternatives) && value.alternatives.every(
|
|
1966
|
+
(alt) => isPlainObject(alt) && typeof alt.source === "string" && typeof alt.text === "string"
|
|
1967
|
+
);
|
|
1968
|
+
}
|
|
1969
|
+
function isFusedSegment(value) {
|
|
1970
|
+
if (!isPlainObject(value)) return false;
|
|
1971
|
+
if (typeof value.speaker !== "string") return false;
|
|
1972
|
+
if (typeof value.isSelf !== "boolean") return false;
|
|
1973
|
+
if (typeof value.text !== "string") return false;
|
|
1974
|
+
if (typeof value.confidence !== "number") return false;
|
|
1975
|
+
return isFusedSegmentProvenance(value.provenance);
|
|
1976
|
+
}
|
|
1977
|
+
function isFusedSpeaker(value) {
|
|
1978
|
+
if (!isPlainObject(value)) return false;
|
|
1979
|
+
if (typeof value.label !== "string") return false;
|
|
1980
|
+
if (typeof value.isSelf !== "boolean") return false;
|
|
1981
|
+
if (typeof value.confidence !== "number") return false;
|
|
1982
|
+
return isStringArray(value.sources);
|
|
1983
|
+
}
|
|
1984
|
+
function isFusedDisagreement(value) {
|
|
1985
|
+
if (!isPlainObject(value)) return false;
|
|
1986
|
+
if (typeof value.kind !== "string") return false;
|
|
1987
|
+
if (!(value.kind in FUSED_DISAGREEMENT_KINDS)) return false;
|
|
1988
|
+
if (typeof value.subject !== "string") return false;
|
|
1989
|
+
return Array.isArray(value.candidates) && value.candidates.every(
|
|
1990
|
+
(cand) => isPlainObject(cand) && typeof cand.source === "string" && typeof cand.value === "string"
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
function isFusedContribution(value) {
|
|
1994
|
+
if (!isPlainObject(value)) return false;
|
|
1995
|
+
if (typeof value.source !== "string") return false;
|
|
1996
|
+
if (typeof value.conversationId !== "string") return false;
|
|
1997
|
+
if (typeof value.startIso !== "string") return false;
|
|
1998
|
+
return typeof value.segmentCount === "number";
|
|
1999
|
+
}
|
|
2000
|
+
function isFusedConversationProvenance(value) {
|
|
2001
|
+
if (!isPlainObject(value)) return false;
|
|
2002
|
+
if (!Array.isArray(value.contributions) || !value.contributions.every(isFusedContribution)) {
|
|
2003
|
+
return false;
|
|
2004
|
+
}
|
|
2005
|
+
if (typeof value.proximityGapMs !== "number") return false;
|
|
2006
|
+
if (typeof value.windowToleranceMs !== "number") return false;
|
|
2007
|
+
return value.method === "time-proximity";
|
|
2008
|
+
}
|
|
2009
|
+
function isFusedWearableConversation(value) {
|
|
2010
|
+
if (!isPlainObject(value)) return false;
|
|
2011
|
+
if (typeof value.id !== "string") return false;
|
|
2012
|
+
if (typeof value.date !== "string") return false;
|
|
2013
|
+
if (typeof value.startIso !== "string") return false;
|
|
2014
|
+
if (!isStringArray(value.sources)) return false;
|
|
2015
|
+
if (!Array.isArray(value.speakers) || !value.speakers.every(isFusedSpeaker)) return false;
|
|
2016
|
+
if (!Array.isArray(value.segments) || !value.segments.every(isFusedSegment)) return false;
|
|
2017
|
+
if (!Array.isArray(value.disagreements) || !value.disagreements.every(isFusedDisagreement)) {
|
|
2018
|
+
return false;
|
|
2019
|
+
}
|
|
2020
|
+
return isFusedConversationProvenance(value.provenance);
|
|
2021
|
+
}
|
|
2022
|
+
function parseFusionDay(raw) {
|
|
2023
|
+
if (!raw.startsWith("---\n")) return null;
|
|
2024
|
+
const closeIndex = raw.indexOf("\n---\n", 4);
|
|
2025
|
+
if (closeIndex === -1) return null;
|
|
2026
|
+
const header = raw.slice(4, closeIndex);
|
|
2027
|
+
const body = raw.slice(closeIndex + 5).replace(/^\n/, "");
|
|
2028
|
+
const scalars = /* @__PURE__ */ new Map();
|
|
2029
|
+
for (const line of header.split("\n")) {
|
|
2030
|
+
const match = line.match(/^([A-Za-z][A-Za-z0-9]*): (.*)$/);
|
|
2031
|
+
if (match) scalars.set(match[1], parseScalar(match[2]));
|
|
2032
|
+
}
|
|
2033
|
+
if (scalars.get("kind") !== FUSION_KIND) return null;
|
|
2034
|
+
const date = scalars.get("date");
|
|
2035
|
+
if (date === void 0) return null;
|
|
2036
|
+
let conversations = [];
|
|
2037
|
+
let parseOk = true;
|
|
2038
|
+
const bodyTrimmed = body.trim();
|
|
2039
|
+
if (bodyTrimmed.length === 0) {
|
|
2040
|
+
parseOk = false;
|
|
2041
|
+
} else {
|
|
2042
|
+
try {
|
|
2043
|
+
const parsed = JSON.parse(bodyTrimmed);
|
|
2044
|
+
if (Array.isArray(parsed) && parsed.every(isFusedWearableConversation)) {
|
|
2045
|
+
conversations = parsed;
|
|
2046
|
+
} else {
|
|
2047
|
+
parseOk = false;
|
|
2048
|
+
}
|
|
2049
|
+
} catch {
|
|
2050
|
+
parseOk = false;
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
const meta = {
|
|
2054
|
+
kind: FUSION_KIND,
|
|
2055
|
+
date,
|
|
2056
|
+
sourceCount: parseNonNegativeInt(scalars.get("sourceCount")),
|
|
2057
|
+
conversationCount: parseNonNegativeInt(scalars.get("conversationCount")),
|
|
2058
|
+
contentHash: scalars.get("contentHash") ?? "",
|
|
2059
|
+
bodyHash: scalars.get("bodyHash") ?? "",
|
|
2060
|
+
fusedAt: scalars.get("fusedAt") ?? ""
|
|
2061
|
+
};
|
|
2062
|
+
return { meta, conversations, parseOk };
|
|
2063
|
+
}
|
|
2064
|
+
var FUSION_DIR_NAME = "_fusion";
|
|
2065
|
+
var FusionArtifactStore = class {
|
|
2066
|
+
constructor(wearablesDir, memoryDir, io) {
|
|
2067
|
+
this.wearablesDir = wearablesDir;
|
|
2068
|
+
this.memoryDir = memoryDir;
|
|
2069
|
+
this.io = io;
|
|
2070
|
+
}
|
|
2071
|
+
wearablesDir;
|
|
2072
|
+
memoryDir;
|
|
2073
|
+
io;
|
|
2074
|
+
fusedDayPath(date) {
|
|
2075
|
+
if (!isValidTranscriptDate(date)) {
|
|
2076
|
+
throw new Error(
|
|
2077
|
+
`invalid wearable fusion date '${String(date)}' \u2014 expected YYYY-MM-DD`
|
|
2078
|
+
);
|
|
2079
|
+
}
|
|
2080
|
+
return path4.join(this.wearablesDir, FUSION_DIR_NAME, `${date}.md`);
|
|
2081
|
+
}
|
|
2082
|
+
async writeFusedDay(date, serialized) {
|
|
2083
|
+
const filePath = this.fusedDayPath(date);
|
|
2084
|
+
await this.assertPathContained(filePath);
|
|
2085
|
+
await this.io.writeFile(filePath, serialized);
|
|
2086
|
+
}
|
|
2087
|
+
/** Read a stored fused-day artifact; null when absent. */
|
|
2088
|
+
async readFusedDay(date) {
|
|
2089
|
+
const filePath = this.fusedDayPath(date);
|
|
2090
|
+
await this.assertPathContained(filePath);
|
|
2091
|
+
try {
|
|
2092
|
+
return await this.io.readFile(filePath);
|
|
2093
|
+
} catch (err) {
|
|
2094
|
+
if (err.code === "ENOENT") return null;
|
|
2095
|
+
throw err;
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
/**
|
|
2099
|
+
* Remove a stored fused-day artifact. Idempotent: a no-op when the
|
|
2100
|
+
* artifact is already absent. Used to clear a now-stale derived file
|
|
2101
|
+
* before a fusion run that deliberately refuses to fuse (e.g. a day
|
|
2102
|
+
* whose sources later conflict on timezone) so fusedConversations()
|
|
2103
|
+
* does not keep serving a stale view (issue #1849).
|
|
2104
|
+
*/
|
|
2105
|
+
async deleteFusedDay(date) {
|
|
2106
|
+
const filePath = this.fusedDayPath(date);
|
|
2107
|
+
await this.assertPathContained(filePath);
|
|
2108
|
+
try {
|
|
2109
|
+
await this.io.deleteFile(filePath);
|
|
2110
|
+
} catch (err) {
|
|
2111
|
+
if (err.code === "ENOENT") return;
|
|
2112
|
+
throw err;
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
/** List dates with stored fused artifacts, newest first. */
|
|
2116
|
+
async listFusedDays() {
|
|
2117
|
+
const fusionDir = path4.join(this.wearablesDir, FUSION_DIR_NAME);
|
|
2118
|
+
await this.assertPathContained(fusionDir);
|
|
2119
|
+
let entries;
|
|
2120
|
+
try {
|
|
2121
|
+
entries = await this.io.readDir(fusionDir);
|
|
2122
|
+
} catch (err) {
|
|
2123
|
+
if (err.code === "ENOENT") return [];
|
|
2124
|
+
throw err;
|
|
2125
|
+
}
|
|
2126
|
+
const days = [];
|
|
2127
|
+
for (const entry of entries) {
|
|
2128
|
+
if (!entry.endsWith(".md")) continue;
|
|
2129
|
+
const date = entry.slice(0, -3);
|
|
2130
|
+
if (!isValidTranscriptDate(date)) continue;
|
|
2131
|
+
days.push(date);
|
|
2132
|
+
}
|
|
2133
|
+
days.sort((a, b) => a > b ? -1 : a < b ? 1 : 0);
|
|
2134
|
+
return days;
|
|
2135
|
+
}
|
|
2136
|
+
/**
|
|
2137
|
+
* Reject a symlinked/traversing fusion artifact path before any IO. The
|
|
2138
|
+
* fusion dir (`<wearablesDir>/_fusion`) and its parents are followed
|
|
2139
|
+
* directly by the secure IO; a symlink placed there (attacker-writable
|
|
2140
|
+
* or a malformed memory dir) would otherwise be followed and
|
|
2141
|
+
* read/write/delete outside the allowed root (AGENTS.md pattern #3).
|
|
2142
|
+
*
|
|
2143
|
+
* Containment is anchored to the real MEMORY-DIR root, not the
|
|
2144
|
+
* wearables dir, AND the wearables root is checked explicitly: if
|
|
2145
|
+
* `wearablesDir` itself is a symlink that resolves outside memoryDir, a
|
|
2146
|
+
* leaf candidate like `<wearablesDir>/_fusion/<date>.md` may not yet
|
|
2147
|
+
* exist (so its realpath ENOENT-skips) and the write would silently
|
|
2148
|
+
* create the file inside the symlinked escape target. Checking
|
|
2149
|
+
* `wearablesDir` itself — which resolves through the symlink when it
|
|
2150
|
+
* exists — closes that gap, while the per-leaf checks catch a nested
|
|
2151
|
+
* `_fusion` or per-file symlink. Absent paths are allowed (a fresh
|
|
2152
|
+
* write creates them lexically under the root; only a path that
|
|
2153
|
+
* resolves to an existing target can redirect IO). Mirrors
|
|
2154
|
+
* `assertPathInsideRoot` in the storage walkers.
|
|
2155
|
+
*/
|
|
2156
|
+
async assertPathContained(targetPath) {
|
|
2157
|
+
let rootReal;
|
|
2158
|
+
try {
|
|
2159
|
+
rootReal = await this.io.realpath(this.memoryDir);
|
|
2160
|
+
} catch {
|
|
2161
|
+
rootReal = path4.resolve(this.memoryDir);
|
|
2162
|
+
}
|
|
2163
|
+
await this.assertNoEscape(rootReal, this.wearablesDir);
|
|
2164
|
+
await this.assertNoEscape(rootReal, path4.dirname(targetPath));
|
|
2165
|
+
await this.assertNoEscape(rootReal, targetPath);
|
|
2166
|
+
await this.assertFusionDirNotSymlinked();
|
|
2167
|
+
}
|
|
2168
|
+
/**
|
|
2169
|
+
* Refuse a pre-existing symbolic link at the `<wearablesDir>/_fusion`
|
|
2170
|
+
* directory. Unlike `assertNoEscape` (which follows the link and only
|
|
2171
|
+
* rejects when the target lands outside the memory dir), this catches a
|
|
2172
|
+
* fusion root that aliases an in-bounds path — e.g. a `_fusion` link
|
|
2173
|
+
* pointed at a raw source transcript — so fusion IO never writes
|
|
2174
|
+
* through it and overwrites the aliased file. Absent dirs are allowed
|
|
2175
|
+
* (a fresh write creates a real directory lexically under the root).
|
|
2176
|
+
*/
|
|
2177
|
+
async assertFusionDirNotSymlinked() {
|
|
2178
|
+
const fusionDir = path4.join(this.wearablesDir, FUSION_DIR_NAME);
|
|
2179
|
+
let stat3;
|
|
2180
|
+
try {
|
|
2181
|
+
stat3 = await this.io.lstat(fusionDir);
|
|
2182
|
+
} catch (err) {
|
|
2183
|
+
if (err.code === "ENOENT") return;
|
|
2184
|
+
throw err;
|
|
2185
|
+
}
|
|
2186
|
+
if (stat3.isSymbolicLink) {
|
|
2187
|
+
throw new Error(
|
|
2188
|
+
"wearable fusion dir '_fusion' is a symbolic link \u2014 refusing to follow it even when it resolves inside the memory dir (AGENTS.md pattern #3)"
|
|
2189
|
+
);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
/**
|
|
2193
|
+
* Refuse a candidate whose realpath escapes the memory root. Absent
|
|
2194
|
+
* candidates are allowed: a missing path cannot yet redirect IO, and
|
|
2195
|
+
* the secure write creates it lexically under the root.
|
|
2196
|
+
*/
|
|
2197
|
+
async assertNoEscape(rootReal, candidate) {
|
|
2198
|
+
let candidateReal;
|
|
2199
|
+
try {
|
|
2200
|
+
candidateReal = await this.io.realpath(candidate);
|
|
2201
|
+
} catch {
|
|
2202
|
+
return;
|
|
2203
|
+
}
|
|
2204
|
+
if (!pathIsInside(rootReal, candidateReal)) {
|
|
2205
|
+
throw new Error(
|
|
2206
|
+
"wearable fusion artifact path resolves outside the memory dir \u2014 refusing to follow a symlink/traversal (AGENTS.md pattern #3)"
|
|
2207
|
+
);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
};
|
|
2211
|
+
|
|
2212
|
+
// src/wearables/fusion/reconstruct.ts
|
|
2213
|
+
var CONVERSATION_HEADING = /^## (.+?)\u2013(.+?)(?:\s\u00b7\s(.*))?\s\(conversation (.+)\)$/;
|
|
2214
|
+
var LOCATION_LINE = /^\*Location: (.+)\*$/;
|
|
2215
|
+
var CLOCK_PATTERN = /^(\d{2}):(\d{2})$/;
|
|
2216
|
+
var MINUTES_PER_DAY = 24 * 60;
|
|
2217
|
+
var MAX_PLAUSIBLE_WRAP_MINUTES = 12 * 60;
|
|
2218
|
+
function clockToIso(clock, date) {
|
|
2219
|
+
const match = CLOCK_PATTERN.exec(clock.trim());
|
|
2220
|
+
if (match === null) return void 0;
|
|
2221
|
+
const hour = match[1] === "24" ? "00" : match[1];
|
|
2222
|
+
return `${date}T${hour}:${match[2]}:00.000Z`;
|
|
2223
|
+
}
|
|
2224
|
+
function clockMinutesOfDay(clock) {
|
|
2225
|
+
const match = CLOCK_PATTERN.exec(clock.trim());
|
|
2226
|
+
if (match === null) return void 0;
|
|
2227
|
+
const hour = match[1] === "24" ? 0 : Number.parseInt(match[1], 10);
|
|
2228
|
+
return hour * 60 + Number.parseInt(match[2], 10);
|
|
2229
|
+
}
|
|
2230
|
+
function nextCalendarDay(date) {
|
|
2231
|
+
const [y, m, d] = date.split("-").map((part) => Number.parseInt(part, 10));
|
|
2232
|
+
const dt = new Date(Date.UTC(y, m - 1, d));
|
|
2233
|
+
dt.setUTCDate(dt.getUTCDate() + 1);
|
|
2234
|
+
const yy = dt.getUTCFullYear();
|
|
2235
|
+
const mm = String(dt.getUTCMonth() + 1).padStart(2, "0");
|
|
2236
|
+
const dd = String(dt.getUTCDate()).padStart(2, "0");
|
|
2237
|
+
return `${yy}-${mm}-${dd}`;
|
|
2238
|
+
}
|
|
2239
|
+
function reconstructFusionInputs(date, dayTranscripts) {
|
|
2240
|
+
if (!isValidTranscriptDate(date)) return [];
|
|
2241
|
+
const inputs = [];
|
|
2242
|
+
for (const { source, body, escaped } of dayTranscripts) {
|
|
2243
|
+
let current = null;
|
|
2244
|
+
const flushCurrent = () => {
|
|
2245
|
+
if (current === null) return;
|
|
2246
|
+
const startIso = current.startIso ?? current.segments.find((segment) => segment.startIso !== void 0)?.startIso ?? `${date}T00:00:00.000Z`;
|
|
2247
|
+
const input = {
|
|
2248
|
+
source,
|
|
2249
|
+
conversationId: current.conversationId,
|
|
2250
|
+
startIso,
|
|
2251
|
+
segments: current.segments
|
|
2252
|
+
};
|
|
2253
|
+
if (current.endIso !== void 0) input.endIso = current.endIso;
|
|
2254
|
+
if (current.title !== void 0) input.title = current.title;
|
|
2255
|
+
inputs.push(input);
|
|
2256
|
+
current = null;
|
|
2257
|
+
};
|
|
2258
|
+
for (const rawLine of body.split("\n")) {
|
|
2259
|
+
const line = rawLine.trimEnd();
|
|
2260
|
+
if (line.length === 0) continue;
|
|
2261
|
+
const heading = CONVERSATION_HEADING.exec(line);
|
|
2262
|
+
if (heading !== null) {
|
|
2263
|
+
flushCurrent();
|
|
2264
|
+
const [, startClock, endClock, title, id] = heading;
|
|
2265
|
+
const startMin = clockMinutesOfDay(startClock);
|
|
2266
|
+
const endMin = clockMinutesOfDay(endClock);
|
|
2267
|
+
const wrapped = startMin !== void 0 && endMin !== void 0 && endMin < startMin;
|
|
2268
|
+
const wrapDuration = startMin !== void 0 && endMin !== void 0 ? MINUTES_PER_DAY - startMin + endMin : void 0;
|
|
2269
|
+
const plausibleWrap = wrapped && wrapDuration !== void 0 && wrapDuration <= MAX_PLAUSIBLE_WRAP_MINUTES;
|
|
2270
|
+
const startIso = clockToIso(startClock, date);
|
|
2271
|
+
const endIso = plausibleWrap ? clockToIso(endClock, nextCalendarDay(date)) : clockToIso(endClock, date);
|
|
2272
|
+
current = {
|
|
2273
|
+
conversationId: id,
|
|
2274
|
+
segments: [],
|
|
2275
|
+
wrapped,
|
|
2276
|
+
...startMin !== void 0 ? { wrapStartMin: startMin } : {},
|
|
2277
|
+
...startIso !== void 0 ? { startIso } : {},
|
|
2278
|
+
...endIso !== void 0 ? { endIso } : {},
|
|
2279
|
+
...title !== void 0 && title.length > 0 ? { title } : {}
|
|
2280
|
+
};
|
|
2281
|
+
continue;
|
|
2282
|
+
}
|
|
2283
|
+
if (LOCATION_LINE.exec(line) !== null) continue;
|
|
2284
|
+
const segmentMatch = parseTranscriptSegmentLine(line);
|
|
2285
|
+
if (segmentMatch !== null) {
|
|
2286
|
+
if (current === null) continue;
|
|
2287
|
+
const { label, clock, text: rawText } = segmentMatch;
|
|
2288
|
+
const text = escaped ? unescapeSegmentText(rawText) : rawText;
|
|
2289
|
+
const segMin = clockMinutesOfDay(clock);
|
|
2290
|
+
const segWrapDuration = current.wrapStartMin !== void 0 && segMin !== void 0 ? MINUTES_PER_DAY - current.wrapStartMin + segMin : void 0;
|
|
2291
|
+
const plausibleSegWrap = current.wrapStartMin !== void 0 && segMin !== void 0 && segMin < current.wrapStartMin && segWrapDuration !== void 0 && segWrapDuration <= MAX_PLAUSIBLE_WRAP_MINUTES;
|
|
2292
|
+
const segDate = plausibleSegWrap ? nextCalendarDay(date) : date;
|
|
2293
|
+
const startIso = clockToIso(clock, segDate);
|
|
2294
|
+
const speaker = escaped ? unescapeSpeakerLabel(label.trim()) : label.trim();
|
|
2295
|
+
const segment = {
|
|
2296
|
+
speaker,
|
|
2297
|
+
// Self status is read from the RESERVED `(you)` marker, which the
|
|
2298
|
+
// renderer guarantees can only appear on the wearer's label -
|
|
2299
|
+
// never on a non-self display name (issue #1849).
|
|
2300
|
+
isSelf: hasSelfMarker(speaker),
|
|
2301
|
+
text,
|
|
2302
|
+
...startIso !== void 0 ? { startIso } : {}
|
|
2303
|
+
};
|
|
2304
|
+
current.segments.push(segment);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
flushCurrent();
|
|
2308
|
+
}
|
|
2309
|
+
return inputs;
|
|
2310
|
+
}
|
|
2311
|
+
|
|
1262
2312
|
// src/storage.ts
|
|
1263
2313
|
var ARTIFACT_SEARCH_STOPWORDS = /* @__PURE__ */ new Set([
|
|
1264
2314
|
"a",
|
|
@@ -1865,17 +2915,17 @@ var KNOWN_ENTITY_FILENAME_PREFIXES = /* @__PURE__ */ new Set([
|
|
|
1865
2915
|
"topic"
|
|
1866
2916
|
]);
|
|
1867
2917
|
function inferEntityTypeFromFilename(pathRel) {
|
|
1868
|
-
const basename =
|
|
2918
|
+
const basename = path5.basename(pathRel, ".md").toLowerCase();
|
|
1869
2919
|
const separator = basename.indexOf("-");
|
|
1870
2920
|
if (separator <= 0) return void 0;
|
|
1871
2921
|
const candidate = basename.slice(0, separator);
|
|
1872
2922
|
return KNOWN_ENTITY_FILENAME_PREFIXES.has(candidate) ? candidate : void 0;
|
|
1873
2923
|
}
|
|
1874
2924
|
function normalizeFrontmatterForPath(frontmatter, pathRel, content = "") {
|
|
1875
|
-
const normalizedPath = pathRel.split(
|
|
2925
|
+
const normalizedPath = pathRel.split(path5.sep).join("/");
|
|
1876
2926
|
let normalizedFrontmatter = frontmatter;
|
|
1877
2927
|
if (normalizedPath === "entities" || normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/")) {
|
|
1878
|
-
const basename =
|
|
2928
|
+
const basename = path5.basename(pathRel, ".md");
|
|
1879
2929
|
const inferredType = inferEntityTypeFromContent(content) || inferEntityTypeFromFilename(pathRel) || "entity";
|
|
1880
2930
|
const existingTags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [];
|
|
1881
2931
|
normalizedFrontmatter = {
|
|
@@ -1942,8 +2992,8 @@ var ContentHashIndex = class _ContentHashIndex {
|
|
|
1942
2992
|
secureStoreKeyProvider;
|
|
1943
2993
|
secureStoreWriteKeyProvider;
|
|
1944
2994
|
memoryDir;
|
|
1945
|
-
constructor(stateDir, secureStoreKeyProvider = () => null, secureStoreWriteKeyProvider = secureStoreKeyProvider, memoryDir =
|
|
1946
|
-
this.filePath =
|
|
2995
|
+
constructor(stateDir, secureStoreKeyProvider = () => null, secureStoreWriteKeyProvider = secureStoreKeyProvider, memoryDir = path5.dirname(stateDir)) {
|
|
2996
|
+
this.filePath = path5.join(stateDir, "fact-hashes.txt");
|
|
1947
2997
|
this.secureStoreKeyProvider = secureStoreKeyProvider;
|
|
1948
2998
|
this.secureStoreWriteKeyProvider = secureStoreWriteKeyProvider;
|
|
1949
2999
|
this.memoryDir = memoryDir;
|
|
@@ -1990,7 +3040,7 @@ var ContentHashIndex = class _ContentHashIndex {
|
|
|
1990
3040
|
/** Persist index to disk if changed. */
|
|
1991
3041
|
async save() {
|
|
1992
3042
|
if (!this.dirty) return;
|
|
1993
|
-
await mkdir(
|
|
3043
|
+
await mkdir(path5.dirname(this.filePath), { recursive: true });
|
|
1994
3044
|
await writeMaybeEncryptedFile(
|
|
1995
3045
|
this.filePath,
|
|
1996
3046
|
[...this.hashes].join("\n") + "\n",
|
|
@@ -2532,7 +3582,7 @@ function fingerprintEntityStructuredFacts(entity) {
|
|
|
2532
3582
|
facts: normalizeStructuredSectionFacts(section.facts).slice().sort((left, right) => left.localeCompare(right))
|
|
2533
3583
|
})).filter((section) => section.facts.length > 0).sort((left, right) => left.key.localeCompare(right.key) || left.title.localeCompare(right.title) || left.facts.join("\n").localeCompare(right.facts.join("\n")));
|
|
2534
3584
|
if (normalizedSections.length === 0) return void 0;
|
|
2535
|
-
return
|
|
3585
|
+
return createHash3("sha256").update(JSON.stringify(normalizedSections)).digest("hex");
|
|
2536
3586
|
}
|
|
2537
3587
|
function isEntitySynthesisStale(entity) {
|
|
2538
3588
|
const structuredFactCount = countEntityStructuredFacts(entity);
|
|
@@ -3056,7 +4106,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3056
4106
|
void 0,
|
|
3057
4107
|
this.baseDir
|
|
3058
4108
|
);
|
|
3059
|
-
const rel =
|
|
4109
|
+
const rel = path5.relative(this.baseDir, filePath).split(path5.sep).join("/");
|
|
3060
4110
|
return `${rel}:${version.versionId}`;
|
|
3061
4111
|
} catch (err) {
|
|
3062
4112
|
log.warn(
|
|
@@ -3113,13 +4163,13 @@ var StorageManager3 = class _StorageManager {
|
|
|
3113
4163
|
}
|
|
3114
4164
|
identityFilePath(workspaceDir, namespace) {
|
|
3115
4165
|
const rawNamespace = typeof namespace === "string" ? namespace.trim() : "";
|
|
3116
|
-
if (!rawNamespace) return
|
|
4166
|
+
if (!rawNamespace) return path5.join(workspaceDir, "IDENTITY.md");
|
|
3117
4167
|
const safeNamespace = rawNamespace.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
3118
|
-
return
|
|
4168
|
+
return path5.join(workspaceDir, `IDENTITY.${safeNamespace}.md`);
|
|
3119
4169
|
}
|
|
3120
4170
|
versionFilePath(kind) {
|
|
3121
4171
|
const fileName = kind === "memory-status" ? ".memory-status-version.log" : kind === "artifact-write" ? ".artifact-write-version.log" : ".cold-write-version.log";
|
|
3122
|
-
return
|
|
4172
|
+
return path5.join(this.stateDir, fileName);
|
|
3123
4173
|
}
|
|
3124
4174
|
bumpSharedVersion(kind, fallbackMap) {
|
|
3125
4175
|
const filePath = this.versionFilePath(kind);
|
|
@@ -3166,7 +4216,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3166
4216
|
// memories.
|
|
3167
4217
|
// -------------------------------------------------------------------------
|
|
3168
4218
|
get wearablesDir() {
|
|
3169
|
-
return
|
|
4219
|
+
return path5.join(this.baseDir, WEARABLES_DIR_NAME);
|
|
3170
4220
|
}
|
|
3171
4221
|
/**
|
|
3172
4222
|
* Resolve the on-disk path for a source/day transcript. Throws on
|
|
@@ -3184,7 +4234,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3184
4234
|
`invalid wearable transcript date '${String(date)}' \u2014 expected YYYY-MM-DD`
|
|
3185
4235
|
);
|
|
3186
4236
|
}
|
|
3187
|
-
return
|
|
4237
|
+
return path5.join(this.wearablesDir, sourceId, `${date}.md`);
|
|
3188
4238
|
}
|
|
3189
4239
|
async writeWearableDayTranscript(sourceId, date, serialized) {
|
|
3190
4240
|
const targetPath = this.wearableTranscriptPath(sourceId, date);
|
|
@@ -3205,6 +4255,19 @@ var StorageManager3 = class _StorageManager {
|
|
|
3205
4255
|
sourceId
|
|
3206
4256
|
);
|
|
3207
4257
|
}
|
|
4258
|
+
_fusionStore;
|
|
4259
|
+
/** Derived fusion-day IO; file IO lives in wearables/fusion (#1810). */
|
|
4260
|
+
fusionArtifactStore() {
|
|
4261
|
+
if (this._fusionStore) return this._fusionStore;
|
|
4262
|
+
return this._fusionStore = new FusionArtifactStore(this.wearablesDir, this.baseDir, {
|
|
4263
|
+
writeFile: (p, c) => this.writeStorageSecureFile(p, c),
|
|
4264
|
+
readFile: (p) => readMaybeEncryptedFile(p, this._secureStoreKey, this.baseDir),
|
|
4265
|
+
readDir: (d) => readdir4(d),
|
|
4266
|
+
deleteFile: (p) => unlink2(p),
|
|
4267
|
+
realpath: (p) => realpath2(p),
|
|
4268
|
+
lstat: (p) => lstat2(p).then((st) => ({ isSymbolicLink: st.isSymbolicLink() }))
|
|
4269
|
+
});
|
|
4270
|
+
}
|
|
3208
4271
|
/**
|
|
3209
4272
|
* Locate a wearable-sourced memory by exact (trimmed) content,
|
|
3210
4273
|
* ignoring the "[Attributes: ...]" suffix writeMemory appends for
|
|
@@ -3271,25 +4334,25 @@ var StorageManager3 = class _StorageManager {
|
|
|
3271
4334
|
});
|
|
3272
4335
|
}
|
|
3273
4336
|
get factsDir() {
|
|
3274
|
-
return
|
|
4337
|
+
return path5.join(this.baseDir, "facts");
|
|
3275
4338
|
}
|
|
3276
4339
|
get correctionsDir() {
|
|
3277
|
-
return
|
|
4340
|
+
return path5.join(this.baseDir, "corrections");
|
|
3278
4341
|
}
|
|
3279
4342
|
get proceduresDir() {
|
|
3280
|
-
return
|
|
4343
|
+
return path5.join(this.baseDir, "procedures");
|
|
3281
4344
|
}
|
|
3282
4345
|
get reasoningTracesDir() {
|
|
3283
|
-
return
|
|
4346
|
+
return path5.join(this.baseDir, "reasoning-traces");
|
|
3284
4347
|
}
|
|
3285
4348
|
get entitiesDir() {
|
|
3286
|
-
return
|
|
4349
|
+
return path5.join(this.baseDir, "entities");
|
|
3287
4350
|
}
|
|
3288
4351
|
resolveEntityFilePath(name) {
|
|
3289
4352
|
if (typeof name !== "string") return null;
|
|
3290
|
-
const filePath =
|
|
3291
|
-
const relative =
|
|
3292
|
-
if (relative === "" || relative.startsWith("..") ||
|
|
4353
|
+
const filePath = path5.resolve(this.entitiesDir, `${name}.md`);
|
|
4354
|
+
const relative = path5.relative(this.entitiesDir, filePath);
|
|
4355
|
+
if (relative === "" || relative.startsWith("..") || path5.isAbsolute(relative)) {
|
|
3293
4356
|
return null;
|
|
3294
4357
|
}
|
|
3295
4358
|
return filePath;
|
|
@@ -3304,10 +4367,10 @@ var StorageManager3 = class _StorageManager {
|
|
|
3304
4367
|
return writeMaybeEncryptedFileFromChunks(filePath, chunks, this.resolveWriteKey(), {}, this.baseDir).then(() => this.notifyCatalogWrite());
|
|
3305
4368
|
}
|
|
3306
4369
|
assertManagedStoragePath(filePath, method) {
|
|
3307
|
-
const resolved =
|
|
3308
|
-
const base =
|
|
3309
|
-
const rel =
|
|
3310
|
-
if (rel === "" || rel === ".." || rel.startsWith(`..${
|
|
4370
|
+
const resolved = path5.resolve(filePath);
|
|
4371
|
+
const base = path5.resolve(this.baseDir);
|
|
4372
|
+
const rel = path5.relative(base, resolved);
|
|
4373
|
+
if (rel === "" || rel === ".." || rel.startsWith(`..${path5.sep}`) || path5.isAbsolute(rel)) {
|
|
3311
4374
|
throw new Error(`${method}: file path escapes memory dir`);
|
|
3312
4375
|
}
|
|
3313
4376
|
return resolved;
|
|
@@ -3319,7 +4382,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3319
4382
|
async digestOfflineSyncFile(filePath) {
|
|
3320
4383
|
const target = this.assertManagedStoragePath(filePath, "storage.digestOfflineSyncFile");
|
|
3321
4384
|
const st = await stat2(target);
|
|
3322
|
-
const relPath =
|
|
4385
|
+
const relPath = path5.relative(this.baseDir, target).split(path5.sep).join("/");
|
|
3323
4386
|
const cache = await this.loadOfflineSyncDigestCache();
|
|
3324
4387
|
const cached = cache.get(relPath);
|
|
3325
4388
|
if (cached && cached.statBytes === st.size && cached.mtimeMs === st.mtimeMs && cached.ctimeMs === st.ctimeMs && !cached.encrypted) {
|
|
@@ -3333,11 +4396,11 @@ var StorageManager3 = class _StorageManager {
|
|
|
3333
4396
|
if (encrypted) {
|
|
3334
4397
|
const content = await readMaybeEncryptedFileBuffer(target, this._secureStoreKey, this.baseDir);
|
|
3335
4398
|
digest = {
|
|
3336
|
-
sha256:
|
|
4399
|
+
sha256: createHash3("sha256").update(content).digest("hex"),
|
|
3337
4400
|
bytes: content.byteLength
|
|
3338
4401
|
};
|
|
3339
4402
|
} else {
|
|
3340
|
-
const hash =
|
|
4403
|
+
const hash = createHash3("sha256");
|
|
3341
4404
|
let bytes = 0;
|
|
3342
4405
|
for await (const rawChunk of createReadStream2(target)) {
|
|
3343
4406
|
const chunk = Buffer.isBuffer(rawChunk) ? rawChunk : Buffer.from(rawChunk);
|
|
@@ -3380,7 +4443,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3380
4443
|
const bytes = typeof record.bytes === "number" ? record.bytes : NaN;
|
|
3381
4444
|
const sha256 = typeof record.sha256 === "string" ? record.sha256 : "";
|
|
3382
4445
|
const encrypted = record.encrypted === true;
|
|
3383
|
-
if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") ||
|
|
4446
|
+
if (cachePath.length === 0 || cachePath === ".." || cachePath.startsWith("../") || path5.isAbsolute(cachePath) || !Number.isFinite(statBytes) || !Number.isFinite(mtimeMs) || !Number.isFinite(ctimeMs) || !Number.isFinite(bytes) || !/^[a-f0-9]{64}$/i.test(sha256)) {
|
|
3384
4447
|
continue;
|
|
3385
4448
|
}
|
|
3386
4449
|
cache.set(cachePath, { statBytes, mtimeMs, ctimeMs, encrypted, sha256, bytes });
|
|
@@ -3422,7 +4485,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3422
4485
|
const cache = this.offlineSyncDigestCache;
|
|
3423
4486
|
if (!cache) return;
|
|
3424
4487
|
const entries = [...cache.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([entryPath, entry]) => ({ path: entryPath, ...entry }));
|
|
3425
|
-
await mkdir(
|
|
4488
|
+
await mkdir(path5.dirname(this.offlineSyncDigestCachePath), { recursive: true });
|
|
3426
4489
|
await writeFile(
|
|
3427
4490
|
this.offlineSyncDigestCachePath,
|
|
3428
4491
|
`${JSON.stringify({ version: 1, entries })}
|
|
@@ -3475,10 +4538,10 @@ var StorageManager3 = class _StorageManager {
|
|
|
3475
4538
|
if (isErrnoCode(error, "ENOENT")) return;
|
|
3476
4539
|
throw error;
|
|
3477
4540
|
});
|
|
3478
|
-
if (filePath.includes(`${
|
|
4541
|
+
if (filePath.includes(`${path5.sep}cold${path5.sep}`)) {
|
|
3479
4542
|
this.invalidateColdMemoriesCache();
|
|
3480
4543
|
}
|
|
3481
|
-
if (filePath.includes(`${
|
|
4544
|
+
if (filePath.includes(`${path5.sep}artifacts${path5.sep}`)) {
|
|
3482
4545
|
this.bumpArtifactWriteVersion();
|
|
3483
4546
|
}
|
|
3484
4547
|
this.bumpMemoryStatusVersion();
|
|
@@ -3506,7 +4569,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3506
4569
|
}
|
|
3507
4570
|
async appendStorageSecureFileUnlocked(filePath, content) {
|
|
3508
4571
|
const writeKey = this.resolveWriteKey();
|
|
3509
|
-
await mkdir(
|
|
4572
|
+
await mkdir(path5.dirname(filePath), { recursive: true });
|
|
3510
4573
|
if (writeKey === null) {
|
|
3511
4574
|
try {
|
|
3512
4575
|
if (isEncryptedFile(await readFile(filePath))) {
|
|
@@ -3532,16 +4595,16 @@ var StorageManager3 = class _StorageManager {
|
|
|
3532
4595
|
this.notifyCatalogWrite();
|
|
3533
4596
|
}
|
|
3534
4597
|
get stateDir() {
|
|
3535
|
-
return
|
|
4598
|
+
return path5.join(this.baseDir, "state");
|
|
3536
4599
|
}
|
|
3537
4600
|
get offlineSyncDigestCachePath() {
|
|
3538
|
-
return
|
|
4601
|
+
return path5.join(this.baseDir, ".offline-sync", "digest-cache.v1.json");
|
|
3539
4602
|
}
|
|
3540
4603
|
get entitySynthesisQueuePath() {
|
|
3541
|
-
return
|
|
4604
|
+
return path5.join(this.stateDir, "entity-synthesis-queue.json");
|
|
3542
4605
|
}
|
|
3543
4606
|
get factHashIndexReadyPath() {
|
|
3544
|
-
return
|
|
4607
|
+
return path5.join(this.stateDir, "fact-hashes.ready");
|
|
3545
4608
|
}
|
|
3546
4609
|
// ── Tombstone store access (issue #1579) ─────────────────────────────────
|
|
3547
4610
|
/**
|
|
@@ -3551,7 +4614,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3551
4614
|
* helpers are injected into the store).
|
|
3552
4615
|
*/
|
|
3553
4616
|
get tombstonesPath() {
|
|
3554
|
-
return
|
|
4617
|
+
return path5.join(this.stateDir, "tombstones.jsonl");
|
|
3555
4618
|
}
|
|
3556
4619
|
/**
|
|
3557
4620
|
* Configure the tombstone invariant for this storage instance. Installed
|
|
@@ -3750,7 +4813,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3750
4813
|
);
|
|
3751
4814
|
}
|
|
3752
4815
|
await factHashIndex.save();
|
|
3753
|
-
await mkdir(
|
|
4816
|
+
await mkdir(path5.dirname(this.factHashIndexReadyPath), { recursive: true });
|
|
3754
4817
|
await writeFile(this.factHashIndexReadyPath, "v1\n", "utf-8");
|
|
3755
4818
|
this.factHashIndexAuthoritative = true;
|
|
3756
4819
|
})().finally(() => {
|
|
@@ -3759,55 +4822,55 @@ var StorageManager3 = class _StorageManager {
|
|
|
3759
4822
|
await this.factHashIndexAuthoritativePromise;
|
|
3760
4823
|
}
|
|
3761
4824
|
get questionsDir() {
|
|
3762
|
-
return
|
|
4825
|
+
return path5.join(this.baseDir, "questions");
|
|
3763
4826
|
}
|
|
3764
4827
|
get artifactsDir() {
|
|
3765
|
-
return
|
|
4828
|
+
return path5.join(this.baseDir, "artifacts");
|
|
3766
4829
|
}
|
|
3767
4830
|
get identityDir() {
|
|
3768
|
-
return
|
|
4831
|
+
return path5.join(this.baseDir, "identity");
|
|
3769
4832
|
}
|
|
3770
4833
|
get identityAnchorPath() {
|
|
3771
|
-
return
|
|
4834
|
+
return path5.join(this.identityDir, "identity-anchor.md");
|
|
3772
4835
|
}
|
|
3773
4836
|
get identityIncidentsDir() {
|
|
3774
|
-
return
|
|
4837
|
+
return path5.join(this.identityDir, "incidents");
|
|
3775
4838
|
}
|
|
3776
4839
|
get identityAuditsWeeklyDir() {
|
|
3777
|
-
return
|
|
4840
|
+
return path5.join(this.identityDir, "audits", "weekly");
|
|
3778
4841
|
}
|
|
3779
4842
|
get identityAuditsMonthlyDir() {
|
|
3780
|
-
return
|
|
4843
|
+
return path5.join(this.identityDir, "audits", "monthly");
|
|
3781
4844
|
}
|
|
3782
4845
|
get identityImprovementLoopsPath() {
|
|
3783
|
-
return
|
|
4846
|
+
return path5.join(this.identityDir, "improvement-loops.md");
|
|
3784
4847
|
}
|
|
3785
4848
|
get identityReflectionsPath() {
|
|
3786
|
-
return
|
|
4849
|
+
return path5.join(this.identityDir, "reflections.md");
|
|
3787
4850
|
}
|
|
3788
4851
|
get profilePath() {
|
|
3789
|
-
return
|
|
4852
|
+
return path5.join(this.baseDir, "profile.md");
|
|
3790
4853
|
}
|
|
3791
4854
|
get memoryActionsPath() {
|
|
3792
|
-
return
|
|
4855
|
+
return path5.join(this.stateDir, "memory-actions.jsonl");
|
|
3793
4856
|
}
|
|
3794
4857
|
get memoryLifecycleLedgerPath() {
|
|
3795
|
-
return
|
|
4858
|
+
return path5.join(this.stateDir, "memory-lifecycle-ledger.jsonl");
|
|
3796
4859
|
}
|
|
3797
4860
|
get compressionGuidelinesPath() {
|
|
3798
|
-
return
|
|
4861
|
+
return path5.join(this.stateDir, "compression-guidelines.md");
|
|
3799
4862
|
}
|
|
3800
4863
|
get compressionGuidelineDraftPath() {
|
|
3801
|
-
return
|
|
4864
|
+
return path5.join(this.stateDir, "compression-guidelines.draft.md");
|
|
3802
4865
|
}
|
|
3803
4866
|
get compressionGuidelineStatePath() {
|
|
3804
|
-
return
|
|
4867
|
+
return path5.join(this.stateDir, "compression-guideline-state.json");
|
|
3805
4868
|
}
|
|
3806
4869
|
get compressionGuidelineDraftStatePath() {
|
|
3807
|
-
return
|
|
4870
|
+
return path5.join(this.stateDir, "compression-guideline-draft-state.json");
|
|
3808
4871
|
}
|
|
3809
4872
|
get behaviorSignalsPath() {
|
|
3810
|
-
return
|
|
4873
|
+
return path5.join(this.stateDir, "behavior-signals.jsonl");
|
|
3811
4874
|
}
|
|
3812
4875
|
/**
|
|
3813
4876
|
* Buffer surprise telemetry ledger (issue #563 PR 3).
|
|
@@ -3820,7 +4883,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3820
4883
|
* governance sweeps can treat it uniformly.
|
|
3821
4884
|
*/
|
|
3822
4885
|
get bufferSurpriseLedgerPath() {
|
|
3823
|
-
return
|
|
4886
|
+
return path5.join(this.stateDir, "buffer-surprise-ledger.jsonl");
|
|
3824
4887
|
}
|
|
3825
4888
|
/**
|
|
3826
4889
|
* Entity alias table loaded from THIS store's config/aliases.json.
|
|
@@ -3854,7 +4917,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3854
4917
|
this.loadAliasesSync();
|
|
3855
4918
|
}
|
|
3856
4919
|
loadAliasesSync() {
|
|
3857
|
-
const aliasPath =
|
|
4920
|
+
const aliasPath = path5.join(this.baseDir, "config", "aliases.json");
|
|
3858
4921
|
this.userAliases = {};
|
|
3859
4922
|
try {
|
|
3860
4923
|
const raw = readFileSync(aliasPath, "utf-8");
|
|
@@ -3879,9 +4942,9 @@ var StorageManager3 = class _StorageManager {
|
|
|
3879
4942
|
}
|
|
3880
4943
|
async ensureDirectories() {
|
|
3881
4944
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3882
|
-
await mkdir(
|
|
3883
|
-
await mkdir(
|
|
3884
|
-
await mkdir(
|
|
4945
|
+
await mkdir(path5.join(this.factsDir, today), { recursive: true });
|
|
4946
|
+
await mkdir(path5.join(this.proceduresDir, today), { recursive: true });
|
|
4947
|
+
await mkdir(path5.join(this.reasoningTracesDir, today), { recursive: true });
|
|
3885
4948
|
await mkdir(this.correctionsDir, { recursive: true });
|
|
3886
4949
|
await mkdir(this.entitiesDir, { recursive: true });
|
|
3887
4950
|
await mkdir(this.stateDir, { recursive: true });
|
|
@@ -3891,7 +4954,7 @@ var StorageManager3 = class _StorageManager {
|
|
|
3891
4954
|
await mkdir(this.identityIncidentsDir, { recursive: true });
|
|
3892
4955
|
await mkdir(this.identityAuditsWeeklyDir, { recursive: true });
|
|
3893
4956
|
await mkdir(this.identityAuditsMonthlyDir, { recursive: true });
|
|
3894
|
-
await mkdir(
|
|
4957
|
+
await mkdir(path5.join(this.baseDir, "config"), { recursive: true });
|
|
3895
4958
|
}
|
|
3896
4959
|
/**
|
|
3897
4960
|
* Resolve the on-disk write path for a memory of the given category, creating
|
|
@@ -3908,11 +4971,11 @@ var StorageManager3 = class _StorageManager {
|
|
|
3908
4971
|
async resolveCategoryWritePath(category, id, today) {
|
|
3909
4972
|
if (category === "correction") {
|
|
3910
4973
|
await mkdir(this.correctionsDir, { recursive: true });
|
|
3911
|
-
return
|
|
4974
|
+
return path5.join(this.correctionsDir, `${id}.md`);
|
|
3912
4975
|
}
|
|
3913
|
-
const datedDir =
|
|
4976
|
+
const datedDir = path5.join(getCategoryDir(this.baseDir, category), today);
|
|
3914
4977
|
await mkdir(datedDir, { recursive: true });
|
|
3915
|
-
return
|
|
4978
|
+
return path5.join(datedDir, `${id}.md`);
|
|
3916
4979
|
}
|
|
3917
4980
|
async writeMemory(category, content, options = {}) {
|
|
3918
4981
|
await this.ensureDirectories();
|
|
@@ -4162,7 +5225,7 @@ ${sanitized.text}
|
|
|
4162
5225
|
await this.ensureDirectories();
|
|
4163
5226
|
const now = /* @__PURE__ */ new Date();
|
|
4164
5227
|
const day = now.toISOString().slice(0, 10);
|
|
4165
|
-
const dir =
|
|
5228
|
+
const dir = path5.join(this.artifactsDir, day);
|
|
4166
5229
|
await mkdir(dir, { recursive: true });
|
|
4167
5230
|
const id = `artifact-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
4168
5231
|
const fm = {
|
|
@@ -4186,7 +5249,7 @@ ${sanitized.text}
|
|
|
4186
5249
|
log.warn(`artifact content rejected for ${id}; violations=${sanitized.violations.join(", ")}`);
|
|
4187
5250
|
return "";
|
|
4188
5251
|
}
|
|
4189
|
-
const filePath =
|
|
5252
|
+
const filePath = path5.join(dir, `${id}.md`);
|
|
4190
5253
|
await this.writeStorageSecureFile(filePath, `${serializeFrontmatter(fm)}
|
|
4191
5254
|
|
|
4192
5255
|
${sanitized.text}
|
|
@@ -4388,7 +5451,7 @@ ${sanitized.text}
|
|
|
4388
5451
|
* per-process in-memory cache safe across process boundaries.
|
|
4389
5452
|
*/
|
|
4390
5453
|
invalidateColdMemoriesCache() {
|
|
4391
|
-
const coldRoot =
|
|
5454
|
+
const coldRoot = path5.join(this.baseDir, "cold");
|
|
4392
5455
|
_StorageManager.coldMemoriesCache.delete(coldRoot);
|
|
4393
5456
|
this.bumpColdWriteVersion();
|
|
4394
5457
|
invalidateAllForDir(this.baseDir);
|
|
@@ -4478,7 +5541,7 @@ ${sanitized.text}
|
|
|
4478
5541
|
const correctionPaths = [];
|
|
4479
5542
|
const factPaths = [];
|
|
4480
5543
|
for (const filePath of filePaths) {
|
|
4481
|
-
if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${
|
|
5544
|
+
if (filePath === this.correctionsDir || filePath.startsWith(`${this.correctionsDir}${path5.sep}`)) {
|
|
4482
5545
|
correctionPaths.push(filePath);
|
|
4483
5546
|
} else {
|
|
4484
5547
|
factPaths.push(filePath);
|
|
@@ -4543,7 +5606,7 @@ ${sanitized.text}
|
|
|
4543
5606
|
try {
|
|
4544
5607
|
const entries = await readdir4(dir, { withFileTypes: true });
|
|
4545
5608
|
for (const entry of entries) {
|
|
4546
|
-
const fullPath =
|
|
5609
|
+
const fullPath = path5.join(dir, entry.name);
|
|
4547
5610
|
if (entry.isDirectory()) {
|
|
4548
5611
|
await readDir(fullPath);
|
|
4549
5612
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -4578,7 +5641,7 @@ ${sanitized.text}
|
|
|
4578
5641
|
);
|
|
4579
5642
|
}
|
|
4580
5643
|
resolveTierRootDir(tier) {
|
|
4581
|
-
return tier === "cold" ?
|
|
5644
|
+
return tier === "cold" ? path5.join(this.baseDir, "cold") : this.baseDir;
|
|
4582
5645
|
}
|
|
4583
5646
|
resolveMemoryDateDir(memory) {
|
|
4584
5647
|
const preferred = memory.frontmatter.created || memory.frontmatter.updated;
|
|
@@ -4593,13 +5656,13 @@ ${sanitized.text}
|
|
|
4593
5656
|
buildTierMemoryPath(memory, tier) {
|
|
4594
5657
|
const root = this.resolveTierRootDir(tier);
|
|
4595
5658
|
if (this.isArtifactMemory(memory)) {
|
|
4596
|
-
return
|
|
5659
|
+
return path5.join(root, "artifacts", this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
|
|
4597
5660
|
}
|
|
4598
5661
|
if (memory.frontmatter.category === "correction") {
|
|
4599
|
-
return
|
|
5662
|
+
return path5.join(root, "corrections", `${memory.frontmatter.id}.md`);
|
|
4600
5663
|
}
|
|
4601
5664
|
const dir = categoryDirName(memory.frontmatter.category);
|
|
4602
|
-
return
|
|
5665
|
+
return path5.join(root, dir, this.resolveMemoryDateDir(memory), `${memory.frontmatter.id}.md`);
|
|
4603
5666
|
}
|
|
4604
5667
|
async writeMemoryFileAtomic(targetPath, memory) {
|
|
4605
5668
|
const fileContent = `${serializeFrontmatter(memory.frontmatter)}
|
|
@@ -4612,8 +5675,8 @@ ${memory.content}
|
|
|
4612
5675
|
}
|
|
4613
5676
|
async moveMemoryToPath(memory, targetPath) {
|
|
4614
5677
|
await this.writeMemoryFileAtomic(targetPath, memory);
|
|
4615
|
-
const sourcePath =
|
|
4616
|
-
const destPath =
|
|
5678
|
+
const sourcePath = path5.resolve(memory.path);
|
|
5679
|
+
const destPath = path5.resolve(targetPath);
|
|
4617
5680
|
if (sourcePath !== destPath) {
|
|
4618
5681
|
try {
|
|
4619
5682
|
await unlink2(memory.path);
|
|
@@ -4629,8 +5692,8 @@ ${memory.content}
|
|
|
4629
5692
|
}
|
|
4630
5693
|
async migrateMemoryToTier(memory, targetTier) {
|
|
4631
5694
|
const targetPath = this.buildTierMemoryPath(memory, targetTier);
|
|
4632
|
-
const sourcePath =
|
|
4633
|
-
const destPath =
|
|
5695
|
+
const sourcePath = path5.resolve(memory.path);
|
|
5696
|
+
const destPath = path5.resolve(targetPath);
|
|
4634
5697
|
if (sourcePath === destPath) {
|
|
4635
5698
|
return { changed: false, targetPath };
|
|
4636
5699
|
}
|
|
@@ -4657,7 +5720,7 @@ ${memory.content}
|
|
|
4657
5720
|
return { changed: true, targetPath };
|
|
4658
5721
|
}
|
|
4659
5722
|
get archiveDir() {
|
|
4660
|
-
return
|
|
5723
|
+
return path5.join(this.baseDir, "archive");
|
|
4661
5724
|
}
|
|
4662
5725
|
/**
|
|
4663
5726
|
* Archive a memory by moving it from facts/ to archive/YYYY-MM-DD/.
|
|
@@ -4668,7 +5731,7 @@ ${memory.content}
|
|
|
4668
5731
|
try {
|
|
4669
5732
|
const now = lifecycle?.at ?? /* @__PURE__ */ new Date();
|
|
4670
5733
|
const today = now.toISOString().slice(0, 10);
|
|
4671
|
-
const destDir =
|
|
5734
|
+
const destDir = path5.join(this.archiveDir, today);
|
|
4672
5735
|
await mkdir(destDir, { recursive: true });
|
|
4673
5736
|
const updatedFm = {
|
|
4674
5737
|
...memory.frontmatter,
|
|
@@ -4680,7 +5743,7 @@ ${memory.content}
|
|
|
4680
5743
|
|
|
4681
5744
|
${memory.content}
|
|
4682
5745
|
`;
|
|
4683
|
-
const destPath =
|
|
5746
|
+
const destPath = path5.join(destDir, path5.basename(memory.path));
|
|
4684
5747
|
await this.writeStorageSecureFile(destPath, fileContent);
|
|
4685
5748
|
await unlink2(memory.path);
|
|
4686
5749
|
markProjectedMemoryPathInvalid(this.baseDir, memory.frontmatter.id);
|
|
@@ -4830,7 +5893,7 @@ ${memory.content}
|
|
|
4830
5893
|
`;
|
|
4831
5894
|
await this.writeStorageSecureFile(memory.path, fileContent);
|
|
4832
5895
|
this.invalidateAllMemoriesCache();
|
|
4833
|
-
if (memory.path.includes(`${
|
|
5896
|
+
if (memory.path.includes(`${path5.sep}cold${path5.sep}`)) {
|
|
4834
5897
|
this.invalidateColdMemoriesCache();
|
|
4835
5898
|
}
|
|
4836
5899
|
try {
|
|
@@ -4903,7 +5966,7 @@ ${memory.content}
|
|
|
4903
5966
|
return deleted;
|
|
4904
5967
|
}
|
|
4905
5968
|
async loadBuffer() {
|
|
4906
|
-
const bufferPath =
|
|
5969
|
+
const bufferPath = path5.join(this.stateDir, "buffer.json");
|
|
4907
5970
|
try {
|
|
4908
5971
|
const raw = await this.readStorageSecureFile(bufferPath);
|
|
4909
5972
|
return JSON.parse(raw);
|
|
@@ -4915,11 +5978,11 @@ ${memory.content}
|
|
|
4915
5978
|
}
|
|
4916
5979
|
async saveBuffer(state) {
|
|
4917
5980
|
await this.ensureDirectories();
|
|
4918
|
-
const bufferPath =
|
|
5981
|
+
const bufferPath = path5.join(this.stateDir, "buffer.json");
|
|
4919
5982
|
await this.writeStorageSecureFile(bufferPath, JSON.stringify(state, null, 2));
|
|
4920
5983
|
}
|
|
4921
5984
|
async loadMeta() {
|
|
4922
|
-
const metaPath =
|
|
5985
|
+
const metaPath = path5.join(this.stateDir, "meta.json");
|
|
4923
5986
|
try {
|
|
4924
5987
|
const raw = await this.readStorageSecureFile(metaPath);
|
|
4925
5988
|
const parsed = JSON.parse(raw);
|
|
@@ -4953,7 +6016,7 @@ ${memory.content}
|
|
|
4953
6016
|
}
|
|
4954
6017
|
async saveMeta(state) {
|
|
4955
6018
|
await this.ensureDirectories();
|
|
4956
|
-
const metaPath =
|
|
6019
|
+
const metaPath = path5.join(this.stateDir, "meta.json");
|
|
4957
6020
|
await this.writeStorageSecureFile(metaPath, JSON.stringify(state, null, 2));
|
|
4958
6021
|
}
|
|
4959
6022
|
async appendMemoryActionEvents(events) {
|
|
@@ -5039,7 +6102,7 @@ ${memory.content}
|
|
|
5039
6102
|
async appendReextractJobs(events) {
|
|
5040
6103
|
if (events.length === 0) return 0;
|
|
5041
6104
|
await this.ensureDirectories();
|
|
5042
|
-
const filePath =
|
|
6105
|
+
const filePath = path5.join(this.stateDir, "reextract-jobs.jsonl");
|
|
5043
6106
|
const lines = events.map((event) => JSON.stringify(event)).join("\n") + "\n";
|
|
5044
6107
|
try {
|
|
5045
6108
|
await this.appendStorageSecureFile(filePath, lines);
|
|
@@ -5052,7 +6115,7 @@ ${memory.content}
|
|
|
5052
6115
|
}
|
|
5053
6116
|
async readReextractJobs(limit = 200) {
|
|
5054
6117
|
const safeLimit = Number.isFinite(limit) ? Math.max(1, Math.min(1e3, Math.floor(limit))) : 200;
|
|
5055
|
-
const filePath =
|
|
6118
|
+
const filePath = path5.join(this.stateDir, "reextract-jobs.jsonl");
|
|
5056
6119
|
try {
|
|
5057
6120
|
const raw = await this.readStorageSecureFile(filePath);
|
|
5058
6121
|
const lines = raw.split("\n").filter((line) => line.trim().length > 0);
|
|
@@ -5210,7 +6273,7 @@ ${memory.content}
|
|
|
5210
6273
|
return false;
|
|
5211
6274
|
}
|
|
5212
6275
|
if (draftState.contentHash) {
|
|
5213
|
-
const contentHash =
|
|
6276
|
+
const contentHash = createHash3("sha256").update(draftContent).digest("hex");
|
|
5214
6277
|
if (contentHash !== draftState.contentHash) return false;
|
|
5215
6278
|
}
|
|
5216
6279
|
await this.writeCompressionGuidelines(draftContent);
|
|
@@ -5290,7 +6353,7 @@ ${question}
|
|
|
5290
6353
|
|
|
5291
6354
|
**Context:** ${context}
|
|
5292
6355
|
`;
|
|
5293
|
-
const filePath =
|
|
6356
|
+
const filePath = path5.join(this.questionsDir, `${id}.md`);
|
|
5294
6357
|
await this.writeStorageSecureFile(filePath, content);
|
|
5295
6358
|
log.debug(`wrote question ${id} to ${filePath}`);
|
|
5296
6359
|
this.invalidateQuestionsCache();
|
|
@@ -5308,7 +6371,7 @@ ${question}
|
|
|
5308
6371
|
if (!match) return null;
|
|
5309
6372
|
const frontmatterStr = match[1];
|
|
5310
6373
|
const body = match[2].trim();
|
|
5311
|
-
const id = this.extractFrontmatterValue(frontmatterStr, "id") ??
|
|
6374
|
+
const id = this.extractFrontmatterValue(frontmatterStr, "id") ?? path5.basename(filePath, ".md");
|
|
5312
6375
|
const created = this.extractFrontmatterValue(frontmatterStr, "created") ?? "";
|
|
5313
6376
|
const priority = parseFloat(
|
|
5314
6377
|
this.extractFrontmatterValue(frontmatterStr, "priority") ?? "0.5"
|
|
@@ -5371,11 +6434,11 @@ ${question}
|
|
|
5371
6434
|
} catch {
|
|
5372
6435
|
}
|
|
5373
6436
|
const hygiene = opts?.hygiene;
|
|
5374
|
-
const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(
|
|
6437
|
+
const rotateEnabled = hygiene?.enabled === true && hygiene.rotateEnabled === true && Array.isArray(hygiene.rotatePaths) && hygiene.rotatePaths.includes(path5.basename(identityPath));
|
|
5375
6438
|
if (rotateEnabled) {
|
|
5376
6439
|
const maxBytes = hygiene.rotateMaxBytes;
|
|
5377
6440
|
if (existing.length > maxBytes) {
|
|
5378
|
-
const archiveDir =
|
|
6441
|
+
const archiveDir = path5.join(workspaceDir, hygiene.archiveDir);
|
|
5379
6442
|
const { newContent } = await rotateMarkdownFileToArchive({
|
|
5380
6443
|
filePath: identityPath,
|
|
5381
6444
|
archiveDir,
|
|
@@ -5469,7 +6532,7 @@ ${reflection}
|
|
|
5469
6532
|
* Deduplicates by target+label.
|
|
5470
6533
|
*/
|
|
5471
6534
|
async addEntityRelationship(name, rel) {
|
|
5472
|
-
const filePath =
|
|
6535
|
+
const filePath = path5.join(this.entitiesDir, `${name}.md`);
|
|
5473
6536
|
let entity;
|
|
5474
6537
|
try {
|
|
5475
6538
|
const content = await this.readStorageSecureFile(filePath);
|
|
@@ -5494,7 +6557,7 @@ ${reflection}
|
|
|
5494
6557
|
* Prepends to the beginning, prunes oldest entries beyond maxEntries.
|
|
5495
6558
|
*/
|
|
5496
6559
|
async addEntityActivity(name, entry, maxEntries) {
|
|
5497
|
-
const filePath =
|
|
6560
|
+
const filePath = path5.join(this.entitiesDir, `${name}.md`);
|
|
5498
6561
|
let entity;
|
|
5499
6562
|
try {
|
|
5500
6563
|
const content = await this.readStorageSecureFile(filePath);
|
|
@@ -5517,7 +6580,7 @@ ${reflection}
|
|
|
5517
6580
|
* Add an alias to an entity file. Deduplicates.
|
|
5518
6581
|
*/
|
|
5519
6582
|
async addEntityAlias(name, alias) {
|
|
5520
|
-
const filePath =
|
|
6583
|
+
const filePath = path5.join(this.entitiesDir, `${name}.md`);
|
|
5521
6584
|
let entity;
|
|
5522
6585
|
try {
|
|
5523
6586
|
const content = await this.readStorageSecureFile(filePath);
|
|
@@ -5548,7 +6611,7 @@ ${reflection}
|
|
|
5548
6611
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5549
6612
|
let synthesisTimelineCount;
|
|
5550
6613
|
try {
|
|
5551
|
-
const filePath =
|
|
6614
|
+
const filePath = path5.join(this.entitiesDir, `${name}.md`);
|
|
5552
6615
|
const content = await this.readStorageSecureFile(filePath);
|
|
5553
6616
|
synthesisTimelineCount = parseEntityFile(content, this.entitySchemas).timeline.length;
|
|
5554
6617
|
} catch (err) {
|
|
@@ -5631,7 +6694,7 @@ ${reflection}
|
|
|
5631
6694
|
if (!raw) continue;
|
|
5632
6695
|
const serialized = serializeEntityFile(parseEntityFile(raw, this.entitySchemas), this.entitySchemas);
|
|
5633
6696
|
if (raw.trimEnd() === serialized.trimEnd()) continue;
|
|
5634
|
-
await this.writeStorageSecureFile(
|
|
6697
|
+
await this.writeStorageSecureFile(path5.join(this.entitiesDir, `${entityName}.md`), serialized);
|
|
5635
6698
|
migrated += 1;
|
|
5636
6699
|
}
|
|
5637
6700
|
if (migrated > 0) {
|
|
@@ -5775,7 +6838,7 @@ ${memory.content}
|
|
|
5775
6838
|
const filePaths = await this.collectActiveMemoryPaths();
|
|
5776
6839
|
const foundIds = /* @__PURE__ */ new Set();
|
|
5777
6840
|
for (const filePath of filePaths) {
|
|
5778
|
-
const basename =
|
|
6841
|
+
const basename = path5.basename(filePath, ".md");
|
|
5779
6842
|
if (wantedIds.has(basename)) {
|
|
5780
6843
|
foundIds.add(basename);
|
|
5781
6844
|
if (foundIds.size === wantedIds.size) break;
|
|
@@ -5967,14 +7030,14 @@ Reason: ${reason}`, {
|
|
|
5967
7030
|
// Memory Summarization (Phase 4A)
|
|
5968
7031
|
// ---------------------------------------------------------------------------
|
|
5969
7032
|
get summariesDir() {
|
|
5970
|
-
return
|
|
7033
|
+
return path5.join(this.baseDir, "summaries");
|
|
5971
7034
|
}
|
|
5972
7035
|
/**
|
|
5973
7036
|
* Write a memory summary.
|
|
5974
7037
|
*/
|
|
5975
7038
|
async writeSummary(summary) {
|
|
5976
7039
|
await mkdir(this.summariesDir, { recursive: true });
|
|
5977
|
-
const filePath =
|
|
7040
|
+
const filePath = path5.join(this.summariesDir, `${summary.id}.json`);
|
|
5978
7041
|
await this.writeStorageSecureFile(filePath, JSON.stringify(summary, null, 2));
|
|
5979
7042
|
log.debug(`wrote summary ${summary.id}`);
|
|
5980
7043
|
}
|
|
@@ -5987,7 +7050,7 @@ Reason: ${reason}`, {
|
|
|
5987
7050
|
const summaries = [];
|
|
5988
7051
|
for (const file of files) {
|
|
5989
7052
|
if (!file.endsWith(".json")) continue;
|
|
5990
|
-
const filePath =
|
|
7053
|
+
const filePath = path5.join(this.summariesDir, file);
|
|
5991
7054
|
const raw = await this.readStorageSecureFile(filePath);
|
|
5992
7055
|
summaries.push(JSON.parse(raw));
|
|
5993
7056
|
}
|
|
@@ -6048,7 +7111,7 @@ ${memory.content}
|
|
|
6048
7111
|
* Save topic scores to meta.json.
|
|
6049
7112
|
*/
|
|
6050
7113
|
async saveTopics(topics) {
|
|
6051
|
-
const metaPath =
|
|
7114
|
+
const metaPath = path5.join(this.stateDir, "topics.json");
|
|
6052
7115
|
await mkdir(this.stateDir, { recursive: true });
|
|
6053
7116
|
await this.writeStorageSecureFile(metaPath, JSON.stringify({ topics, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
|
|
6054
7117
|
log.debug(`saved ${topics.length} topic scores`);
|
|
@@ -6057,7 +7120,7 @@ ${memory.content}
|
|
|
6057
7120
|
* Load topic scores from meta.json.
|
|
6058
7121
|
*/
|
|
6059
7122
|
async loadTopics() {
|
|
6060
|
-
const metaPath =
|
|
7123
|
+
const metaPath = path5.join(this.stateDir, "topics.json");
|
|
6061
7124
|
try {
|
|
6062
7125
|
const raw = await this.readStorageSecureFile(metaPath);
|
|
6063
7126
|
return JSON.parse(raw);
|
|
@@ -6136,6 +7199,19 @@ ${memory.content}
|
|
|
6136
7199
|
|
|
6137
7200
|
export {
|
|
6138
7201
|
selfDeps,
|
|
7202
|
+
DEFAULT_PROXIMITY_GAP_MS,
|
|
7203
|
+
clusterConversations,
|
|
7204
|
+
DEFAULT_WINDOW_TOLERANCE_MS,
|
|
7205
|
+
DEFAULT_SOURCE_TRUST,
|
|
7206
|
+
fusionInputsFromConversations,
|
|
7207
|
+
fuseCluster,
|
|
7208
|
+
fuseDay,
|
|
7209
|
+
FUSION_KIND,
|
|
7210
|
+
hashFusionBody,
|
|
7211
|
+
composeFusionDayMeta,
|
|
7212
|
+
serializeFusionDay,
|
|
7213
|
+
parseFusionDay,
|
|
7214
|
+
reconstructFusionInputs,
|
|
6139
7215
|
parseFrontmatterStringValue,
|
|
6140
7216
|
parseFrontmatter,
|
|
6141
7217
|
normalizeFrontmatterForPath,
|
|
@@ -6154,4 +7230,4 @@ export {
|
|
|
6154
7230
|
isValidBufferSurpriseEvent,
|
|
6155
7231
|
StorageManager3 as StorageManager
|
|
6156
7232
|
};
|
|
6157
|
-
//# sourceMappingURL=chunk-
|
|
7233
|
+
//# sourceMappingURL=chunk-SVOHGUMI.js.map
|