@remnic/core 9.69.28 → 9.69.30
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 +1 -1
- package/dist/access-admin-ops-surface.js +58 -58
- package/dist/access-audit.js +2 -2
- package/dist/access-authorization-probe.d.ts +1 -1
- package/dist/access-authorization-probe.js +59 -59
- package/dist/access-boundary.d.ts +1 -1
- package/dist/access-boundary.js +58 -58
- package/dist/access-cli.js +133 -132
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.js +4 -4
- package/dist/access-extraction-force-flush.d.ts +1 -1
- package/dist/access-extraction-force-flush.js +58 -58
- package/dist/access-http-briefing.d.ts +1 -1
- package/dist/access-http-briefing.js +59 -59
- package/dist/access-http-lcm-compaction.d.ts +1 -1
- package/dist/access-http-lifecycle-flush.d.ts +1 -1
- package/dist/access-http-offline-stream.d.ts +1 -1
- package/dist/access-http-query.js +60 -60
- package/dist/access-http.d.ts +2 -2
- package/dist/access-http.js +76 -76
- package/dist/access-identity-continuity-surface.js +58 -58
- package/dist/access-lcm-surface.d.ts +1 -1
- package/dist/access-lcm-surface.js +58 -58
- package/dist/access-mcp.d.ts +1 -1
- package/dist/access-mcp.js +66 -66
- package/dist/access-namespace-preflight.js +58 -58
- package/dist/access-observe-transcript.js +4 -4
- package/dist/access-observe-write-surface.d.ts +1 -1
- package/dist/access-observe-write-surface.js +58 -58
- package/dist/access-offline-manifest.js +8 -8
- package/dist/access-operations-batch.js +60 -60
- package/dist/access-operations.d.ts +6 -6
- package/dist/access-operations.js +65 -65
- package/dist/access-recall-concurrency.d.ts +1 -1
- package/dist/access-recall-concurrency.js +58 -58
- package/dist/access-recall-response.d.ts +1 -1
- package/dist/access-recall-response.js +58 -58
- package/dist/access-recall-surface.d.ts +1 -1
- package/dist/access-recall-surface.js +58 -58
- package/dist/access-schema.d.ts +91 -91
- package/dist/access-schema.js +3 -3
- package/dist/access-service-helpers.d.ts +1 -1
- package/dist/access-service.d.ts +1 -1
- package/dist/access-service.js +58 -58
- package/dist/access-surface-catalog.d.ts +1 -1
- package/dist/access-surface-catalog.js +60 -60
- package/dist/active-recall.js +11 -11
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/{auto-sync-WNGG2GC2.js → auto-sync-NSHLUAQI.js} +7 -7
- package/dist/briefing.js +19 -19
- package/dist/buffer.js +9 -9
- package/dist/calibration.js +4 -4
- package/dist/causal-consolidation.js +21 -21
- package/dist/{chunk-OO42R444.js → chunk-2MFH376S.js} +3 -3
- package/dist/{chunk-NXH34IPL.js → chunk-353KGBKY.js} +2 -2
- package/dist/{chunk-DZD3WGCD.js → chunk-3JVLGJCY.js} +2 -2
- package/dist/{chunk-NOPN47AL.js → chunk-47DEYNMR.js} +2 -2
- package/dist/chunk-4NZQ7IID.js +63 -0
- package/dist/chunk-4NZQ7IID.js.map +1 -0
- package/dist/{chunk-2OO6TPQG.js → chunk-4UDQUPT5.js} +2 -2
- package/dist/{chunk-IE57QQSZ.js → chunk-565C6ZFO.js} +2 -2
- package/dist/{chunk-C6XEXTSJ.js → chunk-5ABN4WVL.js} +44 -44
- package/dist/{chunk-W7OU4I3Y.js → chunk-666OOKB7.js} +2 -2
- package/dist/{chunk-EYIEWJNI.js → chunk-6KH5NLQS.js} +2 -2
- package/dist/{chunk-R55WAWS3.js → chunk-7DUFJAOE.js} +40 -40
- package/dist/{chunk-EMDLM3LW.js → chunk-7IRZK6MM.js} +2 -2
- package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
- package/dist/{chunk-RFWEDCRC.js → chunk-7VJXIDOC.js} +12 -12
- package/dist/{chunk-IVKIODHO.js → chunk-A7XEPMQ6.js} +5 -5
- package/dist/{chunk-K6MV3TRQ.js → chunk-ADXCCZL2.js} +2 -2
- package/dist/{chunk-GC65K6DI.js → chunk-AOCP6JA7.js} +4 -4
- package/dist/{chunk-JBPKEARU.js → chunk-AU7Q3LSC.js} +4 -4
- package/dist/{chunk-ND6IQGSZ.js → chunk-BA6WOZOT.js} +2 -2
- package/dist/{chunk-JI7U6AS3.js → chunk-C6FQJ52H.js} +2 -2
- package/dist/{chunk-IN673LEP.js → chunk-CARRTDKC.js} +2 -2
- package/dist/{chunk-HLTAZTN7.js → chunk-CBCNKKZD.js} +2 -2
- package/dist/{chunk-DXFG2VGN.js → chunk-CGC5UQCF.js} +2 -2
- package/dist/{chunk-YSSAGB2O.js → chunk-CLLPJ6QT.js} +5 -5
- package/dist/{chunk-U6S754L6.js → chunk-D5LORF7A.js} +3 -3
- package/dist/{chunk-C24UZSFW.js → chunk-DBQWVT2H.js} +2 -2
- package/dist/{chunk-XSTNGNJP.js → chunk-DCJ3YFIC.js} +2 -2
- package/dist/{chunk-2YDWI2LO.js → chunk-DITMGZOL.js} +2 -2
- package/dist/{chunk-LVE64P5Y.js → chunk-E2ZHGBAK.js} +2 -2
- package/dist/{chunk-WW3MR6T3.js → chunk-ENMTJRXA.js} +7 -7
- package/dist/{chunk-COUYFFID.js → chunk-EYMOJ3J6.js} +2 -2
- package/dist/{chunk-INBOGQ3E.js → chunk-EZZV7OQL.js} +2 -2
- package/dist/{chunk-MT47LH5L.js → chunk-FBMYGNOC.js} +2 -2
- package/dist/{chunk-N3SS45OW.js → chunk-FCSZ4K2X.js} +3 -3
- package/dist/{chunk-TWF35IC6.js → chunk-FDLDOEO6.js} +28 -23
- package/dist/chunk-FDLDOEO6.js.map +1 -0
- package/dist/{chunk-PKS56ZRR.js → chunk-FGGYSN4P.js} +2 -2
- package/dist/{chunk-ZMNT26KV.js → chunk-FHQSPTPZ.js} +2 -2
- package/dist/{chunk-6GUG4YNM.js → chunk-GGRRF4PZ.js} +2 -2
- package/dist/{chunk-YIHKAUS4.js → chunk-GTWHVXPA.js} +3 -3
- package/dist/{chunk-UY2RORVF.js → chunk-GVG3JYBI.js} +4 -4
- package/dist/{chunk-I3OQBP23.js → chunk-GY5WZBA6.js} +2 -2
- package/dist/{chunk-3GCK6ONU.js → chunk-HK32G473.js} +2 -2
- package/dist/{chunk-OVAJKCN3.js → chunk-HY55QQD7.js} +2 -2
- package/dist/{chunk-YJETZFLJ.js → chunk-I27RSQRR.js} +2 -2
- package/dist/{chunk-QIEUU4UK.js → chunk-I55KAVET.js} +2 -2
- package/dist/{chunk-UY7VPC6Q.js → chunk-IA2YSHTX.js} +15 -15
- package/dist/{chunk-UEEN7GXR.js → chunk-IY2FVXM6.js} +3 -3
- package/dist/{chunk-NVOFMARR.js → chunk-JDDXXZWW.js} +2 -2
- package/dist/{chunk-2AMEUKCG.js → chunk-JEIXTYVG.js} +2 -2
- package/dist/{chunk-ODW5GDFE.js → chunk-JT3EB7ZL.js} +2 -2
- package/dist/{chunk-XR67IAXP.js → chunk-KLMESRPV.js} +5 -5
- package/dist/{chunk-7LCGFUMB.js → chunk-KQAFEZQX.js} +4 -4
- package/dist/{chunk-3K7V3HE6.js → chunk-KXRX7YC2.js} +2 -2
- package/dist/{chunk-7RZJWZ46.js → chunk-LEPOP46W.js} +5 -5
- package/dist/{chunk-54WHLA65.js → chunk-LRICZIGN.js} +3 -3
- package/dist/{chunk-EWCNCQOU.js → chunk-LWA7MDVO.js} +2 -2
- package/dist/{chunk-EZKSOM5K.js → chunk-MFJBANPX.js} +2 -2
- package/dist/{chunk-OB3XMWX5.js → chunk-MKWKYHXJ.js} +4 -4
- package/dist/{chunk-HMKPFW7R.js → chunk-MPAJFFP3.js} +2 -2
- package/dist/{chunk-4P43SE4H.js → chunk-MPYD657E.js} +2 -2
- package/dist/{chunk-NLDVVWCL.js → chunk-NDNTNE3S.js} +2 -2
- package/dist/{chunk-5ISVONB7.js → chunk-NWWXSJX5.js} +2 -2
- package/dist/{chunk-QBC33MPY.js → chunk-NZXEK3UF.js} +2 -2
- package/dist/{chunk-MYB6DWE5.js → chunk-OGELWNYC.js} +6 -6
- package/dist/{chunk-IES4QHLM.js → chunk-OXNU333D.js} +5 -5
- package/dist/{chunk-JUC24CTX.js → chunk-P2QRMMVQ.js} +6 -1
- package/dist/chunk-P2QRMMVQ.js.map +1 -0
- package/dist/{chunk-MSSJSC2V.js → chunk-PEOTOFH5.js} +2 -2
- package/dist/{chunk-OYHGTHVX.js → chunk-PHNAB54Q.js} +2 -2
- package/dist/{chunk-R5T5FB2R.js → chunk-PLBW64UM.js} +62 -62
- package/dist/{chunk-BD7JTBYP.js → chunk-PSPABFN2.js} +4 -4
- package/dist/{chunk-WOOTZ6DH.js → chunk-PV36INNL.js} +3 -3
- package/dist/{chunk-QW3FMKT2.js → chunk-QDY6KYTN.js} +3 -3
- package/dist/{chunk-6TZWGQTT.js → chunk-RAVRDTP7.js} +5 -5
- package/dist/{chunk-BIVJCVT2.js → chunk-RBGREYVJ.js} +2 -2
- package/dist/{chunk-GGRD3JEH.js → chunk-ROGRI25A.js} +2 -2
- package/dist/{chunk-HTPQJ32S.js → chunk-ROKKIMON.js} +2 -2
- package/dist/{chunk-5KND6CSX.js → chunk-RSVEP77Y.js} +2 -2
- package/dist/{chunk-SV4Z2S67.js → chunk-S5G2LAL7.js} +4 -4
- package/dist/{chunk-5PTRLTK2.js → chunk-S65WXHNK.js} +2 -2
- package/dist/{chunk-XPFC6D45.js → chunk-S7DPKM5W.js} +41 -31
- package/dist/chunk-S7DPKM5W.js.map +1 -0
- package/dist/{chunk-3FEH4C4V.js → chunk-SB6PSOP7.js} +1 -1
- package/dist/{chunk-S2DU3UBN.js → chunk-SH2ZWEWB.js} +6 -6
- package/dist/{chunk-Z5XE7AMC.js → chunk-SMOFBBPU.js} +2 -2
- package/dist/{chunk-GRCREL6Q.js → chunk-SQJ3SDIW.js} +11 -11
- package/dist/{chunk-YFDJVB2K.js → chunk-T7CJQVRZ.js} +2 -2
- package/dist/{chunk-EIJR4PZL.js → chunk-TEYN7ZYF.js} +5 -5
- package/dist/{chunk-JALOAKSZ.js → chunk-TLPZ6MKZ.js} +4 -4
- package/dist/{chunk-BHHONFSK.js → chunk-U34EHBPL.js} +2 -2
- package/dist/{chunk-DFEODULB.js → chunk-V2HHAAPI.js} +2 -2
- package/dist/{chunk-KEF46KL2.js → chunk-V6EGNVUT.js} +3 -3
- package/dist/{chunk-ESNFSSO4.js → chunk-VGXM5B4H.js} +2 -2
- package/dist/{chunk-MJUCDM3C.js → chunk-VLXBE57O.js} +2 -2
- package/dist/{chunk-YGTSOVCR.js → chunk-VP67GZ7T.js} +2 -2
- package/dist/{chunk-ALBYEXFX.js → chunk-VZWXFXLX.js} +2 -2
- package/dist/{chunk-NC7RM2XS.js → chunk-W64HKJJM.js} +3 -3
- package/dist/{chunk-OMLGLMWL.js → chunk-WHBVXTUI.js} +9 -9
- package/dist/{chunk-4KMGFWQY.js → chunk-WJBZMNNS.js} +8 -8
- package/dist/{chunk-WFZBRS6N.js → chunk-X74UAWSI.js} +2 -2
- package/dist/{chunk-EGALNSZ4.js → chunk-XU6OEECT.js} +3 -3
- package/dist/{chunk-4FIH6MPS.js → chunk-YHLWPYHT.js} +3 -3
- package/dist/{chunk-PAZY2ZKP.js → chunk-YQAXP5AC.js} +2 -2
- package/dist/{chunk-ZNR5SVUI.js → chunk-YUMDFDUA.js} +3 -3
- package/dist/{chunk-7HYPN2GC.js → chunk-ZG74PWRW.js} +2 -2
- package/dist/{chunk-TDYAIXHK.js → chunk-ZHXSOMYH.js} +4 -4
- package/dist/{chunk-TNSCIPBQ.js → chunk-ZNJSBIP4.js} +4 -4
- package/dist/{cli-BqMNkQn5.d.ts → cli-DD0P-lu8.d.ts} +1 -1
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +101 -101
- package/dist/coding/export-okf-codegraph.js +21 -21
- package/dist/compounding/engine.js +20 -20
- package/dist/config-discovery.d.ts +26 -0
- package/dist/config-discovery.js +11 -0
- package/dist/config-security.js +2 -2
- package/dist/config.js +11 -11
- package/dist/connectors/codex-materialize-runner.js +20 -20
- package/dist/connectors/codex-materialize.js +3 -3
- package/dist/connectors/index.js +23 -23
- package/dist/convergence-refresh.js +21 -21
- package/dist/conversation-index/backend.js +2 -2
- package/dist/corpus-watermark.js +21 -21
- package/dist/deep-recall-http-glue.d.ts +1 -1
- package/dist/deep-recall-http-glue.js +4 -4
- package/dist/deep-recall-mcp-tools.d.ts +1 -1
- package/dist/deep-recall-policy-llm.js +5 -5
- package/dist/deep-recall.js +2 -2
- package/dist/embedding-fallback.js +2 -2
- package/dist/emit-legacy-tools.js +3 -3
- package/dist/entity-retrieval.js +19 -19
- package/dist/external-wiki-access.d.ts +1 -1
- package/dist/external-wiki-access.js +59 -59
- package/dist/external-wiki-config.js +3 -3
- package/dist/external-wiki-mcp-tools.d.ts +1 -1
- package/dist/extraction-faithfulness.js +5 -5
- package/dist/extraction-judge.js +5 -5
- package/dist/extraction-source-grounding.js +3 -3
- package/dist/extraction.js +34 -34
- package/dist/fallback-llm.js +4 -4
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/index.d.ts +680 -678
- package/dist/index.js +151 -142
- package/dist/live-connectors-runner.js +5 -5
- package/dist/local-llm.js +3 -3
- package/dist/location/index.js +24 -24
- package/dist/maintenance/memory-governance.js +19 -19
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +19 -19
- package/dist/maintenance/rebuild-memory-projection.js +20 -20
- package/dist/mcp-memory-inspector-app.d.ts +1 -1
- package/dist/memory-subject-cli.d.ts +1 -1
- package/dist/memory-subject.d.ts +1 -1
- package/dist/migrate/from-engram.js +2 -2
- package/dist/namespaces/migrate.js +20 -20
- package/dist/namespaces/search.js +11 -11
- package/dist/namespaces/storage.js +19 -19
- package/dist/offline-sync-impression-drain.js +6 -6
- package/dist/operator-doctor-corpus.js +22 -22
- package/dist/operator-toolkit.js +38 -38
- package/dist/opik-exporter.js +1 -1
- package/dist/orchestration/maintenance.js +33 -33
- package/dist/orchestrator.js +133 -132
- package/dist/provenance.js +2 -2
- package/dist/{public-http-ByX2eTla.d.ts → public-http-C4i8Opxc.d.ts} +1 -1
- package/dist/qmd.js +2 -2
- package/dist/recall-planner-llm.js +4 -4
- package/dist/reconcile/manifest.js +1 -1
- package/dist/resolve-provider-secret.js +2 -2
- package/dist/resume-bundles.js +12 -12
- package/dist/runtime/env.d.ts +9 -1
- package/dist/runtime/env.js +3 -1
- package/dist/schemas.d.ts +152 -152
- package/dist/sdk-compat.js +1 -1
- package/dist/search/factory.js +10 -10
- package/dist/search/index.js +15 -15
- package/dist/search/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/orama-backend.js +2 -2
- package/dist/semantic-consolidation.js +21 -21
- package/dist/semantic-rule-promotion.js +19 -19
- package/dist/semantic-rule-verifier.js +19 -19
- package/dist/shared-context/manager.d.ts +6 -6
- package/dist/shared-context/manager.js +3 -3
- package/dist/source-agent-qualifier.js +31 -31
- package/dist/standup/build.js +20 -20
- package/dist/{state-store-Z3EN56O5.js → state-store-I5HLZTZT.js} +4 -4
- package/dist/state-store-I5HLZTZT.js.map +1 -0
- package/dist/storage.js +18 -18
- package/dist/summarizer.js +7 -7
- package/dist/support-passport/index.d.ts +4 -4
- package/dist/support-passport/index.js +61 -61
- package/dist/tokens.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/transfer/export-okf.js +20 -20
- package/dist/transfer/types.d.ts +78 -78
- package/dist/utils/path.js +2 -2
- package/dist/verified-recall.js +19 -19
- package/dist/who-knows-cli.d.ts +1 -1
- package/dist/who-knows-cli.js +20 -20
- package/dist/who-knows.d.ts +1 -1
- package/dist/who-knows.js +19 -19
- package/package.json +2 -2
- package/src/activity/digest.test.ts +107 -1
- package/src/activity/digest.ts +76 -51
- package/src/config-discovery.test.ts +63 -0
- package/src/config-discovery.ts +90 -0
- package/src/index.ts +2 -0
- package/src/reconcile/manifest.ts +59 -50
- package/src/runtime/env.ts +11 -0
- package/dist/chunk-JUC24CTX.js.map +0 -1
- package/dist/chunk-TWF35IC6.js.map +0 -1
- package/dist/chunk-XPFC6D45.js.map +0 -1
- package/dist/{access-service-GrdVg_-Z.d.ts → access-service-DWdY9Mlk.d.ts} +58 -58
- /package/dist/{auto-sync-WNGG2GC2.js.map → auto-sync-NSHLUAQI.js.map} +0 -0
- /package/dist/{chunk-OO42R444.js.map → chunk-2MFH376S.js.map} +0 -0
- /package/dist/{chunk-NXH34IPL.js.map → chunk-353KGBKY.js.map} +0 -0
- /package/dist/{chunk-DZD3WGCD.js.map → chunk-3JVLGJCY.js.map} +0 -0
- /package/dist/{chunk-NOPN47AL.js.map → chunk-47DEYNMR.js.map} +0 -0
- /package/dist/{chunk-2OO6TPQG.js.map → chunk-4UDQUPT5.js.map} +0 -0
- /package/dist/{chunk-IE57QQSZ.js.map → chunk-565C6ZFO.js.map} +0 -0
- /package/dist/{chunk-C6XEXTSJ.js.map → chunk-5ABN4WVL.js.map} +0 -0
- /package/dist/{chunk-W7OU4I3Y.js.map → chunk-666OOKB7.js.map} +0 -0
- /package/dist/{chunk-EYIEWJNI.js.map → chunk-6KH5NLQS.js.map} +0 -0
- /package/dist/{chunk-R55WAWS3.js.map → chunk-7DUFJAOE.js.map} +0 -0
- /package/dist/{chunk-EMDLM3LW.js.map → chunk-7IRZK6MM.js.map} +0 -0
- /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
- /package/dist/{chunk-RFWEDCRC.js.map → chunk-7VJXIDOC.js.map} +0 -0
- /package/dist/{chunk-IVKIODHO.js.map → chunk-A7XEPMQ6.js.map} +0 -0
- /package/dist/{chunk-K6MV3TRQ.js.map → chunk-ADXCCZL2.js.map} +0 -0
- /package/dist/{chunk-GC65K6DI.js.map → chunk-AOCP6JA7.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-AU7Q3LSC.js.map} +0 -0
- /package/dist/{chunk-ND6IQGSZ.js.map → chunk-BA6WOZOT.js.map} +0 -0
- /package/dist/{chunk-JI7U6AS3.js.map → chunk-C6FQJ52H.js.map} +0 -0
- /package/dist/{chunk-IN673LEP.js.map → chunk-CARRTDKC.js.map} +0 -0
- /package/dist/{chunk-HLTAZTN7.js.map → chunk-CBCNKKZD.js.map} +0 -0
- /package/dist/{chunk-DXFG2VGN.js.map → chunk-CGC5UQCF.js.map} +0 -0
- /package/dist/{chunk-YSSAGB2O.js.map → chunk-CLLPJ6QT.js.map} +0 -0
- /package/dist/{chunk-U6S754L6.js.map → chunk-D5LORF7A.js.map} +0 -0
- /package/dist/{chunk-C24UZSFW.js.map → chunk-DBQWVT2H.js.map} +0 -0
- /package/dist/{chunk-XSTNGNJP.js.map → chunk-DCJ3YFIC.js.map} +0 -0
- /package/dist/{chunk-2YDWI2LO.js.map → chunk-DITMGZOL.js.map} +0 -0
- /package/dist/{chunk-LVE64P5Y.js.map → chunk-E2ZHGBAK.js.map} +0 -0
- /package/dist/{chunk-WW3MR6T3.js.map → chunk-ENMTJRXA.js.map} +0 -0
- /package/dist/{chunk-COUYFFID.js.map → chunk-EYMOJ3J6.js.map} +0 -0
- /package/dist/{chunk-INBOGQ3E.js.map → chunk-EZZV7OQL.js.map} +0 -0
- /package/dist/{chunk-MT47LH5L.js.map → chunk-FBMYGNOC.js.map} +0 -0
- /package/dist/{chunk-N3SS45OW.js.map → chunk-FCSZ4K2X.js.map} +0 -0
- /package/dist/{chunk-PKS56ZRR.js.map → chunk-FGGYSN4P.js.map} +0 -0
- /package/dist/{chunk-ZMNT26KV.js.map → chunk-FHQSPTPZ.js.map} +0 -0
- /package/dist/{chunk-6GUG4YNM.js.map → chunk-GGRRF4PZ.js.map} +0 -0
- /package/dist/{chunk-YIHKAUS4.js.map → chunk-GTWHVXPA.js.map} +0 -0
- /package/dist/{chunk-UY2RORVF.js.map → chunk-GVG3JYBI.js.map} +0 -0
- /package/dist/{chunk-I3OQBP23.js.map → chunk-GY5WZBA6.js.map} +0 -0
- /package/dist/{chunk-3GCK6ONU.js.map → chunk-HK32G473.js.map} +0 -0
- /package/dist/{chunk-OVAJKCN3.js.map → chunk-HY55QQD7.js.map} +0 -0
- /package/dist/{chunk-YJETZFLJ.js.map → chunk-I27RSQRR.js.map} +0 -0
- /package/dist/{chunk-QIEUU4UK.js.map → chunk-I55KAVET.js.map} +0 -0
- /package/dist/{chunk-UY7VPC6Q.js.map → chunk-IA2YSHTX.js.map} +0 -0
- /package/dist/{chunk-UEEN7GXR.js.map → chunk-IY2FVXM6.js.map} +0 -0
- /package/dist/{chunk-NVOFMARR.js.map → chunk-JDDXXZWW.js.map} +0 -0
- /package/dist/{chunk-2AMEUKCG.js.map → chunk-JEIXTYVG.js.map} +0 -0
- /package/dist/{chunk-ODW5GDFE.js.map → chunk-JT3EB7ZL.js.map} +0 -0
- /package/dist/{chunk-XR67IAXP.js.map → chunk-KLMESRPV.js.map} +0 -0
- /package/dist/{chunk-7LCGFUMB.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-3K7V3HE6.js.map → chunk-KXRX7YC2.js.map} +0 -0
- /package/dist/{chunk-7RZJWZ46.js.map → chunk-LEPOP46W.js.map} +0 -0
- /package/dist/{chunk-54WHLA65.js.map → chunk-LRICZIGN.js.map} +0 -0
- /package/dist/{chunk-EWCNCQOU.js.map → chunk-LWA7MDVO.js.map} +0 -0
- /package/dist/{chunk-EZKSOM5K.js.map → chunk-MFJBANPX.js.map} +0 -0
- /package/dist/{chunk-OB3XMWX5.js.map → chunk-MKWKYHXJ.js.map} +0 -0
- /package/dist/{chunk-HMKPFW7R.js.map → chunk-MPAJFFP3.js.map} +0 -0
- /package/dist/{chunk-4P43SE4H.js.map → chunk-MPYD657E.js.map} +0 -0
- /package/dist/{chunk-NLDVVWCL.js.map → chunk-NDNTNE3S.js.map} +0 -0
- /package/dist/{chunk-5ISVONB7.js.map → chunk-NWWXSJX5.js.map} +0 -0
- /package/dist/{chunk-QBC33MPY.js.map → chunk-NZXEK3UF.js.map} +0 -0
- /package/dist/{chunk-MYB6DWE5.js.map → chunk-OGELWNYC.js.map} +0 -0
- /package/dist/{chunk-IES4QHLM.js.map → chunk-OXNU333D.js.map} +0 -0
- /package/dist/{chunk-MSSJSC2V.js.map → chunk-PEOTOFH5.js.map} +0 -0
- /package/dist/{chunk-OYHGTHVX.js.map → chunk-PHNAB54Q.js.map} +0 -0
- /package/dist/{chunk-R5T5FB2R.js.map → chunk-PLBW64UM.js.map} +0 -0
- /package/dist/{chunk-BD7JTBYP.js.map → chunk-PSPABFN2.js.map} +0 -0
- /package/dist/{chunk-WOOTZ6DH.js.map → chunk-PV36INNL.js.map} +0 -0
- /package/dist/{chunk-QW3FMKT2.js.map → chunk-QDY6KYTN.js.map} +0 -0
- /package/dist/{chunk-6TZWGQTT.js.map → chunk-RAVRDTP7.js.map} +0 -0
- /package/dist/{chunk-BIVJCVT2.js.map → chunk-RBGREYVJ.js.map} +0 -0
- /package/dist/{chunk-GGRD3JEH.js.map → chunk-ROGRI25A.js.map} +0 -0
- /package/dist/{chunk-HTPQJ32S.js.map → chunk-ROKKIMON.js.map} +0 -0
- /package/dist/{chunk-5KND6CSX.js.map → chunk-RSVEP77Y.js.map} +0 -0
- /package/dist/{chunk-SV4Z2S67.js.map → chunk-S5G2LAL7.js.map} +0 -0
- /package/dist/{chunk-5PTRLTK2.js.map → chunk-S65WXHNK.js.map} +0 -0
- /package/dist/{chunk-3FEH4C4V.js.map → chunk-SB6PSOP7.js.map} +0 -0
- /package/dist/{chunk-S2DU3UBN.js.map → chunk-SH2ZWEWB.js.map} +0 -0
- /package/dist/{chunk-Z5XE7AMC.js.map → chunk-SMOFBBPU.js.map} +0 -0
- /package/dist/{chunk-GRCREL6Q.js.map → chunk-SQJ3SDIW.js.map} +0 -0
- /package/dist/{chunk-YFDJVB2K.js.map → chunk-T7CJQVRZ.js.map} +0 -0
- /package/dist/{chunk-EIJR4PZL.js.map → chunk-TEYN7ZYF.js.map} +0 -0
- /package/dist/{chunk-JALOAKSZ.js.map → chunk-TLPZ6MKZ.js.map} +0 -0
- /package/dist/{chunk-BHHONFSK.js.map → chunk-U34EHBPL.js.map} +0 -0
- /package/dist/{chunk-DFEODULB.js.map → chunk-V2HHAAPI.js.map} +0 -0
- /package/dist/{chunk-KEF46KL2.js.map → chunk-V6EGNVUT.js.map} +0 -0
- /package/dist/{chunk-ESNFSSO4.js.map → chunk-VGXM5B4H.js.map} +0 -0
- /package/dist/{chunk-MJUCDM3C.js.map → chunk-VLXBE57O.js.map} +0 -0
- /package/dist/{chunk-YGTSOVCR.js.map → chunk-VP67GZ7T.js.map} +0 -0
- /package/dist/{chunk-ALBYEXFX.js.map → chunk-VZWXFXLX.js.map} +0 -0
- /package/dist/{chunk-NC7RM2XS.js.map → chunk-W64HKJJM.js.map} +0 -0
- /package/dist/{chunk-OMLGLMWL.js.map → chunk-WHBVXTUI.js.map} +0 -0
- /package/dist/{chunk-4KMGFWQY.js.map → chunk-WJBZMNNS.js.map} +0 -0
- /package/dist/{chunk-WFZBRS6N.js.map → chunk-X74UAWSI.js.map} +0 -0
- /package/dist/{chunk-EGALNSZ4.js.map → chunk-XU6OEECT.js.map} +0 -0
- /package/dist/{chunk-4FIH6MPS.js.map → chunk-YHLWPYHT.js.map} +0 -0
- /package/dist/{chunk-PAZY2ZKP.js.map → chunk-YQAXP5AC.js.map} +0 -0
- /package/dist/{chunk-ZNR5SVUI.js.map → chunk-YUMDFDUA.js.map} +0 -0
- /package/dist/{chunk-7HYPN2GC.js.map → chunk-ZG74PWRW.js.map} +0 -0
- /package/dist/{chunk-TDYAIXHK.js.map → chunk-ZHXSOMYH.js.map} +0 -0
- /package/dist/{chunk-TNSCIPBQ.js.map → chunk-ZNJSBIP4.js.map} +0 -0
- /package/dist/{state-store-Z3EN56O5.js.map → config-discovery.js.map} +0 -0
|
@@ -59,9 +59,7 @@ export interface ReconcileManifest {
|
|
|
59
59
|
files: ReconcileManifestFile[];
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
export type ReconcileMemoryParser = (
|
|
63
|
-
raw: string,
|
|
64
|
-
) => { frontmatter: MemoryFrontmatter; content: string } | null;
|
|
62
|
+
export type ReconcileMemoryParser = (raw: string) => { frontmatter: MemoryFrontmatter; content: string } | null;
|
|
65
63
|
|
|
66
64
|
export interface BuildReconcileManifestOptions {
|
|
67
65
|
files: Iterable<ReconcileFileState>;
|
|
@@ -82,32 +80,26 @@ function isMemoryPath(filePath: string): boolean {
|
|
|
82
80
|
return MEMORY_DIRS.has(segments[index] ?? "");
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
|
|
86
83
|
function parsedMemoryIdentity(
|
|
87
84
|
filePath: string,
|
|
88
85
|
raw: Buffer | string,
|
|
89
86
|
parseMemory: ReconcileMemoryParser,
|
|
90
|
-
citationTemplate: string
|
|
87
|
+
citationTemplate: string
|
|
91
88
|
): ReconcileMemoryIdentity | undefined {
|
|
92
89
|
if (!isMemoryPath(filePath)) return undefined;
|
|
93
90
|
const parsed = parseMemory(Buffer.isBuffer(raw) ? raw.toString("utf8") : raw);
|
|
94
91
|
if (!parsed?.frontmatter.id) return undefined;
|
|
95
92
|
|
|
96
93
|
const storedHash =
|
|
97
|
-
parsed.frontmatter.contentHash &&
|
|
98
|
-
SHA256_PATTERN.test(parsed.frontmatter.contentHash)
|
|
94
|
+
parsed.frontmatter.contentHash && SHA256_PATTERN.test(parsed.frontmatter.contentHash)
|
|
99
95
|
? parsed.frontmatter.contentHash.toLowerCase()
|
|
100
96
|
: undefined;
|
|
101
97
|
const candidates = storedContentIdentityCandidates(parsed.content, (content) =>
|
|
102
98
|
stripCitationForTemplate(content, citationTemplate)
|
|
103
99
|
);
|
|
104
100
|
const bodyHash = ContentHashIndex.computeHash(candidates[0] ?? "");
|
|
105
|
-
const currentMatch = candidates.find(
|
|
106
|
-
|
|
107
|
-
);
|
|
108
|
-
const legacyMatch = [...candidates].reverse().find(
|
|
109
|
-
(content) => computeLegacyContentHash(content) === storedHash
|
|
110
|
-
);
|
|
101
|
+
const currentMatch = candidates.find((content) => ContentHashIndex.computeHash(content) === storedHash);
|
|
102
|
+
const legacyMatch = [...candidates].reverse().find((content) => computeLegacyContentHash(content) === storedHash);
|
|
111
103
|
let contentHash: string;
|
|
112
104
|
let contentHashAliases: string[] | undefined;
|
|
113
105
|
if (currentMatch) {
|
|
@@ -126,7 +118,7 @@ function parsedMemoryIdentity(
|
|
|
126
118
|
// An EMPTY legacy skeleton identifies nothing (every non-ASCII body maps
|
|
127
119
|
// to it), so preserving it would collapse unrelated records. Recovering
|
|
128
120
|
// the current identity here is repair, not replacement.
|
|
129
|
-
contentHash = legacyMatch ? ContentHashIndex.computeHash(legacyMatch) : storedHash ?? bodyHash;
|
|
121
|
+
contentHash = legacyMatch ? ContentHashIndex.computeHash(legacyMatch) : (storedHash ?? bodyHash);
|
|
130
122
|
}
|
|
131
123
|
|
|
132
124
|
return {
|
|
@@ -144,7 +136,7 @@ export async function buildReconcileManifestFile(
|
|
|
144
136
|
file: ReconcileFileState,
|
|
145
137
|
readFile: (file: ReconcileFileState) => Promise<Buffer | string | null>,
|
|
146
138
|
parseMemory: ReconcileMemoryParser,
|
|
147
|
-
citationTemplate = DEFAULT_CITATION_FORMAT
|
|
139
|
+
citationTemplate = DEFAULT_CITATION_FORMAT
|
|
148
140
|
): Promise<ReconcileManifestFile> {
|
|
149
141
|
let raw: Buffer | string | null = null;
|
|
150
142
|
if (isMemoryPath(file.path)) {
|
|
@@ -161,6 +153,15 @@ export async function buildReconcileManifestFile(
|
|
|
161
153
|
return { ...file, ...(memory ? { memory } : {}) };
|
|
162
154
|
}
|
|
163
155
|
|
|
156
|
+
/** Read-batch size for manifest builds. Uncached files are independent (a
|
|
157
|
+
* per-file read + sha256 + frontmatter parse); processing them in bounded
|
|
158
|
+
* batches amortizes the per-file promise/async-hook overhead that dominates
|
|
159
|
+
* boot-scale corpus builds (measured: ~66% of CPU in async_hooks._propagate +
|
|
160
|
+
* GC at ~100k files) and overlaps IO waits, while the bound keeps memory flat.
|
|
161
|
+
* Order is preserved: results land in input order regardless of completion
|
|
162
|
+
* order, so the manifest output is byte-identical to the sequential form. */
|
|
163
|
+
const MANIFEST_BUILD_BATCH_SIZE = 50;
|
|
164
|
+
|
|
164
165
|
export async function buildReconcileManifest(options: BuildReconcileManifestOptions): Promise<ReconcileManifest> {
|
|
165
166
|
const cachedByPath = new Map<string, ReconcileManifestFile>();
|
|
166
167
|
for (const cached of options.cachedFiles ?? []) {
|
|
@@ -168,24 +169,36 @@ export async function buildReconcileManifest(options: BuildReconcileManifestOpti
|
|
|
168
169
|
}
|
|
169
170
|
|
|
170
171
|
const files: ReconcileManifestFile[] = [];
|
|
171
|
-
|
|
172
|
+
// Cache hits stay on a synchronous fast path (no promise allocation, no
|
|
173
|
+
// Promise.all — a fully-cached rebuild must not regress); only the uncached
|
|
174
|
+
// entries ride the bounded batches. Order is preserved by index.
|
|
175
|
+
const uncached: Array<{ index: number; file: ReconcileFileState }> = [];
|
|
176
|
+
const allFiles = [...options.files];
|
|
177
|
+
for (let i = 0; i < allFiles.length; i += 1) {
|
|
178
|
+
const file = allFiles[i]!;
|
|
172
179
|
const cached = cachedByPath.get(file.path);
|
|
173
180
|
if (
|
|
174
|
-
cached
|
|
181
|
+
cached !== undefined &&
|
|
182
|
+
cached.sha256.toLowerCase() === file.sha256.toLowerCase() &&
|
|
175
183
|
(cached.memory === undefined ||
|
|
176
184
|
(cached.memory.normalizerVersion === CONTENT_HASH_NORMALIZER_VERSION &&
|
|
177
185
|
cached.memory.identityResolutionVersion === IDENTITY_RESOLUTION_VERSION))
|
|
178
186
|
) {
|
|
179
187
|
files.push({ ...file, ...(cached.memory ? { memory: cached.memory } : {}) });
|
|
180
|
-
|
|
188
|
+
} else {
|
|
189
|
+
uncached.push({ index: i, file });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
for (let i = 0; i < uncached.length; i += MANIFEST_BUILD_BATCH_SIZE) {
|
|
193
|
+
const batch = uncached.slice(i, i + MANIFEST_BUILD_BATCH_SIZE);
|
|
194
|
+
const results = await Promise.all(
|
|
195
|
+
batch.map(({ file }) =>
|
|
196
|
+
buildReconcileManifestFile(file, options.readFile, options.parseMemory, options.citationTemplate)
|
|
197
|
+
)
|
|
198
|
+
);
|
|
199
|
+
for (let j = 0; j < batch.length; j += 1) {
|
|
200
|
+
files[batch[j]!.index] = results[j]!;
|
|
181
201
|
}
|
|
182
|
-
|
|
183
|
-
files.push(await buildReconcileManifestFile(
|
|
184
|
-
file,
|
|
185
|
-
options.readFile,
|
|
186
|
-
options.parseMemory,
|
|
187
|
-
options.citationTemplate,
|
|
188
|
-
));
|
|
189
202
|
}
|
|
190
203
|
files.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));
|
|
191
204
|
return {
|
|
@@ -209,10 +222,7 @@ function memoryIdentityHashes(memory: ReconcileMemoryIdentity): string[] {
|
|
|
209
222
|
return [memory.contentHash, ...(memory.contentHashAliases ?? [])];
|
|
210
223
|
}
|
|
211
224
|
|
|
212
|
-
function contentHashRows(
|
|
213
|
-
files: Iterable<ActiveFactManifestFile>,
|
|
214
|
-
contentHash: string,
|
|
215
|
-
): ContentHashPathEntry[] {
|
|
225
|
+
function contentHashRows(files: Iterable<ActiveFactManifestFile>, contentHash: string): ContentHashPathEntry[] {
|
|
216
226
|
const rows: ContentHashPathEntry[] = [];
|
|
217
227
|
for (const file of files) {
|
|
218
228
|
rows.push({ path: file.path, contentHash });
|
|
@@ -237,7 +247,7 @@ export function collapseActiveFactDuplicates(
|
|
|
237
247
|
plan: ReconcilePlan,
|
|
238
248
|
localManifests: ReadonlyMap<string, ReconcileManifest>,
|
|
239
249
|
peerManifests: ReadonlyMap<string, ReconcileManifest>,
|
|
240
|
-
priorSemanticAgreements?: ReadonlyMap<string, readonly ReconcileSemanticAgreement[]
|
|
250
|
+
priorSemanticAgreements?: ReadonlyMap<string, readonly ReconcileSemanticAgreement[]>
|
|
241
251
|
): ReconcilePlan {
|
|
242
252
|
const entriesByNamespace = new Map<string, ReconcilePlanEntry[]>();
|
|
243
253
|
for (const entry of plan.entries) {
|
|
@@ -256,10 +266,7 @@ export function collapseActiveFactDuplicates(
|
|
|
256
266
|
const localFilesByPath = new Map((localManifest?.files ?? []).map((file) => [file.path, file]));
|
|
257
267
|
const peerFilesByPath = new Map((peerManifest?.files ?? []).map((file) => [file.path, file]));
|
|
258
268
|
const priorSemanticByPathPair = new Map(
|
|
259
|
-
(priorSemanticAgreements?.get(namespace) ?? []).map((agreement) => [
|
|
260
|
-
semanticAgreementKey(agreement),
|
|
261
|
-
agreement,
|
|
262
|
-
])
|
|
269
|
+
(priorSemanticAgreements?.get(namespace) ?? []).map((agreement) => [semanticAgreementKey(agreement), agreement])
|
|
263
270
|
);
|
|
264
271
|
const localByHash = new Map<string, ActiveFactManifestFile[]>();
|
|
265
272
|
const peerByHash = new Map<string, ActiveFactManifestFile[]>();
|
|
@@ -286,17 +293,17 @@ export function collapseActiveFactDuplicates(
|
|
|
286
293
|
const localCandidates = (localByHash.get(hash) ?? []).filter((file) => {
|
|
287
294
|
const opposite = peerFilesByPath.get(file.path);
|
|
288
295
|
const activeOpposite = peerByPath.get(file.path);
|
|
289
|
-
return
|
|
290
|
-
|
|
291
|
-
memoryIdentityHashes(activeOpposite.memory).includes(hash)
|
|
296
|
+
return (
|
|
297
|
+
opposite === undefined ||
|
|
298
|
+
(activeOpposite !== undefined && memoryIdentityHashes(activeOpposite.memory).includes(hash))
|
|
292
299
|
);
|
|
293
300
|
});
|
|
294
301
|
const peerCandidates = (peerByHash.get(hash) ?? []).filter((file) => {
|
|
295
302
|
const opposite = localFilesByPath.get(file.path);
|
|
296
303
|
const activeOpposite = localByPath.get(file.path);
|
|
297
|
-
return
|
|
298
|
-
|
|
299
|
-
memoryIdentityHashes(activeOpposite.memory).includes(hash)
|
|
304
|
+
return (
|
|
305
|
+
opposite === undefined ||
|
|
306
|
+
(activeOpposite !== undefined && memoryIdentityHashes(activeOpposite.memory).includes(hash))
|
|
300
307
|
);
|
|
301
308
|
});
|
|
302
309
|
const localPath = ContentHashIndex.resolvePathByHash(hash, contentHashRows(localCandidates, hash));
|
|
@@ -313,19 +320,21 @@ export function collapseActiveFactDuplicates(
|
|
|
313
320
|
...localCandidates.map((file) => file.path),
|
|
314
321
|
...peerCandidates.map((file) => file.path),
|
|
315
322
|
]);
|
|
316
|
-
const authoritativeSamePathEntries = new Set(
|
|
317
|
-
(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
+
const authoritativeSamePathEntries = new Set(
|
|
324
|
+
entries.filter(
|
|
325
|
+
(entry) =>
|
|
326
|
+
duplicatePaths.has(entry.path) &&
|
|
327
|
+
localFilesByPath.has(entry.path) &&
|
|
328
|
+
peerFilesByPath.has(entry.path) &&
|
|
329
|
+
entry.action !== "identical"
|
|
330
|
+
)
|
|
331
|
+
);
|
|
323
332
|
if (authoritativeSamePathEntries.size > 0) {
|
|
324
333
|
for (const entry of entries) {
|
|
325
334
|
if (
|
|
326
|
-
duplicatePaths.has(entry.path)
|
|
327
|
-
|
|
328
|
-
|
|
335
|
+
duplicatePaths.has(entry.path) &&
|
|
336
|
+
!authoritativeSamePathEntries.has(entry) &&
|
|
337
|
+
(entry.action === "pull" || entry.action === "push" || entry.action === "identical")
|
|
329
338
|
) {
|
|
330
339
|
removed.add(entry);
|
|
331
340
|
changed = true;
|
package/src/runtime/env.ts
CHANGED
|
@@ -25,6 +25,17 @@ export function readEnvVar(name: string): string | undefined {
|
|
|
25
25
|
}
|
|
26
26
|
return undefined;
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Read an env var by its current name, falling back to a legacy name.
|
|
30
|
+
*
|
|
31
|
+
* Unlike `readEnvVar`, an explicitly-set empty string is returned as-is:
|
|
32
|
+
* callers that must distinguish set-but-invalid from unset (server config
|
|
33
|
+
* readiness, auth-token fallbacks) rely on `??`-only semantics.
|
|
34
|
+
*/
|
|
35
|
+
export function readCompatEnv(primary: string, legacy: string): string | undefined {
|
|
36
|
+
const env = getEnvMap();
|
|
37
|
+
return env?.[primary] ?? env?.[legacy];
|
|
38
|
+
}
|
|
28
39
|
|
|
29
40
|
export function resolveHomeDir(): string {
|
|
30
41
|
return readEnvVar("HOME") || os.homedir();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime/env.ts"],"sourcesContent":["import os from \"node:os\";\n\ntype EnvMap = Record<string, string | undefined>;\n\nfunction getEnvMap(): EnvMap | undefined {\n const runtimeProcess = globalThis.process as { env?: EnvMap } | undefined;\n return runtimeProcess?.[\"env\"];\n}\n\nfunction legacyEnvCandidates(name: string): string[] {\n if (name.startsWith(\"REMNIC_\")) {\n return [name, `ENGRAM_${name.slice(\"REMNIC_\".length)}`];\n }\n if (name.startsWith(\"ENGRAM_\")) {\n return [`REMNIC_${name.slice(\"ENGRAM_\".length)}`, name];\n }\n return [name];\n}\n\nexport function readEnvVar(name: string): string | undefined {\n const env = getEnvMap();\n for (const candidate of legacyEnvCandidates(name)) {\n const value = env?.[candidate];\n if (typeof value === \"string\" && value.length > 0) return value;\n }\n return undefined;\n}\n\nexport function resolveHomeDir(): string {\n return readEnvVar(\"HOME\") || os.homedir();\n}\n\nfunction cloneEnv(): NodeJS.ProcessEnv {\n return { ...(getEnvMap() ?? {}) };\n}\n\nexport function mergeEnv(overrides: Record<string, string | undefined>): NodeJS.ProcessEnv {\n const merged = cloneEnv();\n for (const [key, value] of Object.entries(overrides)) {\n if (typeof value === \"string\") merged[key] = value;\n else delete merged[key];\n }\n return merged;\n}\n"],"mappings":";AAAA,OAAO,QAAQ;AAIf,SAAS,YAAgC;AACvC,QAAM,iBAAiB,WAAW;AAClC,SAAO,iBAAiB,KAAK;AAC/B;AAEA,SAAS,oBAAoB,MAAwB;AACnD,MAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,WAAO,CAAC,MAAM,UAAU,KAAK,MAAM,UAAU,MAAM,CAAC,EAAE;AAAA,EACxD;AACA,MAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,WAAO,CAAC,UAAU,KAAK,MAAM,UAAU,MAAM,CAAC,IAAI,IAAI;AAAA,EACxD;AACA,SAAO,CAAC,IAAI;AACd;AAEO,SAAS,WAAW,MAAkC;AAC3D,QAAM,MAAM,UAAU;AACtB,aAAW,aAAa,oBAAoB,IAAI,GAAG;AACjD,UAAM,QAAQ,MAAM,SAAS;AAC7B,QAAI,OAAO,UAAU,YAAY,MAAM,SAAS,EAAG,QAAO;AAAA,EAC5D;AACA,SAAO;AACT;AAEO,SAAS,iBAAyB;AACvC,SAAO,WAAW,MAAM,KAAK,GAAG,QAAQ;AAC1C;AAEA,SAAS,WAA8B;AACrC,SAAO,EAAE,GAAI,UAAU,KAAK,CAAC,EAAG;AAClC;AAEO,SAAS,SAAS,WAAkE;AACzF,QAAM,SAAS,SAAS;AACxB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,GAAG;AACpD,QAAI,OAAO,UAAU,SAAU,QAAO,GAAG,IAAI;AAAA,QACxC,QAAO,OAAO,GAAG;AAAA,EACxB;AACA,SAAO;AACT;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/reconcile/manifest.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { computeLegacyContentHash, normalizeLegacyContent } from \"../content-hash.js\";\nimport { inferMemoryStatus } from \"../memory-lifecycle-ledger-utils.js\";\nimport { ContentHashIndex, type ContentHashPathEntry } from \"../storage/content-hash-index.js\";\nimport { DEFAULT_CITATION_FORMAT, stripCitationForTemplate } from \"../source-attribution.js\";\nimport { storedContentIdentityCandidates } from \"../structured-attributes.js\";\nimport type { MemoryFrontmatter, MemoryStatus } from \"../types.js\";\nimport { RECALL_FALLBACK_DIRS } from \"../utils/category-dir.js\";\nimport {\n type ReconcileFileState,\n type ReconcilePlan,\n type ReconcilePlanEntry,\n type ReconcileSemanticAgreement,\n type ReconcileSemanticChange,\n compareReconcilePlanEntries,\n semanticAgreementKey,\n summarizeReconcilePlan,\n} from \"./plan.js\";\n\nexport const RECONCILE_MANIFEST_FORMAT = \"remnic-reconcile-manifest\";\nexport const RECONCILE_MANIFEST_SCHEMA_VERSION = 1;\nconst CONTENT_HASH_NORMALIZER_VERSION = 4;\n/**\n * Version of the identity-resolution LOGIC (alias recovery, candidate\n * ordering), independent of the content normalizer: a cached manifest entry\n * written before an identity-resolution change carries an older value and is\n * reparsed even when its normalizerVersion still matches (issue #2367\n * review round 2). Bump when parsedMemoryIdentity's output shape or\n * semantics change.\n */\nconst IDENTITY_RESOLUTION_VERSION = 2;\n\nexport interface ReconcileMemoryIdentity {\n id: string;\n category: string;\n contentHash: string;\n /**\n * Recovered current-normalizer identities for a record whose persisted hash\n * is ambiguous under the legacy normalizer (issue #2367). The persisted\n * hash stays primary; these participate in duplicate bucketing so a\n * replica carrying the current form of the same fact still collapses.\n */\n contentHashAliases?: readonly string[];\n /** See IDENTITY_RESOLUTION_VERSION; absent on pre-versioning cache entries. */\n normalizerVersion?: number;\n identityResolutionVersion?: number;\n status: MemoryStatus;\n}\n\nexport interface ReconcileManifestFile extends ReconcileFileState {\n memory?: ReconcileMemoryIdentity;\n}\n\ntype ActiveFactManifestFile = ReconcileManifestFile & { memory: ReconcileMemoryIdentity };\n\nexport interface ReconcileManifest {\n format: typeof RECONCILE_MANIFEST_FORMAT;\n schemaVersion: typeof RECONCILE_MANIFEST_SCHEMA_VERSION;\n files: ReconcileManifestFile[];\n}\n\nexport type ReconcileMemoryParser = (\n raw: string,\n) => { frontmatter: MemoryFrontmatter; content: string } | null;\n\nexport interface BuildReconcileManifestOptions {\n files: Iterable<ReconcileFileState>;\n readFile: (file: ReconcileFileState) => Promise<Buffer | string | null>;\n parseMemory: ReconcileMemoryParser;\n cachedFiles?: Iterable<ReconcileManifestFile>;\n citationTemplate?: string;\n}\n\nconst SHA256_PATTERN = /^[a-f0-9]{64}$/i;\nconst MEMORY_DIRS = new Set(RECALL_FALLBACK_DIRS);\n\nfunction isMemoryPath(filePath: string): boolean {\n if (!filePath.endsWith(\".md\")) return false;\n const segments = filePath.split(\"/\");\n let index = 0;\n if (segments[index] === \"cold\" || segments[index] === \"archive\") index += 1;\n return MEMORY_DIRS.has(segments[index] ?? \"\");\n}\n\n\nfunction parsedMemoryIdentity(\n filePath: string,\n raw: Buffer | string,\n parseMemory: ReconcileMemoryParser,\n citationTemplate: string,\n): ReconcileMemoryIdentity | undefined {\n if (!isMemoryPath(filePath)) return undefined;\n const parsed = parseMemory(Buffer.isBuffer(raw) ? raw.toString(\"utf8\") : raw);\n if (!parsed?.frontmatter.id) return undefined;\n\n const storedHash =\n parsed.frontmatter.contentHash &&\n SHA256_PATTERN.test(parsed.frontmatter.contentHash)\n ? parsed.frontmatter.contentHash.toLowerCase()\n : undefined;\n const candidates = storedContentIdentityCandidates(parsed.content, (content) =>\n stripCitationForTemplate(content, citationTemplate)\n );\n const bodyHash = ContentHashIndex.computeHash(candidates[0] ?? \"\");\n const currentMatch = candidates.find(\n (content) => ContentHashIndex.computeHash(content) === storedHash\n );\n const legacyMatch = [...candidates].reverse().find(\n (content) => computeLegacyContentHash(content) === storedHash\n );\n let contentHash: string;\n let contentHashAliases: string[] | undefined;\n if (currentMatch) {\n contentHash = ContentHashIndex.computeHash(currentMatch);\n } else if (legacyMatch && normalizeLegacyContent(legacyMatch).length > 0) {\n // A non-empty legacy equality is ambiguous (issue #2367): the persisted\n // hash may be an explicit contentHashSource identity that merely collides\n // with the body's ASCII skeleton under the lossy legacy normalizer, and\n // nothing in the record proves which it is. Keep the persisted hash as\n // the primary identity and expose the recovered current identity as an\n // alias so replicas carrying either form still collapse.\n contentHash = storedHash ?? bodyHash;\n const recovered = ContentHashIndex.computeHash(legacyMatch);\n if (recovered !== contentHash) contentHashAliases = [recovered];\n } else {\n // An EMPTY legacy skeleton identifies nothing (every non-ASCII body maps\n // to it), so preserving it would collapse unrelated records. Recovering\n // the current identity here is repair, not replacement.\n contentHash = legacyMatch ? ContentHashIndex.computeHash(legacyMatch) : storedHash ?? bodyHash;\n }\n\n return {\n id: parsed.frontmatter.id,\n category: parsed.frontmatter.category,\n contentHash,\n ...(contentHashAliases ? { contentHashAliases } : {}),\n normalizerVersion: CONTENT_HASH_NORMALIZER_VERSION,\n identityResolutionVersion: IDENTITY_RESOLUTION_VERSION,\n status: inferMemoryStatus(parsed.frontmatter, filePath),\n };\n}\n\nexport async function buildReconcileManifestFile(\n file: ReconcileFileState,\n readFile: (file: ReconcileFileState) => Promise<Buffer | string | null>,\n parseMemory: ReconcileMemoryParser,\n citationTemplate = DEFAULT_CITATION_FORMAT,\n): Promise<ReconcileManifestFile> {\n let raw: Buffer | string | null = null;\n if (isMemoryPath(file.path)) {\n try {\n raw = await readFile(file);\n } catch {\n raw = null;\n }\n }\n if (raw !== null && createHash(\"sha256\").update(raw).digest(\"hex\") !== file.sha256.toLowerCase()) {\n raw = null;\n }\n const memory = raw === null ? undefined : parsedMemoryIdentity(file.path, raw, parseMemory, citationTemplate);\n return { ...file, ...(memory ? { memory } : {}) };\n}\n\nexport async function buildReconcileManifest(options: BuildReconcileManifestOptions): Promise<ReconcileManifest> {\n const cachedByPath = new Map<string, ReconcileManifestFile>();\n for (const cached of options.cachedFiles ?? []) {\n cachedByPath.set(cached.path, cached);\n }\n\n const files: ReconcileManifestFile[] = [];\n for (const file of options.files) {\n const cached = cachedByPath.get(file.path);\n if (\n cached?.sha256.toLowerCase() === file.sha256.toLowerCase() &&\n (cached.memory === undefined ||\n (cached.memory.normalizerVersion === CONTENT_HASH_NORMALIZER_VERSION &&\n cached.memory.identityResolutionVersion === IDENTITY_RESOLUTION_VERSION))\n ) {\n files.push({ ...file, ...(cached.memory ? { memory: cached.memory } : {}) });\n continue;\n }\n\n files.push(await buildReconcileManifestFile(\n file,\n options.readFile,\n options.parseMemory,\n options.citationTemplate,\n ));\n }\n files.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));\n return {\n format: RECONCILE_MANIFEST_FORMAT,\n schemaVersion: RECONCILE_MANIFEST_SCHEMA_VERSION,\n files,\n };\n}\n\nfunction activeFactByPath(manifest: ReconcileManifest | undefined): Map<string, ActiveFactManifestFile> {\n const result = new Map<string, ActiveFactManifestFile>();\n for (const file of manifest?.files ?? []) {\n if (file.memory?.category === \"fact\" && file.memory.status === \"active\") {\n result.set(file.path, file as ActiveFactManifestFile);\n }\n }\n return result;\n}\n\nfunction memoryIdentityHashes(memory: ReconcileMemoryIdentity): string[] {\n return [memory.contentHash, ...(memory.contentHashAliases ?? [])];\n}\n\nfunction contentHashRows(\n files: Iterable<ActiveFactManifestFile>,\n contentHash: string,\n): ContentHashPathEntry[] {\n const rows: ContentHashPathEntry[] = [];\n for (const file of files) {\n rows.push({ path: file.path, contentHash });\n }\n return rows;\n}\n\nfunction classifySemanticChange(\n current: ReconcileSemanticAgreement,\n prior: ReconcileSemanticAgreement | undefined\n): ReconcileSemanticChange {\n if (!prior) return \"unchanged\";\n const localChanged = current.local.sha256 !== prior.local.sha256;\n const peerChanged = current.peer.sha256 !== prior.peer.sha256;\n if (localChanged && peerChanged) return \"both_modified\";\n if (localChanged) return \"local_changed\";\n if (peerChanged) return \"peer_changed\";\n return \"unchanged\";\n}\n\nexport function collapseActiveFactDuplicates(\n plan: ReconcilePlan,\n localManifests: ReadonlyMap<string, ReconcileManifest>,\n peerManifests: ReadonlyMap<string, ReconcileManifest>,\n priorSemanticAgreements?: ReadonlyMap<string, readonly ReconcileSemanticAgreement[]>,\n): ReconcilePlan {\n const entriesByNamespace = new Map<string, ReconcilePlanEntry[]>();\n for (const entry of plan.entries) {\n const entries = entriesByNamespace.get(entry.namespace) ?? [];\n entries.push({ ...entry });\n entriesByNamespace.set(entry.namespace, entries);\n }\n\n let changed = false;\n for (const namespace of new Set([...localManifests.keys(), ...peerManifests.keys()])) {\n const entries = entriesByNamespace.get(namespace) ?? [];\n const localManifest = localManifests.get(namespace);\n const peerManifest = peerManifests.get(namespace);\n const localByPath = activeFactByPath(localManifest);\n const peerByPath = activeFactByPath(peerManifest);\n const localFilesByPath = new Map((localManifest?.files ?? []).map((file) => [file.path, file]));\n const peerFilesByPath = new Map((peerManifest?.files ?? []).map((file) => [file.path, file]));\n const priorSemanticByPathPair = new Map(\n (priorSemanticAgreements?.get(namespace) ?? []).map((agreement) => [\n semanticAgreementKey(agreement),\n agreement,\n ])\n );\n const localByHash = new Map<string, ActiveFactManifestFile[]>();\n const peerByHash = new Map<string, ActiveFactManifestFile[]>();\n\n for (const file of localByPath.values()) {\n for (const hash of memoryIdentityHashes(file.memory)) {\n const bucket = localByHash.get(hash) ?? [];\n bucket.push(file);\n localByHash.set(hash, bucket);\n }\n }\n for (const file of peerByPath.values()) {\n for (const hash of memoryIdentityHashes(file.memory)) {\n const bucket = peerByHash.get(hash) ?? [];\n bucket.push(file);\n peerByHash.set(hash, bucket);\n }\n }\n\n const removed = new Set<ReconcilePlanEntry>();\n const replacements: ReconcilePlanEntry[] = [];\n const processedPathPairs = new Set<string>();\n for (const hash of new Set([...localByHash.keys(), ...peerByHash.keys()])) {\n const localCandidates = (localByHash.get(hash) ?? []).filter((file) => {\n const opposite = peerFilesByPath.get(file.path);\n const activeOpposite = peerByPath.get(file.path);\n return opposite === undefined || (\n activeOpposite !== undefined &&\n memoryIdentityHashes(activeOpposite.memory).includes(hash)\n );\n });\n const peerCandidates = (peerByHash.get(hash) ?? []).filter((file) => {\n const opposite = localFilesByPath.get(file.path);\n const activeOpposite = localByPath.get(file.path);\n return opposite === undefined || (\n activeOpposite !== undefined &&\n memoryIdentityHashes(activeOpposite.memory).includes(hash)\n );\n });\n const localPath = ContentHashIndex.resolvePathByHash(hash, contentHashRows(localCandidates, hash));\n const peerPath = ContentHashIndex.resolvePathByHash(hash, contentHashRows(peerCandidates, hash));\n\n if (localPath && peerPath && localPath !== peerPath) {\n const pathPair = `${localPath}\\0${peerPath}`;\n if (processedPathPairs.has(pathPair)) continue;\n processedPathPairs.add(pathPair);\n const localFile = localByPath.get(localPath);\n const peerFile = peerByPath.get(peerPath);\n if (!localFile || !peerFile) continue;\n const duplicatePaths = new Set([\n ...localCandidates.map((file) => file.path),\n ...peerCandidates.map((file) => file.path),\n ]);\n const authoritativeSamePathEntries = new Set(entries.filter(\n (entry) =>\n duplicatePaths.has(entry.path)\n && localFilesByPath.has(entry.path)\n && peerFilesByPath.has(entry.path)\n && entry.action !== \"identical\"\n ));\n if (authoritativeSamePathEntries.size > 0) {\n for (const entry of entries) {\n if (\n duplicatePaths.has(entry.path)\n && !authoritativeSamePathEntries.has(entry)\n && (entry.action === \"pull\" || entry.action === \"push\" || entry.action === \"identical\")\n ) {\n removed.add(entry);\n changed = true;\n }\n }\n continue;\n }\n const unsafeEntry = entries.some(\n (entry) => duplicatePaths.has(entry.path) && (entry.action === \"suppress\" || entry.action === \"conflict\")\n );\n if (unsafeEntry) continue;\n for (const entry of entries) {\n if (\n duplicatePaths.has(entry.path) &&\n (entry.action === \"pull\" || entry.action === \"push\" || entry.action === \"identical\")\n ) {\n removed.add(entry);\n }\n }\n const semanticAgreement: ReconcileSemanticAgreement = {\n local: { path: localPath, sha256: localFile.sha256 },\n peer: { path: peerPath, sha256: peerFile.sha256 },\n };\n replacements.push({\n path: localPath < peerPath ? localPath : peerPath,\n namespace,\n action: \"identical\",\n reason: \"semantic_duplicate\",\n semanticAgreement,\n semanticChange: classifySemanticChange(\n semanticAgreement,\n priorSemanticByPathPair.get(semanticAgreementKey(semanticAgreement))\n ),\n });\n changed = true;\n continue;\n }\n\n const sameSideEntries = entries.filter((entry) => {\n if (localPath && entry.reason === \"local_only\") {\n return localCandidates.some((file) => file.path === entry.path);\n }\n if (peerPath && entry.reason === \"peer_only\") {\n return peerCandidates.some((file) => file.path === entry.path);\n }\n return false;\n });\n const canonicalPath = localPath ?? peerPath;\n const hasSharedCanonical = localPath !== undefined && localPath === peerPath;\n if (!canonicalPath || sameSideEntries.length === 0 || (!hasSharedCanonical && sameSideEntries.length < 2)) {\n continue;\n }\n for (const entry of sameSideEntries) {\n if (entry.path !== canonicalPath) {\n removed.add(entry);\n changed = true;\n }\n }\n }\n\n if (removed.size > 0 || replacements.length > 0) {\n entriesByNamespace.set(\n namespace,\n [...entries.filter((entry) => !removed.has(entry)), ...replacements].sort(compareReconcilePlanEntries)\n );\n }\n }\n\n if (!changed) return plan;\n const entries = [...entriesByNamespace.values()].flat().sort(compareReconcilePlanEntries);\n return {\n entries,\n byNamespace: summarizeReconcilePlan(entries),\n converged: entries.every((entry) => entry.action === \"identical\"),\n };\n}\n"],"mappings":"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","names":["entries"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/activity/digest.ts"],"sourcesContent":["/**\n * Deterministic screen-activity day-digest renderer (issue #1899).\n *\n * Renders a day's snapshots into markdown with YAML frontmatter, placed at\n * `<memoryDir>/activity/<date>.md` — outside the memory scan roots but inside\n * the QMD collection root (searchable, never auto-recalled). No LLM: the body\n * is a pure, byte-identical function of its inputs so an unchanged day skips\n * rewrite by contentHash. Day bucketing is DST-aware and half-open\n * [start, end) (AGENTS.md §23); sort keys are total with stable tiebreakers\n * (§12).\n */\n\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\n\nimport type { ActivityDayDigest, ActivityDayMeta, ActivitySnapshot } from \"./types.js\";\n\nexport const ACTIVITY_DIGEST_FORMAT_VERSION = 1;\nexport const ACTIVITY_DIR_NAME = \"activity\";\n\n/** Attribute at most this much dwell to a single snapshot (idle gaps capped). */\nconst MAX_DWELL_MS = 15 * 60_000;\n/** Notable-excerpt caps. */\nconst NOTABLE_MAX_WINDOWS = 10;\nconst NOTABLE_EXCERPT_CHARS = 280;\n\nconst DATE_PATTERN = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport function isValidActivityDate(date: string): boolean {\n if (typeof date !== \"string\" || !DATE_PATTERN.test(date)) return false;\n // Reject impossible calendar days (e.g. 2026-02-30, 2026-13-01): the UTC\n // round-trip must reproduce the same Y-M-D, else Date normalized an overflow.\n const parsed = new Date(`${date}T00:00:00Z`);\n return Number.isFinite(parsed.getTime()) && parsed.toISOString().slice(0, 10) === date;\n}\n\nexport function activityDigestPath(memoryDir: string, date: string): string {\n if (!isValidActivityDate(date)) {\n // Never interpolate an unvalidated date into a filesystem path (a `../`\n // would escape <memoryDir>/activity/). Reject loudly.\n throw new RangeError(`Invalid activity date \"${date}\"; expected YYYY-MM-DD.`);\n }\n return path.join(memoryDir, ACTIVITY_DIR_NAME, `${date}.md`);\n}\n\n// ── DST-aware local-day window ──────────────────────────────────────────────\n\nexport function timezoneOffsetIso(instant: Date, timezone: string): string {\n const parts = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: timezone,\n timeZoneName: \"longOffset\",\n }).formatToParts(instant);\n const name = parts.find((part) => part.type === \"timeZoneName\")?.value ?? \"GMT\";\n const match = name.match(/GMT([+-]\\d{2}:\\d{2})?/);\n return match?.[1] ?? \"+00:00\";\n}\n\nexport function assertValidTimezone(timezone: string): void {\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: timezone });\n } catch {\n throw new RangeError(`Invalid IANA timezone \"${timezone}\".`);\n }\n}\n\nfunction zonedDayStartIso(date: string, timezone: string): string {\n // The first UTC instant whose local wall-clock is this date at 00:00. Probe\n // several instants across the day to collect every offset in play; keep an\n // offset only if constructing local midnight with it lands back on that same\n // offset (so it is genuinely local midnight, not a wall-clock that never\n // occurred), then take the EARLIEST such instant — the FIRST 00:00 across a\n // DST fall-back that repeats local midnight.\n // Probe the previous UTC day too: for zones east of UTC the requested date's\n // UTC instants all fall after local midnight, so the pre-transition offset\n // valid at the real local 00:00 is only observable on the prior UTC day.\n const prevDate = shiftIsoDate(date, -1);\n const probeOffsets = new Set(\n [\n `${prevDate}T12:00:00Z`,\n `${prevDate}T23:00:00Z`,\n `${date}T00:00:00Z`,\n `${date}T12:00:00Z`,\n `${date}T23:00:00Z`,\n ].map((iso) => timezoneOffsetIso(new Date(iso), timezone)),\n );\n let best: number | null = null;\n for (const offset of probeOffsets) {\n const candidate = Date.parse(`${date}T00:00:00${offset}`);\n if (!Number.isFinite(candidate)) continue;\n // Reject an offset whose local midnight does not actually occur (the wall\n // clock skipped by a spring-forward): the offset in effect at the candidate\n // instant must be the same offset we used to build it.\n if (timezoneOffsetIso(new Date(candidate), timezone) !== offset) continue;\n if (best === null || candidate < best) best = candidate;\n }\n if (best === null) {\n // Local midnight was skipped by a spring-forward at 00:00. Advance to the\n // first local wall-clock minute on this date that actually exists (never\n // backdating to a 00:00 that never occurred), scanning forward up to 3h.\n for (let minute = 1; minute <= 180 && best === null; minute++) {\n const hh = String(Math.floor(minute / 60)).padStart(2, \"0\");\n const mm = String(minute % 60).padStart(2, \"0\");\n for (const offset of probeOffsets) {\n const candidate = Date.parse(`${date}T${hh}:${mm}:00${offset}`);\n if (!Number.isFinite(candidate)) continue;\n if (timezoneOffsetIso(new Date(candidate), timezone) !== offset) continue;\n if (best === null || candidate < best) best = candidate;\n }\n }\n }\n if (best === null) {\n // The ENTIRE civil date was skipped — no local wall-clock time on it\n // exists (Pacific/Apia 2011-12-30 is the canonical case: the date-line\n // jump went 2011-12-29 23:59:59-10:00 → 2011-12-31 00:00:00+14:00).\n // Extending the never-backdate convention above, resolve the day start\n // to the transition instant: the earliest instant whose local calendar\n // date reaches `date`. Local date is monotone non-decreasing in the UTC\n // instant (a fall-back never crosses local midnight backwards), so\n // binary-search a 48h bracket at minute granularity. The bracket is\n // safe: `<date>T00:00Z − 24h` is always locally before `date`, and\n // `<date>T00:00Z + 24h` is always locally on/after it.\n let lo = Date.parse(`${date}T00:00:00Z`) - 24 * 3_600_000;\n let hi = lo + 48 * 3_600_000;\n while (hi - lo > 60_000) {\n const mid = lo + Math.floor((hi - lo) / 2 / 60_000) * 60_000;\n if (activityDateInTimezone(new Date(mid), timezone) >= date) hi = mid;\n else lo = mid;\n }\n best = hi;\n }\n if (best === null || !Number.isFinite(best)) {\n throw new RangeError(`activity: could not resolve a local day start for \"${date}\" in \"${timezone}\".`);\n }\n return new Date(best).toISOString();\n}\n\nfunction shiftIsoDate(date: string, days: number): string {\n const parsed = new Date(`${date}T00:00:00Z`);\n parsed.setUTCDate(parsed.getUTCDate() + days);\n return parsed.toISOString().slice(0, 10);\n}\n\nfunction nextIsoDate(date: string): string {\n return shiftIsoDate(date, 1);\n}\n\n/**\n * Half-open [start, end) UTC ISO bounds of a local day. A civil date the\n * zone skipped entirely owns no interval: the window is zero-width\n * `[transition, transition)`.\n */\nexport function activityDayWindow(date: string, timezone: string): { startUtc: string; endUtc: string } {\n if (!isValidActivityDate(date)) {\n throw new RangeError(`Invalid activity date \"${date}\"; expected a real YYYY-MM-DD day.`);\n }\n assertValidTimezone(timezone);\n const startUtc = zonedDayStartIso(date, timezone);\n const endUtc = zonedDayStartIso(nextIsoDate(date), timezone);\n // Skipped-date semantics (Pacific/Apia 2011-12-30 class): the skipped\n // date's start and the following date's start both resolve to the\n // transition instant, so the window is naturally zero-width. Keep it\n // that way: a date that never occurred contributes to no daily total\n // (daysOverlappingWeek drops zero-width days) and a connector sync for\n // it fetches nothing. Pushing the end forward to stay non-degenerate\n // would alias the next real day's interval and double-attribute every\n // card in it to two daily totals.\n return { startUtc, endUtc };\n}\n\n/**\n * The local calendar day (YYYY-MM-DD) an instant falls in for an IANA\n * timezone — the day key `activityDayWindow` buckets on. Callers that need\n * \"today\" for activity artifacts MUST use this rather than the host-local\n * date, which drifts a day near either timezone's midnight.\n */\nexport function activityDateInTimezone(instant: Date, timezone: string): string {\n try {\n const parts = new Intl.DateTimeFormat(\"en-CA\", {\n timeZone: timezone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n }).formatToParts(instant);\n const get = (type: string): string => parts.find((part) => part.type === type)?.value ?? \"\";\n return `${get(\"year\")}-${get(\"month\")}-${get(\"day\")}`;\n } catch {\n return instant.toISOString().slice(0, 10);\n }\n}\n\n// ── Rendering ───────────────────────────────────────────────────────────────\n\nfunction sortedByTime(snapshots: ActivitySnapshot[]): ActivitySnapshot[] {\n return [...snapshots].sort((a, b) => {\n // Compare by parsed instant, not raw string, so mixed valid ISO forms\n // (Z vs offset, varying precision) still order chronologically.\n const at = Date.parse(a.capturedAtUtc);\n const bt = Date.parse(b.capturedAtUtc);\n if (at !== bt && Number.isFinite(at) && Number.isFinite(bt)) return at < bt ? -1 : 1;\n const aid = a.id ?? 0;\n const bid = b.id ?? 0;\n if (aid < bid) return -1;\n if (aid > bid) return 1;\n // Unsaved snapshots (pre-store) both default to id 0; fall back to the\n // content hash (their dedup identity), then app/window, for a total order.\n if (a.contentHash !== b.contentHash) return a.contentHash < b.contentHash ? -1 : 1;\n if (a.app !== b.app) return a.app < b.app ? -1 : 1;\n if (a.windowTitle !== b.windowTitle) return a.windowTitle < b.windowTitle ? -1 : 1;\n return 0;\n });\n}\n\n/**\n * Per-snapshot dwell (gap to that machine's next snapshot, capped), scoped per\n * capture machine so an interleaved snapshot from another machine can't steal\n * or truncate a snapshot's dwell (multi-machine days).\n */\nfunction computeDwell(snapshots: ActivitySnapshot[]): Map<ActivitySnapshot, number> {\n const byMachine = new Map<string, ActivitySnapshot[]>();\n for (const snapshot of snapshots) {\n const list = byMachine.get(snapshot.machine);\n if (list === undefined) byMachine.set(snapshot.machine, [snapshot]);\n else list.push(snapshot);\n }\n const dwell = new Map<ActivitySnapshot, number>();\n for (const list of byMachine.values()) {\n const ordered = sortedByTime(list);\n for (let index = 0; index < ordered.length; index++) {\n const current = ordered[index];\n if (current === undefined) continue;\n const next = ordered[index + 1];\n let value = 0;\n if (next !== undefined) {\n const delta = Date.parse(next.capturedAtUtc) - Date.parse(current.capturedAtUtc);\n if (Number.isFinite(delta) && delta > 0) value = Math.min(delta, MAX_DWELL_MS);\n }\n dwell.set(current, value);\n }\n }\n return dwell;\n}\n\nfunction formatDurationMinutes(ms: number): string {\n return `${Math.round(ms / 60_000)}m`;\n}\n\nfunction clockHhMm(iso: string, timezone: string): string {\n const ms = Date.parse(iso);\n if (!Number.isFinite(ms)) return \"??:??\";\n const parts = new Intl.DateTimeFormat(\"en-GB\", {\n timeZone: timezone,\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false,\n }).formatToParts(new Date(ms));\n const hour = parts.find((p) => p.type === \"hour\")?.value ?? \"00\";\n const minute = parts.find((p) => p.type === \"minute\")?.value ?? \"00\";\n return `${hour}:${minute}`;\n}\n\nfunction collapseWhitespace(text: string): string {\n return text.replace(/\\s+/g, \" \").trim();\n}\n\nfunction perAppSection(ordered: ActivitySnapshot[], dwell: Map<ActivitySnapshot, number>): string {\n const totals = new Map<string, number>();\n for (const snapshot of ordered) {\n totals.set(snapshot.app, (totals.get(snapshot.app) ?? 0) + (dwell.get(snapshot) ?? 0));\n }\n const rows = [...totals.entries()].sort((a, b) => {\n if (b[1] !== a[1]) return b[1] - a[1];\n if (a[0] < b[0]) return -1;\n if (a[0] > b[0]) return 1;\n return 0;\n });\n const lines = [\"## Per-app time\", \"\"];\n if (rows.length === 0) {\n lines.push(\"_No activity recorded._\");\n } else {\n for (const [app, ms] of rows) {\n lines.push(`- ${app}: ${formatDurationMinutes(ms)}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\ninterface TimelineSpan {\n startIso: string;\n machine: string;\n app: string;\n windowTitle: string;\n browserUrl?: string;\n}\n\nfunction timelineSpans(ordered: ActivitySnapshot[]): TimelineSpan[] {\n const spans: TimelineSpan[] = [];\n for (const snapshot of ordered) {\n const last = spans[spans.length - 1];\n if (\n last !== undefined &&\n last.machine === snapshot.machine &&\n last.app === snapshot.app &&\n last.windowTitle === snapshot.windowTitle &&\n last.browserUrl === snapshot.browserUrl\n ) {\n continue;\n }\n spans.push({\n startIso: snapshot.capturedAtUtc,\n machine: snapshot.machine,\n app: snapshot.app,\n windowTitle: snapshot.windowTitle,\n ...(snapshot.browserUrl !== undefined ? { browserUrl: snapshot.browserUrl } : {}),\n });\n }\n return spans;\n}\n\nfunction timelineSection(ordered: ActivitySnapshot[], timezone: string): string {\n const lines = [\"## Timeline\", \"\"];\n const spans = timelineSpans(ordered);\n if (spans.length === 0) {\n lines.push(\"_No activity recorded._\");\n return lines.join(\"\\n\");\n }\n for (const span of spans) {\n const clock = clockHhMm(span.startIso, timezone);\n const window = collapseWhitespace(span.windowTitle);\n const url = span.browserUrl !== undefined ? ` (${collapseWhitespace(span.browserUrl)})` : \"\";\n lines.push(`- [${clock}] ${span.app}${window.length > 0 ? ` — ${window}` : \"\"}${url}`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction notableSection(ordered: ActivitySnapshot[], dwell: Map<ActivitySnapshot, number>): string {\n const withDwell = ordered.map((snapshot) => ({ snapshot, dwell: dwell.get(snapshot) ?? 0 }));\n const ranked = withDwell\n .filter((entry) => collapseWhitespace(entry.snapshot.text).length > 0)\n .sort((a, b) => {\n if (b.dwell !== a.dwell) return b.dwell - a.dwell;\n const at = Date.parse(a.snapshot.capturedAtUtc);\n const bt = Date.parse(b.snapshot.capturedAtUtc);\n if (at !== bt && Number.isFinite(at) && Number.isFinite(bt)) return at < bt ? -1 : 1;\n const idDelta = (a.snapshot.id ?? 0) - (b.snapshot.id ?? 0);\n if (idDelta !== 0) return idDelta;\n if (a.snapshot.contentHash !== b.snapshot.contentHash) {\n return a.snapshot.contentHash < b.snapshot.contentHash ? -1 : 1;\n }\n return 0;\n })\n .slice(0, NOTABLE_MAX_WINDOWS);\n const lines = [\"## Notable\", \"\"];\n if (ranked.length === 0) {\n lines.push(\"_No notable text captured._\");\n return lines.join(\"\\n\");\n }\n for (const { snapshot } of ranked) {\n const excerpt = collapseWhitespace(snapshot.text).slice(0, NOTABLE_EXCERPT_CHARS);\n lines.push(`- **${snapshot.app}** — ${excerpt}`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function composeActivityDigestBody(\n date: string,\n timezone: string,\n snapshots: ActivitySnapshot[],\n): string {\n assertValidTimezone(timezone);\n const ordered = sortedByTime(snapshots);\n const dwell = computeDwell(ordered);\n return [\n `# Activity — ${date}`,\n \"\",\n perAppSection(ordered, dwell),\n \"\",\n timelineSection(ordered, timezone),\n \"\",\n notableSection(ordered, dwell),\n \"\",\n ].join(\"\\n\");\n}\n\nexport function hashActivityBody(body: string): string {\n return createHash(\"sha256\").update(body, \"utf8\").digest(\"hex\");\n}\n\nexport function composeActivityDigestMeta(\n date: string,\n machines: string[],\n snapshots: ActivitySnapshot[],\n body: string,\n): ActivityDayMeta {\n const uniqueMachines = [...new Set(machines)].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n return {\n kind: \"activity-digest\",\n date,\n machines: uniqueMachines,\n snapshotCount: snapshots.length,\n contentHash: hashActivityBody(body),\n formatVersion: ACTIVITY_DIGEST_FORMAT_VERSION,\n };\n}\n\nexport function serializeActivityDigest(meta: ActivityDayMeta, body: string): string {\n const frontmatter = [\n \"---\",\n `kind: ${meta.kind}`,\n `date: ${meta.date}`,\n `machines: ${JSON.stringify(meta.machines)}`,\n `snapshotCount: ${meta.snapshotCount}`,\n `contentHash: ${meta.contentHash}`,\n `formatVersion: ${meta.formatVersion}`,\n \"---\",\n \"\",\n ].join(\"\\n\");\n return `${frontmatter}${body}`;\n}\n\nexport function parseActivityDigest(raw: string): ActivityDayDigest | null {\n if (typeof raw !== \"string\" || !raw.startsWith(\"---\\n\")) return null;\n const end = raw.indexOf(\"\\n---\\n\", 4);\n if (end === -1) return null;\n const frontmatter = raw.slice(4, end);\n const body = raw.slice(end + 5).replace(/^\\n/, \"\");\n const fields = new Map<string, string>();\n for (const line of frontmatter.split(\"\\n\")) {\n const idx = line.indexOf(\":\");\n if (idx === -1) continue;\n fields.set(line.slice(0, idx).trim(), line.slice(idx + 1).trim());\n }\n const date = fields.get(\"date\");\n const contentHash = fields.get(\"contentHash\");\n if (date === undefined || !isValidActivityDate(date) || contentHash === undefined) return null;\n if (fields.get(\"kind\") !== \"activity-digest\") return null;\n const machines = parseMachinesList(fields.get(\"machines\") ?? \"[]\");\n const snapshotCount = parseNonNegativeInt(fields.get(\"snapshotCount\"));\n const formatVersion = parseNonNegativeInt(fields.get(\"formatVersion\"));\n if (snapshotCount === null || formatVersion === null) return null;\n return {\n meta: {\n kind: \"activity-digest\",\n date,\n machines,\n snapshotCount,\n contentHash,\n formatVersion,\n },\n body,\n };\n}\n\nfunction parseNonNegativeInt(value: string | undefined): number | null {\n if (value === undefined) return null;\n const trimmed = value.trim();\n if (!/^\\d+$/.test(trimmed)) return null;\n const parsed = Number(trimmed);\n return Number.isSafeInteger(parsed) ? parsed : null;\n}\n\nfunction parseMachinesList(raw: string): string[] {\n try {\n const parsed: unknown = JSON.parse(raw);\n if (Array.isArray(parsed)) {\n return parsed.filter((entry): entry is string => typeof entry === \"string\");\n }\n } catch {\n // Legacy unquoted inline form (`[a, b]`) — fall through to the split parse.\n }\n return raw\n .replace(/^\\[/, \"\")\n .replace(/\\]$/, \"\")\n .split(\",\")\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0);\n}\n"],"mappings":"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","names":[]}
|