@remnic/core 9.66.8 → 9.66.10
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 +11 -11
- package/dist/access-admin-ops-surface.js +23 -23
- package/dist/access-authorization-probe.d.ts +11 -11
- package/dist/access-authorization-probe.js +24 -24
- package/dist/access-boundary.d.ts +11 -11
- package/dist/access-boundary.js +23 -23
- package/dist/access-cli.js +98 -97
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.d.ts +1 -1
- package/dist/access-extraction-force-flush.d.ts +11 -11
- package/dist/access-extraction-force-flush.js +23 -23
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +11 -11
- package/dist/access-http-lifecycle-flush.d.ts +11 -11
- package/dist/access-http-offline-stream.d.ts +11 -11
- package/dist/access-http-query.d.ts +2 -2
- package/dist/access-http-query.js +25 -25
- package/dist/access-http.d.ts +12 -12
- package/dist/access-http.js +41 -41
- package/dist/access-identity-continuity-surface.d.ts +9 -9
- package/dist/access-identity-continuity-surface.js +23 -23
- package/dist/access-lcm-surface.d.ts +11 -11
- package/dist/access-lcm-surface.js +23 -23
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +11 -11
- package/dist/access-mcp.js +33 -33
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-50VIkPhB.d.ts → access-namespace-preflight-S8fhQcCo.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +23 -23
- package/dist/access-observe-write-surface.d.ts +11 -11
- package/dist/access-observe-write-surface.js +23 -23
- package/dist/access-offline-manifest.d.ts +9 -9
- package/dist/access-operations-batch.js +26 -26
- package/dist/access-operations.d.ts +16 -16
- package/dist/access-operations.js +31 -31
- package/dist/access-recall-concurrency.d.ts +11 -11
- package/dist/access-recall-concurrency.js +23 -23
- package/dist/access-recall-response.d.ts +11 -11
- package/dist/access-recall-response.js +23 -23
- package/dist/access-recall-surface.d.ts +11 -11
- package/dist/access-recall-surface.js +23 -23
- package/dist/access-schema.d.ts +89 -89
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-C2tV2-uL.d.ts → access-service-DcfM0Vf0.d.ts} +71 -71
- package/dist/access-service-helpers.d.ts +11 -11
- package/dist/access-service.d.ts +11 -11
- package/dist/access-service.js +23 -23
- package/dist/access-surface-catalog.d.ts +11 -11
- package/dist/access-surface-catalog.js +25 -25
- package/dist/access-wearables-meetings-surface.d.ts +3 -3
- 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/ambient-provenance.d.ts +1 -1
- package/dist/artifact-search.d.ts +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +9 -9
- package/dist/briefing-window.d.ts +2 -2
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +10 -10
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-turn-helpers.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/buffer.js +4 -4
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{catalog-C2jA-gLm.d.ts → catalog-BmBXTtOs.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +11 -11
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-EKUABFXQ.js → chunk-245QROHZ.js} +6 -6
- package/dist/{chunk-UMZUKOJU.js → chunk-2L5FSNPC.js} +16 -11
- package/dist/chunk-2L5FSNPC.js.map +1 -0
- package/dist/{chunk-KH2LZMD5.js → chunk-2OXBS2LV.js} +2 -2
- package/dist/{chunk-K7NUAY36.js → chunk-4PHT7KE2.js} +5 -5
- package/dist/{chunk-AZLSFKGU.js → chunk-4PWANX5V.js} +6 -6
- package/dist/{chunk-5S6TQ36T.js → chunk-4QKWBVEE.js} +12 -12
- package/dist/{chunk-5S6TQ36T.js.map → chunk-4QKWBVEE.js.map} +1 -1
- package/dist/{chunk-GO657WPH.js → chunk-52I6AHO6.js} +2 -2
- package/dist/{chunk-MBXTGOFR.js → chunk-54BRW3BL.js} +2 -2
- package/dist/{chunk-LWI43S46.js → chunk-5E7KXID5.js} +1 -1
- package/dist/{chunk-MWLBRFLY.js → chunk-5KVMT25I.js} +2 -2
- package/dist/{chunk-KKGWB2LG.js → chunk-7BS5UVXA.js} +3 -3
- package/dist/{chunk-O2RJZR6J.js → chunk-7FLINMUE.js} +2 -2
- package/dist/{chunk-XORZMKVF.js → chunk-7MOYAT4Y.js} +3 -3
- package/dist/{chunk-AVYNKPFS.js → chunk-C6TMLF3A.js} +5 -5
- package/dist/{chunk-C24UZSFW.js → chunk-CEH2AFXG.js} +6 -6
- package/dist/{chunk-IE7N2YK6.js → chunk-CNZVEU4X.js} +2 -2
- package/dist/{chunk-FNK4KIYR.js → chunk-D3AUQXTJ.js} +2 -2
- package/dist/{chunk-BDGWA5GK.js → chunk-DJLH3XWM.js} +2 -2
- package/dist/{chunk-2V4YPDIX.js → chunk-E2PORO7O.js} +2 -2
- package/dist/{chunk-5IYJWCLC.js → chunk-E62M4H4M.js} +2 -2
- package/dist/{chunk-NEWY74GS.js → chunk-EG4FHU5C.js} +2 -2
- package/dist/{chunk-KMPEBHH5.js → chunk-EMAEDM2J.js} +2 -2
- package/dist/{chunk-2YDU4VR7.js → chunk-G3B3LP6A.js} +21 -21
- package/dist/{chunk-D6Q5EPOV.js → chunk-HCERYDRI.js} +2 -2
- package/dist/{chunk-6BYJQ3L2.js → chunk-HJQZQUPC.js} +11 -11
- package/dist/{chunk-S63O62DN.js → chunk-HPGXB56F.js} +2 -2
- package/dist/{chunk-KQAFEZQX.js → chunk-IPLYGWQF.js} +5 -5
- package/dist/{chunk-QK375NXZ.js → chunk-ISX7JODR.js} +2 -2
- package/dist/{chunk-RKNJBZ55.js → chunk-JBPKEARU.js} +4 -4
- package/dist/{chunk-RI4CMRTZ.js → chunk-JNZSNJ43.js} +2 -2
- package/dist/{chunk-IGOINKTD.js → chunk-K4E3Y3ZX.js} +2 -2
- package/dist/chunk-K4E3Y3ZX.js.map +1 -0
- package/dist/{chunk-GUG4LW4I.js → chunk-KIJCXLW7.js} +2 -2
- package/dist/{chunk-XDUQR5R7.js → chunk-KT3ERTF6.js} +2 -2
- package/dist/{chunk-2MYBDWUY.js → chunk-KWLDB64F.js} +2 -2
- package/dist/{chunk-UOQZOV2J.js → chunk-KWVXCRFZ.js} +225 -55
- package/dist/chunk-KWVXCRFZ.js.map +1 -0
- package/dist/chunk-LD72P4YS.js +29 -0
- package/dist/chunk-LD72P4YS.js.map +1 -0
- package/dist/{chunk-UMSTKKMV.js → chunk-LPSTQR26.js} +2 -2
- package/dist/{chunk-MFIFCXS3.js → chunk-LTWFU6VJ.js} +2 -2
- package/dist/{chunk-X32ALJQB.js → chunk-M2BY5IZL.js} +2 -2
- package/dist/{chunk-UJICQ77Y.js → chunk-MK7EJLB4.js} +2 -2
- package/dist/{chunk-7X63THIR.js → chunk-NR36NW24.js} +39 -39
- package/dist/{chunk-VYIPVLRX.js → chunk-QB66LBXA.js} +2 -2
- package/dist/{chunk-RPHCLGQ7.js → chunk-QKTGCL6M.js} +2 -2
- package/dist/{chunk-OMA2B7GY.js → chunk-RLEJULGN.js} +2 -2
- package/dist/chunk-S47XNAWD.js +202 -0
- package/dist/chunk-S47XNAWD.js.map +1 -0
- package/dist/{chunk-I2TIUGLC.js → chunk-SQEIPTDV.js} +2 -2
- package/dist/{chunk-NEDBOZ7G.js → chunk-TGKLVAML.js} +2 -2
- package/dist/{chunk-FY62KW6Q.js → chunk-TS37MXC7.js} +2 -2
- package/dist/{chunk-XUKS57W7.js → chunk-TXCLDIXJ.js} +2 -2
- package/dist/{chunk-YSYHSZWD.js → chunk-VSQG4AXL.js} +2 -2
- package/dist/{chunk-46XR5FNZ.js → chunk-VSWRJQQW.js} +31 -5
- package/dist/chunk-VSWRJQQW.js.map +1 -0
- package/dist/{chunk-ULTK4NZY.js → chunk-WD424KYT.js} +2 -2
- package/dist/{chunk-OERZXNSK.js → chunk-X5SDZMO7.js} +2 -2
- package/dist/{chunk-XSPVSEAN.js → chunk-XN33JLRF.js} +3 -3
- package/dist/{chunk-6ULLVM2V.js → chunk-Y2ECPAJI.js} +8 -8
- package/dist/{chunk-5UP5R37C.js → chunk-Y6KDJQLK.js} +7 -7
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{chunk-6ZRLH4VS.js → chunk-YYDOUOYM.js} +3 -3
- package/dist/{chunk-XVCYV7WQ.js → chunk-ZIGSNLYI.js} +3 -3
- package/dist/{chunk-FI6FT6YX.js → chunk-ZPZLGN4Y.js} +2 -2
- package/dist/{chunk-SVATDJNY.js → chunk-ZRQPX2DW.js} +2 -2
- package/dist/{cli-CsfFMe6n.d.ts → cli-CFpMhqz5.d.ts} +5 -5
- package/dist/cli.d.ts +13 -13
- package/dist/cli.js +67 -67
- package/dist/coding/export-okf-codegraph.d.ts +1 -1
- package/dist/coding/export-okf-codegraph.js +10 -10
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +10 -10
- 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 +10 -10
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +10 -10
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/contradiction/index.d.ts +3 -3
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +12 -12
- package/dist/conversation-index/backend.d.ts +1 -1
- 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/corpus-watermark.d.ts +1 -1
- package/dist/corpus-watermark.js +12 -12
- package/dist/cross-lingual-recall.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/dependency-propagation-config.d.ts +1 -1
- package/dist/{dependency-propagation-delivery-D4WMbOwA.d.ts → dependency-propagation-delivery-BC3bCEet.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-origin-fields.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +10 -10
- package/dist/entity-schema.d.ts +1 -1
- package/dist/episodic-context.d.ts +1 -1
- package/dist/eval-trajectory-contracts.d.ts +1 -1
- package/dist/eval-trajectory-store.d.ts +1 -1
- package/dist/eval-trajectory.d.ts +1 -1
- package/dist/explicit-capture.d.ts +9 -9
- package/dist/external-wiki-access.d.ts +11 -11
- package/dist/external-wiki-access.js +24 -24
- package/dist/external-wiki-collection-registration.d.ts +1 -1
- package/dist/external-wiki-collection.d.ts +1 -1
- package/dist/external-wiki-mcp-tools.d.ts +11 -11
- package/dist/extraction-error-classification.d.ts +1 -1
- 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-liveness.d.ts +1 -1
- package/dist/extraction-normalization.d.ts +1 -1
- package/dist/extraction-prompt.d.ts +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts +1 -1
- package/dist/extraction-span-tokens.d.ts +16 -0
- package/dist/extraction-span-tokens.js +34 -0
- package/dist/extraction-span-tokens.js.map +1 -0
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +13 -13
- package/dist/fallback-llm.d.ts +1 -1
- 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-path-reconstruction.d.ts +1 -1
- package/dist/graph-path-scoring.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/{index-DuJnzwHv.d.ts → index-D4hS9uxK.d.ts} +2 -2
- package/dist/index.d.ts +820 -700
- package/dist/index.js +144 -133
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +5 -4
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +13 -12
- 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/location/index.d.ts +3 -3
- package/dist/location/index.js +12 -12
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +10 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +11 -11
- package/dist/{maintenance-BBeaeYRR.d.ts → maintenance-BRcc3Hx8.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +11 -11
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-controller.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-snapshot.d.ts +1 -1
- package/dist/memory-subject-cli.d.ts +11 -11
- package/dist/memory-subject.d.ts +11 -11
- 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 +11 -11
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +7 -7
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +10 -10
- package/dist/native-binding-hint.d.ts +24 -0
- package/dist/native-binding-hint.js +10 -0
- package/dist/native-binding-hint.js.map +1 -0
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +13 -13
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +20 -20
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +19 -19
- package/dist/{orchestrator-CaqnwNwM.d.ts → orchestrator-Btq9lzAN.d.ts} +8 -8
- package/dist/orchestrator.d.ts +9 -9
- package/dist/orchestrator.js +99 -98
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-CrxVjlJr.d.ts → pipeline-CZoNdFb5.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{public-http-Cwvl4QZr.d.ts → public-http-C9-CHc40.d.ts} +1 -1
- package/dist/{qmd-BZgbJm0g.d.ts → qmd-VIjSCKIE.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/qmd.js +4 -4
- package/dist/recall-concurrency-config.d.ts +1 -1
- package/dist/recall-deep-frontier.d.ts +15 -0
- package/dist/recall-deep-frontier.js +29 -0
- package/dist/recall-deep-frontier.js.map +1 -0
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-memory-map.d.ts +1 -1
- package/dist/recall-navigate-access.d.ts +1 -1
- package/dist/recall-navigate.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/reconcile/cursor.d.ts +1 -1
- package/dist/reconcile/manifest.d.ts +1 -1
- package/dist/reconcile/plan.d.ts +1 -1
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/replica-divergence.d.ts +1 -1
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +3 -3
- 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/salvage-envelope.d.ts +1 -1
- package/dist/schemas.d.ts +176 -176
- package/dist/{scope-profiles-DFaojvoP.d.ts → scope-profiles-DqbxQXIS.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +6 -6
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +12 -12
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-BiX68wZA.d.ts → semantic-consolidation-DW3rEUoW.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 +10 -10
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +10 -10
- package/dist/{service-D5h2zZ0M.d.ts → service-B2vJU_Bx.d.ts} +2 -2
- 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 +7 -7
- package/dist/signal.d.ts +1 -1
- package/dist/source-agent-qualifier.d.ts +1 -1
- package/dist/source-agent-qualifier.js +12 -12
- package/dist/standup/build.d.ts +9 -3
- package/dist/standup/build.js +99 -7
- package/dist/{storage-CtsaojWD.d.ts → storage-6fn7BPmb.d.ts} +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +9 -9
- package/dist/subject-config.d.ts +1 -1
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/support-passport/index.d.ts +14 -14
- package/dist/support-passport/index.js +26 -26
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-timeline-recall.d.ts +1 -1
- 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/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/autodetect.js +1 -1
- package/dist/transfer/backup.js +1 -1
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/export-okf.d.ts +1 -1
- package/dist/transfer/export-okf.js +11 -11
- package/dist/transfer/types.d.ts +78 -78
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-CIpfYz1I.d.ts → types-eM7QIcX2.d.ts} +4 -0
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +10 -10
- package/dist/who-knows-cli.d.ts +11 -11
- package/dist/who-knows-cli.js +11 -11
- package/dist/who-knows.d.ts +11 -11
- package/dist/who-knows.js +10 -10
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +2 -2
- package/scripts/ensure-better-sqlite3.mjs +10 -0
- package/src/access-mcp-output-schemas.ts +1 -1
- package/src/activity/config.test.ts +1 -1
- package/src/activity/config.ts +20 -4
- package/src/activity/index.ts +2 -0
- package/src/activity/journal.test.ts +40 -0
- package/src/activity/privacy-status.test.ts +117 -0
- package/src/activity/privacy-status.ts +65 -0
- package/src/activity/timeline/index.ts +2 -0
- package/src/activity/timeline/recap-window.test.ts +129 -0
- package/src/activity/timeline/recap-window.ts +55 -0
- package/src/activity/timeline/week-previous.test.ts +119 -0
- package/src/activity/timeline/week-previous.ts +83 -0
- package/src/activity/types.ts +4 -0
- package/src/activity/vault-insert.test.ts +105 -0
- package/src/activity/vault-insert.ts +86 -0
- package/src/config.test.ts +1 -1
- package/src/dedup/index.ts +7 -0
- package/src/dedup/merge-decision.test.ts +157 -0
- package/src/dedup/merge-decision.ts +78 -0
- package/src/extraction-span-tokens.test.ts +69 -0
- package/src/extraction-span-tokens.ts +44 -0
- package/src/lcm/engine.ts +4 -1
- package/src/native-binding-hint.test.ts +38 -0
- package/src/native-binding-hint.ts +51 -0
- package/src/recall-deep-frontier.test.ts +85 -0
- package/src/recall-deep-frontier.ts +39 -0
- package/src/standup/build.test.ts +138 -12
- package/src/standup/build.ts +172 -23
- package/src/standup/http-glue.ts +1 -1
- package/dist/chunk-46XR5FNZ.js.map +0 -1
- package/dist/chunk-IGOINKTD.js.map +0 -1
- package/dist/chunk-UMZUKOJU.js.map +0 -1
- package/dist/chunk-UOQZOV2J.js.map +0 -1
- package/dist/chunk-VOSWUO3K.js +0 -100
- package/dist/chunk-VOSWUO3K.js.map +0 -1
- /package/dist/{chunk-EKUABFXQ.js.map → chunk-245QROHZ.js.map} +0 -0
- /package/dist/{chunk-KH2LZMD5.js.map → chunk-2OXBS2LV.js.map} +0 -0
- /package/dist/{chunk-K7NUAY36.js.map → chunk-4PHT7KE2.js.map} +0 -0
- /package/dist/{chunk-AZLSFKGU.js.map → chunk-4PWANX5V.js.map} +0 -0
- /package/dist/{chunk-GO657WPH.js.map → chunk-52I6AHO6.js.map} +0 -0
- /package/dist/{chunk-MBXTGOFR.js.map → chunk-54BRW3BL.js.map} +0 -0
- /package/dist/{chunk-LWI43S46.js.map → chunk-5E7KXID5.js.map} +0 -0
- /package/dist/{chunk-MWLBRFLY.js.map → chunk-5KVMT25I.js.map} +0 -0
- /package/dist/{chunk-KKGWB2LG.js.map → chunk-7BS5UVXA.js.map} +0 -0
- /package/dist/{chunk-O2RJZR6J.js.map → chunk-7FLINMUE.js.map} +0 -0
- /package/dist/{chunk-XORZMKVF.js.map → chunk-7MOYAT4Y.js.map} +0 -0
- /package/dist/{chunk-AVYNKPFS.js.map → chunk-C6TMLF3A.js.map} +0 -0
- /package/dist/{chunk-C24UZSFW.js.map → chunk-CEH2AFXG.js.map} +0 -0
- /package/dist/{chunk-IE7N2YK6.js.map → chunk-CNZVEU4X.js.map} +0 -0
- /package/dist/{chunk-FNK4KIYR.js.map → chunk-D3AUQXTJ.js.map} +0 -0
- /package/dist/{chunk-BDGWA5GK.js.map → chunk-DJLH3XWM.js.map} +0 -0
- /package/dist/{chunk-2V4YPDIX.js.map → chunk-E2PORO7O.js.map} +0 -0
- /package/dist/{chunk-5IYJWCLC.js.map → chunk-E62M4H4M.js.map} +0 -0
- /package/dist/{chunk-NEWY74GS.js.map → chunk-EG4FHU5C.js.map} +0 -0
- /package/dist/{chunk-KMPEBHH5.js.map → chunk-EMAEDM2J.js.map} +0 -0
- /package/dist/{chunk-2YDU4VR7.js.map → chunk-G3B3LP6A.js.map} +0 -0
- /package/dist/{chunk-D6Q5EPOV.js.map → chunk-HCERYDRI.js.map} +0 -0
- /package/dist/{chunk-6BYJQ3L2.js.map → chunk-HJQZQUPC.js.map} +0 -0
- /package/dist/{chunk-S63O62DN.js.map → chunk-HPGXB56F.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-IPLYGWQF.js.map} +0 -0
- /package/dist/{chunk-QK375NXZ.js.map → chunk-ISX7JODR.js.map} +0 -0
- /package/dist/{chunk-RKNJBZ55.js.map → chunk-JBPKEARU.js.map} +0 -0
- /package/dist/{chunk-RI4CMRTZ.js.map → chunk-JNZSNJ43.js.map} +0 -0
- /package/dist/{chunk-GUG4LW4I.js.map → chunk-KIJCXLW7.js.map} +0 -0
- /package/dist/{chunk-XDUQR5R7.js.map → chunk-KT3ERTF6.js.map} +0 -0
- /package/dist/{chunk-2MYBDWUY.js.map → chunk-KWLDB64F.js.map} +0 -0
- /package/dist/{chunk-UMSTKKMV.js.map → chunk-LPSTQR26.js.map} +0 -0
- /package/dist/{chunk-MFIFCXS3.js.map → chunk-LTWFU6VJ.js.map} +0 -0
- /package/dist/{chunk-X32ALJQB.js.map → chunk-M2BY5IZL.js.map} +0 -0
- /package/dist/{chunk-UJICQ77Y.js.map → chunk-MK7EJLB4.js.map} +0 -0
- /package/dist/{chunk-7X63THIR.js.map → chunk-NR36NW24.js.map} +0 -0
- /package/dist/{chunk-VYIPVLRX.js.map → chunk-QB66LBXA.js.map} +0 -0
- /package/dist/{chunk-RPHCLGQ7.js.map → chunk-QKTGCL6M.js.map} +0 -0
- /package/dist/{chunk-OMA2B7GY.js.map → chunk-RLEJULGN.js.map} +0 -0
- /package/dist/{chunk-I2TIUGLC.js.map → chunk-SQEIPTDV.js.map} +0 -0
- /package/dist/{chunk-NEDBOZ7G.js.map → chunk-TGKLVAML.js.map} +0 -0
- /package/dist/{chunk-FY62KW6Q.js.map → chunk-TS37MXC7.js.map} +0 -0
- /package/dist/{chunk-XUKS57W7.js.map → chunk-TXCLDIXJ.js.map} +0 -0
- /package/dist/{chunk-YSYHSZWD.js.map → chunk-VSQG4AXL.js.map} +0 -0
- /package/dist/{chunk-ULTK4NZY.js.map → chunk-WD424KYT.js.map} +0 -0
- /package/dist/{chunk-OERZXNSK.js.map → chunk-X5SDZMO7.js.map} +0 -0
- /package/dist/{chunk-XSPVSEAN.js.map → chunk-XN33JLRF.js.map} +0 -0
- /package/dist/{chunk-6ULLVM2V.js.map → chunk-Y2ECPAJI.js.map} +0 -0
- /package/dist/{chunk-5UP5R37C.js.map → chunk-Y6KDJQLK.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{chunk-6ZRLH4VS.js.map → chunk-YYDOUOYM.js.map} +0 -0
- /package/dist/{chunk-XVCYV7WQ.js.map → chunk-ZIGSNLYI.js.map} +0 -0
- /package/dist/{chunk-FI6FT6YX.js.map → chunk-ZPZLGN4Y.js.map} +0 -0
- /package/dist/{chunk-SVATDJNY.js.map → chunk-ZRQPX2DW.js.map} +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic half-open recap window clip (issue #2051).
|
|
3
|
+
*
|
|
4
|
+
* Clips cards to [windowStartMs, windowEndMs) so recap renderers share one
|
|
5
|
+
* day-boundary derivation instead of re-deriving it per renderer.
|
|
6
|
+
*/
|
|
7
|
+
export interface RecapWindowCard {
|
|
8
|
+
id: string;
|
|
9
|
+
startUtc: string;
|
|
10
|
+
endUtc: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ClippedRecapCard {
|
|
14
|
+
id: string;
|
|
15
|
+
startMs: number;
|
|
16
|
+
endMs: number;
|
|
17
|
+
durationMs: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function clipCardsToRecapWindow(
|
|
21
|
+
cards: readonly RecapWindowCard[],
|
|
22
|
+
windowStartMs: number,
|
|
23
|
+
windowEndMs: number,
|
|
24
|
+
): ClippedRecapCard[] {
|
|
25
|
+
// NaN fails every comparison, so an unchecked non-finite bound slips past the
|
|
26
|
+
// ordering guard and emits NaN timestamps and durations — `durationMs <= 0`
|
|
27
|
+
// is also false for NaN, so the card is not even dropped.
|
|
28
|
+
if (!Number.isFinite(windowStartMs) || !Number.isFinite(windowEndMs)) {
|
|
29
|
+
throw new RangeError(
|
|
30
|
+
`recap window bounds must be finite; got start ${windowStartMs} and end ${windowEndMs}`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
if (windowEndMs <= windowStartMs) {
|
|
34
|
+
throw new RangeError(
|
|
35
|
+
`recap window end ${windowEndMs} must be greater than start ${windowStartMs}`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
const out: ClippedRecapCard[] = [];
|
|
39
|
+
for (const card of cards) {
|
|
40
|
+
const startMs = Date.parse(card.startUtc);
|
|
41
|
+
const endMs = Date.parse(card.endUtc);
|
|
42
|
+
if (!Number.isFinite(startMs) || !Number.isFinite(endMs)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const clippedStart = Math.max(startMs, windowStartMs);
|
|
46
|
+
const clippedEnd = Math.min(endMs, windowEndMs);
|
|
47
|
+
const durationMs = clippedEnd - clippedStart;
|
|
48
|
+
if (durationMs <= 0) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
out.push({ id: card.id, startMs: clippedStart, endMs: clippedEnd, durationMs });
|
|
52
|
+
}
|
|
53
|
+
out.sort((a, b) => a.startMs - b.startMs || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import { compareWeeklyPreviousPeriod } from "./week-previous.js";
|
|
5
|
+
|
|
6
|
+
const CURRENT = {
|
|
7
|
+
activeMs: 3_600_000,
|
|
8
|
+
idleMs: 600_000,
|
|
9
|
+
pauseMs: 120_000,
|
|
10
|
+
gapMs: 300_000,
|
|
11
|
+
unclassifiedMs: 60_000,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const PREVIOUS = {
|
|
15
|
+
activeMs: 1_800_000,
|
|
16
|
+
idleMs: 900_000,
|
|
17
|
+
pauseMs: 120_000,
|
|
18
|
+
gapMs: 100_000,
|
|
19
|
+
unclassifiedMs: 0,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
test("null previous is unavailable, not zero", () => {
|
|
23
|
+
const result = compareWeeklyPreviousPeriod({
|
|
24
|
+
previous: null,
|
|
25
|
+
current: CURRENT,
|
|
26
|
+
previousStartUtc: "2026-07-06T00:00:00Z",
|
|
27
|
+
previousEndUtc: "2026-07-13T00:00:00Z",
|
|
28
|
+
});
|
|
29
|
+
assert.deepEqual(result, { available: false });
|
|
30
|
+
assert.equal("deltaActiveMs" in result, false);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("undefined previous is unavailable", () => {
|
|
34
|
+
const result = compareWeeklyPreviousPeriod({
|
|
35
|
+
previous: undefined,
|
|
36
|
+
current: CURRENT,
|
|
37
|
+
});
|
|
38
|
+
assert.deepEqual(result, { available: false });
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("previous without timestamps is unavailable", () => {
|
|
42
|
+
const result = compareWeeklyPreviousPeriod({ previous: PREVIOUS, current: CURRENT });
|
|
43
|
+
assert.deepEqual(result, { available: false });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("previous with blank timestamps is unavailable", () => {
|
|
47
|
+
const result = compareWeeklyPreviousPeriod({
|
|
48
|
+
previous: PREVIOUS,
|
|
49
|
+
current: CURRENT,
|
|
50
|
+
previousStartUtc: " ",
|
|
51
|
+
previousEndUtc: "\t",
|
|
52
|
+
});
|
|
53
|
+
assert.deepEqual(result, { available: false });
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("mixed deltas keep sign and trim timestamps", () => {
|
|
57
|
+
const result = compareWeeklyPreviousPeriod({
|
|
58
|
+
previous: PREVIOUS,
|
|
59
|
+
current: CURRENT,
|
|
60
|
+
previousStartUtc: " 2026-07-06T00:00:00Z ",
|
|
61
|
+
previousEndUtc: " 2026-07-13T00:00:00Z ",
|
|
62
|
+
});
|
|
63
|
+
assert.equal(result.available, true);
|
|
64
|
+
if (!result.available) return;
|
|
65
|
+
assert.equal(result.previousStartUtc, "2026-07-06T00:00:00Z");
|
|
66
|
+
assert.equal(result.previousEndUtc, "2026-07-13T00:00:00Z");
|
|
67
|
+
assert.equal(result.deltaActiveMs, 1_800_000);
|
|
68
|
+
assert.equal(result.deltaIdleMs, -300_000);
|
|
69
|
+
assert.equal(result.deltaPauseMs, 0);
|
|
70
|
+
assert.equal(result.deltaGapMs, 200_000);
|
|
71
|
+
assert.equal(result.deltaUnclassifiedMs, 60_000);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("NaN duration on previous throws TypeError", () => {
|
|
75
|
+
assert.throws(
|
|
76
|
+
() =>
|
|
77
|
+
compareWeeklyPreviousPeriod({
|
|
78
|
+
previous: { ...PREVIOUS, gapMs: Number.NaN },
|
|
79
|
+
current: CURRENT,
|
|
80
|
+
previousStartUtc: "2026-07-06T00:00:00Z",
|
|
81
|
+
previousEndUtc: "2026-07-13T00:00:00Z",
|
|
82
|
+
}),
|
|
83
|
+
TypeError,
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("Infinity duration on current throws TypeError", () => {
|
|
88
|
+
assert.throws(
|
|
89
|
+
() =>
|
|
90
|
+
compareWeeklyPreviousPeriod({
|
|
91
|
+
previous: PREVIOUS,
|
|
92
|
+
current: { ...CURRENT, activeMs: Number.POSITIVE_INFINITY },
|
|
93
|
+
}),
|
|
94
|
+
/current\.activeMs/,
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("all-zero current with present previous is available with negative deltas", () => {
|
|
99
|
+
const zeros = {
|
|
100
|
+
activeMs: 0,
|
|
101
|
+
idleMs: 0,
|
|
102
|
+
pauseMs: 0,
|
|
103
|
+
gapMs: 0,
|
|
104
|
+
unclassifiedMs: 0,
|
|
105
|
+
};
|
|
106
|
+
const result = compareWeeklyPreviousPeriod({
|
|
107
|
+
previous: PREVIOUS,
|
|
108
|
+
current: zeros,
|
|
109
|
+
previousStartUtc: "2026-07-06T00:00:00Z",
|
|
110
|
+
previousEndUtc: "2026-07-13T00:00:00Z",
|
|
111
|
+
});
|
|
112
|
+
assert.equal(result.available, true);
|
|
113
|
+
if (!result.available) return;
|
|
114
|
+
assert.equal(result.deltaActiveMs, -PREVIOUS.activeMs);
|
|
115
|
+
assert.equal(result.deltaIdleMs, -PREVIOUS.idleMs);
|
|
116
|
+
assert.equal(result.deltaPauseMs, -PREVIOUS.pauseMs);
|
|
117
|
+
assert.equal(result.deltaGapMs, -PREVIOUS.gapMs);
|
|
118
|
+
assert.equal(result.deltaUnclassifiedMs, 0);
|
|
119
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Previous-week duration comparison (issue #2052).
|
|
3
|
+
*
|
|
4
|
+
* The prior week is explicit when unavailable. It is never silently treated
|
|
5
|
+
* as zero.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface WeeklyDurationTotals {
|
|
9
|
+
activeMs: number;
|
|
10
|
+
idleMs: number;
|
|
11
|
+
pauseMs: number;
|
|
12
|
+
gapMs: number;
|
|
13
|
+
unclassifiedMs: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type WeeklyPreviousPeriod =
|
|
17
|
+
| { available: false }
|
|
18
|
+
| {
|
|
19
|
+
available: true;
|
|
20
|
+
previousStartUtc: string;
|
|
21
|
+
previousEndUtc: string;
|
|
22
|
+
deltaActiveMs: number;
|
|
23
|
+
deltaIdleMs: number;
|
|
24
|
+
deltaPauseMs: number;
|
|
25
|
+
deltaGapMs: number;
|
|
26
|
+
deltaUnclassifiedMs: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const DURATION_FIELDS = [
|
|
30
|
+
"activeMs",
|
|
31
|
+
"idleMs",
|
|
32
|
+
"pauseMs",
|
|
33
|
+
"gapMs",
|
|
34
|
+
"unclassifiedMs",
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
function assertFiniteTotals(totals: WeeklyDurationTotals, label: string): void {
|
|
38
|
+
for (const field of DURATION_FIELDS) {
|
|
39
|
+
const value = totals[field];
|
|
40
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
41
|
+
throw new TypeError(`${label}.${field} must be a finite number; got ${String(value)}.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Compare this week's duration totals against the previous week's.
|
|
48
|
+
*
|
|
49
|
+
* `previous` absent (null/undefined) or lacking trimmed start/end timestamps
|
|
50
|
+
* returns `{ available: false }` — never zero deltas. Otherwise returns the
|
|
51
|
+
* per-field deltas (`current - previous`, may be negative). Pure.
|
|
52
|
+
*/
|
|
53
|
+
export function compareWeeklyPreviousPeriod(input: {
|
|
54
|
+
previous: WeeklyDurationTotals | null | undefined;
|
|
55
|
+
current: WeeklyDurationTotals;
|
|
56
|
+
previousStartUtc?: string;
|
|
57
|
+
previousEndUtc?: string;
|
|
58
|
+
}): WeeklyPreviousPeriod {
|
|
59
|
+
const { previous, current, previousStartUtc, previousEndUtc } = input;
|
|
60
|
+
assertFiniteTotals(current, "current");
|
|
61
|
+
|
|
62
|
+
if (previous === null || previous === undefined) {
|
|
63
|
+
return { available: false };
|
|
64
|
+
}
|
|
65
|
+
assertFiniteTotals(previous, "previous");
|
|
66
|
+
|
|
67
|
+
const start = previousStartUtc?.trim() ?? "";
|
|
68
|
+
const end = previousEndUtc?.trim() ?? "";
|
|
69
|
+
if (start === "" || end === "") {
|
|
70
|
+
return { available: false };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
available: true,
|
|
75
|
+
previousStartUtc: start,
|
|
76
|
+
previousEndUtc: end,
|
|
77
|
+
deltaActiveMs: current.activeMs - previous.activeMs,
|
|
78
|
+
deltaIdleMs: current.idleMs - previous.idleMs,
|
|
79
|
+
deltaPauseMs: current.pauseMs - previous.pauseMs,
|
|
80
|
+
deltaGapMs: current.gapMs - previous.gapMs,
|
|
81
|
+
deltaUnclassifiedMs: current.unclassifiedMs - previous.unclassifiedMs,
|
|
82
|
+
};
|
|
83
|
+
}
|
package/src/activity/types.ts
CHANGED
|
@@ -99,6 +99,10 @@ export interface ActivitySourceConfig {
|
|
|
99
99
|
/** Opt-in daily journal settings (issue #1984). Default off. */
|
|
100
100
|
export interface ActivityTimelineJournalConfig {
|
|
101
101
|
enabled: boolean;
|
|
102
|
+
/** Where the journal text is read from (issue #1987). */
|
|
103
|
+
source: "file" | "vault";
|
|
104
|
+
/** Vault section heading, trimmed. Required when `source` is `"vault"`; not stored in `"file"` mode. */
|
|
105
|
+
heading?: string;
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
/** Opt-in timeline Q&A range/search settings (issue #1983 PR1). Default off. */
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import { insertMarkersUnderHeading } from "./vault-insert.js";
|
|
5
|
+
|
|
6
|
+
const START = "<!-- remnic:daily:start -->";
|
|
7
|
+
const END = "<!-- remnic:daily:end -->";
|
|
8
|
+
|
|
9
|
+
test("inserts markers under a unique heading before existing body", () => {
|
|
10
|
+
const fileText = ["# Notes", "", "## Journal", "", "Existing entry.", ""].join("\n");
|
|
11
|
+
const result = insertMarkersUnderHeading(fileText, {
|
|
12
|
+
heading: "Journal",
|
|
13
|
+
name: "daily",
|
|
14
|
+
content: "Line one.\nLine two.",
|
|
15
|
+
});
|
|
16
|
+
assert.ok(result.ok && result.inserted);
|
|
17
|
+
assert.equal(
|
|
18
|
+
result.text,
|
|
19
|
+
["# Notes", "", "## Journal", START, "Line one.", "Line two.", END, "", "Existing entry.", ""].join("\n"),
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("returns text unchanged when both markers already exist", () => {
|
|
24
|
+
const fileText = ["## Journal", START, "old", END, "tail", ""].join("\n");
|
|
25
|
+
const result = insertMarkersUnderHeading(fileText, { heading: "Journal", name: "daily", content: "new" });
|
|
26
|
+
assert.deepEqual(result, { ok: true, text: fileText, inserted: false });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("fails with no_heading when no heading matches exactly", () => {
|
|
30
|
+
const fileText = ["## Journal entry", "body", ""].join("\n");
|
|
31
|
+
const result = insertMarkersUnderHeading(fileText, { heading: "Journal", name: "daily", content: "new" });
|
|
32
|
+
assert.deepEqual(result, { ok: false, reason: "no_heading", text: fileText });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("fails with duplicate_heading and both 1-based line numbers", () => {
|
|
36
|
+
const fileText = ["# Top", "## Journal", "a", "## Journal", "b", ""].join("\n");
|
|
37
|
+
const result = insertMarkersUnderHeading(fileText, { heading: "Journal", name: "daily", content: "new" });
|
|
38
|
+
assert.ok(!result.ok && result.reason === "duplicate_heading");
|
|
39
|
+
assert.deepEqual(result.lines, [2, 4]);
|
|
40
|
+
assert.equal(result.text, fileText);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("inserts before a later same-level heading and leaves that section intact", () => {
|
|
44
|
+
const fileText = ["## Journal", "existing", "## Other", "other body", ""].join("\n");
|
|
45
|
+
const result = insertMarkersUnderHeading(fileText, { heading: "Journal", name: "daily", content: "cards" });
|
|
46
|
+
assert.ok(result.ok && result.inserted);
|
|
47
|
+
assert.equal(
|
|
48
|
+
result.text,
|
|
49
|
+
["## Journal", START, "cards", END, "existing", "## Other", "other body", ""].join("\n"),
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("deeper headings do not end the section", () => {
|
|
54
|
+
const fileText = ["## Journal", "### Nested", "nested body", "## Other", ""].join("\n");
|
|
55
|
+
const result = insertMarkersUnderHeading(fileText, { heading: "Journal", name: "daily", content: "cards" });
|
|
56
|
+
assert.ok(result.ok && result.inserted);
|
|
57
|
+
assert.equal(
|
|
58
|
+
result.text,
|
|
59
|
+
["## Journal", START, "cards", END, "### Nested", "nested body", "## Other", ""].join("\n"),
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("inserts under a heading at EOF without trailing newline", () => {
|
|
64
|
+
const result = insertMarkersUnderHeading("## Journal", { heading: "Journal", name: "daily", content: "cards" });
|
|
65
|
+
assert.ok(result.ok && result.inserted);
|
|
66
|
+
assert.equal(result.text, `## Journal\n${START}\ncards\n${END}\n`);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("keeps content ending in a newline without doubling it", () => {
|
|
70
|
+
const result = insertMarkersUnderHeading("## Journal\nbody\n", {
|
|
71
|
+
heading: "Journal",
|
|
72
|
+
name: "daily",
|
|
73
|
+
content: "cards\n",
|
|
74
|
+
});
|
|
75
|
+
assert.ok(result.ok && result.inserted);
|
|
76
|
+
assert.equal(result.text, `## Journal\n${START}\ncards\n${END}\nbody\n`);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("empty content inserts adjacent markers", () => {
|
|
80
|
+
const result = insertMarkersUnderHeading("## Journal\n", { heading: "Journal", name: "daily", content: "" });
|
|
81
|
+
assert.ok(result.ok && result.inserted);
|
|
82
|
+
assert.equal(result.text, `## Journal\n${START}\n${END}\n`);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("preserves CRLF as the dominant EOL", () => {
|
|
86
|
+
const fileText = ["## Journal", "body", ""].join("\r\n");
|
|
87
|
+
const result = insertMarkersUnderHeading(fileText, {
|
|
88
|
+
heading: "Journal",
|
|
89
|
+
name: "daily",
|
|
90
|
+
content: "line a\r\nline b",
|
|
91
|
+
});
|
|
92
|
+
assert.ok(result.ok && result.inserted);
|
|
93
|
+
assert.equal(result.text, `## Journal\r\n${START}\r\nline a\r\nline b\r\n${END}\r\nbody\r\n`);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("empty heading or name throws RangeError", () => {
|
|
97
|
+
assert.throws(
|
|
98
|
+
() => insertMarkersUnderHeading("## Journal\n", { heading: "", name: "daily", content: "" }),
|
|
99
|
+
(err) => err instanceof RangeError && /empty/i.test(err.message),
|
|
100
|
+
);
|
|
101
|
+
assert.throws(
|
|
102
|
+
() => insertMarkersUnderHeading("## Journal\n", { heading: "Journal", name: "", content: "" }),
|
|
103
|
+
(err) => err instanceof RangeError && /empty/i.test(err.message),
|
|
104
|
+
);
|
|
105
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed-region marker insertion (issue #1985).
|
|
3
|
+
*
|
|
4
|
+
* Inserts a `<!-- remnic:<name>:start/end -->` pair under a unique ATX
|
|
5
|
+
* heading when the region is absent. This helper never replaces (see
|
|
6
|
+
* `vault-publish.ts`), never creates files, and never invents a heading.
|
|
7
|
+
* Pure string-in/string-out.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export type InsertVaultRegionResult =
|
|
11
|
+
| { ok: true; text: string; inserted: true }
|
|
12
|
+
| { ok: true; text: string; inserted: false }
|
|
13
|
+
| { ok: false; reason: "no_heading"; text: string }
|
|
14
|
+
| { ok: false; reason: "duplicate_heading"; lines: readonly number[]; text: string };
|
|
15
|
+
|
|
16
|
+
export function insertMarkersUnderHeading(
|
|
17
|
+
fileText: string,
|
|
18
|
+
opts: { heading: string; name: string; content: string },
|
|
19
|
+
): InsertVaultRegionResult {
|
|
20
|
+
if (typeof opts.heading !== "string" || opts.heading.length === 0) {
|
|
21
|
+
throw new RangeError("Heading must be non-empty.");
|
|
22
|
+
}
|
|
23
|
+
if (typeof opts.name !== "string" || opts.name.length === 0) {
|
|
24
|
+
throw new RangeError("Region name must be non-empty.");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const startMarker = `<!-- remnic:${opts.name}:start -->`;
|
|
28
|
+
const endMarker = `<!-- remnic:${opts.name}:end -->`;
|
|
29
|
+
if (fileText.includes(startMarker) && fileText.includes(endMarker)) {
|
|
30
|
+
return { ok: true, text: fileText, inserted: false };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const rows = fileLines(fileText);
|
|
34
|
+
const hits: Array<{ row: (typeof rows)[number]; level: number }> = [];
|
|
35
|
+
for (const row of rows) {
|
|
36
|
+
const heading = parseAtxHeading(row.line);
|
|
37
|
+
if (heading && heading.text === opts.heading) {
|
|
38
|
+
hits.push({ row, level: heading.level });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (hits.length === 0) return { ok: false, reason: "no_heading", text: fileText };
|
|
42
|
+
if (hits.length > 1) {
|
|
43
|
+
return { ok: false, reason: "duplicate_heading", lines: hits.map((hit) => hit.row.number), text: fileText };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const hit = hits[0]!;
|
|
47
|
+
|
|
48
|
+
const eol = fileText.includes("\r\n") ? "\r\n" : "\n";
|
|
49
|
+
const prefix =
|
|
50
|
+
hit.row.next === fileText.length && !fileText.endsWith("\n") && !fileText.endsWith("\r")
|
|
51
|
+
? `${fileText}${eol}`
|
|
52
|
+
: fileText.slice(0, hit.row.next);
|
|
53
|
+
let content = opts.content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
54
|
+
if (eol === "\r\n") content = content.replace(/\n/g, "\r\n");
|
|
55
|
+
if (content.length > 0 && !content.endsWith(eol)) content += eol;
|
|
56
|
+
|
|
57
|
+
const text = `${prefix}${startMarker}${eol}${content}${endMarker}${eol}${fileText.slice(hit.row.next)}`;
|
|
58
|
+
return { ok: true, text, inserted: true };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type FileLine = { line: string; start: number; next: number; number: number };
|
|
62
|
+
|
|
63
|
+
function fileLines(fileText: string): FileLine[] {
|
|
64
|
+
const rows: FileLine[] = [];
|
|
65
|
+
let start = 0;
|
|
66
|
+
let number = 1;
|
|
67
|
+
while (start < fileText.length) {
|
|
68
|
+
let i = start;
|
|
69
|
+
while (i < fileText.length && fileText[i] !== "\n" && fileText[i] !== "\r") i++;
|
|
70
|
+
let next = i;
|
|
71
|
+
if (fileText[i] === "\r" && fileText[i + 1] === "\n") next = i + 2;
|
|
72
|
+
else if (fileText[i] === "\n" || fileText[i] === "\r") next = i + 1;
|
|
73
|
+
else next = fileText.length;
|
|
74
|
+
rows.push({ line: fileText.slice(start, i), start, next, number });
|
|
75
|
+
number += 1;
|
|
76
|
+
start = next;
|
|
77
|
+
}
|
|
78
|
+
return rows;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function parseAtxHeading(line: string): { level: number; text: string } | null {
|
|
82
|
+
let level = 0;
|
|
83
|
+
while (level < line.length && level < 6 && line[level] === "#") level++;
|
|
84
|
+
if (level === 0 || line[level] !== " ") return null;
|
|
85
|
+
return { level, text: line.slice(level + 1) };
|
|
86
|
+
}
|
package/src/config.test.ts
CHANGED
|
@@ -2569,7 +2569,7 @@ test("parseConfig forwards activity source settings", () => {
|
|
|
2569
2569
|
minConfidence: 0.7,
|
|
2570
2570
|
minImportance: "normal",
|
|
2571
2571
|
maxMemoriesPerDay: 0,
|
|
2572
|
-
timeline: { enabled: false, journal: { enabled: false }, qa: { enabled: false, maxRangeDays: 31 } },
|
|
2572
|
+
timeline: { enabled: false, journal: { enabled: false, source: "file" }, qa: { enabled: false, maxRangeDays: 31 } },
|
|
2573
2573
|
});
|
|
2574
2574
|
});
|
|
2575
2575
|
|
package/src/dedup/index.ts
CHANGED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
decideMergeOnWrite,
|
|
6
|
+
type MergeCandidate,
|
|
7
|
+
type MergeDecisionOptions,
|
|
8
|
+
} from "./merge-decision.js";
|
|
9
|
+
|
|
10
|
+
const OPTS: MergeDecisionOptions = { updateThreshold: 0.8, duplicateThreshold: 0.92 };
|
|
11
|
+
|
|
12
|
+
function candidate(overrides: Partial<MergeCandidate> = {}): MergeCandidate {
|
|
13
|
+
return {
|
|
14
|
+
id: "fact-1",
|
|
15
|
+
similarity: 0.85,
|
|
16
|
+
updatedAt: "2026-01-02T00:00:00.000Z",
|
|
17
|
+
...overrides,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
test("no candidates creates", () => {
|
|
22
|
+
assert.deepEqual(decideMergeOnWrite([], OPTS), { action: "create" });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("best similarity at or above duplicateThreshold skips as duplicate", () => {
|
|
26
|
+
assert.deepEqual(
|
|
27
|
+
decideMergeOnWrite(
|
|
28
|
+
[candidate({ id: "low", similarity: 0.5 }), candidate({ id: "dup", similarity: 0.92 })],
|
|
29
|
+
OPTS,
|
|
30
|
+
),
|
|
31
|
+
{ action: "skip", reason: "duplicate" },
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("best similarity between thresholds updates the best candidate", () => {
|
|
36
|
+
assert.deepEqual(
|
|
37
|
+
decideMergeOnWrite(
|
|
38
|
+
[candidate({ id: "best", similarity: 0.9 }), candidate({ id: "worst", similarity: 0.81 })],
|
|
39
|
+
OPTS,
|
|
40
|
+
),
|
|
41
|
+
{ action: "update", targetId: "best" },
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("best similarity below updateThreshold creates", () => {
|
|
46
|
+
assert.deepEqual(
|
|
47
|
+
decideMergeOnWrite([candidate({ similarity: 0.79 })], OPTS),
|
|
48
|
+
{ action: "create" },
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("invalid thresholds throw RangeError", () => {
|
|
53
|
+
const bad: MergeDecisionOptions[] = [
|
|
54
|
+
{ updateThreshold: Number.NaN, duplicateThreshold: 0.9 },
|
|
55
|
+
{ updateThreshold: 0.8, duplicateThreshold: Number.POSITIVE_INFINITY },
|
|
56
|
+
{ updateThreshold: -0.1, duplicateThreshold: 0.9 },
|
|
57
|
+
{ updateThreshold: 0.8, duplicateThreshold: 1.1 },
|
|
58
|
+
{ updateThreshold: 0.92, duplicateThreshold: 0.8 }, // duplicate < update
|
|
59
|
+
];
|
|
60
|
+
for (const options of bad) {
|
|
61
|
+
assert.throws(() => decideMergeOnWrite([], options), RangeError);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("updateThreshold 0 is honored, never coerced up", () => {
|
|
66
|
+
const zero = { updateThreshold: 0, duplicateThreshold: 0.92 };
|
|
67
|
+
// similarity 0 is >= 0 -> update, not create and not default-band behavior
|
|
68
|
+
assert.deepEqual(
|
|
69
|
+
decideMergeOnWrite([candidate({ similarity: 0 })], zero),
|
|
70
|
+
{ action: "update", targetId: "fact-1" },
|
|
71
|
+
);
|
|
72
|
+
// no candidates still creates
|
|
73
|
+
assert.deepEqual(decideMergeOnWrite([], zero), { action: "create" });
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("malformed candidates are ignored, never thrown on", () => {
|
|
77
|
+
assert.deepEqual(
|
|
78
|
+
decideMergeOnWrite(
|
|
79
|
+
[
|
|
80
|
+
{ id: "", similarity: 0.99, updatedAt: "2026-01-01T00:00:00.000Z" },
|
|
81
|
+
{ id: " ", similarity: 0.99, updatedAt: "2026-01-01T00:00:00.000Z" },
|
|
82
|
+
{ id: "nan", similarity: Number.NaN, updatedAt: "2026-01-01T00:00:00.000Z" },
|
|
83
|
+
{ id: "inf", similarity: Number.POSITIVE_INFINITY, updatedAt: "2026-01-01T00:00:00.000Z" },
|
|
84
|
+
{ id: "high", similarity: 1.5, updatedAt: "2026-01-01T00:00:00.000Z" },
|
|
85
|
+
{ id: "neg", similarity: -0.2, updatedAt: "2026-01-01T00:00:00.000Z" },
|
|
86
|
+
{ id: "good", similarity: 0.85, updatedAt: "2026-01-02T00:00:00.000Z" },
|
|
87
|
+
],
|
|
88
|
+
OPTS,
|
|
89
|
+
),
|
|
90
|
+
{ action: "update", targetId: "good" },
|
|
91
|
+
);
|
|
92
|
+
// all-malformed behaves like no candidates
|
|
93
|
+
assert.deepEqual(
|
|
94
|
+
decideMergeOnWrite([{ id: "nan", similarity: Number.NaN, updatedAt: "x" }], OPTS),
|
|
95
|
+
{ action: "create" },
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("identical similarity and updatedAt tie-breaks on id ascending, deterministically", () => {
|
|
100
|
+
const candidates = [
|
|
101
|
+
candidate({ id: "b", similarity: 0.9, updatedAt: "2026-03-01T00:00:00.000Z" }),
|
|
102
|
+
candidate({ id: "a", similarity: 0.9, updatedAt: "2026-03-01T00:00:00.000Z" }),
|
|
103
|
+
candidate({ id: "c", similarity: 0.9, updatedAt: "2026-03-01T00:00:00.000Z" }),
|
|
104
|
+
];
|
|
105
|
+
const first = decideMergeOnWrite(candidates, OPTS);
|
|
106
|
+
const second = decideMergeOnWrite([...candidates].reverse(), OPTS);
|
|
107
|
+
assert.deepEqual(first, second);
|
|
108
|
+
assert.deepEqual(first, { action: "update", targetId: "a" });
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("unparseable updatedAt sorts last", () => {
|
|
112
|
+
const candidates = [
|
|
113
|
+
candidate({ id: "bad-date", similarity: 0.9, updatedAt: "not-a-timestamp" }),
|
|
114
|
+
candidate({ id: "good-date", similarity: 0.9, updatedAt: "2026-03-01T00:00:00.000Z" }),
|
|
115
|
+
];
|
|
116
|
+
assert.deepEqual(decideMergeOnWrite(candidates, OPTS), { action: "update", targetId: "good-date" });
|
|
117
|
+
// newer timestamp wins when both parse
|
|
118
|
+
assert.deepEqual(
|
|
119
|
+
decideMergeOnWrite(
|
|
120
|
+
[
|
|
121
|
+
candidate({ id: "older", updatedAt: "2026-01-01T00:00:00.000Z" }),
|
|
122
|
+
candidate({ id: "newer", updatedAt: "2026-06-01T00:00:00.000Z" }),
|
|
123
|
+
],
|
|
124
|
+
OPTS,
|
|
125
|
+
),
|
|
126
|
+
{ action: "update", targetId: "newer" },
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Two unparseable timestamps must not make the comparator asymmetric: testing
|
|
131
|
+
// each side against NaN independently returned 1 for both orderings, so the
|
|
132
|
+
// winner depended on array order.
|
|
133
|
+
test("two unparseable updatedAt values break the tie by id, whatever the order", () => {
|
|
134
|
+
const options = { updateThreshold: 0.5, duplicateThreshold: 0.95 };
|
|
135
|
+
const alpha = { id: "alpha", similarity: 0.7, updatedAt: "not-a-date" };
|
|
136
|
+
const beta = { id: "beta", similarity: 0.7, updatedAt: "also-not-a-date" };
|
|
137
|
+
|
|
138
|
+
for (const candidates of [[alpha, beta], [beta, alpha]]) {
|
|
139
|
+
assert.deepEqual(decideMergeOnWrite(candidates, options), {
|
|
140
|
+
action: "update",
|
|
141
|
+
targetId: "alpha",
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("a parseable updatedAt still outranks an unparseable one in both orders", () => {
|
|
147
|
+
const options = { updateThreshold: 0.5, duplicateThreshold: 0.95 };
|
|
148
|
+
const dated = { id: "zeta", similarity: 0.7, updatedAt: "2026-08-19T00:00:00.000Z" };
|
|
149
|
+
const undated = { id: "alpha", similarity: 0.7, updatedAt: "nope" };
|
|
150
|
+
|
|
151
|
+
for (const candidates of [[dated, undated], [undated, dated]]) {
|
|
152
|
+
assert.deepEqual(decideMergeOnWrite(candidates, options), {
|
|
153
|
+
action: "update",
|
|
154
|
+
targetId: "zeta",
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
});
|