@remnic/core 10.0.7 → 10.0.8
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 +40 -39
- package/dist/access-authorization-probe.js +41 -40
- package/dist/access-boundary.js +40 -39
- package/dist/access-cli.js +97 -96
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +40 -39
- package/dist/access-http-briefing.js +41 -40
- package/dist/access-http-query.js +42 -41
- package/dist/access-http.js +61 -60
- package/dist/access-identity-continuity-surface.js +40 -39
- package/dist/access-lcm-surface.js +40 -39
- package/dist/access-mcp.js +50 -49
- package/dist/access-namespace-preflight.js +40 -39
- package/dist/access-observe-write-category.js +8 -8
- package/dist/access-observe-write-surface.js +40 -39
- package/dist/access-offline-manifest.js +5 -5
- package/dist/access-operations-batch.js +41 -40
- package/dist/access-operations.js +48 -47
- package/dist/access-recall-concurrency.js +40 -39
- package/dist/access-recall-response.js +40 -39
- package/dist/access-recall-surface.js +40 -39
- package/dist/access-schema.js +7 -7
- package/dist/access-service.js +40 -39
- package/dist/access-surface-catalog.js +42 -41
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +13 -13
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/briefing.js +10 -10
- package/dist/buffer.js +6 -6
- package/dist/causal-consolidation.js +11 -11
- package/dist/{chunk-B2UK6O2O.js → chunk-2K7D6EFT.js} +2 -2
- package/dist/{chunk-Z4CETAL7.js → chunk-3ENX2RB4.js} +2 -2
- package/dist/{chunk-TPNCVFVI.js → chunk-3NFN4Y4P.js} +4 -4
- package/dist/{chunk-HHE57I2Z.js → chunk-3R6SLDTH.js} +2 -2
- package/dist/{chunk-WUUE2I2A.js → chunk-3VTNNO2B.js} +4 -4
- package/dist/{chunk-ODGXQUPR.js → chunk-4OKPH6FG.js} +2 -2
- package/dist/{chunk-M4MAVJJX.js → chunk-55ZVZBX4.js} +2 -2
- package/dist/{chunk-VQBGV44L.js → chunk-5EOV7ANU.js} +2 -2
- package/dist/{chunk-JH4XB3RX.js → chunk-5FNVK7MW.js} +2 -2
- package/dist/{chunk-2SKI5ZSH.js → chunk-5NOPZYNI.js} +7 -7
- package/dist/{chunk-E3OSDZ6M.js → chunk-5Q4NQNW7.js} +2 -2
- package/dist/chunk-5VC7J76U.js +134 -0
- package/dist/chunk-5VC7J76U.js.map +1 -0
- package/dist/{chunk-YMVLPVQP.js → chunk-6PHB45IU.js} +2 -2
- package/dist/{chunk-QHL33ZDS.js → chunk-76KHEHT2.js} +2 -2
- package/dist/{chunk-PBYY4WYM.js → chunk-7O252IE6.js} +2 -2
- package/dist/{chunk-5GN5LRQW.js → chunk-7OAIOE5P.js} +2 -2
- package/dist/{chunk-YV54LYEB.js → chunk-7UX44C4N.js} +2 -2
- package/dist/{chunk-VBNIQ6H2.js → chunk-A6G7K273.js} +3 -3
- package/dist/{chunk-NJTW2MUV.js → chunk-AAM66QCP.js} +5 -5
- package/dist/{chunk-Q67D4JYB.js → chunk-AMFCRZYB.js} +2 -2
- package/dist/{chunk-KMAHEIOH.js → chunk-AV46CT77.js} +2 -2
- package/dist/{chunk-7PZHH4KC.js → chunk-AZEZSQ5R.js} +23 -2
- package/dist/chunk-AZEZSQ5R.js.map +1 -0
- package/dist/{chunk-DSVRW5BD.js → chunk-BPY4RRTF.js} +14 -14
- package/dist/{chunk-BSWHZJSP.js → chunk-C3WJNRGR.js} +2 -2
- package/dist/{chunk-ZBDTSFRA.js → chunk-CBP4HWCL.js} +3 -3
- package/dist/{chunk-D6C4JWSN.js → chunk-CSUAHUOH.js} +2 -2
- package/dist/{chunk-JALYQUYO.js → chunk-DGRMWDQY.js} +12 -12
- package/dist/{chunk-4EHA327M.js → chunk-DXHVD4DS.js} +3 -3
- package/dist/{chunk-CRYAYFUE.js → chunk-E5274WUC.js} +2 -2
- package/dist/{chunk-OCIJYYCA.js → chunk-FBVLTTVV.js} +6 -6
- package/dist/{chunk-CG2E6WT5.js → chunk-GDI64ITR.js} +3 -3
- package/dist/{chunk-Z5IQTRDN.js → chunk-GSAZBZMA.js} +2 -2
- package/dist/{chunk-IE2J3V5N.js → chunk-HZVYDWUP.js} +2 -2
- package/dist/{chunk-MHGHEBTR.js → chunk-IJWEXCWF.js} +2 -2
- package/dist/{chunk-VIPGYPEG.js → chunk-IOM5QSNR.js} +2 -2
- package/dist/{chunk-KQAFEZQX.js → chunk-IPLYGWQF.js} +5 -5
- package/dist/{chunk-XKEDESWC.js → chunk-JK3DYMOC.js} +2 -2
- package/dist/{chunk-ETGXRGSR.js → chunk-JSIQSZXI.js} +3 -3
- package/dist/{chunk-F2QIPGTG.js → chunk-JTUKDLAD.js} +2 -2
- package/dist/{chunk-M6PEFWJ4.js → chunk-K3DZ3G5I.js} +2 -2
- package/dist/{chunk-TVRTJZQ5.js → chunk-KDYQYMJZ.js} +2 -2
- package/dist/{chunk-JFGX2DKT.js → chunk-KRIEQCKE.js} +2 -2
- package/dist/{chunk-FRRR4KOW.js → chunk-L3Z4NXDO.js} +3 -3
- package/dist/{chunk-T5XG6GQI.js → chunk-LOFVW6JA.js} +2 -2
- package/dist/{chunk-GTSQJTNS.js → chunk-MAJ2OKE4.js} +8 -8
- package/dist/{chunk-J5QL66XK.js → chunk-MB5EJ2CT.js} +5 -5
- package/dist/{chunk-RVJPY6E4.js → chunk-MVRIW6MI.js} +2 -2
- package/dist/{chunk-QWDH4QNA.js → chunk-MZBWIJJN.js} +8 -8
- package/dist/{chunk-OH75RBYF.js → chunk-N44GZ73R.js} +7 -7
- package/dist/{chunk-YBSWXKCH.js → chunk-N6UMXWBA.js} +2 -2
- package/dist/{chunk-2PBZBNY7.js → chunk-NAHUBSUF.js} +2 -2
- package/dist/{chunk-Z2ZUV6FE.js → chunk-NXLQQ6WI.js} +2 -2
- package/dist/{chunk-QF7XX74D.js → chunk-NYVKLB2I.js} +28 -28
- package/dist/{chunk-V4ACBX3C.js → chunk-OC6JYPZX.js} +21 -44
- package/dist/chunk-OC6JYPZX.js.map +1 -0
- package/dist/{chunk-645A37SC.js → chunk-P2S6P7X6.js} +2 -2
- package/dist/{chunk-PXTZOU5F.js → chunk-PBVNVKYN.js} +2 -2
- package/dist/{chunk-3DSRYRGR.js → chunk-QFIPSKPC.js} +2 -2
- package/dist/{chunk-GH5R5BIH.js → chunk-QN77HA6P.js} +2 -2
- package/dist/{chunk-IJU2ZWPE.js → chunk-QW7G7PWN.js} +2 -2
- package/dist/{chunk-3GLQUOL2.js → chunk-R2AWYR4Q.js} +2 -2
- package/dist/{chunk-YRULQW5J.js → chunk-RBJQYMMT.js} +4 -4
- package/dist/{chunk-EBQCVOGC.js → chunk-RH6QEGCT.js} +2 -2
- package/dist/{chunk-PO6MNTWH.js → chunk-RNPJ4GQA.js} +2 -2
- package/dist/{chunk-YNSHGVXT.js → chunk-S4GUMZRB.js} +31 -31
- package/dist/{chunk-5O4UJ6PM.js → chunk-SQ2O52SU.js} +2 -2
- package/dist/{chunk-Y6IHIORY.js → chunk-V4WSQYO6.js} +63 -63
- package/dist/{chunk-Y6IHIORY.js.map → chunk-V4WSQYO6.js.map} +1 -1
- package/dist/{chunk-65FYHYBE.js → chunk-VSHRMIJH.js} +2 -2
- package/dist/{chunk-Y7427SL7.js → chunk-WCGJK4NQ.js} +4 -4
- package/dist/{chunk-OX5LMCEQ.js → chunk-WJLGUY27.js} +11 -11
- package/dist/{chunk-UL7WKKGZ.js → chunk-WPFSZZ35.js} +2 -2
- package/dist/{chunk-64S6X4IU.js → chunk-XTN54NML.js} +4 -4
- package/dist/{chunk-UTXWLTX5.js → chunk-YAF3NRNC.js} +2 -2
- package/dist/{chunk-BR75HFPC.js → chunk-ZQYAE2C5.js} +2 -2
- package/dist/cli.js +74 -73
- package/dist/coding/export-okf-codegraph.js +9 -9
- package/dist/compounding/engine.js +10 -10
- package/dist/config.js +13 -13
- package/dist/connectors/codex-materialize-runner.js +10 -10
- package/dist/connectors/index.js +10 -10
- package/dist/convergence-refresh.js +12 -12
- package/dist/corpus-watermark.js +12 -12
- package/dist/deep-recall-http-glue.js +8 -8
- package/dist/deep-recall.js +2 -2
- package/dist/entity-retrieval.js +10 -10
- package/dist/external-wiki-access.js +41 -40
- package/dist/extraction.js +14 -14
- package/dist/harmonic-retrieval.d.ts.map +1 -1
- package/dist/harmonic-retrieval.js +12 -11
- package/dist/harmonic-source-lookup.d.ts +14 -0
- package/dist/harmonic-source-lookup.d.ts.map +1 -0
- package/dist/harmonic-source-lookup.js +22 -0
- package/dist/harmonic-source-lookup.js.map +1 -0
- package/dist/index.js +109 -108
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.js +4 -4
- package/dist/location/index.js +12 -12
- 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-operations.js +41 -40
- package/dist/memory-browse.js +6 -6
- package/dist/memory-projection-batch.d.ts +2 -0
- package/dist/memory-projection-batch.d.ts.map +1 -1
- package/dist/memory-projection-batch.js +4 -1
- package/dist/namespaces/migrate.js +11 -11
- package/dist/namespaces/search.js +6 -6
- package/dist/namespaces/storage.js +10 -10
- package/dist/offline-sync-changeset-generations.js +3 -3
- package/dist/offline-sync-embedding-generation.js +2 -2
- package/dist/offline-sync-snapshot-stream.js +5 -5
- package/dist/offline-sync.js +6 -6
- package/dist/operator-doctor-corpus.js +13 -13
- package/dist/operator-toolkit.js +22 -22
- package/dist/orchestration/maintenance.js +19 -19
- package/dist/orchestrator.js +97 -96
- package/dist/qmd.js +6 -6
- package/dist/recall-navigation-operations.js +41 -40
- package/dist/recall-navigation.js +40 -39
- package/dist/recall-state-view-admission.js +6 -6
- package/dist/recall-why-service.js +6 -6
- package/dist/resume-bundles.js +13 -13
- package/dist/search/factory.js +5 -5
- package/dist/search/index.js +7 -7
- package/dist/semantic-consolidation.js +11 -11
- package/dist/semantic-rule-promotion.js +10 -10
- package/dist/semantic-rule-verifier.js +10 -10
- package/dist/source-agent-qualifier.js +13 -13
- package/dist/standup/build.js +10 -10
- package/dist/storage.js +9 -9
- package/dist/support-passport/index.js +43 -42
- 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.js +10 -10
- package/dist/verified-recall.js +10 -10
- package/dist/who-knows-cli.js +11 -11
- package/dist/who-knows.js +10 -10
- package/package.json +2 -2
- package/src/harmonic-retrieval.ts +12 -64
- package/src/harmonic-source-lookup.test.ts +178 -0
- package/src/harmonic-source-lookup.ts +142 -0
- package/src/memory-projection-batch.ts +20 -0
- package/src/orchestration/recall-internal.ts +12 -12
- package/src/recall-harmonic-qmd-ordering.test.ts +304 -0
- package/dist/chunk-7PZHH4KC.js.map +0 -1
- package/dist/chunk-V4ACBX3C.js.map +0 -1
- /package/dist/{chunk-B2UK6O2O.js.map → chunk-2K7D6EFT.js.map} +0 -0
- /package/dist/{chunk-Z4CETAL7.js.map → chunk-3ENX2RB4.js.map} +0 -0
- /package/dist/{chunk-TPNCVFVI.js.map → chunk-3NFN4Y4P.js.map} +0 -0
- /package/dist/{chunk-HHE57I2Z.js.map → chunk-3R6SLDTH.js.map} +0 -0
- /package/dist/{chunk-WUUE2I2A.js.map → chunk-3VTNNO2B.js.map} +0 -0
- /package/dist/{chunk-ODGXQUPR.js.map → chunk-4OKPH6FG.js.map} +0 -0
- /package/dist/{chunk-M4MAVJJX.js.map → chunk-55ZVZBX4.js.map} +0 -0
- /package/dist/{chunk-VQBGV44L.js.map → chunk-5EOV7ANU.js.map} +0 -0
- /package/dist/{chunk-JH4XB3RX.js.map → chunk-5FNVK7MW.js.map} +0 -0
- /package/dist/{chunk-2SKI5ZSH.js.map → chunk-5NOPZYNI.js.map} +0 -0
- /package/dist/{chunk-E3OSDZ6M.js.map → chunk-5Q4NQNW7.js.map} +0 -0
- /package/dist/{chunk-YMVLPVQP.js.map → chunk-6PHB45IU.js.map} +0 -0
- /package/dist/{chunk-QHL33ZDS.js.map → chunk-76KHEHT2.js.map} +0 -0
- /package/dist/{chunk-PBYY4WYM.js.map → chunk-7O252IE6.js.map} +0 -0
- /package/dist/{chunk-5GN5LRQW.js.map → chunk-7OAIOE5P.js.map} +0 -0
- /package/dist/{chunk-YV54LYEB.js.map → chunk-7UX44C4N.js.map} +0 -0
- /package/dist/{chunk-VBNIQ6H2.js.map → chunk-A6G7K273.js.map} +0 -0
- /package/dist/{chunk-NJTW2MUV.js.map → chunk-AAM66QCP.js.map} +0 -0
- /package/dist/{chunk-Q67D4JYB.js.map → chunk-AMFCRZYB.js.map} +0 -0
- /package/dist/{chunk-KMAHEIOH.js.map → chunk-AV46CT77.js.map} +0 -0
- /package/dist/{chunk-DSVRW5BD.js.map → chunk-BPY4RRTF.js.map} +0 -0
- /package/dist/{chunk-BSWHZJSP.js.map → chunk-C3WJNRGR.js.map} +0 -0
- /package/dist/{chunk-ZBDTSFRA.js.map → chunk-CBP4HWCL.js.map} +0 -0
- /package/dist/{chunk-D6C4JWSN.js.map → chunk-CSUAHUOH.js.map} +0 -0
- /package/dist/{chunk-JALYQUYO.js.map → chunk-DGRMWDQY.js.map} +0 -0
- /package/dist/{chunk-4EHA327M.js.map → chunk-DXHVD4DS.js.map} +0 -0
- /package/dist/{chunk-CRYAYFUE.js.map → chunk-E5274WUC.js.map} +0 -0
- /package/dist/{chunk-OCIJYYCA.js.map → chunk-FBVLTTVV.js.map} +0 -0
- /package/dist/{chunk-CG2E6WT5.js.map → chunk-GDI64ITR.js.map} +0 -0
- /package/dist/{chunk-Z5IQTRDN.js.map → chunk-GSAZBZMA.js.map} +0 -0
- /package/dist/{chunk-IE2J3V5N.js.map → chunk-HZVYDWUP.js.map} +0 -0
- /package/dist/{chunk-MHGHEBTR.js.map → chunk-IJWEXCWF.js.map} +0 -0
- /package/dist/{chunk-VIPGYPEG.js.map → chunk-IOM5QSNR.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-IPLYGWQF.js.map} +0 -0
- /package/dist/{chunk-XKEDESWC.js.map → chunk-JK3DYMOC.js.map} +0 -0
- /package/dist/{chunk-ETGXRGSR.js.map → chunk-JSIQSZXI.js.map} +0 -0
- /package/dist/{chunk-F2QIPGTG.js.map → chunk-JTUKDLAD.js.map} +0 -0
- /package/dist/{chunk-M6PEFWJ4.js.map → chunk-K3DZ3G5I.js.map} +0 -0
- /package/dist/{chunk-TVRTJZQ5.js.map → chunk-KDYQYMJZ.js.map} +0 -0
- /package/dist/{chunk-JFGX2DKT.js.map → chunk-KRIEQCKE.js.map} +0 -0
- /package/dist/{chunk-FRRR4KOW.js.map → chunk-L3Z4NXDO.js.map} +0 -0
- /package/dist/{chunk-T5XG6GQI.js.map → chunk-LOFVW6JA.js.map} +0 -0
- /package/dist/{chunk-GTSQJTNS.js.map → chunk-MAJ2OKE4.js.map} +0 -0
- /package/dist/{chunk-J5QL66XK.js.map → chunk-MB5EJ2CT.js.map} +0 -0
- /package/dist/{chunk-RVJPY6E4.js.map → chunk-MVRIW6MI.js.map} +0 -0
- /package/dist/{chunk-QWDH4QNA.js.map → chunk-MZBWIJJN.js.map} +0 -0
- /package/dist/{chunk-OH75RBYF.js.map → chunk-N44GZ73R.js.map} +0 -0
- /package/dist/{chunk-YBSWXKCH.js.map → chunk-N6UMXWBA.js.map} +0 -0
- /package/dist/{chunk-2PBZBNY7.js.map → chunk-NAHUBSUF.js.map} +0 -0
- /package/dist/{chunk-Z2ZUV6FE.js.map → chunk-NXLQQ6WI.js.map} +0 -0
- /package/dist/{chunk-QF7XX74D.js.map → chunk-NYVKLB2I.js.map} +0 -0
- /package/dist/{chunk-645A37SC.js.map → chunk-P2S6P7X6.js.map} +0 -0
- /package/dist/{chunk-PXTZOU5F.js.map → chunk-PBVNVKYN.js.map} +0 -0
- /package/dist/{chunk-3DSRYRGR.js.map → chunk-QFIPSKPC.js.map} +0 -0
- /package/dist/{chunk-GH5R5BIH.js.map → chunk-QN77HA6P.js.map} +0 -0
- /package/dist/{chunk-IJU2ZWPE.js.map → chunk-QW7G7PWN.js.map} +0 -0
- /package/dist/{chunk-3GLQUOL2.js.map → chunk-R2AWYR4Q.js.map} +0 -0
- /package/dist/{chunk-YRULQW5J.js.map → chunk-RBJQYMMT.js.map} +0 -0
- /package/dist/{chunk-EBQCVOGC.js.map → chunk-RH6QEGCT.js.map} +0 -0
- /package/dist/{chunk-PO6MNTWH.js.map → chunk-RNPJ4GQA.js.map} +0 -0
- /package/dist/{chunk-YNSHGVXT.js.map → chunk-S4GUMZRB.js.map} +0 -0
- /package/dist/{chunk-5O4UJ6PM.js.map → chunk-SQ2O52SU.js.map} +0 -0
- /package/dist/{chunk-65FYHYBE.js.map → chunk-VSHRMIJH.js.map} +0 -0
- /package/dist/{chunk-Y7427SL7.js.map → chunk-WCGJK4NQ.js.map} +0 -0
- /package/dist/{chunk-OX5LMCEQ.js.map → chunk-WJLGUY27.js.map} +0 -0
- /package/dist/{chunk-UL7WKKGZ.js.map → chunk-WPFSZZ35.js.map} +0 -0
- /package/dist/{chunk-64S6X4IU.js.map → chunk-XTN54NML.js.map} +0 -0
- /package/dist/{chunk-UTXWLTX5.js.map → chunk-YAF3NRNC.js.map} +0 -0
- /package/dist/{chunk-BR75HFPC.js.map → chunk-ZQYAE2C5.js.map} +0 -0
package/dist/who-knows-cli.js
CHANGED
|
@@ -4,14 +4,15 @@ import {
|
|
|
4
4
|
renderWhoKnows,
|
|
5
5
|
renderWhoKnowsJson,
|
|
6
6
|
renderWhoKnowsText
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-LZKOVXMX.js";
|
|
7
|
+
} from "./chunk-KRIEQCKE.js";
|
|
8
|
+
import "./chunk-3ENX2RB4.js";
|
|
9
|
+
import "./chunk-WJLGUY27.js";
|
|
11
10
|
import "./chunk-UHVXE24Y.js";
|
|
11
|
+
import "./chunk-LZKOVXMX.js";
|
|
12
12
|
import "./chunk-V4JZCTMK.js";
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-7UX44C4N.js";
|
|
14
|
+
import "./chunk-MB5EJ2CT.js";
|
|
15
|
+
import "./chunk-CYEPCZN5.js";
|
|
15
16
|
import "./chunk-T3FMRLWQ.js";
|
|
16
17
|
import "./chunk-7VO6E5UD.js";
|
|
17
18
|
import "./chunk-5BUCKFRE.js";
|
|
@@ -19,7 +20,6 @@ import "./chunk-S7LWX2PQ.js";
|
|
|
19
20
|
import "./chunk-T2YX56QI.js";
|
|
20
21
|
import "./chunk-4O6WRBGE.js";
|
|
21
22
|
import "./chunk-GUMZC2BO.js";
|
|
22
|
-
import "./chunk-CYEPCZN5.js";
|
|
23
23
|
import "./chunk-TFA6HPOA.js";
|
|
24
24
|
import "./chunk-F4TWWUMP.js";
|
|
25
25
|
import "./chunk-72A4L5JJ.js";
|
|
@@ -28,8 +28,8 @@ import "./chunk-S2V7RUCL.js";
|
|
|
28
28
|
import "./chunk-X3724WL4.js";
|
|
29
29
|
import "./chunk-MRPOZBJC.js";
|
|
30
30
|
import "./chunk-S2HLHAZ4.js";
|
|
31
|
-
import "./chunk-DM2T26WE.js";
|
|
32
31
|
import "./chunk-LDXUBPMO.js";
|
|
32
|
+
import "./chunk-DM2T26WE.js";
|
|
33
33
|
import "./chunk-FF6N7BXC.js";
|
|
34
34
|
import "./chunk-2DT7PIDZ.js";
|
|
35
35
|
import "./chunk-AAD2ZS6P.js";
|
|
@@ -49,12 +49,12 @@ import "./chunk-5WITETWU.js";
|
|
|
49
49
|
import "./chunk-6CIAGZ6X.js";
|
|
50
50
|
import "./chunk-7CT3AI52.js";
|
|
51
51
|
import "./chunk-G7D6GZ5J.js";
|
|
52
|
-
import "./chunk-
|
|
53
|
-
import "./chunk-IUM3VSHI.js";
|
|
52
|
+
import "./chunk-DGRMWDQY.js";
|
|
54
53
|
import "./chunk-G26YNEOC.js";
|
|
54
|
+
import "./chunk-SIGAGKNE.js";
|
|
55
|
+
import "./chunk-IUM3VSHI.js";
|
|
55
56
|
import "./chunk-WVHRNAXL.js";
|
|
56
57
|
import "./chunk-TPSLVZHS.js";
|
|
57
|
-
import "./chunk-SIGAGKNE.js";
|
|
58
58
|
import "./chunk-23G5P7TA.js";
|
|
59
59
|
import "./chunk-C64XATK7.js";
|
|
60
60
|
import "./chunk-42JKGUFJ.js";
|
package/dist/who-knows.js
CHANGED
|
@@ -9,13 +9,14 @@ import {
|
|
|
9
9
|
loadWhoKnowsEntities,
|
|
10
10
|
tokenizeTopic,
|
|
11
11
|
validateWhoKnowsInput
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-LZKOVXMX.js";
|
|
12
|
+
} from "./chunk-3ENX2RB4.js";
|
|
13
|
+
import "./chunk-WJLGUY27.js";
|
|
15
14
|
import "./chunk-UHVXE24Y.js";
|
|
15
|
+
import "./chunk-LZKOVXMX.js";
|
|
16
16
|
import "./chunk-V4JZCTMK.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-7UX44C4N.js";
|
|
18
|
+
import "./chunk-MB5EJ2CT.js";
|
|
19
|
+
import "./chunk-CYEPCZN5.js";
|
|
19
20
|
import "./chunk-T3FMRLWQ.js";
|
|
20
21
|
import "./chunk-7VO6E5UD.js";
|
|
21
22
|
import "./chunk-5BUCKFRE.js";
|
|
@@ -23,7 +24,6 @@ import "./chunk-S7LWX2PQ.js";
|
|
|
23
24
|
import "./chunk-T2YX56QI.js";
|
|
24
25
|
import "./chunk-4O6WRBGE.js";
|
|
25
26
|
import "./chunk-GUMZC2BO.js";
|
|
26
|
-
import "./chunk-CYEPCZN5.js";
|
|
27
27
|
import "./chunk-TFA6HPOA.js";
|
|
28
28
|
import "./chunk-F4TWWUMP.js";
|
|
29
29
|
import "./chunk-72A4L5JJ.js";
|
|
@@ -32,8 +32,8 @@ import "./chunk-S2V7RUCL.js";
|
|
|
32
32
|
import "./chunk-X3724WL4.js";
|
|
33
33
|
import "./chunk-MRPOZBJC.js";
|
|
34
34
|
import "./chunk-S2HLHAZ4.js";
|
|
35
|
-
import "./chunk-DM2T26WE.js";
|
|
36
35
|
import "./chunk-LDXUBPMO.js";
|
|
36
|
+
import "./chunk-DM2T26WE.js";
|
|
37
37
|
import "./chunk-FF6N7BXC.js";
|
|
38
38
|
import "./chunk-2DT7PIDZ.js";
|
|
39
39
|
import "./chunk-AAD2ZS6P.js";
|
|
@@ -53,12 +53,12 @@ import "./chunk-5WITETWU.js";
|
|
|
53
53
|
import "./chunk-6CIAGZ6X.js";
|
|
54
54
|
import "./chunk-7CT3AI52.js";
|
|
55
55
|
import "./chunk-G7D6GZ5J.js";
|
|
56
|
-
import "./chunk-
|
|
57
|
-
import "./chunk-IUM3VSHI.js";
|
|
56
|
+
import "./chunk-DGRMWDQY.js";
|
|
58
57
|
import "./chunk-G26YNEOC.js";
|
|
58
|
+
import "./chunk-SIGAGKNE.js";
|
|
59
|
+
import "./chunk-IUM3VSHI.js";
|
|
59
60
|
import "./chunk-WVHRNAXL.js";
|
|
60
61
|
import "./chunk-TPSLVZHS.js";
|
|
61
|
-
import "./chunk-SIGAGKNE.js";
|
|
62
62
|
import "./chunk-23G5P7TA.js";
|
|
63
63
|
import "./chunk-C64XATK7.js";
|
|
64
64
|
import "./chunk-42JKGUFJ.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/core",
|
|
3
|
-
"version": "10.0.
|
|
3
|
+
"version": "10.0.8",
|
|
4
4
|
"description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -3327,7 +3327,7 @@
|
|
|
3327
3327
|
"core"
|
|
3328
3328
|
],
|
|
3329
3329
|
"peerDependencies": {
|
|
3330
|
-
"@remnic/coding-graph": "^10.0.
|
|
3330
|
+
"@remnic/coding-graph": "^10.0.8"
|
|
3331
3331
|
},
|
|
3332
3332
|
"peerDependenciesMeta": {
|
|
3333
3333
|
"@remnic/coding-graph": {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
2
|
import { realpath } from "node:fs/promises";
|
|
4
3
|
import { listJsonFilesStrict, readJsonFile } from "./json-store.js";
|
|
5
4
|
import { throwIfAborted } from "./abort-error.js";
|
|
@@ -22,31 +21,11 @@ import { readProjectedMemoryStates } from "./memory-projection-batch.js";
|
|
|
22
21
|
import { SecureStoreLockedError } from "./secure-store/secure-fs.js";
|
|
23
22
|
import { StorageManager } from "./storage.js";
|
|
24
23
|
import { RECALL_FALLBACK_DIRS } from "./utils/category-dir.js";
|
|
25
|
-
import {
|
|
24
|
+
import { readHarmonicSourceMemory, readUnresolvedHarmonicSources } from "./harmonic-source-lookup.js";
|
|
26
25
|
|
|
27
26
|
|
|
28
27
|
type SourceMemoryMap = Map<string, MemoryFile>;
|
|
29
28
|
|
|
30
|
-
// `rootReal` set: a direct probe, which skips the corpus walk's symlink
|
|
31
|
-
// hardening, so the resolved file must stay inside the memory root. Null: the
|
|
32
|
-
// path came from the contained corpus walk and is already trusted.
|
|
33
|
-
async function readMemoryFile(
|
|
34
|
-
storage: StorageManager,
|
|
35
|
-
rootReal: string | null,
|
|
36
|
-
filePath: string,
|
|
37
|
-
abortSignal?: AbortSignal,
|
|
38
|
-
): Promise<MemoryFile | null> {
|
|
39
|
-
throwIfAborted(abortSignal, "harmonic retrieval aborted");
|
|
40
|
-
if (!existsSync(filePath)) return null;
|
|
41
|
-
try {
|
|
42
|
-
if (rootReal !== null && !isPathInsideStorageRoot(rootReal, await realpath(filePath))) return null;
|
|
43
|
-
return await storage.readMemoryByPath(filePath);
|
|
44
|
-
} catch (err) {
|
|
45
|
-
throwIfAborted(abortSignal, "harmonic retrieval aborted");
|
|
46
|
-
if (err instanceof SecureStoreLockedError) throw err;
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
29
|
|
|
51
30
|
// An index older than this is treated as unusable: the date window needed to
|
|
52
31
|
// cover "created since the last rebuild" would stop being cheap.
|
|
@@ -61,13 +40,6 @@ function utcDaysSince(rebuiltMs: number, nowMs: number): string[] {
|
|
|
61
40
|
return days;
|
|
62
41
|
}
|
|
63
42
|
|
|
64
|
-
// Source ids confirmed absent by a corpus path walk. A node only references a
|
|
65
|
-
// source after the source file exists, so a confirmed absence stays true unless
|
|
66
|
-
// the file is restored later; the short TTL bounds that. Without this, one
|
|
67
|
-
// dangling id (a hard-deleted fact) would force a walk on every recall.
|
|
68
|
-
const ABSENT_SOURCE_TTL_MS = 10 * 60_000;
|
|
69
|
-
const ABSENT_SOURCE_MAX_ENTRIES = 4096;
|
|
70
|
-
const absentSourceIds = new Map<string, number>(); // `${memoryDir}\0${id}` -> expiry ms
|
|
71
43
|
|
|
72
44
|
// Memories the projection has no row for were written after its last rebuild, so
|
|
73
45
|
// their dated directory is normally one of `days`. Hot and cold tiers are probed
|
|
@@ -84,16 +56,7 @@ function unprojectedCandidatePaths(memoryDir: string, id: string, days: string[]
|
|
|
84
56
|
return paths;
|
|
85
57
|
}
|
|
86
58
|
|
|
87
|
-
/**
|
|
88
|
-
* Resolve only the source ids the abstraction nodes reference. Returns null when
|
|
89
|
-
* the projection is absent, unreadable, too old, or not known to cover every
|
|
90
|
-
* active memory (a scoped or pre-`complete` rebuild), so the caller keeps the
|
|
91
|
-
* full-corpus scan. Every file is read from disk, so status, tags and validity
|
|
92
|
-
* are current; the index only says where to look. An id the cheap probes cannot
|
|
93
|
-
* place (an import filed under an old date, a tier root outside the memory dir)
|
|
94
|
-
* is looked up by one contained path-only walk, never a frontmatter parse of the
|
|
95
|
-
* corpus.
|
|
96
|
-
*/
|
|
59
|
+
/** Resolve indexed sources first, then use the durable unresolved-id path cache. */
|
|
97
60
|
async function readIndexedSourceMemories(options: {
|
|
98
61
|
memoryDir: string;
|
|
99
62
|
abortSignal?: AbortSignal;
|
|
@@ -103,7 +66,7 @@ async function readIndexedSourceMemories(options: {
|
|
|
103
66
|
// The ids go to SQL as bound parameters, so any id the projection holds is safe to look up.
|
|
104
67
|
const batch = readProjectedMemoryStates(options.memoryDir, options.sourceMemoryIds);
|
|
105
68
|
const rebuiltMs = Date.parse(batch?.rebuiltAt ?? "");
|
|
106
|
-
if (!batch?.complete || !Number.isFinite(rebuiltMs) || options.nowMs - rebuiltMs > INDEX_MAX_AGE_MS) return null;
|
|
69
|
+
if (!batch?.complete || !batch.rebuiltAt || !Number.isFinite(rebuiltMs) || options.nowMs - rebuiltMs > INDEX_MAX_AGE_MS) return null;
|
|
107
70
|
const rootReal = await realpath(options.memoryDir).catch(() => null);
|
|
108
71
|
if (rootReal === null) return null;
|
|
109
72
|
|
|
@@ -120,42 +83,27 @@ async function readIndexedSourceMemories(options: {
|
|
|
120
83
|
} catch {
|
|
121
84
|
safeId = false;
|
|
122
85
|
}
|
|
123
|
-
// An unprojected id that is not a single path segment cannot be probed or
|
|
124
|
-
// matched by filename, and the scan keys sources by frontmatter id, so only
|
|
125
|
-
// the scan can place it. Rare (legacy/imported ids); worst case is the old cost.
|
|
126
|
-
if (!state && !safeId) return null;
|
|
127
86
|
// state.path was containment-checked by the projection reader.
|
|
128
87
|
const candidates = state
|
|
129
88
|
? [state.path, path.join(options.memoryDir, "cold", state.pathRel)]
|
|
130
|
-
: unprojectedCandidatePaths(options.memoryDir, id, days);
|
|
89
|
+
: safeId ? unprojectedCandidatePaths(options.memoryDir, id, days) : [];
|
|
131
90
|
let found = false;
|
|
132
91
|
for (const candidate of candidates) {
|
|
133
|
-
const memory = await
|
|
92
|
+
const memory = await readHarmonicSourceMemory(storage, rootReal, candidate, options.abortSignal);
|
|
134
93
|
if (memory?.frontmatter.id !== id) continue;
|
|
135
94
|
sourceMemories.set(id, memory);
|
|
136
95
|
found = true;
|
|
137
96
|
break;
|
|
138
97
|
}
|
|
139
|
-
|
|
140
|
-
if (!found && safeId && (absentSourceIds.get(absentKey) ?? 0) <= options.nowMs) pending.push(id);
|
|
98
|
+
if (!found) pending.push(id);
|
|
141
99
|
}
|
|
142
100
|
if (pending.length === 0) return sourceMemories;
|
|
143
101
|
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
];
|
|
149
|
-
for (const filePath of walked) {
|
|
150
|
-
throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
|
|
151
|
-
if (!wanted.has(path.basename(filePath, ".md"))) continue;
|
|
152
|
-
const memory = await readMemoryFile(storage, null, filePath, options.abortSignal);
|
|
153
|
-
if (memory && wanted.has(memory.frontmatter.id)) sourceMemories.set(memory.frontmatter.id, memory);
|
|
154
|
-
}
|
|
155
|
-
if (absentSourceIds.size > ABSENT_SOURCE_MAX_ENTRIES) absentSourceIds.clear();
|
|
156
|
-
for (const id of pending) {
|
|
157
|
-
if (!sourceMemories.has(id)) absentSourceIds.set(`${options.memoryDir}\0${id}`, options.nowMs + ABSENT_SOURCE_TTL_MS);
|
|
158
|
-
}
|
|
102
|
+
const unresolved = await readUnresolvedHarmonicSources({
|
|
103
|
+
storage, rootReal, rebuiltAt: batch.rebuiltAt, sourceMemoryIds: pending,
|
|
104
|
+
nowMs: options.nowMs, abortSignal: options.abortSignal,
|
|
105
|
+
});
|
|
106
|
+
for (const [id, memory] of unresolved) sourceMemories.set(id, memory);
|
|
159
107
|
return sourceMemories;
|
|
160
108
|
}
|
|
161
109
|
|
|
@@ -168,7 +116,7 @@ async function readCorpusSourceMemories(options: {
|
|
|
168
116
|
const storage = new StorageManager(options.memoryDir);
|
|
169
117
|
const [hotMemories, coldMemories] = await Promise.all([
|
|
170
118
|
storage.readAllMemories({ abortSignal: options.abortSignal }),
|
|
171
|
-
storage.readAllColdMemories(),
|
|
119
|
+
storage.readAllColdMemories({ abortSignal: options.abortSignal }),
|
|
172
120
|
]);
|
|
173
121
|
for (const memory of [...hotMemories, ...coldMemories]) {
|
|
174
122
|
throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { mkdir, mkdtemp, readFile, realpath, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
import test from "node:test";
|
|
8
|
+
import { recordAbstractionNode } from "./abstraction-nodes.js";
|
|
9
|
+
import { readProjectedHarmonicGraph } from "./harmonic-retrieval.js";
|
|
10
|
+
import { rebuildMemoryProjection } from "./maintenance/rebuild-memory-projection.js";
|
|
11
|
+
import { StorageManager } from "./storage.js";
|
|
12
|
+
import { readUnresolvedHarmonicSources } from "./harmonic-source-lookup.js";
|
|
13
|
+
import { bumpMemoryCorpusVersionForDir } from "./memory-corpus-version.js";
|
|
14
|
+
|
|
15
|
+
async function seed(memoryDir: string) {
|
|
16
|
+
const storage = new StorageManager(memoryDir);
|
|
17
|
+
await storage.ensureDirectories();
|
|
18
|
+
const real = await storage.writeMemory("fact", "real harmonic source", { source: "test" });
|
|
19
|
+
await recordAbstractionNode({ memoryDir, node: {
|
|
20
|
+
schemaVersion: 1, nodeId: "source-lookup", recordedAt: new Date().toISOString(),
|
|
21
|
+
sessionKey: "agent:test", kind: "topic", abstractionLevel: "meso",
|
|
22
|
+
title: "source lookup", summary: "source lookup",
|
|
23
|
+
sourceMemoryIds: [real.id, "missing-source", "hot-import", "cold/import"],
|
|
24
|
+
} });
|
|
25
|
+
await rebuildMemoryProjection({ memoryDir, storage, dryRun: false });
|
|
26
|
+
return { storage, real };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function importFile(memoryDir: string, tier: string, name: string, id: string) {
|
|
30
|
+
const dir = path.join(memoryDir, tier, "facts", "2000-01-01");
|
|
31
|
+
await mkdir(dir, { recursive: true });
|
|
32
|
+
await writeFile(path.join(dir, name),
|
|
33
|
+
`---\nid: ${id}\ncategory: fact\ncreated: 2000-01-01T00:00:00.000Z\nupdated: 2000-01-01T00:00:00.000Z\nsource: test\nconfidence: 0.8\nconfidenceTier: implied\ntags: []\n---\n\nImported ${id} body.\n`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
test("old-dated imports with non-id filenames resolve in both tiers without a corpus parse (#3188)", async (t) => {
|
|
37
|
+
const memoryDir = await mkdtemp(path.join(tmpdir(), "remnic-harmonic-lookup-"));
|
|
38
|
+
try {
|
|
39
|
+
const { real } = await seed(memoryDir);
|
|
40
|
+
await importFile(memoryDir, "", "unrelated-hot-name.md", "hot-import");
|
|
41
|
+
await importFile(memoryDir, "cold", "unrelated-cold-name.md", "cold/import");
|
|
42
|
+
let scans = 0;
|
|
43
|
+
t.mock.method(StorageManager.prototype, "readAllMemories", async () => { scans += 1; return []; });
|
|
44
|
+
const graph = await readProjectedHarmonicGraph({ memoryDir, anchorsEnabled: false });
|
|
45
|
+
assert.deepEqual(graph.nodes[0]?.sourceMemoryIds?.slice().sort(), [real.id, "hot-import", "cold/import"].sort());
|
|
46
|
+
assert.equal(scans, 0, "unprojected legacy ids must not force the full frontmatter corpus scan");
|
|
47
|
+
} finally {
|
|
48
|
+
t.mock.restoreAll();
|
|
49
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("confirmed missing sources survive a fresh process without another path walk (#3188)", async () => {
|
|
54
|
+
const memoryDir = await mkdtemp(path.join(tmpdir(), "remnic-harmonic-durable-"));
|
|
55
|
+
try {
|
|
56
|
+
const { real } = await seed(memoryDir);
|
|
57
|
+
const graph = await readProjectedHarmonicGraph({ memoryDir, anchorsEnabled: false });
|
|
58
|
+
assert.deepEqual(graph.nodes[0]?.sourceMemoryIds, [real.id]);
|
|
59
|
+
const script = `
|
|
60
|
+
import { StorageManager } from ${JSON.stringify(new URL("./storage.ts", import.meta.url).href)};
|
|
61
|
+
import { readProjectedHarmonicGraph } from ${JSON.stringify(new URL("./harmonic-retrieval.ts", import.meta.url).href)};
|
|
62
|
+
StorageManager.prototype.collectActiveMemoryPaths = async () => { throw new Error("unexpected hot walk after restart"); };
|
|
63
|
+
StorageManager.prototype.collectColdMemoryPaths = async () => { throw new Error("unexpected cold walk after restart"); };
|
|
64
|
+
StorageManager.prototype.readAllMemories = async () => { throw new Error("unexpected corpus scan after restart"); };
|
|
65
|
+
const graph = await readProjectedHarmonicGraph({ memoryDir: ${JSON.stringify(memoryDir)}, anchorsEnabled: false });
|
|
66
|
+
if (graph.nodes[0]?.sourceMemoryIds?.join() !== ${JSON.stringify(real.id)}) throw new Error("source lost after restart");
|
|
67
|
+
`;
|
|
68
|
+
await promisify(execFile)(process.execPath, ["--import", "tsx", "--input-type=module", "-e", script]);
|
|
69
|
+
} finally {
|
|
70
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
for (const invalidation of ["ttl", "rebuiltAt", "corpusVersion"]) {
|
|
75
|
+
test(`durable misses invalidate on ${invalidation} without losing an imported source (#3188)`, async () => {
|
|
76
|
+
const memoryDir = await mkdtemp(path.join(tmpdir(), "remnic-harmonic-epoch-"));
|
|
77
|
+
try {
|
|
78
|
+
const { storage } = await seed(memoryDir);
|
|
79
|
+
const nowMs = Date.now();
|
|
80
|
+
const options = {
|
|
81
|
+
storage, rootReal: await realpath(memoryDir), rebuiltAt: new Date(nowMs).toISOString(),
|
|
82
|
+
nowMs, sourceMemoryIds: ["restored-id"],
|
|
83
|
+
};
|
|
84
|
+
assert.equal((await readUnresolvedHarmonicSources(options)).size, 0);
|
|
85
|
+
await importFile(memoryDir, "", "not-the-source-id.md", "restored-id");
|
|
86
|
+
assert.equal((await readUnresolvedHarmonicSources(options)).size, 0, "the existing ten-minute miss window is preserved");
|
|
87
|
+
if (invalidation === "ttl") options.nowMs += 10 * 60_000;
|
|
88
|
+
if (invalidation === "rebuiltAt") options.rebuiltAt = new Date(nowMs + 1).toISOString();
|
|
89
|
+
if (invalidation === "corpusVersion") bumpMemoryCorpusVersionForDir(memoryDir);
|
|
90
|
+
const restored = await readUnresolvedHarmonicSources(options);
|
|
91
|
+
assert.equal(restored.get("restored-id")?.content.trim(), "Imported restored-id body.");
|
|
92
|
+
} finally {
|
|
93
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
test("harmonic cold walk receives cancellation and cannot publish a partial absence cache (#3188)", async (t) => {
|
|
99
|
+
const memoryDir = await mkdtemp(path.join(tmpdir(), "remnic-harmonic-cancel-"));
|
|
100
|
+
try {
|
|
101
|
+
await seed(memoryDir);
|
|
102
|
+
await importFile(memoryDir, "cold", "cold-import.md", "cold/import");
|
|
103
|
+
const controller = new AbortController();
|
|
104
|
+
const original = StorageManager.prototype.collectColdMemoryPaths;
|
|
105
|
+
t.mock.method(StorageManager.prototype, "collectColdMemoryPaths", function (
|
|
106
|
+
this: StorageManager, options?: Parameters<StorageManager["collectColdMemoryPaths"]>[0],
|
|
107
|
+
) {
|
|
108
|
+
assert.equal(options?.abortSignal, controller.signal);
|
|
109
|
+
controller.abort();
|
|
110
|
+
return original.call(this, options);
|
|
111
|
+
});
|
|
112
|
+
await assert.rejects(
|
|
113
|
+
() => readProjectedHarmonicGraph({ memoryDir, anchorsEnabled: false, abortSignal: controller.signal }),
|
|
114
|
+
{ name: "AbortError" },
|
|
115
|
+
);
|
|
116
|
+
await assert.rejects(() => readFile(path.join(memoryDir, "state/harmonic-source-paths.json")), { code: "ENOENT" });
|
|
117
|
+
t.mock.restoreAll();
|
|
118
|
+
const graph = await readProjectedHarmonicGraph({ memoryDir, anchorsEnabled: false });
|
|
119
|
+
assert.equal(graph.nodes[0]?.sourceMemoryIds?.includes("cold/import"), true);
|
|
120
|
+
} finally {
|
|
121
|
+
t.mock.restoreAll();
|
|
122
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("an unreadable/unwritable path cache never suppresses an imported source (#3188)", async () => {
|
|
127
|
+
const memoryDir = await mkdtemp(path.join(tmpdir(), "remnic-harmonic-cache-errors-"));
|
|
128
|
+
try {
|
|
129
|
+
await seed(memoryDir);
|
|
130
|
+
await importFile(memoryDir, "", "not-id.md", "hot-import");
|
|
131
|
+
const cachePath = path.join(memoryDir, "state/harmonic-source-paths.json");
|
|
132
|
+
await mkdir(cachePath);
|
|
133
|
+
const graph = await readProjectedHarmonicGraph({ memoryDir, anchorsEnabled: false });
|
|
134
|
+
assert.equal(graph.nodes[0]?.sourceMemoryIds?.includes("hot-import"), true);
|
|
135
|
+
await rm(cachePath, { recursive: true });
|
|
136
|
+
await writeFile(cachePath, "{broken");
|
|
137
|
+
const recovered = await readProjectedHarmonicGraph({ memoryDir, anchorsEnabled: false });
|
|
138
|
+
assert.equal(recovered.nodes[0]?.sourceMemoryIds?.includes("hot-import"), true);
|
|
139
|
+
} finally {
|
|
140
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("an unresolved opaque id keeps the old scan candidate set for an edited projected file (#3188)", async () => {
|
|
145
|
+
const memoryDir = await mkdtemp(path.join(tmpdir(), "remnic-harmonic-opaque-"));
|
|
146
|
+
try {
|
|
147
|
+
const { storage, real } = await seed(memoryDir);
|
|
148
|
+
const memory = await storage.getMemoryById(real.id);
|
|
149
|
+
assert.ok(memory);
|
|
150
|
+
await writeFile(memory.path,
|
|
151
|
+
`---\nid: cold/import\ncategory: fact\ncreated: 2000-01-01T00:00:00.000Z\nupdated: 2000-01-01T00:00:00.000Z\nsource: test\nconfidence: 0.8\nconfidenceTier: implied\ntags: []\n---\n\nEdited projected legacy source.\n`);
|
|
152
|
+
const graph = await readProjectedHarmonicGraph({ memoryDir, anchorsEnabled: false });
|
|
153
|
+
assert.deepEqual(graph.nodes[0]?.sourceMemoryIds, ["cold/import"]);
|
|
154
|
+
assert.equal(graph.nodes[0]?.summary, "Edited projected legacy source.");
|
|
155
|
+
} finally {
|
|
156
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("cached import paths reread source status without another walk (#3188)", async (t) => {
|
|
161
|
+
const memoryDir = await mkdtemp(path.join(tmpdir(), "remnic-harmonic-fresh-status-"));
|
|
162
|
+
try {
|
|
163
|
+
const { real } = await seed(memoryDir);
|
|
164
|
+
await importFile(memoryDir, "", "not-id.md", "hot-import");
|
|
165
|
+
const first = await readProjectedHarmonicGraph({ memoryDir, anchorsEnabled: false });
|
|
166
|
+
assert.equal(first.nodes[0]?.sourceMemoryIds?.includes("hot-import"), true);
|
|
167
|
+
const filePath = path.join(memoryDir, "facts/2000-01-01/not-id.md");
|
|
168
|
+
await writeFile(filePath, (await readFile(filePath, "utf8")).replace("category: fact", "category: fact\nstatus: quarantined"));
|
|
169
|
+
t.mock.method(StorageManager.prototype, "collectActiveMemoryPaths", async () => { throw new Error("unexpected hot walk"); });
|
|
170
|
+
t.mock.method(StorageManager.prototype, "collectColdMemoryPaths", async () => { throw new Error("unexpected cold walk"); });
|
|
171
|
+
t.mock.method(StorageManager.prototype, "readAllMemories", async () => { throw new Error("unexpected corpus parse"); });
|
|
172
|
+
const second = await readProjectedHarmonicGraph({ memoryDir, anchorsEnabled: false });
|
|
173
|
+
assert.deepEqual(second.nodes[0]?.sourceMemoryIds, [real.id]);
|
|
174
|
+
} finally {
|
|
175
|
+
t.mock.restoreAll();
|
|
176
|
+
await rm(memoryDir, { recursive: true, force: true });
|
|
177
|
+
}
|
|
178
|
+
});
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, realpath } from "node:fs/promises";
|
|
4
|
+
import { throwIfAborted } from "./abort-error.js";
|
|
5
|
+
import { readJsonFile, writeJsonFileAtomic } from "./json-store.js";
|
|
6
|
+
import { readProjectedMemoryPaths } from "./memory-projection-batch.js";
|
|
7
|
+
import { SecureStoreLockedError } from "./secure-store/secure-fs.js";
|
|
8
|
+
import { isPathInsideStorageRoot, isSafeLegacyPathSegment } from "./storage-paths.js";
|
|
9
|
+
import { isRecord } from "./store-contract.js";
|
|
10
|
+
import type { StorageManager } from "./storage.js";
|
|
11
|
+
import type { MemoryFile } from "./types.js";
|
|
12
|
+
import { RECALL_FALLBACK_DIRS } from "./utils/category-dir.js";
|
|
13
|
+
|
|
14
|
+
const LOOKUP_TTL_MS = 10 * 60_000;
|
|
15
|
+
const MAX_CACHE_ENTRIES = 4096;
|
|
16
|
+
type PathEntry = { path: string | null; expiresAt: number };
|
|
17
|
+
|
|
18
|
+
/** Direct and cached probes must retain the walk's realpath containment check. */
|
|
19
|
+
export async function readHarmonicSourceMemory(
|
|
20
|
+
storage: StorageManager,
|
|
21
|
+
rootReal: string,
|
|
22
|
+
filePath: string,
|
|
23
|
+
abortSignal?: AbortSignal,
|
|
24
|
+
): Promise<MemoryFile | null> {
|
|
25
|
+
throwIfAborted(abortSignal, "harmonic retrieval aborted");
|
|
26
|
+
if (!existsSync(filePath)) return null;
|
|
27
|
+
try {
|
|
28
|
+
if (!isPathInsideStorageRoot(rootReal, await realpath(filePath))) return null;
|
|
29
|
+
return await storage.readMemoryByPath(filePath);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
throwIfAborted(abortSignal, "harmonic retrieval aborted");
|
|
32
|
+
if (err instanceof SecureStoreLockedError) throw err;
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isCorpusPath(memoryDir: string, filePath: string): boolean {
|
|
38
|
+
if (!isPathInsideStorageRoot(memoryDir, filePath)) return false;
|
|
39
|
+
const [dir] = path.relative(memoryDir, filePath).split(path.sep);
|
|
40
|
+
return dir === "cold" || RECALL_FALLBACK_DIRS.includes(dir);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** A cache miss is not authoritative: unreadable/invalid cache state keeps the walk. */
|
|
44
|
+
async function readPathCache(
|
|
45
|
+
filePath: string, rebuiltAt: string, corpusVersion: string, nowMs: number,
|
|
46
|
+
): Promise<Map<string, PathEntry>> {
|
|
47
|
+
try {
|
|
48
|
+
const raw = await readJsonFile(filePath);
|
|
49
|
+
if (!isRecord(raw) || raw.rebuiltAt !== rebuiltAt || raw.corpusVersion !== corpusVersion || !Array.isArray(raw.entries)) return new Map();
|
|
50
|
+
const entries = new Map<string, PathEntry>();
|
|
51
|
+
for (const row of raw.entries) {
|
|
52
|
+
if (!Array.isArray(row) || row.length !== 3) continue;
|
|
53
|
+
const [id, storedPath, expiresAt] = row;
|
|
54
|
+
if (typeof id !== "string" || (storedPath !== null && typeof storedPath !== "string")) continue;
|
|
55
|
+
if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt) || expiresAt <= nowMs || expiresAt > nowMs + LOOKUP_TTL_MS) continue;
|
|
56
|
+
entries.set(id, { path: storedPath, expiresAt });
|
|
57
|
+
}
|
|
58
|
+
return entries;
|
|
59
|
+
} catch {
|
|
60
|
+
return new Map();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Resolve only unresolved ids; persist paths/absence, never memory content. */
|
|
65
|
+
export async function readUnresolvedHarmonicSources(options: {
|
|
66
|
+
storage: StorageManager;
|
|
67
|
+
rootReal: string;
|
|
68
|
+
rebuiltAt: string;
|
|
69
|
+
sourceMemoryIds: string[];
|
|
70
|
+
nowMs: number;
|
|
71
|
+
abortSignal?: AbortSignal;
|
|
72
|
+
}): Promise<Map<string, MemoryFile>> {
|
|
73
|
+
const { storage, rootReal, rebuiltAt, nowMs, abortSignal } = options;
|
|
74
|
+
throwIfAborted(abortSignal, "harmonic retrieval aborted");
|
|
75
|
+
const corpusVersion = storage.getCorpusScanVersion();
|
|
76
|
+
const stateDir = path.join(storage.dir, "state");
|
|
77
|
+
const cachePath = path.join(stateDir, "harmonic-source-paths.json");
|
|
78
|
+
const stateReal = await realpath(stateDir).catch(() => null);
|
|
79
|
+
const safeCache = stateReal !== null && isPathInsideStorageRoot(rootReal, stateReal);
|
|
80
|
+
const cache = safeCache ? await readPathCache(cachePath, rebuiltAt, corpusVersion, nowMs) : new Map<string, PathEntry>();
|
|
81
|
+
const found = new Map<string, MemoryFile>();
|
|
82
|
+
const pending = new Set<string>();
|
|
83
|
+
for (const id of options.sourceMemoryIds) {
|
|
84
|
+
throwIfAborted(abortSignal, "harmonic retrieval aborted");
|
|
85
|
+
const entry = cache.get(id);
|
|
86
|
+
if (entry?.path === null) continue;
|
|
87
|
+
if (entry?.path) {
|
|
88
|
+
const candidate = path.resolve(storage.dir, entry.path);
|
|
89
|
+
const memory = isCorpusPath(storage.dir, candidate)
|
|
90
|
+
? await readHarmonicSourceMemory(storage, rootReal, candidate, abortSignal) : null;
|
|
91
|
+
if (memory?.frontmatter.id === id) {
|
|
92
|
+
found.set(id, memory);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
pending.add(id);
|
|
97
|
+
}
|
|
98
|
+
if (pending.size === 0) return found;
|
|
99
|
+
|
|
100
|
+
// Opaque legacy ids previously used the full scan, including edited projected files.
|
|
101
|
+
const inspectProjected = [...pending].some((id) => !isSafeLegacyPathSegment(id));
|
|
102
|
+
const projectedPaths = readProjectedMemoryPaths(storage.dir);
|
|
103
|
+
const walked = [
|
|
104
|
+
...(await storage.collectActiveMemoryPaths({ abortSignal, propagateReadErrors: true })),
|
|
105
|
+
...(await storage.collectColdMemoryPaths({ abortSignal, propagateReadErrors: true })),
|
|
106
|
+
];
|
|
107
|
+
for (const filePath of walked) {
|
|
108
|
+
throwIfAborted(abortSignal, "harmonic retrieval aborted");
|
|
109
|
+
// Existing projected files need no parse unless their filename names a wanted id.
|
|
110
|
+
// New/imported files must be keyed by frontmatter id, not their basename (#3188).
|
|
111
|
+
if (!inspectProjected && !pending.has(path.basename(filePath, ".md")) && projectedPaths?.has(filePath)) continue;
|
|
112
|
+
const memory = await readHarmonicSourceMemory(storage, rootReal, filePath, abortSignal);
|
|
113
|
+
if (!memory) continue;
|
|
114
|
+
const id = memory.frontmatter.id;
|
|
115
|
+
if (pending.has(id)) {
|
|
116
|
+
found.set(id, memory);
|
|
117
|
+
cache.set(id, { path: path.relative(storage.dir, filePath), expiresAt: nowMs + LOOKUP_TTL_MS });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
for (const id of pending) {
|
|
121
|
+
if (!found.has(id)) cache.set(id, { path: null, expiresAt: nowMs + LOOKUP_TTL_MS });
|
|
122
|
+
}
|
|
123
|
+
throwIfAborted(abortSignal, "harmonic retrieval aborted");
|
|
124
|
+
// A concurrent mutation must not publish absence for a different corpus epoch.
|
|
125
|
+
if (storage.getCorpusScanVersion() === corpusVersion) {
|
|
126
|
+
try {
|
|
127
|
+
await mkdir(stateDir, { recursive: true });
|
|
128
|
+
if (isPathInsideStorageRoot(rootReal, await realpath(stateDir))) {
|
|
129
|
+
throwIfAborted(abortSignal, "harmonic retrieval aborted");
|
|
130
|
+
// ponytail: atomic last-writer-wins cache; contention can repeat a walk, not lose sources.
|
|
131
|
+
await writeJsonFileAtomic(cachePath, {
|
|
132
|
+
rebuiltAt, corpusVersion,
|
|
133
|
+
entries: [...cache].slice(-MAX_CACHE_ENTRIES).map(([id, entry]) => [id, entry.path, entry.expiresAt]),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
throwIfAborted(abortSignal, "harmonic retrieval aborted");
|
|
138
|
+
// Cache publication is optional; resolved memories remain usable on a read-only store.
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return found;
|
|
142
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import type { MemoryProjectionCurrentState } from "./types.js";
|
|
3
|
+
import { isRecord } from "./store-contract.js";
|
|
2
4
|
import {
|
|
3
5
|
memoryCurrentSelectExpressions,
|
|
4
6
|
openProjectionReadonly,
|
|
@@ -80,3 +82,21 @@ export function readProjectedMemoryStates(
|
|
|
80
82
|
db.close();
|
|
81
83
|
}
|
|
82
84
|
}
|
|
85
|
+
|
|
86
|
+
/** Path-only census used to avoid parsing already-projected files during a fallback lookup. */
|
|
87
|
+
export function readProjectedMemoryPaths(memoryDir: string): Set<string> | null {
|
|
88
|
+
const db = openProjectionReadonly(memoryDir);
|
|
89
|
+
if (!db) return null;
|
|
90
|
+
try {
|
|
91
|
+
const paths = new Set<string>();
|
|
92
|
+
for (const row of db.prepare("SELECT path_rel FROM memory_current").iterate()) {
|
|
93
|
+
const relative = isRecord(row) ? row.path_rel : undefined;
|
|
94
|
+
if (typeof relative === "string") paths.add(path.resolve(memoryDir, relative));
|
|
95
|
+
}
|
|
96
|
+
return paths;
|
|
97
|
+
} catch {
|
|
98
|
+
return null;
|
|
99
|
+
} finally {
|
|
100
|
+
db.close();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -3648,18 +3648,6 @@ export class RecallInternalCoordinator {
|
|
|
3648
3648
|
this.deps.appendRecallSection(sectionBuckets, "trust-zones", trustZoneSection);
|
|
3649
3649
|
}
|
|
3650
3650
|
|
|
3651
|
-
const harmonicRetrievalSection = await awaitEnrichmentSection(
|
|
3652
|
-
"harmonic",
|
|
3653
|
-
harmonicRetrievalPromise,
|
|
3654
|
-
);
|
|
3655
|
-
if (harmonicRetrievalSection) {
|
|
3656
|
-
this.deps.appendRecallSection(
|
|
3657
|
-
sectionBuckets,
|
|
3658
|
-
"harmonic-retrieval",
|
|
3659
|
-
harmonicRetrievalSection,
|
|
3660
|
-
);
|
|
3661
|
-
}
|
|
3662
|
-
|
|
3663
3651
|
if (verifiedRecallSection) {
|
|
3664
3652
|
this.deps.appendRecallSection(
|
|
3665
3653
|
sectionBuckets,
|
|
@@ -4780,6 +4768,18 @@ export class RecallInternalCoordinator {
|
|
|
4780
4768
|
}
|
|
4781
4769
|
}
|
|
4782
4770
|
const phase2AfterQmdMs = Date.now() - recallStart;
|
|
4771
|
+
|
|
4772
|
+
const harmonicRetrievalSection = await awaitEnrichmentSection(
|
|
4773
|
+
"harmonic",
|
|
4774
|
+
harmonicRetrievalPromise,
|
|
4775
|
+
);
|
|
4776
|
+
if (harmonicRetrievalSection) {
|
|
4777
|
+
this.deps.appendRecallSection(
|
|
4778
|
+
sectionBuckets,
|
|
4779
|
+
"harmonic-retrieval",
|
|
4780
|
+
harmonicRetrievalSection,
|
|
4781
|
+
);
|
|
4782
|
+
}
|
|
4783
4783
|
if (shouldPersistGraphSnapshot) {
|
|
4784
4784
|
if (!graphSnapshotStatus) {
|
|
4785
4785
|
graphSnapshotStatus = "skipped";
|