@remnic/core 10.0.49 → 10.0.51
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.js +49 -48
- package/dist/access-authorization-probe.js +50 -49
- package/dist/access-boundary.d.ts +6 -1
- package/dist/access-boundary.d.ts.map +1 -1
- package/dist/access-boundary.js +49 -48
- package/dist/access-cli.js +120 -119
- package/dist/access-cli.js.map +1 -1
- package/dist/access-errors.d.ts.map +1 -1
- package/dist/access-errors.js +1 -1
- package/dist/access-extraction-force-flush.js +49 -48
- package/dist/access-http-briefing.d.ts +2 -0
- package/dist/access-http-briefing.d.ts.map +1 -1
- package/dist/access-http-briefing.js +50 -49
- package/dist/access-http-query.js +51 -50
- package/dist/access-http.d.ts.map +1 -1
- package/dist/access-http.js +70 -69
- package/dist/access-identity-continuity-surface.js +49 -48
- package/dist/access-lcm-surface.js +49 -48
- package/dist/access-mcp.js +60 -59
- package/dist/access-memory-search-fanout.js +2 -2
- package/dist/access-namespace-preflight.js +49 -48
- package/dist/access-observe-write-category.d.ts +1 -1
- package/dist/access-observe-write-category.d.ts.map +1 -1
- package/dist/access-observe-write-category.js +10 -10
- package/dist/access-observe-write-surface.d.ts.map +1 -1
- package/dist/access-observe-write-surface.js +49 -48
- package/dist/access-offline-manifest.js +6 -6
- package/dist/access-operations-batch.js +50 -49
- package/dist/access-operations.js +57 -56
- package/dist/access-recall-concurrency.js +49 -48
- package/dist/access-recall-diagnostics.js +2 -2
- package/dist/access-recall-response.js +49 -48
- package/dist/access-recall-surface.js +49 -48
- package/dist/access-schema.d.ts +245 -773
- package/dist/access-schema.d.ts.map +1 -1
- package/dist/access-schema.js +6 -6
- package/dist/access-service.d.ts +5 -0
- package/dist/access-service.d.ts.map +1 -1
- package/dist/access-service.js +49 -48
- package/dist/access-surface-catalog.js +51 -50
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-token-capabilities.js +2 -2
- package/dist/active-recall.js +16 -16
- package/dist/{auto-sync-BNCBMU6H.js → auto-sync-UQQ6YJSB.js} +3 -3
- package/dist/briefing-deadline.d.ts +7 -0
- package/dist/briefing-deadline.d.ts.map +1 -0
- package/dist/briefing-deadline.js +13 -0
- package/dist/briefing-window.d.ts +12 -4
- package/dist/briefing-window.d.ts.map +1 -1
- package/dist/briefing-window.js +3 -1
- package/dist/briefing.d.ts +2 -0
- package/dist/briefing.d.ts.map +1 -1
- package/dist/briefing.js +12 -11
- package/dist/buffer.js +3 -3
- package/dist/calibration.js +2 -2
- package/dist/{capsule-merge-RNQUP2VL.js → capsule-merge-D4BTIJGK.js} +3 -3
- package/dist/causal-consolidation.js +11 -11
- package/dist/{chunk-ESDOQEJM.js → chunk-2AKIVSHP.js} +2 -2
- package/dist/{chunk-BWF3KNSQ.js → chunk-2EXF6IIB.js} +2 -2
- package/dist/{chunk-AGCEJDG2.js → chunk-2ONKXEC7.js} +3 -3
- package/dist/{chunk-3NYIXVCT.js → chunk-2S6JADBB.js} +2 -2
- package/dist/chunk-2S6JADBB.js.map +1 -0
- package/dist/{chunk-ZSEFGDCI.js → chunk-2TGIKMMZ.js} +2 -2
- package/dist/{chunk-MCS4LIXP.js → chunk-43TUWQNR.js} +2 -2
- package/dist/{chunk-Q6PYCPHO.js → chunk-44EUCSG4.js} +2 -2
- package/dist/{chunk-2J6BIOVN.js → chunk-4FM35YIA.js} +3 -3
- package/dist/{chunk-2NLCDNGA.js → chunk-564YP3DW.js} +2 -2
- package/dist/{chunk-YY6PWFUC.js → chunk-6ZAU7LAR.js} +3 -3
- package/dist/{chunk-HCPVL6SF.js → chunk-72CBJ5VP.js} +3 -3
- package/dist/{chunk-AF4UIHON.js → chunk-74AY3S7U.js} +9 -9
- package/dist/{chunk-N6EM7ESC.js → chunk-75BK4XGV.js} +27 -19
- package/dist/chunk-75BK4XGV.js.map +1 -0
- package/dist/{chunk-5IDQVE4U.js → chunk-A3UFV4K3.js} +6 -6
- package/dist/{chunk-LWRIGKFM.js → chunk-A5L5KGDI.js} +19 -1
- package/dist/chunk-A5L5KGDI.js.map +1 -0
- package/dist/{chunk-RZDDNH63.js → chunk-A6JDT6QF.js} +27 -15
- package/dist/chunk-A6JDT6QF.js.map +1 -0
- package/dist/{chunk-XFND63OB.js → chunk-AHGOOZUC.js} +2 -2
- package/dist/{chunk-A7AISUJI.js → chunk-AJG2TAMR.js} +2 -2
- package/dist/{chunk-2BY56HE6.js → chunk-AZLD4CKG.js} +36 -36
- package/dist/{chunk-E47UQBYW.js → chunk-B35EQQ7L.js} +3 -3
- package/dist/{chunk-E6UNM67F.js → chunk-B6SPPYGJ.js} +2 -2
- package/dist/{chunk-CMOYD5CA.js → chunk-CCL2OXFO.js} +2 -2
- package/dist/{chunk-SVJ5JVZO.js → chunk-CK6GCGMX.js} +4 -4
- package/dist/{chunk-QZK6HG4J.js → chunk-DF6ZF2BN.js} +3 -3
- package/dist/{chunk-CPBYKOTC.js → chunk-DJFULNXK.js} +4 -4
- package/dist/{chunk-VGRBKEBH.js → chunk-DQOGZZJA.js} +3 -3
- package/dist/{chunk-YB3WN6XA.js → chunk-EC2KVA27.js} +12 -12
- package/dist/{chunk-FRXS6SC7.js → chunk-EKUI7I2X.js} +20 -4
- package/dist/chunk-EKUI7I2X.js.map +1 -0
- package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
- package/dist/{chunk-WIBWONL4.js → chunk-EZS6QJNC.js} +2 -2
- package/dist/{chunk-C7WDWD35.js → chunk-FNNGWN3O.js} +5 -5
- package/dist/{chunk-PBWJVRKE.js → chunk-FT75AQ74.js} +3 -3
- package/dist/{chunk-VY6BD5KB.js → chunk-G6A3SGCE.js} +14 -12
- package/dist/chunk-G6A3SGCE.js.map +1 -0
- package/dist/{chunk-O4CA53UY.js → chunk-GBGU5OZP.js} +111 -104
- package/dist/chunk-GBGU5OZP.js.map +1 -0
- package/dist/{chunk-WJCAAVZX.js → chunk-GE3ZX6YK.js} +2 -2
- package/dist/{chunk-3PVKV3XL.js → chunk-HCIRR3BA.js} +3 -3
- package/dist/{chunk-BJTFLP3J.js → chunk-HEF4BRMT.js} +3 -3
- package/dist/{chunk-BMG3SAXA.js → chunk-HQUYENKK.js} +9 -12
- package/dist/chunk-HQUYENKK.js.map +1 -0
- package/dist/{chunk-6UDLN4IA.js → chunk-I6ORDT54.js} +2 -2
- package/dist/{chunk-N5PISU26.js → chunk-IN6U2BS5.js} +2 -2
- package/dist/{chunk-3INLTKTW.js → chunk-IUQXRRJB.js} +4 -4
- package/dist/{chunk-6W3QH3QW.js → chunk-JIJAWTRK.js} +388 -292
- package/dist/chunk-JIJAWTRK.js.map +1 -0
- package/dist/{chunk-4KS4IHKH.js → chunk-JX3E4XCW.js} +2 -2
- package/dist/{chunk-SW3WHVKN.js → chunk-KAJYSO3U.js} +2 -2
- package/dist/{chunk-D76AHITY.js → chunk-KETS5A62.js} +2 -2
- package/dist/{chunk-LCHFINL4.js → chunk-KIWO4327.js} +2 -2
- package/dist/{chunk-FC3ZFEXF.js → chunk-KJ3MDX4V.js} +2 -2
- package/dist/{chunk-7LCGFUMB.js → chunk-KQAFEZQX.js} +4 -4
- package/dist/{chunk-6TIVVOVU.js → chunk-L3EFYRYK.js} +9 -9
- package/dist/{chunk-3MUKQQ7A.js → chunk-LGEH473S.js} +24 -29
- package/dist/chunk-LGEH473S.js.map +1 -0
- package/dist/{chunk-X52SXKVC.js → chunk-LMB47UM6.js} +2 -2
- package/dist/{chunk-A3WXV7YU.js → chunk-LWMLBVGB.js} +2 -2
- package/dist/{chunk-KMTMMBEB.js → chunk-MC7PXJDP.js} +7 -7
- package/dist/{chunk-NMOEOQV4.js → chunk-MUNYUSBU.js} +2 -2
- package/dist/{chunk-VKUMKVEU.js → chunk-OCRLJJOV.js} +5 -5
- package/dist/{chunk-XSJL62LE.js → chunk-ON77FQXH.js} +2 -2
- package/dist/{chunk-C3HRYVGD.js → chunk-POJRFSJM.js} +3 -3
- package/dist/{chunk-LKRXGOQW.js → chunk-QA3Y2O6H.js} +2 -2
- package/dist/{chunk-23ZLN5X6.js → chunk-QT5MGENX.js} +14 -6
- package/dist/chunk-QT5MGENX.js.map +1 -0
- package/dist/{chunk-QFTNWDJ6.js → chunk-RA7YRL6H.js} +2 -2
- package/dist/{chunk-WQFHHJWK.js → chunk-RJDYDF5K.js} +4 -4
- package/dist/{chunk-E3DL3CAL.js → chunk-ROAKLYOL.js} +2 -2
- package/dist/{chunk-YFXRLRKP.js → chunk-S4OZKPBS.js} +7 -11
- package/dist/{chunk-YFXRLRKP.js.map → chunk-S4OZKPBS.js.map} +1 -1
- package/dist/{chunk-NWIT3U2N.js → chunk-S5CQI2KF.js} +2 -2
- package/dist/{chunk-P6P35FY4.js → chunk-SDESKFKT.js} +2 -2
- package/dist/{chunk-OD7ZXCUF.js → chunk-SFRBUBUZ.js} +10 -10
- package/dist/{chunk-7XFQSQYS.js → chunk-SHNM7RIT.js} +5 -4
- package/dist/chunk-SHNM7RIT.js.map +1 -0
- package/dist/{chunk-NH37SP6V.js → chunk-SJD334AG.js} +81 -78
- package/dist/chunk-SJD334AG.js.map +1 -0
- package/dist/{chunk-O7GNSHFF.js → chunk-SPTPBKZX.js} +2 -2
- package/dist/{chunk-HI53EK3Y.js → chunk-TC55M5PO.js} +2 -2
- package/dist/{chunk-SA6P2KS3.js → chunk-TEH5MDX5.js} +33 -17
- package/dist/chunk-TEH5MDX5.js.map +1 -0
- package/dist/{chunk-FOKTW6GY.js → chunk-UCLJTGP3.js} +2 -2
- package/dist/{chunk-FYZXZUGU.js → chunk-UQBOPCDK.js} +2 -2
- package/dist/{chunk-SUKPM6DV.js → chunk-UWMZT2TY.js} +47 -4
- package/dist/chunk-UWMZT2TY.js.map +1 -0
- package/dist/{chunk-754XN6LX.js → chunk-V27FK6D6.js} +2 -2
- package/dist/{chunk-DM6SOROF.js → chunk-V6Z4NAJZ.js} +2 -2
- package/dist/{chunk-5FNZ3G6X.js → chunk-VKQI47DJ.js} +4 -4
- package/dist/{chunk-NUK5XU3P.js → chunk-VUMWVYMR.js} +28 -13
- package/dist/chunk-VUMWVYMR.js.map +1 -0
- package/dist/{chunk-MPJDQC4G.js → chunk-WJCXUE2J.js} +2 -2
- package/dist/{chunk-VCBS5GRQ.js → chunk-WY66J4PI.js} +2 -2
- package/dist/chunk-X2KO4FK5.js +40 -0
- package/dist/chunk-X2KO4FK5.js.map +1 -0
- package/dist/{chunk-OOOX5C4X.js → chunk-XL2EE5W3.js} +4 -4
- package/dist/{chunk-V4GPFCJ7.js → chunk-XWJUFER3.js} +3 -3
- package/dist/{chunk-CZVNOTLR.js → chunk-XXR4A33N.js} +2 -2
- package/dist/{chunk-CRJX4OMN.js → chunk-Y3T5KQCR.js} +2 -2
- package/dist/{chunk-KNCR7APE.js → chunk-Y77FXULH.js} +8 -8
- package/dist/{chunk-2AV2U2SZ.js → chunk-YDIOMDBW.js} +2 -2
- package/dist/{chunk-IG747LRN.js → chunk-YO2JEX2Z.js} +2 -2
- package/dist/{chunk-HDT3DMUF.js → chunk-ZKK3VMWU.js} +2 -2
- package/dist/cli.js +92 -91
- package/dist/coding/export-okf-codegraph.js +9 -9
- package/dist/compounding/engine.js +11 -11
- package/dist/config.js +16 -16
- package/dist/connectors/codex-materialize-runner.js +10 -10
- package/dist/connectors/index.js +14 -14
- package/dist/consolidation-provenance-check.js +4 -4
- package/dist/consolidation-undo.js +2 -2
- package/dist/convergence-refresh.js +12 -12
- package/dist/corpus-watermark.js +14 -14
- package/dist/correction/passive-correction-notifications.d.ts +1 -1
- package/dist/correction/passive-correction-notifications.d.ts.map +1 -1
- package/dist/dashboard-runtime.js +2 -2
- package/dist/deep-recall-config.js +2 -2
- package/dist/deep-recall-http-glue.js +9 -9
- package/dist/{entity-canonical-id-migration-2YOLMOFC.js → entity-canonical-id-migration-F3JVG6K6.js} +3 -3
- package/dist/entity-canonical-id-migration-F3JVG6K6.js.map +1 -0
- package/dist/entity-retrieval.js +11 -11
- package/dist/explicit-capture.js +2 -2
- package/dist/external-wiki-access.js +50 -49
- package/dist/extraction-span-wire.d.ts.map +1 -1
- package/dist/extraction-span-wire.js +1 -1
- package/dist/extraction.js +22 -22
- package/dist/{first-start-migration-QVD22WWS.js → first-start-migration-A6PHIBUQ.js} +4 -4
- package/dist/harmonic-retrieval.js +10 -10
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +143 -135
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.js +5 -5
- package/dist/local-llm.js +2 -2
- package/dist/location/index.js +16 -16
- package/dist/location/tagging.d.ts +7 -5
- package/dist/location/tagging.d.ts.map +1 -1
- package/dist/maintenance/memory-governance.js +10 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
- package/dist/maintenance/rebuild-memory-projection-runner.js +12 -12
- package/dist/maintenance/rebuild-memory-projection.js +11 -11
- package/dist/memory-browse-http-glue.js +2 -2
- package/dist/memory-browse-operations.js +50 -49
- package/dist/namespaces/migrate.js +11 -11
- package/dist/namespaces/storage.js +10 -10
- package/dist/offline-sync-file-io.d.ts +15 -0
- package/dist/offline-sync-file-io.d.ts.map +1 -1
- package/dist/offline-sync-file-io.js +9 -1
- package/dist/offline-sync-impression-drain.js +2 -2
- package/dist/offline-sync-snapshot-stream.js +4 -4
- package/dist/offline-sync-upload-staging.js +2 -2
- package/dist/offline-sync.d.ts.map +1 -1
- package/dist/offline-sync.js +3 -3
- package/dist/operator-doctor-corpus.js +17 -17
- package/dist/operator-doctor-replica.js +4 -4
- package/dist/operator-toolkit.js +29 -29
- package/dist/orchestration/maintenance.js +25 -25
- package/dist/orchestrator.d.ts +1 -0
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +122 -121
- package/dist/page-versioning.js +2 -2
- package/dist/recall-navigation-http-glue.js +2 -2
- package/dist/recall-navigation-operations.js +50 -49
- package/dist/recall-navigation.js +49 -48
- package/dist/relay/mission.d.ts +731 -3403
- package/dist/relay/mission.d.ts.map +1 -1
- package/dist/replica-divergence.js +3 -3
- package/dist/resume-bundles.js +17 -17
- package/dist/schemas.d.ts +346 -1771
- package/dist/schemas.d.ts.map +1 -1
- package/dist/semantic-consolidation.js +15 -15
- package/dist/semantic-rule-promotion.js +10 -10
- package/dist/semantic-rule-verifier.js +10 -10
- package/dist/shared-context/manager.d.ts +13 -33
- package/dist/shared-context/manager.d.ts.map +1 -1
- package/dist/source-agent-qualifier.js +18 -18
- package/dist/standup/build.js +11 -11
- package/dist/storage/entity-canonical-id-migration-adapter.d.ts +1 -0
- package/dist/storage/entity-canonical-id-migration-adapter.d.ts.map +1 -1
- package/dist/storage/entity-canonical-id-migration.d.ts +7 -0
- package/dist/storage/entity-canonical-id-migration.d.ts.map +1 -1
- package/dist/storage/entity-canonical-id-references.d.ts +2 -0
- package/dist/storage/entity-canonical-id-references.d.ts.map +1 -1
- package/dist/storage/entity-migration-completion-cache.d.ts +46 -0
- package/dist/storage/entity-migration-completion-cache.d.ts.map +1 -0
- package/dist/storage/entity-store.d.ts +1 -8
- package/dist/storage/entity-store.d.ts.map +1 -1
- package/dist/storage/memory-read-store.d.ts +3 -2
- package/dist/storage/memory-read-store.d.ts.map +1 -1
- package/dist/storage/windowed-memory-read.d.ts +6 -0
- package/dist/storage/windowed-memory-read.d.ts.map +1 -1
- package/dist/storage.d.ts +2 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +9 -9
- package/dist/summarizer.js +3 -3
- package/dist/support-passport/access-operations.d.ts +51 -51
- package/dist/support-passport/contracts.d.ts +85 -126
- package/dist/support-passport/contracts.d.ts.map +1 -1
- package/dist/support-passport/generated-batch.d.ts +3 -17
- package/dist/support-passport/generated-batch.d.ts.map +1 -1
- package/dist/support-passport/grant-contracts.d.ts +75 -381
- package/dist/support-passport/grant-contracts.d.ts.map +1 -1
- package/dist/support-passport/index.js +52 -51
- package/dist/support-passport/model-audit.d.ts +17 -82
- package/dist/support-passport/model-audit.d.ts.map +1 -1
- package/dist/support-passport/model-bridge.d.ts +12 -51
- package/dist/support-passport/model-bridge.d.ts.map +1 -1
- package/dist/support-passport/model-contracts.d.ts +53 -192
- package/dist/support-passport/model-contracts.d.ts.map +1 -1
- package/dist/tokens.js +3 -3
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +4 -4
- package/dist/transfer/export-okf.js +10 -10
- package/dist/transfer/types.d.ts +32 -737
- package/dist/transfer/types.d.ts.map +1 -1
- package/dist/verified-recall.js +10 -10
- package/dist/who-knows-cli.js +12 -12
- package/dist/who-knows.js +11 -11
- package/package.json +3 -4
- package/src/access-boundary.test.ts +14 -0
- package/src/access-boundary.ts +48 -42
- package/src/access-category-alias.test.ts +9 -7
- package/src/access-errors.test.ts +21 -9
- package/src/access-errors.ts +45 -31
- package/src/access-http-briefing.ts +4 -0
- package/src/access-http.test.ts +41 -12
- package/src/access-http.ts +6 -0
- package/src/access-observe-write-category.ts +1 -1
- package/src/access-observe-write-surface.ts +24 -19
- package/src/access-operations-batch.ts +18 -2
- package/src/access-schema.ts +13 -17
- package/src/access-service.ts +5 -0
- package/src/briefing-abort.test.ts +173 -0
- package/src/briefing-deadline.test.ts +84 -0
- package/src/briefing-deadline.ts +33 -0
- package/src/briefing-window-abort.test.ts +47 -0
- package/src/briefing-window.ts +33 -4
- package/src/briefing.ts +23 -16
- package/src/correction/passive-correction-notifications-abort.test.ts +42 -0
- package/src/correction/passive-correction-notifications.ts +4 -0
- package/src/entity-lazy-compatibility.test.ts +229 -0
- package/src/entity-migration-completion-notification.test.ts +148 -0
- package/src/extraction-scope-source-agent.test.ts +6 -6
- package/src/extraction-span-wire.test.ts +28 -0
- package/src/extraction-span-wire.ts +34 -6
- package/src/index.ts +1 -1
- package/src/location/tagging.ts +14 -12
- package/src/offline-sync-file-io.ts +61 -2
- package/src/offline-sync.test.ts +313 -20
- package/src/offline-sync.ts +43 -21
- package/src/orchestrator-init.test.ts +49 -1
- package/src/orchestrator.ts +9 -8
- package/src/storage/entity-canonical-id-migration-adapter.ts +16 -1
- package/src/storage/entity-canonical-id-migration.ts +19 -10
- package/src/storage/entity-canonical-id-references.ts +24 -0
- package/src/storage/entity-migration-completion-cache.nofollow.test.ts +223 -0
- package/src/storage/entity-migration-completion-cache.ts +153 -0
- package/src/storage/entity-store.ts +58 -86
- package/src/storage/memory-read-store.ts +9 -3
- package/src/storage/windowed-memory-read.ts +8 -0
- package/src/storage-startup-nonblocking-migration.test.ts +183 -0
- package/src/storage.ts +7 -2
- package/src/testing/subjects/entity-migration-completion-cache.test.ts +90 -0
- package/dist/chunk-23ZLN5X6.js.map +0 -1
- package/dist/chunk-3MUKQQ7A.js.map +0 -1
- package/dist/chunk-3NYIXVCT.js.map +0 -1
- package/dist/chunk-6W3QH3QW.js.map +0 -1
- package/dist/chunk-7XFQSQYS.js.map +0 -1
- package/dist/chunk-BMG3SAXA.js.map +0 -1
- package/dist/chunk-FRXS6SC7.js.map +0 -1
- package/dist/chunk-LWRIGKFM.js.map +0 -1
- package/dist/chunk-N6EM7ESC.js.map +0 -1
- package/dist/chunk-NH37SP6V.js.map +0 -1
- package/dist/chunk-NUK5XU3P.js.map +0 -1
- package/dist/chunk-O4CA53UY.js.map +0 -1
- package/dist/chunk-RZDDNH63.js.map +0 -1
- package/dist/chunk-SA6P2KS3.js.map +0 -1
- package/dist/chunk-SUKPM6DV.js.map +0 -1
- package/dist/chunk-VY6BD5KB.js.map +0 -1
- /package/dist/{auto-sync-BNCBMU6H.js.map → auto-sync-UQQ6YJSB.js.map} +0 -0
- /package/dist/{entity-canonical-id-migration-2YOLMOFC.js.map → briefing-deadline.js.map} +0 -0
- /package/dist/{capsule-merge-RNQUP2VL.js.map → capsule-merge-D4BTIJGK.js.map} +0 -0
- /package/dist/{chunk-ESDOQEJM.js.map → chunk-2AKIVSHP.js.map} +0 -0
- /package/dist/{chunk-BWF3KNSQ.js.map → chunk-2EXF6IIB.js.map} +0 -0
- /package/dist/{chunk-AGCEJDG2.js.map → chunk-2ONKXEC7.js.map} +0 -0
- /package/dist/{chunk-ZSEFGDCI.js.map → chunk-2TGIKMMZ.js.map} +0 -0
- /package/dist/{chunk-MCS4LIXP.js.map → chunk-43TUWQNR.js.map} +0 -0
- /package/dist/{chunk-Q6PYCPHO.js.map → chunk-44EUCSG4.js.map} +0 -0
- /package/dist/{chunk-2J6BIOVN.js.map → chunk-4FM35YIA.js.map} +0 -0
- /package/dist/{chunk-2NLCDNGA.js.map → chunk-564YP3DW.js.map} +0 -0
- /package/dist/{chunk-YY6PWFUC.js.map → chunk-6ZAU7LAR.js.map} +0 -0
- /package/dist/{chunk-HCPVL6SF.js.map → chunk-72CBJ5VP.js.map} +0 -0
- /package/dist/{chunk-AF4UIHON.js.map → chunk-74AY3S7U.js.map} +0 -0
- /package/dist/{chunk-5IDQVE4U.js.map → chunk-A3UFV4K3.js.map} +0 -0
- /package/dist/{chunk-XFND63OB.js.map → chunk-AHGOOZUC.js.map} +0 -0
- /package/dist/{chunk-A7AISUJI.js.map → chunk-AJG2TAMR.js.map} +0 -0
- /package/dist/{chunk-2BY56HE6.js.map → chunk-AZLD4CKG.js.map} +0 -0
- /package/dist/{chunk-E47UQBYW.js.map → chunk-B35EQQ7L.js.map} +0 -0
- /package/dist/{chunk-E6UNM67F.js.map → chunk-B6SPPYGJ.js.map} +0 -0
- /package/dist/{chunk-CMOYD5CA.js.map → chunk-CCL2OXFO.js.map} +0 -0
- /package/dist/{chunk-SVJ5JVZO.js.map → chunk-CK6GCGMX.js.map} +0 -0
- /package/dist/{chunk-QZK6HG4J.js.map → chunk-DF6ZF2BN.js.map} +0 -0
- /package/dist/{chunk-CPBYKOTC.js.map → chunk-DJFULNXK.js.map} +0 -0
- /package/dist/{chunk-VGRBKEBH.js.map → chunk-DQOGZZJA.js.map} +0 -0
- /package/dist/{chunk-YB3WN6XA.js.map → chunk-EC2KVA27.js.map} +0 -0
- /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
- /package/dist/{chunk-WIBWONL4.js.map → chunk-EZS6QJNC.js.map} +0 -0
- /package/dist/{chunk-C7WDWD35.js.map → chunk-FNNGWN3O.js.map} +0 -0
- /package/dist/{chunk-PBWJVRKE.js.map → chunk-FT75AQ74.js.map} +0 -0
- /package/dist/{chunk-WJCAAVZX.js.map → chunk-GE3ZX6YK.js.map} +0 -0
- /package/dist/{chunk-3PVKV3XL.js.map → chunk-HCIRR3BA.js.map} +0 -0
- /package/dist/{chunk-BJTFLP3J.js.map → chunk-HEF4BRMT.js.map} +0 -0
- /package/dist/{chunk-6UDLN4IA.js.map → chunk-I6ORDT54.js.map} +0 -0
- /package/dist/{chunk-N5PISU26.js.map → chunk-IN6U2BS5.js.map} +0 -0
- /package/dist/{chunk-3INLTKTW.js.map → chunk-IUQXRRJB.js.map} +0 -0
- /package/dist/{chunk-4KS4IHKH.js.map → chunk-JX3E4XCW.js.map} +0 -0
- /package/dist/{chunk-SW3WHVKN.js.map → chunk-KAJYSO3U.js.map} +0 -0
- /package/dist/{chunk-D76AHITY.js.map → chunk-KETS5A62.js.map} +0 -0
- /package/dist/{chunk-LCHFINL4.js.map → chunk-KIWO4327.js.map} +0 -0
- /package/dist/{chunk-FC3ZFEXF.js.map → chunk-KJ3MDX4V.js.map} +0 -0
- /package/dist/{chunk-7LCGFUMB.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-6TIVVOVU.js.map → chunk-L3EFYRYK.js.map} +0 -0
- /package/dist/{chunk-X52SXKVC.js.map → chunk-LMB47UM6.js.map} +0 -0
- /package/dist/{chunk-A3WXV7YU.js.map → chunk-LWMLBVGB.js.map} +0 -0
- /package/dist/{chunk-KMTMMBEB.js.map → chunk-MC7PXJDP.js.map} +0 -0
- /package/dist/{chunk-NMOEOQV4.js.map → chunk-MUNYUSBU.js.map} +0 -0
- /package/dist/{chunk-VKUMKVEU.js.map → chunk-OCRLJJOV.js.map} +0 -0
- /package/dist/{chunk-XSJL62LE.js.map → chunk-ON77FQXH.js.map} +0 -0
- /package/dist/{chunk-C3HRYVGD.js.map → chunk-POJRFSJM.js.map} +0 -0
- /package/dist/{chunk-LKRXGOQW.js.map → chunk-QA3Y2O6H.js.map} +0 -0
- /package/dist/{chunk-QFTNWDJ6.js.map → chunk-RA7YRL6H.js.map} +0 -0
- /package/dist/{chunk-WQFHHJWK.js.map → chunk-RJDYDF5K.js.map} +0 -0
- /package/dist/{chunk-E3DL3CAL.js.map → chunk-ROAKLYOL.js.map} +0 -0
- /package/dist/{chunk-NWIT3U2N.js.map → chunk-S5CQI2KF.js.map} +0 -0
- /package/dist/{chunk-P6P35FY4.js.map → chunk-SDESKFKT.js.map} +0 -0
- /package/dist/{chunk-OD7ZXCUF.js.map → chunk-SFRBUBUZ.js.map} +0 -0
- /package/dist/{chunk-O7GNSHFF.js.map → chunk-SPTPBKZX.js.map} +0 -0
- /package/dist/{chunk-HI53EK3Y.js.map → chunk-TC55M5PO.js.map} +0 -0
- /package/dist/{chunk-FOKTW6GY.js.map → chunk-UCLJTGP3.js.map} +0 -0
- /package/dist/{chunk-FYZXZUGU.js.map → chunk-UQBOPCDK.js.map} +0 -0
- /package/dist/{chunk-754XN6LX.js.map → chunk-V27FK6D6.js.map} +0 -0
- /package/dist/{chunk-DM6SOROF.js.map → chunk-V6Z4NAJZ.js.map} +0 -0
- /package/dist/{chunk-5FNZ3G6X.js.map → chunk-VKQI47DJ.js.map} +0 -0
- /package/dist/{chunk-MPJDQC4G.js.map → chunk-WJCXUE2J.js.map} +0 -0
- /package/dist/{chunk-VCBS5GRQ.js.map → chunk-WY66J4PI.js.map} +0 -0
- /package/dist/{chunk-OOOX5C4X.js.map → chunk-XL2EE5W3.js.map} +0 -0
- /package/dist/{chunk-V4GPFCJ7.js.map → chunk-XWJUFER3.js.map} +0 -0
- /package/dist/{chunk-CZVNOTLR.js.map → chunk-XXR4A33N.js.map} +0 -0
- /package/dist/{chunk-CRJX4OMN.js.map → chunk-Y3T5KQCR.js.map} +0 -0
- /package/dist/{chunk-KNCR7APE.js.map → chunk-Y77FXULH.js.map} +0 -0
- /package/dist/{chunk-2AV2U2SZ.js.map → chunk-YDIOMDBW.js.map} +0 -0
- /package/dist/{chunk-IG747LRN.js.map → chunk-YO2JEX2Z.js.map} +0 -0
- /package/dist/{chunk-HDT3DMUF.js.map → chunk-ZKK3VMWU.js.map} +0 -0
- /package/dist/{first-start-migration-QVD22WWS.js.map → first-start-migration-A6PHIBUQ.js.map} +0 -0
package/src/access-http.test.ts
CHANGED
|
@@ -15,11 +15,13 @@ import {
|
|
|
15
15
|
EngramAccessInputError,
|
|
16
16
|
type EngramAccessRecallRequest,
|
|
17
17
|
type EngramAccessService,
|
|
18
|
+
type EngramAccessBriefingRequest,
|
|
18
19
|
} from "./access-service.js";
|
|
19
20
|
import {
|
|
20
21
|
tokenCapabilityStore,
|
|
21
22
|
type TokenCapabilities,
|
|
22
23
|
} from "./access-token-capabilities.js";
|
|
24
|
+
import { BriefingTimeoutError } from "./briefing-deadline.js";
|
|
23
25
|
import { parseConfig } from "./config.js";
|
|
24
26
|
import { readPair, writePair } from "./contradiction/contradiction-review.js";
|
|
25
27
|
import { createChatSession } from "./chat/chat-session.js";
|
|
@@ -859,17 +861,23 @@ test("HTTP briefing endpoint dispatches through the briefing operation", async (
|
|
|
859
861
|
assert.equal(body.format, "markdown");
|
|
860
862
|
assert.equal(body.markdown, "# Briefing");
|
|
861
863
|
assert.deepEqual(body.json.sections.activeThreads, []);
|
|
862
|
-
assert.
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
864
|
+
assert.equal(calls.length, 1);
|
|
865
|
+
// SAFETY: the registered handler builds this request after validating the HTTP body; assertions below check its values.
|
|
866
|
+
const captured = calls[0] as EngramAccessBriefingRequest;
|
|
867
|
+
const { abortSignal, ...briefingRequest } = captured;
|
|
868
|
+
assert.ok(
|
|
869
|
+
abortSignal instanceof AbortSignal,
|
|
870
|
+
"the briefing request carries the HTTP request lifetime signal",
|
|
871
|
+
);
|
|
872
|
+
assert.deepEqual(briefingRequest, {
|
|
873
|
+
since: "24h",
|
|
874
|
+
focus: undefined,
|
|
875
|
+
includeLocation: undefined,
|
|
876
|
+
namespace: "team",
|
|
877
|
+
format: "markdown",
|
|
878
|
+
maxFollowups: 5,
|
|
879
|
+
principal: "panel-user",
|
|
880
|
+
});
|
|
873
881
|
|
|
874
882
|
const invalid = await fetch(
|
|
875
883
|
`http://127.0.0.1:${status.port}/engram/v1/briefing`,
|
|
@@ -890,6 +898,27 @@ test("HTTP briefing endpoint dispatches through the briefing operation", async (
|
|
|
890
898
|
}
|
|
891
899
|
});
|
|
892
900
|
|
|
901
|
+
test("HTTP briefing endpoint answers 504 briefing_timeout when the request budget is exhausted", async () => {
|
|
902
|
+
const service: EngramAccessService = Object.assign(Object.create(null), {
|
|
903
|
+
briefing: async () => {
|
|
904
|
+
throw new BriefingTimeoutError(30_000);
|
|
905
|
+
},
|
|
906
|
+
});
|
|
907
|
+
const server = new EngramAccessHttpServer({ service, port: 0, authToken: "test-token", adminConsoleEnabled: false });
|
|
908
|
+
const status = await server.start();
|
|
909
|
+
try {
|
|
910
|
+
const response = await fetch(`http://127.0.0.1:${status.port}/engram/v1/briefing`, {
|
|
911
|
+
method: "POST",
|
|
912
|
+
headers: { authorization: "Bearer test-token", "content-type": "application/json" },
|
|
913
|
+
body: JSON.stringify({}),
|
|
914
|
+
});
|
|
915
|
+
assert.equal(response.status, 504);
|
|
916
|
+
assert.deepEqual(await response.json(), { error: "briefing timed out after 30000ms", code: "briefing_timeout" });
|
|
917
|
+
} finally {
|
|
918
|
+
await server.stop();
|
|
919
|
+
}
|
|
920
|
+
});
|
|
921
|
+
|
|
893
922
|
test("HTTP contradiction scan uses writable namespace resolver", async () => {
|
|
894
923
|
const resolverCalls: Array<{
|
|
895
924
|
namespace: string | undefined;
|
|
@@ -2136,7 +2165,7 @@ test("HTTP offline snapshot rejects out-of-range baseline mtimes as validation e
|
|
|
2136
2165
|
assert.equal(response.status, 400);
|
|
2137
2166
|
assert.equal(body.code, "validation_error");
|
|
2138
2167
|
assert.equal(body.details?.[0]?.field, "baseFiles.0.mtimeMs");
|
|
2139
|
-
assert.match(body.details?.[0]?.message ?? "", /
|
|
2168
|
+
assert.match(body.details?.[0]?.message ?? "", /<=8640000000000000/);
|
|
2140
2169
|
assert.equal(calls, 0);
|
|
2141
2170
|
} finally {
|
|
2142
2171
|
await server.stop();
|
package/src/access-http.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { log } from "./logger.js";
|
|
|
10
10
|
import { resolveNamespaceCapabilities } from "./capabilities.js";
|
|
11
11
|
import { WriteRateLimiter, type WriteRateLimitReservation } from "./write-rate-limiter.js";
|
|
12
12
|
import { abortError, isAbortError } from "./abort-error.js";
|
|
13
|
+
import { BriefingTimeoutError } from "./briefing-deadline.js";
|
|
13
14
|
import { EngramAccessForbiddenError } from "./access-errors.js";
|
|
14
15
|
import {
|
|
15
16
|
EngramAccessInputError,
|
|
@@ -500,6 +501,10 @@ export class EngramAccessHttpServer extends ReviewDeckAccessHttpBase {
|
|
|
500
501
|
res.once("close", abortDisconnectedRequest);
|
|
501
502
|
correlationIdStore.run(correlationId, () => {
|
|
502
503
|
void this.handle(req, res, correlationId, abortController.signal).catch((err) => {
|
|
504
|
+
if (err instanceof BriefingTimeoutError) {
|
|
505
|
+
this.respondJson(res, 504, { error: err.message, code: "briefing_timeout" });
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
503
508
|
if (isAbortError(err)) {
|
|
504
509
|
if (!res.destroyed && !res.writableEnded) {
|
|
505
510
|
res.end();
|
|
@@ -1979,6 +1984,7 @@ export class EngramAccessHttpServer extends ReviewDeckAccessHttpBase {
|
|
|
1979
1984
|
service: this.service,
|
|
1980
1985
|
principal: this.resolveRequestPrincipal(req),
|
|
1981
1986
|
respondJson: (status, payload) => this.respondJson(res, status, payload),
|
|
1987
|
+
abortSignal,
|
|
1982
1988
|
});
|
|
1983
1989
|
return;
|
|
1984
1990
|
}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./access-schema.js";
|
|
16
16
|
|
|
17
17
|
export { reapplyCategoryCoercion };
|
|
18
|
-
export {
|
|
18
|
+
export { buildWithBriefingLocation } from "./location/tagging.js";
|
|
19
19
|
|
|
20
20
|
export function splitCanonicalWriteRequest<T extends { rawCategory?: string; category?: string }>(
|
|
21
21
|
request: T,
|
|
@@ -29,8 +29,9 @@ import {
|
|
|
29
29
|
type MemoryScopePlan,
|
|
30
30
|
NamespaceNotWritableError,
|
|
31
31
|
} from "./access-service.js";
|
|
32
|
-
import {
|
|
32
|
+
import { buildWithBriefingLocation, reapplyCategoryCoercion, splitCanonicalWriteRequest } from "./access-observe-write-category.js";
|
|
33
33
|
import { abortError } from "./abort-error.js";
|
|
34
|
+
import { withBriefingDeadline } from "./briefing-deadline.js";
|
|
34
35
|
import { extractionForceFlush } from "./access-extraction-force-flush.js";
|
|
35
36
|
import { ObserveTranscriptPersister, observeTranscriptSessionKey } from "./access-observe-transcript.js";
|
|
36
37
|
import { FileCalendarSource, buildBriefing, parseBriefingFocus, parseBriefingWindow } from "./briefing.js";
|
|
@@ -410,7 +411,6 @@ export class AccessObserveWriteSurface {
|
|
|
410
411
|
}
|
|
411
412
|
|
|
412
413
|
const namespace = this.deps.resolveReadableNamespace(request.namespace, request.principal);
|
|
413
|
-
const storage = await this.deps.orchestrator.getStorage(namespace);
|
|
414
414
|
|
|
415
415
|
const token =
|
|
416
416
|
typeof request.since === "string" && request.since.trim().length > 0
|
|
@@ -457,23 +457,28 @@ export class AccessObserveWriteSurface {
|
|
|
457
457
|
? new FileCalendarSource(config.briefing.calendarSource)
|
|
458
458
|
: undefined;
|
|
459
459
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
namespace
|
|
463
|
-
window,
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
460
|
+
// Storage acquisition and the briefing body share one request budget.
|
|
461
|
+
const result = await withBriefingDeadline(async (signal) => {
|
|
462
|
+
const storage = await this.deps.orchestrator.getStorage(namespace);
|
|
463
|
+
return buildWithBriefingLocation(request.includeLocation, storage.dir, window.from.toISOString(), config.location, () => buildBriefing({
|
|
464
|
+
storage,
|
|
465
|
+
namespace,
|
|
466
|
+
window,
|
|
467
|
+
focus,
|
|
468
|
+
calendarSource,
|
|
469
|
+
maxFollowups,
|
|
470
|
+
allowLlm: config.briefing.llmFollowups,
|
|
471
|
+
openaiApiKey: config.openaiApiKey,
|
|
472
|
+
openaiBaseUrl: config.openaiBaseUrl,
|
|
473
|
+
model: config.model,
|
|
474
|
+
// Without a direct OpenAI key, route follow-ups through the configured
|
|
475
|
+
// LLM chain (gateway model source or local LLM) — same fallback every
|
|
476
|
+
// other LLM feature uses. A configured key keeps its precedence so
|
|
477
|
+
// existing deployments are unchanged.
|
|
478
|
+
followupGenerator: config.openaiApiKey ? undefined : this.deps.orchestrator.briefingChainFollowupGenerator,
|
|
479
|
+
abortSignal: signal,
|
|
480
|
+
}));
|
|
481
|
+
}, request.abortSignal);
|
|
477
482
|
|
|
478
483
|
return {
|
|
479
484
|
format,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
retainedCategoryAlias,
|
|
24
24
|
suggestionSubmitRequestSchema,
|
|
25
25
|
} from "./access-schema.js";
|
|
26
|
-
import { EngramAccessInputError, type EngramAccessService } from "./access-service.js";
|
|
26
|
+
import { EngramAccessInputError, type EngramAccessService, type EngramAccessBriefingRequest } from "./access-service.js";
|
|
27
27
|
import { enforceNamespaceAllowList, tokenCapabilityStore } from "./access-token-capabilities.js";
|
|
28
28
|
import { projectTagProjectId } from "./coding/coding-namespace.js";
|
|
29
29
|
import {
|
|
@@ -381,7 +381,23 @@ defineOperation({ name: "memory_promote", description: "Promote memory.", schema
|
|
|
381
381
|
defineOperation({ name: "memory_outcome", description: "Record outcome.", schema: strictSchema({ memoryId: S.str, outcome: S.str, namespace: S.str, sessionKey: S.str, timestamp: S.str }), handler: async (input, ctx) => { const o = optStr(input.outcome); if (o !== "success" && o !== "failure") throw new EngramAccessInputError("memory_outcome: outcome must be \"success\" or \"failure\"; got " + JSON.stringify(o)); return { result: await ctx.service.memoryOutcome({ memoryId: optStr(input.memoryId) ?? "", outcome: o, namespace: optStr(input.namespace), sessionKey: optStr(input.sessionKey), timestamp: optStr(input.timestamp), principal: ctx.authenticatedPrincipal }) }; } });
|
|
382
382
|
defineOperation({ name: "memory_action_apply", description: "Apply action.", schema: strictSchema({ action: S.str, outcome: S.str, reason: S.str, memoryId: S.str, namespace: S.str, sessionKey: S.str, content: S.str, category: S.str, linkTargetId: S.str, linkType: S.str, linkStrength: S.num, artifactType: S.str, execute: S.bool, sourcePrompt: S.str, dryRun: S.bool }), handler: async (input, ctx) => ({ result: await ctx.service.memoryActionApply({ action: optStr(input.action) ?? "", outcome: optStr(input.outcome), reason: optStr(input.reason), memoryId: optStr(input.memoryId) ?? "", namespace: optStr(input.namespace), sessionKey: optStr(input.sessionKey), content: optStr(input.content), category: optStr(input.category), linkTargetId: optStr(input.linkTargetId), linkType: optStr(input.linkType), linkStrength: optNum(input.linkStrength), artifactType: optStr(input.artifactType), execute: optBool(input.execute), sourcePrompt: optStr(input.sourcePrompt), dryRun: input.dryRun === true, principal: ctx.authenticatedPrincipal }) }) });
|
|
383
383
|
defineOperation({ name: "context_checkpoint", description: "Context checkpoint.", schema: strictSchema({ sessionKey: S.str, context: S.str, namespace: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.contextCheckpoint({ sessionKey: optStr(input.sessionKey) ?? "", context: optStr(input.context) ?? "", namespace: optStr(input.namespace), principal: ctx.authenticatedPrincipal }) }) });
|
|
384
|
-
defineOperation({
|
|
384
|
+
defineOperation({
|
|
385
|
+
name: "briefing", description: "Daily briefing.",
|
|
386
|
+
schema: strictSchema({ since: S.str, focus: S.str, namespace: S.str, includeLocation: S.bool, format: S.str, maxFollowups: S.num }),
|
|
387
|
+
handler: async (input, ctx) => {
|
|
388
|
+
const rf = optStr(input.format);
|
|
389
|
+
const fe = validateBriefingFormat(rf);
|
|
390
|
+
if (fe) throw new EngramAccessInputError(fe);
|
|
391
|
+
// SAFETY: validateBriefingFormat rejects every format except json, markdown, or undefined.
|
|
392
|
+
const request: EngramAccessBriefingRequest = {
|
|
393
|
+
since: optStr(input.since), focus: optStr(input.focus), namespace: optStr(input.namespace),
|
|
394
|
+
includeLocation: optBool(input.includeLocation), format: rf as "json" | "markdown" | undefined,
|
|
395
|
+
maxFollowups: optNum(input.maxFollowups), principal: ctx.authenticatedPrincipal,
|
|
396
|
+
};
|
|
397
|
+
if (ctx.abortSignal) request.abortSignal = ctx.abortSignal;
|
|
398
|
+
return { result: await ctx.service.briefing(request) };
|
|
399
|
+
},
|
|
400
|
+
});
|
|
385
401
|
|
|
386
402
|
// === CONTRADICTION/REVIEW ===
|
|
387
403
|
defineOperation({ name: "review_list", description: "List review pairs.", schema: strictSchema({ filter: S.str, namespace: S.str, limit: S.num }),
|
package/src/access-schema.ts
CHANGED
|
@@ -369,11 +369,7 @@ export function reapplyCategoryCoercion<T extends object>(
|
|
|
369
369
|
const categoryWireSchema = z.enum(
|
|
370
370
|
[...MEMORY_CATEGORY_CANONICAL_INPUT, ...MEMORY_CATEGORY_ALIAS_INPUT],
|
|
371
371
|
{
|
|
372
|
-
|
|
373
|
-
message:
|
|
374
|
-
`category must be one of: ${[...MEMORY_CATEGORY_CANONICAL_INPUT, ...MEMORY_CATEGORY_ALIAS_INPUT].join(", ")}; ` +
|
|
375
|
-
'for project state/facts use "fact"',
|
|
376
|
-
}),
|
|
372
|
+
error: `category must be one of: ${[...MEMORY_CATEGORY_CANONICAL_INPUT, ...MEMORY_CATEGORY_ALIAS_INPUT].join(", ")}; for project state/facts use "fact"`,
|
|
377
373
|
},
|
|
378
374
|
);
|
|
379
375
|
|
|
@@ -454,7 +450,7 @@ export const reviewDispositionRequestSchema = z.object({
|
|
|
454
450
|
export const trustZonePromoteRequestSchema = z.object({
|
|
455
451
|
recordId: z.string().trim().min(1, "recordId is required"),
|
|
456
452
|
targetZone: z.enum(["working", "trusted"], {
|
|
457
|
-
|
|
453
|
+
error: "targetZone must be 'working' or 'trusted'",
|
|
458
454
|
}),
|
|
459
455
|
promotionReason: z.string().trim().min(1, "promotionReason is required"),
|
|
460
456
|
recordedAt: z.string().trim().optional(),
|
|
@@ -662,16 +658,13 @@ export const offlineSyncSnapshotRequestSchema = z.object({
|
|
|
662
658
|
.optional(),
|
|
663
659
|
});
|
|
664
660
|
|
|
665
|
-
export const offlineSyncApplyRequestSchema = z
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
message: "changeset is required",
|
|
673
|
-
path: ["changeset"],
|
|
674
|
-
});
|
|
661
|
+
export const offlineSyncApplyRequestSchema = z.object({
|
|
662
|
+
namespace: namespaceSchema,
|
|
663
|
+
// zod 4: refine messages cannot override its synthesized nonoptional check,
|
|
664
|
+
// so presence is enforced on the field itself.
|
|
665
|
+
changeset: z.custom<unknown>((value) => value !== undefined && value !== null, "changeset is required"),
|
|
666
|
+
returnCurrentFiles: z.boolean().optional(),
|
|
667
|
+
});
|
|
675
668
|
|
|
676
669
|
export const offlineSyncFilesRequestSchema = z.object({
|
|
677
670
|
namespace: namespaceSchema,
|
|
@@ -693,8 +686,11 @@ export const offlineSyncFileContentRequestSchema = z.object({
|
|
|
693
686
|
// Action confidence
|
|
694
687
|
// ---------------------------------------------------------------------------
|
|
695
688
|
|
|
689
|
+
// Outer .optional() keeps the inferred property optional: a transform-typed
|
|
690
|
+
// property becomes required-with-undefined under zod 4 inference, breaking
|
|
691
|
+
// object literals that legitimately omit the key.
|
|
696
692
|
const nullableOptional = <T extends z.ZodTypeAny>(schema: T) =>
|
|
697
|
-
schema.
|
|
693
|
+
schema.nullable().transform((value) => value ?? undefined).optional();
|
|
698
694
|
|
|
699
695
|
const actionConfidenceRuleSchema = z
|
|
700
696
|
.object({
|
package/src/access-service.ts
CHANGED
|
@@ -507,6 +507,11 @@ export interface EngramAccessBriefingRequest extends LocationContextRequestOptio
|
|
|
507
507
|
maxFollowups?: number;
|
|
508
508
|
/** Caller principal for namespace access checks. Transport-bound — never from untrusted payloads. */
|
|
509
509
|
principal?: string;
|
|
510
|
+
/**
|
|
511
|
+
* Transport request lifetime. When it aborts, the briefing stops and
|
|
512
|
+
* rejects with that AbortError instead of running on (issue #3139).
|
|
513
|
+
*/
|
|
514
|
+
abortSignal?: AbortSignal;
|
|
510
515
|
}
|
|
511
516
|
|
|
512
517
|
/** Response for `remnic_briefing`. */
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import test, { type TestContext } from "node:test";
|
|
6
|
+
import { abortError } from "./abort-error.js";
|
|
7
|
+
import fs from "node:fs/promises";
|
|
8
|
+
import { syncBuiltinESMExports } from "node:module";
|
|
9
|
+
import { AccessObserveWriteSurface } from "./access-observe-write-surface.js";
|
|
10
|
+
import { Orchestrator } from "./orchestrator.js";
|
|
11
|
+
import { buildBriefing, type ParsedBriefingWindow } from "./briefing.js";
|
|
12
|
+
import type { CorpusReadOptions } from "./corpus-read-cancellation.js";
|
|
13
|
+
import { StorageManager } from "./storage.js";
|
|
14
|
+
import type { WindowedMemoryReadOptions, WindowedMemoryReadResult } from "./storage/windowed-memory-read.js";
|
|
15
|
+
import type { EntityFile, MemoryFile } from "./types.js";
|
|
16
|
+
|
|
17
|
+
const WINDOW: ParsedBriefingWindow = {
|
|
18
|
+
from: new Date("2026-04-10T00:00:00.000Z"),
|
|
19
|
+
to: new Date("2026-04-11T00:00:00.000Z"),
|
|
20
|
+
label: "test-window",
|
|
21
|
+
};
|
|
22
|
+
const MEMORY: MemoryFile = {
|
|
23
|
+
path: "/synthetic/mem.md",
|
|
24
|
+
frontmatter: {
|
|
25
|
+
id: "synthetic-mem",
|
|
26
|
+
category: "fact",
|
|
27
|
+
created: "2026-04-10T01:00:00.000Z",
|
|
28
|
+
updated: "2026-04-10T02:00:00.000Z",
|
|
29
|
+
source: "test",
|
|
30
|
+
confidence: 0.9,
|
|
31
|
+
confidenceTier: "explicit",
|
|
32
|
+
tags: [],
|
|
33
|
+
},
|
|
34
|
+
content: "synthetic briefing memory",
|
|
35
|
+
};
|
|
36
|
+
const ENTITY: EntityFile = {
|
|
37
|
+
name: "SyntheticEntity",
|
|
38
|
+
type: "project",
|
|
39
|
+
updated: "2026-04-10T03:00:00.000Z",
|
|
40
|
+
facts: ["synthetic fact"],
|
|
41
|
+
timeline: [],
|
|
42
|
+
relationships: [],
|
|
43
|
+
activity: [],
|
|
44
|
+
aliases: [],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
function makeStorage(t: TestContext): StorageManager {
|
|
48
|
+
const dir = mkdtempSync(path.join(os.tmpdir(), "remnic-briefing-abort-"));
|
|
49
|
+
t.after(() => rmSync(dir, { recursive: true, force: true }));
|
|
50
|
+
const storage = new StorageManager(dir);
|
|
51
|
+
t.mock.method(storage, "readMemoriesWindow", async (_options: WindowedMemoryReadOptions) => ({
|
|
52
|
+
memories: [MEMORY],
|
|
53
|
+
filePaths: [MEMORY.path],
|
|
54
|
+
}));
|
|
55
|
+
t.mock.method(storage, "readAllEntityFiles", async (_options?: CorpusReadOptions) => [ENTITY]);
|
|
56
|
+
return storage;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function makeStallingStorage(t: TestContext) {
|
|
60
|
+
const storage = makeStorage(t);
|
|
61
|
+
const fallback = Promise.withResolvers<void>();
|
|
62
|
+
// The fallback releases broken signal plumbing too, so the regression cannot hang.
|
|
63
|
+
t.mock.method(
|
|
64
|
+
storage,
|
|
65
|
+
"readMemoriesWindow",
|
|
66
|
+
(options: WindowedMemoryReadOptions): Promise<WindowedMemoryReadResult> => {
|
|
67
|
+
const signal = options.abortSignal;
|
|
68
|
+
if (!signal) return fallback.promise.then(() => ({ memories: [], filePaths: [] }));
|
|
69
|
+
const read = Promise.withResolvers<WindowedMemoryReadResult>();
|
|
70
|
+
const onAbort = () => read.reject(abortError("corpus read aborted"));
|
|
71
|
+
if (signal.aborted) {
|
|
72
|
+
onAbort();
|
|
73
|
+
return read.promise;
|
|
74
|
+
}
|
|
75
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
76
|
+
void fallback.promise.then(() => {
|
|
77
|
+
signal.removeEventListener("abort", onAbort);
|
|
78
|
+
read.resolve({ memories: [], filePaths: [] });
|
|
79
|
+
});
|
|
80
|
+
return read.promise;
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
return { storage, releaseFallback: fallback.resolve };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
test("buildBriefing rejects with an AbortError when the caller's cancel signal fires mid-read", async (t) => {
|
|
87
|
+
const { storage, releaseFallback } = makeStallingStorage(t);
|
|
88
|
+
const controller = new AbortController();
|
|
89
|
+
const call = buildBriefing({ storage, window: WINDOW, allowLlm: false, abortSignal: controller.signal });
|
|
90
|
+
controller.abort();
|
|
91
|
+
releaseFallback();
|
|
92
|
+
await assert.rejects(call, { name: "AbortError", message: /abort|cancel/i });
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("buildBriefing rejects when the caller's cancel signal is already aborted", async (t) => {
|
|
96
|
+
const { storage, releaseFallback } = makeStallingStorage(t);
|
|
97
|
+
const controller = new AbortController();
|
|
98
|
+
controller.abort();
|
|
99
|
+
const call = buildBriefing({ storage, window: WINDOW, allowLlm: false, abortSignal: controller.signal });
|
|
100
|
+
releaseFallback();
|
|
101
|
+
await assert.rejects(call, { name: "AbortError" });
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("a cancelled briefing does not drain the correction-notification queue", async (t) => {
|
|
105
|
+
const storage = makeStorage(t);
|
|
106
|
+
const queueDir = path.join(storage.dir, "state", "corrections");
|
|
107
|
+
mkdirSync(queueDir, { recursive: true });
|
|
108
|
+
const queueFile = path.join(queueDir, "notifications.jsonl");
|
|
109
|
+
writeFileSync(
|
|
110
|
+
queueFile,
|
|
111
|
+
`${JSON.stringify({ planId: "synthetic-plan", summary: "synthetic correction", undoCommand: "remnic correct plan synthetic-plan", createdAt: "2026-04-10T04:00:00.000Z" })}\n`
|
|
112
|
+
);
|
|
113
|
+
const controller = new AbortController();
|
|
114
|
+
const call = buildBriefing({
|
|
115
|
+
storage,
|
|
116
|
+
window: WINDOW,
|
|
117
|
+
abortSignal: controller.signal,
|
|
118
|
+
// Cancel after reads, just before the queue-draining phase.
|
|
119
|
+
followupGenerator: async () => {
|
|
120
|
+
controller.abort();
|
|
121
|
+
return [];
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
await assert.rejects(call, { name: "AbortError" });
|
|
125
|
+
assert.ok(existsSync(queueFile), "a cancelled briefing must not consume correction notifications");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("buildBriefing returns a non-empty briefing when nothing is cancelled", async (t) => {
|
|
129
|
+
const result = await buildBriefing({ storage: makeStorage(t), window: WINDOW, allowLlm: false });
|
|
130
|
+
assert.equal(result.sections.activeThreads.length, 1);
|
|
131
|
+
assert.equal(result.sections.recentEntities.length, 1);
|
|
132
|
+
assert.ok(result.markdown.length > 0);
|
|
133
|
+
assert.deepEqual(result.window, { from: "2026-04-10T00:00:00.000Z", to: "2026-04-11T00:00:00.000Z" });
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("an HTTP/MCP briefing cancelled during the location read keeps the notification queue", async (t) => {
|
|
137
|
+
const storage = makeStorage(t);
|
|
138
|
+
const queueDir = path.join(storage.dir, "state", "corrections");
|
|
139
|
+
mkdirSync(queueDir, { recursive: true });
|
|
140
|
+
const queueFile = path.join(queueDir, "notifications.jsonl");
|
|
141
|
+
writeFileSync(
|
|
142
|
+
queueFile,
|
|
143
|
+
`${JSON.stringify({ planId: "synthetic-plan", summary: "synthetic correction", undoCommand: "remnic correct plan synthetic-plan", createdAt: "2026-04-10T04:00:00.000Z" })}\n`
|
|
144
|
+
);
|
|
145
|
+
const controller = new AbortController();
|
|
146
|
+
const read: (file: string, encoding: "utf-8") => Promise<string> = fs.readFile;
|
|
147
|
+
t.mock.method(fs, "readFile", async (file: string) => {
|
|
148
|
+
if (file.endsWith(path.join("state", "locations", "sync.json"))) controller.abort(abortError("deadline"));
|
|
149
|
+
return read(file, "utf-8");
|
|
150
|
+
});
|
|
151
|
+
syncBuiltinESMExports();
|
|
152
|
+
t.after(() => {
|
|
153
|
+
t.mock.restoreAll();
|
|
154
|
+
syncBuiltinESMExports();
|
|
155
|
+
});
|
|
156
|
+
// Object.create yields untyped values, so no assertion is needed: briefing() reads only these members.
|
|
157
|
+
const orchestrator: Orchestrator = Object.assign(Object.create(Orchestrator.prototype), {
|
|
158
|
+
config: {
|
|
159
|
+
briefing: { enabled: true, defaultWindow: "24h", defaultFormat: "markdown", maxFollowups: 0, llmFollowups: false },
|
|
160
|
+
location: { enabled: true, tagging: { enabled: true }, timezone: "UTC" },
|
|
161
|
+
},
|
|
162
|
+
getStorage: async () => storage,
|
|
163
|
+
});
|
|
164
|
+
const surface = new AccessObserveWriteSurface(
|
|
165
|
+
Object.assign(Object.create(null), { orchestrator, resolveReadableNamespace: () => "default" }),
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
await assert.rejects(
|
|
169
|
+
surface.briefing({ includeLocation: true, abortSignal: controller.signal }),
|
|
170
|
+
{ name: "AbortError" },
|
|
171
|
+
);
|
|
172
|
+
assert.ok(existsSync(queueFile), "a briefing cancelled during the location read must not consume notifications");
|
|
173
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue #3139 — the briefing's default deadline.
|
|
3
|
+
*
|
|
4
|
+
* The budget is a server-side limit, not a client cancellation: exhausting it
|
|
5
|
+
* must surface as an explicit TimeoutError, never as an empty result.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import assert from "node:assert/strict";
|
|
9
|
+
import test from "node:test";
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
BRIEFING_DEADLINE_MS,
|
|
13
|
+
BriefingTimeoutError,
|
|
14
|
+
withBriefingDeadline,
|
|
15
|
+
} from "./briefing-deadline.js";
|
|
16
|
+
|
|
17
|
+
test("withBriefingDeadline rejects with a TimeoutError when the default budget is exhausted", async (t) => {
|
|
18
|
+
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 0 });
|
|
19
|
+
|
|
20
|
+
const pending = withBriefingDeadline(
|
|
21
|
+
() => Promise.withResolvers<never>().promise,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
t.mock.timers.tick(BRIEFING_DEADLINE_MS);
|
|
25
|
+
|
|
26
|
+
await assert.rejects(pending, (err) => {
|
|
27
|
+
assert.ok(
|
|
28
|
+
err instanceof BriefingTimeoutError,
|
|
29
|
+
"budget exhaustion must surface as a timeout",
|
|
30
|
+
);
|
|
31
|
+
assert.equal(err.name, "TimeoutError");
|
|
32
|
+
assert.equal(err.deadlineMs, BRIEFING_DEADLINE_MS);
|
|
33
|
+
return true;
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("withBriefingDeadline clears its timer once the run settles", async (t) => {
|
|
38
|
+
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 0 });
|
|
39
|
+
let observed: AbortSignal | undefined;
|
|
40
|
+
|
|
41
|
+
const result = await withBriefingDeadline(async (signal) => {
|
|
42
|
+
observed = signal;
|
|
43
|
+
return "briefing";
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
assert.equal(result, "briefing");
|
|
47
|
+
t.mock.timers.tick(BRIEFING_DEADLINE_MS);
|
|
48
|
+
assert.equal(
|
|
49
|
+
observed?.aborted,
|
|
50
|
+
false,
|
|
51
|
+
"the budget timer must be cleared when the run settles, not left to fire afterwards",
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("withBriefingDeadline preserves work failures and clears their timer", async (t) => {
|
|
56
|
+
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 0 });
|
|
57
|
+
const failure = new Error("synthetic work failure");
|
|
58
|
+
const signals: AbortSignal[] = [];
|
|
59
|
+
|
|
60
|
+
const pending = withBriefingDeadline(async (signal) => {
|
|
61
|
+
signals.push(signal);
|
|
62
|
+
throw failure;
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
await assert.rejects(pending, (err) => err === failure);
|
|
66
|
+
assert.equal(signals.length, 1);
|
|
67
|
+
t.mock.timers.tick(BRIEFING_DEADLINE_MS);
|
|
68
|
+
assert.equal(signals[0].aborted, false);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("withBriefingDeadline normalizes arbitrary caller cancellation to AbortError", async () => {
|
|
72
|
+
const controller = new AbortController();
|
|
73
|
+
const pending = withBriefingDeadline(
|
|
74
|
+
() => Promise.withResolvers<never>().promise,
|
|
75
|
+
controller.signal,
|
|
76
|
+
);
|
|
77
|
+
controller.abort(new Error("synthetic caller cancellation"));
|
|
78
|
+
|
|
79
|
+
await assert.rejects(pending, (err) => {
|
|
80
|
+
assert.ok(err instanceof Error);
|
|
81
|
+
assert.equal(err.name, "AbortError");
|
|
82
|
+
return true;
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isAbortError, raceAbort } from "./abort-error.js";
|
|
2
|
+
|
|
3
|
+
export const BRIEFING_DEADLINE_MS = 30_000;
|
|
4
|
+
|
|
5
|
+
export class BriefingTimeoutError extends Error {
|
|
6
|
+
constructor(readonly deadlineMs: number) {
|
|
7
|
+
super(`briefing timed out after ${deadlineMs}ms`);
|
|
8
|
+
this.name = "TimeoutError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function withBriefingDeadline<T>(
|
|
13
|
+
run: (signal: AbortSignal) => Promise<T>,
|
|
14
|
+
abortSignal?: AbortSignal
|
|
15
|
+
): Promise<T> {
|
|
16
|
+
const controller = new AbortController();
|
|
17
|
+
const signal = abortSignal ? AbortSignal.any([abortSignal, controller.signal]) : controller.signal;
|
|
18
|
+
const timer = setTimeout(
|
|
19
|
+
() => controller.abort(new BriefingTimeoutError(BRIEFING_DEADLINE_MS)),
|
|
20
|
+
BRIEFING_DEADLINE_MS
|
|
21
|
+
);
|
|
22
|
+
try {
|
|
23
|
+
signal.throwIfAborted();
|
|
24
|
+
return await raceAbort(run(signal), signal, "briefing aborted");
|
|
25
|
+
} catch (err) {
|
|
26
|
+
// raceAbort normalizes cancellation; retain the distinct deadline reason.
|
|
27
|
+
const reason: unknown = signal.reason;
|
|
28
|
+
if (signal.aborted && (reason instanceof BriefingTimeoutError || isAbortError(reason))) throw reason;
|
|
29
|
+
throw err;
|
|
30
|
+
} finally {
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { safeReadMemories } from "./briefing-window.js";
|
|
4
|
+
import type { CorpusReadOptions } from "./corpus-read-cancellation.js";
|
|
5
|
+
import type { MemoryFile } from "./types.js";
|
|
6
|
+
|
|
7
|
+
test("caller cancellation reaches the signal-aware legacy briefing scan", async () => {
|
|
8
|
+
const controller = new AbortController();
|
|
9
|
+
const started = Promise.withResolvers<AbortSignal>();
|
|
10
|
+
const release = Promise.withResolvers<void>();
|
|
11
|
+
const reader = {
|
|
12
|
+
supportsAbortSignal: true,
|
|
13
|
+
async readAllMemories(options?: CorpusReadOptions): Promise<MemoryFile[]> {
|
|
14
|
+
assert.ok(options?.abortSignal);
|
|
15
|
+
started.resolve(options.abortSignal);
|
|
16
|
+
await release.promise;
|
|
17
|
+
options.abortSignal.throwIfAborted();
|
|
18
|
+
return [];
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
const result = safeReadMemories(
|
|
22
|
+
reader,
|
|
23
|
+
{
|
|
24
|
+
from: new Date("2026-04-10T00:00:00.000Z"),
|
|
25
|
+
to: new Date("2026-04-11T00:00:00.000Z"),
|
|
26
|
+
label: "yesterday",
|
|
27
|
+
},
|
|
28
|
+
{ signal: controller.signal }
|
|
29
|
+
).then(
|
|
30
|
+
() => ({ ok: true as const }),
|
|
31
|
+
(error) => ({ ok: false as const, error })
|
|
32
|
+
);
|
|
33
|
+
try {
|
|
34
|
+
const scanSignal = await started.promise;
|
|
35
|
+
assert.equal(scanSignal.aborted, false);
|
|
36
|
+
controller.abort();
|
|
37
|
+
release.resolve();
|
|
38
|
+
const outcome = await result;
|
|
39
|
+
assert.equal(outcome.ok, false, "a cancelled scan must reject, not return an empty corpus");
|
|
40
|
+
assert.ok(outcome.error instanceof Error);
|
|
41
|
+
assert.equal(outcome.error.name, "AbortError");
|
|
42
|
+
assert.equal(scanSignal.aborted, true, "the underlying scan must stop too");
|
|
43
|
+
} finally {
|
|
44
|
+
release.resolve();
|
|
45
|
+
await result;
|
|
46
|
+
}
|
|
47
|
+
});
|