@remnic/core 9.54.4 → 9.54.6
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 +24 -23
- package/dist/access-admin-ops-surface.js +55 -50
- package/dist/access-authorization-probe.d.ts +25 -22
- package/dist/access-authorization-probe.js +58 -51
- package/dist/access-boundary.d.ts +26 -23
- package/dist/access-boundary.js +59 -52
- package/dist/access-cli.js +115 -107
- 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 +19 -18
- package/dist/access-extraction-force-flush.js +55 -50
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +22 -21
- package/dist/access-http-lifecycle-flush.d.ts +22 -21
- package/dist/access-http-offline-stream.d.ts +19 -18
- package/dist/access-http-query.js +55 -50
- package/dist/access-http.d.ts +55 -36
- package/dist/access-http.js +76 -65
- package/dist/access-identity-continuity-surface.d.ts +9 -9
- package/dist/access-identity-continuity-surface.js +55 -50
- package/dist/access-lcm-surface.d.ts +21 -20
- package/dist/access-lcm-surface.js +55 -50
- package/dist/access-mcp.d.ts +22 -21
- package/dist/access-mcp.js +63 -57
- package/dist/access-memory-search-fanout.d.ts +22 -2
- package/dist/access-memory-search-fanout.js +1 -1
- package/dist/{access-namespace-preflight-C7n4tgWC.d.ts → access-namespace-preflight-CCNn_6NE.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +55 -50
- package/dist/access-observe-write-surface.d.ts +22 -21
- package/dist/access-observe-write-surface.js +55 -50
- package/dist/access-offline-manifest.d.ts +10 -9
- package/dist/access-offline-manifest.js +12 -10
- package/dist/access-operations-batch.js +57 -52
- package/dist/access-operations.d.ts +23 -22
- package/dist/access-operations.js +61 -55
- package/dist/access-recall-concurrency.d.ts +21 -20
- package/dist/access-recall-concurrency.js +55 -50
- package/dist/access-recall-response.d.ts +19 -18
- package/dist/access-recall-response.js +55 -50
- package/dist/access-recall-surface.d.ts +19 -18
- package/dist/access-recall-surface.js +55 -50
- package/dist/access-schema.d.ts +2 -2
- package/dist/access-schema.js +5 -4
- package/dist/{access-service-CXvbxLK-.d.ts → access-service-DkSdXK4S.d.ts} +1314 -83
- package/dist/access-service-helpers.d.ts +22 -21
- package/dist/access-service.d.ts +31 -30
- package/dist/access-service.js +55 -50
- package/dist/access-surface-catalog.d.ts +22 -21
- package/dist/access-surface-catalog.js +209 -2
- 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 +14 -1
- package/dist/active-memory-bridge.js +6 -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/admin-console/public/what-helps-me/app.js +1594 -0
- package/dist/admin-console/public/what-helps-me/index.html +339 -0
- package/dist/admin-console/public/what-helps-me/model.js +685 -0
- package/dist/admin-console/public/what-helps-me/what-helps-me.css +1296 -0
- package/dist/ambient-provenance.d.ts +1 -1
- package/dist/artifact-search.d.ts +1 -1
- package/dist/{auto-sync-TDHLZPVP.js → auto-sync-NR3GPCOA.js} +4 -4
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +9 -9
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +33 -12
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-turn-helpers.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/buffer.js +3 -3
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/calibration.js +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{catalog-BOOxl-I2.d.ts → catalog-DGFf8mD9.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 +34 -13
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-ZYLC7NFO.js → chunk-26ZXBTYN.js} +4 -4
- package/dist/chunk-26ZXBTYN.js.map +1 -0
- package/dist/{chunk-LLJMAULE.js → chunk-2FKEIPIT.js} +5 -5
- package/dist/{chunk-3CSX3ETE.js → chunk-2LWQSV6A.js} +23 -11
- package/dist/chunk-2LWQSV6A.js.map +1 -0
- package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
- package/dist/chunk-37DZZFFM.js +502 -0
- package/dist/chunk-37DZZFFM.js.map +1 -0
- package/dist/chunk-3HSRWJTC.js +9 -0
- package/dist/chunk-3HSRWJTC.js.map +1 -0
- package/dist/{chunk-XUAMCLY4.js → chunk-3TIZPSJC.js} +17 -13
- package/dist/chunk-3TIZPSJC.js.map +1 -0
- package/dist/{chunk-PDDTI7IC.js → chunk-43SEBY2M.js} +1 -1
- package/dist/{chunk-HWRD23DW.js → chunk-46SZBVDS.js} +3 -3
- package/dist/{chunk-6HPHEFXT.js → chunk-5FD7JMTX.js} +2 -2
- package/dist/{chunk-7BZOBA5J.js → chunk-5NB726GV.js} +70 -16
- package/dist/chunk-5NB726GV.js.map +1 -0
- package/dist/chunk-62OKGIJA.js +39 -0
- package/dist/chunk-62OKGIJA.js.map +1 -0
- package/dist/{chunk-IBKR2TFR.js → chunk-6CYHUWCO.js} +2 -2
- package/dist/{chunk-YN6ASZUG.js → chunk-6QPI2ITJ.js} +5 -5
- package/dist/{chunk-UU3G6GUP.js → chunk-76JJSXK7.js} +1 -1
- package/dist/chunk-76JJSXK7.js.map +1 -0
- package/dist/{chunk-PX2LSHYM.js → chunk-7BD6O7ZV.js} +189 -4
- package/dist/chunk-7BD6O7ZV.js.map +1 -0
- package/dist/chunk-7TBXNYLO.js +346 -0
- package/dist/chunk-7TBXNYLO.js.map +1 -0
- package/dist/{chunk-NH5IR2WM.js → chunk-BRR5EUTF.js} +6 -2
- package/dist/chunk-BRR5EUTF.js.map +1 -0
- package/dist/{chunk-NIS256NW.js → chunk-CIAI24TQ.js} +3 -3
- package/dist/{chunk-T2JHZWH6.js → chunk-D3LBIUWV.js} +11703 -7573
- package/dist/chunk-D3LBIUWV.js.map +1 -0
- package/dist/{chunk-7FGL6CGA.js → chunk-DVYRD4HY.js} +2 -2
- package/dist/{chunk-G7Z6EENO.js → chunk-EKTP7MNS.js} +4 -4
- package/dist/{chunk-S75M5ZRK.js → chunk-F2JRDPON.js} +16 -1
- package/dist/chunk-F2JRDPON.js.map +1 -0
- package/dist/{chunk-RZ4XGKOJ.js → chunk-FFRTNF3L.js} +8 -8
- package/dist/{chunk-VKXWK44Q.js → chunk-FONWBCVY.js} +3 -3
- package/dist/{chunk-DZD576ZU.js → chunk-FPLM2TKD.js} +2 -2
- package/dist/{chunk-ZPJ4QSGP.js → chunk-FTPONF6B.js} +2 -2
- package/dist/{chunk-LJS7KUPV.js → chunk-FWX7W5PM.js} +2 -2
- package/dist/{chunk-UTRO5UJU.js → chunk-G6DFSS6A.js} +5 -1
- package/dist/chunk-G6DFSS6A.js.map +1 -0
- package/dist/{chunk-6LAPLZOS.js → chunk-GJ776BC2.js} +8 -3
- package/dist/chunk-GJ776BC2.js.map +1 -0
- package/dist/{chunk-G4T7L557.js → chunk-GN3WRFJY.js} +6 -6
- package/dist/{chunk-QT2FRYI4.js → chunk-H7NAZ3UB.js} +2 -2
- package/dist/{chunk-APPFNGX6.js → chunk-HBUFQRIM.js} +2 -2
- package/dist/{chunk-UU7TRFNE.js → chunk-HGJ6NJ4E.js} +2 -2
- package/dist/{chunk-WB7JSQCP.js → chunk-HIEWDJ2O.js} +5 -2
- package/dist/{chunk-WB7JSQCP.js.map → chunk-HIEWDJ2O.js.map} +1 -1
- package/dist/{chunk-UES4BHA2.js → chunk-I3MSGFGD.js} +17 -6
- package/dist/chunk-I3MSGFGD.js.map +1 -0
- package/dist/{chunk-C4ZNGVK3.js → chunk-IKP5OYQQ.js} +2 -2
- package/dist/{chunk-KQAFEZQX.js → chunk-IPLYGWQF.js} +5 -5
- package/dist/{chunk-RDJRFDJY.js → chunk-IQ4NVWEF.js} +2 -2
- package/dist/{chunk-CGVHPCP2.js → chunk-JYG4OLWH.js} +2 -2
- package/dist/{chunk-WOPA3SGI.js → chunk-K26NWEOC.js} +8 -8
- package/dist/{chunk-K4QS7LXU.js → chunk-K2UGPTYY.js} +485 -44
- package/dist/chunk-K2UGPTYY.js.map +1 -0
- package/dist/{chunk-L6CQ7WIW.js → chunk-KFBOPMF6.js} +11 -11
- package/dist/chunk-KFBOPMF6.js.map +1 -0
- package/dist/{chunk-G7A5HLUS.js → chunk-KJH6W2I7.js} +2 -2
- package/dist/{chunk-IXEBUYO4.js → chunk-KM55SMLG.js} +11 -2
- package/dist/{chunk-IXEBUYO4.js.map → chunk-KM55SMLG.js.map} +1 -1
- package/dist/{chunk-HOIRB77A.js → chunk-L6Z5OAS4.js} +2 -2
- package/dist/chunk-LC2BDILZ.js +57 -0
- package/dist/chunk-LC2BDILZ.js.map +1 -0
- package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
- package/dist/{chunk-6R4G7N4S.js → chunk-M4YHAODQ.js} +388 -748
- package/dist/chunk-M4YHAODQ.js.map +1 -0
- package/dist/{chunk-3JLPGJ43.js → chunk-MIH3CJPN.js} +5 -5
- package/dist/{chunk-QHFV6VNU.js → chunk-MK5VEWCR.js} +2 -2
- package/dist/chunk-NISZQW72.js +140 -0
- package/dist/chunk-NISZQW72.js.map +1 -0
- package/dist/{chunk-GUKBW4HL.js → chunk-NQMSEB5D.js} +6 -6
- package/dist/{chunk-G2LUMAUF.js → chunk-OCIP6YMD.js} +12 -5
- package/dist/chunk-OCIP6YMD.js.map +1 -0
- package/dist/{chunk-47P3RYZP.js → chunk-PG4QBPVG.js} +21 -11
- package/dist/chunk-PG4QBPVG.js.map +1 -0
- package/dist/{chunk-WRJVB3C2.js → chunk-PO7NXBG2.js} +2 -2
- package/dist/{chunk-QWGE2PUH.js → chunk-PT54WISF.js} +190 -56
- package/dist/chunk-PT54WISF.js.map +1 -0
- package/dist/{chunk-AZM4CCAC.js → chunk-QZLDRQ4I.js} +8 -8
- package/dist/{chunk-THPPCISA.js → chunk-RBII7637.js} +5 -5
- package/dist/{chunk-JDZPNCMA.js → chunk-RUNORG2P.js} +6 -3
- package/dist/chunk-RUNORG2P.js.map +1 -0
- package/dist/{chunk-JV5YUBIZ.js → chunk-RZQ6W2W4.js} +50 -44
- package/dist/chunk-RZQ6W2W4.js.map +1 -0
- package/dist/{chunk-RUMNY5DT.js → chunk-SMNYAMJD.js} +6 -2
- package/dist/chunk-SMNYAMJD.js.map +1 -0
- package/dist/{chunk-MKQBXQKU.js → chunk-TB6CBZ5V.js} +22 -15
- package/dist/chunk-TB6CBZ5V.js.map +1 -0
- package/dist/{chunk-VMMQDEN5.js → chunk-TO7ZTWJW.js} +2 -2
- package/dist/{chunk-K2TDK7GG.js → chunk-TWTUGCTY.js} +2 -2
- package/dist/{chunk-HLYR2TQL.js → chunk-UCTS3DDH.js} +2 -2
- package/dist/{chunk-JYIJNNN3.js → chunk-UG6VXIOK.js} +2 -2
- package/dist/{chunk-WM65LU67.js → chunk-UKYS3NU5.js} +2 -2
- package/dist/{chunk-WDBX6VER.js → chunk-UPLZNJKN.js} +5 -5
- package/dist/{chunk-C23BYTJV.js → chunk-UW5NPZJ2.js} +40 -12
- package/dist/chunk-UW5NPZJ2.js.map +1 -0
- package/dist/{chunk-2GFK22OZ.js → chunk-V6ERBR7U.js} +2 -2
- package/dist/{chunk-CYF6WVE7.js → chunk-W5ZKPI34.js} +139 -158
- package/dist/chunk-W5ZKPI34.js.map +1 -0
- package/dist/chunk-XX4HPFFM.js +370 -0
- package/dist/chunk-XX4HPFFM.js.map +1 -0
- package/dist/{chunk-ZMYDYNI4.js → chunk-XZHE2DEN.js} +4 -4
- package/dist/chunk-YXQEKCZM.js +223 -0
- package/dist/chunk-YXQEKCZM.js.map +1 -0
- package/dist/{chunk-GYPQL6XN.js → chunk-Z4N7SVVF.js} +35 -47
- package/dist/chunk-Z4N7SVVF.js.map +1 -0
- package/dist/{chunk-MAXVH44E.js → chunk-Z54EM5YZ.js} +7 -7
- package/dist/{chunk-YGLY6QFV.js → chunk-ZRZVLB7O.js} +2 -2
- package/dist/{chunk-4IIFL7GC.js → chunk-ZUKIUXHQ.js} +10 -10
- package/dist/{cli-DVUFIa5E.d.ts → cli-Bze8S0Qs.d.ts} +5 -5
- package/dist/cli.d.ts +22 -21
- package/dist/cli.js +90 -80
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +33 -12
- 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 +33 -12
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +32 -12
- 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 +3 -1
- package/dist/contradiction-scan-JDTBXRGW.js +20 -0
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +35 -14
- 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 +1 -1
- package/dist/corpus-watermark.js +25 -24
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/dependency-propagation-config.d.ts +1 -1
- package/dist/{dependency-propagation-delivery-XzF76C9n.d.ts → dependency-propagation-delivery-CzEfB31P.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 +33 -12
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +9 -9
- package/dist/explicit-capture.js +7 -4
- package/dist/external-wiki-access.d.ts +22 -21
- package/dist/external-wiki-access.js +56 -51
- 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 +22 -21
- package/dist/extraction-error-classification.d.ts +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-faithfulness.js +2 -2
- 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-judge.js +2 -2
- 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 +35 -19
- package/dist/fallback-llm.d.ts +14 -1
- package/dist/fallback-llm.js +1 -1
- package/dist/{first-start-migration-626C5554.js → first-start-migration-CRZCZAJN.js} +11 -3
- package/dist/first-start-migration-CRZCZAJN.js.map +1 -0
- 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 +314 -308
- package/dist/index.js +304 -133
- package/dist/inline-script.d.ts +3 -0
- package/dist/inline-script.js +8 -0
- package/dist/inline-script.js.map +1 -0
- 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 +6 -6
- 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 +2 -1
- package/dist/local-llm.js +2 -2
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +33 -12
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +33 -12
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +34 -13
- package/dist/{maintenance-BJzNIKBE.d.ts → maintenance-C8aRWfhq.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +22 -21
- package/dist/mcp-read-only-tools.js +1 -1
- 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.js +2 -2
- package/dist/memory-projection-store.d.ts +6 -2
- package/dist/memory-projection-store.js +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 +24 -23
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +8 -8
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +33 -12
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-file-io.d.ts +20 -0
- package/dist/offline-sync-file-io.js +18 -0
- package/dist/offline-sync-file-io.js.map +1 -0
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/offline-sync-impression-drain.js +5 -5
- package/dist/offline-sync.d.ts +8 -6
- package/dist/offline-sync.js +2 -1
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +26 -25
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +39 -36
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +38 -18
- package/dist/{orchestrator-BiXgBJBQ.d.ts → orchestrator-D85CzDDY.d.ts} +11 -8
- package/dist/orchestrator.d.ts +9 -9
- package/dist/orchestrator.js +117 -109
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-sz_dcuLg.d.ts → pipeline-DPcUifCO.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-D-SyWNj6.d.ts +25 -0
- package/dist/{purge-533FZLS4.js → purge-GB7PZHT2.js} +2 -2
- package/dist/{qmd-eAWObK4M.d.ts → qmd-dFCHp1r0.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-planner-llm.js +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 +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/reconcile/cursor.d.ts +2 -1
- package/dist/reconcile/manifest.d.ts +2 -1
- package/dist/reconcile/manifest.js +6 -5
- package/dist/reconcile/plan.d.ts +2 -1
- package/dist/reconcile/plan.js +3 -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 +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 +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 +38 -38
- package/dist/{scope-profiles-BBQsXuyj.d.ts → scope-profiles-DICK7GtN.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 +12 -12
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-HD8RkzVA.d.ts → semantic-consolidation-BP7NAX0N.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +34 -13
- package/dist/semantic-rule-promotion.js +33 -12
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +33 -12
- package/dist/{service-DIrtHHEg.d.ts → service-DT-pJyda.d.ts} +660 -660
- 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 +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/source-agent-qualifier.d.ts +1 -1
- package/dist/source-agent-qualifier.js +31 -15
- package/dist/{storage-DqCzXi56.d.ts → storage-qOnaJ1Lw.d.ts} +49 -13
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +33 -12
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +5 -5
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/support-passport/index.d.ts +518 -0
- package/dist/support-passport/index.js +357 -0
- package/dist/support-passport/index.js.map +1 -0
- 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 +2 -2
- package/dist/tier-routing.js +7 -1
- package/dist/{tier-stats-2JCZYEF7.js → tier-stats-EXYSKSVN.js} +8 -2
- package/dist/{tier-stats-2JCZYEF7.js.map → tier-stats-EXYSKSVN.js.map} +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 +1 -1
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/types.d.ts +36 -36
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-d_j4vC6N.d.ts → types-ed-SvS2t.d.ts} +8 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +2 -2
- package/dist/verified-recall.js +33 -12
- package/dist/write-envelope.d.ts +1 -1
- package/dist/write-rate-limiter.d.ts +11 -5
- package/dist/write-rate-limiter.js +1 -1
- package/package.json +12 -2
- package/scripts/build-with-heap.mjs +11 -1
- package/src/access-authorization-probe.ts +20 -2
- package/src/access-boundary.ts +32 -0
- package/src/access-http.test.ts +1971 -643
- package/src/access-http.ts +81 -74
- package/src/access-mcp.ts +3 -1
- package/src/access-memory-search-fanout.ts +24 -1
- package/src/access-offline-manifest.ts +5 -0
- package/src/access-operations.ts +2 -0
- package/src/access-service-namespace.test.ts +14 -0
- package/src/access-service-observe-scope.test.ts +2 -0
- package/src/access-service-offline-file-content.test.ts +211 -0
- package/src/access-service.ts +628 -884
- package/src/access-surface-catalog.test.ts +40 -10
- package/src/access-surface-catalog.ts +15 -0
- package/src/active-memory-bridge.test.ts +151 -0
- package/src/active-memory-bridge.ts +95 -21
- package/src/briefing.test.ts +38 -0
- package/src/briefing.ts +3 -3
- package/src/cli.ts +6 -1
- package/src/config.ts +18 -9
- package/src/connectors/codex-materialize-runner.ts +2 -0
- package/src/contradiction/contradiction-scan.ts +2 -0
- package/src/contradiction/contradiction.test.ts +42 -0
- package/src/correction/correction-access-wiring.ts +8 -2
- package/src/correction/correction-storage-integration.test.ts +7 -0
- package/src/explicit-capture.test.ts +24 -0
- package/src/explicit-capture.ts +2 -0
- package/src/fallback-llm.test.ts +54 -0
- package/src/fallback-llm.ts +54 -9
- package/src/index.ts +3 -0
- package/src/inline-script.ts +6 -0
- package/src/local-llm-headers-timeout.test.ts +42 -0
- package/src/local-llm.ts +8 -8
- package/src/maintenance/first-start-migration.ts +2 -1
- package/src/maintenance/memory-governance.test.ts +25 -0
- package/src/maintenance/memory-governance.ts +4 -1
- package/src/maintenance/pattern-reinforcement.test.ts +20 -0
- package/src/maintenance/pattern-reinforcement.ts +2 -1
- package/src/maintenance/rebuild-memory-projection.ts +8 -8
- package/src/mcp-read-only-tools.ts +3 -0
- package/src/memory-projection-store.ts +25 -27
- package/src/offline-sync-file-io.ts +68 -0
- package/src/offline-sync.ts +43 -57
- package/src/orchestration/consolidation-run.ts +5 -4
- package/src/orchestration/contradiction-linking-coordinator.ts +7 -0
- package/src/orchestration/contradiction-localization.integration.test.ts +115 -0
- package/src/orchestration/lifecycle-policy-coordinator.ts +2 -1
- package/src/orchestration/qmd-result-resolver.test.ts +215 -14
- package/src/orchestration/qmd-result-resolver.ts +142 -82
- package/src/orchestration/recall-search-pipeline.test.ts +41 -0
- package/src/orchestration/recall-search-pipeline.ts +12 -0
- package/src/orchestration/semantic-consolidation-coordinator.ts +2 -1
- package/src/orchestration/tier-migration-coordinator.ts +23 -56
- package/src/orchestration/workspace-ops.test.ts +37 -0
- package/src/orchestration/workspace-ops.ts +5 -29
- package/src/orchestrator.ts +7 -8
- package/src/relay/mission-access.test.ts +11 -11
- package/src/relay/mission-ui.test.ts +3 -1
- package/src/storage/supersession-audit.ts +7 -1
- package/src/storage/supersession-side-effects.ts +17 -5
- package/src/storage/tombstone-blocked-capture-sync.ts +31 -0
- package/src/storage-contract/failure-semantics.test.ts +102 -0
- package/src/storage.ts +18 -19
- package/src/support-passport/access-http-base.ts +143 -0
- package/src/support-passport/access-http.ts +172 -0
- package/src/support-passport/access-operations.ts +272 -0
- package/src/support-passport/access-service-base.test.ts +193 -0
- package/src/support-passport/access-service-base.ts +176 -0
- package/src/support-passport/access-surface.test.ts +283 -0
- package/src/support-passport/access-surface.ts +286 -0
- package/src/support-passport/card-projection.test.ts +137 -0
- package/src/support-passport/card-projection.ts +348 -0
- package/src/support-passport/card-replacement.ts +126 -0
- package/src/support-passport/card-service-commit-forwarding.test.ts +160 -0
- package/src/support-passport/card-service.test.ts +2964 -0
- package/src/support-passport/card-service.ts +1184 -0
- package/src/support-passport/card-state.ts +158 -0
- package/src/support-passport/config-model-routing.test.ts +37 -0
- package/src/support-passport/config.test.ts +34 -0
- package/src/support-passport/config.ts +41 -0
- package/src/support-passport/contracts.test.ts +156 -0
- package/src/support-passport/contracts.ts +149 -0
- package/src/support-passport/errors.ts +30 -0
- package/src/support-passport/generated-batch.test.ts +185 -0
- package/src/support-passport/generated-batch.ts +338 -0
- package/src/support-passport/grant-contracts.ts +183 -0
- package/src/support-passport/grant-generated-batch-scope.test.ts +201 -0
- package/src/support-passport/grant-service-cache.test.ts +148 -0
- package/src/support-passport/grant-service-cancellation.test.ts +83 -0
- package/src/support-passport/grant-service-marker-cache.test.ts +62 -0
- package/src/support-passport/grant-service.test.ts +3496 -0
- package/src/support-passport/grant-service.ts +513 -0
- package/src/support-passport/grant-store-commit-hook.test.ts +123 -0
- package/src/support-passport/grant-store-order.test.ts +60 -0
- package/src/support-passport/grant-store-path-safety.test.ts +30 -0
- package/src/support-passport/grant-store-recovery.test.ts +448 -0
- package/src/support-passport/grant-store.ts +906 -0
- package/src/support-passport/index.ts +17 -0
- package/src/support-passport/mcp-tools.test.ts +222 -0
- package/src/support-passport/mcp-tools.ts +187 -0
- package/src/support-passport/model-adapter.test.ts +840 -0
- package/src/support-passport/model-adapter.ts +602 -0
- package/src/support-passport/model-audit-pinned-write.test.ts +59 -0
- package/src/support-passport/model-audit.ts +152 -0
- package/src/support-passport/model-bridge.test.ts +456 -0
- package/src/support-passport/model-bridge.ts +439 -0
- package/src/support-passport/model-contracts.ts +124 -0
- package/src/support-passport/model-service.test.ts +1731 -0
- package/src/support-passport/model-service.ts +399 -0
- package/src/support-passport/offline-sync-guard.ts +230 -0
- package/src/support-passport/owner-http.test.ts +671 -0
- package/src/support-passport/owner-lock.ts +70 -0
- package/src/support-passport/private-file.test.ts +99 -0
- package/src/support-passport/private-file.ts +498 -0
- package/src/support-passport/public-http.test.ts +476 -0
- package/src/support-passport/public-http.ts +601 -0
- package/src/support-passport/ui.test.ts +181 -0
- package/src/tier-routing.ts +28 -17
- package/src/training-export/converter.test.ts +24 -0
- package/src/training-export/converter.ts +2 -0
- package/src/types.ts +8 -1
- package/src/wearables/service.test.ts +13 -0
- package/src/wearables/service.ts +2 -0
- package/src/write-rate-limiter.test.ts +30 -6
- package/src/write-rate-limiter.ts +29 -18
- package/dist/chunk-3CSX3ETE.js.map +0 -1
- package/dist/chunk-47P3RYZP.js.map +0 -1
- package/dist/chunk-6LAPLZOS.js.map +0 -1
- package/dist/chunk-6R4G7N4S.js.map +0 -1
- package/dist/chunk-7BZOBA5J.js.map +0 -1
- package/dist/chunk-C23BYTJV.js.map +0 -1
- package/dist/chunk-CYF6WVE7.js.map +0 -1
- package/dist/chunk-G2LUMAUF.js.map +0 -1
- package/dist/chunk-GYPQL6XN.js.map +0 -1
- package/dist/chunk-JDZPNCMA.js.map +0 -1
- package/dist/chunk-JV5YUBIZ.js.map +0 -1
- package/dist/chunk-K4QS7LXU.js.map +0 -1
- package/dist/chunk-L6CQ7WIW.js.map +0 -1
- package/dist/chunk-MKQBXQKU.js.map +0 -1
- package/dist/chunk-NH5IR2WM.js.map +0 -1
- package/dist/chunk-PX2LSHYM.js.map +0 -1
- package/dist/chunk-QWGE2PUH.js.map +0 -1
- package/dist/chunk-RUMNY5DT.js.map +0 -1
- package/dist/chunk-S75M5ZRK.js.map +0 -1
- package/dist/chunk-T2JHZWH6.js.map +0 -1
- package/dist/chunk-UES4BHA2.js.map +0 -1
- package/dist/chunk-UTRO5UJU.js.map +0 -1
- package/dist/chunk-UU3G6GUP.js.map +0 -1
- package/dist/chunk-XUAMCLY4.js.map +0 -1
- package/dist/chunk-ZYLC7NFO.js.map +0 -1
- package/dist/contradiction-scan-HYLIRMJ2.js +0 -14
- package/dist/first-start-migration-626C5554.js.map +0 -1
- /package/dist/{auto-sync-TDHLZPVP.js.map → auto-sync-NR3GPCOA.js.map} +0 -0
- /package/dist/{chunk-LLJMAULE.js.map → chunk-2FKEIPIT.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
- /package/dist/{chunk-PDDTI7IC.js.map → chunk-43SEBY2M.js.map} +0 -0
- /package/dist/{chunk-HWRD23DW.js.map → chunk-46SZBVDS.js.map} +0 -0
- /package/dist/{chunk-6HPHEFXT.js.map → chunk-5FD7JMTX.js.map} +0 -0
- /package/dist/{chunk-IBKR2TFR.js.map → chunk-6CYHUWCO.js.map} +0 -0
- /package/dist/{chunk-YN6ASZUG.js.map → chunk-6QPI2ITJ.js.map} +0 -0
- /package/dist/{chunk-NIS256NW.js.map → chunk-CIAI24TQ.js.map} +0 -0
- /package/dist/{chunk-7FGL6CGA.js.map → chunk-DVYRD4HY.js.map} +0 -0
- /package/dist/{chunk-G7Z6EENO.js.map → chunk-EKTP7MNS.js.map} +0 -0
- /package/dist/{chunk-RZ4XGKOJ.js.map → chunk-FFRTNF3L.js.map} +0 -0
- /package/dist/{chunk-VKXWK44Q.js.map → chunk-FONWBCVY.js.map} +0 -0
- /package/dist/{chunk-DZD576ZU.js.map → chunk-FPLM2TKD.js.map} +0 -0
- /package/dist/{chunk-ZPJ4QSGP.js.map → chunk-FTPONF6B.js.map} +0 -0
- /package/dist/{chunk-LJS7KUPV.js.map → chunk-FWX7W5PM.js.map} +0 -0
- /package/dist/{chunk-G4T7L557.js.map → chunk-GN3WRFJY.js.map} +0 -0
- /package/dist/{chunk-QT2FRYI4.js.map → chunk-H7NAZ3UB.js.map} +0 -0
- /package/dist/{chunk-APPFNGX6.js.map → chunk-HBUFQRIM.js.map} +0 -0
- /package/dist/{chunk-UU7TRFNE.js.map → chunk-HGJ6NJ4E.js.map} +0 -0
- /package/dist/{chunk-C4ZNGVK3.js.map → chunk-IKP5OYQQ.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-IPLYGWQF.js.map} +0 -0
- /package/dist/{chunk-RDJRFDJY.js.map → chunk-IQ4NVWEF.js.map} +0 -0
- /package/dist/{chunk-CGVHPCP2.js.map → chunk-JYG4OLWH.js.map} +0 -0
- /package/dist/{chunk-WOPA3SGI.js.map → chunk-K26NWEOC.js.map} +0 -0
- /package/dist/{chunk-G7A5HLUS.js.map → chunk-KJH6W2I7.js.map} +0 -0
- /package/dist/{chunk-HOIRB77A.js.map → chunk-L6Z5OAS4.js.map} +0 -0
- /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
- /package/dist/{chunk-3JLPGJ43.js.map → chunk-MIH3CJPN.js.map} +0 -0
- /package/dist/{chunk-QHFV6VNU.js.map → chunk-MK5VEWCR.js.map} +0 -0
- /package/dist/{chunk-GUKBW4HL.js.map → chunk-NQMSEB5D.js.map} +0 -0
- /package/dist/{chunk-WRJVB3C2.js.map → chunk-PO7NXBG2.js.map} +0 -0
- /package/dist/{chunk-AZM4CCAC.js.map → chunk-QZLDRQ4I.js.map} +0 -0
- /package/dist/{chunk-THPPCISA.js.map → chunk-RBII7637.js.map} +0 -0
- /package/dist/{chunk-VMMQDEN5.js.map → chunk-TO7ZTWJW.js.map} +0 -0
- /package/dist/{chunk-K2TDK7GG.js.map → chunk-TWTUGCTY.js.map} +0 -0
- /package/dist/{chunk-HLYR2TQL.js.map → chunk-UCTS3DDH.js.map} +0 -0
- /package/dist/{chunk-JYIJNNN3.js.map → chunk-UG6VXIOK.js.map} +0 -0
- /package/dist/{chunk-WM65LU67.js.map → chunk-UKYS3NU5.js.map} +0 -0
- /package/dist/{chunk-WDBX6VER.js.map → chunk-UPLZNJKN.js.map} +0 -0
- /package/dist/{chunk-2GFK22OZ.js.map → chunk-V6ERBR7U.js.map} +0 -0
- /package/dist/{chunk-ZMYDYNI4.js.map → chunk-XZHE2DEN.js.map} +0 -0
- /package/dist/{chunk-MAXVH44E.js.map → chunk-Z54EM5YZ.js.map} +0 -0
- /package/dist/{chunk-YGLY6QFV.js.map → chunk-ZRZVLB7O.js.map} +0 -0
- /package/dist/{chunk-4IIFL7GC.js.map → chunk-ZUKIUXHQ.js.map} +0 -0
- /package/dist/{contradiction-scan-HYLIRMJ2.js.map → contradiction-scan-JDTBXRGW.js.map} +0 -0
- /package/dist/{purge-533FZLS4.js.map → purge-GB7PZHT2.js.map} +0 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
import { EngramAccessHttpServer, resolveDefaultAdminConsolePublicDir } from "../access-http.js";
|
|
9
|
+
import type { EngramAccessService } from "../access-service.js";
|
|
10
|
+
import type { StorageManager } from "../storage.js";
|
|
11
|
+
|
|
12
|
+
const adminConsolePublicDir = path.resolve(
|
|
13
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
14
|
+
"../../../../admin-console/public"
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
async function withTempRoot(run: (root: string) => Promise<void>): Promise<void> {
|
|
18
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-support-passport-ui-"));
|
|
19
|
+
try {
|
|
20
|
+
await run(root);
|
|
21
|
+
} finally {
|
|
22
|
+
await rm(root, { recursive: true, force: true });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function fakeService(root: string, enabled: boolean): EngramAccessService {
|
|
27
|
+
const storage = { dir: root } as StorageManager;
|
|
28
|
+
return {
|
|
29
|
+
supportPassportEnabled: enabled,
|
|
30
|
+
configRef: { defaultNamespace: "support-passport", namespacesEnabled: true },
|
|
31
|
+
getReadableStorageForNamespace: async () => ({ namespace: "support-passport", storage }),
|
|
32
|
+
getWritableStorageForNamespace: async () => ({ namespace: "support-passport", storage }),
|
|
33
|
+
} as unknown as EngramAccessService;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
test("What Helps Me serves both aliases from one exact feature-gated allow-list", async () => {
|
|
37
|
+
await withTempRoot(async (root) => {
|
|
38
|
+
const server = new EngramAccessHttpServer({
|
|
39
|
+
service: fakeService(root, true),
|
|
40
|
+
host: "127.0.0.1",
|
|
41
|
+
port: 0,
|
|
42
|
+
authToken: "owner-token",
|
|
43
|
+
principal: "support-passport-owner",
|
|
44
|
+
adminConsoleEnabled: false,
|
|
45
|
+
adminConsolePublicDir,
|
|
46
|
+
adminConsolePrefillToken: true,
|
|
47
|
+
});
|
|
48
|
+
const status = await server.start();
|
|
49
|
+
const origin = `http://127.0.0.1:${status.port}`;
|
|
50
|
+
try {
|
|
51
|
+
for (const prefix of ["remnic", "engram"]) {
|
|
52
|
+
const redirect = await fetch(`${origin}/${prefix}/ui/what-helps-me`, { redirect: "manual" });
|
|
53
|
+
assert.equal(redirect.status, 301);
|
|
54
|
+
assert.equal(redirect.headers.get("location"), `/${prefix}/ui/what-helps-me/`);
|
|
55
|
+
const redirectWithGrant = await fetch(`${origin}/${prefix}/ui/what-helps-me?grant=grant-one&mode=replay`, {
|
|
56
|
+
redirect: "manual",
|
|
57
|
+
});
|
|
58
|
+
assert.equal(
|
|
59
|
+
redirectWithGrant.headers.get("location"),
|
|
60
|
+
`/${prefix}/ui/what-helps-me/?grant=grant-one&mode=replay`
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const shell = await fetch(`${origin}/${prefix}/ui/what-helps-me/`);
|
|
64
|
+
assert.equal(shell.status, 200);
|
|
65
|
+
assert.match(shell.headers.get("content-type") ?? "", /^text\/html/);
|
|
66
|
+
assert.equal(shell.headers.get("content-security-policy"), "frame-ancestors 'none'");
|
|
67
|
+
assert.equal(shell.headers.get("x-frame-options"), "DENY");
|
|
68
|
+
assert.doesNotMatch(await shell.text(), /__REMNIC_ADMIN_CONSOLE_PREFILL_TOKEN__/);
|
|
69
|
+
|
|
70
|
+
const authorizedShell = await fetch(`${origin}/${prefix}/ui/what-helps-me/`, {
|
|
71
|
+
headers: { authorization: "Bearer owner-token" },
|
|
72
|
+
});
|
|
73
|
+
assert.equal(authorizedShell.status, 200);
|
|
74
|
+
assert.equal(authorizedShell.headers.get("cache-control"), "private, no-store");
|
|
75
|
+
const authorizedShellText = await authorizedShell.text();
|
|
76
|
+
assert.match(authorizedShellText, /Object\.defineProperty\(window,key/);
|
|
77
|
+
assert.match(authorizedShellText, /new URLSearchParams\(location\.hash\.slice\(1\)\)\.has\("secret"\)/);
|
|
78
|
+
assert.match(authorizedShellText, /\}\)\("owner-token",document\.currentScript\)/);
|
|
79
|
+
|
|
80
|
+
const helperShell = await fetch(`${origin}/${prefix}/ui/what-helps-me/?grant=grant-one`, {
|
|
81
|
+
headers: { authorization: "Bearer owner-token" },
|
|
82
|
+
});
|
|
83
|
+
assert.equal(helperShell.status, 200);
|
|
84
|
+
assert.doesNotMatch(await helperShell.text(), /__REMNIC_ADMIN_CONSOLE_PREFILL_TOKEN__|owner-token/);
|
|
85
|
+
|
|
86
|
+
const expectedAssets = new Map([
|
|
87
|
+
["what-helps-me.css", /^text\/css/],
|
|
88
|
+
["model.js", /^application\/javascript/],
|
|
89
|
+
["app.js", /^application\/javascript/],
|
|
90
|
+
]);
|
|
91
|
+
for (const [fileName, contentType] of expectedAssets) {
|
|
92
|
+
const asset = await fetch(`${origin}/${prefix}/ui/what-helps-me/${fileName}`);
|
|
93
|
+
assert.equal(asset.status, 200, `${prefix}/${fileName}`);
|
|
94
|
+
assert.match(asset.headers.get("content-type") ?? "", contentType);
|
|
95
|
+
assert.ok((await asset.text()).length > 100);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const unknown = await fetch(`${origin}/${prefix}/ui/what-helps-me/not-allowed.js`);
|
|
99
|
+
assert.equal(unknown.status, 404);
|
|
100
|
+
const nested = await fetch(`${origin}/${prefix}/ui/what-helps-me/app.js/extra`);
|
|
101
|
+
assert.equal(nested.status, 404);
|
|
102
|
+
}
|
|
103
|
+
} finally {
|
|
104
|
+
await server.stop();
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("What Helps Me finds repository assets without a source-mode path override", async () => {
|
|
110
|
+
const sourceModuleUrl = new URL("../access-http.ts", import.meta.url);
|
|
111
|
+
assert.equal(resolveDefaultAdminConsolePublicDir(sourceModuleUrl.href), adminConsolePublicDir);
|
|
112
|
+
await withTempRoot(async (root) => {
|
|
113
|
+
const server = new EngramAccessHttpServer({
|
|
114
|
+
service: fakeService(root, true),
|
|
115
|
+
host: "127.0.0.1",
|
|
116
|
+
port: 0,
|
|
117
|
+
authToken: "owner-token",
|
|
118
|
+
principal: "support-passport-owner",
|
|
119
|
+
adminConsoleEnabled: false,
|
|
120
|
+
});
|
|
121
|
+
const status = await server.start();
|
|
122
|
+
try {
|
|
123
|
+
const shell = await fetch(`http://127.0.0.1:${status.port}/remnic/ui/what-helps-me/`);
|
|
124
|
+
assert.equal(shell.status, 200);
|
|
125
|
+
assert.match(await shell.text(), /What Helps Me/);
|
|
126
|
+
const asset = await fetch(`http://127.0.0.1:${status.port}/remnic/ui/what-helps-me/app.js`);
|
|
127
|
+
assert.equal(asset.status, 200);
|
|
128
|
+
assert.ok((await asset.text()).length > 100);
|
|
129
|
+
} finally {
|
|
130
|
+
await server.stop();
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("What Helps Me finds copied assets from the published source export", async () => {
|
|
136
|
+
await withTempRoot(async (root) => {
|
|
137
|
+
const sourceModulePath = path.join(root, "package", "src", "access-http.ts");
|
|
138
|
+
const publishedAssets = path.join(root, "package", "dist", "admin-console", "public");
|
|
139
|
+
await mkdir(path.dirname(sourceModulePath), { recursive: true });
|
|
140
|
+
await mkdir(publishedAssets, { recursive: true });
|
|
141
|
+
await writeFile(sourceModulePath, "");
|
|
142
|
+
assert.equal(resolveDefaultAdminConsolePublicDir(new URL(`file://${sourceModulePath}`).href), publishedAssets);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("What Helps Me assets stay hidden while support passport is disabled", async () => {
|
|
147
|
+
await withTempRoot(async (root) => {
|
|
148
|
+
const server = new EngramAccessHttpServer({
|
|
149
|
+
service: fakeService(root, false),
|
|
150
|
+
host: "127.0.0.1",
|
|
151
|
+
port: 0,
|
|
152
|
+
authToken: "owner-token",
|
|
153
|
+
principal: "support-passport-owner",
|
|
154
|
+
adminConsoleEnabled: true,
|
|
155
|
+
adminConsolePublicDir,
|
|
156
|
+
});
|
|
157
|
+
const status = await server.start();
|
|
158
|
+
try {
|
|
159
|
+
const response = await fetch(`http://127.0.0.1:${status.port}/remnic/ui/what-helps-me/`);
|
|
160
|
+
assert.equal(response.status, 404);
|
|
161
|
+
} finally {
|
|
162
|
+
await server.stop();
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("What Helps Me disables the browser cache for credentialed API requests", async () => {
|
|
168
|
+
const source = await readFile(path.join(adminConsolePublicDir, "what-helps-me", "app.js"), "utf8");
|
|
169
|
+
assert.match(source, /fetch\(path, \{[\s\S]*?cache: "no-store"/);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("What Helps Me clears any prefill getter before helper initialization", async () => {
|
|
173
|
+
const source = await readFile(path.join(adminConsolePublicDir, "what-helps-me", "app.js"), "utf8");
|
|
174
|
+
assert.match(source, /if \(grantId \|\| hasSecretFragment\) \{\s+clearPrefillToken\(\);/);
|
|
175
|
+
assert.match(source, /delete window\.__REMNIC_ADMIN_CONSOLE_PREFILL_TOKEN__/);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("What Helps Me wordmark does not depend on the optional admin console", async () => {
|
|
179
|
+
const source = await readFile(path.join(adminConsolePublicDir, "what-helps-me", "index.html"), "utf8");
|
|
180
|
+
assert.doesNotMatch(source, /class="wordmark"[^>]*href=/);
|
|
181
|
+
});
|
package/src/tier-routing.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
+
import { type LifecycleSignals, clamp01, computeLifecycleValueInputs, daysSince } from "./lifecycle.js";
|
|
2
|
+
import { hasLiveSupportPassportCard } from "./support-passport/card-projection.js";
|
|
1
3
|
import type { MemoryFile } from "./types.js";
|
|
2
|
-
import {
|
|
3
|
-
clamp01,
|
|
4
|
-
computeLifecycleValueInputs,
|
|
5
|
-
daysSince,
|
|
6
|
-
type LifecycleSignals,
|
|
7
|
-
} from "./lifecycle.js";
|
|
8
4
|
|
|
9
5
|
export type MemoryTier = "hot" | "cold";
|
|
10
6
|
|
|
@@ -23,34 +19,39 @@ export interface TierTransitionDecision {
|
|
|
23
19
|
reason: string;
|
|
24
20
|
}
|
|
25
21
|
|
|
22
|
+
function requiresHotTier(memory: Pick<MemoryFile, "frontmatter" | "content">): boolean {
|
|
23
|
+
return hasLiveSupportPassportCard(memory);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
26
|
export function computeTierValueScore(
|
|
27
27
|
memory: Pick<MemoryFile, "frontmatter">,
|
|
28
28
|
now: Date,
|
|
29
|
-
signals?: LifecycleSignals
|
|
29
|
+
signals?: LifecycleSignals
|
|
30
30
|
): number {
|
|
31
31
|
const fm = memory.frontmatter;
|
|
32
32
|
const inputs = computeLifecycleValueInputs(memory, now, signals);
|
|
33
33
|
const correctionBoost = fm.category === "correction" ? 0.08 : 0;
|
|
34
34
|
const confirmedBoost = fm.verificationState === "user_confirmed" ? 0.05 : 0;
|
|
35
35
|
|
|
36
|
-
const score =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
+
|
|
42
|
-
+
|
|
43
|
-
-
|
|
36
|
+
const score =
|
|
37
|
+
inputs.confidence * 0.24 +
|
|
38
|
+
inputs.access * 0.26 +
|
|
39
|
+
inputs.recency * 0.2 +
|
|
40
|
+
inputs.importance * 0.2 +
|
|
41
|
+
inputs.feedback * 0.1 +
|
|
42
|
+
correctionBoost +
|
|
43
|
+
confirmedBoost -
|
|
44
|
+
inputs.disputedPenalty * 0.5;
|
|
44
45
|
|
|
45
46
|
return clamp01(score);
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
export function decideTierTransition(
|
|
49
|
-
memory: Pick<MemoryFile, "frontmatter">,
|
|
50
|
+
memory: Pick<MemoryFile, "frontmatter" | "content">,
|
|
50
51
|
currentTier: MemoryTier,
|
|
51
52
|
policy: TierRoutingPolicy,
|
|
52
53
|
now: Date,
|
|
53
|
-
signals?: LifecycleSignals
|
|
54
|
+
signals?: LifecycleSignals
|
|
54
55
|
): TierTransitionDecision {
|
|
55
56
|
const valueScore = computeTierValueScore(memory, now, signals);
|
|
56
57
|
if (!policy.enabled) {
|
|
@@ -63,6 +64,16 @@ export function decideTierTransition(
|
|
|
63
64
|
};
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
if (requiresHotTier(memory)) {
|
|
68
|
+
return {
|
|
69
|
+
currentTier,
|
|
70
|
+
nextTier: "hot",
|
|
71
|
+
valueScore,
|
|
72
|
+
changed: currentTier !== "hot",
|
|
73
|
+
reason: "support_passport_card_requires_hot_tier",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
66
77
|
if (currentTier === "hot") {
|
|
67
78
|
const ageDays = daysSince(memory.frontmatter.updated ?? memory.frontmatter.created, now.getTime());
|
|
68
79
|
if (ageDays >= policy.demotionMinAgeDays && valueScore <= policy.demotionValueThreshold) {
|
|
@@ -72,6 +72,30 @@ describe("convertMemoriesToRecords", () => {
|
|
|
72
72
|
assert.deepEqual(records[0].sourceIds, ["mem-001"]);
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
+
it("excludes private support passport cards and audits", async () => {
|
|
76
|
+
const dir = await makeTmpDir();
|
|
77
|
+
await writeSyntheticMemory(dir, "facts", "public.md", {
|
|
78
|
+
id: "public",
|
|
79
|
+
content: "This memory can be exported.",
|
|
80
|
+
});
|
|
81
|
+
await writeSyntheticMemory(dir, "preferences", "card.md", {
|
|
82
|
+
id: "card",
|
|
83
|
+
category: "preference",
|
|
84
|
+
tags: ["support-passport-card"],
|
|
85
|
+
content: "Private support card.",
|
|
86
|
+
});
|
|
87
|
+
await writeSyntheticMemory(dir, "corrections", "audit.md", {
|
|
88
|
+
id: "audit",
|
|
89
|
+
category: "correction",
|
|
90
|
+
tags: ["support-passport-audit"],
|
|
91
|
+
content: "Private support card audit.",
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const records = await convertMemoriesToRecords({ memoryDir: dir });
|
|
95
|
+
|
|
96
|
+
assert.deepEqual(records.map((record) => record.sourceIds?.[0]), ["public"]);
|
|
97
|
+
});
|
|
98
|
+
|
|
75
99
|
it("filters by minConfidence", async () => {
|
|
76
100
|
const dir = await makeTmpDir();
|
|
77
101
|
await writeSyntheticMemory(dir, "facts", "high.md", {
|
|
@@ -15,6 +15,7 @@ import path from "node:path";
|
|
|
15
15
|
|
|
16
16
|
import { parseStrictCliDate } from "./date-parse.js";
|
|
17
17
|
import type { TrainingExportOptions, TrainingExportRecord } from "./types.js";
|
|
18
|
+
import { isSupportPassportPrivateMemory } from "../support-passport/card-projection.js";
|
|
18
19
|
import { RECALL_FALLBACK_DIRS } from "../utils/category-dir.js";
|
|
19
20
|
|
|
20
21
|
// ---------------------------------------------------------------------------
|
|
@@ -293,6 +294,7 @@ export async function convertMemoriesToRecords(
|
|
|
293
294
|
const parsed = parseFrontmatter(raw);
|
|
294
295
|
if (!parsed) continue; // skip malformed files
|
|
295
296
|
if (!parsed.content) continue; // skip empty content
|
|
297
|
+
if (isSupportPassportPrivateMemory({ frontmatter: { tags: parsed.tags } })) continue;
|
|
296
298
|
|
|
297
299
|
parsed.filePath = filePath;
|
|
298
300
|
|
package/src/types.ts
CHANGED
|
@@ -548,6 +548,11 @@ export interface ChatConfig {
|
|
|
548
548
|
sessionTtlHours: number;
|
|
549
549
|
}
|
|
550
550
|
|
|
551
|
+
export interface SupportPassportConfig {
|
|
552
|
+
enabled: boolean;
|
|
553
|
+
trustedProxyAddresses: string[];
|
|
554
|
+
}
|
|
555
|
+
|
|
551
556
|
/**
|
|
552
557
|
* Session-scoped coding context. Produced by `resolveGitContext()` in the
|
|
553
558
|
* connector layer and attached to a session so that recall + write paths can
|
|
@@ -1257,6 +1262,8 @@ export interface PluginConfig extends BoundedJsonlStateConfig {
|
|
|
1257
1262
|
// Conversational memory inspection and correction (issue #1583). Off by
|
|
1258
1263
|
// default — byte-identical pre-feature when enabled === false (rule 39).
|
|
1259
1264
|
chat: ChatConfig;
|
|
1265
|
+
/** Owner-controlled support passport. Off by default. */
|
|
1266
|
+
supportPassport: SupportPassportConfig;
|
|
1260
1267
|
slotBehavior: SlotBehaviorConfig;
|
|
1261
1268
|
/** OpenClaw bridge mode (#2120): `"embedded"` (default) or `"delegate"`. */
|
|
1262
1269
|
bridgeMode: string;
|
|
@@ -3631,7 +3638,7 @@ export interface MemoryProjectionCurrentState {
|
|
|
3631
3638
|
accessCount?: number;
|
|
3632
3639
|
lastAccessed?: string;
|
|
3633
3640
|
tags?: string[];
|
|
3634
|
-
preview?: string;
|
|
3641
|
+
preview?: string; privateRecord?: boolean;
|
|
3635
3642
|
}
|
|
3636
3643
|
|
|
3637
3644
|
export interface CompressionGuidelineOptimizerSourceWindow {
|
|
@@ -562,6 +562,19 @@ test("support corpus includes pending_review rows and excludes terminal statuses
|
|
|
562
562
|
"pending-1",
|
|
563
563
|
);
|
|
564
564
|
|
|
565
|
+
const privatePassport = makeRow(
|
|
566
|
+
"passport-1",
|
|
567
|
+
"pending_review",
|
|
568
|
+
"The launch moved to September twelfth after the vendor call, noted earlier.",
|
|
569
|
+
);
|
|
570
|
+
privatePassport.frontmatter.tags.push("support-passport-card");
|
|
571
|
+
const passportUnsupported = await runSmartSync([privatePassport]);
|
|
572
|
+
assert.equal(passportUnsupported.status, "pending_review");
|
|
573
|
+
assert.equal(
|
|
574
|
+
(passportUnsupported.structuredAttributes as Record<string, string>).supportingMemoryId,
|
|
575
|
+
undefined,
|
|
576
|
+
);
|
|
577
|
+
|
|
565
578
|
// Terminal statuses with the same content are NOT support evidence.
|
|
566
579
|
const similar =
|
|
567
580
|
"The launch moved to September twelfth after the vendor call, noted earlier.";
|
package/src/wearables/service.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from "./corrections.js";
|
|
14
14
|
import { describeErrorForOperator, WearablesInputError } from "./errors.js";
|
|
15
15
|
import { inferMemoryStatus } from "../memory-lifecycle-ledger-utils.js";
|
|
16
|
+
import { isSupportPassportPrivateMemory } from "../support-passport/card-projection.js";
|
|
16
17
|
import {
|
|
17
18
|
bodyIsEscaped,
|
|
18
19
|
decodeTranscriptBody,
|
|
@@ -388,6 +389,7 @@ export class WearablesService {
|
|
|
388
389
|
const memories = await storage.readAllMemories();
|
|
389
390
|
const support: Array<{ id: string; content: string }> = [];
|
|
390
391
|
for (const memory of memories) {
|
|
392
|
+
if (isSupportPassportPrivateMemory(memory)) continue;
|
|
391
393
|
// WearableStorageIo narrows MemoryFrontmatter for
|
|
392
394
|
// testability; production hands us the real thing.
|
|
393
395
|
const status = inferMemoryStatus(
|
|
@@ -28,7 +28,7 @@ test("WriteRateLimiter: capacity check, record, and sampled rejection logging (i
|
|
|
28
28
|
assert.equal(limiter.hasCapacity(), false);
|
|
29
29
|
assert.ok(
|
|
30
30
|
warnings.some((w) => w.includes("write_rate_limited")),
|
|
31
|
-
"a refused write is logged server-side"
|
|
31
|
+
"a refused write is logged server-side"
|
|
32
32
|
);
|
|
33
33
|
assert.equal(warnings.length, 1, "logging is sampled within the interval, not per-refusal");
|
|
34
34
|
} finally {
|
|
@@ -38,15 +38,39 @@ test("WriteRateLimiter: capacity check, record, and sampled rejection logging (i
|
|
|
38
38
|
|
|
39
39
|
test("WriteRateLimiter: reserve returns a release, refuses at the limit, frees on release", () => {
|
|
40
40
|
const limiter = new WriteRateLimiter(1, 60_000);
|
|
41
|
-
const
|
|
42
|
-
assert.ok(
|
|
43
|
-
assert.equal(limiter.
|
|
41
|
+
const reservation = limiter.reserve();
|
|
42
|
+
assert.ok(reservation, "first reservation succeeds");
|
|
43
|
+
assert.equal(limiter.inFlightFor(), 1);
|
|
44
|
+
assert.equal(limiter.totalSlots(), 1);
|
|
45
|
+
assert.equal(limiter.slotsFor().length, 0);
|
|
44
46
|
assert.equal(limiter.reserve(), null, "second reservation refused at the limit");
|
|
45
|
-
release
|
|
46
|
-
assert.equal(limiter.
|
|
47
|
+
reservation?.release();
|
|
48
|
+
assert.equal(limiter.inFlightFor(), 0, "release frees the reserved slot");
|
|
47
49
|
assert.ok(limiter.reserve(), "capacity restored after release");
|
|
48
50
|
});
|
|
49
51
|
|
|
52
|
+
test("WriteRateLimiter: an in-flight write does not expire and commit starts its window", () => {
|
|
53
|
+
const realNow = Date.now;
|
|
54
|
+
try {
|
|
55
|
+
let now = 1_000_000;
|
|
56
|
+
Date.now = () => now;
|
|
57
|
+
const limiter = new WriteRateLimiter(1, 1000);
|
|
58
|
+
const reservation = limiter.reserve();
|
|
59
|
+
assert.ok(reservation);
|
|
60
|
+
now += 1001;
|
|
61
|
+
assert.equal(limiter.reserve(), null, "an active reservation remains capacity-bound");
|
|
62
|
+
|
|
63
|
+
reservation.commit();
|
|
64
|
+
assert.equal(limiter.inFlightFor(), 0);
|
|
65
|
+
assert.equal(limiter.slotsFor()[0]?.recordedAt, now);
|
|
66
|
+
assert.equal(limiter.reserve(), null, "the commit starts a new rolling window");
|
|
67
|
+
now += 1000;
|
|
68
|
+
assert.ok(limiter.reserve(), "capacity returns when the commit window expires");
|
|
69
|
+
} finally {
|
|
70
|
+
Date.now = realNow;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
50
74
|
test("WriteRateLimiter: old slots pruned after the rolling window", () => {
|
|
51
75
|
const realNow = Date.now;
|
|
52
76
|
try {
|
|
@@ -27,6 +27,11 @@ const GLOBAL_BUCKET = "";
|
|
|
27
27
|
|
|
28
28
|
type Slot = { readonly recordedAt: number };
|
|
29
29
|
|
|
30
|
+
export interface WriteRateLimitReservation {
|
|
31
|
+
commit(): void;
|
|
32
|
+
release(): void;
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
function sanitizePositiveInteger(value: number | undefined, fallback: number): number {
|
|
31
36
|
return typeof value === "number" && Number.isInteger(value) && value >= 1 ? value : fallback;
|
|
32
37
|
}
|
|
@@ -37,6 +42,7 @@ export class WriteRateLimiter {
|
|
|
37
42
|
// One rolling window per principal. Empty buckets are pruned so the map does
|
|
38
43
|
// not grow without bound.
|
|
39
44
|
private readonly buckets = new Map<string, Slot[]>();
|
|
45
|
+
private readonly inFlight = new Map<string, number>();
|
|
40
46
|
private lastLogAt = 0;
|
|
41
47
|
private suppressed = 0;
|
|
42
48
|
|
|
@@ -63,16 +69,21 @@ export class WriteRateLimiter {
|
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
71
|
|
|
66
|
-
/**
|
|
72
|
+
/** Committed slots for a principal (test/introspection). */
|
|
67
73
|
slotsFor(principal?: string): ReadonlyArray<Slot> {
|
|
68
74
|
return this.buckets.get(this.key(principal)) ?? [];
|
|
69
75
|
}
|
|
70
76
|
|
|
77
|
+
inFlightFor(principal?: string): number {
|
|
78
|
+
return this.inFlight.get(this.key(principal)) ?? 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
71
81
|
/** Total live reservations across all principals (test/introspection). */
|
|
72
82
|
totalSlots(): number {
|
|
73
83
|
this.sweep(Date.now());
|
|
74
84
|
let total = 0;
|
|
75
85
|
for (const slots of this.buckets.values()) total += slots.length;
|
|
86
|
+
for (const count of this.inFlight.values()) total += count;
|
|
76
87
|
return total;
|
|
77
88
|
}
|
|
78
89
|
|
|
@@ -81,7 +92,7 @@ export class WriteRateLimiter {
|
|
|
81
92
|
this.sweep(Date.now());
|
|
82
93
|
const key = this.key(principal);
|
|
83
94
|
const slots = this.buckets.get(key);
|
|
84
|
-
if (slots
|
|
95
|
+
if ((slots?.length ?? 0) + (this.inFlight.get(key) ?? 0) >= this.maxRequests) {
|
|
85
96
|
this.logRejected(key);
|
|
86
97
|
return false;
|
|
87
98
|
}
|
|
@@ -92,30 +103,32 @@ export class WriteRateLimiter {
|
|
|
92
103
|
record(principal?: string): void {
|
|
93
104
|
this.sweep(Date.now());
|
|
94
105
|
const key = this.key(principal);
|
|
95
|
-
|
|
106
|
+
let slots = this.buckets.get(key);
|
|
107
|
+
if (!slots) {
|
|
108
|
+
slots = [];
|
|
109
|
+
this.buckets.set(key, slots);
|
|
110
|
+
}
|
|
96
111
|
slots.push({ recordedAt: Date.now() });
|
|
97
112
|
}
|
|
98
113
|
|
|
99
114
|
/**
|
|
100
|
-
* Reserve a slot for an in-flight write.
|
|
101
|
-
*
|
|
115
|
+
* Reserve a slot for an in-flight write. Commit starts the rolling window
|
|
116
|
+
* when persistence finishes. Release restores capacity after a failed write.
|
|
102
117
|
*/
|
|
103
|
-
reserve(principal?: string):
|
|
118
|
+
reserve(principal?: string): WriteRateLimitReservation | null {
|
|
104
119
|
if (!this.hasCapacity(principal)) return null;
|
|
105
120
|
const key = this.key(principal);
|
|
106
|
-
|
|
107
|
-
const slot: Slot = { recordedAt: Date.now() };
|
|
108
|
-
slots.push(slot);
|
|
121
|
+
this.inFlight.set(key, (this.inFlight.get(key) ?? 0) + 1);
|
|
109
122
|
let active = true;
|
|
110
|
-
|
|
123
|
+
const finish = (committed: boolean) => {
|
|
111
124
|
if (!active) return;
|
|
112
125
|
active = false;
|
|
113
|
-
const
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
if (
|
|
117
|
-
if (current.length === 0) this.buckets.delete(key);
|
|
126
|
+
const count = this.inFlight.get(key) ?? 0;
|
|
127
|
+
if (count <= 1) this.inFlight.delete(key);
|
|
128
|
+
else this.inFlight.set(key, count - 1);
|
|
129
|
+
if (committed) this.record(principal);
|
|
118
130
|
};
|
|
131
|
+
return { commit: () => finish(true), release: () => finish(false) };
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
private logRejected(principal: string): void {
|
|
@@ -127,9 +140,7 @@ export class WriteRateLimiter {
|
|
|
127
140
|
this.lastLogAt = now;
|
|
128
141
|
const who = principal === GLOBAL_BUCKET ? "(no principal)" : principal;
|
|
129
142
|
log.warn(
|
|
130
|
-
`write_rate_limited: rejected ${rejected} write(s) for principal ${who};
|
|
131
|
-
`per-principal limit is ${this.maxRequests} per ${this.windowMs}ms. Raise ` +
|
|
132
|
-
`server.writeRateLimitMaxRequests (or REMNIC_WRITE_RATE_LIMIT_MAX_REQUESTS) if sustained.`,
|
|
143
|
+
`write_rate_limited: rejected ${rejected} write(s) for principal ${who}; per-principal limit is ${this.maxRequests} per ${this.windowMs}ms. Raise server.writeRateLimitMaxRequests (or REMNIC_WRITE_RATE_LIMIT_MAX_REQUESTS) if sustained.`
|
|
133
144
|
);
|
|
134
145
|
}
|
|
135
146
|
}
|