@remnic/core 9.69.46 → 9.69.48
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 +15 -14
- package/dist/access-admin-ops-surface.js +43 -42
- package/dist/access-authorization-probe.d.ts +15 -14
- package/dist/access-authorization-probe.js +44 -43
- package/dist/access-boundary.d.ts +15 -14
- package/dist/access-boundary.js +43 -42
- package/dist/access-cli.js +120 -115
- 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 +15 -14
- package/dist/access-extraction-force-flush.js +43 -42
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-briefing.d.ts +15 -14
- package/dist/access-http-briefing.js +44 -43
- package/dist/access-http-lcm-compaction.d.ts +15 -14
- package/dist/access-http-lifecycle-flush.d.ts +15 -14
- package/dist/access-http-offline-stream.d.ts +15 -14
- package/dist/access-http-query.d.ts +2 -2
- package/dist/access-http-query.js +45 -44
- package/dist/access-http.d.ts +16 -15
- package/dist/access-http.js +68 -64
- package/dist/access-identity-continuity-surface.d.ts +11 -11
- package/dist/access-identity-continuity-surface.js +43 -42
- package/dist/access-lcm-surface.d.ts +15 -14
- package/dist/access-lcm-surface.js +43 -42
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp-shared-context-tools.d.ts +15 -14
- package/dist/access-mcp.d.ts +15 -14
- package/dist/access-mcp.js +56 -53
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-DDnsN22V.d.ts → access-namespace-preflight-CetF9ziA.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +43 -42
- package/dist/access-observe-transcript.d.ts +11 -11
- package/dist/access-observe-write-category.d.ts +3 -3
- package/dist/access-observe-write-category.js +4 -4
- package/dist/access-observe-write-surface.d.ts +15 -14
- package/dist/access-observe-write-surface.js +43 -42
- package/dist/access-offline-manifest.d.ts +11 -11
- package/dist/access-offline-manifest.js +2 -2
- package/dist/access-operations-batch.js +45 -44
- package/dist/access-operations.d.ts +16 -15
- package/dist/access-operations.js +52 -50
- package/dist/access-recall-concurrency.d.ts +15 -14
- package/dist/access-recall-concurrency.js +43 -42
- package/dist/access-recall-response.d.ts +15 -14
- package/dist/access-recall-response.js +43 -42
- package/dist/access-recall-surface.d.ts +15 -14
- package/dist/access-recall-surface.js +43 -42
- package/dist/access-schema.d.ts +114 -114
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-DGynYlbE.d.ts → access-service-DUkTWyZS.d.ts} +77 -74
- package/dist/access-service-helpers.d.ts +15 -14
- package/dist/access-service.d.ts +15 -14
- package/dist/access-service.js +43 -42
- package/dist/access-surface-catalog.d.ts +15 -14
- package/dist/access-surface-catalog.js +51 -44
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +4 -4
- 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 +3 -2
- package/dist/active-recall.js.map +1 -1
- package/dist/activity/digest.d.ts +1 -1
- 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/background-generation.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 +11 -11
- package/dist/briefing-window.d.ts +2 -2
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +13 -13
- 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 +5 -5
- 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-Dl2hYqpS.d.ts → catalog-Bns9zpl3.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 +14 -14
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-N46SNYMC.js → chunk-2B2RHLHI.js} +2 -2
- package/dist/{chunk-F5V7KRQS.js → chunk-2WMXZYMS.js} +2 -2
- package/dist/{chunk-KF57IQFX.js → chunk-32ZBIGID.js} +19 -15
- package/dist/chunk-32ZBIGID.js.map +1 -0
- package/dist/{chunk-ORQ7AZMU.js → chunk-3RKVSECD.js} +8 -8
- package/dist/{chunk-3NYM6JA4.js → chunk-4LPIVP77.js} +2 -2
- package/dist/{chunk-PW4HTWXL.js → chunk-55XWRL6F.js} +2 -2
- package/dist/{chunk-GGY7WKMB.js → chunk-5KBI2MOC.js} +1 -1
- package/dist/{chunk-IXMWTNNY.js → chunk-6A6HSXWV.js} +2 -2
- package/dist/{chunk-P7S7BVBJ.js → chunk-7DU2F7LM.js} +3 -3
- package/dist/{chunk-4HTQ76O4.js → chunk-7SJCSDQ3.js} +2 -2
- package/dist/{chunk-U4ESGVZ2.js → chunk-7YUX52XZ.js} +3 -3
- package/dist/{chunk-FMEP2RB5.js → chunk-B4WI7OF2.js} +2 -2
- package/dist/{chunk-EUP4AXIW.js → chunk-B6VDWDFN.js} +2 -2
- package/dist/{chunk-UOREPQ3C.js → chunk-BIXELUIR.js} +2 -2
- package/dist/{chunk-GYYLZOSO.js → chunk-BMBAA2M5.js} +13 -6
- package/dist/chunk-BMBAA2M5.js.map +1 -0
- package/dist/{chunk-AYZHHMTK.js → chunk-BNX2TUSF.js} +2 -2
- package/dist/{chunk-5ZXGH2ZL.js → chunk-BXOPUJ3W.js} +2 -2
- package/dist/{chunk-TE6B2UU6.js → chunk-CD7VTZIG.js} +2 -2
- package/dist/{chunk-EC5SVM6H.js → chunk-DE4ZGH2N.js} +2 -2
- package/dist/{chunk-YFVIA5A6.js → chunk-DRLZB3CN.js} +2 -2
- package/dist/{chunk-SRRZZHA5.js → chunk-EGOWY342.js} +2 -2
- package/dist/chunk-EIB4FJVR.js +46 -0
- package/dist/chunk-EIB4FJVR.js.map +1 -0
- package/dist/{chunk-W44T2KHG.js → chunk-EWBDJQ5Y.js} +3 -3
- package/dist/{chunk-JMBTNVMW.js → chunk-FGRJJBFO.js} +2 -2
- package/dist/{chunk-F3TURDFG.js → chunk-FPB5LQWW.js} +4 -1
- package/dist/{chunk-F3TURDFG.js.map → chunk-FPB5LQWW.js.map} +1 -1
- package/dist/{chunk-WGZHSQDV.js → chunk-G2XZFGYN.js} +4 -4
- package/dist/{chunk-CFIHVWYZ.js → chunk-GGROFIYX.js} +2 -2
- package/dist/{chunk-XLZZLUWL.js → chunk-HG74GEVY.js} +2 -2
- package/dist/chunk-HMDYSGY6.js +54 -0
- package/dist/chunk-HMDYSGY6.js.map +1 -0
- package/dist/{chunk-WUUGE7QC.js → chunk-HS75MCQF.js} +4 -4
- package/dist/{chunk-DO6R3LIE.js → chunk-I6IJDTRP.js} +2 -2
- package/dist/{chunk-7ZNJN5WZ.js → chunk-IHOXK2I6.js} +55 -6
- package/dist/chunk-IHOXK2I6.js.map +1 -0
- package/dist/{chunk-2NKY7OC6.js → chunk-IMJPJY7V.js} +2 -2
- package/dist/{chunk-TZ44E732.js → chunk-IO7K7GES.js} +2 -2
- package/dist/{chunk-7BNB7KHB.js → chunk-JIURESYF.js} +7 -7
- package/dist/{chunk-AYP2FZFA.js → chunk-JUOJGZPV.js} +2 -2
- package/dist/{chunk-4XTSKGLX.js → chunk-JYXLW22X.js} +3 -3
- package/dist/{chunk-HXDXR2FH.js → chunk-KPYMORPQ.js} +41 -31
- package/dist/chunk-KPYMORPQ.js.map +1 -0
- package/dist/{chunk-IPLYGWQF.js → chunk-KQAFEZQX.js} +5 -5
- package/dist/{chunk-AN2O4KZY.js → chunk-KVIMQAER.js} +2 -2
- package/dist/chunk-LI4APB6M.js +218 -0
- package/dist/chunk-LI4APB6M.js.map +1 -0
- package/dist/{chunk-VGRVJ6Z6.js → chunk-LIAM7U2J.js} +2 -2
- package/dist/{chunk-S3SND7SO.js → chunk-LIDJWAQV.js} +2 -2
- package/dist/{chunk-T5NI5K46.js → chunk-LYMJ36UI.js} +2 -2
- package/dist/{chunk-UGGOQKO6.js → chunk-MKJFPIVG.js} +93 -51
- package/dist/chunk-MKJFPIVG.js.map +1 -0
- package/dist/{chunk-UEJY6ZTQ.js → chunk-MKLDZNBD.js} +2 -2
- package/dist/{chunk-QUFJ3NJE.js → chunk-MNG536IS.js} +20 -20
- package/dist/{chunk-SW42MMAH.js → chunk-MQT3WP3F.js} +2 -2
- package/dist/{chunk-5EHPB6RL.js → chunk-MUNR43V3.js} +2 -2
- package/dist/{chunk-OV7GJ4KW.js → chunk-NNFB4CU4.js} +2 -2
- package/dist/{chunk-47C6DF43.js → chunk-OS4JVTHR.js} +3 -3
- package/dist/{chunk-W6YDAIVB.js → chunk-OSTXIFZW.js} +13 -2
- package/dist/chunk-OSTXIFZW.js.map +1 -0
- package/dist/chunk-P3YNEMYY.js +212 -0
- package/dist/chunk-P3YNEMYY.js.map +1 -0
- package/dist/{chunk-JOP7W24J.js → chunk-PA67GXYJ.js} +8 -8
- package/dist/{chunk-FSH6KRKO.js → chunk-PPJLJD2D.js} +2 -2
- package/dist/{chunk-AG6PANBG.js → chunk-PXJ6HE2W.js} +11 -11
- package/dist/{chunk-DDBLZJRV.js → chunk-QB4VXCFN.js} +2 -2
- package/dist/{chunk-L63M2PE4.js → chunk-QGAKUOKU.js} +2 -2
- package/dist/{chunk-YUQPUK6H.js → chunk-QLCMOHRE.js} +2 -2
- package/dist/{chunk-Q4AUIFUA.js → chunk-QMWKENNK.js} +4 -4
- package/dist/{chunk-66QOUYNS.js → chunk-R32AEEU3.js} +174 -57
- package/dist/chunk-R32AEEU3.js.map +1 -0
- package/dist/{chunk-TNQR7N52.js → chunk-S3YM4SZQ.js} +2 -1
- package/dist/chunk-S3YM4SZQ.js.map +1 -0
- package/dist/{chunk-RW4QNB4J.js → chunk-S45INSV3.js} +3 -1
- package/dist/{chunk-RW4QNB4J.js.map → chunk-S45INSV3.js.map} +1 -1
- package/dist/{chunk-EEHQY7ER.js → chunk-SK6HEQTW.js} +2 -2
- package/dist/{chunk-PGAB2V53.js → chunk-SMBWBEE7.js} +2 -2
- package/dist/{chunk-62NYUFNH.js → chunk-SS33RR4F.js} +8 -8
- package/dist/{chunk-4ECS33D4.js → chunk-T3T5HTZZ.js} +2 -2
- package/dist/{chunk-KG2OOAFF.js → chunk-TQSCR5DU.js} +6 -6
- package/dist/{chunk-D5DTZBTV.js → chunk-TW4MXM7H.js} +6 -6
- package/dist/chunk-TW4MXM7H.js.map +1 -0
- package/dist/{chunk-AS2NOPDM.js → chunk-V7IONNTJ.js} +2 -2
- package/dist/{chunk-HYWPUYLO.js → chunk-VV5GCNKG.js} +2 -2
- package/dist/{chunk-Y3XHIWVP.js → chunk-WL3PGPGU.js} +2 -2
- package/dist/{chunk-3UQIS2GC.js → chunk-WNMVUWI7.js} +2 -2
- package/dist/{chunk-66YUOI53.js → chunk-WQW6KPVC.js} +1 -1
- package/dist/chunk-WQW6KPVC.js.map +1 -0
- package/dist/{chunk-2AV75BJW.js → chunk-WVI43D54.js} +24 -1
- package/dist/chunk-WVI43D54.js.map +1 -0
- package/dist/{chunk-WOBMSMUK.js → chunk-WYU66IVZ.js} +3 -3
- package/dist/{chunk-A7GQBJP5.js → chunk-X2NFFBTO.js} +4 -4
- package/dist/{chunk-CWMMKFO7.js → chunk-XEHLYA5Z.js} +3 -3
- package/dist/{chunk-JIWZVOQM.js → chunk-XKHRNAK7.js} +2 -2
- package/dist/{chunk-VW5TGNJN.js → chunk-XXLH6KFO.js} +2 -2
- package/dist/chunk-XYGINDIJ.js +74 -0
- package/dist/chunk-XYGINDIJ.js.map +1 -0
- package/dist/{chunk-J5OXWG66.js → chunk-XZUHXKM3.js} +2 -2
- package/dist/{chunk-K4KE5MYE.js → chunk-Y5VT7BIT.js} +2 -2
- package/dist/{chunk-S7KDHFF2.js → chunk-YXWMZAAN.js} +2 -2
- package/dist/{chunk-EAZ3YZKN.js → chunk-ZEIJQ4I3.js} +2 -2
- package/dist/{cli-Cik3H7q1.d.ts → cli-Bbndoc6k.d.ts} +5 -5
- package/dist/cli.d.ts +17 -16
- package/dist/cli.js +90 -85
- package/dist/coding/export-okf-codegraph.d.ts +1 -1
- package/dist/coding/export-okf-codegraph.js +12 -12
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +13 -13
- 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 +3 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +13 -13
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +13 -13
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/contradiction/index.d.ts +4 -4
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +15 -15
- 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 +15 -15
- package/dist/cross-lingual-recall.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/deep-recall-http-glue.d.ts +15 -14
- package/dist/deep-recall-http-glue.js +4 -4
- package/dist/deep-recall-mcp-tools.d.ts +15 -14
- package/dist/deep-recall-policy-llm.d.ts +2 -2
- package/dist/deep-recall-seeds.d.ts +1 -1
- package/dist/deep-recall.js +2 -2
- package/dist/delinearize.d.ts +1 -1
- package/dist/dependency-propagation-config.d.ts +1 -1
- package/dist/{dependency-propagation-delivery-BXaUoVUf.d.ts → dependency-propagation-delivery-B-LvcDaq.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 +14 -14
- 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 +11 -11
- package/dist/external-wiki-access.d.ts +15 -14
- package/dist/external-wiki-access.js +44 -43
- 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 +15 -14
- package/dist/extraction-error-classification.d.ts +1 -1
- package/dist/extraction-evidence-class.d.ts +142 -0
- package/dist/extraction-evidence-class.js +113 -0
- package/dist/extraction-evidence-class.js.map +1 -0
- package/dist/extraction-faithfulness.d.ts +2 -2
- package/dist/extraction-judge-telemetry.d.ts +2 -2
- package/dist/extraction-judge-training.d.ts +2 -2
- package/dist/extraction-judge.d.ts +2 -2
- 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-source-grounding.js +2 -2
- package/dist/extraction-span-config.d.ts +1 -1
- package/dist/extraction-span-materialize.d.ts +1 -1
- package/dist/extraction-span-wire.d.ts +1 -1
- package/dist/extraction.d.ts +2 -2
- package/dist/extraction.js +21 -21
- package/dist/fallback-llm-codex-subscription.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{generic-recall-paths-BkVVEoeO.d.ts → generic-recall-paths-Bfc7zigS.d.ts} +1 -1
- package/dist/graph-append-error.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-jsonl.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/importers/test-utils.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/{index-Zb6SUV4R.d.ts → index-C7IA1DxB.d.ts} +3 -3
- package/dist/index.d.ts +798 -707
- package/dist/index.js +184 -134
- 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 +7 -7
- 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-DdrhmecM.d.ts → local-llm-DH4tWtck.d.ts} +1 -1
- package/dist/local-llm-helpers.d.ts +2 -2
- package/dist/local-llm.d.ts +2 -2
- package/dist/local-llm.js +2 -2
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/location/index.d.ts +5 -5
- package/dist/location/index.js +15 -15
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +13 -13
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +13 -13
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +14 -14
- package/dist/{maintenance-Du_VRvVg.d.ts → maintenance-n6yeTQhR.d.ts} +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +15 -14
- package/dist/mcp-read-only-tools.js +1 -1
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-browse-http-glue.d.ts +170 -0
- package/dist/memory-browse-http-glue.js +9 -0
- package/dist/memory-browse-http-glue.js.map +1 -0
- package/dist/memory-browse-mcp-tools.d.ts +160 -0
- package/dist/memory-browse-mcp-tools.js +8 -0
- package/dist/memory-browse-mcp-tools.js.map +1 -0
- package/dist/memory-browse-operations.d.ts +2 -0
- package/dist/memory-browse-operations.js +246 -0
- package/dist/memory-browse-operations.js.map +1 -0
- package/dist/memory-browse.d.ts +113 -0
- package/dist/memory-browse.js +49 -0
- package/dist/memory-browse.js.map +1 -0
- 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 +15 -14
- package/dist/memory-subject.d.ts +15 -14
- 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 +14 -14
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +6 -6
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +13 -13
- 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 +16 -16
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +23 -22
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +23 -23
- package/dist/{orchestrator-D9U3Zgjp.d.ts → orchestrator-Cirjo3ZB.d.ts} +10 -10
- package/dist/orchestrator.d.ts +11 -11
- package/dist/orchestrator.js +122 -117
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-4lqKJZ_0.d.ts → pipeline-DK79FrgH.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +2 -2
- package/dist/provenance.d.ts +77 -2
- package/dist/provenance.js +7 -3
- package/dist/{public-http-AabioFLh.d.ts → public-http-DaHHhWRR.d.ts} +1 -1
- package/dist/{qmd-DnoWaXKb.d.ts → qmd-BT0ErlRS.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-context-composition.d.ts +43 -3
- package/dist/recall-context-composition.js +5 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +1 -1
- package/dist/recall-navigate-access.d.ts +1 -1
- package/dist/recall-navigate-access.js +2 -2
- package/dist/recall-navigate-disclosure.d.ts +1 -1
- package/dist/recall-navigate-disclosure.js +2 -2
- package/dist/recall-navigate.d.ts +1 -1
- package/dist/recall-navigate.js +2 -2
- package/dist/recall-navigation-http-glue.d.ts +15 -14
- package/dist/recall-navigation-mcp-tools.d.ts +15 -14
- package/dist/recall-navigation-operations.js +44 -43
- package/dist/recall-navigation-renderer.d.ts +1 -1
- package/dist/recall-navigation.d.ts +1 -1
- package/dist/recall-navigation.js +43 -42
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state-view-admission.d.ts +2 -2
- package/dist/recall-state-view-admission.js +5 -5
- package/dist/recall-state-view-anchors.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-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/cursor.d.ts +1 -1
- package/dist/reconcile/manifest.d.ts +4 -1
- package/dist/reconcile/manifest.js +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 +4 -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 +160 -160
- package/dist/{scope-profiles-crazXegZ.d.ts → scope-profiles-BgPQx9iE.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 +5 -5
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +9 -9
- 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-B09JI9WM.d.ts → semantic-consolidation-BrAWKVcm.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +14 -14
- package/dist/semantic-rule-promotion.js +13 -13
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +13 -13
- package/dist/{service-ByjbCuj7.d.ts → service-CqHOTg87.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 +17 -17
- package/dist/standing-memory-block.d.ts +77 -0
- package/dist/standing-memory-block.js +40 -0
- package/dist/standing-memory-block.js.map +1 -0
- package/dist/standup/build.js +13 -13
- package/dist/{storage-CbdF077z.d.ts → storage-mD2YQ8_2.d.ts} +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +12 -12
- package/dist/subject-config.d.ts +1 -1
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +3 -3
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/support-passport/index.d.ts +18 -17
- package/dist/support-passport/index.js +46 -45
- package/dist/{tagging-CF7DNV7_.d.ts → tagging-CiAVA-ID.d.ts} +2 -2
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-timeline-recall.d.ts +1 -1
- package/dist/temporal-timeline-recall.js +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/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 +13 -13
- 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-nmhnJpxx.d.ts → types-DgDaoY61.d.ts} +6 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +13 -13
- package/dist/who-knows-cli.d.ts +15 -14
- package/dist/who-knows-cli.js +14 -14
- package/dist/who-knows.d.ts +15 -14
- package/dist/who-knows.js +13 -13
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +2 -2
- package/src/access-boundary.ts +3 -0
- package/src/access-http.ts +2 -2
- package/src/access-mcp-output-schemas.ts +25 -0
- package/src/access-mcp.ts +3 -3
- package/src/access-operations.ts +2 -0
- package/src/access-service.ts +6 -1
- package/src/access-surface-catalog.test.ts +20 -0
- package/src/access-surface-catalog.ts +6 -0
- package/src/activity/timeline/index.ts +1 -0
- package/src/activity/timeline/journal-recap.test.ts +17 -0
- package/src/activity/timeline/journal-recap.ts +19 -6
- package/src/activity/timeline/recap-export-range.test.ts +289 -0
- package/src/activity/timeline/recap-export-range.ts +169 -0
- package/src/activity/timeline/recap-export.test.ts +73 -1
- package/src/activity/timeline/recap-export.ts +57 -4
- package/src/cli/memory-browse-commands.ts +77 -0
- package/src/cli.ts +2 -2
- package/src/config.ts +11 -0
- package/src/extraction-evidence-class.test.ts +355 -0
- package/src/extraction-evidence-class.ts +241 -0
- package/src/index.ts +1 -0
- package/src/mcp-read-only-tools.ts +3 -0
- package/src/memory-browse-http-glue.ts +93 -0
- package/src/memory-browse-mcp-tools.ts +57 -0
- package/src/memory-browse-operations.ts +88 -0
- package/src/memory-browse-surface.test.ts +500 -0
- package/src/memory-browse.ts +316 -0
- package/src/provenance.ts +3 -3
- package/src/recall-context-composition.test.ts +66 -0
- package/src/recall-context-composition.ts +102 -2
- package/src/reconcile/manifest.test.ts +27 -0
- package/src/reconcile/manifest.ts +7 -0
- package/src/standing-memory-block.test.ts +262 -0
- package/src/standing-memory-block.ts +331 -0
- package/src/types.ts +6 -0
- package/dist/chunk-2AV75BJW.js.map +0 -1
- package/dist/chunk-66QOUYNS.js.map +0 -1
- package/dist/chunk-66YUOI53.js.map +0 -1
- package/dist/chunk-7ZNJN5WZ.js.map +0 -1
- package/dist/chunk-D5DTZBTV.js.map +0 -1
- package/dist/chunk-GYYLZOSO.js.map +0 -1
- package/dist/chunk-HXDXR2FH.js.map +0 -1
- package/dist/chunk-KF57IQFX.js.map +0 -1
- package/dist/chunk-TNQR7N52.js.map +0 -1
- package/dist/chunk-UGGOQKO6.js.map +0 -1
- package/dist/chunk-W6YDAIVB.js.map +0 -1
- /package/dist/{chunk-N46SNYMC.js.map → chunk-2B2RHLHI.js.map} +0 -0
- /package/dist/{chunk-F5V7KRQS.js.map → chunk-2WMXZYMS.js.map} +0 -0
- /package/dist/{chunk-ORQ7AZMU.js.map → chunk-3RKVSECD.js.map} +0 -0
- /package/dist/{chunk-3NYM6JA4.js.map → chunk-4LPIVP77.js.map} +0 -0
- /package/dist/{chunk-PW4HTWXL.js.map → chunk-55XWRL6F.js.map} +0 -0
- /package/dist/{chunk-GGY7WKMB.js.map → chunk-5KBI2MOC.js.map} +0 -0
- /package/dist/{chunk-IXMWTNNY.js.map → chunk-6A6HSXWV.js.map} +0 -0
- /package/dist/{chunk-P7S7BVBJ.js.map → chunk-7DU2F7LM.js.map} +0 -0
- /package/dist/{chunk-4HTQ76O4.js.map → chunk-7SJCSDQ3.js.map} +0 -0
- /package/dist/{chunk-U4ESGVZ2.js.map → chunk-7YUX52XZ.js.map} +0 -0
- /package/dist/{chunk-FMEP2RB5.js.map → chunk-B4WI7OF2.js.map} +0 -0
- /package/dist/{chunk-EUP4AXIW.js.map → chunk-B6VDWDFN.js.map} +0 -0
- /package/dist/{chunk-UOREPQ3C.js.map → chunk-BIXELUIR.js.map} +0 -0
- /package/dist/{chunk-AYZHHMTK.js.map → chunk-BNX2TUSF.js.map} +0 -0
- /package/dist/{chunk-5ZXGH2ZL.js.map → chunk-BXOPUJ3W.js.map} +0 -0
- /package/dist/{chunk-TE6B2UU6.js.map → chunk-CD7VTZIG.js.map} +0 -0
- /package/dist/{chunk-EC5SVM6H.js.map → chunk-DE4ZGH2N.js.map} +0 -0
- /package/dist/{chunk-YFVIA5A6.js.map → chunk-DRLZB3CN.js.map} +0 -0
- /package/dist/{chunk-SRRZZHA5.js.map → chunk-EGOWY342.js.map} +0 -0
- /package/dist/{chunk-W44T2KHG.js.map → chunk-EWBDJQ5Y.js.map} +0 -0
- /package/dist/{chunk-JMBTNVMW.js.map → chunk-FGRJJBFO.js.map} +0 -0
- /package/dist/{chunk-WGZHSQDV.js.map → chunk-G2XZFGYN.js.map} +0 -0
- /package/dist/{chunk-CFIHVWYZ.js.map → chunk-GGROFIYX.js.map} +0 -0
- /package/dist/{chunk-XLZZLUWL.js.map → chunk-HG74GEVY.js.map} +0 -0
- /package/dist/{chunk-WUUGE7QC.js.map → chunk-HS75MCQF.js.map} +0 -0
- /package/dist/{chunk-DO6R3LIE.js.map → chunk-I6IJDTRP.js.map} +0 -0
- /package/dist/{chunk-2NKY7OC6.js.map → chunk-IMJPJY7V.js.map} +0 -0
- /package/dist/{chunk-TZ44E732.js.map → chunk-IO7K7GES.js.map} +0 -0
- /package/dist/{chunk-7BNB7KHB.js.map → chunk-JIURESYF.js.map} +0 -0
- /package/dist/{chunk-AYP2FZFA.js.map → chunk-JUOJGZPV.js.map} +0 -0
- /package/dist/{chunk-4XTSKGLX.js.map → chunk-JYXLW22X.js.map} +0 -0
- /package/dist/{chunk-IPLYGWQF.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-AN2O4KZY.js.map → chunk-KVIMQAER.js.map} +0 -0
- /package/dist/{chunk-VGRVJ6Z6.js.map → chunk-LIAM7U2J.js.map} +0 -0
- /package/dist/{chunk-S3SND7SO.js.map → chunk-LIDJWAQV.js.map} +0 -0
- /package/dist/{chunk-T5NI5K46.js.map → chunk-LYMJ36UI.js.map} +0 -0
- /package/dist/{chunk-UEJY6ZTQ.js.map → chunk-MKLDZNBD.js.map} +0 -0
- /package/dist/{chunk-QUFJ3NJE.js.map → chunk-MNG536IS.js.map} +0 -0
- /package/dist/{chunk-SW42MMAH.js.map → chunk-MQT3WP3F.js.map} +0 -0
- /package/dist/{chunk-5EHPB6RL.js.map → chunk-MUNR43V3.js.map} +0 -0
- /package/dist/{chunk-OV7GJ4KW.js.map → chunk-NNFB4CU4.js.map} +0 -0
- /package/dist/{chunk-47C6DF43.js.map → chunk-OS4JVTHR.js.map} +0 -0
- /package/dist/{chunk-JOP7W24J.js.map → chunk-PA67GXYJ.js.map} +0 -0
- /package/dist/{chunk-FSH6KRKO.js.map → chunk-PPJLJD2D.js.map} +0 -0
- /package/dist/{chunk-AG6PANBG.js.map → chunk-PXJ6HE2W.js.map} +0 -0
- /package/dist/{chunk-DDBLZJRV.js.map → chunk-QB4VXCFN.js.map} +0 -0
- /package/dist/{chunk-L63M2PE4.js.map → chunk-QGAKUOKU.js.map} +0 -0
- /package/dist/{chunk-YUQPUK6H.js.map → chunk-QLCMOHRE.js.map} +0 -0
- /package/dist/{chunk-Q4AUIFUA.js.map → chunk-QMWKENNK.js.map} +0 -0
- /package/dist/{chunk-EEHQY7ER.js.map → chunk-SK6HEQTW.js.map} +0 -0
- /package/dist/{chunk-PGAB2V53.js.map → chunk-SMBWBEE7.js.map} +0 -0
- /package/dist/{chunk-62NYUFNH.js.map → chunk-SS33RR4F.js.map} +0 -0
- /package/dist/{chunk-4ECS33D4.js.map → chunk-T3T5HTZZ.js.map} +0 -0
- /package/dist/{chunk-KG2OOAFF.js.map → chunk-TQSCR5DU.js.map} +0 -0
- /package/dist/{chunk-AS2NOPDM.js.map → chunk-V7IONNTJ.js.map} +0 -0
- /package/dist/{chunk-HYWPUYLO.js.map → chunk-VV5GCNKG.js.map} +0 -0
- /package/dist/{chunk-Y3XHIWVP.js.map → chunk-WL3PGPGU.js.map} +0 -0
- /package/dist/{chunk-3UQIS2GC.js.map → chunk-WNMVUWI7.js.map} +0 -0
- /package/dist/{chunk-WOBMSMUK.js.map → chunk-WYU66IVZ.js.map} +0 -0
- /package/dist/{chunk-A7GQBJP5.js.map → chunk-X2NFFBTO.js.map} +0 -0
- /package/dist/{chunk-CWMMKFO7.js.map → chunk-XEHLYA5Z.js.map} +0 -0
- /package/dist/{chunk-JIWZVOQM.js.map → chunk-XKHRNAK7.js.map} +0 -0
- /package/dist/{chunk-VW5TGNJN.js.map → chunk-XXLH6KFO.js.map} +0 -0
- /package/dist/{chunk-J5OXWG66.js.map → chunk-XZUHXKM3.js.map} +0 -0
- /package/dist/{chunk-K4KE5MYE.js.map → chunk-Y5VT7BIT.js.map} +0 -0
- /package/dist/{chunk-S7KDHFF2.js.map → chunk-YXWMZAAN.js.map} +0 -0
- /package/dist/{chunk-EAZ3YZKN.js.map → chunk-ZEIJQ4I3.js.map} +0 -0
|
@@ -6,15 +6,28 @@
|
|
|
6
6
|
* valid file body. Does not invent people, mood, or productivity claims.
|
|
7
7
|
*/
|
|
8
8
|
import { activityDayWindow } from "../digest.js";
|
|
9
|
-
import type {
|
|
9
|
+
import type { TimelineCardKind } from "./types.js";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Minimal card shape the renderer reads. `TimelineCard` is assignable, and
|
|
13
|
+
* so is the privacy-projected export card whose `title` is stripped
|
|
14
|
+
* (issue #2051): a title-less card renders its stable id instead.
|
|
15
|
+
*/
|
|
16
|
+
export interface JournalRenderCard {
|
|
17
|
+
id: string;
|
|
18
|
+
kind: TimelineCardKind;
|
|
19
|
+
title?: string;
|
|
20
|
+
categoryId: string;
|
|
21
|
+
startUtc: string;
|
|
22
|
+
endUtc: string;
|
|
23
|
+
}
|
|
11
24
|
export interface DeterministicJournalOptions {
|
|
12
25
|
date: string;
|
|
13
26
|
timezone: string;
|
|
14
27
|
}
|
|
15
28
|
|
|
16
29
|
interface ClippedCard {
|
|
17
|
-
card:
|
|
30
|
+
card: JournalRenderCard;
|
|
18
31
|
startMs: number;
|
|
19
32
|
endMs: number;
|
|
20
33
|
durationMs: number;
|
|
@@ -25,7 +38,7 @@ function formatMinutes(ms: number): string {
|
|
|
25
38
|
}
|
|
26
39
|
|
|
27
40
|
function clipToWindow(
|
|
28
|
-
cards: readonly
|
|
41
|
+
cards: readonly JournalRenderCard[],
|
|
29
42
|
winStart: number,
|
|
30
43
|
winEnd: number,
|
|
31
44
|
): ClippedCard[] {
|
|
@@ -42,7 +55,7 @@ function clipToWindow(
|
|
|
42
55
|
clipped.sort((left, right) => {
|
|
43
56
|
const byStart = left.startMs - right.startMs;
|
|
44
57
|
if (byStart !== 0) return byStart;
|
|
45
|
-
const byTitle = left.card.title.localeCompare(right.card.title);
|
|
58
|
+
const byTitle = (left.card.title ?? "").localeCompare(right.card.title ?? "");
|
|
46
59
|
if (byTitle !== 0) return byTitle;
|
|
47
60
|
return left.card.id.localeCompare(right.card.id);
|
|
48
61
|
});
|
|
@@ -91,7 +104,7 @@ function countGaps(
|
|
|
91
104
|
|
|
92
105
|
/** Render a byte-stable Markdown journal for one local day. */
|
|
93
106
|
export function renderDeterministicJournal(
|
|
94
|
-
cards: readonly
|
|
107
|
+
cards: readonly JournalRenderCard[],
|
|
95
108
|
options: DeterministicJournalOptions,
|
|
96
109
|
): string {
|
|
97
110
|
const window = activityDayWindow(options.date, options.timezone);
|
|
@@ -108,7 +121,7 @@ export function renderDeterministicJournal(
|
|
|
108
121
|
const cardLines =
|
|
109
122
|
clipped.length === 0
|
|
110
123
|
? ["_No cards._"]
|
|
111
|
-
: clipped.map((row) => `- ${formatMinutes(row.durationMs)} ${row.card.title}`);
|
|
124
|
+
: clipped.map((row) => `- ${formatMinutes(row.durationMs)} ${row.card.title ?? row.card.id}`);
|
|
112
125
|
return [
|
|
113
126
|
`# Journal — ${options.date} (${options.timezone})`,
|
|
114
127
|
"",
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import type { TimelineCard } from "./types.js";
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_RECAP_RANGE_MAX_DAYS,
|
|
7
|
+
exportDeterministicRecapRange,
|
|
8
|
+
renderDeterministicJournalRange,
|
|
9
|
+
} from "./recap-export-range.js";
|
|
10
|
+
import { renderDeterministicJournal } from "./journal-recap.js";
|
|
11
|
+
|
|
12
|
+
const TZ = "UTC";
|
|
13
|
+
|
|
14
|
+
function card(
|
|
15
|
+
overrides: Partial<TimelineCard> & Pick<TimelineCard, "id" | "dayKey">,
|
|
16
|
+
): TimelineCard {
|
|
17
|
+
return {
|
|
18
|
+
kind: "activity",
|
|
19
|
+
title: "Untitled",
|
|
20
|
+
summary: "none",
|
|
21
|
+
categoryId: "development",
|
|
22
|
+
confidence: 1,
|
|
23
|
+
startUtc: `${overrides.dayKey}T09:00:00.000Z`,
|
|
24
|
+
endUtc: `${overrides.dayKey}T10:00:00.000Z`,
|
|
25
|
+
timezone: TZ,
|
|
26
|
+
machine: "ws-a",
|
|
27
|
+
evidenceIds: [],
|
|
28
|
+
evidenceRange: null,
|
|
29
|
+
...overrides,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function okRange(options: Parameters<typeof exportDeterministicRecapRange>[0]) {
|
|
34
|
+
const result = exportDeterministicRecapRange(options);
|
|
35
|
+
assert.equal(result.ok, true);
|
|
36
|
+
assert.ok(result.ok);
|
|
37
|
+
return result.range;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
test("empty range days are exported with empty card lists", () => {
|
|
41
|
+
const range = okRange({
|
|
42
|
+
startDate: "2026-08-17",
|
|
43
|
+
endDate: "2026-08-18",
|
|
44
|
+
timezone: TZ,
|
|
45
|
+
cards: [],
|
|
46
|
+
});
|
|
47
|
+
assert.deepEqual(
|
|
48
|
+
range.days.map((d) => [d.date, d.cards.length]),
|
|
49
|
+
[
|
|
50
|
+
["2026-08-17", 0],
|
|
51
|
+
["2026-08-18", 0],
|
|
52
|
+
],
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("cards land on their dayKey; out-of-range cards are dropped", () => {
|
|
57
|
+
const range = okRange({
|
|
58
|
+
startDate: "2026-08-17",
|
|
59
|
+
endDate: "2026-08-18",
|
|
60
|
+
timezone: TZ,
|
|
61
|
+
cards: [
|
|
62
|
+
card({ id: "b", dayKey: "2026-08-18" }),
|
|
63
|
+
card({ id: "a", dayKey: "2026-08-17" }),
|
|
64
|
+
card({ id: "x", dayKey: "2026-08-16" }),
|
|
65
|
+
card({ id: "y", dayKey: "2026-08-19" }),
|
|
66
|
+
],
|
|
67
|
+
});
|
|
68
|
+
assert.deepEqual(
|
|
69
|
+
range.days.map((d) => d.cards.map((c) => c.id)),
|
|
70
|
+
[["a"], ["b"]],
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("determinism: same inputs, shuffled card order, identical JSON bytes", () => {
|
|
75
|
+
const cards = [
|
|
76
|
+
card({ id: "c2", dayKey: "2026-08-17" }),
|
|
77
|
+
card({ id: "c1", dayKey: "2026-08-18" }),
|
|
78
|
+
card({ id: "c3", dayKey: "2026-08-17" }),
|
|
79
|
+
];
|
|
80
|
+
const first = JSON.stringify(
|
|
81
|
+
exportDeterministicRecapRange({
|
|
82
|
+
startDate: "2026-08-17",
|
|
83
|
+
endDate: "2026-08-18",
|
|
84
|
+
timezone: TZ,
|
|
85
|
+
cards,
|
|
86
|
+
}),
|
|
87
|
+
);
|
|
88
|
+
const second = JSON.stringify(
|
|
89
|
+
exportDeterministicRecapRange({
|
|
90
|
+
startDate: "2026-08-17",
|
|
91
|
+
endDate: "2026-08-18",
|
|
92
|
+
timezone: TZ,
|
|
93
|
+
cards: [cards[1], cards[2], cards[0]],
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
assert.equal(first, second);
|
|
97
|
+
assert.equal(
|
|
98
|
+
first,
|
|
99
|
+
JSON.stringify(
|
|
100
|
+
exportDeterministicRecapRange({
|
|
101
|
+
startDate: "2026-08-17",
|
|
102
|
+
endDate: "2026-08-18",
|
|
103
|
+
timezone: TZ,
|
|
104
|
+
cards,
|
|
105
|
+
}),
|
|
106
|
+
),
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("privacy boundary: titles are omitted by default in range exports", () => {
|
|
111
|
+
const range = okRange({
|
|
112
|
+
startDate: "2026-08-17",
|
|
113
|
+
endDate: "2026-08-17",
|
|
114
|
+
timezone: TZ,
|
|
115
|
+
cards: [card({ id: "a", dayKey: "2026-08-17", title: "Secret Window Title" })],
|
|
116
|
+
});
|
|
117
|
+
const json = JSON.stringify(range);
|
|
118
|
+
assert.equal(json.includes("Secret Window Title"), false);
|
|
119
|
+
assert.equal(range.days[0].cards[0].title, undefined);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("privacy boundary: includeObservations keeps titles in range exports", () => {
|
|
123
|
+
const range = okRange({
|
|
124
|
+
startDate: "2026-08-17",
|
|
125
|
+
endDate: "2026-08-17",
|
|
126
|
+
timezone: TZ,
|
|
127
|
+
cards: [card({ id: "a", dayKey: "2026-08-17", title: "Secret Window Title" })],
|
|
128
|
+
includeObservations: true,
|
|
129
|
+
});
|
|
130
|
+
assert.equal(range.days[0].cards[0].title, "Secret Window Title");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("markdown: redacted days render card ids, never titles", () => {
|
|
134
|
+
const rendered = renderDeterministicJournalRange({
|
|
135
|
+
startDate: "2026-08-17",
|
|
136
|
+
endDate: "2026-08-17",
|
|
137
|
+
timezone: TZ,
|
|
138
|
+
cards: [card({ id: "card-a", dayKey: "2026-08-17", title: "Secret Window Title" })],
|
|
139
|
+
});
|
|
140
|
+
assert.ok(rendered.ok);
|
|
141
|
+
assert.ok(rendered.ok);
|
|
142
|
+
assert.equal(rendered.markdown.includes("Secret Window Title"), false);
|
|
143
|
+
assert.equal(rendered.markdown.includes("- 60m card-a"), true);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("markdown: a single-day range equals the single-day renderer", () => {
|
|
147
|
+
const cards = [card({ id: "a", dayKey: "2026-08-17", title: "Terminal" })];
|
|
148
|
+
const rendered = renderDeterministicJournalRange({
|
|
149
|
+
startDate: "2026-08-17",
|
|
150
|
+
endDate: "2026-08-17",
|
|
151
|
+
timezone: TZ,
|
|
152
|
+
cards,
|
|
153
|
+
includeObservations: true,
|
|
154
|
+
});
|
|
155
|
+
assert.ok(rendered.ok);
|
|
156
|
+
assert.ok(rendered.ok);
|
|
157
|
+
assert.equal(
|
|
158
|
+
rendered.markdown,
|
|
159
|
+
renderDeterministicJournal(cards, { date: "2026-08-17", timezone: TZ }),
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("markdown: multi-day ranges emit ascending per-day sections", () => {
|
|
164
|
+
const rendered = renderDeterministicJournalRange({
|
|
165
|
+
startDate: "2026-08-17",
|
|
166
|
+
endDate: "2026-08-19",
|
|
167
|
+
timezone: TZ,
|
|
168
|
+
cards: [],
|
|
169
|
+
});
|
|
170
|
+
assert.ok(rendered.ok);
|
|
171
|
+
assert.ok(rendered.ok);
|
|
172
|
+
assert.equal(rendered.dayCount, 3);
|
|
173
|
+
const headings = rendered.markdown
|
|
174
|
+
.split("\n")
|
|
175
|
+
.filter((line) => line.startsWith("# Journal — "));
|
|
176
|
+
assert.deepEqual(headings, [
|
|
177
|
+
"# Journal — 2026-08-17 (UTC)",
|
|
178
|
+
"# Journal — 2026-08-18 (UTC)",
|
|
179
|
+
"# Journal — 2026-08-19 (UTC)",
|
|
180
|
+
]);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("invalid and inverted ranges fail with typed errors", () => {
|
|
184
|
+
const cases: Array<
|
|
185
|
+
[Parameters<typeof exportDeterministicRecapRange>[0], string]
|
|
186
|
+
> = [
|
|
187
|
+
[{ startDate: "", endDate: "2026-08-18", timezone: TZ, cards: [] }, "invalid_start_date"],
|
|
188
|
+
[{ startDate: "2026-8-17", endDate: "2026-08-18", timezone: TZ, cards: [] }, "invalid_start_date"],
|
|
189
|
+
[{ startDate: "2026-02-30", endDate: "2026-03-01", timezone: TZ, cards: [] }, "invalid_start_date"],
|
|
190
|
+
[{ startDate: "2026-08-17", endDate: "2026-13-01", timezone: TZ, cards: [] }, "invalid_end_date"],
|
|
191
|
+
[{ startDate: "2026-08-18", endDate: "2026-08-17", timezone: TZ, cards: [] }, "end_before_start"],
|
|
192
|
+
];
|
|
193
|
+
for (const [options, error] of cases) {
|
|
194
|
+
const result = exportDeterministicRecapRange(options);
|
|
195
|
+
assert.equal(result.ok, false, JSON.stringify(options));
|
|
196
|
+
assert.ok(!result.ok);
|
|
197
|
+
assert.deepEqual(
|
|
198
|
+
{ error: result.error, limit: result.limit },
|
|
199
|
+
{ error, limit: undefined },
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("range bound: spans past the default 366 days fail with the limit", () => {
|
|
205
|
+
const result = exportDeterministicRecapRange({
|
|
206
|
+
startDate: "2026-01-01",
|
|
207
|
+
endDate: "2027-01-02",
|
|
208
|
+
timezone: TZ,
|
|
209
|
+
cards: [],
|
|
210
|
+
});
|
|
211
|
+
assert.ok(!result.ok);
|
|
212
|
+
assert.deepEqual(
|
|
213
|
+
{ error: result.error, limit: result.limit },
|
|
214
|
+
{ error: "range_too_large", limit: DEFAULT_RECAP_RANGE_MAX_DAYS },
|
|
215
|
+
);
|
|
216
|
+
// Exactly the bound still passes.
|
|
217
|
+
const atBound = exportDeterministicRecapRange({
|
|
218
|
+
startDate: "2026-01-01",
|
|
219
|
+
endDate: "2026-12-31",
|
|
220
|
+
timezone: TZ,
|
|
221
|
+
cards: [],
|
|
222
|
+
});
|
|
223
|
+
assert.ok(atBound.ok);
|
|
224
|
+
assert.ok(atBound.ok);
|
|
225
|
+
assert.equal(atBound.range.days.length, 365);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("range bound: maxDays override is enforced and validated", () => {
|
|
229
|
+
const denied = exportDeterministicRecapRange({
|
|
230
|
+
startDate: "2026-08-17",
|
|
231
|
+
endDate: "2026-08-20",
|
|
232
|
+
timezone: TZ,
|
|
233
|
+
cards: [],
|
|
234
|
+
maxDays: 2,
|
|
235
|
+
});
|
|
236
|
+
assert.ok(!denied.ok);
|
|
237
|
+
assert.equal(denied.error, "range_too_large");
|
|
238
|
+
assert.equal(denied.limit, 2);
|
|
239
|
+
assert.throws(
|
|
240
|
+
() =>
|
|
241
|
+
exportDeterministicRecapRange({
|
|
242
|
+
startDate: "2026-08-17",
|
|
243
|
+
endDate: "2026-08-17",
|
|
244
|
+
timezone: TZ,
|
|
245
|
+
cards: [],
|
|
246
|
+
maxDays: 0,
|
|
247
|
+
}),
|
|
248
|
+
RangeError,
|
|
249
|
+
);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test("a card spanning midnight attributes only to its stored dayKey", () => {
|
|
253
|
+
const range = okRange({
|
|
254
|
+
startDate: "2026-08-17",
|
|
255
|
+
endDate: "2026-08-18",
|
|
256
|
+
timezone: TZ,
|
|
257
|
+
cards: [
|
|
258
|
+
card({
|
|
259
|
+
id: "spans",
|
|
260
|
+
dayKey: "2026-08-17",
|
|
261
|
+
startUtc: "2026-08-17T23:00:00.000Z",
|
|
262
|
+
endUtc: "2026-08-18T01:00:00.000Z",
|
|
263
|
+
}),
|
|
264
|
+
],
|
|
265
|
+
includeObservations: true,
|
|
266
|
+
});
|
|
267
|
+
assert.deepEqual(
|
|
268
|
+
range.days.map((d) => d.cards.map((c) => c.id)),
|
|
269
|
+
[["spans"], []],
|
|
270
|
+
);
|
|
271
|
+
// The markdown render clips the spanning card to each day window: it
|
|
272
|
+
// contributes 60m to day 1 and nothing to day 2.
|
|
273
|
+
const day2 = renderDeterministicJournalRange({
|
|
274
|
+
startDate: "2026-08-18",
|
|
275
|
+
endDate: "2026-08-18",
|
|
276
|
+
timezone: TZ,
|
|
277
|
+
cards: [
|
|
278
|
+
card({
|
|
279
|
+
id: "spans",
|
|
280
|
+
dayKey: "2026-08-17",
|
|
281
|
+
startUtc: "2026-08-17T23:00:00.000Z",
|
|
282
|
+
endUtc: "2026-08-18T01:00:00.000Z",
|
|
283
|
+
}),
|
|
284
|
+
],
|
|
285
|
+
});
|
|
286
|
+
assert.ok(day2.ok);
|
|
287
|
+
assert.ok(day2.ok);
|
|
288
|
+
assert.equal(day2.markdown.includes("- 60m spans"), false);
|
|
289
|
+
});
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic recap export over a bounded date range (issue #2051).
|
|
3
|
+
*
|
|
4
|
+
* Pure: cards + inclusive [startDate, endDate] + timezone in, stable JSON or
|
|
5
|
+
* Markdown out. No LLM, no I/O. Every date in the range gets a day entry —
|
|
6
|
+
* empty days included — and cards land on their stored `dayKey`, so reruns
|
|
7
|
+
* with the same inputs always produce the same bytes regardless of input
|
|
8
|
+
* card order. Cards whose `dayKey` falls outside the range are not exported.
|
|
9
|
+
*
|
|
10
|
+
* The range is bounded: at most `maxDays` days (default 366) per call, so a
|
|
11
|
+
* swapped start/end or a multi-year span fails with a typed error instead of
|
|
12
|
+
* producing an unbounded document.
|
|
13
|
+
*/
|
|
14
|
+
import { isValidActivityDate } from "../digest.js";
|
|
15
|
+
import { parseRecapDate } from "./recap-date.js";
|
|
16
|
+
import { renderDeterministicJournal } from "./journal-recap.js";
|
|
17
|
+
import {
|
|
18
|
+
projectCardForRecapExport,
|
|
19
|
+
type RecapExportCard,
|
|
20
|
+
} from "./recap-export.js";
|
|
21
|
+
import type { TimelineCard } from "./types.js";
|
|
22
|
+
|
|
23
|
+
export const DEFAULT_RECAP_RANGE_MAX_DAYS = 366;
|
|
24
|
+
|
|
25
|
+
export interface DeterministicRecapRangeOptions {
|
|
26
|
+
/** Inclusive first local day, YYYY-MM-DD. */
|
|
27
|
+
startDate: string;
|
|
28
|
+
/** Inclusive last local day, YYYY-MM-DD. */
|
|
29
|
+
endDate: string;
|
|
30
|
+
timezone: string;
|
|
31
|
+
cards: readonly TimelineCard[];
|
|
32
|
+
/** Include observation-derived card content (`title`). Default false. */
|
|
33
|
+
includeObservations?: boolean;
|
|
34
|
+
/** Hard upper bound on exported days; default 366. */
|
|
35
|
+
maxDays?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface DeterministicRecapDay {
|
|
39
|
+
date: string;
|
|
40
|
+
timezone: string;
|
|
41
|
+
cards: RecapExportCard[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface DeterministicRecapRange {
|
|
45
|
+
startDate: string;
|
|
46
|
+
endDate: string;
|
|
47
|
+
timezone: string;
|
|
48
|
+
days: DeterministicRecapDay[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type DeterministicRecapRangeResult =
|
|
52
|
+
| { ok: true; range: DeterministicRecapRange }
|
|
53
|
+
| {
|
|
54
|
+
ok: false;
|
|
55
|
+
error:
|
|
56
|
+
| "invalid_start_date"
|
|
57
|
+
| "invalid_end_date"
|
|
58
|
+
| "end_before_start"
|
|
59
|
+
| "range_too_large";
|
|
60
|
+
/** The enforced day bound, present on range_too_large. */
|
|
61
|
+
limit?: number;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type DeterministicRecapRangeMarkdownResult =
|
|
65
|
+
| { ok: true; markdown: string; dayCount: number }
|
|
66
|
+
| Extract<DeterministicRecapRangeResult, { ok: false }>;
|
|
67
|
+
|
|
68
|
+
function compareCardIds(a: RecapExportCard, b: RecapExportCard): number {
|
|
69
|
+
if (a.id < b.id) return -1;
|
|
70
|
+
if (a.id > b.id) return 1;
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** UTC-midnight stepping over validated real calendar dates. */
|
|
75
|
+
function* isoDays(startDate: string, endDate: string): Generator<string> {
|
|
76
|
+
const endMs = Date.parse(`${endDate}T00:00:00Z`);
|
|
77
|
+
let cursor = new Date(`${startDate}T00:00:00Z`);
|
|
78
|
+
while (cursor.getTime() <= endMs) {
|
|
79
|
+
yield cursor.toISOString().slice(0, 10);
|
|
80
|
+
cursor = new Date(cursor.getTime() + 86_400_000);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function dayCount(startDate: string, endDate: string): number {
|
|
85
|
+
return (
|
|
86
|
+
(Date.parse(`${endDate}T00:00:00Z`) - Date.parse(`${startDate}T00:00:00Z`)) /
|
|
87
|
+
86_400_000 +
|
|
88
|
+
1
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Build the byte-stable JSON recap document for an inclusive local-day
|
|
94
|
+
* range. Day entries are ascending; day cards are sorted by id; per-card
|
|
95
|
+
* key order is fixed by `projectCardForRecapExport`.
|
|
96
|
+
*/
|
|
97
|
+
export function exportDeterministicRecapRange(
|
|
98
|
+
options: DeterministicRecapRangeOptions,
|
|
99
|
+
): DeterministicRecapRangeResult {
|
|
100
|
+
const start = parseRecapDate(options.startDate);
|
|
101
|
+
if (!start.ok || !isValidActivityDate(start.date)) {
|
|
102
|
+
return { ok: false, error: "invalid_start_date" };
|
|
103
|
+
}
|
|
104
|
+
const end = parseRecapDate(options.endDate);
|
|
105
|
+
if (!end.ok || !isValidActivityDate(end.date)) {
|
|
106
|
+
return { ok: false, error: "invalid_end_date" };
|
|
107
|
+
}
|
|
108
|
+
if (Date.parse(`${end.date}T00:00:00Z`) < Date.parse(`${start.date}T00:00:00Z`)) {
|
|
109
|
+
return { ok: false, error: "end_before_start" };
|
|
110
|
+
}
|
|
111
|
+
const limit = options.maxDays ?? DEFAULT_RECAP_RANGE_MAX_DAYS;
|
|
112
|
+
if (!Number.isInteger(limit) || limit < 1) {
|
|
113
|
+
throw new RangeError(`maxDays must be a positive integer; got ${options.maxDays}`);
|
|
114
|
+
}
|
|
115
|
+
if (dayCount(start.date, end.date) > limit) {
|
|
116
|
+
return { ok: false, error: "range_too_large", limit };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const includeObservations = options.includeObservations === true;
|
|
120
|
+
const byDay = new Map<string, RecapExportCard[]>();
|
|
121
|
+
for (const card of options.cards) {
|
|
122
|
+
if (card.dayKey < start.date || card.dayKey > end.date) continue;
|
|
123
|
+
const bucket = byDay.get(card.dayKey);
|
|
124
|
+
const projected = projectCardForRecapExport(card, includeObservations);
|
|
125
|
+
if (bucket === undefined) byDay.set(card.dayKey, [projected]);
|
|
126
|
+
else bucket.push(projected);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const days: DeterministicRecapDay[] = [];
|
|
130
|
+
for (const date of isoDays(start.date, end.date)) {
|
|
131
|
+
days.push({
|
|
132
|
+
date,
|
|
133
|
+
timezone: options.timezone,
|
|
134
|
+
cards: (byDay.get(date) ?? []).sort(compareCardIds),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
ok: true,
|
|
139
|
+
range: {
|
|
140
|
+
startDate: start.date,
|
|
141
|
+
endDate: end.date,
|
|
142
|
+
timezone: options.timezone,
|
|
143
|
+
days,
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Render the byte-stable Markdown recap for an inclusive local-day range:
|
|
150
|
+
* one `renderDeterministicJournal` section per day, ascending. Validation
|
|
151
|
+
* and bounds match `exportDeterministicRecapRange`.
|
|
152
|
+
*/
|
|
153
|
+
export function renderDeterministicJournalRange(
|
|
154
|
+
options: DeterministicRecapRangeOptions,
|
|
155
|
+
): DeterministicRecapRangeMarkdownResult {
|
|
156
|
+
const exported = exportDeterministicRecapRange(options);
|
|
157
|
+
if (!exported.ok) return exported;
|
|
158
|
+
const sections = exported.range.days.map((day) =>
|
|
159
|
+
renderDeterministicJournal(day.cards, {
|
|
160
|
+
date: day.date,
|
|
161
|
+
timezone: day.timezone,
|
|
162
|
+
}),
|
|
163
|
+
);
|
|
164
|
+
return {
|
|
165
|
+
ok: true,
|
|
166
|
+
markdown: sections.join("\n"),
|
|
167
|
+
dayCount: exported.range.days.length,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
@@ -2,7 +2,10 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
import test from "node:test";
|
|
3
3
|
|
|
4
4
|
import type { TimelineCard } from "./types.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
exportDeterministicRecap,
|
|
7
|
+
projectCardForRecapExport,
|
|
8
|
+
} from "./recap-export.js";
|
|
6
9
|
|
|
7
10
|
const DATE = "2026-08-17";
|
|
8
11
|
|
|
@@ -76,3 +79,72 @@ test("input cards are not mutated and reruns are stable", () => {
|
|
|
76
79
|
assert.deepEqual(input.map((c) => c.id), ["card-b", "card-a"]);
|
|
77
80
|
assert.equal(JSON.stringify(first), JSON.stringify(second));
|
|
78
81
|
});
|
|
82
|
+
|
|
83
|
+
test("privacy boundary: default export omits observation-derived titles", () => {
|
|
84
|
+
const recap = exportDeterministicRecap({
|
|
85
|
+
date: DATE,
|
|
86
|
+
timezone: "UTC",
|
|
87
|
+
cards: [card({ id: "card-a", title: "Secret Window Title" })],
|
|
88
|
+
});
|
|
89
|
+
const json = JSON.stringify(recap);
|
|
90
|
+
assert.equal(json.includes("Secret Window Title"), false);
|
|
91
|
+
assert.equal(recap.cards[0].title, undefined);
|
|
92
|
+
// Evidence references survive: the export points at content, never copies it.
|
|
93
|
+
assert.deepEqual(recap.cards[0].evidenceIds, [1]);
|
|
94
|
+
assert.equal(recap.cards[0].dayKey, DATE);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("privacy boundary: includeObservations keeps the title", () => {
|
|
98
|
+
const recap = exportDeterministicRecap({
|
|
99
|
+
date: DATE,
|
|
100
|
+
timezone: "UTC",
|
|
101
|
+
cards: [card({ id: "card-a", title: "Secret Window Title" })],
|
|
102
|
+
includeObservations: true,
|
|
103
|
+
});
|
|
104
|
+
assert.equal(recap.cards[0].title, "Secret Window Title");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("manualEdit provenance is kept and sorts last in the projected card", () => {
|
|
108
|
+
const projected = projectCardForRecapExport(
|
|
109
|
+
card({
|
|
110
|
+
id: "card-a",
|
|
111
|
+
manualEdit: { categoryId: "focus", editedAtUtc: "2026-08-17T12:00:00.000Z" },
|
|
112
|
+
}),
|
|
113
|
+
false,
|
|
114
|
+
);
|
|
115
|
+
assert.equal(projected.manualEdit?.categoryId, "focus");
|
|
116
|
+
assert.equal(Object.keys(projected).at(-1), "manualEdit");
|
|
117
|
+
});
|
|
118
|
+
test("projectCardForRecapExport emits a fixed key order without the title", () => {
|
|
119
|
+
const projected = projectCardForRecapExport(card({ id: "card-a" }), false);
|
|
120
|
+
assert.deepEqual(Object.keys(projected), [
|
|
121
|
+
"id",
|
|
122
|
+
"kind",
|
|
123
|
+
"summary",
|
|
124
|
+
"categoryId",
|
|
125
|
+
"confidence",
|
|
126
|
+
"startUtc",
|
|
127
|
+
"endUtc",
|
|
128
|
+
"dayKey",
|
|
129
|
+
"timezone",
|
|
130
|
+
"machine",
|
|
131
|
+
"evidenceIds",
|
|
132
|
+
"evidenceRange",
|
|
133
|
+
]);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
test("projected exports are byte-identical across reruns and shuffled input", () => {
|
|
138
|
+
const cards = [card({ id: "c3" }), card({ id: "c1" }), card({ id: "c2" })];
|
|
139
|
+
const first = JSON.stringify(
|
|
140
|
+
exportDeterministicRecap({ date: DATE, timezone: "UTC", cards }),
|
|
141
|
+
);
|
|
142
|
+
const second = JSON.stringify(
|
|
143
|
+
exportDeterministicRecap({
|
|
144
|
+
date: DATE,
|
|
145
|
+
timezone: "UTC",
|
|
146
|
+
cards: [cards[2], cards[0], cards[1]],
|
|
147
|
+
}),
|
|
148
|
+
);
|
|
149
|
+
assert.equal(first, second);
|
|
150
|
+
});
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
* Pure: cards + date + timezone in, stable JSON out. No LLM, no I/O, no
|
|
5
5
|
* persistence. Same cards always serialize to the same bytes, regardless of
|
|
6
6
|
* input array order: cards are sorted by id before serialization.
|
|
7
|
+
*
|
|
8
|
+
* Privacy boundary (issue #2053 policy): a card `title` is captured
|
|
9
|
+
* observation content (the source window title). It is excluded unless the
|
|
10
|
+
* export explicitly permits observations — the same default as
|
|
11
|
+
* `activity.exportIncludeObservations`. Evidence references (store row ids,
|
|
12
|
+
* identity hashes) are always kept: they point at content without copying it.
|
|
7
13
|
*/
|
|
8
14
|
import type { TimelineCard } from "./types.js";
|
|
9
15
|
|
|
@@ -11,15 +17,58 @@ export interface DeterministicRecapOptions {
|
|
|
11
17
|
date: string;
|
|
12
18
|
timezone: string;
|
|
13
19
|
cards: readonly TimelineCard[];
|
|
20
|
+
/**
|
|
21
|
+
* Include observation-derived card content (`title`). Default false,
|
|
22
|
+
* matching the `activity.exportIncludeObservations` policy default.
|
|
23
|
+
*/
|
|
24
|
+
includeObservations?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Card projected for export: `title` present only when the policy permits. */
|
|
28
|
+
export interface RecapExportCard extends Omit<TimelineCard, "title"> {
|
|
29
|
+
title?: string;
|
|
14
30
|
}
|
|
15
31
|
|
|
16
32
|
export interface DeterministicRecap {
|
|
17
33
|
date: string;
|
|
18
34
|
timezone: string;
|
|
19
|
-
cards:
|
|
35
|
+
cards: RecapExportCard[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Project one card for export with a fixed key order. Observation-derived
|
|
40
|
+
* `title` is dropped unless `includeObservations`; user-authored provenance
|
|
41
|
+
* (manual edits, pause reasons inside `summary`) stays, and evidence
|
|
42
|
+
* references always stay.
|
|
43
|
+
*/
|
|
44
|
+
export function projectCardForRecapExport(
|
|
45
|
+
card: TimelineCard,
|
|
46
|
+
includeObservations: boolean,
|
|
47
|
+
): RecapExportCard {
|
|
48
|
+
const projected: RecapExportCard = {
|
|
49
|
+
id: card.id,
|
|
50
|
+
kind: card.kind,
|
|
51
|
+
summary: card.summary,
|
|
52
|
+
categoryId: card.categoryId,
|
|
53
|
+
confidence: card.confidence,
|
|
54
|
+
startUtc: card.startUtc,
|
|
55
|
+
endUtc: card.endUtc,
|
|
56
|
+
dayKey: card.dayKey,
|
|
57
|
+
timezone: card.timezone,
|
|
58
|
+
machine: card.machine,
|
|
59
|
+
evidenceIds: card.evidenceIds,
|
|
60
|
+
evidenceRange: card.evidenceRange,
|
|
61
|
+
};
|
|
62
|
+
if (card.manualEdit !== undefined) {
|
|
63
|
+
projected.manualEdit = card.manualEdit;
|
|
64
|
+
}
|
|
65
|
+
if (includeObservations) {
|
|
66
|
+
projected.title = card.title;
|
|
67
|
+
}
|
|
68
|
+
return projected;
|
|
20
69
|
}
|
|
21
70
|
|
|
22
|
-
function compareCardIds(a:
|
|
71
|
+
function compareCardIds(a: RecapExportCard, b: RecapExportCard): number {
|
|
23
72
|
if (a.id < b.id) return -1;
|
|
24
73
|
if (a.id > b.id) return 1;
|
|
25
74
|
return 0;
|
|
@@ -28,14 +77,18 @@ function compareCardIds(a: TimelineCard, b: TimelineCard): number {
|
|
|
28
77
|
/**
|
|
29
78
|
* Build the byte-stable JSON recap document for one local day.
|
|
30
79
|
* Callers may `JSON.stringify` the returned object; construction order
|
|
31
|
-
* (date, timezone, cards) is fixed, so
|
|
80
|
+
* (date, timezone, cards, and the per-card key order) is fixed, so
|
|
81
|
+
* serialization is deterministic.
|
|
32
82
|
*/
|
|
33
83
|
export function exportDeterministicRecap(
|
|
34
84
|
options: DeterministicRecapOptions,
|
|
35
85
|
): DeterministicRecap {
|
|
86
|
+
const includeObservations = options.includeObservations === true;
|
|
36
87
|
return {
|
|
37
88
|
date: options.date,
|
|
38
89
|
timezone: options.timezone,
|
|
39
|
-
cards:
|
|
90
|
+
cards: options.cards
|
|
91
|
+
.map((card) => projectCardForRecapExport(card, includeObservations))
|
|
92
|
+
.sort(compareCardIds),
|
|
40
93
|
};
|
|
41
94
|
}
|