@remnic/core 9.57.6 → 9.58.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-admin-ops-surface.d.ts +12 -11
- package/dist/access-admin-ops-surface.js +25 -24
- package/dist/access-authorization-probe.d.ts +12 -11
- package/dist/access-authorization-probe.js +26 -25
- package/dist/access-boundary.d.ts +12 -11
- package/dist/access-boundary.js +25 -24
- package/dist/access-cli.js +77 -76
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.d.ts +1 -1
- package/dist/access-extraction-force-flush.d.ts +12 -11
- package/dist/access-extraction-force-flush.js +25 -24
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +12 -11
- package/dist/access-http-lifecycle-flush.d.ts +12 -11
- package/dist/access-http-offline-stream.d.ts +12 -11
- package/dist/access-http-query.js +25 -24
- package/dist/access-http.d.ts +13 -12
- package/dist/access-http.js +36 -35
- package/dist/access-identity-continuity-surface.d.ts +10 -9
- package/dist/access-identity-continuity-surface.js +25 -24
- package/dist/access-lcm-surface.d.ts +12 -11
- package/dist/access-lcm-surface.js +25 -24
- package/dist/access-mcp.d.ts +12 -11
- package/dist/access-mcp.js +32 -31
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-Bpt-SYP0.d.ts → access-namespace-preflight-TBXz-8s_.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +25 -24
- package/dist/access-observe-write-surface.d.ts +12 -11
- package/dist/access-observe-write-surface.js +25 -24
- package/dist/access-offline-manifest.d.ts +10 -9
- package/dist/access-operations-batch.js +27 -26
- package/dist/access-operations.d.ts +15 -14
- package/dist/access-operations.js +31 -30
- package/dist/access-recall-concurrency.d.ts +12 -11
- package/dist/access-recall-concurrency.js +25 -24
- package/dist/access-recall-response.d.ts +12 -11
- package/dist/access-recall-response.js +25 -24
- package/dist/access-recall-surface.d.ts +12 -11
- package/dist/access-recall-surface.js +25 -24
- package/dist/access-schema.d.ts +88 -88
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-4DO8XMq6.d.ts → access-service-BogiG4Dy.d.ts} +71 -71
- package/dist/access-service-helpers.d.ts +12 -11
- package/dist/access-service.d.ts +12 -11
- package/dist/access-service.js +25 -24
- package/dist/access-surface-catalog.d.ts +12 -11
- package/dist/access-surface-catalog.js +27 -26
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +3 -3
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +1 -1
- package/dist/ambient-provenance.d.ts +1 -1
- package/dist/artifact-search.d.ts +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +10 -9
- package/dist/briefing-window.d.ts +2 -2
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +10 -10
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-surprise.js +4 -3
- package/dist/buffer-turn-helpers.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-GWVG7LGC.js} +2 -2
- package/dist/{catalog-BasnO3Bw.d.ts → catalog-z1UerMbh.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +2 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +14 -13
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-P6WBAR27.js → chunk-2GBFKHBZ.js} +9 -9
- package/dist/chunk-2GBFKHBZ.js.map +1 -0
- package/dist/{chunk-YTZA7U6Q.js → chunk-2VHCLHZ5.js} +3 -3
- package/dist/{chunk-NEJQ65NV.js → chunk-4CLE2LXB.js} +2 -2
- package/dist/{chunk-3VFVQDZO.js → chunk-4IIKJOYM.js} +1 -1
- package/dist/{chunk-3VFVQDZO.js.map → chunk-4IIKJOYM.js.map} +1 -1
- package/dist/{chunk-JLNBQWZ2.js → chunk-5JMAGU26.js} +7 -6
- package/dist/{chunk-JLNBQWZ2.js.map → chunk-5JMAGU26.js.map} +1 -1
- package/dist/{chunk-VDX2J7OX.js → chunk-5W7CTZ2E.js} +4 -4
- package/dist/{chunk-CZUHNJHX.js → chunk-6C7Q6NG3.js} +13 -13
- package/dist/{chunk-LMXUWAXW.js → chunk-6TBIWIAG.js} +9 -8
- package/dist/chunk-6TBIWIAG.js.map +1 -0
- package/dist/{chunk-4O6R3GPK.js → chunk-6W2ISYUV.js} +4 -4
- package/dist/{chunk-3AJOJOFP.js → chunk-77DAFTUU.js} +3 -3
- package/dist/{chunk-IKT6ZVO7.js → chunk-7DHFB5SG.js} +3 -3
- package/dist/{chunk-SFR7J2G6.js → chunk-7G34CBKS.js} +2 -2
- package/dist/{chunk-IT57AOMC.js → chunk-AH2NX6S7.js} +3 -3
- package/dist/{chunk-HYQJQGD3.js → chunk-AM4T6CHX.js} +49 -35
- package/dist/chunk-AM4T6CHX.js.map +1 -0
- package/dist/{chunk-Z54EM5YZ.js → chunk-B2QHVLJO.js} +60 -30
- package/dist/chunk-B2QHVLJO.js.map +1 -0
- package/dist/{chunk-FI3PIOOI.js → chunk-B4CSPFYN.js} +8 -8
- package/dist/{chunk-7PJARJS4.js → chunk-BPM6UHUL.js} +2 -2
- package/dist/{chunk-PPUTUOC3.js → chunk-BTHDQOF4.js} +5 -5
- package/dist/{chunk-DUHMYBVE.js → chunk-CZGOLAEW.js} +41 -41
- package/dist/{chunk-5PGYCWA7.js → chunk-DE6YCZEE.js} +2 -2
- package/dist/{chunk-JOA4Q765.js → chunk-EUYWQ7TS.js} +2 -2
- package/dist/{chunk-O5AFC5KM.js → chunk-EWL5DICB.js} +2 -2
- package/dist/{chunk-4YZCIK5E.js → chunk-EZXGJJXM.js} +2 -2
- package/dist/{chunk-GXIY65UH.js → chunk-FI5EAP4N.js} +2 -2
- package/dist/{chunk-YOKSRIFI.js → chunk-FUWS2MNJ.js} +4 -4
- package/dist/{chunk-6RK2X7BR.js → chunk-G3JFFUKR.js} +2 -2
- package/dist/{chunk-VANZKHTN.js → chunk-G5OB4XZX.js} +4 -4
- package/dist/{chunk-TEHPIMXD.js → chunk-HK6KYIF6.js} +2 -2
- package/dist/{chunk-XBGLEOID.js → chunk-I4BLRM7X.js} +9 -9
- package/dist/{chunk-5ZIWRMZM.js → chunk-IVKIODHO.js} +7 -6
- package/dist/chunk-IVKIODHO.js.map +1 -0
- package/dist/{chunk-6SX4MY5Q.js → chunk-J65AKOD6.js} +2 -2
- package/dist/{chunk-BPWZDHFM.js → chunk-J6QIAYNR.js} +2 -2
- package/dist/{chunk-XL3TATMJ.js → chunk-JHMAYABJ.js} +4 -4
- package/dist/{chunk-F7M36OG2.js → chunk-JNWISMYG.js} +10 -10
- package/dist/{chunk-VYIXCMUP.js → chunk-KBIIE57I.js} +3 -3
- package/dist/{chunk-QKPDN325.js → chunk-KF75ANST.js} +6 -3
- package/dist/chunk-KF75ANST.js.map +1 -0
- package/dist/{chunk-24PNX2GF.js → chunk-KXYMU4IN.js} +3 -3
- package/dist/{chunk-FKTD7IVS.js → chunk-L3JVAM5Q.js} +2 -2
- package/dist/{chunk-5QHDXMXP.js → chunk-LLZKOSGM.js} +1 -1
- package/dist/{chunk-5QHDXMXP.js.map → chunk-LLZKOSGM.js.map} +1 -1
- package/dist/{chunk-LIF6DO6U.js → chunk-MG7GI4TT.js} +2 -2
- package/dist/{chunk-RUZM6Z52.js → chunk-MMZK2DWN.js} +1 -1
- package/dist/{chunk-NTJ6TY44.js → chunk-ODAE36PG.js} +3 -3
- package/dist/{chunk-QFN4U7AG.js → chunk-ODZKV2F7.js} +3 -3
- package/dist/{chunk-QFN4U7AG.js.map → chunk-ODZKV2F7.js.map} +1 -1
- package/dist/{chunk-YLHM5BQQ.js → chunk-OLX2HJFW.js} +4 -4
- package/dist/{chunk-DNC4A7RS.js → chunk-OU7RWWW6.js} +2 -2
- package/dist/{chunk-L3LRWDJW.js → chunk-OV36CROW.js} +3 -3
- package/dist/{chunk-BXLOS5AJ.js → chunk-OWHERGF2.js} +2 -2
- package/dist/{chunk-CSV34HIW.js → chunk-P5OYNV7B.js} +2 -2
- package/dist/{chunk-SNW3YRO6.js → chunk-P6GOYLHN.js} +2 -2
- package/dist/{chunk-REVMY7RA.js → chunk-PFPNUFKZ.js} +109 -59
- package/dist/chunk-PFPNUFKZ.js.map +1 -0
- package/dist/{chunk-USGKHF36.js → chunk-QUJC22CT.js} +2 -2
- package/dist/{chunk-BVRREV3N.js → chunk-R7IV3EUJ.js} +2 -2
- package/dist/{chunk-KSXJOC4F.js → chunk-RDFF2NAU.js} +18 -8
- package/dist/chunk-RDFF2NAU.js.map +1 -0
- package/dist/{chunk-D4LVHPOA.js → chunk-RXN7Z2V5.js} +3 -3
- package/dist/{chunk-7VSHDLJQ.js → chunk-T2VJ2EO5.js} +6 -6
- package/dist/chunk-TOTT6S2V.js +20 -0
- package/dist/chunk-TOTT6S2V.js.map +1 -0
- package/dist/{chunk-U7BMN33M.js → chunk-UBSM6TZP.js} +2 -2
- package/dist/{chunk-DQEMWVMT.js → chunk-UVYI6VIX.js} +1 -1
- package/dist/{chunk-U7XLOSG2.js → chunk-VIM6QH4D.js} +2 -2
- package/dist/{chunk-LJJWFV2Q.js → chunk-VJXSAJFW.js} +2 -2
- package/dist/{chunk-HZC3OECF.js → chunk-VOKK4WCG.js} +2 -2
- package/dist/{chunk-LTAVSOZW.js → chunk-WVP2I6C5.js} +5 -4
- package/dist/chunk-WVP2I6C5.js.map +1 -0
- package/dist/{chunk-LRDP2AC2.js → chunk-YBCZTBN2.js} +2 -2
- package/dist/{chunk-USAUBGBC.js → chunk-YKZFX2HQ.js} +2 -2
- package/dist/{chunk-I2GIYTRU.js → chunk-ZOGOOSB3.js} +2 -2
- package/dist/{chunk-PBGWYM3H.js → chunk-ZPUIRTIZ.js} +27 -15
- package/dist/chunk-ZPUIRTIZ.js.map +1 -0
- package/dist/chunking.js +2 -1
- package/dist/{cli-CQdYilcx.d.ts → cli-CTgFjmDs.d.ts} +5 -5
- package/dist/cli.d.ts +14 -13
- package/dist/cli.js +57 -56
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +10 -10
- package/dist/compounding/preference-consolidator.d.ts +2 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +12 -11
- package/dist/connectors/codex-materialize.d.ts +7 -12
- package/dist/connectors/codex-materialize.js +2 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +12 -11
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/contradiction/index.js +4 -4
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +12 -12
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/corpus-watermark.d.ts +1 -1
- package/dist/corpus-watermark.js +12 -12
- package/dist/day-summary.d.ts +1 -1
- package/dist/day-summary.js +3 -2
- package/dist/delinearize.d.ts +1 -1
- package/dist/dependency-propagation-config.d.ts +1 -1
- package/dist/{dependency-propagation-delivery-C_K_AHcv.d.ts → dependency-propagation-delivery-DdwSc1qh.d.ts} +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +10 -10
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +10 -9
- package/dist/external-wiki-access.d.ts +12 -11
- package/dist/external-wiki-access.js +26 -25
- package/dist/external-wiki-collection-registration.d.ts +1 -1
- package/dist/external-wiki-collection.d.ts +1 -1
- package/dist/external-wiki-mcp-tools.d.ts +12 -11
- package/dist/extraction-error-classification.d.ts +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction-liveness.d.ts +1 -1
- package/dist/extraction-normalization.d.ts +1 -1
- package/dist/extraction-prompt.d.ts +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +16 -15
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-path-reconstruction.d.ts +1 -1
- package/dist/graph-path-scoring.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/index.d.ts +698 -697
- package/dist/index.js +81 -80
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/archive.d.ts +3 -2
- package/dist/lcm/archive.js +2 -1
- package/dist/lcm/engine.d.ts +2 -1
- package/dist/lcm/engine.js +5 -4
- package/dist/lcm/index.d.ts +2 -1
- package/dist/lcm/index.js +7 -6
- package/dist/lcm/recall.d.ts +1 -0
- package/dist/lcm/summarizer.d.ts +1 -0
- package/dist/lcm/summarizer.js +3 -2
- package/dist/lcm/tools.d.ts +2 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +2 -3
- package/dist/local-llm.js +2 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +10 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +11 -11
- package/dist/{maintenance-DdP931i9.d.ts → maintenance-DvkiF7fm.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +12 -11
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-snapshot.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +11 -11
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +7 -7
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +10 -10
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +13 -13
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +18 -18
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +15 -15
- package/dist/{orchestrator-DxUWX7gs.d.ts → orchestrator-CXPIzs3D.d.ts} +9 -9
- package/dist/orchestrator.d.ts +10 -9
- package/dist/orchestrator.js +77 -76
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-BKUMU1vU.d.ts → pipeline-BuYWU9rt.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{public-http-Dw0bJhcC.d.ts → public-http-CEwDOGO7.d.ts} +1 -1
- package/dist/{qmd-DJP-GLFe.d.ts → qmd-DYnrPw-m.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +2 -2
- package/dist/recall-concurrency-config.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +4 -3
- package/dist/recall-memory-map.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +5 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +4 -3
- package/dist/recall-xray.d.ts +2 -7
- package/dist/recall-xray.js +3 -2
- package/dist/reconcile/cursor.d.ts +1 -1
- package/dist/reconcile/manifest.d.ts +1 -1
- package/dist/reconcile/plan.d.ts +1 -1
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/replica-divergence.d.ts +1 -1
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +4 -3
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/salvage-envelope.d.ts +1 -1
- package/dist/schemas.d.ts +138 -138
- package/dist/{scope-profiles-CaKcnB-6.d.ts → scope-profiles-C1QG4Cmv.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +6 -6
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +11 -11
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/orama-backend.js +2 -2
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/semantic-chunking.js +3 -2
- package/dist/{semantic-consolidation-P0eMWqh-.d.ts → semantic-consolidation-DMeX8XS0.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +14 -13
- package/dist/semantic-rule-promotion.js +10 -10
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +10 -10
- package/dist/{service-D5GQLxq_.d.ts → service-CT3ENiTO.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/session-observer-state.js +1 -1
- package/dist/shared-context/manager.d.ts +9 -9
- package/dist/signal.d.ts +1 -1
- package/dist/source-agent-qualifier.d.ts +1 -1
- package/dist/source-agent-qualifier.js +12 -11
- package/dist/{storage-DIyil2ll.d.ts → storage-B0L76y7N.d.ts} +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +9 -9
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +3 -2
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/support-passport/index.d.ts +15 -14
- package/dist/support-passport/index.js +28 -27
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-timeline-recall.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/token-estimate.d.ts +10 -0
- package/dist/token-estimate.js +8 -0
- package/dist/token-estimate.js.map +1 -0
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -6
- package/dist/transcript.js +2 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/transfer/types.d.ts +66 -66
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-CbXieHKr.d.ts → types-D7pB0QwO.d.ts} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +10 -10
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +12 -2
- package/src/chunking.ts +6 -12
- package/src/config.ts +2 -0
- package/src/connectors/codex-materialize.ts +21 -26
- package/src/lcm/archive.ts +4 -5
- package/src/lcm/engine.ts +55 -34
- package/src/lcm/summarizer.ts +27 -16
- package/src/lcm-engine.test.ts +82 -2
- package/src/local-llm.ts +4 -6
- package/src/memory-extension-host/render-extensions-block.ts +3 -9
- package/src/orchestration/recall-section-coordinator.ts +93 -27
- package/src/recall-token-budget.test.ts +51 -0
- package/src/recall-xray.ts +4 -11
- package/src/semantic-chunking.ts +5 -12
- package/src/session-observer-state.ts +3 -3
- package/src/testing/subjects/recall-budget.test.ts +21 -5
- package/src/token-estimate.test.ts +38 -0
- package/src/token-estimate.ts +22 -0
- package/src/transcript.test.ts +38 -3
- package/src/transcript.ts +58 -59
- package/src/types.ts +1 -1
- package/dist/chunk-5ZIWRMZM.js.map +0 -1
- package/dist/chunk-HYQJQGD3.js.map +0 -1
- package/dist/chunk-KSXJOC4F.js.map +0 -1
- package/dist/chunk-LMXUWAXW.js.map +0 -1
- package/dist/chunk-LTAVSOZW.js.map +0 -1
- package/dist/chunk-P6WBAR27.js.map +0 -1
- package/dist/chunk-PBGWYM3H.js.map +0 -1
- package/dist/chunk-QKPDN325.js.map +0 -1
- package/dist/chunk-REVMY7RA.js.map +0 -1
- package/dist/chunk-Z54EM5YZ.js.map +0 -1
- /package/dist/{capsule-crypto-YO5QJ6L3.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
- /package/dist/{chunk-YTZA7U6Q.js.map → chunk-2VHCLHZ5.js.map} +0 -0
- /package/dist/{chunk-NEJQ65NV.js.map → chunk-4CLE2LXB.js.map} +0 -0
- /package/dist/{chunk-VDX2J7OX.js.map → chunk-5W7CTZ2E.js.map} +0 -0
- /package/dist/{chunk-CZUHNJHX.js.map → chunk-6C7Q6NG3.js.map} +0 -0
- /package/dist/{chunk-4O6R3GPK.js.map → chunk-6W2ISYUV.js.map} +0 -0
- /package/dist/{chunk-3AJOJOFP.js.map → chunk-77DAFTUU.js.map} +0 -0
- /package/dist/{chunk-IKT6ZVO7.js.map → chunk-7DHFB5SG.js.map} +0 -0
- /package/dist/{chunk-SFR7J2G6.js.map → chunk-7G34CBKS.js.map} +0 -0
- /package/dist/{chunk-IT57AOMC.js.map → chunk-AH2NX6S7.js.map} +0 -0
- /package/dist/{chunk-FI3PIOOI.js.map → chunk-B4CSPFYN.js.map} +0 -0
- /package/dist/{chunk-7PJARJS4.js.map → chunk-BPM6UHUL.js.map} +0 -0
- /package/dist/{chunk-PPUTUOC3.js.map → chunk-BTHDQOF4.js.map} +0 -0
- /package/dist/{chunk-DUHMYBVE.js.map → chunk-CZGOLAEW.js.map} +0 -0
- /package/dist/{chunk-5PGYCWA7.js.map → chunk-DE6YCZEE.js.map} +0 -0
- /package/dist/{chunk-JOA4Q765.js.map → chunk-EUYWQ7TS.js.map} +0 -0
- /package/dist/{chunk-O5AFC5KM.js.map → chunk-EWL5DICB.js.map} +0 -0
- /package/dist/{chunk-4YZCIK5E.js.map → chunk-EZXGJJXM.js.map} +0 -0
- /package/dist/{chunk-GXIY65UH.js.map → chunk-FI5EAP4N.js.map} +0 -0
- /package/dist/{chunk-YOKSRIFI.js.map → chunk-FUWS2MNJ.js.map} +0 -0
- /package/dist/{chunk-6RK2X7BR.js.map → chunk-G3JFFUKR.js.map} +0 -0
- /package/dist/{chunk-VANZKHTN.js.map → chunk-G5OB4XZX.js.map} +0 -0
- /package/dist/{chunk-TEHPIMXD.js.map → chunk-HK6KYIF6.js.map} +0 -0
- /package/dist/{chunk-XBGLEOID.js.map → chunk-I4BLRM7X.js.map} +0 -0
- /package/dist/{chunk-6SX4MY5Q.js.map → chunk-J65AKOD6.js.map} +0 -0
- /package/dist/{chunk-BPWZDHFM.js.map → chunk-J6QIAYNR.js.map} +0 -0
- /package/dist/{chunk-XL3TATMJ.js.map → chunk-JHMAYABJ.js.map} +0 -0
- /package/dist/{chunk-F7M36OG2.js.map → chunk-JNWISMYG.js.map} +0 -0
- /package/dist/{chunk-VYIXCMUP.js.map → chunk-KBIIE57I.js.map} +0 -0
- /package/dist/{chunk-24PNX2GF.js.map → chunk-KXYMU4IN.js.map} +0 -0
- /package/dist/{chunk-FKTD7IVS.js.map → chunk-L3JVAM5Q.js.map} +0 -0
- /package/dist/{chunk-LIF6DO6U.js.map → chunk-MG7GI4TT.js.map} +0 -0
- /package/dist/{chunk-RUZM6Z52.js.map → chunk-MMZK2DWN.js.map} +0 -0
- /package/dist/{chunk-NTJ6TY44.js.map → chunk-ODAE36PG.js.map} +0 -0
- /package/dist/{chunk-YLHM5BQQ.js.map → chunk-OLX2HJFW.js.map} +0 -0
- /package/dist/{chunk-DNC4A7RS.js.map → chunk-OU7RWWW6.js.map} +0 -0
- /package/dist/{chunk-L3LRWDJW.js.map → chunk-OV36CROW.js.map} +0 -0
- /package/dist/{chunk-BXLOS5AJ.js.map → chunk-OWHERGF2.js.map} +0 -0
- /package/dist/{chunk-CSV34HIW.js.map → chunk-P5OYNV7B.js.map} +0 -0
- /package/dist/{chunk-SNW3YRO6.js.map → chunk-P6GOYLHN.js.map} +0 -0
- /package/dist/{chunk-USGKHF36.js.map → chunk-QUJC22CT.js.map} +0 -0
- /package/dist/{chunk-BVRREV3N.js.map → chunk-R7IV3EUJ.js.map} +0 -0
- /package/dist/{chunk-D4LVHPOA.js.map → chunk-RXN7Z2V5.js.map} +0 -0
- /package/dist/{chunk-7VSHDLJQ.js.map → chunk-T2VJ2EO5.js.map} +0 -0
- /package/dist/{chunk-U7BMN33M.js.map → chunk-UBSM6TZP.js.map} +0 -0
- /package/dist/{chunk-DQEMWVMT.js.map → chunk-UVYI6VIX.js.map} +0 -0
- /package/dist/{chunk-U7XLOSG2.js.map → chunk-VIM6QH4D.js.map} +0 -0
- /package/dist/{chunk-LJJWFV2Q.js.map → chunk-VJXSAJFW.js.map} +0 -0
- /package/dist/{chunk-HZC3OECF.js.map → chunk-VOKK4WCG.js.map} +0 -0
- /package/dist/{chunk-LRDP2AC2.js.map → chunk-YBCZTBN2.js.map} +0 -0
- /package/dist/{chunk-USAUBGBC.js.map → chunk-YKZFX2HQ.js.map} +0 -0
- /package/dist/{chunk-I2GIYTRU.js.map → chunk-ZOGOOSB3.js.map} +0 -0
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
estimateTokenCount
|
|
3
|
+
} from "./chunk-TOTT6S2V.js";
|
|
4
|
+
|
|
1
5
|
// src/memory-extension-host/host-discovery.ts
|
|
2
6
|
import { readdir, readFile, lstat, realpath } from "fs/promises";
|
|
3
7
|
import path from "path";
|
|
@@ -225,9 +229,6 @@ function resolveExtensionsRoot(config) {
|
|
|
225
229
|
}
|
|
226
230
|
|
|
227
231
|
// src/memory-extension-host/render-extensions-block.ts
|
|
228
|
-
function estimateTokens(text) {
|
|
229
|
-
return Math.ceil(text.length / 4);
|
|
230
|
-
}
|
|
231
232
|
function renderExtensionsBlock(extensions) {
|
|
232
233
|
if (extensions.length === 0) return "";
|
|
233
234
|
const header = `## Active memory extensions
|
|
@@ -238,7 +239,7 @@ extension produces or curates.
|
|
|
238
239
|
|
|
239
240
|
`;
|
|
240
241
|
let budget = REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT;
|
|
241
|
-
budget -=
|
|
242
|
+
budget -= estimateTokenCount(header);
|
|
242
243
|
const inlined = [];
|
|
243
244
|
const omitted = [];
|
|
244
245
|
for (const ext of extensions) {
|
|
@@ -248,7 +249,7 @@ ${ext.instructions}
|
|
|
248
249
|
\`\`\`
|
|
249
250
|
|
|
250
251
|
`;
|
|
251
|
-
const cost =
|
|
252
|
+
const cost = estimateTokenCount(block);
|
|
252
253
|
if (cost <= budget) {
|
|
253
254
|
inlined.push(block);
|
|
254
255
|
budget -= cost;
|
|
@@ -277,4 +278,4 @@ export {
|
|
|
277
278
|
renderExtensionsBlock,
|
|
278
279
|
renderExtensionsFooter
|
|
279
280
|
};
|
|
280
|
-
//# sourceMappingURL=chunk-
|
|
281
|
+
//# sourceMappingURL=chunk-5JMAGU26.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/memory-extension-host/host-discovery.ts","../src/memory-extension-host/render-extensions-block.ts"],"sourcesContent":["/**\n * memory-extension-host/host-discovery.ts — Discover third-party memory extensions.\n *\n * Scans a root directory (typically ~/.remnic/memory_extensions/) for valid\n * extension subdirectories. Each extension must contain an instructions.md.\n * The discovery process is read-only and NEVER reads or executes files under\n * any extension's scripts/ directory.\n */\n\nimport { readdir, readFile, lstat, realpath } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { LoggerBackend } from \"../logger.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport type { DiscoveredExtension, ExtensionSchema } from \"./types.js\";\n\n/** Total token budget for all discovered extension instructions combined. */\nexport const REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT = 5_000;\n\n/** Per-extension instructions read cap, using the same 4 chars/token budget heuristic. */\nexport const REMNIC_EXTENSION_INSTRUCTIONS_BYTE_LIMIT =\n REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT * 4;\n\n/** Optional schemas are metadata only; refuse unusually large schema files. */\nexport const REMNIC_EXTENSION_SCHEMA_BYTE_LIMIT = 64 * 1024;\n\n/** Maximum number of example files collected per extension. */\nconst MAX_EXAMPLES_PER_EXTENSION = 10;\n\n/** Slug validation: lowercase letters, digits, hyphens, 1-64 chars. */\nconst VALID_SLUG_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;\n\nconst VALID_MEMORY_TYPES = new Set([\"fact\", \"preference\", \"procedure\", \"reference\"]);\n\n/**\n * Discover all valid memory extensions under the given root directory.\n *\n * Returns extensions sorted by name. Skips entries with warnings when:\n * - The slug is invalid (not lowercase alphanumeric + hyphens, or > 64 chars)\n * - instructions.md is missing\n * - schema.json is malformed (extension still returned but schema is undefined)\n *\n * NEVER reads files under any extension's scripts/ directory.\n */\nexport async function discoverMemoryExtensions(\n root: string,\n log: Pick<LoggerBackend, \"warn\" | \"debug\">,\n): Promise<DiscoveredExtension[]> {\n // If root doesn't exist, return empty silently (not even a warning).\n // Use lstat() for root — a symlinked extensions root could redirect\n // discovery to an untrusted directory tree (#428 P2). When the root\n // IS a symlink, resolve it and verify it still lives under the parent\n // memory directory so that an attacker-controlled symlink can't point\n // discovery at /etc or another user's home.\n let rootStat;\n try {\n rootStat = await lstat(root);\n } catch {\n return [];\n }\n if (rootStat.isSymbolicLink()) {\n // Resolve and verify the real path is inside the expected parent.\n let resolved: string;\n try {\n resolved = await realpath(root);\n } catch {\n return [];\n }\n // Normalize the parent path through realpath so that:\n // 1. Relative roots (e.g. \"memory_extensions\") become absolute (#431 Finding 1)\n // 2. Intermediate symlinks (e.g. macOS /var -> /private/var) are resolved (#431 Finding 2)\n let expectedParent: string;\n try {\n expectedParent = await realpath(path.resolve(path.dirname(root)));\n } catch {\n // Parent directory doesn't exist or is inaccessible — reject.\n return [];\n }\n if (!resolved.startsWith(expectedParent + path.sep) && resolved !== expectedParent) {\n log.warn?.(\n `[memory-extensions] root \"${root}\" is a symlink resolving outside the expected parent directory, skipping`,\n );\n return [];\n }\n // Re-check the resolved path is a directory.\n try {\n rootStat = await lstat(resolved);\n } catch {\n return [];\n }\n }\n if (!rootStat.isDirectory()) {\n return [];\n }\n\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return [];\n }\n\n const extensions: DiscoveredExtension[] = [];\n\n for (const entry of entries) {\n const entryPath = path.join(root, entry);\n\n // Must be a real directory (not a symlink) — lstat() blocks symlink\n // traversal that could escape the extensions root (#382 P2).\n let entryStat;\n try {\n entryStat = await lstat(entryPath);\n } catch {\n continue;\n }\n if (entryStat.isSymbolicLink()) {\n log.warn?.(\n `[memory-extensions] skipping \"${entry}\": symlinks are not followed for security`,\n );\n continue;\n }\n if (!entryStat.isDirectory()) continue;\n\n // Validate slug\n if (!VALID_SLUG_RE.test(entry)) {\n log.warn?.(\n `[memory-extensions] skipping \"${entry}\": invalid slug (must be lowercase alphanumeric + hyphens, 1-64 chars)`,\n );\n continue;\n }\n\n // Require instructions.md — reject symlinked files (#428 P1)\n const instructionsPath = path.join(entryPath, \"instructions.md\");\n if (await isSymlink(instructionsPath)) {\n log.warn?.(\n `[memory-extensions] skipping \"${entry}\": instructions.md is a symlink`,\n );\n continue;\n }\n let instructions: string;\n try {\n instructions = await readUtf8FileWithinLimit(\n instructionsPath,\n REMNIC_EXTENSION_INSTRUCTIONS_BYTE_LIMIT,\n );\n } catch (err) {\n const reason = err instanceof FileTooLargeError\n ? `instructions.md exceeds ${REMNIC_EXTENSION_INSTRUCTIONS_BYTE_LIMIT} bytes`\n : \"missing instructions.md\";\n log.warn?.(`[memory-extensions] skipping \"${entry}\": ${reason}`);\n continue;\n }\n\n // Read optional schema.json — reject symlinked files (#428 P1)\n let schema: ExtensionSchema | undefined;\n const schemaPath = path.join(entryPath, \"schema.json\");\n if (await isSymlink(schemaPath)) {\n log.warn?.(\n `[memory-extensions] \"${entry}\": schema.json is a symlink, ignoring schema`,\n );\n } else {\n try {\n const schemaRaw = await readUtf8FileWithinLimit(\n schemaPath,\n REMNIC_EXTENSION_SCHEMA_BYTE_LIMIT,\n );\n const parsed = JSON.parse(schemaRaw);\n if (typeof parsed === \"object\" && parsed !== null && !Array.isArray(parsed)) {\n schema = validateSchema(parsed);\n } else {\n log.warn?.(\n `[memory-extensions] \"${entry}\": schema.json is not a valid object, ignoring schema`,\n );\n }\n } catch (err) {\n // File doesn't exist → fine, no warning needed\n if (isFileNotFoundError(err)) {\n // schema remains undefined\n } else if (err instanceof FileTooLargeError) {\n log.warn?.(\n `[memory-extensions] \"${entry}\": schema.json exceeds ${REMNIC_EXTENSION_SCHEMA_BYTE_LIMIT} bytes, ignoring schema`,\n );\n } else {\n log.warn?.(\n `[memory-extensions] \"${entry}\": malformed schema.json, ignoring schema`,\n );\n }\n }\n }\n\n // Collect examples/*.md (cap at MAX_EXAMPLES_PER_EXTENSION)\n // NEVER read from scripts/ directory\n const examplesPaths: string[] = [];\n const examplesDir = path.join(entryPath, \"examples\");\n try {\n const examplesStat = await lstat(examplesDir);\n if (examplesStat.isSymbolicLink()) {\n log.warn?.(\n `[memory-extensions] \"${entry}\": examples/ is a symlink, ignoring examples`,\n );\n throw new Error(\"skip symlinked examples directory\");\n }\n if (!examplesStat.isDirectory()) {\n throw new Error(\"skip non-directory examples path\");\n }\n const exampleEntries = await readdir(examplesDir);\n const mdFiles = exampleEntries\n .filter((f) => f.endsWith(\".md\"))\n .sort()\n .slice(0, MAX_EXAMPLES_PER_EXTENSION);\n for (const f of mdFiles) {\n const examplePath = path.join(examplesDir, f);\n const exampleStat = await lstat(examplePath);\n if (exampleStat.isSymbolicLink()) {\n log.warn?.(\n `[memory-extensions] \"${entry}\": examples/${f} is a symlink, ignoring example`,\n );\n continue;\n }\n if (!exampleStat.isFile()) {\n continue;\n }\n examplesPaths.push(examplePath);\n }\n } catch {\n // No examples dir — fine\n }\n\n extensions.push({\n name: entry,\n root: entryPath,\n instructionsPath,\n instructions,\n schema,\n examplesPaths,\n });\n }\n\n // Sort by name for deterministic ordering\n extensions.sort((a, b) => {\n if (a.name < b.name) return -1;\n if (a.name > b.name) return 1;\n return 0;\n });\n\n return extensions;\n}\n\nclass FileTooLargeError extends Error {\n constructor(filePath: string, limitBytes: number, actualBytes: number) {\n super(`${filePath} is ${actualBytes} bytes; limit is ${limitBytes} bytes`);\n this.name = \"FileTooLargeError\";\n }\n}\n\nasync function readUtf8FileWithinLimit(filePath: string, limitBytes: number): Promise<string> {\n const stat = await lstat(filePath);\n if (!stat.isFile()) {\n throw new Error(`${filePath} is not a file`);\n }\n if (stat.size > limitBytes) {\n throw new FileTooLargeError(filePath, limitBytes, stat.size);\n }\n return readFile(filePath, \"utf-8\");\n}\n\nfunction validateSchema(raw: Record<string, unknown>): ExtensionSchema {\n const memoryTypes: ExtensionSchema[\"memoryTypes\"] = (() => {\n if (!Array.isArray(raw.memoryTypes)) return undefined;\n const valid = raw.memoryTypes.filter(\n (t): t is \"fact\" | \"preference\" | \"procedure\" | \"reference\" =>\n typeof t === \"string\" && VALID_MEMORY_TYPES.has(t),\n );\n return valid.length > 0 ? valid : undefined;\n })();\n\n const groupingHints: ExtensionSchema[\"groupingHints\"] = (() => {\n if (!Array.isArray(raw.groupingHints)) return undefined;\n const valid = raw.groupingHints.filter(\n (h): h is string => typeof h === \"string\" && h.length > 0,\n );\n return valid.length > 0 ? valid : undefined;\n })();\n\n const version: ExtensionSchema[\"version\"] =\n typeof raw.version === \"string\" && raw.version.length > 0\n ? raw.version\n : undefined;\n\n return {\n ...(memoryTypes ? { memoryTypes } : {}),\n ...(groupingHints ? { groupingHints } : {}),\n ...(version ? { version } : {}),\n };\n}\n\nfunction isFileNotFoundError(err: unknown): boolean {\n return (\n typeof err === \"object\" &&\n err !== null &&\n \"code\" in err &&\n (err as { code: string }).code === \"ENOENT\"\n );\n}\n\n/**\n * Returns true if the path exists and is a symlink.\n * Returns false if the path does not exist or is not a symlink.\n */\nasync function isSymlink(filePath: string): Promise<boolean> {\n try {\n const s = await lstat(filePath);\n return s.isSymbolicLink();\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve the memory extensions root directory from config.\n * If memoryExtensionsRoot is empty, derive from memoryDir by going up to\n * the Remnic home dir and appending memory_extensions.\n *\n * Moved here from semantic-consolidation.ts (#428 Finding 3) because this\n * is a generic config-to-path resolver with no consolidation logic.\n */\nexport function resolveExtensionsRoot(config: PluginConfig): string {\n if (config.memoryExtensionsRoot.length > 0) {\n return config.memoryExtensionsRoot;\n }\n // Default: memoryDir is typically ~/.openclaw/workspace/memory/local\n // Go up to the parent that owns the memory tree and append memory_extensions\n return path.join(path.dirname(config.memoryDir), \"memory_extensions\");\n}\n","/**\n * memory-extension-host/render-extensions-block.ts — Render discovered extensions\n * into a markdown block for injection into consolidation prompts.\n *\n * Respects the global token budget (REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT) and\n * truncates with a footer listing omitted extensions when over budget.\n */\n\nimport { REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT } from \"./host-discovery.js\";\nimport type { DiscoveredExtension } from \"./types.js\";\n\n/**\n * Approximate token count using the 4 chars per token heuristic.\n */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n/**\n * Render a markdown block containing extension instructions for injection\n * into consolidation prompts.\n *\n * If the list is empty, returns \"\".\n * Inlines extensions in name order until the token budget is exhausted.\n * If the budget is exceeded, appends a truncation footer listing omitted extensions.\n */\nexport function renderExtensionsBlock(extensions: DiscoveredExtension[]): string {\n if (extensions.length === 0) return \"\";\n\n const header = `## Active memory extensions\n\nYou are running with the following third-party memory extensions. Each\nextension's \\`instructions.md\\` tells you how to interpret memories that\nextension produces or curates.\n\n`;\n\n let budget = REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT;\n budget -= estimateTokens(header);\n\n const inlined: string[] = [];\n const omitted: string[] = [];\n\n for (const ext of extensions) {\n const block = `### remnic-extension/${ext.name}\\n\\`\\`\\`\\n${ext.instructions}\\n\\`\\`\\`\\n\\n`;\n const cost = estimateTokens(block);\n if (cost <= budget) {\n inlined.push(block);\n budget -= cost;\n } else {\n omitted.push(ext.name);\n }\n }\n\n let result = header;\n result += inlined.join(\"\");\n\n if (omitted.length > 0) {\n result += `> **Note:** ${omitted.length} extension(s) omitted due to token budget: ${omitted.join(\", \")}\\n`;\n }\n\n return result;\n}\n\n/**\n * Render a compact one-line footer listing active extension names.\n * Used by day-summary and summary-snapshot where full instructions are not needed.\n */\nexport function renderExtensionsFooter(extensions: DiscoveredExtension[]): string {\n if (extensions.length === 0) return \"\";\n const names = extensions.map((ext) => ext.name).join(\", \");\n return `Active extensions: ${names}`;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/memory-extension-host/host-discovery.ts","../src/memory-extension-host/render-extensions-block.ts"],"sourcesContent":["/**\n * memory-extension-host/host-discovery.ts — Discover third-party memory extensions.\n *\n * Scans a root directory (typically ~/.remnic/memory_extensions/) for valid\n * extension subdirectories. Each extension must contain an instructions.md.\n * The discovery process is read-only and NEVER reads or executes files under\n * any extension's scripts/ directory.\n */\n\nimport { readdir, readFile, lstat, realpath } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { LoggerBackend } from \"../logger.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport type { DiscoveredExtension, ExtensionSchema } from \"./types.js\";\n\n/** Total token budget for all discovered extension instructions combined. */\nexport const REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT = 5_000;\n\n/** Per-extension instructions read cap, using the same 4 chars/token budget heuristic. */\nexport const REMNIC_EXTENSION_INSTRUCTIONS_BYTE_LIMIT =\n REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT * 4;\n\n/** Optional schemas are metadata only; refuse unusually large schema files. */\nexport const REMNIC_EXTENSION_SCHEMA_BYTE_LIMIT = 64 * 1024;\n\n/** Maximum number of example files collected per extension. */\nconst MAX_EXAMPLES_PER_EXTENSION = 10;\n\n/** Slug validation: lowercase letters, digits, hyphens, 1-64 chars. */\nconst VALID_SLUG_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;\n\nconst VALID_MEMORY_TYPES = new Set([\"fact\", \"preference\", \"procedure\", \"reference\"]);\n\n/**\n * Discover all valid memory extensions under the given root directory.\n *\n * Returns extensions sorted by name. Skips entries with warnings when:\n * - The slug is invalid (not lowercase alphanumeric + hyphens, or > 64 chars)\n * - instructions.md is missing\n * - schema.json is malformed (extension still returned but schema is undefined)\n *\n * NEVER reads files under any extension's scripts/ directory.\n */\nexport async function discoverMemoryExtensions(\n root: string,\n log: Pick<LoggerBackend, \"warn\" | \"debug\">,\n): Promise<DiscoveredExtension[]> {\n // If root doesn't exist, return empty silently (not even a warning).\n // Use lstat() for root — a symlinked extensions root could redirect\n // discovery to an untrusted directory tree (#428 P2). When the root\n // IS a symlink, resolve it and verify it still lives under the parent\n // memory directory so that an attacker-controlled symlink can't point\n // discovery at /etc or another user's home.\n let rootStat;\n try {\n rootStat = await lstat(root);\n } catch {\n return [];\n }\n if (rootStat.isSymbolicLink()) {\n // Resolve and verify the real path is inside the expected parent.\n let resolved: string;\n try {\n resolved = await realpath(root);\n } catch {\n return [];\n }\n // Normalize the parent path through realpath so that:\n // 1. Relative roots (e.g. \"memory_extensions\") become absolute (#431 Finding 1)\n // 2. Intermediate symlinks (e.g. macOS /var -> /private/var) are resolved (#431 Finding 2)\n let expectedParent: string;\n try {\n expectedParent = await realpath(path.resolve(path.dirname(root)));\n } catch {\n // Parent directory doesn't exist or is inaccessible — reject.\n return [];\n }\n if (!resolved.startsWith(expectedParent + path.sep) && resolved !== expectedParent) {\n log.warn?.(\n `[memory-extensions] root \"${root}\" is a symlink resolving outside the expected parent directory, skipping`,\n );\n return [];\n }\n // Re-check the resolved path is a directory.\n try {\n rootStat = await lstat(resolved);\n } catch {\n return [];\n }\n }\n if (!rootStat.isDirectory()) {\n return [];\n }\n\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return [];\n }\n\n const extensions: DiscoveredExtension[] = [];\n\n for (const entry of entries) {\n const entryPath = path.join(root, entry);\n\n // Must be a real directory (not a symlink) — lstat() blocks symlink\n // traversal that could escape the extensions root (#382 P2).\n let entryStat;\n try {\n entryStat = await lstat(entryPath);\n } catch {\n continue;\n }\n if (entryStat.isSymbolicLink()) {\n log.warn?.(\n `[memory-extensions] skipping \"${entry}\": symlinks are not followed for security`,\n );\n continue;\n }\n if (!entryStat.isDirectory()) continue;\n\n // Validate slug\n if (!VALID_SLUG_RE.test(entry)) {\n log.warn?.(\n `[memory-extensions] skipping \"${entry}\": invalid slug (must be lowercase alphanumeric + hyphens, 1-64 chars)`,\n );\n continue;\n }\n\n // Require instructions.md — reject symlinked files (#428 P1)\n const instructionsPath = path.join(entryPath, \"instructions.md\");\n if (await isSymlink(instructionsPath)) {\n log.warn?.(\n `[memory-extensions] skipping \"${entry}\": instructions.md is a symlink`,\n );\n continue;\n }\n let instructions: string;\n try {\n instructions = await readUtf8FileWithinLimit(\n instructionsPath,\n REMNIC_EXTENSION_INSTRUCTIONS_BYTE_LIMIT,\n );\n } catch (err) {\n const reason = err instanceof FileTooLargeError\n ? `instructions.md exceeds ${REMNIC_EXTENSION_INSTRUCTIONS_BYTE_LIMIT} bytes`\n : \"missing instructions.md\";\n log.warn?.(`[memory-extensions] skipping \"${entry}\": ${reason}`);\n continue;\n }\n\n // Read optional schema.json — reject symlinked files (#428 P1)\n let schema: ExtensionSchema | undefined;\n const schemaPath = path.join(entryPath, \"schema.json\");\n if (await isSymlink(schemaPath)) {\n log.warn?.(\n `[memory-extensions] \"${entry}\": schema.json is a symlink, ignoring schema`,\n );\n } else {\n try {\n const schemaRaw = await readUtf8FileWithinLimit(\n schemaPath,\n REMNIC_EXTENSION_SCHEMA_BYTE_LIMIT,\n );\n const parsed = JSON.parse(schemaRaw);\n if (typeof parsed === \"object\" && parsed !== null && !Array.isArray(parsed)) {\n schema = validateSchema(parsed);\n } else {\n log.warn?.(\n `[memory-extensions] \"${entry}\": schema.json is not a valid object, ignoring schema`,\n );\n }\n } catch (err) {\n // File doesn't exist → fine, no warning needed\n if (isFileNotFoundError(err)) {\n // schema remains undefined\n } else if (err instanceof FileTooLargeError) {\n log.warn?.(\n `[memory-extensions] \"${entry}\": schema.json exceeds ${REMNIC_EXTENSION_SCHEMA_BYTE_LIMIT} bytes, ignoring schema`,\n );\n } else {\n log.warn?.(\n `[memory-extensions] \"${entry}\": malformed schema.json, ignoring schema`,\n );\n }\n }\n }\n\n // Collect examples/*.md (cap at MAX_EXAMPLES_PER_EXTENSION)\n // NEVER read from scripts/ directory\n const examplesPaths: string[] = [];\n const examplesDir = path.join(entryPath, \"examples\");\n try {\n const examplesStat = await lstat(examplesDir);\n if (examplesStat.isSymbolicLink()) {\n log.warn?.(\n `[memory-extensions] \"${entry}\": examples/ is a symlink, ignoring examples`,\n );\n throw new Error(\"skip symlinked examples directory\");\n }\n if (!examplesStat.isDirectory()) {\n throw new Error(\"skip non-directory examples path\");\n }\n const exampleEntries = await readdir(examplesDir);\n const mdFiles = exampleEntries\n .filter((f) => f.endsWith(\".md\"))\n .sort()\n .slice(0, MAX_EXAMPLES_PER_EXTENSION);\n for (const f of mdFiles) {\n const examplePath = path.join(examplesDir, f);\n const exampleStat = await lstat(examplePath);\n if (exampleStat.isSymbolicLink()) {\n log.warn?.(\n `[memory-extensions] \"${entry}\": examples/${f} is a symlink, ignoring example`,\n );\n continue;\n }\n if (!exampleStat.isFile()) {\n continue;\n }\n examplesPaths.push(examplePath);\n }\n } catch {\n // No examples dir — fine\n }\n\n extensions.push({\n name: entry,\n root: entryPath,\n instructionsPath,\n instructions,\n schema,\n examplesPaths,\n });\n }\n\n // Sort by name for deterministic ordering\n extensions.sort((a, b) => {\n if (a.name < b.name) return -1;\n if (a.name > b.name) return 1;\n return 0;\n });\n\n return extensions;\n}\n\nclass FileTooLargeError extends Error {\n constructor(filePath: string, limitBytes: number, actualBytes: number) {\n super(`${filePath} is ${actualBytes} bytes; limit is ${limitBytes} bytes`);\n this.name = \"FileTooLargeError\";\n }\n}\n\nasync function readUtf8FileWithinLimit(filePath: string, limitBytes: number): Promise<string> {\n const stat = await lstat(filePath);\n if (!stat.isFile()) {\n throw new Error(`${filePath} is not a file`);\n }\n if (stat.size > limitBytes) {\n throw new FileTooLargeError(filePath, limitBytes, stat.size);\n }\n return readFile(filePath, \"utf-8\");\n}\n\nfunction validateSchema(raw: Record<string, unknown>): ExtensionSchema {\n const memoryTypes: ExtensionSchema[\"memoryTypes\"] = (() => {\n if (!Array.isArray(raw.memoryTypes)) return undefined;\n const valid = raw.memoryTypes.filter(\n (t): t is \"fact\" | \"preference\" | \"procedure\" | \"reference\" =>\n typeof t === \"string\" && VALID_MEMORY_TYPES.has(t),\n );\n return valid.length > 0 ? valid : undefined;\n })();\n\n const groupingHints: ExtensionSchema[\"groupingHints\"] = (() => {\n if (!Array.isArray(raw.groupingHints)) return undefined;\n const valid = raw.groupingHints.filter(\n (h): h is string => typeof h === \"string\" && h.length > 0,\n );\n return valid.length > 0 ? valid : undefined;\n })();\n\n const version: ExtensionSchema[\"version\"] =\n typeof raw.version === \"string\" && raw.version.length > 0\n ? raw.version\n : undefined;\n\n return {\n ...(memoryTypes ? { memoryTypes } : {}),\n ...(groupingHints ? { groupingHints } : {}),\n ...(version ? { version } : {}),\n };\n}\n\nfunction isFileNotFoundError(err: unknown): boolean {\n return (\n typeof err === \"object\" &&\n err !== null &&\n \"code\" in err &&\n (err as { code: string }).code === \"ENOENT\"\n );\n}\n\n/**\n * Returns true if the path exists and is a symlink.\n * Returns false if the path does not exist or is not a symlink.\n */\nasync function isSymlink(filePath: string): Promise<boolean> {\n try {\n const s = await lstat(filePath);\n return s.isSymbolicLink();\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve the memory extensions root directory from config.\n * If memoryExtensionsRoot is empty, derive from memoryDir by going up to\n * the Remnic home dir and appending memory_extensions.\n *\n * Moved here from semantic-consolidation.ts (#428 Finding 3) because this\n * is a generic config-to-path resolver with no consolidation logic.\n */\nexport function resolveExtensionsRoot(config: PluginConfig): string {\n if (config.memoryExtensionsRoot.length > 0) {\n return config.memoryExtensionsRoot;\n }\n // Default: memoryDir is typically ~/.openclaw/workspace/memory/local\n // Go up to the parent that owns the memory tree and append memory_extensions\n return path.join(path.dirname(config.memoryDir), \"memory_extensions\");\n}\n","/**\n * memory-extension-host/render-extensions-block.ts — Render discovered extensions\n * into a markdown block for injection into consolidation prompts.\n *\n * Respects the global token budget (REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT) and\n * truncates with a footer listing omitted extensions when over budget.\n */\n\nimport { estimateTokenCount } from \"../token-estimate.js\";\nimport { REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT } from \"./host-discovery.js\";\nimport type { DiscoveredExtension } from \"./types.js\";\n\n/**\n * Render a markdown block containing extension instructions for injection\n * into consolidation prompts.\n *\n * If the list is empty, returns \"\".\n * Inlines extensions in name order until the token budget is exhausted.\n * If the budget is exceeded, appends a truncation footer listing omitted extensions.\n */\nexport function renderExtensionsBlock(extensions: DiscoveredExtension[]): string {\n if (extensions.length === 0) return \"\";\n\n const header = `## Active memory extensions\n\nYou are running with the following third-party memory extensions. Each\nextension's \\`instructions.md\\` tells you how to interpret memories that\nextension produces or curates.\n\n`;\n\n let budget = REMNIC_EXTENSIONS_TOTAL_TOKEN_LIMIT;\n budget -= estimateTokenCount(header);\n\n const inlined: string[] = [];\n const omitted: string[] = [];\n\n for (const ext of extensions) {\n const block = `### remnic-extension/${ext.name}\\n\\`\\`\\`\\n${ext.instructions}\\n\\`\\`\\`\\n\\n`;\n const cost = estimateTokenCount(block);\n if (cost <= budget) {\n inlined.push(block);\n budget -= cost;\n } else {\n omitted.push(ext.name);\n }\n }\n\n let result = header;\n result += inlined.join(\"\");\n\n if (omitted.length > 0) {\n result += `> **Note:** ${omitted.length} extension(s) omitted due to token budget: ${omitted.join(\", \")}\\n`;\n }\n\n return result;\n}\n\n/**\n * Render a compact one-line footer listing active extension names.\n * Used by day-summary and summary-snapshot where full instructions are not needed.\n */\nexport function renderExtensionsFooter(extensions: DiscoveredExtension[]): string {\n if (extensions.length === 0) return \"\";\n const names = extensions.map((ext) => ext.name).join(\", \");\n return `Active extensions: ${names}`;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
encryptCapsuleFile
|
|
3
|
+
} from "./chunk-UVYI6VIX.js";
|
|
1
4
|
import {
|
|
2
5
|
CAPSULE_ID_PATTERN,
|
|
3
6
|
CapsuleBlockSchema,
|
|
4
7
|
ExportBundleV2Schema,
|
|
5
8
|
ExportManifestV2Schema
|
|
6
9
|
} from "./chunk-WEHSQBFR.js";
|
|
7
|
-
import {
|
|
8
|
-
encryptCapsuleFile
|
|
9
|
-
} from "./chunk-DQEMWVMT.js";
|
|
10
10
|
import {
|
|
11
11
|
CAPSULE_SCHEMA_VERSION,
|
|
12
12
|
EXPORT_FORMAT
|
|
@@ -261,4 +261,4 @@ export {
|
|
|
261
261
|
exportCapsule,
|
|
262
262
|
isValidCapsuleSince
|
|
263
263
|
};
|
|
264
|
-
//# sourceMappingURL=chunk-
|
|
264
|
+
//# sourceMappingURL=chunk-5W7CTZ2E.js.map
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-GDB4J2H3.js";
|
|
9
9
|
import {
|
|
10
10
|
importCapsule
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-BTHDQOF4.js";
|
|
12
12
|
import {
|
|
13
13
|
WriteQuarantineStore
|
|
14
14
|
} from "./chunk-PJSK6OJM.js";
|
|
@@ -35,13 +35,13 @@ import {
|
|
|
35
35
|
} from "./chunk-H7XKCNR6.js";
|
|
36
36
|
import {
|
|
37
37
|
toRecallExplainJson
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-UBSM6TZP.js";
|
|
39
39
|
import {
|
|
40
40
|
estimateRecallTokens
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-KF75ANST.js";
|
|
42
42
|
import {
|
|
43
43
|
readAggregateExtractionWatermark
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-DE6YCZEE.js";
|
|
45
45
|
import {
|
|
46
46
|
ReplicaDivergenceMonitor
|
|
47
47
|
} from "./chunk-CVILPI77.js";
|
|
@@ -71,7 +71,7 @@ import {
|
|
|
71
71
|
} from "./chunk-NLE6TSLG.js";
|
|
72
72
|
import {
|
|
73
73
|
LocalLlmClient
|
|
74
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-IVKIODHO.js";
|
|
75
75
|
import {
|
|
76
76
|
buildProcedurePersistBody,
|
|
77
77
|
normalizeProcedureSteps
|
|
@@ -99,11 +99,11 @@ import {
|
|
|
99
99
|
listMemoryGovernanceRuns,
|
|
100
100
|
readMemoryGovernanceRunArtifact,
|
|
101
101
|
runMemoryGovernance
|
|
102
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-G3JFFUKR.js";
|
|
103
103
|
import {
|
|
104
104
|
CorpusWatermarkCache,
|
|
105
105
|
computeServiceCorpusCensus
|
|
106
|
-
} from "./chunk-
|
|
106
|
+
} from "./chunk-VJXSAJFW.js";
|
|
107
107
|
import {
|
|
108
108
|
CrossNamespaceBudget,
|
|
109
109
|
toBudgetWarning
|
|
@@ -127,21 +127,21 @@ import {
|
|
|
127
127
|
enqueuePassiveCorrectionNotification,
|
|
128
128
|
parseBriefingFocus,
|
|
129
129
|
parseBriefingWindow
|
|
130
|
-
} from "./chunk-
|
|
130
|
+
} from "./chunk-P5OYNV7B.js";
|
|
131
131
|
import {
|
|
132
132
|
parseEntityFile,
|
|
133
133
|
parseFrontmatter,
|
|
134
134
|
qmdCollectionPathParts,
|
|
135
135
|
qmdResultPathCandidates,
|
|
136
136
|
selfDeps
|
|
137
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-2VHCLHZ5.js";
|
|
138
138
|
import {
|
|
139
139
|
namespaceCollectionName
|
|
140
|
-
} from "./chunk-
|
|
140
|
+
} from "./chunk-P6GOYLHN.js";
|
|
141
141
|
import {
|
|
142
142
|
DEFAULT_RECALL_DISCLOSURE,
|
|
143
143
|
isRecallDisclosure
|
|
144
|
-
} from "./chunk-
|
|
144
|
+
} from "./chunk-LLZKOSGM.js";
|
|
145
145
|
import {
|
|
146
146
|
normalizeProjectionPreview,
|
|
147
147
|
normalizeProjectionTags
|
|
@@ -179,7 +179,7 @@ import {
|
|
|
179
179
|
} from "./chunk-JV3C2MNQ.js";
|
|
180
180
|
import {
|
|
181
181
|
exportCapsule
|
|
182
|
-
} from "./chunk-
|
|
182
|
+
} from "./chunk-5W7CTZ2E.js";
|
|
183
183
|
import {
|
|
184
184
|
evaluateActionConfidence
|
|
185
185
|
} from "./chunk-Z2YFLXHU.js";
|
|
@@ -17672,4 +17672,4 @@ export {
|
|
|
17672
17672
|
EngramAccessService,
|
|
17673
17673
|
AccessAdminOpsSurface
|
|
17674
17674
|
};
|
|
17675
|
-
//# sourceMappingURL=chunk-
|
|
17675
|
+
//# sourceMappingURL=chunk-6C7Q6NG3.js.map
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
estimateTokenCount
|
|
3
|
+
} from "./chunk-TOTT6S2V.js";
|
|
4
|
+
|
|
1
5
|
// src/chunking.ts
|
|
2
6
|
var DEFAULT_CHUNKING_CONFIG = {
|
|
3
7
|
targetTokens: 200,
|
|
4
8
|
minTokens: 150,
|
|
5
9
|
overlapSentences: 2
|
|
6
10
|
};
|
|
7
|
-
function estimateTokens(text) {
|
|
8
|
-
return Math.ceil(text.length / 4);
|
|
9
|
-
}
|
|
10
11
|
var UNICODE_SENTENCE_TERMINATORS = "\u3002\uFF0E\uFF01\uFF1F\u061F\u06D4\u0964\u0965\uFF61\u2026";
|
|
11
12
|
var ASCII_SENTENCE_TERMINATORS = ".!?";
|
|
12
13
|
var CJK_NO_SPACE_TERMINATORS = "\u3002\uFF0E\uFF01\uFF1F\uFF61";
|
|
@@ -106,7 +107,7 @@ function joinSentences(sentences) {
|
|
|
106
107
|
return result;
|
|
107
108
|
}
|
|
108
109
|
function chunkContent(content, config = DEFAULT_CHUNKING_CONFIG) {
|
|
109
|
-
const totalTokens =
|
|
110
|
+
const totalTokens = estimateTokenCount(content);
|
|
110
111
|
if (totalTokens < config.minTokens) {
|
|
111
112
|
return {
|
|
112
113
|
chunked: false,
|
|
@@ -134,7 +135,7 @@ function chunkContent(content, config = DEFAULT_CHUNKING_CONFIG) {
|
|
|
134
135
|
let chunkIndex = 0;
|
|
135
136
|
for (let i = 0; i < sentences.length; i++) {
|
|
136
137
|
const sentence = sentences[i];
|
|
137
|
-
const sentenceTokens =
|
|
138
|
+
const sentenceTokens = estimateTokenCount(sentence);
|
|
138
139
|
currentChunkSentences.push(sentence);
|
|
139
140
|
currentTokens += sentenceTokens;
|
|
140
141
|
const atTarget = currentTokens >= config.targetTokens;
|
|
@@ -144,7 +145,7 @@ function chunkContent(content, config = DEFAULT_CHUNKING_CONFIG) {
|
|
|
144
145
|
chunks.push({
|
|
145
146
|
content: chunkContent2,
|
|
146
147
|
index: chunkIndex,
|
|
147
|
-
tokenCount:
|
|
148
|
+
tokenCount: estimateTokenCount(chunkContent2)
|
|
148
149
|
});
|
|
149
150
|
chunkIndex++;
|
|
150
151
|
if (!isLastSentence) {
|
|
@@ -154,7 +155,7 @@ function chunkContent(content, config = DEFAULT_CHUNKING_CONFIG) {
|
|
|
154
155
|
currentTokens = 0;
|
|
155
156
|
} else {
|
|
156
157
|
currentChunkSentences = currentChunkSentences.slice(-overlapCount);
|
|
157
|
-
currentTokens = currentChunkSentences.reduce((sum, s) => sum +
|
|
158
|
+
currentTokens = currentChunkSentences.reduce((sum, s) => sum + estimateTokenCount(s), 0);
|
|
158
159
|
}
|
|
159
160
|
}
|
|
160
161
|
}
|
|
@@ -197,4 +198,4 @@ export {
|
|
|
197
198
|
chunkContent,
|
|
198
199
|
reassembleChunks
|
|
199
200
|
};
|
|
200
|
-
//# sourceMappingURL=chunk-
|
|
201
|
+
//# sourceMappingURL=chunk-6TBIWIAG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/chunking.ts"],"sourcesContent":["/**\n * Automatic Chunking with Overlap (Phase 2A)\n *\n * Sentence-boundary chunking for long memories.\n * Preserves coherent thoughts by never splitting mid-sentence.\n */\n\nimport { estimateTokenCount } from \"./token-estimate.js\";\n\nexport interface ChunkingConfig {\n /** Target tokens per chunk (default 200) */\n targetTokens: number;\n /** Minimum tokens to trigger chunking (default 150) */\n minTokens: number;\n /** Number of sentences to overlap between chunks (default 2) */\n overlapSentences: number;\n}\n\nexport interface Chunk {\n /** Chunk content */\n content: string;\n /** 0-based index */\n index: number;\n /** Approximate token count */\n tokenCount: number;\n}\n\nexport interface ChunkResult {\n /** Whether content was chunked */\n chunked: boolean;\n /** Array of chunks (length 1 if not chunked) */\n chunks: Chunk[];\n}\n\n/** Default chunking configuration */\nexport const DEFAULT_CHUNKING_CONFIG: ChunkingConfig = {\n targetTokens: 200,\n minTokens: 150,\n overlapSentences: 2,\n};\n\n/**\n * Split text into sentences.\n *\n * The scan stays linear and does not use a backtracking regular expression.\n * ASCII punctuation keeps its old whitespace rule. Unicode terminators also\n * split when the next sentence starts immediately, as in CJK text.\n */\nconst UNICODE_SENTENCE_TERMINATORS = \"。.!?؟۔।॥。…\";\nconst ASCII_SENTENCE_TERMINATORS = \".!?\";\nconst CJK_NO_SPACE_TERMINATORS = \"。.!?。\";\nconst CLOSING_PUNCTUATION = \"\\\"'”’»」』)]】〉》)]}\";\nconst DIGITS = \"01234567890123456789\";\nconst SENTENCE_SEGMENTER =\n typeof Intl.Segmenter === \"function\"\n ? new Intl.Segmenter(undefined, { granularity: \"sentence\" })\n : undefined;\n\nfunction isSentenceTerminator(character: string): boolean {\n return (\n ASCII_SENTENCE_TERMINATORS.includes(character) ||\n UNICODE_SENTENCE_TERMINATORS.includes(character)\n );\n}\n\nfunction isCjk(character: string): boolean {\n return /[\\u3000-\\u9fff\\uf900-\\ufaff\\uac00-\\ud7af]/u.test(character);\n}\n\ntype SentenceList = string[] & { separators: string[] };\n\nfunction splitSentencesFallback(text: string): SentenceList {\n const sentences = [] as unknown as SentenceList;\n Object.defineProperty(sentences, \"separators\", {\n value: [],\n writable: true,\n });\n let start = 0;\n let separator = \"\";\n for (let i = 0; i < text.length; i++) {\n const ch = text[i];\n if (!isSentenceTerminator(ch)) continue;\n\n let end = i;\n let hasUnicodeTerminator = UNICODE_SENTENCE_TERMINATORS.includes(ch);\n while (end + 1 < text.length && isSentenceTerminator(text[end + 1])) {\n end++;\n hasUnicodeTerminator ||= UNICODE_SENTENCE_TERMINATORS.includes(text[end]);\n }\n\n const isFullwidthDecimal =\n ch === \".\" &&\n DIGITS.includes(text[i - 1] ?? \"\") &&\n DIGITS.includes(text[end + 1] ?? \"\");\n while (end + 1 < text.length && CLOSING_PUNCTUATION.includes(text[end + 1])) {\n end++;\n }\n\n const after = text[end + 1];\n const boundary =\n !isFullwidthDecimal &&\n (hasUnicodeTerminator || after === undefined || /\\s/u.test(after));\n if (boundary) {\n const sentence = text.slice(start, end + 1).trim();\n if (sentence.length > 0) {\n sentences.push(sentence);\n if (sentences.length > 1) sentences.separators.push(separator);\n }\n let nextStart = end + 1;\n while (nextStart < text.length && /\\s/u.test(text[nextStart])) nextStart++;\n separator = text.slice(end + 1, nextStart);\n start = nextStart;\n }\n i = end;\n }\n\n const remaining = text.slice(start).trim();\n if (remaining.length > 0) {\n sentences.push(remaining);\n if (sentences.length > 1) sentences.separators.push(separator);\n }\n return sentences;\n}\nexport function splitSentences(text: string): string[] {\n const canUseSegmenter =\n SENTENCE_SEGMENTER !== undefined &&\n !/\\s/u.test(text) &&\n [...text].some((character) => UNICODE_SENTENCE_TERMINATORS.includes(character));\n if (canUseSegmenter) {\n const segments = Array.from(SENTENCE_SEGMENTER.segment(text), ({ segment }) =>\n segment.trim(),\n ).filter((segment) => segment.length > 0) as SentenceList;\n if (\n segments.length > 1 &&\n segments.slice(0, -1).every((segment) =>\n [...segment].some((character) =>\n UNICODE_SENTENCE_TERMINATORS.includes(character),\n ),\n )\n ) {\n Object.defineProperty(segments, \"separators\", {\n value: Array(segments.length - 1).fill(\"\"),\n writable: true,\n });\n return segments;\n }\n }\n return splitSentencesFallback(text);\n}\n\nfunction endsWithoutSpace(text: string): boolean {\n let index = text.length - 1;\n while (index >= 0 && CLOSING_PUNCTUATION.includes(text[index])) index--;\n const terminator = text[index] ?? \"\";\n if (CJK_NO_SPACE_TERMINATORS.includes(terminator)) {\n return isCjk(text[index - 1] ?? \"\");\n }\n return terminator === \"…\" && isCjk(text[index - 1] ?? \"\");\n}\nexport function joinSentences(sentences: string[]): string {\n let result = \"\";\n const separators = (sentences as Partial<SentenceList>).separators;\n for (let i = 0; i < sentences.length; i++) {\n const sentence = sentences[i];\n if (result.length > 0) {\n const separator = separators?.[i - 1];\n result += separator ?? (endsWithoutSpace(result) ? \"\" : \" \");\n }\n result += sentence;\n }\n return result;\n}\n\n\n/**\n * Chunk content into overlapping segments at sentence boundaries.\n *\n * @param content - The text content to chunk\n * @param config - Chunking configuration\n * @returns ChunkResult with chunks array\n */\nexport function chunkContent(\n content: string,\n config: ChunkingConfig = DEFAULT_CHUNKING_CONFIG,\n): ChunkResult {\n const totalTokens = estimateTokenCount(content);\n\n // Don't chunk if below minimum threshold\n if (totalTokens < config.minTokens) {\n return {\n chunked: false,\n chunks: [{\n content,\n index: 0,\n tokenCount: totalTokens,\n }],\n };\n }\n\n const sentences = splitSentences(content);\n\n // If we couldn't split into multiple sentences, don't chunk\n if (sentences.length <= 1) {\n return {\n chunked: false,\n chunks: [{\n content,\n index: 0,\n tokenCount: totalTokens,\n }],\n };\n }\n\n const chunks: Chunk[] = [];\n let currentChunkSentences: string[] = [];\n let currentTokens = 0;\n let chunkIndex = 0;\n\n for (let i = 0; i < sentences.length; i++) {\n const sentence = sentences[i];\n const sentenceTokens = estimateTokenCount(sentence);\n\n // Add sentence to current chunk\n currentChunkSentences.push(sentence);\n currentTokens += sentenceTokens;\n\n // Check if we've reached target size (with some flexibility)\n // Allow going over by up to 50% to avoid tiny final chunks\n const atTarget = currentTokens >= config.targetTokens;\n const isLastSentence = i === sentences.length - 1;\n\n if (atTarget || isLastSentence) {\n // Create chunk from accumulated sentences\n const chunkContent = joinSentences(currentChunkSentences);\n chunks.push({\n content: chunkContent,\n index: chunkIndex,\n tokenCount: estimateTokenCount(chunkContent),\n });\n chunkIndex++;\n\n // Start new chunk with overlap (if not at end)\n if (!isLastSentence) {\n // Keep last N sentences for overlap.\n // Guard: slice(-0) === slice(0), which returns the ENTIRE array\n // (CLAUDE.md gotcha #27). When overlapSentences is 0, clear fully.\n const overlapCount = Math.min(config.overlapSentences, currentChunkSentences.length);\n if (overlapCount <= 0) {\n currentChunkSentences = [];\n currentTokens = 0;\n } else {\n currentChunkSentences = currentChunkSentences.slice(-overlapCount);\n currentTokens = currentChunkSentences.reduce((sum, s) => sum + estimateTokenCount(s), 0);\n }\n }\n }\n }\n\n // Only consider it \"chunked\" if we got multiple chunks\n return {\n chunked: chunks.length > 1,\n chunks,\n };\n}\n\n/**\n * Get parent content by reassembling chunks.\n * Useful for displaying full context when a chunk is retrieved.\n *\n * @param chunks - Array of chunk contents in order\n * @returns Reassembled parent content (with overlap removed)\n */\nexport function reassembleChunks(chunks: string[]): string {\n if (chunks.length === 0) return \"\";\n if (chunks.length === 1) return chunks[0];\n\n // For overlapping chunks, we need to deduplicate\n // Simple approach: use full first chunk, then non-overlapping parts of subsequent chunks\n // This is imperfect but handles most cases\n const result: string[] = [chunks[0]];\n\n for (let i = 1; i < chunks.length; i++) {\n const prevChunk = chunks[i - 1];\n const currChunk = chunks[i];\n\n // Find overlap by looking for common suffix/prefix\n // Try to find where the previous chunk ends in the current chunk\n const prevSentences = splitSentences(prevChunk);\n const currSentences = splitSentences(currChunk);\n\n // Find how many sentences from prev are at the start of curr\n let overlapCount = 0;\n for (let j = 0; j < Math.min(prevSentences.length, currSentences.length); j++) {\n // Check if last N sentences of prev match first N sentences of curr\n const prevEnd = prevSentences.slice(-(j + 1));\n const currStart = currSentences.slice(0, j + 1);\n\n if (joinSentences(prevEnd) === joinSentences(currStart)) {\n overlapCount = j + 1;\n }\n }\n\n // Add non-overlapping portion\n if (overlapCount > 0 && overlapCount < currSentences.length) {\n result.push(joinSentences(currSentences.slice(overlapCount)));\n } else if (overlapCount === 0) {\n // No detected overlap, add full chunk\n result.push(currChunk);\n }\n // If overlapCount === currSentences.length, skip (fully contained)\n }\n\n return joinSentences(result);\n}\n"],"mappings":"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","names":["chunkContent"]}
|
|
@@ -9,14 +9,14 @@ import {
|
|
|
9
9
|
} from "./chunk-666A3MOW.js";
|
|
10
10
|
import {
|
|
11
11
|
rebuildMemoryLifecycleLedger
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-OU7RWWW6.js";
|
|
13
13
|
import {
|
|
14
14
|
planNamespaceMaintenance,
|
|
15
15
|
runNamespaceMaintenanceBatchPlan
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-EZXGJJXM.js";
|
|
17
17
|
import {
|
|
18
18
|
rebuildMemoryProjection
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-AH2NX6S7.js";
|
|
20
20
|
import {
|
|
21
21
|
activityDayWindow,
|
|
22
22
|
activityDigestPath,
|
|
@@ -1719,4 +1719,4 @@ export {
|
|
|
1719
1719
|
ActivitySyncScheduler,
|
|
1720
1720
|
MaintenanceScheduler
|
|
1721
1721
|
};
|
|
1722
|
-
//# sourceMappingURL=chunk-
|
|
1722
|
+
//# sourceMappingURL=chunk-6W2ISYUV.js.map
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
discoverMemoryExtensions,
|
|
3
3
|
renderExtensionsBlock,
|
|
4
4
|
resolveExtensionsRoot
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-5JMAGU26.js";
|
|
6
6
|
import {
|
|
7
7
|
runPostConsolidationMaterialize
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KBIIE57I.js";
|
|
9
9
|
import {
|
|
10
10
|
isSemanticConsolidationLlmOperator
|
|
11
11
|
} from "./chunk-G7D6GZ5J.js";
|
|
@@ -220,4 +220,4 @@ export {
|
|
|
220
220
|
buildExtensionsBlockForConsolidation,
|
|
221
221
|
materializeAfterSemanticConsolidation
|
|
222
222
|
};
|
|
223
|
-
//# sourceMappingURL=chunk-
|
|
223
|
+
//# sourceMappingURL=chunk-77DAFTUU.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parseXrayFormat
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-UBSM6TZP.js";
|
|
4
4
|
import {
|
|
5
5
|
RECALL_DISCLOSURE_LEVELS,
|
|
6
6
|
isRecallDisclosure
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-LLZKOSGM.js";
|
|
8
8
|
|
|
9
9
|
// src/recall-xray-cli.ts
|
|
10
10
|
function parseXrayDisclosureFlag(value) {
|
|
@@ -50,4 +50,4 @@ export {
|
|
|
50
50
|
parseXrayBudgetFlag,
|
|
51
51
|
parseXrayCliOptions
|
|
52
52
|
};
|
|
53
|
-
//# sourceMappingURL=chunk-
|
|
53
|
+
//# sourceMappingURL=chunk-7DHFB5SG.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
SupportPassportError,
|
|
3
3
|
SupportPassportOwnerCreateGrantRequestSchema,
|
|
4
4
|
getOperation
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-6C7Q6NG3.js";
|
|
6
6
|
|
|
7
7
|
// src/support-passport/access-http.ts
|
|
8
8
|
var OWNER_ROOT = "/engram/v1/support-passport";
|
|
@@ -137,4 +137,4 @@ export {
|
|
|
137
137
|
SUPPORT_PASSPORT_OWNER_HTTP_ROUTES,
|
|
138
138
|
handleSupportPassportOwnerHttp
|
|
139
139
|
};
|
|
140
|
-
//# sourceMappingURL=chunk-
|
|
140
|
+
//# sourceMappingURL=chunk-7G34CBKS.js.map
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
listMemoryGovernanceRuns,
|
|
9
9
|
readMemoryGovernanceRunArtifact
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-G3JFFUKR.js";
|
|
11
11
|
import {
|
|
12
12
|
StorageManager
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-2VHCLHZ5.js";
|
|
14
14
|
import {
|
|
15
15
|
normalizeProjectionPreview,
|
|
16
16
|
normalizeProjectionTags
|
|
@@ -1005,4 +1005,4 @@ export {
|
|
|
1005
1005
|
verifyMemoryProjection,
|
|
1006
1006
|
repairMemoryProjection
|
|
1007
1007
|
};
|
|
1008
|
-
//# sourceMappingURL=chunk-
|
|
1008
|
+
//# sourceMappingURL=chunk-AH2NX6S7.js.map
|
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
sessionStoragePaths
|
|
6
6
|
} from "./chunk-S4DDLTPX.js";
|
|
7
|
+
import {
|
|
8
|
+
estimateTokenCount
|
|
9
|
+
} from "./chunk-TOTT6S2V.js";
|
|
7
10
|
import {
|
|
8
11
|
resolveSafeStoragePath
|
|
9
12
|
} from "./chunk-FF4KLI5W.js";
|
|
@@ -42,8 +45,6 @@ var TranscriptManager = class _TranscriptManager {
|
|
|
42
45
|
directoryOwnershipCache = /* @__PURE__ */ new Map();
|
|
43
46
|
/** Default checkpoint TTL in hours */
|
|
44
47
|
static DEFAULT_CHECKPOINT_TTL_HOURS = 24;
|
|
45
|
-
/** Approximate characters per token for rough estimation */
|
|
46
|
-
static CHARS_PER_TOKEN = 4;
|
|
47
48
|
constructor(config) {
|
|
48
49
|
this.config = config;
|
|
49
50
|
this.transcriptsDir = path.join(config.memoryDir, "transcripts");
|
|
@@ -327,6 +328,7 @@ var TranscriptManager = class _TranscriptManager {
|
|
|
327
328
|
async estimateSessionFootprint(sessionKey) {
|
|
328
329
|
const { dir, alternateDir, legacyDir, readbackDirs } = this.getTranscriptPath(sessionKey);
|
|
329
330
|
let bytes = 0;
|
|
331
|
+
let tokens = 0;
|
|
330
332
|
try {
|
|
331
333
|
const files = await this.getSessionStorageFiles(
|
|
332
334
|
this.transcriptsDir,
|
|
@@ -339,27 +341,30 @@ var TranscriptManager = class _TranscriptManager {
|
|
|
339
341
|
if (!cached) {
|
|
340
342
|
const fileBytes = /* @__PURE__ */ new Map();
|
|
341
343
|
const fileSizes = /* @__PURE__ */ new Map();
|
|
344
|
+
const fileTokens = /* @__PURE__ */ new Map();
|
|
342
345
|
for (const file of files) {
|
|
343
346
|
try {
|
|
344
347
|
const fileInfo = await stat(file.path);
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
);
|
|
349
|
-
fileBytes.set(file.cacheKey, sessionBytes);
|
|
348
|
+
const estimate = await this.estimateSessionBytesInFile(file.path, sessionKey);
|
|
349
|
+
fileBytes.set(file.cacheKey, estimate.bytes);
|
|
350
|
+
fileTokens.set(file.cacheKey, estimate.tokens);
|
|
350
351
|
fileSizes.set(file.cacheKey, Math.max(0, fileInfo.size));
|
|
351
|
-
bytes +=
|
|
352
|
+
bytes += estimate.bytes;
|
|
353
|
+
tokens += estimate.tokens;
|
|
352
354
|
} catch {
|
|
353
355
|
}
|
|
354
356
|
}
|
|
355
|
-
this.sessionFootprintCache.set(sessionKey, { totalBytes: bytes, fileBytes, fileSizes });
|
|
357
|
+
this.sessionFootprintCache.set(sessionKey, { totalBytes: bytes, totalTokens: tokens, fileBytes, fileSizes, fileTokens });
|
|
356
358
|
} else {
|
|
357
359
|
bytes = cached.totalBytes;
|
|
360
|
+
tokens = cached.totalTokens;
|
|
358
361
|
const seen = new Set(files.map((file) => file.cacheKey));
|
|
359
362
|
for (const [cachedFile, cachedSessionBytes] of cached.fileBytes.entries()) {
|
|
360
363
|
if (!seen.has(cachedFile)) {
|
|
361
364
|
bytes -= cachedSessionBytes;
|
|
365
|
+
tokens -= cached.fileTokens.get(cachedFile) ?? 0;
|
|
362
366
|
cached.fileBytes.delete(cachedFile);
|
|
367
|
+
cached.fileTokens.delete(cachedFile);
|
|
363
368
|
cached.fileSizes.delete(cachedFile);
|
|
364
369
|
}
|
|
365
370
|
}
|
|
@@ -367,10 +372,12 @@ var TranscriptManager = class _TranscriptManager {
|
|
|
367
372
|
if (cached.fileBytes.has(file.cacheKey)) continue;
|
|
368
373
|
try {
|
|
369
374
|
const fileInfo = await stat(file.path);
|
|
370
|
-
const
|
|
371
|
-
cached.fileBytes.set(file.cacheKey,
|
|
375
|
+
const estimate = await this.estimateSessionBytesInFile(file.path, sessionKey);
|
|
376
|
+
cached.fileBytes.set(file.cacheKey, estimate.bytes);
|
|
377
|
+
cached.fileTokens.set(file.cacheKey, estimate.tokens);
|
|
372
378
|
cached.fileSizes.set(file.cacheKey, Math.max(0, fileInfo.size));
|
|
373
|
-
bytes +=
|
|
379
|
+
bytes += estimate.bytes;
|
|
380
|
+
tokens += estimate.tokens;
|
|
374
381
|
} catch {
|
|
375
382
|
}
|
|
376
383
|
}
|
|
@@ -378,51 +385,54 @@ var TranscriptManager = class _TranscriptManager {
|
|
|
378
385
|
try {
|
|
379
386
|
const fileInfo = await stat(file.path);
|
|
380
387
|
const size = Math.max(0, fileInfo.size);
|
|
381
|
-
const
|
|
388
|
+
const previousEstimate = {
|
|
389
|
+
bytes: cached.fileBytes.get(file.cacheKey) ?? 0,
|
|
390
|
+
tokens: cached.fileTokens.get(file.cacheKey) ?? 0
|
|
391
|
+
};
|
|
382
392
|
const previousSize = cached.fileSizes.get(file.cacheKey) ?? -1;
|
|
383
393
|
if (size !== previousSize) {
|
|
384
|
-
const
|
|
385
|
-
cached.fileBytes.set(file.cacheKey,
|
|
394
|
+
const estimate = await this.estimateSessionBytesInFile(file.path, sessionKey);
|
|
395
|
+
cached.fileBytes.set(file.cacheKey, estimate.bytes);
|
|
396
|
+
cached.fileTokens.set(file.cacheKey, estimate.tokens);
|
|
386
397
|
cached.fileSizes.set(file.cacheKey, size);
|
|
387
|
-
bytes +=
|
|
398
|
+
bytes += estimate.bytes - previousEstimate.bytes;
|
|
399
|
+
tokens += estimate.tokens - previousEstimate.tokens;
|
|
388
400
|
}
|
|
389
401
|
} catch {
|
|
390
402
|
}
|
|
391
403
|
}
|
|
392
|
-
|
|
404
|
+
bytes = Math.max(0, bytes);
|
|
405
|
+
tokens = Math.max(0, tokens);
|
|
393
406
|
cached.totalBytes = bytes;
|
|
407
|
+
cached.totalTokens = tokens;
|
|
394
408
|
}
|
|
395
409
|
} catch {
|
|
396
410
|
this.sessionFootprintCache.delete(sessionKey);
|
|
397
411
|
}
|
|
398
|
-
return {
|
|
399
|
-
bytes,
|
|
400
|
-
tokens: Math.floor(bytes / _TranscriptManager.CHARS_PER_TOKEN)
|
|
401
|
-
};
|
|
412
|
+
return { bytes, tokens };
|
|
402
413
|
}
|
|
403
414
|
async estimateSessionBytesInFile(filePath, sessionKey) {
|
|
404
415
|
try {
|
|
405
416
|
const raw = await readFile(filePath, "utf-8");
|
|
406
|
-
let
|
|
417
|
+
let bytes = 0;
|
|
418
|
+
let tokens = 0;
|
|
407
419
|
for (const line of raw.split("\n")) {
|
|
408
420
|
if (!line.trim()) continue;
|
|
409
421
|
try {
|
|
410
422
|
const parsed = JSON.parse(line);
|
|
411
423
|
if (parsed.sessionKey === sessionKey) {
|
|
412
|
-
|
|
424
|
+
bytes += Buffer.byteLength(`${line}
|
|
413
425
|
`, "utf-8");
|
|
426
|
+
if (typeof parsed.content === "string") tokens += estimateTokenCount(parsed.content);
|
|
414
427
|
}
|
|
415
428
|
} catch {
|
|
416
429
|
}
|
|
417
430
|
}
|
|
418
|
-
return
|
|
431
|
+
return { bytes, tokens };
|
|
419
432
|
} catch {
|
|
420
|
-
return 0;
|
|
433
|
+
return { bytes: 0, tokens: 0 };
|
|
421
434
|
}
|
|
422
435
|
}
|
|
423
|
-
/**
|
|
424
|
-
* Check if a file is a legacy flat transcript file (YYYY-MM-DD.jsonl format).
|
|
425
|
-
*/
|
|
426
436
|
isLegacyTranscriptFile(filename) {
|
|
427
437
|
return /^\d{4}-\d{2}-\d{2}\.jsonl$/.test(filename);
|
|
428
438
|
}
|
|
@@ -808,7 +818,8 @@ var TranscriptManager = class _TranscriptManager {
|
|
|
808
818
|
if (entries.length === 0) {
|
|
809
819
|
return "";
|
|
810
820
|
}
|
|
811
|
-
const
|
|
821
|
+
const maxTokenBudget = Math.max(0, Math.floor(maxTokens));
|
|
822
|
+
if (maxTokenBudget === 0) return "";
|
|
812
823
|
const lines = [];
|
|
813
824
|
const firstEntry = new Date(entries[0].timestamp);
|
|
814
825
|
const lastEntry = new Date(entries[entries.length - 1].timestamp);
|
|
@@ -819,6 +830,9 @@ var TranscriptManager = class _TranscriptManager {
|
|
|
819
830
|
lines.push(`## Recent Conversation (last ${hoursDiff} hour${hoursDiff === 1 ? "" : "s"})`);
|
|
820
831
|
}
|
|
821
832
|
lines.push("");
|
|
833
|
+
if (estimateTokenCount(lines.join("\n")) > maxTokenBudget) {
|
|
834
|
+
return "";
|
|
835
|
+
}
|
|
822
836
|
const formattedEntries = [];
|
|
823
837
|
for (const entry of entries) {
|
|
824
838
|
const time = new Date(entry.timestamp);
|
|
@@ -830,17 +844,17 @@ var TranscriptManager = class _TranscriptManager {
|
|
|
830
844
|
const roleLabel = entry.role === "user" ? "User" : "Assistant";
|
|
831
845
|
formattedEntries.push(`[${timeStr}] ${roleLabel}: ${entry.content}`);
|
|
832
846
|
}
|
|
833
|
-
let totalChars = lines.join("\n").length;
|
|
834
847
|
const selectedEntries = [];
|
|
835
848
|
for (let i = formattedEntries.length - 1; i >= 0; i--) {
|
|
836
849
|
const entry = formattedEntries[i];
|
|
837
|
-
const
|
|
838
|
-
if (
|
|
839
|
-
break;
|
|
850
|
+
const candidate = [...lines, entry, ...selectedEntries, ""].join("\n");
|
|
851
|
+
if (estimateTokenCount(candidate) > maxTokenBudget) {
|
|
852
|
+
if (selectedEntries.length > 0) break;
|
|
853
|
+
return "";
|
|
840
854
|
}
|
|
841
855
|
selectedEntries.unshift(entry);
|
|
842
|
-
totalChars += entryChars;
|
|
843
856
|
}
|
|
857
|
+
if (selectedEntries.length === 0) return "";
|
|
844
858
|
lines.push(...selectedEntries);
|
|
845
859
|
lines.push("");
|
|
846
860
|
const result = lines.join("\n");
|
|
@@ -938,4 +952,4 @@ export {
|
|
|
938
952
|
utcDayRange,
|
|
939
953
|
TranscriptManager
|
|
940
954
|
};
|
|
941
|
-
//# sourceMappingURL=chunk-
|
|
955
|
+
//# sourceMappingURL=chunk-AM4T6CHX.js.map
|