@clef-sh/core 0.1.28 → 0.2.0

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 (73) hide show
  1. package/README.md +1 -2
  2. package/dist/artifact/packer.d.ts +4 -3
  3. package/dist/artifact/packer.d.ts.map +1 -1
  4. package/dist/artifact/resolve.d.ts +3 -2
  5. package/dist/artifact/resolve.d.ts.map +1 -1
  6. package/dist/compliance/run.d.ts.map +1 -1
  7. package/dist/diff/engine.d.ts +18 -8
  8. package/dist/diff/engine.d.ts.map +1 -1
  9. package/dist/import/index.d.ts +5 -5
  10. package/dist/import/index.d.ts.map +1 -1
  11. package/dist/index.d.mts +12 -10
  12. package/dist/index.d.ts +12 -10
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1080 -838
  15. package/dist/index.js.map +4 -4
  16. package/dist/index.mjs +1049 -794
  17. package/dist/index.mjs.map +4 -4
  18. package/dist/lint/runner.d.ts +7 -7
  19. package/dist/lint/runner.d.ts.map +1 -1
  20. package/dist/matrix/manager.d.ts +4 -16
  21. package/dist/matrix/manager.d.ts.map +1 -1
  22. package/dist/merge/driver.d.ts +2 -2
  23. package/dist/merge/driver.d.ts.map +1 -1
  24. package/dist/merge/metadata-driver.d.ts +5 -4
  25. package/dist/merge/metadata-driver.d.ts.map +1 -1
  26. package/dist/migration/backend.d.ts +10 -7
  27. package/dist/migration/backend.d.ts.map +1 -1
  28. package/dist/pack/backends/json-envelope.d.ts.map +1 -1
  29. package/dist/pack/types.d.ts +9 -3
  30. package/dist/pack/types.d.ts.map +1 -1
  31. package/dist/pending/metadata.d.ts +1 -3
  32. package/dist/pending/metadata.d.ts.map +1 -1
  33. package/dist/recipients/index.d.ts +4 -3
  34. package/dist/recipients/index.d.ts.map +1 -1
  35. package/dist/report/generator.d.ts +4 -3
  36. package/dist/report/generator.d.ts.map +1 -1
  37. package/dist/reset/manager.d.ts +21 -3
  38. package/dist/reset/manager.d.ts.map +1 -1
  39. package/dist/service-identity/manager.d.ts +6 -3
  40. package/dist/service-identity/manager.d.ts.map +1 -1
  41. package/dist/sops/client.d.ts +80 -55
  42. package/dist/sops/client.d.ts.map +1 -1
  43. package/dist/sops/linux-stdin-fifo.d.ts +31 -0
  44. package/dist/sops/linux-stdin-fifo.d.ts.map +1 -0
  45. package/dist/source/compose.d.ts +10 -0
  46. package/dist/source/compose.d.ts.map +1 -0
  47. package/dist/source/default-bulk.d.ts +12 -0
  48. package/dist/source/default-bulk.d.ts.map +1 -0
  49. package/dist/source/encryption-backend.d.ts +85 -0
  50. package/dist/source/encryption-backend.d.ts.map +1 -0
  51. package/dist/source/errors.d.ts +19 -0
  52. package/dist/source/errors.d.ts.map +1 -0
  53. package/dist/source/filesystem-storage-backend.d.ts +26 -0
  54. package/dist/source/filesystem-storage-backend.d.ts.map +1 -0
  55. package/dist/source/guards.d.ts +14 -0
  56. package/dist/source/guards.d.ts.map +1 -0
  57. package/dist/source/index.d.ts +10 -0
  58. package/dist/source/index.d.ts.map +1 -0
  59. package/dist/source/mock-source.d.ts +89 -0
  60. package/dist/source/mock-source.d.ts.map +1 -0
  61. package/dist/source/storage-backend.d.ts +61 -0
  62. package/dist/source/storage-backend.d.ts.map +1 -0
  63. package/dist/source/types.d.ts +212 -0
  64. package/dist/source/types.d.ts.map +1 -0
  65. package/dist/structure/manager.d.ts +17 -3
  66. package/dist/structure/manager.d.ts.map +1 -1
  67. package/dist/sync/manager.d.ts +7 -6
  68. package/dist/sync/manager.d.ts.map +1 -1
  69. package/dist/types/index.d.ts +10 -23
  70. package/dist/types/index.d.ts.map +1 -1
  71. package/package.json +3 -3
  72. package/dist/bulk/ops.d.ts +0 -57
  73. package/dist/bulk/ops.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -306,13 +306,13 @@ var require_lib = __commonJS({
306
306
  "../../node_modules/write-file-atomic/lib/index.js"(exports, module) {
307
307
  "use strict";
308
308
  module.exports = writeFile;
309
- module.exports.sync = writeFileSync7;
309
+ module.exports.sync = writeFileSync8;
310
310
  module.exports._getTmpname = getTmpname;
311
311
  module.exports._cleanupOnExit = cleanupOnExit;
312
- var fs22 = __require("fs");
312
+ var fs23 = __require("fs");
313
313
  var crypto6 = __require("node:crypto");
314
314
  var { onExit } = require_cjs();
315
- var path29 = __require("path");
315
+ var path28 = __require("path");
316
316
  var { promisify } = __require("util");
317
317
  var activeFiles = {};
318
318
  var threadId = (function getId() {
@@ -330,7 +330,7 @@ var require_lib = __commonJS({
330
330
  function cleanupOnExit(tmpfile) {
331
331
  return () => {
332
332
  try {
333
- fs22.unlinkSync(typeof tmpfile === "function" ? tmpfile() : tmpfile);
333
+ fs23.unlinkSync(typeof tmpfile === "function" ? tmpfile() : tmpfile);
334
334
  } catch {
335
335
  }
336
336
  };
@@ -365,13 +365,13 @@ var require_lib = __commonJS({
365
365
  let fd;
366
366
  let tmpfile;
367
367
  const removeOnExitHandler = onExit(cleanupOnExit(() => tmpfile));
368
- const absoluteName = path29.resolve(filename);
368
+ const absoluteName = path28.resolve(filename);
369
369
  try {
370
370
  await serializeActiveFile(absoluteName);
371
- const truename = await promisify(fs22.realpath)(filename).catch(() => filename);
371
+ const truename = await promisify(fs23.realpath)(filename).catch(() => filename);
372
372
  tmpfile = getTmpname(truename);
373
373
  if (!options.mode || !options.chown) {
374
- const stats = await promisify(fs22.stat)(truename).catch(() => {
374
+ const stats = await promisify(fs23.stat)(truename).catch(() => {
375
375
  });
376
376
  if (stats) {
377
377
  if (options.mode == null) {
@@ -382,45 +382,45 @@ var require_lib = __commonJS({
382
382
  }
383
383
  }
384
384
  }
385
- fd = await promisify(fs22.open)(tmpfile, "w", options.mode);
385
+ fd = await promisify(fs23.open)(tmpfile, "w", options.mode);
386
386
  if (options.tmpfileCreated) {
387
387
  await options.tmpfileCreated(tmpfile);
388
388
  }
389
389
  if (ArrayBuffer.isView(data)) {
390
- await promisify(fs22.write)(fd, data, 0, data.length, 0);
390
+ await promisify(fs23.write)(fd, data, 0, data.length, 0);
391
391
  } else if (data != null) {
392
- await promisify(fs22.write)(fd, String(data), 0, String(options.encoding || "utf8"));
392
+ await promisify(fs23.write)(fd, String(data), 0, String(options.encoding || "utf8"));
393
393
  }
394
394
  if (options.fsync !== false) {
395
- await promisify(fs22.fsync)(fd);
395
+ await promisify(fs23.fsync)(fd);
396
396
  }
397
- await promisify(fs22.close)(fd);
397
+ await promisify(fs23.close)(fd);
398
398
  fd = null;
399
399
  if (options.chown) {
400
- await promisify(fs22.chown)(tmpfile, options.chown.uid, options.chown.gid).catch((err) => {
400
+ await promisify(fs23.chown)(tmpfile, options.chown.uid, options.chown.gid).catch((err) => {
401
401
  if (!isChownErrOk(err)) {
402
402
  throw err;
403
403
  }
404
404
  });
405
405
  }
406
406
  if (options.mode) {
407
- await promisify(fs22.chmod)(tmpfile, options.mode).catch((err) => {
407
+ await promisify(fs23.chmod)(tmpfile, options.mode).catch((err) => {
408
408
  if (!isChownErrOk(err)) {
409
409
  throw err;
410
410
  }
411
411
  });
412
412
  }
413
- await promisify(fs22.rename)(tmpfile, truename);
413
+ await promisify(fs23.rename)(tmpfile, truename);
414
414
  } finally {
415
415
  if (fd) {
416
- await promisify(fs22.close)(fd).catch(
416
+ await promisify(fs23.close)(fd).catch(
417
417
  /* istanbul ignore next */
418
418
  () => {
419
419
  }
420
420
  );
421
421
  }
422
422
  removeOnExitHandler();
423
- await promisify(fs22.unlink)(tmpfile).catch(() => {
423
+ await promisify(fs23.unlink)(tmpfile).catch(() => {
424
424
  });
425
425
  activeFiles[absoluteName].shift();
426
426
  if (activeFiles[absoluteName].length > 0) {
@@ -446,20 +446,20 @@ var require_lib = __commonJS({
446
446
  }
447
447
  return promise;
448
448
  }
449
- function writeFileSync7(filename, data, options) {
449
+ function writeFileSync8(filename, data, options) {
450
450
  if (typeof options === "string") {
451
451
  options = { encoding: options };
452
452
  } else if (!options) {
453
453
  options = {};
454
454
  }
455
455
  try {
456
- filename = fs22.realpathSync(filename);
456
+ filename = fs23.realpathSync(filename);
457
457
  } catch (ex) {
458
458
  }
459
459
  const tmpfile = getTmpname(filename);
460
460
  if (!options.mode || !options.chown) {
461
461
  try {
462
- const stats = fs22.statSync(filename);
462
+ const stats = fs23.statSync(filename);
463
463
  options = Object.assign({}, options);
464
464
  if (!options.mode) {
465
465
  options.mode = stats.mode;
@@ -475,23 +475,23 @@ var require_lib = __commonJS({
475
475
  const removeOnExitHandler = onExit(cleanup);
476
476
  let threw = true;
477
477
  try {
478
- fd = fs22.openSync(tmpfile, "w", options.mode || 438);
478
+ fd = fs23.openSync(tmpfile, "w", options.mode || 438);
479
479
  if (options.tmpfileCreated) {
480
480
  options.tmpfileCreated(tmpfile);
481
481
  }
482
482
  if (ArrayBuffer.isView(data)) {
483
- fs22.writeSync(fd, data, 0, data.length, 0);
483
+ fs23.writeSync(fd, data, 0, data.length, 0);
484
484
  } else if (data != null) {
485
- fs22.writeSync(fd, String(data), 0, String(options.encoding || "utf8"));
485
+ fs23.writeSync(fd, String(data), 0, String(options.encoding || "utf8"));
486
486
  }
487
487
  if (options.fsync !== false) {
488
- fs22.fsyncSync(fd);
488
+ fs23.fsyncSync(fd);
489
489
  }
490
- fs22.closeSync(fd);
490
+ fs23.closeSync(fd);
491
491
  fd = null;
492
492
  if (options.chown) {
493
493
  try {
494
- fs22.chownSync(tmpfile, options.chown.uid, options.chown.gid);
494
+ fs23.chownSync(tmpfile, options.chown.uid, options.chown.gid);
495
495
  } catch (err) {
496
496
  if (!isChownErrOk(err)) {
497
497
  throw err;
@@ -500,19 +500,19 @@ var require_lib = __commonJS({
500
500
  }
501
501
  if (options.mode) {
502
502
  try {
503
- fs22.chmodSync(tmpfile, options.mode);
503
+ fs23.chmodSync(tmpfile, options.mode);
504
504
  } catch (err) {
505
505
  if (!isChownErrOk(err)) {
506
506
  throw err;
507
507
  }
508
508
  }
509
509
  }
510
- fs22.renameSync(tmpfile, filename);
510
+ fs23.renameSync(tmpfile, filename);
511
511
  threw = false;
512
512
  } finally {
513
513
  if (fd) {
514
514
  try {
515
- fs22.closeSync(fd);
515
+ fs23.closeSync(fd);
516
516
  } catch (ex) {
517
517
  }
518
518
  }
@@ -551,54 +551,54 @@ var require_polyfills = __commonJS({
551
551
  }
552
552
  var chdir;
553
553
  module.exports = patch;
554
- function patch(fs22) {
554
+ function patch(fs23) {
555
555
  if (constants.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
556
- patchLchmod(fs22);
557
- }
558
- if (!fs22.lutimes) {
559
- patchLutimes(fs22);
560
- }
561
- fs22.chown = chownFix(fs22.chown);
562
- fs22.fchown = chownFix(fs22.fchown);
563
- fs22.lchown = chownFix(fs22.lchown);
564
- fs22.chmod = chmodFix(fs22.chmod);
565
- fs22.fchmod = chmodFix(fs22.fchmod);
566
- fs22.lchmod = chmodFix(fs22.lchmod);
567
- fs22.chownSync = chownFixSync(fs22.chownSync);
568
- fs22.fchownSync = chownFixSync(fs22.fchownSync);
569
- fs22.lchownSync = chownFixSync(fs22.lchownSync);
570
- fs22.chmodSync = chmodFixSync(fs22.chmodSync);
571
- fs22.fchmodSync = chmodFixSync(fs22.fchmodSync);
572
- fs22.lchmodSync = chmodFixSync(fs22.lchmodSync);
573
- fs22.stat = statFix(fs22.stat);
574
- fs22.fstat = statFix(fs22.fstat);
575
- fs22.lstat = statFix(fs22.lstat);
576
- fs22.statSync = statFixSync(fs22.statSync);
577
- fs22.fstatSync = statFixSync(fs22.fstatSync);
578
- fs22.lstatSync = statFixSync(fs22.lstatSync);
579
- if (fs22.chmod && !fs22.lchmod) {
580
- fs22.lchmod = function(path29, mode, cb) {
556
+ patchLchmod(fs23);
557
+ }
558
+ if (!fs23.lutimes) {
559
+ patchLutimes(fs23);
560
+ }
561
+ fs23.chown = chownFix(fs23.chown);
562
+ fs23.fchown = chownFix(fs23.fchown);
563
+ fs23.lchown = chownFix(fs23.lchown);
564
+ fs23.chmod = chmodFix(fs23.chmod);
565
+ fs23.fchmod = chmodFix(fs23.fchmod);
566
+ fs23.lchmod = chmodFix(fs23.lchmod);
567
+ fs23.chownSync = chownFixSync(fs23.chownSync);
568
+ fs23.fchownSync = chownFixSync(fs23.fchownSync);
569
+ fs23.lchownSync = chownFixSync(fs23.lchownSync);
570
+ fs23.chmodSync = chmodFixSync(fs23.chmodSync);
571
+ fs23.fchmodSync = chmodFixSync(fs23.fchmodSync);
572
+ fs23.lchmodSync = chmodFixSync(fs23.lchmodSync);
573
+ fs23.stat = statFix(fs23.stat);
574
+ fs23.fstat = statFix(fs23.fstat);
575
+ fs23.lstat = statFix(fs23.lstat);
576
+ fs23.statSync = statFixSync(fs23.statSync);
577
+ fs23.fstatSync = statFixSync(fs23.fstatSync);
578
+ fs23.lstatSync = statFixSync(fs23.lstatSync);
579
+ if (fs23.chmod && !fs23.lchmod) {
580
+ fs23.lchmod = function(path28, mode, cb) {
581
581
  if (cb) process.nextTick(cb);
582
582
  };
583
- fs22.lchmodSync = function() {
583
+ fs23.lchmodSync = function() {
584
584
  };
585
585
  }
586
- if (fs22.chown && !fs22.lchown) {
587
- fs22.lchown = function(path29, uid, gid, cb) {
586
+ if (fs23.chown && !fs23.lchown) {
587
+ fs23.lchown = function(path28, uid, gid, cb) {
588
588
  if (cb) process.nextTick(cb);
589
589
  };
590
- fs22.lchownSync = function() {
590
+ fs23.lchownSync = function() {
591
591
  };
592
592
  }
593
593
  if (platform === "win32") {
594
- fs22.rename = typeof fs22.rename !== "function" ? fs22.rename : (function(fs$rename) {
594
+ fs23.rename = typeof fs23.rename !== "function" ? fs23.rename : (function(fs$rename) {
595
595
  function rename(from, to, cb) {
596
596
  var start = Date.now();
597
597
  var backoff = 0;
598
598
  fs$rename(from, to, function CB(er) {
599
599
  if (er && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY") && Date.now() - start < 6e4) {
600
600
  setTimeout(function() {
601
- fs22.stat(to, function(stater, st) {
601
+ fs23.stat(to, function(stater, st) {
602
602
  if (stater && stater.code === "ENOENT")
603
603
  fs$rename(from, to, CB);
604
604
  else
@@ -614,9 +614,9 @@ var require_polyfills = __commonJS({
614
614
  }
615
615
  if (Object.setPrototypeOf) Object.setPrototypeOf(rename, fs$rename);
616
616
  return rename;
617
- })(fs22.rename);
617
+ })(fs23.rename);
618
618
  }
619
- fs22.read = typeof fs22.read !== "function" ? fs22.read : (function(fs$read) {
619
+ fs23.read = typeof fs23.read !== "function" ? fs23.read : (function(fs$read) {
620
620
  function read(fd, buffer, offset, length, position, callback_) {
621
621
  var callback;
622
622
  if (callback_ && typeof callback_ === "function") {
@@ -624,22 +624,22 @@ var require_polyfills = __commonJS({
624
624
  callback = function(er, _, __) {
625
625
  if (er && er.code === "EAGAIN" && eagCounter < 10) {
626
626
  eagCounter++;
627
- return fs$read.call(fs22, fd, buffer, offset, length, position, callback);
627
+ return fs$read.call(fs23, fd, buffer, offset, length, position, callback);
628
628
  }
629
629
  callback_.apply(this, arguments);
630
630
  };
631
631
  }
632
- return fs$read.call(fs22, fd, buffer, offset, length, position, callback);
632
+ return fs$read.call(fs23, fd, buffer, offset, length, position, callback);
633
633
  }
634
634
  if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read);
635
635
  return read;
636
- })(fs22.read);
637
- fs22.readSync = typeof fs22.readSync !== "function" ? fs22.readSync : /* @__PURE__ */ (function(fs$readSync) {
636
+ })(fs23.read);
637
+ fs23.readSync = typeof fs23.readSync !== "function" ? fs23.readSync : /* @__PURE__ */ (function(fs$readSync) {
638
638
  return function(fd, buffer, offset, length, position) {
639
639
  var eagCounter = 0;
640
640
  while (true) {
641
641
  try {
642
- return fs$readSync.call(fs22, fd, buffer, offset, length, position);
642
+ return fs$readSync.call(fs23, fd, buffer, offset, length, position);
643
643
  } catch (er) {
644
644
  if (er.code === "EAGAIN" && eagCounter < 10) {
645
645
  eagCounter++;
@@ -649,11 +649,11 @@ var require_polyfills = __commonJS({
649
649
  }
650
650
  }
651
651
  };
652
- })(fs22.readSync);
653
- function patchLchmod(fs23) {
654
- fs23.lchmod = function(path29, mode, callback) {
655
- fs23.open(
656
- path29,
652
+ })(fs23.readSync);
653
+ function patchLchmod(fs24) {
654
+ fs24.lchmod = function(path28, mode, callback) {
655
+ fs24.open(
656
+ path28,
657
657
  constants.O_WRONLY | constants.O_SYMLINK,
658
658
  mode,
659
659
  function(err, fd) {
@@ -661,80 +661,80 @@ var require_polyfills = __commonJS({
661
661
  if (callback) callback(err);
662
662
  return;
663
663
  }
664
- fs23.fchmod(fd, mode, function(err2) {
665
- fs23.close(fd, function(err22) {
664
+ fs24.fchmod(fd, mode, function(err2) {
665
+ fs24.close(fd, function(err22) {
666
666
  if (callback) callback(err2 || err22);
667
667
  });
668
668
  });
669
669
  }
670
670
  );
671
671
  };
672
- fs23.lchmodSync = function(path29, mode) {
673
- var fd = fs23.openSync(path29, constants.O_WRONLY | constants.O_SYMLINK, mode);
672
+ fs24.lchmodSync = function(path28, mode) {
673
+ var fd = fs24.openSync(path28, constants.O_WRONLY | constants.O_SYMLINK, mode);
674
674
  var threw = true;
675
675
  var ret;
676
676
  try {
677
- ret = fs23.fchmodSync(fd, mode);
677
+ ret = fs24.fchmodSync(fd, mode);
678
678
  threw = false;
679
679
  } finally {
680
680
  if (threw) {
681
681
  try {
682
- fs23.closeSync(fd);
682
+ fs24.closeSync(fd);
683
683
  } catch (er) {
684
684
  }
685
685
  } else {
686
- fs23.closeSync(fd);
686
+ fs24.closeSync(fd);
687
687
  }
688
688
  }
689
689
  return ret;
690
690
  };
691
691
  }
692
- function patchLutimes(fs23) {
693
- if (constants.hasOwnProperty("O_SYMLINK") && fs23.futimes) {
694
- fs23.lutimes = function(path29, at, mt, cb) {
695
- fs23.open(path29, constants.O_SYMLINK, function(er, fd) {
692
+ function patchLutimes(fs24) {
693
+ if (constants.hasOwnProperty("O_SYMLINK") && fs24.futimes) {
694
+ fs24.lutimes = function(path28, at, mt, cb) {
695
+ fs24.open(path28, constants.O_SYMLINK, function(er, fd) {
696
696
  if (er) {
697
697
  if (cb) cb(er);
698
698
  return;
699
699
  }
700
- fs23.futimes(fd, at, mt, function(er2) {
701
- fs23.close(fd, function(er22) {
700
+ fs24.futimes(fd, at, mt, function(er2) {
701
+ fs24.close(fd, function(er22) {
702
702
  if (cb) cb(er2 || er22);
703
703
  });
704
704
  });
705
705
  });
706
706
  };
707
- fs23.lutimesSync = function(path29, at, mt) {
708
- var fd = fs23.openSync(path29, constants.O_SYMLINK);
707
+ fs24.lutimesSync = function(path28, at, mt) {
708
+ var fd = fs24.openSync(path28, constants.O_SYMLINK);
709
709
  var ret;
710
710
  var threw = true;
711
711
  try {
712
- ret = fs23.futimesSync(fd, at, mt);
712
+ ret = fs24.futimesSync(fd, at, mt);
713
713
  threw = false;
714
714
  } finally {
715
715
  if (threw) {
716
716
  try {
717
- fs23.closeSync(fd);
717
+ fs24.closeSync(fd);
718
718
  } catch (er) {
719
719
  }
720
720
  } else {
721
- fs23.closeSync(fd);
721
+ fs24.closeSync(fd);
722
722
  }
723
723
  }
724
724
  return ret;
725
725
  };
726
- } else if (fs23.futimes) {
727
- fs23.lutimes = function(_a, _b, _c, cb) {
726
+ } else if (fs24.futimes) {
727
+ fs24.lutimes = function(_a, _b, _c, cb) {
728
728
  if (cb) process.nextTick(cb);
729
729
  };
730
- fs23.lutimesSync = function() {
730
+ fs24.lutimesSync = function() {
731
731
  };
732
732
  }
733
733
  }
734
734
  function chmodFix(orig) {
735
735
  if (!orig) return orig;
736
736
  return function(target, mode, cb) {
737
- return orig.call(fs22, target, mode, function(er) {
737
+ return orig.call(fs23, target, mode, function(er) {
738
738
  if (chownErOk(er)) er = null;
739
739
  if (cb) cb.apply(this, arguments);
740
740
  });
@@ -744,7 +744,7 @@ var require_polyfills = __commonJS({
744
744
  if (!orig) return orig;
745
745
  return function(target, mode) {
746
746
  try {
747
- return orig.call(fs22, target, mode);
747
+ return orig.call(fs23, target, mode);
748
748
  } catch (er) {
749
749
  if (!chownErOk(er)) throw er;
750
750
  }
@@ -753,7 +753,7 @@ var require_polyfills = __commonJS({
753
753
  function chownFix(orig) {
754
754
  if (!orig) return orig;
755
755
  return function(target, uid, gid, cb) {
756
- return orig.call(fs22, target, uid, gid, function(er) {
756
+ return orig.call(fs23, target, uid, gid, function(er) {
757
757
  if (chownErOk(er)) er = null;
758
758
  if (cb) cb.apply(this, arguments);
759
759
  });
@@ -763,7 +763,7 @@ var require_polyfills = __commonJS({
763
763
  if (!orig) return orig;
764
764
  return function(target, uid, gid) {
765
765
  try {
766
- return orig.call(fs22, target, uid, gid);
766
+ return orig.call(fs23, target, uid, gid);
767
767
  } catch (er) {
768
768
  if (!chownErOk(er)) throw er;
769
769
  }
@@ -783,13 +783,13 @@ var require_polyfills = __commonJS({
783
783
  }
784
784
  if (cb) cb.apply(this, arguments);
785
785
  }
786
- return options ? orig.call(fs22, target, options, callback) : orig.call(fs22, target, callback);
786
+ return options ? orig.call(fs23, target, options, callback) : orig.call(fs23, target, callback);
787
787
  };
788
788
  }
789
789
  function statFixSync(orig) {
790
790
  if (!orig) return orig;
791
791
  return function(target, options) {
792
- var stats = options ? orig.call(fs22, target, options) : orig.call(fs22, target);
792
+ var stats = options ? orig.call(fs23, target, options) : orig.call(fs23, target);
793
793
  if (stats) {
794
794
  if (stats.uid < 0) stats.uid += 4294967296;
795
795
  if (stats.gid < 0) stats.gid += 4294967296;
@@ -818,16 +818,16 @@ var require_legacy_streams = __commonJS({
818
818
  "../../node_modules/graceful-fs/legacy-streams.js"(exports, module) {
819
819
  var Stream = __require("stream").Stream;
820
820
  module.exports = legacy;
821
- function legacy(fs22) {
821
+ function legacy(fs23) {
822
822
  return {
823
823
  ReadStream,
824
824
  WriteStream
825
825
  };
826
- function ReadStream(path29, options) {
827
- if (!(this instanceof ReadStream)) return new ReadStream(path29, options);
826
+ function ReadStream(path28, options) {
827
+ if (!(this instanceof ReadStream)) return new ReadStream(path28, options);
828
828
  Stream.call(this);
829
829
  var self = this;
830
- this.path = path29;
830
+ this.path = path28;
831
831
  this.fd = null;
832
832
  this.readable = true;
833
833
  this.paused = false;
@@ -861,7 +861,7 @@ var require_legacy_streams = __commonJS({
861
861
  });
862
862
  return;
863
863
  }
864
- fs22.open(this.path, this.flags, this.mode, function(err, fd) {
864
+ fs23.open(this.path, this.flags, this.mode, function(err, fd) {
865
865
  if (err) {
866
866
  self.emit("error", err);
867
867
  self.readable = false;
@@ -872,10 +872,10 @@ var require_legacy_streams = __commonJS({
872
872
  self._read();
873
873
  });
874
874
  }
875
- function WriteStream(path29, options) {
876
- if (!(this instanceof WriteStream)) return new WriteStream(path29, options);
875
+ function WriteStream(path28, options) {
876
+ if (!(this instanceof WriteStream)) return new WriteStream(path28, options);
877
877
  Stream.call(this);
878
- this.path = path29;
878
+ this.path = path28;
879
879
  this.fd = null;
880
880
  this.writable = true;
881
881
  this.flags = "w";
@@ -900,7 +900,7 @@ var require_legacy_streams = __commonJS({
900
900
  this.busy = false;
901
901
  this._queue = [];
902
902
  if (this.fd === null) {
903
- this._open = fs22.open;
903
+ this._open = fs23.open;
904
904
  this._queue.push([this._open, this.path, this.flags, this.mode, void 0]);
905
905
  this.flush();
906
906
  }
@@ -935,7 +935,7 @@ var require_clone = __commonJS({
935
935
  // ../../node_modules/graceful-fs/graceful-fs.js
936
936
  var require_graceful_fs = __commonJS({
937
937
  "../../node_modules/graceful-fs/graceful-fs.js"(exports, module) {
938
- var fs22 = __require("fs");
938
+ var fs23 = __require("fs");
939
939
  var polyfills = require_polyfills();
940
940
  var legacy = require_legacy_streams();
941
941
  var clone = require_clone();
@@ -967,12 +967,12 @@ var require_graceful_fs = __commonJS({
967
967
  m = "GFS4: " + m.split(/\n/).join("\nGFS4: ");
968
968
  console.error(m);
969
969
  };
970
- if (!fs22[gracefulQueue]) {
970
+ if (!fs23[gracefulQueue]) {
971
971
  queue = global[gracefulQueue] || [];
972
- publishQueue(fs22, queue);
973
- fs22.close = (function(fs$close) {
972
+ publishQueue(fs23, queue);
973
+ fs23.close = (function(fs$close) {
974
974
  function close(fd, cb) {
975
- return fs$close.call(fs22, fd, function(err) {
975
+ return fs$close.call(fs23, fd, function(err) {
976
976
  if (!err) {
977
977
  resetQueue();
978
978
  }
@@ -984,48 +984,48 @@ var require_graceful_fs = __commonJS({
984
984
  value: fs$close
985
985
  });
986
986
  return close;
987
- })(fs22.close);
988
- fs22.closeSync = (function(fs$closeSync) {
989
- function closeSync2(fd) {
990
- fs$closeSync.apply(fs22, arguments);
987
+ })(fs23.close);
988
+ fs23.closeSync = (function(fs$closeSync) {
989
+ function closeSync3(fd) {
990
+ fs$closeSync.apply(fs23, arguments);
991
991
  resetQueue();
992
992
  }
993
- Object.defineProperty(closeSync2, previousSymbol, {
993
+ Object.defineProperty(closeSync3, previousSymbol, {
994
994
  value: fs$closeSync
995
995
  });
996
- return closeSync2;
997
- })(fs22.closeSync);
996
+ return closeSync3;
997
+ })(fs23.closeSync);
998
998
  if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
999
999
  process.on("exit", function() {
1000
- debug(fs22[gracefulQueue]);
1001
- __require("assert").equal(fs22[gracefulQueue].length, 0);
1000
+ debug(fs23[gracefulQueue]);
1001
+ __require("assert").equal(fs23[gracefulQueue].length, 0);
1002
1002
  });
1003
1003
  }
1004
1004
  }
1005
1005
  var queue;
1006
1006
  if (!global[gracefulQueue]) {
1007
- publishQueue(global, fs22[gracefulQueue]);
1008
- }
1009
- module.exports = patch(clone(fs22));
1010
- if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs22.__patched) {
1011
- module.exports = patch(fs22);
1012
- fs22.__patched = true;
1013
- }
1014
- function patch(fs23) {
1015
- polyfills(fs23);
1016
- fs23.gracefulify = patch;
1017
- fs23.createReadStream = createReadStream;
1018
- fs23.createWriteStream = createWriteStream;
1019
- var fs$readFile = fs23.readFile;
1020
- fs23.readFile = readFile;
1021
- function readFile(path29, options, cb) {
1007
+ publishQueue(global, fs23[gracefulQueue]);
1008
+ }
1009
+ module.exports = patch(clone(fs23));
1010
+ if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs23.__patched) {
1011
+ module.exports = patch(fs23);
1012
+ fs23.__patched = true;
1013
+ }
1014
+ function patch(fs24) {
1015
+ polyfills(fs24);
1016
+ fs24.gracefulify = patch;
1017
+ fs24.createReadStream = createReadStream;
1018
+ fs24.createWriteStream = createWriteStream;
1019
+ var fs$readFile = fs24.readFile;
1020
+ fs24.readFile = readFile;
1021
+ function readFile(path28, options, cb) {
1022
1022
  if (typeof options === "function")
1023
1023
  cb = options, options = null;
1024
- return go$readFile(path29, options, cb);
1025
- function go$readFile(path30, options2, cb2, startTime) {
1026
- return fs$readFile(path30, options2, function(err) {
1024
+ return go$readFile(path28, options, cb);
1025
+ function go$readFile(path29, options2, cb2, startTime) {
1026
+ return fs$readFile(path29, options2, function(err) {
1027
1027
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
1028
- enqueue([go$readFile, [path30, options2, cb2], err, startTime || Date.now(), Date.now()]);
1028
+ enqueue([go$readFile, [path29, options2, cb2], err, startTime || Date.now(), Date.now()]);
1029
1029
  else {
1030
1030
  if (typeof cb2 === "function")
1031
1031
  cb2.apply(this, arguments);
@@ -1033,16 +1033,16 @@ var require_graceful_fs = __commonJS({
1033
1033
  });
1034
1034
  }
1035
1035
  }
1036
- var fs$writeFile = fs23.writeFile;
1037
- fs23.writeFile = writeFile;
1038
- function writeFile(path29, data, options, cb) {
1036
+ var fs$writeFile = fs24.writeFile;
1037
+ fs24.writeFile = writeFile;
1038
+ function writeFile(path28, data, options, cb) {
1039
1039
  if (typeof options === "function")
1040
1040
  cb = options, options = null;
1041
- return go$writeFile(path29, data, options, cb);
1042
- function go$writeFile(path30, data2, options2, cb2, startTime) {
1043
- return fs$writeFile(path30, data2, options2, function(err) {
1041
+ return go$writeFile(path28, data, options, cb);
1042
+ function go$writeFile(path29, data2, options2, cb2, startTime) {
1043
+ return fs$writeFile(path29, data2, options2, function(err) {
1044
1044
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
1045
- enqueue([go$writeFile, [path30, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
1045
+ enqueue([go$writeFile, [path29, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
1046
1046
  else {
1047
1047
  if (typeof cb2 === "function")
1048
1048
  cb2.apply(this, arguments);
@@ -1050,17 +1050,17 @@ var require_graceful_fs = __commonJS({
1050
1050
  });
1051
1051
  }
1052
1052
  }
1053
- var fs$appendFile = fs23.appendFile;
1053
+ var fs$appendFile = fs24.appendFile;
1054
1054
  if (fs$appendFile)
1055
- fs23.appendFile = appendFile;
1056
- function appendFile(path29, data, options, cb) {
1055
+ fs24.appendFile = appendFile;
1056
+ function appendFile(path28, data, options, cb) {
1057
1057
  if (typeof options === "function")
1058
1058
  cb = options, options = null;
1059
- return go$appendFile(path29, data, options, cb);
1060
- function go$appendFile(path30, data2, options2, cb2, startTime) {
1061
- return fs$appendFile(path30, data2, options2, function(err) {
1059
+ return go$appendFile(path28, data, options, cb);
1060
+ function go$appendFile(path29, data2, options2, cb2, startTime) {
1061
+ return fs$appendFile(path29, data2, options2, function(err) {
1062
1062
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
1063
- enqueue([go$appendFile, [path30, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
1063
+ enqueue([go$appendFile, [path29, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
1064
1064
  else {
1065
1065
  if (typeof cb2 === "function")
1066
1066
  cb2.apply(this, arguments);
@@ -1068,9 +1068,9 @@ var require_graceful_fs = __commonJS({
1068
1068
  });
1069
1069
  }
1070
1070
  }
1071
- var fs$copyFile = fs23.copyFile;
1071
+ var fs$copyFile = fs24.copyFile;
1072
1072
  if (fs$copyFile)
1073
- fs23.copyFile = copyFile;
1073
+ fs24.copyFile = copyFile;
1074
1074
  function copyFile(src, dest, flags, cb) {
1075
1075
  if (typeof flags === "function") {
1076
1076
  cb = flags;
@@ -1088,34 +1088,34 @@ var require_graceful_fs = __commonJS({
1088
1088
  });
1089
1089
  }
1090
1090
  }
1091
- var fs$readdir = fs23.readdir;
1092
- fs23.readdir = readdir;
1091
+ var fs$readdir = fs24.readdir;
1092
+ fs24.readdir = readdir;
1093
1093
  var noReaddirOptionVersions = /^v[0-5]\./;
1094
- function readdir(path29, options, cb) {
1094
+ function readdir(path28, options, cb) {
1095
1095
  if (typeof options === "function")
1096
1096
  cb = options, options = null;
1097
- var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path30, options2, cb2, startTime) {
1098
- return fs$readdir(path30, fs$readdirCallback(
1099
- path30,
1097
+ var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path29, options2, cb2, startTime) {
1098
+ return fs$readdir(path29, fs$readdirCallback(
1099
+ path29,
1100
1100
  options2,
1101
1101
  cb2,
1102
1102
  startTime
1103
1103
  ));
1104
- } : function go$readdir2(path30, options2, cb2, startTime) {
1105
- return fs$readdir(path30, options2, fs$readdirCallback(
1106
- path30,
1104
+ } : function go$readdir2(path29, options2, cb2, startTime) {
1105
+ return fs$readdir(path29, options2, fs$readdirCallback(
1106
+ path29,
1107
1107
  options2,
1108
1108
  cb2,
1109
1109
  startTime
1110
1110
  ));
1111
1111
  };
1112
- return go$readdir(path29, options, cb);
1113
- function fs$readdirCallback(path30, options2, cb2, startTime) {
1112
+ return go$readdir(path28, options, cb);
1113
+ function fs$readdirCallback(path29, options2, cb2, startTime) {
1114
1114
  return function(err, files) {
1115
1115
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
1116
1116
  enqueue([
1117
1117
  go$readdir,
1118
- [path30, options2, cb2],
1118
+ [path29, options2, cb2],
1119
1119
  err,
1120
1120
  startTime || Date.now(),
1121
1121
  Date.now()
@@ -1130,21 +1130,21 @@ var require_graceful_fs = __commonJS({
1130
1130
  }
1131
1131
  }
1132
1132
  if (process.version.substr(0, 4) === "v0.8") {
1133
- var legStreams = legacy(fs23);
1133
+ var legStreams = legacy(fs24);
1134
1134
  ReadStream = legStreams.ReadStream;
1135
1135
  WriteStream = legStreams.WriteStream;
1136
1136
  }
1137
- var fs$ReadStream = fs23.ReadStream;
1137
+ var fs$ReadStream = fs24.ReadStream;
1138
1138
  if (fs$ReadStream) {
1139
1139
  ReadStream.prototype = Object.create(fs$ReadStream.prototype);
1140
1140
  ReadStream.prototype.open = ReadStream$open;
1141
1141
  }
1142
- var fs$WriteStream = fs23.WriteStream;
1142
+ var fs$WriteStream = fs24.WriteStream;
1143
1143
  if (fs$WriteStream) {
1144
1144
  WriteStream.prototype = Object.create(fs$WriteStream.prototype);
1145
1145
  WriteStream.prototype.open = WriteStream$open;
1146
1146
  }
1147
- Object.defineProperty(fs23, "ReadStream", {
1147
+ Object.defineProperty(fs24, "ReadStream", {
1148
1148
  get: function() {
1149
1149
  return ReadStream;
1150
1150
  },
@@ -1154,7 +1154,7 @@ var require_graceful_fs = __commonJS({
1154
1154
  enumerable: true,
1155
1155
  configurable: true
1156
1156
  });
1157
- Object.defineProperty(fs23, "WriteStream", {
1157
+ Object.defineProperty(fs24, "WriteStream", {
1158
1158
  get: function() {
1159
1159
  return WriteStream;
1160
1160
  },
@@ -1165,7 +1165,7 @@ var require_graceful_fs = __commonJS({
1165
1165
  configurable: true
1166
1166
  });
1167
1167
  var FileReadStream = ReadStream;
1168
- Object.defineProperty(fs23, "FileReadStream", {
1168
+ Object.defineProperty(fs24, "FileReadStream", {
1169
1169
  get: function() {
1170
1170
  return FileReadStream;
1171
1171
  },
@@ -1176,7 +1176,7 @@ var require_graceful_fs = __commonJS({
1176
1176
  configurable: true
1177
1177
  });
1178
1178
  var FileWriteStream = WriteStream;
1179
- Object.defineProperty(fs23, "FileWriteStream", {
1179
+ Object.defineProperty(fs24, "FileWriteStream", {
1180
1180
  get: function() {
1181
1181
  return FileWriteStream;
1182
1182
  },
@@ -1186,7 +1186,7 @@ var require_graceful_fs = __commonJS({
1186
1186
  enumerable: true,
1187
1187
  configurable: true
1188
1188
  });
1189
- function ReadStream(path29, options) {
1189
+ function ReadStream(path28, options) {
1190
1190
  if (this instanceof ReadStream)
1191
1191
  return fs$ReadStream.apply(this, arguments), this;
1192
1192
  else
@@ -1206,7 +1206,7 @@ var require_graceful_fs = __commonJS({
1206
1206
  }
1207
1207
  });
1208
1208
  }
1209
- function WriteStream(path29, options) {
1209
+ function WriteStream(path28, options) {
1210
1210
  if (this instanceof WriteStream)
1211
1211
  return fs$WriteStream.apply(this, arguments), this;
1212
1212
  else
@@ -1224,22 +1224,22 @@ var require_graceful_fs = __commonJS({
1224
1224
  }
1225
1225
  });
1226
1226
  }
1227
- function createReadStream(path29, options) {
1228
- return new fs23.ReadStream(path29, options);
1227
+ function createReadStream(path28, options) {
1228
+ return new fs24.ReadStream(path28, options);
1229
1229
  }
1230
- function createWriteStream(path29, options) {
1231
- return new fs23.WriteStream(path29, options);
1230
+ function createWriteStream(path28, options) {
1231
+ return new fs24.WriteStream(path28, options);
1232
1232
  }
1233
- var fs$open = fs23.open;
1234
- fs23.open = open;
1235
- function open(path29, flags, mode, cb) {
1233
+ var fs$open = fs24.open;
1234
+ fs24.open = open;
1235
+ function open(path28, flags, mode, cb) {
1236
1236
  if (typeof mode === "function")
1237
1237
  cb = mode, mode = null;
1238
- return go$open(path29, flags, mode, cb);
1239
- function go$open(path30, flags2, mode2, cb2, startTime) {
1240
- return fs$open(path30, flags2, mode2, function(err, fd) {
1238
+ return go$open(path28, flags, mode, cb);
1239
+ function go$open(path29, flags2, mode2, cb2, startTime) {
1240
+ return fs$open(path29, flags2, mode2, function(err, fd) {
1241
1241
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
1242
- enqueue([go$open, [path30, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
1242
+ enqueue([go$open, [path29, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
1243
1243
  else {
1244
1244
  if (typeof cb2 === "function")
1245
1245
  cb2.apply(this, arguments);
@@ -1247,20 +1247,20 @@ var require_graceful_fs = __commonJS({
1247
1247
  });
1248
1248
  }
1249
1249
  }
1250
- return fs23;
1250
+ return fs24;
1251
1251
  }
1252
1252
  function enqueue(elem) {
1253
1253
  debug("ENQUEUE", elem[0].name, elem[1]);
1254
- fs22[gracefulQueue].push(elem);
1254
+ fs23[gracefulQueue].push(elem);
1255
1255
  retry();
1256
1256
  }
1257
1257
  var retryTimer;
1258
1258
  function resetQueue() {
1259
1259
  var now = Date.now();
1260
- for (var i = 0; i < fs22[gracefulQueue].length; ++i) {
1261
- if (fs22[gracefulQueue][i].length > 2) {
1262
- fs22[gracefulQueue][i][3] = now;
1263
- fs22[gracefulQueue][i][4] = now;
1260
+ for (var i = 0; i < fs23[gracefulQueue].length; ++i) {
1261
+ if (fs23[gracefulQueue][i].length > 2) {
1262
+ fs23[gracefulQueue][i][3] = now;
1263
+ fs23[gracefulQueue][i][4] = now;
1264
1264
  }
1265
1265
  }
1266
1266
  retry();
@@ -1268,9 +1268,9 @@ var require_graceful_fs = __commonJS({
1268
1268
  function retry() {
1269
1269
  clearTimeout(retryTimer);
1270
1270
  retryTimer = void 0;
1271
- if (fs22[gracefulQueue].length === 0)
1271
+ if (fs23[gracefulQueue].length === 0)
1272
1272
  return;
1273
- var elem = fs22[gracefulQueue].shift();
1273
+ var elem = fs23[gracefulQueue].shift();
1274
1274
  var fn = elem[0];
1275
1275
  var args = elem[1];
1276
1276
  var err = elem[2];
@@ -1292,7 +1292,7 @@ var require_graceful_fs = __commonJS({
1292
1292
  debug("RETRY", fn.name, args);
1293
1293
  fn.apply(null, args.concat([startTime]));
1294
1294
  } else {
1295
- fs22[gracefulQueue].push(elem);
1295
+ fs23[gracefulQueue].push(elem);
1296
1296
  }
1297
1297
  }
1298
1298
  if (retryTimer === void 0) {
@@ -1727,10 +1727,10 @@ var require_mtime_precision = __commonJS({
1727
1727
  "../../node_modules/proper-lockfile/lib/mtime-precision.js"(exports, module) {
1728
1728
  "use strict";
1729
1729
  var cacheSymbol = /* @__PURE__ */ Symbol();
1730
- function probe(file, fs22, callback) {
1731
- const cachedPrecision = fs22[cacheSymbol];
1730
+ function probe(file, fs23, callback) {
1731
+ const cachedPrecision = fs23[cacheSymbol];
1732
1732
  if (cachedPrecision) {
1733
- return fs22.stat(file, (err, stat) => {
1733
+ return fs23.stat(file, (err, stat) => {
1734
1734
  if (err) {
1735
1735
  return callback(err);
1736
1736
  }
@@ -1738,16 +1738,16 @@ var require_mtime_precision = __commonJS({
1738
1738
  });
1739
1739
  }
1740
1740
  const mtime = new Date(Math.ceil(Date.now() / 1e3) * 1e3 + 5);
1741
- fs22.utimes(file, mtime, mtime, (err) => {
1741
+ fs23.utimes(file, mtime, mtime, (err) => {
1742
1742
  if (err) {
1743
1743
  return callback(err);
1744
1744
  }
1745
- fs22.stat(file, (err2, stat) => {
1745
+ fs23.stat(file, (err2, stat) => {
1746
1746
  if (err2) {
1747
1747
  return callback(err2);
1748
1748
  }
1749
1749
  const precision = stat.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
1750
- Object.defineProperty(fs22, cacheSymbol, { value: precision });
1750
+ Object.defineProperty(fs23, cacheSymbol, { value: precision });
1751
1751
  callback(null, stat.mtime, precision);
1752
1752
  });
1753
1753
  });
@@ -1768,8 +1768,8 @@ var require_mtime_precision = __commonJS({
1768
1768
  var require_lockfile = __commonJS({
1769
1769
  "../../node_modules/proper-lockfile/lib/lockfile.js"(exports, module) {
1770
1770
  "use strict";
1771
- var path29 = __require("path");
1772
- var fs22 = require_graceful_fs();
1771
+ var path28 = __require("path");
1772
+ var fs23 = require_graceful_fs();
1773
1773
  var retry = require_retry2();
1774
1774
  var onExit = require_signal_exit();
1775
1775
  var mtimePrecision = require_mtime_precision();
@@ -1779,7 +1779,7 @@ var require_lockfile = __commonJS({
1779
1779
  }
1780
1780
  function resolveCanonicalPath(file, options, callback) {
1781
1781
  if (!options.realpath) {
1782
- return callback(null, path29.resolve(file));
1782
+ return callback(null, path28.resolve(file));
1783
1783
  }
1784
1784
  options.fs.realpath(file, callback);
1785
1785
  }
@@ -1900,7 +1900,7 @@ var require_lockfile = __commonJS({
1900
1900
  update: null,
1901
1901
  realpath: true,
1902
1902
  retries: 0,
1903
- fs: fs22,
1903
+ fs: fs23,
1904
1904
  onCompromised: (err) => {
1905
1905
  throw err;
1906
1906
  },
@@ -1944,7 +1944,7 @@ var require_lockfile = __commonJS({
1944
1944
  }
1945
1945
  function unlock(file, options, callback) {
1946
1946
  options = {
1947
- fs: fs22,
1947
+ fs: fs23,
1948
1948
  realpath: true,
1949
1949
  ...options
1950
1950
  };
@@ -1966,7 +1966,7 @@ var require_lockfile = __commonJS({
1966
1966
  options = {
1967
1967
  stale: 1e4,
1968
1968
  realpath: true,
1969
- fs: fs22,
1969
+ fs: fs23,
1970
1970
  ...options
1971
1971
  };
1972
1972
  options.stale = Math.max(options.stale || 0, 2e3);
@@ -2005,16 +2005,16 @@ var require_lockfile = __commonJS({
2005
2005
  var require_adapter = __commonJS({
2006
2006
  "../../node_modules/proper-lockfile/lib/adapter.js"(exports, module) {
2007
2007
  "use strict";
2008
- var fs22 = require_graceful_fs();
2009
- function createSyncFs(fs23) {
2008
+ var fs23 = require_graceful_fs();
2009
+ function createSyncFs(fs24) {
2010
2010
  const methods = ["mkdir", "realpath", "stat", "rmdir", "utimes"];
2011
- const newFs = { ...fs23 };
2011
+ const newFs = { ...fs24 };
2012
2012
  methods.forEach((method) => {
2013
2013
  newFs[method] = (...args) => {
2014
2014
  const callback = args.pop();
2015
2015
  let ret;
2016
2016
  try {
2017
- ret = fs23[`${method}Sync`](...args);
2017
+ ret = fs24[`${method}Sync`](...args);
2018
2018
  } catch (err) {
2019
2019
  return callback(err);
2020
2020
  }
@@ -2052,7 +2052,7 @@ var require_adapter = __commonJS({
2052
2052
  }
2053
2053
  function toSyncOptions(options) {
2054
2054
  options = { ...options };
2055
- options.fs = createSyncFs(options.fs || fs22);
2055
+ options.fs = createSyncFs(options.fs || fs23);
2056
2056
  if (typeof options.retries === "number" && options.retries > 0 || options.retries && typeof options.retries.retries === "number" && options.retries.retries > 0) {
2057
2057
  throw Object.assign(new Error("Cannot use retries with the sync api"), { code: "ESYNC" });
2058
2058
  }
@@ -3447,10 +3447,6 @@ async function getPendingKeys(filePath) {
3447
3447
  const metadata = await loadMetadata(filePath);
3448
3448
  return metadata.pending.map((p) => p.key);
3449
3449
  }
3450
- async function isPending(filePath, key) {
3451
- const metadata = await loadMetadata(filePath);
3452
- return metadata.pending.some((p) => p.key === key);
3453
- }
3454
3450
  async function recordRotation(filePath, keys, rotatedBy, now = /* @__PURE__ */ new Date()) {
3455
3451
  const metadata = await loadMetadata(filePath);
3456
3452
  for (const key of keys) {
@@ -3486,14 +3482,6 @@ async function getRotations(filePath) {
3486
3482
  function generateRandomValue() {
3487
3483
  return crypto.randomBytes(32).toString("hex");
3488
3484
  }
3489
- async function markPendingWithRetry(filePath, keys, setBy, retryDelayMs = 200) {
3490
- try {
3491
- await markPending(filePath, keys, setBy);
3492
- } catch {
3493
- await new Promise((r) => setTimeout(r, retryDelayMs));
3494
- await markPending(filePath, keys, setBy);
3495
- }
3496
- }
3497
3485
 
3498
3486
  // src/sops/keys.ts
3499
3487
  import * as fs6 from "fs";
@@ -3543,34 +3531,17 @@ var MatrixManager = class {
3543
3531
  detectMissingCells(manifest, repoRoot) {
3544
3532
  return this.resolveMatrix(manifest, repoRoot).filter((cell) => !cell.exists);
3545
3533
  }
3546
- /**
3547
- * Create an empty encrypted SOPS file for a missing matrix cell.
3548
- *
3549
- * @param cell - The cell to scaffold (must not already exist).
3550
- * @param sopsClient - SOPS client used to write the initial encrypted file.
3551
- * @param manifest - Parsed manifest used to determine the encryption backend.
3552
- */
3553
- async scaffoldCell(cell, sopsClient, manifest) {
3554
- const dir = path5.dirname(cell.filePath);
3555
- if (!fs7.existsSync(dir)) {
3556
- fs7.mkdirSync(dir, { recursive: true });
3557
- }
3558
- await sopsClient.encrypt(cell.filePath, {}, manifest, cell.environment);
3559
- }
3560
3534
  /**
3561
3535
  * Read each cell and return key counts, pending counts, and cross-environment issues.
3562
3536
  *
3563
- * The SOPS client parameter is currently unused keys are read from the
3564
- * plaintext YAML structure directly, no decryption needed. It is retained
3565
- * in the signature for back-compat with callers that may need to swap to a
3566
- * decrypt-based implementation later (e.g. for backends that don't expose
3567
- * key names without decryption).
3537
+ * Keys are read from the plaintext YAML structure directly no
3538
+ * decryption needed. A future backend that doesn't expose key names
3539
+ * without decryption would need its own implementation.
3568
3540
  *
3569
3541
  * @param manifest - Parsed manifest.
3570
3542
  * @param repoRoot - Absolute path to the repository root.
3571
- * @param _sopsClient - Reserved for future use; pass any `EncryptionBackend`.
3572
3543
  */
3573
- async getMatrixStatus(manifest, repoRoot, _sopsClient) {
3544
+ async getMatrixStatus(manifest, repoRoot) {
3574
3545
  const cells = this.resolveMatrix(manifest, repoRoot);
3575
3546
  const statuses = [];
3576
3547
  const cellKeys = /* @__PURE__ */ new Map();
@@ -3886,7 +3857,6 @@ function orderedKeys(keys) {
3886
3857
  }
3887
3858
 
3888
3859
  // src/diff/engine.ts
3889
- import * as path7 from "path";
3890
3860
  var DiffEngine = class {
3891
3861
  /**
3892
3862
  * Compare two in-memory value maps and produce a sorted diff result.
@@ -3937,131 +3907,21 @@ var DiffEngine = class {
3937
3907
  * @param namespace - Namespace containing both cells.
3938
3908
  * @param envA - Name of environment A.
3939
3909
  * @param envB - Name of environment B.
3940
- * @param manifest - Parsed manifest used to resolve file paths.
3941
- * @param sopsClient - SOPS client used to decrypt both files.
3942
- * @param repoRoot - Absolute path to the repository root.
3943
- * @throws {@link SopsDecryptionError} If either file cannot be decrypted.
3910
+ * @param source - SecretSource that resolves both cells (substrate-agnostic).
3911
+ * @throws {@link SopsDecryptionError} If either cell cannot be decrypted.
3944
3912
  */
3945
- async diffFiles(namespace, envA, envB, manifest, sopsClient, repoRoot) {
3946
- const fileA = path7.join(
3947
- repoRoot,
3948
- manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", envA)
3949
- );
3950
- const fileB = path7.join(
3951
- repoRoot,
3952
- manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", envB)
3953
- );
3913
+ async diffCells(namespace, envA, envB, source) {
3954
3914
  const [decryptedA, decryptedB] = await Promise.all([
3955
- sopsClient.decrypt(fileA),
3956
- sopsClient.decrypt(fileB)
3915
+ source.readCell({ namespace, environment: envA }),
3916
+ source.readCell({ namespace, environment: envB })
3957
3917
  ]);
3958
3918
  return this.diff(decryptedA.values, decryptedB.values, envA, envB, namespace);
3959
3919
  }
3960
3920
  };
3961
3921
 
3962
- // src/bulk/ops.ts
3963
- import * as path8 from "path";
3964
- var BulkOps = class {
3965
- constructor(tx) {
3966
- this.tx = tx;
3967
- }
3968
- tx;
3969
- /**
3970
- * Set a key to different values in multiple environments at once.
3971
- *
3972
- * @param namespace - Target namespace.
3973
- * @param key - Secret key name to set.
3974
- * @param values - Map of `{ environment: value }` pairs.
3975
- * @param manifest - Parsed manifest.
3976
- * @param sopsClient - SOPS client used to decrypt and re-encrypt each file.
3977
- * @param repoRoot - Absolute path to the repository root.
3978
- * @throws Whatever the underlying encrypt throws — the transaction rolls back.
3979
- */
3980
- async setAcrossEnvironments(namespace, key, values, manifest, sopsClient, repoRoot) {
3981
- const targets = manifest.environments.filter((env) => env.name in values).map((env) => ({
3982
- env: env.name,
3983
- filePath: path8.join(
3984
- repoRoot,
3985
- manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", env.name)
3986
- )
3987
- }));
3988
- if (targets.length === 0) return;
3989
- await this.tx.run(repoRoot, {
3990
- description: `clef set: ${namespace}/${key} across ${targets.length} env(s)`,
3991
- paths: targets.map((t) => path8.relative(repoRoot, t.filePath)),
3992
- mutate: async () => {
3993
- for (const target of targets) {
3994
- const decrypted = await sopsClient.decrypt(target.filePath);
3995
- decrypted.values[key] = values[target.env];
3996
- await sopsClient.encrypt(target.filePath, decrypted.values, manifest, target.env);
3997
- }
3998
- }
3999
- });
4000
- }
4001
- /**
4002
- * Delete a key from every environment in a namespace.
4003
- *
4004
- * @param namespace - Target namespace.
4005
- * @param key - Secret key name to delete.
4006
- * @param manifest - Parsed manifest.
4007
- * @param sopsClient - SOPS client.
4008
- * @param repoRoot - Absolute path to the repository root.
4009
- */
4010
- async deleteAcrossEnvironments(namespace, key, manifest, sopsClient, repoRoot) {
4011
- const targets = manifest.environments.map((env) => ({
4012
- env: env.name,
4013
- filePath: path8.join(
4014
- repoRoot,
4015
- manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", env.name)
4016
- )
4017
- }));
4018
- await this.tx.run(repoRoot, {
4019
- description: `clef delete: ${namespace}/${key} from ${targets.length} env(s)`,
4020
- paths: targets.map((t) => path8.relative(repoRoot, t.filePath)),
4021
- mutate: async () => {
4022
- for (const target of targets) {
4023
- const decrypted = await sopsClient.decrypt(target.filePath);
4024
- if (key in decrypted.values) {
4025
- delete decrypted.values[key];
4026
- await sopsClient.encrypt(target.filePath, decrypted.values, manifest, target.env);
4027
- }
4028
- }
4029
- }
4030
- });
4031
- }
4032
- /**
4033
- * Copy a single key's value from one matrix cell to another.
4034
- *
4035
- * @param key - Secret key name to copy.
4036
- * @param fromCell - Source matrix cell.
4037
- * @param toCell - Destination matrix cell.
4038
- * @param sopsClient - SOPS client.
4039
- * @param manifest - Parsed manifest.
4040
- * @param repoRoot - Absolute path to the repository root.
4041
- * @throws `Error` if the key does not exist in the source cell.
4042
- */
4043
- async copyValue(key, fromCell, toCell, sopsClient, manifest, repoRoot) {
4044
- const source = await sopsClient.decrypt(fromCell.filePath);
4045
- if (!(key in source.values)) {
4046
- throw new Error(
4047
- `Key '${key}' does not exist in ${fromCell.namespace}/${fromCell.environment}.`
4048
- );
4049
- }
4050
- await this.tx.run(repoRoot, {
4051
- description: `clef copy: ${key} from ${fromCell.namespace}/${fromCell.environment} to ${toCell.namespace}/${toCell.environment}`,
4052
- paths: [path8.relative(repoRoot, toCell.filePath)],
4053
- mutate: async () => {
4054
- const dest = await sopsClient.decrypt(toCell.filePath);
4055
- dest.values[key] = source.values[key];
4056
- await sopsClient.encrypt(toCell.filePath, dest.values, manifest, toCell.environment);
4057
- }
4058
- });
4059
- }
4060
- };
4061
-
4062
3922
  // src/git/integration.ts
4063
3923
  import * as fs10 from "fs";
4064
- import * as path9 from "path";
3924
+ import * as path7 from "path";
4065
3925
  var PRE_COMMIT_HOOK = `#!/bin/sh
4066
3926
  # Clef pre-commit hook \u2014 blocks commits of files missing SOPS encryption metadata
4067
3927
  # and scans staged files for plaintext secrets.
@@ -4237,17 +4097,17 @@ var GitIntegration = class {
4237
4097
  * @returns The kind of operation in progress, or null if none.
4238
4098
  */
4239
4099
  async isMidOperation(repoRoot) {
4240
- const gitDir = path9.join(repoRoot, ".git");
4241
- if (fs10.existsSync(path9.join(gitDir, "MERGE_HEAD"))) {
4100
+ const gitDir = path7.join(repoRoot, ".git");
4101
+ if (fs10.existsSync(path7.join(gitDir, "MERGE_HEAD"))) {
4242
4102
  return { midOp: true, kind: "merge" };
4243
4103
  }
4244
- if (fs10.existsSync(path9.join(gitDir, "rebase-merge")) || fs10.existsSync(path9.join(gitDir, "rebase-apply"))) {
4104
+ if (fs10.existsSync(path7.join(gitDir, "rebase-merge")) || fs10.existsSync(path7.join(gitDir, "rebase-apply"))) {
4245
4105
  return { midOp: true, kind: "rebase" };
4246
4106
  }
4247
- if (fs10.existsSync(path9.join(gitDir, "CHERRY_PICK_HEAD"))) {
4107
+ if (fs10.existsSync(path7.join(gitDir, "CHERRY_PICK_HEAD"))) {
4248
4108
  return { midOp: true, kind: "cherry-pick" };
4249
4109
  }
4250
- if (fs10.existsSync(path9.join(gitDir, "REVERT_HEAD"))) {
4110
+ if (fs10.existsSync(path7.join(gitDir, "REVERT_HEAD"))) {
4251
4111
  return { midOp: true, kind: "revert" };
4252
4112
  }
4253
4113
  return { midOp: false };
@@ -4459,14 +4319,14 @@ var GitIntegration = class {
4459
4319
  { cwd: repoRoot }
4460
4320
  );
4461
4321
  const metadataGitConfig = metaConfig.exitCode === 0 && metaConfig.stdout.trim().length > 0;
4462
- const attrFilePath = path9.join(repoRoot, ".gitattributes");
4322
+ const attrFilePath = path7.join(repoRoot, ".gitattributes");
4463
4323
  const attrContent = fs10.existsSync(attrFilePath) ? fs10.readFileSync(attrFilePath, "utf-8") : "";
4464
4324
  const gitattributes = attrContent.includes("merge=sops");
4465
4325
  const metadataGitattributes = attrContent.includes("merge=clef-metadata");
4466
4326
  return { gitConfig, gitattributes, metadataGitConfig, metadataGitattributes };
4467
4327
  }
4468
4328
  async ensureGitattributes(repoRoot) {
4469
- const attrPath = path9.join(repoRoot, ".gitattributes");
4329
+ const attrPath = path7.join(repoRoot, ".gitattributes");
4470
4330
  const existing = fs10.existsSync(attrPath) ? fs10.readFileSync(attrPath, "utf-8") : "";
4471
4331
  let newContent = existing;
4472
4332
  if (!existing.includes("merge=sops")) {
@@ -4501,9 +4361,9 @@ ${block}` : block;
4501
4361
  * @throws {@link GitOperationError} On failure.
4502
4362
  */
4503
4363
  async installPreCommitHook(repoRoot) {
4504
- const hookPath = path9.join(repoRoot, ".git", "hooks", "pre-commit");
4364
+ const hookPath = path7.join(repoRoot, ".git", "hooks", "pre-commit");
4505
4365
  try {
4506
- const hooksDir = path9.dirname(hookPath);
4366
+ const hooksDir = path7.dirname(hookPath);
4507
4367
  if (!fs10.existsSync(hooksDir)) {
4508
4368
  fs10.mkdirSync(hooksDir, { recursive: true });
4509
4369
  }
@@ -4520,7 +4380,7 @@ ${block}` : block;
4520
4380
  // src/tx/transaction-manager.ts
4521
4381
  var lockfile = __toESM(require_proper_lockfile());
4522
4382
  import * as fs11 from "fs";
4523
- import * as path10 from "path";
4383
+ import * as path8 from "path";
4524
4384
 
4525
4385
  // src/tx/errors.ts
4526
4386
  var TransactionLockError = class extends Error {
@@ -4568,15 +4428,15 @@ var TransactionManager = class {
4568
4428
  async run(repoRoot, opts) {
4569
4429
  const shouldCommit = opts.commit !== false;
4570
4430
  const allowDirty = opts.allowDirty === true;
4571
- const clefDir = path10.join(repoRoot, CLEF_DIR);
4431
+ const clefDir = path8.join(repoRoot, CLEF_DIR);
4572
4432
  if (!fs11.existsSync(clefDir)) {
4573
4433
  fs11.mkdirSync(clefDir, { recursive: true });
4574
4434
  }
4575
- const clefGitignore = path10.join(clefDir, ".gitignore");
4435
+ const clefGitignore = path8.join(clefDir, ".gitignore");
4576
4436
  if (!fs11.existsSync(clefGitignore)) {
4577
4437
  fs11.writeFileSync(clefGitignore, "*\n");
4578
4438
  }
4579
- const lockPath = path10.join(clefDir, LOCK_FILE);
4439
+ const lockPath = path8.join(clefDir, LOCK_FILE);
4580
4440
  if (!fs11.existsSync(lockPath)) {
4581
4441
  fs11.writeFileSync(lockPath, "");
4582
4442
  }
@@ -4714,7 +4574,6 @@ var TransactionManager = class {
4714
4574
  };
4715
4575
 
4716
4576
  // src/sops/client.ts
4717
- var import_write_file_atomic3 = __toESM(require_lib());
4718
4577
  import * as fs14 from "fs";
4719
4578
  import * as net from "net";
4720
4579
  import { randomBytes as randomBytes2 } from "crypto";
@@ -4722,11 +4581,11 @@ import * as YAML8 from "yaml";
4722
4581
 
4723
4582
  // src/sops/resolver.ts
4724
4583
  import * as fs13 from "fs";
4725
- import * as path12 from "path";
4584
+ import * as path10 from "path";
4726
4585
 
4727
4586
  // src/sops/bundled.ts
4728
4587
  import * as fs12 from "fs";
4729
- import * as path11 from "path";
4588
+ import * as path9 from "path";
4730
4589
  function tryBundled() {
4731
4590
  const platform = process.platform;
4732
4591
  const arch = process.arch;
@@ -4738,8 +4597,8 @@ function tryBundled() {
4738
4597
  const binName = platform === "win32" ? "sops.exe" : "sops";
4739
4598
  try {
4740
4599
  const packageMain = __require.resolve(`${packageName}/package.json`);
4741
- const packageDir = path11.dirname(packageMain);
4742
- const binPath = path11.join(packageDir, "bin", binName);
4600
+ const packageDir = path9.dirname(packageMain);
4601
+ const binPath = path9.join(packageDir, "bin", binName);
4743
4602
  return fs12.existsSync(binPath) ? binPath : null;
4744
4603
  } catch {
4745
4604
  return null;
@@ -4748,7 +4607,7 @@ function tryBundled() {
4748
4607
 
4749
4608
  // src/sops/resolver.ts
4750
4609
  function validateSopsPath(candidate) {
4751
- if (!path12.isAbsolute(candidate)) {
4610
+ if (!path10.isAbsolute(candidate)) {
4752
4611
  throw new Error(`CLEF_SOPS_PATH must be an absolute path, got '${candidate}'.`);
4753
4612
  }
4754
4613
  const segments = candidate.split(/[/\\]/);
@@ -4927,6 +4786,17 @@ function isClefHsmArn(arn) {
4927
4786
  function formatFromPath(filePath) {
4928
4787
  return filePath.endsWith(".json") ? "json" : "yaml";
4929
4788
  }
4789
+ async function openInputPipe(content) {
4790
+ if (process.platform === "win32") {
4791
+ const pipe = await openWindowsInputPipe(content);
4792
+ return { inputArg: pipe.inputArg, cleanup: pipe.cleanup };
4793
+ }
4794
+ return { inputArg: "/dev/stdin", cleanup: () => {
4795
+ }, runnerStdin: content };
4796
+ }
4797
+ function nullConfigPath() {
4798
+ return process.platform === "win32" ? "NUL" : "/dev/null";
4799
+ }
4930
4800
  function openWindowsInputPipe(content) {
4931
4801
  const pipeName = `\\\\.\\pipe\\clef-sops-${randomBytes2(8).toString("hex")}`;
4932
4802
  return new Promise((resolve2, reject) => {
@@ -4974,6 +4844,10 @@ var SopsClient = class {
4974
4844
  runner;
4975
4845
  ageKeyFile;
4976
4846
  ageKey;
4847
+ /** {@link EncryptionBackend} identifier. */
4848
+ id = "sops";
4849
+ /** {@link EncryptionBackend} short description (used by `clef doctor`). */
4850
+ description = "SOPS-based encryption via the bundled `sops` binary";
4977
4851
  sopsCommand;
4978
4852
  keyserviceArgs;
4979
4853
  buildSopsEnv() {
@@ -4987,14 +4861,18 @@ var SopsClient = class {
4987
4861
  return Object.keys(env).length > 0 ? env : void 0;
4988
4862
  }
4989
4863
  /**
4990
- * Decrypt a SOPS-encrypted file and return its values and metadata.
4864
+ * Decrypt a SOPS-encrypted file by path. The only remaining file-path
4865
+ * entry point on this class — kept for the merge driver, which
4866
+ * receives temp filesystem paths from git that don't map onto a
4867
+ * `CellRef`. Production `SecretSource` consumers should call
4868
+ * `source.readCell` instead.
4991
4869
  *
4992
4870
  * @param filePath - Path to the `.enc.yaml` or `.enc.json` file.
4993
4871
  * @returns {@link DecryptedFile} with plaintext values in memory only.
4994
4872
  * @throws {@link SopsKeyNotFoundError} If no matching decryption key is available.
4995
4873
  * @throws {@link SopsDecryptionError} On any other decryption failure.
4996
4874
  */
4997
- async decrypt(filePath) {
4875
+ async decryptFile(filePath) {
4998
4876
  await assertSops(this.runner, this.sopsCommand);
4999
4877
  const fmt = formatFromPath(filePath);
5000
4878
  const env = this.buildSopsEnv();
@@ -5030,170 +4908,9 @@ var SopsClient = class {
5030
4908
  for (const [key, value] of Object.entries(parsed)) {
5031
4909
  values[key] = String(value);
5032
4910
  }
5033
- const metadata = await this.getMetadata(filePath);
4911
+ const metadata = this.parseMetadataFromFile(filePath);
5034
4912
  return { values, metadata };
5035
4913
  }
5036
- /**
5037
- * Encrypt a key/value map and write it to an encrypted SOPS file.
5038
- *
5039
- * @param filePath - Destination path for the encrypted file.
5040
- * @param values - Flat key/value map to encrypt.
5041
- * @param manifest - Manifest used to determine the encryption backend and key configuration.
5042
- * @param environment - Optional environment name. When provided, per-env backend overrides
5043
- * are resolved from the manifest. When omitted, the global `sops.default_backend` is used.
5044
- * @throws {@link SopsEncryptionError} On encryption or write failure.
5045
- */
5046
- async encrypt(filePath, values, manifest, environment) {
5047
- await assertSops(this.runner, this.sopsCommand);
5048
- const fmt = formatFromPath(filePath);
5049
- const content = fmt === "json" ? JSON.stringify(values, null, 2) : YAML8.stringify(values);
5050
- const args = this.buildEncryptArgs(filePath, manifest, environment);
5051
- const env = this.buildSopsEnv();
5052
- let inputArg;
5053
- let pipeCleanup;
5054
- if (process.platform === "win32") {
5055
- const pipe = await openWindowsInputPipe(content);
5056
- inputArg = pipe.inputArg;
5057
- pipeCleanup = pipe.cleanup;
5058
- } else {
5059
- inputArg = "/dev/stdin";
5060
- }
5061
- let result;
5062
- try {
5063
- const configPath = process.platform === "win32" ? "NUL" : "/dev/null";
5064
- result = await this.runner.run(
5065
- this.sopsCommand,
5066
- [
5067
- "--config",
5068
- configPath,
5069
- "encrypt",
5070
- ...this.keyserviceArgs,
5071
- ...args,
5072
- "--input-type",
5073
- fmt,
5074
- "--output-type",
5075
- fmt,
5076
- "--filename-override",
5077
- filePath,
5078
- inputArg
5079
- ],
5080
- {
5081
- // stdin is still piped on Unix (/dev/stdin reads from it);
5082
- // on Windows the named pipe server feeds content directly.
5083
- ...process.platform !== "win32" ? { stdin: content } : {},
5084
- ...env ? { env } : {}
5085
- }
5086
- );
5087
- } finally {
5088
- pipeCleanup?.();
5089
- }
5090
- if (result.exitCode !== 0) {
5091
- throw new SopsEncryptionError(
5092
- `Failed to encrypt '${filePath}': ${result.stderr.trim()}`,
5093
- filePath
5094
- );
5095
- }
5096
- try {
5097
- await (0, import_write_file_atomic3.default)(filePath, result.stdout);
5098
- } catch (err) {
5099
- throw new SopsEncryptionError(
5100
- `Failed to write encrypted data to '${filePath}': ${err.message}`,
5101
- filePath
5102
- );
5103
- }
5104
- }
5105
- /**
5106
- * Rotate encryption by adding a new age recipient key to an existing SOPS file.
5107
- *
5108
- * @param filePath - Path to the encrypted file to re-encrypt.
5109
- * @param newKey - New age public key to add as a recipient.
5110
- * @throws {@link SopsEncryptionError} On failure.
5111
- */
5112
- async reEncrypt(filePath, newKey) {
5113
- await this.addRecipient(filePath, newKey);
5114
- }
5115
- /**
5116
- * Add an age recipient to an existing SOPS file.
5117
- *
5118
- * @param filePath - Path to the encrypted file.
5119
- * @param key - age public key to add as a recipient.
5120
- * @throws {@link SopsEncryptionError} On failure.
5121
- */
5122
- async addRecipient(filePath, key) {
5123
- await assertSops(this.runner, this.sopsCommand);
5124
- const env = this.buildSopsEnv();
5125
- const result = await this.runner.run(
5126
- this.sopsCommand,
5127
- ["rotate", ...this.keyserviceArgs, "-i", "--add-age", key, filePath],
5128
- {
5129
- ...env ? { env } : {}
5130
- }
5131
- );
5132
- if (result.exitCode !== 0) {
5133
- throw new SopsEncryptionError(
5134
- `Failed to add recipient to '${filePath}': ${result.stderr.trim()}`,
5135
- filePath
5136
- );
5137
- }
5138
- }
5139
- /**
5140
- * Remove an age recipient from an existing SOPS file.
5141
- *
5142
- * @param filePath - Path to the encrypted file.
5143
- * @param key - age public key to remove.
5144
- * @throws {@link SopsEncryptionError} On failure.
5145
- */
5146
- async removeRecipient(filePath, key) {
5147
- await assertSops(this.runner, this.sopsCommand);
5148
- const env = this.buildSopsEnv();
5149
- const result = await this.runner.run(
5150
- this.sopsCommand,
5151
- ["rotate", ...this.keyserviceArgs, "-i", "--rm-age", key, filePath],
5152
- {
5153
- ...env ? { env } : {}
5154
- }
5155
- );
5156
- if (result.exitCode !== 0) {
5157
- throw new SopsEncryptionError(
5158
- `Failed to remove recipient from '${filePath}': ${result.stderr.trim()}`,
5159
- filePath
5160
- );
5161
- }
5162
- }
5163
- /**
5164
- * Check whether a file contains valid SOPS encryption metadata.
5165
- *
5166
- * @param filePath - Path to the file to check.
5167
- * @returns `true` if valid SOPS metadata is present; `false` otherwise. Never throws.
5168
- */
5169
- async validateEncryption(filePath) {
5170
- await assertSops(this.runner, this.sopsCommand);
5171
- try {
5172
- await this.getMetadata(filePath);
5173
- return true;
5174
- } catch {
5175
- return false;
5176
- }
5177
- }
5178
- /**
5179
- * Extract SOPS metadata (backend, recipients, last-modified timestamp) from an encrypted file
5180
- * without decrypting its values.
5181
- *
5182
- * @param filePath - Path to the encrypted file.
5183
- * @returns {@link SopsMetadata} parsed from the file's `sops:` block.
5184
- * @throws {@link SopsDecryptionError} If the file cannot be read or parsed.
5185
- */
5186
- async getMetadata(filePath) {
5187
- await assertSops(this.runner, this.sopsCommand);
5188
- const env = this.buildSopsEnv();
5189
- const result = await this.runner.run(this.sopsCommand, ["filestatus", filePath], {
5190
- ...env ? { env } : {}
5191
- });
5192
- if (result.exitCode !== 0) {
5193
- return this.parseMetadataFromFile(filePath);
5194
- }
5195
- return this.parseMetadataFromFile(filePath);
5196
- }
5197
4914
  /**
5198
4915
  * Determine whether a decrypt failure is caused by a missing/mismatched key (vs. some other
5199
4916
  * SOPS error) without relying on stderr message text.
@@ -5237,20 +4954,30 @@ var SopsClient = class {
5237
4954
  filePath
5238
4955
  );
5239
4956
  }
4957
+ return this.parseMetadataFromContent(content, filePath);
4958
+ }
4959
+ /**
4960
+ * Parse SOPS metadata from a string (no IO). Used by both
4961
+ * `parseMetadataFromFile` (after reading from disk) and the blob-shaped
4962
+ * `getMetadataFromBlob` (which receives ciphertext directly from a
4963
+ * BlobStore). The `label` is woven into error messages so callers can
4964
+ * include the file path or cell ref the content came from.
4965
+ */
4966
+ parseMetadataFromContent(content, label) {
5240
4967
  let parsed;
5241
4968
  try {
5242
4969
  parsed = YAML8.parse(content);
5243
4970
  } catch {
5244
4971
  throw new SopsDecryptionError(
5245
- `File '${filePath}' is not valid YAML. Cannot extract SOPS metadata.`,
5246
- filePath
4972
+ `${label} is not valid YAML. Cannot extract SOPS metadata.`,
4973
+ label
5247
4974
  );
5248
4975
  }
5249
4976
  const sops = parsed?.sops;
5250
4977
  if (!sops) {
5251
4978
  throw new SopsDecryptionError(
5252
- `File '${filePath}' does not contain SOPS metadata. It may not be encrypted.`,
5253
- filePath
4979
+ `${label} does not contain SOPS metadata. It may not be encrypted.`,
4980
+ label
5254
4981
  );
5255
4982
  }
5256
4983
  const backend = this.detectBackend(sops);
@@ -5313,7 +5040,7 @@ var SopsClient = class {
5313
5040
  }
5314
5041
  }
5315
5042
  }
5316
- buildEncryptArgs(filePath, manifest, environment) {
5043
+ buildEncryptArgs(manifest, environment) {
5317
5044
  const args = [];
5318
5045
  const config = environment ? resolveBackendConfig(manifest, environment) : {
5319
5046
  backend: manifest.sops.default_backend,
@@ -5361,11 +5088,255 @@ var SopsClient = class {
5361
5088
  }
5362
5089
  return args;
5363
5090
  }
5091
+ // ── Blob-shaped methods ─────────────────────────────────────────────────
5092
+ //
5093
+ // These mirror the file-path methods above but operate on opaque
5094
+ // ciphertext bytes via SOPS' stdin/stdout. They are the substrate-
5095
+ // agnostic primitives used by the `composeSecretSource` factory to
5096
+ // wrap any `BlobStore` (filesystem, postgres, etc.) into a full
5097
+ // `SecretSource`. Plaintext never leaves the SOPS subprocess.
5098
+ /**
5099
+ * {@link EncryptionBackend.decrypt} — decrypt SOPS-encrypted bytes (e.g.
5100
+ * read from a `StorageBackend`) and return plaintext values + metadata.
5101
+ * Plaintext lives only in memory.
5102
+ */
5103
+ async decrypt(blob, ctx) {
5104
+ await assertSops(this.runner, this.sopsCommand);
5105
+ const env = this.buildSopsEnv();
5106
+ const pipe = await openInputPipe(blob);
5107
+ let result;
5108
+ try {
5109
+ result = await this.runner.run(
5110
+ this.sopsCommand,
5111
+ [
5112
+ "decrypt",
5113
+ ...this.keyserviceArgs,
5114
+ "--input-type",
5115
+ ctx.format,
5116
+ "--output-type",
5117
+ ctx.format,
5118
+ pipe.inputArg
5119
+ ],
5120
+ {
5121
+ ...pipe.runnerStdin !== void 0 ? { stdin: pipe.runnerStdin } : {},
5122
+ ...env ? { env } : {}
5123
+ }
5124
+ );
5125
+ } finally {
5126
+ pipe.cleanup();
5127
+ }
5128
+ if (result.exitCode !== 0) {
5129
+ const errorType = await this.classifyDecryptErrorFromContent(blob);
5130
+ if (errorType === "key-not-found") {
5131
+ throw new SopsKeyNotFoundError(`No decryption key found for cell. ${result.stderr.trim()}`);
5132
+ }
5133
+ throw new SopsDecryptionError(`Failed to decrypt cell: ${result.stderr.trim()}`);
5134
+ }
5135
+ let parsed;
5136
+ try {
5137
+ parsed = YAML8.parse(result.stdout) ?? {};
5138
+ } catch {
5139
+ throw new SopsDecryptionError("Decrypted content is not valid YAML.");
5140
+ }
5141
+ const values = {};
5142
+ for (const [key, value] of Object.entries(parsed)) {
5143
+ values[key] = String(value);
5144
+ }
5145
+ const metadata = this.parseMetadataFromContent(blob, "<cell>");
5146
+ return { values, metadata };
5147
+ }
5148
+ /**
5149
+ * {@link EncryptionBackend.encrypt} — encrypt plaintext values into a
5150
+ * SOPS-formatted ciphertext blob. Returns the bytes as a string;
5151
+ * caller (typically a `StorageBackend`) decides where to put them.
5152
+ * Plaintext is piped via stdin only.
5153
+ */
5154
+ async encrypt(values, ctx) {
5155
+ await assertSops(this.runner, this.sopsCommand);
5156
+ const content = ctx.format === "json" ? JSON.stringify(values, null, 2) : YAML8.stringify(values);
5157
+ const args = this.buildEncryptArgs(ctx.manifest, ctx.environment);
5158
+ const env = this.buildSopsEnv();
5159
+ const pipe = await openInputPipe(content);
5160
+ let result;
5161
+ try {
5162
+ result = await this.runner.run(
5163
+ this.sopsCommand,
5164
+ [
5165
+ "--config",
5166
+ nullConfigPath(),
5167
+ "encrypt",
5168
+ ...this.keyserviceArgs,
5169
+ ...args,
5170
+ "--input-type",
5171
+ ctx.format,
5172
+ "--output-type",
5173
+ ctx.format,
5174
+ pipe.inputArg
5175
+ ],
5176
+ {
5177
+ ...pipe.runnerStdin !== void 0 ? { stdin: pipe.runnerStdin } : {},
5178
+ ...env ? { env } : {}
5179
+ }
5180
+ );
5181
+ } finally {
5182
+ pipe.cleanup();
5183
+ }
5184
+ if (result.exitCode !== 0) {
5185
+ throw new SopsEncryptionError(`Failed to encrypt cell: ${result.stderr.trim()}`);
5186
+ }
5187
+ return result.stdout;
5188
+ }
5189
+ /**
5190
+ * {@link EncryptionBackend.rotate} — add or remove recipients from an
5191
+ * encrypted SOPS blob via stdin/stdout. Drops the in-place `-i` flag
5192
+ * the deleted file-path-shaped methods used, so SOPS writes the
5193
+ * rotated ciphertext to stdout instead of back to a file. Plaintext
5194
+ * stays inside the SOPS subprocess; no plaintext window exists in
5195
+ * this Node process.
5196
+ *
5197
+ * Single SOPS invocation can both add and remove recipients
5198
+ * simultaneously (matches the CLI flag set).
5199
+ */
5200
+ async rotate(blob, opts, ctx) {
5201
+ await assertSops(this.runner, this.sopsCommand);
5202
+ const env = this.buildSopsEnv();
5203
+ const pipe = await openInputPipe(blob);
5204
+ const flagArgs = [];
5205
+ if (opts.addAge) flagArgs.push("--add-age", opts.addAge);
5206
+ if (opts.rmAge) flagArgs.push("--rm-age", opts.rmAge);
5207
+ if (opts.addKms) flagArgs.push("--add-kms", opts.addKms);
5208
+ if (opts.rmKms) flagArgs.push("--rm-kms", opts.rmKms);
5209
+ if (opts.addGcpKms) flagArgs.push("--add-gcp-kms", opts.addGcpKms);
5210
+ if (opts.rmGcpKms) flagArgs.push("--rm-gcp-kms", opts.rmGcpKms);
5211
+ if (opts.addAzureKv) flagArgs.push("--add-azure-kv", opts.addAzureKv);
5212
+ if (opts.rmAzureKv) flagArgs.push("--rm-azure-kv", opts.rmAzureKv);
5213
+ if (opts.addPgp) flagArgs.push("--add-pgp", opts.addPgp);
5214
+ if (opts.rmPgp) flagArgs.push("--rm-pgp", opts.rmPgp);
5215
+ let result;
5216
+ try {
5217
+ result = await this.runner.run(
5218
+ this.sopsCommand,
5219
+ [
5220
+ "--config",
5221
+ nullConfigPath(),
5222
+ "rotate",
5223
+ ...this.keyserviceArgs,
5224
+ ...flagArgs,
5225
+ "--input-type",
5226
+ ctx.format,
5227
+ "--output-type",
5228
+ ctx.format,
5229
+ pipe.inputArg
5230
+ ],
5231
+ {
5232
+ ...pipe.runnerStdin !== void 0 ? { stdin: pipe.runnerStdin } : {},
5233
+ ...env ? { env } : {}
5234
+ }
5235
+ );
5236
+ } finally {
5237
+ pipe.cleanup();
5238
+ }
5239
+ if (result.exitCode !== 0) {
5240
+ throw new SopsEncryptionError(`Failed to rotate cell: ${result.stderr.trim()}`);
5241
+ }
5242
+ return result.stdout;
5243
+ }
5244
+ /**
5245
+ * {@link EncryptionBackend.getMetadata} — extract SOPS metadata from a
5246
+ * ciphertext blob without decrypting. Pure parser, no IO, no
5247
+ * subprocess.
5248
+ */
5249
+ getMetadata(content) {
5250
+ return this.parseMetadataFromContent(content, "<cell>");
5251
+ }
5252
+ /**
5253
+ * {@link EncryptionBackend.validateEncryption} — whether `content` is a
5254
+ * valid SOPS-encrypted blob (parses + has the `sops:` metadata
5255
+ * block). Never throws.
5256
+ */
5257
+ validateEncryption(content) {
5258
+ try {
5259
+ this.parseMetadataFromContent(content, "<cell>");
5260
+ return true;
5261
+ } catch {
5262
+ return false;
5263
+ }
5264
+ }
5265
+ /**
5266
+ * Blob-shaped variant of `classifyDecryptError`. Same logic as the
5267
+ * file-path version but reads metadata from the in-memory ciphertext
5268
+ * instead of disk.
5269
+ */
5270
+ async classifyDecryptErrorFromContent(content) {
5271
+ let metadata;
5272
+ try {
5273
+ metadata = this.parseMetadataFromContent(content, "<cell>");
5274
+ } catch {
5275
+ return "other";
5276
+ }
5277
+ if (metadata.backend !== "age") return "other";
5278
+ if (!this.ageKey && !this.ageKeyFile) return "key-not-found";
5279
+ let keyContent;
5280
+ try {
5281
+ keyContent = this.ageKey ?? fs14.readFileSync(this.ageKeyFile, "utf-8");
5282
+ } catch {
5283
+ return "key-not-found";
5284
+ }
5285
+ const privateKeys = keyContent.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("AGE-SECRET-KEY-"));
5286
+ if (privateKeys.length === 0) return "key-not-found";
5287
+ try {
5288
+ const publicKeys = await Promise.all(privateKeys.map((k) => deriveAgePublicKey(k)));
5289
+ const recipients = new Set(metadata.recipients);
5290
+ return publicKeys.some((pk) => recipients.has(pk)) ? "other" : "key-not-found";
5291
+ } catch {
5292
+ return "other";
5293
+ }
5294
+ }
5364
5295
  };
5365
5296
 
5297
+ // src/sops/linux-stdin-fifo.ts
5298
+ import * as os from "os";
5299
+ import * as path11 from "path";
5300
+ import { execFileSync, spawn } from "child_process";
5301
+ function shouldUseLinuxStdinFifo() {
5302
+ return process.platform === "linux" && !process.env.JEST_WORKER_ID;
5303
+ }
5304
+ function wrapWithLinuxStdinFifo(runner) {
5305
+ if (!shouldUseLinuxStdinFifo()) return runner;
5306
+ return {
5307
+ run: (cmd, args, opts) => {
5308
+ const stdinIdx = args.indexOf("/dev/stdin");
5309
+ if (stdinIdx < 0 || opts?.stdin === void 0) {
5310
+ return runner.run(cmd, args, opts);
5311
+ }
5312
+ const fifoDir = execFileSync("mktemp", ["-d", path11.join(os.tmpdir(), "clef-fifo-XXXXXX")]).toString().trim();
5313
+ const fifoPath = path11.join(fifoDir, "input");
5314
+ execFileSync("mkfifo", [fifoPath]);
5315
+ const writer = spawn("dd", [`of=${fifoPath}`, "status=none"], {
5316
+ stdio: ["pipe", "ignore", "ignore"]
5317
+ });
5318
+ writer.stdin.write(opts.stdin);
5319
+ writer.stdin.end();
5320
+ const patchedArgs = [...args];
5321
+ patchedArgs[stdinIdx] = fifoPath;
5322
+ const { stdin: _stdin, ...restOpts } = opts;
5323
+ return runner.run(cmd, patchedArgs, restOpts).finally(() => {
5324
+ try {
5325
+ writer.kill();
5326
+ } catch {
5327
+ }
5328
+ try {
5329
+ execFileSync("rm", ["-rf", fifoDir]);
5330
+ } catch {
5331
+ }
5332
+ });
5333
+ }
5334
+ };
5335
+ }
5336
+
5366
5337
  // src/hsm/bundled.ts
5367
5338
  import * as fs15 from "fs";
5368
- import * as path13 from "path";
5339
+ import * as path12 from "path";
5369
5340
  function tryBundledKeyservice() {
5370
5341
  const platform = process.platform;
5371
5342
  const arch = process.arch;
@@ -5377,8 +5348,8 @@ function tryBundledKeyservice() {
5377
5348
  const binName = "clef-keyservice";
5378
5349
  try {
5379
5350
  const packageMain = __require.resolve(`${packageName}/package.json`);
5380
- const packageDir = path13.dirname(packageMain);
5381
- const binPath = path13.join(packageDir, "bin", binName);
5351
+ const packageDir = path12.dirname(packageMain);
5352
+ const binPath = path12.join(packageDir, "bin", binName);
5382
5353
  return fs15.existsSync(binPath) ? binPath : null;
5383
5354
  } catch {
5384
5355
  return null;
@@ -5387,9 +5358,9 @@ function tryBundledKeyservice() {
5387
5358
 
5388
5359
  // src/hsm/resolver.ts
5389
5360
  import * as fs16 from "fs";
5390
- import * as path14 from "path";
5361
+ import * as path13 from "path";
5391
5362
  function validateKeyservicePath(candidate) {
5392
- if (!path14.isAbsolute(candidate)) {
5363
+ if (!path13.isAbsolute(candidate)) {
5393
5364
  throw new Error(`CLEF_KEYSERVICE_PATH must be an absolute path, got '${candidate}'.`);
5394
5365
  }
5395
5366
  const segments = candidate.split(/[/\\]/);
@@ -5424,7 +5395,7 @@ function resetKeyserviceResolution() {
5424
5395
  }
5425
5396
 
5426
5397
  // src/hsm/keyservice.ts
5427
- import { spawn } from "child_process";
5398
+ import { spawn as spawn2 } from "child_process";
5428
5399
  import * as readline from "readline";
5429
5400
  var PORT_REGEX = /^PORT=(\d+)$/;
5430
5401
  var STARTUP_TIMEOUT_MS = 5e3;
@@ -5442,7 +5413,7 @@ async function spawnKeyservice(options) {
5442
5413
  ...options.pin ? { CLEF_PKCS11_PIN: options.pin } : {},
5443
5414
  ...options.pinFile ? { CLEF_PKCS11_PIN_FILE: options.pinFile } : {}
5444
5415
  };
5445
- const child = spawn(options.binaryPath, args, {
5416
+ const child = spawn2(options.binaryPath, args, {
5446
5417
  stdio: ["ignore", "pipe", "pipe"],
5447
5418
  env: childEnv
5448
5419
  });
@@ -5518,16 +5489,16 @@ function killGracefully(child) {
5518
5489
  }
5519
5490
 
5520
5491
  // src/lint/runner.ts
5521
- import * as path15 from "path";
5492
+ import * as path14 from "path";
5522
5493
  var LintRunner = class {
5523
- constructor(matrixManager, schemaValidator, sopsClient) {
5494
+ constructor(matrixManager, schemaValidator, source) {
5524
5495
  this.matrixManager = matrixManager;
5525
5496
  this.schemaValidator = schemaValidator;
5526
- this.sopsClient = sopsClient;
5497
+ this.source = source;
5527
5498
  }
5528
5499
  matrixManager;
5529
5500
  schemaValidator;
5530
- sopsClient;
5501
+ source;
5531
5502
  /**
5532
5503
  * Lint the entire matrix: check missing files, schema errors, SOPS integrity,
5533
5504
  * single-recipient warnings, and cross-environment key drift.
@@ -5554,8 +5525,9 @@ var LintRunner = class {
5554
5525
  fileCount = existingCells.length;
5555
5526
  const namespaceKeys = {};
5556
5527
  for (const cell of existingCells) {
5528
+ const ref = { namespace: cell.namespace, environment: cell.environment };
5557
5529
  try {
5558
- const isValid = await this.sopsClient.validateEncryption(cell.filePath);
5530
+ const isValid = await this.source.validateEncryption(ref);
5559
5531
  if (!isValid) {
5560
5532
  issues.push({
5561
5533
  severity: "error",
@@ -5576,7 +5548,7 @@ var LintRunner = class {
5576
5548
  continue;
5577
5549
  }
5578
5550
  try {
5579
- const decrypted = await this.sopsClient.decrypt(cell.filePath);
5551
+ const decrypted = await this.source.readCell(ref);
5580
5552
  const keys = Object.keys(decrypted.values);
5581
5553
  if (!namespaceKeys[cell.namespace]) {
5582
5554
  namespaceKeys[cell.namespace] = {};
@@ -5621,7 +5593,7 @@ var LintRunner = class {
5621
5593
  }
5622
5594
  const ns = manifest.namespaces.find((n) => n.name === cell.namespace);
5623
5595
  if (ns?.schema) {
5624
- const schemaPath = path15.join(repoRoot, ns.schema);
5596
+ const schemaPath = path14.join(repoRoot, ns.schema);
5625
5597
  try {
5626
5598
  const schema = this.schemaValidator.loadSchema(schemaPath);
5627
5599
  const result = this.schemaValidator.validate(decrypted.values, schema);
@@ -5664,7 +5636,8 @@ var LintRunner = class {
5664
5636
  }
5665
5637
  }
5666
5638
  try {
5667
- const pendingKeys = await getPendingKeys(cell.filePath);
5639
+ const meta = await this.source.getPendingMetadata(ref);
5640
+ const pendingKeys = meta.pending.map((p) => p.key);
5668
5641
  pendingCount += pendingKeys.length;
5669
5642
  for (const pendingKey of pendingKeys) {
5670
5643
  issues.push({
@@ -5717,7 +5690,6 @@ var LintRunner = class {
5717
5690
  const siIssues = await this.lintServiceIdentities(
5718
5691
  manifest.service_identities,
5719
5692
  manifest,
5720
- repoRoot,
5721
5693
  existingCells
5722
5694
  );
5723
5695
  issues.push(...siIssues);
@@ -5727,18 +5699,27 @@ var LintRunner = class {
5727
5699
  return { issues, fileCount: fileCount + missingCells.length, pendingCount };
5728
5700
  }
5729
5701
  /**
5730
- * Cross-reference `.clef-meta.yaml` against the cipher's plaintext key
5702
+ * Cross-reference cell metadata against the cipher's plaintext key
5731
5703
  * names for each existing cell. Reports orphan rotation records and
5732
- * dual-state (pending + rotation) inconsistencies. Uses
5733
- * {@link readSopsKeyNames} (plaintext YAML parse) — no decryption.
5704
+ * dual-state (pending + rotation) inconsistencies. Uses the source's
5705
+ * `listKeys` (no decryption).
5734
5706
  */
5735
5707
  async lintMetadataConsistency(cells) {
5736
5708
  const issues = [];
5737
5709
  for (const cell of cells) {
5738
- const keysInCipher = readSopsKeyNames(cell.filePath);
5739
- if (keysInCipher === null) continue;
5740
- const cipherKeys = new Set(keysInCipher);
5741
- const metadata = await loadMetadata(cell.filePath);
5710
+ const ref = { namespace: cell.namespace, environment: cell.environment };
5711
+ let cipherKeys;
5712
+ try {
5713
+ cipherKeys = new Set(await this.source.listKeys(ref));
5714
+ } catch {
5715
+ continue;
5716
+ }
5717
+ let metadata;
5718
+ try {
5719
+ metadata = await this.source.getPendingMetadata(ref);
5720
+ } catch {
5721
+ continue;
5722
+ }
5742
5723
  for (const record of metadata.rotations) {
5743
5724
  if (!cipherKeys.has(record.key)) {
5744
5725
  issues.push({
@@ -5769,7 +5750,7 @@ var LintRunner = class {
5769
5750
  /**
5770
5751
  * Lint service identity configurations for drift issues.
5771
5752
  */
5772
- async lintServiceIdentities(identities, manifest, repoRoot, existingCells) {
5753
+ async lintServiceIdentities(identities, manifest, existingCells) {
5773
5754
  const issues = [];
5774
5755
  const declaredEnvNames = new Set(manifest.environments.map((e) => e.name));
5775
5756
  const declaredNsNames = new Set(manifest.namespaces.map((ns) => ns.name));
@@ -5810,9 +5791,10 @@ var LintRunner = class {
5810
5791
  const envConfig = si.environments[cell.environment];
5811
5792
  if (!envConfig) continue;
5812
5793
  if (!envConfig.recipient) continue;
5794
+ const ref = { namespace: cell.namespace, environment: cell.environment };
5813
5795
  if (si.namespaces.includes(cell.namespace)) {
5814
5796
  try {
5815
- const metadata = await this.sopsClient.getMetadata(cell.filePath);
5797
+ const metadata = await this.source.getCellMetadata(ref);
5816
5798
  if (!metadata.recipients.includes(envConfig.recipient)) {
5817
5799
  issues.push({
5818
5800
  severity: "warning",
@@ -5826,7 +5808,7 @@ var LintRunner = class {
5826
5808
  }
5827
5809
  } else {
5828
5810
  try {
5829
- const metadata = await this.sopsClient.getMetadata(cell.filePath);
5811
+ const metadata = await this.source.getCellMetadata(ref);
5830
5812
  if (metadata.recipients.includes(envConfig.recipient)) {
5831
5813
  issues.push({
5832
5814
  severity: "warning",
@@ -5852,7 +5834,10 @@ var LintRunner = class {
5852
5834
  async fix(manifest, repoRoot) {
5853
5835
  const missingCells = this.matrixManager.detectMissingCells(manifest, repoRoot);
5854
5836
  for (const cell of missingCells) {
5855
- await this.matrixManager.scaffoldCell(cell, this.sopsClient, manifest);
5837
+ await this.source.scaffoldCell(
5838
+ { namespace: cell.namespace, environment: cell.environment },
5839
+ manifest
5840
+ );
5856
5841
  }
5857
5842
  return this.run(manifest, repoRoot);
5858
5843
  }
@@ -5907,15 +5892,12 @@ Use 'clef exec' to inject secrets directly into a process, or 'clef export --for
5907
5892
  }
5908
5893
  };
5909
5894
 
5910
- // src/import/index.ts
5911
- import * as path17 from "path";
5912
-
5913
5895
  // src/import/parsers.ts
5914
- import * as path16 from "path";
5896
+ import * as path15 from "path";
5915
5897
  import * as YAML9 from "yaml";
5916
5898
  function detectFormat(filePath, content) {
5917
- const base = path16.basename(filePath);
5918
- const ext = path16.extname(filePath).toLowerCase();
5899
+ const base = path15.basename(filePath);
5900
+ const ext = path15.extname(filePath).toLowerCase();
5919
5901
  if (base === ".env" || base.startsWith(".env.")) {
5920
5902
  return "dotenv";
5921
5903
  }
@@ -6065,11 +6047,11 @@ function parse9(content, format, filePath) {
6065
6047
 
6066
6048
  // src/import/index.ts
6067
6049
  var ImportRunner = class {
6068
- constructor(sopsClient, tx) {
6069
- this.sopsClient = sopsClient;
6050
+ constructor(source, tx) {
6051
+ this.source = source;
6070
6052
  this.tx = tx;
6071
6053
  }
6072
- sopsClient;
6054
+ source;
6073
6055
  tx;
6074
6056
  /**
6075
6057
  * Parse a source file and import its key/value pairs into a target `namespace/environment` cell.
@@ -6083,10 +6065,8 @@ var ImportRunner = class {
6083
6065
  */
6084
6066
  async import(target, sourcePath, content, manifest, repoRoot, options) {
6085
6067
  const [ns, env] = target.split("/");
6086
- const filePath = path17.join(
6087
- repoRoot,
6088
- manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
6089
- );
6068
+ const ref = { namespace: ns, environment: env };
6069
+ const relCellPath = manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env);
6090
6070
  const parsed = parse9(content, options.format ?? "auto", sourcePath ?? "");
6091
6071
  let candidates = Object.entries(parsed.pairs);
6092
6072
  if (options.prefix) {
@@ -6104,7 +6084,7 @@ var ImportRunner = class {
6104
6084
  if (options.dryRun) {
6105
6085
  let existingKeys;
6106
6086
  try {
6107
- const decrypted2 = await this.sopsClient.decrypt(filePath);
6087
+ const decrypted2 = await this.source.readCell(ref);
6108
6088
  existingKeys = new Set(Object.keys(decrypted2.values));
6109
6089
  } catch {
6110
6090
  existingKeys = /* @__PURE__ */ new Set();
@@ -6118,7 +6098,7 @@ var ImportRunner = class {
6118
6098
  }
6119
6099
  return { imported, skipped, failed, warnings, dryRun: true };
6120
6100
  }
6121
- const decrypted = await this.sopsClient.decrypt(filePath);
6101
+ const decrypted = await this.source.readCell(ref);
6122
6102
  const newValues = { ...decrypted.values };
6123
6103
  const rotatedKeys = [];
6124
6104
  for (const [key, value] of candidates) {
@@ -6135,7 +6115,6 @@ var ImportRunner = class {
6135
6115
  if (imported.length === 0) {
6136
6116
  return { imported, skipped, failed, warnings, dryRun: false };
6137
6117
  }
6138
- const relCellPath = path17.relative(repoRoot, filePath);
6139
6118
  const relMetaPath = relCellPath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml");
6140
6119
  await this.tx.run(repoRoot, {
6141
6120
  description: `clef import ${target}: ${imported.length} key(s)`,
@@ -6143,9 +6122,9 @@ var ImportRunner = class {
6143
6122
  // callback are staged and rolled back atomically with the ciphertext.
6144
6123
  paths: [relCellPath, relMetaPath],
6145
6124
  mutate: async () => {
6146
- await this.sopsClient.encrypt(filePath, newValues, manifest, env);
6125
+ await this.source.writeCell(ref, newValues);
6147
6126
  if (options.rotatedBy && rotatedKeys.length > 0) {
6148
- await recordRotation(filePath, rotatedKeys, options.rotatedBy);
6127
+ await this.source.recordRotation(ref, rotatedKeys, options.rotatedBy);
6149
6128
  }
6150
6129
  }
6151
6130
  });
@@ -6154,7 +6133,7 @@ var ImportRunner = class {
6154
6133
  };
6155
6134
 
6156
6135
  // src/recipients/index.ts
6157
- import * as path18 from "path";
6136
+ import * as path16 from "path";
6158
6137
  function parseRecipientEntry(entry) {
6159
6138
  if (typeof entry === "string") {
6160
6139
  return { key: entry };
@@ -6222,12 +6201,12 @@ function ensureEnvironmentRecipientsArray(doc, envName) {
6222
6201
  return env.recipients;
6223
6202
  }
6224
6203
  var RecipientManager = class {
6225
- constructor(encryption, matrixManager, tx) {
6226
- this.encryption = encryption;
6204
+ constructor(source, matrixManager, tx) {
6205
+ this.source = source;
6227
6206
  this.matrixManager = matrixManager;
6228
6207
  this.tx = tx;
6229
6208
  }
6230
- encryption;
6209
+ source;
6231
6210
  matrixManager;
6232
6211
  tx;
6233
6212
  /**
@@ -6282,7 +6261,7 @@ var RecipientManager = class {
6282
6261
  const reEncryptedFiles = [];
6283
6262
  await this.tx.run(repoRoot, {
6284
6263
  description: environment ? `clef recipients add ${keyPreview(normalizedKey)} -e ${environment}` : `clef recipients add ${keyPreview(normalizedKey)}`,
6285
- paths: [...cells.map((c) => path18.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
6264
+ paths: [...cells.map((c) => path16.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
6286
6265
  mutate: async () => {
6287
6266
  const doc = readManifestYaml(repoRoot);
6288
6267
  const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
@@ -6293,7 +6272,8 @@ var RecipientManager = class {
6293
6272
  }
6294
6273
  writeManifestYaml(repoRoot, doc);
6295
6274
  for (const cell of cells) {
6296
- await this.encryption.addRecipient(cell.filePath, normalizedKey);
6275
+ const ref = { namespace: cell.namespace, environment: cell.environment };
6276
+ await this.source.rotate(ref, { addAge: normalizedKey });
6297
6277
  reEncryptedFiles.push(cell.filePath);
6298
6278
  }
6299
6279
  }
@@ -6341,7 +6321,7 @@ var RecipientManager = class {
6341
6321
  const reEncryptedFiles = [];
6342
6322
  await this.tx.run(repoRoot, {
6343
6323
  description: environment ? `clef recipients remove ${keyPreview(trimmedKey)} -e ${environment}` : `clef recipients remove ${keyPreview(trimmedKey)}`,
6344
- paths: [...cells.map((c) => path18.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
6324
+ paths: [...cells.map((c) => path16.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
6345
6325
  mutate: async () => {
6346
6326
  const doc = readManifestYaml(repoRoot);
6347
6327
  const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
@@ -6349,7 +6329,8 @@ var RecipientManager = class {
6349
6329
  recipients.splice(idx, 1);
6350
6330
  writeManifestYaml(repoRoot, doc);
6351
6331
  for (const cell of cells) {
6352
- await this.encryption.removeRecipient(cell.filePath, trimmedKey);
6332
+ const ref = { namespace: cell.namespace, environment: cell.environment };
6333
+ await this.source.rotate(ref, { rmAge: trimmedKey });
6353
6334
  reEncryptedFiles.push(cell.filePath);
6354
6335
  }
6355
6336
  }
@@ -6371,12 +6352,12 @@ var RecipientManager = class {
6371
6352
 
6372
6353
  // src/recipients/requests.ts
6373
6354
  import * as fs17 from "fs";
6374
- import * as path19 from "path";
6355
+ import * as path17 from "path";
6375
6356
  import * as YAML10 from "yaml";
6376
6357
  var REQUESTS_FILENAME = ".clef-requests.yaml";
6377
6358
  var HEADER_COMMENT2 = "# Pending recipient access requests. Approve with: clef recipients approve <label>\n";
6378
6359
  function requestsFilePath(repoRoot) {
6379
- return path19.join(repoRoot, REQUESTS_FILENAME);
6360
+ return path17.join(repoRoot, REQUESTS_FILENAME);
6380
6361
  }
6381
6362
  function loadRequests(repoRoot) {
6382
6363
  const filePath = requestsFilePath(repoRoot);
@@ -6451,7 +6432,7 @@ function findInList(requests, identifier) {
6451
6432
  }
6452
6433
 
6453
6434
  // src/drift/detector.ts
6454
- import * as path20 from "path";
6435
+ import * as path18 from "path";
6455
6436
  var DriftDetector = class {
6456
6437
  parser = new ManifestParser();
6457
6438
  matrix = new MatrixManager();
@@ -6464,8 +6445,8 @@ var DriftDetector = class {
6464
6445
  * @returns Drift result with any issues found.
6465
6446
  */
6466
6447
  detect(localRoot, remoteRoot, namespaceFilter) {
6467
- const localManifest = this.parser.parse(path20.join(localRoot, CLEF_MANIFEST_FILENAME));
6468
- const remoteManifest = this.parser.parse(path20.join(remoteRoot, CLEF_MANIFEST_FILENAME));
6448
+ const localManifest = this.parser.parse(path18.join(localRoot, CLEF_MANIFEST_FILENAME));
6449
+ const remoteManifest = this.parser.parse(path18.join(remoteRoot, CLEF_MANIFEST_FILENAME));
6469
6450
  const localCells = this.matrix.resolveMatrix(localManifest, localRoot);
6470
6451
  const remoteCells = this.matrix.resolveMatrix(remoteManifest, remoteRoot);
6471
6452
  const localEnvNames = localManifest.environments.map((e) => e.name);
@@ -6529,7 +6510,7 @@ var DriftDetector = class {
6529
6510
  };
6530
6511
 
6531
6512
  // src/report/generator.ts
6532
- import * as path21 from "path";
6513
+ import * as path19 from "path";
6533
6514
 
6534
6515
  // src/report/sanitizer.ts
6535
6516
  var ReportSanitizer = class {
@@ -6666,14 +6647,14 @@ var ReportSanitizer = class {
6666
6647
 
6667
6648
  // src/report/generator.ts
6668
6649
  var ReportGenerator = class {
6669
- constructor(runner, sopsClient, matrixManager, schemaValidator) {
6650
+ constructor(runner, source, matrixManager, schemaValidator) {
6670
6651
  this.runner = runner;
6671
- this.sopsClient = sopsClient;
6652
+ this.source = source;
6672
6653
  this.matrixManager = matrixManager;
6673
6654
  this.schemaValidator = schemaValidator;
6674
6655
  }
6675
6656
  runner;
6676
- sopsClient;
6657
+ source;
6677
6658
  matrixManager;
6678
6659
  schemaValidator;
6679
6660
  /**
@@ -6689,7 +6670,7 @@ var ReportGenerator = class {
6689
6670
  let manifest = null;
6690
6671
  try {
6691
6672
  const parser = new ManifestParser();
6692
- manifest = parser.parse(path21.join(repoRoot, "clef.yaml"));
6673
+ manifest = parser.parse(path19.join(repoRoot, "clef.yaml"));
6693
6674
  } catch {
6694
6675
  const emptyManifest = {
6695
6676
  manifestVersion: 0,
@@ -6810,16 +6791,17 @@ var ReportGenerator = class {
6810
6791
  metadata: null
6811
6792
  };
6812
6793
  }
6794
+ const ref = { namespace: cell.namespace, environment: cell.environment };
6813
6795
  const keyCount = this.readKeyCount(cell.filePath);
6814
6796
  let pendingCount = 0;
6815
6797
  try {
6816
- const pending = await getPendingKeys(cell.filePath);
6817
- pendingCount = pending.length;
6798
+ const meta = await this.source.getPendingMetadata(ref);
6799
+ pendingCount = meta.pending.length;
6818
6800
  } catch {
6819
6801
  }
6820
6802
  let metadata = null;
6821
6803
  try {
6822
- const sopsMetadata = await this.sopsClient.getMetadata(cell.filePath);
6804
+ const sopsMetadata = await this.source.getCellMetadata(ref);
6823
6805
  metadata = {
6824
6806
  backend: sopsMetadata.backend,
6825
6807
  recipients: sopsMetadata.recipients,
@@ -6842,7 +6824,7 @@ var ReportGenerator = class {
6842
6824
  }
6843
6825
  async buildPolicy(manifest, repoRoot) {
6844
6826
  try {
6845
- const lintRunner = new LintRunner(this.matrixManager, this.schemaValidator, this.sopsClient);
6827
+ const lintRunner = new LintRunner(this.matrixManager, this.schemaValidator, this.source);
6846
6828
  const lintResult = await lintRunner.run(manifest, repoRoot);
6847
6829
  return new ReportSanitizer().sanitize(lintResult.issues);
6848
6830
  } catch {
@@ -7159,9 +7141,9 @@ var SopsMergeDriver = class {
7159
7141
  */
7160
7142
  async mergeFiles(basePath, oursPath, theirsPath) {
7161
7143
  const [baseDecrypted, oursDecrypted, theirsDecrypted] = await Promise.all([
7162
- this.sopsClient.decrypt(basePath),
7163
- this.sopsClient.decrypt(oursPath),
7164
- this.sopsClient.decrypt(theirsPath)
7144
+ this.sopsClient.decryptFile(basePath),
7145
+ this.sopsClient.decryptFile(oursPath),
7146
+ this.sopsClient.decryptFile(theirsPath)
7165
7147
  ]);
7166
7148
  return this.merge(baseDecrypted.values, oursDecrypted.values, theirsDecrypted.values);
7167
7149
  }
@@ -7278,22 +7260,26 @@ function mergeMetadataFiles(_basePath, oursPath, theirsPath) {
7278
7260
  }
7279
7261
 
7280
7262
  // src/service-identity/manager.ts
7281
- import * as path22 from "path";
7263
+ import * as path20 from "path";
7282
7264
  var ServiceIdentityManager = class {
7283
- constructor(encryption, matrixManager, tx) {
7284
- this.encryption = encryption;
7265
+ constructor(source, matrixManager, tx) {
7266
+ this.source = source;
7285
7267
  this.matrixManager = matrixManager;
7286
7268
  this.tx = tx;
7287
7269
  }
7288
- encryption;
7270
+ source;
7289
7271
  matrixManager;
7290
7272
  tx;
7273
+ /** Helper: cell → ref for the source seam. */
7274
+ ref(cell) {
7275
+ return { namespace: cell.namespace, environment: cell.environment };
7276
+ }
7291
7277
  /**
7292
7278
  * Compute repo-relative paths for a set of cells plus the manifest. Used
7293
7279
  * to seed TransactionManager.run's `paths` argument.
7294
7280
  */
7295
7281
  txPaths(repoRoot, cells) {
7296
- return [...cells.map((c) => path22.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME];
7282
+ return [...cells.map((c) => path20.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME];
7297
7283
  }
7298
7284
  /**
7299
7285
  * Create a new service identity with per-environment age key pairs or KMS envelope config.
@@ -7385,7 +7371,7 @@ var ServiceIdentityManager = class {
7385
7371
  if (!envConfig?.recipient) continue;
7386
7372
  if (isKmsEnvelope(envConfig)) continue;
7387
7373
  try {
7388
- await this.encryption.removeRecipient(cell.filePath, envConfig.recipient);
7374
+ await this.source.rotate(this.ref(cell), { rmAge: envConfig.recipient });
7389
7375
  } catch {
7390
7376
  }
7391
7377
  }
@@ -7435,7 +7421,7 @@ var ServiceIdentityManager = class {
7435
7421
  const scopedCells = cells.filter((c) => c.environment === envName);
7436
7422
  for (const cell of scopedCells) {
7437
7423
  try {
7438
- await this.encryption.removeRecipient(cell.filePath, oldConfig.recipient);
7424
+ await this.source.rotate(this.ref(cell), { rmAge: oldConfig.recipient });
7439
7425
  } catch {
7440
7426
  }
7441
7427
  }
@@ -7462,7 +7448,7 @@ var ServiceIdentityManager = class {
7462
7448
  if (isKmsEnvelope(envConfig)) continue;
7463
7449
  if (!envConfig.recipient) continue;
7464
7450
  try {
7465
- await this.encryption.addRecipient(cell.filePath, envConfig.recipient);
7451
+ await this.source.rotate(this.ref(cell), { addAge: envConfig.recipient });
7466
7452
  } catch (err) {
7467
7453
  const message = err instanceof Error ? err.message : String(err);
7468
7454
  if (!message.includes("already")) {
@@ -7510,7 +7496,7 @@ var ServiceIdentityManager = class {
7510
7496
  if (isKmsEnvelope(envConfig)) continue;
7511
7497
  if (!envConfig.recipient) continue;
7512
7498
  try {
7513
- await this.encryption.addRecipient(cell.filePath, envConfig.recipient);
7499
+ await this.source.rotate(this.ref(cell), { addAge: envConfig.recipient });
7514
7500
  affectedFiles.push(cell.filePath);
7515
7501
  } catch (err) {
7516
7502
  const message = err instanceof Error ? err.message : String(err);
@@ -7571,7 +7557,7 @@ var ServiceIdentityManager = class {
7571
7557
  if (isKmsEnvelope(envConfig)) continue;
7572
7558
  if (!envConfig.recipient) continue;
7573
7559
  try {
7574
- await this.encryption.removeRecipient(cell.filePath, envConfig.recipient);
7560
+ await this.source.rotate(this.ref(cell), { rmAge: envConfig.recipient });
7575
7561
  affectedFiles.push(cell.filePath);
7576
7562
  } catch {
7577
7563
  }
@@ -7640,7 +7626,7 @@ var ServiceIdentityManager = class {
7640
7626
  if (!identity.pack_only && !isKmsEnvelope(envConfig) && envConfig.recipient) {
7641
7627
  for (const cell of cells) {
7642
7628
  try {
7643
- await this.encryption.addRecipient(cell.filePath, envConfig.recipient);
7629
+ await this.source.rotate(this.ref(cell), { addAge: envConfig.recipient });
7644
7630
  } catch (err) {
7645
7631
  const message = err instanceof Error ? err.message : String(err);
7646
7632
  if (!message.includes("already")) {
@@ -7717,10 +7703,10 @@ var ServiceIdentityManager = class {
7717
7703
  const scopedCells = cells.filter((c) => c.environment === envName);
7718
7704
  for (const cell of scopedCells) {
7719
7705
  try {
7720
- await this.encryption.removeRecipient(cell.filePath, oldRecipient);
7706
+ await this.source.rotate(this.ref(cell), { rmAge: oldRecipient });
7721
7707
  } catch {
7722
7708
  }
7723
- await this.encryption.addRecipient(cell.filePath, newPublicKey);
7709
+ await this.source.rotate(this.ref(cell), { addAge: newPublicKey });
7724
7710
  }
7725
7711
  }
7726
7712
  }
@@ -7779,7 +7765,7 @@ var ServiceIdentityManager = class {
7779
7765
  if (!envConfig.recipient) continue;
7780
7766
  if (si.namespaces.includes(cell.namespace)) {
7781
7767
  try {
7782
- const metadata = await this.encryption.getMetadata(cell.filePath);
7768
+ const metadata = await this.source.getCellMetadata(this.ref(cell));
7783
7769
  if (!metadata.recipients.includes(envConfig.recipient)) {
7784
7770
  issues.push({
7785
7771
  identity: si.name,
@@ -7794,7 +7780,7 @@ var ServiceIdentityManager = class {
7794
7780
  }
7795
7781
  } else {
7796
7782
  try {
7797
- const metadata = await this.encryption.getMetadata(cell.filePath);
7783
+ const metadata = await this.source.getCellMetadata(this.ref(cell));
7798
7784
  if (metadata.recipients.includes(envConfig.recipient)) {
7799
7785
  issues.push({
7800
7786
  identity: si.name,
@@ -7816,15 +7802,15 @@ var ServiceIdentityManager = class {
7816
7802
 
7817
7803
  // src/structure/manager.ts
7818
7804
  import * as fs19 from "fs";
7819
- import * as path23 from "path";
7805
+ import * as path21 from "path";
7820
7806
  var StructureManager = class {
7821
- constructor(matrixManager, encryption, tx) {
7807
+ constructor(matrixManager, buildSource, tx) {
7822
7808
  this.matrixManager = matrixManager;
7823
- this.encryption = encryption;
7809
+ this.buildSource = buildSource;
7824
7810
  this.tx = tx;
7825
7811
  }
7826
7812
  matrixManager;
7827
- encryption;
7813
+ buildSource;
7828
7814
  tx;
7829
7815
  // ── add ──────────────────────────────────────────────────────────────────
7830
7816
  /**
@@ -7840,7 +7826,7 @@ var StructureManager = class {
7840
7826
  this.assertValidIdentifier("namespace", name);
7841
7827
  const newCellPaths = manifest.environments.map((env) => ({
7842
7828
  environment: env.name,
7843
- filePath: path23.join(
7829
+ filePath: path21.join(
7844
7830
  repoRoot,
7845
7831
  manifest.file_pattern.replace("{namespace}", name).replace("{environment}", env.name)
7846
7832
  )
@@ -7848,7 +7834,7 @@ var StructureManager = class {
7848
7834
  for (const cell of newCellPaths) {
7849
7835
  if (fs19.existsSync(cell.filePath)) {
7850
7836
  throw new Error(
7851
- `Cannot add namespace '${name}': file '${path23.relative(repoRoot, cell.filePath)}' already exists.`
7837
+ `Cannot add namespace '${name}': file '${path21.relative(repoRoot, cell.filePath)}' already exists.`
7852
7838
  );
7853
7839
  }
7854
7840
  }
@@ -7867,21 +7853,14 @@ var StructureManager = class {
7867
7853
  await this.tx.run(repoRoot, {
7868
7854
  description: `clef namespace add ${name}`,
7869
7855
  paths: [
7870
- ...newCellPaths.map((c) => path23.relative(repoRoot, c.filePath)),
7856
+ ...newCellPaths.map((c) => path21.relative(repoRoot, c.filePath)),
7871
7857
  CLEF_MANIFEST_FILENAME
7872
7858
  ],
7873
7859
  mutate: async () => {
7860
+ const source = this.buildSource(updatedManifest);
7874
7861
  for (const cell of newCellPaths) {
7875
- await this.matrixManager.scaffoldCell(
7876
- {
7877
- namespace: name,
7878
- environment: cell.environment,
7879
- filePath: cell.filePath,
7880
- exists: false
7881
- },
7882
- this.encryption,
7883
- updatedManifest
7884
- );
7862
+ const ref = { namespace: name, environment: cell.environment };
7863
+ await source.scaffoldCell(ref, updatedManifest);
7885
7864
  }
7886
7865
  const doc = readManifestYaml(repoRoot);
7887
7866
  const namespaces = doc.namespaces;
@@ -7912,7 +7891,7 @@ var StructureManager = class {
7912
7891
  this.assertValidIdentifier("environment", name);
7913
7892
  const newCellPaths = manifest.namespaces.map((ns) => ({
7914
7893
  namespace: ns.name,
7915
- filePath: path23.join(
7894
+ filePath: path21.join(
7916
7895
  repoRoot,
7917
7896
  manifest.file_pattern.replace("{namespace}", ns.name).replace("{environment}", name)
7918
7897
  )
@@ -7920,7 +7899,7 @@ var StructureManager = class {
7920
7899
  for (const cell of newCellPaths) {
7921
7900
  if (fs19.existsSync(cell.filePath)) {
7922
7901
  throw new Error(
7923
- `Cannot add environment '${name}': file '${path23.relative(repoRoot, cell.filePath)}' already exists.`
7902
+ `Cannot add environment '${name}': file '${path21.relative(repoRoot, cell.filePath)}' already exists.`
7924
7903
  );
7925
7904
  }
7926
7905
  }
@@ -7939,21 +7918,14 @@ var StructureManager = class {
7939
7918
  await this.tx.run(repoRoot, {
7940
7919
  description: `clef env add ${name}`,
7941
7920
  paths: [
7942
- ...newCellPaths.map((c) => path23.relative(repoRoot, c.filePath)),
7921
+ ...newCellPaths.map((c) => path21.relative(repoRoot, c.filePath)),
7943
7922
  CLEF_MANIFEST_FILENAME
7944
7923
  ],
7945
7924
  mutate: async () => {
7925
+ const source = this.buildSource(updatedManifest);
7946
7926
  for (const cell of newCellPaths) {
7947
- await this.matrixManager.scaffoldCell(
7948
- {
7949
- namespace: cell.namespace,
7950
- environment: name,
7951
- filePath: cell.filePath,
7952
- exists: false
7953
- },
7954
- this.encryption,
7955
- updatedManifest
7956
- );
7927
+ const ref = { namespace: cell.namespace, environment: name };
7928
+ await source.scaffoldCell(ref, updatedManifest);
7957
7929
  }
7958
7930
  const doc = readManifestYaml(repoRoot);
7959
7931
  const environments = doc.environments;
@@ -8096,7 +8068,7 @@ var StructureManager = class {
8096
8068
  for (const pair of renamePairs) {
8097
8069
  if (fs19.existsSync(pair.to)) {
8098
8070
  throw new Error(
8099
- `Rename target '${path23.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
8071
+ `Rename target '${path21.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
8100
8072
  );
8101
8073
  }
8102
8074
  }
@@ -8139,7 +8111,7 @@ var StructureManager = class {
8139
8111
  for (const pair of renamePairs) {
8140
8112
  if (fs19.existsSync(pair.to)) {
8141
8113
  throw new Error(
8142
- `Rename target '${path23.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
8114
+ `Rename target '${path21.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
8143
8115
  );
8144
8116
  }
8145
8117
  }
@@ -8189,7 +8161,7 @@ var StructureManager = class {
8189
8161
  swapAxisInCellPath(repoRoot, manifest, cell, axis, newName) {
8190
8162
  const ns = axis === "namespace" ? newName : cell.namespace;
8191
8163
  const env = axis === "environment" ? newName : cell.environment;
8192
- return path23.join(
8164
+ return path21.join(
8193
8165
  repoRoot,
8194
8166
  manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
8195
8167
  );
@@ -8201,8 +8173,8 @@ var StructureManager = class {
8201
8173
  txPaths(repoRoot, renamePairs) {
8202
8174
  const paths = /* @__PURE__ */ new Set();
8203
8175
  for (const pair of renamePairs) {
8204
- paths.add(path23.relative(repoRoot, pair.from));
8205
- paths.add(path23.relative(repoRoot, pair.to));
8176
+ paths.add(path21.relative(repoRoot, pair.from));
8177
+ paths.add(path21.relative(repoRoot, pair.to));
8206
8178
  }
8207
8179
  paths.add(CLEF_MANIFEST_FILENAME);
8208
8180
  return [...paths];
@@ -8213,7 +8185,7 @@ var StructureManager = class {
8213
8185
  */
8214
8186
  applyRenames(pairs) {
8215
8187
  for (const pair of pairs) {
8216
- const targetDir = path23.dirname(pair.to);
8188
+ const targetDir = path21.dirname(pair.to);
8217
8189
  if (!fs19.existsSync(targetDir)) {
8218
8190
  fs19.mkdirSync(targetDir, { recursive: true });
8219
8191
  }
@@ -8228,10 +8200,10 @@ var StructureManager = class {
8228
8200
  deletePaths(repoRoot, cells) {
8229
8201
  const paths = /* @__PURE__ */ new Set();
8230
8202
  for (const cell of cells) {
8231
- paths.add(path23.relative(repoRoot, cell.filePath));
8203
+ paths.add(path21.relative(repoRoot, cell.filePath));
8232
8204
  const meta = cell.filePath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml");
8233
8205
  if (fs19.existsSync(meta)) {
8234
- paths.add(path23.relative(repoRoot, meta));
8206
+ paths.add(path21.relative(repoRoot, meta));
8235
8207
  }
8236
8208
  }
8237
8209
  paths.add(CLEF_MANIFEST_FILENAME);
@@ -8346,7 +8318,7 @@ function renameKeyPreservingOrder(obj, oldKey, newKey) {
8346
8318
  }
8347
8319
 
8348
8320
  // src/artifact/resolve.ts
8349
- async function resolveIdentitySecrets(identityName, environment, manifest, repoRoot, encryption, matrixManager) {
8321
+ async function resolveIdentitySecrets(identityName, environment, manifest, repoRoot, source, matrixManager) {
8350
8322
  const identity = manifest.service_identities?.find((si) => si.name === identityName);
8351
8323
  if (!identity) {
8352
8324
  throw new Error(`Service identity '${identityName}' not found in manifest.`);
@@ -8362,7 +8334,10 @@ async function resolveIdentitySecrets(identityName, environment, manifest, repoR
8362
8334
  (c) => c.exists && identity.namespaces.includes(c.namespace) && c.environment === environment
8363
8335
  );
8364
8336
  for (const cell of cells) {
8365
- const decrypted = await encryption.decrypt(cell.filePath);
8337
+ const decrypted = await source.readCell({
8338
+ namespace: cell.namespace,
8339
+ environment: cell.environment
8340
+ });
8366
8341
  const bucket = allValues[cell.namespace] ??= {};
8367
8342
  for (const [key, value] of Object.entries(decrypted.values)) {
8368
8343
  if (key in bucket && bucket[key] !== value) {
@@ -8386,14 +8361,14 @@ import * as crypto4 from "crypto";
8386
8361
 
8387
8362
  // src/artifact/output.ts
8388
8363
  import * as fs20 from "fs";
8389
- import * as path24 from "path";
8364
+ import * as path22 from "path";
8390
8365
  var FilePackOutput = class {
8391
8366
  constructor(outputPath) {
8392
8367
  this.outputPath = outputPath;
8393
8368
  }
8394
8369
  outputPath;
8395
8370
  async write(_artifact, json) {
8396
- const outputDir = path24.dirname(this.outputPath);
8371
+ const outputDir = path22.dirname(this.outputPath);
8397
8372
  if (!fs20.existsSync(outputDir)) {
8398
8373
  fs20.mkdirSync(outputDir, { recursive: true });
8399
8374
  }
@@ -8440,17 +8415,6 @@ function buildSigningPayload(artifact) {
8440
8415
  ];
8441
8416
  return Buffer.from(fields.join("\n"), "utf-8");
8442
8417
  }
8443
- function generateSigningKeyPair() {
8444
- const pair = crypto2.generateKeyPairSync("ed25519");
8445
- return {
8446
- publicKey: pair.publicKey.export({ type: "spki", format: "der" }).toString(
8447
- "base64"
8448
- ),
8449
- privateKey: pair.privateKey.export({ type: "pkcs8", format: "der" }).toString(
8450
- "base64"
8451
- )
8452
- };
8453
- }
8454
8418
  function signEd25519(payload, privateKeyBase64) {
8455
8419
  const keyObj = crypto2.createPrivateKey({
8456
8420
  key: Buffer.from(privateKeyBase64, "base64"),
@@ -8486,17 +8450,6 @@ function verifySignature(payload, signatureBase64, publicKeyBase64) {
8486
8450
  }
8487
8451
  throw new Error(`Unsupported key type for signature verification: ${keyType}`);
8488
8452
  }
8489
- function detectAlgorithm(publicKeyBase64) {
8490
- const keyObj = crypto2.createPublicKey({
8491
- key: Buffer.from(publicKeyBase64, "base64"),
8492
- format: "der",
8493
- type: "spki"
8494
- });
8495
- const keyType = keyObj.asymmetricKeyType;
8496
- if (keyType === "ed25519") return "Ed25519";
8497
- if (keyType === "ec") return "ECDSA_SHA256";
8498
- throw new Error(`Unsupported key type: ${keyType}`);
8499
- }
8500
8453
 
8501
8454
  // src/artifact/hash.ts
8502
8455
  import * as crypto3 from "crypto";
@@ -8506,12 +8459,12 @@ function computeCiphertextHash(ciphertext) {
8506
8459
 
8507
8460
  // src/artifact/packer.ts
8508
8461
  var ArtifactPacker = class {
8509
- constructor(encryption, matrixManager, kms) {
8510
- this.encryption = encryption;
8462
+ constructor(source, matrixManager, kms) {
8463
+ this.source = source;
8511
8464
  this.matrixManager = matrixManager;
8512
8465
  this.kms = kms;
8513
8466
  }
8514
- encryption;
8467
+ source;
8515
8468
  matrixManager;
8516
8469
  kms;
8517
8470
  /**
@@ -8529,7 +8482,7 @@ var ArtifactPacker = class {
8529
8482
  config.environment,
8530
8483
  manifest,
8531
8484
  repoRoot,
8532
- this.encryption,
8485
+ this.source,
8533
8486
  this.matrixManager
8534
8487
  );
8535
8488
  const plaintext = JSON.stringify(resolved.values);
@@ -8914,11 +8867,7 @@ var JsonEnvelopeBackend = class {
8914
8867
  }
8915
8868
  async pack(req) {
8916
8869
  const opts = req.backendOptions;
8917
- const packer = new ArtifactPacker(
8918
- req.services.encryption,
8919
- new MatrixManager(),
8920
- req.services.kms
8921
- );
8870
+ const packer = new ArtifactPacker(req.services.source, new MatrixManager(), req.services.kms);
8922
8871
  const output = opts.output ?? (opts.outputPath ? new FilePackOutput(opts.outputPath) : void 0);
8923
8872
  const result = await packer.pack(
8924
8873
  {
@@ -8947,7 +8896,7 @@ var JsonEnvelopeBackend = class {
8947
8896
  var VALID_KMS_PROVIDERS = ["aws", "gcp", "azure"];
8948
8897
 
8949
8898
  // src/migration/backend.ts
8950
- import * as path25 from "path";
8899
+ import * as path23 from "path";
8951
8900
  import * as YAML12 from "yaml";
8952
8901
  var BACKEND_KEY_FIELDS = {
8953
8902
  age: void 0,
@@ -8975,23 +8924,24 @@ function metadataMatchesTarget(meta, target) {
8975
8924
  }
8976
8925
  var BackendMigrator = class {
8977
8926
  /**
8978
- * @param encryption - Backend used for both decrypt and encrypt (standard case).
8927
+ * @param buildSource - Factory that builds a `SecretSource` bound to a
8928
+ * given manifest. Called twice during a real migration: once with the
8929
+ * pre-migration manifest (for classification + decrypt) and once with
8930
+ * the post-mutation manifest (for re-encrypt + verify). The factory
8931
+ * pattern is required because the encryption layer of a composed
8932
+ * source is bound to a manifest at construction.
8979
8933
  * @param matrixManager - Matrix resolver.
8980
8934
  * @param tx - Transaction manager that wraps the migration in a single git commit
8981
8935
  * so a partial failure rolls back ALL files + the manifest via `git reset --hard`.
8982
- * @param targetEncryption - Optional separate backend for encrypt. Use when migrating
8983
- * from cloud (decrypt via keyservice) to another backend (encrypt via local credentials).
8984
8936
  */
8985
- constructor(encryption, matrixManager, tx, targetEncryption) {
8937
+ constructor(buildSource, matrixManager, tx) {
8938
+ this.buildSource = buildSource;
8986
8939
  this.matrixManager = matrixManager;
8987
8940
  this.tx = tx;
8988
- this.decryptBackend = encryption;
8989
- this.encryptBackend = targetEncryption ?? encryption;
8990
8941
  }
8942
+ buildSource;
8991
8943
  matrixManager;
8992
8944
  tx;
8993
- decryptBackend;
8994
- encryptBackend;
8995
8945
  async migrate(manifest, repoRoot, options, onProgress) {
8996
8946
  const { target, environment, dryRun, skipVerify } = options;
8997
8947
  if (environment) {
@@ -9011,10 +8961,12 @@ var BackendMigrator = class {
9011
8961
  warnings: ["No encrypted files found to migrate."]
9012
8962
  };
9013
8963
  }
8964
+ const sourceBefore = this.buildSource(manifest);
9014
8965
  const toMigrate = [];
9015
8966
  const skippedFiles = [];
9016
8967
  for (const cell of targetCells) {
9017
- const meta = await this.decryptBackend.getMetadata(cell.filePath);
8968
+ const ref = { namespace: cell.namespace, environment: cell.environment };
8969
+ const meta = await sourceBefore.getCellMetadata(ref);
9018
8970
  if (metadataMatchesTarget(meta, target)) {
9019
8971
  skippedFiles.push(cell.filePath);
9020
8972
  onProgress?.({
@@ -9065,11 +9017,12 @@ var BackendMigrator = class {
9065
9017
  const migratedFiles = [];
9066
9018
  let migrationFailed = false;
9067
9019
  let migrationError;
9020
+ let sourceAfter;
9068
9021
  try {
9069
9022
  await this.tx.run(repoRoot, {
9070
9023
  description: environment ? `clef migrate-backend ${target.backend}: ${environment}` : `clef migrate-backend ${target.backend}`,
9071
9024
  paths: [
9072
- ...toMigrate.map((c) => path25.relative(repoRoot, c.filePath)),
9025
+ ...toMigrate.map((c) => path23.relative(repoRoot, c.filePath)),
9073
9026
  CLEF_MANIFEST_FILENAME
9074
9027
  ],
9075
9028
  mutate: async () => {
@@ -9077,19 +9030,16 @@ var BackendMigrator = class {
9077
9030
  this.updateManifestDoc(doc, target, environment);
9078
9031
  writeManifestYaml(repoRoot, doc);
9079
9032
  const updatedManifest = YAML12.parse(YAML12.stringify(doc));
9033
+ sourceAfter = this.buildSource(updatedManifest);
9080
9034
  for (const cell of toMigrate) {
9081
9035
  onProgress?.({
9082
9036
  type: "migrate",
9083
9037
  file: cell.filePath,
9084
9038
  message: `Migrating ${cell.namespace}/${cell.environment}...`
9085
9039
  });
9086
- const decrypted = await this.decryptBackend.decrypt(cell.filePath);
9087
- await this.encryptBackend.encrypt(
9088
- cell.filePath,
9089
- decrypted.values,
9090
- updatedManifest,
9091
- cell.environment
9092
- );
9040
+ const ref = { namespace: cell.namespace, environment: cell.environment };
9041
+ const decrypted = await sourceBefore.readCell(ref);
9042
+ await sourceAfter.writeCell(ref, decrypted.values);
9093
9043
  migratedFiles.push(cell.filePath);
9094
9044
  }
9095
9045
  }
@@ -9119,7 +9069,7 @@ var BackendMigrator = class {
9119
9069
  }
9120
9070
  const verifiedFiles = [];
9121
9071
  const warnings = [];
9122
- if (!skipVerify) {
9072
+ if (!skipVerify && sourceAfter) {
9123
9073
  for (const cell of toMigrate) {
9124
9074
  try {
9125
9075
  onProgress?.({
@@ -9127,7 +9077,8 @@ var BackendMigrator = class {
9127
9077
  file: cell.filePath,
9128
9078
  message: `Verifying ${cell.namespace}/${cell.environment}...`
9129
9079
  });
9130
- await this.encryptBackend.decrypt(cell.filePath);
9080
+ const ref = { namespace: cell.namespace, environment: cell.environment };
9081
+ await sourceAfter.readCell(ref);
9131
9082
  verifiedFiles.push(cell.filePath);
9132
9083
  } catch (err) {
9133
9084
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -9172,16 +9123,16 @@ var BackendMigrator = class {
9172
9123
  };
9173
9124
 
9174
9125
  // src/reset/manager.ts
9175
- import * as path26 from "path";
9126
+ import * as path24 from "path";
9176
9127
  var ResetManager = class {
9177
- constructor(matrixManager, encryption, schemaValidator, tx) {
9128
+ constructor(matrixManager, buildSource, schemaValidator, tx) {
9178
9129
  this.matrixManager = matrixManager;
9179
- this.encryption = encryption;
9130
+ this.buildSource = buildSource;
9180
9131
  this.schemaValidator = schemaValidator;
9181
9132
  this.tx = tx;
9182
9133
  }
9183
9134
  matrixManager;
9184
- encryption;
9135
+ buildSource;
9185
9136
  schemaValidator;
9186
9137
  tx;
9187
9138
  async reset(opts, manifest, repoRoot) {
@@ -9201,11 +9152,11 @@ var ResetManager = class {
9201
9152
  txPaths.push(CLEF_MANIFEST_FILENAME);
9202
9153
  }
9203
9154
  for (const cell of targetCells) {
9204
- txPaths.push(path26.relative(repoRoot, cell.filePath));
9155
+ txPaths.push(path24.relative(repoRoot, cell.filePath));
9205
9156
  const cellKeys = keyPlan.get(cell.namespace) ?? [];
9206
9157
  if (cellKeys.length > 0) {
9207
9158
  txPaths.push(
9208
- path26.relative(repoRoot, cell.filePath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml"))
9159
+ path24.relative(repoRoot, cell.filePath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml"))
9209
9160
  );
9210
9161
  }
9211
9162
  }
@@ -9222,17 +9173,14 @@ var ResetManager = class {
9222
9173
  writeManifestYaml(repoRoot, doc);
9223
9174
  effectiveManifest = withBackendOverride(manifest, affectedEnvs, opts.backend, opts.key);
9224
9175
  }
9176
+ const source = this.buildSource(effectiveManifest);
9225
9177
  for (const cell of targetCells) {
9226
9178
  const keys = keyPlan.get(cell.namespace) ?? [];
9227
9179
  const placeholders = this.buildPlaceholders(keys);
9228
- await this.encryption.encrypt(
9229
- cell.filePath,
9230
- placeholders,
9231
- effectiveManifest,
9232
- cell.environment
9233
- );
9180
+ const ref = { namespace: cell.namespace, environment: cell.environment };
9181
+ await source.writeCell(ref, placeholders);
9234
9182
  if (keys.length > 0) {
9235
- await markPendingWithRetry(cell.filePath, keys, "clef reset");
9183
+ await source.markPending(ref, keys, "clef reset");
9236
9184
  pendingKeysByCell[cell.filePath] = keys;
9237
9185
  }
9238
9186
  scaffoldedCells.push(cell.filePath);
@@ -9293,7 +9241,7 @@ var ResetManager = class {
9293
9241
  for (const namespace of namespaces) {
9294
9242
  const nsDef = manifest.namespaces.find((n) => n.name === namespace);
9295
9243
  if (nsDef?.schema) {
9296
- const schema = this.schemaValidator.loadSchema(path26.join(repoRoot, nsDef.schema));
9244
+ const schema = this.schemaValidator.loadSchema(path24.join(repoRoot, nsDef.schema));
9297
9245
  plan.set(namespace, Object.keys(schema.keys));
9298
9246
  continue;
9299
9247
  }
@@ -9372,15 +9320,15 @@ function withBackendOverride(manifest, envNames, backend, key) {
9372
9320
  }
9373
9321
 
9374
9322
  // src/sync/manager.ts
9375
- import * as path27 from "path";
9323
+ import * as path25 from "path";
9376
9324
  var SyncManager = class {
9377
- constructor(matrixManager, encryption, tx) {
9325
+ constructor(matrixManager, source, tx) {
9378
9326
  this.matrixManager = matrixManager;
9379
- this.encryption = encryption;
9327
+ this.source = source;
9380
9328
  this.tx = tx;
9381
9329
  }
9382
9330
  matrixManager;
9383
- encryption;
9331
+ source;
9384
9332
  tx;
9385
9333
  /**
9386
9334
  * Compute what sync would do without mutating anything.
@@ -9397,8 +9345,13 @@ var SyncManager = class {
9397
9345
  const targetCells = opts.namespace ? existingCells.filter((c) => c.namespace === opts.namespace) : existingCells;
9398
9346
  const keysByNsEnv = {};
9399
9347
  for (const cell of targetCells) {
9400
- const keys = readSopsKeyNames(cell.filePath);
9401
- if (!keys) continue;
9348
+ const ref = { namespace: cell.namespace, environment: cell.environment };
9349
+ let keys;
9350
+ try {
9351
+ keys = await this.source.listKeys(ref);
9352
+ } catch {
9353
+ continue;
9354
+ }
9402
9355
  if (!keysByNsEnv[cell.namespace]) keysByNsEnv[cell.namespace] = {};
9403
9356
  keysByNsEnv[cell.namespace][cell.environment] = new Set(keys);
9404
9357
  }
@@ -9444,7 +9397,7 @@ var SyncManager = class {
9444
9397
  }
9445
9398
  const txPaths = [];
9446
9399
  for (const cell of syncPlan.cells) {
9447
- const rel = path27.relative(repoRoot, cell.filePath);
9400
+ const rel = path25.relative(repoRoot, cell.filePath);
9448
9401
  txPaths.push(rel);
9449
9402
  txPaths.push(rel.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml"));
9450
9403
  }
@@ -9457,17 +9410,13 @@ var SyncManager = class {
9457
9410
  paths: txPaths,
9458
9411
  mutate: async () => {
9459
9412
  for (const cell of syncPlan.cells) {
9460
- const decrypted = await this.encryption.decrypt(cell.filePath);
9413
+ const ref = { namespace: cell.namespace, environment: cell.environment };
9414
+ const decrypted = await this.source.readCell(ref);
9461
9415
  for (const key of cell.missingKeys) {
9462
9416
  decrypted.values[key] = generateRandomValue();
9463
9417
  }
9464
- await this.encryption.encrypt(
9465
- cell.filePath,
9466
- decrypted.values,
9467
- manifest,
9468
- cell.environment
9469
- );
9470
- await markPendingWithRetry(cell.filePath, cell.missingKeys, "clef sync");
9418
+ await this.source.writeCell(ref, decrypted.values);
9419
+ await this.source.markPending(ref, cell.missingKeys, "clef sync");
9471
9420
  const cellLabel = `${cell.namespace}/${cell.environment}`;
9472
9421
  modifiedCells.push(cellLabel);
9473
9422
  scaffoldedKeys[cellLabel] = cell.missingKeys;
@@ -9727,13 +9676,272 @@ var ComplianceGenerator = class {
9727
9676
  };
9728
9677
 
9729
9678
  // src/compliance/run.ts
9730
- import * as path28 from "path";
9679
+ import * as path27 from "path";
9680
+
9681
+ // src/source/compose.ts
9682
+ import * as YAML14 from "yaml";
9683
+
9684
+ // src/source/default-bulk.ts
9685
+ function defaultBulk(source) {
9686
+ return {
9687
+ async bulkSet(namespace, key, valuesByEnv, _manifest) {
9688
+ for (const [environment, value] of Object.entries(valuesByEnv)) {
9689
+ const cell = { namespace, environment };
9690
+ const existing = await source.cellExists(cell) ? (await source.readCell(cell)).values : {};
9691
+ await source.writeCell(cell, { ...existing, [key]: value });
9692
+ }
9693
+ },
9694
+ async bulkDelete(namespace, key, manifest) {
9695
+ for (const env of manifest.environments) {
9696
+ const cell = { namespace, environment: env.name };
9697
+ if (!await source.cellExists(cell)) continue;
9698
+ const data = await source.readCell(cell);
9699
+ if (!(key in data.values)) continue;
9700
+ const next = { ...data.values };
9701
+ delete next[key];
9702
+ await source.writeCell(cell, next);
9703
+ }
9704
+ },
9705
+ async copyValue(key, from, to, _manifest) {
9706
+ const src = await source.readCell(from);
9707
+ if (!(key in src.values)) {
9708
+ throw new Error(
9709
+ `Cannot copy: key '${key}' not present in ${from.namespace}/${from.environment}`
9710
+ );
9711
+ }
9712
+ const dst = await source.cellExists(to) ? (await source.readCell(to)).values : {};
9713
+ await source.writeCell(to, { ...dst, [key]: src.values[key] });
9714
+ }
9715
+ };
9716
+ }
9717
+
9718
+ // src/source/compose.ts
9719
+ function composeSecretSource(storage, encryption, manifest) {
9720
+ return new ComposedSecretSource(storage, encryption, manifest);
9721
+ }
9722
+ var ComposedSecretSource = class {
9723
+ constructor(storage, encryption, manifest) {
9724
+ this.storage = storage;
9725
+ this.encryption = encryption;
9726
+ this.manifest = manifest;
9727
+ this.id = `${storage.id}+${encryption.id}`;
9728
+ this.description = `${storage.description} / ${encryption.description}`;
9729
+ }
9730
+ storage;
9731
+ encryption;
9732
+ manifest;
9733
+ id;
9734
+ description;
9735
+ context(cell) {
9736
+ return {
9737
+ manifest: this.manifest,
9738
+ environment: cell.environment,
9739
+ format: this.storage.blobFormat(cell)
9740
+ };
9741
+ }
9742
+ // ── Core SecretSource ──────────────────────────────────────────────────
9743
+ async readCell(cell) {
9744
+ const blob = await this.storage.readBlob(cell);
9745
+ return this.encryption.decrypt(blob, this.context(cell));
9746
+ }
9747
+ async writeCell(cell, values) {
9748
+ const blob = await this.encryption.encrypt(values, this.context(cell));
9749
+ await this.storage.writeBlob(cell, blob);
9750
+ }
9751
+ async deleteCell(cell) {
9752
+ await this.storage.deleteBlob(cell);
9753
+ }
9754
+ async cellExists(cell) {
9755
+ return this.storage.blobExists(cell);
9756
+ }
9757
+ /**
9758
+ * List cell keys WITHOUT decrypting. SOPS files store key names in
9759
+ * plaintext at the top level of the YAML/JSON document — we read the
9760
+ * blob and return everything except the `sops:` metadata block.
9761
+ *
9762
+ * NOTE: this is currently SOPS-shaped. A future non-SOPS
9763
+ * `EncryptionBackend` whose ciphertext doesn't expose key names in
9764
+ * the clear would need its own listing strategy — likely a
9765
+ * `listKeys(blob)` method on `EncryptionBackend`. Deferred until a
9766
+ * second backend exists.
9767
+ */
9768
+ async listKeys(cell) {
9769
+ if (!await this.storage.blobExists(cell)) return [];
9770
+ const blob = await this.storage.readBlob(cell);
9771
+ const parsed = YAML14.parse(blob);
9772
+ if (!parsed || typeof parsed !== "object") return [];
9773
+ return Object.keys(parsed).filter((k) => k !== "sops");
9774
+ }
9775
+ async getCellMetadata(cell) {
9776
+ const blob = await this.storage.readBlob(cell);
9777
+ return this.encryption.getMetadata(blob);
9778
+ }
9779
+ async scaffoldCell(cell, manifest) {
9780
+ if (await this.storage.blobExists(cell)) return;
9781
+ const blob = await this.encryption.encrypt(
9782
+ {},
9783
+ {
9784
+ manifest,
9785
+ environment: cell.environment,
9786
+ format: this.storage.blobFormat(cell)
9787
+ }
9788
+ );
9789
+ await this.storage.writeBlob(cell, blob);
9790
+ }
9791
+ // ── Pending / rotation metadata ────────────────────────────────────────
9792
+ async getPendingMetadata(cell) {
9793
+ return this.storage.readPendingMetadata(cell);
9794
+ }
9795
+ async markPending(cell, keys, setBy) {
9796
+ const meta = await this.storage.readPendingMetadata(cell);
9797
+ const now = /* @__PURE__ */ new Date();
9798
+ for (const key of keys) {
9799
+ if (!meta.pending.find((p) => p.key === key)) {
9800
+ meta.pending.push({ key, since: now, setBy });
9801
+ }
9802
+ }
9803
+ await this.storage.writePendingMetadata(cell, meta);
9804
+ }
9805
+ async markResolved(cell, keys) {
9806
+ const meta = await this.storage.readPendingMetadata(cell);
9807
+ meta.pending = meta.pending.filter((p) => !keys.includes(p.key));
9808
+ await this.storage.writePendingMetadata(cell, meta);
9809
+ }
9810
+ async recordRotation(cell, keys, rotatedBy) {
9811
+ const meta = await this.storage.readPendingMetadata(cell);
9812
+ const now = /* @__PURE__ */ new Date();
9813
+ for (const key of keys) {
9814
+ const existing = meta.rotations.find((r) => r.key === key);
9815
+ if (existing) {
9816
+ existing.lastRotatedAt = now;
9817
+ existing.rotatedBy = rotatedBy;
9818
+ existing.rotationCount += 1;
9819
+ } else {
9820
+ meta.rotations.push({ key, lastRotatedAt: now, rotatedBy, rotationCount: 1 });
9821
+ }
9822
+ }
9823
+ meta.pending = meta.pending.filter((p) => !keys.includes(p.key));
9824
+ await this.storage.writePendingMetadata(cell, meta);
9825
+ }
9826
+ async removeRotation(cell, keys) {
9827
+ const meta = await this.storage.readPendingMetadata(cell);
9828
+ meta.rotations = meta.rotations.filter((r) => !keys.includes(r.key));
9829
+ await this.storage.writePendingMetadata(cell, meta);
9830
+ }
9831
+ // ── Lintable ───────────────────────────────────────────────────────────
9832
+ async validateEncryption(cell) {
9833
+ if (!await this.storage.blobExists(cell)) return false;
9834
+ const blob = await this.storage.readBlob(cell);
9835
+ return this.encryption.validateEncryption(blob);
9836
+ }
9837
+ async checkRecipientDrift(cell, expected) {
9838
+ const blob = await this.storage.readBlob(cell);
9839
+ const meta = this.encryption.getMetadata(blob);
9840
+ const actual = new Set(meta.recipients);
9841
+ const expectedSet = new Set(expected);
9842
+ return {
9843
+ missing: expected.filter((r) => !actual.has(r)),
9844
+ unexpected: meta.recipients.filter((r) => !expectedSet.has(r))
9845
+ };
9846
+ }
9847
+ // ── Rotatable ──────────────────────────────────────────────────────────
9848
+ async rotate(cell, opts) {
9849
+ const blob = await this.storage.readBlob(cell);
9850
+ const rotated = await this.encryption.rotate(blob, opts, this.context(cell));
9851
+ await this.storage.writeBlob(cell, rotated);
9852
+ }
9853
+ // ── Bulk ───────────────────────────────────────────────────────────────
9854
+ //
9855
+ // Default looped implementation. A future StorageBackend that supports
9856
+ // batch operations (e.g. PostgresStorageBackend with row-level UPDATE
9857
+ // batching) can override these by wrapping `composeSecretSource`'s
9858
+ // output and replacing just the bulk methods.
9859
+ bulkSet = (namespace, key, valuesByEnv, manifest) => defaultBulk(this).bulkSet(namespace, key, valuesByEnv, manifest);
9860
+ bulkDelete = (namespace, key, manifest) => defaultBulk(this).bulkDelete(namespace, key, manifest);
9861
+ copyValue = (key, from, to, manifest) => defaultBulk(this).copyValue(key, from, to, manifest);
9862
+ };
9863
+
9864
+ // src/source/filesystem-storage-backend.ts
9865
+ import * as fs22 from "fs";
9866
+ import * as path26 from "path";
9867
+ import { randomBytes as randomBytes4 } from "crypto";
9868
+ var FilesystemStorageBackend = class {
9869
+ constructor(manifest, repoRoot) {
9870
+ this.manifest = manifest;
9871
+ this.repoRoot = repoRoot;
9872
+ }
9873
+ manifest;
9874
+ repoRoot;
9875
+ id = "filesystem";
9876
+ description = "Filesystem-backed cell storage (default substrate)";
9877
+ /**
9878
+ * Resolve a cell reference to its absolute filesystem path. Public —
9879
+ * used by substrate-specific trait implementations.
9880
+ */
9881
+ cellPath(cell) {
9882
+ const relativePath = this.manifest.file_pattern.replace("{namespace}", cell.namespace).replace("{environment}", cell.environment);
9883
+ return path26.join(this.repoRoot, relativePath);
9884
+ }
9885
+ /** The repo root, exposed for filesystem-shaped trait implementations. */
9886
+ getRepoRoot() {
9887
+ return this.repoRoot;
9888
+ }
9889
+ blobFormat(cell) {
9890
+ return this.cellPath(cell).endsWith(".json") ? "json" : "yaml";
9891
+ }
9892
+ async readBlob(cell) {
9893
+ const filePath = this.cellPath(cell);
9894
+ return fs22.readFileSync(filePath, "utf-8");
9895
+ }
9896
+ async writeBlob(cell, blob) {
9897
+ const filePath = this.cellPath(cell);
9898
+ const dir = path26.dirname(filePath);
9899
+ if (!fs22.existsSync(dir)) {
9900
+ fs22.mkdirSync(dir, { recursive: true });
9901
+ }
9902
+ const tmpPath = `${filePath}.${Date.now()}.${randomBytes4(4).toString("hex")}.tmp`;
9903
+ const handle = fs22.openSync(tmpPath, "w");
9904
+ try {
9905
+ fs22.writeFileSync(handle, blob);
9906
+ fs22.fsyncSync(handle);
9907
+ } finally {
9908
+ fs22.closeSync(handle);
9909
+ }
9910
+ fs22.renameSync(tmpPath, filePath);
9911
+ }
9912
+ async deleteBlob(cell) {
9913
+ const filePath = this.cellPath(cell);
9914
+ if (fs22.existsSync(filePath)) {
9915
+ fs22.unlinkSync(filePath);
9916
+ }
9917
+ const sidecar = this.sidecarPath(filePath);
9918
+ if (fs22.existsSync(sidecar)) {
9919
+ fs22.unlinkSync(sidecar);
9920
+ }
9921
+ }
9922
+ async blobExists(cell) {
9923
+ return fs22.existsSync(this.cellPath(cell));
9924
+ }
9925
+ async readPendingMetadata(cell) {
9926
+ return loadMetadata(this.cellPath(cell));
9927
+ }
9928
+ async writePendingMetadata(cell, meta) {
9929
+ await saveMetadata(this.cellPath(cell), meta);
9930
+ }
9931
+ sidecarPath(filePath) {
9932
+ const dir = path26.dirname(filePath);
9933
+ const base = path26.basename(filePath).replace(/\.enc\.(yaml|json)$/, "");
9934
+ return path26.join(dir, `${base}.clef-meta.yaml`);
9935
+ }
9936
+ };
9937
+
9938
+ // src/compliance/run.ts
9731
9939
  var UNKNOWN = "unknown";
9732
9940
  async function runCompliance(opts) {
9733
9941
  const start = Date.now();
9734
9942
  const repoRoot = opts.repoRoot ?? process.cwd();
9735
- const manifestPath = opts.manifestPath ?? path28.join(repoRoot, "clef.yaml");
9736
- const policyPath = opts.policyPath ?? path28.join(repoRoot, CLEF_POLICY_FILENAME);
9943
+ const manifestPath = opts.manifestPath ?? path27.join(repoRoot, "clef.yaml");
9944
+ const policyPath = opts.policyPath ?? path27.join(repoRoot, CLEF_POLICY_FILENAME);
9737
9945
  const include = {
9738
9946
  scan: opts.include?.scan ?? true,
9739
9947
  lint: opts.include?.lint ?? true,
@@ -9745,6 +9953,11 @@ async function runCompliance(opts) {
9745
9953
  const sopsClient = new SopsClient(opts.runner, opts.ageKeyFile, opts.ageKey, opts.sopsPath);
9746
9954
  const matrixManager = new MatrixManager();
9747
9955
  const schemaValidator = new SchemaValidator();
9956
+ const lintSource = composeSecretSource(
9957
+ new FilesystemStorageBackend(manifest, repoRoot),
9958
+ sopsClient,
9959
+ manifest
9960
+ );
9748
9961
  const [sha, repo, files, scanResult, lintResult] = await Promise.all([
9749
9962
  opts.sha !== void 0 ? Promise.resolve(opts.sha) : detectSha(opts.runner, repoRoot),
9750
9963
  opts.repo !== void 0 ? Promise.resolve(opts.repo) : detectRepo(opts.runner, repoRoot),
@@ -9753,12 +9966,12 @@ async function runCompliance(opts) {
9753
9966
  repoRoot,
9754
9967
  policy,
9755
9968
  matrixManager,
9756
- sopsClient,
9969
+ source: lintSource,
9757
9970
  filter: opts.filter,
9758
9971
  now
9759
9972
  }) : Promise.resolve([]),
9760
9973
  include.scan ? new ScanRunner(opts.runner).scan(repoRoot, manifest) : Promise.resolve(emptyScan()),
9761
- include.lint ? new LintRunner(matrixManager, schemaValidator, sopsClient).run(manifest, repoRoot) : Promise.resolve(emptyLint())
9974
+ include.lint ? new LintRunner(matrixManager, schemaValidator, lintSource).run(manifest, repoRoot) : Promise.resolve(emptyLint())
9762
9975
  ]);
9763
9976
  const adjustedLint = downgradeDecryptIssues(lintResult);
9764
9977
  const document = new ComplianceGenerator().generate({
@@ -9778,8 +9991,11 @@ async function evaluateMatrix(args) {
9778
9991
  const cells = args.matrixManager.resolveMatrix(args.manifest, args.repoRoot).filter((c) => applyFilter(c.namespace, c.environment, args.filter)).filter((c) => c.exists);
9779
9992
  return Promise.all(
9780
9993
  cells.map(async (cell) => {
9781
- const metadata = await args.sopsClient.getMetadata(cell.filePath);
9782
- const relPath = path28.relative(args.repoRoot, cell.filePath).replace(/\\/g, "/");
9994
+ const metadata = await args.source.getCellMetadata({
9995
+ namespace: cell.namespace,
9996
+ environment: cell.environment
9997
+ });
9998
+ const relPath = path27.relative(args.repoRoot, cell.filePath).replace(/\\/g, "/");
9783
9999
  const keys = readSopsKeyNames(cell.filePath) ?? [];
9784
10000
  const rotations = await getRotations(cell.filePath);
9785
10001
  return evaluator.evaluateFile(relPath, cell.environment, metadata, keys, rotations, args.now);
@@ -9837,10 +10053,61 @@ async function detectRepo(runner, repoRoot) {
9837
10053
  const match = url.match(/[:/]([^/:]+)\/([^/]+?)(?:\.git)?\/?$/);
9838
10054
  return match ? `${match[1]}/${match[2]}` : UNKNOWN;
9839
10055
  }
10056
+
10057
+ // src/source/guards.ts
10058
+ function isFn(o, name) {
10059
+ return typeof o === "object" && o !== null && typeof o[name] === "function";
10060
+ }
10061
+ function isLintable(s) {
10062
+ return isFn(s, "validateEncryption") && isFn(s, "checkRecipientDrift");
10063
+ }
10064
+ function isRotatable(s) {
10065
+ return isFn(s, "rotate");
10066
+ }
10067
+ function isRecipientManaged(s) {
10068
+ return isFn(s, "listRecipients") && isFn(s, "addRecipient") && isFn(s, "removeRecipient");
10069
+ }
10070
+ function isMergeAware(s) {
10071
+ return isFn(s, "mergeCells") && isFn(s, "installMergeDriver");
10072
+ }
10073
+ function isMigratable(s) {
10074
+ return isFn(s, "migrateBackend");
10075
+ }
10076
+ function isBulk(s) {
10077
+ return isFn(s, "bulkSet") && isFn(s, "bulkDelete") && isFn(s, "copyValue");
10078
+ }
10079
+ function isStructural(s) {
10080
+ return isFn(s, "addNamespace") && isFn(s, "addEnvironment") && isFn(s, "renameNamespace") && isFn(s, "renameEnvironment");
10081
+ }
10082
+ function describeCapabilities(s) {
10083
+ return {
10084
+ lint: isLintable(s),
10085
+ rotate: isRotatable(s),
10086
+ recipients: isRecipientManaged(s),
10087
+ merge: isMergeAware(s),
10088
+ migrate: isMigratable(s),
10089
+ bulk: isBulk(s),
10090
+ structural: isStructural(s)
10091
+ };
10092
+ }
10093
+
10094
+ // src/source/errors.ts
10095
+ var SourceCapabilityUnsupportedError = class extends ClefError {
10096
+ constructor(capability, sourceId) {
10097
+ super(
10098
+ `'${capability}' is not supported by the '${sourceId}' source.`,
10099
+ `Switch to a source that implements ${capability}, or use a different command.`
10100
+ );
10101
+ this.capability = capability;
10102
+ this.sourceId = sourceId;
10103
+ this.name = "SourceCapabilityUnsupportedError";
10104
+ }
10105
+ capability;
10106
+ sourceId;
10107
+ };
9840
10108
  export {
9841
10109
  ArtifactPacker,
9842
10110
  BackendMigrator,
9843
- BulkOps,
9844
10111
  CLEF_MANIFEST_FILENAME,
9845
10112
  CLEF_POLICY_FILENAME,
9846
10113
  CLEF_REPORT_SCHEMA_VERSION,
@@ -9854,6 +10121,7 @@ export {
9854
10121
  DiffEngine,
9855
10122
  DriftDetector,
9856
10123
  FilePackOutput,
10124
+ FilesystemStorageBackend,
9857
10125
  GitIntegration,
9858
10126
  GitOperationError,
9859
10127
  ImportRunner,
@@ -9870,7 +10138,6 @@ export {
9870
10138
  PolicyValidationError,
9871
10139
  REQUESTS_FILENAME,
9872
10140
  REQUIREMENTS,
9873
- REVEAL_WARNING,
9874
10141
  RecipientManager,
9875
10142
  ReportGenerator,
9876
10143
  ReportSanitizer,
@@ -9887,6 +10154,7 @@ export {
9887
10154
  SopsMergeDriver,
9888
10155
  SopsMissingError,
9889
10156
  SopsVersionError,
10157
+ SourceCapabilityUnsupportedError,
9890
10158
  StructureManager,
9891
10159
  SyncManager,
9892
10160
  TransactionLockError,
@@ -9906,11 +10174,11 @@ export {
9906
10174
  checkAll,
9907
10175
  checkDependency,
9908
10176
  collectCIContext,
10177
+ composeSecretSource,
9909
10178
  computeCiphertextHash,
9910
10179
  deriveAgePublicKey,
10180
+ describeCapabilities,
9911
10181
  describeScope,
9912
- detectAlgorithm,
9913
- detectFormat,
9914
10182
  emptyTemplate,
9915
10183
  exampleTemplate,
9916
10184
  findRequest,
@@ -9918,35 +10186,27 @@ export {
9918
10186
  formatRevealWarning,
9919
10187
  generateAgeIdentity,
9920
10188
  generateRandomValue,
9921
- generateSigningKeyPair,
9922
- getPendingKeys,
9923
- getRotations,
10189
+ isBulk,
9924
10190
  isClefHsmArn,
9925
- isHighEntropy,
9926
10191
  isKmsEnvelope,
10192
+ isLintable,
10193
+ isMergeAware,
10194
+ isMigratable,
9927
10195
  isPackedArtifact,
9928
- isPending,
10196
+ isRecipientManaged,
10197
+ isRotatable,
10198
+ isStructural,
9929
10199
  keyPreview,
9930
- loadIgnoreRules,
9931
- loadMetadata,
9932
10200
  loadRequests,
9933
10201
  markPending,
9934
- markPendingWithRetry,
9935
10202
  markResolved,
9936
- matchPatterns,
9937
- mergeMetadataContents,
9938
10203
  mergeMetadataFiles,
9939
- metadataPath,
9940
10204
  parse9 as parse,
9941
- parseDotenv,
9942
- parseIgnoreContent,
9943
- parseJson,
9944
10205
  parseSignerKey,
9945
10206
  parseYaml,
9946
10207
  pkcs11UriToSyntheticArn,
9947
10208
  readManifestYaml,
9948
10209
  recordRotation,
9949
- redactValue,
9950
10210
  removeRequest as removeAccessRequest,
9951
10211
  removeRotation,
9952
10212
  requestsFilePath,
@@ -9958,14 +10218,8 @@ export {
9958
10218
  resolveRecipientsForEnvironment,
9959
10219
  resolveSopsPath,
9960
10220
  runCompliance,
9961
- saveMetadata,
9962
10221
  saveRequests,
9963
- serializeSchema,
9964
- shannonEntropy,
9965
- shouldIgnoreFile,
9966
- shouldIgnoreMatch,
9967
- signEd25519,
9968
- signKms,
10222
+ shouldUseLinuxStdinFifo,
9969
10223
  spawnKeyservice,
9970
10224
  syntheticArnToPkcs11Uri,
9971
10225
  tryBundledKeyservice,
@@ -9975,6 +10229,7 @@ export {
9975
10229
  validatePackedArtifact,
9976
10230
  validateResetScope,
9977
10231
  verifySignature,
10232
+ wrapWithLinuxStdinFifo,
9978
10233
  writeManifestYaml,
9979
10234
  writeManifestYamlRaw,
9980
10235
  writeSchema,