@remnic/core 9.26.0 → 9.28.0
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 +13 -10
- package/dist/access-admin-ops-surface.js +43 -38
- package/dist/access-audit.js +2 -2
- package/dist/access-authorization-probe.d.ts +13 -10
- package/dist/access-authorization-probe.js +44 -39
- package/dist/access-boundary.d.ts +13 -10
- package/dist/access-boundary.js +43 -38
- package/dist/access-cli.js +100 -94
- package/dist/access-cli.js.map +1 -1
- package/dist/access-health-types.d.ts +10 -1
- package/dist/access-http-lcm-compaction.d.ts +13 -10
- package/dist/access-http.d.ts +13 -10
- package/dist/access-http.js +53 -48
- package/dist/access-identity-continuity-surface.d.ts +9 -8
- package/dist/access-identity-continuity-surface.js +43 -38
- package/dist/access-lcm-surface.d.ts +13 -10
- package/dist/access-lcm-surface.js +43 -38
- package/dist/access-mcp.d.ts +13 -10
- package/dist/access-mcp.js +48 -43
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-wRSZEO5V.d.ts → access-namespace-preflight-BiQ_-iUJ.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +43 -38
- package/dist/access-observe-write-surface.d.ts +13 -10
- package/dist/access-observe-write-surface.js +43 -38
- package/dist/access-operations-batch.js +45 -40
- package/dist/access-operations.d.ts +16 -13
- package/dist/access-operations.js +47 -42
- package/dist/access-recall-concurrency.d.ts +13 -10
- package/dist/access-recall-concurrency.js +43 -38
- package/dist/access-recall-response.d.ts +13 -10
- package/dist/access-recall-response.js +43 -38
- package/dist/access-recall-surface.d.ts +13 -10
- package/dist/access-recall-surface.js +43 -38
- package/dist/access-schema.d.ts +80 -80
- package/dist/access-schema.js +4 -4
- package/dist/{access-service-DL8FJnTj.d.ts → access-service-CXkIgcGh.d.ts} +12 -8
- package/dist/access-service.d.ts +13 -10
- package/dist/access-service.js +43 -38
- package/dist/access-surface-catalog.d.ts +13 -10
- package/dist/access-wearables-meetings-surface.d.ts +4 -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 +4 -2
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +9 -8
- package/dist/briefing.d.ts +3 -2
- package/dist/briefing.js +12 -10
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +3 -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-7FJQINUR.js} +2 -2
- package/dist/{catalog-BLLxZ5L5.d.ts → catalog-Bouj8Gfg.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +13 -11
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-7RZJWZ46.js → chunk-227UFSEQ.js} +5 -5
- package/dist/{chunk-VGEH3STZ.js → chunk-2BEJ4XCF.js} +2 -2
- package/dist/{chunk-LIIQPDFN.js → chunk-2FYNLDKJ.js} +24 -3
- package/dist/chunk-2FYNLDKJ.js.map +1 -0
- package/dist/{chunk-BXLOS5AJ.js → chunk-2NLLXCJG.js} +2 -2
- package/dist/{chunk-6NNNURLK.js → chunk-2PHX3I5C.js} +8 -8
- package/dist/{chunk-YN4AUGNF.js → chunk-2TQ2UFKH.js} +65 -60
- package/dist/chunk-2TQ2UFKH.js.map +1 -0
- package/dist/{chunk-XAAIUXJO.js → chunk-3BSJBIZ3.js} +2 -2
- package/dist/{chunk-JCVQV6QX.js → chunk-3UOSVTFR.js} +11 -11
- package/dist/{chunk-AJ7QCSIS.js → chunk-7CPOZH6Y.js} +2 -2
- package/dist/{chunk-EXM2Q555.js → chunk-AHFZXUZM.js} +7 -5
- package/dist/chunk-AHFZXUZM.js.map +1 -0
- package/dist/{chunk-M2KGXXTL.js → chunk-ALTP3MFS.js} +2 -2
- package/dist/{chunk-77CNV7DY.js → chunk-BLAKS3CP.js} +4 -4
- package/dist/{chunk-FE5FKTCI.js → chunk-BR4UFMLO.js} +2 -2
- package/dist/chunk-CVILPI77.js +432 -0
- package/dist/chunk-CVILPI77.js.map +1 -0
- package/dist/{chunk-H2PBM562.js → chunk-DKQM5Q6Q.js} +2 -2
- package/dist/{chunk-CSXHRAJJ.js → chunk-EG64LXKL.js} +3 -3
- package/dist/{chunk-PTN6UAUA.js → chunk-ES36HTSC.js} +4 -4
- package/dist/{chunk-WMDRLTNA.js → chunk-EZWWCN7I.js} +2 -2
- package/dist/{chunk-XKGPIWGI.js → chunk-FBZTWUK5.js} +5 -5
- package/dist/{chunk-GJJBPI6I.js → chunk-FOCEI3TN.js} +6 -3
- package/dist/chunk-FOCEI3TN.js.map +1 -0
- package/dist/{chunk-Y6E37WRG.js → chunk-GJPCP5CA.js} +2 -2
- package/dist/{chunk-IHMXPG4P.js → chunk-GQSMYXKL.js} +6 -4
- package/dist/{chunk-IHMXPG4P.js.map → chunk-GQSMYXKL.js.map} +1 -1
- package/dist/{chunk-TGQ2NTWH.js → chunk-IJ6WHMFB.js} +16 -2
- package/dist/{chunk-TGQ2NTWH.js.map → chunk-IJ6WHMFB.js.map} +1 -1
- package/dist/{chunk-VDX2J7OX.js → chunk-IPLYGWQF.js} +6 -6
- package/dist/{chunk-XNUBF6RF.js → chunk-IYT632D5.js} +3 -3
- package/dist/{chunk-2QSZNTDO.js → chunk-JBPKEARU.js} +7 -7
- package/dist/{chunk-67DSDRUB.js → chunk-JIF3VRKQ.js} +8 -8
- package/dist/{chunk-V25OWXAC.js → chunk-JQ7T5VDC.js} +1 -1
- package/dist/chunk-JQ7T5VDC.js.map +1 -0
- package/dist/{chunk-MIFF37NN.js → chunk-KKBTBUVT.js} +2 -2
- package/dist/{chunk-ZHP4SUPB.js → chunk-LIHC3T43.js} +2 -2
- package/dist/{chunk-PX7VDW7R.js → chunk-MJPV4LBH.js} +79 -79
- package/dist/{chunk-PX7VDW7R.js.map → chunk-MJPV4LBH.js.map} +1 -1
- package/dist/{chunk-UGH6VPPO.js → chunk-MWTMTW2T.js} +2 -2
- package/dist/{chunk-F6LSNPPB.js → chunk-MXJ3VP6S.js} +6 -6
- package/dist/{chunk-KPWLZBXZ.js → chunk-NBNDVNJ2.js} +186 -25
- package/dist/chunk-NBNDVNJ2.js.map +1 -0
- package/dist/{chunk-M5EPMNS4.js → chunk-P2CLYN6H.js} +2 -2
- package/dist/{chunk-7XXCIO6X.js → chunk-PXQM2HOG.js} +13 -6
- package/dist/{chunk-7XXCIO6X.js.map → chunk-PXQM2HOG.js.map} +1 -1
- package/dist/{chunk-UZK7VVPD.js → chunk-Q5VJUNXA.js} +1858 -272
- package/dist/chunk-Q5VJUNXA.js.map +1 -0
- package/dist/{chunk-KGTD2KZJ.js → chunk-Q6YJW6KE.js} +2 -2
- package/dist/{chunk-X3SQYAPP.js → chunk-R372P2EH.js} +2 -2
- package/dist/{chunk-HBVOJNV4.js → chunk-RKXZ7P4V.js} +3 -3
- package/dist/chunk-RMMVQQA6.js +70 -0
- package/dist/chunk-RMMVQQA6.js.map +1 -0
- package/dist/{chunk-E6EAB4J6.js → chunk-S24E4MBQ.js} +14 -14
- package/dist/chunk-S24E4MBQ.js.map +1 -0
- package/dist/{chunk-RYHWZ52A.js → chunk-S2BBISHU.js} +4 -4
- package/dist/{chunk-LLISELSY.js → chunk-TBMRQZDY.js} +2 -2
- package/dist/{chunk-FMLKOL2Z.js → chunk-TC3VNKGX.js} +4 -4
- package/dist/{chunk-7K5Q6COX.js → chunk-TVVEYCNW.js} +4 -4
- package/dist/{chunk-2XP3PWL3.js → chunk-UR5SIN7H.js} +53 -35
- package/dist/chunk-UR5SIN7H.js.map +1 -0
- package/dist/{chunk-NKDVXEFU.js → chunk-VFNI3RPT.js} +2 -2
- package/dist/chunk-VNA7W7QF.js +134 -0
- package/dist/chunk-VNA7W7QF.js.map +1 -0
- package/dist/{chunk-PQPSZICJ.js → chunk-VYYNBJXH.js} +5 -5
- package/dist/chunk-WNIUPHWV.js +152 -0
- package/dist/chunk-WNIUPHWV.js.map +1 -0
- package/dist/chunk-WRJVB3C2.js +118 -0
- package/dist/chunk-WRJVB3C2.js.map +1 -0
- package/dist/{chunk-SN3ZESWQ.js → chunk-WVVK2RFM.js} +6 -6
- package/dist/{chunk-DQEMWVMT.js → chunk-X7Y7WX73.js} +1 -1
- package/dist/{chunk-4KKV7W62.js → chunk-YOBNCD3Z.js} +6 -6
- package/dist/chunk-YXZG5TVN.js +40 -0
- package/dist/chunk-YXZG5TVN.js.map +1 -0
- package/dist/{chunk-4DJQYKMN.js → chunk-ZIKENA2C.js} +2 -2
- package/dist/chunk-ZIKENA2C.js.map +1 -0
- package/dist/{chunk-SK3EYPKC.js → chunk-ZN4UZWMT.js} +2 -2
- package/dist/{cli-BoouX6LX.d.ts → cli-DJbkaZBU.d.ts} +5 -5
- package/dist/cli.d.ts +14 -12
- package/dist/cli.js +79 -74
- package/dist/compounding/engine.d.ts +3 -2
- package/dist/compounding/engine.js +12 -10
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +4 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +12 -10
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +12 -10
- package/dist/consolidation-provenance-check.d.ts +3 -2
- package/dist/consolidation-undo.d.ts +3 -2
- package/dist/contradiction/index.d.ts +3 -2
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/backend.js +2 -2
- 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 +15 -2
- package/dist/corpus-watermark.js +25 -21
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.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-id-normalization.d.ts +4 -0
- package/dist/entity-id-normalization.js +10 -0
- package/dist/entity-id-normalization.js.map +1 -0
- package/dist/entity-retrieval-boundaries.d.ts +3 -0
- package/dist/entity-retrieval-boundaries.js +8 -0
- package/dist/entity-retrieval-boundaries.js.map +1 -0
- package/dist/entity-retrieval.d.ts +3 -2
- package/dist/entity-retrieval.js +13 -10
- package/dist/entity-schema.d.ts +1 -1
- package/dist/entity-schema.js +1 -1
- package/dist/explicit-capture.d.ts +9 -8
- 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.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-LEXL3XYL.js → first-start-migration-BKNGOFED.js} +4 -4
- 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-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +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 +409 -407
- package/dist/index.js +147 -141
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +9 -9
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -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 +12 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +12 -10
- package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-projection.js +13 -11
- package/dist/{maintenance-DD22oIx9.d.ts → maintenance-DveW6azo.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +13 -10
- 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-mutations.d.ts +4 -0
- package/dist/memory-projection-mutations.js +15 -0
- package/dist/memory-projection-mutations.js.map +1 -0
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +3 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +4 -3
- package/dist/namespaces/migrate.js +22 -20
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +9 -9
- package/dist/namespaces/storage.d.ts +4 -3
- package/dist/namespaces/storage.js +12 -10
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/offline-sync-impression-drain.js +3 -3
- package/dist/operator-doctor-corpus.d.ts +22 -3
- package/dist/operator-doctor-corpus.js +32 -22
- package/dist/operator-doctor-replica.d.ts +52 -0
- package/dist/operator-doctor-replica.js +15 -0
- package/dist/operator-doctor-replica.js.map +1 -0
- package/dist/operator-toolkit.d.ts +7 -3
- package/dist/operator-toolkit.js +33 -27
- package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
- package/dist/orchestration/maintenance.d.ts +5 -4
- package/dist/orchestration/maintenance.js +17 -15
- package/dist/{orchestrator-CFJ_TG6D.d.ts → orchestrator-Cvlgpe6I.d.ts} +7 -7
- package/dist/orchestrator.d.ts +9 -8
- package/dist/orchestrator.js +99 -93
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-Bq5zU6Bp.d.ts → pipeline-BveYVaz7.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/{qmd-3ILJkC70.d.ts → qmd-CLWDsbYR.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 +3 -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-state.js +2 -2
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/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 +279 -0
- package/dist/replica-divergence.js +28 -0
- package/dist/replica-divergence.js.map +1 -0
- package/dist/replica-peers-config.d.ts +5 -0
- package/dist/replica-peers-config.js +13 -0
- package/dist/replica-peers-config.js.map +1 -0
- package/dist/resolve-auth-token.d.ts +21 -2
- package/dist/resolve-auth-token.js +5 -1
- package/dist/resume-bundles.js +5 -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 +76 -76
- package/dist/{scope-profiles-D0-ff4xT.d.ts → scope-profiles-BVf3DZ7z.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 +8 -8
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +13 -13
- 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-consolidation-4Tfh7c1g.d.ts → semantic-consolidation-DXLV47y2.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +13 -11
- package/dist/semantic-rule-promotion.js +12 -10
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +12 -10
- package/dist/{service-Z8uzoAST.d.ts → service-DbgPTeMJ.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +9 -9
- package/dist/signal.d.ts +1 -1
- package/dist/{storage-BZVMn8yJ.d.ts → storage-DOzTm8wG.d.ts} +13 -22
- package/dist/storage.d.ts +3 -2
- package/dist/storage.js +13 -10
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +3 -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 +3 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/autodetect.js +1 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +3 -3
- 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-DHBxIF0s.d.ts → types-BA7W-_xy.d.ts} +53 -4
- 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 +12 -10
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +2 -2
- package/src/access-health-types.ts +8 -0
- package/src/access-http.test.ts +4 -0
- package/src/access-service-health.test.ts +23 -0
- package/src/access-service.ts +27 -4
- package/src/cli.ts +9 -7
- package/src/config.ts +2 -1
- package/src/corpus-watermark.test.ts +21 -0
- package/src/corpus-watermark.ts +25 -3
- package/src/entity-id-normalization.ts +55 -0
- package/src/entity-retrieval-boundaries.ts +134 -0
- package/src/entity-retrieval.ts +253 -27
- package/src/entity-schema.ts +2 -1
- package/src/memory-projection-mutations.ts +132 -0
- package/src/namespaces/storage.ts +5 -3
- package/src/operator-doctor-corpus.ts +41 -0
- package/src/operator-doctor-replica.test.ts +261 -0
- package/src/operator-doctor-replica.ts +129 -0
- package/src/operator-toolkit.ts +5 -4
- package/src/orchestration/orchestrator-init.ts +2 -2
- package/src/replica-divergence.test.ts +1475 -0
- package/src/replica-divergence.ts +910 -0
- package/src/replica-peers-config.ts +250 -0
- package/src/resolve-auth-token.ts +38 -0
- package/src/storage/entity-canonical-id-migration-adapter.ts +72 -0
- package/src/storage/entity-canonical-id-migration-runner.ts +68 -0
- package/src/storage/entity-canonical-id-migration.ts +904 -0
- package/src/storage/entity-store.ts +44 -0
- package/src/storage/memory-frontmatter-metadata.ts +17 -0
- package/src/storage/memory-migration-serialization.ts +37 -0
- package/src/storage/memory-read-store.ts +3 -2
- package/src/storage/profile-header.ts +898 -0
- package/src/storage-profile-timestamp.test.ts +3358 -0
- package/src/storage.ts +73 -77
- package/src/testing/subjects/profile-header-write.test.ts +71 -0
- package/src/types.ts +3 -3
- package/dist/chunk-2XP3PWL3.js.map +0 -1
- package/dist/chunk-4DJQYKMN.js.map +0 -1
- package/dist/chunk-E6EAB4J6.js.map +0 -1
- package/dist/chunk-EXM2Q555.js.map +0 -1
- package/dist/chunk-GJJBPI6I.js.map +0 -1
- package/dist/chunk-KPWLZBXZ.js.map +0 -1
- package/dist/chunk-LIIQPDFN.js.map +0 -1
- package/dist/chunk-UZK7VVPD.js.map +0 -1
- package/dist/chunk-V25OWXAC.js.map +0 -1
- package/dist/chunk-YN4AUGNF.js.map +0 -1
- /package/dist/{capsule-crypto-YO5QJ6L3.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
- /package/dist/{chunk-7RZJWZ46.js.map → chunk-227UFSEQ.js.map} +0 -0
- /package/dist/{chunk-VGEH3STZ.js.map → chunk-2BEJ4XCF.js.map} +0 -0
- /package/dist/{chunk-BXLOS5AJ.js.map → chunk-2NLLXCJG.js.map} +0 -0
- /package/dist/{chunk-6NNNURLK.js.map → chunk-2PHX3I5C.js.map} +0 -0
- /package/dist/{chunk-XAAIUXJO.js.map → chunk-3BSJBIZ3.js.map} +0 -0
- /package/dist/{chunk-JCVQV6QX.js.map → chunk-3UOSVTFR.js.map} +0 -0
- /package/dist/{chunk-AJ7QCSIS.js.map → chunk-7CPOZH6Y.js.map} +0 -0
- /package/dist/{chunk-M2KGXXTL.js.map → chunk-ALTP3MFS.js.map} +0 -0
- /package/dist/{chunk-77CNV7DY.js.map → chunk-BLAKS3CP.js.map} +0 -0
- /package/dist/{chunk-FE5FKTCI.js.map → chunk-BR4UFMLO.js.map} +0 -0
- /package/dist/{chunk-H2PBM562.js.map → chunk-DKQM5Q6Q.js.map} +0 -0
- /package/dist/{chunk-CSXHRAJJ.js.map → chunk-EG64LXKL.js.map} +0 -0
- /package/dist/{chunk-PTN6UAUA.js.map → chunk-ES36HTSC.js.map} +0 -0
- /package/dist/{chunk-WMDRLTNA.js.map → chunk-EZWWCN7I.js.map} +0 -0
- /package/dist/{chunk-XKGPIWGI.js.map → chunk-FBZTWUK5.js.map} +0 -0
- /package/dist/{chunk-Y6E37WRG.js.map → chunk-GJPCP5CA.js.map} +0 -0
- /package/dist/{chunk-VDX2J7OX.js.map → chunk-IPLYGWQF.js.map} +0 -0
- /package/dist/{chunk-XNUBF6RF.js.map → chunk-IYT632D5.js.map} +0 -0
- /package/dist/{chunk-2QSZNTDO.js.map → chunk-JBPKEARU.js.map} +0 -0
- /package/dist/{chunk-67DSDRUB.js.map → chunk-JIF3VRKQ.js.map} +0 -0
- /package/dist/{chunk-MIFF37NN.js.map → chunk-KKBTBUVT.js.map} +0 -0
- /package/dist/{chunk-ZHP4SUPB.js.map → chunk-LIHC3T43.js.map} +0 -0
- /package/dist/{chunk-UGH6VPPO.js.map → chunk-MWTMTW2T.js.map} +0 -0
- /package/dist/{chunk-F6LSNPPB.js.map → chunk-MXJ3VP6S.js.map} +0 -0
- /package/dist/{chunk-M5EPMNS4.js.map → chunk-P2CLYN6H.js.map} +0 -0
- /package/dist/{chunk-KGTD2KZJ.js.map → chunk-Q6YJW6KE.js.map} +0 -0
- /package/dist/{chunk-X3SQYAPP.js.map → chunk-R372P2EH.js.map} +0 -0
- /package/dist/{chunk-HBVOJNV4.js.map → chunk-RKXZ7P4V.js.map} +0 -0
- /package/dist/{chunk-RYHWZ52A.js.map → chunk-S2BBISHU.js.map} +0 -0
- /package/dist/{chunk-LLISELSY.js.map → chunk-TBMRQZDY.js.map} +0 -0
- /package/dist/{chunk-FMLKOL2Z.js.map → chunk-TC3VNKGX.js.map} +0 -0
- /package/dist/{chunk-7K5Q6COX.js.map → chunk-TVVEYCNW.js.map} +0 -0
- /package/dist/{chunk-NKDVXEFU.js.map → chunk-VFNI3RPT.js.map} +0 -0
- /package/dist/{chunk-PQPSZICJ.js.map → chunk-VYYNBJXH.js.map} +0 -0
- /package/dist/{chunk-SN3ZESWQ.js.map → chunk-WVVK2RFM.js.map} +0 -0
- /package/dist/{chunk-DQEMWVMT.js.map → chunk-X7Y7WX73.js.map} +0 -0
- /package/dist/{chunk-4KKV7W62.js.map → chunk-YOBNCD3Z.js.map} +0 -0
- /package/dist/{chunk-SK3EYPKC.js.map → chunk-ZN4UZWMT.js.map} +0 -0
- /package/dist/{first-start-migration-LEXL3XYL.js.map → first-start-migration-BKNGOFED.js.map} +0 -0
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { aR as AccessTrackingEntry, a0 as ActiveRecallChatType, a4 as ActiveRecallModelFallbackPolicy, a2 as ActiveRecallPromptStyle, a1 as ActiveRecallQueryMode, a3 as ActiveRecallThinking, t as AgentAccessAuthToken, c9 as AgentAccessHttpConfig, ca as AgentDefaultsConfig, cb as AgentPersona, A as AgentPersonaModelConfig, cc as BehaviorLoopAdjustment, r as BehaviorLoopPolicyState, cd as BehaviorSignalDirection, a5 as BehaviorSignalEvent, ce as BehaviorSignalType, ba as BootstrapOptions, bb as BootstrapResult, g as BriefingActiveThread, cf as BriefingCalendarSourceError, bv as BriefingConfig, e as BriefingFocus, d as BriefingFollowup, bw as BriefingOpenCommitment, i as BriefingRecentEntity, h as BriefingResult, B as BriefingSections, bx as BriefingWindow, cg as BufferEntryState, aM as BufferState, a6 as BufferSurpriseEvent, j as BufferTurn, f as CalendarEvent, C as CalendarSource, ch as CaptureMode, ci as ChatConfig, m as Checkpoint, cj as CodexCliReasoningEffort, ck as CodexCompactionFlushMode, bA as CodexCompatConfig, cl as CodexConnectorConfig, b7 as CodingContext, cm as CodingGraphLspConfig, bj as CodingKnowledgeConfig, bd as CodingModeConfig, cn as CompressionGuidelineActivationState, ac as CompressionGuidelineOptimizerActionSummary, ab as CompressionGuidelineOptimizerEventCounts, ad as CompressionGuidelineOptimizerRuleUpdate, co as CompressionGuidelineOptimizerSourceWindow, ag as CompressionGuidelineOptimizerState, cp as ConfidenceTier, cq as ConsolidationAction, cr as ConsolidationItem, bc as ConsolidationObservation, J as ConsolidationResult, cs as ContradictionScanConfig, U as ConversationThread, ct as CronConversationRecallMode, cu as CronRecallMode, bB as DEFAULT_RECALL_DISCLOSURE, K as DaySummaryResult, cv as DreamingConfig, cw as DreamingNarrativePromptStyle, cx as DreamsDeepSleepConfig, cy as DreamsLightSleepConfig, D as DreamsPhase, cz as DreamsPhaseStatus, cA as DreamsPhasesConfig, cB as DreamsRemConfig, a as DreamsRunResult, b8 as DreamsStatusResult, cC as EngramTraceEvent, aQ as EntityActivityEntry, E as EntityFile, ah as EntityMention, aP as EntityRelationship, ai as EntitySchemaDefinition, aj as EntitySchemaSectionDefinition, ak as EntityStructuredSection, aK as EntityTimelineEntry, bD as ExtractedFact, cD as ExtractedProcedureStep, cE as ExtractedQuestion, cF as ExtractedReasoningTrace, cG as ExtractedReasoningTraceStep, cH as ExtractedRelationship, _ as ExtractionFailureClass, cI as ExtractionPassSource, z as ExtractionResult, F as FaithfulnessFrontmatter, aO as FileHygieneConfig, G as GatewayConfig, cJ as GitHubLiveConnectorConfig, cK as GmailLiveConnectorConfig, cL as GoogleDriveLiveConnectorConfig, cM as HeartbeatConfig, cN as HeartbeatDetectionMode, H as HourlySummary, I as IdentityInjectionMode, $ as ImportanceLevel, al as ImportanceScore, V as LifecycleState, L as LiveConnectorsConfig, cO as LlmTraceCallback, cP as LlmTraceEvent, an as MemoryActionEligibilityContext, bM as MemoryActionEligibilitySource, af as MemoryActionEvent, cQ as MemoryActionOutcome, cR as MemoryActionPolicyDecision, ao as MemoryActionPolicyResult, cS as MemoryActionStatus, ae as MemoryActionType, v as MemoryCategory, M as MemoryFile, l as MemoryFrontmatter, am as MemoryIntent, y as MemoryLifecycleEvent, ap as MemoryLifecycleEventType, aq as MemoryLifecycleStateSummary, aL as MemoryLink, cT as MemoryLinkType, bN as MemoryObservation, cU as MemoryOsPresetName, x as MemoryProjectionCurrentState, bO as MemoryScope, w as MemoryStatus, aS as MemorySummary, aN as MetaState, cV as ModelApi, cW as ModelDefinitionConfig, cX as ModelProviderAuthMode, ar as ModelProviderConfig, cY as NamespacePolicy, as as NativeKnowledgeConfig, cZ as NativeKnowledgeFolderRuleConfig, c_ as NativeKnowledgeObsidianVaultConfig, c$ as NativeKnowledgeOpenClawWorkspaceConfig, d0 as NotionLiveConnectorConfig, P as PluginConfig, X as PolicyClass, d1 as PrincipalFromSessionKeyMode, d2 as PrincipalRule, d3 as ProceduralConfig, av as ProvenanceConfig, N as ProvenanceSource, az as QmdSearchExplain, Q as QmdSearchResult, d4 as QuestionEntry, bP as RECALL_DISCLOSURE_LEVELS, d5 as ReasoningEffort, b as RecallDisclosure, d6 as RecallPipelineConfig, R as RecallPlanMode, b9 as RecallSectionConfig, c as RecallTierExplain, d7 as RecallTraceEvent, d8 as RelevanceFeedback, aw as RetrievalTier, d9 as SPECULATIVE_TTL_DAYS, da as ScopeProfileAutoPromoteConfig, o as ScopeProfileConfig, p as ScopeProfileLayerId, q as ScopeProfilePromotionTarget, db as ScopeProfileTeamProjectConfig, dc as ScopeTeamConfig, dd as ScoredEntity, s as SecretRef, de as SemanticChunkingConfigShape, S as SessionObserverBandConfig, df as SignalLevel, ax as SignalScanResult, dg as SlotBehaviorConfig, dh as SlotMismatchMode, n as SourceConnectorProvenance, ay as TopicScore, T as TranscriptEntry, di as TriggerMode, O as TrustWeights, W as VerificationState, dj as confidenceTier, bX as isRecallDisclosure } from './types-BA7W-_xy.js';
|
|
2
2
|
import './message-parts/index.js';
|
|
3
3
|
import './bounded-jsonl-state.js';
|
|
4
4
|
export { ContinuityImprovementLoop, ContinuityIncidentCloseInput, ContinuityIncidentOpenInput, ContinuityIncidentRecord, ContinuityIncidentState, ContinuityLoopCadence, ContinuityLoopReviewInput, ContinuityLoopStatus, ContinuityLoopUpsertInput } from './types-continuity.js';
|
package/dist/types.js
CHANGED
package/dist/verified-recall.js
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
import {
|
|
2
2
|
compareVerifiedEpisodeResults,
|
|
3
3
|
searchVerifiedEpisodes
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2BEJ4XCF.js";
|
|
5
5
|
import "./chunk-B7RWBZXW.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-UHVXE24Y.js";
|
|
6
|
+
import "./chunk-Q5VJUNXA.js";
|
|
8
7
|
import "./chunk-2QMKMVHH.js";
|
|
8
|
+
import "./chunk-UHVXE24Y.js";
|
|
9
9
|
import "./chunk-DEBHXHJR.js";
|
|
10
10
|
import "./chunk-DNHVPZOD.js";
|
|
11
11
|
import "./chunk-6CIAGZ6X.js";
|
|
12
|
-
import "./chunk-HKF5VASQ.js";
|
|
13
12
|
import "./chunk-J6A3CX5N.js";
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-HKF5VASQ.js";
|
|
14
|
+
import "./chunk-JQ7T5VDC.js";
|
|
15
|
+
import "./chunk-FBZTWUK5.js";
|
|
16
16
|
import "./chunk-EGGE52UU.js";
|
|
17
|
-
import "./chunk-GCASGYIO.js";
|
|
18
17
|
import "./chunk-WL5EBRDH.js";
|
|
19
18
|
import "./chunk-ILGC6JH6.js";
|
|
20
19
|
import "./chunk-SCU65EZI.js";
|
|
20
|
+
import "./chunk-WRJVB3C2.js";
|
|
21
|
+
import "./chunk-GCASGYIO.js";
|
|
21
22
|
import "./chunk-3CSX3ETE.js";
|
|
22
23
|
import "./chunk-RL6NEVXT.js";
|
|
23
24
|
import "./chunk-DM2T26WE.js";
|
|
24
25
|
import "./chunk-LDXUBPMO.js";
|
|
26
|
+
import "./chunk-JYIJNNN3.js";
|
|
27
|
+
import "./chunk-AAD2ZS6P.js";
|
|
25
28
|
import "./chunk-CGASUJVP.js";
|
|
26
29
|
import "./chunk-R3DJVOSM.js";
|
|
27
30
|
import "./chunk-BT7NVCML.js";
|
|
28
|
-
import "./chunk-
|
|
29
|
-
import "./chunk-AAD2ZS6P.js";
|
|
31
|
+
import "./chunk-YXZG5TVN.js";
|
|
30
32
|
import "./chunk-5VQJBH2G.js";
|
|
31
33
|
import "./chunk-AITCS2RC.js";
|
|
32
34
|
import "./chunk-XMMESCPD.js";
|
|
@@ -41,8 +43,8 @@ import "./chunk-45GF7Y3V.js";
|
|
|
41
43
|
import "./chunk-RGMVMVMF.js";
|
|
42
44
|
import "./chunk-N7RWREIQ.js";
|
|
43
45
|
import "./chunk-5I4M26Q7.js";
|
|
46
|
+
import "./chunk-ZIKENA2C.js";
|
|
44
47
|
import "./chunk-5GKPFL3S.js";
|
|
45
|
-
import "./chunk-4DJQYKMN.js";
|
|
46
48
|
import "./chunk-PQVCH2AE.js";
|
|
47
49
|
import "./chunk-EYIEWJNI.js";
|
|
48
50
|
import "./chunk-JUC24CTX.js";
|
package/dist/write-envelope.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/core",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.28.0",
|
|
4
4
|
"description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -3076,7 +3076,7 @@
|
|
|
3076
3076
|
"core"
|
|
3077
3077
|
],
|
|
3078
3078
|
"peerDependencies": {
|
|
3079
|
-
"@remnic/coding-graph": "^9.
|
|
3079
|
+
"@remnic/coding-graph": "^9.28.0"
|
|
3080
3080
|
},
|
|
3081
3081
|
"peerDependenciesMeta": {
|
|
3082
3082
|
"@remnic/coding-graph": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { ExtractionLivenessStatus } from "./extraction-liveness.js";
|
|
12
12
|
import type { CorpusWatermark } from "./corpus-watermark.js";
|
|
13
|
+
import type { ReplicaDivergenceStatus } from "./replica-divergence.js";
|
|
13
14
|
|
|
14
15
|
export interface EngramAccessHealthResponse {
|
|
15
16
|
ok: true;
|
|
@@ -23,6 +24,13 @@ export interface EngramAccessHealthResponse {
|
|
|
23
24
|
projectionAvailable: boolean;
|
|
24
25
|
extraction: ExtractionLivenessStatus;
|
|
25
26
|
corpus: CorpusWatermark[];
|
|
27
|
+
/**
|
|
28
|
+
* Whether `corpus` above is the COMPLETE census for this responder, from the
|
|
29
|
+
* same call that produced it. A polling peer must refuse to certify
|
|
30
|
+
* convergence against a partial array (issue #2149).
|
|
31
|
+
*/
|
|
32
|
+
corpusComplete: boolean;
|
|
33
|
+
replica: ReplicaDivergenceStatus;
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
export type EngramAccessQmdCollectionState =
|
package/src/access-http.test.ts
CHANGED
|
@@ -1870,6 +1870,8 @@ test("HTTP externalRequestHandler runs pre-auth, can end responses, and falls th
|
|
|
1870
1870
|
watermarkScope: "root-store",
|
|
1871
1871
|
},
|
|
1872
1872
|
corpus: [],
|
|
1873
|
+
corpusComplete: true,
|
|
1874
|
+
replica: { enabled: false, pending: false, polledAt: null, peers: [] },
|
|
1873
1875
|
}),
|
|
1874
1876
|
} satisfies Pick<EngramAccessService, "health">;
|
|
1875
1877
|
const service = healthStub as unknown as EngramAccessService;
|
|
@@ -1995,6 +1997,8 @@ test("HTTP authTokenEntriesGetter is authoritative: scope policy binds connector
|
|
|
1995
1997
|
watermarkScope: "root-store",
|
|
1996
1998
|
},
|
|
1997
1999
|
corpus: [],
|
|
2000
|
+
corpusComplete: true,
|
|
2001
|
+
replica: { enabled: false, pending: false, polledAt: null, peers: [] },
|
|
1998
2002
|
}),
|
|
1999
2003
|
} satisfies Pick<EngramAccessService, "health">;
|
|
2000
2004
|
const entries = [
|
|
@@ -108,6 +108,29 @@ test("health reports active QMD version and collection state", async () => {
|
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
+
test("health reports replica divergence disabled by default (no peers -> behaves as today)", async () => {
|
|
112
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-health-replica-"));
|
|
113
|
+
try {
|
|
114
|
+
const config = parseConfig({ memoryDir });
|
|
115
|
+
const service = new EngramAccessService({
|
|
116
|
+
config,
|
|
117
|
+
qmd: makeQmd({}),
|
|
118
|
+
async getStorage() {
|
|
119
|
+
return { dir: memoryDir };
|
|
120
|
+
},
|
|
121
|
+
} as unknown as Orchestrator);
|
|
122
|
+
|
|
123
|
+
const health = await service.health();
|
|
124
|
+
|
|
125
|
+
assert.equal(health.replica.enabled, false);
|
|
126
|
+
assert.equal(health.replica.pending, false);
|
|
127
|
+
assert.equal(health.replica.polledAt, null);
|
|
128
|
+
assert.equal(health.replica.peers.length, 0);
|
|
129
|
+
} finally {
|
|
130
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
111
134
|
test("health treats qmdEmbeddingBacklogThreshold 0 as backlog degradation disabled", async () => {
|
|
112
135
|
const config = parseConfig({ qmdEnabled: true, qmdEmbeddingBacklogThreshold: 0 });
|
|
113
136
|
const qmd = makeQmd({
|
package/src/access-service.ts
CHANGED
|
@@ -19,7 +19,9 @@ import { resolveNamespaceCapabilities,
|
|
|
19
19
|
resolveMemoryLifecycleCapabilities,
|
|
20
20
|
resolveQmdCapabilities,
|
|
21
21
|
resolveSecurityCapabilities, resolveObjectiveStateCapabilities, resolveCompressionCapabilities, resolveRecallAuxiliaryCapabilities } from "./capabilities.js";
|
|
22
|
-
import { CorpusWatermarkCache,
|
|
22
|
+
import { CorpusWatermarkCache, computeServiceCorpusCensus } from "./corpus-watermark.js";
|
|
23
|
+
import { ReplicaDivergenceMonitor } from "./replica-divergence.js";
|
|
24
|
+
import type { ResolveSecretRefFn } from "./resolve-auth-token.js";
|
|
23
25
|
import type {
|
|
24
26
|
EngramAccessHealthResponse,
|
|
25
27
|
EngramAccessQmdCollectionState,
|
|
@@ -1277,6 +1279,7 @@ export class EngramAccessService {
|
|
|
1277
1279
|
private readonly budget: CrossNamespaceBudget;
|
|
1278
1280
|
private readonly auditAdapter: AccessAuditAdapter | null;
|
|
1279
1281
|
private readonly corpusWatermarkCache = new CorpusWatermarkCache();
|
|
1282
|
+
private readonly replicaDivergenceMonitor: ReplicaDivergenceMonitor;
|
|
1280
1283
|
|
|
1281
1284
|
/** AccessObserveWriteSurface (access-service decomposition). Lazy; selfDeps live wiring. */
|
|
1282
1285
|
private _accessObserveWriteSurface: AccessObserveWriteSurface | undefined;
|
|
@@ -1339,8 +1342,13 @@ export class EngramAccessService {
|
|
|
1339
1342
|
}
|
|
1340
1343
|
private readonly extractionLivenessWarn = new ExtractionLivenessWarnThrottle();
|
|
1341
1344
|
|
|
1342
|
-
constructor(private readonly orchestrator: Orchestrator) {
|
|
1345
|
+
constructor(private readonly orchestrator: Orchestrator, options: { resolveSecretRef?: ResolveSecretRefFn | null } = {}) {
|
|
1343
1346
|
this.idempotency = new AccessIdempotencyStore(orchestrator.config.memoryDir);
|
|
1347
|
+
// Peer SecretRef tokens resolve at poll time through the host resolver, the
|
|
1348
|
+
// same indirection as agentAccessHttp.authToken (review round 1). Absent a
|
|
1349
|
+
// resolver, string/${ENV} tokens still work and a SecretRef degrades to a
|
|
1350
|
+
// per-peer `unreachable` (never a throw).
|
|
1351
|
+
this.replicaDivergenceMonitor = new ReplicaDivergenceMonitor({ resolveSecretRef: options.resolveSecretRef });
|
|
1344
1352
|
const accessCaps = resolveAccessSetupCapabilities(orchestrator.config); // #1566 Cluster B
|
|
1345
1353
|
this.budget = new CrossNamespaceBudget({
|
|
1346
1354
|
enabled: accessCaps.recallCrossNamespaceBudget,
|
|
@@ -2432,6 +2440,11 @@ export class EngramAccessService {
|
|
|
2432
2440
|
const searchBackend = this.orchestrator.config.searchBackend ?? "qmd";
|
|
2433
2441
|
const qmdEnabled = resolveQmdCapabilities(this.orchestrator.config).qmd === true;
|
|
2434
2442
|
const extraction = await computeExtractionLivenessStatus(this.orchestrator, this.extractionLivenessWarn);
|
|
2443
|
+
// ONE call: the corpus array and the flag describing it must not come from
|
|
2444
|
+
// two independently-cached scans (round 8, codex P1).
|
|
2445
|
+
const caps = tokenCapabilityStore.getStore();
|
|
2446
|
+
const corpusCensus = await computeServiceCorpusCensus(this.orchestrator, {
|
|
2447
|
+
cache: this.corpusWatermarkCache, caps });
|
|
2435
2448
|
let projectionAvailable = false;
|
|
2436
2449
|
try {
|
|
2437
2450
|
await stat(getMemoryProjectionPath(storage.dir));
|
|
@@ -2456,8 +2469,18 @@ export class EngramAccessService {
|
|
|
2456
2469
|
nativeKnowledgeEnabled: this.orchestrator.config.nativeKnowledge?.enabled === true,
|
|
2457
2470
|
projectionAvailable,
|
|
2458
2471
|
extraction,
|
|
2459
|
-
corpus:
|
|
2460
|
-
|
|
2472
|
+
corpus: corpusCensus.watermarks,
|
|
2473
|
+
// Describes THIS response's array (round 8): a separate scan could report
|
|
2474
|
+
// complete while the shipped corpus was partial, and peers trust it.
|
|
2475
|
+
corpusComplete: corpusCensus.complete,
|
|
2476
|
+
replica: this.replicaDivergenceMonitor.getReport({
|
|
2477
|
+
config: this.orchestrator.config.replicaPeers,
|
|
2478
|
+
// Capability-INDEPENDENT: this poll is cached instance-wide, so a
|
|
2479
|
+
// restricted caller's filtered census must never seed it (round 9).
|
|
2480
|
+
computeLocalWatermarks: () => computeServiceCorpusCensus(this.orchestrator, {}),
|
|
2481
|
+
caps,
|
|
2482
|
+
localCensusComplete: corpusCensus.complete,
|
|
2483
|
+
}),
|
|
2461
2484
|
};
|
|
2462
2485
|
}
|
|
2463
2486
|
|
package/src/cli.ts
CHANGED
|
@@ -115,6 +115,8 @@ import {
|
|
|
115
115
|
renderActionConfidenceText,
|
|
116
116
|
} from "./action-confidence.js";
|
|
117
117
|
import {
|
|
118
|
+
hostSecretRefResolver,
|
|
119
|
+
loadHostSecretRefResolver,
|
|
118
120
|
resolveAgentAccessAuthToken,
|
|
119
121
|
type ResolveSecretRefFn,
|
|
120
122
|
} from "./resolve-auth-token.js";
|
|
@@ -3797,7 +3799,8 @@ export function registerCli(
|
|
|
3797
3799
|
.option("--json", "Emit machine-readable JSON only")
|
|
3798
3800
|
.action(async (...args: unknown[]) => {
|
|
3799
3801
|
const options = (args[0] ?? {}) as Record<string, unknown>;
|
|
3800
|
-
const
|
|
3802
|
+
const resolveSecretRef = await loadHostSecretRefResolver(registerOptions);
|
|
3803
|
+
const report = await runOperatorDoctor({ orchestrator, resolveSecretRef });
|
|
3801
3804
|
if (reportHasMachineReadableOutput(options)) {
|
|
3802
3805
|
console.log(JSON.stringify(report, null, 2));
|
|
3803
3806
|
} else {
|
|
@@ -6767,7 +6770,10 @@ export function registerCli(
|
|
|
6767
6770
|
console.log("OK");
|
|
6768
6771
|
});
|
|
6769
6772
|
|
|
6770
|
-
|
|
6773
|
+
// /health's replica monitor resolves peer-token SecretRefs at poll time (#2149).
|
|
6774
|
+
const accessService = new EngramAccessService(orchestrator, {
|
|
6775
|
+
resolveSecretRef: hostSecretRefResolver(registerOptions),
|
|
6776
|
+
});
|
|
6771
6777
|
const accessCmd = cmd
|
|
6772
6778
|
.command("access")
|
|
6773
6779
|
.description("Manage Engram HTTP and MCP access surfaces");
|
|
@@ -6796,11 +6802,7 @@ export function registerCli(
|
|
|
6796
6802
|
typeof options.token === "string" && options.token.trim().length > 0
|
|
6797
6803
|
? options.token
|
|
6798
6804
|
: undefined;
|
|
6799
|
-
const resolveSecretRef =
|
|
6800
|
-
registerOptions.resolveSecretRef ??
|
|
6801
|
-
(registerOptions.loadResolveSecretRef
|
|
6802
|
-
? await registerOptions.loadResolveSecretRef()
|
|
6803
|
-
: null);
|
|
6805
|
+
const resolveSecretRef = await loadHostSecretRefResolver(registerOptions);
|
|
6804
6806
|
const resolvedConfigAuthToken = cliTokenOverride
|
|
6805
6807
|
? undefined
|
|
6806
6808
|
: await resolveAgentAccessAuthToken(
|
package/src/config.ts
CHANGED
|
@@ -38,6 +38,7 @@ import { expandTildePath } from "./utils/path.js";
|
|
|
38
38
|
import { coerceBool, coerceBooleanLike, coerceInstallExtension, coerceNumber } from "./connectors/coerce.js";
|
|
39
39
|
import { parseRecallConcurrencyConfig } from "./recall-concurrency-config.js";
|
|
40
40
|
import { parseExtractionLivenessConfig } from "./extraction-liveness.js";
|
|
41
|
+
import { parseReplicaPeersConfig } from "./replica-peers-config.js";
|
|
41
42
|
import { hasLegacyConnectorEntries } from "./connectors/paths.js";
|
|
42
43
|
import {
|
|
43
44
|
parseQmdChunkStrategy,
|
|
@@ -2335,6 +2336,7 @@ export function parseConfig(
|
|
|
2335
2336
|
dreamsPhases,
|
|
2336
2337
|
procedural,
|
|
2337
2338
|
extractionLiveness: parseExtractionLivenessConfig(cfg),
|
|
2339
|
+
replicaPeers: parseReplicaPeersConfig(cfg),
|
|
2338
2340
|
wearables,
|
|
2339
2341
|
meetings,
|
|
2340
2342
|
activity,
|
|
@@ -2349,7 +2351,6 @@ export function parseConfig(
|
|
|
2349
2351
|
codexCompat,
|
|
2350
2352
|
codingKnowledge: parseCodingKnowledgeConfig(cfg.codingKnowledge),
|
|
2351
2353
|
chat: parseChatConfig(cfg.chat),
|
|
2352
|
-
// Hourly summaries
|
|
2353
2354
|
hourlySummariesEnabled: cfg.hourlySummariesEnabled !== false, // default: true
|
|
2354
2355
|
daySummaryEnabled: cfg.daySummaryEnabled !== false, // default: true
|
|
2355
2356
|
hourlySummaryCronAutoRegister: cfg.hourlySummaryCronAutoRegister === true,
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
buildPartitionCensus,
|
|
26
26
|
computeCorpusWatermark,
|
|
27
27
|
computeCorpusWatermarks,
|
|
28
|
+
computeServiceCorpusCensus,
|
|
28
29
|
computeServiceCorpusWatermarks,
|
|
29
30
|
digestPartitionCensus,
|
|
30
31
|
resolveCorpusNamespaceRoots,
|
|
@@ -838,3 +839,23 @@ test("finding round-10: a non-directory category root fails a strict census (nam
|
|
|
838
839
|
await rm(memoryDir, { recursive: true, force: true });
|
|
839
840
|
}
|
|
840
841
|
});
|
|
842
|
+
|
|
843
|
+
test("round 6 (coderabbit): a failed namespace enumeration is an INCOMPLETE census, not an empty corpus", async () => {
|
|
844
|
+
// computeServiceCorpusCensus wraps resolveCorpusNamespaceRoots: when enumeration
|
|
845
|
+
// throws, the census must report complete:false (so a peer is never certified
|
|
846
|
+
// converged against it) rather than an empty set that reads as an empty deployment.
|
|
847
|
+
const throwingConfig = new Proxy({} as PluginConfig, {
|
|
848
|
+
get() {
|
|
849
|
+
throw new Error("namespace enumeration unavailable");
|
|
850
|
+
},
|
|
851
|
+
});
|
|
852
|
+
const host = {
|
|
853
|
+
config: throwingConfig,
|
|
854
|
+
getStorage: () => {
|
|
855
|
+
throw new Error("getStorage must not be reached once enumeration fails");
|
|
856
|
+
},
|
|
857
|
+
};
|
|
858
|
+
const census = await computeServiceCorpusCensus(host);
|
|
859
|
+
assert.equal(census.complete, false, "an enumeration failure is incomplete, never a certified empty census");
|
|
860
|
+
assert.deepEqual(census.watermarks, [], "and it yields no watermarks");
|
|
861
|
+
});
|
package/src/corpus-watermark.ts
CHANGED
|
@@ -500,6 +500,22 @@ export async function computeServiceCorpusWatermarks(
|
|
|
500
500
|
host: CorpusWatermarkHost,
|
|
501
501
|
options: ServiceCorpusWatermarkOptions = {},
|
|
502
502
|
): Promise<CorpusWatermark[]> {
|
|
503
|
+
return (await computeServiceCorpusCensus(host, options)).watermarks;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Watermarks PLUS whether every configured namespace made it into the set.
|
|
508
|
+
*
|
|
509
|
+
* Completeness is returned ATOMICALLY with the data rather than stashed in a
|
|
510
|
+
* side channel: every early exit here (enumeration threw, roots still warming,
|
|
511
|
+
* a per-namespace scan failed, a cache entry not yet populated) yields an
|
|
512
|
+
* incomplete set, and a caller that certifies convergence against a partial
|
|
513
|
+
* census would hide the divergence of whatever was dropped (issue #2149).
|
|
514
|
+
*/
|
|
515
|
+
export async function computeServiceCorpusCensus(
|
|
516
|
+
host: CorpusWatermarkHost,
|
|
517
|
+
options: ServiceCorpusWatermarkOptions = {},
|
|
518
|
+
): Promise<{ watermarks: CorpusWatermark[]; complete: boolean }> {
|
|
503
519
|
let roots: CorpusNamespaceRoot[] | undefined;
|
|
504
520
|
if (options.cache) {
|
|
505
521
|
roots = options.cache.getResolvedRoots(() => resolveCorpusNamespaceRoots({ config: host.config }));
|
|
@@ -507,25 +523,31 @@ export async function computeServiceCorpusWatermarks(
|
|
|
507
523
|
try {
|
|
508
524
|
roots = await resolveCorpusNamespaceRoots({ config: host.config });
|
|
509
525
|
} catch {
|
|
510
|
-
return [];
|
|
526
|
+
return { watermarks: [], complete: false }; // never enumerated — not an empty corpus
|
|
511
527
|
}
|
|
512
528
|
}
|
|
513
|
-
|
|
529
|
+
// Enumeration still warming (cold): served on a later probe, and NOT complete.
|
|
530
|
+
if (!roots) return { watermarks: [], complete: false };
|
|
514
531
|
const visible = roots.filter((root) => root.namespaces.some((ns) => capabilityAllowsNamespace(options.caps, ns)));
|
|
515
532
|
const watermarks: CorpusWatermark[] = [];
|
|
533
|
+
let complete = true;
|
|
516
534
|
for (const { namespace } of visible) {
|
|
517
535
|
const compute = async (): Promise<CorpusWatermark> =>
|
|
518
536
|
computeNamespaceWatermark(namespace, await host.getStorage(namespace), options.now);
|
|
519
537
|
if (options.cache) {
|
|
520
538
|
const cached = options.cache.get(namespace, compute);
|
|
521
539
|
if (cached) watermarks.push(cached);
|
|
540
|
+
else complete = false; // still warming — the set is not the full census yet
|
|
522
541
|
} else {
|
|
523
542
|
try {
|
|
524
543
|
watermarks.push(await compute());
|
|
525
544
|
} catch {
|
|
526
545
|
// One tenant's storage/scan failed — omit just that namespace.
|
|
546
|
+
complete = false;
|
|
527
547
|
}
|
|
528
548
|
}
|
|
529
549
|
}
|
|
530
|
-
return watermarks;
|
|
550
|
+
return { watermarks, complete };
|
|
531
551
|
}
|
|
552
|
+
|
|
553
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const BUILTIN_ALIASES: Record<string, string> = {
|
|
2
|
+
openclaw: "openclaw",
|
|
3
|
+
"open-claw": "openclaw",
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
function normalizeEntityNameWithPattern(
|
|
7
|
+
raw: string,
|
|
8
|
+
type: string,
|
|
9
|
+
aliases: Readonly<Record<string, string>> | undefined,
|
|
10
|
+
pattern: RegExp,
|
|
11
|
+
normalizeUnicode: boolean
|
|
12
|
+
): string {
|
|
13
|
+
const rawStr = typeof raw === "string" ? raw : "";
|
|
14
|
+
const typeStr = typeof type === "string" && type.trim().length > 0 ? type : "entity";
|
|
15
|
+
const typePrefix = `${typeStr.toLowerCase()}-`;
|
|
16
|
+
let name = normalizeUnicode ? rawStr.normalize("NFC").toLowerCase().trim() : rawStr.toLowerCase().trim();
|
|
17
|
+
if (name.startsWith(typePrefix)) name = name.slice(typePrefix.length);
|
|
18
|
+
|
|
19
|
+
let normalized = name.replace(pattern, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
20
|
+
let legacyNormalized: string | undefined;
|
|
21
|
+
if (normalizeUnicode) {
|
|
22
|
+
let legacyName = rawStr.toLowerCase().trim();
|
|
23
|
+
if (legacyName.startsWith(typePrefix)) legacyName = legacyName.slice(typePrefix.length);
|
|
24
|
+
legacyNormalized = legacyName.replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
25
|
+
}
|
|
26
|
+
const unicodeAlias = aliases !== undefined && Object.hasOwn(aliases, normalized) ? aliases[normalized] : undefined;
|
|
27
|
+
const legacyAlias =
|
|
28
|
+
legacyNormalized !== undefined && legacyNormalized !== normalized && aliases !== undefined &&
|
|
29
|
+
Object.hasOwn(aliases, legacyNormalized)
|
|
30
|
+
? aliases[legacyNormalized]
|
|
31
|
+
: undefined;
|
|
32
|
+
const userAlias =
|
|
33
|
+
typeof unicodeAlias === "string" && unicodeAlias.length > 0
|
|
34
|
+
? unicodeAlias
|
|
35
|
+
: legacyAlias;
|
|
36
|
+
if (typeof userAlias === "string" && userAlias.length > 0) {
|
|
37
|
+
normalized = userAlias;
|
|
38
|
+
} else if (Object.hasOwn(BUILTIN_ALIASES, normalized)) {
|
|
39
|
+
normalized = BUILTIN_ALIASES[normalized];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return `${typeStr.toLowerCase()}-${normalized}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function normalizeEntityName(raw: string, type: string, aliases?: Readonly<Record<string, string>>): string {
|
|
46
|
+
return normalizeEntityNameWithPattern(raw, type, aliases, /[^\p{L}\p{M}\p{N}]+/gu, true);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function normalizeLegacyEntityName(
|
|
50
|
+
raw: string,
|
|
51
|
+
type: string,
|
|
52
|
+
aliases?: Readonly<Record<string, string>>
|
|
53
|
+
): string {
|
|
54
|
+
return normalizeEntityNameWithPattern(raw, type, aliases, /[^a-z0-9]+/g, false);
|
|
55
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
const UNICODE_WORD_OR_NUMBER_RE = /[\p{L}\p{M}\p{N}]/u;
|
|
2
|
+
|
|
3
|
+
function firstUnicodeCharacter(value: string): string {
|
|
4
|
+
const codePoint = value.codePointAt(0);
|
|
5
|
+
return codePoint === undefined ? "" : String.fromCodePoint(codePoint);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function lastUnicodeCharacter(value: string): string {
|
|
9
|
+
const codePoint = [...value].at(-1);
|
|
10
|
+
return codePoint ?? "";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const JAPANESE_PARTICLE_RE = /^[のはがをにへともやかでだ]$/u;
|
|
14
|
+
const JAPANESE_MULTI_CHARACTER_PARTICLES = [
|
|
15
|
+
"について",
|
|
16
|
+
"にとって",
|
|
17
|
+
"によって",
|
|
18
|
+
"に関して",
|
|
19
|
+
"に対して",
|
|
20
|
+
"とは",
|
|
21
|
+
"では",
|
|
22
|
+
"には",
|
|
23
|
+
"にも",
|
|
24
|
+
"って",
|
|
25
|
+
] as const;
|
|
26
|
+
const KOREAN_PARTICLES = [
|
|
27
|
+
"에서", "에게", "한테", "으로", "까지", "부터", "보다", "처럼", "같이",
|
|
28
|
+
"이나", "라도", "밖에", "마다", "조차", "이랑", "하고", "은", "는",
|
|
29
|
+
"이", "가", "을", "를", "의", "께", "와", "과", "도", "만", "든",
|
|
30
|
+
"에", "로", "나", "랑",
|
|
31
|
+
] as const;
|
|
32
|
+
const KOREAN_UNSPACED_QUESTION_PARTICLES = ["은", "는", "이", "가"] as const;
|
|
33
|
+
const KOREAN_INTERROGATIVE_PREFIXES = [
|
|
34
|
+
"어디", "무엇", "뭐", "왜", "어떻게", "언제", "누구", "어느", "몇", "얼마",
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
const HANGUL_RUN_RE = /^[\p{Script=Hangul}]+/u;
|
|
38
|
+
|
|
39
|
+
const UNICODE_WORD_SEGMENTER =
|
|
40
|
+
typeof Intl.Segmenter === "function" ? new Intl.Segmenter(undefined, { granularity: "word" }) : null;
|
|
41
|
+
const KOREAN_WORD_SEGMENTER =
|
|
42
|
+
typeof Intl.Segmenter === "function" ? new Intl.Segmenter("ko", { granularity: "word" }) : null;
|
|
43
|
+
|
|
44
|
+
const JAPANESE_WORD_SEGMENTER =
|
|
45
|
+
typeof Intl.Segmenter === "function" ? new Intl.Segmenter("ja", { granularity: "word" }) : null;
|
|
46
|
+
const JAPANESE_KANA_RE = /[\p{Script=Hiragana}\p{Script=Katakana}]/u;
|
|
47
|
+
|
|
48
|
+
function isJapaneseParticleBoundary(suffix: string): boolean {
|
|
49
|
+
const firstSegment = JAPANESE_WORD_SEGMENTER?.segment(suffix).containing(0)?.segment;
|
|
50
|
+
if (firstSegment !== undefined) {
|
|
51
|
+
if (JAPANESE_MULTI_CHARACTER_PARTICLES.some((particle) => particle === firstSegment)) return true;
|
|
52
|
+
return JAPANESE_PARTICLE_RE.test(firstSegment);
|
|
53
|
+
}
|
|
54
|
+
const firstCharacter = firstUnicodeCharacter(suffix);
|
|
55
|
+
return (
|
|
56
|
+
JAPANESE_MULTI_CHARACTER_PARTICLES.some((particle) => suffix.startsWith(particle)) ||
|
|
57
|
+
(JAPANESE_PARTICLE_RE.test(firstCharacter) &&
|
|
58
|
+
!UNICODE_WORD_OR_NUMBER_RE.test(firstUnicodeCharacter(suffix.slice(firstCharacter.length))))
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function isIntlWordBoundary(source: string, index: number): boolean {
|
|
63
|
+
if (index <= 0 || index >= source.length) return true;
|
|
64
|
+
return UNICODE_WORD_SEGMENTER?.segment(source).containing(index)?.index === index;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isKoreanUnspacedQuestionBoundary(suffix: string): boolean {
|
|
68
|
+
return KOREAN_UNSPACED_QUESTION_PARTICLES.some((particle) =>
|
|
69
|
+
suffix.startsWith(particle) &&
|
|
70
|
+
KOREAN_INTERROGATIVE_PREFIXES.some((prefix) => suffix.startsWith(prefix, particle.length)),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function isKoreanParticleBoundary(suffix: string): boolean {
|
|
75
|
+
if (isKoreanUnspacedQuestionBoundary(suffix)) return true;
|
|
76
|
+
const firstSegment = KOREAN_WORD_SEGMENTER?.segment(suffix).containing(0)?.segment;
|
|
77
|
+
if (firstSegment !== undefined) {
|
|
78
|
+
return KOREAN_PARTICLES.some((particle) => particle === firstSegment);
|
|
79
|
+
}
|
|
80
|
+
const particleRun = suffix.match(HANGUL_RUN_RE)?.[0] ?? "";
|
|
81
|
+
const nextCharacter = firstUnicodeCharacter(suffix.slice(particleRun.length));
|
|
82
|
+
return (
|
|
83
|
+
KOREAN_PARTICLES.some((particle) => particle === particleRun) &&
|
|
84
|
+
(nextCharacter.length === 0 || !UNICODE_WORD_OR_NUMBER_RE.test(nextCharacter))
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function isUnicodePhraseBoundary(
|
|
89
|
+
character: string,
|
|
90
|
+
suffix: string = "",
|
|
91
|
+
source: string = "",
|
|
92
|
+
boundaryIndex: number = -1,
|
|
93
|
+
strictUnicode = false,
|
|
94
|
+
allowLeadingParticle = false,
|
|
95
|
+
): boolean {
|
|
96
|
+
return (
|
|
97
|
+
character.length === 0
|
|
98
|
+
|| !UNICODE_WORD_OR_NUMBER_RE.test(character)
|
|
99
|
+
|| (allowLeadingParticle && isJapaneseParticleBoundary(character))
|
|
100
|
+
|| isJapaneseParticleBoundary(suffix)
|
|
101
|
+
|| (!strictUnicode &&
|
|
102
|
+
boundaryIndex >= 0 &&
|
|
103
|
+
!JAPANESE_KANA_RE.test(suffix) &&
|
|
104
|
+
isIntlWordBoundary(source, boundaryIndex))
|
|
105
|
+
|| (allowLeadingParticle && isKoreanParticleBoundary(character))
|
|
106
|
+
|| isKoreanParticleBoundary(suffix)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function containsPhrase(haystack: string, needle: string): boolean {
|
|
111
|
+
if (!needle) return false;
|
|
112
|
+
const caseInsensitive = /^[a-z0-9 ]+$/i.test(needle);
|
|
113
|
+
const searchHaystack = caseInsensitive ? haystack.toLowerCase() : haystack;
|
|
114
|
+
const searchNeedle = caseInsensitive ? needle.toLowerCase() : needle;
|
|
115
|
+
let offset = searchHaystack.indexOf(searchNeedle);
|
|
116
|
+
while (offset >= 0) {
|
|
117
|
+
const before = lastUnicodeCharacter(searchHaystack.slice(0, offset));
|
|
118
|
+
const after = searchHaystack.slice(offset + searchNeedle.length);
|
|
119
|
+
if (
|
|
120
|
+
isUnicodePhraseBoundary(before, "", searchHaystack, offset, caseInsensitive, true)
|
|
121
|
+
&& isUnicodePhraseBoundary(
|
|
122
|
+
firstUnicodeCharacter(after),
|
|
123
|
+
after,
|
|
124
|
+
searchHaystack,
|
|
125
|
+
offset + searchNeedle.length,
|
|
126
|
+
caseInsensitive,
|
|
127
|
+
)
|
|
128
|
+
) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
offset = searchHaystack.indexOf(searchNeedle, offset + searchNeedle.length);
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
}
|