@remnic/core 9.69.46 → 9.69.47
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 +15 -14
- package/dist/access-admin-ops-surface.js +42 -41
- package/dist/access-authorization-probe.d.ts +15 -14
- package/dist/access-authorization-probe.js +43 -42
- package/dist/access-boundary.d.ts +15 -14
- package/dist/access-boundary.js +42 -41
- package/dist/access-cli.js +119 -114
- 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 +15 -14
- package/dist/access-extraction-force-flush.js +42 -41
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-briefing.d.ts +15 -14
- package/dist/access-http-briefing.js +43 -42
- package/dist/access-http-lcm-compaction.d.ts +15 -14
- package/dist/access-http-lifecycle-flush.d.ts +15 -14
- package/dist/access-http-offline-stream.d.ts +15 -14
- package/dist/access-http-query.d.ts +2 -2
- package/dist/access-http-query.js +44 -43
- package/dist/access-http.d.ts +16 -15
- package/dist/access-http.js +67 -63
- package/dist/access-identity-continuity-surface.d.ts +11 -11
- package/dist/access-identity-continuity-surface.js +42 -41
- package/dist/access-lcm-surface.d.ts +15 -14
- package/dist/access-lcm-surface.js +42 -41
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp-shared-context-tools.d.ts +15 -14
- package/dist/access-mcp.d.ts +15 -14
- package/dist/access-mcp.js +55 -52
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-DDnsN22V.d.ts → access-namespace-preflight-CetF9ziA.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +42 -41
- package/dist/access-observe-transcript.d.ts +11 -11
- package/dist/access-observe-write-category.d.ts +3 -3
- package/dist/access-observe-write-category.js +4 -4
- package/dist/access-observe-write-surface.d.ts +15 -14
- package/dist/access-observe-write-surface.js +42 -41
- package/dist/access-offline-manifest.d.ts +11 -11
- package/dist/access-offline-manifest.js +2 -2
- package/dist/access-operations-batch.js +44 -43
- package/dist/access-operations.d.ts +16 -15
- package/dist/access-operations.js +51 -49
- package/dist/access-recall-concurrency.d.ts +15 -14
- package/dist/access-recall-concurrency.js +42 -41
- package/dist/access-recall-response.d.ts +15 -14
- package/dist/access-recall-response.js +42 -41
- package/dist/access-recall-surface.d.ts +15 -14
- package/dist/access-recall-surface.js +42 -41
- package/dist/access-schema.d.ts +1 -1
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-DGynYlbE.d.ts → access-service-BXYrJ3pO.d.ts} +13 -10
- package/dist/access-service-helpers.d.ts +15 -14
- package/dist/access-service.d.ts +15 -14
- package/dist/access-service.js +42 -41
- package/dist/access-surface-catalog.d.ts +15 -14
- package/dist/access-surface-catalog.js +50 -43
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +4 -4
- 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 +3 -2
- package/dist/active-recall.js.map +1 -1
- package/dist/activity/digest.d.ts +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/ambient-provenance.d.ts +1 -1
- package/dist/artifact-search.d.ts +1 -1
- package/dist/background-generation.d.ts +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +11 -11
- package/dist/briefing-window.d.ts +2 -2
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +13 -13
- 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 +5 -5
- 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/{catalog-Dl2hYqpS.d.ts → catalog-Bns9zpl3.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 +14 -14
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-D5DTZBTV.js → chunk-2JFSQWFH.js} +6 -6
- package/dist/chunk-2JFSQWFH.js.map +1 -0
- package/dist/{chunk-5EHPB6RL.js → chunk-2QX65IEC.js} +2 -2
- package/dist/{chunk-F5V7KRQS.js → chunk-2WMXZYMS.js} +2 -2
- package/dist/{chunk-ORQ7AZMU.js → chunk-3RKVSECD.js} +8 -8
- package/dist/{chunk-UGGOQKO6.js → chunk-44BILQ7U.js} +93 -51
- package/dist/chunk-44BILQ7U.js.map +1 -0
- package/dist/{chunk-3NYM6JA4.js → chunk-4LPIVP77.js} +2 -2
- package/dist/{chunk-PW4HTWXL.js → chunk-55XWRL6F.js} +2 -2
- package/dist/{chunk-GGY7WKMB.js → chunk-5KBI2MOC.js} +1 -1
- package/dist/{chunk-IXMWTNNY.js → chunk-6A6HSXWV.js} +2 -2
- package/dist/{chunk-4HTQ76O4.js → chunk-7SJCSDQ3.js} +2 -2
- package/dist/{chunk-U4ESGVZ2.js → chunk-7YUX52XZ.js} +3 -3
- package/dist/{chunk-HXDXR2FH.js → chunk-AS4YKT75.js} +40 -30
- package/dist/chunk-AS4YKT75.js.map +1 -0
- package/dist/{chunk-EUP4AXIW.js → chunk-B6VDWDFN.js} +2 -2
- package/dist/{chunk-AN2O4KZY.js → chunk-BMENHAJL.js} +2 -2
- package/dist/{chunk-5ZXGH2ZL.js → chunk-BXOPUJ3W.js} +2 -2
- package/dist/{chunk-TE6B2UU6.js → chunk-CD7VTZIG.js} +2 -2
- package/dist/{chunk-EC5SVM6H.js → chunk-DE4ZGH2N.js} +2 -2
- package/dist/{chunk-YFVIA5A6.js → chunk-DRLZB3CN.js} +2 -2
- package/dist/{chunk-SRRZZHA5.js → chunk-EGOWY342.js} +2 -2
- package/dist/chunk-EIB4FJVR.js +46 -0
- package/dist/chunk-EIB4FJVR.js.map +1 -0
- package/dist/{chunk-W44T2KHG.js → chunk-EWBDJQ5Y.js} +3 -3
- package/dist/{chunk-JMBTNVMW.js → chunk-FGRJJBFO.js} +2 -2
- package/dist/{chunk-F3TURDFG.js → chunk-FPB5LQWW.js} +4 -1
- package/dist/{chunk-F3TURDFG.js.map → chunk-FPB5LQWW.js.map} +1 -1
- package/dist/{chunk-7BNB7KHB.js → chunk-G2SJRFGP.js} +7 -7
- package/dist/{chunk-WGZHSQDV.js → chunk-G2XZFGYN.js} +4 -4
- package/dist/{chunk-CFIHVWYZ.js → chunk-GGROFIYX.js} +2 -2
- package/dist/chunk-GXJSLNYO.js +74 -0
- package/dist/chunk-GXJSLNYO.js.map +1 -0
- package/dist/{chunk-XLZZLUWL.js → chunk-HG74GEVY.js} +2 -2
- package/dist/chunk-HMDYSGY6.js +54 -0
- package/dist/chunk-HMDYSGY6.js.map +1 -0
- package/dist/{chunk-WUUGE7QC.js → chunk-HS75MCQF.js} +4 -4
- package/dist/{chunk-DO6R3LIE.js → chunk-I6IJDTRP.js} +2 -2
- package/dist/{chunk-TZ44E732.js → chunk-IO7K7GES.js} +2 -2
- package/dist/{chunk-AYP2FZFA.js → chunk-JUOJGZPV.js} +2 -2
- package/dist/{chunk-P7S7BVBJ.js → chunk-JXLEQIJ7.js} +2 -2
- package/dist/{chunk-4XTSKGLX.js → chunk-JYXLW22X.js} +3 -3
- package/dist/{chunk-IPLYGWQF.js → chunk-KQAFEZQX.js} +5 -5
- package/dist/chunk-LI4APB6M.js +218 -0
- package/dist/chunk-LI4APB6M.js.map +1 -0
- package/dist/{chunk-VGRVJ6Z6.js → chunk-LIAM7U2J.js} +2 -2
- package/dist/{chunk-S3SND7SO.js → chunk-LIDJWAQV.js} +2 -2
- package/dist/{chunk-T5NI5K46.js → chunk-LYMJ36UI.js} +2 -2
- package/dist/{chunk-KF57IQFX.js → chunk-MMQVWKFY.js} +19 -15
- package/dist/chunk-MMQVWKFY.js.map +1 -0
- package/dist/{chunk-QUFJ3NJE.js → chunk-MNG536IS.js} +20 -20
- package/dist/{chunk-SW42MMAH.js → chunk-MQT3WP3F.js} +2 -2
- package/dist/{chunk-UEJY6ZTQ.js → chunk-NE45P3OF.js} +2 -2
- package/dist/{chunk-N46SNYMC.js → chunk-NMA7RQPR.js} +2 -2
- package/dist/{chunk-47C6DF43.js → chunk-OS4JVTHR.js} +3 -3
- package/dist/{chunk-W6YDAIVB.js → chunk-OSTXIFZW.js} +13 -2
- package/dist/chunk-OSTXIFZW.js.map +1 -0
- package/dist/chunk-P3YNEMYY.js +212 -0
- package/dist/chunk-P3YNEMYY.js.map +1 -0
- package/dist/{chunk-JOP7W24J.js → chunk-PA67GXYJ.js} +8 -8
- package/dist/{chunk-FSH6KRKO.js → chunk-PPJLJD2D.js} +2 -2
- package/dist/{chunk-AG6PANBG.js → chunk-PXJ6HE2W.js} +11 -11
- package/dist/{chunk-DDBLZJRV.js → chunk-QB4VXCFN.js} +2 -2
- package/dist/{chunk-L63M2PE4.js → chunk-QGAKUOKU.js} +2 -2
- package/dist/{chunk-AYZHHMTK.js → chunk-QKFYJVDG.js} +2 -2
- package/dist/{chunk-YUQPUK6H.js → chunk-QLCMOHRE.js} +2 -2
- package/dist/{chunk-Q4AUIFUA.js → chunk-QMWKENNK.js} +4 -4
- package/dist/{chunk-GYYLZOSO.js → chunk-R4JTUTU6.js} +13 -6
- package/dist/chunk-R4JTUTU6.js.map +1 -0
- package/dist/{chunk-66QOUYNS.js → chunk-ROBGBT3D.js} +173 -56
- package/dist/chunk-ROBGBT3D.js.map +1 -0
- package/dist/{chunk-TNQR7N52.js → chunk-S3YM4SZQ.js} +2 -1
- package/dist/chunk-S3YM4SZQ.js.map +1 -0
- package/dist/{chunk-RW4QNB4J.js → chunk-S45INSV3.js} +3 -1
- package/dist/{chunk-RW4QNB4J.js.map → chunk-S45INSV3.js.map} +1 -1
- package/dist/{chunk-FMEP2RB5.js → chunk-SJ7ZNUXB.js} +2 -2
- package/dist/{chunk-EEHQY7ER.js → chunk-SK6HEQTW.js} +2 -2
- package/dist/{chunk-PGAB2V53.js → chunk-SMBWBEE7.js} +2 -2
- package/dist/{chunk-62NYUFNH.js → chunk-SS33RR4F.js} +8 -8
- package/dist/{chunk-4ECS33D4.js → chunk-T3T5HTZZ.js} +2 -2
- package/dist/{chunk-KG2OOAFF.js → chunk-TQSCR5DU.js} +6 -6
- package/dist/{chunk-OV7GJ4KW.js → chunk-V2XNMIAM.js} +2 -2
- package/dist/{chunk-AS2NOPDM.js → chunk-V7IONNTJ.js} +2 -2
- package/dist/{chunk-HYWPUYLO.js → chunk-VV5GCNKG.js} +2 -2
- package/dist/{chunk-Y3XHIWVP.js → chunk-WL3PGPGU.js} +2 -2
- package/dist/{chunk-3UQIS2GC.js → chunk-WNMVUWI7.js} +2 -2
- package/dist/{chunk-66YUOI53.js → chunk-WQW6KPVC.js} +1 -1
- package/dist/chunk-WQW6KPVC.js.map +1 -0
- package/dist/{chunk-2AV75BJW.js → chunk-WVI43D54.js} +24 -1
- package/dist/chunk-WVI43D54.js.map +1 -0
- package/dist/{chunk-WOBMSMUK.js → chunk-WYU66IVZ.js} +3 -3
- package/dist/{chunk-A7GQBJP5.js → chunk-X2NFFBTO.js} +4 -4
- package/dist/{chunk-CWMMKFO7.js → chunk-XEHLYA5Z.js} +3 -3
- package/dist/{chunk-JIWZVOQM.js → chunk-XKHRNAK7.js} +2 -2
- package/dist/{chunk-VW5TGNJN.js → chunk-XXLH6KFO.js} +2 -2
- package/dist/{chunk-J5OXWG66.js → chunk-XZUHXKM3.js} +2 -2
- package/dist/{chunk-K4KE5MYE.js → chunk-Y5VT7BIT.js} +2 -2
- package/dist/{chunk-UOREPQ3C.js → chunk-YOSLKZLZ.js} +2 -2
- package/dist/{chunk-S7KDHFF2.js → chunk-YXWMZAAN.js} +2 -2
- package/dist/{chunk-EAZ3YZKN.js → chunk-ZEIJQ4I3.js} +2 -2
- package/dist/{cli-Cik3H7q1.d.ts → cli-B8YyIrPR.d.ts} +5 -5
- package/dist/cli.d.ts +17 -16
- package/dist/cli.js +89 -84
- package/dist/coding/export-okf-codegraph.d.ts +1 -1
- package/dist/coding/export-okf-codegraph.js +12 -12
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +13 -13
- 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 +3 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +13 -13
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +13 -13
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/contradiction/index.d.ts +4 -4
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +15 -15
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/corpus-watermark.d.ts +1 -1
- package/dist/corpus-watermark.js +15 -15
- package/dist/cross-lingual-recall.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/deep-recall-http-glue.d.ts +15 -14
- package/dist/deep-recall-http-glue.js +4 -4
- package/dist/deep-recall-mcp-tools.d.ts +15 -14
- package/dist/deep-recall-policy-llm.d.ts +2 -2
- package/dist/deep-recall-seeds.d.ts +1 -1
- package/dist/deep-recall.js +2 -2
- package/dist/delinearize.d.ts +1 -1
- package/dist/dependency-propagation-config.d.ts +1 -1
- package/dist/{dependency-propagation-delivery-BXaUoVUf.d.ts → dependency-propagation-delivery-B-LvcDaq.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-origin-fields.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +13 -13
- package/dist/entity-schema.d.ts +1 -1
- package/dist/episodic-context.d.ts +1 -1
- package/dist/eval-trajectory-contracts.d.ts +1 -1
- package/dist/eval-trajectory-store.d.ts +1 -1
- package/dist/eval-trajectory.d.ts +1 -1
- package/dist/explicit-capture.d.ts +11 -11
- package/dist/external-wiki-access.d.ts +15 -14
- package/dist/external-wiki-access.js +43 -42
- 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 +15 -14
- package/dist/extraction-error-classification.d.ts +1 -1
- package/dist/extraction-evidence-class.d.ts +142 -0
- package/dist/extraction-evidence-class.js +113 -0
- package/dist/extraction-evidence-class.js.map +1 -0
- package/dist/extraction-faithfulness.d.ts +2 -2
- package/dist/extraction-judge-telemetry.d.ts +2 -2
- package/dist/extraction-judge-training.d.ts +2 -2
- package/dist/extraction-judge.d.ts +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-source-grounding.js +2 -2
- package/dist/extraction-span-config.d.ts +1 -1
- package/dist/extraction-span-materialize.d.ts +1 -1
- package/dist/extraction-span-wire.d.ts +1 -1
- package/dist/extraction.d.ts +2 -2
- package/dist/extraction.js +21 -21
- package/dist/fallback-llm-codex-subscription.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{generic-recall-paths-BkVVEoeO.d.ts → generic-recall-paths-Bfc7zigS.d.ts} +1 -1
- package/dist/graph-append-error.d.ts +1 -1
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-jsonl.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/importers/test-utils.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/{index-Zb6SUV4R.d.ts → index-C7IA1DxB.d.ts} +3 -3
- package/dist/index.d.ts +121 -30
- package/dist/index.js +179 -133
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +7 -7
- 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-DdrhmecM.d.ts → local-llm-DH4tWtck.d.ts} +1 -1
- package/dist/local-llm-helpers.d.ts +2 -2
- package/dist/local-llm.d.ts +2 -2
- package/dist/local-llm.js +2 -2
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/location/index.d.ts +5 -5
- package/dist/location/index.js +15 -15
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +13 -13
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +13 -13
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +14 -14
- package/dist/{maintenance-Du_VRvVg.d.ts → maintenance-n6yeTQhR.d.ts} +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +15 -14
- package/dist/mcp-read-only-tools.js +1 -1
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-browse-http-glue.d.ts +170 -0
- package/dist/memory-browse-http-glue.js +9 -0
- package/dist/memory-browse-http-glue.js.map +1 -0
- package/dist/memory-browse-mcp-tools.d.ts +160 -0
- package/dist/memory-browse-mcp-tools.js +8 -0
- package/dist/memory-browse-mcp-tools.js.map +1 -0
- package/dist/memory-browse-operations.d.ts +2 -0
- package/dist/memory-browse-operations.js +246 -0
- package/dist/memory-browse-operations.js.map +1 -0
- package/dist/memory-browse.d.ts +113 -0
- package/dist/memory-browse.js +49 -0
- package/dist/memory-browse.js.map +1 -0
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-controller.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-snapshot.d.ts +1 -1
- package/dist/memory-subject-cli.d.ts +15 -14
- package/dist/memory-subject.d.ts +15 -14
- 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 +14 -14
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +6 -6
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +13 -13
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +16 -16
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +23 -22
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +23 -23
- package/dist/{orchestrator-D9U3Zgjp.d.ts → orchestrator-Cirjo3ZB.d.ts} +10 -10
- package/dist/orchestrator.d.ts +11 -11
- package/dist/orchestrator.js +121 -116
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-4lqKJZ_0.d.ts → pipeline-DK79FrgH.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +2 -2
- package/dist/provenance.d.ts +77 -2
- package/dist/provenance.js +7 -3
- package/dist/{public-http-AabioFLh.d.ts → public-http-VB85y0ZH.d.ts} +1 -1
- package/dist/{qmd-DnoWaXKb.d.ts → qmd-BT0ErlRS.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/qmd.js +4 -4
- 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-navigate-access.d.ts +1 -1
- package/dist/recall-navigate-access.js +2 -2
- package/dist/recall-navigate-disclosure.d.ts +1 -1
- package/dist/recall-navigate-disclosure.js +2 -2
- package/dist/recall-navigate.d.ts +1 -1
- package/dist/recall-navigate.js +2 -2
- package/dist/recall-navigation-http-glue.d.ts +15 -14
- package/dist/recall-navigation-mcp-tools.d.ts +15 -14
- package/dist/recall-navigation-operations.js +43 -42
- package/dist/recall-navigation-renderer.d.ts +1 -1
- package/dist/recall-navigation.d.ts +1 -1
- package/dist/recall-navigation.js +42 -41
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state-view-admission.d.ts +2 -2
- package/dist/recall-state-view-admission.js +5 -5
- package/dist/recall-state-view-anchors.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +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 +1 -1
- package/dist/reconcile/manifest.d.ts +4 -1
- package/dist/reconcile/manifest.js +1 -1
- package/dist/reconcile/plan.d.ts +1 -1
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/replica-divergence.d.ts +1 -1
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +4 -3
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/salvage-envelope.d.ts +1 -1
- package/dist/{scope-profiles-crazXegZ.d.ts → scope-profiles-BgPQx9iE.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 +5 -5
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +9 -9
- 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-B09JI9WM.d.ts → semantic-consolidation-BrAWKVcm.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +14 -14
- package/dist/semantic-rule-promotion.js +13 -13
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +13 -13
- package/dist/{service-ByjbCuj7.d.ts → service-CqHOTg87.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 +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/source-agent-qualifier.d.ts +1 -1
- package/dist/source-agent-qualifier.js +17 -17
- package/dist/standing-memory-block.d.ts +77 -0
- package/dist/standing-memory-block.js +40 -0
- package/dist/standing-memory-block.js.map +1 -0
- package/dist/standup/build.js +13 -13
- package/dist/{storage-CbdF077z.d.ts → storage-mD2YQ8_2.d.ts} +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +12 -12
- package/dist/subject-config.d.ts +1 -1
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +3 -3
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/support-passport/index.d.ts +18 -17
- package/dist/support-passport/index.js +45 -44
- package/dist/{tagging-CF7DNV7_.d.ts → tagging-CiAVA-ID.d.ts} +2 -2
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-timeline-recall.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/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/export-okf.d.ts +1 -1
- package/dist/transfer/export-okf.js +13 -13
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-nmhnJpxx.d.ts → types-DgDaoY61.d.ts} +6 -0
- 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 +13 -13
- package/dist/who-knows-cli.d.ts +15 -14
- package/dist/who-knows-cli.js +14 -14
- package/dist/who-knows.d.ts +15 -14
- package/dist/who-knows.js +13 -13
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +2 -2
- package/src/access-boundary.ts +3 -0
- package/src/access-http.ts +2 -2
- package/src/access-mcp-output-schemas.ts +25 -0
- package/src/access-mcp.ts +3 -3
- package/src/access-operations.ts +2 -0
- package/src/access-service.ts +6 -1
- package/src/access-surface-catalog.test.ts +20 -0
- package/src/access-surface-catalog.ts +6 -0
- package/src/activity/timeline/index.ts +1 -0
- package/src/activity/timeline/journal-recap.test.ts +17 -0
- package/src/activity/timeline/journal-recap.ts +19 -6
- package/src/activity/timeline/recap-export-range.test.ts +289 -0
- package/src/activity/timeline/recap-export-range.ts +169 -0
- package/src/activity/timeline/recap-export.test.ts +73 -1
- package/src/activity/timeline/recap-export.ts +57 -4
- package/src/cli/memory-browse-commands.ts +77 -0
- package/src/cli.ts +2 -2
- package/src/config.ts +11 -0
- package/src/extraction-evidence-class.test.ts +355 -0
- package/src/extraction-evidence-class.ts +241 -0
- package/src/index.ts +1 -0
- package/src/mcp-read-only-tools.ts +3 -0
- package/src/memory-browse-http-glue.ts +93 -0
- package/src/memory-browse-mcp-tools.ts +57 -0
- package/src/memory-browse-operations.ts +88 -0
- package/src/memory-browse-surface.test.ts +500 -0
- package/src/memory-browse.ts +316 -0
- package/src/provenance.ts +3 -3
- package/src/reconcile/manifest.test.ts +27 -0
- package/src/reconcile/manifest.ts +7 -0
- package/src/standing-memory-block.test.ts +262 -0
- package/src/standing-memory-block.ts +331 -0
- package/src/types.ts +6 -0
- package/dist/chunk-2AV75BJW.js.map +0 -1
- package/dist/chunk-66QOUYNS.js.map +0 -1
- package/dist/chunk-66YUOI53.js.map +0 -1
- package/dist/chunk-D5DTZBTV.js.map +0 -1
- package/dist/chunk-GYYLZOSO.js.map +0 -1
- package/dist/chunk-HXDXR2FH.js.map +0 -1
- package/dist/chunk-KF57IQFX.js.map +0 -1
- package/dist/chunk-TNQR7N52.js.map +0 -1
- package/dist/chunk-UGGOQKO6.js.map +0 -1
- package/dist/chunk-W6YDAIVB.js.map +0 -1
- /package/dist/{chunk-5EHPB6RL.js.map → chunk-2QX65IEC.js.map} +0 -0
- /package/dist/{chunk-F5V7KRQS.js.map → chunk-2WMXZYMS.js.map} +0 -0
- /package/dist/{chunk-ORQ7AZMU.js.map → chunk-3RKVSECD.js.map} +0 -0
- /package/dist/{chunk-3NYM6JA4.js.map → chunk-4LPIVP77.js.map} +0 -0
- /package/dist/{chunk-PW4HTWXL.js.map → chunk-55XWRL6F.js.map} +0 -0
- /package/dist/{chunk-GGY7WKMB.js.map → chunk-5KBI2MOC.js.map} +0 -0
- /package/dist/{chunk-IXMWTNNY.js.map → chunk-6A6HSXWV.js.map} +0 -0
- /package/dist/{chunk-4HTQ76O4.js.map → chunk-7SJCSDQ3.js.map} +0 -0
- /package/dist/{chunk-U4ESGVZ2.js.map → chunk-7YUX52XZ.js.map} +0 -0
- /package/dist/{chunk-EUP4AXIW.js.map → chunk-B6VDWDFN.js.map} +0 -0
- /package/dist/{chunk-AN2O4KZY.js.map → chunk-BMENHAJL.js.map} +0 -0
- /package/dist/{chunk-5ZXGH2ZL.js.map → chunk-BXOPUJ3W.js.map} +0 -0
- /package/dist/{chunk-TE6B2UU6.js.map → chunk-CD7VTZIG.js.map} +0 -0
- /package/dist/{chunk-EC5SVM6H.js.map → chunk-DE4ZGH2N.js.map} +0 -0
- /package/dist/{chunk-YFVIA5A6.js.map → chunk-DRLZB3CN.js.map} +0 -0
- /package/dist/{chunk-SRRZZHA5.js.map → chunk-EGOWY342.js.map} +0 -0
- /package/dist/{chunk-W44T2KHG.js.map → chunk-EWBDJQ5Y.js.map} +0 -0
- /package/dist/{chunk-JMBTNVMW.js.map → chunk-FGRJJBFO.js.map} +0 -0
- /package/dist/{chunk-7BNB7KHB.js.map → chunk-G2SJRFGP.js.map} +0 -0
- /package/dist/{chunk-WGZHSQDV.js.map → chunk-G2XZFGYN.js.map} +0 -0
- /package/dist/{chunk-CFIHVWYZ.js.map → chunk-GGROFIYX.js.map} +0 -0
- /package/dist/{chunk-XLZZLUWL.js.map → chunk-HG74GEVY.js.map} +0 -0
- /package/dist/{chunk-WUUGE7QC.js.map → chunk-HS75MCQF.js.map} +0 -0
- /package/dist/{chunk-DO6R3LIE.js.map → chunk-I6IJDTRP.js.map} +0 -0
- /package/dist/{chunk-TZ44E732.js.map → chunk-IO7K7GES.js.map} +0 -0
- /package/dist/{chunk-AYP2FZFA.js.map → chunk-JUOJGZPV.js.map} +0 -0
- /package/dist/{chunk-P7S7BVBJ.js.map → chunk-JXLEQIJ7.js.map} +0 -0
- /package/dist/{chunk-4XTSKGLX.js.map → chunk-JYXLW22X.js.map} +0 -0
- /package/dist/{chunk-IPLYGWQF.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-VGRVJ6Z6.js.map → chunk-LIAM7U2J.js.map} +0 -0
- /package/dist/{chunk-S3SND7SO.js.map → chunk-LIDJWAQV.js.map} +0 -0
- /package/dist/{chunk-T5NI5K46.js.map → chunk-LYMJ36UI.js.map} +0 -0
- /package/dist/{chunk-QUFJ3NJE.js.map → chunk-MNG536IS.js.map} +0 -0
- /package/dist/{chunk-SW42MMAH.js.map → chunk-MQT3WP3F.js.map} +0 -0
- /package/dist/{chunk-UEJY6ZTQ.js.map → chunk-NE45P3OF.js.map} +0 -0
- /package/dist/{chunk-N46SNYMC.js.map → chunk-NMA7RQPR.js.map} +0 -0
- /package/dist/{chunk-47C6DF43.js.map → chunk-OS4JVTHR.js.map} +0 -0
- /package/dist/{chunk-JOP7W24J.js.map → chunk-PA67GXYJ.js.map} +0 -0
- /package/dist/{chunk-FSH6KRKO.js.map → chunk-PPJLJD2D.js.map} +0 -0
- /package/dist/{chunk-AG6PANBG.js.map → chunk-PXJ6HE2W.js.map} +0 -0
- /package/dist/{chunk-DDBLZJRV.js.map → chunk-QB4VXCFN.js.map} +0 -0
- /package/dist/{chunk-L63M2PE4.js.map → chunk-QGAKUOKU.js.map} +0 -0
- /package/dist/{chunk-AYZHHMTK.js.map → chunk-QKFYJVDG.js.map} +0 -0
- /package/dist/{chunk-YUQPUK6H.js.map → chunk-QLCMOHRE.js.map} +0 -0
- /package/dist/{chunk-Q4AUIFUA.js.map → chunk-QMWKENNK.js.map} +0 -0
- /package/dist/{chunk-FMEP2RB5.js.map → chunk-SJ7ZNUXB.js.map} +0 -0
- /package/dist/{chunk-EEHQY7ER.js.map → chunk-SK6HEQTW.js.map} +0 -0
- /package/dist/{chunk-PGAB2V53.js.map → chunk-SMBWBEE7.js.map} +0 -0
- /package/dist/{chunk-62NYUFNH.js.map → chunk-SS33RR4F.js.map} +0 -0
- /package/dist/{chunk-4ECS33D4.js.map → chunk-T3T5HTZZ.js.map} +0 -0
- /package/dist/{chunk-KG2OOAFF.js.map → chunk-TQSCR5DU.js.map} +0 -0
- /package/dist/{chunk-OV7GJ4KW.js.map → chunk-V2XNMIAM.js.map} +0 -0
- /package/dist/{chunk-AS2NOPDM.js.map → chunk-V7IONNTJ.js.map} +0 -0
- /package/dist/{chunk-HYWPUYLO.js.map → chunk-VV5GCNKG.js.map} +0 -0
- /package/dist/{chunk-Y3XHIWVP.js.map → chunk-WL3PGPGU.js.map} +0 -0
- /package/dist/{chunk-3UQIS2GC.js.map → chunk-WNMVUWI7.js.map} +0 -0
- /package/dist/{chunk-WOBMSMUK.js.map → chunk-WYU66IVZ.js.map} +0 -0
- /package/dist/{chunk-A7GQBJP5.js.map → chunk-X2NFFBTO.js.map} +0 -0
- /package/dist/{chunk-CWMMKFO7.js.map → chunk-XEHLYA5Z.js.map} +0 -0
- /package/dist/{chunk-JIWZVOQM.js.map → chunk-XKHRNAK7.js.map} +0 -0
- /package/dist/{chunk-VW5TGNJN.js.map → chunk-XXLH6KFO.js.map} +0 -0
- /package/dist/{chunk-J5OXWG66.js.map → chunk-XZUHXKM3.js.map} +0 -0
- /package/dist/{chunk-K4KE5MYE.js.map → chunk-Y5VT7BIT.js.map} +0 -0
- /package/dist/{chunk-UOREPQ3C.js.map → chunk-YOSLKZLZ.js.map} +0 -0
- /package/dist/{chunk-S7KDHFF2.js.map → chunk-YXWMZAAN.js.map} +0 -0
- /package/dist/{chunk-EAZ3YZKN.js.map → chunk-ZEIJQ4I3.js.map} +0 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory-store browse verbs (issue #2978) — deterministic `ls` / `tree` /
|
|
3
|
+
* `find` over ONE resolved namespace's memory store, so an agent can see
|
|
4
|
+
* what exists instead of guessing ids at an opaque search box.
|
|
5
|
+
*
|
|
6
|
+
* Scope rules (all existing contracts, no new ones):
|
|
7
|
+
* - Every call resolves through the caller's `resolveReadableNamespace`
|
|
8
|
+
* (read/write path symmetry) and ONE storage instance — browse never
|
|
9
|
+
* enumerates across namespaces.
|
|
10
|
+
* - Only the recall corpus is browsable: a path's top segment must be a
|
|
11
|
+
* `RECALL_FALLBACK_DIRS` category AND survive
|
|
12
|
+
* `isGenericRecallExcludedPath`. Derived stores (`artifacts/`,
|
|
13
|
+
* `meetings/` records, wearables day stores, `state/`, ...) are
|
|
14
|
+
* indistinguishable from missing paths — `not_found`, never listed.
|
|
15
|
+
* - Support-passport private memories are filtered exactly like
|
|
16
|
+
* `memoryBrowse` (the paginated list): their names never appear.
|
|
17
|
+
* - Output is deterministically sorted (plain code-point order, no
|
|
18
|
+
* locale) and entry-capped so a huge store cannot blow the response.
|
|
19
|
+
*
|
|
20
|
+
* `ponytail:` the index is rebuilt from `readAllMemories()` per call —
|
|
21
|
+
* O(corpus) per browse. Fine at agent cadence; swap for a cached directory
|
|
22
|
+
* index if browsing ever sits on a hot path.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { toMemoryPathRel } from "./memory-lifecycle-ledger-utils.js";
|
|
26
|
+
import { normalizeProjectionPreview } from "./memory-projection-format.js";
|
|
27
|
+
import { isGenericRecallExcludedPath } from "./orchestration/generic-recall-paths.js";
|
|
28
|
+
import { isSupportPassportPrivateMemory } from "./support-passport/card-projection.js";
|
|
29
|
+
import { RECALL_FALLBACK_DIRS } from "./utils/category-dir.js";
|
|
30
|
+
import type { MemoryFile } from "./types.js";
|
|
31
|
+
|
|
32
|
+
/** Browse reads touch only these storage members. */
|
|
33
|
+
export interface MemoryBrowseStorage {
|
|
34
|
+
readonly dir: string;
|
|
35
|
+
readAllMemories(): Promise<MemoryFile[]>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Injected seams; the service supplies live wiring, tests supply doubles. */
|
|
39
|
+
export interface MemoryBrowseDeps {
|
|
40
|
+
readonly resolveReadableNamespace: (namespace: string | undefined, principal?: string) => string;
|
|
41
|
+
readonly getStorage: (namespace: string) => Promise<MemoryBrowseStorage>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type BrowseVerb = "ls" | "tree" | "find";
|
|
45
|
+
|
|
46
|
+
export interface MemoryStoreBrowseRequest {
|
|
47
|
+
readonly verb: BrowseVerb;
|
|
48
|
+
/** ls/tree: directory relative to the store root ("" or "/" = root). */
|
|
49
|
+
readonly path?: string;
|
|
50
|
+
/** tree: expansion depth, 1..MAX_TREE_DEPTH (default 1). */
|
|
51
|
+
readonly depth?: number;
|
|
52
|
+
/** find: glob (`*` wildcard) or substring matched against path and name. */
|
|
53
|
+
readonly pattern?: string;
|
|
54
|
+
readonly namespace?: string;
|
|
55
|
+
readonly authenticatedPrincipal?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface MemoryBrowseEntry {
|
|
59
|
+
/** Store-relative path with forward slashes; dirs carry no trailing slash. */
|
|
60
|
+
readonly path: string;
|
|
61
|
+
readonly kind: "dir" | "file";
|
|
62
|
+
readonly name: string;
|
|
63
|
+
/** Files: first content line (180-char preview). Dirs: empty. */
|
|
64
|
+
readonly description: string;
|
|
65
|
+
/** Dirs: recursive memory count beneath. Files: 1. */
|
|
66
|
+
readonly count: number;
|
|
67
|
+
/** 0-based depth relative to the browse root (tree nests; ls/find are 0). */
|
|
68
|
+
readonly depth: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type MemoryBrowseError = "invalid_path" | "not_found" | "invalid_depth" | "invalid_pattern";
|
|
72
|
+
|
|
73
|
+
export type MemoryStoreBrowseResult =
|
|
74
|
+
| {
|
|
75
|
+
ok: true;
|
|
76
|
+
verb: BrowseVerb;
|
|
77
|
+
namespace: string;
|
|
78
|
+
path: string;
|
|
79
|
+
total: number;
|
|
80
|
+
entries: MemoryBrowseEntry[];
|
|
81
|
+
truncated: boolean;
|
|
82
|
+
rendered: string;
|
|
83
|
+
}
|
|
84
|
+
| {
|
|
85
|
+
ok: false;
|
|
86
|
+
verb: BrowseVerb;
|
|
87
|
+
path: string;
|
|
88
|
+
error: MemoryBrowseError;
|
|
89
|
+
message: string;
|
|
90
|
+
rendered: string;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const MAX_LS_ENTRIES = 200;
|
|
94
|
+
export const MAX_TREE_ENTRIES = 400;
|
|
95
|
+
export const MAX_TREE_DEPTH = 4;
|
|
96
|
+
export const MAX_FIND_ENTRIES = 200;
|
|
97
|
+
const MAX_PATH_CHARS = 512;
|
|
98
|
+
const MAX_PATTERN_CHARS = 256;
|
|
99
|
+
|
|
100
|
+
const BROWSABLE_ROOTS: Record<string, true> = Object.fromEntries(RECALL_FALLBACK_DIRS.map((dir) => [dir, true]));
|
|
101
|
+
|
|
102
|
+
/** The recall-corpus visibility rule shared by every browse code path. */
|
|
103
|
+
function isBrowsableMemoryPath(relPath: string): boolean {
|
|
104
|
+
if (!relPath.endsWith(".md")) return false;
|
|
105
|
+
const top = relPath.split("/")[0] ?? "";
|
|
106
|
+
return BROWSABLE_ROOTS[top] === true && !isGenericRecallExcludedPath(relPath);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Normalize a caller-supplied store path. Returns "" for the root. Throws
|
|
111
|
+
* `Error` on absolute paths, `..`/`.` segments, backslashes, control
|
|
112
|
+
* characters, or oversize input — never reinterpreted (pattern 39).
|
|
113
|
+
*/
|
|
114
|
+
export function sanitizeBrowsePath(raw: string | undefined): string {
|
|
115
|
+
const trimmed = (raw ?? "").trim();
|
|
116
|
+
if (trimmed === "" || trimmed === "/") return "";
|
|
117
|
+
if (trimmed.length > MAX_PATH_CHARS) throw new Error("path is too long");
|
|
118
|
+
if (trimmed.includes("\\")) throw new Error("path must use '/' separators");
|
|
119
|
+
const segments = trimmed.split("/");
|
|
120
|
+
for (const segment of segments) {
|
|
121
|
+
if (segment === "") throw new Error("path has an empty segment");
|
|
122
|
+
if (segment === "." || segment === "..") throw new Error("path must not contain '.' or '..' segments");
|
|
123
|
+
for (const ch of segment) {
|
|
124
|
+
const code = ch.charCodeAt(0);
|
|
125
|
+
if (code < 0x20 || code === 0x7f) throw new Error("path has control characters");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return segments.join("/");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Escape every regex metacharacter in a glob segment. */
|
|
132
|
+
function segmentRegex(segment: string): RegExp {
|
|
133
|
+
const source = `^${segment.split("*").map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join(".*")}$`;
|
|
134
|
+
return new RegExp(source, "i");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* `*` glob (one segment per pattern segment, `find -name` semantics — `*`
|
|
139
|
+
* never crosses `/`) or case-insensitive substring over path and name.
|
|
140
|
+
*/
|
|
141
|
+
export function browsePatternMatches(pattern: string, relPath: string): boolean {
|
|
142
|
+
const segments = relPath.split("/");
|
|
143
|
+
const name = segments[segments.length - 1] ?? "";
|
|
144
|
+
const patternSegments = pattern.split("/");
|
|
145
|
+
if (patternSegments.length === 1) {
|
|
146
|
+
const single = patternSegments[0]!;
|
|
147
|
+
if (single.includes("*")) return segmentRegex(single).test(name);
|
|
148
|
+
const needle = single.toLowerCase();
|
|
149
|
+
return relPath.toLowerCase().includes(needle) || name.toLowerCase().includes(needle);
|
|
150
|
+
}
|
|
151
|
+
if (patternSegments.length !== segments.length) return false;
|
|
152
|
+
return patternSegments.every((segment, index) => segmentRegex(segment).test(segments[index]!));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
interface DirNode {
|
|
156
|
+
readonly subdirs: Map<string, DirNode>;
|
|
157
|
+
readonly files: Map<string, MemoryFile>;
|
|
158
|
+
count: number;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function emptyNode(): DirNode {
|
|
162
|
+
return { subdirs: new Map(), files: new Map(), count: 0 };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Directory index over the browsable corpus: root "" holds category dirs. */
|
|
166
|
+
function buildIndex(memories: readonly MemoryFile[], dir: string): DirNode {
|
|
167
|
+
const root = emptyNode();
|
|
168
|
+
for (const memory of memories) {
|
|
169
|
+
const rel = toMemoryPathRel(dir, memory.path);
|
|
170
|
+
if (!isBrowsableMemoryPath(rel)) continue;
|
|
171
|
+
const segments = rel.split("/");
|
|
172
|
+
let node = root;
|
|
173
|
+
node.count += 1;
|
|
174
|
+
for (let index = 0; index < segments.length - 1; index += 1) {
|
|
175
|
+
const name = segments[index]!;
|
|
176
|
+
let child = node.subdirs.get(name);
|
|
177
|
+
if (child === undefined) {
|
|
178
|
+
child = emptyNode();
|
|
179
|
+
node.subdirs.set(name, child);
|
|
180
|
+
}
|
|
181
|
+
node = child;
|
|
182
|
+
node.count += 1;
|
|
183
|
+
}
|
|
184
|
+
node.files.set(segments[segments.length - 1]!, memory);
|
|
185
|
+
}
|
|
186
|
+
return root;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function byPath(left: { path: string }, right: { path: string }): number {
|
|
190
|
+
return left.path < right.path ? -1 : left.path > right.path ? 1 : 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function dirEntries(node: DirNode, dirPath: string): MemoryBrowseEntry[] {
|
|
194
|
+
const prefix = dirPath === "" ? "" : `${dirPath}/`;
|
|
195
|
+
const entries: MemoryBrowseEntry[] = [];
|
|
196
|
+
for (const [name, child] of node.subdirs) {
|
|
197
|
+
entries.push({ path: `${prefix}${name}`, kind: "dir", name, description: "", count: child.count, depth: 0 });
|
|
198
|
+
}
|
|
199
|
+
for (const [name, memory] of node.files) {
|
|
200
|
+
entries.push({
|
|
201
|
+
path: `${prefix}${name}`,
|
|
202
|
+
kind: "file",
|
|
203
|
+
name,
|
|
204
|
+
description: normalizeProjectionPreview(memory.content),
|
|
205
|
+
count: 1,
|
|
206
|
+
depth: 0,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return entries.sort(byPath);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function renderEntries(verb: BrowseVerb, namespace: string, browsePath: string, entries: readonly MemoryBrowseEntry[]): string {
|
|
213
|
+
const lines = [`${verb} ${namespace}:${browsePath === "" ? "/" : browsePath}`];
|
|
214
|
+
for (const entry of entries) {
|
|
215
|
+
const indent = " ".repeat(entry.depth);
|
|
216
|
+
if (entry.kind === "dir") {
|
|
217
|
+
lines.push(`${indent}${entry.path}/ (${entry.count} memories)`);
|
|
218
|
+
} else {
|
|
219
|
+
const description = entry.description.length > 0 ? ` — ${entry.description}` : "";
|
|
220
|
+
lines.push(`${indent}${entry.path}${description}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return lines.join("\n");
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function refusal(verb: BrowseVerb, browsePath: string, error: MemoryBrowseError, message: string): MemoryStoreBrowseResult {
|
|
227
|
+
return { ok: false, verb, path: browsePath, error, message, rendered: `browse ${verb} failed: ${error} — ${message}` };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Run one browse verb. Malformed input throws `Error`; typed refusals return in-band. */
|
|
231
|
+
export async function runMemoryBrowse(
|
|
232
|
+
deps: MemoryBrowseDeps,
|
|
233
|
+
request: MemoryStoreBrowseRequest,
|
|
234
|
+
): Promise<MemoryStoreBrowseResult> {
|
|
235
|
+
const namespace = deps.resolveReadableNamespace(request.namespace, request.authenticatedPrincipal);
|
|
236
|
+
const storage = await deps.getStorage(namespace);
|
|
237
|
+
const memories = (await storage.readAllMemories()).filter((memory) => !isSupportPassportPrivateMemory(memory));
|
|
238
|
+
|
|
239
|
+
if (request.verb === "find") {
|
|
240
|
+
const pattern = (request.pattern ?? "").trim();
|
|
241
|
+
if (pattern.length === 0) return refusal(request.verb, "", "invalid_pattern", "pattern is required");
|
|
242
|
+
if (pattern.length > MAX_PATTERN_CHARS) {
|
|
243
|
+
return refusal(request.verb, "", "invalid_pattern", "pattern is too long");
|
|
244
|
+
}
|
|
245
|
+
const hits: MemoryBrowseEntry[] = [];
|
|
246
|
+
let truncated = false;
|
|
247
|
+
let total = 0;
|
|
248
|
+
for (const memory of memories) {
|
|
249
|
+
const rel = toMemoryPathRel(storage.dir, memory.path);
|
|
250
|
+
if (!isBrowsableMemoryPath(rel)) continue;
|
|
251
|
+
if (!browsePatternMatches(pattern, rel)) continue;
|
|
252
|
+
total += 1;
|
|
253
|
+
if (hits.length >= MAX_FIND_ENTRIES) {
|
|
254
|
+
truncated = true;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
hits.push({
|
|
258
|
+
path: rel,
|
|
259
|
+
kind: "file",
|
|
260
|
+
name: rel.split("/").pop() ?? rel,
|
|
261
|
+
description: normalizeProjectionPreview(memory.content),
|
|
262
|
+
count: 1,
|
|
263
|
+
depth: 0,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
hits.sort(byPath);
|
|
267
|
+
return { ok: true, verb: "find", namespace, path: "", total, entries: hits, truncated, rendered: renderEntries("find", namespace, "", hits) };
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
let browsePath: string;
|
|
271
|
+
try {
|
|
272
|
+
browsePath = sanitizeBrowsePath(request.path);
|
|
273
|
+
} catch (err) {
|
|
274
|
+
return refusal(request.verb, request.path ?? "", "invalid_path", err instanceof Error ? err.message : String(err));
|
|
275
|
+
}
|
|
276
|
+
const root = buildIndex(memories, storage.dir);
|
|
277
|
+
let node: DirNode | undefined = root;
|
|
278
|
+
for (const segment of browsePath === "" ? [] : browsePath.split("/")) {
|
|
279
|
+
node = node?.subdirs.get(segment);
|
|
280
|
+
if (node === undefined) break;
|
|
281
|
+
}
|
|
282
|
+
// Invisible-by-design stores resolve as not_found, indistinguishable from
|
|
283
|
+
// a missing path: the index only ever contains browsable corpus paths.
|
|
284
|
+
if (node === undefined) {
|
|
285
|
+
return refusal(request.verb, browsePath, "not_found", `no browsable store path: ${browsePath}`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (request.verb === "ls") {
|
|
289
|
+
const all = dirEntries(node, browsePath);
|
|
290
|
+
const truncated = all.length > MAX_LS_ENTRIES;
|
|
291
|
+
const entries = all.slice(0, MAX_LS_ENTRIES);
|
|
292
|
+
return { ok: true, verb: "ls", namespace, path: browsePath, total: all.length, entries, truncated, rendered: renderEntries("ls", namespace, browsePath, entries) };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (request.depth !== undefined && (!Number.isInteger(request.depth) || request.depth < 1 || request.depth > MAX_TREE_DEPTH)) {
|
|
296
|
+
return refusal(request.verb, browsePath, "invalid_depth", `depth must be an integer between 1 and ${MAX_TREE_DEPTH}`);
|
|
297
|
+
}
|
|
298
|
+
const depth = request.depth ?? 1;
|
|
299
|
+
const entries: MemoryBrowseEntry[] = [];
|
|
300
|
+
let truncated = false;
|
|
301
|
+
const walk = (current: DirNode, currentPath: string, currentDepth: number): void => {
|
|
302
|
+
for (const entry of dirEntries(current, currentPath)) {
|
|
303
|
+
if (entries.length >= MAX_TREE_ENTRIES) {
|
|
304
|
+
truncated = true;
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
entries.push({ ...entry, depth: currentDepth });
|
|
308
|
+
if (entry.kind === "dir" && currentDepth < depth - 1) {
|
|
309
|
+
walk(current.subdirs.get(entry.name)!, entry.path, currentDepth + 1);
|
|
310
|
+
if (truncated) return;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
walk(node, browsePath, 0);
|
|
315
|
+
return { ok: true, verb: "tree", namespace, path: browsePath, total: entries.length, entries, truncated, rendered: renderEntries("tree", namespace, browsePath, entries) };
|
|
316
|
+
}
|
package/src/provenance.ts
CHANGED
|
@@ -652,11 +652,11 @@ function casefold(s: string): string {
|
|
|
652
652
|
* this as a verified match and record a source without offsets (cursor
|
|
653
653
|
* thread Ocver — "Normalized match drops verified provenance").
|
|
654
654
|
*/
|
|
655
|
-
type LocateQuoteResult =
|
|
655
|
+
export type LocateQuoteResult =
|
|
656
656
|
| { matched: false }
|
|
657
657
|
| { matched: true; offsets?: { charStart: number; charEnd: number } };
|
|
658
658
|
|
|
659
|
-
function locateQuoteOffsets(quote: string, text: string): LocateQuoteResult {
|
|
659
|
+
export function locateQuoteOffsets(quote: string, text: string): LocateQuoteResult {
|
|
660
660
|
// 1. Exact substring match (handles unicode, curly quotes, emoji verbatim).
|
|
661
661
|
const exactIdx = text.indexOf(quote);
|
|
662
662
|
if (exactIdx >= 0) {
|
|
@@ -769,7 +769,7 @@ function locateQuoteOffsets(quote: string, text: string): LocateQuoteResult {
|
|
|
769
769
|
* original meaning (chatgpt-codex-connector thread 4xA — limiting role-prefix
|
|
770
770
|
* stripping to actual prompt labels).
|
|
771
771
|
*/
|
|
772
|
-
function stripLeadingRolePrefix(quote: string): string {
|
|
772
|
+
export function stripLeadingRolePrefix(quote: string): string {
|
|
773
773
|
return quote.replace(/^\s*\[(?:context\s+)?(?:user|assistant)\]\s+/i, "");
|
|
774
774
|
}
|
|
775
775
|
|
|
@@ -39,6 +39,33 @@ test("peer manifest revision includes the citation-template fingerprint", () =>
|
|
|
39
39
|
assert.equal(peerManifestRevision("{{source}}"), custom);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
+
test("buildReconcileManifest stops scheduling read batches once the signal aborts (#2954)", async () => {
|
|
43
|
+
const controller = new AbortController();
|
|
44
|
+
let reads = 0;
|
|
45
|
+
const stub = Buffer.from("stub");
|
|
46
|
+
// 120 files = three 50-file read batches; the abort lands inside batch 1.
|
|
47
|
+
const files = Array.from({ length: 120 }, (_, i) => ({
|
|
48
|
+
path: `facts/batch-abort-${i}.md`,
|
|
49
|
+
sha256: createHash("sha256").update(String(i)).digest("hex"),
|
|
50
|
+
}));
|
|
51
|
+
await assert.rejects(
|
|
52
|
+
buildReconcileManifest({
|
|
53
|
+
files,
|
|
54
|
+
parseMemory: parseFrontmatter,
|
|
55
|
+
signal: controller.signal,
|
|
56
|
+
readFile: async () => {
|
|
57
|
+
reads += 1;
|
|
58
|
+
if (reads === 1) controller.abort();
|
|
59
|
+
return stub;
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
(error: unknown) => (error as Error)?.name === "AbortError"
|
|
63
|
+
);
|
|
64
|
+
// Batch 1 was already in flight when the abort landed, so exactly its 50
|
|
65
|
+
// reads ran; batches 2 and 3 must never be scheduled.
|
|
66
|
+
assert.equal(reads, 50);
|
|
67
|
+
});
|
|
68
|
+
|
|
42
69
|
test("reconcile manifest keeps file identity separate from canonical semantic identity", async () => {
|
|
43
70
|
const content = "The deployment uses a durable queue with an enrichment suffix.";
|
|
44
71
|
const semanticHash = ContentHashIndex.computeHash("The deployment uses a durable queue.");
|
|
@@ -82,6 +82,9 @@ export interface BuildReconcileManifestOptions {
|
|
|
82
82
|
parseMemory: ReconcileMemoryParser;
|
|
83
83
|
cachedFiles?: Iterable<ReconcileManifestFile>;
|
|
84
84
|
citationTemplate?: string;
|
|
85
|
+
/** Cancellation (#2954): checked between read batches so an aborted run
|
|
86
|
+
* stops scheduling new file reads instead of walking the whole corpus. */
|
|
87
|
+
signal?: AbortSignal;
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
const SHA256_PATTERN = /^[a-f0-9]{64}$/i;
|
|
@@ -287,6 +290,10 @@ export async function buildReconcileManifest(options: BuildReconcileManifestOpti
|
|
|
287
290
|
}
|
|
288
291
|
}
|
|
289
292
|
for (let i = 0; i < uncached.length; i += MANIFEST_BUILD_BATCH_SIZE) {
|
|
293
|
+
// Between batches, not within one: an abort mid-batch lets the in-flight
|
|
294
|
+
// reads settle (their own fetch signal does the aborting) and stops the
|
|
295
|
+
// NEXT batch from ever being scheduled.
|
|
296
|
+
options.signal?.throwIfAborted();
|
|
290
297
|
const batch = uncached.slice(i, i + MANIFEST_BUILD_BATCH_SIZE);
|
|
291
298
|
const results = await Promise.all(
|
|
292
299
|
batch.map(({ file }) =>
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* standing-memory-block.test.ts — issue #2971 foundation slice.
|
|
3
|
+
*
|
|
4
|
+
* Pins the prefix-cache contract:
|
|
5
|
+
* - the block is byte-identical across consecutive builds with an unchanged
|
|
6
|
+
* store (same entries), regardless of input order and of the evaluation
|
|
7
|
+
* instant (the clock classifies bands but never renders);
|
|
8
|
+
* - the volatility lint refuses clocks, dates, and counters at build time;
|
|
9
|
+
* - three-band layering (pinned full, fresh full, older compressed to a
|
|
10
|
+
* recognition hook) with a hook ledger that makes steady-state rebuilds
|
|
11
|
+
* free and lets a later model slice pre-seed hooks;
|
|
12
|
+
* - the mechanical trim fallback drops compressed lines from the tail and
|
|
13
|
+
* never a pinned line;
|
|
14
|
+
* - zero-diff: with the feature off (and even on, pre-wiring), the live
|
|
15
|
+
* recall output is byte-identical and contains no standing block.
|
|
16
|
+
*/
|
|
17
|
+
import assert from "node:assert/strict";
|
|
18
|
+
import os from "node:os";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
import { mkdtemp, mkdir, writeFile, rm } from "node:fs/promises";
|
|
21
|
+
import test from "node:test";
|
|
22
|
+
|
|
23
|
+
import { parseConfig } from "./config.js";
|
|
24
|
+
import { Orchestrator } from "./orchestrator.js";
|
|
25
|
+
import type { PluginConfig } from "./types.js";
|
|
26
|
+
import {
|
|
27
|
+
buildStandingMemoryBlock,
|
|
28
|
+
lintStandingBlockVolatility,
|
|
29
|
+
parseRecallStandingBlock,
|
|
30
|
+
parseStandingBlockFreshDays,
|
|
31
|
+
parseStandingBlockMaxChars,
|
|
32
|
+
standingHookLedgerKey,
|
|
33
|
+
StandingBlockBudgetError,
|
|
34
|
+
StandingBlockVolatilityError,
|
|
35
|
+
type StandingMemoryEntry,
|
|
36
|
+
} from "./standing-memory-block.js";
|
|
37
|
+
|
|
38
|
+
const NOW = Date.parse("2026-08-25T12:00:00.000Z");
|
|
39
|
+
|
|
40
|
+
const PINNED: StandingMemoryEntry = {
|
|
41
|
+
id: "p-core",
|
|
42
|
+
description: "Deploys always go through the blue pipeline, never green.",
|
|
43
|
+
pinned: true,
|
|
44
|
+
};
|
|
45
|
+
const PINNED2: StandingMemoryEntry = {
|
|
46
|
+
id: "p-two",
|
|
47
|
+
description: "Every release tag is signed with the release key.",
|
|
48
|
+
pinned: true,
|
|
49
|
+
};
|
|
50
|
+
const FRESH: StandingMemoryEntry = {
|
|
51
|
+
id: "f-recent",
|
|
52
|
+
description: "The auth service owner is Priya.",
|
|
53
|
+
lastChangedAt: "2026-08-20T09:00:00.000Z",
|
|
54
|
+
};
|
|
55
|
+
const OLD_LONG: StandingMemoryEntry = {
|
|
56
|
+
id: "o-history",
|
|
57
|
+
description:
|
|
58
|
+
"The billing stack migrated off the legacy invoice service after the Q3 review " +
|
|
59
|
+
"because duplicate charges surfaced twice and the team rebuilt invoicing around " +
|
|
60
|
+
"the ledger event stream that the finance group already trusted.",
|
|
61
|
+
lastChangedAt: "2025-11-01T00:00:00.000Z",
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
test("parseConfig: standing block keys default off with byte-identical behavior", () => {
|
|
65
|
+
const base = { memoryDir: "/tmp/remnic-standing-config-test" };
|
|
66
|
+
const parsed = parseConfig(base);
|
|
67
|
+
assert.equal(parsed.recallStandingBlock, false, "absent → false");
|
|
68
|
+
assert.equal(parsed.standingBlockFreshDays, 14);
|
|
69
|
+
assert.equal(parsed.standingBlockMaxChars, 2048);
|
|
70
|
+
assert.equal(parseConfig({ ...base, recallStandingBlock: false }).recallStandingBlock, false);
|
|
71
|
+
assert.equal(parseConfig({ ...base, recallStandingBlock: 0 }).recallStandingBlock, false);
|
|
72
|
+
assert.equal(parseConfig({ ...base, recallStandingBlock: "false" }).recallStandingBlock, false);
|
|
73
|
+
assert.equal(parseConfig({ ...base, recallStandingBlock: true }).recallStandingBlock, true);
|
|
74
|
+
assert.equal(parseConfig({ ...base, recallStandingBlock: 1 }).recallStandingBlock, true);
|
|
75
|
+
assert.equal(parseConfig({ ...base, recallStandingBlock: "true" }).recallStandingBlock, true);
|
|
76
|
+
assert.equal(parseStandingBlockFreshDays("30"), 30);
|
|
77
|
+
assert.equal(parseStandingBlockMaxChars(1024), 1024);
|
|
78
|
+
assert.throws(() => parseStandingBlockFreshDays(-1), /Invalid standingBlockFreshDays/);
|
|
79
|
+
assert.throws(() => parseStandingBlockMaxChars(0), /Invalid standingBlockMaxChars/);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("block is byte-identical across consecutive builds with an unchanged store", () => {
|
|
83
|
+
const entries = [PINNED, FRESH, OLD_LONG];
|
|
84
|
+
const first = buildStandingMemoryBlock({ entries, nowMs: NOW });
|
|
85
|
+
const second = buildStandingMemoryBlock({ entries, nowMs: NOW });
|
|
86
|
+
assert.equal(first.text, second.text);
|
|
87
|
+
assert.equal(first.text, buildStandingMemoryBlock({ entries: [...entries].reverse(), nowMs: NOW }).text);
|
|
88
|
+
assert.equal(
|
|
89
|
+
first.text,
|
|
90
|
+
buildStandingMemoryBlock({ entries, nowMs: NOW + 3_600_000, ledger: first.ledger }).text,
|
|
91
|
+
"the evaluation clock must never render into the block",
|
|
92
|
+
);
|
|
93
|
+
assert.ok(first.text.startsWith("## Standing Memory (Remnic)"));
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("volatility lint refuses dates, clocks, relative dates, and counters at build time", () => {
|
|
97
|
+
assert.deepEqual(lintStandingBlockVolatility("shipped 2026-08-01"), [
|
|
98
|
+
{ kind: "iso-date", token: "2026-08-01" },
|
|
99
|
+
]);
|
|
100
|
+
assert.deepEqual(lintStandingBlockVolatility("standup at 10:30 sharp"), [
|
|
101
|
+
{ kind: "clock-time", token: "10:30" },
|
|
102
|
+
]);
|
|
103
|
+
assert.deepEqual(lintStandingBlockVolatility("fixed yesterday"), [
|
|
104
|
+
{ kind: "relative-date", token: "yesterday" },
|
|
105
|
+
]);
|
|
106
|
+
assert.deepEqual(lintStandingBlockVolatility("index has memories: 42 rows"), [
|
|
107
|
+
{ kind: "counter", token: "memories: 42" },
|
|
108
|
+
]);
|
|
109
|
+
assert.deepEqual(lintStandingBlockVolatility("quiet, stable line"), []);
|
|
110
|
+
|
|
111
|
+
const refuses = (entry: StandingMemoryEntry, kind: string) => {
|
|
112
|
+
assert.throws(
|
|
113
|
+
() => buildStandingMemoryBlock({ entries: [entry], nowMs: NOW }),
|
|
114
|
+
(err: unknown) => {
|
|
115
|
+
assert.ok(err instanceof StandingBlockVolatilityError);
|
|
116
|
+
assert.equal(err.matches[0]?.kind, kind);
|
|
117
|
+
return true;
|
|
118
|
+
},
|
|
119
|
+
`expected refusal for ${kind}`,
|
|
120
|
+
);
|
|
121
|
+
};
|
|
122
|
+
refuses({ id: "d1", description: "Deployed on 2026-08-01 to prod." }, "iso-date");
|
|
123
|
+
refuses({ id: "d2", description: "The standup moved to 09:15." }, "clock-time");
|
|
124
|
+
refuses({ id: "d3", description: "The on-call rota changed yesterday." }, "relative-date");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("three-band layering: pinned full first, fresh full, older compressed to a hook", () => {
|
|
128
|
+
const built = buildStandingMemoryBlock({ entries: [OLD_LONG, FRESH, PINNED], nowMs: NOW });
|
|
129
|
+
const body = built.lines.filter((line) => line.startsWith("- "));
|
|
130
|
+
assert.deepEqual(built.bandCounts, { pinned: 1, fresh: 1, compressed: 1, dropped: 0 });
|
|
131
|
+
// Band rank, then id order: pinned band has p-core alone.
|
|
132
|
+
assert.equal(body[0], `- ${PINNED.description}`);
|
|
133
|
+
assert.equal(body[1], `- ${FRESH.description}`);
|
|
134
|
+
const hookLine = body[2] ?? "";
|
|
135
|
+
assert.ok(hookLine.startsWith("- "), "compressed line must render");
|
|
136
|
+
assert.ok(hookLine.endsWith("..."), "mechanical hook marks truncation");
|
|
137
|
+
assert.ok(hookLine.length <= 2 + 96 + 3, "hook stays inside the char budget");
|
|
138
|
+
assert.ok(
|
|
139
|
+
built.ledger.get(standingHookLedgerKey(OLD_LONG.description, 96))?.endsWith("..."),
|
|
140
|
+
"generated hook lands in the ledger",
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("hook ledger: pre-seeded hooks are used verbatim; reuse keeps bytes identical", () => {
|
|
145
|
+
const seeded = new Map([[standingHookLedgerKey(OLD_LONG.description, 96), "Billing moved to the ledger stream."]]);
|
|
146
|
+
const built = buildStandingMemoryBlock({ entries: [OLD_LONG], nowMs: NOW, ledger: seeded });
|
|
147
|
+
assert.ok(built.text.includes("- Billing moved to the ledger stream."));
|
|
148
|
+
const rebuilt = buildStandingMemoryBlock({ entries: [OLD_LONG], nowMs: NOW, ledger: built.ledger });
|
|
149
|
+
assert.equal(built.text, rebuilt.text);
|
|
150
|
+
assert.equal(seeded.size, 1, "input ledger is never mutated");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("mechanical trim: drops compressed lines from the tail, never pinned lines", () => {
|
|
154
|
+
const built = buildStandingMemoryBlock({ entries: [OLD_LONG, FRESH, PINNED], nowMs: NOW, maxChars: 220 });
|
|
155
|
+
assert.equal(built.bandCounts.pinned, 1, "pinned line survives");
|
|
156
|
+
assert.ok(built.bandCounts.dropped >= 1, "tail lines dropped");
|
|
157
|
+
assert.ok(built.text.includes("- ...(older lines trimmed)"));
|
|
158
|
+
assert.ok(!built.text.includes(OLD_LONG.description.slice(0, 40)), "the longest compressed line is gone");
|
|
159
|
+
assert.throws(
|
|
160
|
+
() => buildStandingMemoryBlock({ entries: [PINNED, PINNED2], nowMs: NOW, maxChars: 80 }),
|
|
161
|
+
StandingBlockBudgetError,
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("no entries render an empty block; bad input is refused loudly", () => {
|
|
166
|
+
assert.equal(buildStandingMemoryBlock({ entries: [], nowMs: NOW }).text, "");
|
|
167
|
+
assert.throws(
|
|
168
|
+
() => buildStandingMemoryBlock({ entries: [{ id: "x", description: "" }], nowMs: NOW }),
|
|
169
|
+
/requires a non-empty description/,
|
|
170
|
+
);
|
|
171
|
+
assert.throws(
|
|
172
|
+
() =>
|
|
173
|
+
buildStandingMemoryBlock({
|
|
174
|
+
entries: [
|
|
175
|
+
{ id: "x", description: "One." },
|
|
176
|
+
{ id: "x", description: "Two." },
|
|
177
|
+
],
|
|
178
|
+
nowMs: NOW,
|
|
179
|
+
}),
|
|
180
|
+
/ids must be unique/,
|
|
181
|
+
);
|
|
182
|
+
assert.throws(
|
|
183
|
+
() => buildStandingMemoryBlock({ entries: [{ id: "x", description: "One.", lastChangedAt: "nope" }], nowMs: NOW }),
|
|
184
|
+
/unparseable lastChangedAt/,
|
|
185
|
+
);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Zero-diff proof for the foundation slice: nothing on the live recall path
|
|
190
|
+
* reads the new keys yet, so recall output must stay byte-identical whether
|
|
191
|
+
* the flag is absent or explicitly true, and must contain no standing block.
|
|
192
|
+
* When the server wiring slice lands, this test flips to assert the block IS
|
|
193
|
+
* prepended when on — that flip is the wiring PR's fail-before receipt.
|
|
194
|
+
*/
|
|
195
|
+
async function makeOrchestrator(
|
|
196
|
+
overrides: Partial<PluginConfig> = {},
|
|
197
|
+
): Promise<{ orchestrator: Orchestrator; memoryDir: string }> {
|
|
198
|
+
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-standing-zero-diff-"));
|
|
199
|
+
const config = parseConfig({
|
|
200
|
+
openaiApiKey: "sk-test",
|
|
201
|
+
memoryDir,
|
|
202
|
+
workspaceDir: path.join(memoryDir, "workspace"),
|
|
203
|
+
qmdEnabled: false,
|
|
204
|
+
embeddingFallbackEnabled: false,
|
|
205
|
+
multiGraphMemoryEnabled: false,
|
|
206
|
+
entityGraphEnabled: false,
|
|
207
|
+
timeGraphEnabled: false,
|
|
208
|
+
causalGraphEnabled: false,
|
|
209
|
+
extractionJudgeEnabled: false,
|
|
210
|
+
contradictionDetectionEnabled: false,
|
|
211
|
+
chunkingEnabled: false,
|
|
212
|
+
extractionMinChars: 0,
|
|
213
|
+
extractionMinImportanceLevel: "trivial",
|
|
214
|
+
inlineSourceAttributionEnabled: false,
|
|
215
|
+
initGateTimeoutMs: 200,
|
|
216
|
+
...overrides,
|
|
217
|
+
});
|
|
218
|
+
return { orchestrator: new Orchestrator(config), memoryDir };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function writeFact(memoryDir: string): Promise<void> {
|
|
222
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
223
|
+
const factsDir = path.join(memoryDir, "facts", today);
|
|
224
|
+
await mkdir(factsDir, { recursive: true });
|
|
225
|
+
const now = new Date().toISOString();
|
|
226
|
+
const fact = [
|
|
227
|
+
"---",
|
|
228
|
+
"id: standing-fact",
|
|
229
|
+
"category: fact",
|
|
230
|
+
`created: ${now}`,
|
|
231
|
+
`updated: ${now}`,
|
|
232
|
+
"source: extraction",
|
|
233
|
+
"confidence: 0.8",
|
|
234
|
+
"confidenceTier: high",
|
|
235
|
+
"tags: []",
|
|
236
|
+
"status: active",
|
|
237
|
+
"---",
|
|
238
|
+
"",
|
|
239
|
+
"The blue pipeline is the only deploy path.",
|
|
240
|
+
"",
|
|
241
|
+
];
|
|
242
|
+
await writeFile(path.join(factsDir, "standing-fact.md"), `${fact.join("\n")}\n`, "utf-8");
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
test("zero-diff: recall output is byte-identical with the flag off vs on (pre-wiring)", async () => {
|
|
246
|
+
const off = await makeOrchestrator();
|
|
247
|
+
const on = await makeOrchestrator({ recallStandingBlock: true });
|
|
248
|
+
try {
|
|
249
|
+
await writeFact(off.memoryDir);
|
|
250
|
+
await writeFact(on.memoryDir);
|
|
251
|
+
const outOff = await off.orchestrator.recall("how do deploys go out", "sess-standing-off");
|
|
252
|
+
const outOn = await on.orchestrator.recall("how do deploys go out", "sess-standing-on");
|
|
253
|
+
assert.equal(outOn, outOff, "recall must not change until the wiring slice lands");
|
|
254
|
+
assert.ok(!outOn.includes("## Standing Memory (Remnic)"), "no standing block in recall output");
|
|
255
|
+
assert.ok(outOn.includes("blue pipeline"), "sanity: the fact is recalled");
|
|
256
|
+
} finally {
|
|
257
|
+
await off.orchestrator.destroy();
|
|
258
|
+
await on.orchestrator.destroy();
|
|
259
|
+
await rm(off.memoryDir, { recursive: true, force: true });
|
|
260
|
+
await rm(on.memoryDir, { recursive: true, force: true });
|
|
261
|
+
}
|
|
262
|
+
});
|