@remnic/core 1.1.16 → 1.1.18
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-cli.js +16 -16
- package/dist/access-http.d.ts +2 -1
- package/dist/access-http.js +10 -10
- package/dist/access-mcp.d.ts +1 -1
- package/dist/access-mcp.js +9 -9
- package/dist/access-schema.d.ts +23 -3
- package/dist/access-schema.js +6 -1
- package/dist/{access-service-DZXc7qwR.d.ts → access-service-DT9L2DW4.d.ts} +14 -2
- package/dist/access-service.d.ts +1 -1
- package/dist/access-service.js +7 -7
- package/dist/briefing.js +4 -4
- package/dist/causal-consolidation.js +5 -5
- package/dist/{chunk-NOHC2L57.js → chunk-2IRT26RZ.js} +2 -2
- package/dist/{chunk-HJILHQOR.js → chunk-2XX25T6U.js} +15 -15
- package/dist/{chunk-66H2DZYB.js → chunk-4J3BTQRB.js} +13 -1
- package/dist/chunk-4J3BTQRB.js.map +1 -0
- package/dist/{chunk-MS3ULOZF.js → chunk-5IQC4OG6.js} +2 -2
- package/dist/{chunk-ZPXYWTN5.js → chunk-5ML4TH3E.js} +4 -4
- package/dist/{chunk-V7WH7DEM.js → chunk-6ORWKANA.js} +2 -2
- package/dist/{chunk-IOAY54RF.js → chunk-7Q2P774N.js} +11 -11
- package/dist/{chunk-JFEH2LZM.js → chunk-CN4P6SVA.js} +2 -2
- package/dist/{chunk-OGROP7ZN.js → chunk-FFU4GMST.js} +5 -5
- package/dist/{chunk-C7DGCHJE.js → chunk-FSODDMR2.js} +2 -2
- package/dist/{chunk-AAX3SUM3.js → chunk-GGCJ253V.js} +11 -11
- package/dist/{chunk-2OZ6GP27.js → chunk-J4VRI4BH.js} +101 -5
- package/dist/chunk-J4VRI4BH.js.map +1 -0
- package/dist/{chunk-IG5VGHYB.js → chunk-KSFBM6TV.js} +2 -2
- package/dist/{chunk-M3AA636B.js → chunk-NOQ74SJN.js} +2 -2
- package/dist/{chunk-MTYLGYOQ.js → chunk-P7FRFY6S.js} +38 -4
- package/dist/chunk-P7FRFY6S.js.map +1 -0
- package/dist/{chunk-QLKBF3TI.js → chunk-QOHBYVZG.js} +2 -2
- package/dist/{chunk-OJRKZLZ4.js → chunk-SGIXDVSF.js} +2 -2
- package/dist/{chunk-SK42SSAN.js → chunk-SPEVF47M.js} +4 -4
- package/dist/{chunk-YCVWX2NF.js → chunk-SZKCBLS5.js} +2 -2
- package/dist/{chunk-BEB4GUU5.js → chunk-TLM762GT.js} +2 -2
- package/dist/{chunk-65HQPW6O.js → chunk-TOFUTKQN.js} +2 -2
- package/dist/{chunk-Y2YBRCEF.js → chunk-TUQXQOGR.js} +34 -9
- package/dist/chunk-TUQXQOGR.js.map +1 -0
- package/dist/{chunk-G7JBLD65.js → chunk-YO3AZEE5.js} +3 -3
- package/dist/{cli-kVwab1_L.d.ts → cli-BN0CkYzI.d.ts} +1 -1
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +19 -19
- package/dist/compounding/engine.js +4 -4
- package/dist/connectors/codex-materialize-runner.js +4 -4
- package/dist/connectors/index.js +4 -4
- package/dist/entity-retrieval.js +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +50 -46
- package/dist/index.js.map +1 -1
- package/dist/maintenance/memory-governance.js +4 -4
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +4 -4
- package/dist/maintenance/rebuild-memory-projection.js +5 -5
- package/dist/mcp-memory-inspector-app.d.ts +1 -1
- package/dist/namespaces/migrate.js +5 -5
- package/dist/namespaces/storage.js +4 -4
- package/dist/offline-sync.d.ts +16 -1
- package/dist/offline-sync.js +8 -2
- package/dist/operator-toolkit.js +7 -7
- package/dist/orchestrator.js +12 -12
- package/dist/schemas.d.ts +22 -22
- package/dist/secure-store/index.js +17 -17
- package/dist/semantic-consolidation.js +5 -5
- package/dist/semantic-rule-promotion.js +4 -4
- package/dist/semantic-rule-verifier.js +4 -4
- package/dist/storage.js +3 -3
- package/dist/transfer/types.d.ts +12 -12
- package/dist/verified-recall.js +4 -4
- package/package.json +1 -1
- package/src/access-http.test.ts +90 -0
- package/src/access-http.ts +47 -0
- package/src/access-schema.ts +13 -0
- package/src/access-service.ts +48 -0
- package/src/index.ts +3 -0
- package/src/offline-sync.test.ts +81 -0
- package/src/offline-sync.ts +117 -0
- package/dist/chunk-2OZ6GP27.js.map +0 -1
- package/dist/chunk-66H2DZYB.js.map +0 -1
- package/dist/chunk-MTYLGYOQ.js.map +0 -1
- package/dist/chunk-Y2YBRCEF.js.map +0 -1
- /package/dist/{chunk-NOHC2L57.js.map → chunk-2IRT26RZ.js.map} +0 -0
- /package/dist/{chunk-HJILHQOR.js.map → chunk-2XX25T6U.js.map} +0 -0
- /package/dist/{chunk-MS3ULOZF.js.map → chunk-5IQC4OG6.js.map} +0 -0
- /package/dist/{chunk-ZPXYWTN5.js.map → chunk-5ML4TH3E.js.map} +0 -0
- /package/dist/{chunk-V7WH7DEM.js.map → chunk-6ORWKANA.js.map} +0 -0
- /package/dist/{chunk-IOAY54RF.js.map → chunk-7Q2P774N.js.map} +0 -0
- /package/dist/{chunk-JFEH2LZM.js.map → chunk-CN4P6SVA.js.map} +0 -0
- /package/dist/{chunk-OGROP7ZN.js.map → chunk-FFU4GMST.js.map} +0 -0
- /package/dist/{chunk-C7DGCHJE.js.map → chunk-FSODDMR2.js.map} +0 -0
- /package/dist/{chunk-AAX3SUM3.js.map → chunk-GGCJ253V.js.map} +0 -0
- /package/dist/{chunk-IG5VGHYB.js.map → chunk-KSFBM6TV.js.map} +0 -0
- /package/dist/{chunk-M3AA636B.js.map → chunk-NOQ74SJN.js.map} +0 -0
- /package/dist/{chunk-QLKBF3TI.js.map → chunk-QOHBYVZG.js.map} +0 -0
- /package/dist/{chunk-OJRKZLZ4.js.map → chunk-SGIXDVSF.js.map} +0 -0
- /package/dist/{chunk-SK42SSAN.js.map → chunk-SPEVF47M.js.map} +0 -0
- /package/dist/{chunk-YCVWX2NF.js.map → chunk-SZKCBLS5.js.map} +0 -0
- /package/dist/{chunk-BEB4GUU5.js.map → chunk-TLM762GT.js.map} +0 -0
- /package/dist/{chunk-65HQPW6O.js.map → chunk-TOFUTKQN.js.map} +0 -0
- /package/dist/{chunk-G7JBLD65.js.map → chunk-YO3AZEE5.js.map} +0 -0
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
searchVerifiedSemanticRules
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-QOHBYVZG.js";
|
|
4
|
+
import "./chunk-7Q2P774N.js";
|
|
5
5
|
import "./chunk-5UZXUTVO.js";
|
|
6
|
-
import "./chunk-SH5S7XYD.js";
|
|
7
6
|
import "./chunk-NN2DKE4T.js";
|
|
8
7
|
import "./chunk-Q7P4WJDP.js";
|
|
9
|
-
import "./chunk-P7FMDTKL.js";
|
|
10
8
|
import "./chunk-SCU65EZI.js";
|
|
11
9
|
import "./chunk-3KW65B36.js";
|
|
12
10
|
import "./chunk-3HPAPHUK.js";
|
|
@@ -20,7 +18,9 @@ import "./chunk-FAAFWE4G.js";
|
|
|
20
18
|
import "./chunk-DT5TVLJE.js";
|
|
21
19
|
import "./chunk-4DJQYKMN.js";
|
|
22
20
|
import "./chunk-2ODBA7MQ.js";
|
|
21
|
+
import "./chunk-SH5S7XYD.js";
|
|
23
22
|
import "./chunk-A6XUJE5D.js";
|
|
23
|
+
import "./chunk-P7FMDTKL.js";
|
|
24
24
|
import "./chunk-PZ5AY32C.js";
|
|
25
25
|
export {
|
|
26
26
|
searchVerifiedSemanticRules
|
package/dist/storage.js
CHANGED
|
@@ -8,12 +8,10 @@ import {
|
|
|
8
8
|
normalizeEntityName,
|
|
9
9
|
parseEntityFile,
|
|
10
10
|
serializeEntityFile
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-7Q2P774N.js";
|
|
12
12
|
import "./chunk-5UZXUTVO.js";
|
|
13
|
-
import "./chunk-SH5S7XYD.js";
|
|
14
13
|
import "./chunk-NN2DKE4T.js";
|
|
15
14
|
import "./chunk-Q7P4WJDP.js";
|
|
16
|
-
import "./chunk-P7FMDTKL.js";
|
|
17
15
|
import "./chunk-SCU65EZI.js";
|
|
18
16
|
import "./chunk-3KW65B36.js";
|
|
19
17
|
import "./chunk-3HPAPHUK.js";
|
|
@@ -26,7 +24,9 @@ import "./chunk-G7D6GZ5J.js";
|
|
|
26
24
|
import "./chunk-FAAFWE4G.js";
|
|
27
25
|
import "./chunk-4DJQYKMN.js";
|
|
28
26
|
import "./chunk-2ODBA7MQ.js";
|
|
27
|
+
import "./chunk-SH5S7XYD.js";
|
|
29
28
|
import "./chunk-A6XUJE5D.js";
|
|
29
|
+
import "./chunk-P7FMDTKL.js";
|
|
30
30
|
import "./chunk-PZ5AY32C.js";
|
|
31
31
|
export {
|
|
32
32
|
ContentHashIndex,
|
package/dist/transfer/types.d.ts
CHANGED
|
@@ -313,13 +313,13 @@ declare const CapsuleBlockSchema: z.ZodObject<{
|
|
|
313
313
|
peerProfiles: boolean;
|
|
314
314
|
}>;
|
|
315
315
|
}, "strip", z.ZodTypeAny, {
|
|
316
|
+
schemaVersion: string;
|
|
316
317
|
includes: {
|
|
317
318
|
procedural: boolean;
|
|
318
319
|
taxonomy: boolean;
|
|
319
320
|
identityAnchors: boolean;
|
|
320
321
|
peerProfiles: boolean;
|
|
321
322
|
};
|
|
322
|
-
schemaVersion: string;
|
|
323
323
|
id: string;
|
|
324
324
|
description: string;
|
|
325
325
|
version: string;
|
|
@@ -334,13 +334,13 @@ declare const CapsuleBlockSchema: z.ZodObject<{
|
|
|
334
334
|
directAnswerEnabled: boolean;
|
|
335
335
|
};
|
|
336
336
|
}, {
|
|
337
|
+
schemaVersion: string;
|
|
337
338
|
includes: {
|
|
338
339
|
procedural: boolean;
|
|
339
340
|
taxonomy: boolean;
|
|
340
341
|
identityAnchors: boolean;
|
|
341
342
|
peerProfiles: boolean;
|
|
342
343
|
};
|
|
343
|
-
schemaVersion: string;
|
|
344
344
|
id: string;
|
|
345
345
|
description: string;
|
|
346
346
|
version: string;
|
|
@@ -464,13 +464,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
464
464
|
peerProfiles: boolean;
|
|
465
465
|
}>;
|
|
466
466
|
}, "strip", z.ZodTypeAny, {
|
|
467
|
+
schemaVersion: string;
|
|
467
468
|
includes: {
|
|
468
469
|
procedural: boolean;
|
|
469
470
|
taxonomy: boolean;
|
|
470
471
|
identityAnchors: boolean;
|
|
471
472
|
peerProfiles: boolean;
|
|
472
473
|
};
|
|
473
|
-
schemaVersion: string;
|
|
474
474
|
id: string;
|
|
475
475
|
description: string;
|
|
476
476
|
version: string;
|
|
@@ -485,13 +485,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
485
485
|
directAnswerEnabled: boolean;
|
|
486
486
|
};
|
|
487
487
|
}, {
|
|
488
|
+
schemaVersion: string;
|
|
488
489
|
includes: {
|
|
489
490
|
procedural: boolean;
|
|
490
491
|
taxonomy: boolean;
|
|
491
492
|
identityAnchors: boolean;
|
|
492
493
|
peerProfiles: boolean;
|
|
493
494
|
};
|
|
494
|
-
schemaVersion: string;
|
|
495
495
|
id: string;
|
|
496
496
|
description: string;
|
|
497
497
|
version: string;
|
|
@@ -518,13 +518,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
518
518
|
pluginVersion: string;
|
|
519
519
|
includesTranscripts: boolean;
|
|
520
520
|
capsule: {
|
|
521
|
+
schemaVersion: string;
|
|
521
522
|
includes: {
|
|
522
523
|
procedural: boolean;
|
|
523
524
|
taxonomy: boolean;
|
|
524
525
|
identityAnchors: boolean;
|
|
525
526
|
peerProfiles: boolean;
|
|
526
527
|
};
|
|
527
|
-
schemaVersion: string;
|
|
528
528
|
id: string;
|
|
529
529
|
description: string;
|
|
530
530
|
version: string;
|
|
@@ -551,13 +551,13 @@ declare const ExportManifestV2Schema: z.ZodObject<{
|
|
|
551
551
|
pluginVersion: string;
|
|
552
552
|
includesTranscripts: boolean;
|
|
553
553
|
capsule: {
|
|
554
|
+
schemaVersion: string;
|
|
554
555
|
includes: {
|
|
555
556
|
procedural: boolean;
|
|
556
557
|
taxonomy: boolean;
|
|
557
558
|
identityAnchors: boolean;
|
|
558
559
|
peerProfiles: boolean;
|
|
559
560
|
};
|
|
560
|
-
schemaVersion: string;
|
|
561
561
|
id: string;
|
|
562
562
|
description: string;
|
|
563
563
|
version: string;
|
|
@@ -683,13 +683,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
683
683
|
peerProfiles: boolean;
|
|
684
684
|
}>;
|
|
685
685
|
}, "strip", z.ZodTypeAny, {
|
|
686
|
+
schemaVersion: string;
|
|
686
687
|
includes: {
|
|
687
688
|
procedural: boolean;
|
|
688
689
|
taxonomy: boolean;
|
|
689
690
|
identityAnchors: boolean;
|
|
690
691
|
peerProfiles: boolean;
|
|
691
692
|
};
|
|
692
|
-
schemaVersion: string;
|
|
693
693
|
id: string;
|
|
694
694
|
description: string;
|
|
695
695
|
version: string;
|
|
@@ -704,13 +704,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
704
704
|
directAnswerEnabled: boolean;
|
|
705
705
|
};
|
|
706
706
|
}, {
|
|
707
|
+
schemaVersion: string;
|
|
707
708
|
includes: {
|
|
708
709
|
procedural: boolean;
|
|
709
710
|
taxonomy: boolean;
|
|
710
711
|
identityAnchors: boolean;
|
|
711
712
|
peerProfiles: boolean;
|
|
712
713
|
};
|
|
713
|
-
schemaVersion: string;
|
|
714
714
|
id: string;
|
|
715
715
|
description: string;
|
|
716
716
|
version: string;
|
|
@@ -737,13 +737,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
737
737
|
pluginVersion: string;
|
|
738
738
|
includesTranscripts: boolean;
|
|
739
739
|
capsule: {
|
|
740
|
+
schemaVersion: string;
|
|
740
741
|
includes: {
|
|
741
742
|
procedural: boolean;
|
|
742
743
|
taxonomy: boolean;
|
|
743
744
|
identityAnchors: boolean;
|
|
744
745
|
peerProfiles: boolean;
|
|
745
746
|
};
|
|
746
|
-
schemaVersion: string;
|
|
747
747
|
id: string;
|
|
748
748
|
description: string;
|
|
749
749
|
version: string;
|
|
@@ -770,13 +770,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
770
770
|
pluginVersion: string;
|
|
771
771
|
includesTranscripts: boolean;
|
|
772
772
|
capsule: {
|
|
773
|
+
schemaVersion: string;
|
|
773
774
|
includes: {
|
|
774
775
|
procedural: boolean;
|
|
775
776
|
taxonomy: boolean;
|
|
776
777
|
identityAnchors: boolean;
|
|
777
778
|
peerProfiles: boolean;
|
|
778
779
|
};
|
|
779
|
-
schemaVersion: string;
|
|
780
780
|
id: string;
|
|
781
781
|
description: string;
|
|
782
782
|
version: string;
|
|
@@ -815,13 +815,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
815
815
|
pluginVersion: string;
|
|
816
816
|
includesTranscripts: boolean;
|
|
817
817
|
capsule: {
|
|
818
|
+
schemaVersion: string;
|
|
818
819
|
includes: {
|
|
819
820
|
procedural: boolean;
|
|
820
821
|
taxonomy: boolean;
|
|
821
822
|
identityAnchors: boolean;
|
|
822
823
|
peerProfiles: boolean;
|
|
823
824
|
};
|
|
824
|
-
schemaVersion: string;
|
|
825
825
|
id: string;
|
|
826
826
|
description: string;
|
|
827
827
|
version: string;
|
|
@@ -854,13 +854,13 @@ declare const ExportBundleV2Schema: z.ZodObject<{
|
|
|
854
854
|
pluginVersion: string;
|
|
855
855
|
includesTranscripts: boolean;
|
|
856
856
|
capsule: {
|
|
857
|
+
schemaVersion: string;
|
|
857
858
|
includes: {
|
|
858
859
|
procedural: boolean;
|
|
859
860
|
taxonomy: boolean;
|
|
860
861
|
identityAnchors: boolean;
|
|
861
862
|
peerProfiles: boolean;
|
|
862
863
|
};
|
|
863
|
-
schemaVersion: string;
|
|
864
864
|
id: string;
|
|
865
865
|
description: string;
|
|
866
866
|
version: string;
|
package/dist/verified-recall.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
searchVerifiedEpisodes
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5IQC4OG6.js";
|
|
4
4
|
import "./chunk-NZL6GGQE.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-7Q2P774N.js";
|
|
6
6
|
import "./chunk-5UZXUTVO.js";
|
|
7
|
-
import "./chunk-SH5S7XYD.js";
|
|
8
7
|
import "./chunk-NN2DKE4T.js";
|
|
9
8
|
import "./chunk-Q7P4WJDP.js";
|
|
10
|
-
import "./chunk-P7FMDTKL.js";
|
|
11
9
|
import "./chunk-SCU65EZI.js";
|
|
12
10
|
import "./chunk-3KW65B36.js";
|
|
13
11
|
import "./chunk-3HPAPHUK.js";
|
|
@@ -21,7 +19,9 @@ import "./chunk-FAAFWE4G.js";
|
|
|
21
19
|
import "./chunk-DT5TVLJE.js";
|
|
22
20
|
import "./chunk-4DJQYKMN.js";
|
|
23
21
|
import "./chunk-2ODBA7MQ.js";
|
|
22
|
+
import "./chunk-SH5S7XYD.js";
|
|
24
23
|
import "./chunk-A6XUJE5D.js";
|
|
24
|
+
import "./chunk-P7FMDTKL.js";
|
|
25
25
|
import "./chunk-PZ5AY32C.js";
|
|
26
26
|
export {
|
|
27
27
|
searchVerifiedEpisodes
|
package/package.json
CHANGED
package/src/access-http.test.ts
CHANGED
|
@@ -359,6 +359,96 @@ test("HTTP offline files forwards namespace and requested paths", async () => {
|
|
|
359
359
|
}
|
|
360
360
|
});
|
|
361
361
|
|
|
362
|
+
test("HTTP offline file-content forwards range options and returns binary metadata", async () => {
|
|
363
|
+
const calls: Array<{
|
|
364
|
+
namespace: string | undefined;
|
|
365
|
+
principal: string | undefined;
|
|
366
|
+
includeTranscripts: boolean | undefined;
|
|
367
|
+
path: string;
|
|
368
|
+
offset: number | undefined;
|
|
369
|
+
length: number | undefined;
|
|
370
|
+
}> = [];
|
|
371
|
+
const service = {
|
|
372
|
+
offlineSyncFileContent: async (options: {
|
|
373
|
+
namespace?: string;
|
|
374
|
+
principal?: string;
|
|
375
|
+
includeTranscripts?: boolean;
|
|
376
|
+
path: string;
|
|
377
|
+
offset?: number;
|
|
378
|
+
length?: number;
|
|
379
|
+
}) => {
|
|
380
|
+
calls.push({
|
|
381
|
+
namespace: options.namespace,
|
|
382
|
+
principal: options.principal,
|
|
383
|
+
includeTranscripts: options.includeTranscripts,
|
|
384
|
+
path: options.path,
|
|
385
|
+
offset: options.offset,
|
|
386
|
+
length: options.length,
|
|
387
|
+
});
|
|
388
|
+
return {
|
|
389
|
+
namespace: options.namespace ?? "default",
|
|
390
|
+
path: options.path,
|
|
391
|
+
sha256: "a".repeat(64),
|
|
392
|
+
bytes: 12,
|
|
393
|
+
mtimeMs: 1234,
|
|
394
|
+
offset: options.offset ?? 0,
|
|
395
|
+
chunkBytes: 5,
|
|
396
|
+
content: Buffer.from("hello"),
|
|
397
|
+
};
|
|
398
|
+
},
|
|
399
|
+
} as unknown as EngramAccessService;
|
|
400
|
+
const server = new EngramAccessHttpServer({
|
|
401
|
+
service,
|
|
402
|
+
port: 0,
|
|
403
|
+
authToken: "test-token",
|
|
404
|
+
principal: "reader",
|
|
405
|
+
adminConsoleEnabled: false,
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
const status = await server.start();
|
|
409
|
+
try {
|
|
410
|
+
const response = await fetch(
|
|
411
|
+
`http://127.0.0.1:${status.port}/remnic/v1/offline-sync/file-content`,
|
|
412
|
+
{
|
|
413
|
+
method: "POST",
|
|
414
|
+
headers: {
|
|
415
|
+
authorization: "Bearer test-token",
|
|
416
|
+
"content-type": "application/json",
|
|
417
|
+
},
|
|
418
|
+
body: JSON.stringify({
|
|
419
|
+
namespace: "team",
|
|
420
|
+
includeTranscripts: false,
|
|
421
|
+
path: "state/memory-lifecycle-ledger.jsonl",
|
|
422
|
+
offset: 8,
|
|
423
|
+
length: 5,
|
|
424
|
+
}),
|
|
425
|
+
},
|
|
426
|
+
);
|
|
427
|
+
const body = Buffer.from(await response.arrayBuffer());
|
|
428
|
+
|
|
429
|
+
assert.equal(response.status, 200);
|
|
430
|
+
assert.equal(body.toString("utf-8"), "hello");
|
|
431
|
+
assert.equal(response.headers.get("content-type"), "application/octet-stream");
|
|
432
|
+
assert.equal(response.headers.get("x-remnic-namespace"), "team");
|
|
433
|
+
assert.equal(response.headers.get("x-remnic-file-path"), "state%2Fmemory-lifecycle-ledger.jsonl");
|
|
434
|
+
assert.equal(response.headers.get("x-remnic-file-sha256"), "a".repeat(64));
|
|
435
|
+
assert.equal(response.headers.get("x-remnic-file-bytes"), "12");
|
|
436
|
+
assert.equal(response.headers.get("x-remnic-file-mtime-ms"), "1234");
|
|
437
|
+
assert.equal(response.headers.get("x-remnic-chunk-offset"), "8");
|
|
438
|
+
assert.equal(response.headers.get("x-remnic-chunk-bytes"), "5");
|
|
439
|
+
assert.deepEqual(calls, [{
|
|
440
|
+
namespace: "team",
|
|
441
|
+
principal: "reader",
|
|
442
|
+
includeTranscripts: false,
|
|
443
|
+
path: "state/memory-lifecycle-ledger.jsonl",
|
|
444
|
+
offset: 8,
|
|
445
|
+
length: 5,
|
|
446
|
+
}]);
|
|
447
|
+
} finally {
|
|
448
|
+
await server.stop();
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
|
|
362
452
|
test("HTTP offline snapshot rejects invalid boolean query values", async () => {
|
|
363
453
|
let calls = 0;
|
|
364
454
|
const service = {
|
package/src/access-http.ts
CHANGED
|
@@ -641,6 +641,34 @@ export class EngramAccessHttpServer {
|
|
|
641
641
|
return;
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
+
if (
|
|
645
|
+
req.method === "POST" &&
|
|
646
|
+
(
|
|
647
|
+
pathname === "/engram/v1/offline-sync/file-content" ||
|
|
648
|
+
pathname === "/remnic/v1/offline-sync/file-content"
|
|
649
|
+
)
|
|
650
|
+
) {
|
|
651
|
+
const body = await this.readValidatedBody(req, "offlineSyncFileContent");
|
|
652
|
+
const result = await this.service.offlineSyncFileContent({
|
|
653
|
+
namespace: this.resolveNamespace(req, body.namespace),
|
|
654
|
+
principal: this.resolveRequestPrincipal(req),
|
|
655
|
+
includeTranscripts: body.includeTranscripts,
|
|
656
|
+
path: body.path,
|
|
657
|
+
offset: body.offset,
|
|
658
|
+
length: body.length,
|
|
659
|
+
});
|
|
660
|
+
this.respondBinary(res, 200, result.content, {
|
|
661
|
+
"x-remnic-namespace": encodeURIComponent(result.namespace),
|
|
662
|
+
"x-remnic-file-path": encodeURIComponent(result.path),
|
|
663
|
+
"x-remnic-file-bytes": String(result.bytes),
|
|
664
|
+
"x-remnic-file-mtime-ms": String(result.mtimeMs),
|
|
665
|
+
"x-remnic-chunk-offset": String(result.offset),
|
|
666
|
+
"x-remnic-chunk-bytes": String(result.chunkBytes),
|
|
667
|
+
...(result.sha256 ? { "x-remnic-file-sha256": result.sha256 } : {}),
|
|
668
|
+
});
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
|
|
644
672
|
if (
|
|
645
673
|
req.method === "POST" &&
|
|
646
674
|
(pathname === "/engram/v1/offline-sync/apply" || pathname === "/remnic/v1/offline-sync/apply")
|
|
@@ -1803,6 +1831,25 @@ export class EngramAccessHttpServer {
|
|
|
1803
1831
|
res.end(body);
|
|
1804
1832
|
}
|
|
1805
1833
|
|
|
1834
|
+
private respondBinary(
|
|
1835
|
+
res: ServerResponse,
|
|
1836
|
+
status: number,
|
|
1837
|
+
body: Buffer,
|
|
1838
|
+
headers: Record<string, string> = {},
|
|
1839
|
+
): void {
|
|
1840
|
+
res.statusCode = status;
|
|
1841
|
+
res.setHeader("content-type", "application/octet-stream");
|
|
1842
|
+
res.setHeader("content-length", String(body.length));
|
|
1843
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
1844
|
+
res.setHeader(key, value);
|
|
1845
|
+
}
|
|
1846
|
+
const cid = correlationIdStore.getStore();
|
|
1847
|
+
if (cid) {
|
|
1848
|
+
res.setHeader("x-request-id", cid);
|
|
1849
|
+
}
|
|
1850
|
+
res.end(body);
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1806
1853
|
private async handleAdminConsole(
|
|
1807
1854
|
req: IncomingMessage,
|
|
1808
1855
|
res: ServerResponse,
|
package/src/access-schema.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "./action-confidence.js";
|
|
11
11
|
import { isValidCapsuleSince } from "./transfer/capsule-export.js";
|
|
12
12
|
import { CAPSULE_ID_PATTERN } from "./transfer/types.js";
|
|
13
|
+
import { OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES } from "./offline-sync.js";
|
|
13
14
|
|
|
14
15
|
// ---------------------------------------------------------------------------
|
|
15
16
|
// Error formatting
|
|
@@ -386,6 +387,14 @@ export const offlineSyncFilesRequestSchema = z.object({
|
|
|
386
387
|
.max(5000, "paths must contain 5000 or fewer entries"),
|
|
387
388
|
});
|
|
388
389
|
|
|
390
|
+
export const offlineSyncFileContentRequestSchema = z.object({
|
|
391
|
+
namespace: namespaceSchema,
|
|
392
|
+
includeTranscripts: z.boolean().optional(),
|
|
393
|
+
path: z.string().trim().min(1, "path must be non-empty").max(4096),
|
|
394
|
+
offset: z.number().int().min(0).optional(),
|
|
395
|
+
length: z.number().int().min(1).max(OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES).optional(),
|
|
396
|
+
});
|
|
397
|
+
|
|
389
398
|
// ---------------------------------------------------------------------------
|
|
390
399
|
// Action confidence
|
|
391
400
|
// ---------------------------------------------------------------------------
|
|
@@ -453,6 +462,7 @@ export type CapsuleImportRequest = z.infer<typeof capsuleImportRequestSchema>;
|
|
|
453
462
|
export type CapsuleListRequest = z.infer<typeof capsuleListRequestSchema>;
|
|
454
463
|
export type OfflineSyncApplyRequest = z.infer<typeof offlineSyncApplyRequestSchema>;
|
|
455
464
|
export type OfflineSyncFilesRequest = z.infer<typeof offlineSyncFilesRequestSchema>;
|
|
465
|
+
export type OfflineSyncFileContentRequest = z.infer<typeof offlineSyncFileContentRequestSchema>;
|
|
456
466
|
export type ActionConfidenceRequest = z.infer<typeof actionConfidenceRequestSchema>;
|
|
457
467
|
|
|
458
468
|
// ---------------------------------------------------------------------------
|
|
@@ -477,6 +487,7 @@ export type SchemaName =
|
|
|
477
487
|
| "capsuleImport"
|
|
478
488
|
| "capsuleList"
|
|
479
489
|
| "offlineSyncFiles"
|
|
490
|
+
| "offlineSyncFileContent"
|
|
480
491
|
| "offlineSyncApply"
|
|
481
492
|
| "actionConfidence";
|
|
482
493
|
|
|
@@ -498,6 +509,7 @@ export type SchemaTypeFor<N extends SchemaName> =
|
|
|
498
509
|
: N extends "capsuleImport" ? CapsuleImportRequest
|
|
499
510
|
: N extends "capsuleList" ? CapsuleListRequest
|
|
500
511
|
: N extends "offlineSyncFiles" ? OfflineSyncFilesRequest
|
|
512
|
+
: N extends "offlineSyncFileContent" ? OfflineSyncFileContentRequest
|
|
501
513
|
: N extends "offlineSyncApply" ? OfflineSyncApplyRequest
|
|
502
514
|
: N extends "actionConfidence" ? ActionConfidenceRequest
|
|
503
515
|
: never;
|
|
@@ -520,6 +532,7 @@ const schemas: Record<SchemaName, z.ZodTypeAny> = {
|
|
|
520
532
|
capsuleImport: capsuleImportRequestSchema,
|
|
521
533
|
capsuleList: capsuleListRequestSchema,
|
|
522
534
|
offlineSyncFiles: offlineSyncFilesRequestSchema,
|
|
535
|
+
offlineSyncFileContent: offlineSyncFileContentRequestSchema,
|
|
523
536
|
offlineSyncApply: offlineSyncApplyRequestSchema,
|
|
524
537
|
actionConfidence: actionConfidenceRequestSchema,
|
|
525
538
|
};
|
package/src/access-service.ts
CHANGED
|
@@ -139,7 +139,9 @@ import {
|
|
|
139
139
|
applyOfflineSyncChangeset,
|
|
140
140
|
buildOfflineSyncSnapshot,
|
|
141
141
|
buildOfflineSyncSnapshotForPaths,
|
|
142
|
+
readOfflineSyncFileContentChunk,
|
|
142
143
|
type OfflineSyncApplyChangesetResult,
|
|
144
|
+
type OfflineSyncFileContentChunk,
|
|
143
145
|
type OfflineSyncSnapshot,
|
|
144
146
|
} from "./offline-sync.js";
|
|
145
147
|
import {
|
|
@@ -624,6 +626,15 @@ export interface EngramAccessOfflineSyncFilesRequest {
|
|
|
624
626
|
paths: string[];
|
|
625
627
|
}
|
|
626
628
|
|
|
629
|
+
export interface EngramAccessOfflineSyncFileContentRequest {
|
|
630
|
+
namespace?: string;
|
|
631
|
+
principal?: string;
|
|
632
|
+
includeTranscripts?: boolean;
|
|
633
|
+
path: string;
|
|
634
|
+
offset?: number;
|
|
635
|
+
length?: number;
|
|
636
|
+
}
|
|
637
|
+
|
|
627
638
|
export interface EngramAccessOfflineSyncApplyRequest {
|
|
628
639
|
namespace?: string;
|
|
629
640
|
principal?: string;
|
|
@@ -638,6 +649,10 @@ export interface EngramAccessOfflineSyncFilesResponse extends OfflineSyncSnapsho
|
|
|
638
649
|
namespace: string;
|
|
639
650
|
}
|
|
640
651
|
|
|
652
|
+
export interface EngramAccessOfflineSyncFileContentResponse extends OfflineSyncFileContentChunk {
|
|
653
|
+
namespace: string;
|
|
654
|
+
}
|
|
655
|
+
|
|
641
656
|
export interface EngramAccessOfflineSyncApplyResponse extends OfflineSyncApplyChangesetResult {
|
|
642
657
|
namespace: string;
|
|
643
658
|
}
|
|
@@ -5612,6 +5627,39 @@ export class EngramAccessService {
|
|
|
5612
5627
|
}
|
|
5613
5628
|
}
|
|
5614
5629
|
|
|
5630
|
+
async offlineSyncFileContent(
|
|
5631
|
+
options: EngramAccessOfflineSyncFileContentRequest,
|
|
5632
|
+
): Promise<EngramAccessOfflineSyncFileContentResponse> {
|
|
5633
|
+
const resolvedNamespace = this.resolveReadableNamespace(options.namespace, options.principal);
|
|
5634
|
+
const storage = await this.orchestrator.getStorage(resolvedNamespace);
|
|
5635
|
+
try {
|
|
5636
|
+
const chunk = await readOfflineSyncFileContentChunk({
|
|
5637
|
+
root: storage.dir,
|
|
5638
|
+
path: options.path,
|
|
5639
|
+
offset: options.offset,
|
|
5640
|
+
length: options.length,
|
|
5641
|
+
includeTranscripts: options.includeTranscripts !== false,
|
|
5642
|
+
readFile: async ({ filePath }) => storage.readOfflineSyncFile(filePath),
|
|
5643
|
+
});
|
|
5644
|
+
return {
|
|
5645
|
+
namespace: resolvedNamespace,
|
|
5646
|
+
...chunk,
|
|
5647
|
+
};
|
|
5648
|
+
} catch (error) {
|
|
5649
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5650
|
+
if (
|
|
5651
|
+
message.startsWith("path:") ||
|
|
5652
|
+
message.startsWith("offset ") ||
|
|
5653
|
+
message.startsWith("offset must ") ||
|
|
5654
|
+
message.startsWith("length ") ||
|
|
5655
|
+
message.startsWith("offline sync file content ")
|
|
5656
|
+
) {
|
|
5657
|
+
throw new EngramAccessInputError(message);
|
|
5658
|
+
}
|
|
5659
|
+
throw error;
|
|
5660
|
+
}
|
|
5661
|
+
}
|
|
5662
|
+
|
|
5615
5663
|
async offlineSyncApply(
|
|
5616
5664
|
options: EngramAccessOfflineSyncApplyRequest,
|
|
5617
5665
|
): Promise<EngramAccessOfflineSyncApplyResponse> {
|
package/src/index.ts
CHANGED
|
@@ -680,6 +680,7 @@ export {
|
|
|
680
680
|
|
|
681
681
|
export {
|
|
682
682
|
OFFLINE_SYNC_CHANGESET_FORMAT,
|
|
683
|
+
OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
|
|
683
684
|
OFFLINE_SYNC_SNAPSHOT_FORMAT,
|
|
684
685
|
OFFLINE_SYNC_STATE_VERSION,
|
|
685
686
|
applyOfflineSyncChangeset,
|
|
@@ -692,6 +693,7 @@ export {
|
|
|
692
693
|
normalizeOfflineSyncChangeset,
|
|
693
694
|
normalizeOfflineSyncSnapshot,
|
|
694
695
|
offlineSyncStateFromSnapshot,
|
|
696
|
+
readOfflineSyncFileContentChunk,
|
|
695
697
|
readOfflineSyncState,
|
|
696
698
|
summarizeOfflineSyncChangeset,
|
|
697
699
|
writeOfflineSyncState,
|
|
@@ -701,6 +703,7 @@ export {
|
|
|
701
703
|
type OfflineSyncChangeset,
|
|
702
704
|
type OfflineSyncConflict,
|
|
703
705
|
type OfflineSyncFileRecord,
|
|
706
|
+
type OfflineSyncFileContentChunk,
|
|
704
707
|
type OfflineSyncFileState,
|
|
705
708
|
type OfflineSyncFileTarget,
|
|
706
709
|
type OfflineSyncFileWriteTarget,
|
package/src/offline-sync.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
2
3
|
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
4
|
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
buildOfflineSyncChangeset,
|
|
11
12
|
buildOfflineSyncSnapshot,
|
|
12
13
|
buildOfflineSyncSnapshotForPaths,
|
|
14
|
+
readOfflineSyncFileContentChunk,
|
|
13
15
|
} from "./offline-sync.js";
|
|
14
16
|
import { isEncryptedFile } from "./secure-store/secure-fs.js";
|
|
15
17
|
import { StorageManager } from "./storage.js";
|
|
@@ -39,6 +41,9 @@ test("offline snapshot captures source-of-truth files and excludes private/inter
|
|
|
39
41
|
await write(root, ".offline-sync/state/local.json", "state");
|
|
40
42
|
await write(root, "state/fact-hashes.txt", "derived");
|
|
41
43
|
await write(root, "state/fact-hashes.ready", "v1");
|
|
44
|
+
await write(root, "state/lcm.sqlite", "live db");
|
|
45
|
+
await write(root, "state/lcm.sqlite-shm", "live shm");
|
|
46
|
+
await write(root, "state/lcm.sqlite-wal", "live wal");
|
|
42
47
|
|
|
43
48
|
const snapshot = await buildOfflineSyncSnapshot({
|
|
44
49
|
root,
|
|
@@ -68,6 +73,82 @@ test("offline snapshot captures source-of-truth files and excludes private/inter
|
|
|
68
73
|
}
|
|
69
74
|
});
|
|
70
75
|
|
|
76
|
+
test("offline sync excludes live LCM sqlite artifacts without deleting existing local copies", async () => {
|
|
77
|
+
const root = await tempDir("remnic-offline-lcm-sqlite");
|
|
78
|
+
try {
|
|
79
|
+
await write(root, "facts/a.md", "alpha");
|
|
80
|
+
await write(root, "state/lcm.sqlite", "live db");
|
|
81
|
+
await write(root, "state/lcm.sqlite-shm", "live shm");
|
|
82
|
+
await write(root, "state/lcm.sqlite-wal", "live wal");
|
|
83
|
+
|
|
84
|
+
const snapshot = await buildOfflineSyncSnapshot({
|
|
85
|
+
root,
|
|
86
|
+
sourceId: "remote",
|
|
87
|
+
includeContent: true,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
assert.deepEqual(snapshot.files.map((file) => file.path), ["facts/a.md"]);
|
|
91
|
+
await assert.rejects(
|
|
92
|
+
() =>
|
|
93
|
+
buildOfflineSyncSnapshotForPaths({
|
|
94
|
+
root,
|
|
95
|
+
sourceId: "remote",
|
|
96
|
+
paths: ["state/lcm.sqlite"],
|
|
97
|
+
includeContent: true,
|
|
98
|
+
}),
|
|
99
|
+
/offline sync snapshot path is excluded: state\/lcm\.sqlite/,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const oldDb = Buffer.from("old live db");
|
|
103
|
+
const pull = await applyOfflineSyncSnapshot({
|
|
104
|
+
root,
|
|
105
|
+
snapshot,
|
|
106
|
+
baseFiles: [{
|
|
107
|
+
path: "state/lcm.sqlite",
|
|
108
|
+
sha256: createHash("sha256").update(oldDb).digest("hex"),
|
|
109
|
+
bytes: oldDb.byteLength,
|
|
110
|
+
mtimeMs: 0,
|
|
111
|
+
}],
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
assert.equal(pull.deleted, 0);
|
|
115
|
+
assert.equal(await readUtf8(root, "state/lcm.sqlite"), "live db");
|
|
116
|
+
} finally {
|
|
117
|
+
await rm(root, { recursive: true, force: true });
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("offline sync reads bounded file content chunks with metadata", async () => {
|
|
122
|
+
const root = await tempDir("remnic-offline-file-content");
|
|
123
|
+
try {
|
|
124
|
+
await write(root, "state/memory-lifecycle-ledger.jsonl", "alpha\nbeta\ngamma\n");
|
|
125
|
+
|
|
126
|
+
const chunk = await readOfflineSyncFileContentChunk({
|
|
127
|
+
root,
|
|
128
|
+
path: "state/memory-lifecycle-ledger.jsonl",
|
|
129
|
+
offset: 6,
|
|
130
|
+
length: 5,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
assert.equal(chunk.path, "state/memory-lifecycle-ledger.jsonl");
|
|
134
|
+
assert.equal(chunk.offset, 6);
|
|
135
|
+
assert.equal(chunk.chunkBytes, 5);
|
|
136
|
+
assert.equal(chunk.content.toString("utf-8"), "beta\n");
|
|
137
|
+
assert.equal(chunk.bytes, Buffer.byteLength("alpha\nbeta\ngamma\n"));
|
|
138
|
+
|
|
139
|
+
await assert.rejects(
|
|
140
|
+
() =>
|
|
141
|
+
readOfflineSyncFileContentChunk({
|
|
142
|
+
root,
|
|
143
|
+
path: "state/lcm.sqlite",
|
|
144
|
+
}),
|
|
145
|
+
/offline sync file content path is excluded: state\/lcm\.sqlite/,
|
|
146
|
+
);
|
|
147
|
+
} finally {
|
|
148
|
+
await rm(root, { recursive: true, force: true });
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
71
152
|
test("offline changeset pushes local edits when the remote is still at the shared base", async () => {
|
|
72
153
|
const remote = await tempDir("remnic-offline-remote");
|
|
73
154
|
const local = await tempDir("remnic-offline-local");
|