@remnic/core 9.3.663 → 9.3.665
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 +25 -23
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.js +20 -18
- package/dist/access-mcp.js +19 -17
- package/dist/access-schema.d.ts +36 -36
- package/dist/access-schema.js +4 -3
- package/dist/access-service.js +17 -15
- package/dist/briefing.js +5 -4
- package/dist/{capsule-merge-T2JRE46P.js → capsule-merge-GK5E647P.js} +3 -2
- package/dist/{capsule-merge-T2JRE46P.js.map → capsule-merge-GK5E647P.js.map} +1 -1
- package/dist/causal-consolidation.js +6 -5
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/{chunk-2KDQI363.js → chunk-2HEZXPYU.js} +4 -4
- package/dist/{chunk-HSCJYHYV.js → chunk-2OPARZ4B.js} +49 -19
- package/dist/chunk-2OPARZ4B.js.map +1 -0
- package/dist/chunk-5GPPACXK.js +16 -0
- package/dist/chunk-5GPPACXK.js.map +1 -0
- package/dist/{chunk-F6O7IOS3.js → chunk-6JBKHTQD.js} +2 -2
- package/dist/{chunk-YYQRVNSV.js → chunk-7C4MPEPE.js} +6 -6
- package/dist/{chunk-AL4RAJL5.js → chunk-7XH7VJN4.js} +6 -4
- package/dist/chunk-7XH7VJN4.js.map +1 -0
- package/dist/{chunk-Q4CAQGKQ.js → chunk-AER6MT24.js} +12 -21
- package/dist/chunk-AER6MT24.js.map +1 -0
- package/dist/{chunk-DHGSZ3UD.js → chunk-ARV3AUOM.js} +2 -2
- package/dist/{chunk-PXVFMQLD.js → chunk-BZG2CWOQ.js} +3 -3
- package/dist/{chunk-ANJOULTP.js → chunk-C7AF236A.js} +2 -2
- package/dist/{chunk-TBLGI2LT.js → chunk-D7IXTY5E.js} +31 -4
- package/dist/chunk-D7IXTY5E.js.map +1 -0
- package/dist/{chunk-FZC2WSDB.js → chunk-DOCTITOP.js} +2 -2
- package/dist/{chunk-WOQIHC67.js → chunk-DQY7NJ5L.js} +2 -2
- package/dist/{chunk-NMPEJV5M.js → chunk-DSLUOQDY.js} +2 -2
- package/dist/{chunk-A7EF2XRO.js → chunk-EXXBA5OM.js} +30 -8
- package/dist/chunk-EXXBA5OM.js.map +1 -0
- package/dist/{chunk-QXHBWFR3.js → chunk-IHG6CC7T.js} +2 -2
- package/dist/{chunk-4KDLCMLK.js → chunk-IROWLAWG.js} +5 -5
- package/dist/{chunk-ILXTATKK.js → chunk-J2HSAU72.js} +5 -5
- package/dist/chunk-J2HSAU72.js.map +1 -0
- package/dist/{chunk-DFAXGZKI.js → chunk-JIX3ZL2J.js} +8 -8
- package/dist/{chunk-GY3V3SUI.js → chunk-KHGE6PMF.js} +2 -2
- package/dist/{chunk-TWAJICBN.js → chunk-OHJFJ4HI.js} +2 -2
- package/dist/{chunk-WSQG37DV.js → chunk-OUWAQVDJ.js} +2 -2
- package/dist/{chunk-ZLDUQWT2.js → chunk-PWWWLD7D.js} +2 -2
- package/dist/{chunk-ZJH723NM.js → chunk-Q5ZU3RNY.js} +2 -2
- package/dist/{chunk-35HP3TGR.js → chunk-ROHLEUTH.js} +4 -4
- package/dist/{chunk-5RIRL3XL.js → chunk-RS25QOKZ.js} +2 -2
- package/dist/{chunk-RQGR3ETH.js → chunk-T2AN3BSP.js} +2 -2
- package/dist/{chunk-UAU5U5ML.js → chunk-UDJLF3BO.js} +2 -2
- package/dist/{chunk-ALEPI75L.js → chunk-VF4XKTX3.js} +6 -4
- package/dist/{chunk-ALEPI75L.js.map → chunk-VF4XKTX3.js.map} +1 -1
- package/dist/{chunk-AX5O25EF.js → chunk-VH6EIKVS.js} +152 -190
- package/dist/chunk-VH6EIKVS.js.map +1 -0
- package/dist/chunk-VS2IYZRU.js +43 -0
- package/dist/chunk-VS2IYZRU.js.map +1 -0
- package/dist/{chunk-TGOOJCGA.js → chunk-WH4SKYPX.js} +76 -54
- package/dist/chunk-WH4SKYPX.js.map +1 -0
- package/dist/{chunk-5AYAZN45.js → chunk-XRSIGVTS.js} +5 -5
- package/dist/{chunk-D2EFNQMY.js → chunk-XW3W4PV4.js} +2 -2
- package/dist/{chunk-TYIXG4VR.js → chunk-YW52BQSU.js} +2 -2
- package/dist/{cli-C6twwe84.d.ts → cli-BQRqR9N-.d.ts} +12 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +32 -28
- package/dist/compounding/engine.js +5 -4
- package/dist/connectors/codex-materialize-runner.js +5 -4
- package/dist/connectors/index.js +5 -4
- package/dist/consolidation-provenance-check.js +3 -2
- package/dist/consolidation-undo.js +2 -1
- package/dist/consolidation-undo.js.map +1 -1
- package/dist/entity-retrieval.js +5 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +39 -36
- package/dist/index.js.map +1 -1
- package/dist/maintenance/memory-governance.js +6 -4
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +5 -4
- package/dist/maintenance/rebuild-memory-projection.js +7 -5
- package/dist/namespaces/migrate.js +13 -11
- package/dist/namespaces/search.js +8 -6
- package/dist/namespaces/storage.d.ts +13 -0
- package/dist/namespaces/storage.js +5 -4
- package/dist/offline-sync.js +3 -2
- package/dist/operator-toolkit.js +16 -14
- package/dist/orchestrator.js +21 -19
- package/dist/page-versioning.js +2 -1
- package/dist/schemas.d.ts +64 -64
- package/dist/search/document-scanner.d.ts +11 -7
- package/dist/search/document-scanner.js +3 -1
- package/dist/search/factory.js +7 -5
- package/dist/search/index.js +7 -5
- package/dist/search/lancedb-backend.js +4 -2
- package/dist/search/meilisearch-backend.js +4 -2
- package/dist/search/orama-backend.js +4 -2
- package/dist/secure-store/index.js +3 -2
- package/dist/semantic-consolidation.js +6 -5
- package/dist/semantic-rule-promotion.js +5 -4
- package/dist/semantic-rule-verifier.js +5 -4
- package/dist/shared-context/manager.d.ts +2 -2
- package/dist/storage.d.ts +17 -3
- package/dist/storage.js +4 -3
- package/dist/transfer/capsule-import.js +3 -2
- package/dist/transfer/types.d.ts +12 -12
- package/dist/verified-recall.js +5 -4
- package/package.json +1 -1
- package/src/cli.ts +62 -23
- package/src/consolidation-provenance-check.ts +7 -6
- package/src/maintenance/memory-governance.ts +47 -7
- package/src/namespaces/catalog.test.ts +12 -12
- package/src/namespaces/storage.ts +28 -1
- package/src/orchestrator.ts +84 -58
- package/src/page-versioning.ts +7 -4
- package/src/search/document-scanner.test.ts +29 -0
- package/src/search/document-scanner.ts +17 -29
- package/src/secure-store/secure-fs.ts +19 -5
- package/src/secure-store/secure-store.test.ts +28 -0
- package/src/storage.ts +42 -43
- package/src/training-export/converter.test.ts +19 -0
- package/src/training-export/converter.ts +8 -5
- package/src/utils/category-dir.ts +10 -4
- package/src/utils/path-containment.ts +40 -0
- package/dist/chunk-A7EF2XRO.js.map +0 -1
- package/dist/chunk-AL4RAJL5.js.map +0 -1
- package/dist/chunk-AX5O25EF.js.map +0 -1
- package/dist/chunk-HSCJYHYV.js.map +0 -1
- package/dist/chunk-ILXTATKK.js.map +0 -1
- package/dist/chunk-Q4CAQGKQ.js.map +0 -1
- package/dist/chunk-TBLGI2LT.js.map +0 -1
- package/dist/chunk-TGOOJCGA.js.map +0 -1
- /package/dist/{chunk-2KDQI363.js.map → chunk-2HEZXPYU.js.map} +0 -0
- /package/dist/{chunk-F6O7IOS3.js.map → chunk-6JBKHTQD.js.map} +0 -0
- /package/dist/{chunk-YYQRVNSV.js.map → chunk-7C4MPEPE.js.map} +0 -0
- /package/dist/{chunk-DHGSZ3UD.js.map → chunk-ARV3AUOM.js.map} +0 -0
- /package/dist/{chunk-PXVFMQLD.js.map → chunk-BZG2CWOQ.js.map} +0 -0
- /package/dist/{chunk-ANJOULTP.js.map → chunk-C7AF236A.js.map} +0 -0
- /package/dist/{chunk-FZC2WSDB.js.map → chunk-DOCTITOP.js.map} +0 -0
- /package/dist/{chunk-WOQIHC67.js.map → chunk-DQY7NJ5L.js.map} +0 -0
- /package/dist/{chunk-NMPEJV5M.js.map → chunk-DSLUOQDY.js.map} +0 -0
- /package/dist/{chunk-QXHBWFR3.js.map → chunk-IHG6CC7T.js.map} +0 -0
- /package/dist/{chunk-4KDLCMLK.js.map → chunk-IROWLAWG.js.map} +0 -0
- /package/dist/{chunk-DFAXGZKI.js.map → chunk-JIX3ZL2J.js.map} +0 -0
- /package/dist/{chunk-GY3V3SUI.js.map → chunk-KHGE6PMF.js.map} +0 -0
- /package/dist/{chunk-TWAJICBN.js.map → chunk-OHJFJ4HI.js.map} +0 -0
- /package/dist/{chunk-WSQG37DV.js.map → chunk-OUWAQVDJ.js.map} +0 -0
- /package/dist/{chunk-ZLDUQWT2.js.map → chunk-PWWWLD7D.js.map} +0 -0
- /package/dist/{chunk-ZJH723NM.js.map → chunk-Q5ZU3RNY.js.map} +0 -0
- /package/dist/{chunk-35HP3TGR.js.map → chunk-ROHLEUTH.js.map} +0 -0
- /package/dist/{chunk-5RIRL3XL.js.map → chunk-RS25QOKZ.js.map} +0 -0
- /package/dist/{chunk-RQGR3ETH.js.map → chunk-T2AN3BSP.js.map} +0 -0
- /package/dist/{chunk-UAU5U5ML.js.map → chunk-UDJLF3BO.js.map} +0 -0
- /package/dist/{chunk-5AYAZN45.js.map → chunk-XRSIGVTS.js.map} +0 -0
- /package/dist/{chunk-D2EFNQMY.js.map → chunk-XW3W4PV4.js.map} +0 -0
- /package/dist/{chunk-TYIXG4VR.js.map → chunk-YW52BQSU.js.map} +0 -0
package/dist/access-schema.d.ts
CHANGED
|
@@ -104,9 +104,9 @@ declare const recallRequestSchema: z.ZodObject<{
|
|
|
104
104
|
includeLowConfidence: z.ZodOptional<z.ZodBoolean>;
|
|
105
105
|
}, "strip", z.ZodTypeAny, {
|
|
106
106
|
query: string;
|
|
107
|
+
namespace?: string | undefined;
|
|
107
108
|
sessionKey?: string | undefined;
|
|
108
109
|
tags?: string[] | undefined;
|
|
109
|
-
namespace?: string | undefined;
|
|
110
110
|
topK?: number | undefined;
|
|
111
111
|
mode?: "auto" | "no_recall" | "minimal" | "full" | "graph_mode" | undefined;
|
|
112
112
|
cwd?: string | undefined;
|
|
@@ -125,9 +125,9 @@ declare const recallRequestSchema: z.ZodObject<{
|
|
|
125
125
|
tagMatch?: "all" | "any" | undefined;
|
|
126
126
|
}, {
|
|
127
127
|
query: string;
|
|
128
|
+
namespace?: string | undefined;
|
|
128
129
|
sessionKey?: string | undefined;
|
|
129
130
|
tags?: string[] | undefined;
|
|
130
|
-
namespace?: string | undefined;
|
|
131
131
|
topK?: number | undefined;
|
|
132
132
|
mode?: "auto" | "no_recall" | "minimal" | "full" | "graph_mode" | undefined;
|
|
133
133
|
cwd?: string | undefined;
|
|
@@ -149,11 +149,11 @@ declare const recallExplainRequestSchema: z.ZodObject<{
|
|
|
149
149
|
sessionKey: z.ZodOptional<z.ZodString>;
|
|
150
150
|
namespace: z.ZodOptional<z.ZodString>;
|
|
151
151
|
}, "strip", z.ZodTypeAny, {
|
|
152
|
-
sessionKey?: string | undefined;
|
|
153
152
|
namespace?: string | undefined;
|
|
154
|
-
}, {
|
|
155
153
|
sessionKey?: string | undefined;
|
|
154
|
+
}, {
|
|
156
155
|
namespace?: string | undefined;
|
|
156
|
+
sessionKey?: string | undefined;
|
|
157
157
|
}>;
|
|
158
158
|
/**
|
|
159
159
|
* Standalone "set coding context" request. Used by the HTTP endpoint
|
|
@@ -365,30 +365,30 @@ declare const memoryStoreRequestSchema: z.ZodObject<{
|
|
|
365
365
|
projectTag: z.ZodOptional<z.ZodString>;
|
|
366
366
|
}, "strip", z.ZodTypeAny, {
|
|
367
367
|
content: string;
|
|
368
|
+
namespace?: string | undefined;
|
|
369
|
+
category?: "fact" | "preference" | "correction" | "entity" | "decision" | "relationship" | "principle" | "commitment" | "moment" | "skill" | "rule" | "procedure" | "reasoning_trace" | undefined;
|
|
370
|
+
confidence?: number | undefined;
|
|
371
|
+
ttl?: string | undefined;
|
|
368
372
|
schemaVersion?: number | undefined;
|
|
369
373
|
sessionKey?: string | undefined;
|
|
370
374
|
tags?: string[] | undefined;
|
|
371
375
|
dryRun?: boolean | undefined;
|
|
372
|
-
namespace?: string | undefined;
|
|
373
|
-
category?: "fact" | "preference" | "correction" | "entity" | "decision" | "relationship" | "principle" | "commitment" | "moment" | "skill" | "rule" | "procedure" | "reasoning_trace" | undefined;
|
|
374
|
-
confidence?: number | undefined;
|
|
375
376
|
entityRef?: string | undefined;
|
|
376
|
-
ttl?: string | undefined;
|
|
377
377
|
sourceReason?: string | undefined;
|
|
378
378
|
cwd?: string | undefined;
|
|
379
379
|
idempotencyKey?: string | undefined;
|
|
380
380
|
projectTag?: string | undefined;
|
|
381
381
|
}, {
|
|
382
382
|
content: string;
|
|
383
|
+
namespace?: string | undefined;
|
|
384
|
+
category?: "fact" | "preference" | "correction" | "entity" | "decision" | "relationship" | "principle" | "commitment" | "moment" | "skill" | "rule" | "procedure" | "reasoning_trace" | undefined;
|
|
385
|
+
confidence?: number | undefined;
|
|
386
|
+
ttl?: string | undefined;
|
|
383
387
|
schemaVersion?: number | undefined;
|
|
384
388
|
sessionKey?: string | undefined;
|
|
385
389
|
tags?: string[] | undefined;
|
|
386
390
|
dryRun?: boolean | undefined;
|
|
387
|
-
namespace?: string | undefined;
|
|
388
|
-
category?: "fact" | "preference" | "correction" | "entity" | "decision" | "relationship" | "principle" | "commitment" | "moment" | "skill" | "rule" | "procedure" | "reasoning_trace" | undefined;
|
|
389
|
-
confidence?: number | undefined;
|
|
390
391
|
entityRef?: string | undefined;
|
|
391
|
-
ttl?: string | undefined;
|
|
392
392
|
sourceReason?: string | undefined;
|
|
393
393
|
cwd?: string | undefined;
|
|
394
394
|
idempotencyKey?: string | undefined;
|
|
@@ -411,30 +411,30 @@ declare const suggestionSubmitRequestSchema: z.ZodObject<{
|
|
|
411
411
|
projectTag: z.ZodOptional<z.ZodString>;
|
|
412
412
|
}, "strip", z.ZodTypeAny, {
|
|
413
413
|
content: string;
|
|
414
|
+
namespace?: string | undefined;
|
|
415
|
+
category?: "fact" | "preference" | "correction" | "entity" | "decision" | "relationship" | "principle" | "commitment" | "moment" | "skill" | "rule" | "procedure" | "reasoning_trace" | undefined;
|
|
416
|
+
confidence?: number | undefined;
|
|
417
|
+
ttl?: string | undefined;
|
|
414
418
|
schemaVersion?: number | undefined;
|
|
415
419
|
sessionKey?: string | undefined;
|
|
416
420
|
tags?: string[] | undefined;
|
|
417
421
|
dryRun?: boolean | undefined;
|
|
418
|
-
namespace?: string | undefined;
|
|
419
|
-
category?: "fact" | "preference" | "correction" | "entity" | "decision" | "relationship" | "principle" | "commitment" | "moment" | "skill" | "rule" | "procedure" | "reasoning_trace" | undefined;
|
|
420
|
-
confidence?: number | undefined;
|
|
421
422
|
entityRef?: string | undefined;
|
|
422
|
-
ttl?: string | undefined;
|
|
423
423
|
sourceReason?: string | undefined;
|
|
424
424
|
cwd?: string | undefined;
|
|
425
425
|
idempotencyKey?: string | undefined;
|
|
426
426
|
projectTag?: string | undefined;
|
|
427
427
|
}, {
|
|
428
428
|
content: string;
|
|
429
|
+
namespace?: string | undefined;
|
|
430
|
+
category?: "fact" | "preference" | "correction" | "entity" | "decision" | "relationship" | "principle" | "commitment" | "moment" | "skill" | "rule" | "procedure" | "reasoning_trace" | undefined;
|
|
431
|
+
confidence?: number | undefined;
|
|
432
|
+
ttl?: string | undefined;
|
|
429
433
|
schemaVersion?: number | undefined;
|
|
430
434
|
sessionKey?: string | undefined;
|
|
431
435
|
tags?: string[] | undefined;
|
|
432
436
|
dryRun?: boolean | undefined;
|
|
433
|
-
namespace?: string | undefined;
|
|
434
|
-
category?: "fact" | "preference" | "correction" | "entity" | "decision" | "relationship" | "principle" | "commitment" | "moment" | "skill" | "rule" | "procedure" | "reasoning_trace" | undefined;
|
|
435
|
-
confidence?: number | undefined;
|
|
436
437
|
entityRef?: string | undefined;
|
|
437
|
-
ttl?: string | undefined;
|
|
438
438
|
sourceReason?: string | undefined;
|
|
439
439
|
cwd?: string | undefined;
|
|
440
440
|
idempotencyKey?: string | undefined;
|
|
@@ -468,18 +468,18 @@ declare const trustZonePromoteRequestSchema: z.ZodObject<{
|
|
|
468
468
|
recordId: string;
|
|
469
469
|
targetZone: "working" | "trusted";
|
|
470
470
|
promotionReason: string;
|
|
471
|
+
namespace?: string | undefined;
|
|
471
472
|
recordedAt?: string | undefined;
|
|
472
473
|
summary?: string | undefined;
|
|
473
474
|
dryRun?: boolean | undefined;
|
|
474
|
-
namespace?: string | undefined;
|
|
475
475
|
}, {
|
|
476
476
|
recordId: string;
|
|
477
477
|
targetZone: "working" | "trusted";
|
|
478
478
|
promotionReason: string;
|
|
479
|
+
namespace?: string | undefined;
|
|
479
480
|
recordedAt?: string | undefined;
|
|
480
481
|
summary?: string | undefined;
|
|
481
482
|
dryRun?: boolean | undefined;
|
|
482
|
-
namespace?: string | undefined;
|
|
483
483
|
}>;
|
|
484
484
|
declare const trustZoneDemoSeedRequestSchema: z.ZodObject<{
|
|
485
485
|
scenario: z.ZodOptional<z.ZodString>;
|
|
@@ -487,14 +487,14 @@ declare const trustZoneDemoSeedRequestSchema: z.ZodObject<{
|
|
|
487
487
|
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
488
488
|
namespace: z.ZodOptional<z.ZodString>;
|
|
489
489
|
}, "strip", z.ZodTypeAny, {
|
|
490
|
+
namespace?: string | undefined;
|
|
490
491
|
recordedAt?: string | undefined;
|
|
491
492
|
dryRun?: boolean | undefined;
|
|
492
|
-
namespace?: string | undefined;
|
|
493
493
|
scenario?: string | undefined;
|
|
494
494
|
}, {
|
|
495
|
+
namespace?: string | undefined;
|
|
495
496
|
recordedAt?: string | undefined;
|
|
496
497
|
dryRun?: boolean | undefined;
|
|
497
|
-
namespace?: string | undefined;
|
|
498
498
|
scenario?: string | undefined;
|
|
499
499
|
}>;
|
|
500
500
|
declare const lcmSearchRequestSchema: z.ZodObject<{
|
|
@@ -505,15 +505,15 @@ declare const lcmSearchRequestSchema: z.ZodObject<{
|
|
|
505
505
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
506
506
|
}, "strip", z.ZodTypeAny, {
|
|
507
507
|
query: string;
|
|
508
|
-
sessionKey?: string | undefined;
|
|
509
508
|
namespace?: string | undefined;
|
|
510
509
|
limit?: number | undefined;
|
|
510
|
+
sessionKey?: string | undefined;
|
|
511
511
|
sessionPrefix?: string | undefined;
|
|
512
512
|
}, {
|
|
513
513
|
query: string;
|
|
514
|
-
sessionKey?: string | undefined;
|
|
515
514
|
namespace?: string | undefined;
|
|
516
515
|
limit?: number | undefined;
|
|
516
|
+
sessionKey?: string | undefined;
|
|
517
517
|
sessionPrefix?: string | undefined;
|
|
518
518
|
}>;
|
|
519
519
|
declare const lcmCompactionFlushRequestSchema: z.ZodObject<{
|
|
@@ -548,14 +548,14 @@ declare const daySummaryRequestSchema: z.ZodObject<{
|
|
|
548
548
|
namespace: z.ZodOptional<z.ZodString>;
|
|
549
549
|
timeZone: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
550
550
|
}, "strip", z.ZodTypeAny, {
|
|
551
|
+
namespace?: string | undefined;
|
|
551
552
|
sessionKey?: string | undefined;
|
|
552
553
|
timeZone?: string | undefined;
|
|
553
|
-
namespace?: string | undefined;
|
|
554
554
|
memories?: string | undefined;
|
|
555
555
|
}, {
|
|
556
|
+
namespace?: string | undefined;
|
|
556
557
|
sessionKey?: string | undefined;
|
|
557
558
|
timeZone?: string | undefined;
|
|
558
|
-
namespace?: string | undefined;
|
|
559
559
|
memories?: string | undefined;
|
|
560
560
|
}>;
|
|
561
561
|
declare const capsuleExportRequestSchema: z.ZodObject<{
|
|
@@ -603,11 +603,11 @@ declare const capsuleListRequestSchema: z.ZodObject<{
|
|
|
603
603
|
namespace: z.ZodOptional<z.ZodString>;
|
|
604
604
|
sessionKey: z.ZodOptional<z.ZodString>;
|
|
605
605
|
}, "strip", z.ZodTypeAny, {
|
|
606
|
-
sessionKey?: string | undefined;
|
|
607
606
|
namespace?: string | undefined;
|
|
608
|
-
}, {
|
|
609
607
|
sessionKey?: string | undefined;
|
|
608
|
+
}, {
|
|
610
609
|
namespace?: string | undefined;
|
|
610
|
+
sessionKey?: string | undefined;
|
|
611
611
|
}>;
|
|
612
612
|
declare const offlineSyncSnapshotRequestSchema: z.ZodObject<{
|
|
613
613
|
namespace: z.ZodOptional<z.ZodString>;
|
|
@@ -748,11 +748,11 @@ declare const actionConfidenceRequestSchema: z.ZodObject<{
|
|
|
748
748
|
safety: z.ZodEffects<z.ZodNullable<z.ZodOptional<z.ZodEnum<["safe", "requires-review", "blocked"]>>>, NonNullable<"blocked" | "safe" | "requires-review"> | undefined, "blocked" | "safe" | "requires-review" | null | undefined>;
|
|
749
749
|
safetyReasons: z.ZodEffects<z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>, string[] | undefined, string[] | null | undefined>;
|
|
750
750
|
}, "strict", z.ZodTypeAny, {
|
|
751
|
+
confidence?: number | undefined;
|
|
751
752
|
source?: string | undefined;
|
|
752
753
|
stale?: boolean | undefined;
|
|
753
754
|
created?: string | undefined;
|
|
754
755
|
updated?: string | undefined;
|
|
755
|
-
confidence?: number | undefined;
|
|
756
756
|
scope?: string | undefined;
|
|
757
757
|
retrievalReason?: string | undefined;
|
|
758
758
|
safety?: NonNullable<"blocked" | "safe" | "requires-review"> | undefined;
|
|
@@ -762,11 +762,11 @@ declare const actionConfidenceRequestSchema: z.ZodObject<{
|
|
|
762
762
|
safetyReasons?: string[] | undefined;
|
|
763
763
|
userContextScopes?: string[] | undefined;
|
|
764
764
|
}, {
|
|
765
|
+
confidence?: number | null | undefined;
|
|
765
766
|
source?: string | null | undefined;
|
|
766
767
|
stale?: boolean | null | undefined;
|
|
767
768
|
created?: string | null | undefined;
|
|
768
769
|
updated?: string | null | undefined;
|
|
769
|
-
confidence?: number | null | undefined;
|
|
770
770
|
scope?: string | null | undefined;
|
|
771
771
|
retrievalReason?: string | null | undefined;
|
|
772
772
|
safety?: "blocked" | "safe" | "requires-review" | null | undefined;
|
|
@@ -776,11 +776,11 @@ declare const actionConfidenceRequestSchema: z.ZodObject<{
|
|
|
776
776
|
safetyReasons?: string[] | null | undefined;
|
|
777
777
|
userContextScopes?: string[] | null | undefined;
|
|
778
778
|
}>, "many">>>, {
|
|
779
|
+
confidence?: number | undefined;
|
|
779
780
|
source?: string | undefined;
|
|
780
781
|
stale?: boolean | undefined;
|
|
781
782
|
created?: string | undefined;
|
|
782
783
|
updated?: string | undefined;
|
|
783
|
-
confidence?: number | undefined;
|
|
784
784
|
scope?: string | undefined;
|
|
785
785
|
retrievalReason?: string | undefined;
|
|
786
786
|
safety?: NonNullable<"blocked" | "safe" | "requires-review"> | undefined;
|
|
@@ -790,11 +790,11 @@ declare const actionConfidenceRequestSchema: z.ZodObject<{
|
|
|
790
790
|
safetyReasons?: string[] | undefined;
|
|
791
791
|
userContextScopes?: string[] | undefined;
|
|
792
792
|
}[] | undefined, {
|
|
793
|
+
confidence?: number | null | undefined;
|
|
793
794
|
source?: string | null | undefined;
|
|
794
795
|
stale?: boolean | null | undefined;
|
|
795
796
|
created?: string | null | undefined;
|
|
796
797
|
updated?: string | null | undefined;
|
|
797
|
-
confidence?: number | null | undefined;
|
|
798
798
|
scope?: string | null | undefined;
|
|
799
799
|
retrievalReason?: string | null | undefined;
|
|
800
800
|
safety?: "blocked" | "safe" | "requires-review" | null | undefined;
|
|
@@ -816,11 +816,11 @@ declare const actionConfidenceRequestSchema: z.ZodObject<{
|
|
|
816
816
|
matched?: boolean | undefined;
|
|
817
817
|
}[] | undefined;
|
|
818
818
|
retrievedMemories?: {
|
|
819
|
+
confidence?: number | undefined;
|
|
819
820
|
source?: string | undefined;
|
|
820
821
|
stale?: boolean | undefined;
|
|
821
822
|
created?: string | undefined;
|
|
822
823
|
updated?: string | undefined;
|
|
823
|
-
confidence?: number | undefined;
|
|
824
824
|
scope?: string | undefined;
|
|
825
825
|
retrievalReason?: string | undefined;
|
|
826
826
|
safety?: NonNullable<"blocked" | "safe" | "requires-review"> | undefined;
|
|
@@ -842,11 +842,11 @@ declare const actionConfidenceRequestSchema: z.ZodObject<{
|
|
|
842
842
|
matched?: boolean | null | undefined;
|
|
843
843
|
}[] | null | undefined;
|
|
844
844
|
retrievedMemories?: {
|
|
845
|
+
confidence?: number | null | undefined;
|
|
845
846
|
source?: string | null | undefined;
|
|
846
847
|
stale?: boolean | null | undefined;
|
|
847
848
|
created?: string | null | undefined;
|
|
848
849
|
updated?: string | null | undefined;
|
|
849
|
-
confidence?: number | null | undefined;
|
|
850
850
|
scope?: string | null | undefined;
|
|
851
851
|
retrievalReason?: string | null | undefined;
|
|
852
852
|
safety?: "blocked" | "safe" | "requires-review" | null | undefined;
|
package/dist/access-schema.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
trustZoneDemoSeedRequestSchema,
|
|
26
26
|
trustZonePromoteRequestSchema,
|
|
27
27
|
validateRequest
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-UDJLF3BO.js";
|
|
29
29
|
import "./chunk-KQAFEZQX.js";
|
|
30
30
|
import "./chunk-WEHSQBFR.js";
|
|
31
31
|
import "./chunk-X7Y7WX73.js";
|
|
@@ -33,12 +33,13 @@ import "./chunk-J4EB7DNW.js";
|
|
|
33
33
|
import "./chunk-BJMBJZ2Y.js";
|
|
34
34
|
import "./chunk-UKJAGEXH.js";
|
|
35
35
|
import "./chunk-FP2373TW.js";
|
|
36
|
-
import "./chunk-
|
|
36
|
+
import "./chunk-PWWWLD7D.js";
|
|
37
37
|
import "./chunk-UI3NYK34.js";
|
|
38
38
|
import "./chunk-GCGJW34D.js";
|
|
39
|
-
import "./chunk-
|
|
39
|
+
import "./chunk-J2HSAU72.js";
|
|
40
40
|
import "./chunk-A6XUJE5D.js";
|
|
41
41
|
import "./chunk-P7FMDTKL.js";
|
|
42
|
+
import "./chunk-VS2IYZRU.js";
|
|
42
43
|
import "./chunk-AH2JUU6X.js";
|
|
43
44
|
import "./chunk-AC5LO7IU.js";
|
|
44
45
|
import "./chunk-SOAU2OE2.js";
|
package/dist/access-service.js
CHANGED
|
@@ -3,31 +3,32 @@ import {
|
|
|
3
3
|
EngramAccessInputError,
|
|
4
4
|
EngramAccessService,
|
|
5
5
|
shapeMemorySummary
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JIX3ZL2J.js";
|
|
7
7
|
import "./chunk-GDASG7NC.js";
|
|
8
8
|
import "./chunk-GDB4J2H3.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-ARV3AUOM.js";
|
|
10
10
|
import "./chunk-H7XKCNR6.js";
|
|
11
11
|
import "./chunk-TIJYQXDI.js";
|
|
12
12
|
import "./chunk-SOBJ6NEY.js";
|
|
13
13
|
import "./chunk-BT7NVCML.js";
|
|
14
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-EXXBA5OM.js";
|
|
15
15
|
import "./chunk-GYSYLGNE.js";
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-RS25QOKZ.js";
|
|
17
17
|
import "./chunk-JGSKJHF7.js";
|
|
18
18
|
import "./chunk-FF4KLI5W.js";
|
|
19
19
|
import "./chunk-2MXEVL75.js";
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
20
|
+
import "./chunk-DQY7NJ5L.js";
|
|
21
|
+
import "./chunk-ROHLEUTH.js";
|
|
22
|
+
import "./chunk-DOCTITOP.js";
|
|
23
23
|
import "./chunk-CYEPCZN5.js";
|
|
24
|
-
import "./chunk-
|
|
24
|
+
import "./chunk-Q5ZU3RNY.js";
|
|
25
25
|
import "./chunk-JOASJWQR.js";
|
|
26
26
|
import "./chunk-RN7MUWON.js";
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-OUWAQVDJ.js";
|
|
28
|
+
import "./chunk-AER6MT24.js";
|
|
29
29
|
import "./chunk-CINZGPSJ.js";
|
|
30
30
|
import "./chunk-ZFXCQPNO.js";
|
|
31
|
+
import "./chunk-5GPPACXK.js";
|
|
31
32
|
import "./chunk-7OGJQP7T.js";
|
|
32
33
|
import "./chunk-E6ZDCOHM.js";
|
|
33
34
|
import "./chunk-OIF36KGD.js";
|
|
@@ -49,8 +50,8 @@ import "./chunk-3ONXXHQO.js";
|
|
|
49
50
|
import "./chunk-Y56J7CXW.js";
|
|
50
51
|
import "./chunk-2LSZVONP.js";
|
|
51
52
|
import "./chunk-DEUNUKTD.js";
|
|
52
|
-
import "./chunk-
|
|
53
|
-
import "./chunk-
|
|
53
|
+
import "./chunk-KHGE6PMF.js";
|
|
54
|
+
import "./chunk-VH6EIKVS.js";
|
|
54
55
|
import "./chunk-M7XQSUBB.js";
|
|
55
56
|
import "./chunk-5UZXUTVO.js";
|
|
56
57
|
import "./chunk-J6A3CX5N.js";
|
|
@@ -65,7 +66,7 @@ import "./chunk-DM2T26WE.js";
|
|
|
65
66
|
import "./chunk-LDXUBPMO.js";
|
|
66
67
|
import "./chunk-FVQJYWH7.js";
|
|
67
68
|
import "./chunk-G7D6GZ5J.js";
|
|
68
|
-
import "./chunk-
|
|
69
|
+
import "./chunk-VF4XKTX3.js";
|
|
69
70
|
import "./chunk-RGMVMVMF.js";
|
|
70
71
|
import "./chunk-ZY2MNJR6.js";
|
|
71
72
|
import "./chunk-SSOMTUCA.js";
|
|
@@ -91,12 +92,13 @@ import "./chunk-J4EB7DNW.js";
|
|
|
91
92
|
import "./chunk-BJMBJZ2Y.js";
|
|
92
93
|
import "./chunk-UKJAGEXH.js";
|
|
93
94
|
import "./chunk-FP2373TW.js";
|
|
94
|
-
import "./chunk-
|
|
95
|
+
import "./chunk-PWWWLD7D.js";
|
|
95
96
|
import "./chunk-UI3NYK34.js";
|
|
96
97
|
import "./chunk-GCGJW34D.js";
|
|
97
|
-
import "./chunk-
|
|
98
|
+
import "./chunk-J2HSAU72.js";
|
|
98
99
|
import "./chunk-A6XUJE5D.js";
|
|
99
100
|
import "./chunk-P7FMDTKL.js";
|
|
101
|
+
import "./chunk-VS2IYZRU.js";
|
|
100
102
|
import "./chunk-AH2JUU6X.js";
|
|
101
103
|
import "./chunk-AC5LO7IU.js";
|
|
102
104
|
import "./chunk-SOAU2OE2.js";
|
package/dist/briefing.js
CHANGED
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
renderBriefingMarkdown,
|
|
18
18
|
resolveBriefingSaveDir,
|
|
19
19
|
validateBriefingFormat
|
|
20
|
-
} from "./chunk-
|
|
21
|
-
import "./chunk-
|
|
20
|
+
} from "./chunk-KHGE6PMF.js";
|
|
21
|
+
import "./chunk-VH6EIKVS.js";
|
|
22
22
|
import "./chunk-M7XQSUBB.js";
|
|
23
23
|
import "./chunk-5UZXUTVO.js";
|
|
24
24
|
import "./chunk-J6A3CX5N.js";
|
|
@@ -33,14 +33,15 @@ import "./chunk-DM2T26WE.js";
|
|
|
33
33
|
import "./chunk-LDXUBPMO.js";
|
|
34
34
|
import "./chunk-FVQJYWH7.js";
|
|
35
35
|
import "./chunk-G7D6GZ5J.js";
|
|
36
|
-
import "./chunk-
|
|
36
|
+
import "./chunk-VF4XKTX3.js";
|
|
37
37
|
import "./chunk-RGMVMVMF.js";
|
|
38
38
|
import "./chunk-4DJQYKMN.js";
|
|
39
39
|
import "./chunk-JUC24CTX.js";
|
|
40
40
|
import "./chunk-2ODBA7MQ.js";
|
|
41
|
-
import "./chunk-
|
|
41
|
+
import "./chunk-J2HSAU72.js";
|
|
42
42
|
import "./chunk-A6XUJE5D.js";
|
|
43
43
|
import "./chunk-P7FMDTKL.js";
|
|
44
|
+
import "./chunk-VS2IYZRU.js";
|
|
44
45
|
import "./chunk-PZ5AY32C.js";
|
|
45
46
|
export {
|
|
46
47
|
BRIEFING_FOLLOWUP_DEFAULT_MODEL,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createVersion
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VF4XKTX3.js";
|
|
4
4
|
import {
|
|
5
5
|
parseExportBundle
|
|
6
6
|
} from "./chunk-WEHSQBFR.js";
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
isPathInsideRoot,
|
|
12
12
|
sha256String
|
|
13
13
|
} from "./chunk-GCGJW34D.js";
|
|
14
|
+
import "./chunk-VS2IYZRU.js";
|
|
14
15
|
import "./chunk-PZ5AY32C.js";
|
|
15
16
|
|
|
16
17
|
// src/transfer/capsule-merge.ts
|
|
@@ -186,4 +187,4 @@ async function readLocalFile(absPath) {
|
|
|
186
187
|
export {
|
|
187
188
|
mergeCapsule
|
|
188
189
|
};
|
|
189
|
-
//# sourceMappingURL=capsule-merge-
|
|
190
|
+
//# sourceMappingURL=capsule-merge-GK5E647P.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/transfer/capsule-merge.ts"],"sourcesContent":["import { lstat, mkdir, readFile, realpath, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { gunzipSync } from \"node:zlib\";\nimport {\n createVersion,\n type VersioningConfig,\n type VersioningLogger,\n} from \"../page-versioning.js\";\nimport {\n assertIsDirectoryNotSymlink,\n assertRealpathInsideRoot,\n fromPosixRelPath,\n isPathInsideRoot,\n sha256String,\n} from \"./fs-utils.js\";\nimport {\n parseExportBundle,\n type CapsuleBlock,\n type ExportManifestV2,\n type ExportMemoryRecordV1,\n} from \"./types.js\";\n\n/**\n * Three-way conflict-resolution mode for {@link mergeCapsule}.\n *\n * A \"conflict\" is defined as: the same memory-file path exists in both the\n * source archive and the target directory AND the content hash of the local\n * file differs from the archive's manifest entry for that path.\n *\n * Files that exist only in the archive (no local counterpart) are always\n * written regardless of mode — there is no conflict to resolve.\n *\n * Files that are byte-identical (same content hash in both locations) are\n * recorded as {@link MergeCapsuleResult.skipped} with reason `\"identical\"` and\n * are never re-written regardless of mode; this is a no-op optimisation rather\n * than a conflict.\n *\n * - `\"skip-conflicts\"` (default) — log the conflict, skip the conflicting\n * archive entries, but continue importing non-conflicting entries. The\n * resulting merge is the union of:\n * - all non-conflicting archive files (written to target)\n * - all pre-existing local files (left unchanged)\n *\n * - `\"prefer-source\"` — for conflicting files, snapshot the local content via\n * page-versioning (gotcha #54: snapshot before overwrite) then overwrite\n * with the archive content.\n *\n * - `\"prefer-local\"` — for conflicting files, keep the local content; the\n * archive entry is skipped.\n */\nexport type MergeCapsuleConflictMode =\n | \"skip-conflicts\"\n | \"prefer-source\"\n | \"prefer-local\";\n\n/**\n * Options accepted by {@link mergeCapsule}.\n *\n * `sourceArchive` — absolute or cwd-relative path to a `.capsule.json.gz`\n * archive produced by `exportCapsule`. Must be a V2 bundle.\n *\n * `targetRoot` — absolute or cwd-relative path to the memory directory that\n * receives the merged records. Must be an existing, non-symlink directory.\n *\n * `conflictMode` — see {@link MergeCapsuleConflictMode}. Defaults to\n * `\"skip-conflicts\"`.\n *\n * `versioning` — optional page-versioning config forwarded to\n * {@link createVersion} in `\"prefer-source\"` mode. When omitted or disabled,\n * overwrites proceed without snapshotting (not recommended for production).\n *\n * `log` — optional logger forwarded to {@link createVersion}.\n */\nexport interface MergeCapsuleOptions {\n sourceArchive: string;\n targetRoot: string;\n conflictMode?: MergeCapsuleConflictMode;\n versioning?: VersioningConfig;\n log?: VersioningLogger;\n}\n\nexport interface MergeCapsuleWrittenRecord {\n /** Capsule-relative posix path. */\n sourcePath: string;\n /** Memory-dir-relative posix path written on disk. */\n targetPath: string;\n /** Whether a page-versioning snapshot was taken before overwriting. */\n snapshotted: boolean;\n}\n\nexport interface MergeCapsuleSkippedRecord {\n /** Capsule-relative posix path. */\n path: string;\n /**\n * Why the archive entry was not written.\n *\n * `\"conflict\"` — the entry existed locally with different content and the\n * active mode did not resolve the conflict with a write (`\"skip-conflicts\"` /\n * `\"prefer-local\"`).\n *\n * `\"identical\"` — the entry's content hash matches what is already on disk;\n * no write is needed.\n */\n reason: \"conflict\" | \"identical\";\n}\n\nexport interface MergeCapsuleConflictRecord {\n /** Capsule-relative posix path of the conflicting entry. */\n path: string;\n /** SHA-256 of the archive's copy. */\n archiveSha256: string;\n /** SHA-256 of the local copy. */\n localSha256: string;\n}\n\nexport interface MergeCapsuleResult {\n /** Records that were written to the target directory. */\n merged: MergeCapsuleWrittenRecord[];\n /**\n * Records that were NOT written (conflict skipped, or byte-identical).\n * Includes conflicts that were resolved by `\"prefer-local\"`.\n */\n skipped: MergeCapsuleSkippedRecord[];\n /**\n * Metadata about every detected conflict, regardless of which mode resolved\n * it. Callers can use this to report \"N conflicts encountered; M overwritten\".\n */\n conflicts: MergeCapsuleConflictRecord[];\n /** The manifest decoded from the archive. */\n manifest: ExportManifestV2;\n}\n\n// ---------------------------------------------------------------------------\n// Main entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Merge a V2 capsule archive into an existing memory directory using\n * three-way conflict semantics.\n *\n * Sequence:\n * 1. Read + gunzip + JSON.parse the archive.\n * 2. Validate through `parseExportBundle` (V1 rejected).\n * 3. Verify every record's content sha256 against the manifest.\n * Any mismatch aborts BEFORE any file is written (gotcha #25).\n * 4. Classify each record as: new (no local copy), identical (same hash),\n * or conflicting (different hash).\n * 5. Apply the selected {@link MergeCapsuleConflictMode} to conflicting\n * entries; always write new entries; always skip identical entries.\n *\n * Determinism: `merged`, `skipped`, and `conflicts` are all returned sorted\n * by `path`/`sourcePath` so callers get stable output regardless of bundle\n * order.\n */\nexport async function mergeCapsule(\n opts: MergeCapsuleOptions,\n): Promise<MergeCapsuleResult> {\n const archiveAbs = path.resolve(opts.sourceArchive);\n const rootAbs = path.resolve(opts.targetRoot);\n\n await assertIsDirectoryNotSymlink(rootAbs, \"mergeCapsule\", \"targetRoot\");\n\n const conflictMode: MergeCapsuleConflictMode =\n opts.conflictMode ?? \"skip-conflicts\";\n\n // Rule 51: reject invalid conflictMode values up-front before any I/O.\n if (\n conflictMode !== \"skip-conflicts\" &&\n conflictMode !== \"prefer-source\" &&\n conflictMode !== \"prefer-local\"\n ) {\n throw new Error(\n `mergeCapsule: unknown conflictMode ${JSON.stringify(conflictMode)}; ` +\n `expected \"skip-conflicts\", \"prefer-source\", or \"prefer-local\"`,\n );\n }\n\n // ---------------------------------------------------------------------------\n // Parse + validate archive\n // ---------------------------------------------------------------------------\n\n const raw = await readFile(archiveAbs);\n let json: string;\n try {\n json = gunzipSync(raw).toString(\"utf-8\");\n } catch (cause) {\n throw new Error(\n `mergeCapsule: archive is not a valid gzip file: ${archiveAbs}`,\n { cause: cause as Error },\n );\n }\n\n let parsedJson: unknown;\n try {\n parsedJson = JSON.parse(json);\n } catch (cause) {\n throw new Error(\n `mergeCapsule: archive is not valid JSON after gunzip: ${archiveAbs}`,\n { cause: cause as Error },\n );\n }\n\n const parsed = parseExportBundle(parsedJson);\n if (parsed.capsuleVersion !== 2) {\n throw new Error(\n \"mergeCapsule: archive is V1; only V2 capsule archives are supported\",\n );\n }\n\n const bundle = parsed.bundle as {\n manifest: ExportManifestV2;\n records: ExportMemoryRecordV1[];\n };\n const manifest = bundle.manifest;\n const capsule = manifest.capsule;\n\n // Build path → manifest entry index for O(1) checksum lookup.\n const manifestIndex = new Map<string, ExportManifestV2[\"files\"][number]>();\n for (const f of manifest.files) {\n manifestIndex.set(f.path, f);\n }\n if (manifestIndex.size !== manifest.files.length) {\n throw new Error(\"mergeCapsule: manifest contains duplicate file paths\");\n }\n\n const recordPaths = new Set<string>();\n for (const rec of bundle.records) {\n if (recordPaths.has(rec.path)) {\n throw new Error(\n `mergeCapsule: bundle contains duplicate record path: ${rec.path}`,\n );\n }\n recordPaths.add(rec.path);\n }\n\n // ---------------------------------------------------------------------------\n // Phase 1: verify checksums + validate paths before ANY filesystem mutation.\n // (gotcha #25: don't destroy old state before confirming new state succeeds)\n // ---------------------------------------------------------------------------\n\n const rootReal = await realpath(rootAbs).catch(() => rootAbs);\n\n // Tracks normalized, case-folded target paths seen so far in phase 1. Maps\n // targetAbs.toLowerCase() → first source path so the collision error can name\n // both offending entries. Two manifest entries whose computed target paths\n // normalise to the same absolute path (e.g. `subdir/file.md` and\n // `subdir/./file.md`, or differing case on case-insensitive filesystems such\n // as macOS and Windows) would both refer to the same inode. In\n // `skip-conflicts`/`prefer-local` modes one entry would be misclassified as a\n // local conflict against the OTHER entry's just-written content; in\n // `prefer-source` the second entry would silently overwrite the first. We\n // reject the import up-front before any write (Codex P2 thread on PR #748,\n // mirroring `capsule-import.ts`).\n const seenTargetPaths = new Map<string, string>();\n\n for (const rec of bundle.records) {\n // Checksum validation.\n const entry = manifestIndex.get(rec.path);\n if (!entry) {\n throw new Error(\n `mergeCapsule: archive checksum mismatch (record without manifest entry: ${rec.path})`,\n );\n }\n const { sha256, bytes } = sha256String(rec.content);\n if (sha256 !== entry.sha256 || bytes !== entry.bytes) {\n throw new Error(\n `mergeCapsule: archive checksum mismatch for ${rec.path}: ` +\n `expected sha256=${entry.sha256} bytes=${entry.bytes}, ` +\n `got sha256=${sha256} bytes=${bytes}`,\n );\n }\n\n // Path-traversal validation (mirrors capsule-import.ts).\n if (rec.path.includes(\"\\\\\")) {\n throw new Error(\n `mergeCapsule: record path contains backslash separators (Windows-style paths are not allowed): ${rec.path}`,\n );\n }\n const posixNormalized = path.posix.normalize(rec.path);\n if (\n rec.path.startsWith(\"/\") ||\n rec.path.split(\"/\").some((seg) => seg === \"..\") ||\n posixNormalized.startsWith(\"..\") ||\n posixNormalized.startsWith(\"/\")\n ) {\n throw new Error(\n `mergeCapsule: record path escapes target root: ${rec.path}`,\n );\n }\n\n // Lexical root containment check.\n const targetAbs = path.join(rootReal, fromPosixRelPath(rec.path));\n if (!isPathInsideRoot(rootReal, targetAbs)) {\n throw new Error(\n `mergeCapsule: record path escapes target root: ${rec.path}`,\n );\n }\n\n // Symlink-aware containment check (shared helper from fs-utils).\n await assertRealpathInsideRoot(rootReal, targetAbs, rec.path, \"mergeCapsule\");\n\n // Target-file symlink guard: if the target already exists as a symlink,\n // reject — writes through symlinks can redirect to unexpected locations.\n const targetLstat = await lstat(targetAbs).catch(() => null);\n if (targetLstat !== null && targetLstat.isSymbolicLink()) {\n throw new Error(\n `mergeCapsule: record target is a symlink and cannot be written to safely: ${rec.path}`,\n );\n }\n\n // Duplicate normalized target path detection (Codex P2 #748, mirrors\n // capsule-import.ts). `path.join` already normalises `.` segments\n // (e.g. `subdir/./file.md` → `subdir/file.md`). On case-insensitive\n // filesystems (macOS default, Windows), two paths that differ only in case\n // would resolve to the same inode. We fold the dedup key to lowercase so\n // that `subdir/File.md` and `subdir/file.md` are detected as duplicates\n // before any write occurs. This is intentionally unconditional: the cost\n // of an extra `.toLowerCase()` on case-sensitive filesystems is negligible,\n // and a defensive lowercase is far simpler than probing filesystem\n // case-sensitivity at runtime. Without this guard, prefer-source mode\n // would silently overwrite one entry with the other, and skip-conflicts /\n // prefer-local would misclassify the second entry as a local conflict\n // against the first entry's freshly written content.\n const dedupKey = targetAbs.toLowerCase();\n const firstSourcePath = seenTargetPaths.get(dedupKey);\n if (firstSourcePath !== undefined) {\n throw new Error(\n `mergeCapsule: manifest contains two entries that resolve to the same target path: ` +\n `\"${firstSourcePath}\" and \"${rec.path}\" both map to \"${rec.path}\"`,\n );\n }\n seenTargetPaths.set(dedupKey, rec.path);\n }\n\n // Detect manifest-only entries (missing record). Treat as corruption.\n for (const f of manifest.files) {\n if (!recordPaths.has(f.path)) {\n throw new Error(\n `mergeCapsule: archive checksum mismatch (manifest entry without record: ${f.path})`,\n );\n }\n }\n\n // ---------------------------------------------------------------------------\n // Phase 2: classify records and apply conflict mode.\n // ---------------------------------------------------------------------------\n\n const merged: MergeCapsuleWrittenRecord[] = [];\n const skipped: MergeCapsuleSkippedRecord[] = [];\n const conflicts: MergeCapsuleConflictRecord[] = [];\n\n // Sort by source path for deterministic output (mirrors capsule-import.ts).\n const sortedRecords = [...bundle.records].sort((a, b) =>\n a.path.localeCompare(b.path),\n );\n\n for (const rec of sortedRecords) {\n const targetAbs = path.join(rootReal, fromPosixRelPath(rec.path));\n const entry = manifestIndex.get(rec.path)!; // validated above\n\n const localContent = await readLocalFile(targetAbs);\n\n if (localContent === null) {\n // No local copy — always write regardless of mode.\n await mkdir(path.dirname(targetAbs), { recursive: true });\n await writeFile(targetAbs, rec.content, \"utf-8\");\n merged.push({ sourcePath: rec.path, targetPath: rec.path, snapshotted: false });\n continue;\n }\n\n // Local file exists. Check if it is byte-identical to the archive entry.\n const { sha256: localSha256 } = sha256String(localContent);\n\n if (localSha256 === entry.sha256) {\n // Byte-identical — no write needed.\n skipped.push({ path: rec.path, reason: \"identical\" });\n continue;\n }\n\n // Content differs → conflict.\n const { sha256: archiveSha256 } = sha256String(rec.content);\n conflicts.push({\n path: rec.path,\n archiveSha256,\n localSha256,\n });\n\n if (conflictMode === \"skip-conflicts\" || conflictMode === \"prefer-local\") {\n // Keep local copy, skip archive entry.\n skipped.push({ path: rec.path, reason: \"conflict\" });\n continue;\n }\n\n // conflictMode === \"prefer-source\": snapshot local then overwrite.\n let snapshotted = false;\n if (opts.versioning && opts.versioning.enabled) {\n // Gotcha #54: snapshot BEFORE overwriting.\n await createVersion(\n targetAbs,\n localContent,\n \"manual\",\n opts.versioning,\n opts.log,\n `capsule-merge: ${capsule.id}`,\n rootReal,\n );\n snapshotted = true;\n }\n\n await writeFile(targetAbs, rec.content, \"utf-8\");\n merged.push({ sourcePath: rec.path, targetPath: rec.path, snapshotted });\n }\n\n // Sort output lists for determinism.\n merged.sort((a, b) => a.sourcePath.localeCompare(b.sourcePath));\n skipped.sort((a, b) => a.path.localeCompare(b.path));\n conflicts.sort((a, b) => a.path.localeCompare(b.path));\n\n return { merged, skipped, conflicts, manifest };\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\nasync function readLocalFile(absPath: string): Promise<string | null> {\n const st = await stat(absPath).catch(() => null);\n if (!st || !st.isFile()) return null;\n return readFile(absPath, \"utf-8\");\n}\n\n// Re-export CapsuleBlock so callers don't need a deep import from types.ts.\nexport type { CapsuleBlock };\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/transfer/capsule-merge.ts"],"sourcesContent":["import { lstat, mkdir, readFile, realpath, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { gunzipSync } from \"node:zlib\";\nimport {\n createVersion,\n type VersioningConfig,\n type VersioningLogger,\n} from \"../page-versioning.js\";\nimport {\n assertIsDirectoryNotSymlink,\n assertRealpathInsideRoot,\n fromPosixRelPath,\n isPathInsideRoot,\n sha256String,\n} from \"./fs-utils.js\";\nimport {\n parseExportBundle,\n type CapsuleBlock,\n type ExportManifestV2,\n type ExportMemoryRecordV1,\n} from \"./types.js\";\n\n/**\n * Three-way conflict-resolution mode for {@link mergeCapsule}.\n *\n * A \"conflict\" is defined as: the same memory-file path exists in both the\n * source archive and the target directory AND the content hash of the local\n * file differs from the archive's manifest entry for that path.\n *\n * Files that exist only in the archive (no local counterpart) are always\n * written regardless of mode — there is no conflict to resolve.\n *\n * Files that are byte-identical (same content hash in both locations) are\n * recorded as {@link MergeCapsuleResult.skipped} with reason `\"identical\"` and\n * are never re-written regardless of mode; this is a no-op optimisation rather\n * than a conflict.\n *\n * - `\"skip-conflicts\"` (default) — log the conflict, skip the conflicting\n * archive entries, but continue importing non-conflicting entries. The\n * resulting merge is the union of:\n * - all non-conflicting archive files (written to target)\n * - all pre-existing local files (left unchanged)\n *\n * - `\"prefer-source\"` — for conflicting files, snapshot the local content via\n * page-versioning (gotcha #54: snapshot before overwrite) then overwrite\n * with the archive content.\n *\n * - `\"prefer-local\"` — for conflicting files, keep the local content; the\n * archive entry is skipped.\n */\nexport type MergeCapsuleConflictMode =\n | \"skip-conflicts\"\n | \"prefer-source\"\n | \"prefer-local\";\n\n/**\n * Options accepted by {@link mergeCapsule}.\n *\n * `sourceArchive` — absolute or cwd-relative path to a `.capsule.json.gz`\n * archive produced by `exportCapsule`. Must be a V2 bundle.\n *\n * `targetRoot` — absolute or cwd-relative path to the memory directory that\n * receives the merged records. Must be an existing, non-symlink directory.\n *\n * `conflictMode` — see {@link MergeCapsuleConflictMode}. Defaults to\n * `\"skip-conflicts\"`.\n *\n * `versioning` — optional page-versioning config forwarded to\n * {@link createVersion} in `\"prefer-source\"` mode. When omitted or disabled,\n * overwrites proceed without snapshotting (not recommended for production).\n *\n * `log` — optional logger forwarded to {@link createVersion}.\n */\nexport interface MergeCapsuleOptions {\n sourceArchive: string;\n targetRoot: string;\n conflictMode?: MergeCapsuleConflictMode;\n versioning?: VersioningConfig;\n log?: VersioningLogger;\n}\n\nexport interface MergeCapsuleWrittenRecord {\n /** Capsule-relative posix path. */\n sourcePath: string;\n /** Memory-dir-relative posix path written on disk. */\n targetPath: string;\n /** Whether a page-versioning snapshot was taken before overwriting. */\n snapshotted: boolean;\n}\n\nexport interface MergeCapsuleSkippedRecord {\n /** Capsule-relative posix path. */\n path: string;\n /**\n * Why the archive entry was not written.\n *\n * `\"conflict\"` — the entry existed locally with different content and the\n * active mode did not resolve the conflict with a write (`\"skip-conflicts\"` /\n * `\"prefer-local\"`).\n *\n * `\"identical\"` — the entry's content hash matches what is already on disk;\n * no write is needed.\n */\n reason: \"conflict\" | \"identical\";\n}\n\nexport interface MergeCapsuleConflictRecord {\n /** Capsule-relative posix path of the conflicting entry. */\n path: string;\n /** SHA-256 of the archive's copy. */\n archiveSha256: string;\n /** SHA-256 of the local copy. */\n localSha256: string;\n}\n\nexport interface MergeCapsuleResult {\n /** Records that were written to the target directory. */\n merged: MergeCapsuleWrittenRecord[];\n /**\n * Records that were NOT written (conflict skipped, or byte-identical).\n * Includes conflicts that were resolved by `\"prefer-local\"`.\n */\n skipped: MergeCapsuleSkippedRecord[];\n /**\n * Metadata about every detected conflict, regardless of which mode resolved\n * it. Callers can use this to report \"N conflicts encountered; M overwritten\".\n */\n conflicts: MergeCapsuleConflictRecord[];\n /** The manifest decoded from the archive. */\n manifest: ExportManifestV2;\n}\n\n// ---------------------------------------------------------------------------\n// Main entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Merge a V2 capsule archive into an existing memory directory using\n * three-way conflict semantics.\n *\n * Sequence:\n * 1. Read + gunzip + JSON.parse the archive.\n * 2. Validate through `parseExportBundle` (V1 rejected).\n * 3. Verify every record's content sha256 against the manifest.\n * Any mismatch aborts BEFORE any file is written (gotcha #25).\n * 4. Classify each record as: new (no local copy), identical (same hash),\n * or conflicting (different hash).\n * 5. Apply the selected {@link MergeCapsuleConflictMode} to conflicting\n * entries; always write new entries; always skip identical entries.\n *\n * Determinism: `merged`, `skipped`, and `conflicts` are all returned sorted\n * by `path`/`sourcePath` so callers get stable output regardless of bundle\n * order.\n */\nexport async function mergeCapsule(\n opts: MergeCapsuleOptions,\n): Promise<MergeCapsuleResult> {\n const archiveAbs = path.resolve(opts.sourceArchive);\n const rootAbs = path.resolve(opts.targetRoot);\n\n await assertIsDirectoryNotSymlink(rootAbs, \"mergeCapsule\", \"targetRoot\");\n\n const conflictMode: MergeCapsuleConflictMode =\n opts.conflictMode ?? \"skip-conflicts\";\n\n // Rule 51: reject invalid conflictMode values up-front before any I/O.\n if (\n conflictMode !== \"skip-conflicts\" &&\n conflictMode !== \"prefer-source\" &&\n conflictMode !== \"prefer-local\"\n ) {\n throw new Error(\n `mergeCapsule: unknown conflictMode ${JSON.stringify(conflictMode)}; ` +\n `expected \"skip-conflicts\", \"prefer-source\", or \"prefer-local\"`,\n );\n }\n\n // ---------------------------------------------------------------------------\n // Parse + validate archive\n // ---------------------------------------------------------------------------\n\n const raw = await readFile(archiveAbs);\n let json: string;\n try {\n json = gunzipSync(raw).toString(\"utf-8\");\n } catch (cause) {\n throw new Error(\n `mergeCapsule: archive is not a valid gzip file: ${archiveAbs}`,\n { cause: cause as Error },\n );\n }\n\n let parsedJson: unknown;\n try {\n parsedJson = JSON.parse(json);\n } catch (cause) {\n throw new Error(\n `mergeCapsule: archive is not valid JSON after gunzip: ${archiveAbs}`,\n { cause: cause as Error },\n );\n }\n\n const parsed = parseExportBundle(parsedJson);\n if (parsed.capsuleVersion !== 2) {\n throw new Error(\n \"mergeCapsule: archive is V1; only V2 capsule archives are supported\",\n );\n }\n\n const bundle = parsed.bundle as {\n manifest: ExportManifestV2;\n records: ExportMemoryRecordV1[];\n };\n const manifest = bundle.manifest;\n const capsule = manifest.capsule;\n\n // Build path → manifest entry index for O(1) checksum lookup.\n const manifestIndex = new Map<string, ExportManifestV2[\"files\"][number]>();\n for (const f of manifest.files) {\n manifestIndex.set(f.path, f);\n }\n if (manifestIndex.size !== manifest.files.length) {\n throw new Error(\"mergeCapsule: manifest contains duplicate file paths\");\n }\n\n const recordPaths = new Set<string>();\n for (const rec of bundle.records) {\n if (recordPaths.has(rec.path)) {\n throw new Error(\n `mergeCapsule: bundle contains duplicate record path: ${rec.path}`,\n );\n }\n recordPaths.add(rec.path);\n }\n\n // ---------------------------------------------------------------------------\n // Phase 1: verify checksums + validate paths before ANY filesystem mutation.\n // (gotcha #25: don't destroy old state before confirming new state succeeds)\n // ---------------------------------------------------------------------------\n\n const rootReal = await realpath(rootAbs).catch(() => rootAbs);\n\n // Tracks normalized, case-folded target paths seen so far in phase 1. Maps\n // targetAbs.toLowerCase() → first source path so the collision error can name\n // both offending entries. Two manifest entries whose computed target paths\n // normalise to the same absolute path (e.g. `subdir/file.md` and\n // `subdir/./file.md`, or differing case on case-insensitive filesystems such\n // as macOS and Windows) would both refer to the same inode. In\n // `skip-conflicts`/`prefer-local` modes one entry would be misclassified as a\n // local conflict against the OTHER entry's just-written content; in\n // `prefer-source` the second entry would silently overwrite the first. We\n // reject the import up-front before any write (Codex P2 thread on PR #748,\n // mirroring `capsule-import.ts`).\n const seenTargetPaths = new Map<string, string>();\n\n for (const rec of bundle.records) {\n // Checksum validation.\n const entry = manifestIndex.get(rec.path);\n if (!entry) {\n throw new Error(\n `mergeCapsule: archive checksum mismatch (record without manifest entry: ${rec.path})`,\n );\n }\n const { sha256, bytes } = sha256String(rec.content);\n if (sha256 !== entry.sha256 || bytes !== entry.bytes) {\n throw new Error(\n `mergeCapsule: archive checksum mismatch for ${rec.path}: ` +\n `expected sha256=${entry.sha256} bytes=${entry.bytes}, ` +\n `got sha256=${sha256} bytes=${bytes}`,\n );\n }\n\n // Path-traversal validation (mirrors capsule-import.ts).\n if (rec.path.includes(\"\\\\\")) {\n throw new Error(\n `mergeCapsule: record path contains backslash separators (Windows-style paths are not allowed): ${rec.path}`,\n );\n }\n const posixNormalized = path.posix.normalize(rec.path);\n if (\n rec.path.startsWith(\"/\") ||\n rec.path.split(\"/\").some((seg) => seg === \"..\") ||\n posixNormalized.startsWith(\"..\") ||\n posixNormalized.startsWith(\"/\")\n ) {\n throw new Error(\n `mergeCapsule: record path escapes target root: ${rec.path}`,\n );\n }\n\n // Lexical root containment check.\n const targetAbs = path.join(rootReal, fromPosixRelPath(rec.path));\n if (!isPathInsideRoot(rootReal, targetAbs)) {\n throw new Error(\n `mergeCapsule: record path escapes target root: ${rec.path}`,\n );\n }\n\n // Symlink-aware containment check (shared helper from fs-utils).\n await assertRealpathInsideRoot(rootReal, targetAbs, rec.path, \"mergeCapsule\");\n\n // Target-file symlink guard: if the target already exists as a symlink,\n // reject — writes through symlinks can redirect to unexpected locations.\n const targetLstat = await lstat(targetAbs).catch(() => null);\n if (targetLstat !== null && targetLstat.isSymbolicLink()) {\n throw new Error(\n `mergeCapsule: record target is a symlink and cannot be written to safely: ${rec.path}`,\n );\n }\n\n // Duplicate normalized target path detection (Codex P2 #748, mirrors\n // capsule-import.ts). `path.join` already normalises `.` segments\n // (e.g. `subdir/./file.md` → `subdir/file.md`). On case-insensitive\n // filesystems (macOS default, Windows), two paths that differ only in case\n // would resolve to the same inode. We fold the dedup key to lowercase so\n // that `subdir/File.md` and `subdir/file.md` are detected as duplicates\n // before any write occurs. This is intentionally unconditional: the cost\n // of an extra `.toLowerCase()` on case-sensitive filesystems is negligible,\n // and a defensive lowercase is far simpler than probing filesystem\n // case-sensitivity at runtime. Without this guard, prefer-source mode\n // would silently overwrite one entry with the other, and skip-conflicts /\n // prefer-local would misclassify the second entry as a local conflict\n // against the first entry's freshly written content.\n const dedupKey = targetAbs.toLowerCase();\n const firstSourcePath = seenTargetPaths.get(dedupKey);\n if (firstSourcePath !== undefined) {\n throw new Error(\n `mergeCapsule: manifest contains two entries that resolve to the same target path: ` +\n `\"${firstSourcePath}\" and \"${rec.path}\" both map to \"${rec.path}\"`,\n );\n }\n seenTargetPaths.set(dedupKey, rec.path);\n }\n\n // Detect manifest-only entries (missing record). Treat as corruption.\n for (const f of manifest.files) {\n if (!recordPaths.has(f.path)) {\n throw new Error(\n `mergeCapsule: archive checksum mismatch (manifest entry without record: ${f.path})`,\n );\n }\n }\n\n // ---------------------------------------------------------------------------\n // Phase 2: classify records and apply conflict mode.\n // ---------------------------------------------------------------------------\n\n const merged: MergeCapsuleWrittenRecord[] = [];\n const skipped: MergeCapsuleSkippedRecord[] = [];\n const conflicts: MergeCapsuleConflictRecord[] = [];\n\n // Sort by source path for deterministic output (mirrors capsule-import.ts).\n const sortedRecords = [...bundle.records].sort((a, b) =>\n a.path.localeCompare(b.path),\n );\n\n for (const rec of sortedRecords) {\n const targetAbs = path.join(rootReal, fromPosixRelPath(rec.path));\n const entry = manifestIndex.get(rec.path)!; // validated above\n\n const localContent = await readLocalFile(targetAbs);\n\n if (localContent === null) {\n // No local copy — always write regardless of mode.\n await mkdir(path.dirname(targetAbs), { recursive: true });\n await writeFile(targetAbs, rec.content, \"utf-8\");\n merged.push({ sourcePath: rec.path, targetPath: rec.path, snapshotted: false });\n continue;\n }\n\n // Local file exists. Check if it is byte-identical to the archive entry.\n const { sha256: localSha256 } = sha256String(localContent);\n\n if (localSha256 === entry.sha256) {\n // Byte-identical — no write needed.\n skipped.push({ path: rec.path, reason: \"identical\" });\n continue;\n }\n\n // Content differs → conflict.\n const { sha256: archiveSha256 } = sha256String(rec.content);\n conflicts.push({\n path: rec.path,\n archiveSha256,\n localSha256,\n });\n\n if (conflictMode === \"skip-conflicts\" || conflictMode === \"prefer-local\") {\n // Keep local copy, skip archive entry.\n skipped.push({ path: rec.path, reason: \"conflict\" });\n continue;\n }\n\n // conflictMode === \"prefer-source\": snapshot local then overwrite.\n let snapshotted = false;\n if (opts.versioning && opts.versioning.enabled) {\n // Gotcha #54: snapshot BEFORE overwriting.\n await createVersion(\n targetAbs,\n localContent,\n \"manual\",\n opts.versioning,\n opts.log,\n `capsule-merge: ${capsule.id}`,\n rootReal,\n );\n snapshotted = true;\n }\n\n await writeFile(targetAbs, rec.content, \"utf-8\");\n merged.push({ sourcePath: rec.path, targetPath: rec.path, snapshotted });\n }\n\n // Sort output lists for determinism.\n merged.sort((a, b) => a.sourcePath.localeCompare(b.sourcePath));\n skipped.sort((a, b) => a.path.localeCompare(b.path));\n conflicts.sort((a, b) => a.path.localeCompare(b.path));\n\n return { merged, skipped, conflicts, manifest };\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\nasync function readLocalFile(absPath: string): Promise<string | null> {\n const st = await stat(absPath).catch(() => null);\n if (!st || !st.isFile()) return null;\n return readFile(absPath, \"utf-8\");\n}\n\n// Re-export CapsuleBlock so callers don't need a deep import from types.ts.\nexport type { CapsuleBlock };\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA,SAAS,OAAO,OAAO,UAAU,UAAU,MAAM,iBAAiB;AAClE,OAAO,UAAU;AACjB,SAAS,kBAAkB;AAwJ3B,eAAsB,aACpB,MAC6B;AAC7B,QAAM,aAAa,KAAK,QAAQ,KAAK,aAAa;AAClD,QAAM,UAAU,KAAK,QAAQ,KAAK,UAAU;AAE5C,QAAM,4BAA4B,SAAS,gBAAgB,YAAY;AAEvE,QAAM,eACJ,KAAK,gBAAgB;AAGvB,MACE,iBAAiB,oBACjB,iBAAiB,mBACjB,iBAAiB,gBACjB;AACA,UAAM,IAAI;AAAA,MACR,sCAAsC,KAAK,UAAU,YAAY,CAAC;AAAA,IAEpE;AAAA,EACF;AAMA,QAAM,MAAM,MAAM,SAAS,UAAU;AACrC,MAAI;AACJ,MAAI;AACF,WAAO,WAAW,GAAG,EAAE,SAAS,OAAO;AAAA,EACzC,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,mDAAmD,UAAU;AAAA,MAC7D,EAAE,MAAsB;AAAA,IAC1B;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,iBAAa,KAAK,MAAM,IAAI;AAAA,EAC9B,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,yDAAyD,UAAU;AAAA,MACnE,EAAE,MAAsB;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,SAAS,kBAAkB,UAAU;AAC3C,MAAI,OAAO,mBAAmB,GAAG;AAC/B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,OAAO;AAItB,QAAM,WAAW,OAAO;AACxB,QAAM,UAAU,SAAS;AAGzB,QAAM,gBAAgB,oBAAI,IAA+C;AACzE,aAAW,KAAK,SAAS,OAAO;AAC9B,kBAAc,IAAI,EAAE,MAAM,CAAC;AAAA,EAC7B;AACA,MAAI,cAAc,SAAS,SAAS,MAAM,QAAQ;AAChD,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AAEA,QAAM,cAAc,oBAAI,IAAY;AACpC,aAAW,OAAO,OAAO,SAAS;AAChC,QAAI,YAAY,IAAI,IAAI,IAAI,GAAG;AAC7B,YAAM,IAAI;AAAA,QACR,wDAAwD,IAAI,IAAI;AAAA,MAClE;AAAA,IACF;AACA,gBAAY,IAAI,IAAI,IAAI;AAAA,EAC1B;AAOA,QAAM,WAAW,MAAM,SAAS,OAAO,EAAE,MAAM,MAAM,OAAO;AAa5D,QAAM,kBAAkB,oBAAI,IAAoB;AAEhD,aAAW,OAAO,OAAO,SAAS;AAEhC,UAAM,QAAQ,cAAc,IAAI,IAAI,IAAI;AACxC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI;AAAA,QACR,2EAA2E,IAAI,IAAI;AAAA,MACrF;AAAA,IACF;AACA,UAAM,EAAE,QAAQ,MAAM,IAAI,aAAa,IAAI,OAAO;AAClD,QAAI,WAAW,MAAM,UAAU,UAAU,MAAM,OAAO;AACpD,YAAM,IAAI;AAAA,QACR,+CAA+C,IAAI,IAAI,qBAClC,MAAM,MAAM,UAAU,MAAM,KAAK,gBACtC,MAAM,UAAU,KAAK;AAAA,MACvC;AAAA,IACF;AAGA,QAAI,IAAI,KAAK,SAAS,IAAI,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR,kGAAkG,IAAI,IAAI;AAAA,MAC5G;AAAA,IACF;AACA,UAAM,kBAAkB,KAAK,MAAM,UAAU,IAAI,IAAI;AACrD,QACE,IAAI,KAAK,WAAW,GAAG,KACvB,IAAI,KAAK,MAAM,GAAG,EAAE,KAAK,CAAC,QAAQ,QAAQ,IAAI,KAC9C,gBAAgB,WAAW,IAAI,KAC/B,gBAAgB,WAAW,GAAG,GAC9B;AACA,YAAM,IAAI;AAAA,QACR,kDAAkD,IAAI,IAAI;AAAA,MAC5D;AAAA,IACF;AAGA,UAAM,YAAY,KAAK,KAAK,UAAU,iBAAiB,IAAI,IAAI,CAAC;AAChE,QAAI,CAAC,iBAAiB,UAAU,SAAS,GAAG;AAC1C,YAAM,IAAI;AAAA,QACR,kDAAkD,IAAI,IAAI;AAAA,MAC5D;AAAA,IACF;AAGA,UAAM,yBAAyB,UAAU,WAAW,IAAI,MAAM,cAAc;AAI5E,UAAM,cAAc,MAAM,MAAM,SAAS,EAAE,MAAM,MAAM,IAAI;AAC3D,QAAI,gBAAgB,QAAQ,YAAY,eAAe,GAAG;AACxD,YAAM,IAAI;AAAA,QACR,6EAA6E,IAAI,IAAI;AAAA,MACvF;AAAA,IACF;AAeA,UAAM,WAAW,UAAU,YAAY;AACvC,UAAM,kBAAkB,gBAAgB,IAAI,QAAQ;AACpD,QAAI,oBAAoB,QAAW;AACjC,YAAM,IAAI;AAAA,QACR,sFACM,eAAe,UAAU,IAAI,IAAI,kBAAkB,IAAI,IAAI;AAAA,MACnE;AAAA,IACF;AACA,oBAAgB,IAAI,UAAU,IAAI,IAAI;AAAA,EACxC;AAGA,aAAW,KAAK,SAAS,OAAO;AAC9B,QAAI,CAAC,YAAY,IAAI,EAAE,IAAI,GAAG;AAC5B,YAAM,IAAI;AAAA,QACR,2EAA2E,EAAE,IAAI;AAAA,MACnF;AAAA,IACF;AAAA,EACF;AAMA,QAAM,SAAsC,CAAC;AAC7C,QAAM,UAAuC,CAAC;AAC9C,QAAM,YAA0C,CAAC;AAGjD,QAAM,gBAAgB,CAAC,GAAG,OAAO,OAAO,EAAE;AAAA,IAAK,CAAC,GAAG,MACjD,EAAE,KAAK,cAAc,EAAE,IAAI;AAAA,EAC7B;AAEA,aAAW,OAAO,eAAe;AAC/B,UAAM,YAAY,KAAK,KAAK,UAAU,iBAAiB,IAAI,IAAI,CAAC;AAChE,UAAM,QAAQ,cAAc,IAAI,IAAI,IAAI;AAExC,UAAM,eAAe,MAAM,cAAc,SAAS;AAElD,QAAI,iBAAiB,MAAM;AAEzB,YAAM,MAAM,KAAK,QAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AACxD,YAAM,UAAU,WAAW,IAAI,SAAS,OAAO;AAC/C,aAAO,KAAK,EAAE,YAAY,IAAI,MAAM,YAAY,IAAI,MAAM,aAAa,MAAM,CAAC;AAC9E;AAAA,IACF;AAGA,UAAM,EAAE,QAAQ,YAAY,IAAI,aAAa,YAAY;AAEzD,QAAI,gBAAgB,MAAM,QAAQ;AAEhC,cAAQ,KAAK,EAAE,MAAM,IAAI,MAAM,QAAQ,YAAY,CAAC;AACpD;AAAA,IACF;AAGA,UAAM,EAAE,QAAQ,cAAc,IAAI,aAAa,IAAI,OAAO;AAC1D,cAAU,KAAK;AAAA,MACb,MAAM,IAAI;AAAA,MACV;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,iBAAiB,oBAAoB,iBAAiB,gBAAgB;AAExE,cAAQ,KAAK,EAAE,MAAM,IAAI,MAAM,QAAQ,WAAW,CAAC;AACnD;AAAA,IACF;AAGA,QAAI,cAAc;AAClB,QAAI,KAAK,cAAc,KAAK,WAAW,SAAS;AAE9C,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK;AAAA,QACL,KAAK;AAAA,QACL,kBAAkB,QAAQ,EAAE;AAAA,QAC5B;AAAA,MACF;AACA,oBAAc;AAAA,IAChB;AAEA,UAAM,UAAU,WAAW,IAAI,SAAS,OAAO;AAC/C,WAAO,KAAK,EAAE,YAAY,IAAI,MAAM,YAAY,IAAI,MAAM,YAAY,CAAC;AAAA,EACzE;AAGA,SAAO,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,cAAc,EAAE,UAAU,CAAC;AAC9D,UAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AACnD,YAAU,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAErD,SAAO,EAAE,QAAQ,SAAS,WAAW,SAAS;AAChD;AAMA,eAAe,cAAc,SAAyC;AACpE,QAAM,KAAK,MAAM,KAAK,OAAO,EAAE,MAAM,MAAM,IAAI;AAC/C,MAAI,CAAC,MAAM,CAAC,GAAG,OAAO,EAAG,QAAO;AAChC,SAAO,SAAS,SAAS,OAAO;AAClC;","names":[]}
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-UXA5L2DZ.js";
|
|
5
5
|
import {
|
|
6
6
|
buildExtensionsBlockForConsolidation
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XW3W4PV4.js";
|
|
8
8
|
import {
|
|
9
9
|
runPostConsolidationMaterialize
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-C7AF236A.js";
|
|
11
11
|
import "./chunk-LN4YGHTM.js";
|
|
12
12
|
import "./chunk-JLNBQWZ2.js";
|
|
13
13
|
import "./chunk-3UXOZBHV.js";
|
|
@@ -20,7 +20,7 @@ import "./chunk-L2EXJQJP.js";
|
|
|
20
20
|
import "./chunk-7SI52C65.js";
|
|
21
21
|
import "./chunk-RK6F44Y6.js";
|
|
22
22
|
import "./chunk-HQ6NIBL6.js";
|
|
23
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-VH6EIKVS.js";
|
|
24
24
|
import "./chunk-M7XQSUBB.js";
|
|
25
25
|
import "./chunk-5UZXUTVO.js";
|
|
26
26
|
import "./chunk-J6A3CX5N.js";
|
|
@@ -35,7 +35,7 @@ import "./chunk-DM2T26WE.js";
|
|
|
35
35
|
import "./chunk-LDXUBPMO.js";
|
|
36
36
|
import "./chunk-FVQJYWH7.js";
|
|
37
37
|
import "./chunk-G7D6GZ5J.js";
|
|
38
|
-
import "./chunk-
|
|
38
|
+
import "./chunk-VF4XKTX3.js";
|
|
39
39
|
import "./chunk-RGMVMVMF.js";
|
|
40
40
|
import {
|
|
41
41
|
resolveCausalTrajectoryStoreDir
|
|
@@ -55,9 +55,10 @@ import {
|
|
|
55
55
|
listJsonFiles,
|
|
56
56
|
readJsonFile
|
|
57
57
|
} from "./chunk-LPSF4OQH.js";
|
|
58
|
-
import "./chunk-
|
|
58
|
+
import "./chunk-J2HSAU72.js";
|
|
59
59
|
import "./chunk-A6XUJE5D.js";
|
|
60
60
|
import "./chunk-P7FMDTKL.js";
|
|
61
|
+
import "./chunk-VS2IYZRU.js";
|
|
61
62
|
import "./chunk-PZ5AY32C.js";
|
|
62
63
|
|
|
63
64
|
// src/causal-consolidation.ts
|