@remnic/core 9.45.2 → 9.45.4
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/abort-error.d.ts +2 -1
- package/dist/abort-error.js +3 -1
- package/dist/access-admin-ops-surface.d.ts +14 -10
- package/dist/access-admin-ops-surface.js +84 -76
- package/dist/access-audit.js +2 -2
- package/dist/access-authorization-probe.d.ts +14 -10
- package/dist/access-authorization-probe.js +85 -77
- package/dist/access-boundary.d.ts +15 -11
- package/dist/access-boundary.js +84 -76
- package/dist/access-citation-namespace.js +2 -2
- package/dist/access-cli.js +193 -181
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.d.ts +16 -0
- package/dist/access-coding-context-resolution.js +13 -0
- package/dist/access-coding-context-resolution.js.map +1 -0
- package/dist/access-extraction-force-flush.d.ts +14 -10
- package/dist/access-extraction-force-flush.js +84 -76
- package/dist/access-health-types.d.ts +2 -1
- package/dist/access-http-lcm-compaction.d.ts +16 -12
- package/dist/access-http-lcm-compaction.js +3 -3
- package/dist/access-http-lifecycle-flush.d.ts +14 -10
- package/dist/access-http-lifecycle-flush.js +2 -2
- package/dist/access-http-offline-stream.d.ts +123 -0
- package/dist/access-http-offline-stream.js +10 -0
- package/dist/access-http-offline-stream.js.map +1 -0
- package/dist/access-http-query.js +84 -76
- package/dist/access-http.d.ts +15 -10
- package/dist/access-http.js +105 -92
- package/dist/access-identity-continuity-surface.d.ts +9 -8
- package/dist/access-identity-continuity-surface.js +84 -76
- package/dist/access-lcm-surface.d.ts +14 -10
- package/dist/access-lcm-surface.js +84 -76
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +14 -10
- package/dist/access-mcp.js +95 -83
- package/dist/access-memory-search-fanout.d.ts +3 -2
- package/dist/{access-namespace-preflight-5yZ4g6F8.d.ts → access-namespace-preflight-CWUDwB4M.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +4 -3
- package/dist/access-namespace-preflight.js +84 -76
- package/dist/access-observe-helpers.d.ts +1 -0
- package/dist/access-observe-helpers.js +1 -1
- package/dist/access-observe-write-surface.d.ts +16 -10
- package/dist/access-observe-write-surface.js +84 -76
- package/dist/access-offline-manifest.d.ts +104 -0
- package/dist/access-offline-manifest.js +45 -0
- package/dist/access-offline-manifest.js.map +1 -0
- package/dist/access-operations-batch.js +86 -78
- package/dist/access-operations.d.ts +18 -14
- package/dist/access-operations.js +91 -80
- package/dist/access-recall-concurrency.d.ts +16 -26
- package/dist/access-recall-concurrency.js +86 -77
- package/dist/access-recall-response.d.ts +18 -14
- package/dist/access-recall-response.js +84 -76
- package/dist/access-recall-surface.d.ts +29 -24
- package/dist/access-recall-surface.js +84 -76
- package/dist/access-schema.d.ts +84 -84
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-CiJRsgAB.d.ts → access-service-CsU-ljFD.d.ts} +25 -16
- package/dist/access-service-helpers.d.ts +14 -10
- package/dist/access-service.d.ts +14 -10
- package/dist/access-service.js +84 -76
- package/dist/access-surface-catalog.d.ts +14 -10
- package/dist/access-surface-catalog.js +4 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +4 -3
- package/dist/action-confidence.d.ts +2 -1
- package/dist/active-memory-bridge.d.ts +2 -1
- package/dist/active-recall.d.ts +2 -1
- package/dist/active-recall.js +10 -8
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/{auto-sync-5OE5QOZB.js → auto-sync-UPTUVE4X.js} +6 -6
- package/dist/behavior-learner.d.ts +2 -1
- package/dist/behavior-learner.js +1 -1
- package/dist/behavior-signals.d.ts +2 -1
- package/dist/bootstrap.d.ts +9 -8
- package/dist/briefing.d.ts +3 -2
- package/dist/briefing.js +23 -22
- package/dist/buffer-surprise-report.d.ts +2 -1
- package/dist/buffer-turn-helpers.d.ts +2 -1
- package/dist/buffer.d.ts +3 -2
- package/dist/buffer.js +12 -11
- package/dist/bulk-import/index.d.ts +4 -3
- package/dist/calibration.d.ts +2 -1
- package/dist/capabilities.d.ts +2 -1
- package/dist/{capsule-merge-IDWJPCWK.js → capsule-merge-Q6AR3XL7.js} +67 -54
- package/dist/capsule-merge-Q6AR3XL7.js.map +1 -0
- package/dist/{catalog-scBmy0sO.d.ts → catalog-bctMURhN.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +2 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +2 -1
- package/dist/causal-consolidation.js +27 -26
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +2 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-VUPTKTDV.js → chunk-2MRHJNWL.js} +3 -3
- package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
- package/dist/{chunk-5IVLTFOV.js → chunk-44N6ESJ4.js} +2 -2
- package/dist/{chunk-WOCNN776.js → chunk-4POAMKV6.js} +100 -41
- package/dist/chunk-4POAMKV6.js.map +1 -0
- package/dist/{chunk-HO3QBJEY.js → chunk-5546W5SI.js} +2 -2
- package/dist/{chunk-U7GW7NE7.js → chunk-5CEECY6P.js} +10 -10
- package/dist/{chunk-4UH4BTGK.js → chunk-5SNZSWWR.js} +82 -82
- package/dist/{chunk-6CZPDBJS.js → chunk-5U7ID3EZ.js} +3 -3
- package/dist/{chunk-GF22HWS2.js → chunk-6NNNURLK.js} +7 -7
- package/dist/chunk-773TRRGT.js +36 -0
- package/dist/chunk-773TRRGT.js.map +1 -0
- package/dist/chunk-7CITSYSH.js +242 -0
- package/dist/chunk-7CITSYSH.js.map +1 -0
- package/dist/{chunk-227UFSEQ.js → chunk-7RZJWZ46.js} +5 -5
- package/dist/{chunk-E5UK4VPE.js → chunk-7SHJHPTY.js} +5 -5
- package/dist/{chunk-UVIKWC7M.js → chunk-7YERSTN7.js} +17 -17
- package/dist/{chunk-DLVPUX7U.js → chunk-7YKVM5H3.js} +8 -6
- package/dist/chunk-7YKVM5H3.js.map +1 -0
- package/dist/{chunk-3CE77VAP.js → chunk-A4JMGKCD.js} +87 -74
- package/dist/chunk-A4JMGKCD.js.map +1 -0
- package/dist/chunk-A5KNZSNA.js +26 -0
- package/dist/chunk-A5KNZSNA.js.map +1 -0
- package/dist/{chunk-S2NCTZGJ.js → chunk-AJQ57VV3.js} +15 -15
- package/dist/chunk-AJQ57VV3.js.map +1 -0
- package/dist/{chunk-CUM2BBPN.js → chunk-AUMWZSE7.js} +19 -10
- package/dist/chunk-AUMWZSE7.js.map +1 -0
- package/dist/{chunk-XYTOI63Z.js → chunk-BGHFOD5A.js} +19 -11
- package/dist/chunk-BGHFOD5A.js.map +1 -0
- package/dist/{chunk-BUE5E2HL.js → chunk-BGLY7EEM.js} +5 -314
- package/dist/chunk-BGLY7EEM.js.map +1 -0
- package/dist/chunk-BIPBQQFI.js +44 -0
- package/dist/chunk-BIPBQQFI.js.map +1 -0
- package/dist/{chunk-S5SLVSVY.js → chunk-BQIFZ2MP.js} +5 -5
- package/dist/chunk-BTTPKDIL.js +34 -0
- package/dist/{chunk-PVGDJXVK.js.map → chunk-BTTPKDIL.js.map} +1 -1
- package/dist/{chunk-E53DSZEN.js → chunk-C26TE27X.js} +3 -3
- package/dist/{chunk-LZ4LDKHZ.js → chunk-CLB32OHM.js} +6 -6
- package/dist/{chunk-Q6IP2ARR.js → chunk-CSOYVTRX.js} +2 -2
- package/dist/{chunk-XOQSEF7X.js → chunk-CVILPI77.js} +6 -6
- package/dist/chunk-D3I2MCN7.js +29 -0
- package/dist/chunk-D3I2MCN7.js.map +1 -0
- package/dist/{chunk-A5OJCXZL.js → chunk-DSUAAZZX.js} +15 -4
- package/dist/chunk-DSUAAZZX.js.map +1 -0
- package/dist/{chunk-HREE4JHI.js → chunk-DYVMXPCF.js} +486 -287
- package/dist/chunk-DYVMXPCF.js.map +1 -0
- package/dist/{chunk-J7VGGECD.js → chunk-DZPFMQZ7.js} +1 -1
- package/dist/chunk-DZPFMQZ7.js.map +1 -0
- package/dist/{chunk-PDLBLTOK.js → chunk-EITZHSX6.js} +9 -9
- package/dist/{chunk-D3J5SLQK.js → chunk-EJHEWCGQ.js} +81 -20
- package/dist/chunk-EJHEWCGQ.js.map +1 -0
- package/dist/{chunk-WUNIWKY4.js → chunk-ELIL2A37.js} +6 -6
- package/dist/{chunk-E6PNLPGJ.js → chunk-FZP32336.js} +806 -470
- package/dist/chunk-FZP32336.js.map +1 -0
- package/dist/{chunk-4L6HUREQ.js → chunk-G7A5HLUS.js} +23 -17
- package/dist/chunk-G7A5HLUS.js.map +1 -0
- package/dist/{chunk-CINZGPSJ.js → chunk-GUMZC2BO.js} +2 -2
- package/dist/{chunk-H24WNPA2.js → chunk-GWFSVJ4P.js} +3 -3
- package/dist/{chunk-7XC2HX75.js → chunk-GYPQL6XN.js} +157 -16
- package/dist/chunk-GYPQL6XN.js.map +1 -0
- package/dist/{chunk-TSH56VPU.js → chunk-HAYSYUAB.js} +2 -2
- package/dist/{chunk-TDHTVMPG.js → chunk-HFPASSFV.js} +7 -2
- package/dist/chunk-HFPASSFV.js.map +1 -0
- package/dist/chunk-J2WC5LF4.js +395 -0
- package/dist/chunk-J2WC5LF4.js.map +1 -0
- package/dist/{chunk-PKNLM44P.js → chunk-JH6BPLOP.js} +9 -9
- package/dist/{chunk-KXB4VXHY.js → chunk-JIYDRBVZ.js} +2 -2
- package/dist/chunk-JV3C2MNQ.js +74 -0
- package/dist/chunk-JV3C2MNQ.js.map +1 -0
- package/dist/{chunk-AV5ZEH4M.js → chunk-KVJRXN2E.js} +2 -2
- package/dist/{chunk-JVLCVFQ4.js → chunk-KXEFRMCF.js} +3 -3
- package/dist/{chunk-WFTIGIIS.js → chunk-L6CQ7WIW.js} +5 -5
- package/dist/{chunk-EJUEXZHX.js → chunk-LLJMAULE.js} +2 -2
- package/dist/{chunk-N5Z4EVOR.js → chunk-LNEWDF2A.js} +36 -11
- package/dist/chunk-LNEWDF2A.js.map +1 -0
- package/dist/{chunk-AS7YMSL6.js → chunk-M23RF3LJ.js} +4 -4
- package/dist/{chunk-UYLMNVY6.js → chunk-MDISBSYA.js} +16 -9
- package/dist/chunk-MDISBSYA.js.map +1 -0
- package/dist/{chunk-3F2LKUMU.js → chunk-NIS256NW.js} +2 -2
- package/dist/{chunk-YIAA2X3D.js → chunk-NK5RGJ65.js} +3 -3
- package/dist/chunk-NLDVVWCL.js +84 -0
- package/dist/chunk-NLDVVWCL.js.map +1 -0
- package/dist/{chunk-OQ5PRDDS.js → chunk-NTOIP2E6.js} +6 -6
- package/dist/{chunk-HLPD7B7P.js → chunk-NUEQKLNB.js} +2 -2
- package/dist/{chunk-4J7G5SY4.js → chunk-NZBZ7IS2.js} +72 -24
- package/dist/chunk-NZBZ7IS2.js.map +1 -0
- package/dist/{chunk-3TBLDMJA.js → chunk-O4KMGRXE.js} +5 -2
- package/dist/chunk-O4KMGRXE.js.map +1 -0
- package/dist/{chunk-33PLLLL7.js → chunk-P7NGM24P.js} +6 -6
- package/dist/{chunk-7TWUCYER.js → chunk-PNRA7FAD.js} +7 -7
- package/dist/{chunk-5I4M26Q7.js → chunk-QBSFOKY6.js} +4 -4
- package/dist/{chunk-QJAQNXWI.js → chunk-QCECHYZL.js} +76 -79
- package/dist/chunk-QCECHYZL.js.map +1 -0
- package/dist/{chunk-P4DRWEYC.js → chunk-QVSBTCVP.js} +2 -2
- package/dist/{chunk-AAIUERNB.js → chunk-R5RFK3CB.js} +6 -6
- package/dist/{chunk-WDISJRMG.js → chunk-RMMVQQA6.js} +2 -2
- package/dist/{chunk-KWMXR7XS.js → chunk-S2V7RUCL.js} +8 -1
- package/dist/{chunk-KWMXR7XS.js.map → chunk-S2V7RUCL.js.map} +1 -1
- package/dist/{chunk-5SM35XZR.js → chunk-S5NZBKKQ.js} +2 -2
- package/dist/{chunk-VNA7W7QF.js → chunk-SVH57F5Z.js} +12 -4
- package/dist/chunk-SVH57F5Z.js.map +1 -0
- package/dist/{chunk-WIPEXG6R.js → chunk-SXIMQLGV.js} +2 -2
- package/dist/{chunk-RVLJEII5.js → chunk-SYUBB3WM.js} +256 -187
- package/dist/chunk-SYUBB3WM.js.map +1 -0
- package/dist/{chunk-OAEQLRCY.js → chunk-TN76AKO3.js} +5 -5
- package/dist/{chunk-QN25OCUF.js → chunk-TQ4GD737.js} +5 -5
- package/dist/{chunk-VCD4PSK2.js → chunk-TQZ4DVBC.js} +7 -4
- package/dist/chunk-TQZ4DVBC.js.map +1 -0
- package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
- package/dist/{chunk-DNWXFTLD.js → chunk-TYISDI6B.js} +2 -2
- package/dist/{chunk-4LMA77JH.js → chunk-U2VLVBBH.js} +3 -3
- package/dist/{chunk-5ZE7QHTK.js → chunk-ULVR5KG7.js} +5 -5
- package/dist/{chunk-NVRYW264.js → chunk-UQWIKLQK.js} +18 -15
- package/dist/chunk-UQWIKLQK.js.map +1 -0
- package/dist/{chunk-YV32N67O.js → chunk-URS5GSM7.js} +1 -1
- package/dist/chunk-URS5GSM7.js.map +1 -0
- package/dist/{chunk-4B77XSG5.js → chunk-UV72DEZD.js} +5 -5
- package/dist/{chunk-S2BBISHU.js → chunk-VANZKHTN.js} +3 -3
- package/dist/chunk-VHFXP27N.js +250 -0
- package/dist/chunk-VHFXP27N.js.map +1 -0
- package/dist/{chunk-3Y224NYC.js → chunk-VYISFWVX.js} +2 -2
- package/dist/{chunk-TIHMZFIV.js → chunk-W3IC7QOY.js} +3 -3
- package/dist/{chunk-NRV4Y3PM.js → chunk-W4FBGYGK.js} +1 -1
- package/dist/{chunk-P2BM76KT.js → chunk-WAS4HV46.js} +174 -43
- package/dist/chunk-WAS4HV46.js.map +1 -0
- package/dist/{chunk-57QKLRBV.js → chunk-WB7JSQCP.js} +2 -1
- package/dist/chunk-WB7JSQCP.js.map +1 -0
- package/dist/chunk-WGP57SR3.js +68 -0
- package/dist/chunk-WGP57SR3.js.map +1 -0
- package/dist/{chunk-ECK75GDJ.js → chunk-WQIHRA5F.js} +43 -24
- package/dist/chunk-WQIHRA5F.js.map +1 -0
- package/dist/{chunk-MU7ZHSZE.js → chunk-WZFAPHIK.js} +2 -2
- package/dist/{chunk-T2TTP3KU.js → chunk-X4IDNPOS.js} +2 -2
- package/dist/{chunk-BLAKS3CP.js → chunk-XL3TATMJ.js} +3 -3
- package/dist/{chunk-W4XJFLAL.js → chunk-XPRJSHNI.js} +2 -2
- package/dist/{chunk-5TFP4CUL.js → chunk-XQ3HXAQH.js} +14 -11
- package/dist/chunk-XQ3HXAQH.js.map +1 -0
- package/dist/{chunk-VWAXN2BN.js → chunk-XSFHWBQO.js} +93 -31
- package/dist/chunk-XSFHWBQO.js.map +1 -0
- package/dist/{chunk-DL7ZD3JH.js → chunk-XTAUXTDO.js} +14 -9
- package/dist/chunk-XTAUXTDO.js.map +1 -0
- package/dist/{chunk-JE7EK33X.js → chunk-Y7HRYCNW.js} +2 -2
- package/dist/{chunk-E6EE5B67.js → chunk-YK6BDDHP.js} +4 -4
- package/dist/{chunk-ES36HTSC.js → chunk-YLHM5BQQ.js} +3 -3
- package/dist/{chunk-RN7DY3FC.js → chunk-YMAQDHQM.js} +31 -12
- package/dist/chunk-YMAQDHQM.js.map +1 -0
- package/dist/{chunk-ULARSG5Z.js → chunk-YN6ASZUG.js} +10 -8
- package/dist/{chunk-ULARSG5Z.js.map → chunk-YN6ASZUG.js.map} +1 -1
- package/dist/{chunk-IKKWIPYN.js → chunk-YYQAKIDJ.js} +37 -1
- package/dist/chunk-YYQAKIDJ.js.map +1 -0
- package/dist/{chunk-BJKPPZ6Z.js → chunk-ZFGZ6PZ2.js} +2 -2
- package/dist/{chunk-CJ2ZR7UA.js → chunk-ZI32MKDW.js} +267 -214
- package/dist/chunk-ZI32MKDW.js.map +1 -0
- package/dist/{chunk-64UDOIMI.js → chunk-ZLQ37WJX.js} +2 -2
- package/dist/chunk-ZMAYKGPN.js +351 -0
- package/dist/chunk-ZMAYKGPN.js.map +1 -0
- package/dist/{cli-BUGN3d6_.d.ts → cli-BBHDtG36.d.ts} +5 -5
- package/dist/cli.d.ts +16 -12
- package/dist/cli.js +138 -124
- package/dist/compounding/engine.d.ts +3 -2
- package/dist/compounding/engine.js +24 -23
- package/dist/compounding/preference-consolidator.d.ts +2 -1
- package/dist/compression-optimizer.d.ts +2 -1
- package/dist/config.d.ts +2 -1
- package/dist/config.js +10 -8
- package/dist/connectors/codex-materialize-runner.d.ts +2 -1
- package/dist/connectors/codex-materialize-runner.js +23 -22
- package/dist/connectors/codex-materialize.d.ts +2 -1
- package/dist/connectors/index.d.ts +2 -1
- package/dist/connectors/index.js +26 -25
- package/dist/consolidation-provenance-check.d.ts +3 -2
- package/dist/consolidation-provenance-check.js +4 -4
- package/dist/consolidation-undo.d.ts +3 -2
- package/dist/consolidation-undo.js +10 -7
- package/dist/consolidation-undo.js.map +1 -1
- package/dist/contradiction/index.d.ts +3 -2
- package/dist/converge-config.d.ts +2 -1
- package/dist/convergence-refresh.d.ts +4 -3
- package/dist/convergence-refresh.js +27 -26
- package/dist/conversation-index/backend.d.ts +2 -1
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/chunker.d.ts +2 -1
- package/dist/conversation-index/faiss-adapter.d.ts +2 -1
- package/dist/conversation-index/indexer.d.ts +2 -1
- package/dist/conversation-index/search.d.ts +2 -1
- package/dist/corpus-watermark.d.ts +2 -1
- package/dist/corpus-watermark.js +42 -41
- package/dist/day-summary.d.ts +2 -1
- package/dist/delinearize.d.ts +2 -1
- package/dist/direct-answer-wiring.d.ts +2 -1
- package/dist/direct-answer-wiring.js +2 -2
- package/dist/direct-answer.d.ts +2 -1
- package/dist/embedding-fallback.d.ts +2 -1
- package/dist/embedding-fallback.js +2 -2
- package/dist/enrichment/index.d.ts +2 -1
- package/dist/entity-retrieval-boundaries.js +1 -1
- package/dist/entity-retrieval.d.ts +3 -2
- package/dist/entity-retrieval.js +24 -23
- package/dist/entity-schema.d.ts +2 -1
- package/dist/explicit-capture.d.ts +9 -8
- package/dist/explicit-capture.js +11 -9
- package/dist/external-wiki-access.d.ts +127 -0
- package/dist/external-wiki-access.js +186 -0
- package/dist/external-wiki-access.js.map +1 -0
- package/dist/external-wiki-cli.d.ts +13 -0
- package/dist/external-wiki-cli.js +96 -0
- package/dist/external-wiki-cli.js.map +1 -0
- package/dist/external-wiki-collection-registration.d.ts +39 -0
- package/dist/external-wiki-collection-registration.js +79 -0
- package/dist/external-wiki-collection-registration.js.map +1 -0
- package/dist/external-wiki-collection.d.ts +50 -0
- package/dist/external-wiki-collection.js +387 -0
- package/dist/external-wiki-collection.js.map +1 -0
- package/dist/external-wiki-config.d.ts +13 -0
- package/dist/external-wiki-config.js +13 -0
- package/dist/external-wiki-config.js.map +1 -0
- package/dist/external-wiki-guard.d.ts +11 -0
- package/dist/external-wiki-guard.js +18 -0
- package/dist/external-wiki-guard.js.map +1 -0
- package/dist/external-wiki-mcp-tools.d.ts +123 -0
- package/dist/external-wiki-mcp-tools.js +8 -0
- package/dist/external-wiki-mcp-tools.js.map +1 -0
- package/dist/external-wiki-search.d.ts +42 -0
- package/dist/external-wiki-search.js +11 -0
- package/dist/external-wiki-search.js.map +1 -0
- package/dist/external-wiki.d.ts +43 -0
- package/dist/external-wiki.js +16 -0
- package/dist/external-wiki.js.map +1 -0
- package/dist/extraction-error-classification.d.ts +2 -1
- package/dist/extraction-faithfulness.d.ts +2 -1
- package/dist/extraction-judge-telemetry.d.ts +2 -1
- package/dist/extraction-judge-training.d.ts +2 -1
- package/dist/extraction-judge.d.ts +2 -1
- package/dist/extraction-liveness.d.ts +2 -1
- package/dist/extraction-source-grounding-helpers.d.ts +5 -3
- package/dist/extraction-source-grounding-helpers.js +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +2 -1
- package/dist/extraction-source-grounding-rules.js +2 -2
- package/dist/extraction-source-grounding.d.ts +2 -1
- package/dist/extraction-source-grounding.js +5 -5
- package/dist/extraction.d.ts +2 -1
- package/dist/extraction.js +45 -43
- package/dist/fallback-llm.d.ts +2 -1
- package/dist/graph-dashboard-diff.d.ts +2 -1
- package/dist/graph-dashboard-key.d.ts +2 -1
- package/dist/graph-dashboard-parser.d.ts +2 -1
- package/dist/graph-edge-reinforcement.d.ts +2 -1
- package/dist/graph-snapshot.d.ts +2 -1
- package/dist/graph.d.ts +2 -1
- package/dist/harmonic-retrieval.js +2 -2
- package/dist/importance.d.ts +2 -1
- package/dist/importers/index.d.ts +2 -1
- package/dist/in-flight-reads.d.ts +2 -1
- package/dist/index.d.ts +732 -720
- package/dist/index.js +291 -259
- package/dist/intent.d.ts +2 -1
- package/dist/lcm/engine.d.ts +2 -1
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.d.ts +2 -1
- package/dist/lcm/index.js +8 -8
- package/dist/lcm/tools.d.ts +2 -1
- package/dist/lifecycle.d.ts +2 -1
- package/dist/live-connectors-runner.d.ts +2 -1
- package/dist/local-llm.d.ts +2 -1
- package/dist/local-llm.js +2 -2
- package/dist/local-model-endpoint.d.ts +2 -1
- package/dist/maintenance/memory-governance.d.ts +2 -1
- package/dist/maintenance/memory-governance.js +24 -23
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +24 -23
- package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-projection.js +26 -25
- package/dist/{maintenance-LbuS2rUA.d.ts → maintenance-D2mveyCd.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +14 -10
- package/dist/mcp-read-only-tools.js +1 -1
- package/dist/memory-action-policy.d.ts +2 -1
- package/dist/memory-cache.d.ts +2 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
- package/dist/memory-projection-store.d.ts +2 -1
- package/dist/memory-provenance.d.ts +2 -1
- package/dist/memory-worth-outcomes.d.ts +3 -2
- package/dist/models-json.d.ts +2 -1
- package/dist/namespaces/migrate.d.ts +4 -3
- package/dist/namespaces/migrate.js +40 -39
- package/dist/namespaces/principal.d.ts +2 -1
- package/dist/namespaces/search.d.ts +2 -1
- package/dist/namespaces/search.js +18 -18
- package/dist/namespaces/storage.d.ts +4 -3
- package/dist/namespaces/storage.js +23 -22
- package/dist/native-knowledge.d.ts +2 -1
- package/dist/offline-sync-impression-drain.d.ts +2 -1
- package/dist/offline-sync-impression-drain.js +11 -9
- package/dist/offline-sync.d.ts +29 -3
- package/dist/offline-sync.js +6 -2
- package/dist/operator-doctor-corpus.d.ts +2 -1
- package/dist/operator-doctor-corpus.js +45 -44
- package/dist/operator-doctor-replica.d.ts +2 -1
- package/dist/operator-doctor-replica.js +3 -3
- package/dist/operator-toolkit.d.ts +4 -3
- package/dist/operator-toolkit.js +59 -55
- package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
- package/dist/orchestration/maintenance.d.ts +5 -4
- package/dist/orchestration/maintenance.js +36 -33
- package/dist/{orchestrator-rHiWt32X.d.ts → orchestrator-DJYlwiUv.d.ts} +14 -7
- package/dist/orchestrator.d.ts +9 -8
- package/dist/orchestrator.js +201 -189
- package/dist/page-versioning.js +3 -3
- package/dist/patterns-cli.d.ts +2 -1
- package/dist/{pipeline-W_97O8BV.d.ts → pipeline-CNjY4wk3.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +2 -1
- package/dist/policy-runtime.js +1 -1
- package/dist/proactive-contention.d.ts +2 -1
- package/dist/provenance.d.ts +2 -1
- package/dist/provenance.js +2 -2
- package/dist/{qmd-LWtMofAf.d.ts → qmd-C0UDZidt.d.ts} +9 -7
- package/dist/qmd-preflight.d.ts +5 -4
- package/dist/qmd-preflight.js +2 -2
- package/dist/qmd-recall-cache.d.ts +2 -1
- package/dist/qmd.d.ts +4 -3
- package/dist/qmd.js +5 -5
- package/dist/recall-concurrency-config.d.ts +2 -1
- package/dist/recall-disclosure-escalation.d.ts +2 -1
- package/dist/recall-explain-renderer.d.ts +2 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +2 -1
- package/dist/recall-planner-llm.d.ts +2 -1
- package/dist/recall-state.d.ts +2 -1
- package/dist/recall-tag-filter.d.ts +2 -1
- package/dist/recall-timings.d.ts +2 -1
- package/dist/recall-xray-cli.d.ts +2 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +2 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +8 -1
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/cursor.d.ts +12 -2
- package/dist/reconcile/cursor.js +46 -7
- package/dist/reconcile/cursor.js.map +1 -1
- package/dist/reconcile/manifest.d.ts +9 -2
- package/dist/reconcile/manifest.js +15 -268
- package/dist/reconcile/manifest.js.map +1 -1
- package/dist/reconcile/plan.d.ts +6 -2
- package/dist/reconcile/plan.js +4 -4
- package/dist/replay/normalizers/chatgpt.d.ts +2 -1
- package/dist/replay/normalizers/claude.d.ts +2 -1
- package/dist/replay/normalizers/openclaw.d.ts +2 -1
- package/dist/replay/normalizers/shared.d.ts +2 -1
- package/dist/replay/runner.d.ts +2 -1
- package/dist/replay/types.d.ts +2 -1
- package/dist/replica-divergence.d.ts +2 -1
- package/dist/replica-divergence.js +2 -2
- package/dist/replica-peers-config.d.ts +2 -1
- package/dist/resolve-auth-token.d.ts +2 -1
- package/dist/resume-bundles.js +12 -10
- package/dist/retrieval-agents.d.ts +4 -3
- package/dist/retrieval-agents.js +2 -2
- package/dist/retrieval-tiers.d.ts +2 -1
- package/dist/routing/engine.d.ts +2 -1
- package/dist/routing/store.d.ts +2 -1
- package/dist/salvage-envelope.d.ts +2 -1
- package/dist/schemas.d.ts +76 -76
- package/dist/{scope-profiles-BiQKOE-p.d.ts → scope-profiles-BJzp2F5A.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +2 -1
- package/dist/search/embed-helper.js +3 -3
- package/dist/search/factory.d.ts +4 -2
- package/dist/search/factory.js +20 -18
- package/dist/search/index.d.ts +2 -1
- package/dist/search/index.js +22 -22
- package/dist/search/lancedb-backend.d.ts +2 -1
- package/dist/search/lancedb-backend.js +4 -4
- package/dist/search/meilisearch-backend.d.ts +2 -1
- package/dist/search/meilisearch-backend.js +4 -4
- package/dist/search/noop-backend.d.ts +2 -1
- package/dist/search/orama-backend.d.ts +2 -1
- package/dist/search/orama-backend.js +4 -4
- package/dist/search/port.d.ts +18 -1
- package/dist/search/port.js +1 -1
- package/dist/search/remote-backend.d.ts +2 -1
- package/dist/search/remote-backend.js +2 -2
- package/dist/secure-store/index.js +2 -2
- package/dist/{semantic-consolidation-dHYCyqgh.d.ts → semantic-consolidation-D4KAZO2G.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +3 -2
- package/dist/semantic-consolidation.js +25 -24
- package/dist/semantic-rule-promotion.js +23 -22
- package/dist/semantic-rule-verifier.d.ts +2 -1
- package/dist/semantic-rule-verifier.js +24 -23
- package/dist/{service-DJG3KCQ4.d.ts → service-BeDxSqE-.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +2 -1
- package/dist/session-observer-state.d.ts +2 -1
- package/dist/shared-context/manager.d.ts +10 -9
- package/dist/shared-context/manager.js +2 -2
- package/dist/signal.d.ts +2 -1
- package/dist/source-agent-qualifier.d.ts +2 -1
- package/dist/source-agent-qualifier.js +42 -40
- package/dist/{storage-F9FVh-w9.d.ts → storage-DfjxusTE.d.ts} +24 -12
- package/dist/storage.d.ts +3 -2
- package/dist/storage.js +25 -24
- package/dist/summarizer.d.ts +2 -1
- package/dist/summarizer.js +5 -5
- package/dist/summary-snapshot.d.ts +2 -1
- package/dist/temporal-supersession.d.ts +3 -2
- package/dist/temporal-timeline-recall.d.ts +2 -1
- package/dist/temporal-validity.d.ts +2 -1
- package/dist/threading.d.ts +2 -1
- package/dist/tier-migration.d.ts +3 -2
- package/dist/tier-routing.d.ts +2 -1
- package/dist/tool-scoped-memory.d.ts +5 -1
- package/dist/tool-scoped-memory.js +3 -1
- package/dist/topics.d.ts +2 -1
- package/dist/transcript.d.ts +2 -1
- package/dist/transfer/capsule-import.js +4 -4
- package/dist/transfer/types.d.ts +66 -66
- package/dist/trust-score-stage.d.ts +2 -1
- package/dist/trust-score.d.ts +2 -1
- package/dist/{types-rEwubvim.d.ts → types-yX_FwERf.d.ts} +8 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +2 -1
- package/dist/verified-recall.js +24 -23
- package/dist/write-envelope.d.ts +2 -1
- package/package.json +2 -2
- package/src/abort-error.ts +17 -0
- package/src/access-admin-ops-surface.ts +1 -0
- package/src/access-boundary.ts +1 -0
- package/src/access-coding-context-resolution.ts +42 -0
- package/src/access-extraction-force-flush.ts +38 -2
- package/src/access-http-lcm-compaction.ts +5 -2
- package/src/access-http-offline-stream.ts +79 -0
- package/src/access-http.test.ts +310 -3
- package/src/access-http.ts +85 -21
- package/src/access-mcp-output-schemas.ts +36 -0
- package/src/access-mcp.test.ts +95 -1
- package/src/access-mcp.ts +7 -9
- package/src/access-observe-helpers.ts +64 -22
- package/src/access-observe-write-surface.ts +8 -0
- package/src/access-offline-manifest.ts +54 -0
- package/src/access-operations-batch.ts +3 -3
- package/src/access-operations.ts +13 -7
- package/src/access-recall-concurrency.ts +3 -27
- package/src/access-recall-surface.ts +3 -0
- package/src/access-service-health.test.ts +32 -7
- package/src/access-service-namespace.test.ts +55 -0
- package/src/access-service-observe-idempotency.test.ts +34 -2
- package/src/access-service-observe-lcm-parity.test.ts +138 -3
- package/src/access-service-observe-scope.test.ts +160 -1
- package/src/access-service-offline-file-content.test.ts +345 -1
- package/src/access-service.ts +86 -59
- package/src/access-surface-catalog.ts +4 -0
- package/src/admin/admin-surfaces.ts +2 -0
- package/src/binary-lifecycle/pipeline.test.ts +106 -1
- package/src/binary-lifecycle/pipeline.ts +3 -0
- package/src/coding/git-context.test.ts +47 -0
- package/src/coding/git-context.ts +129 -27
- package/src/config.test.ts +24 -0
- package/src/config.ts +9 -12
- package/src/connector-provenance.test.ts +101 -0
- package/src/consolidation-undo.ts +3 -0
- package/src/converge-conflict-policy-type.test.ts +15 -0
- package/src/convergence-refresh.ts +14 -2
- package/src/correction/correction-access-wiring.ts +9 -7
- package/src/correction/correction-executor.test.ts +206 -2
- package/src/correction/correction-executor.ts +29 -20
- package/src/correction/correction-planner.test.ts +36 -0
- package/src/correction/correction-planner.ts +9 -15
- package/src/correction/correction-service.ts +3 -1
- package/src/correction/correction-storage-integration.test.ts +77 -0
- package/src/correction/correction-surfaces.test.ts +41 -28
- package/src/correction/passive-capture.test.ts +59 -0
- package/src/correction/passive-capture.ts +4 -1
- package/src/entity-retrieval-boundaries.ts +17 -4
- package/src/entity-retrieval.ts +27 -6
- package/src/external-wiki-access.test.ts +65 -0
- package/src/external-wiki-access.ts +31 -0
- package/src/external-wiki-cli.ts +92 -0
- package/src/external-wiki-collection-registration.test.ts +163 -0
- package/src/external-wiki-collection-registration.ts +101 -0
- package/src/external-wiki-collection.test.ts +502 -0
- package/src/external-wiki-collection.ts +503 -0
- package/src/external-wiki-config.test.ts +135 -0
- package/src/external-wiki-config.ts +100 -0
- package/src/external-wiki-guard.ts +83 -0
- package/src/external-wiki-mcp-tools.ts +23 -0
- package/src/external-wiki-search.test.ts +301 -0
- package/src/external-wiki-search.ts +362 -0
- package/src/external-wiki.test.ts +240 -0
- package/src/external-wiki.ts +453 -0
- package/src/extraction-scope-source-agent.test.ts +21 -0
- package/src/extraction-source-grounding-helpers.ts +243 -53
- package/src/extraction-source-grounding-rules.ts +133 -39
- package/src/extraction-source-grounding.test.ts +363 -33
- package/src/extraction-timeout.test.ts +1 -0
- package/src/extraction-watermark.test.ts +150 -7
- package/src/extraction.ts +8 -1
- package/src/index.ts +8 -0
- package/src/mcp-read-only-tools.ts +1 -0
- package/src/offline-sync.test.ts +194 -0
- package/src/offline-sync.ts +217 -13
- package/src/orchestration/external-wiki-recall-guard.test.ts +94 -0
- package/src/orchestration/extraction-persist.ts +19 -2
- package/src/orchestration/extraction-run-helpers.ts +37 -19
- package/src/orchestration/extraction-run.test.ts +171 -2
- package/src/orchestration/extraction-run.ts +11 -13
- package/src/orchestration/extraction-watermark.ts +106 -17
- package/src/orchestration/generic-recall-paths.ts +14 -0
- package/src/orchestration/orchestrator-helpers.ts +2 -0
- package/src/orchestration/orchestrator-init.ts +9 -0
- package/src/orchestration/recall-internal-deps.ts +6 -0
- package/src/orchestration/recall-internal.ts +154 -33
- package/src/orchestration/recall-rerank-coordinator.ts +60 -25
- package/src/orchestration/recall-search-pipeline.test.ts +75 -1
- package/src/orchestration/recall-search-pipeline.ts +50 -10
- package/src/orchestrator-convergence-refresh.test.ts +36 -2
- package/src/orchestrator.ts +13 -3
- package/src/page-versioning.ts +5 -19
- package/src/procedural/procedure-recall.ts +5 -1
- package/src/provenance-surfaces.test.ts +3 -0
- package/src/qmd-client.test.ts +78 -17
- package/src/qmd.test.ts +24 -0
- package/src/qmd.ts +224 -315
- package/src/recall-explain-renderer.ts +3 -0
- package/src/recall-rerank-coordinator.test.ts +61 -0
- package/src/recall-xray-renderer.test.ts +6 -0
- package/src/recall-xray.test.ts +88 -1
- package/src/recall-xray.ts +15 -0
- package/src/reconcile/cursor.test.ts +48 -0
- package/src/reconcile/cursor.ts +58 -11
- package/src/reconcile/manifest.test.ts +4 -0
- package/src/reconcile/manifest.ts +41 -51
- package/src/reconcile/plan.test.ts +4 -0
- package/src/reconcile/plan.ts +29 -16
- package/src/search/factory.ts +6 -6
- package/src/search/port.ts +25 -9
- package/src/secure-store/secure-fs.ts +20 -12
- package/src/secure-store/secure-store.test.ts +41 -2
- package/src/spaces/index.test.ts +61 -2
- package/src/spaces/index.ts +44 -18
- package/src/storage/entity-alias-config.ts +97 -0
- package/src/storage/entity-canonical-id-lock.ts +53 -23
- package/src/storage/entity-canonical-id-migration.ts +53 -22
- package/src/storage/entity-canonical-id-references.ts +3 -0
- package/src/storage/entity-id-safety.ts +7 -0
- package/src/storage/entity-store.ts +6 -2
- package/src/storage/memory-frontmatter-metadata.ts +4 -9
- package/src/storage/memory-migration-serialization.ts +10 -15
- package/src/storage/tombstone-blocked-capture-mutation.ts +52 -64
- package/src/storage/tombstone-blocked-capture-sync.ts +244 -199
- package/src/storage-deletion-revisions.test.ts +91 -0
- package/src/storage-fact-hash-index-defer.test.ts +446 -163
- package/src/storage.ts +534 -245
- package/src/tool-scoped-memory.ts +10 -0
- package/src/transfer/capsule-import.ts +13 -0
- package/src/transfer/capsule-merge.ts +13 -0
- package/src/trust-score-recall-paths.test.ts +75 -1
- package/src/types.ts +7 -3
- package/dist/capsule-merge-IDWJPCWK.js.map +0 -1
- package/dist/chunk-3CE77VAP.js.map +0 -1
- package/dist/chunk-3TBLDMJA.js.map +0 -1
- package/dist/chunk-4J7G5SY4.js.map +0 -1
- package/dist/chunk-4L6HUREQ.js.map +0 -1
- package/dist/chunk-57QKLRBV.js.map +0 -1
- package/dist/chunk-5TFP4CUL.js.map +0 -1
- package/dist/chunk-7XC2HX75.js.map +0 -1
- package/dist/chunk-A5OJCXZL.js.map +0 -1
- package/dist/chunk-BUE5E2HL.js.map +0 -1
- package/dist/chunk-CJ2ZR7UA.js.map +0 -1
- package/dist/chunk-CUM2BBPN.js.map +0 -1
- package/dist/chunk-D3J5SLQK.js.map +0 -1
- package/dist/chunk-DL7ZD3JH.js.map +0 -1
- package/dist/chunk-DLVPUX7U.js.map +0 -1
- package/dist/chunk-E6PNLPGJ.js.map +0 -1
- package/dist/chunk-ECK75GDJ.js.map +0 -1
- package/dist/chunk-HREE4JHI.js.map +0 -1
- package/dist/chunk-IKKWIPYN.js.map +0 -1
- package/dist/chunk-J7VGGECD.js.map +0 -1
- package/dist/chunk-N5Z4EVOR.js.map +0 -1
- package/dist/chunk-NVRYW264.js.map +0 -1
- package/dist/chunk-P2BM76KT.js.map +0 -1
- package/dist/chunk-PVGDJXVK.js +0 -21
- package/dist/chunk-QJAQNXWI.js.map +0 -1
- package/dist/chunk-RN7DY3FC.js.map +0 -1
- package/dist/chunk-RVLJEII5.js.map +0 -1
- package/dist/chunk-S2NCTZGJ.js.map +0 -1
- package/dist/chunk-TDHTVMPG.js.map +0 -1
- package/dist/chunk-UYLMNVY6.js.map +0 -1
- package/dist/chunk-VCD4PSK2.js.map +0 -1
- package/dist/chunk-VNA7W7QF.js.map +0 -1
- package/dist/chunk-VWAXN2BN.js.map +0 -1
- package/dist/chunk-WOCNN776.js.map +0 -1
- package/dist/chunk-XYTOI63Z.js.map +0 -1
- package/dist/chunk-YV32N67O.js.map +0 -1
- /package/dist/{auto-sync-5OE5QOZB.js.map → auto-sync-UPTUVE4X.js.map} +0 -0
- /package/dist/{chunk-VUPTKTDV.js.map → chunk-2MRHJNWL.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
- /package/dist/{chunk-5IVLTFOV.js.map → chunk-44N6ESJ4.js.map} +0 -0
- /package/dist/{chunk-HO3QBJEY.js.map → chunk-5546W5SI.js.map} +0 -0
- /package/dist/{chunk-U7GW7NE7.js.map → chunk-5CEECY6P.js.map} +0 -0
- /package/dist/{chunk-4UH4BTGK.js.map → chunk-5SNZSWWR.js.map} +0 -0
- /package/dist/{chunk-6CZPDBJS.js.map → chunk-5U7ID3EZ.js.map} +0 -0
- /package/dist/{chunk-GF22HWS2.js.map → chunk-6NNNURLK.js.map} +0 -0
- /package/dist/{chunk-227UFSEQ.js.map → chunk-7RZJWZ46.js.map} +0 -0
- /package/dist/{chunk-E5UK4VPE.js.map → chunk-7SHJHPTY.js.map} +0 -0
- /package/dist/{chunk-UVIKWC7M.js.map → chunk-7YERSTN7.js.map} +0 -0
- /package/dist/{chunk-S5SLVSVY.js.map → chunk-BQIFZ2MP.js.map} +0 -0
- /package/dist/{chunk-E53DSZEN.js.map → chunk-C26TE27X.js.map} +0 -0
- /package/dist/{chunk-LZ4LDKHZ.js.map → chunk-CLB32OHM.js.map} +0 -0
- /package/dist/{chunk-Q6IP2ARR.js.map → chunk-CSOYVTRX.js.map} +0 -0
- /package/dist/{chunk-XOQSEF7X.js.map → chunk-CVILPI77.js.map} +0 -0
- /package/dist/{chunk-PDLBLTOK.js.map → chunk-EITZHSX6.js.map} +0 -0
- /package/dist/{chunk-WUNIWKY4.js.map → chunk-ELIL2A37.js.map} +0 -0
- /package/dist/{chunk-CINZGPSJ.js.map → chunk-GUMZC2BO.js.map} +0 -0
- /package/dist/{chunk-H24WNPA2.js.map → chunk-GWFSVJ4P.js.map} +0 -0
- /package/dist/{chunk-TSH56VPU.js.map → chunk-HAYSYUAB.js.map} +0 -0
- /package/dist/{chunk-PKNLM44P.js.map → chunk-JH6BPLOP.js.map} +0 -0
- /package/dist/{chunk-KXB4VXHY.js.map → chunk-JIYDRBVZ.js.map} +0 -0
- /package/dist/{chunk-AV5ZEH4M.js.map → chunk-KVJRXN2E.js.map} +0 -0
- /package/dist/{chunk-JVLCVFQ4.js.map → chunk-KXEFRMCF.js.map} +0 -0
- /package/dist/{chunk-WFTIGIIS.js.map → chunk-L6CQ7WIW.js.map} +0 -0
- /package/dist/{chunk-EJUEXZHX.js.map → chunk-LLJMAULE.js.map} +0 -0
- /package/dist/{chunk-AS7YMSL6.js.map → chunk-M23RF3LJ.js.map} +0 -0
- /package/dist/{chunk-3F2LKUMU.js.map → chunk-NIS256NW.js.map} +0 -0
- /package/dist/{chunk-YIAA2X3D.js.map → chunk-NK5RGJ65.js.map} +0 -0
- /package/dist/{chunk-OQ5PRDDS.js.map → chunk-NTOIP2E6.js.map} +0 -0
- /package/dist/{chunk-HLPD7B7P.js.map → chunk-NUEQKLNB.js.map} +0 -0
- /package/dist/{chunk-33PLLLL7.js.map → chunk-P7NGM24P.js.map} +0 -0
- /package/dist/{chunk-7TWUCYER.js.map → chunk-PNRA7FAD.js.map} +0 -0
- /package/dist/{chunk-5I4M26Q7.js.map → chunk-QBSFOKY6.js.map} +0 -0
- /package/dist/{chunk-P4DRWEYC.js.map → chunk-QVSBTCVP.js.map} +0 -0
- /package/dist/{chunk-AAIUERNB.js.map → chunk-R5RFK3CB.js.map} +0 -0
- /package/dist/{chunk-WDISJRMG.js.map → chunk-RMMVQQA6.js.map} +0 -0
- /package/dist/{chunk-5SM35XZR.js.map → chunk-S5NZBKKQ.js.map} +0 -0
- /package/dist/{chunk-WIPEXG6R.js.map → chunk-SXIMQLGV.js.map} +0 -0
- /package/dist/{chunk-OAEQLRCY.js.map → chunk-TN76AKO3.js.map} +0 -0
- /package/dist/{chunk-QN25OCUF.js.map → chunk-TQ4GD737.js.map} +0 -0
- /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
- /package/dist/{chunk-DNWXFTLD.js.map → chunk-TYISDI6B.js.map} +0 -0
- /package/dist/{chunk-4LMA77JH.js.map → chunk-U2VLVBBH.js.map} +0 -0
- /package/dist/{chunk-5ZE7QHTK.js.map → chunk-ULVR5KG7.js.map} +0 -0
- /package/dist/{chunk-4B77XSG5.js.map → chunk-UV72DEZD.js.map} +0 -0
- /package/dist/{chunk-S2BBISHU.js.map → chunk-VANZKHTN.js.map} +0 -0
- /package/dist/{chunk-3Y224NYC.js.map → chunk-VYISFWVX.js.map} +0 -0
- /package/dist/{chunk-TIHMZFIV.js.map → chunk-W3IC7QOY.js.map} +0 -0
- /package/dist/{chunk-NRV4Y3PM.js.map → chunk-W4FBGYGK.js.map} +0 -0
- /package/dist/{chunk-MU7ZHSZE.js.map → chunk-WZFAPHIK.js.map} +0 -0
- /package/dist/{chunk-T2TTP3KU.js.map → chunk-X4IDNPOS.js.map} +0 -0
- /package/dist/{chunk-BLAKS3CP.js.map → chunk-XL3TATMJ.js.map} +0 -0
- /package/dist/{chunk-W4XJFLAL.js.map → chunk-XPRJSHNI.js.map} +0 -0
- /package/dist/{chunk-JE7EK33X.js.map → chunk-Y7HRYCNW.js.map} +0 -0
- /package/dist/{chunk-E6EE5B67.js.map → chunk-YK6BDDHP.js.map} +0 -0
- /package/dist/{chunk-ES36HTSC.js.map → chunk-YLHM5BQQ.js.map} +0 -0
- /package/dist/{chunk-BJKPPZ6Z.js.map → chunk-ZFGZ6PZ2.js.map} +0 -0
- /package/dist/{chunk-64UDOIMI.js.map → chunk-ZLQ37WJX.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/reconcile/plan.ts"],"sourcesContent":["import { normalizeNamespaceIdentity } from \"../namespaces/identity.js\";\nimport { OFFLINE_SYNC_MAX_MTIME_MS } from \"../offline-sync.js\";\nimport { validateArchiveRelativePath } from \"../transfer/fs-utils.js\";\nimport type { OfflineSyncFileState } from \"../offline-sync.js\";\nimport {\n CONVERGE_CONFLICT_POLICIES,\n DEFAULT_CONVERGE_CONFLICT_POLICY,\n} from \"../converge-config.js\";\nimport type { ConvergeConflictPolicy } from \"../types.js\";\n\n/**\n * Bootstrap reconciliation planner for two peer daemons whose corpora have\n * already diverged (issue #2150).\n *\n * The offline-sync protocol assumes a satellite that shares a common base with\n * one daemon: every path it does not know about is a pull, and a conflict is\n * rare. Two long-lived daemons are the opposite case — each side holds months\n * of history the other never saw, both sides are authoritative, and there is\n * NO common base on the first run. That is a different decision problem, so it\n * gets its own planner rather than another mode flag inside `applyOfflineSync*`.\n *\n * This module is deliberately pure: it takes two file censuses and returns what\n * to do. No I/O, no transport, no clock. Everything that makes reconciliation\n * risky — which side wins, what counts as converged, what is reported — is\n * decided here where it can be exhaustively tested, and the transport layer is\n * left to carry out an already-settled plan.\n */\n\n/** Which way a path must move for the two corpora to agree. */\nexport type ReconcileAction = \"pull\" | \"push\" | \"identical\" | \"conflict\" | \"suppress\";\n\n/**\n * What the planner decided for a conflicting path.\n * `supersede-link` records that both revisions need durable preservation when\n * timestamps cannot safely select a winner. Apply must stop until transport\n * can assign distinct durable identities to both revisions.\n */\nexport type ReconcileResolution = \"local-wins\" | \"peer-wins\" | \"supersede-link\" | \"unresolved\";\n\nexport interface ReconcileSemanticFileState {\n path: string;\n sha256: string;\n}\n\nexport interface ReconcileSemanticAgreement {\n local: ReconcileSemanticFileState;\n peer: ReconcileSemanticFileState;\n}\n\nexport type ReconcileSemanticChange = \"unchanged\" | \"local_changed\" | \"peer_changed\" | \"both_modified\";\n\nexport interface ReconcilePlanEntry {\n path: string;\n namespace: string;\n action: ReconcileAction;\n /** Stable machine-readable cause, safe to assert on and to aggregate. */\n reason: ReconcileReason;\n localSha256?: string;\n peerSha256?: string;\n /** Present only when a prior converged run left a cursor covering this path. */\n baseSha256?: string;\n /** Set only when `action` is `conflict`. */\n resolution?: ReconcileResolution;\n /**\n * Which side holds the retracted revision. Set only when `action` is\n * `suppress`: with different digests on each side and only one retracted,\n * the entry would otherwise be identical either way and transport could\n * delete the live copy instead of the retracted one.\n */\n suppressSide?: \"local\" | \"peer\" | \"both\";\n /**\n * Real per-side identities for a cross-path semantic agreement. Synthetic\n * rows omit the top-level side digests because `path` cannot name both files.\n */\n semanticAgreement?: ReconcileSemanticAgreement;\n /** Each side's current digest compared with its own prior semantic digest. */\n semanticChange?: ReconcileSemanticChange;\n}\n\nexport type ReconcileReason =\n | \"peer_only\"\n | \"local_only\"\n /** Cursor showed only that side moved since agreement; both still hold the path. */\n | \"peer_changed\"\n | \"local_changed\"\n | \"same_content\"\n | \"semantic_duplicate\"\n | \"both_modified\"\n | \"peer_deleted\"\n | \"local_deleted\"\n /** Peer deleted it while this side edited it — the offline-sync delete/modify pair. */\n | \"local_modified_peer_deleted\"\n | \"local_deleted_peer_modified\"\n | \"tombstoned\";\n\nexport interface ReconcileNamespaceReport {\n namespace: string;\n pull: number;\n push: number;\n identical: number;\n conflict: number;\n /** Local retractions the peer must be told about before the pair agrees. */\n suppress: number;\n /**\n * Conflicts still needing an operator: those the policy declined to settle,\n * plus supersede links whose direction could not be determined.\n */\n unresolved: number;\n}\n\nexport interface ReconcilePlan {\n entries: ReconcilePlanEntry[];\n byNamespace: ReconcileNamespaceReport[];\n /**\n * True when the two corpora already agree — every shared path matches and\n * neither side holds a path the other lacks.\n *\n * This is the idempotency contract from #2150: running reconciliation against\n * an already-converged peer must be a no-op, and a caller can skip the whole\n * transfer phase on this flag alone.\n */\n converged: boolean;\n}\n\n/** Minimal shape the planner needs; `OfflineSyncFileState` satisfies it. */\nexport type ReconcileFileState = Pick<OfflineSyncFileState, \"path\" | \"sha256\"> &\n Partial<Pick<OfflineSyncFileState, \"mtimeMs\" | \"bytes\">>;\n\nexport interface ReconcileNamespaceInput {\n namespace: string;\n local: Iterable<ReconcileFileState>;\n peer: Iterable<ReconcileFileState>;\n /**\n * File states agreed at the end of the last converged run with THIS peer.\n * Absent on a bootstrap merge, which is why a path missing from one side is\n * read as \"never seen\" rather than \"deleted\".\n */\n base?: Iterable<ReconcileFileState>;\n /**\n * Revision timestamps for paths deleted locally since the base cursor.\n * A deletion is a revision and must carry a comparable time for\n * `newest-wins`; absence alone has no timestamp.\n */\n localDeletionMtimeMs?: ReadonlyMap<string, number>;\n /** Revision timestamps for paths deleted by the peer since the base cursor. */\n peerDeletionMtimeMs?: ReadonlyMap<string, number>;\n /**\n * Digests of FILES this side has retracted, in the same form as\n * `ReconcileFileState.sha256` — a hash of the serialized file.\n *\n * Deliberately NOT `TombstoneEntry.contentHash`, which hashes the canonical\n * raw fact text and therefore never equals a file digest (§13: one content\n * form, everywhere). Mapping retracted fact hashes onto the file digests that\n * carry them is the caller's job, because only the caller can read its own\n * corpus; handing this the wrong form would silently plan `pull` and\n * resurrect every retracted fact, so the parameter name states the form.\n */\n tombstonedFileSha256?: Iterable<string>;\n /**\n * Digests the PEER has retracted, same form.\n *\n * Without this a bootstrap merge cannot tell \"the peer never had it\" from\n * \"the peer deliberately retracted it\": the peer census simply omits both,\n * so a file we still hold is planned `push` and the peer's retraction is\n * undone. Reconciliation is symmetric, so retraction has to be too.\n *\n * SCOPE: these sets decide what happens to files that still EXIST on one\n * side. Sharing the retraction records themselves is not modelled here -\n * tombstones are corpus files (`state/tombstones.jsonl`), so they reconcile\n * as ordinary paths through this same plan. A digest both censuses have\n * already dropped therefore produces no entry, by design: there is no file\n * left to act on, and synthesizing a path-less entry would hand transport\n * something it cannot apply.\n */\n peerTombstonedFileSha256?: Iterable<string>;\n}\n\nexport interface ReconcileOptions {\n conflictPolicy?: ConvergeConflictPolicy;\n}\n\n/**\n * A census the planner refuses to reason about.\n *\n * Dropping a malformed or contradictory record would let the planner return\n * `converged: true` for a corpus it could not actually read, and transport is\n * invited to skip everything on that flag — so bad input fails loudly instead\n * (§1/§39).\n */\nexport class ReconcilePlanInputError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ReconcilePlanInputError\";\n }\n}\n\n/** Matches `assertSha256` in offline-sync so both surfaces reject the same values (§40). */\nconst SHA256_PATTERN = /^[a-f0-9]{64}$/i;\n\n/**\n * Validate a census record's identity fields.\n *\n * The digest matters as much as the path: two records that both omit `sha256`\n * compare `undefined === undefined` and plan as `identical`, converging a\n * corpus the planner never actually read.\n */\nfunction assertCensusRecord(\n file: ReconcileFileState | undefined,\n side: string,\n namespace: string,\n): ReconcileFileState {\n const path = file?.path;\n if (typeof path !== \"string\" || path.length === 0) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} contains a record with no path`,\n );\n }\n // Same boundary offline-sync applies to this field: a peer census is\n // untrusted input, and an absolute or traversal path would otherwise become\n // a transfer instruction pointing outside the corpus root.\n try {\n validateArchiveRelativePath(path, `reconcile: ${side} census for namespace ${namespace}`);\n } catch (err) {\n throw new ReconcilePlanInputError(err instanceof Error ? err.message : String(err));\n }\n assertPortablePathSegments(path, side, namespace);\n return {\n ...file,\n path,\n sha256: assertDigest(file?.sha256, `${side} census for namespace ${namespace} entry ${path}`),\n ...(file?.mtimeMs === undefined\n ? {}\n : { mtimeMs: assertMtimeMs(file.mtimeMs, `${side} census for namespace ${namespace} entry ${path}`) }),\n };\n}\n\n/**\n * `newest-wins` decides which corpus keeps its history from this number, so a\n * NaN, an Infinity or a value past the Date range must not pick the winner.\n *\n * Fractional values ARE valid: `fs.stat()` reports sub-millisecond mtimes on\n * common filesystems and offline-sync forwards them unrounded, so this matches\n * its `assertOfflineSyncMtimeMs` — non-negative finite within Date range — and\n * deliberately does not require an integer.\n */\nfunction assertMtimeMs(value: unknown, context: string): number {\n if (\n typeof value !== \"number\"\n || !Number.isFinite(value)\n || value < 0\n || value > OFFLINE_SYNC_MAX_MTIME_MS\n ) {\n throw new ReconcilePlanInputError(\n `reconcile: ${context} has an out-of-range mtimeMs; expected a finite value between 0 and ${OFFLINE_SYNC_MAX_MTIME_MS}`,\n );\n }\n return value;\n}\n\n/**\n * Digests are canonicalized to lowercase, exactly as offline-sync's\n * `assertSha256` does. Keeping the caller's spelling would make two forms of\n * one digest compare unequal, so identical files would plan `both_modified`\n * and tombstone lookups would silently miss.\n */\nfunction assertDigest(value: unknown, context: string): string {\n if (typeof value !== \"string\" || !SHA256_PATTERN.test(value)) {\n throw new ReconcilePlanInputError(\n `reconcile: ${context} must carry a 64-character sha256 hex digest`,\n );\n }\n return value.toLowerCase();\n}\n\nfunction isPlainObject(value: unknown): boolean {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction assertNamespace(namespace: unknown): string {\n if (typeof namespace !== \"string\" || namespace.length === 0) {\n throw new ReconcilePlanInputError(\"reconcile: every namespace input needs a non-empty namespace\");\n }\n // `team` and ` team ` are one namespace to the rest of core, so accepting\n // both here would slip two inputs past the duplicate check and let them plan\n // contradictory actions for the same path. Rejected rather than silently\n // rewritten, so the namespace on every entry is the caller's own string.\n if (LONE_SURROGATE.test(namespace)) {\n // `namespaceIdentityToken()` encodes through TextEncoder, so a lone\n // surrogate and a literal U+FFFD collapse to ONE storage identity while\n // comparing as two here - slipping both past the duplicate-namespace guard.\n throw new ReconcilePlanInputError(\n \"reconcile: namespace contains an unpaired surrogate; it would collide with another namespace on disk\",\n );\n }\n if (normalizeNamespaceIdentity(namespace) !== namespace) {\n throw new ReconcilePlanInputError(\n `reconcile: namespace ${JSON.stringify(namespace)} is not canonical; pass ${JSON.stringify(normalizeNamespaceIdentity(namespace))}`,\n );\n }\n return namespace;\n}\n\nfunction assertIterable(value: unknown, side: string, namespace: string): Iterable<ReconcileFileState> {\n if (value === null || typeof value !== \"object\" || typeof (value as Iterable<ReconcileFileState>)[Symbol.iterator] !== \"function\") {\n throw new ReconcilePlanInputError(`reconcile: ${side} census for namespace ${namespace} must be iterable`);\n }\n return value as Iterable<ReconcileFileState>;\n}\n\n/**\n * Two paths that a participant's filesystem resolves to ONE file must not draw\n * separate push/pull work, or application order decides which revision\n * survives. Remnic is explicitly multi-platform, so all three aliasing rules\n * are folded together and a collision is rejected rather than raced:\n * case (macOS, Windows), Unicode normalization (macOS stores decomposed and\n * compares canonically), and Win32 trailing dots/spaces, which the Windows API\n * strips before touching disk.\n */\n// eslint-disable-next-line no-control-regex -- control characters are exactly what this rejects\nconst WIN32_INVALID_CHARS = /[<>:\"|?*\\u0000-\\u001f]/;\n// Windows treats the superscripts as their digits in COM/LPT device names.\nconst LONE_SURROGATE = /[\\ud800-\\udbff](?![\\udc00-\\udfff])|(?<![\\ud800-\\udbff])[\\udc00-\\udfff]/;\nconst WIN32_RESERVED_NAMES = /^(con|prn|aux|nul|(com|lpt)[1-9\\u00b9\\u00b2\\u00b3])$/i;\n\nfunction assertPortablePathSegments(path: string, side: string, namespace: string): void {\n for (const segment of path.split(\"/\")) {\n if (segment.length === 0) continue;\n if (segment.endsWith(\".\") || segment.endsWith(\" \")) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} path ${path} has a segment ending in a dot or space; ` +\n \"Windows strips those and would alias it onto another file\",\n );\n }\n // `:` opens an alternate data stream, the rest cannot be created at all,\n // and a reserved device name resolves to hardware. A plan containing any of\n // them cannot be applied on a Windows participant.\n if (LONE_SURROGATE.test(segment)) {\n // Node encodes an unpaired surrogate as U+FFFD, so this path and a\n // literal U+FFFD path are one file on disk while comparing as distinct.\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} path ${path} contains an unpaired surrogate`,\n );\n }\n if (WIN32_INVALID_CHARS.test(segment)) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} path ${path} contains a character Windows cannot store`,\n );\n }\n if (WIN32_RESERVED_NAMES.test(segment.split(\".\")[0] ?? \"\")) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} path ${path} uses a reserved Windows device name`,\n );\n }\n }\n}\n\nfunction assertNoPathAlias(\n seen: Map<string, string>,\n path: string,\n namespace: string,\n): void {\n // NFC first: macOS stores decomposed names and compares canonically, so\n // `é` (U+00E9) and `é` (e + U+0301) are ONE file there. Then a FULL caseless\n // fold - upper-then-lower, which collapses forms a bare toLowerCase() keeps\n // apart, such as final sigma `ς` against `σ`. Lowercasing alone would leave\n // those distinct and the planner would emit both a push and a pull.\n // `ß` upper-folds to `ss` while `ẞ` folds to `ß`, so one more pass equalizes\n // the pair that a single upper-then-lower still leaves apart.\n const folded = path.normalize(\"NFC\").toUpperCase().toLowerCase().replace(/\\u00df/g, \"ss\");\n const existing = seen.get(folded);\n if (existing !== undefined && existing !== path) {\n throw new ReconcilePlanInputError(\n `reconcile: namespace ${namespace} has aliasing paths (${existing}, ${path}); ` +\n \"they resolve to one file on a case-insensitive or Unicode-normalizing peer\",\n );\n }\n seen.set(folded, path);\n}\n\n/**\n * Duplicate paths are accepted only when they agree. Two digests for one path\n * make the plan depend on which record arrived last, which would break the\n * byte-stable ordering the convergence report relies on.\n */\nfunction rejectConflictingDuplicate(\n existing: { sha256: string; mtimeMs?: number } | undefined,\n incoming: { sha256: string; mtimeMs?: number },\n path: string,\n side: string,\n namespace: string,\n): boolean {\n if (!existing) return false;\n if (existing.sha256 !== incoming.sha256) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} lists ${path} twice with different digests`,\n );\n }\n // Same bytes but a different mtime is still ambiguous: `newest-wins` reads\n // that timestamp, so accepting the first arrival would let input order decide\n // the winner.\n if (existing.mtimeMs !== incoming.mtimeMs) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} lists ${path} twice with different mtimeMs`,\n );\n }\n return true;\n}\n\nfunction indexByPath(\n files: Iterable<ReconcileFileState>,\n side: string,\n namespace: string,\n): Map<string, ReconcileFileState> {\n const index = new Map<string, ReconcileFileState>();\n for (const raw of files) {\n const file = assertCensusRecord(raw, side, namespace);\n if (rejectConflictingDuplicate(index.get(file.path), file, file.path, side, namespace)) continue;\n index.set(file.path, file);\n }\n return index;\n}\n\n/**\n * A bare string satisfies `Iterable<string>`, and `new Set(\"abc…\")` would split\n * it into 64 one-character members — every membership test then misses and each\n * retracted file is planned as `pull` and resurrected. Reject the scalar and\n * canonicalize every member.\n */\nfunction parseTombstonedDigests(\n value: Iterable<string> | undefined,\n namespace: string,\n field = \"tombstonedFileSha256\",\n): Set<string> {\n if (value === undefined) return new Set();\n if (typeof value === \"string\") {\n throw new ReconcilePlanInputError(\n `reconcile: ${field} for namespace ${namespace} must be a collection of digests, not a single string`,\n );\n }\n if (value === null || typeof value !== \"object\" || typeof value[Symbol.iterator] !== \"function\") {\n // Otherwise the for...of below throws a raw TypeError and a caller handling\n // ReconcilePlanInputError cannot tell a bad request from a planner bug.\n throw new ReconcilePlanInputError(\n `reconcile: ${field} for namespace ${namespace} must be an iterable collection of digests`,\n );\n }\n const digests = new Set<string>();\n for (const entry of value) {\n digests.add(assertDigest(entry, `${field} for namespace ${namespace}`));\n }\n return digests;\n}\n\n/**\n * Validate a census while keeping ONLY path -> digest.\n *\n * The base cursor is read for digests alone, so indexing full records and\n * compacting afterwards would hold a corpus-sized record map and its copy at\n * once - the peak this avoids.\n */\nfunction indexDigestsByPath(\n files: Iterable<ReconcileFileState>,\n side: string,\n namespace: string,\n): Map<string, string> {\n const index = new Map<string, string>();\n for (const raw of files) {\n const file = assertCensusRecord(raw, side, namespace);\n const existing = index.get(file.path);\n // One map, not a parallel `seen`: the base's own mtimeMs is never a\n // decision input (only the local and peer timestamps order a conflict), so\n // a duplicate that agrees on the digest is unambiguous here regardless of\n // its timestamp, and the digest alone is enough to detect a real clash.\n if (existing !== undefined) {\n if (existing !== file.sha256) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} lists ${file.path} twice with different digests`,\n );\n }\n continue;\n }\n index.set(file.path, file.sha256);\n }\n return index;\n}\n\nfunction assertConflictPolicy(value: ConvergeConflictPolicy | undefined): ConvergeConflictPolicy {\n if (value === undefined) return DEFAULT_CONVERGE_CONFLICT_POLICY;\n if (!CONVERGE_CONFLICT_POLICIES.includes(value)) {\n throw new ReconcilePlanInputError(\n `reconcile: unknown conflictPolicy ${JSON.stringify(value)}; expected one of ${CONVERGE_CONFLICT_POLICIES.join(\", \")}`,\n );\n }\n return value;\n}\n\n/**\n * Total ordering for plan entries (§12): namespace, then path. Both are unique\n * per entry, so equal keys are impossible and the comparator never has to\n * return 0 for distinct rows — the output is byte-identical across runs, which\n * is what makes a convergence report diffable.\n */\nfunction compareEntries(a: ReconcilePlanEntry, b: ReconcilePlanEntry): number {\n if (a.namespace !== b.namespace) return a.namespace < b.namespace ? -1 : 1;\n if (a.path !== b.path) return a.path < b.path ? -1 : 1;\n return 0;\n}\n\n\nfunction resolveConflict(\n policy: ConvergeConflictPolicy,\n localMtimeMs: number | undefined,\n peerMtimeMs: number | undefined,\n missingTimestampResolution: ReconcileResolution,\n): ReconcileResolution {\n if (policy !== \"newest-wins\") return \"unresolved\";\n if (localMtimeMs === undefined || peerMtimeMs === undefined || localMtimeMs === peerMtimeMs) {\n return missingTimestampResolution;\n }\n return localMtimeMs > peerMtimeMs ? \"local-wins\" : \"peer-wins\";\n}\n\nfunction parseDeletionMtimes(\n value: ReadonlyMap<string, number> | undefined,\n side: string,\n namespace: string,\n): ReadonlyMap<string, number> {\n if (value === undefined) return new Map();\n if (!(value instanceof Map)) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} deletion mtimes for namespace ${namespace} must be a Map`,\n );\n }\n const parsed = new Map<string, number>();\n for (const [path, mtimeMs] of value) {\n try {\n validateArchiveRelativePath(path, `reconcile: ${side} deletion mtimes for namespace ${namespace}`);\n } catch (err) {\n throw new ReconcilePlanInputError(err instanceof Error ? err.message : String(err));\n }\n assertPortablePathSegments(path, side, namespace);\n parsed.set(path, assertMtimeMs(mtimeMs, `${side} deletion for namespace ${namespace} entry ${path}`));\n }\n return parsed;\n}\n\n/**\n * Plan one namespace. Exposed for callers that stream namespaces one at a time.\n *\n * Residency is one peer index + a set of local paths + the entry list. The\n * local census is consumed as a stream and never materialized, so a 100k-file\n * corpus does not hold two full censuses at once — but this is NOT constant\n * memory, and a caller holding its own census arrays adds to that.\n */\nexport function planNamespaceReconciliation(\n input: ReconcileNamespaceInput,\n options: ReconcileOptions = {},\n): ReconcilePlanEntry[] {\n if (!isPlainObject(input)) {\n throw new ReconcilePlanInputError(\"reconcile: namespace input must be a plain object\");\n }\n if (!isPlainObject(options)) {\n // A Date, Map or RegExp passes a bare typeof check, exposes no\n // `conflictPolicy`, and would silently take the default policy - hiding a\n // malformed request behind `manual`.\n throw new ReconcilePlanInputError(\"reconcile: options must be a plain object\");\n }\n const namespace = assertNamespace(input.namespace);\n const policy = assertConflictPolicy(options.conflictPolicy);\n const localCensus = assertIterable(input.local, \"local\", namespace);\n const caseFold = new Map<string, string>();\n // Index the peer census only, then stream the local one against it, removing\n // each match as it is consumed. Peak residency is one index plus the entry\n // list rather than two full censuses (round 2, codex P2).\n const peer = indexByPath(assertIterable(input.peer, \"peer\", namespace), \"peer\", namespace);\n // Only `base.sha256` is ever read, so the base is compacted to path -> digest\n // instead of a second full record index (round 7, codex P2).\n // Only an ABSENT base means bootstrap. A null/invalid cursor silently read as\n // \"no prior agreement\" would turn a peer-side deletion into a push and\n // resurrect it.\n const base = input.base === undefined\n ? null\n : indexDigestsByPath(assertIterable(input.base, \"base\", namespace), \"base\", namespace);\n const tombstoned = parseTombstonedDigests(input.tombstonedFileSha256, namespace);\n const peerTombstoned = parseTombstonedDigests(\n input.peerTombstonedFileSha256,\n namespace,\n \"peerTombstonedFileSha256\",\n );\n const localDeletionMtimeMs = parseDeletionMtimes(input.localDeletionMtimeMs, \"local\", namespace);\n const peerDeletionMtimeMs = parseDeletionMtimes(input.peerDeletionMtimeMs, \"peer\", namespace);\n const entries: ReconcilePlanEntry[] = [];\n\n // Path -> digest only, never the file objects: enough to make the stream\n // idempotent and to catch contradictory duplicates without materializing the\n // second census.\n // Base paths participate in the collision check: a base `Facts/A.md` against\n // a local `facts/a.md` is the same delete/change ambiguity on a\n // case-insensitive participant.\n if (base) for (const basePath of base.keys()) assertNoPathAlias(caseFold, basePath, namespace);\n // Path -> decision-relevant fields only, never the whole record: enough to\n // make the stream idempotent and to catch contradictory duplicates without\n // materializing the second census.\n const seenLocal = new Map<string, { sha256: string; mtimeMs?: number }>();\n for (const rawLocal of localCensus) {\n const localFile = assertCensusRecord(rawLocal, \"local\", namespace);\n const path = localFile.path;\n assertNoPathAlias(caseFold, path, namespace);\n const seen = seenLocal.get(path);\n if (seen !== undefined) {\n // Same rule the indexed censuses get: mtimeMs is decision-relevant under\n // `newest-wins`, so a duplicate that disagrees on it is ambiguous too.\n if (rejectConflictingDuplicate(seen, localFile, path, \"local\", namespace)) continue;\n }\n seenLocal.set(path, { sha256: localFile.sha256, mtimeMs: localFile.mtimeMs });\n const peerFile = peer.get(path);\n // Consumed: whatever remains in the index afterwards is peer-only.\n peer.delete(path);\n const baseSha256 = base?.get(path);\n // Retraction outranks every other decision for this path, on EITHER side.\n // Checked before hash comparison and conflict resolution: a retracted peer\n // revision reaching the conflict ladder can win under `newest-wins`, and a\n // retracted LOCAL revision would otherwise be pushed - which is also how a\n // suppression undoes itself on the next run, since the local copy survives\n // the peer-side delete (round 4).\n // Either side's retraction removes the copy that carries the digest, so a\n // peer retraction of something we still hold suppresses OUR copy rather\n // than pushing it back.\n const localRetracted = tombstoned.has(localFile.sha256) || peerTombstoned.has(localFile.sha256);\n const peerRetracted =\n peerFile !== undefined && (tombstoned.has(peerFile.sha256) || peerTombstoned.has(peerFile.sha256));\n if (localRetracted || peerRetracted) {\n entries.push({\n path,\n namespace,\n action: \"suppress\",\n reason: \"tombstoned\",\n localSha256: localFile.sha256,\n ...(peerFile ? { peerSha256: peerFile.sha256 } : {}),\n ...(baseSha256 === undefined ? {} : { baseSha256 }),\n suppressSide: localRetracted && peerRetracted ? \"both\" : localRetracted ? \"local\" : \"peer\",\n });\n continue;\n }\n if (!peerFile) {\n // Base PRESENCE is what proves a deletion, not equality with whatever the\n // surviving side now holds. If we also edited since the base, this is\n // delete-versus-modify: still a conflict, and pushing it would resurrect\n // a deliberate deletion. Without a base the peer simply never saw the\n // path, and a bootstrap merge must push — both sides hold unique data.\n if (baseSha256 !== undefined) {\n entries.push({\n path,\n namespace,\n action: \"conflict\",\n reason: baseSha256 === localFile.sha256 ? \"peer_deleted\" : \"local_modified_peer_deleted\",\n localSha256: localFile.sha256,\n baseSha256,\n resolution: baseSha256 === localFile.sha256\n ? \"unresolved\"\n : resolveConflict(\n policy,\n localFile.mtimeMs,\n peerDeletionMtimeMs.get(path),\n \"unresolved\",\n ),\n });\n continue;\n }\n entries.push({\n path,\n namespace,\n action: \"push\",\n reason: \"local_only\",\n localSha256: localFile.sha256,\n });\n continue;\n }\n if (peerFile.sha256 === localFile.sha256) {\n entries.push({\n path,\n namespace,\n action: \"identical\",\n reason: \"same_content\",\n localSha256: localFile.sha256,\n peerSha256: peerFile.sha256,\n ...(baseSha256 === undefined ? {} : { baseSha256 }),\n });\n continue;\n }\n // A base that matches one side turns a \"conflict\" into an ordinary\n // one-sided change: that side is the only one that moved since agreement.\n if (baseSha256 !== undefined && baseSha256 === localFile.sha256) {\n entries.push({\n path,\n namespace,\n action: \"pull\",\n reason: \"peer_changed\",\n localSha256: localFile.sha256,\n peerSha256: peerFile.sha256,\n baseSha256,\n });\n continue;\n }\n if (baseSha256 !== undefined && baseSha256 === peerFile.sha256) {\n entries.push({\n path,\n namespace,\n action: \"push\",\n reason: \"local_changed\",\n localSha256: localFile.sha256,\n peerSha256: peerFile.sha256,\n baseSha256,\n });\n continue;\n }\n const resolution = resolveConflict(\n policy,\n localFile.mtimeMs,\n peerFile.mtimeMs,\n \"supersede-link\",\n );\n entries.push({\n path,\n namespace,\n action: \"conflict\",\n reason: \"both_modified\",\n localSha256: localFile.sha256,\n peerSha256: peerFile.sha256,\n ...(baseSha256 === undefined ? {} : { baseSha256 }),\n resolution,\n });\n }\n\n for (const [path, peerFile] of peer) {\n assertNoPathAlias(caseFold, path, namespace);\n const baseSha256 = base?.get(path);\n if (tombstoned.has(peerFile.sha256) || peerTombstoned.has(peerFile.sha256)) {\n // Retracted here on purpose, and the peer still serves it. Pulling it\n // back would undo the retraction; calling it `identical` would be worse,\n // because a converged plan lets transport skip everything and the peer\n // keeps serving the retracted fact forever. It is work: propagate the\n // tombstone.\n entries.push({\n path,\n namespace,\n action: \"suppress\",\n reason: \"tombstoned\",\n peerSha256: peerFile.sha256,\n ...(baseSha256 === undefined ? {} : { baseSha256 }),\n suppressSide: \"peer\",\n });\n continue;\n }\n if (baseSha256 !== undefined) {\n entries.push({\n path,\n namespace,\n action: \"conflict\",\n reason: baseSha256 === peerFile.sha256 ? \"local_deleted\" : \"local_deleted_peer_modified\",\n peerSha256: peerFile.sha256,\n baseSha256,\n resolution: baseSha256 === peerFile.sha256\n ? \"unresolved\"\n : resolveConflict(\n policy,\n localDeletionMtimeMs.get(path),\n peerFile.mtimeMs,\n \"unresolved\",\n ),\n });\n continue;\n }\n entries.push({\n path,\n namespace,\n action: \"pull\",\n reason: \"peer_only\",\n peerSha256: peerFile.sha256,\n });\n }\n\n return entries.sort(compareEntries);\n}\n\n/** Aggregate entries into the per-namespace convergence report (#2150). */\nexport function summarizeReconcilePlan(entries: readonly ReconcilePlanEntry[]): ReconcileNamespaceReport[] {\n const byNamespace = new Map<string, ReconcileNamespaceReport>();\n for (const entry of entries) {\n let report = byNamespace.get(entry.namespace);\n if (!report) {\n report = { namespace: entry.namespace, pull: 0, push: 0, identical: 0, conflict: 0, suppress: 0, unresolved: 0 };\n byNamespace.set(entry.namespace, report);\n }\n report[entry.action] += 1;\n const needsOperator =\n entry.resolution === \"unresolved\"\n || entry.resolution === \"supersede-link\";\n if (entry.action === \"conflict\" && needsOperator) report.unresolved += 1;\n }\n return [...byNamespace.values()].sort((a, b) => (a.namespace === b.namespace ? 0 : a.namespace < b.namespace ? -1 : 1));\n}\n\n/**\n * Plan a full reconciliation across namespaces.\n *\n * `converged` is an affirmative claim that nothing needs to move, so it is\n * derived from the entries rather than tracked alongside them: any action other\n * than `identical` disproves it.\n */\nexport function planReconciliation(\n namespaces: readonly ReconcileNamespaceInput[],\n options: ReconcileOptions = {},\n): ReconcilePlan {\n if (!Array.isArray(namespaces)) {\n throw new ReconcilePlanInputError(\"reconcile: planReconciliation expects an array of namespace inputs\");\n }\n // Validated here too: with an empty array the per-namespace path never runs,\n // and a malformed options envelope would return `converged` instead of\n // raising - the same call failing or succeeding based on list length.\n if (!isPlainObject(options)) {\n throw new ReconcilePlanInputError(\"reconcile: options must be a plain object\");\n }\n assertConflictPolicy(options.conflictPolicy);\n const entries: ReconcilePlanEntry[] = [];\n // Two inputs for one namespace are planned independently, so the same\n // (namespace, path) can draw contradictory actions - and because those\n // entries also sort equal, batch order would decide which revision survives.\n const seenNamespaces = new Set<string>();\n for (const namespace of namespaces) {\n const name = assertNamespace(namespace?.namespace);\n if (seenNamespaces.has(name)) {\n throw new ReconcilePlanInputError(\n `reconcile: namespace ${name} appears twice; merge its censuses before planning`,\n );\n }\n seenNamespaces.add(name);\n entries.push(...planNamespaceReconciliation(namespace, options));\n }\n entries.sort(compareEntries);\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":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp-read-only-tools.ts"],"sourcesContent":["/**\n * Conservative allowlist of canonical MCP tool suffixes that are\n * unambiguously read-only. Tools in this set are tagged with\n * `annotations: { readOnlyHint: true }` so ChatGPT (and other MCP\n * clients that honor the hint) can skip per-call confirmation.\n *\n * The list is suffix-based so it covers both the `remnic.*` and\n * `engram.*` naming forms. Anything not on it stays unannotated:\n * uncertainty is resolved as \"might mutate\".\n *\n * Excluded by construction: anything that writes, runs a pipeline,\n * flushes, applies, records, imports, or destructively deletes.\n */\nexport const MCP_READ_ONLY_TOOL_SUFFIXES: Readonly<Record<string, true>> = {\n recall: true,\n recall_explain: true,\n recall_tier_explain: true,\n recall_xray: true,\n briefing: true,\n wearables_status: true,\n transcript_day: true,\n transcript_search: true,\n transcript_memories: true,\n meetings_list: true,\n meetings_get: true,\n action_confidence: true,\n capsule_list: true,\n procedural_stats: true,\n memory_get: true,\n memory_timeline: true,\n entity_get: true,\n review_queue_list: true,\n lcm_search: true,\n continuity_incident_list: true,\n identity_anchor_get: true,\n memory_identity: true,\n memory_search: true,\n memory_profile: true,\n memory_entities_list: true,\n memory_questions: true,\n memory_last_recall: true,\n memory_intent_debug: true,\n memory_qmd_debug: true,\n memory_graph_explain: true,\n graph_snapshot: true,\n review_list: true,\n profiling_report: true,\n peer_list: true,\n peer_get: true,\n peer_profile_get: true,\n console_state: true,\n dreams_status: true,\n codegraph_list_projects: true,\n codegraph_index_status: true,\n codegraph_search_graph: true,\n codegraph_trace_path: true,\n codegraph_detect_changes: true,\n codegraph_query_graph: true,\n codegraph_get_schema: true,\n codegraph_get_snippet: true,\n codegraph_get_architecture: true,\n codegraph_search_code: true,\n};\n"],"mappings":";AAaO,IAAM,8BAA8D;AAAA,EACzE,QAAQ;AAAA,EACR,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,aAAa;AAAA,EACb,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,0BAA0B;AAAA,EAC1B,qBAAqB;AAAA,EACrB,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,sBAAsB;AAAA,EACtB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,WAAW;AAAA,EACX,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,yBAAyB;AAAA,EACzB,wBAAwB;AAAA,EACxB,wBAAwB;AAAA,EACxB,sBAAsB;AAAA,EACtB,0BAA0B;AAAA,EAC1B,uBAAuB;AAAA,EACvB,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,4BAA4B;AAAA,EAC5B,uBAAuB;AACzB;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/secure-store/secure-fs.ts"],"sourcesContent":["/**\n * Transparent file-level encryption for the secure-store module.\n *\n * Issue #690 (PR 3/4) — storage.ts integration layer.\n *\n * This module sits between the raw filesystem and StorageManager.\n * Every memory file is either:\n * - a plain UTF-8 text file (legacy, back-compat), or\n * - a REMNIC-ENC sealed file (AES-256-GCM, see format below).\n *\n * On-disk format\n * --------------\n * Encrypted files begin with a 9-byte magic header:\n *\n * REMNIC-ENC (7 ASCII bytes)\n * VER (1 byte, currently 0x01)\n * FLAGS (1 byte, reserved, must be 0x00)\n *\n * Followed immediately by a `seal()` envelope from `cipher.ts`:\n *\n * [VERSION:1][SALT:16][IV:12][AUTHTAG:16][CIPHERTEXT:...]\n *\n * The magic header makes encrypted files sniffable without attempting\n * a full `open()` call and gives operators a clear signal that the\n * file cannot be read by opening it in an editor.\n *\n * AAD\n * ---\n * The file path relative to the memory root is bound as Associated\n * Authenticated Data (AAD) on both encrypt and decrypt. This means\n * moving or renaming an encrypted file without re-encrypting it will\n * cause auth-tag failure on the next read — the file is tied to its\n * path. Callers that move files must re-encrypt them.\n *\n * Back-compat\n * -----------\n * `readMaybeEncryptedFile` transparently handles both formats: if the\n * file does NOT start with the magic bytes, it is returned as-is (plain\n * text). This lets an operator migrate incrementally: newly-written\n * files are encrypted while existing files continue to be read in plain\n * form until `migrateMemoryDirToEncrypted` is run.\n *\n * Naming: `secure-fs.ts` (not `vault-fs.ts`) — see `kdf.ts` naming note.\n */\n\nimport { createCipheriv, createDecipheriv, randomBytes, randomUUID } from \"node:crypto\";\nimport { lstat, mkdir, open as openFile, readFile, readdir, rename, unlink, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport {\n AUTH_TAG_LENGTH,\n ENVELOPE_HEADER_SIZE,\n ENVELOPE_LAYOUT,\n ENVELOPE_SALT_LENGTH,\n ENVELOPE_VERSION,\n IV_LENGTH,\n generateSalt,\n open as openEnvelope,\n parseEnvelope,\n seal,\n} from \"./cipher.js\";\nimport { RECALL_FALLBACK_DIRS } from \"../utils/category-dir.js\";\nimport { isErrnoCode } from \"../utils/errno.js\";\n\n// ---------------------------------------------------------------------------\n// Error classes\n// ---------------------------------------------------------------------------\n\n/**\n * Thrown when a read is attempted but the keyring entry for this\n * store is absent (i.e. `secure-store unlock` has not been run\n * since the last daemon start).\n */\nexport class SecureStoreLockedError extends Error {\n constructor(message = \"secure-store is locked — run `remnic secure-store unlock` to decrypt\") {\n super(message);\n this.name = \"SecureStoreLockedError\";\n }\n}\n\n/**\n * Thrown when `open()` fails because the auth tag does not validate.\n * This covers both wrong-key and tampered-ciphertext scenarios —\n * intentionally indistinguishable from the caller's perspective.\n */\nexport class SecureStoreDecryptError extends Error {\n constructor(message = \"secure-store decryption failed — wrong key or tampered ciphertext\") {\n super(message);\n this.name = \"SecureStoreDecryptError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Magic header\n// ---------------------------------------------------------------------------\n\n/** Magic bytes: the ASCII string \"REMNIC-ENC\" (10 bytes). */\nexport const MAGIC_BYTES = Buffer.from(\"REMNIC-ENC\", \"ascii\");\n\n/** Current on-disk version byte. */\nexport const FILE_FORMAT_VERSION = 0x01;\n\n/** Reserved flags byte — must be 0x00. */\nexport const FILE_FORMAT_FLAGS = 0x00;\n\n/** Total size of the magic header prefix (magic + version + flags). */\nexport const MAGIC_HEADER_SIZE = MAGIC_BYTES.length + 2; // 12 bytes\n\n/**\n * Exact, deterministic bytes `writeMaybeEncryptedFile` adds to an encrypted\n * file beyond its plaintext body: the magic header prefix plus the fixed\n * envelope header (version + salt + IV + auth tag). AES-256-GCM ciphertext\n * matches the plaintext length and the state-file write path applies no\n * compression, so an encrypted state file is exactly `plaintext +\n * SECURE_STORE_ENVELOPE_OVERHEAD_BYTES` on disk. Compaction reserves this so an\n * encrypted ledger lands strictly below the reader's whole-file decrypt cap\n * (issue #2033).\n */\nexport const SECURE_STORE_ENVELOPE_OVERHEAD_BYTES = MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE;\n\n// ---------------------------------------------------------------------------\n// Detection\n// ---------------------------------------------------------------------------\n\n/**\n * Return true iff `buf` begins with the REMNIC-ENC magic header.\n * Does not validate the envelope; just identifies the format.\n */\nexport function isEncryptedFile(buf: Uint8Array): boolean {\n if (buf.length < MAGIC_HEADER_SIZE) return false;\n const b = Buffer.isBuffer(buf) ? buf : Buffer.from(buf);\n return b.subarray(0, MAGIC_BYTES.length).equals(MAGIC_BYTES);\n}\n\n/**\n * True when the REGULAR file at `probePath` is encrypted at rest (its first\n * bytes are the REMNIC-ENC magic header). ENOENT resolves to false — an absent\n * file has nothing to probe. A symlink, FIFO, device, or any other non-regular\n * path is REFUSED with a throw rather than opened: opening a FIFO blocks until a\n * writer appears and a symlink would redirect the probe outside our tree. The\n * ledgers and per-event spills we manage are always regular files, so a\n * non-regular path is an anomaly the caller must treat as unsafe, never follow\n * (#2033). Shared by the CLI ledger recovery probe and the auto-compaction probe\n * so both enforce identical open safety.\n */\nexport async function probeEncryptedRegularFileHeader(probePath: string): Promise<boolean> {\n let entryStat;\n try {\n entryStat = await lstat(probePath);\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return false;\n throw err;\n }\n if (!entryStat.isFile()) {\n throw new Error(\n `refusing to probe non-regular state path ${probePath} `\n + `(symlink/FIFO/device); opening it could block or escape containment (#2033)`,\n );\n }\n const handle = await openFile(probePath, \"r\");\n try {\n const header = Buffer.alloc(MAGIC_HEADER_SIZE);\n const { bytesRead } = await handle.read(header, 0, header.length, 0);\n return isEncryptedFile(header.subarray(0, bytesRead));\n } finally {\n await handle.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Encrypt / decrypt file body\n// ---------------------------------------------------------------------------\n\n/**\n * Encrypt `plain` (UTF-8 content of a memory file) and return a\n * Buffer ready to write to disk.\n *\n * @param plain Plain-text file content (UTF-8 string or Buffer).\n * @param key 32-byte AES-256 key from the keyring.\n * @param aad Optional associated data — defaults to empty if omitted.\n * Callers should pass the file path relative to memoryDir\n * so the ciphertext is bound to its location.\n */\nexport function encryptFileBody(plain: string | Buffer, key: Buffer, aad?: Buffer): Buffer {\n const plainBuf = typeof plain === \"string\" ? Buffer.from(plain, \"utf8\") : plain;\n const salt = generateSalt();\n const envelope = seal(key, salt, plainBuf, aad ? { aad } : {});\n\n const header = Buffer.alloc(MAGIC_HEADER_SIZE);\n MAGIC_BYTES.copy(header, 0);\n header.writeUInt8(FILE_FORMAT_VERSION, MAGIC_BYTES.length);\n header.writeUInt8(FILE_FORMAT_FLAGS, MAGIC_BYTES.length + 1);\n\n return Buffer.concat([header, envelope]);\n}\n\n/**\n * Decrypt a buffer produced by `encryptFileBody` and return the\n * original UTF-8 content.\n *\n * Throws `SecureStoreDecryptError` on auth failure (wrong key or\n * tampered ciphertext). Throws a plain `Error` for structural problems\n * (truncated buffer, wrong magic, unsupported version).\n */\nexport function decryptFileBody(buf: Buffer, key: Buffer, aad?: Buffer): Buffer {\n if (!isEncryptedFile(buf)) {\n throw new Error(\"decryptFileBody: buffer does not start with REMNIC-ENC magic header\");\n }\n const version = buf.readUInt8(MAGIC_BYTES.length);\n if (version !== FILE_FORMAT_VERSION) {\n throw new Error(\n `decryptFileBody: unsupported file format version ${version} (this build supports ${FILE_FORMAT_VERSION})`\n );\n }\n const flags = buf.readUInt8(MAGIC_BYTES.length + 1);\n if (flags !== FILE_FORMAT_FLAGS) {\n throw new Error(`decryptFileBody: unknown flags byte 0x${flags.toString(16).padStart(2, \"0\")}`);\n }\n const envelope = buf.subarray(MAGIC_HEADER_SIZE);\n parseEnvelope(envelope);\n try {\n return openEnvelope(key, envelope, aad ? { aad } : {});\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new SecureStoreDecryptError(`secure-store decryption failed: ${msg}`);\n }\n}\n\nfunction buildHeaderAad(salt: Uint8Array): Buffer {\n const out = Buffer.alloc(1 + ENVELOPE_SALT_LENGTH);\n out.writeUInt8(ENVELOPE_VERSION, 0);\n Buffer.from(salt).copy(out, 1);\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Path → AAD helper\n// ---------------------------------------------------------------------------\n\n/**\n * Build the AAD buffer for a file at `filePath` relative to\n * `memoryDir`. The AAD binds the ciphertext to its path so a\n * file cannot be silently relocated without re-encryption.\n *\n * When `memoryDir` is supplied and `filePath` is absolute, the\n * relative sub-path is used. Otherwise `filePath` is used verbatim.\n */\nexport function filePathAad(filePath: string, memoryDir?: string): Buffer {\n let rel = filePath;\n if (memoryDir && path.isAbsolute(filePath)) {\n rel = path.relative(memoryDir, filePath);\n }\n return Buffer.from(rel, \"utf8\");\n}\n\n// ---------------------------------------------------------------------------\n// High-level read / write helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Read a file from `filePath`.\n *\n * - If the file is plaintext (no magic header), return its content\n * as-is — back-compat with unencrypted stores.\n * - If the file is encrypted AND `key` is provided, decrypt and return\n * the plaintext content.\n * - If the file is encrypted AND `key` is null, throw\n * `SecureStoreLockedError`.\n *\n * @param filePath Absolute path to the file.\n * @param key 32-byte AES-256 key, or null when the store is locked.\n * @param memoryDir Memory root for path-bound AAD. Should be absolute.\n */\nexport async function readMaybeEncryptedFileBuffer(\n filePath: string,\n key: Buffer | null,\n memoryDir?: string\n): Promise<Buffer> {\n const buf = await readFile(filePath);\n if (!isEncryptedFile(buf)) {\n // Plain file — legacy or unencrypted store.\n return buf;\n }\n // Encrypted — key required.\n if (key === null) {\n throw new SecureStoreLockedError(\n `secure-store is locked — cannot read encrypted file at ${filePath}. Run \\`remnic secure-store unlock\\` to decrypt.`\n );\n }\n return decryptFileBodyForPath(buf, key, filePath, memoryDir);\n}\n\nexport async function readMaybeEncryptedFile(\n filePath: string,\n key: Buffer | null,\n memoryDir?: string\n): Promise<string> {\n return (await readMaybeEncryptedFileBuffer(filePath, key, memoryDir)).toString(\"utf8\");\n}\n\nexport interface WriteMaybeEncryptedFileOptions {\n /**\n * File mode bits. Default 0o600 (owner read/write only).\n * Applied only on create; existing files inherit their existing mode.\n */\n mode?: number;\n /**\n * If true, write atomically via a temp file + rename (CLAUDE.md gotcha #54).\n * Default true.\n */\n atomic?: boolean;\n}\n\n/**\n * Write `content` to `filePath`.\n *\n * - If `key` is provided and non-null, encrypt the content first.\n * - If `key` is null, write the content as plain UTF-8 (unencrypted store).\n *\n * Writes atomically: content is written to a unique temp file\n * first, then renamed into place (CLAUDE.md gotcha #54 — never delete\n * before write).\n */\nexport async function writeMaybeEncryptedFile(\n filePath: string,\n content: string | Buffer,\n key: Buffer | null,\n options: WriteMaybeEncryptedFileOptions = {},\n memoryDir?: string\n): Promise<void> {\n const { mode = 0o600, atomic = true } = options;\n await mkdir(path.dirname(filePath), { recursive: true });\n\n let data: Buffer | string;\n if (key !== null) {\n const aad = filePathAad(filePath, memoryDir);\n data = encryptFileBody(content, key, aad);\n } else {\n data = content;\n }\n\n if (atomic) {\n const tempPath = uniqueAtomicTempPath(filePath, \"tmp\");\n try {\n await writeFile(tempPath, data, { mode });\n await rename(tempPath, filePath);\n } catch (err) {\n // Best-effort cleanup of the temp file.\n try {\n await unlink(tempPath);\n } catch {\n // ignore\n }\n throw err;\n }\n } else {\n await writeFile(filePath, data, { mode });\n }\n}\n\nexport async function writeMaybeEncryptedFileFromChunks(\n filePath: string,\n chunks: AsyncIterable<Buffer>,\n key: Buffer | null,\n options: WriteMaybeEncryptedFileOptions = {},\n memoryDir?: string\n): Promise<void> {\n const { mode = 0o600, atomic = true } = options;\n await mkdir(path.dirname(filePath), { recursive: true });\n const writePath = atomic ? `${filePath}.tmp-${process.pid}-${Date.now()}` : filePath;\n let completed = false;\n try {\n const handle = await openFile(writePath, \"w\", mode);\n try {\n if (key !== null) {\n const salt = generateSalt();\n const iv = randomBytes(IV_LENGTH);\n const header = Buffer.alloc(MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE);\n MAGIC_BYTES.copy(header, 0);\n header.writeUInt8(FILE_FORMAT_VERSION, MAGIC_BYTES.length);\n header.writeUInt8(FILE_FORMAT_FLAGS, MAGIC_BYTES.length + 1);\n const envelopeOffset = MAGIC_HEADER_SIZE;\n header.writeUInt8(ENVELOPE_VERSION, envelopeOffset + ENVELOPE_LAYOUT.version);\n salt.copy(header, envelopeOffset + ENVELOPE_LAYOUT.salt);\n iv.copy(header, envelopeOffset + ENVELOPE_LAYOUT.iv);\n await handle.write(header);\n\n const cipher = createCipheriv(\"aes-256-gcm\", key, iv, { authTagLength: AUTH_TAG_LENGTH });\n const aad = filePathAad(filePath, memoryDir);\n cipher.setAAD(Buffer.concat([buildHeaderAad(salt), aad]));\n for await (const chunk of chunks) {\n if (chunk.length === 0) continue;\n const encrypted = cipher.update(chunk);\n if (encrypted.length > 0) await handle.write(encrypted);\n }\n const final = cipher.final();\n if (final.length > 0) await handle.write(final);\n const authTag = cipher.getAuthTag();\n await handle.write(authTag, 0, authTag.length, MAGIC_HEADER_SIZE + ENVELOPE_LAYOUT.authTag);\n } else {\n for await (const chunk of chunks) {\n if (chunk.length > 0) await handle.write(chunk);\n }\n }\n } finally {\n await handle.close();\n }\n if (atomic) {\n await rename(writePath, filePath);\n }\n completed = true;\n } finally {\n if (!completed && atomic) {\n await unlink(writePath).catch(() => {});\n }\n }\n}\n\n/**\n * Stream a file through the secure-store reader without buffering the whole\n * payload. Plaintext files are passed through unchanged; encrypted files are\n * authenticated and decrypted incrementally.\n */\nexport async function* readMaybeEncryptedFileFromChunks(\n filePath: string,\n key: Buffer | null,\n memoryDir?: string,\n chunkSize = 64 * 1024\n): AsyncIterable<Buffer> {\n const handle = await openFile(filePath, \"r\");\n const headerSize = MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE;\n try {\n const prefix = Buffer.alloc(headerSize);\n const { bytesRead: prefixBytes } = await handle.read(prefix, 0, prefix.length, 0);\n const prefixView = prefix.subarray(0, prefixBytes);\n if (!isEncryptedFile(prefixView)) {\n if (prefixBytes > 0) yield Buffer.from(prefixView);\n let position = prefixBytes;\n const buffer = Buffer.alloc(chunkSize);\n for (;;) {\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, position);\n if (bytesRead === 0) break;\n position += bytesRead;\n yield Buffer.from(buffer.subarray(0, bytesRead));\n }\n return;\n }\n if (prefixBytes < headerSize) {\n throw new Error(`encrypted file header is truncated: ${filePath}`);\n }\n if (key === null) {\n throw new SecureStoreLockedError(\n `secure-store is locked — cannot read encrypted file at ${filePath}. ` +\n \"Run `remnic secure-store unlock` to decrypt.\"\n );\n }\n const envelope = prefix.subarray(MAGIC_HEADER_SIZE);\n const version = envelope.readUInt8(ENVELOPE_LAYOUT.version);\n if (version !== ENVELOPE_VERSION) {\n throw new Error(`secure-store: unsupported envelope version ${version}`);\n }\n const salt = envelope.subarray(\n ENVELOPE_LAYOUT.salt,\n ENVELOPE_LAYOUT.salt + ENVELOPE_SALT_LENGTH\n );\n const iv = envelope.subarray(ENVELOPE_LAYOUT.iv, ENVELOPE_LAYOUT.iv + IV_LENGTH);\n const authTag = envelope.subarray(\n ENVELOPE_LAYOUT.authTag,\n ENVELOPE_LAYOUT.authTag + AUTH_TAG_LENGTH\n );\n const decipher = createDecipheriv(\"aes-256-gcm\", key, iv, { authTagLength: AUTH_TAG_LENGTH });\n decipher.setAAD(Buffer.concat([buildHeaderAad(salt), filePathAad(filePath, memoryDir)]));\n decipher.setAuthTag(authTag);\n let position = headerSize;\n const buffer = Buffer.alloc(chunkSize);\n try {\n for (;;) {\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, position);\n if (bytesRead === 0) break;\n position += bytesRead;\n const plain = decipher.update(buffer.subarray(0, bytesRead));\n if (plain.length > 0) yield plain;\n }\n const final = decipher.final();\n if (final.length > 0) yield final;\n } catch (err) {\n if (err instanceof SecureStoreDecryptError) throw err;\n const message = err instanceof Error ? err.message : String(err);\n throw new SecureStoreDecryptError(`secure-store decryption failed: ${message}`);\n }\n } finally {\n await handle.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Migration\n// ---------------------------------------------------------------------------\n\nexport interface MigrateResult {\n /** Number of files successfully encrypted. */\n encrypted: number;\n /** Number of files already encrypted (skipped). */\n skipped: number;\n /** Files that failed to encrypt (path → error message). */\n errors: Array<{ filePath: string; error: string }>;\n}\n\nexport interface DecryptResult {\n /** Number of files successfully decrypted back to plaintext. */\n decrypted: number;\n /** Number of files already plaintext (skipped). */\n skipped: number;\n /** Files that failed to decrypt (path → error message). */\n errors: Array<{ filePath: string; error: string }>;\n}\n\n/**\n * Walk `dir` recursively, find encryptable storage-managed files that are not\n * yet encrypted, and re-write them as encrypted files under `key`.\n *\n * Safety rules per CLAUDE.md gotchas #54 and #25:\n * 1. A page-version snapshot is taken (via `createVersion`) BEFORE\n * each overwrite so the plaintext version is preserved in history.\n * Since this module has no direct access to `page-versioning.ts`\n * internals, callers who have page-versioning configured should\n * pass `onBeforeEncrypt` to take the snapshot.\n * 2. The new encrypted content is written to a temp file first,\n * then renamed atomically — never deleted before written.\n * 3. If encryption of any file fails, the error is recorded and the\n * original file is left intact (partial migration is safe).\n *\n * @param dir Absolute path to the memory directory.\n * @param key 32-byte AES-256 key.\n * @param onBeforeEncrypt Optional callback invoked before encrypting\n * each file. Can be used to take page-version\n * snapshots. Errors here are non-fatal.\n */\nexport async function migrateMemoryDirToEncrypted(\n dir: string,\n key: Buffer,\n onBeforeEncrypt?: (filePath: string) => Promise<void>\n): Promise<MigrateResult> {\n const result: MigrateResult = { encrypted: 0, skipped: 0, errors: [] };\n\n const files = await collectEncryptableStorageFiles(dir);\n for (const filePath of files) {\n try {\n const buf = await readFile(filePath);\n if (isEncryptedFile(buf)) {\n result.skipped++;\n continue;\n }\n // Call optional pre-encryption hook (e.g. page-version snapshot).\n if (onBeforeEncrypt) {\n try {\n await onBeforeEncrypt(filePath);\n } catch {\n // Non-fatal — continue with encryption even if snapshot fails.\n }\n }\n const content = buf.toString(\"utf8\");\n const aad = filePathAad(filePath, dir);\n const encrypted = encryptFileBody(content, key, aad);\n\n // Atomic write: temp → rename (gotcha #54).\n const tempPath = uniqueAtomicTempPath(filePath, \"enc-tmp\");\n try {\n await writeFile(tempPath, encrypted, { mode: 0o600 });\n await rename(tempPath, filePath);\n result.encrypted++;\n } catch (writeErr) {\n // Clean up temp file, leave original intact.\n try {\n const { unlink } = await import(\"node:fs/promises\");\n await unlink(tempPath);\n } catch {\n // ignore\n }\n throw writeErr;\n }\n } catch (err) {\n result.errors.push({\n filePath,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n return result;\n}\n\n/**\n * Walk `dir` recursively, find storage-managed encrypted files, and\n * re-write them as plaintext under the same paths.\n *\n * This is the reversible counterpart to {@link migrateMemoryDirToEncrypted}.\n * It only touches files under the same storage-managed roots, skips\n * plaintext files, skips symlinks, excludes `.secure-store/`, and writes\n * each plaintext replacement via temp-file + rename so a per-file failure\n * leaves the ciphertext intact.\n */\nexport async function decryptMemoryDirToPlaintext(dir: string, key: Buffer): Promise<DecryptResult> {\n const result: DecryptResult = { decrypted: 0, skipped: 0, errors: [] };\n\n const files = await collectStorageManagedFiles(dir, isDecryptableStoragePath);\n for (const filePath of files) {\n try {\n const buf = await readFile(filePath);\n if (!isEncryptedFile(buf)) {\n result.skipped++;\n continue;\n }\n\n const plaintext = decryptFileBodyForPath(buf, key, filePath, dir);\n const tempPath = uniqueAtomicTempPath(filePath, \"dec-tmp\");\n try {\n await writeFile(tempPath, plaintext, { mode: 0o600 });\n await rename(tempPath, filePath);\n result.decrypted++;\n } catch (writeErr) {\n try {\n await unlink(tempPath);\n } catch {\n // ignore cleanup errors; original ciphertext is still intact.\n }\n throw writeErr;\n }\n } catch (err) {\n result.errors.push({\n filePath,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction uniqueAtomicTempPath(filePath: string, label: string): string {\n return `${filePath}.${label}-${process.pid}-${Date.now()}-${randomUUID()}`;\n}\n\nfunction decryptFileBodyForPath(buf: Buffer, key: Buffer, filePath: string, memoryDir?: string): Buffer {\n const aad = filePathAad(filePath, memoryDir);\n try {\n return decryptFileBody(buf, key, aad);\n } catch (err) {\n if (!(err instanceof SecureStoreDecryptError)) {\n throw err;\n }\n const legacyRoot = legacyNamespaceAadRootForFile(filePath, memoryDir);\n if (legacyRoot) {\n try {\n return decryptFileBody(buf, key, filePathAad(filePath, legacyRoot));\n } catch {\n // Fall through to the namespace-reader fallback below.\n }\n }\n\n const topLevelRoot = topLevelAadRootForNamespaceReader(filePath, memoryDir);\n if (topLevelRoot) {\n try {\n return decryptFileBody(buf, key, filePathAad(filePath, topLevelRoot));\n } catch {\n // Preserve the caller-facing error from the canonical decrypt attempt.\n }\n }\n\n throw err;\n }\n}\n\nfunction topLevelAadRootForNamespaceReader(filePath: string, memoryDir?: string): string | null {\n if (!memoryDir || !path.isAbsolute(filePath)) return null;\n const resolvedMemoryDir = path.resolve(memoryDir);\n const rel = path.relative(resolvedMemoryDir, filePath);\n if (rel === \"\" || rel.startsWith(\"..\") || path.isAbsolute(rel)) return null;\n const parts = resolvedMemoryDir.split(path.sep);\n if (parts.length < 3 || parts.at(-2) !== \"namespaces\" || !parts.at(-1)) return null;\n const topLevelRoot = parts.slice(0, -2).join(path.sep) || path.sep;\n const topRel = path.relative(topLevelRoot, filePath);\n if (topRel === \"\" || topRel.startsWith(\"..\") || path.isAbsolute(topRel)) {\n return null;\n }\n const topParts = topRel.split(path.sep);\n if (topParts[0] !== \"namespaces\" || topParts[1] !== parts.at(-1)) {\n return null;\n }\n return topLevelRoot;\n}\n\nfunction legacyNamespaceAadRootForFile(filePath: string, memoryDir?: string): string | null {\n if (!memoryDir || !path.isAbsolute(filePath)) return null;\n const rel = path.relative(memoryDir, filePath);\n if (rel === \"\" || rel.startsWith(\"..\") || path.isAbsolute(rel)) return null;\n const parts = rel.split(path.sep);\n if (parts[0] === \"namespaces\" && parts.length >= 3 && parts[1]) {\n return path.join(memoryDir, \"namespaces\", parts[1]);\n }\n return null;\n}\n\n/**\n * Recursively collect files under `dir` that are read through the\n * storage-layer secure-store helpers, excluding symlinked entries and\n * `.secure-store/` metadata.\n */\nasync function collectEncryptableStorageFiles(dir: string, rootDir = dir): Promise<string[]> {\n return collectStorageManagedFiles(dir, isEncryptableStoragePath, rootDir);\n}\n\n/**\n * Recursively collect regular files under storage-managed roots, excluding\n * symlinked entries and `.secure-store/` metadata. This broader collector is\n * used by the decrypt/disable path so future encrypted sidecars can be\n * restored without requiring extension-specific logic.\n */\nasync function collectStorageManagedFiles(\n dir: string,\n includeFile: (filePath: string, rootDir: string) => boolean,\n rootDir = dir\n): Promise<string[]> {\n const results: string[] = [];\n let scanDir = dir;\n let scanRootDir = rootDir;\n if (path.resolve(dir) === path.resolve(rootDir)) {\n const normalizedRoot = await resolveStorageManagedRootForScan(dir);\n if (!normalizedRoot) return results;\n scanDir = normalizedRoot;\n scanRootDir = normalizedRoot;\n }\n let names: string[];\n try {\n names = await readdir(scanDir, { encoding: \"utf8\" });\n } catch {\n return results;\n }\n for (const name of names) {\n if (name.startsWith(\".secure-store\")) continue;\n const full = path.join(scanDir, name);\n let isDir = false;\n let isFile = false;\n try {\n const s = await lstat(full);\n if (s.isSymbolicLink()) continue;\n isDir = s.isDirectory();\n isFile = s.isFile();\n } catch {\n continue;\n }\n if (isDir) {\n const sub = await collectStorageManagedFiles(full, includeFile, scanRootDir);\n results.push(...sub);\n } else if (isFile && includeFile(full, scanRootDir)) {\n results.push(full);\n }\n }\n return results;\n}\n\nasync function resolveStorageManagedRootForScan(dir: string): Promise<string | null> {\n const lstatPath = normalizePathForLstat(dir);\n let stat: Awaited<ReturnType<typeof lstat>>;\n try {\n stat = await lstat(lstatPath);\n } catch (error) {\n if (isFsErrorWithCode(error, \"ENOENT\")) return null;\n throw error;\n }\n if (stat.isSymbolicLink()) {\n throw new Error(`secure-store migration root must not be a symlink: ${dir}`);\n }\n if (!stat.isDirectory()) {\n throw new Error(`secure-store migration root must be a directory: ${dir}`);\n }\n return lstatPath;\n}\n\nfunction normalizePathForLstat(filePath: string): string {\n return stripTrailingPathSeparators(path.normalize(filePath));\n}\n\nfunction isFsErrorWithCode(error: unknown, code: string): boolean {\n return typeof error === \"object\" && error !== null && (error as { code?: unknown }).code === code;\n}\n\nfunction stripTrailingPathSeparators(filePath: string): string {\n const root = path.parse(filePath).root;\n let end = filePath.length;\n while (\n end > root.length &&\n (filePath[end - 1] === path.sep || filePath[end - 1] === path.posix.sep || filePath[end - 1] === path.win32.sep)\n ) {\n end -= 1;\n }\n return end === filePath.length ? filePath : filePath.slice(0, end);\n}\n\nfunction isEncryptableStoragePath(filePath: string, rootDir: string): boolean {\n const rel = path.relative(rootDir, filePath);\n if (rel === \"\" || rel.startsWith(\"..\") || path.isAbsolute(rel)) return false;\n const normalized = normalizeStorageRelativePath(rel);\n if (normalized === \"profile.md\") return true;\n if (isEncryptableStateSidecar(normalized)) return true;\n if (isEncryptableSummarySidecar(normalized)) return true;\n const firstSegment = normalized.split(\"/\", 1)[0];\n return ENCRYPTABLE_MARKDOWN_STORAGE_ROOTS.has(firstSegment) && normalized.endsWith(\".md\");\n}\n\nfunction isDecryptableStoragePath(filePath: string, rootDir: string): boolean {\n if (isEncryptableStoragePath(filePath, rootDir)) return true;\n const rel = path.relative(rootDir, filePath);\n if (rel === \"\" || rel.startsWith(\"..\") || path.isAbsolute(rel)) return false;\n const normalized = normalizeStorageRelativePath(rel);\n const firstSegment = normalized.split(\"/\", 1)[0];\n return DECRYPTABLE_SIDECAR_ROOTS.has(firstSegment);\n}\n\nfunction normalizeStorageRelativePath(rel: string): string {\n const normalized = rel.split(path.sep).join(\"/\");\n const parts = normalized.split(\"/\");\n if (parts[0] === \"namespaces\" && parts.length >= 3) {\n return parts.slice(2).join(\"/\");\n }\n return normalized;\n}\n\n// Every recall MEMORY category directory (facts/ + the CATEGORY_DIR_MAP memory\n// dirs) must be encryptable at rest — #1546 routes decision/preference/moment/...\n// memories into their own dirs, so hardcoding only facts/corrections/procedures/\n// reasoning-traces would silently write those categories in plaintext on\n// encrypted stores. RECALL_FALLBACK_DIRS is the single source of truth for that\n// set; the extra non-category markdown roots (artifacts/archive/entities/\n// identity) are appended.\n//\n// questions/ is deliberately EXCLUDED (RECALL_FALLBACK_DIRS omits the non-memory\n// queue dirs): the question queue is written/resolved through plain readFile/\n// writeFile (StorageManager.writeQuestion/resolveQuestion), NOT the secure-file\n// helpers. Encrypting questions/ here would make migration seal those files,\n// after which resolveQuestion() would read ciphertext as UTF-8, fail to update\n// the frontmatter, and overwrite/corrupt the file while returning success\n// (codex #1563 review). Keeping questions/ plaintext preserves the queue's\n// existing behavior; #1546 does not change question encryption.\nconst ENCRYPTABLE_MARKDOWN_STORAGE_ROOTS = new Set<string>([\n ...RECALL_FALLBACK_DIRS,\n \"artifacts\",\n \"archive\",\n \"entities\",\n \"identity\",\n]);\n\nconst ENCRYPTABLE_STATE_SIDECARS = new Set([\n \"state/behavior-signals.jsonl\",\n \"state/buffer-surprise-ledger.jsonl\",\n \"state/buffer.json\",\n \"state/compression-guideline-draft-state.json\",\n \"state/compression-guideline-state.json\",\n \"state/compression-guidelines.draft.md\",\n \"state/compression-guidelines.md\",\n \"state/entity-synthesis-queue.json\",\n \"state/fact-hashes.txt\",\n \"state/memory-actions.jsonl\",\n \"state/memory-lifecycle-ledger.jsonl\",\n \"state/meta.json\",\n \"state/reextract-jobs.jsonl\",\n \"state/topics.json\",\n]);\n\nfunction isEncryptableStateSidecar(normalized: string): boolean {\n return ENCRYPTABLE_STATE_SIDECARS.has(normalized);\n}\n\nfunction isEncryptableSummarySidecar(normalized: string): boolean {\n return normalized.startsWith(\"summaries/\") && normalized.endsWith(\".json\");\n}\n\nconst DECRYPTABLE_SIDECAR_ROOTS = new Set([\"state\", \"indexes\", \"index\", \"provenance\"]);\n"],"mappings":"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","names":["position","buffer","unlink"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/offline-sync.ts"],"sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport {\n lstat,\n mkdir,\n open,\n readdir,\n readFile,\n rename,\n rm,\n stat,\n unlink,\n utimes,\n writeFile,\n} from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n DEFAULT_TRANSFER_EXCLUDE_DIRS,\n} from \"./transfer/exclusions.js\";\nimport { isEncryptedFile, MAGIC_HEADER_SIZE } from \"./secure-store/secure-fs.js\";\nimport {\n prepareSafeArchiveRoot,\n resolveSafeArchiveTarget,\n sha256Bytes,\n validateArchiveRelativePath,\n type SafeArchiveRoot,\n} from \"./transfer/fs-utils.js\";\nimport { parseFlexibleIsoTimestamp } from \"./utils/iso-timestamp.js\";\nimport { DEFAULT_OFFLINE_SYNC_EXCLUDE_GLOBS } from \"./offline-sync-exclude-globs.js\";\n\nexport const OFFLINE_SYNC_SNAPSHOT_FORMAT = \"remnic.offline-sync.snapshot.v1\";\nexport const OFFLINE_SYNC_CHANGESET_FORMAT = \"remnic.offline-sync.changeset.v1\";\nexport const OFFLINE_SYNC_STATE_VERSION = 1;\nexport const OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES = 64 * 1024 * 1024;\nexport const OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES = 8 * 1024 * 1024;\nexport const OFFLINE_SYNC_APPLY_MAX_BODY_BYTES = 16 * 1024 * 1024;\nexport const OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES = 64 * 1024 * 1024;\nexport const OFFLINE_SYNC_MAX_MTIME_MS = 8_640_000_000_000_000;\n\nexport interface OfflineSyncFileState {\n path: string;\n sha256: string;\n /** Byte length of the transferable content, after any readFile hook such as secure-store decryption. */\n bytes: number;\n mtimeMs: number;\n}\n\nexport interface OfflineSyncFileRecord extends OfflineSyncFileState {\n contentBase64?: string;\n}\n\nexport interface OfflineSyncFileDigest {\n sha256: string;\n bytes: number;\n}\n\nexport interface OfflineSyncSnapshot {\n format: typeof OFFLINE_SYNC_SNAPSHOT_FORMAT;\n schemaVersion: 1;\n createdAt: string;\n sourceId: string;\n includeTranscripts: boolean;\n files: OfflineSyncFileRecord[];\n}\n\nexport type OfflineSyncChange =\n | {\n type: \"upsert\";\n path: string;\n baseSha256?: string;\n file: OfflineSyncFileRecord & { contentBase64: string };\n }\n | {\n type: \"delete\";\n path: string;\n baseSha256: string;\n };\n\nexport interface OfflineSyncChangeset {\n format: typeof OFFLINE_SYNC_CHANGESET_FORMAT;\n schemaVersion: 1;\n createdAt: string;\n sourceId: string;\n includeTranscripts: boolean;\n changes: OfflineSyncChange[];\n}\n\nexport interface OfflineSyncState {\n version: typeof OFFLINE_SYNC_STATE_VERSION;\n remoteId: string;\n namespace?: string;\n includeTranscripts: boolean;\n lastSyncedAt: string;\n baseFiles: OfflineSyncFileState[];\n}\n\nexport interface OfflineSyncConflict {\n path: string;\n reason:\n | \"both_modified\"\n | \"local_deleted_remote_modified\"\n | \"local_modified_remote_deleted\"\n | \"remote_exists_for_local_create\"\n | \"remote_changed_for_local_update\"\n | \"remote_deleted_for_local_update\"\n | \"remote_changed_for_local_delete\";\n baseSha256?: string;\n localSha256?: string;\n incomingSha256?: string;\n conflictPath?: string;\n}\n\nexport interface OfflineSyncApplySnapshotResult {\n upserted: number;\n deleted: number;\n skipped: number;\n pendingLocal: number;\n conflicts: OfflineSyncConflict[];\n nextBaseFiles: OfflineSyncFileState[];\n}\n\nexport interface OfflineSyncApplyChangesetResult {\n appliedUpserts: number;\n appliedDeletes: number;\n skipped: number;\n conflicts: OfflineSyncConflict[];\n currentFiles: OfflineSyncFileState[];\n currentFilesComplete?: boolean;\n}\n\nexport interface OfflineSyncChangesetSummary {\n upserts: number;\n deletes: number;\n total: number;\n}\n\nexport interface OfflineSyncFileTarget {\n root: string;\n path: string;\n filePath: string;\n}\n\nexport interface OfflineSyncFileWriteTarget extends OfflineSyncFileTarget {\n content: Buffer;\n}\n\nexport interface OfflineSyncFileWriteChunksTarget extends OfflineSyncFileTarget {\n chunks: AsyncIterable<Buffer>;\n}\n\nexport interface OfflineSyncFileStagingWriteTarget extends OfflineSyncFileWriteTarget {}\n\nexport interface OfflineSyncFileContentChunk extends Omit<OfflineSyncFileState, \"sha256\"> {\n sha256?: string;\n offset: number;\n chunkBytes: number;\n content: Buffer;\n}\n\nexport interface OfflineSyncApplyFileContentChunkResult {\n path: string;\n sha256: string;\n bytes: number;\n mtimeMs: number;\n offset: number;\n chunkBytes: number;\n done: boolean;\n applied: boolean;\n skipped: boolean;\n conflict?: OfflineSyncConflict;\n currentFile?: OfflineSyncFileState;\n}\n\ninterface OfflineUploadStaging {\n kind: \"single\" | \"chunks\";\n relPath: string;\n filePath: string;\n}\n\ninterface OfflineSyncFileRecordOptions {\n root: SafeArchiveRoot;\n relPath: string;\n filePath: string;\n includeContent: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n signal?: AbortSignal;\n}\n\nconst SYNC_INTERNAL_DIR = \".offline-sync\";\nconst OFFLINE_SYNC_UPLOAD_STAGING_MAX_AGE_MS = 24 * 60 * 60 * 1000;\nconst OFFLINE_SYNC_FAST_BASE_MTIME_TOLERANCE_MS = 1_000;\nconst OFFLINE_SYNC_FAST_BASE_CTIME_TOLERANCE_MS = 1;\nconst EXCLUDED_FILE_NAMES = new Set([\n \".sync-state.json\",\n]);\n\nconst EXCLUDED_FILE_PREFIXES = [\n \".remnic-sync.\",\n \".remnic-sync-state.\",\n];\n\n/**\n * Convert a tiny subset of glob syntax (`*`, `**`, `?`, literal text) into a\n * regular expression anchored at the start and end of the input. The matcher\n * is intentionally narrow — it is only used for operator-supplied\n * `offlineSyncExcludes` entries, not for full shell-style globbing.\n * `*` and `?` match within a single path segment. `**` is cross-segment\n * wherever it appears: a `star-star-slash` prefix (leading or embedded)\n * matches zero or more whole segments, and a trailing `dir/star-star`\n * matches everything under `dir/` at any depth.\n */\nexport function globToRegExp(glob: string): RegExp {\n if (typeof glob !== \"string\" || glob.length === 0) {\n throw new Error(\"offlineSyncExcludes entry must be a non-empty string\");\n }\n if (glob.includes(\"\\0\")) {\n throw new Error(\"offlineSyncExcludes entry must not contain NUL bytes\");\n }\n let source = \"\";\n for (let i = 0; i < glob.length; i += 1) {\n const ch = glob[i];\n if (ch === \"*\") {\n if (glob[i + 1] === \"*\") {\n // `**` is cross-segment wherever it appears:\n // leading `**/` -> zero or more whole segments\n // `/**` at end -> everything under the directory\n // `a/**/b` -> any depth between segments\n // (Cursor review on PR #1793: trailing `scratch/**` must match\n // nested `scratch/a/b.md`, matching the offline-mode guide.)\n if (glob[i + 2] === \"/\") {\n source += \"(?:.*/)?\";\n i += 2;\n continue;\n }\n source += \".*\";\n i += 1;\n continue;\n }\n source += \"[^/]*\";\n continue;\n }\n if (ch === \"?\") {\n source += \"[^/]\";\n continue;\n }\n if (ch === \"/\") {\n source += \"/\";\n continue;\n }\n source += ch.replace(/[\\\\^$.+()|{}\\[\\]]/g, \"\\\\$&\");\n }\n return new RegExp(`^${source}$`);\n}\n\nfunction hashText(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction sha256Buffer(buffer: Buffer): { sha256: string; bytes: number } {\n return sha256Bytes(buffer);\n}\n\nfunction throwIfOfflineSyncAborted(signal: AbortSignal | undefined): void {\n if (!signal?.aborted) return;\n throw new Error(\"offline sync request aborted\");\n}\n\nfunction compareByPath<T extends { path: string }>(left: T, right: T): number {\n return left.path.localeCompare(right.path);\n}\n\nfunction assertSha256(value: unknown, field: string): string {\n if (typeof value !== \"string\" || !/^[a-f0-9]{64}$/i.test(value)) {\n throw new Error(`${field} must be a 64-character sha256 hex string`);\n }\n return value.toLowerCase();\n}\n\nfunction assertNonNegativeInteger(value: unknown, field: string): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n !Number.isInteger(value) ||\n value < 0\n ) {\n throw new Error(`${field} must be a non-negative integer`);\n }\n return value;\n}\n\nfunction assertNonNegativeFinite(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n throw new Error(`${field} must be a non-negative finite number`);\n }\n return value;\n}\n\nfunction assertOfflineSyncMtimeMs(value: unknown, field: string): number {\n const mtimeMs = assertNonNegativeFinite(value, field);\n if (mtimeMs > OFFLINE_SYNC_MAX_MTIME_MS) {\n throw new Error(`${field} must be within JavaScript Date range`);\n }\n return mtimeMs;\n}\n\nfunction assertBoolean(value: unknown, field: string): boolean {\n if (typeof value !== \"boolean\") {\n throw new Error(`${field} must be a boolean`);\n }\n return value;\n}\n\nfunction normalizeSourceId(value: unknown, field: string): string {\n if (typeof value !== \"string\" || value.trim().length === 0 || value.length > 512) {\n throw new Error(`${field} must be a non-empty string no longer than 512 characters`);\n }\n return value.trim();\n}\n\nfunction normalizeFileState(input: unknown, fieldPrefix: string): OfflineSyncFileState {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(`${fieldPrefix} must be an object`);\n }\n const obj = input as Record<string, unknown>;\n const relPath = normalizeRelativePath(obj.path, `${fieldPrefix}.path`);\n return {\n path: relPath,\n sha256: assertSha256(obj.sha256, `${fieldPrefix}.sha256`),\n bytes: assertNonNegativeInteger(obj.bytes, `${fieldPrefix}.bytes`),\n mtimeMs: assertOfflineSyncMtimeMs(obj.mtimeMs, `${fieldPrefix}.mtimeMs`),\n };\n}\n\nfunction normalizeFileRecord(\n input: unknown,\n fieldPrefix: string,\n requireContent: boolean,\n): OfflineSyncFileRecord {\n const state = normalizeFileState(input, fieldPrefix);\n const obj = input as Record<string, unknown>;\n const contentBase64 = obj.contentBase64;\n if (requireContent && typeof contentBase64 !== \"string\") {\n throw new Error(`${fieldPrefix}.contentBase64 is required`);\n }\n if (contentBase64 !== undefined && typeof contentBase64 !== \"string\") {\n throw new Error(`${fieldPrefix}.contentBase64 must be a base64 string`);\n }\n return {\n ...state,\n ...(contentBase64 !== undefined ? { contentBase64 } : {}),\n };\n}\n\nfunction normalizeFileStates(input: readonly unknown[] | undefined): OfflineSyncFileState[] {\n if (!input) return [];\n if (!Array.isArray(input)) {\n throw new Error(\"baseFiles must be an array\");\n }\n return input.map((entry, index) => normalizeFileState(entry, `baseFiles[${index}]`));\n}\n\nexport function normalizeOfflineSyncSnapshot(\n input: unknown,\n options: { requireContent?: boolean } = {},\n): OfflineSyncSnapshot {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(\"offline sync snapshot must be an object\");\n }\n const obj = input as Record<string, unknown>;\n if (obj.format !== OFFLINE_SYNC_SNAPSHOT_FORMAT) {\n throw new Error(`offline sync snapshot format must be ${OFFLINE_SYNC_SNAPSHOT_FORMAT}`);\n }\n if (obj.schemaVersion !== 1) {\n throw new Error(\"offline sync snapshot schemaVersion must be 1\");\n }\n const createdAt = normalizeIsoString(obj.createdAt, \"createdAt\");\n const sourceId = normalizeSourceId(obj.sourceId, \"sourceId\");\n const includeTranscripts = assertBoolean(obj.includeTranscripts, \"includeTranscripts\");\n if (!Array.isArray(obj.files)) {\n throw new Error(\"offline sync snapshot files must be an array\");\n }\n const files = obj.files\n .map((entry, index) =>\n normalizeFileRecord(entry, `files[${index}]`, options.requireContent === true))\n .filter((file) => !shouldIgnoreIncomingRuntimePath(file.path))\n .sort(compareByPath);\n assertUniquePaths(files, \"offline sync snapshot\");\n if (!includeTranscripts) {\n const transcriptPath = files.find((file) => file.path.split(\"/\")[0] === \"transcripts\")?.path;\n if (transcriptPath) {\n throw new Error(\n `offline sync snapshot includeTranscripts is false but contains transcript path: ${transcriptPath}`,\n );\n }\n }\n const excludedPath = files.find((file) => shouldExcludeRelPath(file.path, true))?.path;\n if (excludedPath) {\n throw new Error(`offline sync snapshot contains excluded path: ${excludedPath}`);\n }\n return {\n format: OFFLINE_SYNC_SNAPSHOT_FORMAT,\n schemaVersion: 1,\n createdAt,\n sourceId,\n includeTranscripts,\n files,\n };\n}\n\nexport function normalizeOfflineSyncChangeset(\n input: unknown,\n): OfflineSyncChangeset {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(\"offline sync changeset must be an object\");\n }\n const obj = input as Record<string, unknown>;\n if (obj.format !== OFFLINE_SYNC_CHANGESET_FORMAT) {\n throw new Error(`offline sync changeset format must be ${OFFLINE_SYNC_CHANGESET_FORMAT}`);\n }\n if (obj.schemaVersion !== 1) {\n throw new Error(\"offline sync changeset schemaVersion must be 1\");\n }\n const createdAt = normalizeIsoString(obj.createdAt, \"createdAt\");\n const sourceId = normalizeSourceId(obj.sourceId, \"sourceId\");\n const includeTranscripts = assertBoolean(obj.includeTranscripts, \"includeTranscripts\");\n if (!Array.isArray(obj.changes)) {\n throw new Error(\"offline sync changeset changes must be an array\");\n }\n const changes = obj.changes.map((entry, index): OfflineSyncChange => {\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n throw new Error(`changes[${index}] must be an object`);\n }\n const change = entry as Record<string, unknown>;\n const type = change.type;\n const relPath = normalizeRelativePath(change.path, `changes[${index}].path`);\n if (type === \"upsert\") {\n const file = normalizeFileRecord(\n change.file,\n `changes[${index}].file`,\n true,\n ) as OfflineSyncFileRecord & { contentBase64: string };\n if (file.path !== relPath) {\n throw new Error(`changes[${index}].file.path must match changes[${index}].path`);\n }\n const baseSha256 =\n change.baseSha256 === undefined\n ? undefined\n : assertSha256(change.baseSha256, `changes[${index}].baseSha256`);\n return {\n type: \"upsert\",\n path: relPath,\n ...(baseSha256 ? { baseSha256 } : {}),\n file,\n };\n }\n if (type === \"delete\") {\n return {\n type: \"delete\",\n path: relPath,\n baseSha256: assertSha256(change.baseSha256, `changes[${index}].baseSha256`),\n };\n }\n throw new Error(`changes[${index}].type must be \"upsert\" or \"delete\"`);\n }).filter((change) => !shouldIgnoreIncomingRuntimePath(change.path));\n assertUniquePaths(changes, \"offline sync changeset\");\n if (!includeTranscripts) {\n const transcriptPath = changes.find((change) => change.path.split(\"/\")[0] === \"transcripts\")?.path;\n if (transcriptPath) {\n throw new Error(\n `offline sync changeset includeTranscripts is false but contains transcript path: ${transcriptPath}`,\n );\n }\n }\n const excludedPath = changes.find((change) => shouldExcludeRelPath(change.path, true))?.path;\n if (excludedPath) {\n throw new Error(`offline sync changeset contains excluded path: ${excludedPath}`);\n }\n return {\n format: OFFLINE_SYNC_CHANGESET_FORMAT,\n schemaVersion: 1,\n createdAt,\n sourceId,\n includeTranscripts,\n changes: changes.sort(compareByPath),\n };\n}\n\nfunction normalizeIsoString(input: unknown, field: string): string {\n if (typeof input !== \"string\" || input.trim().length === 0) {\n throw new Error(`${field} must be an ISO timestamp string`);\n }\n const parsed = parseFlexibleIsoTimestamp(input.trim());\n if (parsed === null) {\n throw new Error(`${field} must be a parseable ISO timestamp`);\n }\n return new Date(parsed).toISOString();\n}\n\nfunction normalizeRelativePath(input: unknown, field: string): string {\n if (typeof input !== \"string\") {\n throw new Error(`${field} must be a POSIX relative path string`);\n }\n return validateArchiveRelativePath(input, field);\n}\n\nfunction assertUniquePaths(entries: readonly { path: string }[], context: string): void {\n const seen = new Set<string>();\n for (const entry of entries) {\n const key = entry.path.toLowerCase();\n if (seen.has(key)) {\n throw new Error(`${context} contains duplicate path: ${entry.path}`);\n }\n seen.add(key);\n }\n}\n\nfunction shouldExcludeRelPath(relPosix: string, includeTranscripts: boolean): boolean {\n const parts = relPosix.split(\"/\");\n if (parts.some((part) => DEFAULT_TRANSFER_EXCLUDE_DIRS.has(part))) return true;\n if (parts.some((part) => part === SYNC_INTERNAL_DIR)) return true;\n if (!includeTranscripts && parts[0] === \"transcripts\") return true;\n const basename = parts[parts.length - 1] ?? \"\";\n if (isCanonicalRuntimeStatePath(parts) && basename.includes(\".tmp-\")) return true;\n if (EXCLUDED_FILE_NAMES.has(basename)) return true;\n if (EXCLUDED_FILE_PREFIXES.some((prefix) => basename.startsWith(prefix))) return true;\n return false;\n}\n\n/**\n * Push-side variant of `shouldExcludeRelPath` for issue #1786. Combines the\n * legacy structural exclude (private dirs, sync internal, tmp runtime state,\n * excluded file names/prefixes) with the new push-only exclusion layers:\n * - the `state/*.sqlite`, `state/index_tags.json`, etc. defaults that\n * describe node-local runtime state each node rebuilds from synced\n * records, and\n * - operator-supplied `offlineSyncExcludes` regexps.\n *\n * Used ONLY by push-side enumeration/validation paths. Apply-side callers\n * must use the legacy `shouldExcludeRelPath` so a remote snapshot containing\n * `state/lcm.sqlite` can still be accepted on first sync -- the remote's\n * view is authoritative for that file until the local LCM is bootstrapped.\n */\nfunction shouldExcludePushRelPath(\n relPosix: string,\n includeTranscripts: boolean,\n userExcludeRegexps?: readonly RegExp[],\n): boolean {\n if (shouldExcludeRelPath(relPosix, includeTranscripts)) return true;\n // Issue #1786: node-local runtime state (live sqlite, derived indexes,\n // per-node governance run logs) is rebuilt by each node, never synced.\n if (matchesOfflineSyncDefaultExclude(relPosix)) return true;\n if (userExcludeRegexps && userExcludeRegexps.some((re) => re.test(relPosix))) return true;\n return false;\n}\n\n// Precompiled once at module load — this check sits on the hot\n// enumeration path for every walked file (Kilo review, PR #1793).\nconst DEFAULT_OFFLINE_SYNC_EXCLUDE_REGEXPS: readonly RegExp[] =\n DEFAULT_OFFLINE_SYNC_EXCLUDE_GLOBS.map((glob) => globToRegExp(glob));\n\nfunction matchesOfflineSyncDefaultExclude(relPosix: string): boolean {\n for (const regexp of DEFAULT_OFFLINE_SYNC_EXCLUDE_REGEXPS) {\n if (regexp.test(relPosix)) return true;\n }\n return false;\n}\n\n/**\n * Compile operator-supplied `offlineSyncExcludes` glob strings into a\n * pre-validated array of regular expressions. Empty input is allowed and\n * returns an empty list. Throws on any invalid entry — callers should treat\n * a thrown error as a fatal configuration mistake and refuse to start the\n * sync run rather than silently dropping the bad entry.\n */\nexport function compileOfflineSyncExcludeGlobs(\n globs: readonly unknown[],\n): RegExp[] {\n const out: RegExp[] = [];\n for (const entry of globs) {\n if (typeof entry !== \"string\" || entry.length === 0) {\n throw new Error(\"offlineSyncExcludes must contain only non-empty strings\");\n }\n out.push(globToRegExp(entry));\n }\n return out;\n}\n\n/**\n * Validate the operator-supplied offline-sync exclude list (#1786).\n * Rejects loudly instead of silently defaulting (CLAUDE.md rule 39):\n * a misspelled key value must fail config parse, not be ignored.\n * Lives next to the glob compiler so config.ts only carries the call.\n */\nexport function parseOfflineSyncExcludes(raw: unknown): string[] {\n if (raw === undefined || raw === null) return [];\n if (!Array.isArray(raw)) {\n throw new Error(\n `offlineSyncExcludes must be an array of non-empty glob strings; got ${typeof raw}`,\n );\n }\n for (const entry of raw) {\n if (typeof entry !== \"string\" || entry.trim().length === 0) {\n throw new Error(\n \"offlineSyncExcludes must contain only non-empty glob strings\",\n );\n }\n }\n const globs = raw.map((entry) => (entry as string).trim());\n // Compile-check every glob now so a bad pattern fails at parse time\n // rather than mid-sync. compileOfflineSyncExcludeGlobs throws with a\n // per-entry message.\n compileOfflineSyncExcludeGlobs(globs);\n return globs;\n}\n\nfunction shouldIgnoreIncomingRuntimePath(relPosix: string): boolean {\n const parts = relPosix.split(\"/\");\n const basename = parts[parts.length - 1] ?? \"\";\n return isCanonicalRuntimeStatePath(parts) && basename.includes(\".tmp-\");\n}\n\nfunction isCanonicalRuntimeStatePath(parts: string[]): boolean {\n if (parts[0] === \"state\") return true;\n return parts[0] === \"namespaces\" && parts.length >= 4 && parts[2] === \"state\";\n}\n\nconst REMOTE_AUTHORITATIVE_RUNTIME_STATE_FILES = new Set([\n \".artifact-write-version.log\",\n \".memory-status-version.log\",\n \"buffer.json\",\n \"embeddings.json\",\n \"index_time.json\",\n \"last_intent.json\",\n \"last_qmd_recall.json\",\n \"last_recall.json\",\n \"lcm.sqlite-shm\",\n \"lcm.sqlite-wal\",\n \"memory-lifecycle-ledger.jsonl\",\n \"recall_impressions.jsonl\",\n]);\n\nconst ABSENT_INCOMING_RUNTIME_DELETE_FILES = new Set([\n \"lcm.sqlite-shm\",\n \"lcm.sqlite-wal\",\n]);\n\nexport function shouldPreferIncomingOfflineRuntimeFile(relPosix: string): boolean {\n const parts = relPosix.split(\"/\");\n const basename = parts[parts.length - 1] ?? \"\";\n return isCanonicalRuntimeStatePath(parts) && REMOTE_AUTHORITATIVE_RUNTIME_STATE_FILES.has(basename);\n}\n\nfunction shouldDeleteAbsentIncomingOfflineRuntimeFile(relPosix: string): boolean {\n const parts = relPosix.split(\"/\");\n const basename = parts[parts.length - 1] ?? \"\";\n return isCanonicalRuntimeStatePath(parts) && ABSENT_INCOMING_RUNTIME_DELETE_FILES.has(basename);\n}\n\nfunction filterBaseFilesForMode(\n files: readonly OfflineSyncFileState[],\n includeTranscripts: boolean,\n): OfflineSyncFileState[] {\n return files.filter((file) => !shouldExcludeRelPath(file.path, includeTranscripts));\n}\n\nfunction canReuseFastBaseFileState(\n baseEntry: OfflineSyncFileState,\n st: { size: number; mtimeMs: number; ctimeMs: number },\n baseCapturedAtMs: number | null,\n): boolean {\n if (baseEntry.bytes !== st.size) return false;\n if (Math.abs(baseEntry.mtimeMs - st.mtimeMs) > OFFLINE_SYNC_FAST_BASE_MTIME_TOLERANCE_MS) {\n return false;\n }\n if (baseCapturedAtMs === null) return false;\n // Node reports stat times as fractional milliseconds while Date snapshots are\n // whole milliseconds, so allow only a tiny precision window around capture.\n return st.ctimeMs - baseCapturedAtMs <= OFFLINE_SYNC_FAST_BASE_CTIME_TOLERANCE_MS;\n}\n\nasync function canReuseFastBaseFileStateFromDisk(\n baseEntry: OfflineSyncFileState,\n st: { size: number; mtimeMs: number; ctimeMs: number },\n baseCapturedAtMs: number | null,\n): Promise<boolean> {\n return canReuseFastBaseFileState(baseEntry, st, baseCapturedAtMs);\n}\n\nasync function readOfflineSyncFileRecord(\n options: OfflineSyncFileRecordOptions,\n): Promise<OfflineSyncFileRecord> {\n throwIfOfflineSyncAborted(options.signal);\n const relPath = validateArchiveRelativePath(options.relPath, \"offlineSyncFile.path\");\n let content: Buffer | null = null;\n let digest: OfflineSyncFileDigest;\n if (options.includeContent) {\n content = options.readFile\n ? await options.readFile({ root: options.root.abs, path: relPath, filePath: options.filePath })\n : await readFile(options.filePath);\n throwIfOfflineSyncAborted(options.signal);\n digest = sha256Buffer(content);\n } else if (options.readFileDigest) {\n digest = await options.readFileDigest({ root: options.root.abs, path: relPath, filePath: options.filePath });\n throwIfOfflineSyncAborted(options.signal);\n } else if (options.readFile) {\n content = await options.readFile({ root: options.root.abs, path: relPath, filePath: options.filePath });\n throwIfOfflineSyncAborted(options.signal);\n digest = sha256Buffer(content);\n content = null;\n } else {\n digest = await sha256File(options.filePath, options.signal);\n }\n throwIfOfflineSyncAborted(options.signal);\n const st = await stat(options.filePath);\n return {\n path: relPath,\n sha256: digest.sha256,\n bytes: digest.bytes,\n mtimeMs: st.mtimeMs,\n ...(content ? { contentBase64: content.toString(\"base64\") } : {}),\n };\n}\n\nasync function sha256File(filePath: string, signal?: AbortSignal): Promise<OfflineSyncFileDigest> {\n const hash = createHash(\"sha256\");\n let bytes = 0;\n for await (const chunk of createReadStream(filePath)) {\n throwIfOfflineSyncAborted(signal);\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n hash.update(buffer);\n bytes += buffer.length;\n }\n throwIfOfflineSyncAborted(signal);\n return {\n sha256: hash.digest(\"hex\"),\n bytes,\n };\n}\n\nasync function fileIsSecureStoreEncrypted(filePath: string): Promise<boolean> {\n const handle = await open(filePath, \"r\");\n try {\n const header = Buffer.alloc(MAGIC_HEADER_SIZE);\n const { bytesRead } = await handle.read(header, 0, header.length, 0);\n return bytesRead >= MAGIC_HEADER_SIZE && isEncryptedFile(header);\n } finally {\n await handle.close();\n }\n}\n\nasync function readPlainFileContentChunk(options: {\n filePath: string;\n offset: number;\n length: number;\n bytes: number;\n}): Promise<Buffer> {\n const chunkBytes = Math.min(options.length, options.bytes - options.offset);\n const chunk = Buffer.alloc(chunkBytes);\n if (chunkBytes === 0) return chunk;\n const handle = await open(options.filePath, \"r\");\n try {\n const { bytesRead } = await handle.read(chunk, 0, chunk.length, options.offset);\n return bytesRead === chunk.length ? chunk : chunk.subarray(0, bytesRead);\n } finally {\n await handle.close();\n }\n}\n\nexport async function* iterateOfflineSyncSnapshotFileRecords(options: {\n root: string;\n includeContent?: boolean;\n includeTranscripts?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n signal?: AbortSignal;\n}): AsyncIterable<OfflineSyncFileRecord> {\n throwIfOfflineSyncAborted(options.signal);\n const rootAbs = path.resolve(options.root);\n const root = await prepareSafeArchiveRoot(rootAbs, \"iterateOfflineSyncSnapshotFileRecords\", \"root\");\n const includeTranscripts = options.includeTranscripts !== false;\n\n async function* walk(dirAbs: string): AsyncIterable<OfflineSyncFileRecord> {\n throwIfOfflineSyncAborted(options.signal);\n let entries = await readdir(dirAbs, { withFileTypes: true });\n entries = entries.sort((left, right) => left.name.localeCompare(right.name));\n for (const entry of entries) {\n const abs = path.join(dirAbs, entry.name);\n const relPosix = path.relative(root.abs, abs).split(path.sep).join(\"/\");\n if (\n options.excludeNodeLocalState === false\n ? shouldExcludeRelPath(relPosix, includeTranscripts)\n : shouldExcludePushRelPath(relPosix, includeTranscripts, options.userExcludeRegexps)\n ) continue;\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n yield* walk(abs);\n continue;\n }\n if (!entry.isFile()) continue;\n yield await readOfflineSyncFileRecord({\n root,\n relPath: relPosix,\n filePath: abs,\n includeContent: options.includeContent === true,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n signal: options.signal,\n });\n }\n }\n\n yield* walk(root.abs);\n}\n\nexport async function buildOfflineSyncSnapshot(options: {\n root: string;\n sourceId: string;\n includeContent?: boolean;\n includeTranscripts?: boolean;\n now?: Date;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n signal?: AbortSignal;\n}): Promise<OfflineSyncSnapshot> {\n throwIfOfflineSyncAborted(options.signal);\n const includeTranscripts = options.includeTranscripts !== false;\n const files: OfflineSyncFileRecord[] = [];\n for await (const file of iterateOfflineSyncSnapshotFileRecords(options)) files.push(file);\n throwIfOfflineSyncAborted(options.signal);\n\n return {\n format: OFFLINE_SYNC_SNAPSHOT_FORMAT,\n schemaVersion: 1,\n createdAt: (options.now ?? new Date()).toISOString(),\n sourceId: normalizeSourceId(options.sourceId, \"sourceId\"),\n includeTranscripts,\n files: files.sort(compareByPath),\n };\n}\n\nexport async function buildOfflineSyncSnapshotFromBase(options: {\n root: string;\n sourceId: string;\n baseFiles?: readonly OfflineSyncFileState[];\n baseCapturedAt?: Date;\n includeContent?: boolean;\n includeTranscripts?: boolean;\n now?: Date;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n signal?: AbortSignal;\n}): Promise<OfflineSyncSnapshot> {\n throwIfOfflineSyncAborted(options.signal);\n const rootAbs = path.resolve(options.root);\n const root = await prepareSafeArchiveRoot(rootAbs, \"buildOfflineSyncSnapshotFromBase\", \"root\");\n const includeTranscripts = options.includeTranscripts !== false;\n const base = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.baseFiles),\n includeTranscripts,\n ));\n const rawBaseCapturedAtMs = options.baseCapturedAt?.getTime();\n const baseCapturedAtMs = rawBaseCapturedAtMs !== undefined && Number.isFinite(rawBaseCapturedAtMs)\n ? rawBaseCapturedAtMs\n : null;\n const files: OfflineSyncFileRecord[] = [];\n\n async function walk(dirAbs: string): Promise<void> {\n throwIfOfflineSyncAborted(options.signal);\n let entries = await readdir(dirAbs, { withFileTypes: true });\n entries = entries.sort((left, right) => left.name.localeCompare(right.name));\n for (const entry of entries) {\n throwIfOfflineSyncAborted(options.signal);\n const abs = path.join(dirAbs, entry.name);\n const relPosix = path.relative(root.abs, abs).split(path.sep).join(\"/\");\n if (\n options.excludeNodeLocalState === false\n ? shouldExcludeRelPath(relPosix, includeTranscripts)\n : shouldExcludePushRelPath(relPosix, includeTranscripts, options.userExcludeRegexps)\n ) continue;\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n await walk(abs);\n continue;\n }\n if (!entry.isFile()) continue;\n const st = await stat(abs);\n const baseEntry = base.get(relPosix);\n if (\n options.includeContent !== true &&\n baseEntry &&\n baseCapturedAtMs !== null &&\n await canReuseFastBaseFileStateFromDisk(baseEntry, st, baseCapturedAtMs)\n ) {\n files.push(baseEntry);\n continue;\n }\n files.push(await readOfflineSyncFileRecord({\n root,\n relPath: relPosix,\n filePath: abs,\n includeContent: options.includeContent === true,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n signal: options.signal,\n }));\n }\n }\n\n await walk(root.abs);\n throwIfOfflineSyncAborted(options.signal);\n\n return {\n format: OFFLINE_SYNC_SNAPSHOT_FORMAT,\n schemaVersion: 1,\n createdAt: (options.now ?? new Date()).toISOString(),\n sourceId: normalizeSourceId(options.sourceId, \"sourceId\"),\n includeTranscripts,\n files: files.sort(compareByPath),\n };\n}\n\nexport async function buildOfflineSyncSnapshotForPaths(options: {\n root: string;\n sourceId: string;\n paths: readonly string[];\n includeContent?: boolean;\n includeTranscripts?: boolean;\n now?: Date;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n signal?: AbortSignal;\n}): Promise<OfflineSyncSnapshot> {\n throwIfOfflineSyncAborted(options.signal);\n const rootAbs = path.resolve(options.root);\n const root = await prepareSafeArchiveRoot(rootAbs, \"buildOfflineSyncSnapshotForPaths\", \"root\");\n const includeTranscripts = options.includeTranscripts !== false;\n const files: OfflineSyncFileRecord[] = [];\n const seen = new Set<string>();\n\n for (const rawPath of options.paths) {\n throwIfOfflineSyncAborted(options.signal);\n const relPath = normalizeRelativePath(rawPath, \"paths[]\");\n if (seen.has(relPath)) continue;\n seen.add(relPath);\n if (\n options.excludeNodeLocalState === false\n ? shouldExcludeRelPath(relPath, includeTranscripts)\n : shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps)\n ) {\n throw new Error(`offline sync snapshot path is excluded: ${relPath}`);\n }\n const filePath = await resolveSafeArchiveTarget(root, relPath);\n const st = await lstat(filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!st || st.isSymbolicLink() || !st.isFile()) continue;\n files.push(await readOfflineSyncFileRecord({\n root,\n relPath,\n filePath,\n includeContent: options.includeContent === true,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n signal: options.signal,\n }));\n }\n throwIfOfflineSyncAborted(options.signal);\n\n return {\n format: OFFLINE_SYNC_SNAPSHOT_FORMAT,\n schemaVersion: 1,\n createdAt: (options.now ?? new Date()).toISOString(),\n sourceId: normalizeSourceId(options.sourceId, \"sourceId\"),\n includeTranscripts,\n files: files.sort(compareByPath),\n };\n}\n\nexport async function readOfflineSyncFileContentChunk(options: {\n root: string;\n path: string;\n offset?: number;\n length?: number;\n includeTranscripts?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n}): Promise<OfflineSyncFileContentChunk> {\n const rootAbs = path.resolve(options.root);\n const root = await prepareSafeArchiveRoot(rootAbs, \"readOfflineSyncFileContentChunk\", \"root\");\n const includeTranscripts = options.includeTranscripts !== false;\n const relPath = normalizeRelativePath(options.path, \"path\");\n if (\n options.excludeNodeLocalState === false\n ? shouldExcludeRelPath(relPath, includeTranscripts)\n : shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps)\n ) {\n throw new Error(`offline sync file content path is excluded: ${relPath}`);\n }\n const offset = options.offset === undefined\n ? 0\n : assertNonNegativeInteger(options.offset, \"offset\");\n const requestedLength = options.length === undefined\n ? OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES\n : assertNonNegativeInteger(options.length, \"length\");\n if (requestedLength < 1 || requestedLength > OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES) {\n throw new Error(\n `length must be an integer from 1 to ${OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES}`,\n );\n }\n const filePath = await resolveSafeArchiveTarget(root, relPath);\n const st = await lstat(filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!st || st.isSymbolicLink() || !st.isFile()) {\n throw new Error(`offline sync file content path not found: ${relPath}`);\n }\n const encrypted = await fileIsSecureStoreEncrypted(filePath);\n if (!encrypted) {\n if (offset > st.size) {\n throw new Error(`offset must be <= file size for ${relPath}`);\n }\n const chunk = await readPlainFileContentChunk({\n filePath,\n offset,\n length: requestedLength,\n bytes: st.size,\n });\n return {\n path: relPath,\n bytes: st.size,\n mtimeMs: st.mtimeMs,\n offset,\n chunkBytes: chunk.length,\n content: chunk,\n };\n }\n if (!options.readFile) {\n throw new Error(`offline sync file content requires a secure-store read hook: ${relPath}`);\n }\n const content = await options.readFile({ root: root.abs, path: relPath, filePath });\n if (offset > content.length) {\n throw new Error(`offset must be <= file size for ${relPath}`);\n }\n const digest = sha256Buffer(content);\n const end = Math.min(content.length, offset + requestedLength);\n const chunk = content.subarray(offset, end);\n return {\n path: relPath,\n sha256: digest.sha256,\n bytes: digest.bytes,\n mtimeMs: st.mtimeMs,\n offset,\n chunkBytes: chunk.length,\n content: Buffer.from(chunk),\n };\n}\n\nexport async function buildOfflineSyncChangeset(options: {\n root: string;\n sourceId: string;\n baseFiles?: readonly OfflineSyncFileState[];\n baseCapturedAt?: Date;\n excludePaths?: readonly string[];\n includeTranscripts?: boolean;\n now?: Date;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n}): Promise<OfflineSyncChangeset> {\n const includeTranscripts = options.includeTranscripts !== false;\n const current = await buildOfflineSyncSnapshotFromBase({\n root: options.root,\n sourceId: options.sourceId,\n baseFiles: options.baseFiles,\n baseCapturedAt: options.baseCapturedAt,\n includeContent: false,\n includeTranscripts,\n now: options.now,\n userExcludeRegexps: options.userExcludeRegexps,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n });\n return buildOfflineSyncChangesetFromSnapshot({\n root: options.root,\n sourceId: options.sourceId,\n baseFiles: options.baseFiles,\n currentFiles: current.files,\n excludePaths: options.excludePaths,\n includeTranscripts,\n now: options.now,\n userExcludeRegexps: options.userExcludeRegexps,\n readFile: options.readFile,\n });\n}\n\nexport async function buildOfflineSyncChangesetFromSnapshot(options: {\n root: string;\n sourceId: string;\n currentFiles: readonly OfflineSyncFileState[];\n baseFiles?: readonly OfflineSyncFileState[];\n excludePaths?: readonly string[];\n includeTranscripts?: boolean;\n now?: Date;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): Promise<OfflineSyncChangeset> {\n const includeTranscripts = options.includeTranscripts !== false;\n const excludedPaths = new Set(\n (options.excludePaths ?? []).map((relPath) => normalizeRelativePath(relPath, \"excludePaths[]\")),\n );\n const base = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.baseFiles),\n includeTranscripts,\n ));\n const currentMap = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.currentFiles),\n includeTranscripts,\n ));\n const changes: OfflineSyncChange[] = [];\n\n for (const relPath of unionPaths(base, currentMap)) {\n if (excludedPaths.has(relPath)) continue;\n // Issue #1786: node-local runtime state must never appear in a push-side\n // changeset — each node rebuilds it from synced records.\n if (shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps)) continue;\n // Runtime state is remote-authoritative in offline sync: local edits and\n // deletes are not pushed; the pull phase restores or removes these files\n // from the remote snapshot.\n if (shouldPreferIncomingOfflineRuntimeFile(relPath)) continue;\n const baseEntry = base.get(relPath);\n const currentEntry = currentMap.get(relPath);\n if (currentEntry && currentEntry.sha256 !== baseEntry?.sha256) {\n const file = await buildOfflineSyncSnapshotForPaths({\n root: options.root,\n sourceId: options.sourceId,\n paths: [relPath],\n includeContent: true,\n includeTranscripts,\n now: options.now,\n userExcludeRegexps: options.userExcludeRegexps,\n readFile: options.readFile,\n });\n const record = file.files[0];\n if (!record || typeof record.contentBase64 !== \"string\" || record.sha256 !== currentEntry.sha256) {\n throw new Error(`offline sync file changed while building changeset: ${relPath}`);\n }\n changes.push({\n type: \"upsert\",\n path: relPath,\n ...(baseEntry ? { baseSha256: baseEntry.sha256 } : {}),\n file: record as OfflineSyncFileRecord & { contentBase64: string },\n });\n continue;\n }\n if (!currentEntry && baseEntry) {\n changes.push({\n type: \"delete\",\n path: relPath,\n baseSha256: baseEntry.sha256,\n });\n }\n }\n\n return {\n format: OFFLINE_SYNC_CHANGESET_FORMAT,\n schemaVersion: 1,\n createdAt: (options.now ?? new Date()).toISOString(),\n sourceId: normalizeSourceId(options.sourceId, \"sourceId\"),\n includeTranscripts,\n changes: changes.sort(compareByPath),\n };\n}\n\nexport function summarizeOfflineSyncChangeset(\n changeset: OfflineSyncChangeset,\n): OfflineSyncChangesetSummary {\n const upserts = changeset.changes.filter((change) => change.type === \"upsert\").length;\n const deletes = changeset.changes.filter((change) => change.type === \"delete\").length;\n return {\n upserts,\n deletes,\n total: changeset.changes.length,\n };\n}\n\nexport async function summarizeOfflineSyncPendingChanges(options: {\n root: string;\n sourceId: string;\n baseFiles?: readonly OfflineSyncFileState[];\n baseCapturedAt?: Date;\n includeTranscripts?: boolean;\n now?: Date;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n}): Promise<OfflineSyncChangesetSummary> {\n const includeTranscripts = options.includeTranscripts !== false;\n const current = await buildOfflineSyncSnapshotFromBase({\n root: options.root,\n sourceId: options.sourceId,\n baseFiles: options.baseFiles,\n baseCapturedAt: options.baseCapturedAt,\n includeContent: false,\n includeTranscripts,\n now: options.now,\n userExcludeRegexps: options.userExcludeRegexps,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n });\n return summarizeOfflineSyncPendingFiles({\n baseFiles: options.baseFiles,\n currentFiles: current.files,\n includeTranscripts,\n userExcludeRegexps: options.userExcludeRegexps,\n });\n}\n\nexport function summarizeOfflineSyncPendingFiles(options: {\n baseFiles?: readonly OfflineSyncFileState[];\n currentFiles: readonly OfflineSyncFileState[];\n includeTranscripts?: boolean;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n}): OfflineSyncChangesetSummary {\n const includeTranscripts = options.includeTranscripts !== false;\n const base = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.baseFiles),\n includeTranscripts,\n ));\n const currentMap = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.currentFiles),\n includeTranscripts,\n ));\n let upserts = 0;\n let deletes = 0;\n for (const relPath of unionPaths(base, currentMap)) {\n if (shouldPreferIncomingOfflineRuntimeFile(relPath)) continue;\n if (shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps)) continue;\n const baseEntry = base.get(relPath);\n const currentEntry = currentMap.get(relPath);\n if (currentEntry && currentEntry.sha256 !== baseEntry?.sha256) {\n upserts += 1;\n continue;\n }\n if (!currentEntry && baseEntry) {\n deletes += 1;\n }\n }\n\n return {\n upserts,\n deletes,\n total: upserts + deletes,\n };\n}\n\nexport async function applyOfflineSyncSnapshot(options: {\n root: string;\n snapshot: unknown;\n baseFiles?: readonly OfflineSyncFileState[];\n currentFiles?: readonly OfflineSyncFileState[];\n deferredPaths?: readonly string[];\n allowMissingConflictContent?: boolean;\n writeConflictCopies?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n deleteFile?: (target: OfflineSyncFileTarget) => Promise<void>;\n}): Promise<OfflineSyncApplySnapshotResult> {\n const snapshot = normalizeOfflineSyncSnapshot(options.snapshot);\n const baseMap = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.baseFiles),\n snapshot.includeTranscripts,\n ));\n const incomingMap = byPath(snapshot.files);\n const incomingBuffers = verifyRecordContents(snapshot.files, \"offline sync snapshot\", {\n requireContent: false,\n });\n const root = await ensureSyncRoot(options.root, \"applyOfflineSyncSnapshot\");\n const currentFiles = options.currentFiles\n ? filterBaseFilesForMode(normalizeFileStates(options.currentFiles), snapshot.includeTranscripts).sort(compareByPath)\n : (await buildOfflineSyncSnapshot({\n root: root.abs,\n sourceId: \"local\",\n includeContent: false,\n includeTranscripts: snapshot.includeTranscripts,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n excludeNodeLocalState: false,\n })).files;\n const currentMap = byPath(currentFiles);\n const deferredPaths = new Set(options.deferredPaths ?? []);\n const nextBase = new Map(baseMap);\n const conflicts: OfflineSyncConflict[] = [];\n let upserted = 0;\n let deleted = 0;\n let skipped = 0;\n let pendingLocal = 0;\n const conflictIncomingBuffer = (relPath: string): Buffer | undefined => {\n if (options.writeConflictCopies === false) return undefined;\n const buffer = incomingBuffers.get(relPath);\n if (buffer || options.allowMissingConflictContent === true) return buffer;\n return requiredBuffer(incomingBuffers, relPath);\n };\n\n for (const relPath of unionPaths(baseMap, incomingMap, currentMap)) {\n const base = baseMap.get(relPath);\n const incoming = incomingMap.get(relPath);\n const currentEntry = currentMap.get(relPath);\n\n if (deferredPaths.has(relPath)) {\n if (base) nextBase.set(relPath, base);\n else nextBase.delete(relPath);\n skipped += 1;\n continue;\n }\n\n if (incoming) {\n if (currentEntry?.sha256 === incoming.sha256) {\n if (await setSafeFileMtime(root, relPath, incoming.mtimeMs)) {\n nextBase.set(relPath, toFileState(incoming));\n } else {\n if (base) nextBase.set(relPath, base);\n else nextBase.delete(relPath);\n pendingLocal += 1;\n }\n skipped += 1;\n continue;\n }\n if (shouldPreferIncomingOfflineRuntimeFile(relPath) && currentEntry && base && incoming.sha256 === base.sha256) {\n nextBase.set(relPath, base);\n skipped += 1;\n continue;\n }\n if (shouldPreferIncomingOfflineRuntimeFile(relPath)) {\n await writeSafeFile(root, relPath, requiredBuffer(incomingBuffers, relPath), options.writeFile, incoming.mtimeMs);\n nextBase.set(relPath, toFileState(incoming));\n upserted += 1;\n continue;\n }\n if (!currentEntry && base && incoming.sha256 === base.sha256) {\n nextBase.set(relPath, base);\n pendingLocal += 1;\n skipped += 1;\n continue;\n }\n if (!currentEntry && base && incoming.sha256 !== base.sha256) {\n conflicts.push(await recordConflict({\n root,\n relPath,\n reason: \"local_deleted_remote_modified\",\n baseSha256: base.sha256,\n incomingSha256: incoming.sha256,\n incomingBuffer: conflictIncomingBuffer(relPath),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: snapshot.sourceId,\n writeFile: options.writeFile,\n }));\n nextBase.set(relPath, base);\n continue;\n }\n if (!currentEntry && !base) {\n await writeSafeFile(root, relPath, requiredBuffer(incomingBuffers, relPath), options.writeFile, incoming.mtimeMs);\n nextBase.set(relPath, toFileState(incoming));\n upserted += 1;\n continue;\n }\n if (base && currentEntry && currentEntry.sha256 === base.sha256) {\n await writeSafeFile(root, relPath, requiredBuffer(incomingBuffers, relPath), options.writeFile, incoming.mtimeMs);\n nextBase.set(relPath, toFileState(incoming));\n upserted += 1;\n continue;\n }\n if (base && incoming.sha256 === base.sha256) {\n nextBase.set(relPath, base);\n pendingLocal += 1;\n skipped += 1;\n continue;\n }\n conflicts.push(await recordConflict({\n root,\n relPath,\n reason: base ? \"both_modified\" : \"remote_exists_for_local_create\",\n baseSha256: base?.sha256,\n localSha256: currentEntry?.sha256,\n incomingSha256: incoming.sha256,\n incomingBuffer: conflictIncomingBuffer(relPath),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: snapshot.sourceId,\n writeFile: options.writeFile,\n }));\n if (base) nextBase.set(relPath, base);\n continue;\n }\n\n // Node-local runtime state (#1786): a push-filtered remote snapshot\n // never carries these paths, so their absence is NOT a delete\n // instruction. Drop any stale base entry (pre-#1786 state files still\n // carry them) and leave the local file untouched — deleting a live\n // sqlite WAL/SHM here would corrupt the local LCM store.\n if (matchesOfflineSyncDefaultExclude(relPath)) {\n nextBase.delete(relPath);\n skipped += 1;\n continue;\n }\n if (!currentEntry) {\n nextBase.delete(relPath);\n skipped += 1;\n continue;\n }\n if (\n shouldPreferIncomingOfflineRuntimeFile(relPath) &&\n (base || shouldDeleteAbsentIncomingOfflineRuntimeFile(relPath))\n ) {\n await deleteSafeFile(root, relPath, options.deleteFile);\n nextBase.delete(relPath);\n deleted += 1;\n continue;\n }\n if (shouldPreferIncomingOfflineRuntimeFile(relPath)) {\n pendingLocal += 1;\n skipped += 1;\n continue;\n }\n if (base && currentEntry.sha256 === base.sha256) {\n await deleteSafeFile(root, relPath, options.deleteFile);\n nextBase.delete(relPath);\n deleted += 1;\n continue;\n }\n if (base) {\n conflicts.push({\n path: relPath,\n reason: \"local_modified_remote_deleted\",\n baseSha256: base.sha256,\n localSha256: currentEntry.sha256,\n });\n nextBase.set(relPath, base);\n continue;\n }\n pendingLocal += 1;\n skipped += 1;\n }\n\n return {\n upserted,\n deleted,\n skipped,\n pendingLocal,\n conflicts,\n nextBaseFiles: [...nextBase.values()].sort(compareByPath),\n };\n}\n\nexport async function applyOfflineSyncChangeset(options: {\n root: string;\n changeset: unknown;\n currentFiles?: readonly OfflineSyncFileState[];\n returnCurrentFiles?: boolean;\n writeConflictCopies?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n deleteFile?: (target: OfflineSyncFileTarget) => Promise<void>;\n}): Promise<OfflineSyncApplyChangesetResult> {\n let changeset: OfflineSyncChangeset;\n try {\n changeset = normalizeOfflineSyncChangeset(options.changeset);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n message.startsWith(\"offline sync\")\n ? message\n : `offline sync changeset invalid: ${message}`,\n );\n }\n const root = await ensureSyncRoot(options.root, \"applyOfflineSyncChangeset\");\n const records = changeset.changes\n .filter((change): change is Extract<OfflineSyncChange, { type: \"upsert\" }> => change.type === \"upsert\")\n .map((change) => change.file);\n const incomingBuffers = verifyRecordContents(records, \"offline sync changeset\");\n const currentFiles = options.currentFiles\n ? filterBaseFilesForMode(normalizeFileStates(options.currentFiles), changeset.includeTranscripts).sort(compareByPath)\n : (await buildOfflineSyncSnapshotForPaths({\n root: root.abs,\n sourceId: \"local\",\n paths: changeset.changes.map((change) => change.path),\n includeContent: false,\n includeTranscripts: changeset.includeTranscripts,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n excludeNodeLocalState: false,\n })).files;\n const currentMap = byPath(currentFiles);\n const conflicts: OfflineSyncConflict[] = [];\n let appliedUpserts = 0;\n let appliedDeletes = 0;\n let skipped = 0;\n\n for (const change of changeset.changes) {\n const currentEntry = currentMap.get(change.path);\n if (change.type === \"upsert\") {\n if (currentEntry?.sha256 === change.file.sha256) {\n if (await setSafeFileMtime(root, change.path, change.file.mtimeMs)) {\n skipped += 1;\n } else {\n await writeSafeFile(root, change.path, requiredBuffer(incomingBuffers, change.path), options.writeFile, change.file.mtimeMs);\n currentMap.set(change.path, toFileState(change.file));\n appliedUpserts += 1;\n }\n continue;\n }\n if (!change.baseSha256) {\n if (!currentEntry) {\n await writeSafeFile(root, change.path, requiredBuffer(incomingBuffers, change.path), options.writeFile, change.file.mtimeMs);\n currentMap.set(change.path, toFileState(change.file));\n appliedUpserts += 1;\n continue;\n }\n conflicts.push(await recordConflict({\n root,\n relPath: change.path,\n reason: \"remote_exists_for_local_create\",\n localSha256: currentEntry.sha256,\n incomingSha256: change.file.sha256,\n incomingBuffer: incomingBuffers.get(change.path),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: changeset.sourceId,\n writeFile: options.writeFile,\n }));\n continue;\n }\n if (currentEntry?.sha256 === change.baseSha256) {\n await writeSafeFile(root, change.path, requiredBuffer(incomingBuffers, change.path), options.writeFile, change.file.mtimeMs);\n currentMap.set(change.path, toFileState(change.file));\n appliedUpserts += 1;\n continue;\n }\n conflicts.push(await recordConflict({\n root,\n relPath: change.path,\n reason: currentEntry ? \"remote_changed_for_local_update\" : \"remote_deleted_for_local_update\",\n baseSha256: change.baseSha256,\n localSha256: currentEntry?.sha256,\n incomingSha256: change.file.sha256,\n incomingBuffer: incomingBuffers.get(change.path),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: changeset.sourceId,\n writeFile: options.writeFile,\n }));\n continue;\n }\n\n if (!currentEntry) {\n skipped += 1;\n continue;\n }\n if (currentEntry.sha256 === change.baseSha256) {\n await deleteSafeFile(root, change.path, options.deleteFile);\n currentMap.delete(change.path);\n appliedDeletes += 1;\n continue;\n }\n conflicts.push({\n path: change.path,\n reason: \"remote_changed_for_local_delete\",\n baseSha256: change.baseSha256,\n localSha256: currentEntry.sha256,\n });\n }\n\n return {\n appliedUpserts,\n appliedDeletes,\n skipped,\n conflicts,\n currentFiles: options.returnCurrentFiles === false\n ? [...currentMap.values()].sort(compareByPath)\n : (await buildOfflineSyncSnapshot({\n root: root.abs,\n sourceId: \"local\",\n includeContent: false,\n includeTranscripts: changeset.includeTranscripts,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n excludeNodeLocalState: false,\n })).files,\n ...(options.returnCurrentFiles === false ? { currentFilesComplete: false } : {}),\n };\n}\n\nfunction verifyRecordContents(\n records: readonly OfflineSyncFileRecord[],\n context: string,\n options: { requireContent?: boolean } = {},\n): Map<string, Buffer> {\n const buffers = new Map<string, Buffer>();\n for (const record of records) {\n if (typeof record.contentBase64 !== \"string\") {\n if (options.requireContent === false) continue;\n throw new Error(`${context}: contentBase64 is required for ${record.path}`);\n }\n const buffer = Buffer.from(record.contentBase64, \"base64\");\n const digest = sha256Buffer(buffer);\n if (digest.sha256 !== record.sha256 || digest.bytes !== record.bytes) {\n throw new Error(\n `${context}: content checksum mismatch for ${record.path}`,\n );\n }\n buffers.set(record.path, buffer);\n }\n return buffers;\n}\n\nfunction requiredBuffer(buffers: Map<string, Buffer>, relPath: string): Buffer {\n const buffer = buffers.get(relPath);\n if (!buffer) {\n throw new Error(`missing decoded content for ${relPath}`);\n }\n return buffer;\n}\n\nasync function ensureSyncRoot(rootPath: string, errorPrefix: string): Promise<SafeArchiveRoot> {\n const rootAbs = path.resolve(rootPath);\n await mkdir(rootAbs, { recursive: true });\n return prepareSafeArchiveRoot(rootAbs, errorPrefix, \"root\");\n}\n\nfunction byPath<T extends OfflineSyncFileState>(files: readonly T[]): Map<string, T> {\n const out = new Map<string, T>();\n for (const file of files) {\n out.set(validateArchiveRelativePath(file.path, \"offlineSync\"), file);\n }\n return out;\n}\n\nfunction unionPaths(...maps: Array<Map<string, unknown>>): string[] {\n const paths = new Set<string>();\n for (const map of maps) {\n for (const key of map.keys()) paths.add(key);\n }\n return [...paths].sort();\n}\n\nfunction toFileState(file: OfflineSyncFileState): OfflineSyncFileState {\n return {\n path: file.path,\n sha256: file.sha256,\n bytes: file.bytes,\n mtimeMs: file.mtimeMs,\n };\n}\n\nasync function writeSafeFile(\n root: SafeArchiveRoot,\n relPath: string,\n content: Buffer,\n writeFileHook?: (target: OfflineSyncFileWriteTarget) => Promise<void>,\n mtimeMs?: number,\n): Promise<void> {\n const target = await resolveSafeArchiveTarget(root, relPath);\n if (writeFileHook) {\n await writeFileHook({ root: root.abs, path: relPath, filePath: target, content });\n await setSafeFileMtime(root, relPath, mtimeMs);\n return;\n }\n await mkdir(path.dirname(target), { recursive: true });\n const tmp = path.join(\n path.dirname(target),\n `.remnic-sync.${process.pid}.${randomUUID()}.tmp`,\n );\n await writeFile(tmp, content);\n try {\n const targetStat = await lstat(target).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (targetStat?.isSymbolicLink()) {\n throw new Error(`offline sync target is a symlink: ${relPath}`);\n }\n await rename(tmp, target);\n await setSafeFileMtime(root, relPath, mtimeMs);\n } catch (error) {\n await unlink(tmp).catch(() => {});\n throw error;\n }\n}\n\nasync function setSafeFileMtime(\n root: SafeArchiveRoot,\n relPath: string,\n mtimeMs: number | undefined,\n): Promise<boolean> {\n if (mtimeMs === undefined) return true;\n const target = await resolveSafeArchiveTarget(root, relPath);\n const targetStat = await lstat(target).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!targetStat) return false;\n if (targetStat.isSymbolicLink()) {\n throw new Error(`offline sync target is a symlink: ${relPath}`);\n }\n const targetMtimeMs = assertOfflineSyncMtimeMs(mtimeMs, \"mtimeMs\");\n if (Math.abs(targetStat.mtimeMs - targetMtimeMs) <= OFFLINE_SYNC_FAST_BASE_MTIME_TOLERANCE_MS) {\n return true;\n }\n const mtime = new Date(targetMtimeMs);\n await utimes(target, mtime, mtime);\n return true;\n}\n\n/**\n * Read the local file digest for a single relative path without applying\n * push-side exclude rules. Used by apply-side helpers that need to check\n * the current local state of a path that the push-side exclude would\n * reject (e.g. `state/lcm.sqlite`). Returns `null` if the file does not\n * exist, is not a regular file, or is a symlink.\n */\nasync function readLocalFileState(options: {\n rootAbs: string;\n relPath: string;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n signal?: AbortSignal;\n}): Promise<OfflineSyncFileState | null> {\n const filePath = await resolveSafeArchiveTarget(\n await prepareSafeArchiveRoot(options.rootAbs, \"readLocalFileState\", \"rootAbs\"),\n options.relPath,\n );\n const st = await lstat(filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!st || st.isSymbolicLink() || !st.isFile()) return null;\n throwIfOfflineSyncAborted(options.signal);\n let digest: OfflineSyncFileDigest;\n if (options.readFileDigest) {\n digest = await options.readFileDigest({ root: options.rootAbs, path: options.relPath, filePath });\n } else if (options.readFile) {\n const content = await options.readFile({ root: options.rootAbs, path: options.relPath, filePath });\n digest = sha256Buffer(content);\n } else {\n digest = await sha256File(filePath, options.signal);\n }\n throwIfOfflineSyncAborted(options.signal);\n return {\n path: options.relPath,\n sha256: digest.sha256,\n bytes: digest.bytes,\n mtimeMs: st.mtimeMs,\n };\n}\n\nexport async function applyOfflineSyncFileContentChunk(options: {\n root: string;\n sourceId: string;\n path: string;\n sha256: string;\n bytes: number;\n mtimeMs: number;\n offset?: number;\n content: Buffer;\n baseSha256?: string;\n includeTranscripts?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n writeStagingFile?: (target: OfflineSyncFileStagingWriteTarget) => Promise<void>;\n writeFileChunks?: (target: OfflineSyncFileWriteChunksTarget) => Promise<void>;\n}): Promise<OfflineSyncApplyFileContentChunkResult> {\n const root = await ensureSyncRoot(options.root, \"applyOfflineSyncFileContentChunk\");\n const sourceId = normalizeSourceId(options.sourceId, \"sourceId\");\n const relPath = normalizeRelativePath(options.path, \"path\");\n const includeTranscripts = options.includeTranscripts !== false;\n if (shouldExcludeRelPath(relPath, includeTranscripts)) {\n throw new Error(`offline sync file content path is excluded: ${relPath}`);\n }\n const sha256 = assertSha256(options.sha256, \"sha256\");\n const bytes = assertNonNegativeInteger(options.bytes, \"bytes\");\n const mtimeMs = assertOfflineSyncMtimeMs(options.mtimeMs, \"mtimeMs\");\n const offset = options.offset === undefined\n ? 0\n : assertNonNegativeInteger(options.offset, \"offset\");\n const baseSha256 = options.baseSha256 === undefined\n ? undefined\n : assertSha256(options.baseSha256, \"baseSha256\");\n const preferIncomingRuntimeFile = shouldPreferIncomingOfflineRuntimeFile(relPath);\n if (!Buffer.isBuffer(options.content)) {\n throw new Error(\"content must be a Buffer\");\n }\n if (options.content.length > OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES) {\n throw new Error(\n `content chunk must be ${OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES} bytes or fewer`,\n );\n }\n if (bytes > 0 && options.content.length === 0) {\n throw new Error(\"content chunk must be non-empty before EOF\");\n }\n if (offset > bytes || offset + options.content.length > bytes) {\n throw new Error(`content chunk range exceeds declared file size for ${relPath}`);\n }\n if (options.writeFile && !options.writeFileChunks) {\n throw new Error(\"offline sync upload storage hooks require writeFileChunks\");\n }\n if (options.writeFile && !options.writeStagingFile) {\n throw new Error(\"offline sync upload storage hooks require writeStagingFile\");\n }\n const baseResult = {\n path: relPath,\n sha256,\n bytes,\n mtimeMs,\n offset,\n chunkBytes: options.content.length,\n done: offset + options.content.length === bytes,\n };\n const currentFileConflict = async (\n currentFile: OfflineSyncFileState | undefined,\n ): Promise<{ conflict: OfflineSyncConflict; currentFile?: OfflineSyncFileState } | null> => {\n if (!baseSha256 && currentFile && !preferIncomingRuntimeFile) {\n const conflict = await recordConflict({\n root,\n relPath,\n reason: \"remote_exists_for_local_create\",\n localSha256: currentFile.sha256,\n incomingSha256: sha256,\n writeConflictCopies: false,\n sourceId,\n writeFile: options.writeFile,\n });\n return {\n conflict,\n currentFile,\n };\n }\n if (baseSha256 && currentFile?.sha256 !== baseSha256 && !preferIncomingRuntimeFile) {\n const conflict = await recordConflict({\n root,\n relPath,\n reason: currentFile ? \"remote_changed_for_local_update\" : \"remote_deleted_for_local_update\",\n baseSha256,\n localSha256: currentFile?.sha256,\n incomingSha256: sha256,\n writeConflictCopies: false,\n sourceId,\n writeFile: options.writeFile,\n });\n return {\n conflict,\n ...(currentFile ? { currentFile } : {}),\n };\n }\n return null;\n };\n if (offset === 0) {\n await pruneOfflineUploadStaging(root);\n const currentFile = await readLocalFileState({\n rootAbs: root.abs,\n relPath,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n });\n if (currentFile && currentFile.sha256 === sha256) {\n await setSafeFileMtime(root, relPath, mtimeMs);\n return {\n ...baseResult,\n done: true,\n chunkBytes: 0,\n applied: false,\n skipped: true,\n currentFile: toFileState(currentFile),\n };\n }\n const conflictResult = await currentFileConflict(currentFile ? toFileState(currentFile) : undefined);\n if (conflictResult) {\n return {\n ...baseResult,\n done: true,\n chunkBytes: 0,\n applied: false,\n skipped: false,\n ...conflictResult,\n };\n }\n }\n\n const upload = await writeOfflineUploadChunk({\n root,\n sourceId,\n relPath,\n sha256,\n bytes,\n offset,\n content: options.content,\n readFile: options.readFile,\n writeFile: options.writeFile,\n writeStagingFile: options.writeStagingFile,\n });\n const done = baseResult.done;\n if (!done) {\n return {\n ...baseResult,\n applied: false,\n skipped: false,\n };\n }\n\n const digest = await digestOfflineUploadStagingContent({\n root,\n upload,\n readFile: options.readFile,\n });\n if (digest.sha256 !== sha256 || digest.bytes !== bytes) {\n await cleanupOfflineUpload(upload).catch(() => {});\n throw new Error(`offline sync upload checksum mismatch for ${relPath}`);\n }\n\n const currentFile = await readLocalFileState({\n rootAbs: root.abs,\n relPath,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n });\n const uploadedState: OfflineSyncFileState = {\n path: relPath,\n sha256,\n bytes,\n mtimeMs,\n };\n\n try {\n if (currentFile && currentFile.sha256 === sha256) {\n await setSafeFileMtime(root, relPath, mtimeMs);\n return {\n ...baseResult,\n applied: false,\n skipped: true,\n currentFile: uploadedState,\n };\n }\n\n const conflictResult = await currentFileConflict(currentFile ? toFileState(currentFile) : undefined);\n if (conflictResult) {\n return {\n ...baseResult,\n applied: false,\n skipped: false,\n ...conflictResult,\n };\n }\n\n await writeSafeFileFromUpload(root, relPath, upload, options.readFile, options.writeFileChunks, mtimeMs);\n return {\n ...baseResult,\n applied: true,\n skipped: false,\n currentFile: uploadedState,\n };\n } finally {\n await cleanupOfflineUpload(upload).catch(() => {});\n }\n}\n\nfunction offlineUploadRelPath(options: {\n sourceId: string;\n relPath: string;\n sha256: string;\n bytes: number;\n}): string {\n const key = hashText([\n options.sourceId,\n options.relPath,\n options.sha256,\n String(options.bytes),\n ].join(\"\\0\"));\n return `${SYNC_INTERNAL_DIR}/uploads/${key}.part`;\n}\n\nasync function offlineUploadPath(root: SafeArchiveRoot, options: {\n sourceId: string;\n relPath: string;\n sha256: string;\n bytes: number;\n}): Promise<OfflineUploadStaging> {\n const relPath = offlineUploadRelPath(options);\n return {\n kind: \"single\",\n relPath,\n filePath: await resolveSafeArchiveTarget(root, relPath),\n };\n}\n\nasync function offlineUploadChunkPath(root: SafeArchiveRoot, options: {\n sourceId: string;\n relPath: string;\n sha256: string;\n bytes: number;\n offset: number;\n}): Promise<OfflineUploadStaging> {\n const uploadRelPath = offlineUploadRelPath(options);\n const relPath = `${uploadRelPath}/${String(options.offset).padStart(20, \"0\")}.part`;\n return {\n kind: \"chunks\",\n relPath,\n filePath: await resolveSafeArchiveTarget(root, relPath),\n };\n}\n\nasync function writeOfflineUploadChunk(options: {\n root: SafeArchiveRoot;\n sourceId: string;\n relPath: string;\n sha256: string;\n bytes: number;\n offset: number;\n content: Buffer;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n writeStagingFile?: (target: OfflineSyncFileStagingWriteTarget) => Promise<void>;\n}): Promise<OfflineUploadStaging> {\n if ((options.writeFile || options.writeStagingFile) && !options.readFile) {\n throw new Error(\"offline sync upload chunk storage hooks require readFile\");\n }\n const uploadRoot = {\n ...(await offlineUploadPath(options.root, options)),\n kind: \"chunks\" as const,\n };\n if (options.offset === 0) {\n await rm(uploadRoot.filePath, { recursive: true, force: true }).catch(() => {});\n } else {\n const existing = await stat(uploadRoot.filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!existing || !existing.isDirectory()) {\n throw new Error(`offline sync upload is missing initial chunk for ${options.relPath}`);\n }\n }\n const chunk = await offlineUploadChunkPath(options.root, { ...options, offset: options.offset });\n\n const writeStagingFile = options.writeStagingFile ?? options.writeFile;\n if (writeStagingFile) {\n // Storage-backed services provide these hooks so secure-store deployments\n // keep staged partial uploads encrypted at rest without mutating indexes.\n await writeOfflineUploadContent({\n root: options.root,\n relPath: chunk.relPath,\n filePath: chunk.filePath,\n content: options.content,\n writeFile: writeStagingFile,\n });\n return uploadRoot;\n }\n\n await mkdir(path.dirname(chunk.filePath), { recursive: true });\n const existingChunk = await lstat(chunk.filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (existingChunk?.isSymbolicLink()) {\n throw new Error(`offline sync upload chunk is a symlink: ${chunk.relPath}`);\n }\n await writeFile(chunk.filePath, options.content, { mode: 0o600 });\n return uploadRoot;\n}\n\nasync function pruneOfflineUploadStaging(root: SafeArchiveRoot): Promise<void> {\n const uploadsRelPath = `${SYNC_INTERNAL_DIR}/uploads`;\n const uploadsPath = await resolveSafeArchiveTarget(root, uploadsRelPath);\n const entries = await readdir(uploadsPath, { withFileTypes: true }).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw error;\n });\n const now = Date.now();\n await Promise.all(entries.map(async (entry) => {\n if (!/^[a-f0-9]{64}\\.part$/i.test(entry.name)) return;\n const relPath = `${uploadsRelPath}/${entry.name}`;\n const filePath = await resolveSafeArchiveTarget(root, relPath);\n const info = await lstat(filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!info) return;\n if (now - info.mtimeMs <= OFFLINE_SYNC_UPLOAD_STAGING_MAX_AGE_MS) return;\n await rm(filePath, { recursive: true, force: true });\n }));\n}\n\nasync function* readOfflineUploadStagingChunks(options: {\n root: SafeArchiveRoot;\n upload: OfflineUploadStaging;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): AsyncGenerator<Buffer> {\n if (options.upload.kind === \"single\") {\n yield await readOfflineUploadContent({\n root: options.root,\n relPath: options.upload.relPath,\n filePath: options.upload.filePath,\n readFile: options.readFile,\n });\n return;\n }\n\n const entries = await readdir(options.upload.filePath);\n const chunkNames = entries\n .filter((entry) => /^\\d{20}\\.part$/.test(entry))\n .sort();\n if (chunkNames.length === 0) {\n throw new Error(`offline sync upload is missing chunks for ${options.upload.relPath}`);\n }\n let expectedOffset = 0;\n for (const chunkName of chunkNames) {\n const offset = Number(chunkName.slice(0, 20));\n if (!Number.isSafeInteger(offset) || offset !== expectedOffset) {\n throw new Error(\n `offline sync upload offset mismatch for ${options.upload.relPath}: expected ${expectedOffset}, got ${offset}`,\n );\n }\n const relPath = `${options.upload.relPath}/${chunkName}`;\n const filePath = await resolveSafeArchiveTarget(options.root, relPath);\n const content = await readOfflineUploadContent({\n root: options.root,\n relPath,\n filePath,\n readFile: options.readFile,\n });\n expectedOffset += content.length;\n yield content;\n }\n}\n\nasync function digestOfflineUploadStagingContent(options: {\n root: SafeArchiveRoot;\n upload: OfflineUploadStaging;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): Promise<{ sha256: string; bytes: number }> {\n const hash = createHash(\"sha256\");\n let bytes = 0;\n for await (const chunk of readOfflineUploadStagingChunks(options)) {\n hash.update(chunk);\n bytes += chunk.length;\n }\n return { sha256: hash.digest(\"hex\"), bytes };\n}\n\nasync function writeSafeFileFromUpload(\n root: SafeArchiveRoot,\n relPath: string,\n upload: OfflineUploadStaging,\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>,\n writeFileChunks?: (target: OfflineSyncFileWriteChunksTarget) => Promise<void>,\n mtimeMs?: number,\n): Promise<void> {\n const target = await resolveSafeArchiveTarget(root, relPath);\n const chunks = readOfflineUploadStagingChunks({ root, upload, readFile });\n if (writeFileChunks) {\n await writeFileChunks({ root: root.abs, path: relPath, filePath: target, chunks });\n await setSafeFileMtime(root, relPath, mtimeMs);\n return;\n }\n\n await mkdir(path.dirname(target), { recursive: true });\n const tmp = path.join(\n path.dirname(target),\n `.remnic-sync.${process.pid}.${randomUUID()}.tmp`,\n );\n const handle = await open(tmp, \"w\", 0o600);\n try {\n for await (const chunk of chunks) {\n if (chunk.length > 0) await handle.write(chunk);\n }\n await handle.close();\n const targetStat = await lstat(target).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (targetStat?.isSymbolicLink()) {\n throw new Error(`offline sync target is a symlink: ${relPath}`);\n }\n await rename(tmp, target);\n await setSafeFileMtime(root, relPath, mtimeMs);\n } catch (error) {\n await handle.close().catch(() => {});\n await unlink(tmp).catch(() => {});\n throw error;\n }\n}\n\nasync function cleanupOfflineUpload(upload: OfflineUploadStaging): Promise<void> {\n if (upload.kind === \"chunks\") {\n await rm(upload.filePath, { recursive: true, force: true });\n return;\n }\n await unlink(upload.filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw error;\n });\n}\n\nasync function readOfflineUploadContent(options: {\n root: SafeArchiveRoot;\n relPath: string;\n filePath: string;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): Promise<Buffer> {\n if (options.readFile) {\n return options.readFile({\n root: options.root.abs,\n path: options.relPath,\n filePath: options.filePath,\n });\n }\n return readFile(options.filePath);\n}\n\nasync function writeOfflineUploadContent(options: {\n root: SafeArchiveRoot;\n relPath: string;\n filePath: string;\n content: Buffer;\n writeFile: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n}): Promise<void> {\n await options.writeFile({\n root: options.root.abs,\n path: options.relPath,\n filePath: options.filePath,\n content: options.content,\n });\n}\n\nasync function deleteSafeFile(\n root: SafeArchiveRoot,\n relPath: string,\n deleteFile?: (target: OfflineSyncFileTarget) => Promise<void>,\n): Promise<void> {\n const target = await resolveSafeArchiveTarget(root, relPath);\n if (deleteFile) {\n await deleteFile({ root: root.abs, path: relPath, filePath: target });\n return;\n }\n await unlink(target).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw error;\n });\n}\n\nasync function recordConflict(options: {\n root: SafeArchiveRoot;\n relPath: string;\n reason: OfflineSyncConflict[\"reason\"];\n baseSha256?: string;\n localSha256?: string;\n incomingSha256?: string;\n incomingBuffer?: Buffer;\n writeConflictCopies: boolean;\n sourceId: string;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n}): Promise<OfflineSyncConflict> {\n let conflictPath: string | undefined;\n if (options.writeConflictCopies && options.incomingBuffer) {\n const sourceHash = hashText(options.sourceId).slice(0, 12);\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n conflictPath = `${SYNC_INTERNAL_DIR}/conflicts/${stamp}-${sourceHash}/${options.relPath}`;\n await writeSafeFile(options.root, conflictPath, options.incomingBuffer, options.writeFile);\n }\n return {\n path: options.relPath,\n reason: options.reason,\n baseSha256: options.baseSha256,\n localSha256: options.localSha256,\n incomingSha256: options.incomingSha256,\n ...(conflictPath ? { conflictPath } : {}),\n };\n}\n\nexport function defaultOfflineSyncStatePath(\n memoryDir: string,\n remoteId: string,\n namespace?: string,\n): string {\n const key = hashText(`${remoteId}\\0${namespace ?? \"\"}`).slice(0, 16);\n return path.join(path.resolve(memoryDir), SYNC_INTERNAL_DIR, \"state\", `${key}.json`);\n}\n\nexport async function readOfflineSyncState(\n statePath: string,\n): Promise<OfflineSyncState | null> {\n let raw: string;\n try {\n raw = await readFile(path.resolve(statePath), \"utf-8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n }\n const parsed = JSON.parse(raw) as unknown;\n return normalizeOfflineSyncState(parsed);\n}\n\nexport async function writeOfflineSyncState(\n statePath: string,\n state: OfflineSyncState,\n): Promise<void> {\n const normalized = normalizeOfflineSyncState(state);\n const target = path.resolve(statePath);\n await mkdir(path.dirname(target), { recursive: true });\n const tmp = path.join(\n path.dirname(target),\n `.remnic-sync-state.${process.pid}.${randomUUID()}.tmp`,\n );\n await writeFile(tmp, JSON.stringify(normalized, null, 2) + \"\\n\", \"utf-8\");\n try {\n await rename(tmp, target);\n } catch (error) {\n await unlink(tmp).catch(() => {});\n throw error;\n }\n}\n\nexport function offlineSyncStateFromSnapshot(options: {\n remoteId: string;\n namespace?: string;\n snapshot: OfflineSyncSnapshot;\n baseFiles?: readonly OfflineSyncFileState[];\n}): OfflineSyncState {\n const snapshot = normalizeOfflineSyncSnapshot(options.snapshot);\n return normalizeOfflineSyncState({\n version: OFFLINE_SYNC_STATE_VERSION,\n remoteId: options.remoteId,\n namespace: options.namespace,\n includeTranscripts: snapshot.includeTranscripts,\n lastSyncedAt: new Date().toISOString(),\n baseFiles: options.baseFiles ?? snapshot.files.map(toFileState),\n });\n}\n\nexport function normalizeOfflineSyncState(input: unknown): OfflineSyncState {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(\"offline sync state must be an object\");\n }\n const obj = input as Record<string, unknown>;\n if (obj.version !== OFFLINE_SYNC_STATE_VERSION) {\n throw new Error(`offline sync state version must be ${OFFLINE_SYNC_STATE_VERSION}`);\n }\n const namespace =\n typeof obj.namespace === \"string\" && obj.namespace.trim().length > 0\n ? obj.namespace.trim()\n : undefined;\n const baseFiles = normalizeFileStates(obj.baseFiles as readonly unknown[] | undefined)\n .sort(compareByPath);\n assertUniquePaths(baseFiles, \"offline sync state\");\n return {\n version: OFFLINE_SYNC_STATE_VERSION,\n remoteId: normalizeSourceId(obj.remoteId, \"remoteId\"),\n ...(namespace ? { namespace } : {}),\n includeTranscripts: assertBoolean(obj.includeTranscripts, \"includeTranscripts\"),\n lastSyncedAt: normalizeIsoString(obj.lastSyncedAt, \"lastSyncedAt\"),\n baseFiles,\n };\n}\n\nexport function fileStatesFromSnapshot(snapshot: OfflineSyncSnapshot): OfflineSyncFileState[] {\n return normalizeOfflineSyncSnapshot(snapshot).files.map(toFileState).sort(compareByPath);\n}\n"],"mappings":"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","names":["chunk","currentFile","readFile"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/convergence-refresh.ts"],"sourcesContent":["import {\n type RebuildMemoryProjectionOptions,\n rebuildMemoryProjection,\n} from \"./maintenance/rebuild-memory-projection.js\";\nimport type { NamespaceSearchRouter } from \"./namespaces/search.js\";\n\ntype ConvergenceStorage = NonNullable<RebuildMemoryProjectionOptions[\"storage\"]>;\n\nexport async function refreshConvergedNamespaces(\n namespaces: readonly string[],\n namespaceSearchRouter: Pick<NamespaceSearchRouter, \"updateNamespacesDetailed\">,\n getStorage: (namespace: string) => Promise<ConvergenceStorage>\n): Promise<void> {\n const targetNamespaces = Array.from(new Set(namespaces.map((namespace) => namespace.trim()).filter(Boolean)));\n if (targetNamespaces.length === 0) return;\n\n await namespaceSearchRouter.updateNamespacesDetailed(targetNamespaces, undefined, { strict: true });\n\n for (const namespace of targetNamespaces) {\n const storage = await getStorage(namespace);\n await rebuildMemoryProjection({\n memoryDir: storage.dir,\n storage,\n defaultNamespace: namespace,\n dryRun: false,\n });\n }\n}\n"],"mappings":";;;;;AAQA,eAAsB,2BACpB,YACA,uBACA,YACe;AACf,QAAM,mBAAmB,MAAM,KAAK,IAAI,IAAI,WAAW,IAAI,CAAC,cAAc,UAAU,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC;AAC5G,MAAI,iBAAiB,WAAW,EAAG;AAEnC,QAAM,sBAAsB,yBAAyB,kBAAkB,QAAW,EAAE,QAAQ,KAAK,CAAC;AAElG,aAAW,aAAa,kBAAkB;AACxC,UAAM,UAAU,MAAM,WAAW,SAAS;AAC1C,UAAM,wBAAwB;AAAA,MAC5B,WAAW,QAAQ;AAAA,MACnB;AAAA,MACA,kBAAkB;AAAA,MAClB,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACF;","names":[]}
|