@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.js CHANGED
@@ -301,13 +301,13 @@ var require_lib = __commonJS({
301
301
  "../../node_modules/write-file-atomic/lib/index.js"(exports2, module2) {
302
302
  "use strict";
303
303
  module2.exports = writeFile;
304
- module2.exports.sync = writeFileSync7;
304
+ module2.exports.sync = writeFileSync8;
305
305
  module2.exports._getTmpname = getTmpname;
306
306
  module2.exports._cleanupOnExit = cleanupOnExit;
307
- var fs22 = require("fs");
307
+ var fs23 = require("fs");
308
308
  var crypto7 = require("node:crypto");
309
309
  var { onExit } = require_cjs();
310
- var path29 = require("path");
310
+ var path28 = require("path");
311
311
  var { promisify } = require("util");
312
312
  var activeFiles = {};
313
313
  var threadId = (function getId() {
@@ -325,7 +325,7 @@ var require_lib = __commonJS({
325
325
  function cleanupOnExit(tmpfile) {
326
326
  return () => {
327
327
  try {
328
- fs22.unlinkSync(typeof tmpfile === "function" ? tmpfile() : tmpfile);
328
+ fs23.unlinkSync(typeof tmpfile === "function" ? tmpfile() : tmpfile);
329
329
  } catch {
330
330
  }
331
331
  };
@@ -360,13 +360,13 @@ var require_lib = __commonJS({
360
360
  let fd;
361
361
  let tmpfile;
362
362
  const removeOnExitHandler = onExit(cleanupOnExit(() => tmpfile));
363
- const absoluteName = path29.resolve(filename);
363
+ const absoluteName = path28.resolve(filename);
364
364
  try {
365
365
  await serializeActiveFile(absoluteName);
366
- const truename = await promisify(fs22.realpath)(filename).catch(() => filename);
366
+ const truename = await promisify(fs23.realpath)(filename).catch(() => filename);
367
367
  tmpfile = getTmpname(truename);
368
368
  if (!options.mode || !options.chown) {
369
- const stats = await promisify(fs22.stat)(truename).catch(() => {
369
+ const stats = await promisify(fs23.stat)(truename).catch(() => {
370
370
  });
371
371
  if (stats) {
372
372
  if (options.mode == null) {
@@ -377,45 +377,45 @@ var require_lib = __commonJS({
377
377
  }
378
378
  }
379
379
  }
380
- fd = await promisify(fs22.open)(tmpfile, "w", options.mode);
380
+ fd = await promisify(fs23.open)(tmpfile, "w", options.mode);
381
381
  if (options.tmpfileCreated) {
382
382
  await options.tmpfileCreated(tmpfile);
383
383
  }
384
384
  if (ArrayBuffer.isView(data)) {
385
- await promisify(fs22.write)(fd, data, 0, data.length, 0);
385
+ await promisify(fs23.write)(fd, data, 0, data.length, 0);
386
386
  } else if (data != null) {
387
- await promisify(fs22.write)(fd, String(data), 0, String(options.encoding || "utf8"));
387
+ await promisify(fs23.write)(fd, String(data), 0, String(options.encoding || "utf8"));
388
388
  }
389
389
  if (options.fsync !== false) {
390
- await promisify(fs22.fsync)(fd);
390
+ await promisify(fs23.fsync)(fd);
391
391
  }
392
- await promisify(fs22.close)(fd);
392
+ await promisify(fs23.close)(fd);
393
393
  fd = null;
394
394
  if (options.chown) {
395
- await promisify(fs22.chown)(tmpfile, options.chown.uid, options.chown.gid).catch((err) => {
395
+ await promisify(fs23.chown)(tmpfile, options.chown.uid, options.chown.gid).catch((err) => {
396
396
  if (!isChownErrOk(err)) {
397
397
  throw err;
398
398
  }
399
399
  });
400
400
  }
401
401
  if (options.mode) {
402
- await promisify(fs22.chmod)(tmpfile, options.mode).catch((err) => {
402
+ await promisify(fs23.chmod)(tmpfile, options.mode).catch((err) => {
403
403
  if (!isChownErrOk(err)) {
404
404
  throw err;
405
405
  }
406
406
  });
407
407
  }
408
- await promisify(fs22.rename)(tmpfile, truename);
408
+ await promisify(fs23.rename)(tmpfile, truename);
409
409
  } finally {
410
410
  if (fd) {
411
- await promisify(fs22.close)(fd).catch(
411
+ await promisify(fs23.close)(fd).catch(
412
412
  /* istanbul ignore next */
413
413
  () => {
414
414
  }
415
415
  );
416
416
  }
417
417
  removeOnExitHandler();
418
- await promisify(fs22.unlink)(tmpfile).catch(() => {
418
+ await promisify(fs23.unlink)(tmpfile).catch(() => {
419
419
  });
420
420
  activeFiles[absoluteName].shift();
421
421
  if (activeFiles[absoluteName].length > 0) {
@@ -441,20 +441,20 @@ var require_lib = __commonJS({
441
441
  }
442
442
  return promise;
443
443
  }
444
- function writeFileSync7(filename, data, options) {
444
+ function writeFileSync8(filename, data, options) {
445
445
  if (typeof options === "string") {
446
446
  options = { encoding: options };
447
447
  } else if (!options) {
448
448
  options = {};
449
449
  }
450
450
  try {
451
- filename = fs22.realpathSync(filename);
451
+ filename = fs23.realpathSync(filename);
452
452
  } catch (ex) {
453
453
  }
454
454
  const tmpfile = getTmpname(filename);
455
455
  if (!options.mode || !options.chown) {
456
456
  try {
457
- const stats = fs22.statSync(filename);
457
+ const stats = fs23.statSync(filename);
458
458
  options = Object.assign({}, options);
459
459
  if (!options.mode) {
460
460
  options.mode = stats.mode;
@@ -470,23 +470,23 @@ var require_lib = __commonJS({
470
470
  const removeOnExitHandler = onExit(cleanup);
471
471
  let threw = true;
472
472
  try {
473
- fd = fs22.openSync(tmpfile, "w", options.mode || 438);
473
+ fd = fs23.openSync(tmpfile, "w", options.mode || 438);
474
474
  if (options.tmpfileCreated) {
475
475
  options.tmpfileCreated(tmpfile);
476
476
  }
477
477
  if (ArrayBuffer.isView(data)) {
478
- fs22.writeSync(fd, data, 0, data.length, 0);
478
+ fs23.writeSync(fd, data, 0, data.length, 0);
479
479
  } else if (data != null) {
480
- fs22.writeSync(fd, String(data), 0, String(options.encoding || "utf8"));
480
+ fs23.writeSync(fd, String(data), 0, String(options.encoding || "utf8"));
481
481
  }
482
482
  if (options.fsync !== false) {
483
- fs22.fsyncSync(fd);
483
+ fs23.fsyncSync(fd);
484
484
  }
485
- fs22.closeSync(fd);
485
+ fs23.closeSync(fd);
486
486
  fd = null;
487
487
  if (options.chown) {
488
488
  try {
489
- fs22.chownSync(tmpfile, options.chown.uid, options.chown.gid);
489
+ fs23.chownSync(tmpfile, options.chown.uid, options.chown.gid);
490
490
  } catch (err) {
491
491
  if (!isChownErrOk(err)) {
492
492
  throw err;
@@ -495,19 +495,19 @@ var require_lib = __commonJS({
495
495
  }
496
496
  if (options.mode) {
497
497
  try {
498
- fs22.chmodSync(tmpfile, options.mode);
498
+ fs23.chmodSync(tmpfile, options.mode);
499
499
  } catch (err) {
500
500
  if (!isChownErrOk(err)) {
501
501
  throw err;
502
502
  }
503
503
  }
504
504
  }
505
- fs22.renameSync(tmpfile, filename);
505
+ fs23.renameSync(tmpfile, filename);
506
506
  threw = false;
507
507
  } finally {
508
508
  if (fd) {
509
509
  try {
510
- fs22.closeSync(fd);
510
+ fs23.closeSync(fd);
511
511
  } catch (ex) {
512
512
  }
513
513
  }
@@ -546,54 +546,54 @@ var require_polyfills = __commonJS({
546
546
  }
547
547
  var chdir;
548
548
  module2.exports = patch;
549
- function patch(fs22) {
549
+ function patch(fs23) {
550
550
  if (constants.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
551
- patchLchmod(fs22);
552
- }
553
- if (!fs22.lutimes) {
554
- patchLutimes(fs22);
555
- }
556
- fs22.chown = chownFix(fs22.chown);
557
- fs22.fchown = chownFix(fs22.fchown);
558
- fs22.lchown = chownFix(fs22.lchown);
559
- fs22.chmod = chmodFix(fs22.chmod);
560
- fs22.fchmod = chmodFix(fs22.fchmod);
561
- fs22.lchmod = chmodFix(fs22.lchmod);
562
- fs22.chownSync = chownFixSync(fs22.chownSync);
563
- fs22.fchownSync = chownFixSync(fs22.fchownSync);
564
- fs22.lchownSync = chownFixSync(fs22.lchownSync);
565
- fs22.chmodSync = chmodFixSync(fs22.chmodSync);
566
- fs22.fchmodSync = chmodFixSync(fs22.fchmodSync);
567
- fs22.lchmodSync = chmodFixSync(fs22.lchmodSync);
568
- fs22.stat = statFix(fs22.stat);
569
- fs22.fstat = statFix(fs22.fstat);
570
- fs22.lstat = statFix(fs22.lstat);
571
- fs22.statSync = statFixSync(fs22.statSync);
572
- fs22.fstatSync = statFixSync(fs22.fstatSync);
573
- fs22.lstatSync = statFixSync(fs22.lstatSync);
574
- if (fs22.chmod && !fs22.lchmod) {
575
- fs22.lchmod = function(path29, mode, cb) {
551
+ patchLchmod(fs23);
552
+ }
553
+ if (!fs23.lutimes) {
554
+ patchLutimes(fs23);
555
+ }
556
+ fs23.chown = chownFix(fs23.chown);
557
+ fs23.fchown = chownFix(fs23.fchown);
558
+ fs23.lchown = chownFix(fs23.lchown);
559
+ fs23.chmod = chmodFix(fs23.chmod);
560
+ fs23.fchmod = chmodFix(fs23.fchmod);
561
+ fs23.lchmod = chmodFix(fs23.lchmod);
562
+ fs23.chownSync = chownFixSync(fs23.chownSync);
563
+ fs23.fchownSync = chownFixSync(fs23.fchownSync);
564
+ fs23.lchownSync = chownFixSync(fs23.lchownSync);
565
+ fs23.chmodSync = chmodFixSync(fs23.chmodSync);
566
+ fs23.fchmodSync = chmodFixSync(fs23.fchmodSync);
567
+ fs23.lchmodSync = chmodFixSync(fs23.lchmodSync);
568
+ fs23.stat = statFix(fs23.stat);
569
+ fs23.fstat = statFix(fs23.fstat);
570
+ fs23.lstat = statFix(fs23.lstat);
571
+ fs23.statSync = statFixSync(fs23.statSync);
572
+ fs23.fstatSync = statFixSync(fs23.fstatSync);
573
+ fs23.lstatSync = statFixSync(fs23.lstatSync);
574
+ if (fs23.chmod && !fs23.lchmod) {
575
+ fs23.lchmod = function(path28, mode, cb) {
576
576
  if (cb) process.nextTick(cb);
577
577
  };
578
- fs22.lchmodSync = function() {
578
+ fs23.lchmodSync = function() {
579
579
  };
580
580
  }
581
- if (fs22.chown && !fs22.lchown) {
582
- fs22.lchown = function(path29, uid, gid, cb) {
581
+ if (fs23.chown && !fs23.lchown) {
582
+ fs23.lchown = function(path28, uid, gid, cb) {
583
583
  if (cb) process.nextTick(cb);
584
584
  };
585
- fs22.lchownSync = function() {
585
+ fs23.lchownSync = function() {
586
586
  };
587
587
  }
588
588
  if (platform === "win32") {
589
- fs22.rename = typeof fs22.rename !== "function" ? fs22.rename : (function(fs$rename) {
589
+ fs23.rename = typeof fs23.rename !== "function" ? fs23.rename : (function(fs$rename) {
590
590
  function rename(from, to, cb) {
591
591
  var start = Date.now();
592
592
  var backoff = 0;
593
593
  fs$rename(from, to, function CB(er) {
594
594
  if (er && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY") && Date.now() - start < 6e4) {
595
595
  setTimeout(function() {
596
- fs22.stat(to, function(stater, st) {
596
+ fs23.stat(to, function(stater, st) {
597
597
  if (stater && stater.code === "ENOENT")
598
598
  fs$rename(from, to, CB);
599
599
  else
@@ -609,9 +609,9 @@ var require_polyfills = __commonJS({
609
609
  }
610
610
  if (Object.setPrototypeOf) Object.setPrototypeOf(rename, fs$rename);
611
611
  return rename;
612
- })(fs22.rename);
612
+ })(fs23.rename);
613
613
  }
614
- fs22.read = typeof fs22.read !== "function" ? fs22.read : (function(fs$read) {
614
+ fs23.read = typeof fs23.read !== "function" ? fs23.read : (function(fs$read) {
615
615
  function read(fd, buffer, offset, length, position, callback_) {
616
616
  var callback;
617
617
  if (callback_ && typeof callback_ === "function") {
@@ -619,22 +619,22 @@ var require_polyfills = __commonJS({
619
619
  callback = function(er, _, __) {
620
620
  if (er && er.code === "EAGAIN" && eagCounter < 10) {
621
621
  eagCounter++;
622
- return fs$read.call(fs22, fd, buffer, offset, length, position, callback);
622
+ return fs$read.call(fs23, fd, buffer, offset, length, position, callback);
623
623
  }
624
624
  callback_.apply(this, arguments);
625
625
  };
626
626
  }
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
  if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read);
630
630
  return read;
631
- })(fs22.read);
632
- fs22.readSync = typeof fs22.readSync !== "function" ? fs22.readSync : /* @__PURE__ */ (function(fs$readSync) {
631
+ })(fs23.read);
632
+ fs23.readSync = typeof fs23.readSync !== "function" ? fs23.readSync : /* @__PURE__ */ (function(fs$readSync) {
633
633
  return function(fd, buffer, offset, length, position) {
634
634
  var eagCounter = 0;
635
635
  while (true) {
636
636
  try {
637
- return fs$readSync.call(fs22, fd, buffer, offset, length, position);
637
+ return fs$readSync.call(fs23, fd, buffer, offset, length, position);
638
638
  } catch (er) {
639
639
  if (er.code === "EAGAIN" && eagCounter < 10) {
640
640
  eagCounter++;
@@ -644,11 +644,11 @@ var require_polyfills = __commonJS({
644
644
  }
645
645
  }
646
646
  };
647
- })(fs22.readSync);
648
- function patchLchmod(fs23) {
649
- fs23.lchmod = function(path29, mode, callback) {
650
- fs23.open(
651
- path29,
647
+ })(fs23.readSync);
648
+ function patchLchmod(fs24) {
649
+ fs24.lchmod = function(path28, mode, callback) {
650
+ fs24.open(
651
+ path28,
652
652
  constants.O_WRONLY | constants.O_SYMLINK,
653
653
  mode,
654
654
  function(err, fd) {
@@ -656,80 +656,80 @@ var require_polyfills = __commonJS({
656
656
  if (callback) callback(err);
657
657
  return;
658
658
  }
659
- fs23.fchmod(fd, mode, function(err2) {
660
- fs23.close(fd, function(err22) {
659
+ fs24.fchmod(fd, mode, function(err2) {
660
+ fs24.close(fd, function(err22) {
661
661
  if (callback) callback(err2 || err22);
662
662
  });
663
663
  });
664
664
  }
665
665
  );
666
666
  };
667
- fs23.lchmodSync = function(path29, mode) {
668
- var fd = fs23.openSync(path29, constants.O_WRONLY | constants.O_SYMLINK, mode);
667
+ fs24.lchmodSync = function(path28, mode) {
668
+ var fd = fs24.openSync(path28, constants.O_WRONLY | constants.O_SYMLINK, mode);
669
669
  var threw = true;
670
670
  var ret;
671
671
  try {
672
- ret = fs23.fchmodSync(fd, mode);
672
+ ret = fs24.fchmodSync(fd, mode);
673
673
  threw = false;
674
674
  } finally {
675
675
  if (threw) {
676
676
  try {
677
- fs23.closeSync(fd);
677
+ fs24.closeSync(fd);
678
678
  } catch (er) {
679
679
  }
680
680
  } else {
681
- fs23.closeSync(fd);
681
+ fs24.closeSync(fd);
682
682
  }
683
683
  }
684
684
  return ret;
685
685
  };
686
686
  }
687
- function patchLutimes(fs23) {
688
- if (constants.hasOwnProperty("O_SYMLINK") && fs23.futimes) {
689
- fs23.lutimes = function(path29, at, mt, cb) {
690
- fs23.open(path29, constants.O_SYMLINK, function(er, fd) {
687
+ function patchLutimes(fs24) {
688
+ if (constants.hasOwnProperty("O_SYMLINK") && fs24.futimes) {
689
+ fs24.lutimes = function(path28, at, mt, cb) {
690
+ fs24.open(path28, constants.O_SYMLINK, function(er, fd) {
691
691
  if (er) {
692
692
  if (cb) cb(er);
693
693
  return;
694
694
  }
695
- fs23.futimes(fd, at, mt, function(er2) {
696
- fs23.close(fd, function(er22) {
695
+ fs24.futimes(fd, at, mt, function(er2) {
696
+ fs24.close(fd, function(er22) {
697
697
  if (cb) cb(er2 || er22);
698
698
  });
699
699
  });
700
700
  });
701
701
  };
702
- fs23.lutimesSync = function(path29, at, mt) {
703
- var fd = fs23.openSync(path29, constants.O_SYMLINK);
702
+ fs24.lutimesSync = function(path28, at, mt) {
703
+ var fd = fs24.openSync(path28, constants.O_SYMLINK);
704
704
  var ret;
705
705
  var threw = true;
706
706
  try {
707
- ret = fs23.futimesSync(fd, at, mt);
707
+ ret = fs24.futimesSync(fd, at, mt);
708
708
  threw = false;
709
709
  } finally {
710
710
  if (threw) {
711
711
  try {
712
- fs23.closeSync(fd);
712
+ fs24.closeSync(fd);
713
713
  } catch (er) {
714
714
  }
715
715
  } else {
716
- fs23.closeSync(fd);
716
+ fs24.closeSync(fd);
717
717
  }
718
718
  }
719
719
  return ret;
720
720
  };
721
- } else if (fs23.futimes) {
722
- fs23.lutimes = function(_a, _b, _c, cb) {
721
+ } else if (fs24.futimes) {
722
+ fs24.lutimes = function(_a, _b, _c, cb) {
723
723
  if (cb) process.nextTick(cb);
724
724
  };
725
- fs23.lutimesSync = function() {
725
+ fs24.lutimesSync = function() {
726
726
  };
727
727
  }
728
728
  }
729
729
  function chmodFix(orig) {
730
730
  if (!orig) return orig;
731
731
  return function(target, mode, cb) {
732
- return orig.call(fs22, target, mode, function(er) {
732
+ return orig.call(fs23, target, mode, function(er) {
733
733
  if (chownErOk(er)) er = null;
734
734
  if (cb) cb.apply(this, arguments);
735
735
  });
@@ -739,7 +739,7 @@ var require_polyfills = __commonJS({
739
739
  if (!orig) return orig;
740
740
  return function(target, mode) {
741
741
  try {
742
- return orig.call(fs22, target, mode);
742
+ return orig.call(fs23, target, mode);
743
743
  } catch (er) {
744
744
  if (!chownErOk(er)) throw er;
745
745
  }
@@ -748,7 +748,7 @@ var require_polyfills = __commonJS({
748
748
  function chownFix(orig) {
749
749
  if (!orig) return orig;
750
750
  return function(target, uid, gid, cb) {
751
- return orig.call(fs22, target, uid, gid, function(er) {
751
+ return orig.call(fs23, target, uid, gid, function(er) {
752
752
  if (chownErOk(er)) er = null;
753
753
  if (cb) cb.apply(this, arguments);
754
754
  });
@@ -758,7 +758,7 @@ var require_polyfills = __commonJS({
758
758
  if (!orig) return orig;
759
759
  return function(target, uid, gid) {
760
760
  try {
761
- return orig.call(fs22, target, uid, gid);
761
+ return orig.call(fs23, target, uid, gid);
762
762
  } catch (er) {
763
763
  if (!chownErOk(er)) throw er;
764
764
  }
@@ -778,13 +778,13 @@ var require_polyfills = __commonJS({
778
778
  }
779
779
  if (cb) cb.apply(this, arguments);
780
780
  }
781
- return options ? orig.call(fs22, target, options, callback) : orig.call(fs22, target, callback);
781
+ return options ? orig.call(fs23, target, options, callback) : orig.call(fs23, target, callback);
782
782
  };
783
783
  }
784
784
  function statFixSync(orig) {
785
785
  if (!orig) return orig;
786
786
  return function(target, options) {
787
- var stats = options ? orig.call(fs22, target, options) : orig.call(fs22, target);
787
+ var stats = options ? orig.call(fs23, target, options) : orig.call(fs23, target);
788
788
  if (stats) {
789
789
  if (stats.uid < 0) stats.uid += 4294967296;
790
790
  if (stats.gid < 0) stats.gid += 4294967296;
@@ -813,16 +813,16 @@ var require_legacy_streams = __commonJS({
813
813
  "../../node_modules/graceful-fs/legacy-streams.js"(exports2, module2) {
814
814
  var Stream = require("stream").Stream;
815
815
  module2.exports = legacy;
816
- function legacy(fs22) {
816
+ function legacy(fs23) {
817
817
  return {
818
818
  ReadStream,
819
819
  WriteStream
820
820
  };
821
- function ReadStream(path29, options) {
822
- if (!(this instanceof ReadStream)) return new ReadStream(path29, options);
821
+ function ReadStream(path28, options) {
822
+ if (!(this instanceof ReadStream)) return new ReadStream(path28, options);
823
823
  Stream.call(this);
824
824
  var self = this;
825
- this.path = path29;
825
+ this.path = path28;
826
826
  this.fd = null;
827
827
  this.readable = true;
828
828
  this.paused = false;
@@ -856,7 +856,7 @@ var require_legacy_streams = __commonJS({
856
856
  });
857
857
  return;
858
858
  }
859
- fs22.open(this.path, this.flags, this.mode, function(err, fd) {
859
+ fs23.open(this.path, this.flags, this.mode, function(err, fd) {
860
860
  if (err) {
861
861
  self.emit("error", err);
862
862
  self.readable = false;
@@ -867,10 +867,10 @@ var require_legacy_streams = __commonJS({
867
867
  self._read();
868
868
  });
869
869
  }
870
- function WriteStream(path29, options) {
871
- if (!(this instanceof WriteStream)) return new WriteStream(path29, options);
870
+ function WriteStream(path28, options) {
871
+ if (!(this instanceof WriteStream)) return new WriteStream(path28, options);
872
872
  Stream.call(this);
873
- this.path = path29;
873
+ this.path = path28;
874
874
  this.fd = null;
875
875
  this.writable = true;
876
876
  this.flags = "w";
@@ -895,7 +895,7 @@ var require_legacy_streams = __commonJS({
895
895
  this.busy = false;
896
896
  this._queue = [];
897
897
  if (this.fd === null) {
898
- this._open = fs22.open;
898
+ this._open = fs23.open;
899
899
  this._queue.push([this._open, this.path, this.flags, this.mode, void 0]);
900
900
  this.flush();
901
901
  }
@@ -930,7 +930,7 @@ var require_clone = __commonJS({
930
930
  // ../../node_modules/graceful-fs/graceful-fs.js
931
931
  var require_graceful_fs = __commonJS({
932
932
  "../../node_modules/graceful-fs/graceful-fs.js"(exports2, module2) {
933
- var fs22 = require("fs");
933
+ var fs23 = require("fs");
934
934
  var polyfills = require_polyfills();
935
935
  var legacy = require_legacy_streams();
936
936
  var clone = require_clone();
@@ -962,12 +962,12 @@ var require_graceful_fs = __commonJS({
962
962
  m = "GFS4: " + m.split(/\n/).join("\nGFS4: ");
963
963
  console.error(m);
964
964
  };
965
- if (!fs22[gracefulQueue]) {
965
+ if (!fs23[gracefulQueue]) {
966
966
  queue = global[gracefulQueue] || [];
967
- publishQueue(fs22, queue);
968
- fs22.close = (function(fs$close) {
967
+ publishQueue(fs23, queue);
968
+ fs23.close = (function(fs$close) {
969
969
  function close(fd, cb) {
970
- return fs$close.call(fs22, fd, function(err) {
970
+ return fs$close.call(fs23, fd, function(err) {
971
971
  if (!err) {
972
972
  resetQueue();
973
973
  }
@@ -979,48 +979,48 @@ var require_graceful_fs = __commonJS({
979
979
  value: fs$close
980
980
  });
981
981
  return close;
982
- })(fs22.close);
983
- fs22.closeSync = (function(fs$closeSync) {
984
- function closeSync2(fd) {
985
- fs$closeSync.apply(fs22, arguments);
982
+ })(fs23.close);
983
+ fs23.closeSync = (function(fs$closeSync) {
984
+ function closeSync3(fd) {
985
+ fs$closeSync.apply(fs23, arguments);
986
986
  resetQueue();
987
987
  }
988
- Object.defineProperty(closeSync2, previousSymbol, {
988
+ Object.defineProperty(closeSync3, previousSymbol, {
989
989
  value: fs$closeSync
990
990
  });
991
- return closeSync2;
992
- })(fs22.closeSync);
991
+ return closeSync3;
992
+ })(fs23.closeSync);
993
993
  if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
994
994
  process.on("exit", function() {
995
- debug(fs22[gracefulQueue]);
996
- require("assert").equal(fs22[gracefulQueue].length, 0);
995
+ debug(fs23[gracefulQueue]);
996
+ require("assert").equal(fs23[gracefulQueue].length, 0);
997
997
  });
998
998
  }
999
999
  }
1000
1000
  var queue;
1001
1001
  if (!global[gracefulQueue]) {
1002
- publishQueue(global, fs22[gracefulQueue]);
1003
- }
1004
- module2.exports = patch(clone(fs22));
1005
- if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs22.__patched) {
1006
- module2.exports = patch(fs22);
1007
- fs22.__patched = true;
1008
- }
1009
- function patch(fs23) {
1010
- polyfills(fs23);
1011
- fs23.gracefulify = patch;
1012
- fs23.createReadStream = createReadStream;
1013
- fs23.createWriteStream = createWriteStream;
1014
- var fs$readFile = fs23.readFile;
1015
- fs23.readFile = readFile;
1016
- function readFile(path29, options, cb) {
1002
+ publishQueue(global, fs23[gracefulQueue]);
1003
+ }
1004
+ module2.exports = patch(clone(fs23));
1005
+ if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs23.__patched) {
1006
+ module2.exports = patch(fs23);
1007
+ fs23.__patched = true;
1008
+ }
1009
+ function patch(fs24) {
1010
+ polyfills(fs24);
1011
+ fs24.gracefulify = patch;
1012
+ fs24.createReadStream = createReadStream;
1013
+ fs24.createWriteStream = createWriteStream;
1014
+ var fs$readFile = fs24.readFile;
1015
+ fs24.readFile = readFile;
1016
+ function readFile(path28, options, cb) {
1017
1017
  if (typeof options === "function")
1018
1018
  cb = options, options = null;
1019
- return go$readFile(path29, options, cb);
1020
- function go$readFile(path30, options2, cb2, startTime) {
1021
- return fs$readFile(path30, options2, function(err) {
1019
+ return go$readFile(path28, options, cb);
1020
+ function go$readFile(path29, options2, cb2, startTime) {
1021
+ return fs$readFile(path29, options2, function(err) {
1022
1022
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
1023
- enqueue([go$readFile, [path30, options2, cb2], err, startTime || Date.now(), Date.now()]);
1023
+ enqueue([go$readFile, [path29, options2, cb2], err, startTime || Date.now(), Date.now()]);
1024
1024
  else {
1025
1025
  if (typeof cb2 === "function")
1026
1026
  cb2.apply(this, arguments);
@@ -1028,16 +1028,16 @@ var require_graceful_fs = __commonJS({
1028
1028
  });
1029
1029
  }
1030
1030
  }
1031
- var fs$writeFile = fs23.writeFile;
1032
- fs23.writeFile = writeFile;
1033
- function writeFile(path29, data, options, cb) {
1031
+ var fs$writeFile = fs24.writeFile;
1032
+ fs24.writeFile = writeFile;
1033
+ function writeFile(path28, data, options, cb) {
1034
1034
  if (typeof options === "function")
1035
1035
  cb = options, options = null;
1036
- return go$writeFile(path29, data, options, cb);
1037
- function go$writeFile(path30, data2, options2, cb2, startTime) {
1038
- return fs$writeFile(path30, data2, options2, function(err) {
1036
+ return go$writeFile(path28, data, options, cb);
1037
+ function go$writeFile(path29, data2, options2, cb2, startTime) {
1038
+ return fs$writeFile(path29, data2, options2, function(err) {
1039
1039
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
1040
- enqueue([go$writeFile, [path30, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
1040
+ enqueue([go$writeFile, [path29, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
1041
1041
  else {
1042
1042
  if (typeof cb2 === "function")
1043
1043
  cb2.apply(this, arguments);
@@ -1045,17 +1045,17 @@ var require_graceful_fs = __commonJS({
1045
1045
  });
1046
1046
  }
1047
1047
  }
1048
- var fs$appendFile = fs23.appendFile;
1048
+ var fs$appendFile = fs24.appendFile;
1049
1049
  if (fs$appendFile)
1050
- fs23.appendFile = appendFile;
1051
- function appendFile(path29, data, options, cb) {
1050
+ fs24.appendFile = appendFile;
1051
+ function appendFile(path28, data, options, cb) {
1052
1052
  if (typeof options === "function")
1053
1053
  cb = options, options = null;
1054
- return go$appendFile(path29, data, options, cb);
1055
- function go$appendFile(path30, data2, options2, cb2, startTime) {
1056
- return fs$appendFile(path30, data2, options2, function(err) {
1054
+ return go$appendFile(path28, data, options, cb);
1055
+ function go$appendFile(path29, data2, options2, cb2, startTime) {
1056
+ return fs$appendFile(path29, data2, options2, function(err) {
1057
1057
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
1058
- enqueue([go$appendFile, [path30, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
1058
+ enqueue([go$appendFile, [path29, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
1059
1059
  else {
1060
1060
  if (typeof cb2 === "function")
1061
1061
  cb2.apply(this, arguments);
@@ -1063,9 +1063,9 @@ var require_graceful_fs = __commonJS({
1063
1063
  });
1064
1064
  }
1065
1065
  }
1066
- var fs$copyFile = fs23.copyFile;
1066
+ var fs$copyFile = fs24.copyFile;
1067
1067
  if (fs$copyFile)
1068
- fs23.copyFile = copyFile;
1068
+ fs24.copyFile = copyFile;
1069
1069
  function copyFile(src, dest, flags, cb) {
1070
1070
  if (typeof flags === "function") {
1071
1071
  cb = flags;
@@ -1083,34 +1083,34 @@ var require_graceful_fs = __commonJS({
1083
1083
  });
1084
1084
  }
1085
1085
  }
1086
- var fs$readdir = fs23.readdir;
1087
- fs23.readdir = readdir;
1086
+ var fs$readdir = fs24.readdir;
1087
+ fs24.readdir = readdir;
1088
1088
  var noReaddirOptionVersions = /^v[0-5]\./;
1089
- function readdir(path29, options, cb) {
1089
+ function readdir(path28, options, cb) {
1090
1090
  if (typeof options === "function")
1091
1091
  cb = options, options = null;
1092
- var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path30, options2, cb2, startTime) {
1093
- return fs$readdir(path30, fs$readdirCallback(
1094
- path30,
1092
+ var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path29, options2, cb2, startTime) {
1093
+ return fs$readdir(path29, fs$readdirCallback(
1094
+ path29,
1095
1095
  options2,
1096
1096
  cb2,
1097
1097
  startTime
1098
1098
  ));
1099
- } : function go$readdir2(path30, options2, cb2, startTime) {
1100
- return fs$readdir(path30, options2, fs$readdirCallback(
1101
- path30,
1099
+ } : function go$readdir2(path29, options2, cb2, startTime) {
1100
+ return fs$readdir(path29, options2, fs$readdirCallback(
1101
+ path29,
1102
1102
  options2,
1103
1103
  cb2,
1104
1104
  startTime
1105
1105
  ));
1106
1106
  };
1107
- return go$readdir(path29, options, cb);
1108
- function fs$readdirCallback(path30, options2, cb2, startTime) {
1107
+ return go$readdir(path28, options, cb);
1108
+ function fs$readdirCallback(path29, options2, cb2, startTime) {
1109
1109
  return function(err, files) {
1110
1110
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
1111
1111
  enqueue([
1112
1112
  go$readdir,
1113
- [path30, options2, cb2],
1113
+ [path29, options2, cb2],
1114
1114
  err,
1115
1115
  startTime || Date.now(),
1116
1116
  Date.now()
@@ -1125,21 +1125,21 @@ var require_graceful_fs = __commonJS({
1125
1125
  }
1126
1126
  }
1127
1127
  if (process.version.substr(0, 4) === "v0.8") {
1128
- var legStreams = legacy(fs23);
1128
+ var legStreams = legacy(fs24);
1129
1129
  ReadStream = legStreams.ReadStream;
1130
1130
  WriteStream = legStreams.WriteStream;
1131
1131
  }
1132
- var fs$ReadStream = fs23.ReadStream;
1132
+ var fs$ReadStream = fs24.ReadStream;
1133
1133
  if (fs$ReadStream) {
1134
1134
  ReadStream.prototype = Object.create(fs$ReadStream.prototype);
1135
1135
  ReadStream.prototype.open = ReadStream$open;
1136
1136
  }
1137
- var fs$WriteStream = fs23.WriteStream;
1137
+ var fs$WriteStream = fs24.WriteStream;
1138
1138
  if (fs$WriteStream) {
1139
1139
  WriteStream.prototype = Object.create(fs$WriteStream.prototype);
1140
1140
  WriteStream.prototype.open = WriteStream$open;
1141
1141
  }
1142
- Object.defineProperty(fs23, "ReadStream", {
1142
+ Object.defineProperty(fs24, "ReadStream", {
1143
1143
  get: function() {
1144
1144
  return ReadStream;
1145
1145
  },
@@ -1149,7 +1149,7 @@ var require_graceful_fs = __commonJS({
1149
1149
  enumerable: true,
1150
1150
  configurable: true
1151
1151
  });
1152
- Object.defineProperty(fs23, "WriteStream", {
1152
+ Object.defineProperty(fs24, "WriteStream", {
1153
1153
  get: function() {
1154
1154
  return WriteStream;
1155
1155
  },
@@ -1160,7 +1160,7 @@ var require_graceful_fs = __commonJS({
1160
1160
  configurable: true
1161
1161
  });
1162
1162
  var FileReadStream = ReadStream;
1163
- Object.defineProperty(fs23, "FileReadStream", {
1163
+ Object.defineProperty(fs24, "FileReadStream", {
1164
1164
  get: function() {
1165
1165
  return FileReadStream;
1166
1166
  },
@@ -1171,7 +1171,7 @@ var require_graceful_fs = __commonJS({
1171
1171
  configurable: true
1172
1172
  });
1173
1173
  var FileWriteStream = WriteStream;
1174
- Object.defineProperty(fs23, "FileWriteStream", {
1174
+ Object.defineProperty(fs24, "FileWriteStream", {
1175
1175
  get: function() {
1176
1176
  return FileWriteStream;
1177
1177
  },
@@ -1181,7 +1181,7 @@ var require_graceful_fs = __commonJS({
1181
1181
  enumerable: true,
1182
1182
  configurable: true
1183
1183
  });
1184
- function ReadStream(path29, options) {
1184
+ function ReadStream(path28, options) {
1185
1185
  if (this instanceof ReadStream)
1186
1186
  return fs$ReadStream.apply(this, arguments), this;
1187
1187
  else
@@ -1201,7 +1201,7 @@ var require_graceful_fs = __commonJS({
1201
1201
  }
1202
1202
  });
1203
1203
  }
1204
- function WriteStream(path29, options) {
1204
+ function WriteStream(path28, options) {
1205
1205
  if (this instanceof WriteStream)
1206
1206
  return fs$WriteStream.apply(this, arguments), this;
1207
1207
  else
@@ -1219,22 +1219,22 @@ var require_graceful_fs = __commonJS({
1219
1219
  }
1220
1220
  });
1221
1221
  }
1222
- function createReadStream(path29, options) {
1223
- return new fs23.ReadStream(path29, options);
1222
+ function createReadStream(path28, options) {
1223
+ return new fs24.ReadStream(path28, options);
1224
1224
  }
1225
- function createWriteStream(path29, options) {
1226
- return new fs23.WriteStream(path29, options);
1225
+ function createWriteStream(path28, options) {
1226
+ return new fs24.WriteStream(path28, options);
1227
1227
  }
1228
- var fs$open = fs23.open;
1229
- fs23.open = open;
1230
- function open(path29, flags, mode, cb) {
1228
+ var fs$open = fs24.open;
1229
+ fs24.open = open;
1230
+ function open(path28, flags, mode, cb) {
1231
1231
  if (typeof mode === "function")
1232
1232
  cb = mode, mode = null;
1233
- return go$open(path29, flags, mode, cb);
1234
- function go$open(path30, flags2, mode2, cb2, startTime) {
1235
- return fs$open(path30, flags2, mode2, function(err, fd) {
1233
+ return go$open(path28, flags, mode, cb);
1234
+ function go$open(path29, flags2, mode2, cb2, startTime) {
1235
+ return fs$open(path29, flags2, mode2, function(err, fd) {
1236
1236
  if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
1237
- enqueue([go$open, [path30, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
1237
+ enqueue([go$open, [path29, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
1238
1238
  else {
1239
1239
  if (typeof cb2 === "function")
1240
1240
  cb2.apply(this, arguments);
@@ -1242,20 +1242,20 @@ var require_graceful_fs = __commonJS({
1242
1242
  });
1243
1243
  }
1244
1244
  }
1245
- return fs23;
1245
+ return fs24;
1246
1246
  }
1247
1247
  function enqueue(elem) {
1248
1248
  debug("ENQUEUE", elem[0].name, elem[1]);
1249
- fs22[gracefulQueue].push(elem);
1249
+ fs23[gracefulQueue].push(elem);
1250
1250
  retry();
1251
1251
  }
1252
1252
  var retryTimer;
1253
1253
  function resetQueue() {
1254
1254
  var now = Date.now();
1255
- for (var i = 0; i < fs22[gracefulQueue].length; ++i) {
1256
- if (fs22[gracefulQueue][i].length > 2) {
1257
- fs22[gracefulQueue][i][3] = now;
1258
- fs22[gracefulQueue][i][4] = now;
1255
+ for (var i = 0; i < fs23[gracefulQueue].length; ++i) {
1256
+ if (fs23[gracefulQueue][i].length > 2) {
1257
+ fs23[gracefulQueue][i][3] = now;
1258
+ fs23[gracefulQueue][i][4] = now;
1259
1259
  }
1260
1260
  }
1261
1261
  retry();
@@ -1263,9 +1263,9 @@ var require_graceful_fs = __commonJS({
1263
1263
  function retry() {
1264
1264
  clearTimeout(retryTimer);
1265
1265
  retryTimer = void 0;
1266
- if (fs22[gracefulQueue].length === 0)
1266
+ if (fs23[gracefulQueue].length === 0)
1267
1267
  return;
1268
- var elem = fs22[gracefulQueue].shift();
1268
+ var elem = fs23[gracefulQueue].shift();
1269
1269
  var fn = elem[0];
1270
1270
  var args = elem[1];
1271
1271
  var err = elem[2];
@@ -1287,7 +1287,7 @@ var require_graceful_fs = __commonJS({
1287
1287
  debug("RETRY", fn.name, args);
1288
1288
  fn.apply(null, args.concat([startTime]));
1289
1289
  } else {
1290
- fs22[gracefulQueue].push(elem);
1290
+ fs23[gracefulQueue].push(elem);
1291
1291
  }
1292
1292
  }
1293
1293
  if (retryTimer === void 0) {
@@ -1722,10 +1722,10 @@ var require_mtime_precision = __commonJS({
1722
1722
  "../../node_modules/proper-lockfile/lib/mtime-precision.js"(exports2, module2) {
1723
1723
  "use strict";
1724
1724
  var cacheSymbol = /* @__PURE__ */ Symbol();
1725
- function probe(file, fs22, callback) {
1726
- const cachedPrecision = fs22[cacheSymbol];
1725
+ function probe(file, fs23, callback) {
1726
+ const cachedPrecision = fs23[cacheSymbol];
1727
1727
  if (cachedPrecision) {
1728
- return fs22.stat(file, (err, stat) => {
1728
+ return fs23.stat(file, (err, stat) => {
1729
1729
  if (err) {
1730
1730
  return callback(err);
1731
1731
  }
@@ -1733,16 +1733,16 @@ var require_mtime_precision = __commonJS({
1733
1733
  });
1734
1734
  }
1735
1735
  const mtime = new Date(Math.ceil(Date.now() / 1e3) * 1e3 + 5);
1736
- fs22.utimes(file, mtime, mtime, (err) => {
1736
+ fs23.utimes(file, mtime, mtime, (err) => {
1737
1737
  if (err) {
1738
1738
  return callback(err);
1739
1739
  }
1740
- fs22.stat(file, (err2, stat) => {
1740
+ fs23.stat(file, (err2, stat) => {
1741
1741
  if (err2) {
1742
1742
  return callback(err2);
1743
1743
  }
1744
1744
  const precision = stat.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
1745
- Object.defineProperty(fs22, cacheSymbol, { value: precision });
1745
+ Object.defineProperty(fs23, cacheSymbol, { value: precision });
1746
1746
  callback(null, stat.mtime, precision);
1747
1747
  });
1748
1748
  });
@@ -1763,8 +1763,8 @@ var require_mtime_precision = __commonJS({
1763
1763
  var require_lockfile = __commonJS({
1764
1764
  "../../node_modules/proper-lockfile/lib/lockfile.js"(exports2, module2) {
1765
1765
  "use strict";
1766
- var path29 = require("path");
1767
- var fs22 = require_graceful_fs();
1766
+ var path28 = require("path");
1767
+ var fs23 = require_graceful_fs();
1768
1768
  var retry = require_retry2();
1769
1769
  var onExit = require_signal_exit();
1770
1770
  var mtimePrecision = require_mtime_precision();
@@ -1774,7 +1774,7 @@ var require_lockfile = __commonJS({
1774
1774
  }
1775
1775
  function resolveCanonicalPath(file, options, callback) {
1776
1776
  if (!options.realpath) {
1777
- return callback(null, path29.resolve(file));
1777
+ return callback(null, path28.resolve(file));
1778
1778
  }
1779
1779
  options.fs.realpath(file, callback);
1780
1780
  }
@@ -1895,7 +1895,7 @@ var require_lockfile = __commonJS({
1895
1895
  update: null,
1896
1896
  realpath: true,
1897
1897
  retries: 0,
1898
- fs: fs22,
1898
+ fs: fs23,
1899
1899
  onCompromised: (err) => {
1900
1900
  throw err;
1901
1901
  },
@@ -1939,7 +1939,7 @@ var require_lockfile = __commonJS({
1939
1939
  }
1940
1940
  function unlock(file, options, callback) {
1941
1941
  options = {
1942
- fs: fs22,
1942
+ fs: fs23,
1943
1943
  realpath: true,
1944
1944
  ...options
1945
1945
  };
@@ -1961,7 +1961,7 @@ var require_lockfile = __commonJS({
1961
1961
  options = {
1962
1962
  stale: 1e4,
1963
1963
  realpath: true,
1964
- fs: fs22,
1964
+ fs: fs23,
1965
1965
  ...options
1966
1966
  };
1967
1967
  options.stale = Math.max(options.stale || 0, 2e3);
@@ -2000,16 +2000,16 @@ var require_lockfile = __commonJS({
2000
2000
  var require_adapter = __commonJS({
2001
2001
  "../../node_modules/proper-lockfile/lib/adapter.js"(exports2, module2) {
2002
2002
  "use strict";
2003
- var fs22 = require_graceful_fs();
2004
- function createSyncFs(fs23) {
2003
+ var fs23 = require_graceful_fs();
2004
+ function createSyncFs(fs24) {
2005
2005
  const methods = ["mkdir", "realpath", "stat", "rmdir", "utimes"];
2006
- const newFs = { ...fs23 };
2006
+ const newFs = { ...fs24 };
2007
2007
  methods.forEach((method) => {
2008
2008
  newFs[method] = (...args) => {
2009
2009
  const callback = args.pop();
2010
2010
  let ret;
2011
2011
  try {
2012
- ret = fs23[`${method}Sync`](...args);
2012
+ ret = fs24[`${method}Sync`](...args);
2013
2013
  } catch (err) {
2014
2014
  return callback(err);
2015
2015
  }
@@ -2047,7 +2047,7 @@ var require_adapter = __commonJS({
2047
2047
  }
2048
2048
  function toSyncOptions(options) {
2049
2049
  options = { ...options };
2050
- options.fs = createSyncFs(options.fs || fs22);
2050
+ options.fs = createSyncFs(options.fs || fs23);
2051
2051
  if (typeof options.retries === "number" && options.retries > 0 || options.retries && typeof options.retries.retries === "number" && options.retries.retries > 0) {
2052
2052
  throw Object.assign(new Error("Cannot use retries with the sync api"), { code: "ESYNC" });
2053
2053
  }
@@ -2303,7 +2303,7 @@ var require_age_encryption = __commonJS({
2303
2303
  Object.assign(hashC, info);
2304
2304
  return Object.freeze(hashC);
2305
2305
  }
2306
- function randomBytes4(bytesLength = 32) {
2306
+ function randomBytes5(bytesLength = 32) {
2307
2307
  anumber(bytesLength, "bytesLength");
2308
2308
  const cr = typeof globalThis === "object" ? globalThis.crypto : null;
2309
2309
  if (typeof cr?.getRandomValues !== "function")
@@ -3030,7 +3030,7 @@ var require_age_encryption = __commonJS({
3030
3030
  };
3031
3031
  }
3032
3032
  // @__NO_SIDE_EFFECTS__
3033
- function join21(separator = "") {
3033
+ function join20(separator = "") {
3034
3034
  astr("join", separator);
3035
3035
  return {
3036
3036
  encode: (from) => {
@@ -3160,9 +3160,9 @@ var require_age_encryption = __commonJS({
3160
3160
  decode(s) {
3161
3161
  return decodeBase64Builtin(s, false);
3162
3162
  }
3163
- } : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */ join21("")));
3164
- var base64nopad = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ join21("")));
3165
- var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */ join21(""));
3163
+ } : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */ join20("")));
3164
+ var base64nopad = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ join20("")));
3165
+ var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */ join20(""));
3166
3166
  var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059];
3167
3167
  function bech32Polymod(pre) {
3168
3168
  const b = pre >> 25;
@@ -7655,7 +7655,7 @@ var require_age_encryption = __commonJS({
7655
7655
  var concatBytes4 = (...arrays) => concatBytes(...arrays);
7656
7656
  var hexToBytes3 = (hex) => hexToBytes(hex);
7657
7657
  var isBytes5 = isBytes;
7658
- var randomBytes5 = (bytesLength) => randomBytes4(bytesLength);
7658
+ var randomBytes52 = (bytesLength) => randomBytes5(bytesLength);
7659
7659
  var _0n7 = /* @__PURE__ */ BigInt(0);
7660
7660
  var _1n8 = /* @__PURE__ */ BigInt(1);
7661
7661
  function abool3(value, title = "") {
@@ -9127,7 +9127,7 @@ var require_age_encryption = __commonJS({
9127
9127
  }
9128
9128
  function ecdh2(Point, ecdhOpts = {}) {
9129
9129
  const { Fn: Fn2 } = Point;
9130
- const randomBytes_ = ecdhOpts.randomBytes === void 0 ? randomBytes5 : ecdhOpts.randomBytes;
9130
+ const randomBytes_ = ecdhOpts.randomBytes === void 0 ? randomBytes52 : ecdhOpts.randomBytes;
9131
9131
  const lengths = Object.assign(getWLengths2(Point.Fp, Fn2), {
9132
9132
  seed: Math.max(getMinHashLength2(Fn2.ORDER), 16)
9133
9133
  });
@@ -9201,7 +9201,7 @@ var require_age_encryption = __commonJS({
9201
9201
  bits2int_modN: "function"
9202
9202
  });
9203
9203
  ecdsaOpts = Object.assign({}, ecdsaOpts);
9204
- const randomBytes6 = ecdsaOpts.randomBytes === void 0 ? randomBytes5 : ecdsaOpts.randomBytes;
9204
+ const randomBytes6 = ecdsaOpts.randomBytes === void 0 ? randomBytes52 : ecdsaOpts.randomBytes;
9205
9205
  const hmac3 = ecdsaOpts.hmac === void 0 ? (key, msg) => hmac(hash_, key, msg) : ecdsaOpts.hmac;
9206
9206
  const { Fp: Fp2, Fn: Fn2 } = Point;
9207
9207
  const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn2;
@@ -9815,7 +9815,7 @@ var require_age_encryption = __commonJS({
9815
9815
  const is25519 = type === "x25519";
9816
9816
  if (!is25519 && type !== "x448")
9817
9817
  throw new Error("invalid type");
9818
- const randomBytes_ = rand === void 0 ? randomBytes5 : rand;
9818
+ const randomBytes_ = rand === void 0 ? randomBytes52 : rand;
9819
9819
  const montgomeryBits = is25519 ? 255 : 448;
9820
9820
  const fieldLen = is25519 ? 32 : 56;
9821
9821
  const Gu = is25519 ? BigInt(9) : BigInt(5);
@@ -10449,12 +10449,12 @@ var require_age_encryption = __commonJS({
10449
10449
  return generateX25519Identity();
10450
10450
  }
10451
10451
  function generateX25519Identity() {
10452
- const scalar = randomBytes4(32);
10452
+ const scalar = randomBytes5(32);
10453
10453
  const identity = bech32.encodeFromBytes("AGE-SECRET-KEY-", scalar).toUpperCase();
10454
10454
  return Promise.resolve(identity);
10455
10455
  }
10456
10456
  function generateHybridIdentity() {
10457
- const scalar = randomBytes4(32);
10457
+ const scalar = randomBytes5(32);
10458
10458
  const identity = bech32.encodeFromBytes("AGE-SECRET-KEY-PQ-", scalar).toUpperCase();
10459
10459
  return Promise.resolve(identity);
10460
10460
  }
@@ -10662,7 +10662,7 @@ var require_age_encryption = __commonJS({
10662
10662
  this.recipient = res.bytes;
10663
10663
  }
10664
10664
  async wrapFileKey(fileKey) {
10665
- const ephemeral = randomBytes4(32);
10665
+ const ephemeral = randomBytes5(32);
10666
10666
  const share = await scalarMultBase(ephemeral);
10667
10667
  const secret = await scalarMult(ephemeral, this.recipient);
10668
10668
  const salt = new Uint8Array(share.length + this.recipient.length);
@@ -10723,7 +10723,7 @@ var require_age_encryption = __commonJS({
10723
10723
  this.logN = logN;
10724
10724
  }
10725
10725
  wrapFileKey(fileKey) {
10726
- const salt = randomBytes4(16);
10726
+ const salt = randomBytes5(16);
10727
10727
  const label2 = "age-encryption.org/v1/scrypt";
10728
10728
  const labelAndSalt = new Uint8Array(label2.length + 16);
10729
10729
  labelAndSalt.set(new TextEncoder().encode(label2));
@@ -11058,7 +11058,7 @@ var require_age_encryption = __commonJS({
11058
11058
  rp: { name: "", id: options.rpId },
11059
11059
  user: {
11060
11060
  name: options.keyName,
11061
- id: domBuffer2(randomBytes4(8)),
11061
+ id: domBuffer2(randomBytes5(8)),
11062
11062
  // avoid overwriting existing keys
11063
11063
  displayName: ""
11064
11064
  },
@@ -11128,7 +11128,7 @@ var require_age_encryption = __commonJS({
11128
11128
  transports: this.transports,
11129
11129
  type: "public-key"
11130
11130
  }] : [],
11131
- challenge: domBuffer2(randomBytes4(16)),
11131
+ challenge: domBuffer2(randomBytes5(16)),
11132
11132
  extensions: { prf: { eval: prfInputs(nonce) } },
11133
11133
  userVerification: "required",
11134
11134
  // prf requires UV
@@ -11147,7 +11147,7 @@ var require_age_encryption = __commonJS({
11147
11147
  * Implements {@link Recipient.wrapFileKey}.
11148
11148
  */
11149
11149
  async wrapFileKey(fileKey) {
11150
- const nonce = randomBytes4(16);
11150
+ const nonce = randomBytes5(16);
11151
11151
  const results = await this.getCredential(nonce);
11152
11152
  const key = deriveKey(results);
11153
11153
  return [new Stanza([label, base64nopad.encode(nonce)], encryptFileKey(fileKey, key))];
@@ -11270,7 +11270,7 @@ var require_age_encryption = __commonJS({
11270
11270
  }
11271
11271
  }
11272
11272
  async encrypt(file) {
11273
- const fileKey = randomBytes4(16);
11273
+ const fileKey = randomBytes5(16);
11274
11274
  const stanzas = [];
11275
11275
  let recipients = this.recipients;
11276
11276
  if (this.passphrase !== null) {
@@ -11283,7 +11283,7 @@ var require_age_encryption = __commonJS({
11283
11283
  const hmacKey = hkdf(sha256, fileKey, void 0, labelHeader, 32);
11284
11284
  const mac = hmac(sha256, hmacKey, encodeHeaderNoMAC(stanzas));
11285
11285
  const header = encodeHeader(stanzas, mac);
11286
- const nonce = randomBytes4(16);
11286
+ const nonce = randomBytes5(16);
11287
11287
  const labelPayload = new TextEncoder().encode("payload");
11288
11288
  const streamKey = hkdf(sha256, fileKey, nonce, labelPayload, 32);
11289
11289
  const encrypter = encryptSTREAM(streamKey);
@@ -11420,7 +11420,6 @@ var index_exports = {};
11420
11420
  __export(index_exports, {
11421
11421
  ArtifactPacker: () => ArtifactPacker,
11422
11422
  BackendMigrator: () => BackendMigrator,
11423
- BulkOps: () => BulkOps,
11424
11423
  CLEF_MANIFEST_FILENAME: () => CLEF_MANIFEST_FILENAME,
11425
11424
  CLEF_POLICY_FILENAME: () => CLEF_POLICY_FILENAME,
11426
11425
  CLEF_REPORT_SCHEMA_VERSION: () => CLEF_REPORT_SCHEMA_VERSION,
@@ -11434,6 +11433,7 @@ __export(index_exports, {
11434
11433
  DiffEngine: () => DiffEngine,
11435
11434
  DriftDetector: () => DriftDetector,
11436
11435
  FilePackOutput: () => FilePackOutput,
11436
+ FilesystemStorageBackend: () => FilesystemStorageBackend,
11437
11437
  GitIntegration: () => GitIntegration,
11438
11438
  GitOperationError: () => GitOperationError,
11439
11439
  ImportRunner: () => ImportRunner,
@@ -11450,7 +11450,6 @@ __export(index_exports, {
11450
11450
  PolicyValidationError: () => PolicyValidationError,
11451
11451
  REQUESTS_FILENAME: () => REQUESTS_FILENAME,
11452
11452
  REQUIREMENTS: () => REQUIREMENTS,
11453
- REVEAL_WARNING: () => REVEAL_WARNING,
11454
11453
  RecipientManager: () => RecipientManager,
11455
11454
  ReportGenerator: () => ReportGenerator,
11456
11455
  ReportSanitizer: () => ReportSanitizer,
@@ -11467,6 +11466,7 @@ __export(index_exports, {
11467
11466
  SopsMergeDriver: () => SopsMergeDriver,
11468
11467
  SopsMissingError: () => SopsMissingError,
11469
11468
  SopsVersionError: () => SopsVersionError,
11469
+ SourceCapabilityUnsupportedError: () => SourceCapabilityUnsupportedError,
11470
11470
  StructureManager: () => StructureManager,
11471
11471
  SyncManager: () => SyncManager,
11472
11472
  TransactionLockError: () => TransactionLockError,
@@ -11486,11 +11486,11 @@ __export(index_exports, {
11486
11486
  checkAll: () => checkAll,
11487
11487
  checkDependency: () => checkDependency,
11488
11488
  collectCIContext: () => collectCIContext,
11489
+ composeSecretSource: () => composeSecretSource,
11489
11490
  computeCiphertextHash: () => computeCiphertextHash,
11490
11491
  deriveAgePublicKey: () => deriveAgePublicKey,
11492
+ describeCapabilities: () => describeCapabilities,
11491
11493
  describeScope: () => describeScope,
11492
- detectAlgorithm: () => detectAlgorithm,
11493
- detectFormat: () => detectFormat,
11494
11494
  emptyTemplate: () => emptyTemplate,
11495
11495
  exampleTemplate: () => exampleTemplate,
11496
11496
  findRequest: () => findRequest,
@@ -11498,35 +11498,27 @@ __export(index_exports, {
11498
11498
  formatRevealWarning: () => formatRevealWarning,
11499
11499
  generateAgeIdentity: () => generateAgeIdentity,
11500
11500
  generateRandomValue: () => generateRandomValue,
11501
- generateSigningKeyPair: () => generateSigningKeyPair,
11502
- getPendingKeys: () => getPendingKeys,
11503
- getRotations: () => getRotations,
11501
+ isBulk: () => isBulk,
11504
11502
  isClefHsmArn: () => isClefHsmArn,
11505
- isHighEntropy: () => isHighEntropy,
11506
11503
  isKmsEnvelope: () => isKmsEnvelope,
11504
+ isLintable: () => isLintable,
11505
+ isMergeAware: () => isMergeAware,
11506
+ isMigratable: () => isMigratable,
11507
11507
  isPackedArtifact: () => isPackedArtifact,
11508
- isPending: () => isPending,
11508
+ isRecipientManaged: () => isRecipientManaged,
11509
+ isRotatable: () => isRotatable,
11510
+ isStructural: () => isStructural,
11509
11511
  keyPreview: () => keyPreview,
11510
- loadIgnoreRules: () => loadIgnoreRules,
11511
- loadMetadata: () => loadMetadata,
11512
11512
  loadRequests: () => loadRequests,
11513
11513
  markPending: () => markPending,
11514
- markPendingWithRetry: () => markPendingWithRetry,
11515
11514
  markResolved: () => markResolved,
11516
- matchPatterns: () => matchPatterns,
11517
- mergeMetadataContents: () => mergeMetadataContents,
11518
11515
  mergeMetadataFiles: () => mergeMetadataFiles,
11519
- metadataPath: () => metadataPath,
11520
11516
  parse: () => parse9,
11521
- parseDotenv: () => parseDotenv,
11522
- parseIgnoreContent: () => parseIgnoreContent,
11523
- parseJson: () => parseJson,
11524
11517
  parseSignerKey: () => parseSignerKey,
11525
11518
  parseYaml: () => parseYaml,
11526
11519
  pkcs11UriToSyntheticArn: () => pkcs11UriToSyntheticArn,
11527
11520
  readManifestYaml: () => readManifestYaml,
11528
11521
  recordRotation: () => recordRotation,
11529
- redactValue: () => redactValue,
11530
11522
  removeAccessRequest: () => removeRequest,
11531
11523
  removeRotation: () => removeRotation,
11532
11524
  requestsFilePath: () => requestsFilePath,
@@ -11538,14 +11530,8 @@ __export(index_exports, {
11538
11530
  resolveRecipientsForEnvironment: () => resolveRecipientsForEnvironment,
11539
11531
  resolveSopsPath: () => resolveSopsPath,
11540
11532
  runCompliance: () => runCompliance,
11541
- saveMetadata: () => saveMetadata,
11542
11533
  saveRequests: () => saveRequests,
11543
- serializeSchema: () => serializeSchema,
11544
- shannonEntropy: () => shannonEntropy,
11545
- shouldIgnoreFile: () => shouldIgnoreFile,
11546
- shouldIgnoreMatch: () => shouldIgnoreMatch,
11547
- signEd25519: () => signEd25519,
11548
- signKms: () => signKms,
11534
+ shouldUseLinuxStdinFifo: () => shouldUseLinuxStdinFifo,
11549
11535
  spawnKeyservice: () => spawnKeyservice,
11550
11536
  syntheticArnToPkcs11Uri: () => syntheticArnToPkcs11Uri,
11551
11537
  tryBundledKeyservice: () => tryBundledKeyservice,
@@ -11555,6 +11541,7 @@ __export(index_exports, {
11555
11541
  validatePackedArtifact: () => validatePackedArtifact,
11556
11542
  validateResetScope: () => validateResetScope,
11557
11543
  verifySignature: () => verifySignature,
11544
+ wrapWithLinuxStdinFifo: () => wrapWithLinuxStdinFifo,
11558
11545
  writeManifestYaml: () => writeManifestYaml,
11559
11546
  writeManifestYamlRaw: () => writeManifestYamlRaw,
11560
11547
  writeSchema: () => writeSchema,
@@ -12907,10 +12894,6 @@ async function getPendingKeys(filePath) {
12907
12894
  const metadata = await loadMetadata(filePath);
12908
12895
  return metadata.pending.map((p) => p.key);
12909
12896
  }
12910
- async function isPending(filePath, key) {
12911
- const metadata = await loadMetadata(filePath);
12912
- return metadata.pending.some((p) => p.key === key);
12913
- }
12914
12897
  async function recordRotation(filePath, keys, rotatedBy, now = /* @__PURE__ */ new Date()) {
12915
12898
  const metadata = await loadMetadata(filePath);
12916
12899
  for (const key of keys) {
@@ -12946,14 +12929,6 @@ async function getRotations(filePath) {
12946
12929
  function generateRandomValue() {
12947
12930
  return crypto2.randomBytes(32).toString("hex");
12948
12931
  }
12949
- async function markPendingWithRetry(filePath, keys, setBy, retryDelayMs = 200) {
12950
- try {
12951
- await markPending(filePath, keys, setBy);
12952
- } catch {
12953
- await new Promise((r) => setTimeout(r, retryDelayMs));
12954
- await markPending(filePath, keys, setBy);
12955
- }
12956
- }
12957
12932
 
12958
12933
  // src/sops/keys.ts
12959
12934
  var fs6 = __toESM(require("fs"));
@@ -13003,34 +12978,17 @@ var MatrixManager = class {
13003
12978
  detectMissingCells(manifest, repoRoot) {
13004
12979
  return this.resolveMatrix(manifest, repoRoot).filter((cell) => !cell.exists);
13005
12980
  }
13006
- /**
13007
- * Create an empty encrypted SOPS file for a missing matrix cell.
13008
- *
13009
- * @param cell - The cell to scaffold (must not already exist).
13010
- * @param sopsClient - SOPS client used to write the initial encrypted file.
13011
- * @param manifest - Parsed manifest used to determine the encryption backend.
13012
- */
13013
- async scaffoldCell(cell, sopsClient, manifest) {
13014
- const dir = path5.dirname(cell.filePath);
13015
- if (!fs7.existsSync(dir)) {
13016
- fs7.mkdirSync(dir, { recursive: true });
13017
- }
13018
- await sopsClient.encrypt(cell.filePath, {}, manifest, cell.environment);
13019
- }
13020
12981
  /**
13021
12982
  * Read each cell and return key counts, pending counts, and cross-environment issues.
13022
12983
  *
13023
- * The SOPS client parameter is currently unused keys are read from the
13024
- * plaintext YAML structure directly, no decryption needed. It is retained
13025
- * in the signature for back-compat with callers that may need to swap to a
13026
- * decrypt-based implementation later (e.g. for backends that don't expose
13027
- * key names without decryption).
12984
+ * Keys are read from the plaintext YAML structure directly no
12985
+ * decryption needed. A future backend that doesn't expose key names
12986
+ * without decryption would need its own implementation.
13028
12987
  *
13029
12988
  * @param manifest - Parsed manifest.
13030
12989
  * @param repoRoot - Absolute path to the repository root.
13031
- * @param _sopsClient - Reserved for future use; pass any `EncryptionBackend`.
13032
12990
  */
13033
- async getMatrixStatus(manifest, repoRoot, _sopsClient) {
12991
+ async getMatrixStatus(manifest, repoRoot) {
13034
12992
  const cells = this.resolveMatrix(manifest, repoRoot);
13035
12993
  const statuses = [];
13036
12994
  const cellKeys = /* @__PURE__ */ new Map();
@@ -13346,7 +13304,6 @@ function orderedKeys(keys) {
13346
13304
  }
13347
13305
 
13348
13306
  // src/diff/engine.ts
13349
- var path7 = __toESM(require("path"));
13350
13307
  var DiffEngine = class {
13351
13308
  /**
13352
13309
  * Compare two in-memory value maps and produce a sorted diff result.
@@ -13397,131 +13354,21 @@ var DiffEngine = class {
13397
13354
  * @param namespace - Namespace containing both cells.
13398
13355
  * @param envA - Name of environment A.
13399
13356
  * @param envB - Name of environment B.
13400
- * @param manifest - Parsed manifest used to resolve file paths.
13401
- * @param sopsClient - SOPS client used to decrypt both files.
13402
- * @param repoRoot - Absolute path to the repository root.
13403
- * @throws {@link SopsDecryptionError} If either file cannot be decrypted.
13357
+ * @param source - SecretSource that resolves both cells (substrate-agnostic).
13358
+ * @throws {@link SopsDecryptionError} If either cell cannot be decrypted.
13404
13359
  */
13405
- async diffFiles(namespace, envA, envB, manifest, sopsClient, repoRoot) {
13406
- const fileA = path7.join(
13407
- repoRoot,
13408
- manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", envA)
13409
- );
13410
- const fileB = path7.join(
13411
- repoRoot,
13412
- manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", envB)
13413
- );
13360
+ async diffCells(namespace, envA, envB, source) {
13414
13361
  const [decryptedA, decryptedB] = await Promise.all([
13415
- sopsClient.decrypt(fileA),
13416
- sopsClient.decrypt(fileB)
13362
+ source.readCell({ namespace, environment: envA }),
13363
+ source.readCell({ namespace, environment: envB })
13417
13364
  ]);
13418
13365
  return this.diff(decryptedA.values, decryptedB.values, envA, envB, namespace);
13419
13366
  }
13420
13367
  };
13421
13368
 
13422
- // src/bulk/ops.ts
13423
- var path8 = __toESM(require("path"));
13424
- var BulkOps = class {
13425
- constructor(tx) {
13426
- this.tx = tx;
13427
- }
13428
- tx;
13429
- /**
13430
- * Set a key to different values in multiple environments at once.
13431
- *
13432
- * @param namespace - Target namespace.
13433
- * @param key - Secret key name to set.
13434
- * @param values - Map of `{ environment: value }` pairs.
13435
- * @param manifest - Parsed manifest.
13436
- * @param sopsClient - SOPS client used to decrypt and re-encrypt each file.
13437
- * @param repoRoot - Absolute path to the repository root.
13438
- * @throws Whatever the underlying encrypt throws — the transaction rolls back.
13439
- */
13440
- async setAcrossEnvironments(namespace, key, values, manifest, sopsClient, repoRoot) {
13441
- const targets = manifest.environments.filter((env) => env.name in values).map((env) => ({
13442
- env: env.name,
13443
- filePath: path8.join(
13444
- repoRoot,
13445
- manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", env.name)
13446
- )
13447
- }));
13448
- if (targets.length === 0) return;
13449
- await this.tx.run(repoRoot, {
13450
- description: `clef set: ${namespace}/${key} across ${targets.length} env(s)`,
13451
- paths: targets.map((t) => path8.relative(repoRoot, t.filePath)),
13452
- mutate: async () => {
13453
- for (const target of targets) {
13454
- const decrypted = await sopsClient.decrypt(target.filePath);
13455
- decrypted.values[key] = values[target.env];
13456
- await sopsClient.encrypt(target.filePath, decrypted.values, manifest, target.env);
13457
- }
13458
- }
13459
- });
13460
- }
13461
- /**
13462
- * Delete a key from every environment in a namespace.
13463
- *
13464
- * @param namespace - Target namespace.
13465
- * @param key - Secret key name to delete.
13466
- * @param manifest - Parsed manifest.
13467
- * @param sopsClient - SOPS client.
13468
- * @param repoRoot - Absolute path to the repository root.
13469
- */
13470
- async deleteAcrossEnvironments(namespace, key, manifest, sopsClient, repoRoot) {
13471
- const targets = manifest.environments.map((env) => ({
13472
- env: env.name,
13473
- filePath: path8.join(
13474
- repoRoot,
13475
- manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", env.name)
13476
- )
13477
- }));
13478
- await this.tx.run(repoRoot, {
13479
- description: `clef delete: ${namespace}/${key} from ${targets.length} env(s)`,
13480
- paths: targets.map((t) => path8.relative(repoRoot, t.filePath)),
13481
- mutate: async () => {
13482
- for (const target of targets) {
13483
- const decrypted = await sopsClient.decrypt(target.filePath);
13484
- if (key in decrypted.values) {
13485
- delete decrypted.values[key];
13486
- await sopsClient.encrypt(target.filePath, decrypted.values, manifest, target.env);
13487
- }
13488
- }
13489
- }
13490
- });
13491
- }
13492
- /**
13493
- * Copy a single key's value from one matrix cell to another.
13494
- *
13495
- * @param key - Secret key name to copy.
13496
- * @param fromCell - Source matrix cell.
13497
- * @param toCell - Destination matrix cell.
13498
- * @param sopsClient - SOPS client.
13499
- * @param manifest - Parsed manifest.
13500
- * @param repoRoot - Absolute path to the repository root.
13501
- * @throws `Error` if the key does not exist in the source cell.
13502
- */
13503
- async copyValue(key, fromCell, toCell, sopsClient, manifest, repoRoot) {
13504
- const source = await sopsClient.decrypt(fromCell.filePath);
13505
- if (!(key in source.values)) {
13506
- throw new Error(
13507
- `Key '${key}' does not exist in ${fromCell.namespace}/${fromCell.environment}.`
13508
- );
13509
- }
13510
- await this.tx.run(repoRoot, {
13511
- description: `clef copy: ${key} from ${fromCell.namespace}/${fromCell.environment} to ${toCell.namespace}/${toCell.environment}`,
13512
- paths: [path8.relative(repoRoot, toCell.filePath)],
13513
- mutate: async () => {
13514
- const dest = await sopsClient.decrypt(toCell.filePath);
13515
- dest.values[key] = source.values[key];
13516
- await sopsClient.encrypt(toCell.filePath, dest.values, manifest, toCell.environment);
13517
- }
13518
- });
13519
- }
13520
- };
13521
-
13522
13369
  // src/git/integration.ts
13523
13370
  var fs10 = __toESM(require("fs"));
13524
- var path9 = __toESM(require("path"));
13371
+ var path7 = __toESM(require("path"));
13525
13372
  var PRE_COMMIT_HOOK = `#!/bin/sh
13526
13373
  # Clef pre-commit hook \u2014 blocks commits of files missing SOPS encryption metadata
13527
13374
  # and scans staged files for plaintext secrets.
@@ -13697,17 +13544,17 @@ var GitIntegration = class {
13697
13544
  * @returns The kind of operation in progress, or null if none.
13698
13545
  */
13699
13546
  async isMidOperation(repoRoot) {
13700
- const gitDir = path9.join(repoRoot, ".git");
13701
- if (fs10.existsSync(path9.join(gitDir, "MERGE_HEAD"))) {
13547
+ const gitDir = path7.join(repoRoot, ".git");
13548
+ if (fs10.existsSync(path7.join(gitDir, "MERGE_HEAD"))) {
13702
13549
  return { midOp: true, kind: "merge" };
13703
13550
  }
13704
- if (fs10.existsSync(path9.join(gitDir, "rebase-merge")) || fs10.existsSync(path9.join(gitDir, "rebase-apply"))) {
13551
+ if (fs10.existsSync(path7.join(gitDir, "rebase-merge")) || fs10.existsSync(path7.join(gitDir, "rebase-apply"))) {
13705
13552
  return { midOp: true, kind: "rebase" };
13706
13553
  }
13707
- if (fs10.existsSync(path9.join(gitDir, "CHERRY_PICK_HEAD"))) {
13554
+ if (fs10.existsSync(path7.join(gitDir, "CHERRY_PICK_HEAD"))) {
13708
13555
  return { midOp: true, kind: "cherry-pick" };
13709
13556
  }
13710
- if (fs10.existsSync(path9.join(gitDir, "REVERT_HEAD"))) {
13557
+ if (fs10.existsSync(path7.join(gitDir, "REVERT_HEAD"))) {
13711
13558
  return { midOp: true, kind: "revert" };
13712
13559
  }
13713
13560
  return { midOp: false };
@@ -13919,14 +13766,14 @@ var GitIntegration = class {
13919
13766
  { cwd: repoRoot }
13920
13767
  );
13921
13768
  const metadataGitConfig = metaConfig.exitCode === 0 && metaConfig.stdout.trim().length > 0;
13922
- const attrFilePath = path9.join(repoRoot, ".gitattributes");
13769
+ const attrFilePath = path7.join(repoRoot, ".gitattributes");
13923
13770
  const attrContent = fs10.existsSync(attrFilePath) ? fs10.readFileSync(attrFilePath, "utf-8") : "";
13924
13771
  const gitattributes = attrContent.includes("merge=sops");
13925
13772
  const metadataGitattributes = attrContent.includes("merge=clef-metadata");
13926
13773
  return { gitConfig, gitattributes, metadataGitConfig, metadataGitattributes };
13927
13774
  }
13928
13775
  async ensureGitattributes(repoRoot) {
13929
- const attrPath = path9.join(repoRoot, ".gitattributes");
13776
+ const attrPath = path7.join(repoRoot, ".gitattributes");
13930
13777
  const existing = fs10.existsSync(attrPath) ? fs10.readFileSync(attrPath, "utf-8") : "";
13931
13778
  let newContent = existing;
13932
13779
  if (!existing.includes("merge=sops")) {
@@ -13961,9 +13808,9 @@ ${block}` : block;
13961
13808
  * @throws {@link GitOperationError} On failure.
13962
13809
  */
13963
13810
  async installPreCommitHook(repoRoot) {
13964
- const hookPath = path9.join(repoRoot, ".git", "hooks", "pre-commit");
13811
+ const hookPath = path7.join(repoRoot, ".git", "hooks", "pre-commit");
13965
13812
  try {
13966
- const hooksDir = path9.dirname(hookPath);
13813
+ const hooksDir = path7.dirname(hookPath);
13967
13814
  if (!fs10.existsSync(hooksDir)) {
13968
13815
  fs10.mkdirSync(hooksDir, { recursive: true });
13969
13816
  }
@@ -13979,7 +13826,7 @@ ${block}` : block;
13979
13826
 
13980
13827
  // src/tx/transaction-manager.ts
13981
13828
  var fs11 = __toESM(require("fs"));
13982
- var path10 = __toESM(require("path"));
13829
+ var path8 = __toESM(require("path"));
13983
13830
  var lockfile = __toESM(require_proper_lockfile());
13984
13831
 
13985
13832
  // src/tx/errors.ts
@@ -14028,15 +13875,15 @@ var TransactionManager = class {
14028
13875
  async run(repoRoot, opts) {
14029
13876
  const shouldCommit = opts.commit !== false;
14030
13877
  const allowDirty = opts.allowDirty === true;
14031
- const clefDir = path10.join(repoRoot, CLEF_DIR);
13878
+ const clefDir = path8.join(repoRoot, CLEF_DIR);
14032
13879
  if (!fs11.existsSync(clefDir)) {
14033
13880
  fs11.mkdirSync(clefDir, { recursive: true });
14034
13881
  }
14035
- const clefGitignore = path10.join(clefDir, ".gitignore");
13882
+ const clefGitignore = path8.join(clefDir, ".gitignore");
14036
13883
  if (!fs11.existsSync(clefGitignore)) {
14037
13884
  fs11.writeFileSync(clefGitignore, "*\n");
14038
13885
  }
14039
- const lockPath = path10.join(clefDir, LOCK_FILE);
13886
+ const lockPath = path8.join(clefDir, LOCK_FILE);
14040
13887
  if (!fs11.existsSync(lockPath)) {
14041
13888
  fs11.writeFileSync(lockPath, "");
14042
13889
  }
@@ -14177,16 +14024,15 @@ var TransactionManager = class {
14177
14024
  var fs14 = __toESM(require("fs"));
14178
14025
  var net = __toESM(require("net"));
14179
14026
  var import_crypto = require("crypto");
14180
- var import_write_file_atomic3 = __toESM(require_lib());
14181
14027
  var YAML8 = __toESM(require("yaml"));
14182
14028
 
14183
14029
  // src/sops/resolver.ts
14184
14030
  var fs13 = __toESM(require("fs"));
14185
- var path12 = __toESM(require("path"));
14031
+ var path10 = __toESM(require("path"));
14186
14032
 
14187
14033
  // src/sops/bundled.ts
14188
14034
  var fs12 = __toESM(require("fs"));
14189
- var path11 = __toESM(require("path"));
14035
+ var path9 = __toESM(require("path"));
14190
14036
  function tryBundled() {
14191
14037
  const platform = process.platform;
14192
14038
  const arch = process.arch;
@@ -14198,8 +14044,8 @@ function tryBundled() {
14198
14044
  const binName = platform === "win32" ? "sops.exe" : "sops";
14199
14045
  try {
14200
14046
  const packageMain = require.resolve(`${packageName}/package.json`);
14201
- const packageDir = path11.dirname(packageMain);
14202
- const binPath = path11.join(packageDir, "bin", binName);
14047
+ const packageDir = path9.dirname(packageMain);
14048
+ const binPath = path9.join(packageDir, "bin", binName);
14203
14049
  return fs12.existsSync(binPath) ? binPath : null;
14204
14050
  } catch {
14205
14051
  return null;
@@ -14208,7 +14054,7 @@ function tryBundled() {
14208
14054
 
14209
14055
  // src/sops/resolver.ts
14210
14056
  function validateSopsPath(candidate) {
14211
- if (!path12.isAbsolute(candidate)) {
14057
+ if (!path10.isAbsolute(candidate)) {
14212
14058
  throw new Error(`CLEF_SOPS_PATH must be an absolute path, got '${candidate}'.`);
14213
14059
  }
14214
14060
  const segments = candidate.split(/[/\\]/);
@@ -14387,6 +14233,17 @@ function isClefHsmArn(arn) {
14387
14233
  function formatFromPath(filePath) {
14388
14234
  return filePath.endsWith(".json") ? "json" : "yaml";
14389
14235
  }
14236
+ async function openInputPipe(content) {
14237
+ if (process.platform === "win32") {
14238
+ const pipe = await openWindowsInputPipe(content);
14239
+ return { inputArg: pipe.inputArg, cleanup: pipe.cleanup };
14240
+ }
14241
+ return { inputArg: "/dev/stdin", cleanup: () => {
14242
+ }, runnerStdin: content };
14243
+ }
14244
+ function nullConfigPath() {
14245
+ return process.platform === "win32" ? "NUL" : "/dev/null";
14246
+ }
14390
14247
  function openWindowsInputPipe(content) {
14391
14248
  const pipeName = `\\\\.\\pipe\\clef-sops-${(0, import_crypto.randomBytes)(8).toString("hex")}`;
14392
14249
  return new Promise((resolve2, reject) => {
@@ -14434,6 +14291,10 @@ var SopsClient = class {
14434
14291
  runner;
14435
14292
  ageKeyFile;
14436
14293
  ageKey;
14294
+ /** {@link EncryptionBackend} identifier. */
14295
+ id = "sops";
14296
+ /** {@link EncryptionBackend} short description (used by `clef doctor`). */
14297
+ description = "SOPS-based encryption via the bundled `sops` binary";
14437
14298
  sopsCommand;
14438
14299
  keyserviceArgs;
14439
14300
  buildSopsEnv() {
@@ -14447,14 +14308,18 @@ var SopsClient = class {
14447
14308
  return Object.keys(env).length > 0 ? env : void 0;
14448
14309
  }
14449
14310
  /**
14450
- * Decrypt a SOPS-encrypted file and return its values and metadata.
14311
+ * Decrypt a SOPS-encrypted file by path. The only remaining file-path
14312
+ * entry point on this class — kept for the merge driver, which
14313
+ * receives temp filesystem paths from git that don't map onto a
14314
+ * `CellRef`. Production `SecretSource` consumers should call
14315
+ * `source.readCell` instead.
14451
14316
  *
14452
14317
  * @param filePath - Path to the `.enc.yaml` or `.enc.json` file.
14453
14318
  * @returns {@link DecryptedFile} with plaintext values in memory only.
14454
14319
  * @throws {@link SopsKeyNotFoundError} If no matching decryption key is available.
14455
14320
  * @throws {@link SopsDecryptionError} On any other decryption failure.
14456
14321
  */
14457
- async decrypt(filePath) {
14322
+ async decryptFile(filePath) {
14458
14323
  await assertSops(this.runner, this.sopsCommand);
14459
14324
  const fmt = formatFromPath(filePath);
14460
14325
  const env = this.buildSopsEnv();
@@ -14490,170 +14355,9 @@ var SopsClient = class {
14490
14355
  for (const [key, value] of Object.entries(parsed)) {
14491
14356
  values[key] = String(value);
14492
14357
  }
14493
- const metadata = await this.getMetadata(filePath);
14358
+ const metadata = this.parseMetadataFromFile(filePath);
14494
14359
  return { values, metadata };
14495
14360
  }
14496
- /**
14497
- * Encrypt a key/value map and write it to an encrypted SOPS file.
14498
- *
14499
- * @param filePath - Destination path for the encrypted file.
14500
- * @param values - Flat key/value map to encrypt.
14501
- * @param manifest - Manifest used to determine the encryption backend and key configuration.
14502
- * @param environment - Optional environment name. When provided, per-env backend overrides
14503
- * are resolved from the manifest. When omitted, the global `sops.default_backend` is used.
14504
- * @throws {@link SopsEncryptionError} On encryption or write failure.
14505
- */
14506
- async encrypt(filePath, values, manifest, environment) {
14507
- await assertSops(this.runner, this.sopsCommand);
14508
- const fmt = formatFromPath(filePath);
14509
- const content = fmt === "json" ? JSON.stringify(values, null, 2) : YAML8.stringify(values);
14510
- const args = this.buildEncryptArgs(filePath, manifest, environment);
14511
- const env = this.buildSopsEnv();
14512
- let inputArg;
14513
- let pipeCleanup;
14514
- if (process.platform === "win32") {
14515
- const pipe = await openWindowsInputPipe(content);
14516
- inputArg = pipe.inputArg;
14517
- pipeCleanup = pipe.cleanup;
14518
- } else {
14519
- inputArg = "/dev/stdin";
14520
- }
14521
- let result;
14522
- try {
14523
- const configPath = process.platform === "win32" ? "NUL" : "/dev/null";
14524
- result = await this.runner.run(
14525
- this.sopsCommand,
14526
- [
14527
- "--config",
14528
- configPath,
14529
- "encrypt",
14530
- ...this.keyserviceArgs,
14531
- ...args,
14532
- "--input-type",
14533
- fmt,
14534
- "--output-type",
14535
- fmt,
14536
- "--filename-override",
14537
- filePath,
14538
- inputArg
14539
- ],
14540
- {
14541
- // stdin is still piped on Unix (/dev/stdin reads from it);
14542
- // on Windows the named pipe server feeds content directly.
14543
- ...process.platform !== "win32" ? { stdin: content } : {},
14544
- ...env ? { env } : {}
14545
- }
14546
- );
14547
- } finally {
14548
- pipeCleanup?.();
14549
- }
14550
- if (result.exitCode !== 0) {
14551
- throw new SopsEncryptionError(
14552
- `Failed to encrypt '${filePath}': ${result.stderr.trim()}`,
14553
- filePath
14554
- );
14555
- }
14556
- try {
14557
- await (0, import_write_file_atomic3.default)(filePath, result.stdout);
14558
- } catch (err) {
14559
- throw new SopsEncryptionError(
14560
- `Failed to write encrypted data to '${filePath}': ${err.message}`,
14561
- filePath
14562
- );
14563
- }
14564
- }
14565
- /**
14566
- * Rotate encryption by adding a new age recipient key to an existing SOPS file.
14567
- *
14568
- * @param filePath - Path to the encrypted file to re-encrypt.
14569
- * @param newKey - New age public key to add as a recipient.
14570
- * @throws {@link SopsEncryptionError} On failure.
14571
- */
14572
- async reEncrypt(filePath, newKey) {
14573
- await this.addRecipient(filePath, newKey);
14574
- }
14575
- /**
14576
- * Add an age recipient to an existing SOPS file.
14577
- *
14578
- * @param filePath - Path to the encrypted file.
14579
- * @param key - age public key to add as a recipient.
14580
- * @throws {@link SopsEncryptionError} On failure.
14581
- */
14582
- async addRecipient(filePath, key) {
14583
- await assertSops(this.runner, this.sopsCommand);
14584
- const env = this.buildSopsEnv();
14585
- const result = await this.runner.run(
14586
- this.sopsCommand,
14587
- ["rotate", ...this.keyserviceArgs, "-i", "--add-age", key, filePath],
14588
- {
14589
- ...env ? { env } : {}
14590
- }
14591
- );
14592
- if (result.exitCode !== 0) {
14593
- throw new SopsEncryptionError(
14594
- `Failed to add recipient to '${filePath}': ${result.stderr.trim()}`,
14595
- filePath
14596
- );
14597
- }
14598
- }
14599
- /**
14600
- * Remove an age recipient from an existing SOPS file.
14601
- *
14602
- * @param filePath - Path to the encrypted file.
14603
- * @param key - age public key to remove.
14604
- * @throws {@link SopsEncryptionError} On failure.
14605
- */
14606
- async removeRecipient(filePath, key) {
14607
- await assertSops(this.runner, this.sopsCommand);
14608
- const env = this.buildSopsEnv();
14609
- const result = await this.runner.run(
14610
- this.sopsCommand,
14611
- ["rotate", ...this.keyserviceArgs, "-i", "--rm-age", key, filePath],
14612
- {
14613
- ...env ? { env } : {}
14614
- }
14615
- );
14616
- if (result.exitCode !== 0) {
14617
- throw new SopsEncryptionError(
14618
- `Failed to remove recipient from '${filePath}': ${result.stderr.trim()}`,
14619
- filePath
14620
- );
14621
- }
14622
- }
14623
- /**
14624
- * Check whether a file contains valid SOPS encryption metadata.
14625
- *
14626
- * @param filePath - Path to the file to check.
14627
- * @returns `true` if valid SOPS metadata is present; `false` otherwise. Never throws.
14628
- */
14629
- async validateEncryption(filePath) {
14630
- await assertSops(this.runner, this.sopsCommand);
14631
- try {
14632
- await this.getMetadata(filePath);
14633
- return true;
14634
- } catch {
14635
- return false;
14636
- }
14637
- }
14638
- /**
14639
- * Extract SOPS metadata (backend, recipients, last-modified timestamp) from an encrypted file
14640
- * without decrypting its values.
14641
- *
14642
- * @param filePath - Path to the encrypted file.
14643
- * @returns {@link SopsMetadata} parsed from the file's `sops:` block.
14644
- * @throws {@link SopsDecryptionError} If the file cannot be read or parsed.
14645
- */
14646
- async getMetadata(filePath) {
14647
- await assertSops(this.runner, this.sopsCommand);
14648
- const env = this.buildSopsEnv();
14649
- const result = await this.runner.run(this.sopsCommand, ["filestatus", filePath], {
14650
- ...env ? { env } : {}
14651
- });
14652
- if (result.exitCode !== 0) {
14653
- return this.parseMetadataFromFile(filePath);
14654
- }
14655
- return this.parseMetadataFromFile(filePath);
14656
- }
14657
14361
  /**
14658
14362
  * Determine whether a decrypt failure is caused by a missing/mismatched key (vs. some other
14659
14363
  * SOPS error) without relying on stderr message text.
@@ -14697,20 +14401,30 @@ var SopsClient = class {
14697
14401
  filePath
14698
14402
  );
14699
14403
  }
14404
+ return this.parseMetadataFromContent(content, filePath);
14405
+ }
14406
+ /**
14407
+ * Parse SOPS metadata from a string (no IO). Used by both
14408
+ * `parseMetadataFromFile` (after reading from disk) and the blob-shaped
14409
+ * `getMetadataFromBlob` (which receives ciphertext directly from a
14410
+ * BlobStore). The `label` is woven into error messages so callers can
14411
+ * include the file path or cell ref the content came from.
14412
+ */
14413
+ parseMetadataFromContent(content, label) {
14700
14414
  let parsed;
14701
14415
  try {
14702
14416
  parsed = YAML8.parse(content);
14703
14417
  } catch {
14704
14418
  throw new SopsDecryptionError(
14705
- `File '${filePath}' is not valid YAML. Cannot extract SOPS metadata.`,
14706
- filePath
14419
+ `${label} is not valid YAML. Cannot extract SOPS metadata.`,
14420
+ label
14707
14421
  );
14708
14422
  }
14709
14423
  const sops = parsed?.sops;
14710
14424
  if (!sops) {
14711
14425
  throw new SopsDecryptionError(
14712
- `File '${filePath}' does not contain SOPS metadata. It may not be encrypted.`,
14713
- filePath
14426
+ `${label} does not contain SOPS metadata. It may not be encrypted.`,
14427
+ label
14714
14428
  );
14715
14429
  }
14716
14430
  const backend = this.detectBackend(sops);
@@ -14773,7 +14487,7 @@ var SopsClient = class {
14773
14487
  }
14774
14488
  }
14775
14489
  }
14776
- buildEncryptArgs(filePath, manifest, environment) {
14490
+ buildEncryptArgs(manifest, environment) {
14777
14491
  const args = [];
14778
14492
  const config = environment ? resolveBackendConfig(manifest, environment) : {
14779
14493
  backend: manifest.sops.default_backend,
@@ -14821,11 +14535,255 @@ var SopsClient = class {
14821
14535
  }
14822
14536
  return args;
14823
14537
  }
14538
+ // ── Blob-shaped methods ─────────────────────────────────────────────────
14539
+ //
14540
+ // These mirror the file-path methods above but operate on opaque
14541
+ // ciphertext bytes via SOPS' stdin/stdout. They are the substrate-
14542
+ // agnostic primitives used by the `composeSecretSource` factory to
14543
+ // wrap any `BlobStore` (filesystem, postgres, etc.) into a full
14544
+ // `SecretSource`. Plaintext never leaves the SOPS subprocess.
14545
+ /**
14546
+ * {@link EncryptionBackend.decrypt} — decrypt SOPS-encrypted bytes (e.g.
14547
+ * read from a `StorageBackend`) and return plaintext values + metadata.
14548
+ * Plaintext lives only in memory.
14549
+ */
14550
+ async decrypt(blob, ctx) {
14551
+ await assertSops(this.runner, this.sopsCommand);
14552
+ const env = this.buildSopsEnv();
14553
+ const pipe = await openInputPipe(blob);
14554
+ let result;
14555
+ try {
14556
+ result = await this.runner.run(
14557
+ this.sopsCommand,
14558
+ [
14559
+ "decrypt",
14560
+ ...this.keyserviceArgs,
14561
+ "--input-type",
14562
+ ctx.format,
14563
+ "--output-type",
14564
+ ctx.format,
14565
+ pipe.inputArg
14566
+ ],
14567
+ {
14568
+ ...pipe.runnerStdin !== void 0 ? { stdin: pipe.runnerStdin } : {},
14569
+ ...env ? { env } : {}
14570
+ }
14571
+ );
14572
+ } finally {
14573
+ pipe.cleanup();
14574
+ }
14575
+ if (result.exitCode !== 0) {
14576
+ const errorType = await this.classifyDecryptErrorFromContent(blob);
14577
+ if (errorType === "key-not-found") {
14578
+ throw new SopsKeyNotFoundError(`No decryption key found for cell. ${result.stderr.trim()}`);
14579
+ }
14580
+ throw new SopsDecryptionError(`Failed to decrypt cell: ${result.stderr.trim()}`);
14581
+ }
14582
+ let parsed;
14583
+ try {
14584
+ parsed = YAML8.parse(result.stdout) ?? {};
14585
+ } catch {
14586
+ throw new SopsDecryptionError("Decrypted content is not valid YAML.");
14587
+ }
14588
+ const values = {};
14589
+ for (const [key, value] of Object.entries(parsed)) {
14590
+ values[key] = String(value);
14591
+ }
14592
+ const metadata = this.parseMetadataFromContent(blob, "<cell>");
14593
+ return { values, metadata };
14594
+ }
14595
+ /**
14596
+ * {@link EncryptionBackend.encrypt} — encrypt plaintext values into a
14597
+ * SOPS-formatted ciphertext blob. Returns the bytes as a string;
14598
+ * caller (typically a `StorageBackend`) decides where to put them.
14599
+ * Plaintext is piped via stdin only.
14600
+ */
14601
+ async encrypt(values, ctx) {
14602
+ await assertSops(this.runner, this.sopsCommand);
14603
+ const content = ctx.format === "json" ? JSON.stringify(values, null, 2) : YAML8.stringify(values);
14604
+ const args = this.buildEncryptArgs(ctx.manifest, ctx.environment);
14605
+ const env = this.buildSopsEnv();
14606
+ const pipe = await openInputPipe(content);
14607
+ let result;
14608
+ try {
14609
+ result = await this.runner.run(
14610
+ this.sopsCommand,
14611
+ [
14612
+ "--config",
14613
+ nullConfigPath(),
14614
+ "encrypt",
14615
+ ...this.keyserviceArgs,
14616
+ ...args,
14617
+ "--input-type",
14618
+ ctx.format,
14619
+ "--output-type",
14620
+ ctx.format,
14621
+ pipe.inputArg
14622
+ ],
14623
+ {
14624
+ ...pipe.runnerStdin !== void 0 ? { stdin: pipe.runnerStdin } : {},
14625
+ ...env ? { env } : {}
14626
+ }
14627
+ );
14628
+ } finally {
14629
+ pipe.cleanup();
14630
+ }
14631
+ if (result.exitCode !== 0) {
14632
+ throw new SopsEncryptionError(`Failed to encrypt cell: ${result.stderr.trim()}`);
14633
+ }
14634
+ return result.stdout;
14635
+ }
14636
+ /**
14637
+ * {@link EncryptionBackend.rotate} — add or remove recipients from an
14638
+ * encrypted SOPS blob via stdin/stdout. Drops the in-place `-i` flag
14639
+ * the deleted file-path-shaped methods used, so SOPS writes the
14640
+ * rotated ciphertext to stdout instead of back to a file. Plaintext
14641
+ * stays inside the SOPS subprocess; no plaintext window exists in
14642
+ * this Node process.
14643
+ *
14644
+ * Single SOPS invocation can both add and remove recipients
14645
+ * simultaneously (matches the CLI flag set).
14646
+ */
14647
+ async rotate(blob, opts, ctx) {
14648
+ await assertSops(this.runner, this.sopsCommand);
14649
+ const env = this.buildSopsEnv();
14650
+ const pipe = await openInputPipe(blob);
14651
+ const flagArgs = [];
14652
+ if (opts.addAge) flagArgs.push("--add-age", opts.addAge);
14653
+ if (opts.rmAge) flagArgs.push("--rm-age", opts.rmAge);
14654
+ if (opts.addKms) flagArgs.push("--add-kms", opts.addKms);
14655
+ if (opts.rmKms) flagArgs.push("--rm-kms", opts.rmKms);
14656
+ if (opts.addGcpKms) flagArgs.push("--add-gcp-kms", opts.addGcpKms);
14657
+ if (opts.rmGcpKms) flagArgs.push("--rm-gcp-kms", opts.rmGcpKms);
14658
+ if (opts.addAzureKv) flagArgs.push("--add-azure-kv", opts.addAzureKv);
14659
+ if (opts.rmAzureKv) flagArgs.push("--rm-azure-kv", opts.rmAzureKv);
14660
+ if (opts.addPgp) flagArgs.push("--add-pgp", opts.addPgp);
14661
+ if (opts.rmPgp) flagArgs.push("--rm-pgp", opts.rmPgp);
14662
+ let result;
14663
+ try {
14664
+ result = await this.runner.run(
14665
+ this.sopsCommand,
14666
+ [
14667
+ "--config",
14668
+ nullConfigPath(),
14669
+ "rotate",
14670
+ ...this.keyserviceArgs,
14671
+ ...flagArgs,
14672
+ "--input-type",
14673
+ ctx.format,
14674
+ "--output-type",
14675
+ ctx.format,
14676
+ pipe.inputArg
14677
+ ],
14678
+ {
14679
+ ...pipe.runnerStdin !== void 0 ? { stdin: pipe.runnerStdin } : {},
14680
+ ...env ? { env } : {}
14681
+ }
14682
+ );
14683
+ } finally {
14684
+ pipe.cleanup();
14685
+ }
14686
+ if (result.exitCode !== 0) {
14687
+ throw new SopsEncryptionError(`Failed to rotate cell: ${result.stderr.trim()}`);
14688
+ }
14689
+ return result.stdout;
14690
+ }
14691
+ /**
14692
+ * {@link EncryptionBackend.getMetadata} — extract SOPS metadata from a
14693
+ * ciphertext blob without decrypting. Pure parser, no IO, no
14694
+ * subprocess.
14695
+ */
14696
+ getMetadata(content) {
14697
+ return this.parseMetadataFromContent(content, "<cell>");
14698
+ }
14699
+ /**
14700
+ * {@link EncryptionBackend.validateEncryption} — whether `content` is a
14701
+ * valid SOPS-encrypted blob (parses + has the `sops:` metadata
14702
+ * block). Never throws.
14703
+ */
14704
+ validateEncryption(content) {
14705
+ try {
14706
+ this.parseMetadataFromContent(content, "<cell>");
14707
+ return true;
14708
+ } catch {
14709
+ return false;
14710
+ }
14711
+ }
14712
+ /**
14713
+ * Blob-shaped variant of `classifyDecryptError`. Same logic as the
14714
+ * file-path version but reads metadata from the in-memory ciphertext
14715
+ * instead of disk.
14716
+ */
14717
+ async classifyDecryptErrorFromContent(content) {
14718
+ let metadata;
14719
+ try {
14720
+ metadata = this.parseMetadataFromContent(content, "<cell>");
14721
+ } catch {
14722
+ return "other";
14723
+ }
14724
+ if (metadata.backend !== "age") return "other";
14725
+ if (!this.ageKey && !this.ageKeyFile) return "key-not-found";
14726
+ let keyContent;
14727
+ try {
14728
+ keyContent = this.ageKey ?? fs14.readFileSync(this.ageKeyFile, "utf-8");
14729
+ } catch {
14730
+ return "key-not-found";
14731
+ }
14732
+ const privateKeys = keyContent.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("AGE-SECRET-KEY-"));
14733
+ if (privateKeys.length === 0) return "key-not-found";
14734
+ try {
14735
+ const publicKeys = await Promise.all(privateKeys.map((k) => deriveAgePublicKey(k)));
14736
+ const recipients = new Set(metadata.recipients);
14737
+ return publicKeys.some((pk) => recipients.has(pk)) ? "other" : "key-not-found";
14738
+ } catch {
14739
+ return "other";
14740
+ }
14741
+ }
14824
14742
  };
14825
14743
 
14744
+ // src/sops/linux-stdin-fifo.ts
14745
+ var os = __toESM(require("os"));
14746
+ var path11 = __toESM(require("path"));
14747
+ var import_child_process = require("child_process");
14748
+ function shouldUseLinuxStdinFifo() {
14749
+ return process.platform === "linux" && !process.env.JEST_WORKER_ID;
14750
+ }
14751
+ function wrapWithLinuxStdinFifo(runner) {
14752
+ if (!shouldUseLinuxStdinFifo()) return runner;
14753
+ return {
14754
+ run: (cmd, args, opts) => {
14755
+ const stdinIdx = args.indexOf("/dev/stdin");
14756
+ if (stdinIdx < 0 || opts?.stdin === void 0) {
14757
+ return runner.run(cmd, args, opts);
14758
+ }
14759
+ const fifoDir = (0, import_child_process.execFileSync)("mktemp", ["-d", path11.join(os.tmpdir(), "clef-fifo-XXXXXX")]).toString().trim();
14760
+ const fifoPath = path11.join(fifoDir, "input");
14761
+ (0, import_child_process.execFileSync)("mkfifo", [fifoPath]);
14762
+ const writer = (0, import_child_process.spawn)("dd", [`of=${fifoPath}`, "status=none"], {
14763
+ stdio: ["pipe", "ignore", "ignore"]
14764
+ });
14765
+ writer.stdin.write(opts.stdin);
14766
+ writer.stdin.end();
14767
+ const patchedArgs = [...args];
14768
+ patchedArgs[stdinIdx] = fifoPath;
14769
+ const { stdin: _stdin, ...restOpts } = opts;
14770
+ return runner.run(cmd, patchedArgs, restOpts).finally(() => {
14771
+ try {
14772
+ writer.kill();
14773
+ } catch {
14774
+ }
14775
+ try {
14776
+ (0, import_child_process.execFileSync)("rm", ["-rf", fifoDir]);
14777
+ } catch {
14778
+ }
14779
+ });
14780
+ }
14781
+ };
14782
+ }
14783
+
14826
14784
  // src/hsm/bundled.ts
14827
14785
  var fs15 = __toESM(require("fs"));
14828
- var path13 = __toESM(require("path"));
14786
+ var path12 = __toESM(require("path"));
14829
14787
  function tryBundledKeyservice() {
14830
14788
  const platform = process.platform;
14831
14789
  const arch = process.arch;
@@ -14837,8 +14795,8 @@ function tryBundledKeyservice() {
14837
14795
  const binName = "clef-keyservice";
14838
14796
  try {
14839
14797
  const packageMain = require.resolve(`${packageName}/package.json`);
14840
- const packageDir = path13.dirname(packageMain);
14841
- const binPath = path13.join(packageDir, "bin", binName);
14798
+ const packageDir = path12.dirname(packageMain);
14799
+ const binPath = path12.join(packageDir, "bin", binName);
14842
14800
  return fs15.existsSync(binPath) ? binPath : null;
14843
14801
  } catch {
14844
14802
  return null;
@@ -14847,9 +14805,9 @@ function tryBundledKeyservice() {
14847
14805
 
14848
14806
  // src/hsm/resolver.ts
14849
14807
  var fs16 = __toESM(require("fs"));
14850
- var path14 = __toESM(require("path"));
14808
+ var path13 = __toESM(require("path"));
14851
14809
  function validateKeyservicePath(candidate) {
14852
- if (!path14.isAbsolute(candidate)) {
14810
+ if (!path13.isAbsolute(candidate)) {
14853
14811
  throw new Error(`CLEF_KEYSERVICE_PATH must be an absolute path, got '${candidate}'.`);
14854
14812
  }
14855
14813
  const segments = candidate.split(/[/\\]/);
@@ -14884,7 +14842,7 @@ function resetKeyserviceResolution() {
14884
14842
  }
14885
14843
 
14886
14844
  // src/hsm/keyservice.ts
14887
- var import_child_process = require("child_process");
14845
+ var import_child_process2 = require("child_process");
14888
14846
  var readline = __toESM(require("readline"));
14889
14847
  var PORT_REGEX = /^PORT=(\d+)$/;
14890
14848
  var STARTUP_TIMEOUT_MS = 5e3;
@@ -14902,7 +14860,7 @@ async function spawnKeyservice(options) {
14902
14860
  ...options.pin ? { CLEF_PKCS11_PIN: options.pin } : {},
14903
14861
  ...options.pinFile ? { CLEF_PKCS11_PIN_FILE: options.pinFile } : {}
14904
14862
  };
14905
- const child = (0, import_child_process.spawn)(options.binaryPath, args, {
14863
+ const child = (0, import_child_process2.spawn)(options.binaryPath, args, {
14906
14864
  stdio: ["ignore", "pipe", "pipe"],
14907
14865
  env: childEnv
14908
14866
  });
@@ -14978,16 +14936,16 @@ function killGracefully(child) {
14978
14936
  }
14979
14937
 
14980
14938
  // src/lint/runner.ts
14981
- var path15 = __toESM(require("path"));
14939
+ var path14 = __toESM(require("path"));
14982
14940
  var LintRunner = class {
14983
- constructor(matrixManager, schemaValidator, sopsClient) {
14941
+ constructor(matrixManager, schemaValidator, source) {
14984
14942
  this.matrixManager = matrixManager;
14985
14943
  this.schemaValidator = schemaValidator;
14986
- this.sopsClient = sopsClient;
14944
+ this.source = source;
14987
14945
  }
14988
14946
  matrixManager;
14989
14947
  schemaValidator;
14990
- sopsClient;
14948
+ source;
14991
14949
  /**
14992
14950
  * Lint the entire matrix: check missing files, schema errors, SOPS integrity,
14993
14951
  * single-recipient warnings, and cross-environment key drift.
@@ -15014,8 +14972,9 @@ var LintRunner = class {
15014
14972
  fileCount = existingCells.length;
15015
14973
  const namespaceKeys = {};
15016
14974
  for (const cell of existingCells) {
14975
+ const ref = { namespace: cell.namespace, environment: cell.environment };
15017
14976
  try {
15018
- const isValid = await this.sopsClient.validateEncryption(cell.filePath);
14977
+ const isValid = await this.source.validateEncryption(ref);
15019
14978
  if (!isValid) {
15020
14979
  issues.push({
15021
14980
  severity: "error",
@@ -15036,7 +14995,7 @@ var LintRunner = class {
15036
14995
  continue;
15037
14996
  }
15038
14997
  try {
15039
- const decrypted = await this.sopsClient.decrypt(cell.filePath);
14998
+ const decrypted = await this.source.readCell(ref);
15040
14999
  const keys = Object.keys(decrypted.values);
15041
15000
  if (!namespaceKeys[cell.namespace]) {
15042
15001
  namespaceKeys[cell.namespace] = {};
@@ -15081,7 +15040,7 @@ var LintRunner = class {
15081
15040
  }
15082
15041
  const ns = manifest.namespaces.find((n) => n.name === cell.namespace);
15083
15042
  if (ns?.schema) {
15084
- const schemaPath = path15.join(repoRoot, ns.schema);
15043
+ const schemaPath = path14.join(repoRoot, ns.schema);
15085
15044
  try {
15086
15045
  const schema = this.schemaValidator.loadSchema(schemaPath);
15087
15046
  const result = this.schemaValidator.validate(decrypted.values, schema);
@@ -15124,7 +15083,8 @@ var LintRunner = class {
15124
15083
  }
15125
15084
  }
15126
15085
  try {
15127
- const pendingKeys = await getPendingKeys(cell.filePath);
15086
+ const meta = await this.source.getPendingMetadata(ref);
15087
+ const pendingKeys = meta.pending.map((p) => p.key);
15128
15088
  pendingCount += pendingKeys.length;
15129
15089
  for (const pendingKey of pendingKeys) {
15130
15090
  issues.push({
@@ -15177,7 +15137,6 @@ var LintRunner = class {
15177
15137
  const siIssues = await this.lintServiceIdentities(
15178
15138
  manifest.service_identities,
15179
15139
  manifest,
15180
- repoRoot,
15181
15140
  existingCells
15182
15141
  );
15183
15142
  issues.push(...siIssues);
@@ -15187,18 +15146,27 @@ var LintRunner = class {
15187
15146
  return { issues, fileCount: fileCount + missingCells.length, pendingCount };
15188
15147
  }
15189
15148
  /**
15190
- * Cross-reference `.clef-meta.yaml` against the cipher's plaintext key
15149
+ * Cross-reference cell metadata against the cipher's plaintext key
15191
15150
  * names for each existing cell. Reports orphan rotation records and
15192
- * dual-state (pending + rotation) inconsistencies. Uses
15193
- * {@link readSopsKeyNames} (plaintext YAML parse) — no decryption.
15151
+ * dual-state (pending + rotation) inconsistencies. Uses the source's
15152
+ * `listKeys` (no decryption).
15194
15153
  */
15195
15154
  async lintMetadataConsistency(cells) {
15196
15155
  const issues = [];
15197
15156
  for (const cell of cells) {
15198
- const keysInCipher = readSopsKeyNames(cell.filePath);
15199
- if (keysInCipher === null) continue;
15200
- const cipherKeys = new Set(keysInCipher);
15201
- const metadata = await loadMetadata(cell.filePath);
15157
+ const ref = { namespace: cell.namespace, environment: cell.environment };
15158
+ let cipherKeys;
15159
+ try {
15160
+ cipherKeys = new Set(await this.source.listKeys(ref));
15161
+ } catch {
15162
+ continue;
15163
+ }
15164
+ let metadata;
15165
+ try {
15166
+ metadata = await this.source.getPendingMetadata(ref);
15167
+ } catch {
15168
+ continue;
15169
+ }
15202
15170
  for (const record of metadata.rotations) {
15203
15171
  if (!cipherKeys.has(record.key)) {
15204
15172
  issues.push({
@@ -15229,7 +15197,7 @@ var LintRunner = class {
15229
15197
  /**
15230
15198
  * Lint service identity configurations for drift issues.
15231
15199
  */
15232
- async lintServiceIdentities(identities, manifest, repoRoot, existingCells) {
15200
+ async lintServiceIdentities(identities, manifest, existingCells) {
15233
15201
  const issues = [];
15234
15202
  const declaredEnvNames = new Set(manifest.environments.map((e) => e.name));
15235
15203
  const declaredNsNames = new Set(manifest.namespaces.map((ns) => ns.name));
@@ -15270,9 +15238,10 @@ var LintRunner = class {
15270
15238
  const envConfig = si.environments[cell.environment];
15271
15239
  if (!envConfig) continue;
15272
15240
  if (!envConfig.recipient) continue;
15241
+ const ref = { namespace: cell.namespace, environment: cell.environment };
15273
15242
  if (si.namespaces.includes(cell.namespace)) {
15274
15243
  try {
15275
- const metadata = await this.sopsClient.getMetadata(cell.filePath);
15244
+ const metadata = await this.source.getCellMetadata(ref);
15276
15245
  if (!metadata.recipients.includes(envConfig.recipient)) {
15277
15246
  issues.push({
15278
15247
  severity: "warning",
@@ -15286,7 +15255,7 @@ var LintRunner = class {
15286
15255
  }
15287
15256
  } else {
15288
15257
  try {
15289
- const metadata = await this.sopsClient.getMetadata(cell.filePath);
15258
+ const metadata = await this.source.getCellMetadata(ref);
15290
15259
  if (metadata.recipients.includes(envConfig.recipient)) {
15291
15260
  issues.push({
15292
15261
  severity: "warning",
@@ -15312,7 +15281,10 @@ var LintRunner = class {
15312
15281
  async fix(manifest, repoRoot) {
15313
15282
  const missingCells = this.matrixManager.detectMissingCells(manifest, repoRoot);
15314
15283
  for (const cell of missingCells) {
15315
- await this.matrixManager.scaffoldCell(cell, this.sopsClient, manifest);
15284
+ await this.source.scaffoldCell(
15285
+ { namespace: cell.namespace, environment: cell.environment },
15286
+ manifest
15287
+ );
15316
15288
  }
15317
15289
  return this.run(manifest, repoRoot);
15318
15290
  }
@@ -15367,15 +15339,12 @@ Use 'clef exec' to inject secrets directly into a process, or 'clef export --for
15367
15339
  }
15368
15340
  };
15369
15341
 
15370
- // src/import/index.ts
15371
- var path17 = __toESM(require("path"));
15372
-
15373
15342
  // src/import/parsers.ts
15374
- var path16 = __toESM(require("path"));
15343
+ var path15 = __toESM(require("path"));
15375
15344
  var YAML9 = __toESM(require("yaml"));
15376
15345
  function detectFormat(filePath, content) {
15377
- const base = path16.basename(filePath);
15378
- const ext = path16.extname(filePath).toLowerCase();
15346
+ const base = path15.basename(filePath);
15347
+ const ext = path15.extname(filePath).toLowerCase();
15379
15348
  if (base === ".env" || base.startsWith(".env.")) {
15380
15349
  return "dotenv";
15381
15350
  }
@@ -15525,11 +15494,11 @@ function parse9(content, format, filePath) {
15525
15494
 
15526
15495
  // src/import/index.ts
15527
15496
  var ImportRunner = class {
15528
- constructor(sopsClient, tx) {
15529
- this.sopsClient = sopsClient;
15497
+ constructor(source, tx) {
15498
+ this.source = source;
15530
15499
  this.tx = tx;
15531
15500
  }
15532
- sopsClient;
15501
+ source;
15533
15502
  tx;
15534
15503
  /**
15535
15504
  * Parse a source file and import its key/value pairs into a target `namespace/environment` cell.
@@ -15543,10 +15512,8 @@ var ImportRunner = class {
15543
15512
  */
15544
15513
  async import(target, sourcePath, content, manifest, repoRoot, options) {
15545
15514
  const [ns, env] = target.split("/");
15546
- const filePath = path17.join(
15547
- repoRoot,
15548
- manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
15549
- );
15515
+ const ref = { namespace: ns, environment: env };
15516
+ const relCellPath = manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env);
15550
15517
  const parsed = parse9(content, options.format ?? "auto", sourcePath ?? "");
15551
15518
  let candidates = Object.entries(parsed.pairs);
15552
15519
  if (options.prefix) {
@@ -15564,7 +15531,7 @@ var ImportRunner = class {
15564
15531
  if (options.dryRun) {
15565
15532
  let existingKeys;
15566
15533
  try {
15567
- const decrypted2 = await this.sopsClient.decrypt(filePath);
15534
+ const decrypted2 = await this.source.readCell(ref);
15568
15535
  existingKeys = new Set(Object.keys(decrypted2.values));
15569
15536
  } catch {
15570
15537
  existingKeys = /* @__PURE__ */ new Set();
@@ -15578,7 +15545,7 @@ var ImportRunner = class {
15578
15545
  }
15579
15546
  return { imported, skipped, failed, warnings, dryRun: true };
15580
15547
  }
15581
- const decrypted = await this.sopsClient.decrypt(filePath);
15548
+ const decrypted = await this.source.readCell(ref);
15582
15549
  const newValues = { ...decrypted.values };
15583
15550
  const rotatedKeys = [];
15584
15551
  for (const [key, value] of candidates) {
@@ -15595,7 +15562,6 @@ var ImportRunner = class {
15595
15562
  if (imported.length === 0) {
15596
15563
  return { imported, skipped, failed, warnings, dryRun: false };
15597
15564
  }
15598
- const relCellPath = path17.relative(repoRoot, filePath);
15599
15565
  const relMetaPath = relCellPath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml");
15600
15566
  await this.tx.run(repoRoot, {
15601
15567
  description: `clef import ${target}: ${imported.length} key(s)`,
@@ -15603,9 +15569,9 @@ var ImportRunner = class {
15603
15569
  // callback are staged and rolled back atomically with the ciphertext.
15604
15570
  paths: [relCellPath, relMetaPath],
15605
15571
  mutate: async () => {
15606
- await this.sopsClient.encrypt(filePath, newValues, manifest, env);
15572
+ await this.source.writeCell(ref, newValues);
15607
15573
  if (options.rotatedBy && rotatedKeys.length > 0) {
15608
- await recordRotation(filePath, rotatedKeys, options.rotatedBy);
15574
+ await this.source.recordRotation(ref, rotatedKeys, options.rotatedBy);
15609
15575
  }
15610
15576
  }
15611
15577
  });
@@ -15614,7 +15580,7 @@ var ImportRunner = class {
15614
15580
  };
15615
15581
 
15616
15582
  // src/recipients/index.ts
15617
- var path18 = __toESM(require("path"));
15583
+ var path16 = __toESM(require("path"));
15618
15584
  function parseRecipientEntry(entry) {
15619
15585
  if (typeof entry === "string") {
15620
15586
  return { key: entry };
@@ -15682,12 +15648,12 @@ function ensureEnvironmentRecipientsArray(doc, envName) {
15682
15648
  return env.recipients;
15683
15649
  }
15684
15650
  var RecipientManager = class {
15685
- constructor(encryption, matrixManager, tx) {
15686
- this.encryption = encryption;
15651
+ constructor(source, matrixManager, tx) {
15652
+ this.source = source;
15687
15653
  this.matrixManager = matrixManager;
15688
15654
  this.tx = tx;
15689
15655
  }
15690
- encryption;
15656
+ source;
15691
15657
  matrixManager;
15692
15658
  tx;
15693
15659
  /**
@@ -15742,7 +15708,7 @@ var RecipientManager = class {
15742
15708
  const reEncryptedFiles = [];
15743
15709
  await this.tx.run(repoRoot, {
15744
15710
  description: environment ? `clef recipients add ${keyPreview(normalizedKey)} -e ${environment}` : `clef recipients add ${keyPreview(normalizedKey)}`,
15745
- paths: [...cells.map((c) => path18.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
15711
+ paths: [...cells.map((c) => path16.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
15746
15712
  mutate: async () => {
15747
15713
  const doc = readManifestYaml(repoRoot);
15748
15714
  const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
@@ -15753,7 +15719,8 @@ var RecipientManager = class {
15753
15719
  }
15754
15720
  writeManifestYaml(repoRoot, doc);
15755
15721
  for (const cell of cells) {
15756
- await this.encryption.addRecipient(cell.filePath, normalizedKey);
15722
+ const ref = { namespace: cell.namespace, environment: cell.environment };
15723
+ await this.source.rotate(ref, { addAge: normalizedKey });
15757
15724
  reEncryptedFiles.push(cell.filePath);
15758
15725
  }
15759
15726
  }
@@ -15801,7 +15768,7 @@ var RecipientManager = class {
15801
15768
  const reEncryptedFiles = [];
15802
15769
  await this.tx.run(repoRoot, {
15803
15770
  description: environment ? `clef recipients remove ${keyPreview(trimmedKey)} -e ${environment}` : `clef recipients remove ${keyPreview(trimmedKey)}`,
15804
- paths: [...cells.map((c) => path18.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
15771
+ paths: [...cells.map((c) => path16.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
15805
15772
  mutate: async () => {
15806
15773
  const doc = readManifestYaml(repoRoot);
15807
15774
  const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
@@ -15809,7 +15776,8 @@ var RecipientManager = class {
15809
15776
  recipients.splice(idx, 1);
15810
15777
  writeManifestYaml(repoRoot, doc);
15811
15778
  for (const cell of cells) {
15812
- await this.encryption.removeRecipient(cell.filePath, trimmedKey);
15779
+ const ref = { namespace: cell.namespace, environment: cell.environment };
15780
+ await this.source.rotate(ref, { rmAge: trimmedKey });
15813
15781
  reEncryptedFiles.push(cell.filePath);
15814
15782
  }
15815
15783
  }
@@ -15831,12 +15799,12 @@ var RecipientManager = class {
15831
15799
 
15832
15800
  // src/recipients/requests.ts
15833
15801
  var fs17 = __toESM(require("fs"));
15834
- var path19 = __toESM(require("path"));
15802
+ var path17 = __toESM(require("path"));
15835
15803
  var YAML10 = __toESM(require("yaml"));
15836
15804
  var REQUESTS_FILENAME = ".clef-requests.yaml";
15837
15805
  var HEADER_COMMENT2 = "# Pending recipient access requests. Approve with: clef recipients approve <label>\n";
15838
15806
  function requestsFilePath(repoRoot) {
15839
- return path19.join(repoRoot, REQUESTS_FILENAME);
15807
+ return path17.join(repoRoot, REQUESTS_FILENAME);
15840
15808
  }
15841
15809
  function loadRequests(repoRoot) {
15842
15810
  const filePath = requestsFilePath(repoRoot);
@@ -15911,7 +15879,7 @@ function findInList(requests, identifier) {
15911
15879
  }
15912
15880
 
15913
15881
  // src/drift/detector.ts
15914
- var path20 = __toESM(require("path"));
15882
+ var path18 = __toESM(require("path"));
15915
15883
  var DriftDetector = class {
15916
15884
  parser = new ManifestParser();
15917
15885
  matrix = new MatrixManager();
@@ -15924,8 +15892,8 @@ var DriftDetector = class {
15924
15892
  * @returns Drift result with any issues found.
15925
15893
  */
15926
15894
  detect(localRoot, remoteRoot, namespaceFilter) {
15927
- const localManifest = this.parser.parse(path20.join(localRoot, CLEF_MANIFEST_FILENAME));
15928
- const remoteManifest = this.parser.parse(path20.join(remoteRoot, CLEF_MANIFEST_FILENAME));
15895
+ const localManifest = this.parser.parse(path18.join(localRoot, CLEF_MANIFEST_FILENAME));
15896
+ const remoteManifest = this.parser.parse(path18.join(remoteRoot, CLEF_MANIFEST_FILENAME));
15929
15897
  const localCells = this.matrix.resolveMatrix(localManifest, localRoot);
15930
15898
  const remoteCells = this.matrix.resolveMatrix(remoteManifest, remoteRoot);
15931
15899
  const localEnvNames = localManifest.environments.map((e) => e.name);
@@ -15989,7 +15957,7 @@ var DriftDetector = class {
15989
15957
  };
15990
15958
 
15991
15959
  // src/report/generator.ts
15992
- var path21 = __toESM(require("path"));
15960
+ var path19 = __toESM(require("path"));
15993
15961
 
15994
15962
  // src/report/sanitizer.ts
15995
15963
  var ReportSanitizer = class {
@@ -16126,14 +16094,14 @@ var ReportSanitizer = class {
16126
16094
 
16127
16095
  // src/report/generator.ts
16128
16096
  var ReportGenerator = class {
16129
- constructor(runner, sopsClient, matrixManager, schemaValidator) {
16097
+ constructor(runner, source, matrixManager, schemaValidator) {
16130
16098
  this.runner = runner;
16131
- this.sopsClient = sopsClient;
16099
+ this.source = source;
16132
16100
  this.matrixManager = matrixManager;
16133
16101
  this.schemaValidator = schemaValidator;
16134
16102
  }
16135
16103
  runner;
16136
- sopsClient;
16104
+ source;
16137
16105
  matrixManager;
16138
16106
  schemaValidator;
16139
16107
  /**
@@ -16149,7 +16117,7 @@ var ReportGenerator = class {
16149
16117
  let manifest = null;
16150
16118
  try {
16151
16119
  const parser = new ManifestParser();
16152
- manifest = parser.parse(path21.join(repoRoot, "clef.yaml"));
16120
+ manifest = parser.parse(path19.join(repoRoot, "clef.yaml"));
16153
16121
  } catch {
16154
16122
  const emptyManifest = {
16155
16123
  manifestVersion: 0,
@@ -16270,16 +16238,17 @@ var ReportGenerator = class {
16270
16238
  metadata: null
16271
16239
  };
16272
16240
  }
16241
+ const ref = { namespace: cell.namespace, environment: cell.environment };
16273
16242
  const keyCount = this.readKeyCount(cell.filePath);
16274
16243
  let pendingCount = 0;
16275
16244
  try {
16276
- const pending = await getPendingKeys(cell.filePath);
16277
- pendingCount = pending.length;
16245
+ const meta = await this.source.getPendingMetadata(ref);
16246
+ pendingCount = meta.pending.length;
16278
16247
  } catch {
16279
16248
  }
16280
16249
  let metadata = null;
16281
16250
  try {
16282
- const sopsMetadata = await this.sopsClient.getMetadata(cell.filePath);
16251
+ const sopsMetadata = await this.source.getCellMetadata(ref);
16283
16252
  metadata = {
16284
16253
  backend: sopsMetadata.backend,
16285
16254
  recipients: sopsMetadata.recipients,
@@ -16302,7 +16271,7 @@ var ReportGenerator = class {
16302
16271
  }
16303
16272
  async buildPolicy(manifest, repoRoot) {
16304
16273
  try {
16305
- const lintRunner = new LintRunner(this.matrixManager, this.schemaValidator, this.sopsClient);
16274
+ const lintRunner = new LintRunner(this.matrixManager, this.schemaValidator, this.source);
16306
16275
  const lintResult = await lintRunner.run(manifest, repoRoot);
16307
16276
  return new ReportSanitizer().sanitize(lintResult.issues);
16308
16277
  } catch {
@@ -16619,9 +16588,9 @@ var SopsMergeDriver = class {
16619
16588
  */
16620
16589
  async mergeFiles(basePath, oursPath, theirsPath) {
16621
16590
  const [baseDecrypted, oursDecrypted, theirsDecrypted] = await Promise.all([
16622
- this.sopsClient.decrypt(basePath),
16623
- this.sopsClient.decrypt(oursPath),
16624
- this.sopsClient.decrypt(theirsPath)
16591
+ this.sopsClient.decryptFile(basePath),
16592
+ this.sopsClient.decryptFile(oursPath),
16593
+ this.sopsClient.decryptFile(theirsPath)
16625
16594
  ]);
16626
16595
  return this.merge(baseDecrypted.values, oursDecrypted.values, theirsDecrypted.values);
16627
16596
  }
@@ -16738,22 +16707,26 @@ function mergeMetadataFiles(_basePath, oursPath, theirsPath) {
16738
16707
  }
16739
16708
 
16740
16709
  // src/service-identity/manager.ts
16741
- var path22 = __toESM(require("path"));
16710
+ var path20 = __toESM(require("path"));
16742
16711
  var ServiceIdentityManager = class {
16743
- constructor(encryption, matrixManager, tx) {
16744
- this.encryption = encryption;
16712
+ constructor(source, matrixManager, tx) {
16713
+ this.source = source;
16745
16714
  this.matrixManager = matrixManager;
16746
16715
  this.tx = tx;
16747
16716
  }
16748
- encryption;
16717
+ source;
16749
16718
  matrixManager;
16750
16719
  tx;
16720
+ /** Helper: cell → ref for the source seam. */
16721
+ ref(cell) {
16722
+ return { namespace: cell.namespace, environment: cell.environment };
16723
+ }
16751
16724
  /**
16752
16725
  * Compute repo-relative paths for a set of cells plus the manifest. Used
16753
16726
  * to seed TransactionManager.run's `paths` argument.
16754
16727
  */
16755
16728
  txPaths(repoRoot, cells) {
16756
- return [...cells.map((c) => path22.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME];
16729
+ return [...cells.map((c) => path20.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME];
16757
16730
  }
16758
16731
  /**
16759
16732
  * Create a new service identity with per-environment age key pairs or KMS envelope config.
@@ -16845,7 +16818,7 @@ var ServiceIdentityManager = class {
16845
16818
  if (!envConfig?.recipient) continue;
16846
16819
  if (isKmsEnvelope(envConfig)) continue;
16847
16820
  try {
16848
- await this.encryption.removeRecipient(cell.filePath, envConfig.recipient);
16821
+ await this.source.rotate(this.ref(cell), { rmAge: envConfig.recipient });
16849
16822
  } catch {
16850
16823
  }
16851
16824
  }
@@ -16895,7 +16868,7 @@ var ServiceIdentityManager = class {
16895
16868
  const scopedCells = cells.filter((c) => c.environment === envName);
16896
16869
  for (const cell of scopedCells) {
16897
16870
  try {
16898
- await this.encryption.removeRecipient(cell.filePath, oldConfig.recipient);
16871
+ await this.source.rotate(this.ref(cell), { rmAge: oldConfig.recipient });
16899
16872
  } catch {
16900
16873
  }
16901
16874
  }
@@ -16922,7 +16895,7 @@ var ServiceIdentityManager = class {
16922
16895
  if (isKmsEnvelope(envConfig)) continue;
16923
16896
  if (!envConfig.recipient) continue;
16924
16897
  try {
16925
- await this.encryption.addRecipient(cell.filePath, envConfig.recipient);
16898
+ await this.source.rotate(this.ref(cell), { addAge: envConfig.recipient });
16926
16899
  } catch (err) {
16927
16900
  const message = err instanceof Error ? err.message : String(err);
16928
16901
  if (!message.includes("already")) {
@@ -16970,7 +16943,7 @@ var ServiceIdentityManager = class {
16970
16943
  if (isKmsEnvelope(envConfig)) continue;
16971
16944
  if (!envConfig.recipient) continue;
16972
16945
  try {
16973
- await this.encryption.addRecipient(cell.filePath, envConfig.recipient);
16946
+ await this.source.rotate(this.ref(cell), { addAge: envConfig.recipient });
16974
16947
  affectedFiles.push(cell.filePath);
16975
16948
  } catch (err) {
16976
16949
  const message = err instanceof Error ? err.message : String(err);
@@ -17031,7 +17004,7 @@ var ServiceIdentityManager = class {
17031
17004
  if (isKmsEnvelope(envConfig)) continue;
17032
17005
  if (!envConfig.recipient) continue;
17033
17006
  try {
17034
- await this.encryption.removeRecipient(cell.filePath, envConfig.recipient);
17007
+ await this.source.rotate(this.ref(cell), { rmAge: envConfig.recipient });
17035
17008
  affectedFiles.push(cell.filePath);
17036
17009
  } catch {
17037
17010
  }
@@ -17100,7 +17073,7 @@ var ServiceIdentityManager = class {
17100
17073
  if (!identity.pack_only && !isKmsEnvelope(envConfig) && envConfig.recipient) {
17101
17074
  for (const cell of cells) {
17102
17075
  try {
17103
- await this.encryption.addRecipient(cell.filePath, envConfig.recipient);
17076
+ await this.source.rotate(this.ref(cell), { addAge: envConfig.recipient });
17104
17077
  } catch (err) {
17105
17078
  const message = err instanceof Error ? err.message : String(err);
17106
17079
  if (!message.includes("already")) {
@@ -17177,10 +17150,10 @@ var ServiceIdentityManager = class {
17177
17150
  const scopedCells = cells.filter((c) => c.environment === envName);
17178
17151
  for (const cell of scopedCells) {
17179
17152
  try {
17180
- await this.encryption.removeRecipient(cell.filePath, oldRecipient);
17153
+ await this.source.rotate(this.ref(cell), { rmAge: oldRecipient });
17181
17154
  } catch {
17182
17155
  }
17183
- await this.encryption.addRecipient(cell.filePath, newPublicKey);
17156
+ await this.source.rotate(this.ref(cell), { addAge: newPublicKey });
17184
17157
  }
17185
17158
  }
17186
17159
  }
@@ -17239,7 +17212,7 @@ var ServiceIdentityManager = class {
17239
17212
  if (!envConfig.recipient) continue;
17240
17213
  if (si.namespaces.includes(cell.namespace)) {
17241
17214
  try {
17242
- const metadata = await this.encryption.getMetadata(cell.filePath);
17215
+ const metadata = await this.source.getCellMetadata(this.ref(cell));
17243
17216
  if (!metadata.recipients.includes(envConfig.recipient)) {
17244
17217
  issues.push({
17245
17218
  identity: si.name,
@@ -17254,7 +17227,7 @@ var ServiceIdentityManager = class {
17254
17227
  }
17255
17228
  } else {
17256
17229
  try {
17257
- const metadata = await this.encryption.getMetadata(cell.filePath);
17230
+ const metadata = await this.source.getCellMetadata(this.ref(cell));
17258
17231
  if (metadata.recipients.includes(envConfig.recipient)) {
17259
17232
  issues.push({
17260
17233
  identity: si.name,
@@ -17276,15 +17249,15 @@ var ServiceIdentityManager = class {
17276
17249
 
17277
17250
  // src/structure/manager.ts
17278
17251
  var fs19 = __toESM(require("fs"));
17279
- var path23 = __toESM(require("path"));
17252
+ var path21 = __toESM(require("path"));
17280
17253
  var StructureManager = class {
17281
- constructor(matrixManager, encryption, tx) {
17254
+ constructor(matrixManager, buildSource, tx) {
17282
17255
  this.matrixManager = matrixManager;
17283
- this.encryption = encryption;
17256
+ this.buildSource = buildSource;
17284
17257
  this.tx = tx;
17285
17258
  }
17286
17259
  matrixManager;
17287
- encryption;
17260
+ buildSource;
17288
17261
  tx;
17289
17262
  // ── add ──────────────────────────────────────────────────────────────────
17290
17263
  /**
@@ -17300,7 +17273,7 @@ var StructureManager = class {
17300
17273
  this.assertValidIdentifier("namespace", name);
17301
17274
  const newCellPaths = manifest.environments.map((env) => ({
17302
17275
  environment: env.name,
17303
- filePath: path23.join(
17276
+ filePath: path21.join(
17304
17277
  repoRoot,
17305
17278
  manifest.file_pattern.replace("{namespace}", name).replace("{environment}", env.name)
17306
17279
  )
@@ -17308,7 +17281,7 @@ var StructureManager = class {
17308
17281
  for (const cell of newCellPaths) {
17309
17282
  if (fs19.existsSync(cell.filePath)) {
17310
17283
  throw new Error(
17311
- `Cannot add namespace '${name}': file '${path23.relative(repoRoot, cell.filePath)}' already exists.`
17284
+ `Cannot add namespace '${name}': file '${path21.relative(repoRoot, cell.filePath)}' already exists.`
17312
17285
  );
17313
17286
  }
17314
17287
  }
@@ -17327,21 +17300,14 @@ var StructureManager = class {
17327
17300
  await this.tx.run(repoRoot, {
17328
17301
  description: `clef namespace add ${name}`,
17329
17302
  paths: [
17330
- ...newCellPaths.map((c) => path23.relative(repoRoot, c.filePath)),
17303
+ ...newCellPaths.map((c) => path21.relative(repoRoot, c.filePath)),
17331
17304
  CLEF_MANIFEST_FILENAME
17332
17305
  ],
17333
17306
  mutate: async () => {
17307
+ const source = this.buildSource(updatedManifest);
17334
17308
  for (const cell of newCellPaths) {
17335
- await this.matrixManager.scaffoldCell(
17336
- {
17337
- namespace: name,
17338
- environment: cell.environment,
17339
- filePath: cell.filePath,
17340
- exists: false
17341
- },
17342
- this.encryption,
17343
- updatedManifest
17344
- );
17309
+ const ref = { namespace: name, environment: cell.environment };
17310
+ await source.scaffoldCell(ref, updatedManifest);
17345
17311
  }
17346
17312
  const doc = readManifestYaml(repoRoot);
17347
17313
  const namespaces = doc.namespaces;
@@ -17372,7 +17338,7 @@ var StructureManager = class {
17372
17338
  this.assertValidIdentifier("environment", name);
17373
17339
  const newCellPaths = manifest.namespaces.map((ns) => ({
17374
17340
  namespace: ns.name,
17375
- filePath: path23.join(
17341
+ filePath: path21.join(
17376
17342
  repoRoot,
17377
17343
  manifest.file_pattern.replace("{namespace}", ns.name).replace("{environment}", name)
17378
17344
  )
@@ -17380,7 +17346,7 @@ var StructureManager = class {
17380
17346
  for (const cell of newCellPaths) {
17381
17347
  if (fs19.existsSync(cell.filePath)) {
17382
17348
  throw new Error(
17383
- `Cannot add environment '${name}': file '${path23.relative(repoRoot, cell.filePath)}' already exists.`
17349
+ `Cannot add environment '${name}': file '${path21.relative(repoRoot, cell.filePath)}' already exists.`
17384
17350
  );
17385
17351
  }
17386
17352
  }
@@ -17399,21 +17365,14 @@ var StructureManager = class {
17399
17365
  await this.tx.run(repoRoot, {
17400
17366
  description: `clef env add ${name}`,
17401
17367
  paths: [
17402
- ...newCellPaths.map((c) => path23.relative(repoRoot, c.filePath)),
17368
+ ...newCellPaths.map((c) => path21.relative(repoRoot, c.filePath)),
17403
17369
  CLEF_MANIFEST_FILENAME
17404
17370
  ],
17405
17371
  mutate: async () => {
17372
+ const source = this.buildSource(updatedManifest);
17406
17373
  for (const cell of newCellPaths) {
17407
- await this.matrixManager.scaffoldCell(
17408
- {
17409
- namespace: cell.namespace,
17410
- environment: name,
17411
- filePath: cell.filePath,
17412
- exists: false
17413
- },
17414
- this.encryption,
17415
- updatedManifest
17416
- );
17374
+ const ref = { namespace: cell.namespace, environment: name };
17375
+ await source.scaffoldCell(ref, updatedManifest);
17417
17376
  }
17418
17377
  const doc = readManifestYaml(repoRoot);
17419
17378
  const environments = doc.environments;
@@ -17556,7 +17515,7 @@ var StructureManager = class {
17556
17515
  for (const pair of renamePairs) {
17557
17516
  if (fs19.existsSync(pair.to)) {
17558
17517
  throw new Error(
17559
- `Rename target '${path23.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
17518
+ `Rename target '${path21.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
17560
17519
  );
17561
17520
  }
17562
17521
  }
@@ -17599,7 +17558,7 @@ var StructureManager = class {
17599
17558
  for (const pair of renamePairs) {
17600
17559
  if (fs19.existsSync(pair.to)) {
17601
17560
  throw new Error(
17602
- `Rename target '${path23.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
17561
+ `Rename target '${path21.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
17603
17562
  );
17604
17563
  }
17605
17564
  }
@@ -17649,7 +17608,7 @@ var StructureManager = class {
17649
17608
  swapAxisInCellPath(repoRoot, manifest, cell, axis, newName) {
17650
17609
  const ns = axis === "namespace" ? newName : cell.namespace;
17651
17610
  const env = axis === "environment" ? newName : cell.environment;
17652
- return path23.join(
17611
+ return path21.join(
17653
17612
  repoRoot,
17654
17613
  manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
17655
17614
  );
@@ -17661,8 +17620,8 @@ var StructureManager = class {
17661
17620
  txPaths(repoRoot, renamePairs) {
17662
17621
  const paths = /* @__PURE__ */ new Set();
17663
17622
  for (const pair of renamePairs) {
17664
- paths.add(path23.relative(repoRoot, pair.from));
17665
- paths.add(path23.relative(repoRoot, pair.to));
17623
+ paths.add(path21.relative(repoRoot, pair.from));
17624
+ paths.add(path21.relative(repoRoot, pair.to));
17666
17625
  }
17667
17626
  paths.add(CLEF_MANIFEST_FILENAME);
17668
17627
  return [...paths];
@@ -17673,7 +17632,7 @@ var StructureManager = class {
17673
17632
  */
17674
17633
  applyRenames(pairs) {
17675
17634
  for (const pair of pairs) {
17676
- const targetDir = path23.dirname(pair.to);
17635
+ const targetDir = path21.dirname(pair.to);
17677
17636
  if (!fs19.existsSync(targetDir)) {
17678
17637
  fs19.mkdirSync(targetDir, { recursive: true });
17679
17638
  }
@@ -17688,10 +17647,10 @@ var StructureManager = class {
17688
17647
  deletePaths(repoRoot, cells) {
17689
17648
  const paths = /* @__PURE__ */ new Set();
17690
17649
  for (const cell of cells) {
17691
- paths.add(path23.relative(repoRoot, cell.filePath));
17650
+ paths.add(path21.relative(repoRoot, cell.filePath));
17692
17651
  const meta = cell.filePath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml");
17693
17652
  if (fs19.existsSync(meta)) {
17694
- paths.add(path23.relative(repoRoot, meta));
17653
+ paths.add(path21.relative(repoRoot, meta));
17695
17654
  }
17696
17655
  }
17697
17656
  paths.add(CLEF_MANIFEST_FILENAME);
@@ -17806,7 +17765,7 @@ function renameKeyPreservingOrder(obj, oldKey, newKey) {
17806
17765
  }
17807
17766
 
17808
17767
  // src/artifact/resolve.ts
17809
- async function resolveIdentitySecrets(identityName, environment, manifest, repoRoot, encryption, matrixManager) {
17768
+ async function resolveIdentitySecrets(identityName, environment, manifest, repoRoot, source, matrixManager) {
17810
17769
  const identity = manifest.service_identities?.find((si) => si.name === identityName);
17811
17770
  if (!identity) {
17812
17771
  throw new Error(`Service identity '${identityName}' not found in manifest.`);
@@ -17822,7 +17781,10 @@ async function resolveIdentitySecrets(identityName, environment, manifest, repoR
17822
17781
  (c) => c.exists && identity.namespaces.includes(c.namespace) && c.environment === environment
17823
17782
  );
17824
17783
  for (const cell of cells) {
17825
- const decrypted = await encryption.decrypt(cell.filePath);
17784
+ const decrypted = await source.readCell({
17785
+ namespace: cell.namespace,
17786
+ environment: cell.environment
17787
+ });
17826
17788
  const bucket = allValues[cell.namespace] ??= {};
17827
17789
  for (const [key, value] of Object.entries(decrypted.values)) {
17828
17790
  if (key in bucket && bucket[key] !== value) {
@@ -17846,14 +17808,14 @@ var crypto5 = __toESM(require("crypto"));
17846
17808
 
17847
17809
  // src/artifact/output.ts
17848
17810
  var fs20 = __toESM(require("fs"));
17849
- var path24 = __toESM(require("path"));
17811
+ var path22 = __toESM(require("path"));
17850
17812
  var FilePackOutput = class {
17851
17813
  constructor(outputPath) {
17852
17814
  this.outputPath = outputPath;
17853
17815
  }
17854
17816
  outputPath;
17855
17817
  async write(_artifact, json) {
17856
- const outputDir = path24.dirname(this.outputPath);
17818
+ const outputDir = path22.dirname(this.outputPath);
17857
17819
  if (!fs20.existsSync(outputDir)) {
17858
17820
  fs20.mkdirSync(outputDir, { recursive: true });
17859
17821
  }
@@ -17900,17 +17862,6 @@ function buildSigningPayload(artifact) {
17900
17862
  ];
17901
17863
  return Buffer.from(fields.join("\n"), "utf-8");
17902
17864
  }
17903
- function generateSigningKeyPair() {
17904
- const pair = crypto3.generateKeyPairSync("ed25519");
17905
- return {
17906
- publicKey: pair.publicKey.export({ type: "spki", format: "der" }).toString(
17907
- "base64"
17908
- ),
17909
- privateKey: pair.privateKey.export({ type: "pkcs8", format: "der" }).toString(
17910
- "base64"
17911
- )
17912
- };
17913
- }
17914
17865
  function signEd25519(payload, privateKeyBase64) {
17915
17866
  const keyObj = crypto3.createPrivateKey({
17916
17867
  key: Buffer.from(privateKeyBase64, "base64"),
@@ -17946,17 +17897,6 @@ function verifySignature(payload, signatureBase64, publicKeyBase64) {
17946
17897
  }
17947
17898
  throw new Error(`Unsupported key type for signature verification: ${keyType}`);
17948
17899
  }
17949
- function detectAlgorithm(publicKeyBase64) {
17950
- const keyObj = crypto3.createPublicKey({
17951
- key: Buffer.from(publicKeyBase64, "base64"),
17952
- format: "der",
17953
- type: "spki"
17954
- });
17955
- const keyType = keyObj.asymmetricKeyType;
17956
- if (keyType === "ed25519") return "Ed25519";
17957
- if (keyType === "ec") return "ECDSA_SHA256";
17958
- throw new Error(`Unsupported key type: ${keyType}`);
17959
- }
17960
17900
 
17961
17901
  // src/artifact/hash.ts
17962
17902
  var crypto4 = __toESM(require("crypto"));
@@ -17966,12 +17906,12 @@ function computeCiphertextHash(ciphertext) {
17966
17906
 
17967
17907
  // src/artifact/packer.ts
17968
17908
  var ArtifactPacker = class {
17969
- constructor(encryption, matrixManager, kms) {
17970
- this.encryption = encryption;
17909
+ constructor(source, matrixManager, kms) {
17910
+ this.source = source;
17971
17911
  this.matrixManager = matrixManager;
17972
17912
  this.kms = kms;
17973
17913
  }
17974
- encryption;
17914
+ source;
17975
17915
  matrixManager;
17976
17916
  kms;
17977
17917
  /**
@@ -17989,7 +17929,7 @@ var ArtifactPacker = class {
17989
17929
  config.environment,
17990
17930
  manifest,
17991
17931
  repoRoot,
17992
- this.encryption,
17932
+ this.source,
17993
17933
  this.matrixManager
17994
17934
  );
17995
17935
  const plaintext = JSON.stringify(resolved.values);
@@ -18374,11 +18314,7 @@ var JsonEnvelopeBackend = class {
18374
18314
  }
18375
18315
  async pack(req) {
18376
18316
  const opts = req.backendOptions;
18377
- const packer = new ArtifactPacker(
18378
- req.services.encryption,
18379
- new MatrixManager(),
18380
- req.services.kms
18381
- );
18317
+ const packer = new ArtifactPacker(req.services.source, new MatrixManager(), req.services.kms);
18382
18318
  const output = opts.output ?? (opts.outputPath ? new FilePackOutput(opts.outputPath) : void 0);
18383
18319
  const result = await packer.pack(
18384
18320
  {
@@ -18407,7 +18343,7 @@ var JsonEnvelopeBackend = class {
18407
18343
  var VALID_KMS_PROVIDERS = ["aws", "gcp", "azure"];
18408
18344
 
18409
18345
  // src/migration/backend.ts
18410
- var path25 = __toESM(require("path"));
18346
+ var path23 = __toESM(require("path"));
18411
18347
  var YAML12 = __toESM(require("yaml"));
18412
18348
  var BACKEND_KEY_FIELDS = {
18413
18349
  age: void 0,
@@ -18435,23 +18371,24 @@ function metadataMatchesTarget(meta, target) {
18435
18371
  }
18436
18372
  var BackendMigrator = class {
18437
18373
  /**
18438
- * @param encryption - Backend used for both decrypt and encrypt (standard case).
18374
+ * @param buildSource - Factory that builds a `SecretSource` bound to a
18375
+ * given manifest. Called twice during a real migration: once with the
18376
+ * pre-migration manifest (for classification + decrypt) and once with
18377
+ * the post-mutation manifest (for re-encrypt + verify). The factory
18378
+ * pattern is required because the encryption layer of a composed
18379
+ * source is bound to a manifest at construction.
18439
18380
  * @param matrixManager - Matrix resolver.
18440
18381
  * @param tx - Transaction manager that wraps the migration in a single git commit
18441
18382
  * so a partial failure rolls back ALL files + the manifest via `git reset --hard`.
18442
- * @param targetEncryption - Optional separate backend for encrypt. Use when migrating
18443
- * from cloud (decrypt via keyservice) to another backend (encrypt via local credentials).
18444
18383
  */
18445
- constructor(encryption, matrixManager, tx, targetEncryption) {
18384
+ constructor(buildSource, matrixManager, tx) {
18385
+ this.buildSource = buildSource;
18446
18386
  this.matrixManager = matrixManager;
18447
18387
  this.tx = tx;
18448
- this.decryptBackend = encryption;
18449
- this.encryptBackend = targetEncryption ?? encryption;
18450
18388
  }
18389
+ buildSource;
18451
18390
  matrixManager;
18452
18391
  tx;
18453
- decryptBackend;
18454
- encryptBackend;
18455
18392
  async migrate(manifest, repoRoot, options, onProgress) {
18456
18393
  const { target, environment, dryRun, skipVerify } = options;
18457
18394
  if (environment) {
@@ -18471,10 +18408,12 @@ var BackendMigrator = class {
18471
18408
  warnings: ["No encrypted files found to migrate."]
18472
18409
  };
18473
18410
  }
18411
+ const sourceBefore = this.buildSource(manifest);
18474
18412
  const toMigrate = [];
18475
18413
  const skippedFiles = [];
18476
18414
  for (const cell of targetCells) {
18477
- const meta = await this.decryptBackend.getMetadata(cell.filePath);
18415
+ const ref = { namespace: cell.namespace, environment: cell.environment };
18416
+ const meta = await sourceBefore.getCellMetadata(ref);
18478
18417
  if (metadataMatchesTarget(meta, target)) {
18479
18418
  skippedFiles.push(cell.filePath);
18480
18419
  onProgress?.({
@@ -18525,11 +18464,12 @@ var BackendMigrator = class {
18525
18464
  const migratedFiles = [];
18526
18465
  let migrationFailed = false;
18527
18466
  let migrationError;
18467
+ let sourceAfter;
18528
18468
  try {
18529
18469
  await this.tx.run(repoRoot, {
18530
18470
  description: environment ? `clef migrate-backend ${target.backend}: ${environment}` : `clef migrate-backend ${target.backend}`,
18531
18471
  paths: [
18532
- ...toMigrate.map((c) => path25.relative(repoRoot, c.filePath)),
18472
+ ...toMigrate.map((c) => path23.relative(repoRoot, c.filePath)),
18533
18473
  CLEF_MANIFEST_FILENAME
18534
18474
  ],
18535
18475
  mutate: async () => {
@@ -18537,19 +18477,16 @@ var BackendMigrator = class {
18537
18477
  this.updateManifestDoc(doc, target, environment);
18538
18478
  writeManifestYaml(repoRoot, doc);
18539
18479
  const updatedManifest = YAML12.parse(YAML12.stringify(doc));
18480
+ sourceAfter = this.buildSource(updatedManifest);
18540
18481
  for (const cell of toMigrate) {
18541
18482
  onProgress?.({
18542
18483
  type: "migrate",
18543
18484
  file: cell.filePath,
18544
18485
  message: `Migrating ${cell.namespace}/${cell.environment}...`
18545
18486
  });
18546
- const decrypted = await this.decryptBackend.decrypt(cell.filePath);
18547
- await this.encryptBackend.encrypt(
18548
- cell.filePath,
18549
- decrypted.values,
18550
- updatedManifest,
18551
- cell.environment
18552
- );
18487
+ const ref = { namespace: cell.namespace, environment: cell.environment };
18488
+ const decrypted = await sourceBefore.readCell(ref);
18489
+ await sourceAfter.writeCell(ref, decrypted.values);
18553
18490
  migratedFiles.push(cell.filePath);
18554
18491
  }
18555
18492
  }
@@ -18579,7 +18516,7 @@ var BackendMigrator = class {
18579
18516
  }
18580
18517
  const verifiedFiles = [];
18581
18518
  const warnings = [];
18582
- if (!skipVerify) {
18519
+ if (!skipVerify && sourceAfter) {
18583
18520
  for (const cell of toMigrate) {
18584
18521
  try {
18585
18522
  onProgress?.({
@@ -18587,7 +18524,8 @@ var BackendMigrator = class {
18587
18524
  file: cell.filePath,
18588
18525
  message: `Verifying ${cell.namespace}/${cell.environment}...`
18589
18526
  });
18590
- await this.encryptBackend.decrypt(cell.filePath);
18527
+ const ref = { namespace: cell.namespace, environment: cell.environment };
18528
+ await sourceAfter.readCell(ref);
18591
18529
  verifiedFiles.push(cell.filePath);
18592
18530
  } catch (err) {
18593
18531
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -18632,16 +18570,16 @@ var BackendMigrator = class {
18632
18570
  };
18633
18571
 
18634
18572
  // src/reset/manager.ts
18635
- var path26 = __toESM(require("path"));
18573
+ var path24 = __toESM(require("path"));
18636
18574
  var ResetManager = class {
18637
- constructor(matrixManager, encryption, schemaValidator, tx) {
18575
+ constructor(matrixManager, buildSource, schemaValidator, tx) {
18638
18576
  this.matrixManager = matrixManager;
18639
- this.encryption = encryption;
18577
+ this.buildSource = buildSource;
18640
18578
  this.schemaValidator = schemaValidator;
18641
18579
  this.tx = tx;
18642
18580
  }
18643
18581
  matrixManager;
18644
- encryption;
18582
+ buildSource;
18645
18583
  schemaValidator;
18646
18584
  tx;
18647
18585
  async reset(opts, manifest, repoRoot) {
@@ -18661,11 +18599,11 @@ var ResetManager = class {
18661
18599
  txPaths.push(CLEF_MANIFEST_FILENAME);
18662
18600
  }
18663
18601
  for (const cell of targetCells) {
18664
- txPaths.push(path26.relative(repoRoot, cell.filePath));
18602
+ txPaths.push(path24.relative(repoRoot, cell.filePath));
18665
18603
  const cellKeys = keyPlan.get(cell.namespace) ?? [];
18666
18604
  if (cellKeys.length > 0) {
18667
18605
  txPaths.push(
18668
- path26.relative(repoRoot, cell.filePath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml"))
18606
+ path24.relative(repoRoot, cell.filePath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml"))
18669
18607
  );
18670
18608
  }
18671
18609
  }
@@ -18682,17 +18620,14 @@ var ResetManager = class {
18682
18620
  writeManifestYaml(repoRoot, doc);
18683
18621
  effectiveManifest = withBackendOverride(manifest, affectedEnvs, opts.backend, opts.key);
18684
18622
  }
18623
+ const source = this.buildSource(effectiveManifest);
18685
18624
  for (const cell of targetCells) {
18686
18625
  const keys = keyPlan.get(cell.namespace) ?? [];
18687
18626
  const placeholders = this.buildPlaceholders(keys);
18688
- await this.encryption.encrypt(
18689
- cell.filePath,
18690
- placeholders,
18691
- effectiveManifest,
18692
- cell.environment
18693
- );
18627
+ const ref = { namespace: cell.namespace, environment: cell.environment };
18628
+ await source.writeCell(ref, placeholders);
18694
18629
  if (keys.length > 0) {
18695
- await markPendingWithRetry(cell.filePath, keys, "clef reset");
18630
+ await source.markPending(ref, keys, "clef reset");
18696
18631
  pendingKeysByCell[cell.filePath] = keys;
18697
18632
  }
18698
18633
  scaffoldedCells.push(cell.filePath);
@@ -18753,7 +18688,7 @@ var ResetManager = class {
18753
18688
  for (const namespace of namespaces) {
18754
18689
  const nsDef = manifest.namespaces.find((n) => n.name === namespace);
18755
18690
  if (nsDef?.schema) {
18756
- const schema = this.schemaValidator.loadSchema(path26.join(repoRoot, nsDef.schema));
18691
+ const schema = this.schemaValidator.loadSchema(path24.join(repoRoot, nsDef.schema));
18757
18692
  plan.set(namespace, Object.keys(schema.keys));
18758
18693
  continue;
18759
18694
  }
@@ -18832,15 +18767,15 @@ function withBackendOverride(manifest, envNames, backend, key) {
18832
18767
  }
18833
18768
 
18834
18769
  // src/sync/manager.ts
18835
- var path27 = __toESM(require("path"));
18770
+ var path25 = __toESM(require("path"));
18836
18771
  var SyncManager = class {
18837
- constructor(matrixManager, encryption, tx) {
18772
+ constructor(matrixManager, source, tx) {
18838
18773
  this.matrixManager = matrixManager;
18839
- this.encryption = encryption;
18774
+ this.source = source;
18840
18775
  this.tx = tx;
18841
18776
  }
18842
18777
  matrixManager;
18843
- encryption;
18778
+ source;
18844
18779
  tx;
18845
18780
  /**
18846
18781
  * Compute what sync would do without mutating anything.
@@ -18857,8 +18792,13 @@ var SyncManager = class {
18857
18792
  const targetCells = opts.namespace ? existingCells.filter((c) => c.namespace === opts.namespace) : existingCells;
18858
18793
  const keysByNsEnv = {};
18859
18794
  for (const cell of targetCells) {
18860
- const keys = readSopsKeyNames(cell.filePath);
18861
- if (!keys) continue;
18795
+ const ref = { namespace: cell.namespace, environment: cell.environment };
18796
+ let keys;
18797
+ try {
18798
+ keys = await this.source.listKeys(ref);
18799
+ } catch {
18800
+ continue;
18801
+ }
18862
18802
  if (!keysByNsEnv[cell.namespace]) keysByNsEnv[cell.namespace] = {};
18863
18803
  keysByNsEnv[cell.namespace][cell.environment] = new Set(keys);
18864
18804
  }
@@ -18904,7 +18844,7 @@ var SyncManager = class {
18904
18844
  }
18905
18845
  const txPaths = [];
18906
18846
  for (const cell of syncPlan.cells) {
18907
- const rel = path27.relative(repoRoot, cell.filePath);
18847
+ const rel = path25.relative(repoRoot, cell.filePath);
18908
18848
  txPaths.push(rel);
18909
18849
  txPaths.push(rel.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml"));
18910
18850
  }
@@ -18917,17 +18857,13 @@ var SyncManager = class {
18917
18857
  paths: txPaths,
18918
18858
  mutate: async () => {
18919
18859
  for (const cell of syncPlan.cells) {
18920
- const decrypted = await this.encryption.decrypt(cell.filePath);
18860
+ const ref = { namespace: cell.namespace, environment: cell.environment };
18861
+ const decrypted = await this.source.readCell(ref);
18921
18862
  for (const key of cell.missingKeys) {
18922
18863
  decrypted.values[key] = generateRandomValue();
18923
18864
  }
18924
- await this.encryption.encrypt(
18925
- cell.filePath,
18926
- decrypted.values,
18927
- manifest,
18928
- cell.environment
18929
- );
18930
- await markPendingWithRetry(cell.filePath, cell.missingKeys, "clef sync");
18865
+ await this.source.writeCell(ref, decrypted.values);
18866
+ await this.source.markPending(ref, cell.missingKeys, "clef sync");
18931
18867
  const cellLabel = `${cell.namespace}/${cell.environment}`;
18932
18868
  modifiedCells.push(cellLabel);
18933
18869
  scaffoldedKeys[cellLabel] = cell.missingKeys;
@@ -19187,13 +19123,272 @@ var ComplianceGenerator = class {
19187
19123
  };
19188
19124
 
19189
19125
  // src/compliance/run.ts
19190
- var path28 = __toESM(require("path"));
19126
+ var path27 = __toESM(require("path"));
19127
+
19128
+ // src/source/compose.ts
19129
+ var YAML14 = __toESM(require("yaml"));
19130
+
19131
+ // src/source/default-bulk.ts
19132
+ function defaultBulk(source) {
19133
+ return {
19134
+ async bulkSet(namespace, key, valuesByEnv, _manifest) {
19135
+ for (const [environment, value] of Object.entries(valuesByEnv)) {
19136
+ const cell = { namespace, environment };
19137
+ const existing = await source.cellExists(cell) ? (await source.readCell(cell)).values : {};
19138
+ await source.writeCell(cell, { ...existing, [key]: value });
19139
+ }
19140
+ },
19141
+ async bulkDelete(namespace, key, manifest) {
19142
+ for (const env of manifest.environments) {
19143
+ const cell = { namespace, environment: env.name };
19144
+ if (!await source.cellExists(cell)) continue;
19145
+ const data = await source.readCell(cell);
19146
+ if (!(key in data.values)) continue;
19147
+ const next = { ...data.values };
19148
+ delete next[key];
19149
+ await source.writeCell(cell, next);
19150
+ }
19151
+ },
19152
+ async copyValue(key, from, to, _manifest) {
19153
+ const src = await source.readCell(from);
19154
+ if (!(key in src.values)) {
19155
+ throw new Error(
19156
+ `Cannot copy: key '${key}' not present in ${from.namespace}/${from.environment}`
19157
+ );
19158
+ }
19159
+ const dst = await source.cellExists(to) ? (await source.readCell(to)).values : {};
19160
+ await source.writeCell(to, { ...dst, [key]: src.values[key] });
19161
+ }
19162
+ };
19163
+ }
19164
+
19165
+ // src/source/compose.ts
19166
+ function composeSecretSource(storage, encryption, manifest) {
19167
+ return new ComposedSecretSource(storage, encryption, manifest);
19168
+ }
19169
+ var ComposedSecretSource = class {
19170
+ constructor(storage, encryption, manifest) {
19171
+ this.storage = storage;
19172
+ this.encryption = encryption;
19173
+ this.manifest = manifest;
19174
+ this.id = `${storage.id}+${encryption.id}`;
19175
+ this.description = `${storage.description} / ${encryption.description}`;
19176
+ }
19177
+ storage;
19178
+ encryption;
19179
+ manifest;
19180
+ id;
19181
+ description;
19182
+ context(cell) {
19183
+ return {
19184
+ manifest: this.manifest,
19185
+ environment: cell.environment,
19186
+ format: this.storage.blobFormat(cell)
19187
+ };
19188
+ }
19189
+ // ── Core SecretSource ──────────────────────────────────────────────────
19190
+ async readCell(cell) {
19191
+ const blob = await this.storage.readBlob(cell);
19192
+ return this.encryption.decrypt(blob, this.context(cell));
19193
+ }
19194
+ async writeCell(cell, values) {
19195
+ const blob = await this.encryption.encrypt(values, this.context(cell));
19196
+ await this.storage.writeBlob(cell, blob);
19197
+ }
19198
+ async deleteCell(cell) {
19199
+ await this.storage.deleteBlob(cell);
19200
+ }
19201
+ async cellExists(cell) {
19202
+ return this.storage.blobExists(cell);
19203
+ }
19204
+ /**
19205
+ * List cell keys WITHOUT decrypting. SOPS files store key names in
19206
+ * plaintext at the top level of the YAML/JSON document — we read the
19207
+ * blob and return everything except the `sops:` metadata block.
19208
+ *
19209
+ * NOTE: this is currently SOPS-shaped. A future non-SOPS
19210
+ * `EncryptionBackend` whose ciphertext doesn't expose key names in
19211
+ * the clear would need its own listing strategy — likely a
19212
+ * `listKeys(blob)` method on `EncryptionBackend`. Deferred until a
19213
+ * second backend exists.
19214
+ */
19215
+ async listKeys(cell) {
19216
+ if (!await this.storage.blobExists(cell)) return [];
19217
+ const blob = await this.storage.readBlob(cell);
19218
+ const parsed = YAML14.parse(blob);
19219
+ if (!parsed || typeof parsed !== "object") return [];
19220
+ return Object.keys(parsed).filter((k) => k !== "sops");
19221
+ }
19222
+ async getCellMetadata(cell) {
19223
+ const blob = await this.storage.readBlob(cell);
19224
+ return this.encryption.getMetadata(blob);
19225
+ }
19226
+ async scaffoldCell(cell, manifest) {
19227
+ if (await this.storage.blobExists(cell)) return;
19228
+ const blob = await this.encryption.encrypt(
19229
+ {},
19230
+ {
19231
+ manifest,
19232
+ environment: cell.environment,
19233
+ format: this.storage.blobFormat(cell)
19234
+ }
19235
+ );
19236
+ await this.storage.writeBlob(cell, blob);
19237
+ }
19238
+ // ── Pending / rotation metadata ────────────────────────────────────────
19239
+ async getPendingMetadata(cell) {
19240
+ return this.storage.readPendingMetadata(cell);
19241
+ }
19242
+ async markPending(cell, keys, setBy) {
19243
+ const meta = await this.storage.readPendingMetadata(cell);
19244
+ const now = /* @__PURE__ */ new Date();
19245
+ for (const key of keys) {
19246
+ if (!meta.pending.find((p) => p.key === key)) {
19247
+ meta.pending.push({ key, since: now, setBy });
19248
+ }
19249
+ }
19250
+ await this.storage.writePendingMetadata(cell, meta);
19251
+ }
19252
+ async markResolved(cell, keys) {
19253
+ const meta = await this.storage.readPendingMetadata(cell);
19254
+ meta.pending = meta.pending.filter((p) => !keys.includes(p.key));
19255
+ await this.storage.writePendingMetadata(cell, meta);
19256
+ }
19257
+ async recordRotation(cell, keys, rotatedBy) {
19258
+ const meta = await this.storage.readPendingMetadata(cell);
19259
+ const now = /* @__PURE__ */ new Date();
19260
+ for (const key of keys) {
19261
+ const existing = meta.rotations.find((r) => r.key === key);
19262
+ if (existing) {
19263
+ existing.lastRotatedAt = now;
19264
+ existing.rotatedBy = rotatedBy;
19265
+ existing.rotationCount += 1;
19266
+ } else {
19267
+ meta.rotations.push({ key, lastRotatedAt: now, rotatedBy, rotationCount: 1 });
19268
+ }
19269
+ }
19270
+ meta.pending = meta.pending.filter((p) => !keys.includes(p.key));
19271
+ await this.storage.writePendingMetadata(cell, meta);
19272
+ }
19273
+ async removeRotation(cell, keys) {
19274
+ const meta = await this.storage.readPendingMetadata(cell);
19275
+ meta.rotations = meta.rotations.filter((r) => !keys.includes(r.key));
19276
+ await this.storage.writePendingMetadata(cell, meta);
19277
+ }
19278
+ // ── Lintable ───────────────────────────────────────────────────────────
19279
+ async validateEncryption(cell) {
19280
+ if (!await this.storage.blobExists(cell)) return false;
19281
+ const blob = await this.storage.readBlob(cell);
19282
+ return this.encryption.validateEncryption(blob);
19283
+ }
19284
+ async checkRecipientDrift(cell, expected) {
19285
+ const blob = await this.storage.readBlob(cell);
19286
+ const meta = this.encryption.getMetadata(blob);
19287
+ const actual = new Set(meta.recipients);
19288
+ const expectedSet = new Set(expected);
19289
+ return {
19290
+ missing: expected.filter((r) => !actual.has(r)),
19291
+ unexpected: meta.recipients.filter((r) => !expectedSet.has(r))
19292
+ };
19293
+ }
19294
+ // ── Rotatable ──────────────────────────────────────────────────────────
19295
+ async rotate(cell, opts) {
19296
+ const blob = await this.storage.readBlob(cell);
19297
+ const rotated = await this.encryption.rotate(blob, opts, this.context(cell));
19298
+ await this.storage.writeBlob(cell, rotated);
19299
+ }
19300
+ // ── Bulk ───────────────────────────────────────────────────────────────
19301
+ //
19302
+ // Default looped implementation. A future StorageBackend that supports
19303
+ // batch operations (e.g. PostgresStorageBackend with row-level UPDATE
19304
+ // batching) can override these by wrapping `composeSecretSource`'s
19305
+ // output and replacing just the bulk methods.
19306
+ bulkSet = (namespace, key, valuesByEnv, manifest) => defaultBulk(this).bulkSet(namespace, key, valuesByEnv, manifest);
19307
+ bulkDelete = (namespace, key, manifest) => defaultBulk(this).bulkDelete(namespace, key, manifest);
19308
+ copyValue = (key, from, to, manifest) => defaultBulk(this).copyValue(key, from, to, manifest);
19309
+ };
19310
+
19311
+ // src/source/filesystem-storage-backend.ts
19312
+ var fs22 = __toESM(require("fs"));
19313
+ var path26 = __toESM(require("path"));
19314
+ var import_crypto3 = require("crypto");
19315
+ var FilesystemStorageBackend = class {
19316
+ constructor(manifest, repoRoot) {
19317
+ this.manifest = manifest;
19318
+ this.repoRoot = repoRoot;
19319
+ }
19320
+ manifest;
19321
+ repoRoot;
19322
+ id = "filesystem";
19323
+ description = "Filesystem-backed cell storage (default substrate)";
19324
+ /**
19325
+ * Resolve a cell reference to its absolute filesystem path. Public —
19326
+ * used by substrate-specific trait implementations.
19327
+ */
19328
+ cellPath(cell) {
19329
+ const relativePath = this.manifest.file_pattern.replace("{namespace}", cell.namespace).replace("{environment}", cell.environment);
19330
+ return path26.join(this.repoRoot, relativePath);
19331
+ }
19332
+ /** The repo root, exposed for filesystem-shaped trait implementations. */
19333
+ getRepoRoot() {
19334
+ return this.repoRoot;
19335
+ }
19336
+ blobFormat(cell) {
19337
+ return this.cellPath(cell).endsWith(".json") ? "json" : "yaml";
19338
+ }
19339
+ async readBlob(cell) {
19340
+ const filePath = this.cellPath(cell);
19341
+ return fs22.readFileSync(filePath, "utf-8");
19342
+ }
19343
+ async writeBlob(cell, blob) {
19344
+ const filePath = this.cellPath(cell);
19345
+ const dir = path26.dirname(filePath);
19346
+ if (!fs22.existsSync(dir)) {
19347
+ fs22.mkdirSync(dir, { recursive: true });
19348
+ }
19349
+ const tmpPath = `${filePath}.${Date.now()}.${(0, import_crypto3.randomBytes)(4).toString("hex")}.tmp`;
19350
+ const handle = fs22.openSync(tmpPath, "w");
19351
+ try {
19352
+ fs22.writeFileSync(handle, blob);
19353
+ fs22.fsyncSync(handle);
19354
+ } finally {
19355
+ fs22.closeSync(handle);
19356
+ }
19357
+ fs22.renameSync(tmpPath, filePath);
19358
+ }
19359
+ async deleteBlob(cell) {
19360
+ const filePath = this.cellPath(cell);
19361
+ if (fs22.existsSync(filePath)) {
19362
+ fs22.unlinkSync(filePath);
19363
+ }
19364
+ const sidecar = this.sidecarPath(filePath);
19365
+ if (fs22.existsSync(sidecar)) {
19366
+ fs22.unlinkSync(sidecar);
19367
+ }
19368
+ }
19369
+ async blobExists(cell) {
19370
+ return fs22.existsSync(this.cellPath(cell));
19371
+ }
19372
+ async readPendingMetadata(cell) {
19373
+ return loadMetadata(this.cellPath(cell));
19374
+ }
19375
+ async writePendingMetadata(cell, meta) {
19376
+ await saveMetadata(this.cellPath(cell), meta);
19377
+ }
19378
+ sidecarPath(filePath) {
19379
+ const dir = path26.dirname(filePath);
19380
+ const base = path26.basename(filePath).replace(/\.enc\.(yaml|json)$/, "");
19381
+ return path26.join(dir, `${base}.clef-meta.yaml`);
19382
+ }
19383
+ };
19384
+
19385
+ // src/compliance/run.ts
19191
19386
  var UNKNOWN = "unknown";
19192
19387
  async function runCompliance(opts) {
19193
19388
  const start = Date.now();
19194
19389
  const repoRoot = opts.repoRoot ?? process.cwd();
19195
- const manifestPath = opts.manifestPath ?? path28.join(repoRoot, "clef.yaml");
19196
- const policyPath = opts.policyPath ?? path28.join(repoRoot, CLEF_POLICY_FILENAME);
19390
+ const manifestPath = opts.manifestPath ?? path27.join(repoRoot, "clef.yaml");
19391
+ const policyPath = opts.policyPath ?? path27.join(repoRoot, CLEF_POLICY_FILENAME);
19197
19392
  const include = {
19198
19393
  scan: opts.include?.scan ?? true,
19199
19394
  lint: opts.include?.lint ?? true,
@@ -19205,6 +19400,11 @@ async function runCompliance(opts) {
19205
19400
  const sopsClient = new SopsClient(opts.runner, opts.ageKeyFile, opts.ageKey, opts.sopsPath);
19206
19401
  const matrixManager = new MatrixManager();
19207
19402
  const schemaValidator = new SchemaValidator();
19403
+ const lintSource = composeSecretSource(
19404
+ new FilesystemStorageBackend(manifest, repoRoot),
19405
+ sopsClient,
19406
+ manifest
19407
+ );
19208
19408
  const [sha, repo, files, scanResult, lintResult] = await Promise.all([
19209
19409
  opts.sha !== void 0 ? Promise.resolve(opts.sha) : detectSha(opts.runner, repoRoot),
19210
19410
  opts.repo !== void 0 ? Promise.resolve(opts.repo) : detectRepo(opts.runner, repoRoot),
@@ -19213,12 +19413,12 @@ async function runCompliance(opts) {
19213
19413
  repoRoot,
19214
19414
  policy,
19215
19415
  matrixManager,
19216
- sopsClient,
19416
+ source: lintSource,
19217
19417
  filter: opts.filter,
19218
19418
  now
19219
19419
  }) : Promise.resolve([]),
19220
19420
  include.scan ? new ScanRunner(opts.runner).scan(repoRoot, manifest) : Promise.resolve(emptyScan()),
19221
- include.lint ? new LintRunner(matrixManager, schemaValidator, sopsClient).run(manifest, repoRoot) : Promise.resolve(emptyLint())
19421
+ include.lint ? new LintRunner(matrixManager, schemaValidator, lintSource).run(manifest, repoRoot) : Promise.resolve(emptyLint())
19222
19422
  ]);
19223
19423
  const adjustedLint = downgradeDecryptIssues(lintResult);
19224
19424
  const document = new ComplianceGenerator().generate({
@@ -19238,8 +19438,11 @@ async function evaluateMatrix(args) {
19238
19438
  const cells = args.matrixManager.resolveMatrix(args.manifest, args.repoRoot).filter((c) => applyFilter(c.namespace, c.environment, args.filter)).filter((c) => c.exists);
19239
19439
  return Promise.all(
19240
19440
  cells.map(async (cell) => {
19241
- const metadata = await args.sopsClient.getMetadata(cell.filePath);
19242
- const relPath = path28.relative(args.repoRoot, cell.filePath).replace(/\\/g, "/");
19441
+ const metadata = await args.source.getCellMetadata({
19442
+ namespace: cell.namespace,
19443
+ environment: cell.environment
19444
+ });
19445
+ const relPath = path27.relative(args.repoRoot, cell.filePath).replace(/\\/g, "/");
19243
19446
  const keys = readSopsKeyNames(cell.filePath) ?? [];
19244
19447
  const rotations = await getRotations(cell.filePath);
19245
19448
  return evaluator.evaluateFile(relPath, cell.environment, metadata, keys, rotations, args.now);
@@ -19297,11 +19500,62 @@ async function detectRepo(runner, repoRoot) {
19297
19500
  const match = url.match(/[:/]([^/:]+)\/([^/]+?)(?:\.git)?\/?$/);
19298
19501
  return match ? `${match[1]}/${match[2]}` : UNKNOWN;
19299
19502
  }
19503
+
19504
+ // src/source/guards.ts
19505
+ function isFn(o, name) {
19506
+ return typeof o === "object" && o !== null && typeof o[name] === "function";
19507
+ }
19508
+ function isLintable(s) {
19509
+ return isFn(s, "validateEncryption") && isFn(s, "checkRecipientDrift");
19510
+ }
19511
+ function isRotatable(s) {
19512
+ return isFn(s, "rotate");
19513
+ }
19514
+ function isRecipientManaged(s) {
19515
+ return isFn(s, "listRecipients") && isFn(s, "addRecipient") && isFn(s, "removeRecipient");
19516
+ }
19517
+ function isMergeAware(s) {
19518
+ return isFn(s, "mergeCells") && isFn(s, "installMergeDriver");
19519
+ }
19520
+ function isMigratable(s) {
19521
+ return isFn(s, "migrateBackend");
19522
+ }
19523
+ function isBulk(s) {
19524
+ return isFn(s, "bulkSet") && isFn(s, "bulkDelete") && isFn(s, "copyValue");
19525
+ }
19526
+ function isStructural(s) {
19527
+ return isFn(s, "addNamespace") && isFn(s, "addEnvironment") && isFn(s, "renameNamespace") && isFn(s, "renameEnvironment");
19528
+ }
19529
+ function describeCapabilities(s) {
19530
+ return {
19531
+ lint: isLintable(s),
19532
+ rotate: isRotatable(s),
19533
+ recipients: isRecipientManaged(s),
19534
+ merge: isMergeAware(s),
19535
+ migrate: isMigratable(s),
19536
+ bulk: isBulk(s),
19537
+ structural: isStructural(s)
19538
+ };
19539
+ }
19540
+
19541
+ // src/source/errors.ts
19542
+ var SourceCapabilityUnsupportedError = class extends ClefError {
19543
+ constructor(capability, sourceId) {
19544
+ super(
19545
+ `'${capability}' is not supported by the '${sourceId}' source.`,
19546
+ `Switch to a source that implements ${capability}, or use a different command.`
19547
+ );
19548
+ this.capability = capability;
19549
+ this.sourceId = sourceId;
19550
+ this.name = "SourceCapabilityUnsupportedError";
19551
+ }
19552
+ capability;
19553
+ sourceId;
19554
+ };
19300
19555
  // Annotate the CommonJS export names for ESM import in node:
19301
19556
  0 && (module.exports = {
19302
19557
  ArtifactPacker,
19303
19558
  BackendMigrator,
19304
- BulkOps,
19305
19559
  CLEF_MANIFEST_FILENAME,
19306
19560
  CLEF_POLICY_FILENAME,
19307
19561
  CLEF_REPORT_SCHEMA_VERSION,
@@ -19315,6 +19569,7 @@ async function detectRepo(runner, repoRoot) {
19315
19569
  DiffEngine,
19316
19570
  DriftDetector,
19317
19571
  FilePackOutput,
19572
+ FilesystemStorageBackend,
19318
19573
  GitIntegration,
19319
19574
  GitOperationError,
19320
19575
  ImportRunner,
@@ -19331,7 +19586,6 @@ async function detectRepo(runner, repoRoot) {
19331
19586
  PolicyValidationError,
19332
19587
  REQUESTS_FILENAME,
19333
19588
  REQUIREMENTS,
19334
- REVEAL_WARNING,
19335
19589
  RecipientManager,
19336
19590
  ReportGenerator,
19337
19591
  ReportSanitizer,
@@ -19348,6 +19602,7 @@ async function detectRepo(runner, repoRoot) {
19348
19602
  SopsMergeDriver,
19349
19603
  SopsMissingError,
19350
19604
  SopsVersionError,
19605
+ SourceCapabilityUnsupportedError,
19351
19606
  StructureManager,
19352
19607
  SyncManager,
19353
19608
  TransactionLockError,
@@ -19367,11 +19622,11 @@ async function detectRepo(runner, repoRoot) {
19367
19622
  checkAll,
19368
19623
  checkDependency,
19369
19624
  collectCIContext,
19625
+ composeSecretSource,
19370
19626
  computeCiphertextHash,
19371
19627
  deriveAgePublicKey,
19628
+ describeCapabilities,
19372
19629
  describeScope,
19373
- detectAlgorithm,
19374
- detectFormat,
19375
19630
  emptyTemplate,
19376
19631
  exampleTemplate,
19377
19632
  findRequest,
@@ -19379,35 +19634,27 @@ async function detectRepo(runner, repoRoot) {
19379
19634
  formatRevealWarning,
19380
19635
  generateAgeIdentity,
19381
19636
  generateRandomValue,
19382
- generateSigningKeyPair,
19383
- getPendingKeys,
19384
- getRotations,
19637
+ isBulk,
19385
19638
  isClefHsmArn,
19386
- isHighEntropy,
19387
19639
  isKmsEnvelope,
19640
+ isLintable,
19641
+ isMergeAware,
19642
+ isMigratable,
19388
19643
  isPackedArtifact,
19389
- isPending,
19644
+ isRecipientManaged,
19645
+ isRotatable,
19646
+ isStructural,
19390
19647
  keyPreview,
19391
- loadIgnoreRules,
19392
- loadMetadata,
19393
19648
  loadRequests,
19394
19649
  markPending,
19395
- markPendingWithRetry,
19396
19650
  markResolved,
19397
- matchPatterns,
19398
- mergeMetadataContents,
19399
19651
  mergeMetadataFiles,
19400
- metadataPath,
19401
19652
  parse,
19402
- parseDotenv,
19403
- parseIgnoreContent,
19404
- parseJson,
19405
19653
  parseSignerKey,
19406
19654
  parseYaml,
19407
19655
  pkcs11UriToSyntheticArn,
19408
19656
  readManifestYaml,
19409
19657
  recordRotation,
19410
- redactValue,
19411
19658
  removeAccessRequest,
19412
19659
  removeRotation,
19413
19660
  requestsFilePath,
@@ -19419,14 +19666,8 @@ async function detectRepo(runner, repoRoot) {
19419
19666
  resolveRecipientsForEnvironment,
19420
19667
  resolveSopsPath,
19421
19668
  runCompliance,
19422
- saveMetadata,
19423
19669
  saveRequests,
19424
- serializeSchema,
19425
- shannonEntropy,
19426
- shouldIgnoreFile,
19427
- shouldIgnoreMatch,
19428
- signEd25519,
19429
- signKms,
19670
+ shouldUseLinuxStdinFifo,
19430
19671
  spawnKeyservice,
19431
19672
  syntheticArnToPkcs11Uri,
19432
19673
  tryBundledKeyservice,
@@ -19436,6 +19677,7 @@ async function detectRepo(runner, repoRoot) {
19436
19677
  validatePackedArtifact,
19437
19678
  validateResetScope,
19438
19679
  verifySignature,
19680
+ wrapWithLinuxStdinFifo,
19439
19681
  writeManifestYaml,
19440
19682
  writeManifestYamlRaw,
19441
19683
  writeSchema,