@remnic/core 1.0.2 → 1.0.3
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/LICENSE +21 -0
- package/README.md +1 -0
- package/dist/access-cli.d.ts +13 -3
- package/dist/access-cli.js +90 -75
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +10 -3
- package/dist/access-http.js +25 -18
- package/dist/access-mcp.d.ts +30 -3
- package/dist/access-mcp.js +16 -1
- package/dist/access-schema.d.ts +12 -12
- package/dist/access-schema.js +1 -1
- package/dist/access-service.d.ts +65 -4
- package/dist/access-service.js +21 -15
- package/dist/active-memory-bridge.d.ts +66 -0
- package/dist/active-memory-bridge.js +11 -0
- package/dist/active-recall.d.ts +96 -0
- package/dist/active-recall.js +308 -0
- package/dist/active-recall.js.map +1 -0
- package/dist/behavior-learner.js +1 -1
- package/dist/bootstrap.d.ts +6 -3
- package/dist/bootstrap.js +2 -2
- package/dist/boxes.js +2 -2
- package/dist/briefing.d.ts +169 -0
- package/dist/briefing.js +52 -0
- package/dist/briefing.js.map +1 -0
- package/dist/buffer.d.ts +19 -5
- package/dist/buffer.js +2 -2
- package/dist/calibration.js +6 -6
- package/dist/causal-behavior.js +5 -5
- package/dist/causal-chain.js +3 -3
- package/dist/causal-consolidation.d.ts +22 -2
- package/dist/causal-consolidation.js +36 -9
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +6 -6
- package/dist/causal-trajectory-graph.js +1 -1
- package/dist/causal-trajectory.d.ts +14 -1
- package/dist/causal-trajectory.js +5 -1
- package/dist/{chunk-KWBU5S5U.js → chunk-2ODBA7MQ.js} +9 -3
- package/dist/chunk-2ODBA7MQ.js.map +1 -0
- package/dist/{chunk-6UJQNRIO.js → chunk-2VFW5K5U.js} +93 -36
- package/dist/chunk-2VFW5K5U.js.map +1 -0
- package/dist/chunk-3PG3H5TD.js +7 -0
- package/dist/chunk-3PG3H5TD.js.map +1 -0
- package/dist/{chunk-NTTLPF7F.js → chunk-3QFQGRHO.js} +5 -5
- package/dist/chunk-4DJQYKMN.js +187 -0
- package/dist/chunk-4DJQYKMN.js.map +1 -0
- package/dist/chunk-4KAN3GZ3.js +225 -0
- package/dist/chunk-4KAN3GZ3.js.map +1 -0
- package/dist/{chunk-ORZMT74A.js → chunk-4NRAJUDS.js} +11 -1
- package/dist/chunk-4NRAJUDS.js.map +1 -0
- package/dist/{chunk-B7LOFDVE.js → chunk-4WMCPJWX.js} +8 -3
- package/dist/chunk-4WMCPJWX.js.map +1 -0
- package/dist/{chunk-G3AG3KZN.js → chunk-5IZL4DCV.js} +2 -2
- package/dist/{chunk-BRK4ODMI.js → chunk-5NPGSAVB.js} +2 -2
- package/dist/chunk-6MKAMLQL.js +16 -0
- package/dist/chunk-6MKAMLQL.js.map +1 -0
- package/dist/{chunk-ESSMF2FR.js → chunk-6PFRXT4K.js} +15 -6
- package/dist/chunk-6PFRXT4K.js.map +1 -0
- package/dist/chunk-6ZH4TU6I.js +245 -0
- package/dist/chunk-6ZH4TU6I.js.map +1 -0
- package/dist/{chunk-V4YC4LUK.js → chunk-74JR4N5J.js} +175 -63
- package/dist/chunk-74JR4N5J.js.map +1 -0
- package/dist/{chunk-L5RPWGFK.js → chunk-7DHTMOND.js} +2 -2
- package/dist/{chunk-TVVVQQAK.js → chunk-7PA4OZEU.js} +53 -11
- package/dist/chunk-7PA4OZEU.js.map +1 -0
- package/dist/{chunk-Q6FETXJA.js → chunk-7SEAZFFB.js} +2 -2
- package/dist/chunk-ALXMCZEU.js +332 -0
- package/dist/chunk-ALXMCZEU.js.map +1 -0
- package/dist/{chunk-QANCTXQF.js → chunk-AYPYCLR7.js} +3 -3
- package/dist/{chunk-WWIQTB2Y.js → chunk-BKQJBXXX.js} +9 -2
- package/dist/chunk-BKQJBXXX.js.map +1 -0
- package/dist/{chunk-LP47L3ZX.js → chunk-BTY5RRRF.js} +7 -7
- package/dist/{chunk-SCHEKPYH.js → chunk-C2EFFULQ.js} +1 -1
- package/dist/{chunk-GJR6D6KC.js → chunk-D654IBA6.js} +2 -2
- package/dist/{chunk-UV2FO7J4.js → chunk-E6K4NIEU.js} +2 -2
- package/dist/{chunk-T4WRIV2C.js → chunk-EABGC2TL.js} +2 -2
- package/dist/chunk-ECKDIK5F.js +813 -0
- package/dist/chunk-ECKDIK5F.js.map +1 -0
- package/dist/chunk-EJI5XIBB.js +232 -0
- package/dist/chunk-EJI5XIBB.js.map +1 -0
- package/dist/{chunk-ONRU4L2N.js → chunk-FEMOX5AD.js} +2 -2
- package/dist/{chunk-IFFFR3MR.js → chunk-FSFEQI74.js} +3 -3
- package/dist/chunk-G4SK7DSQ.js +121 -0
- package/dist/chunk-G4SK7DSQ.js.map +1 -0
- package/dist/{chunk-UIYZ5T3I.js → chunk-GJQPH5G3.js} +8 -8
- package/dist/{chunk-2PO5ZRKV.js → chunk-GZCUW5IC.js} +16 -3
- package/dist/chunk-GZCUW5IC.js.map +1 -0
- package/dist/{chunk-IZME7KW2.js → chunk-HITJFT7E.js} +24 -10
- package/dist/{chunk-IZME7KW2.js.map → chunk-HITJFT7E.js.map} +1 -1
- package/dist/chunk-IQT3XTKW.js +121 -0
- package/dist/chunk-IQT3XTKW.js.map +1 -0
- package/dist/{chunk-BDFZXRSO.js → chunk-J4IYOZZ5.js} +15 -2
- package/dist/chunk-J4IYOZZ5.js.map +1 -0
- package/dist/{chunk-ZKYI7UVO.js → chunk-JR4ZC3G4.js} +2 -2
- package/dist/{chunk-UCYSTFZR.js → chunk-JRNQ3RNA.js} +2 -2
- package/dist/{chunk-UYSKNO6E.js → chunk-JROGC36Y.js} +15 -4
- package/dist/chunk-JROGC36Y.js.map +1 -0
- package/dist/{chunk-GPGBSNKM.js → chunk-K4FLSOR5.js} +2 -2
- package/dist/{chunk-M5ZBBBJI.js → chunk-KEG4GNGI.js} +2 -2
- package/dist/chunk-KVE7R4CG.js +320 -0
- package/dist/chunk-KVE7R4CG.js.map +1 -0
- package/dist/{chunk-L7WO3MZ4.js → chunk-KWP7T3DP.js} +2 -2
- package/dist/chunk-LAYN4LDC.js +267 -0
- package/dist/chunk-LAYN4LDC.js.map +1 -0
- package/dist/{chunk-PGK3VUHN.js → chunk-MTLYEMJB.js} +3 -2
- package/dist/chunk-MTLYEMJB.js.map +1 -0
- package/dist/{chunk-J47FNDR7.js → chunk-MYQWXITD.js} +7 -7
- package/dist/{chunk-YNI4S5WT.js → chunk-N53K2EXC.js} +2 -2
- package/dist/{chunk-763GUIOU.js → chunk-NBNN5GOB.js} +2 -2
- package/dist/{chunk-CXWFUJR2.js → chunk-NSB3WSYS.js} +125 -6
- package/dist/chunk-NSB3WSYS.js.map +1 -0
- package/dist/{chunk-KL4CP4SB.js → chunk-O5ETUNBT.js} +17 -5
- package/dist/chunk-O5ETUNBT.js.map +1 -0
- package/dist/{chunk-OOSWAUYB.js → chunk-ODWDQNRE.js} +2 -2
- package/dist/{chunk-ISY75RLM.js → chunk-OJFGVJS6.js} +288 -7
- package/dist/chunk-OJFGVJS6.js.map +1 -0
- package/dist/{chunk-HLBYLYRD.js → chunk-PAORGQRI.js} +70 -13
- package/dist/chunk-PAORGQRI.js.map +1 -0
- package/dist/{chunk-ZJLY4QSU.js → chunk-PMB3WGDL.js} +69 -6
- package/dist/chunk-PMB3WGDL.js.map +1 -0
- package/dist/{chunk-J3BT33K7.js → chunk-POBPGDWI.js} +5 -5
- package/dist/{chunk-QWUUMMIK.js → chunk-POMSFKTB.js} +1351 -76
- package/dist/chunk-POMSFKTB.js.map +1 -0
- package/dist/{chunk-OTAVQCSF.js → chunk-PYXS46O7.js} +2 -2
- package/dist/chunk-QDW3E4RD.js +108 -0
- package/dist/chunk-QDW3E4RD.js.map +1 -0
- package/dist/{chunk-YNCQ7E4M.js → chunk-QDYXG4CS.js} +4 -3
- package/dist/chunk-QDYXG4CS.js.map +1 -0
- package/dist/{chunk-XUHI52HK.js → chunk-QKAH5B6E.js} +4 -4
- package/dist/{chunk-HLXVTBF3.js → chunk-QNJMBKFK.js} +3 -2
- package/dist/chunk-QNJMBKFK.js.map +1 -0
- package/dist/chunk-RCICHSHL.js +789 -0
- package/dist/chunk-RCICHSHL.js.map +1 -0
- package/dist/{chunk-HG2NKWR2.js → chunk-S4LX5EBI.js} +2 -2
- package/dist/{chunk-4A24LIM2.js → chunk-S75M5ZRK.js} +2 -2
- package/dist/{chunk-QCCCQT3O.js → chunk-TBBDFYXW.js} +2 -2
- package/dist/chunk-TBBDFYXW.js.map +1 -0
- package/dist/{chunk-U4PV25RD.js → chunk-U2IQTSBY.js} +1 -1
- package/dist/chunk-U2IQTSBY.js.map +1 -0
- package/dist/chunk-U66YHYC7.js +31 -0
- package/dist/chunk-U66YHYC7.js.map +1 -0
- package/dist/{chunk-MWGVGUIS.js → chunk-UEYA6UC7.js} +36 -4
- package/dist/chunk-UEYA6UC7.js.map +1 -0
- package/dist/{chunk-MDDAA2AO.js → chunk-UPMD5XND.js} +2 -2
- package/dist/{chunk-M5KEYE5E.js → chunk-URB2WSKZ.js} +2 -2
- package/dist/chunk-UVJFDP7P.js +202 -0
- package/dist/chunk-UVJFDP7P.js.map +1 -0
- package/dist/{chunk-QY2BHY5O.js → chunk-V7XCAHIB.js} +265 -25
- package/dist/chunk-V7XCAHIB.js.map +1 -0
- package/dist/chunk-W6SL7OFG.js +180 -0
- package/dist/chunk-W6SL7OFG.js.map +1 -0
- package/dist/{chunk-QDOSNLB4.js → chunk-X4WESCKA.js} +17 -15
- package/dist/chunk-X4WESCKA.js.map +1 -0
- package/dist/{chunk-OTFNI3OO.js → chunk-XMGSSBFX.js} +1738 -383
- package/dist/chunk-XMGSSBFX.js.map +1 -0
- package/dist/chunk-YDBIWGNI.js +298 -0
- package/dist/chunk-YDBIWGNI.js.map +1 -0
- package/dist/chunk-YFYL2SIJ.js +7857 -0
- package/dist/chunk-YFYL2SIJ.js.map +1 -0
- package/dist/chunking.js +1 -1
- package/dist/citations.d.ts +67 -0
- package/dist/citations.js +13 -0
- package/dist/citations.js.map +1 -0
- package/dist/cli-DwIBnp2g.d.ts +1240 -0
- package/dist/cli.d.ts +31 -1147
- package/dist/cli.js +149 -7092
- package/dist/cli.js.map +1 -1
- package/dist/codex-materialize-CQlLTzke.d.ts +139 -0
- package/dist/codex-thread-key.d.ts +3 -0
- package/dist/codex-thread-key.js +7 -0
- package/dist/codex-thread-key.js.map +1 -0
- package/dist/config.js +3 -2
- package/dist/connectors/codex/instructions.md +160 -0
- package/dist/connectors/codex/resources/namespace-cheatsheet.md +48 -0
- package/dist/day-summary.d.ts +7 -2
- package/dist/day-summary.js +5 -2
- package/dist/embedding-fallback.d.ts +96 -2
- package/dist/embedding-fallback.js +6 -4
- package/dist/{engine-2A6J4XEX.js → engine-X7X3AAG3.js} +10 -7
- package/dist/engine-X7X3AAG3.js.map +1 -0
- package/dist/entity-retrieval.d.ts +3 -2
- package/dist/entity-retrieval.js +10 -7
- package/dist/entity-schema.d.ts +11 -0
- package/dist/entity-schema.js +19 -0
- package/dist/entity-schema.js.map +1 -0
- package/dist/explicit-capture.d.ts +6 -3
- package/dist/explicit-capture.js +2 -2
- package/dist/extraction-judge.d.ts +66 -0
- package/dist/extraction-judge.js +18 -0
- package/dist/extraction-judge.js.map +1 -0
- package/dist/extraction.d.ts +1 -0
- package/dist/extraction.js +12 -10
- package/dist/fallback-llm.js +4 -4
- package/dist/graph.js +1 -1
- package/dist/importance.d.ts +11 -1
- package/dist/importance.js +3 -1
- package/dist/index.d.ts +1140 -8
- package/dist/index.js +3350 -333
- package/dist/index.js.map +1 -1
- package/dist/intent.d.ts +2 -1
- package/dist/intent.js +3 -1
- package/dist/lifecycle.js +1 -1
- package/dist/local-llm.js +2 -2
- package/dist/logger.d.ts +1 -1
- package/dist/logger.js +1 -1
- package/dist/memory-cache.d.ts +2 -2
- package/dist/memory-cache.js +1 -1
- package/dist/{memory-projection-store-NxMkbocT.d.ts → memory-projection-store-DeSXPh1j.d.ts} +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/model-registry.js +2 -2
- package/dist/models-json.js +2 -2
- package/dist/native-knowledge.js +2 -2
- package/dist/negative.js +2 -2
- package/dist/operator-toolkit.js +20 -16
- package/dist/{orchestrator-zTa-Qo-1.d.ts → orchestrator-B9kwlCep.d.ts} +252 -7
- package/dist/orchestrator.d.ts +6 -3
- package/dist/orchestrator.js +70 -58
- package/dist/page-versioning.d.ts +77 -0
- package/dist/page-versioning.js +15 -0
- package/dist/page-versioning.js.map +1 -0
- package/dist/plugin-id.d.ts +37 -0
- package/dist/plugin-id.js +11 -0
- package/dist/plugin-id.js.map +1 -0
- package/dist/policy-runtime.js +2 -2
- package/dist/profiling.js +2 -2
- package/dist/qmd.d.ts +5 -2
- package/dist/qmd.js +3 -3
- package/dist/recall-audit.d.ts +20 -0
- package/dist/recall-audit.js +50 -0
- package/dist/recall-audit.js.map +1 -0
- package/dist/recall-mmr.d.ts +152 -0
- package/dist/recall-mmr.js +17 -0
- package/dist/recall-mmr.js.map +1 -0
- package/dist/recall-qos.js +2 -2
- package/dist/recall-state.js +2 -2
- package/dist/relevance.js +2 -2
- package/dist/resolve-provider-secret.js +2 -2
- package/dist/resume-bundles.js +5 -4
- package/dist/retrieval-agents.js +2 -2
- package/dist/retrieval.js +2 -2
- package/dist/schemas.d.ts +398 -40
- package/dist/schemas.js +3 -1
- package/dist/sdk-compat.d.ts +2 -0
- package/dist/sdk-compat.js +6 -3
- package/dist/sdk-compat.js.map +1 -1
- package/dist/semantic-chunking.d.ts +87 -0
- package/dist/semantic-chunking.js +20 -0
- package/dist/semantic-chunking.js.map +1 -0
- package/dist/semantic-consolidation-DrvSYRdB.d.ts +119 -0
- package/dist/semantic-consolidation.d.ts +4 -42
- package/dist/semantic-consolidation.js +23 -2
- package/dist/semantic-rule-promotion.js +9 -6
- package/dist/semantic-rule-verifier.js +10 -7
- package/dist/session-observer-state.js +2 -2
- package/dist/session-toggles.d.ts +22 -0
- package/dist/session-toggles.js +116 -0
- package/dist/session-toggles.js.map +1 -0
- package/dist/skills-registry.d.ts +47 -0
- package/dist/skills-registry.js +48 -0
- package/dist/skills-registry.js.map +1 -0
- package/dist/source-attribution.d.ts +169 -0
- package/dist/source-attribution.js +27 -0
- package/dist/source-attribution.js.map +1 -0
- package/dist/storage.d.ts +171 -10
- package/dist/storage.js +16 -5
- package/dist/summarizer.js +7 -7
- package/dist/temporal-supersession.d.ts +127 -0
- package/dist/temporal-supersession.js +20 -0
- package/dist/temporal-supersession.js.map +1 -0
- package/dist/threading.js +2 -2
- package/dist/tier-migration.d.ts +2 -1
- package/dist/tier-routing.js +2 -2
- package/dist/tokens.d.ts +21 -1
- package/dist/tokens.js +5 -1
- package/dist/transcript.js +2 -2
- package/dist/types.d.ts +497 -3
- package/dist/types.js +1 -1
- package/dist/utility-learner.js +2 -2
- package/dist/utility-runtime.js +3 -3
- package/dist/verified-recall.js +11 -8
- package/dist/whitespace.d.ts +4 -0
- package/dist/whitespace.js +9 -0
- package/dist/whitespace.js.map +1 -0
- package/package.json +14 -8
- package/dist/chunk-2CJCWDMR.js +0 -87
- package/dist/chunk-2CJCWDMR.js.map +0 -1
- package/dist/chunk-2PO5ZRKV.js.map +0 -1
- package/dist/chunk-6UJQNRIO.js.map +0 -1
- package/dist/chunk-B7LOFDVE.js.map +0 -1
- package/dist/chunk-BDFZXRSO.js.map +0 -1
- package/dist/chunk-CXWFUJR2.js.map +0 -1
- package/dist/chunk-DORBM6OB.js +0 -81
- package/dist/chunk-DORBM6OB.js.map +0 -1
- package/dist/chunk-ESSMF2FR.js.map +0 -1
- package/dist/chunk-HLBYLYRD.js.map +0 -1
- package/dist/chunk-HLXVTBF3.js.map +0 -1
- package/dist/chunk-ISY75RLM.js.map +0 -1
- package/dist/chunk-KL4CP4SB.js.map +0 -1
- package/dist/chunk-KWBU5S5U.js.map +0 -1
- package/dist/chunk-MWGVGUIS.js.map +0 -1
- package/dist/chunk-ORZMT74A.js.map +0 -1
- package/dist/chunk-OTFNI3OO.js.map +0 -1
- package/dist/chunk-PGK3VUHN.js.map +0 -1
- package/dist/chunk-QCCCQT3O.js.map +0 -1
- package/dist/chunk-QDOSNLB4.js.map +0 -1
- package/dist/chunk-QPKFPHOO.js +0 -178
- package/dist/chunk-QPKFPHOO.js.map +0 -1
- package/dist/chunk-QWUUMMIK.js.map +0 -1
- package/dist/chunk-QY2BHY5O.js.map +0 -1
- package/dist/chunk-TVVVQQAK.js.map +0 -1
- package/dist/chunk-U4PV25RD.js.map +0 -1
- package/dist/chunk-UYSKNO6E.js.map +0 -1
- package/dist/chunk-V4YC4LUK.js.map +0 -1
- package/dist/chunk-WWIQTB2Y.js.map +0 -1
- package/dist/chunk-YNCQ7E4M.js.map +0 -1
- package/dist/chunk-ZJLY4QSU.js.map +0 -1
- /package/dist/{engine-2A6J4XEX.js.map → active-memory-bridge.js.map} +0 -0
- /package/dist/{chunk-NTTLPF7F.js.map → chunk-3QFQGRHO.js.map} +0 -0
- /package/dist/{chunk-G3AG3KZN.js.map → chunk-5IZL4DCV.js.map} +0 -0
- /package/dist/{chunk-BRK4ODMI.js.map → chunk-5NPGSAVB.js.map} +0 -0
- /package/dist/{chunk-L5RPWGFK.js.map → chunk-7DHTMOND.js.map} +0 -0
- /package/dist/{chunk-Q6FETXJA.js.map → chunk-7SEAZFFB.js.map} +0 -0
- /package/dist/{chunk-QANCTXQF.js.map → chunk-AYPYCLR7.js.map} +0 -0
- /package/dist/{chunk-LP47L3ZX.js.map → chunk-BTY5RRRF.js.map} +0 -0
- /package/dist/{chunk-SCHEKPYH.js.map → chunk-C2EFFULQ.js.map} +0 -0
- /package/dist/{chunk-GJR6D6KC.js.map → chunk-D654IBA6.js.map} +0 -0
- /package/dist/{chunk-UV2FO7J4.js.map → chunk-E6K4NIEU.js.map} +0 -0
- /package/dist/{chunk-T4WRIV2C.js.map → chunk-EABGC2TL.js.map} +0 -0
- /package/dist/{chunk-ONRU4L2N.js.map → chunk-FEMOX5AD.js.map} +0 -0
- /package/dist/{chunk-IFFFR3MR.js.map → chunk-FSFEQI74.js.map} +0 -0
- /package/dist/{chunk-UIYZ5T3I.js.map → chunk-GJQPH5G3.js.map} +0 -0
- /package/dist/{chunk-ZKYI7UVO.js.map → chunk-JR4ZC3G4.js.map} +0 -0
- /package/dist/{chunk-UCYSTFZR.js.map → chunk-JRNQ3RNA.js.map} +0 -0
- /package/dist/{chunk-GPGBSNKM.js.map → chunk-K4FLSOR5.js.map} +0 -0
- /package/dist/{chunk-M5ZBBBJI.js.map → chunk-KEG4GNGI.js.map} +0 -0
- /package/dist/{chunk-L7WO3MZ4.js.map → chunk-KWP7T3DP.js.map} +0 -0
- /package/dist/{chunk-J47FNDR7.js.map → chunk-MYQWXITD.js.map} +0 -0
- /package/dist/{chunk-YNI4S5WT.js.map → chunk-N53K2EXC.js.map} +0 -0
- /package/dist/{chunk-763GUIOU.js.map → chunk-NBNN5GOB.js.map} +0 -0
- /package/dist/{chunk-OOSWAUYB.js.map → chunk-ODWDQNRE.js.map} +0 -0
- /package/dist/{chunk-J3BT33K7.js.map → chunk-POBPGDWI.js.map} +0 -0
- /package/dist/{chunk-OTAVQCSF.js.map → chunk-PYXS46O7.js.map} +0 -0
- /package/dist/{chunk-XUHI52HK.js.map → chunk-QKAH5B6E.js.map} +0 -0
- /package/dist/{chunk-HG2NKWR2.js.map → chunk-S4LX5EBI.js.map} +0 -0
- /package/dist/{chunk-4A24LIM2.js.map → chunk-S75M5ZRK.js.map} +0 -0
- /package/dist/{chunk-MDDAA2AO.js.map → chunk-UPMD5XND.js.map} +0 -0
- /package/dist/{chunk-M5KEYE5E.js.map → chunk-URB2WSKZ.js.map} +0 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// src/page-versioning.ts
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import {
|
|
5
|
+
access,
|
|
6
|
+
mkdir,
|
|
7
|
+
readFile,
|
|
8
|
+
writeFile,
|
|
9
|
+
unlink
|
|
10
|
+
} from "fs/promises";
|
|
11
|
+
var NOOP_LOGGER = {
|
|
12
|
+
debug: () => {
|
|
13
|
+
},
|
|
14
|
+
warn: () => {
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var writeLocks = /* @__PURE__ */ new Map();
|
|
18
|
+
function withPageLock(pageKey, fn) {
|
|
19
|
+
const prev = writeLocks.get(pageKey) ?? Promise.resolve();
|
|
20
|
+
const next = prev.then(fn, fn);
|
|
21
|
+
writeLocks.set(pageKey, next.then(() => {
|
|
22
|
+
}, () => {
|
|
23
|
+
}));
|
|
24
|
+
return next;
|
|
25
|
+
}
|
|
26
|
+
function contentHash(content) {
|
|
27
|
+
return createHash("sha256").update(content, "utf-8").digest("hex");
|
|
28
|
+
}
|
|
29
|
+
function sidecarKey(pagePath) {
|
|
30
|
+
const withoutExt = pagePath.replace(/\.md$/i, "");
|
|
31
|
+
return withoutExt.replace(/[\\/]/g, "__");
|
|
32
|
+
}
|
|
33
|
+
function sidecarDir(memoryDir, sidecar, pagePath) {
|
|
34
|
+
return path.join(memoryDir, sidecar, sidecarKey(pagePath));
|
|
35
|
+
}
|
|
36
|
+
function manifestPath(memoryDir, sidecar, pagePath) {
|
|
37
|
+
return path.join(sidecarDir(memoryDir, sidecar, pagePath), "manifest.json");
|
|
38
|
+
}
|
|
39
|
+
async function fileExists(p) {
|
|
40
|
+
try {
|
|
41
|
+
await access(p);
|
|
42
|
+
return true;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function readManifest(memoryDir, sidecar, pagePath) {
|
|
48
|
+
const mp = manifestPath(memoryDir, sidecar, pagePath);
|
|
49
|
+
try {
|
|
50
|
+
const raw = await readFile(mp, "utf-8");
|
|
51
|
+
const parsed = JSON.parse(raw);
|
|
52
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
53
|
+
return { pagePath, versions: [], currentVersion: "0" };
|
|
54
|
+
}
|
|
55
|
+
const obj = parsed;
|
|
56
|
+
const versions = Array.isArray(obj.versions) ? obj.versions : [];
|
|
57
|
+
const currentVersion = typeof obj.currentVersion === "string" ? obj.currentVersion : "0";
|
|
58
|
+
return { pagePath: typeof obj.pagePath === "string" ? obj.pagePath : pagePath, versions, currentVersion };
|
|
59
|
+
} catch {
|
|
60
|
+
return { pagePath, versions: [], currentVersion: "0" };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function writeManifest(memoryDir, sidecar, pagePath, history) {
|
|
64
|
+
const dir = sidecarDir(memoryDir, sidecar, pagePath);
|
|
65
|
+
await mkdir(dir, { recursive: true });
|
|
66
|
+
const mp = manifestPath(memoryDir, sidecar, pagePath);
|
|
67
|
+
await writeFile(mp, JSON.stringify(history, null, 2) + "\n", "utf-8");
|
|
68
|
+
}
|
|
69
|
+
async function createVersion(pagePath, content, trigger, config, log = NOOP_LOGGER, note, memoryDir) {
|
|
70
|
+
const { sidecarDir: sidecar, maxVersionsPerPage } = config;
|
|
71
|
+
const resolvedMemoryDir = memoryDir ?? resolveMemoryDir(pagePath);
|
|
72
|
+
const mPath = manifestPath(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir));
|
|
73
|
+
return withPageLock(mPath, async () => {
|
|
74
|
+
const history = await readManifest(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir));
|
|
75
|
+
const nextId = String(history.versions.length > 0 ? Math.max(...history.versions.map((v) => Number(v.versionId))) + 1 : 1);
|
|
76
|
+
const hash = contentHash(content);
|
|
77
|
+
const version = {
|
|
78
|
+
versionId: nextId,
|
|
79
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
80
|
+
contentHash: hash,
|
|
81
|
+
sizeBytes: Buffer.byteLength(content, "utf-8"),
|
|
82
|
+
trigger,
|
|
83
|
+
...note !== void 0 ? { note } : {}
|
|
84
|
+
};
|
|
85
|
+
const dir = sidecarDir(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir));
|
|
86
|
+
await mkdir(dir, { recursive: true });
|
|
87
|
+
const ext = path.extname(pagePath) || ".md";
|
|
88
|
+
const snapshotPath = path.join(dir, `${nextId}${ext}`);
|
|
89
|
+
await writeFile(snapshotPath, content, "utf-8");
|
|
90
|
+
history.versions.push(version);
|
|
91
|
+
history.currentVersion = nextId;
|
|
92
|
+
if (maxVersionsPerPage > 0 && history.versions.length > maxVersionsPerPage) {
|
|
93
|
+
const toRemove = history.versions.splice(0, history.versions.length - maxVersionsPerPage);
|
|
94
|
+
for (const old of toRemove) {
|
|
95
|
+
const oldPath = path.join(dir, `${old.versionId}${ext}`);
|
|
96
|
+
try {
|
|
97
|
+
await unlink(oldPath);
|
|
98
|
+
} catch {
|
|
99
|
+
log.debug(`page-versioning: could not remove old snapshot ${oldPath}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
await writeManifest(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir), history);
|
|
104
|
+
log.debug(`page-versioning: created version ${nextId} for ${pagePath} (trigger=${trigger})`);
|
|
105
|
+
return version;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
async function listVersions(pagePath, config, memoryDir) {
|
|
109
|
+
const resolvedMemoryDir = memoryDir ?? resolveMemoryDir(pagePath);
|
|
110
|
+
const rel = relPath(pagePath, resolvedMemoryDir);
|
|
111
|
+
const history = await readManifest(resolvedMemoryDir, config.sidecarDir, rel);
|
|
112
|
+
history.versions.sort((a, b) => Number(a.versionId) - Number(b.versionId));
|
|
113
|
+
return history;
|
|
114
|
+
}
|
|
115
|
+
async function getVersion(pagePath, versionId, config, memoryDir) {
|
|
116
|
+
const resolvedMemoryDir = memoryDir ?? resolveMemoryDir(pagePath);
|
|
117
|
+
const rel = relPath(pagePath, resolvedMemoryDir);
|
|
118
|
+
const ext = path.extname(pagePath) || ".md";
|
|
119
|
+
const dir = sidecarDir(resolvedMemoryDir, config.sidecarDir, rel);
|
|
120
|
+
const snapshotPath = path.join(dir, `${versionId}${ext}`);
|
|
121
|
+
if (!await fileExists(snapshotPath)) {
|
|
122
|
+
throw new Error(`Version ${versionId} not found for ${pagePath}`);
|
|
123
|
+
}
|
|
124
|
+
return readFile(snapshotPath, "utf-8");
|
|
125
|
+
}
|
|
126
|
+
async function revertToVersion(pagePath, versionId, config, log = NOOP_LOGGER, memoryDir) {
|
|
127
|
+
const resolvedMemoryDir = memoryDir ?? resolveMemoryDir(pagePath);
|
|
128
|
+
const targetContent = await getVersion(pagePath, versionId, config, resolvedMemoryDir);
|
|
129
|
+
let currentContent = "";
|
|
130
|
+
try {
|
|
131
|
+
currentContent = await readFile(pagePath, "utf-8");
|
|
132
|
+
} catch {
|
|
133
|
+
}
|
|
134
|
+
const version = await createVersion(
|
|
135
|
+
pagePath,
|
|
136
|
+
currentContent,
|
|
137
|
+
"revert",
|
|
138
|
+
config,
|
|
139
|
+
log,
|
|
140
|
+
`reverted to version ${versionId}`,
|
|
141
|
+
resolvedMemoryDir
|
|
142
|
+
);
|
|
143
|
+
await writeFile(pagePath, targetContent, "utf-8");
|
|
144
|
+
log.debug(`page-versioning: reverted ${pagePath} to version ${versionId}`);
|
|
145
|
+
return version;
|
|
146
|
+
}
|
|
147
|
+
async function diffVersions(pagePath, v1, v2, config, memoryDir) {
|
|
148
|
+
const resolvedMemoryDir = memoryDir ?? resolveMemoryDir(pagePath);
|
|
149
|
+
const content1 = await getVersion(pagePath, v1, config, resolvedMemoryDir);
|
|
150
|
+
const content2 = await getVersion(pagePath, v2, config, resolvedMemoryDir);
|
|
151
|
+
const lines1 = content1.split("\n");
|
|
152
|
+
const lines2 = content2.split("\n");
|
|
153
|
+
const result = [];
|
|
154
|
+
result.push(`--- version ${v1}`);
|
|
155
|
+
result.push(`+++ version ${v2}`);
|
|
156
|
+
const lcs = computeLCS(lines1, lines2);
|
|
157
|
+
let i = 0;
|
|
158
|
+
let j = 0;
|
|
159
|
+
let k = 0;
|
|
160
|
+
while (k < lcs.length) {
|
|
161
|
+
while (i < lines1.length && lines1[i] !== lcs[k]) {
|
|
162
|
+
result.push(`-${lines1[i]}`);
|
|
163
|
+
i++;
|
|
164
|
+
}
|
|
165
|
+
while (j < lines2.length && lines2[j] !== lcs[k]) {
|
|
166
|
+
result.push(`+${lines2[j]}`);
|
|
167
|
+
j++;
|
|
168
|
+
}
|
|
169
|
+
result.push(` ${lcs[k]}`);
|
|
170
|
+
i++;
|
|
171
|
+
j++;
|
|
172
|
+
k++;
|
|
173
|
+
}
|
|
174
|
+
while (i < lines1.length) {
|
|
175
|
+
result.push(`-${lines1[i]}`);
|
|
176
|
+
i++;
|
|
177
|
+
}
|
|
178
|
+
while (j < lines2.length) {
|
|
179
|
+
result.push(`+${lines2[j]}`);
|
|
180
|
+
j++;
|
|
181
|
+
}
|
|
182
|
+
return result.join("\n");
|
|
183
|
+
}
|
|
184
|
+
function computeLCS(a, b) {
|
|
185
|
+
const m = a.length;
|
|
186
|
+
const n = b.length;
|
|
187
|
+
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
|
|
188
|
+
for (let i2 = 1; i2 <= m; i2++) {
|
|
189
|
+
for (let j2 = 1; j2 <= n; j2++) {
|
|
190
|
+
if (a[i2 - 1] === b[j2 - 1]) {
|
|
191
|
+
dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
|
|
192
|
+
} else {
|
|
193
|
+
dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const result = [];
|
|
198
|
+
let i = m;
|
|
199
|
+
let j = n;
|
|
200
|
+
while (i > 0 && j > 0) {
|
|
201
|
+
if (a[i - 1] === b[j - 1]) {
|
|
202
|
+
result.unshift(a[i - 1]);
|
|
203
|
+
i--;
|
|
204
|
+
j--;
|
|
205
|
+
} else if (dp[i - 1][j] > dp[i][j - 1]) {
|
|
206
|
+
i--;
|
|
207
|
+
} else {
|
|
208
|
+
j--;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
function resolveMemoryDir(pagePath) {
|
|
214
|
+
const knownSubdirs = /* @__PURE__ */ new Set([
|
|
215
|
+
"facts",
|
|
216
|
+
"corrections",
|
|
217
|
+
"entities",
|
|
218
|
+
"state",
|
|
219
|
+
"artifacts",
|
|
220
|
+
"questions",
|
|
221
|
+
"profiles"
|
|
222
|
+
]);
|
|
223
|
+
let dir = path.dirname(pagePath);
|
|
224
|
+
for (let depth = 0; depth < 5; depth++) {
|
|
225
|
+
const base = path.basename(dir);
|
|
226
|
+
if (knownSubdirs.has(base) || /^\d{4}-\d{2}-\d{2}$/.test(base)) {
|
|
227
|
+
dir = path.dirname(dir);
|
|
228
|
+
} else {
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return dir;
|
|
233
|
+
}
|
|
234
|
+
function relPath(pagePath, memoryDir) {
|
|
235
|
+
return path.relative(memoryDir, pagePath);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export {
|
|
239
|
+
createVersion,
|
|
240
|
+
listVersions,
|
|
241
|
+
getVersion,
|
|
242
|
+
revertToVersion,
|
|
243
|
+
diffVersions
|
|
244
|
+
};
|
|
245
|
+
//# sourceMappingURL=chunk-6ZH4TU6I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/page-versioning.ts"],"sourcesContent":["/**\n * Page-level versioning with history and revert (issue #371).\n *\n * Provides snapshot-based versioning for memory files using a sidecar\n * directory layout. Each memory page gets a `.versions/<pageName>/`\n * subdirectory containing numbered snapshots and a `manifest.json` that\n * records the version history.\n *\n * Storage layout:\n * memoryDir/\n * facts/preferences.md <- current file\n * .versions/\n * facts__preferences/\n * manifest.json <- VersionHistory\n * 1.md <- version 1 snapshot\n * 2.md <- version 2 snapshot\n */\n\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport {\n access,\n mkdir,\n readFile,\n writeFile,\n unlink,\n} from \"node:fs/promises\";\n\n// ---------------------------------------------------------------------------\n// Public interfaces\n// ---------------------------------------------------------------------------\n\nexport interface PageVersion {\n versionId: string;\n timestamp: string;\n contentHash: string;\n sizeBytes: number;\n trigger: VersionTrigger;\n note?: string;\n}\n\nexport type VersionTrigger = \"write\" | \"consolidation\" | \"revert\" | \"manual\";\n\nexport interface VersionHistory {\n pagePath: string;\n versions: PageVersion[];\n currentVersion: string;\n}\n\nexport interface VersioningConfig {\n enabled: boolean;\n maxVersionsPerPage: number;\n sidecarDir: string;\n}\n\n// ---------------------------------------------------------------------------\n// Logger interface (minimal, avoids coupling to the host logger)\n// ---------------------------------------------------------------------------\n\nexport interface VersioningLogger {\n debug(msg: string): void;\n warn(msg: string): void;\n}\n\nconst NOOP_LOGGER: VersioningLogger = {\n debug: () => {},\n warn: () => {},\n};\n\n// ---------------------------------------------------------------------------\n// Per-page write lock (promise-chain pattern, see gotcha #40)\n// ---------------------------------------------------------------------------\n\nconst writeLocks = new Map<string, Promise<void>>();\n\nfunction withPageLock<T>(pageKey: string, fn: () => Promise<T>): Promise<T> {\n const prev = writeLocks.get(pageKey) ?? Promise.resolve();\n const next = prev.then(fn, fn); // run fn after previous completes, even if previous failed\n writeLocks.set(pageKey, next.then(() => {}, () => {})); // recover chain per gotcha #40\n return next;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction contentHash(content: string): string {\n return createHash(\"sha256\").update(content, \"utf-8\").digest(\"hex\");\n}\n\n/**\n * Derive a filesystem-safe sidecar key from a page path relative to memoryDir.\n *\n * `facts/2026-01-15/pref-001.md` -> `facts__2026-01-15__pref-001`\n */\nfunction sidecarKey(pagePath: string): string {\n const withoutExt = pagePath.replace(/\\.md$/i, \"\");\n return withoutExt.replace(/[\\\\/]/g, \"__\");\n}\n\nfunction sidecarDir(memoryDir: string, sidecar: string, pagePath: string): string {\n return path.join(memoryDir, sidecar, sidecarKey(pagePath));\n}\n\nfunction manifestPath(memoryDir: string, sidecar: string, pagePath: string): string {\n return path.join(sidecarDir(memoryDir, sidecar, pagePath), \"manifest.json\");\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n await access(p);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function readManifest(\n memoryDir: string,\n sidecar: string,\n pagePath: string,\n): Promise<VersionHistory> {\n const mp = manifestPath(memoryDir, sidecar, pagePath);\n try {\n const raw = await readFile(mp, \"utf-8\");\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== \"object\" || parsed === null) {\n return { pagePath, versions: [], currentVersion: \"0\" };\n }\n const obj = parsed as Record<string, unknown>;\n const versions = Array.isArray(obj.versions) ? (obj.versions as PageVersion[]) : [];\n const currentVersion = typeof obj.currentVersion === \"string\" ? obj.currentVersion : \"0\";\n return { pagePath: typeof obj.pagePath === \"string\" ? obj.pagePath : pagePath, versions, currentVersion };\n } catch {\n return { pagePath, versions: [], currentVersion: \"0\" };\n }\n}\n\nasync function writeManifest(\n memoryDir: string,\n sidecar: string,\n pagePath: string,\n history: VersionHistory,\n): Promise<void> {\n const dir = sidecarDir(memoryDir, sidecar, pagePath);\n await mkdir(dir, { recursive: true });\n const mp = manifestPath(memoryDir, sidecar, pagePath);\n await writeFile(mp, JSON.stringify(history, null, 2) + \"\\n\", \"utf-8\");\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a new version snapshot for a page.\n *\n * Call this BEFORE overwriting the current file so the previous content is\n * preserved. If the file does not exist yet (first write), the provided\n * `content` is snapshotted as version 1.\n *\n * Pruning: when the number of versions exceeds `config.maxVersionsPerPage`,\n * the oldest snapshots (and their files) are removed.\n */\nexport async function createVersion(\n pagePath: string,\n content: string,\n trigger: VersionTrigger,\n config: VersioningConfig,\n log: VersioningLogger = NOOP_LOGGER,\n note?: string,\n memoryDir?: string,\n): Promise<PageVersion> {\n const { sidecarDir: sidecar, maxVersionsPerPage } = config;\n const resolvedMemoryDir = memoryDir ?? resolveMemoryDir(pagePath);\n const mPath = manifestPath(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir));\n\n return withPageLock(mPath, async () => {\n const history = await readManifest(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir));\n const nextId = String(history.versions.length > 0\n ? Math.max(...history.versions.map((v) => Number(v.versionId))) + 1\n : 1);\n\n const hash = contentHash(content);\n const version: PageVersion = {\n versionId: nextId,\n timestamp: new Date().toISOString(),\n contentHash: hash,\n sizeBytes: Buffer.byteLength(content, \"utf-8\"),\n trigger,\n ...(note !== undefined ? { note } : {}),\n };\n\n // Write snapshot file\n const dir = sidecarDir(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir));\n await mkdir(dir, { recursive: true });\n const ext = path.extname(pagePath) || \".md\";\n const snapshotPath = path.join(dir, `${nextId}${ext}`);\n await writeFile(snapshotPath, content, \"utf-8\");\n\n history.versions.push(version);\n history.currentVersion = nextId;\n\n // Prune old versions if exceeding max\n if (maxVersionsPerPage > 0 && history.versions.length > maxVersionsPerPage) {\n const toRemove = history.versions.splice(0, history.versions.length - maxVersionsPerPage);\n for (const old of toRemove) {\n const oldPath = path.join(dir, `${old.versionId}${ext}`);\n try {\n await unlink(oldPath);\n } catch {\n log.debug(`page-versioning: could not remove old snapshot ${oldPath}`);\n }\n }\n }\n\n await writeManifest(resolvedMemoryDir, sidecar, relPath(pagePath, resolvedMemoryDir), history);\n log.debug(`page-versioning: created version ${nextId} for ${pagePath} (trigger=${trigger})`);\n\n return version;\n });\n}\n\n/**\n * List all versions for a page.\n */\nexport async function listVersions(\n pagePath: string,\n config: VersioningConfig,\n memoryDir?: string,\n): Promise<VersionHistory> {\n const resolvedMemoryDir = memoryDir ?? resolveMemoryDir(pagePath);\n const rel = relPath(pagePath, resolvedMemoryDir);\n const history = await readManifest(resolvedMemoryDir, config.sidecarDir, rel);\n // Sort ascending by versionId (numeric)\n history.versions.sort((a, b) => Number(a.versionId) - Number(b.versionId));\n return history;\n}\n\n/**\n * Read the content of a specific version.\n */\nexport async function getVersion(\n pagePath: string,\n versionId: string,\n config: VersioningConfig,\n memoryDir?: string,\n): Promise<string> {\n const resolvedMemoryDir = memoryDir ?? resolveMemoryDir(pagePath);\n const rel = relPath(pagePath, resolvedMemoryDir);\n const ext = path.extname(pagePath) || \".md\";\n const dir = sidecarDir(resolvedMemoryDir, config.sidecarDir, rel);\n const snapshotPath = path.join(dir, `${versionId}${ext}`);\n\n if (!(await fileExists(snapshotPath))) {\n throw new Error(`Version ${versionId} not found for ${pagePath}`);\n }\n\n return readFile(snapshotPath, \"utf-8\");\n}\n\n/**\n * Revert a page to a previous version.\n *\n * 1. Reads the target version's content.\n * 2. Snapshots the CURRENT content as a new version (trigger: \"revert\").\n * 3. Writes the reverted content to the page file.\n *\n * Returns the newly created version entry for the revert snapshot.\n */\nexport async function revertToVersion(\n pagePath: string,\n versionId: string,\n config: VersioningConfig,\n log: VersioningLogger = NOOP_LOGGER,\n memoryDir?: string,\n): Promise<PageVersion> {\n const resolvedMemoryDir = memoryDir ?? resolveMemoryDir(pagePath);\n\n // Read target version content\n const targetContent = await getVersion(pagePath, versionId, config, resolvedMemoryDir);\n\n // Snapshot current content before overwriting\n let currentContent = \"\";\n try {\n currentContent = await readFile(pagePath, \"utf-8\");\n } catch {\n // File may not exist; that's okay\n }\n\n const version = await createVersion(\n pagePath,\n currentContent,\n \"revert\",\n config,\n log,\n `reverted to version ${versionId}`,\n resolvedMemoryDir,\n );\n\n // Write the reverted content to the actual page\n await writeFile(pagePath, targetContent, \"utf-8\");\n log.debug(`page-versioning: reverted ${pagePath} to version ${versionId}`);\n\n return version;\n}\n\n/**\n * Simple line-based diff between two versions.\n *\n * Returns a unified-style diff string showing added (+) and removed (-) lines.\n */\nexport async function diffVersions(\n pagePath: string,\n v1: string,\n v2: string,\n config: VersioningConfig,\n memoryDir?: string,\n): Promise<string> {\n const resolvedMemoryDir = memoryDir ?? resolveMemoryDir(pagePath);\n const content1 = await getVersion(pagePath, v1, config, resolvedMemoryDir);\n const content2 = await getVersion(pagePath, v2, config, resolvedMemoryDir);\n\n const lines1 = content1.split(\"\\n\");\n const lines2 = content2.split(\"\\n\");\n\n const result: string[] = [];\n result.push(`--- version ${v1}`);\n result.push(`+++ version ${v2}`);\n\n // Simple LCS-based diff\n const lcs = computeLCS(lines1, lines2);\n let i = 0;\n let j = 0;\n let k = 0;\n\n while (k < lcs.length) {\n // Emit removed lines before the next common line\n while (i < lines1.length && lines1[i] !== lcs[k]) {\n result.push(`-${lines1[i]}`);\n i++;\n }\n // Emit added lines before the next common line\n while (j < lines2.length && lines2[j] !== lcs[k]) {\n result.push(`+${lines2[j]}`);\n j++;\n }\n // Common line\n result.push(` ${lcs[k]}`);\n i++;\n j++;\n k++;\n }\n // Remaining removed lines\n while (i < lines1.length) {\n result.push(`-${lines1[i]}`);\n i++;\n }\n // Remaining added lines\n while (j < lines2.length) {\n result.push(`+${lines2[j]}`);\n j++;\n }\n\n return result.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// LCS helper for diffVersions\n// ---------------------------------------------------------------------------\n\nfunction computeLCS(a: string[], b: string[]): string[] {\n const m = a.length;\n const n = b.length;\n // Build DP table\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array<number>(n + 1).fill(0));\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n if (a[i - 1] === b[j - 1]) {\n dp[i][j] = dp[i - 1][j - 1] + 1;\n } else {\n dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);\n }\n }\n }\n // Backtrack to build LCS\n const result: string[] = [];\n let i = m;\n let j = n;\n while (i > 0 && j > 0) {\n if (a[i - 1] === b[j - 1]) {\n result.unshift(a[i - 1]);\n i--;\n j--;\n } else if (dp[i - 1][j] > dp[i][j - 1]) {\n i--;\n } else {\n j--;\n }\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Path helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Legacy fallback: given an absolute page path, heuristically resolve the\n * memory directory by walking up past known subdirectory names.\n *\n * Callers should always pass an explicit `memoryDir` instead of relying on\n * this heuristic. It is retained only for backward compatibility when the\n * optional `memoryDir` parameter is omitted.\n */\nfunction resolveMemoryDir(pagePath: string): string {\n const knownSubdirs = new Set([\n \"facts\",\n \"corrections\",\n \"entities\",\n \"state\",\n \"artifacts\",\n \"questions\",\n \"profiles\",\n ]);\n\n let dir = path.dirname(pagePath);\n // Walk up past date directories (YYYY-MM-DD) and known subdirs\n for (let depth = 0; depth < 5; depth++) {\n const base = path.basename(dir);\n if (knownSubdirs.has(base) || /^\\d{4}-\\d{2}-\\d{2}$/.test(base)) {\n dir = path.dirname(dir);\n } else {\n break;\n }\n }\n return dir;\n}\n\n/**\n * Compute relative path of a page within its memory directory.\n */\nfunction relPath(pagePath: string, memoryDir: string): string {\n return path.relative(memoryDir, pagePath);\n}\n"],"mappings":"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","names":["i","j"]}
|
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
2
|
collectNativeKnowledgeChunks
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7SEAZFFB.js";
|
|
4
4
|
import {
|
|
5
|
+
compareEntityTimestamps,
|
|
5
6
|
normalizeEntityName
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-POMSFKTB.js";
|
|
7
8
|
import {
|
|
8
9
|
sanitizeMemoryContent
|
|
9
10
|
} from "./chunk-M62O4P4T.js";
|
|
11
|
+
import {
|
|
12
|
+
normalizeEntityText,
|
|
13
|
+
resolveRequestedEntitySectionKeys
|
|
14
|
+
} from "./chunk-4DJQYKMN.js";
|
|
10
15
|
|
|
11
16
|
// src/entity-retrieval.ts
|
|
12
17
|
import { createHash } from "crypto";
|
|
13
18
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
14
19
|
import path from "path";
|
|
15
|
-
var ENTITY_INDEX_VERSION =
|
|
20
|
+
var ENTITY_INDEX_VERSION = 3;
|
|
16
21
|
var RECENT_TRANSCRIPT_LOOKBACK_HOURS = 24;
|
|
17
22
|
var INSTRUCTION_LIKE_RE = /\b(always|never|must|should|remember to|do not|don't|process|workflow|template|checklist|instruction)\b/i;
|
|
18
23
|
var METADATA_WRAPPER_RE = /^(source|context|metadata|notes?):/i;
|
|
19
24
|
var ENTITY_PRONOUN_RE = /\b(he|him|his|she|her|they|them|their|it|its)\b/i;
|
|
20
|
-
function normalizeText(value) {
|
|
21
|
-
return value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
22
|
-
}
|
|
23
25
|
function tokenize(value) {
|
|
24
|
-
return
|
|
26
|
+
return normalizeEntityText(value).split(/\s+/).filter((token) => token.length >= 2);
|
|
25
27
|
}
|
|
26
28
|
function uniqueStrings(values) {
|
|
27
29
|
return [...new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))];
|
|
@@ -36,18 +38,37 @@ function compactLine(value, maxLength = 220) {
|
|
|
36
38
|
if (normalized.length <= maxLength) return normalized;
|
|
37
39
|
return `${normalized.slice(0, Math.max(0, maxLength - 1)).trimEnd()}\u2026`;
|
|
38
40
|
}
|
|
41
|
+
function dedupeHintSnippetsByText(snippets) {
|
|
42
|
+
const seen = /* @__PURE__ */ new Set();
|
|
43
|
+
const result = [];
|
|
44
|
+
for (const snippet of snippets) {
|
|
45
|
+
const key = normalizeEntityText(snippet.text);
|
|
46
|
+
if (seen.has(key)) continue;
|
|
47
|
+
seen.add(key);
|
|
48
|
+
result.push(snippet);
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
39
52
|
function relationLine(entry, relationship) {
|
|
40
53
|
const normalizedLabel = relationship.label.replace(/\s+/g, " ").trim();
|
|
41
54
|
if (normalizedLabel.length === 0) return `${entry.name} is connected to ${relationship.target}`;
|
|
42
55
|
return `${entry.name} ${normalizedLabel} ${relationship.target}`;
|
|
43
56
|
}
|
|
44
57
|
function detectEntityQueryMode(query) {
|
|
45
|
-
const normalized =
|
|
58
|
+
const normalized = normalizeEntityText(query);
|
|
46
59
|
if (!normalized) return null;
|
|
47
60
|
if (/^(what about|and what about|how about|what happened (with|to) (he|him|his|she|her|they|them|their|it|its)|did (he|she|they|it)|is (he|she|they|it)|was (he|she|they|it))\b/.test(normalized)) {
|
|
48
61
|
return "follow_up";
|
|
49
62
|
}
|
|
50
|
-
if (/^(who is|who s|what do we know about|tell me about|what can you tell me about|what s new with|what happened with|what happened to|status of|where is|how is)\b/.test(normalized)) {
|
|
63
|
+
if (/^(who is|who s|what do we know about|what does|tell me about|what can you tell me about|what s new with|what happened with|what happened to|status of|where is|how is)\b/.test(normalized)) {
|
|
64
|
+
if (/^what does\b/.test(normalized)) {
|
|
65
|
+
if (/^what does (?:this|that|it|the|a|an|my|our|your|their)\b/.test(normalized)) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
if (/^what does [a-z0-9-]+ (?:error|warning|exception|failure|stack|trace|code|message|log)\b/.test(normalized) && /\b(mean|means|indicate|indicates|imply|implies)\b/.test(normalized)) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
51
72
|
return /what happened|what s new|status of|how is|where is/.test(normalized) ? "timeline" : "direct";
|
|
52
73
|
}
|
|
53
74
|
if (ENTITY_PRONOUN_RE.test(normalized) && normalized.split(/\s+/).length <= 8) {
|
|
@@ -56,8 +77,8 @@ function detectEntityQueryMode(query) {
|
|
|
56
77
|
return null;
|
|
57
78
|
}
|
|
58
79
|
function scoreAliasMatch(query, alias) {
|
|
59
|
-
const normalizedQuery =
|
|
60
|
-
const normalizedAlias =
|
|
80
|
+
const normalizedQuery = normalizeEntityText(query);
|
|
81
|
+
const normalizedAlias = normalizeEntityText(alias);
|
|
61
82
|
if (!normalizedAlias) return 0;
|
|
62
83
|
if (normalizedQuery === normalizedAlias) return 10;
|
|
63
84
|
if (containsPhrase(normalizedQuery, normalizedAlias)) return 8 + Math.min(normalizedAlias.split(/\s+/).length, 3);
|
|
@@ -77,6 +98,26 @@ function sanitizeEntityFact(fact) {
|
|
|
77
98
|
if (INSTRUCTION_LIKE_RE.test(clean) && clean.length > 100) return "";
|
|
78
99
|
return clean;
|
|
79
100
|
}
|
|
101
|
+
function scoreHintSnippet(snippet, queryTokens) {
|
|
102
|
+
const normalized = normalizeEntityText(snippet.text);
|
|
103
|
+
if (!normalized) return null;
|
|
104
|
+
const scored = { ...snippet };
|
|
105
|
+
if (isLikelyInstructionLike(scored.text) && scored.kind !== "summary") {
|
|
106
|
+
scored.score -= 3;
|
|
107
|
+
}
|
|
108
|
+
const overlap = queryTokens.filter((token) => normalized.includes(token)).length;
|
|
109
|
+
scored.score += overlap * 2;
|
|
110
|
+
if (METADATA_WRAPPER_RE.test(scored.text)) scored.score -= 2;
|
|
111
|
+
if (scored.text.length <= 160) scored.score += 1;
|
|
112
|
+
return scored.score > 0 ? scored : null;
|
|
113
|
+
}
|
|
114
|
+
function sortTimelineEntriesDesc(left, right) {
|
|
115
|
+
const timestampOrder = compareEntityTimestamps(right.timestamp, left.timestamp);
|
|
116
|
+
if (timestampOrder !== 0) {
|
|
117
|
+
return timestampOrder;
|
|
118
|
+
}
|
|
119
|
+
return right.text.localeCompare(left.text);
|
|
120
|
+
}
|
|
80
121
|
function jaccardSimilarity(a, b) {
|
|
81
122
|
const aTokens = new Set(tokenize(a));
|
|
82
123
|
const bTokens = new Set(tokenize(b));
|
|
@@ -91,7 +132,7 @@ function jaccardSimilarity(a, b) {
|
|
|
91
132
|
function buildAliasIndex(entries) {
|
|
92
133
|
const index = /* @__PURE__ */ new Map();
|
|
93
134
|
for (const entry of entries) {
|
|
94
|
-
const aliases = uniqueStrings([entry.name, ...entry.aliases]).map(
|
|
135
|
+
const aliases = uniqueStrings([entry.name, ...entry.aliases]).map(normalizeEntityText).filter(Boolean);
|
|
95
136
|
for (const alias of aliases) {
|
|
96
137
|
const existing = index.get(alias) ?? [];
|
|
97
138
|
existing.push(entry);
|
|
@@ -143,6 +184,9 @@ function createPseudoNativeEntry(chunk) {
|
|
|
143
184
|
type: chunk.sourceKind,
|
|
144
185
|
aliases: uniqueStrings(chunk.aliases ?? []),
|
|
145
186
|
facts: [],
|
|
187
|
+
structuredSections: [],
|
|
188
|
+
timelineFacts: [],
|
|
189
|
+
timeline: [],
|
|
146
190
|
relationships: [],
|
|
147
191
|
activity: [],
|
|
148
192
|
factCount: 0,
|
|
@@ -183,13 +227,21 @@ async function buildEntityMentionIndex(storage, config, recallNamespaces) {
|
|
|
183
227
|
for (const entity of entityFiles) {
|
|
184
228
|
const canonicalId = normalizeEntityName(entity.name, entity.type);
|
|
185
229
|
const sanitizedFacts = entity.facts.map((fact) => sanitizeEntityFact(fact)).filter(Boolean).map((fact) => compactLine(fact, 180));
|
|
230
|
+
const sanitizedTimelineFacts = entity.timeline.map((entry) => sanitizeEntityFact(entry.text)).filter(Boolean).map((fact) => compactLine(fact, 180));
|
|
186
231
|
entities.set(canonicalId, {
|
|
187
232
|
canonicalId,
|
|
188
233
|
name: entity.name,
|
|
189
234
|
type: entity.type,
|
|
190
235
|
aliases: uniqueStrings(entity.aliases),
|
|
191
|
-
summary: entity.summary,
|
|
236
|
+
summary: entity.synthesis?.trim() || entity.summary?.trim() || void 0,
|
|
192
237
|
facts: sanitizedFacts,
|
|
238
|
+
timelineFacts: uniqueStrings(sanitizedTimelineFacts),
|
|
239
|
+
structuredSections: (entity.structuredSections ?? []).map((section) => ({
|
|
240
|
+
key: section.key,
|
|
241
|
+
title: section.title,
|
|
242
|
+
facts: section.facts.map((fact) => sanitizeEntityFact(fact)).filter(Boolean).map((fact) => compactLine(fact, 180))
|
|
243
|
+
})).filter((section) => section.facts.length > 0),
|
|
244
|
+
timeline: entity.timeline.map((entry) => ({ ...entry })),
|
|
193
245
|
relationships: entity.relationships.map((relationship) => ({ ...relationship })),
|
|
194
246
|
activity: entity.activity.map((activity) => ({ ...activity })),
|
|
195
247
|
factCount: sanitizedFacts.length,
|
|
@@ -214,7 +266,7 @@ async function buildEntityMentionIndex(storage, config, recallNamespaces) {
|
|
|
214
266
|
mergeNativeChunk(existingPseudo, chunk);
|
|
215
267
|
continue;
|
|
216
268
|
}
|
|
217
|
-
const candidateAliases = uniqueStrings([chunk.title, ...chunk.aliases ?? []]).map(
|
|
269
|
+
const candidateAliases = uniqueStrings([chunk.title, ...chunk.aliases ?? []]).map(normalizeEntityText).filter(Boolean);
|
|
218
270
|
let matched = false;
|
|
219
271
|
for (const alias of candidateAliases) {
|
|
220
272
|
for (const entry of aliasIndex.get(alias) ?? []) {
|
|
@@ -287,60 +339,86 @@ async function readMemorySnippet(memory) {
|
|
|
287
339
|
const content = memory.content.replace(/\s+/g, " ").trim();
|
|
288
340
|
return compactLine(content, 180);
|
|
289
341
|
}
|
|
290
|
-
async function buildHintSnippets(entry, queryTokens, mode, maxSupportingFacts) {
|
|
342
|
+
async function buildHintSnippets(entry, queryTokens, mode, maxSupportingFacts, requestedSectionKeys) {
|
|
291
343
|
const snippets = [];
|
|
344
|
+
const aliasTokens = new Set(tokenize(uniqueStrings([entry.name, ...entry.aliases]).join(" ")));
|
|
292
345
|
if (entry.summary) {
|
|
293
346
|
snippets.push({ text: compactLine(entry.summary, 180), score: 10, kind: "summary" });
|
|
294
347
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
348
|
+
if (requestedSectionKeys.size > 0) {
|
|
349
|
+
for (const section of entry.structuredSections) {
|
|
350
|
+
if (!requestedSectionKeys.has(normalizeEntityText(section.key).replace(/\s+/g, "_"))) continue;
|
|
351
|
+
for (const fact of section.facts) {
|
|
352
|
+
snippets.push({ text: fact, score: mode === "direct" ? 8 : 9, kind: "section" });
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
} else {
|
|
356
|
+
for (const fact of entry.timelineFacts) {
|
|
357
|
+
snippets.push({ text: fact, score: mode === "direct" ? 6 : 7, kind: "fact" });
|
|
358
|
+
}
|
|
359
|
+
for (const section of entry.structuredSections) {
|
|
360
|
+
for (const fact of section.facts) {
|
|
361
|
+
const normalizedFact = normalizeEntityText(fact);
|
|
362
|
+
const hasNonAliasQueryOverlap = queryTokens.some(
|
|
363
|
+
(token) => !aliasTokens.has(token) && normalizedFact.includes(token)
|
|
364
|
+
);
|
|
365
|
+
if (entry.timelineFacts.length > 0 && !hasNonAliasQueryOverlap) {
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
snippets.push({ text: fact, score: mode === "direct" ? 6 : 7, kind: "fact" });
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (entry.timelineFacts.length === 0 && entry.structuredSections.length === 0) {
|
|
372
|
+
for (const fact of entry.facts) {
|
|
373
|
+
if (!fact.trim()) continue;
|
|
374
|
+
snippets.push({ text: fact, score: mode === "direct" ? 6 : 7, kind: "fact" });
|
|
375
|
+
}
|
|
376
|
+
}
|
|
318
377
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
378
|
+
if (requestedSectionKeys.size === 0) {
|
|
379
|
+
for (const relationship of entry.relationships) {
|
|
380
|
+
snippets.push({
|
|
381
|
+
text: compactLine(relationLine(entry, relationship), 180),
|
|
382
|
+
score: mode === "direct" && entry.type.toLowerCase() === "person" ? 6 : 4,
|
|
383
|
+
kind: "relationship"
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
for (const activity of entry.activity) {
|
|
387
|
+
snippets.push({
|
|
388
|
+
text: compactLine(`${activity.date}: ${activity.note}`, 180),
|
|
389
|
+
score: 4,
|
|
390
|
+
kind: "activity"
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
for (const memorySnippet of entry.memorySnippets.slice(0, Math.min(maxSupportingFacts, 4))) {
|
|
394
|
+
snippets.push({
|
|
395
|
+
text: memorySnippet,
|
|
396
|
+
score: 5,
|
|
397
|
+
kind: "memory"
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
for (const chunk of entry.nativeChunks) {
|
|
401
|
+
snippets.push({
|
|
402
|
+
text: compactLine(chunk.snippet, 180),
|
|
403
|
+
score: 3,
|
|
404
|
+
kind: "native"
|
|
405
|
+
});
|
|
406
|
+
}
|
|
325
407
|
}
|
|
326
408
|
const deduped = /* @__PURE__ */ new Map();
|
|
327
409
|
for (const snippet of snippets) {
|
|
328
|
-
const
|
|
329
|
-
if (!
|
|
330
|
-
|
|
331
|
-
snippet.score -= 3;
|
|
332
|
-
}
|
|
333
|
-
const overlap = queryTokens.filter((token) => normalizeText(snippet.text).includes(token)).length;
|
|
334
|
-
snippet.score += overlap * 2;
|
|
335
|
-
if (METADATA_WRAPPER_RE.test(snippet.text)) snippet.score -= 2;
|
|
336
|
-
if (snippet.text.length <= 160) snippet.score += 1;
|
|
410
|
+
const scored = scoreHintSnippet(snippet, queryTokens);
|
|
411
|
+
if (!scored) continue;
|
|
412
|
+
const normalized = normalizeEntityText(scored.text);
|
|
337
413
|
const existing = deduped.get(normalized);
|
|
338
|
-
if (!existing ||
|
|
414
|
+
if (!existing || scored.score > existing.score) deduped.set(normalized, scored);
|
|
339
415
|
}
|
|
340
416
|
return [...deduped.values()].filter((snippet) => snippet.score > 0).sort((left, right) => right.score - left.score).slice(0, maxSupportingFacts);
|
|
341
417
|
}
|
|
342
418
|
function summarizeUncertainty(snippets) {
|
|
343
|
-
const direct = snippets.filter(
|
|
419
|
+
const direct = snippets.filter(
|
|
420
|
+
(snippet) => snippet.kind === "summary" || snippet.kind === "fact" || snippet.kind === "section" || snippet.kind === "memory"
|
|
421
|
+
);
|
|
344
422
|
if (direct.length < 2) return null;
|
|
345
423
|
for (let index = 0; index < direct.length; index += 1) {
|
|
346
424
|
for (let compare = index + 1; compare < direct.length; compare += 1) {
|
|
@@ -351,12 +429,36 @@ function summarizeUncertainty(snippets) {
|
|
|
351
429
|
}
|
|
352
430
|
return null;
|
|
353
431
|
}
|
|
354
|
-
function formatEntityHintSection(candidates, mode, maxRelatedEntities, maxChars) {
|
|
432
|
+
function formatEntityHintSection(candidates, queryTokens, mode, maxRelatedEntities, maxChars) {
|
|
355
433
|
if (candidates.length === 0) return null;
|
|
356
434
|
const lines = ["## entity_answer_hints", ""];
|
|
357
435
|
for (const { candidate, snippets, uncertainty } of candidates) {
|
|
358
|
-
const
|
|
359
|
-
const
|
|
436
|
+
const hasSummary = Boolean(candidate.entry.summary?.trim());
|
|
437
|
+
const preferredTopSnippets = hasSummary ? snippets.filter((snippet) => snippet.kind !== "fact") : snippets;
|
|
438
|
+
let topSnippets = (preferredTopSnippets.length > 0 ? preferredTopSnippets : snippets).slice(0, 3);
|
|
439
|
+
const buildTimelineSnippets = (seedExcludedTexts) => {
|
|
440
|
+
const explicitTimelinePool = dedupeHintSnippetsByText(
|
|
441
|
+
(candidate.entry.timeline ?? []).slice().sort(sortTimelineEntriesDesc).map((entry) => sanitizeEntityFact(entry.text)).filter(Boolean).map((text) => scoreHintSnippet({
|
|
442
|
+
text: compactLine(text, 180),
|
|
443
|
+
score: 7,
|
|
444
|
+
kind: "activity"
|
|
445
|
+
}, queryTokens)).filter((snippet) => snippet !== null).filter((snippet) => !seedExcludedTexts.has(normalizeEntityText(snippet.text)))
|
|
446
|
+
).slice(0, 2);
|
|
447
|
+
const activityTimelinePool = dedupeHintSnippetsByText(
|
|
448
|
+
snippets.filter((snippet) => (snippet.kind === "activity" || snippet.kind === "memory") && !seedExcludedTexts.has(normalizeEntityText(snippet.text)))
|
|
449
|
+
).slice(0, 2);
|
|
450
|
+
return explicitTimelinePool.length > 0 ? explicitTimelinePool : activityTimelinePool.length > 0 ? activityTimelinePool : dedupeHintSnippetsByText(
|
|
451
|
+
snippets.filter((snippet) => (snippet.kind === "fact" || snippet.kind === "summary") && !seedExcludedTexts.has(normalizeEntityText(snippet.text)))
|
|
452
|
+
).slice(0, 2);
|
|
453
|
+
};
|
|
454
|
+
const baseTopSnippetTexts = new Set(topSnippets.map((snippet) => normalizeEntityText(snippet.text)));
|
|
455
|
+
const timelinePool = mode !== "direct" ? buildTimelineSnippets(baseTopSnippetTexts) : [];
|
|
456
|
+
if (mode !== "direct" && hasSummary && topSnippets.length < 2) {
|
|
457
|
+
if (timelinePool.length > 0) {
|
|
458
|
+
topSnippets = [...topSnippets, timelinePool[0]].slice(0, 3);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
const topSnippetTexts = new Set(topSnippets.map((snippet) => normalizeEntityText(snippet.text)));
|
|
360
462
|
lines.push(`- target: ${candidate.entry.name} (${candidate.entry.type})`);
|
|
361
463
|
if (candidate.source === "recent_turn") {
|
|
362
464
|
lines.push(`- resolution: carried forward from recent turns via alias "${candidate.alias}"`);
|
|
@@ -371,8 +473,9 @@ function formatEntityHintSection(candidates, mode, maxRelatedEntities, maxChars)
|
|
|
371
473
|
}
|
|
372
474
|
}
|
|
373
475
|
if (mode !== "direct") {
|
|
374
|
-
const
|
|
375
|
-
|
|
476
|
+
const fallbackTimeline = timelinePool.filter(
|
|
477
|
+
(snippet) => !topSnippetTexts.has(normalizeEntityText(snippet.text))
|
|
478
|
+
);
|
|
376
479
|
if (fallbackTimeline.length > 0) {
|
|
377
480
|
lines.push("- recent timeline:");
|
|
378
481
|
for (const snippet of fallbackTimeline) {
|
|
@@ -409,11 +512,20 @@ async function buildEntityRecallSection(options) {
|
|
|
409
512
|
const rankedCandidates = candidates.slice(0, candidateLimit);
|
|
410
513
|
const enriched = await Promise.all(
|
|
411
514
|
rankedCandidates.map(async (candidate) => {
|
|
515
|
+
const requestedSectionKeys = new Set(
|
|
516
|
+
resolveRequestedEntitySectionKeys(
|
|
517
|
+
options.query,
|
|
518
|
+
candidate.entry.type,
|
|
519
|
+
candidate.entry.structuredSections,
|
|
520
|
+
options.config.entitySchemas
|
|
521
|
+
)
|
|
522
|
+
);
|
|
412
523
|
const snippets = await buildHintSnippets(
|
|
413
524
|
candidate.entry,
|
|
414
525
|
queryTokens,
|
|
415
526
|
mode,
|
|
416
|
-
options.maxSupportingFacts
|
|
527
|
+
options.maxSupportingFacts,
|
|
528
|
+
requestedSectionKeys
|
|
417
529
|
);
|
|
418
530
|
return {
|
|
419
531
|
candidate,
|
|
@@ -422,7 +534,7 @@ async function buildEntityRecallSection(options) {
|
|
|
422
534
|
};
|
|
423
535
|
})
|
|
424
536
|
);
|
|
425
|
-
const section = formatEntityHintSection(enriched, mode, options.maxRelatedEntities, options.maxChars);
|
|
537
|
+
const section = formatEntityHintSection(enriched, queryTokens, mode, options.maxRelatedEntities, options.maxChars);
|
|
426
538
|
if (!section) return null;
|
|
427
539
|
return section;
|
|
428
540
|
}
|
|
@@ -441,4 +553,4 @@ export {
|
|
|
441
553
|
entityIndexVersion,
|
|
442
554
|
entityRecentTranscriptLookbackHours
|
|
443
555
|
};
|
|
444
|
-
//# sourceMappingURL=chunk-
|
|
556
|
+
//# sourceMappingURL=chunk-74JR4N5J.js.map
|