@remnic/core 9.3.543 → 9.3.545

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.
Files changed (81) hide show
  1. package/dist/access-cli.js +15 -15
  2. package/dist/access-http.js +9 -9
  3. package/dist/access-mcp.js +8 -8
  4. package/dist/access-schema.js +3 -3
  5. package/dist/access-service.js +6 -6
  6. package/dist/briefing.js +3 -3
  7. package/dist/causal-consolidation.js +4 -4
  8. package/dist/{chunk-FWYUJY4N.js → chunk-25BY3HHZ.js} +2 -2
  9. package/dist/{chunk-K6OABSBA.js → chunk-5GX5MUQ2.js} +2 -2
  10. package/dist/{chunk-NHZHAZCJ.js → chunk-5RIRL3XL.js} +2 -2
  11. package/dist/{chunk-QKV4LVLA.js → chunk-5WLYNZPC.js} +2 -2
  12. package/dist/{chunk-PR577DSG.js → chunk-6PDPQLSV.js} +12 -12
  13. package/dist/{chunk-NJBIGWAI.js → chunk-ACCAZOBX.js} +2 -2
  14. package/dist/{chunk-BRCYNT4I.js → chunk-CC2ESOOG.js} +2 -2
  15. package/dist/{chunk-QWQX7YK5.js → chunk-E5OECWZ5.js} +2 -2
  16. package/dist/{chunk-J62VXZR2.js → chunk-FADZBOR4.js} +2 -2
  17. package/dist/{chunk-GWUUEPOR.js → chunk-FVCZINOF.js} +2 -2
  18. package/dist/{chunk-73JGZ5VA.js → chunk-ILXTATKK.js} +47 -20
  19. package/dist/chunk-ILXTATKK.js.map +1 -0
  20. package/dist/{chunk-FXE46BJ5.js → chunk-JFN6K74Q.js} +2 -2
  21. package/dist/{chunk-ENIIJ3MZ.js → chunk-M3BAMVAE.js} +2 -2
  22. package/dist/{chunk-QCJLDMY5.js → chunk-OF46AKZC.js} +8 -8
  23. package/dist/{chunk-7NEW7PTS.js → chunk-QFGWYIB6.js} +5 -5
  24. package/dist/{chunk-LKUNOD7B.js → chunk-S53PAX2V.js} +2 -2
  25. package/dist/{chunk-INMWM3UZ.js → chunk-SCKIZM6L.js} +4 -4
  26. package/dist/{chunk-3M7OTJ5H.js → chunk-SI3QCHWF.js} +4 -4
  27. package/dist/{chunk-UMXWQL3P.js → chunk-SOTR74FK.js} +2 -2
  28. package/dist/{chunk-A5TLPLUO.js → chunk-TVZ6LKKS.js} +2 -2
  29. package/dist/{chunk-25XNFWT3.js → chunk-VKVKH6XO.js} +2 -2
  30. package/dist/{chunk-GAMKRZRP.js → chunk-XOSQ4MRE.js} +5 -5
  31. package/dist/{chunk-RGLJNOQN.js → chunk-Y4YATXHL.js} +3 -3
  32. package/dist/{chunk-XE23FSDQ.js → chunk-Z56KAZQL.js} +2 -2
  33. package/dist/cli.js +18 -18
  34. package/dist/compounding/engine.js +3 -3
  35. package/dist/connectors/codex-materialize-runner.js +3 -3
  36. package/dist/connectors/index.js +3 -3
  37. package/dist/entity-retrieval.js +3 -3
  38. package/dist/index.js +24 -24
  39. package/dist/maintenance/memory-governance.js +3 -3
  40. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  41. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  42. package/dist/namespaces/migrate.js +4 -4
  43. package/dist/namespaces/storage.js +3 -3
  44. package/dist/offline-sync.js +2 -2
  45. package/dist/operator-toolkit.js +6 -6
  46. package/dist/orchestrator.js +11 -11
  47. package/dist/schemas.d.ts +22 -22
  48. package/dist/secure-store/index.js +2 -2
  49. package/dist/semantic-consolidation.js +4 -4
  50. package/dist/semantic-rule-promotion.js +3 -3
  51. package/dist/semantic-rule-verifier.js +3 -3
  52. package/dist/storage.js +2 -2
  53. package/dist/transfer/types.d.ts +12 -12
  54. package/dist/verified-recall.js +3 -3
  55. package/package.json +1 -1
  56. package/src/secure-store/secure-fs.ts +63 -38
  57. package/src/secure-store/secure-store.test.ts +155 -106
  58. package/dist/chunk-73JGZ5VA.js.map +0 -1
  59. /package/dist/{chunk-FWYUJY4N.js.map → chunk-25BY3HHZ.js.map} +0 -0
  60. /package/dist/{chunk-K6OABSBA.js.map → chunk-5GX5MUQ2.js.map} +0 -0
  61. /package/dist/{chunk-NHZHAZCJ.js.map → chunk-5RIRL3XL.js.map} +0 -0
  62. /package/dist/{chunk-QKV4LVLA.js.map → chunk-5WLYNZPC.js.map} +0 -0
  63. /package/dist/{chunk-PR577DSG.js.map → chunk-6PDPQLSV.js.map} +0 -0
  64. /package/dist/{chunk-NJBIGWAI.js.map → chunk-ACCAZOBX.js.map} +0 -0
  65. /package/dist/{chunk-BRCYNT4I.js.map → chunk-CC2ESOOG.js.map} +0 -0
  66. /package/dist/{chunk-QWQX7YK5.js.map → chunk-E5OECWZ5.js.map} +0 -0
  67. /package/dist/{chunk-J62VXZR2.js.map → chunk-FADZBOR4.js.map} +0 -0
  68. /package/dist/{chunk-GWUUEPOR.js.map → chunk-FVCZINOF.js.map} +0 -0
  69. /package/dist/{chunk-FXE46BJ5.js.map → chunk-JFN6K74Q.js.map} +0 -0
  70. /package/dist/{chunk-ENIIJ3MZ.js.map → chunk-M3BAMVAE.js.map} +0 -0
  71. /package/dist/{chunk-QCJLDMY5.js.map → chunk-OF46AKZC.js.map} +0 -0
  72. /package/dist/{chunk-7NEW7PTS.js.map → chunk-QFGWYIB6.js.map} +0 -0
  73. /package/dist/{chunk-LKUNOD7B.js.map → chunk-S53PAX2V.js.map} +0 -0
  74. /package/dist/{chunk-INMWM3UZ.js.map → chunk-SCKIZM6L.js.map} +0 -0
  75. /package/dist/{chunk-3M7OTJ5H.js.map → chunk-SI3QCHWF.js.map} +0 -0
  76. /package/dist/{chunk-UMXWQL3P.js.map → chunk-SOTR74FK.js.map} +0 -0
  77. /package/dist/{chunk-A5TLPLUO.js.map → chunk-TVZ6LKKS.js.map} +0 -0
  78. /package/dist/{chunk-25XNFWT3.js.map → chunk-VKVKH6XO.js.map} +0 -0
  79. /package/dist/{chunk-GAMKRZRP.js.map → chunk-XOSQ4MRE.js.map} +0 -0
  80. /package/dist/{chunk-RGLJNOQN.js.map → chunk-Y4YATXHL.js.map} +0 -0
  81. /package/dist/{chunk-XE23FSDQ.js.map → chunk-Z56KAZQL.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  promoteSemanticRuleFromMemory
3
- } from "./chunk-XE23FSDQ.js";
4
- import "./chunk-A5TLPLUO.js";
3
+ } from "./chunk-Z56KAZQL.js";
4
+ import "./chunk-TVZ6LKKS.js";
5
5
  import "./chunk-5UZXUTVO.js";
6
6
  import "./chunk-4H5ZJHEN.js";
7
7
  import "./chunk-M5T4Q2ZU.js";
@@ -17,7 +17,7 @@ import "./chunk-G7D6GZ5J.js";
17
17
  import "./chunk-ALEPI75L.js";
18
18
  import "./chunk-4DJQYKMN.js";
19
19
  import "./chunk-2ODBA7MQ.js";
20
- import "./chunk-73JGZ5VA.js";
20
+ import "./chunk-ILXTATKK.js";
21
21
  import "./chunk-A6XUJE5D.js";
22
22
  import "./chunk-P7FMDTKL.js";
23
23
  import "./chunk-PZ5AY32C.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  searchVerifiedSemanticRules
3
- } from "./chunk-J62VXZR2.js";
4
- import "./chunk-A5TLPLUO.js";
3
+ } from "./chunk-FADZBOR4.js";
4
+ import "./chunk-TVZ6LKKS.js";
5
5
  import "./chunk-5UZXUTVO.js";
6
6
  import "./chunk-4H5ZJHEN.js";
7
7
  import "./chunk-M5T4Q2ZU.js";
@@ -18,7 +18,7 @@ import "./chunk-ALEPI75L.js";
18
18
  import "./chunk-DT5TVLJE.js";
19
19
  import "./chunk-4DJQYKMN.js";
20
20
  import "./chunk-2ODBA7MQ.js";
21
- import "./chunk-73JGZ5VA.js";
21
+ import "./chunk-ILXTATKK.js";
22
22
  import "./chunk-A6XUJE5D.js";
23
23
  import "./chunk-P7FMDTKL.js";
24
24
  import "./chunk-PZ5AY32C.js";
package/dist/storage.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  normalizeEntityName,
9
9
  parseEntityFile,
10
10
  serializeEntityFile
11
- } from "./chunk-A5TLPLUO.js";
11
+ } from "./chunk-TVZ6LKKS.js";
12
12
  import "./chunk-5UZXUTVO.js";
13
13
  import "./chunk-4H5ZJHEN.js";
14
14
  import "./chunk-M5T4Q2ZU.js";
@@ -24,7 +24,7 @@ import "./chunk-G7D6GZ5J.js";
24
24
  import "./chunk-ALEPI75L.js";
25
25
  import "./chunk-4DJQYKMN.js";
26
26
  import "./chunk-2ODBA7MQ.js";
27
- import "./chunk-73JGZ5VA.js";
27
+ import "./chunk-ILXTATKK.js";
28
28
  import "./chunk-A6XUJE5D.js";
29
29
  import "./chunk-P7FMDTKL.js";
30
30
  import "./chunk-PZ5AY32C.js";
@@ -313,13 +313,13 @@ declare const CapsuleBlockSchema: z.ZodObject<{
313
313
  peerProfiles: boolean;
314
314
  }>;
315
315
  }, "strip", z.ZodTypeAny, {
316
- schemaVersion: string;
317
316
  includes: {
318
317
  procedural: boolean;
319
318
  taxonomy: boolean;
320
319
  identityAnchors: boolean;
321
320
  peerProfiles: boolean;
322
321
  };
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;
338
337
  includes: {
339
338
  procedural: boolean;
340
339
  taxonomy: boolean;
341
340
  identityAnchors: boolean;
342
341
  peerProfiles: boolean;
343
342
  };
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;
468
467
  includes: {
469
468
  procedural: boolean;
470
469
  taxonomy: boolean;
471
470
  identityAnchors: boolean;
472
471
  peerProfiles: boolean;
473
472
  };
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;
489
488
  includes: {
490
489
  procedural: boolean;
491
490
  taxonomy: boolean;
492
491
  identityAnchors: boolean;
493
492
  peerProfiles: boolean;
494
493
  };
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;
522
521
  includes: {
523
522
  procedural: boolean;
524
523
  taxonomy: boolean;
525
524
  identityAnchors: boolean;
526
525
  peerProfiles: boolean;
527
526
  };
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;
555
554
  includes: {
556
555
  procedural: boolean;
557
556
  taxonomy: boolean;
558
557
  identityAnchors: boolean;
559
558
  peerProfiles: boolean;
560
559
  };
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;
687
686
  includes: {
688
687
  procedural: boolean;
689
688
  taxonomy: boolean;
690
689
  identityAnchors: boolean;
691
690
  peerProfiles: boolean;
692
691
  };
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;
708
707
  includes: {
709
708
  procedural: boolean;
710
709
  taxonomy: boolean;
711
710
  identityAnchors: boolean;
712
711
  peerProfiles: boolean;
713
712
  };
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;
741
740
  includes: {
742
741
  procedural: boolean;
743
742
  taxonomy: boolean;
744
743
  identityAnchors: boolean;
745
744
  peerProfiles: boolean;
746
745
  };
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;
774
773
  includes: {
775
774
  procedural: boolean;
776
775
  taxonomy: boolean;
777
776
  identityAnchors: boolean;
778
777
  peerProfiles: boolean;
779
778
  };
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;
819
818
  includes: {
820
819
  procedural: boolean;
821
820
  taxonomy: boolean;
822
821
  identityAnchors: boolean;
823
822
  peerProfiles: boolean;
824
823
  };
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;
858
857
  includes: {
859
858
  procedural: boolean;
860
859
  taxonomy: boolean;
861
860
  identityAnchors: boolean;
862
861
  peerProfiles: boolean;
863
862
  };
863
+ schemaVersion: string;
864
864
  id: string;
865
865
  description: string;
866
866
  version: string;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  searchVerifiedEpisodes
3
- } from "./chunk-QKV4LVLA.js";
3
+ } from "./chunk-5WLYNZPC.js";
4
4
  import "./chunk-HQ6NIBL6.js";
5
- import "./chunk-A5TLPLUO.js";
5
+ import "./chunk-TVZ6LKKS.js";
6
6
  import "./chunk-5UZXUTVO.js";
7
7
  import "./chunk-4H5ZJHEN.js";
8
8
  import "./chunk-M5T4Q2ZU.js";
@@ -19,7 +19,7 @@ import "./chunk-ALEPI75L.js";
19
19
  import "./chunk-DT5TVLJE.js";
20
20
  import "./chunk-4DJQYKMN.js";
21
21
  import "./chunk-2ODBA7MQ.js";
22
- import "./chunk-73JGZ5VA.js";
22
+ import "./chunk-ILXTATKK.js";
23
23
  import "./chunk-A6XUJE5D.js";
24
24
  import "./chunk-P7FMDTKL.js";
25
25
  import "./chunk-PZ5AY32C.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.3.543",
3
+ "version": "9.3.545",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -160,7 +160,7 @@ export function decryptFileBody(buf: Buffer, key: Buffer, aad?: Buffer): Buffer
160
160
  const version = buf.readUInt8(MAGIC_BYTES.length);
161
161
  if (version !== FILE_FORMAT_VERSION) {
162
162
  throw new Error(
163
- `decryptFileBody: unsupported file format version ${version} (this build supports ${FILE_FORMAT_VERSION})`,
163
+ `decryptFileBody: unsupported file format version ${version} (this build supports ${FILE_FORMAT_VERSION})`
164
164
  );
165
165
  }
166
166
  const flags = buf.readUInt8(MAGIC_BYTES.length + 1);
@@ -173,9 +173,7 @@ export function decryptFileBody(buf: Buffer, key: Buffer, aad?: Buffer): Buffer
173
173
  return openEnvelope(key, envelope, aad ? { aad } : {});
174
174
  } catch (err) {
175
175
  const msg = err instanceof Error ? err.message : String(err);
176
- throw new SecureStoreDecryptError(
177
- `secure-store decryption failed: ${msg}`,
178
- );
176
+ throw new SecureStoreDecryptError(`secure-store decryption failed: ${msg}`);
179
177
  }
180
178
  }
181
179
 
@@ -227,7 +225,7 @@ export function filePathAad(filePath: string, memoryDir?: string): Buffer {
227
225
  export async function readMaybeEncryptedFileBuffer(
228
226
  filePath: string,
229
227
  key: Buffer | null,
230
- memoryDir?: string,
228
+ memoryDir?: string
231
229
  ): Promise<Buffer> {
232
230
  const buf = await readFile(filePath);
233
231
  if (!isEncryptedFile(buf)) {
@@ -237,8 +235,7 @@ export async function readMaybeEncryptedFileBuffer(
237
235
  // Encrypted — key required.
238
236
  if (key === null) {
239
237
  throw new SecureStoreLockedError(
240
- `secure-store is locked — cannot read encrypted file at ${filePath}. ` +
241
- "Run `remnic secure-store unlock` to decrypt.",
238
+ `secure-store is locked — cannot read encrypted file at ${filePath}. Run \`remnic secure-store unlock\` to decrypt.`
242
239
  );
243
240
  }
244
241
  return decryptFileBodyForPath(buf, key, filePath, memoryDir);
@@ -247,7 +244,7 @@ export async function readMaybeEncryptedFileBuffer(
247
244
  export async function readMaybeEncryptedFile(
248
245
  filePath: string,
249
246
  key: Buffer | null,
250
- memoryDir?: string,
247
+ memoryDir?: string
251
248
  ): Promise<string> {
252
249
  return (await readMaybeEncryptedFileBuffer(filePath, key, memoryDir)).toString("utf8");
253
250
  }
@@ -280,7 +277,7 @@ export async function writeMaybeEncryptedFile(
280
277
  content: string | Buffer,
281
278
  key: Buffer | null,
282
279
  options: WriteMaybeEncryptedFileOptions = {},
283
- memoryDir?: string,
280
+ memoryDir?: string
284
281
  ): Promise<void> {
285
282
  const { mode = 0o600, atomic = true } = options;
286
283
  await mkdir(path.dirname(filePath), { recursive: true });
@@ -317,7 +314,7 @@ export async function writeMaybeEncryptedFileFromChunks(
317
314
  chunks: AsyncIterable<Buffer>,
318
315
  key: Buffer | null,
319
316
  options: WriteMaybeEncryptedFileOptions = {},
320
- memoryDir?: string,
317
+ memoryDir?: string
321
318
  ): Promise<void> {
322
319
  const { mode = 0o600, atomic = true } = options;
323
320
  await mkdir(path.dirname(filePath), { recursive: true });
@@ -350,12 +347,7 @@ export async function writeMaybeEncryptedFileFromChunks(
350
347
  const final = cipher.final();
351
348
  if (final.length > 0) await handle.write(final);
352
349
  const authTag = cipher.getAuthTag();
353
- await handle.write(
354
- authTag,
355
- 0,
356
- authTag.length,
357
- MAGIC_HEADER_SIZE + ENVELOPE_LAYOUT.authTag,
358
- );
350
+ await handle.write(authTag, 0, authTag.length, MAGIC_HEADER_SIZE + ENVELOPE_LAYOUT.authTag);
359
351
  } else {
360
352
  for await (const chunk of chunks) {
361
353
  if (chunk.length > 0) await handle.write(chunk);
@@ -421,7 +413,7 @@ export interface DecryptResult {
421
413
  export async function migrateMemoryDirToEncrypted(
422
414
  dir: string,
423
415
  key: Buffer,
424
- onBeforeEncrypt?: (filePath: string) => Promise<void>,
416
+ onBeforeEncrypt?: (filePath: string) => Promise<void>
425
417
  ): Promise<MigrateResult> {
426
418
  const result: MigrateResult = { encrypted: 0, skipped: 0, errors: [] };
427
419
 
@@ -482,10 +474,7 @@ export async function migrateMemoryDirToEncrypted(
482
474
  * each plaintext replacement via temp-file + rename so a per-file failure
483
475
  * leaves the ciphertext intact.
484
476
  */
485
- export async function decryptMemoryDirToPlaintext(
486
- dir: string,
487
- key: Buffer,
488
- ): Promise<DecryptResult> {
477
+ export async function decryptMemoryDirToPlaintext(dir: string, key: Buffer): Promise<DecryptResult> {
489
478
  const result: DecryptResult = { decrypted: 0, skipped: 0, errors: [] };
490
479
 
491
480
  const files = await collectStorageManagedFiles(dir, isDecryptableStoragePath);
@@ -530,12 +519,7 @@ function uniqueAtomicTempPath(filePath: string, label: string): string {
530
519
  return `${filePath}.${label}-${process.pid}-${Date.now()}-${randomUUID()}`;
531
520
  }
532
521
 
533
- function decryptFileBodyForPath(
534
- buf: Buffer,
535
- key: Buffer,
536
- filePath: string,
537
- memoryDir?: string,
538
- ): Buffer {
522
+ function decryptFileBodyForPath(buf: Buffer, key: Buffer, filePath: string, memoryDir?: string): Buffer {
539
523
  const aad = filePathAad(filePath, memoryDir);
540
524
  try {
541
525
  return decryptFileBody(buf, key, aad);
@@ -613,18 +597,26 @@ async function collectEncryptableStorageFiles(dir: string, rootDir = dir): Promi
613
597
  async function collectStorageManagedFiles(
614
598
  dir: string,
615
599
  includeFile: (filePath: string, rootDir: string) => boolean,
616
- rootDir = dir,
600
+ rootDir = dir
617
601
  ): Promise<string[]> {
618
602
  const results: string[] = [];
603
+ let scanDir = dir;
604
+ let scanRootDir = rootDir;
605
+ if (path.resolve(dir) === path.resolve(rootDir)) {
606
+ const normalizedRoot = await resolveStorageManagedRootForScan(dir);
607
+ if (!normalizedRoot) return results;
608
+ scanDir = normalizedRoot;
609
+ scanRootDir = normalizedRoot;
610
+ }
619
611
  let names: string[];
620
612
  try {
621
- names = await readdir(dir, { encoding: "utf8" });
613
+ names = await readdir(scanDir, { encoding: "utf8" });
622
614
  } catch {
623
615
  return results;
624
616
  }
625
617
  for (const name of names) {
626
618
  if (name.startsWith(".secure-store")) continue;
627
- const full = path.join(dir, name);
619
+ const full = path.join(scanDir, name);
628
620
  let isDir = false;
629
621
  let isFile = false;
630
622
  try {
@@ -636,15 +628,53 @@ async function collectStorageManagedFiles(
636
628
  continue;
637
629
  }
638
630
  if (isDir) {
639
- const sub = await collectStorageManagedFiles(full, includeFile, rootDir);
631
+ const sub = await collectStorageManagedFiles(full, includeFile, scanRootDir);
640
632
  results.push(...sub);
641
- } else if (isFile && includeFile(full, rootDir)) {
633
+ } else if (isFile && includeFile(full, scanRootDir)) {
642
634
  results.push(full);
643
635
  }
644
636
  }
645
637
  return results;
646
638
  }
647
639
 
640
+ async function resolveStorageManagedRootForScan(dir: string): Promise<string | null> {
641
+ const lstatPath = normalizePathForLstat(dir);
642
+ let stat: Awaited<ReturnType<typeof lstat>>;
643
+ try {
644
+ stat = await lstat(lstatPath);
645
+ } catch (error) {
646
+ if (isFsErrorWithCode(error, "ENOENT")) return null;
647
+ throw error;
648
+ }
649
+ if (stat.isSymbolicLink()) {
650
+ throw new Error(`secure-store migration root must not be a symlink: ${dir}`);
651
+ }
652
+ if (!stat.isDirectory()) {
653
+ throw new Error(`secure-store migration root must be a directory: ${dir}`);
654
+ }
655
+ return lstatPath;
656
+ }
657
+
658
+ function normalizePathForLstat(filePath: string): string {
659
+ return stripTrailingPathSeparators(path.normalize(filePath));
660
+ }
661
+
662
+ function isFsErrorWithCode(error: unknown, code: string): boolean {
663
+ return typeof error === "object" && error !== null && (error as { code?: unknown }).code === code;
664
+ }
665
+
666
+ function stripTrailingPathSeparators(filePath: string): string {
667
+ const root = path.parse(filePath).root;
668
+ let end = filePath.length;
669
+ while (
670
+ end > root.length &&
671
+ (filePath[end - 1] === path.sep || filePath[end - 1] === path.posix.sep || filePath[end - 1] === path.win32.sep)
672
+ ) {
673
+ end -= 1;
674
+ }
675
+ return end === filePath.length ? filePath : filePath.slice(0, end);
676
+ }
677
+
648
678
  function isEncryptableStoragePath(filePath: string, rootDir: string): boolean {
649
679
  const rel = path.relative(rootDir, filePath);
650
680
  if (rel === "" || rel.startsWith("..") || path.isAbsolute(rel)) return false;
@@ -710,9 +740,4 @@ function isEncryptableSummarySidecar(normalized: string): boolean {
710
740
  return normalized.startsWith("summaries/") && normalized.endsWith(".json");
711
741
  }
712
742
 
713
- const DECRYPTABLE_SIDECAR_ROOTS = new Set([
714
- "state",
715
- "indexes",
716
- "index",
717
- "provenance",
718
- ]);
743
+ const DECRYPTABLE_SIDECAR_ROOTS = new Set(["state", "indexes", "index", "provenance"]);