@solaqua/gji 0.12.0 → 0.12.2

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.
@@ -3462,7 +3462,7 @@ var require_commander = __commonJS({
3462
3462
  // node_modules/.pnpm/graceful-fs@4.2.11/node_modules/graceful-fs/polyfills.js
3463
3463
  var require_polyfills = __commonJS({
3464
3464
  "node_modules/.pnpm/graceful-fs@4.2.11/node_modules/graceful-fs/polyfills.js"(exports, module) {
3465
- var constants9 = __require("constants");
3465
+ var constants10 = __require("constants");
3466
3466
  var origCwd = process.cwd;
3467
3467
  var cwd = null;
3468
3468
  var platform3 = process.env.GRACEFUL_FS_PLATFORM || process.platform;
@@ -3486,7 +3486,7 @@ var require_polyfills = __commonJS({
3486
3486
  var chdir;
3487
3487
  module.exports = patch;
3488
3488
  function patch(fs5) {
3489
- if (constants9.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
3489
+ if (constants10.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
3490
3490
  patchLchmod(fs5);
3491
3491
  }
3492
3492
  if (!fs5.lutimes) {
@@ -3526,7 +3526,7 @@ var require_polyfills = __commonJS({
3526
3526
  }
3527
3527
  if (platform3 === "win32") {
3528
3528
  fs5.rename = typeof fs5.rename !== "function" ? fs5.rename : (function(fs$rename) {
3529
- function rename5(from, to, cb) {
3529
+ function rename4(from, to, cb) {
3530
3530
  var start = Date.now();
3531
3531
  var backoff = 0;
3532
3532
  fs$rename(from, to, function CB(er) {
@@ -3546,8 +3546,8 @@ var require_polyfills = __commonJS({
3546
3546
  if (cb) cb(er);
3547
3547
  });
3548
3548
  }
3549
- if (Object.setPrototypeOf) Object.setPrototypeOf(rename5, fs$rename);
3550
- return rename5;
3549
+ if (Object.setPrototypeOf) Object.setPrototypeOf(rename4, fs$rename);
3550
+ return rename4;
3551
3551
  })(fs5.rename);
3552
3552
  }
3553
3553
  fs5.read = typeof fs5.read !== "function" ? fs5.read : (function(fs$read) {
@@ -3588,7 +3588,7 @@ var require_polyfills = __commonJS({
3588
3588
  fs6.lchmod = function(path9, mode, callback) {
3589
3589
  fs6.open(
3590
3590
  path9,
3591
- constants9.O_WRONLY | constants9.O_SYMLINK,
3591
+ constants10.O_WRONLY | constants10.O_SYMLINK,
3592
3592
  mode,
3593
3593
  function(err, fd) {
3594
3594
  if (err) {
@@ -3604,7 +3604,7 @@ var require_polyfills = __commonJS({
3604
3604
  );
3605
3605
  };
3606
3606
  fs6.lchmodSync = function(path9, mode) {
3607
- var fd = fs6.openSync(path9, constants9.O_WRONLY | constants9.O_SYMLINK, mode);
3607
+ var fd = fs6.openSync(path9, constants10.O_WRONLY | constants10.O_SYMLINK, mode);
3608
3608
  var threw = true;
3609
3609
  var ret;
3610
3610
  try {
@@ -3624,9 +3624,9 @@ var require_polyfills = __commonJS({
3624
3624
  };
3625
3625
  }
3626
3626
  function patchLutimes(fs6) {
3627
- if (constants9.hasOwnProperty("O_SYMLINK") && fs6.futimes) {
3627
+ if (constants10.hasOwnProperty("O_SYMLINK") && fs6.futimes) {
3628
3628
  fs6.lutimes = function(path9, at, mt, cb) {
3629
- fs6.open(path9, constants9.O_SYMLINK, function(er, fd) {
3629
+ fs6.open(path9, constants10.O_SYMLINK, function(er, fd) {
3630
3630
  if (er) {
3631
3631
  if (cb) cb(er);
3632
3632
  return;
@@ -3639,7 +3639,7 @@ var require_polyfills = __commonJS({
3639
3639
  });
3640
3640
  };
3641
3641
  fs6.lutimesSync = function(path9, at, mt) {
3642
- var fd = fs6.openSync(path9, constants9.O_SYMLINK);
3642
+ var fd = fs6.openSync(path9, constants10.O_SYMLINK);
3643
3643
  var ret;
3644
3644
  var threw = true;
3645
3645
  try {
@@ -3951,8 +3951,8 @@ var require_graceful_fs = __commonJS({
3951
3951
  fs6.createReadStream = createReadStream;
3952
3952
  fs6.createWriteStream = createWriteStream;
3953
3953
  var fs$readFile = fs6.readFile;
3954
- fs6.readFile = readFile12;
3955
- function readFile12(path9, options, cb) {
3954
+ fs6.readFile = readFile11;
3955
+ function readFile11(path9, options, cb) {
3956
3956
  if (typeof options === "function")
3957
3957
  cb = options, options = null;
3958
3958
  return go$readFile(path9, options, cb);
@@ -3968,8 +3968,8 @@ var require_graceful_fs = __commonJS({
3968
3968
  }
3969
3969
  }
3970
3970
  var fs$writeFile = fs6.writeFile;
3971
- fs6.writeFile = writeFile12;
3972
- function writeFile12(path9, data, options, cb) {
3971
+ fs6.writeFile = writeFile11;
3972
+ function writeFile11(path9, data, options, cb) {
3973
3973
  if (typeof options === "function")
3974
3974
  cb = options, options = null;
3975
3975
  return go$writeFile(path9, data, options, cb);
@@ -4128,7 +4128,7 @@ var require_graceful_fs = __commonJS({
4128
4128
  }
4129
4129
  function ReadStream$open() {
4130
4130
  var that = this;
4131
- open3(that.path, that.flags, that.mode, function(err, fd) {
4131
+ open4(that.path, that.flags, that.mode, function(err, fd) {
4132
4132
  if (err) {
4133
4133
  if (that.autoClose)
4134
4134
  that.destroy();
@@ -4148,7 +4148,7 @@ var require_graceful_fs = __commonJS({
4148
4148
  }
4149
4149
  function WriteStream$open() {
4150
4150
  var that = this;
4151
- open3(that.path, that.flags, that.mode, function(err, fd) {
4151
+ open4(that.path, that.flags, that.mode, function(err, fd) {
4152
4152
  if (err) {
4153
4153
  that.destroy();
4154
4154
  that.emit("error", err);
@@ -4165,8 +4165,8 @@ var require_graceful_fs = __commonJS({
4165
4165
  return new fs6.WriteStream(path9, options);
4166
4166
  }
4167
4167
  var fs$open = fs6.open;
4168
- fs6.open = open3;
4169
- function open3(path9, flags, mode, cb) {
4168
+ fs6.open = open4;
4169
+ function open4(path9, flags, mode, cb) {
4170
4170
  if (typeof mode === "function")
4171
4171
  cb = mode, mode = null;
4172
4172
  return go$open(path9, flags, mode, cb);
@@ -5386,7 +5386,7 @@ var require_minimist = __commonJS({
5386
5386
  var require_rc = __commonJS({
5387
5387
  "node_modules/.pnpm/rc@1.2.8/node_modules/rc/index.js"(exports, module) {
5388
5388
  var cc = require_utils();
5389
- var join19 = __require("path").join;
5389
+ var join18 = __require("path").join;
5390
5390
  var deepExtend = require_deep_extend();
5391
5391
  var etc = "/etc";
5392
5392
  var win = process.platform === "win32";
@@ -5411,15 +5411,15 @@ var require_rc = __commonJS({
5411
5411
  }
5412
5412
  if (!win)
5413
5413
  [
5414
- join19(etc, name, "config"),
5415
- join19(etc, name + "rc")
5414
+ join18(etc, name, "config"),
5415
+ join18(etc, name + "rc")
5416
5416
  ].forEach(addConfigFile);
5417
5417
  if (home)
5418
5418
  [
5419
- join19(home, ".config", name, "config"),
5420
- join19(home, ".config", name),
5421
- join19(home, "." + name, "config"),
5422
- join19(home, "." + name + "rc")
5419
+ join18(home, ".config", name, "config"),
5420
+ join18(home, ".config", name),
5421
+ join18(home, "." + name, "config"),
5422
+ join18(home, "." + name + "rc")
5423
5423
  ].forEach(addConfigFile);
5424
5424
  addConfigFile(cc.find("." + name + "rc"));
5425
5425
  if (env5.config) addConfigFile(env5.config);
@@ -5436,7 +5436,7 @@ var require_rc = __commonJS({
5436
5436
  // node_modules/.pnpm/graceful-fs@4.2.10/node_modules/graceful-fs/polyfills.js
5437
5437
  var require_polyfills2 = __commonJS({
5438
5438
  "node_modules/.pnpm/graceful-fs@4.2.10/node_modules/graceful-fs/polyfills.js"(exports, module) {
5439
- var constants9 = __require("constants");
5439
+ var constants10 = __require("constants");
5440
5440
  var origCwd = process.cwd;
5441
5441
  var cwd = null;
5442
5442
  var platform3 = process.env.GRACEFUL_FS_PLATFORM || process.platform;
@@ -5460,7 +5460,7 @@ var require_polyfills2 = __commonJS({
5460
5460
  var chdir;
5461
5461
  module.exports = patch;
5462
5462
  function patch(fs5) {
5463
- if (constants9.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
5463
+ if (constants10.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
5464
5464
  patchLchmod(fs5);
5465
5465
  }
5466
5466
  if (!fs5.lutimes) {
@@ -5500,7 +5500,7 @@ var require_polyfills2 = __commonJS({
5500
5500
  }
5501
5501
  if (platform3 === "win32") {
5502
5502
  fs5.rename = typeof fs5.rename !== "function" ? fs5.rename : (function(fs$rename) {
5503
- function rename5(from, to, cb) {
5503
+ function rename4(from, to, cb) {
5504
5504
  var start = Date.now();
5505
5505
  var backoff = 0;
5506
5506
  fs$rename(from, to, function CB(er) {
@@ -5520,8 +5520,8 @@ var require_polyfills2 = __commonJS({
5520
5520
  if (cb) cb(er);
5521
5521
  });
5522
5522
  }
5523
- if (Object.setPrototypeOf) Object.setPrototypeOf(rename5, fs$rename);
5524
- return rename5;
5523
+ if (Object.setPrototypeOf) Object.setPrototypeOf(rename4, fs$rename);
5524
+ return rename4;
5525
5525
  })(fs5.rename);
5526
5526
  }
5527
5527
  fs5.read = typeof fs5.read !== "function" ? fs5.read : (function(fs$read) {
@@ -5562,7 +5562,7 @@ var require_polyfills2 = __commonJS({
5562
5562
  fs6.lchmod = function(path9, mode, callback) {
5563
5563
  fs6.open(
5564
5564
  path9,
5565
- constants9.O_WRONLY | constants9.O_SYMLINK,
5565
+ constants10.O_WRONLY | constants10.O_SYMLINK,
5566
5566
  mode,
5567
5567
  function(err, fd) {
5568
5568
  if (err) {
@@ -5578,7 +5578,7 @@ var require_polyfills2 = __commonJS({
5578
5578
  );
5579
5579
  };
5580
5580
  fs6.lchmodSync = function(path9, mode) {
5581
- var fd = fs6.openSync(path9, constants9.O_WRONLY | constants9.O_SYMLINK, mode);
5581
+ var fd = fs6.openSync(path9, constants10.O_WRONLY | constants10.O_SYMLINK, mode);
5582
5582
  var threw = true;
5583
5583
  var ret;
5584
5584
  try {
@@ -5598,9 +5598,9 @@ var require_polyfills2 = __commonJS({
5598
5598
  };
5599
5599
  }
5600
5600
  function patchLutimes(fs6) {
5601
- if (constants9.hasOwnProperty("O_SYMLINK") && fs6.futimes) {
5601
+ if (constants10.hasOwnProperty("O_SYMLINK") && fs6.futimes) {
5602
5602
  fs6.lutimes = function(path9, at, mt, cb) {
5603
- fs6.open(path9, constants9.O_SYMLINK, function(er, fd) {
5603
+ fs6.open(path9, constants10.O_SYMLINK, function(er, fd) {
5604
5604
  if (er) {
5605
5605
  if (cb) cb(er);
5606
5606
  return;
@@ -5613,7 +5613,7 @@ var require_polyfills2 = __commonJS({
5613
5613
  });
5614
5614
  };
5615
5615
  fs6.lutimesSync = function(path9, at, mt) {
5616
- var fd = fs6.openSync(path9, constants9.O_SYMLINK);
5616
+ var fd = fs6.openSync(path9, constants10.O_SYMLINK);
5617
5617
  var ret;
5618
5618
  var threw = true;
5619
5619
  try {
@@ -5925,8 +5925,8 @@ var require_graceful_fs2 = __commonJS({
5925
5925
  fs6.createReadStream = createReadStream;
5926
5926
  fs6.createWriteStream = createWriteStream;
5927
5927
  var fs$readFile = fs6.readFile;
5928
- fs6.readFile = readFile12;
5929
- function readFile12(path9, options, cb) {
5928
+ fs6.readFile = readFile11;
5929
+ function readFile11(path9, options, cb) {
5930
5930
  if (typeof options === "function")
5931
5931
  cb = options, options = null;
5932
5932
  return go$readFile(path9, options, cb);
@@ -5942,8 +5942,8 @@ var require_graceful_fs2 = __commonJS({
5942
5942
  }
5943
5943
  }
5944
5944
  var fs$writeFile = fs6.writeFile;
5945
- fs6.writeFile = writeFile12;
5946
- function writeFile12(path9, data, options, cb) {
5945
+ fs6.writeFile = writeFile11;
5946
+ function writeFile11(path9, data, options, cb) {
5947
5947
  if (typeof options === "function")
5948
5948
  cb = options, options = null;
5949
5949
  return go$writeFile(path9, data, options, cb);
@@ -6102,7 +6102,7 @@ var require_graceful_fs2 = __commonJS({
6102
6102
  }
6103
6103
  function ReadStream$open() {
6104
6104
  var that = this;
6105
- open3(that.path, that.flags, that.mode, function(err, fd) {
6105
+ open4(that.path, that.flags, that.mode, function(err, fd) {
6106
6106
  if (err) {
6107
6107
  if (that.autoClose)
6108
6108
  that.destroy();
@@ -6122,7 +6122,7 @@ var require_graceful_fs2 = __commonJS({
6122
6122
  }
6123
6123
  function WriteStream$open() {
6124
6124
  var that = this;
6125
- open3(that.path, that.flags, that.mode, function(err, fd) {
6125
+ open4(that.path, that.flags, that.mode, function(err, fd) {
6126
6126
  if (err) {
6127
6127
  that.destroy();
6128
6128
  that.emit("error", err);
@@ -6139,8 +6139,8 @@ var require_graceful_fs2 = __commonJS({
6139
6139
  return new fs6.WriteStream(path9, options);
6140
6140
  }
6141
6141
  var fs$open = fs6.open;
6142
- fs6.open = open3;
6143
- function open3(path9, flags, mode, cb) {
6142
+ fs6.open = open4;
6143
+ function open4(path9, flags, mode, cb) {
6144
6144
  if (typeof mode === "function")
6145
6145
  cb = mode, mode = null;
6146
6146
  return go$open(path9, flags, mode, cb);
@@ -6990,12 +6990,12 @@ var require_conf = __commonJS({
6990
6990
  Object.defineProperty(this, "prefix", {
6991
6991
  enumerable: true,
6992
6992
  set: (prefix) => {
6993
- const g = this.get("global");
6994
- this[g ? "globalPrefix" : "localPrefix"] = prefix;
6993
+ const g2 = this.get("global");
6994
+ this[g2 ? "globalPrefix" : "localPrefix"] = prefix;
6995
6995
  },
6996
6996
  get: () => {
6997
- const g = this.get("global");
6998
- return g ? this.globalPrefix : this.localPrefix;
6997
+ const g2 = this.get("global");
6998
+ return g2 ? this.globalPrefix : this.localPrefix;
6999
6999
  }
7000
7000
  });
7001
7001
  Object.defineProperty(this, "globalPrefix", {
@@ -8729,7 +8729,7 @@ var require_semver2 = __commonJS({
8729
8729
  "node_modules/.pnpm/semver@7.7.4/node_modules/semver/index.js"(exports, module) {
8730
8730
  "use strict";
8731
8731
  var internalRe = require_re();
8732
- var constants9 = require_constants();
8732
+ var constants10 = require_constants();
8733
8733
  var SemVer = require_semver();
8734
8734
  var identifiers = require_identifiers();
8735
8735
  var parse = require_parse();
@@ -8811,8 +8811,8 @@ var require_semver2 = __commonJS({
8811
8811
  re: internalRe.re,
8812
8812
  src: internalRe.src,
8813
8813
  tokens: internalRe.t,
8814
- SEMVER_SPEC_VERSION: constants9.SEMVER_SPEC_VERSION,
8815
- RELEASE_TYPES: constants9.RELEASE_TYPES,
8814
+ SEMVER_SPEC_VERSION: constants10.SEMVER_SPEC_VERSION,
8815
+ RELEASE_TYPES: constants10.RELEASE_TYPES,
8816
8816
  compareIdentifiers: identifiers.compareIdentifiers,
8817
8817
  rcompareIdentifiers: identifiers.rcompareIdentifiers
8818
8818
  };
@@ -9356,9 +9356,9 @@ var require_picocolors = __commonJS({
9356
9356
  var argv = p2.argv || [];
9357
9357
  var env5 = p2.env || {};
9358
9358
  var isColorSupported = !(!!env5.NO_COLOR || argv.includes("--no-color")) && (!!env5.FORCE_COLOR || argv.includes("--color") || p2.platform === "win32" || (p2.stdout || {}).isTTY && env5.TERM !== "dumb" || !!env5.CI);
9359
- var formatter = (open3, close, replace = open3) => (input) => {
9360
- let string = "" + input, index = string.indexOf(close, open3.length);
9361
- return ~index ? open3 + replaceClose(string, close, replace, index) + close : open3 + string + close;
9359
+ var formatter = (open4, close, replace = open4) => (input) => {
9360
+ let string = "" + input, index = string.indexOf(close, open4.length);
9361
+ return ~index ? open4 + replaceClose(string, close, replace, index) + close : open4 + string + close;
9362
9362
  };
9363
9363
  var replaceClose = (string, close, replace, index) => {
9364
9364
  let result = "", cursor = 0;
@@ -9422,7 +9422,7 @@ var require_picocolors = __commonJS({
9422
9422
  });
9423
9423
 
9424
9424
  // src/index.ts
9425
- import { homedir as homedir11 } from "node:os";
9425
+ import { homedir as homedir10 } from "node:os";
9426
9426
 
9427
9427
  // src/cli.ts
9428
9428
  import { createRequire } from "node:module";
@@ -9781,14 +9781,14 @@ var Temp = {
9781
9781
  }
9782
9782
  },
9783
9783
  truncate: (filePath) => {
9784
- const basename12 = path2.basename(filePath);
9785
- if (basename12.length <= LIMIT_BASENAME_LENGTH)
9784
+ const basename13 = path2.basename(filePath);
9785
+ if (basename13.length <= LIMIT_BASENAME_LENGTH)
9786
9786
  return filePath;
9787
- const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(basename12);
9787
+ const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(basename13);
9788
9788
  if (!truncable)
9789
9789
  return filePath;
9790
- const truncationLength = basename12.length - LIMIT_BASENAME_LENGTH;
9791
- return `${filePath.slice(0, -basename12.length)}${truncable[1]}${truncable[2].slice(0, -truncationLength)}${truncable[3]}`;
9790
+ const truncationLength = basename13.length - LIMIT_BASENAME_LENGTH;
9791
+ return `${filePath.slice(0, -basename13.length)}${truncable[1]}${truncable[2].slice(0, -truncationLength)}${truncable[3]}`;
9792
9792
  }
9793
9793
  };
9794
9794
  node_default(Temp.purgeSyncAll);
@@ -10617,18 +10617,18 @@ var proto = Object.defineProperties(() => {
10617
10617
  }
10618
10618
  }
10619
10619
  });
10620
- var createStyler = (open3, close, parent) => {
10620
+ var createStyler = (open4, close, parent) => {
10621
10621
  let openAll;
10622
10622
  let closeAll;
10623
10623
  if (parent === void 0) {
10624
- openAll = open3;
10624
+ openAll = open4;
10625
10625
  closeAll = close;
10626
10626
  } else {
10627
- openAll = parent.openAll + open3;
10627
+ openAll = parent.openAll + open4;
10628
10628
  closeAll = close + parent.closeAll;
10629
10629
  }
10630
10630
  return {
10631
- open: open3,
10631
+ open: open4,
10632
10632
  close,
10633
10633
  openAll,
10634
10634
  closeAll,
@@ -12319,9 +12319,9 @@ var NEWLINE = "\n";
12319
12319
  var PAD = " ";
12320
12320
  var NONE = "none";
12321
12321
  var terminalColumns = () => {
12322
- const { env: env5, stdout: stdout2, stderr } = process9;
12323
- if (stdout2?.columns) {
12324
- return stdout2.columns;
12322
+ const { env: env5, stdout: stdout3, stderr } = process9;
12323
+ if (stdout3?.columns) {
12324
+ return stdout3.columns;
12325
12325
  }
12326
12326
  if (stderr?.columns) {
12327
12327
  return stderr.columns;
@@ -13205,15 +13205,15 @@ function isHistoryEntry(value) {
13205
13205
 
13206
13206
  // src/hooks.ts
13207
13207
  import { spawn as spawn2 } from "node:child_process";
13208
- async function runHook(hookCmd, cwd, context, stderr, stdout2 = (chunk) => process.stdout.write(chunk)) {
13208
+ async function runHook(hookCmd, cwd, context, stderr, stdout3 = (chunk) => process.stdout.write(chunk)) {
13209
13209
  if (!hookCmd) return;
13210
13210
  if (Array.isArray(hookCmd)) {
13211
- await runArgvHook(hookCmd, cwd, context, stderr, stdout2);
13211
+ await runArgvHook(hookCmd, cwd, context, stderr, stdout3);
13212
13212
  return;
13213
13213
  }
13214
- await runShellHook(hookCmd, cwd, context, stderr, stdout2);
13214
+ await runShellHook(hookCmd, cwd, context, stderr, stdout3);
13215
13215
  }
13216
- async function runArgvHook(hookCmd, cwd, context, stderr, stdout2) {
13216
+ async function runArgvHook(hookCmd, cwd, context, stderr, stdout3) {
13217
13217
  const [command, ...args] = hookCmd.map((arg) => interpolate(arg, context));
13218
13218
  if (!command) {
13219
13219
  stderr("gji: hook argv command must include a non-empty command\n");
@@ -13227,7 +13227,7 @@ async function runArgvHook(hookCmd, cwd, context, stderr, stdout2) {
13227
13227
  env: hookEnvironment(context)
13228
13228
  });
13229
13229
  child.stdout.on("data", (chunk) => {
13230
- stdout2(chunk.toString());
13230
+ stdout3(chunk.toString());
13231
13231
  });
13232
13232
  child.stderr.on("data", (chunk) => {
13233
13233
  stderr(chunk.toString());
@@ -13248,7 +13248,7 @@ async function runArgvHook(hookCmd, cwd, context, stderr, stdout2) {
13248
13248
  });
13249
13249
  });
13250
13250
  }
13251
- async function runShellHook(hookCmd, cwd, context, stderr, stdout2) {
13251
+ async function runShellHook(hookCmd, cwd, context, stderr, stdout3) {
13252
13252
  const interpolated = interpolate(hookCmd, context);
13253
13253
  await new Promise((resolve13) => {
13254
13254
  const child = spawn2(interpolated, {
@@ -13258,7 +13258,7 @@ async function runShellHook(hookCmd, cwd, context, stderr, stdout2) {
13258
13258
  env: hookEnvironment(context)
13259
13259
  });
13260
13260
  child.stdout.on("data", (chunk) => {
13261
- stdout2(chunk.toString());
13261
+ stdout3(chunk.toString());
13262
13262
  });
13263
13263
  child.stderr.on("data", (chunk) => {
13264
13264
  stderr(chunk.toString());
@@ -13338,20 +13338,20 @@ import { promisify as promisify2 } from "node:util";
13338
13338
  var execFileAsync = promisify2(execFile);
13339
13339
  async function runGit(cwd, args) {
13340
13340
  try {
13341
- const { stdout: stdout2 } = await execFileAsync("git", args, { cwd });
13342
- return stdout2.trim();
13341
+ const { stdout: stdout3 } = await execFileAsync("git", args, { cwd });
13342
+ return stdout3.trim();
13343
13343
  } catch (error) {
13344
13344
  const message = error instanceof Error ? error.message : String(error);
13345
13345
  throw new Error(`Git command failed in '${cwd}': ${message}`);
13346
13346
  }
13347
13347
  }
13348
13348
  async function readWorktreeHealth(cwd) {
13349
- const { stdout: stdout2 } = await execFileAsync(
13349
+ const { stdout: stdout3 } = await execFileAsync(
13350
13350
  "git",
13351
13351
  ["status", "--porcelain=v2", "--branch"],
13352
13352
  { cwd }
13353
13353
  );
13354
- return parseWorktreeHealth(stdout2);
13354
+ return parseWorktreeHealth(stdout3);
13355
13355
  }
13356
13356
  async function isDirtyWorktree(cwd) {
13357
13357
  const health = await readWorktreeHealth(cwd);
@@ -13371,12 +13371,12 @@ async function isBranchMergedInto(cwd, branch, base = "HEAD") {
13371
13371
  }
13372
13372
  }
13373
13373
  async function resolveRemoteDefaultBranch(cwd, remote) {
13374
- const { stdout: stdout2 } = await execFileAsync(
13374
+ const { stdout: stdout3 } = await execFileAsync(
13375
13375
  "git",
13376
13376
  ["ls-remote", "--symref", remote, "HEAD"],
13377
13377
  { cwd }
13378
13378
  );
13379
- const refLine = stdout2.split("\n").find((line) => line.startsWith("ref: refs/heads/"));
13379
+ const refLine = stdout3.split("\n").find((line) => line.startsWith("ref: refs/heads/"));
13380
13380
  if (!refLine) {
13381
13381
  return null;
13382
13382
  }
@@ -13428,12 +13428,12 @@ async function resolveCachedRemoteDefaultBranch(cwd, remote) {
13428
13428
  }
13429
13429
  async function readBranchLastCommitTimestamp(cwd, branch) {
13430
13430
  try {
13431
- const { stdout: stdout2 } = await execFileAsync(
13431
+ const { stdout: stdout3 } = await execFileAsync(
13432
13432
  "git",
13433
13433
  ["log", "-1", "--format=%ct", branch],
13434
13434
  { cwd }
13435
13435
  );
13436
- const timestamp = Number(stdout2.trim());
13436
+ const timestamp = Number(stdout3.trim());
13437
13437
  return Number.isFinite(timestamp) ? timestamp : null;
13438
13438
  } catch {
13439
13439
  return null;
@@ -13629,14 +13629,14 @@ function findOptionalPorcelainValue(block, key) {
13629
13629
 
13630
13630
  // src/shell-handoff.ts
13631
13631
  import { writeFile as writeFile3 } from "node:fs/promises";
13632
- async function writeShellOutput(envVar, value, stdout2) {
13632
+ async function writeShellOutput(envVar, value, stdout3) {
13633
13633
  const output = `${value}
13634
13634
  `;
13635
13635
  if (process.env[envVar]) {
13636
13636
  await writeFile3(process.env[envVar], output, "utf8");
13637
13637
  return;
13638
13638
  }
13639
- stdout2(output);
13639
+ stdout3(output);
13640
13640
  }
13641
13641
 
13642
13642
  // src/back.ts
@@ -13752,8 +13752,9 @@ function formatAge(timestamp) {
13752
13752
 
13753
13753
  // node_modules/.pnpm/@clack+core@0.5.0/node_modules/@clack/core/dist/index.mjs
13754
13754
  var import_sisteransi = __toESM(require_src(), 1);
13755
- import { stdin as j, stdout as M } from "node:process";
13756
13755
  var import_picocolors = __toESM(require_picocolors(), 1);
13756
+ import { stdin as j, stdout as M } from "node:process";
13757
+ import * as g from "node:readline";
13757
13758
  import O from "node:readline";
13758
13759
  import { Writable as X } from "node:stream";
13759
13760
  function DD({ onlyFirst: e2 = false } = {}) {
@@ -13965,6 +13966,27 @@ function m(e2, u2) {
13965
13966
  const t = e2;
13966
13967
  t.isTTY && t.setRawMode(u2);
13967
13968
  }
13969
+ function fD({ input: e2 = j, output: u2 = M, overwrite: t = true, hideCursor: F2 = true } = {}) {
13970
+ const s = g.createInterface({ input: e2, output: u2, prompt: "", tabSize: 1 });
13971
+ g.emitKeypressEvents(e2, s), e2.isTTY && e2.setRawMode(true);
13972
+ const i = (D2, { name: C2, sequence: n }) => {
13973
+ const E = String(D2);
13974
+ if ($([E, C2, n], "cancel")) {
13975
+ F2 && u2.write(import_sisteransi.cursor.show), process.exit(0);
13976
+ return;
13977
+ }
13978
+ if (!t) return;
13979
+ const a = C2 === "return" ? 0 : -1, o2 = C2 === "return" ? -1 : 0;
13980
+ g.moveCursor(u2, a, o2, () => {
13981
+ g.clearLine(u2, 1, () => {
13982
+ e2.once("keypress", i);
13983
+ });
13984
+ });
13985
+ };
13986
+ return F2 && u2.write(import_sisteransi.cursor.hide), e2.once("keypress", i), () => {
13987
+ e2.off("keypress", i), F2 && u2.write(import_sisteransi.cursor.show), e2.isTTY && !AD && e2.setRawMode(false), s.terminal = false, s.close();
13988
+ };
13989
+ }
13968
13990
  var gD = Object.defineProperty;
13969
13991
  var vD = (e2, u2, t) => u2 in e2 ? gD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
13970
13992
  var h = (e2, u2, t) => (vD(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
@@ -14167,9 +14189,9 @@ var G2 = (t) => {
14167
14189
  const { cursor: n, options: r2, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5));
14168
14190
  let l2 = 0;
14169
14191
  n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r2.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
14170
- const $2 = a < r2.length && l2 > 0, g = a < r2.length && l2 + a < r2.length;
14192
+ const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
14171
14193
  return r2.slice(l2, l2 + a).map((p2, v2, f) => {
14172
- const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g;
14194
+ const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
14173
14195
  return j2 || E ? import_picocolors2.default.dim("...") : i(p2, v2 + l2 === n);
14174
14196
  });
14175
14197
  };
@@ -14279,6 +14301,53 @@ var M2 = { message: (t = "", { symbol: n = import_picocolors2.default.gray(o) }
14279
14301
  M2.message(t, { symbol: import_picocolors2.default.red(K2) });
14280
14302
  } };
14281
14303
  var J2 = `${import_picocolors2.default.gray(o)} `;
14304
+ var Y2 = ({ indicator: t = "dots" } = {}) => {
14305
+ const n = V2 ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], r2 = V2 ? 80 : 120, i = process.env.CI === "true";
14306
+ let s, c, a = false, l2 = "", $2, g2 = performance.now();
14307
+ const p2 = (m2) => {
14308
+ const h2 = m2 > 1 ? "Something went wrong" : "Canceled";
14309
+ a && N2(h2, m2);
14310
+ }, v2 = () => p2(2), f = () => p2(1), j2 = () => {
14311
+ process.on("uncaughtExceptionMonitor", v2), process.on("unhandledRejection", v2), process.on("SIGINT", f), process.on("SIGTERM", f), process.on("exit", p2);
14312
+ }, E = () => {
14313
+ process.removeListener("uncaughtExceptionMonitor", v2), process.removeListener("unhandledRejection", v2), process.removeListener("SIGINT", f), process.removeListener("SIGTERM", f), process.removeListener("exit", p2);
14314
+ }, B2 = () => {
14315
+ if ($2 === void 0) return;
14316
+ i && process.stdout.write(`
14317
+ `);
14318
+ const m2 = $2.split(`
14319
+ `);
14320
+ process.stdout.write(import_sisteransi2.cursor.move(-999, m2.length - 1)), process.stdout.write(import_sisteransi2.erase.down(m2.length));
14321
+ }, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
14322
+ const h2 = (performance.now() - m2) / 1e3, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
14323
+ return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
14324
+ }, H = (m2 = "") => {
14325
+ a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
14326
+ `);
14327
+ let h2 = 0, w2 = 0;
14328
+ j2(), c = setInterval(() => {
14329
+ if (i && l2 === $2) return;
14330
+ B2(), $2 = l2;
14331
+ const I2 = import_picocolors2.default.magenta(n[h2]);
14332
+ if (i) process.stdout.write(`${I2} ${l2}...`);
14333
+ else if (t === "timer") process.stdout.write(`${I2} ${l2} ${O2(g2)}`);
14334
+ else {
14335
+ const z2 = ".".repeat(Math.floor(w2)).slice(0, 3);
14336
+ process.stdout.write(`${I2} ${l2}${z2}`);
14337
+ }
14338
+ h2 = h2 + 1 < n.length ? h2 + 1 : 0, w2 = w2 < n.length ? w2 + 0.125 : 0;
14339
+ }, r2);
14340
+ }, N2 = (m2 = "", h2 = 0) => {
14341
+ a = false, clearInterval(c), B2();
14342
+ const w2 = h2 === 0 ? import_picocolors2.default.green(C) : h2 === 1 ? import_picocolors2.default.red(L2) : import_picocolors2.default.red(W2);
14343
+ l2 = R2(m2 ?? l2), t === "timer" ? process.stdout.write(`${w2} ${l2} ${O2(g2)}
14344
+ `) : process.stdout.write(`${w2} ${l2}
14345
+ `), E(), s();
14346
+ };
14347
+ return { start: H, stop: N2, message: (m2 = "") => {
14348
+ l2 = R2(m2 ?? l2);
14349
+ } };
14350
+ };
14282
14351
 
14283
14352
  // src/headless.ts
14284
14353
  function isHeadless() {
@@ -15263,8 +15332,8 @@ function providerRepositoryCoordinate(remote) {
15263
15332
  const coordinate = `${remote.namespace}/${remote.repository}`;
15264
15333
  return remote.host === "github.com" || remote.host === "bitbucket.org" ? coordinate : `${remote.host}/${coordinate}`;
15265
15334
  }
15266
- function parseProviderOutput(remote, stdout2, query) {
15267
- const payload = JSON.parse(stdout2);
15335
+ function parseProviderOutput(remote, stdout3, query) {
15336
+ const payload = JSON.parse(stdout3);
15268
15337
  const values = remote.forge === "bitbucket" && isRecord(payload) ? Array.isArray(payload.values) ? payload.values : [] : Array.isArray(payload) ? payload : [payload];
15269
15338
  return values.map((value) => normalizePullRequest(value, query)).filter((value) => value !== null).filter(
15270
15339
  (value) => query.kind === "branch" ? value.sourceBranch === query.sourceBranch : query.kind === "number" ? value.number === query.number : true
@@ -15416,6 +15485,18 @@ function isWideCodePoint(codePoint) {
15416
15485
  var MAX_PULL_REQUEST_REPOSITORY_QUERY_CONCURRENCY = 4;
15417
15486
  var MAX_TASK_READ_CONCURRENCY = 8;
15418
15487
  async function buildWorktreePromptEntries(sources, dependencies = {}) {
15488
+ const loading = stdin.isTTY === true && stdout.isTTY === true ? Y2({ indicator: "timer" }) : null;
15489
+ loading?.start("Loading worktrees");
15490
+ try {
15491
+ return await buildWorktreePromptEntriesWithoutLoading(
15492
+ sources,
15493
+ dependencies
15494
+ );
15495
+ } finally {
15496
+ loading?.stop();
15497
+ }
15498
+ }
15499
+ async function buildWorktreePromptEntriesWithoutLoading(sources, dependencies) {
15419
15500
  const metadataMode = dependencies.metadata ?? "full";
15420
15501
  const includeMetadata = metadataMode === "full";
15421
15502
  const pullRequestQuery = createPullRequestQuery();
@@ -16113,9 +16194,9 @@ function red(value) {
16113
16194
  function yellow(value) {
16114
16195
  return color("\x1B[33m", "\x1B[39m", value);
16115
16196
  }
16116
- function color(open3, close, value) {
16197
+ function color(open4, close, value) {
16117
16198
  if (env4.NO_COLOR !== void 0) return value;
16118
- return `${open3}${value}${close}`;
16199
+ return `${open4}${value}${close}`;
16119
16200
  }
16120
16201
  function supportsUnicode() {
16121
16202
  if (platform !== "win32") {
@@ -17581,8 +17662,8 @@ async function runConfigCommand(options) {
17581
17662
  `Invalid config arguments: ${[options.action, options.key, options.value].filter(Boolean).join(" ")}`
17582
17663
  );
17583
17664
  }
17584
- function writeJson(stdout2, value) {
17585
- stdout2(`${JSON.stringify(value, null, 2)}
17665
+ function writeJson(stdout3, value) {
17666
+ stdout3(`${JSON.stringify(value, null, 2)}
17586
17667
  `);
17587
17668
  }
17588
17669
 
@@ -18084,8 +18165,8 @@ function expandTilde2(path9, home) {
18084
18165
  }
18085
18166
  async function checkGitVersion() {
18086
18167
  try {
18087
- const { stdout: stdout2 } = await execFileAsync4("git", ["--version"]);
18088
- const version = parseGitVersion(stdout2);
18168
+ const { stdout: stdout3 } = await execFileAsync4("git", ["--version"]);
18169
+ const version = parseGitVersion(stdout3);
18089
18170
  if (!version) {
18090
18171
  return failedCheck(
18091
18172
  "git-version",
@@ -18604,7 +18685,7 @@ function toMessage3(error) {
18604
18685
  }
18605
18686
 
18606
18687
  // src/go.ts
18607
- import { basename as basename9 } from "node:path";
18688
+ import { basename as basename10 } from "node:path";
18608
18689
 
18609
18690
  // src/context-card.ts
18610
18691
  async function renderContextCard(worktreePath) {
@@ -18632,7 +18713,7 @@ function formatLastCommit2(info) {
18632
18713
 
18633
18714
  // src/pr.ts
18634
18715
  import { execFile as execFile7 } from "node:child_process";
18635
- import { mkdir as mkdir9 } from "node:fs/promises";
18716
+ import { mkdir as mkdir8 } from "node:fs/promises";
18636
18717
  import { dirname as dirname11 } from "node:path";
18637
18718
  import { promisify as promisify8 } from "node:util";
18638
18719
 
@@ -18653,7 +18734,6 @@ function formatBytes(bytes) {
18653
18734
  // src/bootstrap-output.ts
18654
18735
  function createBootstrapReporter(write, json, measureCloneSize = false) {
18655
18736
  return {
18656
- emitCachedFailureWarnings: !json,
18657
18737
  measureCloneSize: measureCloneSize && !json,
18658
18738
  write,
18659
18739
  cloned: (directory) => {
@@ -18682,248 +18762,22 @@ function formatDuration(ms) {
18682
18762
 
18683
18763
  // src/dependency-bootstrap.ts
18684
18764
  import { execFile as execFile6 } from "node:child_process";
18685
- import { lstat as lstat4, readFile as readFile10, realpath as realpath3, rm as rm5 } from "node:fs/promises";
18686
- import { join as join13, relative as relative2, resolve as resolve9, sep as sep2 } from "node:path";
18687
- import { promisify as promisify7 } from "node:util";
18688
-
18689
- // src/clone-failure-store.ts
18690
- import { randomUUID as randomUUID2 } from "node:crypto";
18765
+ import { constants as constants6 } from "node:fs";
18766
+ import { lstat as lstat4, open as open3, readdir as readdir2, readFile as readFile9, realpath as realpath3, rm as rm4 } from "node:fs/promises";
18691
18767
  import {
18692
- mkdir as mkdir6,
18693
- mkdtemp,
18694
- readdir,
18695
- readFile as readFile8,
18696
- rename as rename3,
18697
- rm as rm3,
18698
- rmdir,
18699
- stat as stat2,
18700
- unlink as unlink3,
18701
- utimes,
18702
- writeFile as writeFile8
18703
- } from "node:fs/promises";
18704
- import { homedir as homedir8 } from "node:os";
18705
- import { dirname as dirname8, join as join10, resolve as resolve7 } from "node:path";
18706
- var STATE_FILE_NAME = "state.json";
18707
- var STATE_LOCK_SUFFIX = ".lock";
18708
- var CLONE_FAILURE_TTL_MS = 24 * 60 * 60 * 1e3;
18709
- var STATE_LOCK_TTL_MS = 30 * 1e3;
18710
- var FileCloneFailureStore = class {
18711
- updateQueue = Promise.resolve();
18712
- async isCached(repoRoot, directory, scope) {
18713
- const state = await this.readState();
18714
- const repoState = state.syncDirs?.[repoRoot];
18715
- const key = failureKey(directory, scope);
18716
- if (!repoState || !Object.hasOwn(repoState, key)) return false;
18717
- const failure = repoState[key];
18718
- return isPlainObject2(failure) && typeof failure.failedAt === "number" && Date.now() - failure.failedAt < CLONE_FAILURE_TTL_MS;
18719
- }
18720
- async cache(repoRoot, directory, reason, scope) {
18721
- await this.update(async () => {
18722
- const state = await this.readState();
18723
- const syncDirs = state.syncDirs ?? {};
18724
- const repoState = syncDirs[repoRoot] ?? {};
18725
- const key = failureKey(directory, scope);
18726
- syncDirs[repoRoot] = {
18727
- ...repoState,
18728
- [key]: { failedAt: Date.now(), reason }
18729
- };
18730
- await this.writeState({ ...state, syncDirs });
18731
- });
18732
- }
18733
- async clear(repoRoot, directory, scope) {
18734
- await this.update(async () => {
18735
- const state = await this.readState();
18736
- const repoState = state.syncDirs?.[repoRoot];
18737
- const key = failureKey(directory, scope);
18738
- if (!repoState || !Object.hasOwn(repoState, key)) return;
18739
- const nextRepoState = { ...repoState };
18740
- delete nextRepoState[key];
18741
- const syncDirs = { ...state.syncDirs };
18742
- if (Object.keys(nextRepoState).length === 0) delete syncDirs[repoRoot];
18743
- else syncDirs[repoRoot] = nextRepoState;
18744
- await this.writeState({ ...state, syncDirs });
18745
- });
18746
- }
18747
- async update(operation) {
18748
- const next = this.updateQueue.then(
18749
- () => this.withStateLock(operation),
18750
- () => this.withStateLock(operation)
18751
- );
18752
- this.updateQueue = next.then(
18753
- () => void 0,
18754
- () => void 0
18755
- );
18756
- await next;
18757
- }
18758
- async withStateLock(operation) {
18759
- const lockPath = `${this.stateFilePath()}${STATE_LOCK_SUFFIX}`;
18760
- const lockToken = await acquireStateLock(lockPath);
18761
- if (lockToken === void 0) return;
18762
- const stopHeartbeat = startStateLockHeartbeat(lockPath, lockToken);
18763
- try {
18764
- await operation();
18765
- } finally {
18766
- stopHeartbeat();
18767
- await releaseStateLock(lockPath, lockToken);
18768
- }
18769
- }
18770
- async readState() {
18771
- try {
18772
- const raw = await readFile8(this.stateFilePath(), "utf8");
18773
- const parsed = JSON.parse(raw);
18774
- if (!isPlainObject2(parsed)) return {};
18775
- return isPlainObject2(parsed.syncDirs) ? parsed : { ...parsed, syncDirs: {} };
18776
- } catch {
18777
- return {};
18778
- }
18779
- }
18780
- async writeState(state) {
18781
- try {
18782
- const path9 = this.stateFilePath();
18783
- const directory = dirname8(path9);
18784
- await mkdir6(directory, { recursive: true });
18785
- const temporaryDirectory = await mkdtemp(
18786
- join10(directory, `.gji-state-${randomUUID2()}-`)
18787
- );
18788
- const temporaryPath = join10(temporaryDirectory, STATE_FILE_NAME);
18789
- try {
18790
- await writeFile8(
18791
- temporaryPath,
18792
- `${JSON.stringify(state, null, 2)}
18793
- `,
18794
- "utf8"
18795
- );
18796
- await rename3(temporaryPath, path9);
18797
- } finally {
18798
- await rm3(temporaryDirectory, { force: true, recursive: true });
18799
- }
18800
- } catch {
18801
- }
18802
- }
18803
- stateFilePath(home = homedir8()) {
18804
- const configuredDirectory = process.env.GJI_CONFIG_DIR;
18805
- const directory = configuredDirectory ? resolve7(configuredDirectory) : join10(home, GLOBAL_CONFIG_DIRECTORY);
18806
- return join10(directory, STATE_FILE_NAME);
18807
- }
18808
- };
18809
- async function acquireStateLock(lockPath) {
18810
- const lockToken = randomUUID2();
18811
- await mkdir6(dirname8(lockPath), { recursive: true }).catch(() => void 0);
18812
- for (let attempt = 0; attempt < 200; attempt += 1) {
18813
- try {
18814
- await mkdir6(lockPath);
18815
- } catch (error) {
18816
- if (!isErrorCode(error, "EEXIST")) return void 0;
18817
- try {
18818
- const freshnessPath = await lockFreshnessPath(lockPath);
18819
- const lockStats = await stat2(freshnessPath);
18820
- if (Date.now() - lockStats.mtimeMs >= STATE_LOCK_TTL_MS) {
18821
- const stalePath = `${lockPath}.stale-${randomUUID2()}`;
18822
- try {
18823
- await rename3(lockPath, stalePath);
18824
- } catch (renameError) {
18825
- if (isErrorCode(renameError, "ENOENT")) continue;
18826
- return void 0;
18827
- }
18828
- await rm3(stalePath, { force: true, recursive: true });
18829
- continue;
18830
- }
18831
- } catch (lockError) {
18832
- if (!isErrorCode(lockError, "ENOENT")) return void 0;
18833
- }
18834
- await new Promise((resolve13) => setTimeout(resolve13, 25));
18835
- continue;
18836
- }
18837
- try {
18838
- await writeFile8(
18839
- join10(lockPath, ownerFileName(lockToken)),
18840
- `${lockToken}
18841
- `,
18842
- {
18843
- flag: "wx"
18844
- }
18845
- );
18846
- return lockToken;
18847
- } catch {
18848
- await rm3(lockPath, { force: true, recursive: true }).catch(
18849
- () => void 0
18850
- );
18851
- return void 0;
18852
- }
18853
- }
18854
- return void 0;
18855
- }
18856
- async function lockFreshnessPath(lockPath) {
18857
- try {
18858
- const owner = (await readdir(lockPath)).find(
18859
- (entry) => entry.startsWith("owner-")
18860
- );
18861
- return owner ? join10(lockPath, owner) : lockPath;
18862
- } catch (error) {
18863
- if (isErrorCode(error, "ENOENT")) throw error;
18864
- return lockPath;
18865
- }
18866
- }
18867
- function startStateLockHeartbeat(lockPath, lockToken) {
18868
- const timer = setInterval(() => {
18869
- void refreshStateLock(lockPath, lockToken);
18870
- }, STATE_LOCK_TTL_MS / 3);
18871
- timer.unref?.();
18872
- return () => clearInterval(timer);
18873
- }
18874
- async function refreshStateLock(lockPath, lockToken) {
18875
- try {
18876
- const ownerPath = join10(lockPath, ownerFileName(lockToken));
18877
- await readFile8(ownerPath, "utf8");
18878
- const now = /* @__PURE__ */ new Date();
18879
- await utimes(ownerPath, now, now);
18880
- } catch {
18881
- }
18882
- }
18883
- async function releaseStateLock(lockPath, lockToken) {
18884
- try {
18885
- const ownerPath = join10(lockPath, ownerFileName(lockToken));
18886
- await unlink3(ownerPath);
18887
- await rmdir(lockPath);
18888
- } catch (error) {
18889
- if (!isErrorCode(error, "ENOENT") && !isErrorCode(error, "ENOTEMPTY")) {
18890
- return;
18891
- }
18892
- }
18893
- }
18894
- function ownerFileName(lockToken) {
18895
- return `owner-${lockToken}`;
18896
- }
18897
- var defaultCloneFailureStore = new FileCloneFailureStore();
18898
- async function cloneFailureScope(source, destination) {
18899
- const sourcePath = resolve7(source);
18900
- const destinationParent = resolve7(dirname8(destination));
18901
- const [sourceDevice, destinationDevice] = await Promise.all([
18902
- readDevice(sourcePath),
18903
- readDevice(destinationParent)
18904
- ]);
18905
- return JSON.stringify([sourcePath, sourceDevice, destinationDevice]);
18906
- }
18907
- async function readDevice(path9) {
18908
- try {
18909
- return (await stat2(path9)).dev;
18910
- } catch {
18911
- return void 0;
18912
- }
18913
- }
18914
- function failureKey(directory, scope) {
18915
- return scope === void 0 ? directory : JSON.stringify([scope, directory]);
18916
- }
18917
- function isPlainObject2(value) {
18918
- return typeof value === "object" && value !== null && !Array.isArray(value);
18919
- }
18920
- function isErrorCode(error, code) {
18921
- return error instanceof Error && "code" in error && error.code === code;
18922
- }
18768
+ basename as basename7,
18769
+ dirname as dirname9,
18770
+ isAbsolute as isAbsolute4,
18771
+ join as join12,
18772
+ relative as relative3,
18773
+ resolve as resolve9,
18774
+ sep as sep3
18775
+ } from "node:path";
18776
+ import { promisify as promisify7 } from "node:util";
18923
18777
 
18924
18778
  // src/command-runner.ts
18925
18779
  import { spawn as spawn4 } from "node:child_process";
18926
- var runCommand = async (command, cwd, stderr, stdout2 = (chunk) => process.stdout.write(chunk), options) => {
18780
+ var runCommand = async (command, cwd, stderr, stdout3 = (chunk) => process.stdout.write(chunk), options) => {
18927
18781
  await new Promise((resolve13, reject) => {
18928
18782
  const shell = options?.shell ?? true;
18929
18783
  const [executable, args] = shell ? [command, []] : splitCommand(command);
@@ -18934,7 +18788,7 @@ var runCommand = async (command, cwd, stderr, stdout2 = (chunk) => process.stdou
18934
18788
  stdio: ["ignore", "pipe", "pipe"]
18935
18789
  });
18936
18790
  child.stdout.on("data", (chunk) => {
18937
- stdout2(chunk.toString());
18791
+ stdout3(chunk.toString());
18938
18792
  });
18939
18793
  child.stderr.on("data", (chunk) => {
18940
18794
  stderr(chunk.toString());
@@ -18961,28 +18815,28 @@ function splitCommand(command) {
18961
18815
 
18962
18816
  // src/dir-clone.ts
18963
18817
  import { execFile as execFile5 } from "node:child_process";
18964
- import { randomUUID as randomUUID3 } from "node:crypto";
18818
+ import { randomUUID as randomUUID2 } from "node:crypto";
18965
18819
  import { constants as constants5 } from "node:fs";
18966
18820
  import {
18967
18821
  chmod,
18968
18822
  cp,
18969
18823
  lstat as lstat3,
18970
- mkdir as mkdir8,
18971
- mkdtemp as mkdtemp2,
18824
+ mkdir as mkdir7,
18825
+ mkdtemp,
18972
18826
  opendir,
18973
- readdir as readdir2,
18974
- readFile as readFile9,
18827
+ readdir,
18828
+ readFile as readFile8,
18975
18829
  readlink,
18976
18830
  realpath as realpath2,
18977
- rename as rename4,
18978
- rm as rm4,
18979
- rmdir as rmdir2,
18831
+ rename as rename3,
18832
+ rm as rm3,
18833
+ rmdir,
18980
18834
  symlink,
18981
- unlink as unlink4,
18982
- utimes as utimes2,
18983
- writeFile as writeFile9
18835
+ unlink as unlink3,
18836
+ utimes,
18837
+ writeFile as writeFile8
18984
18838
  } from "node:fs/promises";
18985
- import { basename as basename6, dirname as dirname9, join as join12 } from "node:path";
18839
+ import { basename as basename6, dirname as dirname8, join as join11, relative as relative2, resolve as resolve8, sep as sep2 } from "node:path";
18986
18840
  import { promisify as promisify6 } from "node:util";
18987
18841
 
18988
18842
  // src/fs-utils.ts
@@ -19011,20 +18865,30 @@ function hasErrorCode(error, code) {
19011
18865
 
19012
18866
  // src/safe-destination.ts
19013
18867
  import { constants as constants4 } from "node:fs";
19014
- import { lstat as lstat2, mkdir as mkdir7, open as open2 } from "node:fs/promises";
19015
- import { isAbsolute as isAbsolute3, join as join11, relative, resolve as resolve8, sep } from "node:path";
18868
+ import { lstat as lstat2, mkdir as mkdir6, open as open2 } from "node:fs/promises";
18869
+ import { isAbsolute as isAbsolute3, join as join10, relative, resolve as resolve7, sep } from "node:path";
19016
18870
  async function openDestinationDirectory(root, path9) {
19017
18871
  const segments = destinationSegments(root, path9);
18872
+ if (process.platform === "darwin") {
18873
+ await ensureDestinationDirectory(root, path9);
18874
+ const handle2 = await open2(path9, destinationDirectoryFlags());
18875
+ return {
18876
+ path: resolve7(path9),
18877
+ close: async () => handle2.close()
18878
+ };
18879
+ }
19018
18880
  if (process.platform !== "linux") {
19019
18881
  await ensureDestinationDirectory(root, path9);
19020
- return { path: resolve8(path9), close: async () => void 0 };
18882
+ const handle2 = await open2(path9, destinationDirectoryFlags());
18883
+ await handle2.close();
18884
+ return { path: resolve7(path9), close: async () => void 0 };
19021
18885
  }
19022
18886
  let handle = await open2(root, destinationDirectoryFlags());
19023
18887
  try {
19024
18888
  for (const segment of segments) {
19025
- const childPath = join11(fileDescriptorPath(handle.fd), segment);
18889
+ const childPath = join10(fileDescriptorPath(handle.fd), segment);
19026
18890
  try {
19027
- await mkdir7(childPath);
18891
+ await mkdir6(childPath);
19028
18892
  } catch (error) {
19029
18893
  if (!isAlreadyExistsError(error)) throw error;
19030
18894
  }
@@ -19042,8 +18906,8 @@ async function openDestinationDirectory(root, path9) {
19042
18906
  }
19043
18907
  }
19044
18908
  async function inspectDestination(root, path9) {
19045
- const resolvedPath = resolve8(path9);
19046
- const resolvedRoot = resolve8(root);
18909
+ const resolvedPath = resolve7(path9);
18910
+ const resolvedRoot = resolve7(root);
19047
18911
  const distance = relative(resolvedRoot, resolvedPath);
19048
18912
  if (isAbsolute3(distance) || distance === ".." || distance.startsWith(`..${sep}`)) {
19049
18913
  return { kind: "unsafe", reason: "destination escapes the worktree" };
@@ -19060,7 +18924,7 @@ async function inspectDestination(root, path9) {
19060
18924
  }
19061
18925
  const segments = distance.split(sep).filter(Boolean);
19062
18926
  for (const [index, segment] of segments.entries()) {
19063
- current = resolve8(current, segment);
18927
+ current = resolve7(current, segment);
19064
18928
  try {
19065
18929
  const stats = await lstat2(current);
19066
18930
  if (stats.isSymbolicLink()) {
@@ -19101,8 +18965,8 @@ async function inspectDestination(root, path9) {
19101
18965
  }
19102
18966
  }
19103
18967
  function destinationSegments(root, path9) {
19104
- const resolvedRoot = resolve8(root);
19105
- const resolvedPath = resolve8(path9);
18968
+ const resolvedRoot = resolve7(root);
18969
+ const resolvedPath = resolve7(path9);
19106
18970
  const distance = relative(resolvedRoot, resolvedPath);
19107
18971
  if (isAbsolute3(distance) || distance === ".." || distance.startsWith(`..${sep}`)) {
19108
18972
  throw new Error("destination escapes the worktree");
@@ -19120,8 +18984,8 @@ function fileDescriptorPath(fd) {
19120
18984
  );
19121
18985
  }
19122
18986
  async function ensureDestinationDirectory(root, path9) {
19123
- const resolvedRoot = resolve8(root);
19124
- const resolvedPath = resolve8(path9);
18987
+ const resolvedRoot = resolve7(root);
18988
+ const resolvedPath = resolve7(path9);
19125
18989
  const distance = relative(resolvedRoot, resolvedPath);
19126
18990
  if (isAbsolute3(distance) || distance === ".." || distance.startsWith(`..${sep}`)) {
19127
18991
  throw new Error("destination escapes the worktree");
@@ -19132,7 +18996,7 @@ async function ensureDestinationDirectory(root, path9) {
19132
18996
  throw new Error("worktree root is not a directory");
19133
18997
  }
19134
18998
  for (const segment of distance.split(sep).filter(Boolean)) {
19135
- current = resolve8(current, segment);
18999
+ current = resolve7(current, segment);
19136
19000
  try {
19137
19001
  const stats = await lstat2(current);
19138
19002
  if (stats.isSymbolicLink() || !stats.isDirectory()) {
@@ -19141,7 +19005,7 @@ async function ensureDestinationDirectory(root, path9) {
19141
19005
  } catch (error) {
19142
19006
  if (!isNotFoundError(error)) throw error;
19143
19007
  try {
19144
- await mkdir7(current);
19008
+ await mkdir6(current);
19145
19009
  } catch (mkdirError) {
19146
19010
  if (!isAlreadyExistsError(mkdirError)) throw mkdirError;
19147
19011
  }
@@ -19155,13 +19019,13 @@ async function ensureDestinationDirectory(root, path9) {
19155
19019
 
19156
19020
  // src/dir-clone.ts
19157
19021
  var execFileAsync5 = promisify6(execFile5);
19158
- var CLONE_LOCK_TTL_MS = 24 * 60 * 60 * 1e3;
19022
+ var CLONE_LOCK_TTL_MS = 5 * 60 * 1e3;
19023
+ var CLONE_GUARD_TTL_MS = 30 * 1e3;
19159
19024
  var CLONE_LOCK_SUFFIX = ".gji-clone-lock";
19160
19025
  var SIZE_ESTIMATE_MAX_ENTRIES = 1e6;
19161
19026
  var SIZE_ESTIMATE_MAX_MS = 5e3;
19162
19027
  async function cloneDir(source, destination, options = {}) {
19163
19028
  const platform3 = options.platform ?? process.platform;
19164
- const strategy = cloneStrategy(platform3);
19165
19029
  if (!isClonePlatformSupported(platform3)) {
19166
19030
  throw new CloneUnsupportedError(`platform ${platform3} has no CoW strategy`);
19167
19031
  }
@@ -19170,11 +19034,13 @@ async function cloneDir(source, destination, options = {}) {
19170
19034
  if (!sourceStats.isDirectory()) {
19171
19035
  throw new Error("source is not a directory");
19172
19036
  }
19173
- if (await destinationExists(destination)) {
19174
- throw new CloneDestinationExistsError(destination);
19037
+ const destinationPath = await resolveProspectivePath(destination);
19038
+ const destinationDistance = relative2(sourcePath, destinationPath);
19039
+ if (destinationDistance === "" || destinationDistance !== ".." && !destinationDistance.startsWith(`..${sep2}`)) {
19040
+ throw new Error("clone destination must not be inside its source");
19175
19041
  }
19176
19042
  const startedAt = Date.now();
19177
- const parent = dirname9(destination);
19043
+ const parent = dirname8(destination);
19178
19044
  let safeParent;
19179
19045
  try {
19180
19046
  if (options.destinationRoot) {
@@ -19190,37 +19056,36 @@ async function cloneDir(source, destination, options = {}) {
19190
19056
  parent
19191
19057
  );
19192
19058
  } else {
19193
- await mkdir8(parent, { recursive: true });
19059
+ await mkdir7(parent, { recursive: true });
19194
19060
  }
19195
19061
  const operationParent = safeParent?.path ?? parent;
19196
- const operationDestination = join12(operationParent, basename6(destination));
19197
- if (await destinationExists(operationDestination)) {
19198
- throw new CloneDestinationExistsError(destination);
19199
- }
19200
- const lockPath = `${destination}${CLONE_LOCK_SUFFIX}`;
19201
- const lockToken = await acquireCloneLock(lockPath, destination);
19202
- const stopLockHeartbeat = startLockHeartbeat(lockPath, lockToken);
19062
+ const operationDestination = join11(operationParent, basename6(destination));
19063
+ const cloneLock = await acquireCloneLock(
19064
+ `${operationDestination}${CLONE_LOCK_SUFFIX}`,
19065
+ destination
19066
+ );
19067
+ const stopLockHeartbeat = startLockHeartbeat(cloneLock);
19203
19068
  let temporaryRoot;
19204
- let reservationPath;
19205
- const reservationEntries = [];
19069
+ let reservation;
19070
+ const publishedEntries = [];
19206
19071
  try {
19207
- reservationPath = await reserveDestination(operationDestination);
19208
- temporaryRoot = await mkdtemp2(
19209
- join12(operationParent, `.${basename6(destination)}.gji-clone-`)
19072
+ if (await destinationExists(operationDestination)) {
19073
+ throw new CloneDestinationExistsError(destination);
19074
+ }
19075
+ reservation = await reserveDestination(operationDestination);
19076
+ temporaryRoot = await mkdtemp(
19077
+ join11(operationParent, `.${basename6(destination)}.gji-clone-`)
19210
19078
  );
19211
- const temporaryDestination = join12(temporaryRoot, basename6(destination));
19212
- const copyDirectory = options.copyDirectory ?? (platformIsDarwin(platform3) ? runNativeCloneDirectory : async (source2, target) => {
19213
- if (!strategy) {
19214
- throw new CloneUnsupportedError(
19215
- `platform ${platform3} has no CoW strategy`
19216
- );
19217
- }
19218
- const runCommand2 = options.runCommand ?? runCloneCommand;
19219
- await runCommand2("cp", strategy(source2, target));
19220
- });
19079
+ const temporaryDestination = join11(temporaryRoot, basename6(destination));
19221
19080
  try {
19222
- await copyDirectory(sourcePath, temporaryDestination);
19081
+ await (options.copyDirectory ?? ((sourcePath2, targetPath) => copyDirectoryWithCow(
19082
+ sourcePath2,
19083
+ targetPath,
19084
+ platform3,
19085
+ options.runLinuxCommand
19086
+ )))(sourcePath, temporaryDestination);
19223
19087
  } catch (error) {
19088
+ if (error instanceof CloneUnsupportedError) throw error;
19224
19089
  if (isUnsupportedCloneError(error)) {
19225
19090
  throw new CloneUnsupportedError(toErrorMessage(error));
19226
19091
  }
@@ -19229,45 +19094,70 @@ async function cloneDir(source, destination, options = {}) {
19229
19094
  await publishCloneContents(
19230
19095
  temporaryDestination,
19231
19096
  operationDestination,
19232
- reservationPath,
19233
- (entry) => reservationEntries.push(entry),
19097
+ reservation.path,
19098
+ (entry) => publishedEntries.push(entry),
19234
19099
  options.copyFile ?? runForcedCloneFileCopy
19235
19100
  );
19236
- reservationPath = void 0;
19101
+ reservation = void 0;
19237
19102
  } finally {
19238
19103
  stopLockHeartbeat();
19239
- if (reservationPath) {
19104
+ if (reservation) {
19240
19105
  await cleanupReservedDestination(
19241
19106
  operationDestination,
19242
- reservationPath,
19243
- reservationEntries
19107
+ reservation,
19108
+ publishedEntries
19244
19109
  );
19245
19110
  }
19246
- try {
19247
- if (temporaryRoot) {
19248
- await rm4(temporaryRoot, { force: true, recursive: true });
19249
- }
19250
- } catch {
19251
- }
19252
- try {
19253
- await releaseCloneLock(lockPath, lockToken);
19254
- } catch {
19111
+ if (temporaryRoot) {
19112
+ await rm3(temporaryRoot, { force: true, recursive: true }).catch(
19113
+ () => void 0
19114
+ );
19255
19115
  }
19116
+ await releaseCloneLock(cloneLock).catch(() => void 0);
19256
19117
  }
19257
- const bytes = options.measureBytes === false ? void 0 : await estimateCloneBytes(sourcePath);
19258
- return { bytes, ms: Date.now() - startedAt };
19118
+ return cloneResult(sourcePath, startedAt, options.measureBytes);
19259
19119
  } finally {
19260
19120
  await safeParent?.close().catch(() => void 0);
19261
19121
  }
19262
19122
  }
19263
- async function runNativeCloneDirectory(source, destination) {
19264
- await cp(source, destination, {
19265
- errorOnExist: true,
19266
- force: false,
19267
- mode: constants5.COPYFILE_FICLONE_FORCE,
19268
- preserveTimestamps: true,
19269
- recursive: true
19270
- });
19123
+ async function copyDirectoryWithCow(source, destination, platform3, runLinuxCommand) {
19124
+ if (platform3 === "darwin") {
19125
+ await cp(source, destination, {
19126
+ errorOnExist: true,
19127
+ force: false,
19128
+ mode: constants5.COPYFILE_FICLONE_FORCE,
19129
+ preserveTimestamps: true,
19130
+ recursive: true
19131
+ });
19132
+ return;
19133
+ }
19134
+ const strategy = cloneStrategy(platform3);
19135
+ if (!strategy) {
19136
+ throw new CloneUnsupportedError(`platform ${platform3} has no CoW strategy`);
19137
+ }
19138
+ await (runLinuxCommand ?? runCloneCommand)(
19139
+ "cp",
19140
+ strategy(source, destination)
19141
+ );
19142
+ }
19143
+ async function resolveProspectivePath(path9) {
19144
+ let current = resolve8(path9);
19145
+ const missing = [];
19146
+ while (true) {
19147
+ try {
19148
+ return join11(await realpath2(current), ...missing);
19149
+ } catch (error) {
19150
+ if (!isNotFoundError(error)) throw error;
19151
+ const parent = dirname8(current);
19152
+ if (parent === current) throw error;
19153
+ missing.unshift(basename6(current));
19154
+ current = parent;
19155
+ }
19156
+ }
19157
+ }
19158
+ async function cloneResult(source, startedAt, measureBytes) {
19159
+ const bytes = measureBytes === false ? void 0 : await estimateCloneBytes(source);
19160
+ return { bytes, ms: Date.now() - startedAt };
19271
19161
  }
19272
19162
  var CloneDestinationExistsError = class extends Error {
19273
19163
  code = "GJI_CLONE_DESTINATION_EXISTS";
@@ -19293,9 +19183,6 @@ var CloneInProgressError = class extends Error {
19293
19183
  function isCloneDestinationExistsError(error) {
19294
19184
  return error instanceof CloneDestinationExistsError;
19295
19185
  }
19296
- function isCloneUnsupportedError(error) {
19297
- return error instanceof CloneUnsupportedError || isUnsupportedCloneError(error);
19298
- }
19299
19186
  function isCloneInProgressError(error) {
19300
19187
  return error instanceof CloneInProgressError;
19301
19188
  }
@@ -19316,7 +19203,7 @@ async function directorySize(path9) {
19316
19203
  if (entryCount > SIZE_ESTIMATE_MAX_ENTRIES || Date.now() - startedAt > SIZE_ESTIMATE_MAX_MS) {
19317
19204
  throw new Error("directory size estimate exceeded its safety limit");
19318
19205
  }
19319
- const entryPath = join12(current, entry.name);
19206
+ const entryPath = join11(current, entry.name);
19320
19207
  if (entry.isDirectory()) pending.push(entryPath);
19321
19208
  else total += (await lstat3(entryPath)).size;
19322
19209
  }
@@ -19358,119 +19245,231 @@ async function runCloneCommand(command, args) {
19358
19245
  }
19359
19246
  }
19360
19247
  async function acquireCloneLock(lockPath, destination) {
19361
- const lockToken = randomUUID3();
19248
+ const releaseGuard = await acquireCloneLockGuard(lockPath, destination);
19249
+ try {
19250
+ return await acquireCloneLockWithGuard(lockPath, destination);
19251
+ } finally {
19252
+ await releaseGuard();
19253
+ }
19254
+ }
19255
+ async function acquireCloneLockWithGuard(lockPath, destination) {
19256
+ const lockToken = randomUUID2();
19362
19257
  for (let attempt = 0; attempt < 3; attempt += 1) {
19258
+ const published = await publishCloneLock(lockPath, lockToken);
19259
+ if (published) return published;
19260
+ let staleLock;
19363
19261
  try {
19364
- await mkdir8(lockPath);
19365
- try {
19366
- await writeFile9(
19367
- join12(lockPath, ownerFileName2(lockToken)),
19368
- `${lockToken}
19369
- `,
19370
- {
19371
- flag: "wx"
19372
- }
19373
- );
19374
- } catch (error) {
19375
- await rm4(lockPath, { force: true, recursive: true });
19376
- throw error;
19377
- }
19378
- return lockToken;
19379
- } catch (error) {
19380
- if (!isAlreadyExistsError(error)) throw error;
19381
- }
19382
- let lockStats;
19383
- try {
19384
- lockStats = await lstat3(await lockFreshnessPath2(lockPath));
19262
+ staleLock = await inspectCloneLock(lockPath);
19385
19263
  } catch (error) {
19386
19264
  if (isNotFoundError(error)) continue;
19387
19265
  throw error;
19388
19266
  }
19389
- if (Date.now() - lockStats.mtimeMs < CLONE_LOCK_TTL_MS) {
19267
+ if (staleLock.kind === "invalid" || Date.now() - staleLock.mtimeMs < CLONE_LOCK_TTL_MS) {
19390
19268
  throw new CloneInProgressError(destination);
19391
19269
  }
19392
- const stalePath = `${lockPath}.stale-${randomUUID3()}`;
19270
+ const stalePath = `${lockPath}.stale-${randomUUID2()}`;
19393
19271
  try {
19394
- await rename4(lockPath, stalePath);
19272
+ await rename3(lockPath, stalePath);
19395
19273
  } catch (error) {
19396
19274
  if (isNotFoundError(error)) continue;
19397
19275
  throw error;
19398
19276
  }
19399
19277
  try {
19400
- await mkdir8(lockPath);
19401
- try {
19402
- await writeFile9(
19403
- join12(lockPath, ownerFileName2(lockToken)),
19404
- `${lockToken}
19405
- `,
19406
- {
19407
- flag: "wx"
19408
- }
19409
- );
19410
- } catch (error) {
19411
- await rm4(lockPath, { force: true, recursive: true });
19412
- throw error;
19278
+ const replacement = await publishCloneLock(lockPath, lockToken);
19279
+ if (!replacement) {
19280
+ await cleanupStaleCloneLock(stalePath, staleLock);
19281
+ continue;
19413
19282
  }
19414
19283
  try {
19415
- await rm4(stalePath, { force: true, recursive: true });
19284
+ await cleanupStaleCloneLock(stalePath, staleLock);
19416
19285
  } catch (cleanupError) {
19417
- await releaseCloneLock(lockPath, lockToken).catch(() => void 0);
19286
+ await releaseCloneLockWithGuard(replacement).catch(() => void 0);
19418
19287
  throw cleanupError;
19419
19288
  }
19420
- return lockToken;
19289
+ return replacement;
19421
19290
  } catch (error) {
19422
- await rm4(stalePath, { force: true, recursive: true }).catch(
19423
- () => void 0
19424
- );
19291
+ await cleanupStaleCloneLock(stalePath, staleLock).catch(() => void 0);
19425
19292
  if (isAlreadyExistsError(error)) continue;
19426
19293
  throw error;
19427
19294
  }
19428
19295
  }
19429
19296
  throw new CloneInProgressError(destination);
19430
19297
  }
19431
- async function lockFreshnessPath2(lockPath) {
19298
+ async function acquireCloneLockGuard(lockPath, destination) {
19299
+ const guardPath = `${lockPath}.guard`;
19300
+ const deadline = Date.now() + 5e3;
19301
+ while (true) {
19302
+ try {
19303
+ await mkdir7(guardPath, { mode: 448 });
19304
+ const markerName = `${process.pid}-${randomUUID2()}`;
19305
+ const markerPath = join11(guardPath, markerName);
19306
+ try {
19307
+ await writeFile8(markerPath, `${markerName}
19308
+ `, {
19309
+ flag: "wx",
19310
+ mode: 384
19311
+ });
19312
+ } catch (error) {
19313
+ await rmdir(guardPath).catch(() => void 0);
19314
+ throw error;
19315
+ }
19316
+ return async () => {
19317
+ await unlink3(markerPath).catch((error) => {
19318
+ if (!isNotFoundError(error)) throw error;
19319
+ });
19320
+ await rmdir(guardPath).catch((error) => {
19321
+ if (!isNotFoundError(error)) throw error;
19322
+ });
19323
+ };
19324
+ } catch (error) {
19325
+ if (!isAlreadyExistsError(error)) throw error;
19326
+ if (await reclaimAbandonedCloneGuard(guardPath)) continue;
19327
+ if (Date.now() >= deadline) {
19328
+ throw new CloneInProgressError(destination);
19329
+ }
19330
+ await new Promise((resolve13) => setTimeout(resolve13, 10));
19331
+ }
19332
+ }
19333
+ }
19334
+ async function reclaimAbandonedCloneGuard(guardPath) {
19335
+ let expectedMarker;
19432
19336
  try {
19433
- const entries = await readdir2(lockPath);
19434
- const owner = entries.find((entry) => entry.startsWith("owner-"));
19435
- return owner ? join12(lockPath, owner) : lockPath;
19337
+ const entries = await readdir(guardPath);
19338
+ if (entries.length > 1) return false;
19339
+ expectedMarker = entries[0];
19340
+ const freshnessPath = expectedMarker ? join11(guardPath, expectedMarker) : guardPath;
19341
+ const stats = await lstat3(freshnessPath);
19342
+ if (Date.now() - stats.mtimeMs < CLONE_GUARD_TTL_MS) return false;
19343
+ if (expectedMarker) {
19344
+ const ownerPid = Number(expectedMarker.split("-", 1)[0]);
19345
+ if (!Number.isSafeInteger(ownerPid) || ownerPid <= 0) return false;
19346
+ if (processIsAlive(ownerPid)) return false;
19347
+ }
19348
+ } catch (error) {
19349
+ return isNotFoundError(error);
19350
+ }
19351
+ const stalePath = `${guardPath}.stale-${randomUUID2()}`;
19352
+ try {
19353
+ await rename3(guardPath, stalePath);
19354
+ } catch (error) {
19355
+ if (isNotFoundError(error)) return true;
19356
+ throw error;
19357
+ }
19358
+ const movedEntries = await readdir(stalePath).catch(() => []);
19359
+ if (movedEntries.length !== (expectedMarker ? 1 : 0) || expectedMarker && movedEntries[0] !== expectedMarker) {
19360
+ await rename3(stalePath, guardPath).catch(() => void 0);
19361
+ return false;
19362
+ }
19363
+ if (expectedMarker) await unlink3(join11(stalePath, expectedMarker));
19364
+ await rmdir(stalePath);
19365
+ return true;
19366
+ }
19367
+ function processIsAlive(pid) {
19368
+ try {
19369
+ process.kill(pid, 0);
19370
+ return true;
19371
+ } catch (error) {
19372
+ return error.code === "EPERM";
19373
+ }
19374
+ }
19375
+ async function publishCloneLock(lockPath, lockToken) {
19376
+ try {
19377
+ await mkdir7(lockPath, { mode: 448 });
19378
+ } catch (error) {
19379
+ if (isAlreadyExistsError(error)) return void 0;
19380
+ throw error;
19381
+ }
19382
+ const markerPath = join11(lockPath, lockToken);
19383
+ try {
19384
+ await writeFile8(markerPath, `${lockToken}
19385
+ `, { flag: "wx", mode: 384 });
19386
+ return {
19387
+ lockPath,
19388
+ markerName: lockToken,
19389
+ markerPath,
19390
+ token: lockToken
19391
+ };
19392
+ } catch (error) {
19393
+ await rmdir(lockPath).catch(() => void 0);
19394
+ throw error;
19395
+ }
19396
+ }
19397
+ async function inspectCloneLock(lockPath) {
19398
+ try {
19399
+ const stats = await lstat3(lockPath);
19400
+ if (!stats.isDirectory() || stats.isSymbolicLink()) {
19401
+ return { kind: "invalid", mtimeMs: stats.mtimeMs };
19402
+ }
19403
+ const entries = await readdir(lockPath);
19404
+ if (entries.length === 0) return { kind: "empty", mtimeMs: stats.mtimeMs };
19405
+ if (entries.length !== 1) {
19406
+ return { kind: "invalid", mtimeMs: stats.mtimeMs };
19407
+ }
19408
+ const markerName = entries[0];
19409
+ const token = markerName?.startsWith("owner-") ? markerName.slice("owner-".length) : markerName;
19410
+ if (!token || !/^[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}$/iu.test(token)) {
19411
+ return { kind: "invalid", mtimeMs: stats.mtimeMs };
19412
+ }
19413
+ const markerPath = join11(lockPath, markerName);
19414
+ const markerStats = await lstat3(markerPath);
19415
+ if (!markerStats.isFile() || markerStats.isSymbolicLink()) {
19416
+ return { kind: "invalid", mtimeMs: markerStats.mtimeMs };
19417
+ }
19418
+ if ((await readFile8(markerPath, "utf8")).trim() !== token) {
19419
+ return { kind: "invalid", mtimeMs: markerStats.mtimeMs };
19420
+ }
19421
+ return {
19422
+ kind: "owned",
19423
+ lockPath,
19424
+ markerName,
19425
+ markerPath,
19426
+ mtimeMs: markerStats.mtimeMs,
19427
+ token
19428
+ };
19436
19429
  } catch (error) {
19437
19430
  if (isNotFoundError(error)) throw error;
19438
- return lockPath;
19431
+ return { kind: "invalid", mtimeMs: Date.now() };
19432
+ }
19433
+ }
19434
+ async function cleanupStaleCloneLock(lockPath, inspection) {
19435
+ if (inspection.kind === "owned") {
19436
+ await unlink3(join11(lockPath, inspection.markerName));
19439
19437
  }
19438
+ await rmdir(lockPath);
19440
19439
  }
19441
19440
  async function publishCloneContents(temporaryDestination, destination, reservationPath, onEntryPublished, copyFileEntry) {
19442
19441
  const reservationName = basename6(reservationPath);
19443
- const destinationEntries = await readdir2(destination);
19442
+ const destinationEntries = await readdir(destination);
19444
19443
  if (destinationEntries.length !== 1 || destinationEntries[0] !== reservationName) {
19445
19444
  throw new CloneDestinationExistsError(destination);
19446
19445
  }
19447
- const temporaryEntries = await readdir2(temporaryDestination);
19446
+ const temporaryEntries = await readdir(temporaryDestination);
19448
19447
  for (const entry of temporaryEntries) {
19449
19448
  await publishCloneEntry(
19450
- join12(temporaryDestination, entry),
19451
- join12(destination, entry),
19452
- () => onEntryPublished(entry),
19449
+ join11(temporaryDestination, entry),
19450
+ join11(destination, entry),
19451
+ (entry2) => onEntryPublished(entry2),
19453
19452
  copyFileEntry
19454
19453
  );
19455
19454
  }
19456
- await unlink4(reservationPath);
19455
+ await unlink3(reservationPath);
19457
19456
  }
19458
19457
  async function publishCloneEntry(source, destination, onCreated, copyFileEntry) {
19459
19458
  const sourceStats = await lstat3(source);
19460
19459
  if (sourceStats.isDirectory()) {
19461
19460
  try {
19462
- await mkdir8(destination);
19461
+ await mkdir7(destination);
19463
19462
  } catch (error) {
19464
19463
  if (isAlreadyExistsError(error)) {
19465
19464
  throw new CloneDestinationExistsError(destination);
19466
19465
  }
19467
19466
  throw error;
19468
19467
  }
19469
- onCreated();
19470
- for (const entry of await readdir2(source)) {
19468
+ onCreated(await inspectOwnedCloneEntry(destination, "directory"));
19469
+ for (const entry of await readdir(source)) {
19471
19470
  await publishCloneEntry(
19472
- join12(source, entry),
19473
- join12(destination, entry),
19471
+ join11(source, entry),
19472
+ join11(destination, entry),
19474
19473
  () => void 0,
19475
19474
  copyFileEntry
19476
19475
  );
@@ -19487,7 +19486,7 @@ async function publishCloneEntry(source, destination, onCreated, copyFileEntry)
19487
19486
  }
19488
19487
  throw error;
19489
19488
  }
19490
- onCreated();
19489
+ onCreated(await inspectOwnedCloneEntry(destination, "symlink"));
19491
19490
  return;
19492
19491
  }
19493
19492
  if (!sourceStats.isFile()) {
@@ -19504,7 +19503,7 @@ async function publishCloneEntry(source, destination, onCreated, copyFileEntry)
19504
19503
  }
19505
19504
  throw error;
19506
19505
  }
19507
- onCreated();
19506
+ onCreated(await inspectOwnedCloneEntry(destination, "file"));
19508
19507
  await copyCloneMetadata(sourceStats, destination);
19509
19508
  }
19510
19509
  async function runForcedCloneFileCopy(source, destination) {
@@ -19517,41 +19516,47 @@ async function runForcedCloneFileCopy(source, destination) {
19517
19516
  }
19518
19517
  async function copyCloneMetadata(sourceStats, destination) {
19519
19518
  await chmod(destination, Number(sourceStats.mode) & 4095);
19520
- await utimes2(destination, sourceStats.atime, sourceStats.mtime);
19519
+ await utimes(destination, sourceStats.atime, sourceStats.mtime);
19521
19520
  }
19522
19521
  async function reserveDestination(destination) {
19523
19522
  try {
19524
- await mkdir8(destination);
19523
+ await mkdir7(destination);
19525
19524
  } catch (error) {
19526
19525
  if (isAlreadyExistsError(error)) {
19527
19526
  throw new CloneDestinationExistsError(destination);
19528
19527
  }
19529
19528
  throw error;
19530
19529
  }
19531
- const reservationPath = join12(
19530
+ const reservationPath = join11(
19532
19531
  destination,
19533
- `.gji-clone-reservation-${randomUUID3()}`
19532
+ `.gji-clone-reservation-${randomUUID2()}`
19534
19533
  );
19535
19534
  try {
19536
- await writeFile9(reservationPath, "gji clone reservation\n", {
19535
+ await writeFile8(reservationPath, "gji clone reservation\n", {
19537
19536
  flag: "wx"
19538
19537
  });
19539
- return reservationPath;
19538
+ return await inspectOwnedCloneEntry(reservationPath, "file");
19540
19539
  } catch (error) {
19541
- await rmdir2(destination).catch(() => void 0);
19540
+ await rmdir(destination).catch(() => void 0);
19542
19541
  throw error;
19543
19542
  }
19544
19543
  }
19545
- async function cleanupReservedDestination(destination, reservationPath, reservationEntries) {
19544
+ async function cleanupReservedDestination(destination, reservation, publishedEntries) {
19545
+ for (const entry of [...publishedEntries, reservation].reverse()) {
19546
+ await removeOwnedCloneEntry(entry);
19547
+ }
19548
+ await rmdir(destination).catch(() => void 0);
19549
+ }
19550
+ async function inspectOwnedCloneEntry(path9, kind) {
19551
+ const stats = await lstat3(path9, { bigint: true });
19552
+ return { dev: stats.dev, ino: stats.ino, kind, path: path9 };
19553
+ }
19554
+ async function removeOwnedCloneEntry(entry) {
19546
19555
  try {
19547
- const entries = await readdir2(destination);
19548
- const ownedEntries = /* @__PURE__ */ new Set([
19549
- basename6(reservationPath),
19550
- ...reservationEntries
19551
- ]);
19552
- if (entries.every((entry) => ownedEntries.has(entry))) {
19553
- await rm4(destination, { force: true, recursive: true });
19554
- }
19556
+ const current = await lstat3(entry.path, { bigint: true });
19557
+ if (current.dev !== entry.dev || current.ino !== entry.ino) return;
19558
+ if (entry.kind === "directory") await rmdir(entry.path);
19559
+ else await unlink3(entry.path);
19555
19560
  } catch {
19556
19561
  }
19557
19562
  }
@@ -19564,57 +19569,65 @@ async function destinationExists(path9) {
19564
19569
  throw error;
19565
19570
  }
19566
19571
  }
19567
- function startLockHeartbeat(lockPath, lockToken) {
19572
+ function startLockHeartbeat(lock) {
19568
19573
  const timer = setInterval(() => {
19569
- void refreshCloneLock(lockPath, lockToken);
19574
+ void refreshCloneLock(lock);
19570
19575
  }, CLONE_LOCK_TTL_MS / 3);
19571
19576
  timer.unref?.();
19572
19577
  return () => clearInterval(timer);
19573
19578
  }
19574
- async function refreshCloneLock(lockPath, lockToken) {
19579
+ async function refreshCloneLock(lock) {
19575
19580
  try {
19576
- const ownerPath = join12(lockPath, ownerFileName2(lockToken));
19577
- await readFile9(ownerPath, "utf8");
19578
19581
  const now = /* @__PURE__ */ new Date();
19579
- await utimes2(ownerPath, now, now);
19582
+ await utimes(lock.markerPath, now, now);
19580
19583
  } catch {
19581
19584
  }
19582
19585
  }
19583
- async function releaseCloneLock(lockPath, lockToken) {
19586
+ async function releaseCloneLock(lock) {
19587
+ const releaseGuard = await acquireCloneLockGuard(
19588
+ lock.lockPath,
19589
+ lock.lockPath
19590
+ );
19591
+ try {
19592
+ await releaseCloneLockWithGuard(lock);
19593
+ } finally {
19594
+ await releaseGuard();
19595
+ }
19596
+ }
19597
+ async function releaseCloneLockWithGuard(lock) {
19598
+ try {
19599
+ await unlink3(join11(lock.lockPath, lock.token));
19600
+ } catch (error) {
19601
+ if (!isNotFoundError(error)) throw error;
19602
+ }
19584
19603
  try {
19585
- const ownerPath = join12(lockPath, ownerFileName2(lockToken));
19586
- await unlink4(ownerPath);
19587
- await rmdir2(lockPath);
19604
+ await rmdir(lock.lockPath);
19588
19605
  } catch (error) {
19589
- if (!isNotFoundError(error) && !isDirectoryNotEmptyError(error))
19606
+ const code = "code" in error ? error.code : void 0;
19607
+ if (!isNotFoundError(error) && code !== "ENOTEMPTY" && code !== "EEXIST") {
19590
19608
  throw error;
19609
+ }
19591
19610
  }
19592
19611
  }
19593
- function ownerFileName2(lockToken) {
19594
- return `owner-${lockToken}`;
19595
- }
19596
19612
  function isUnsupportedCloneError(error) {
19597
19613
  if (!(error instanceof Error)) return false;
19598
19614
  const code = "code" in error ? error.code : "";
19599
19615
  if (["EINVAL", "ENOSYS", "ENOTSUP", "EOPNOTSUPP", "EXDEV"].includes(code ?? "")) {
19600
19616
  return true;
19601
19617
  }
19602
- return /clonefile|reflink|unsupported|operation not supported|not supported|invalid cross-device|cross-device/iu.test(
19618
+ return /reflink|unsupported|operation not supported|not supported|invalid cross-device|cross-device/iu.test(
19603
19619
  error.message
19604
19620
  );
19605
19621
  }
19606
- function isDirectoryNotEmptyError(error) {
19607
- return error instanceof Error && "code" in error && error.code === "ENOTEMPTY";
19608
- }
19609
19622
  function toErrorMessage(error) {
19610
19623
  return error instanceof Error ? error.message : String(error);
19611
19624
  }
19612
- function platformIsDarwin(platform3) {
19613
- return platform3 === "darwin";
19614
- }
19615
19625
 
19616
19626
  // src/dependency-bootstrap.ts
19617
19627
  var execFileAsync6 = promisify7(execFile6);
19628
+ var UV_VALIDATION_MAX_ENTRIES = 1e4;
19629
+ var UV_VALIDATION_MAX_FILE_BYTES = 1024 * 1024;
19630
+ var UV_VALIDATION_MAX_TOTAL_BYTES = 16 * 1024 * 1024;
19618
19631
  async function prepareDependencyBootstrap(mode, context) {
19619
19632
  if (mode === "off") return { mode, targets: [] };
19620
19633
  const adapters = createBootstrapAdapters(
@@ -19634,7 +19647,7 @@ async function prepareDependencyBootstrap(mode, context) {
19634
19647
  const plannedRelativePaths = /* @__PURE__ */ new Set();
19635
19648
  for (const adapter of adapters) {
19636
19649
  if (plannedRelativePaths.has(adapter.relativePath)) continue;
19637
- let fallback;
19650
+ let firstDetected;
19638
19651
  let selected;
19639
19652
  for (const sourceRoot of sourceRoots) {
19640
19653
  const target = await adapter.detect({
@@ -19644,14 +19657,14 @@ async function prepareDependencyBootstrap(mode, context) {
19644
19657
  });
19645
19658
  if (!target) continue;
19646
19659
  const seedable = mode !== "install-only" && await adapter.canSeed(target);
19647
- const candidate = { adapter, target, seedable };
19648
- fallback ??= candidate;
19660
+ const candidate = { target, seedable };
19661
+ firstDetected ??= candidate;
19649
19662
  if (mode === "install-only" || seedable) {
19650
19663
  selected = candidate;
19651
19664
  break;
19652
19665
  }
19653
19666
  }
19654
- const plannedTarget = selected ?? fallback;
19667
+ const plannedTarget = selected ?? firstDetected;
19655
19668
  if (plannedTarget) {
19656
19669
  targets.push(plannedTarget);
19657
19670
  plannedRelativePaths.add(adapter.relativePath);
@@ -19664,9 +19677,9 @@ async function detectDependencyBootstrapCandidate(context) {
19664
19677
  const planned = plan.targets[0];
19665
19678
  if (!planned) return null;
19666
19679
  return {
19667
- adapter: planned.adapter.name,
19668
- kind: planned.adapter.kind,
19669
- lockfile: planned.adapter.lockfile,
19680
+ adapter: planned.target.adapter,
19681
+ kind: planned.target.kind,
19682
+ lockfile: adapterForTarget(planned.target).lockfile,
19670
19683
  target: planned.target.relativePath,
19671
19684
  repairCommand: planned.target.repairCommand,
19672
19685
  seedable: planned.seedable
@@ -19675,10 +19688,10 @@ async function detectDependencyBootstrapCandidate(context) {
19675
19688
  function previewDependencyBootstrap(plan) {
19676
19689
  return {
19677
19690
  mode: plan.mode,
19678
- targets: plan.targets.map(({ adapter, target, seedable }) => ({
19679
- adapter: adapter.output(target).adapter,
19680
- kind: adapter.kind,
19681
- target: adapter.output(target).target,
19691
+ targets: plan.targets.map(({ target, seedable }) => ({
19692
+ adapter: target.adapter,
19693
+ kind: target.kind,
19694
+ target: target.relativePath,
19682
19695
  repairCommand: target.repairCommand,
19683
19696
  seedable,
19684
19697
  strategy: bootstrapStrategy(plan.mode, target, seedable)
@@ -19688,7 +19701,6 @@ function previewDependencyBootstrap(plan) {
19688
19701
  async function executeDependencyBootstrap(plan, options) {
19689
19702
  if (plan.mode === "off") return { mode: plan.mode, ready: true, events: [] };
19690
19703
  const events = [];
19691
- const failureStore = options.failureStore ?? defaultCloneFailureStore;
19692
19704
  const cloneDirectory = options.cloneDirectory ?? cloneDir;
19693
19705
  const execution = {
19694
19706
  runCommand: options.runCommand ?? runCommand,
@@ -19707,19 +19719,18 @@ async function executeDependencyBootstrap(plan, options) {
19707
19719
  });
19708
19720
  return { mode: plan.mode, ready: true, events };
19709
19721
  }
19710
- for (const { adapter, target, seedable } of plan.targets) {
19722
+ for (const { target, seedable } of plan.targets) {
19723
+ const adapter = adapterForTarget(target);
19711
19724
  await executeBootstrapTarget(
19712
19725
  adapter,
19713
19726
  target,
19714
19727
  seedable,
19715
19728
  plan.mode,
19716
19729
  cloneDirectory,
19717
- failureStore,
19718
19730
  execution,
19719
19731
  seededDirectories.has(target.relativePath),
19720
19732
  events,
19721
- options.reporter,
19722
- options.repoRoot
19733
+ options.reporter
19723
19734
  );
19724
19735
  }
19725
19736
  return {
@@ -19728,7 +19739,7 @@ async function executeDependencyBootstrap(plan, options) {
19728
19739
  events
19729
19740
  };
19730
19741
  }
19731
- async function executeBootstrapTarget(adapter, target, seedable, mode, cloneDirectory, failureStore, execution, seededBySyncDirs, events, reporter, repoRoot) {
19742
+ async function executeBootstrapTarget(adapter, target, seedable, mode, cloneDirectory, execution, seededBySyncDirs, events, reporter) {
19732
19743
  const destinationInspection = await inspectDestination(
19733
19744
  target.worktreePath,
19734
19745
  target.targetPath
@@ -19749,18 +19760,15 @@ async function executeBootstrapTarget(adapter, target, seedable, mode, cloneDire
19749
19760
  adapter,
19750
19761
  target,
19751
19762
  execution,
19752
- false,
19753
- target.existingBeforeBootstrap ? "preserve" : "empty",
19763
+ destinationInspection.kind === "exists" ? "preserve" : "clean",
19754
19764
  events,
19755
19765
  reporter
19756
19766
  );
19757
19767
  return;
19758
19768
  }
19759
- let seeded = false;
19760
- const failureScope = seedable ? await cloneFailureScope(adapter.seedPath(target), target.targetPath) : void 0;
19761
- let ownership = target.existingBeforeBootstrap ? "preserve" : "empty";
19769
+ let input = destinationInspection.kind === "exists" ? "preserve" : "clean";
19762
19770
  const destinationExistsNow = destinationInspection.kind === "exists";
19763
- if (target.existingBeforeBootstrap) {
19771
+ if (target.initialInput === "preserve" && destinationExistsNow) {
19764
19772
  recordBootstrapEvent(events, reporter, {
19765
19773
  adapter: adapter.name,
19766
19774
  kind: adapter.kind,
@@ -19771,8 +19779,7 @@ async function executeBootstrapTarget(adapter, target, seedable, mode, cloneDire
19771
19779
  });
19772
19780
  } else if (seededBySyncDirs && destinationExistsNow) {
19773
19781
  if (seedable) {
19774
- seeded = true;
19775
- ownership = "syncDirs";
19782
+ input = "seed";
19776
19783
  recordBootstrapEvent(events, reporter, {
19777
19784
  adapter: adapter.name,
19778
19785
  kind: adapter.kind,
@@ -19782,18 +19789,18 @@ async function executeBootstrapTarget(adapter, target, seedable, mode, cloneDire
19782
19789
  message: "reusing a seed created by syncDirs"
19783
19790
  });
19784
19791
  } else {
19785
- ownership = "preserve";
19792
+ input = "preserve";
19786
19793
  recordBootstrapEvent(events, reporter, {
19787
19794
  adapter: adapter.name,
19788
19795
  kind: adapter.kind,
19789
19796
  reason: "generic-seed",
19790
- state: "fallback",
19797
+ state: "repair-only",
19791
19798
  target: target.relativePath,
19792
19799
  message: "syncDirs created a generic target; this adapter uses repair without CoW"
19793
19800
  });
19794
19801
  }
19795
19802
  } else if (destinationExistsNow) {
19796
- ownership = "preserve";
19803
+ input = "preserve";
19797
19804
  recordBootstrapEvent(events, reporter, {
19798
19805
  adapter: adapter.name,
19799
19806
  kind: adapter.kind,
@@ -19802,24 +19809,13 @@ async function executeBootstrapTarget(adapter, target, seedable, mode, cloneDire
19802
19809
  target: target.relativePath,
19803
19810
  message: "target appeared during bootstrap; preserving it as the repair input"
19804
19811
  });
19805
- } else if (seedable && await failureStore.isCached(repoRoot, target.relativePath, failureScope)) {
19806
- recordBootstrapEvent(events, reporter, {
19807
- adapter: adapter.name,
19808
- kind: adapter.kind,
19809
- reason: "cow-failure-cached",
19810
- state: "fallback",
19811
- target: target.relativePath,
19812
- message: "previous CoW failure is cached; repairing from an empty target"
19813
- });
19814
19812
  } else if (seedable) {
19815
19813
  try {
19816
19814
  await cloneDirectory(adapter.seedPath(target), target.targetPath, {
19817
19815
  destinationRoot: target.worktreePath,
19818
19816
  measureBytes: reporter.measureCloneSize
19819
19817
  });
19820
- await failureStore.clear(repoRoot, target.relativePath, failureScope);
19821
- seeded = true;
19822
- ownership = "adapter";
19818
+ input = "seed";
19823
19819
  recordBootstrapEvent(events, reporter, {
19824
19820
  adapter: adapter.name,
19825
19821
  kind: adapter.kind,
@@ -19829,7 +19825,7 @@ async function executeBootstrapTarget(adapter, target, seedable, mode, cloneDire
19829
19825
  });
19830
19826
  } catch (error) {
19831
19827
  if (isCloneDestinationExistsError(error)) {
19832
- ownership = "preserve";
19828
+ input = "preserve";
19833
19829
  recordBootstrapEvent(events, reporter, {
19834
19830
  adapter: adapter.name,
19835
19831
  kind: adapter.kind,
@@ -19837,15 +19833,7 @@ async function executeBootstrapTarget(adapter, target, seedable, mode, cloneDire
19837
19833
  target: target.relativePath,
19838
19834
  message: "target appeared during CoW seeding; preserving it as the repair input"
19839
19835
  });
19840
- await repairTarget(
19841
- adapter,
19842
- target,
19843
- execution,
19844
- false,
19845
- ownership,
19846
- events,
19847
- reporter
19848
- );
19836
+ await repairTarget(adapter, target, execution, input, events, reporter);
19849
19837
  return;
19850
19838
  }
19851
19839
  if (isCloneInProgressError(error)) {
@@ -19859,21 +19847,30 @@ async function executeBootstrapTarget(adapter, target, seedable, mode, cloneDire
19859
19847
  );
19860
19848
  return;
19861
19849
  }
19862
- if (isCloneUnsupportedError(error)) {
19863
- await failureStore.cache(
19864
- repoRoot,
19865
- target.relativePath,
19866
- toErrorMessage2(error),
19867
- failureScope
19850
+ const failedCloneInspection = await inspectDestination(
19851
+ target.worktreePath,
19852
+ target.targetPath
19853
+ );
19854
+ if (failedCloneInspection.kind === "unsafe") {
19855
+ recordBootstrapFailure(
19856
+ events,
19857
+ reporter,
19858
+ adapter,
19859
+ target,
19860
+ failedCloneInspection.reason,
19861
+ "destination-unsafe"
19868
19862
  );
19863
+ return;
19869
19864
  }
19865
+ input = failedCloneInspection.kind === "exists" ? "preserve" : "clean";
19866
+ const repairInput = input === "preserve" ? "the preserved target" : "an empty target";
19870
19867
  recordBootstrapEvent(events, reporter, {
19871
19868
  adapter: adapter.name,
19872
19869
  kind: adapter.kind,
19873
- reason: "cow-unsupported",
19874
- state: "fallback",
19870
+ reason: "cow-seed-failed",
19871
+ state: "repair-only",
19875
19872
  target: target.relativePath,
19876
- message: `CoW seed failed; repairing from an empty target (${toErrorMessage2(error)})`
19873
+ message: `CoW seed failed; repairing from ${repairInput} (${toErrorMessage2(error)})`
19877
19874
  });
19878
19875
  }
19879
19876
  } else {
@@ -19881,22 +19878,14 @@ async function executeBootstrapTarget(adapter, target, seedable, mode, cloneDire
19881
19878
  adapter: adapter.name,
19882
19879
  kind: adapter.kind,
19883
19880
  reason: "seed-unavailable",
19884
- state: "fallback",
19881
+ state: "repair-only",
19885
19882
  target: target.relativePath,
19886
19883
  message: "CoW seed is unavailable; repairing from an empty target"
19887
19884
  });
19888
19885
  }
19889
- await repairTarget(
19890
- adapter,
19891
- target,
19892
- execution,
19893
- seeded,
19894
- ownership,
19895
- events,
19896
- reporter
19897
- );
19886
+ await repairTarget(adapter, target, execution, input, events, reporter);
19898
19887
  }
19899
- async function repairTarget(adapter, target, execution, seeded, ownership, events, reporter) {
19888
+ async function repairTarget(adapter, target, execution, input, events, reporter) {
19900
19889
  const beforeRepairInspection = await inspectDestination(
19901
19890
  target.worktreePath,
19902
19891
  target.targetPath
@@ -19912,21 +19901,20 @@ async function repairTarget(adapter, target, execution, seeded, ownership, event
19912
19901
  );
19913
19902
  return;
19914
19903
  }
19915
- const presentBeforeRepair = beforeRepairInspection.kind === "exists";
19904
+ const effectiveInput = beforeRepairInspection.kind === "exists" ? input === "seed" ? "seed" : "preserve" : "clean";
19916
19905
  try {
19917
- await adapter.repair(target, execution);
19906
+ await adapter.repair(target, { ...execution, input: effectiveInput });
19918
19907
  recordBootstrapEvent(events, reporter, {
19919
19908
  adapter: adapter.name,
19920
19909
  kind: adapter.kind,
19921
19910
  state: target.repairState,
19922
19911
  target: target.relativePath,
19923
- message: seeded ? "reused and repaired" : "installed or repaired from a clean target"
19912
+ message: repairSuccessMessage(target, effectiveInput)
19924
19913
  });
19925
19914
  } catch (firstError) {
19926
19915
  const firstFailureContext = {
19927
- target,
19928
- ownership,
19929
- targetExistedBeforeRepair: presentBeforeRepair
19916
+ input: effectiveInput,
19917
+ target
19930
19918
  };
19931
19919
  const cleanupError = await adapter.cleanupAfterRepairFailure(firstFailureContext).then(() => void 0).catch((error) => toErrorMessage2(error));
19932
19920
  if (!adapter.shouldRetryAfterRepairFailure(firstFailureContext)) {
@@ -19958,7 +19946,7 @@ async function repairTarget(adapter, target, execution, seeded, ownership, event
19958
19946
  adapter: adapter.name,
19959
19947
  kind: adapter.kind,
19960
19948
  reason: "seed-repair-failed",
19961
- state: "fallback",
19949
+ state: "repair-only",
19962
19950
  target: target.relativePath,
19963
19951
  message: `seed repair failed; removed the seed and retrying clean (${toErrorMessage2(firstError)})`
19964
19952
  });
@@ -19977,22 +19965,21 @@ async function repairTarget(adapter, target, execution, seeded, ownership, event
19977
19965
  );
19978
19966
  return;
19979
19967
  }
19980
- const presentBeforeRetry = beforeRetryInspection.kind === "exists";
19968
+ const retryInput = beforeRetryInspection.kind === "exists" ? "preserve" : "clean";
19981
19969
  try {
19982
- await adapter.repair(target, execution);
19970
+ await adapter.repair(target, { ...execution, input: retryInput });
19983
19971
  recordBootstrapEvent(events, reporter, {
19984
19972
  adapter: adapter.name,
19985
19973
  kind: adapter.kind,
19986
19974
  reason: "repair-retry",
19987
19975
  state: target.repairState,
19988
19976
  target: target.relativePath,
19989
- message: "installed or repaired from a clean target"
19977
+ message: repairSuccessMessage(target, retryInput)
19990
19978
  });
19991
19979
  } catch (secondError) {
19992
19980
  const cleanupError2 = await adapter.cleanupAfterRepairFailure({
19993
- target,
19994
- ownership,
19995
- targetExistedBeforeRepair: presentBeforeRetry
19981
+ input: retryInput,
19982
+ target
19996
19983
  }).then(() => void 0).catch((error) => toErrorMessage2(error));
19997
19984
  recordBootstrapFailure(
19998
19985
  events,
@@ -20005,6 +19992,11 @@ async function repairTarget(adapter, target, execution, seeded, ownership, event
20005
19992
  }
20006
19993
  }
20007
19994
  }
19995
+ function repairSuccessMessage(target, input) {
19996
+ if (input === "seed") return "reused and repaired";
19997
+ if (input === "preserve") return "repaired the existing target";
19998
+ return target.repairState === "installed" ? "installed from a clean target" : "repaired from a clean target";
19999
+ }
20008
20000
  function recordBootstrapFailure(events, reporter, adapter, target, message, reason) {
20009
20001
  recordBootstrapEvent(events, reporter, {
20010
20002
  adapter: adapter.name,
@@ -20029,6 +20021,14 @@ function bootstrapStrategy(mode, target, seedable) {
20029
20021
  }
20030
20022
  return seedable ? "cow-then-repair" : "repair-only";
20031
20023
  }
20024
+ function adapterForTarget(target) {
20025
+ const adapter = createBootstrapAdapters(defaultCheckUvRuntime).find(
20026
+ (candidate) => candidate.name === target.adapter
20027
+ );
20028
+ if (!adapter)
20029
+ throw new Error(`unsupported bootstrap adapter: ${target.adapter}`);
20030
+ return adapter;
20031
+ }
20032
20032
  function createBootstrapAdapters(checkUvRuntime, cargoBuildCommand) {
20033
20033
  return [
20034
20034
  new LockfileBootstrapAdapter({
@@ -20038,9 +20038,9 @@ function createBootstrapAdapters(checkUvRuntime, cargoBuildCommand) {
20038
20038
  relativePath: "node_modules",
20039
20039
  repairCommand: "pnpm install --frozen-lockfile",
20040
20040
  shell: false,
20041
- beforeRepair: async (target) => {
20042
- if (!target.existingBeforeBootstrap) {
20043
- await rm5(join13(target.targetPath, ".modules.yaml"), {
20041
+ beforeRepair: async (target, context) => {
20042
+ if (context.input === "seed") {
20043
+ await rm4(join12(target.targetPath, ".modules.yaml"), {
20044
20044
  force: true
20045
20045
  });
20046
20046
  }
@@ -20052,7 +20052,14 @@ function createBootstrapAdapters(checkUvRuntime, cargoBuildCommand) {
20052
20052
  lockfile: "yarn.lock",
20053
20053
  relativePath: "node_modules",
20054
20054
  repairCommand: "yarn install --immutable",
20055
- shell: false
20055
+ shell: false,
20056
+ beforeRepair: async (target, context) => {
20057
+ if (context.input === "seed") {
20058
+ await rm4(join12(target.targetPath, ".yarn-state.yml"), {
20059
+ force: true
20060
+ });
20061
+ }
20062
+ }
20056
20063
  }),
20057
20064
  new LockfileBootstrapAdapter({
20058
20065
  name: "npm",
@@ -20062,7 +20069,7 @@ function createBootstrapAdapters(checkUvRuntime, cargoBuildCommand) {
20062
20069
  repairCommand: "npm ci",
20063
20070
  shell: false,
20064
20071
  seedPolicy: "never",
20065
- repairCommandOverride: (target) => target.existingBeforeBootstrap ? "npm install" : "npm ci",
20072
+ selectRepairCommand: (_target, input) => input === "preserve" ? "npm install" : "npm ci",
20066
20073
  repairState: "installed"
20067
20074
  }),
20068
20075
  new LockfileBootstrapAdapter({
@@ -20074,7 +20081,12 @@ function createBootstrapAdapters(checkUvRuntime, cargoBuildCommand) {
20074
20081
  shell: false,
20075
20082
  commandOptions: () => ({
20076
20083
  env: { BUNDLE_PATH: "vendor/bundle" }
20077
- })
20084
+ }),
20085
+ beforeRepair: async (target, context) => {
20086
+ if (context.input === "seed") {
20087
+ await removeBundlerExtensionMarkers(target.targetPath);
20088
+ }
20089
+ }
20078
20090
  }),
20079
20091
  new LockfileBootstrapAdapter({
20080
20092
  name: "uv",
@@ -20083,7 +20095,9 @@ function createBootstrapAdapters(checkUvRuntime, cargoBuildCommand) {
20083
20095
  relativePath: ".venv",
20084
20096
  repairCommand: "uv sync --locked",
20085
20097
  shell: false,
20086
- canSeedOverride: checkUvRuntime
20098
+ canSeedOverride: checkUvRuntime,
20099
+ beforeRepair: validateUvStructure,
20100
+ afterRepair: validateUvRelocation
20087
20101
  }),
20088
20102
  new LockfileBootstrapAdapter({
20089
20103
  name: "cargo",
@@ -20091,7 +20105,7 @@ function createBootstrapAdapters(checkUvRuntime, cargoBuildCommand) {
20091
20105
  lockfile: "Cargo.lock",
20092
20106
  relativePath: "target",
20093
20107
  repairCommand: cargoBuildCommand?.trim() || "cargo check",
20094
- shell: cargoBuildCommand ? void 0 : false
20108
+ shell: Boolean(cargoBuildCommand)
20095
20109
  })
20096
20110
  ];
20097
20111
  }
@@ -20105,8 +20119,9 @@ var LockfileBootstrapAdapter = class {
20105
20119
  seedPolicy;
20106
20120
  canSeedOverride;
20107
20121
  beforeRepair;
20122
+ afterRepair;
20108
20123
  commandOptions;
20109
- repairCommandOverride;
20124
+ selectRepairCommand;
20110
20125
  repairState;
20111
20126
  constructor(spec) {
20112
20127
  this.name = spec.name;
@@ -20118,19 +20133,21 @@ var LockfileBootstrapAdapter = class {
20118
20133
  this.seedPolicy = spec.seedPolicy ?? "always";
20119
20134
  this.canSeedOverride = spec.canSeedOverride;
20120
20135
  this.beforeRepair = spec.beforeRepair;
20136
+ this.afterRepair = spec.afterRepair;
20121
20137
  this.commandOptions = spec.commandOptions;
20122
- this.repairCommandOverride = spec.repairCommandOverride;
20138
+ this.selectRepairCommand = spec.selectRepairCommand;
20123
20139
  this.repairState = spec.repairState ?? "repaired";
20124
20140
  }
20125
20141
  async detect(context) {
20126
20142
  const detectionRoot = context.detectionRoot ?? context.sourceRoot;
20127
- if (!await pathExists2(join13(detectionRoot, this.lockfile))) return null;
20128
- const sourcePath = join13(context.sourceRoot, this.relativePath);
20129
- const targetPath = join13(context.worktreePath, this.relativePath);
20143
+ if (!await pathExists2(join12(detectionRoot, this.lockfile))) return null;
20144
+ const sourcePath = join12(context.sourceRoot, this.relativePath);
20145
+ const targetPath = join12(context.worktreePath, this.relativePath);
20130
20146
  const destinationInspection = await inspectDestination(
20131
20147
  context.worktreePath,
20132
20148
  targetPath
20133
20149
  );
20150
+ const initialInput = destinationInspection.kind === "exists" ? "preserve" : "clean";
20134
20151
  const target = {
20135
20152
  adapter: this.name,
20136
20153
  kind: this.kind,
@@ -20141,56 +20158,43 @@ var LockfileBootstrapAdapter = class {
20141
20158
  targetPath,
20142
20159
  repairCommand: this.defaultRepairCommand,
20143
20160
  repairState: this.repairState,
20144
- existingBeforeBootstrap: destinationInspection.kind === "exists"
20161
+ shell: this.shell,
20162
+ initialInput
20145
20163
  };
20146
20164
  return {
20147
20165
  ...target,
20148
- repairCommand: this.repairCommandOverride?.(target) ?? target.repairCommand
20166
+ repairCommand: this.selectRepairCommand?.(target, initialInput) ?? target.repairCommand
20149
20167
  };
20150
20168
  }
20151
20169
  seedPath(target) {
20152
20170
  return target.sourcePath;
20153
20171
  }
20154
20172
  async repair(target, context) {
20155
- await this.beforeRepair?.(target);
20173
+ await this.beforeRepair?.(target, context);
20174
+ const repairCommand = this.selectRepairCommand?.(target, context.input) ?? target.repairCommand;
20156
20175
  await context.runCommand(
20157
- target.repairCommand,
20176
+ repairCommand,
20158
20177
  target.worktreePath,
20159
20178
  context.stderr,
20160
20179
  context.stdout,
20161
20180
  {
20162
20181
  ...this.commandOptions?.(target),
20163
- shell: this.shell
20182
+ shell: target.shell
20164
20183
  }
20165
20184
  );
20185
+ await this.afterRepair?.(target, context);
20166
20186
  }
20167
20187
  async canSeed(target) {
20168
20188
  if (this.seedPolicy === "never") return false;
20169
20189
  if (!await safeSourceDirectory(target)) return false;
20170
20190
  return await this.canSeedOverride?.(target) ?? true;
20171
20191
  }
20172
- output(target) {
20173
- return {
20174
- adapter: this.name,
20175
- kind: this.kind,
20176
- target: target.relativePath,
20177
- repairCommand: target.repairCommand
20178
- };
20179
- }
20180
20192
  shouldRetryAfterRepairFailure(context) {
20181
- return context.ownership === "adapter" || context.ownership === "syncDirs";
20193
+ return context.input === "seed";
20182
20194
  }
20183
20195
  async cleanupAfterRepairFailure(context) {
20184
- if (context.target.existingBeforeBootstrap) {
20185
- return;
20186
- }
20187
- if (context.ownership === "adapter" || context.ownership === "syncDirs") {
20188
- await rm5(context.target.targetPath, { force: true, recursive: true });
20189
- return;
20190
- }
20191
- if (context.ownership === "empty" && !context.targetExistedBeforeRepair) {
20192
- await rm5(context.target.targetPath, { force: true, recursive: true });
20193
- }
20196
+ if (context.input !== "seed") return;
20197
+ await rm4(context.target.targetPath, { force: true, recursive: true });
20194
20198
  }
20195
20199
  };
20196
20200
  async function safeSourceDirectory(target) {
@@ -20207,28 +20211,247 @@ async function safeSourceDirectory(target) {
20207
20211
  }
20208
20212
  async function defaultCheckUvRuntime(target) {
20209
20213
  try {
20210
- const config = await readFile10(
20211
- join13(target.sourcePath, "pyvenv.cfg"),
20214
+ const config = await readFile9(
20215
+ join12(target.sourcePath, "pyvenv.cfg"),
20212
20216
  "utf8"
20213
20217
  );
20214
- const expected = config.match(/^version\s*=\s*(\d+\.\d+)/mu)?.[1];
20218
+ const expected = config.match(/^version(?:_info)?\s*=\s*(\d+\.\d+)/mu)?.[1];
20215
20219
  if (!expected) return false;
20216
- const sourceInterpreter = join13(
20220
+ const expectedImplementation = config.match(/^implementation\s*=\s*([^\s#]+)/imu)?.[1]?.toLowerCase();
20221
+ const sourceInterpreter = join12(
20217
20222
  target.sourcePath,
20218
20223
  process.platform === "win32" ? "Scripts/python.exe" : "bin/python"
20219
20224
  );
20220
- const fingerprintScript = "import platform, sys; print(f'{sys.version_info.major}.{sys.version_info.minor}|{platform.machine()}|{sys.implementation.cache_tag}')";
20221
- const [source, current] = await Promise.all([
20222
- execFileAsync6(sourceInterpreter, ["-c", fingerprintScript]),
20223
- execFileAsync6("python3", ["-c", fingerprintScript])
20225
+ const fingerprintScript = "import platform, sys; print(f'{sys.version_info.major}.{sys.version_info.minor}|{platform.machine()}|{sys.implementation.name}')";
20226
+ const source = await execFileAsync6(sourceInterpreter, [
20227
+ "-c",
20228
+ fingerprintScript
20224
20229
  ]);
20225
20230
  const sourceFingerprint = source.stdout.trim();
20226
- const currentFingerprint = current.stdout.trim();
20227
- return sourceFingerprint === currentFingerprint && sourceFingerprint.startsWith(`${expected}|`);
20231
+ const [sourceVersion, sourceMachine, sourceImplementation, extra] = sourceFingerprint.split("|");
20232
+ return extra === void 0 && sourceVersion === expected && Boolean(sourceMachine) && Boolean(sourceImplementation) && (expectedImplementation === void 0 || sourceImplementation.toLowerCase() === expectedImplementation);
20228
20233
  } catch {
20229
20234
  return false;
20230
20235
  }
20231
20236
  }
20237
+ function virtualEnvironmentPrefixes(text) {
20238
+ const prefixes = [];
20239
+ for (const line of text.split(/\r?\n/u)) {
20240
+ if (!/\bVIRTUAL_ENV\b/u.test(line)) continue;
20241
+ const quotedAssignment = line.match(
20242
+ /\bVIRTUAL_ENV(?:\s*=|\s+)\s*(?:"([^"]+)"|'([^']+)')/u
20243
+ );
20244
+ const quotedPrefix = quotedAssignment?.[1] ?? quotedAssignment?.[2];
20245
+ if (quotedPrefix && isAbsolute4(quotedPrefix)) prefixes.push(quotedPrefix);
20246
+ const unquoted = line.match(/\bVIRTUAL_ENV(?:\s*=|\s+)\s*([^\s"']+)/u)?.[1];
20247
+ if (unquoted && isAbsolute4(unquoted)) prefixes.push(unquoted);
20248
+ }
20249
+ return uniquePaths(prefixes);
20250
+ }
20251
+ function pythonPrefixFromShebang(text) {
20252
+ const command = text.match(/^#!\s*([^\r\n]+)/u)?.[1]?.trim().split(/\s+/u)[0];
20253
+ if (!command || !isAbsolute4(command)) return void 0;
20254
+ if (!/^python(?:\d+(?:\.\d+)?)?(?:\.exe)?$/iu.test(
20255
+ command.split(sep3).at(-1) ?? ""
20256
+ )) {
20257
+ return void 0;
20258
+ }
20259
+ return dirname9(dirname9(command));
20260
+ }
20261
+ function pythonPrefixesFromText(text) {
20262
+ const interpreters = [];
20263
+ for (const match of text.matchAll(/["'](\/[^"']+)["']/gu)) {
20264
+ if (match[1]) interpreters.push(match[1]);
20265
+ }
20266
+ for (const match of text.matchAll(/(?:^|\s)(\/[^\s"']+)/gmu)) {
20267
+ if (match[1]) interpreters.push(match[1]);
20268
+ }
20269
+ return uniquePaths(
20270
+ interpreters.flatMap((interpreter) => {
20271
+ const name = interpreter.split(sep3).at(-1) ?? "";
20272
+ return /^python(?:\d+(?:\.\d+)?)?(?:\.exe)?$/iu.test(name) ? [dirname9(dirname9(interpreter))] : [];
20273
+ })
20274
+ );
20275
+ }
20276
+ async function validateUvRelocation(target, context) {
20277
+ if (context.input === "preserve") return;
20278
+ const scriptsDirectory = join12(
20279
+ target.targetPath,
20280
+ process.platform === "win32" ? "Scripts" : "bin"
20281
+ );
20282
+ const interpreter = join12(
20283
+ scriptsDirectory,
20284
+ process.platform === "win32" ? "python.exe" : "python"
20285
+ );
20286
+ const { stdout: stdout3 } = await execFileAsync6(interpreter, [
20287
+ "-c",
20288
+ "import os, sys; print(os.path.realpath(sys.prefix))"
20289
+ ]);
20290
+ const [actualPrefix, expectedPrefix] = await Promise.all([
20291
+ realpath3(stdout3.trim()),
20292
+ realpath3(target.targetPath)
20293
+ ]);
20294
+ if (actualPrefix !== expectedPrefix) {
20295
+ throw new Error(
20296
+ `uv environment still points to its source prefix: ${actualPrefix}`
20297
+ );
20298
+ }
20299
+ const sourcePaths = uniquePaths([
20300
+ target.sourcePath,
20301
+ await realpath3(target.sourcePath).catch(() => void 0)
20302
+ ]);
20303
+ const entries = await readdir2(scriptsDirectory, { withFileTypes: true });
20304
+ assertSafeUvScriptEntries(entries);
20305
+ const environmentName = basename7(target.targetPath);
20306
+ const acceptedPrefixes = /* @__PURE__ */ new Set([
20307
+ resolve9(target.targetPath),
20308
+ await realpath3(target.targetPath)
20309
+ ]);
20310
+ let validatedBytes = 0;
20311
+ for (const path9 of [
20312
+ join12(target.targetPath, "pyvenv.cfg"),
20313
+ ...entries.filter((entry) => entry.isFile()).map((entry) => join12(scriptsDirectory, entry.name))
20314
+ ]) {
20315
+ const validated = await readBoundedUvTextFile(
20316
+ path9,
20317
+ UV_VALIDATION_MAX_TOTAL_BYTES - validatedBytes
20318
+ );
20319
+ if (!validated) continue;
20320
+ validatedBytes += validated.bytes;
20321
+ if (validated.text === void 0) continue;
20322
+ const { text } = validated;
20323
+ if (sourcePaths.some((sourcePath) => text.includes(sourcePath))) {
20324
+ throw new Error(`uv environment contains a stale source path: ${path9}`);
20325
+ }
20326
+ const shebangPrefix = pythonPrefixFromShebang(text);
20327
+ if (shebangPrefix && basename7(shebangPrefix) === environmentName && !acceptedPrefixes.has(resolve9(shebangPrefix))) {
20328
+ throw new Error(`uv launcher points outside its environment: ${path9}`);
20329
+ }
20330
+ if (pythonPrefixesFromText(text).filter((prefix) => basename7(prefix) === environmentName).some((prefix) => !acceptedPrefixes.has(resolve9(prefix)))) {
20331
+ throw new Error(`uv launcher points outside its environment: ${path9}`);
20332
+ }
20333
+ if (virtualEnvironmentPrefixes(text).some(
20334
+ (prefix) => !acceptedPrefixes.has(resolve9(prefix))
20335
+ )) {
20336
+ throw new Error(
20337
+ `uv activation script points outside its environment: ${path9}`
20338
+ );
20339
+ }
20340
+ }
20341
+ }
20342
+ async function validateUvStructure(target, context) {
20343
+ if (context.input === "preserve") return;
20344
+ const targetStats = await lstat4(target.targetPath).catch(() => void 0);
20345
+ if (!targetStats) return;
20346
+ if (!targetStats.isDirectory() || targetStats.isSymbolicLink()) {
20347
+ throw new Error("uv environment must be a real directory");
20348
+ }
20349
+ const configStats = await lstat4(join12(target.targetPath, "pyvenv.cfg")).catch(
20350
+ () => void 0
20351
+ );
20352
+ if (configStats && (!configStats.isFile() || configStats.isSymbolicLink())) {
20353
+ throw new Error("uv pyvenv.cfg must be a regular file");
20354
+ }
20355
+ const scriptsDirectory = join12(
20356
+ target.targetPath,
20357
+ process.platform === "win32" ? "Scripts" : "bin"
20358
+ );
20359
+ const scriptsStats = await lstat4(scriptsDirectory).catch(() => void 0);
20360
+ if (!scriptsStats) return;
20361
+ if (!scriptsStats.isDirectory() || scriptsStats.isSymbolicLink()) {
20362
+ throw new Error("uv scripts path must be a real directory");
20363
+ }
20364
+ assertSafeUvScriptEntries(
20365
+ await readdir2(scriptsDirectory, { withFileTypes: true })
20366
+ );
20367
+ }
20368
+ function assertSafeUvScriptEntries(entries) {
20369
+ if (entries.length > UV_VALIDATION_MAX_ENTRIES) {
20370
+ throw new Error("uv scripts directory exceeds the validation entry limit");
20371
+ }
20372
+ for (const entry of entries) {
20373
+ if (entry.isSymbolicLink() && !isUvInterpreterName(entry.name)) {
20374
+ throw new Error(`uv script must not be a symbolic link: ${entry.name}`);
20375
+ }
20376
+ }
20377
+ }
20378
+ async function readBoundedUvTextFile(path9, remainingBytes) {
20379
+ let handle;
20380
+ try {
20381
+ handle = await open3(
20382
+ path9,
20383
+ constants6.O_RDONLY | (process.platform === "win32" ? 0 : constants6.O_NOFOLLOW)
20384
+ );
20385
+ } catch (error) {
20386
+ if (isNotFoundError(error)) return void 0;
20387
+ throw error;
20388
+ }
20389
+ try {
20390
+ const stats = await handle.stat();
20391
+ if (!stats.isFile()) return void 0;
20392
+ if (stats.size > UV_VALIDATION_MAX_FILE_BYTES) {
20393
+ throw new Error(`uv launcher exceeds the validation size limit: ${path9}`);
20394
+ }
20395
+ if (stats.size > remainingBytes) {
20396
+ throw new Error("uv launchers exceed the total validation size limit");
20397
+ }
20398
+ const readLimit = Math.min(UV_VALIDATION_MAX_FILE_BYTES, remainingBytes);
20399
+ const contents = await readFilePrefix(handle, readLimit + 1);
20400
+ if (contents.byteLength > UV_VALIDATION_MAX_FILE_BYTES) {
20401
+ throw new Error(`uv launcher exceeds the validation size limit: ${path9}`);
20402
+ }
20403
+ if (contents.byteLength > remainingBytes) {
20404
+ throw new Error("uv launchers exceed the total validation size limit");
20405
+ }
20406
+ const text = contents.toString("utf8");
20407
+ return Buffer.from(text, "utf8").equals(contents) ? { bytes: contents.byteLength, text } : { bytes: contents.byteLength };
20408
+ } finally {
20409
+ await handle.close();
20410
+ }
20411
+ }
20412
+ async function readFilePrefix(handle, maxBytes) {
20413
+ const contents = Buffer.allocUnsafe(maxBytes);
20414
+ let offset = 0;
20415
+ while (offset < contents.byteLength) {
20416
+ const { bytesRead } = await handle.read(
20417
+ contents,
20418
+ offset,
20419
+ contents.byteLength - offset,
20420
+ offset
20421
+ );
20422
+ if (bytesRead === 0) break;
20423
+ offset += bytesRead;
20424
+ }
20425
+ return contents.subarray(0, offset);
20426
+ }
20427
+ function isUvInterpreterName(name) {
20428
+ return /^python(?:\d+(?:\.\d+)?)?(?:\.exe)?$/iu.test(name);
20429
+ }
20430
+ async function removeBundlerExtensionMarkers(root) {
20431
+ const pending = [root];
20432
+ while (pending.length > 0) {
20433
+ const current = pending.pop();
20434
+ if (!current) continue;
20435
+ let entries;
20436
+ try {
20437
+ entries = await readdir2(current, { withFileTypes: true });
20438
+ } catch (error) {
20439
+ if (isNotFoundError(error)) continue;
20440
+ throw error;
20441
+ }
20442
+ for (const entry of entries) {
20443
+ const path9 = join12(current, entry.name);
20444
+ if (entry.isDirectory()) pending.push(path9);
20445
+ else if (entry.isFile() && isBundlerExtensionMarker(root, path9)) {
20446
+ await rm4(path9, { force: true });
20447
+ }
20448
+ }
20449
+ }
20450
+ }
20451
+ function isBundlerExtensionMarker(root, path9) {
20452
+ const segments = relative3(root, path9).split(sep3);
20453
+ return segments.length >= 7 && segments[0] === "ruby" && segments[2] === "extensions" && segments.at(-1) === "gem.build_complete";
20454
+ }
20232
20455
  function uniquePaths(paths) {
20233
20456
  return [...new Set(paths.filter((path9) => Boolean(path9)))];
20234
20457
  }
@@ -20239,11 +20462,11 @@ async function isAllowedSourceRoot(repoRoot, sourceRoot) {
20239
20462
  realpath3(sourceRoot)
20240
20463
  ]);
20241
20464
  if (resolvedRepoRoot === resolvedSourceRoot) return true;
20242
- const gitFile = await readFile10(join13(resolvedSourceRoot, ".git"), "utf8");
20465
+ const gitFile = await readFile9(join12(resolvedSourceRoot, ".git"), "utf8");
20243
20466
  const gitDirectory = gitFile.match(/^gitdir:\s*(.+)$/mu)?.[1];
20244
20467
  if (!gitDirectory) return false;
20245
20468
  return isWithin(
20246
- join13(resolvedRepoRoot, ".git", "worktrees"),
20469
+ join12(resolvedRepoRoot, ".git", "worktrees"),
20247
20470
  resolve9(resolvedSourceRoot, gitDirectory)
20248
20471
  );
20249
20472
  } catch {
@@ -20251,8 +20474,8 @@ async function isAllowedSourceRoot(repoRoot, sourceRoot) {
20251
20474
  }
20252
20475
  }
20253
20476
  function isWithin(root, candidate) {
20254
- const distance = relative2(root, candidate);
20255
- return distance === "" || distance !== ".." && !distance.startsWith(`..${sep2}`);
20477
+ const distance = relative3(root, candidate);
20478
+ return distance === "" || distance !== ".." && !distance.startsWith(`..${sep3}`);
20256
20479
  }
20257
20480
  function toErrorMessage2(error) {
20258
20481
  return error instanceof Error ? error.message : String(error);
@@ -20283,11 +20506,11 @@ function formatBootstrapStrategy(strategy) {
20283
20506
  }
20284
20507
 
20285
20508
  // src/conflict.ts
20286
- import { constants as constants6 } from "node:fs";
20509
+ import { constants as constants7 } from "node:fs";
20287
20510
  import { access as access7 } from "node:fs/promises";
20288
20511
  async function pathExists3(path9) {
20289
20512
  try {
20290
- await access7(path9, constants6.F_OK);
20513
+ await access7(path9, constants7.F_OK);
20291
20514
  return true;
20292
20515
  } catch {
20293
20516
  return false;
@@ -20419,12 +20642,12 @@ function toErrorMessage3(error) {
20419
20642
 
20420
20643
  // src/sync-plan.ts
20421
20644
  import { lstat as lstat5, realpath as realpath4 } from "node:fs/promises";
20422
- import { isAbsolute as isAbsolute4, join as join14, relative as relative3, resolve as resolve10, sep as sep3 } from "node:path";
20645
+ import { isAbsolute as isAbsolute5, join as join13, relative as relative4, resolve as resolve10, sep as sep4 } from "node:path";
20423
20646
  async function prepareSyncDirectoryPlan(repoRoot, worktreePath, directories) {
20424
20647
  const normalizedDirectories = directories.map(validateSyncDirPattern).sort(directoryDepthAscending);
20425
20648
  const plan = [];
20426
20649
  for (const directory of normalizedDirectories) {
20427
- const destination = join14(worktreePath, directory);
20650
+ const destination = join13(worktreePath, directory);
20428
20651
  const destinationState = await inspectDestination(
20429
20652
  worktreePath,
20430
20653
  destination
@@ -20498,7 +20721,7 @@ async function estimateSyncDirectories(repoRoot, worktreePath, directories) {
20498
20721
  return estimateSyncDirectoryPlan(plan);
20499
20722
  }
20500
20723
  async function resolveSyncDirectorySource(repoRoot, directory) {
20501
- const source = join14(repoRoot, directory);
20724
+ const source = join13(repoRoot, directory);
20502
20725
  let resolvedSource;
20503
20726
  try {
20504
20727
  resolvedSource = await realpath4(source);
@@ -20524,35 +20747,35 @@ function directoryDepthAscending(left, right) {
20524
20747
  return left.split(/[\\/]+/u).length - right.split(/[\\/]+/u).length;
20525
20748
  }
20526
20749
  function isPathInside2(parent, child) {
20527
- const relativePath = relative3(resolve10(parent), resolve10(child));
20528
- return relativePath !== "" && !isAbsolute4(relativePath) && relativePath !== ".." && !relativePath.startsWith(`..${sep3}`);
20750
+ const relativePath = relative4(resolve10(parent), resolve10(child));
20751
+ return relativePath !== "" && !isAbsolute5(relativePath) && relativePath !== ".." && !relativePath.startsWith(`..${sep4}`);
20529
20752
  }
20530
20753
  function toErrorMessage4(error) {
20531
20754
  return error instanceof Error ? error.message : String(error);
20532
20755
  }
20533
20756
 
20534
20757
  // src/worktree-bootstrap.ts
20535
- import { basename as basename8 } from "node:path";
20758
+ import { basename as basename9 } from "node:path";
20536
20759
 
20537
20760
  // src/file-sync.ts
20538
- import { constants as constants7 } from "node:fs";
20761
+ import { constants as constants8 } from "node:fs";
20539
20762
  import { copyFile, lstat as lstat6, realpath as realpath5 } from "node:fs/promises";
20540
20763
  import {
20541
- basename as basename7,
20764
+ basename as basename8,
20542
20765
  dirname as dirname10,
20543
- isAbsolute as isAbsolute5,
20544
- join as join15,
20766
+ isAbsolute as isAbsolute6,
20767
+ join as join14,
20545
20768
  normalize as normalize2,
20546
- relative as relative4,
20769
+ relative as relative5,
20547
20770
  resolve as resolve11,
20548
- sep as sep4
20771
+ sep as sep5
20549
20772
  } from "node:path";
20550
20773
  async function syncFiles(mainRoot, targetPath, patterns) {
20551
20774
  for (const pattern of patterns) {
20552
20775
  const normalized = validateSyncFilePattern(pattern);
20553
20776
  const sourcePath = await resolveSyncFileSource(mainRoot, normalized);
20554
20777
  if (!sourcePath) continue;
20555
- const destPath = join15(targetPath, normalized);
20778
+ const destPath = join14(targetPath, normalized);
20556
20779
  const existingDestination = await readDestinationEntry(destPath);
20557
20780
  if (existingDestination?.isSymbolicLink()) {
20558
20781
  throw new Error(`destination is a symbolic link: ${destPath}`);
@@ -20573,14 +20796,14 @@ async function syncFiles(mainRoot, targetPath, patterns) {
20573
20796
  destinationParent
20574
20797
  );
20575
20798
  try {
20576
- const safeDestination = join15(safeParent.path, basename7(destPath));
20799
+ const safeDestination = join14(safeParent.path, basename8(destPath));
20577
20800
  const safeExistingDestination = await readDestinationEntry(safeDestination);
20578
20801
  if (safeExistingDestination?.isSymbolicLink()) {
20579
20802
  throw new Error(`destination is a symbolic link: ${destPath}`);
20580
20803
  }
20581
20804
  if (safeExistingDestination) continue;
20582
20805
  try {
20583
- await copyFile(sourcePath, safeDestination, constants7.COPYFILE_EXCL);
20806
+ await copyFile(sourcePath, safeDestination, constants8.COPYFILE_EXCL);
20584
20807
  } catch (error) {
20585
20808
  if (!isAlreadyExistsError(error)) throw error;
20586
20809
  }
@@ -20590,7 +20813,7 @@ async function syncFiles(mainRoot, targetPath, patterns) {
20590
20813
  }
20591
20814
  }
20592
20815
  function validateSyncFilePattern(pattern) {
20593
- if (isAbsolute5(pattern)) {
20816
+ if (isAbsolute6(pattern)) {
20594
20817
  throw new Error(
20595
20818
  `syncFiles: pattern must be a relative path, got: ${pattern}`
20596
20819
  );
@@ -20609,7 +20832,7 @@ async function resolveSyncFileSource(mainRoot, pattern) {
20609
20832
  try {
20610
20833
  [resolvedRoot, resolvedSource] = await Promise.all([
20611
20834
  realpath5(mainRoot),
20612
- realpath5(join15(mainRoot, pattern))
20835
+ realpath5(join14(mainRoot, pattern))
20613
20836
  ]);
20614
20837
  } catch (error) {
20615
20838
  if (isNotFoundError(error)) return void 0;
@@ -20623,7 +20846,7 @@ async function resolveSyncFileSource(mainRoot, pattern) {
20623
20846
  const sourceStats = await lstat6(resolvedSource);
20624
20847
  if (!sourceStats.isFile()) {
20625
20848
  throw new Error(
20626
- `syncFiles: source is not a file: ${join15(mainRoot, pattern)}`
20849
+ `syncFiles: source is not a file: ${join14(mainRoot, pattern)}`
20627
20850
  );
20628
20851
  }
20629
20852
  return resolvedSource;
@@ -20637,13 +20860,13 @@ async function readDestinationEntry(path9) {
20637
20860
  }
20638
20861
  }
20639
20862
  function isPathInside3(root, candidate) {
20640
- const distance = relative4(resolve11(root), resolve11(candidate));
20641
- return distance === "" || !isAbsolute5(distance) && distance !== ".." && !distance.startsWith(`..${sep4}`);
20863
+ const distance = relative5(resolve11(root), resolve11(candidate));
20864
+ return distance === "" || !isAbsolute6(distance) && distance !== ".." && !distance.startsWith(`..${sep5}`);
20642
20865
  }
20643
20866
 
20644
20867
  // src/package-manager.ts
20645
20868
  import { access as access8, readdir as readdir3 } from "node:fs/promises";
20646
- import { join as join16 } from "node:path";
20869
+ import { join as join15 } from "node:path";
20647
20870
  var ENTRIES = [
20648
20871
  // JavaScript / TypeScript
20649
20872
  { name: "pnpm", signals: ["pnpm-lock.yaml"], command: "pnpm install" },
@@ -20773,7 +20996,7 @@ async function detectPackageManager(repoRoot) {
20773
20996
  async function matchesExact(repoRoot, signals) {
20774
20997
  for (const signal of signals) {
20775
20998
  try {
20776
- await access8(join16(repoRoot, signal));
20999
+ await access8(join15(repoRoot, signal));
20777
21000
  return true;
20778
21001
  } catch {
20779
21002
  }
@@ -20888,9 +21111,9 @@ async function defaultWriteGlobalRepoConfigKey(repoRoot, key, value) {
20888
21111
  }
20889
21112
  async function loadExistingGlobalRepoHooks(repoRoot) {
20890
21113
  const { config: globalConfig } = await loadGlobalConfig();
20891
- const repos = isPlainObject3(globalConfig.repos) ? globalConfig.repos : {};
20892
- const perRepo = isPlainObject3(repos[repoRoot]) ? repos[repoRoot] : {};
20893
- return isPlainObject3(perRepo.hooks) ? perRepo.hooks : {};
21114
+ const repos = isPlainObject2(globalConfig.repos) ? globalConfig.repos : {};
21115
+ const perRepo = isPlainObject2(repos[repoRoot]) ? repos[repoRoot] : {};
21116
+ return isPlainObject2(perRepo.hooks) ? perRepo.hooks : {};
20894
21117
  }
20895
21118
  async function defaultPromptForInstallChoice(pm) {
20896
21119
  const choice = await ve({
@@ -20911,13 +21134,12 @@ async function defaultPromptForInstallChoice(pm) {
20911
21134
  }
20912
21135
  return choice;
20913
21136
  }
20914
- function isPlainObject3(value) {
21137
+ function isPlainObject2(value) {
20915
21138
  return typeof value === "object" && value !== null && !Array.isArray(value);
20916
21139
  }
20917
21140
 
20918
21141
  // src/sync-directories.ts
20919
21142
  async function executeSyncDirectoryPlan(plan, options) {
20920
- const failureStore = options.failureStore ?? defaultCloneFailureStore;
20921
21143
  const outcomes = [];
20922
21144
  for (const entry of plan) {
20923
21145
  if (entry.destinationWarning) {
@@ -20960,37 +21182,6 @@ async function executeSyncDirectoryPlan(plan, options) {
20960
21182
  );
20961
21183
  continue;
20962
21184
  }
20963
- const failureScope = await cloneFailureScope(
20964
- entry.source,
20965
- entry.destination
20966
- );
20967
- if (await failureStore.isCached(
20968
- options.repoRoot,
20969
- entry.directory,
20970
- failureScope
20971
- )) {
20972
- if (options.reporter.emitCachedFailureWarnings || options.reporter.skipped) {
20973
- recordSkipped(
20974
- outcomes,
20975
- options.reporter,
20976
- entry.directory,
20977
- "copy-on-write failure cached"
20978
- );
20979
- } else {
20980
- options.reporter.write(
20981
- `syncDirs: previous copy-on-write failure cached, skipped ${entry.directory}
20982
- `
20983
- );
20984
- recordSkipped(
20985
- outcomes,
20986
- options.reporter,
20987
- entry.directory,
20988
- "copy-on-write failure cached",
20989
- false
20990
- );
20991
- }
20992
- continue;
20993
- }
20994
21185
  const refreshedDestinationState = await inspectDestination(
20995
21186
  entry.worktreePath,
20996
21187
  entry.destination
@@ -21031,18 +21222,9 @@ async function executeSyncDirectoryPlan(plan, options) {
21031
21222
  continue;
21032
21223
  }
21033
21224
  const reason = toErrorMessage5(error);
21034
- if (isCloneUnsupportedError(error)) {
21035
- await failureStore.cache(
21036
- options.repoRoot,
21037
- entry.directory,
21038
- reason,
21039
- failureScope
21040
- );
21041
- }
21042
21225
  recordSkipped(outcomes, options.reporter, entry.directory, reason);
21043
21226
  continue;
21044
21227
  }
21045
- await failureStore.clear(options.repoRoot, entry.directory, failureScope);
21046
21228
  const clonedDirectory = {
21047
21229
  bytes: result.bytes,
21048
21230
  dir: entry.directory,
@@ -21054,13 +21236,11 @@ async function executeSyncDirectoryPlan(plan, options) {
21054
21236
  }
21055
21237
  return outcomes;
21056
21238
  }
21057
- function recordSkipped(outcomes, reporter, dir, reason, notify = true) {
21239
+ function recordSkipped(outcomes, reporter, dir, reason) {
21058
21240
  outcomes.push({ kind: "skipped", dir, reason });
21059
- if (notify) {
21060
- if (reporter.skipped) reporter.skipped({ dir, reason });
21061
- else reporter.write(`syncDirs: ${reason}, skipped ${dir}
21241
+ if (reporter.skipped) reporter.skipped({ dir, reason });
21242
+ else reporter.write(`syncDirs: ${reason}, skipped ${dir}
21062
21243
  `);
21063
- }
21064
21244
  }
21065
21245
  function toErrorMessage5(error) {
21066
21246
  return error instanceof Error ? error.message : String(error);
@@ -21083,7 +21263,6 @@ async function bootstrapWorktree(options) {
21083
21263
  );
21084
21264
  const outcomes = await executeSyncDirectoryPlan(syncPlan, {
21085
21265
  cloneDirectory: options.cloneDirectory ?? cloneDir,
21086
- repoRoot: options.repoRoot,
21087
21266
  reporter: options.reporter
21088
21267
  });
21089
21268
  const clonedDirs = outcomes.flatMap(
@@ -21115,7 +21294,6 @@ async function bootstrapWorktree(options) {
21115
21294
  }
21116
21295
  const dependencyBootstrap = syncFileFailures.length > 0 ? { mode: dependencyMode, ready: false, events: [] } : await executeDependencyBootstrap(dependencyPlan, {
21117
21296
  cloneDirectory: options.cloneDirectory,
21118
- repoRoot: options.repoRoot,
21119
21297
  reporter: options.reporter,
21120
21298
  stderr: options.commandStderr ?? options.reporter.write,
21121
21299
  stdout: options.commandStdout,
@@ -21151,7 +21329,7 @@ async function bootstrapWorktree(options) {
21151
21329
  {
21152
21330
  branch: options.branch,
21153
21331
  path: options.worktreePath,
21154
- repo: basename8(options.repoRoot),
21332
+ repo: basename9(options.repoRoot),
21155
21333
  slot
21156
21334
  },
21157
21335
  options.reporter.write,
@@ -21348,7 +21526,7 @@ ${dryRunSyncDirs.map(({ dir, bytes }) => `Would clone ${dir} (${formatBytes(byte
21348
21526
  }
21349
21527
  return 1;
21350
21528
  }
21351
- await mkdir9(dirname11(worktreePath), { recursive: true });
21529
+ await mkdir8(dirname11(worktreePath), { recursive: true });
21352
21530
  const branchAlreadyExists = await localBranchExists(
21353
21531
  repository.repoRoot,
21354
21532
  branchName
@@ -21507,8 +21685,8 @@ function sourceRefForForge(forge, prNumber) {
21507
21685
  return `refs/merge-requests/${prNumber}/head`;
21508
21686
  }
21509
21687
  }
21510
- async function writeOutput(worktreePath, stdout2, outputEnv) {
21511
- await writeShellOutput(outputEnv ?? PR_OUTPUT_FILE_ENV, worktreePath, stdout2);
21688
+ async function writeOutput(worktreePath, stdout3, outputEnv) {
21689
+ await writeShellOutput(outputEnv ?? PR_OUTPUT_FILE_ENV, worktreePath, stdout3);
21512
21690
  }
21513
21691
 
21514
21692
  // src/worktree-sources.ts
@@ -21765,7 +21943,7 @@ function normalizeRemoteUrl(value) {
21765
21943
 
21766
21944
  // src/new.ts
21767
21945
  import { execFile as execFile8 } from "node:child_process";
21768
- import { access as access9, mkdir as mkdir10 } from "node:fs/promises";
21946
+ import { access as access9, mkdir as mkdir9 } from "node:fs/promises";
21769
21947
  import { dirname as dirname12, resolve as resolve12 } from "node:path";
21770
21948
  import { promisify as promisify9 } from "node:util";
21771
21949
  var execFileAsync8 = promisify9(execFile8);
@@ -22020,7 +22198,7 @@ ${dryRunSyncDirs.map(({ dir, bytes }) => `Would clone ${dir} (${formatBytes(byte
22020
22198
  }
22021
22199
  return 0;
22022
22200
  }
22023
- await mkdir10(dirname12(worktreePath), { recursive: true });
22201
+ await mkdir9(dirname12(worktreePath), { recursive: true });
22024
22202
  const startPoint = options.fromCurrent && !options.detached ? await resolveCurrentWorktreeHead(options.cwd) : void 0;
22025
22203
  const takeStartPoint = options.take ? await resolveCurrentWorktreeHead(options.cwd) : void 0;
22026
22204
  const changedTakeFiles = options.take ? await listTakeFiles(options.cwd) : [];
@@ -22417,7 +22595,7 @@ async function localBranchExists2(repoRoot, branchName) {
22417
22595
  }
22418
22596
  async function resolveCurrentWorktreeHead(cwd) {
22419
22597
  return execFileAsync8("git", ["rev-parse", "--verify", "HEAD"], { cwd }).then(
22420
- ({ stdout: stdout2 }) => stdout2.trim()
22598
+ ({ stdout: stdout3 }) => stdout3.trim()
22421
22599
  );
22422
22600
  }
22423
22601
  async function createTakeStash(cwd, worktreeName) {
@@ -22427,12 +22605,12 @@ async function createTakeStash(cwd, worktreeName) {
22427
22605
  ["stash", "push", "--include-untracked", "-m", message],
22428
22606
  { cwd }
22429
22607
  );
22430
- const { stdout: stdout2 } = await execFileAsync8(
22608
+ const { stdout: stdout3 } = await execFileAsync8(
22431
22609
  "git",
22432
22610
  ["stash", "list", "--format=%H%x00%s"],
22433
22611
  { cwd }
22434
22612
  );
22435
- const line = stdout2.split("\n").map((candidate) => candidate.split("\0")).find(([, subject]) => subject?.endsWith(message));
22613
+ const line = stdout3.split("\n").map((candidate) => candidate.split("\0")).find(([, subject]) => subject?.endsWith(message));
22436
22614
  if (!line?.[0])
22437
22615
  throw new Error("could not identify the stash created for --take");
22438
22616
  return line[0];
@@ -22448,23 +22626,23 @@ async function detectInProgressGitState(cwd) {
22448
22626
  ];
22449
22627
  for (const [marker, name] of markers) {
22450
22628
  try {
22451
- const { stdout: stdout2 } = await execFileAsync8(
22629
+ const { stdout: stdout3 } = await execFileAsync8(
22452
22630
  "git",
22453
22631
  ["rev-parse", "--git-path", marker],
22454
22632
  { cwd }
22455
22633
  );
22456
- await access9(resolve12(cwd, stdout2.trim()));
22634
+ await access9(resolve12(cwd, stdout3.trim()));
22457
22635
  return name;
22458
22636
  } catch {
22459
22637
  }
22460
22638
  }
22461
22639
  return null;
22462
22640
  }
22463
- async function writeOutput2(worktreePath, stdout2, outputEnv) {
22641
+ async function writeOutput2(worktreePath, stdout3, outputEnv) {
22464
22642
  await writeShellOutput(
22465
22643
  outputEnv ?? NEW_OUTPUT_FILE_ENV,
22466
22644
  worktreePath,
22467
- stdout2
22645
+ stdout3
22468
22646
  );
22469
22647
  }
22470
22648
  function isNotRegisteredWorktreeError(error) {
@@ -22500,24 +22678,24 @@ async function openWorktree(worktreePath, editorCli, spawnFn, stderr) {
22500
22678
  }
22501
22679
  async function listTakeFiles(cwd) {
22502
22680
  try {
22503
- const { stdout: stdout2 } = await execFileAsync8(
22681
+ const { stdout: stdout3 } = await execFileAsync8(
22504
22682
  "git",
22505
22683
  ["status", "--porcelain=v1"],
22506
22684
  { cwd }
22507
22685
  );
22508
- return stdout2.split("\n").filter((line) => line.length > 3).map((line) => line.slice(3).replace(/^"|"$/g, ""));
22686
+ return stdout3.split("\n").filter((line) => line.length > 3).map((line) => line.slice(3).replace(/^"|"$/g, ""));
22509
22687
  } catch {
22510
22688
  return [];
22511
22689
  }
22512
22690
  }
22513
22691
  async function listIgnoredFiles(cwd) {
22514
22692
  try {
22515
- const { stdout: stdout2 } = await execFileAsync8(
22693
+ const { stdout: stdout3 } = await execFileAsync8(
22516
22694
  "git",
22517
22695
  ["status", "--porcelain=v1", "--ignored", "--untracked-files=all"],
22518
22696
  { cwd }
22519
22697
  );
22520
- return stdout2.split("\n").filter((line) => line.startsWith("!! ")).map((line) => line.slice(3).replace(/^"|"$/g, ""));
22698
+ return stdout3.split("\n").filter((line) => line.startsWith("!! ")).map((line) => line.slice(3).replace(/^"|"$/g, ""));
22521
22699
  } catch {
22522
22700
  return [];
22523
22701
  }
@@ -22525,11 +22703,11 @@ async function listIgnoredFiles(cwd) {
22525
22703
  async function listSubmoduleFiles(cwd, changedFiles) {
22526
22704
  if (changedFiles.length === 0) return [];
22527
22705
  try {
22528
- const { stdout: stdout2 } = await execFileAsync8("git", ["ls-files", "--stage"], {
22706
+ const { stdout: stdout3 } = await execFileAsync8("git", ["ls-files", "--stage"], {
22529
22707
  cwd
22530
22708
  });
22531
22709
  const submodules = new Set(
22532
- stdout2.split("\n").filter((line) => line.startsWith("160000 ")).map((line) => line.slice(line.indexOf(" ") + 1))
22710
+ stdout3.split("\n").filter((line) => line.startsWith("160000 ")).map((line) => line.slice(line.indexOf(" ") + 1))
22533
22711
  );
22534
22712
  return changedFiles.filter((file) => submodules.has(file));
22535
22713
  } catch {
@@ -22538,12 +22716,12 @@ async function listSubmoduleFiles(cwd, changedFiles) {
22538
22716
  }
22539
22717
  async function countUntrackedFiles(cwd) {
22540
22718
  try {
22541
- const { stdout: stdout2 } = await execFileAsync8(
22719
+ const { stdout: stdout3 } = await execFileAsync8(
22542
22720
  "git",
22543
22721
  ["status", "--porcelain=v1", "--untracked-files=all"],
22544
22722
  { cwd }
22545
22723
  );
22546
- return stdout2.split("\n").filter((line) => line.startsWith("?? ")).length;
22724
+ return stdout3.split("\n").filter((line) => line.startsWith("?? ")).length;
22547
22725
  } catch {
22548
22726
  return 0;
22549
22727
  }
@@ -22573,12 +22751,12 @@ async function applyTakeStash(worktreePath, sourcePath, stashSha, copy, stderr)
22573
22751
  }
22574
22752
  }
22575
22753
  try {
22576
- const { stdout: stdout2 } = await execFileAsync8(
22754
+ const { stdout: stdout3 } = await execFileAsync8(
22577
22755
  "git",
22578
22756
  ["stash", "list", "--format=%H %gd"],
22579
22757
  { cwd: sourcePath }
22580
22758
  );
22581
- const line = stdout2.split("\n").find((candidate) => candidate.startsWith(stashSha));
22759
+ const line = stdout3.split("\n").find((candidate) => candidate.startsWith(stashSha));
22582
22760
  const ref = line?.trim().split(/\s+/).at(1);
22583
22761
  if (ref)
22584
22762
  await execFileAsync8("git", ["stash", "drop", ref], { cwd: sourcePath });
@@ -22867,7 +23045,7 @@ async function navigateToExistingWorktree(options, path9, worktree) {
22867
23045
  {
22868
23046
  branch: worktree?.branch ?? void 0,
22869
23047
  path: path9,
22870
- repo: basename9(repository.repoRoot),
23048
+ repo: basename10(repository.repoRoot),
22871
23049
  slot: await getWorktreeSlot(path9)
22872
23050
  },
22873
23051
  options.stderr
@@ -23005,7 +23183,8 @@ async function runHistoryCommand(options) {
23005
23183
  }
23006
23184
 
23007
23185
  // src/hub.ts
23008
- import { basename as basename10 } from "node:path";
23186
+ import { basename as basename11 } from "node:path";
23187
+ import { stdin as stdin2, stdout as stdout2 } from "node:process";
23009
23188
  var MAX_HUB_REPOSITORY_CONCURRENCY = 4;
23010
23189
  var defaultDependencies = {
23011
23190
  queryRepositoryPullRequests: createPullRequestQuery().listOpenPullRequestsForRepository
@@ -23027,7 +23206,7 @@ async function buildHubData(cwd, dependencies = {}) {
23027
23206
  existing.sources.push(source);
23028
23207
  } else {
23029
23208
  groups.set(repoRoot, {
23030
- name: source.repoName || basename10(repoRoot),
23209
+ name: source.repoName || basename11(repoRoot),
23031
23210
  sources: [source]
23032
23211
  });
23033
23212
  }
@@ -23070,7 +23249,14 @@ async function buildHubData(cwd, dependencies = {}) {
23070
23249
  };
23071
23250
  }
23072
23251
  async function runHubCommand(options, dependencies = {}) {
23073
- const data = await buildHubData(options.cwd, dependencies);
23252
+ const loading = !options.json && stdin2.isTTY === true && stdout2.isTTY === true ? Y2({ indicator: "timer" }) : null;
23253
+ loading?.start("Loading worktrees");
23254
+ let data;
23255
+ try {
23256
+ data = await buildHubData(options.cwd, dependencies);
23257
+ } finally {
23258
+ loading?.stop();
23259
+ }
23074
23260
  if (options.json) {
23075
23261
  options.stdout(`${JSON.stringify(data, null, 2)}
23076
23262
  `);
@@ -23282,9 +23468,9 @@ async function mapWithConcurrency4(items, limit, mapper) {
23282
23468
  }
23283
23469
 
23284
23470
  // src/init.ts
23285
- import { constants as constants8 } from "node:fs";
23286
- import { access as access10, mkdir as mkdir11, readFile as readFile11, writeFile as writeFile10 } from "node:fs/promises";
23287
- import { homedir as homedir9 } from "node:os";
23471
+ import { constants as constants9 } from "node:fs";
23472
+ import { access as access10, mkdir as mkdir10, readFile as readFile10, writeFile as writeFile9 } from "node:fs/promises";
23473
+ import { homedir as homedir8 } from "node:os";
23288
23474
  import { dirname as dirname13 } from "node:path";
23289
23475
  var ZSH_COMPLETION_PATH_LINE = "fpath=(~/.zsh/completions $fpath)";
23290
23476
  var SHELL_WRAPPED_COMMANDS = [
@@ -23355,7 +23541,7 @@ async function runOnboardingInitCommand(options) {
23355
23541
  if (options.json || isHeadless() || !canRunOnboarding(options)) {
23356
23542
  return writeNonInteractiveInitError(options);
23357
23543
  }
23358
- const home = options.home ?? homedir9();
23544
+ const home = options.home ?? homedir8();
23359
23545
  const context = {
23360
23546
  detectedShell: resolveSupportedShell(void 0, process.env.SHELL),
23361
23547
  home
@@ -23409,8 +23595,8 @@ async function runDefaultOnboarding(context) {
23409
23595
  const installCompletion = await promptForCompletion(shell, completionPath);
23410
23596
  if (installCompletion === null) return abortDefaultOnboarding();
23411
23597
  if (installCompletion) {
23412
- await mkdir11(dirname13(completionPath), { recursive: true });
23413
- await writeFile10(completionPath, renderShellCompletion(shell), "utf8");
23598
+ await mkdir10(dirname13(completionPath), { recursive: true });
23599
+ await writeFile9(completionPath, renderShellCompletion(shell), "utf8");
23414
23600
  }
23415
23601
  if (shell === "zsh" && (completionAlreadyInstalled || installCompletion)) {
23416
23602
  await ensureZshCompletionPath(rcPath);
@@ -23502,8 +23688,8 @@ async function applyOnboardingResult(result, home) {
23502
23688
  const completionAlreadyInstalled = await fileExists(completionPath);
23503
23689
  await applyShellIntegration(result.shell, result.shellIntegration, home);
23504
23690
  if (result.installCompletion) {
23505
- await mkdir11(dirname13(completionPath), { recursive: true });
23506
- await writeFile10(
23691
+ await mkdir10(dirname13(completionPath), { recursive: true });
23692
+ await writeFile9(
23507
23693
  completionPath,
23508
23694
  renderShellCompletion(result.shell),
23509
23695
  "utf8"
@@ -23518,17 +23704,17 @@ async function applyOnboardingResult(result, home) {
23518
23704
  }
23519
23705
  async function installOnboardingShellIntegration(shell, home) {
23520
23706
  const rcPath = resolveShellConfigPath(shell, home);
23521
- await mkdir11(dirname13(rcPath), { recursive: true });
23707
+ await mkdir10(dirname13(rcPath), { recursive: true });
23522
23708
  const current = await readExistingConfig(rcPath);
23523
23709
  if (shell === "fish") {
23524
- await writeFile10(
23710
+ await writeFile9(
23525
23711
  rcPath,
23526
23712
  upsertShellIntegration(current, renderShellIntegration(shell)),
23527
23713
  "utf8"
23528
23714
  );
23529
23715
  return;
23530
23716
  }
23531
- await writeFile10(
23717
+ await writeFile9(
23532
23718
  rcPath,
23533
23719
  upsertOnboardingShellIntegration(current, shell),
23534
23720
  "utf8"
@@ -23562,7 +23748,7 @@ async function ensureZshCompletionPath(rcPath) {
23562
23748
  const current = await readExistingConfig(rcPath);
23563
23749
  const next = upsertZshCompletionPath(current);
23564
23750
  if (next !== current) {
23565
- await writeFile10(rcPath, next, "utf8");
23751
+ await writeFile9(rcPath, next, "utf8");
23566
23752
  }
23567
23753
  }
23568
23754
  function upsertZshCompletionPath(existingConfig) {
@@ -23585,7 +23771,7 @@ ${suffix}`
23585
23771
  }
23586
23772
  async function fileExists(path9) {
23587
23773
  try {
23588
- await access10(path9, constants8.F_OK);
23774
+ await access10(path9, constants9.F_OK);
23589
23775
  return true;
23590
23776
  } catch {
23591
23777
  return false;
@@ -23593,7 +23779,7 @@ async function fileExists(path9) {
23593
23779
  }
23594
23780
  async function runLegacyInitCommand(options) {
23595
23781
  const shell = resolveSupportedShell(options.shell, process.env.SHELL);
23596
- const home = options.home ?? homedir9();
23782
+ const home = options.home ?? homedir8();
23597
23783
  if (!shell) {
23598
23784
  options.stderr?.(
23599
23785
  "Unable to detect a supported shell. Specify one explicitly: bash, fish, or zsh.\n"
@@ -23606,10 +23792,10 @@ async function runLegacyInitCommand(options) {
23606
23792
  return 0;
23607
23793
  }
23608
23794
  const rcPath = resolveShellConfigPath(shell, home);
23609
- await mkdir11(dirname13(rcPath), { recursive: true });
23795
+ await mkdir10(dirname13(rcPath), { recursive: true });
23610
23796
  const current = await readExistingConfig(rcPath);
23611
23797
  const next = upsertShellIntegration(current, script);
23612
- await writeFile10(rcPath, next, "utf8");
23798
+ await writeFile9(rcPath, next, "utf8");
23613
23799
  options.stdout(`${rcPath}
23614
23800
  `);
23615
23801
  const { config: globalConfig } = await loadGlobalConfig(home);
@@ -23700,7 +23886,7 @@ async function saveWizardConfig(result, cwd, home) {
23700
23886
  }
23701
23887
  async function readExistingConfig(path9) {
23702
23888
  try {
23703
- return await readFile11(path9, "utf8");
23889
+ return await readFile10(path9, "utf8");
23704
23890
  } catch (error) {
23705
23891
  if (isMissingFileError3(error)) {
23706
23892
  return "";
@@ -23950,8 +24136,8 @@ function sortWorktrees(worktrees) {
23950
24136
 
23951
24137
  // src/open.ts
23952
24138
  import { execFile as execFile9 } from "node:child_process";
23953
- import { access as access11, writeFile as writeFile11 } from "node:fs/promises";
23954
- import { join as join17 } from "node:path";
24139
+ import { access as access11, writeFile as writeFile10 } from "node:fs/promises";
24140
+ import { join as join16 } from "node:path";
23955
24141
  import { promisify as promisify10 } from "node:util";
23956
24142
  var execFileAsync9 = promisify10(execFile9);
23957
24143
  function createOpenCommand(dependencies = {}) {
@@ -24118,14 +24304,14 @@ async function defaultPromptForEditor(editors) {
24118
24304
  return choice;
24119
24305
  }
24120
24306
  async function ensureWorkspaceFile(worktreePath, repoName) {
24121
- const workspacePath = join17(worktreePath, `${repoName}.code-workspace`);
24307
+ const workspacePath = join16(worktreePath, `${repoName}.code-workspace`);
24122
24308
  try {
24123
24309
  await access11(workspacePath);
24124
24310
  return workspacePath;
24125
24311
  } catch {
24126
24312
  }
24127
24313
  const workspace = { folders: [{ path: "." }], settings: {} };
24128
- await writeFile11(
24314
+ await writeFile10(
24129
24315
  workspacePath,
24130
24316
  `${JSON.stringify(workspace, null, 2)}
24131
24317
  `,
@@ -24533,7 +24719,7 @@ function formatError(error) {
24533
24719
  }
24534
24720
 
24535
24721
  // src/remove.ts
24536
- import { basename as basename11 } from "node:path";
24722
+ import { basename as basename12 } from "node:path";
24537
24723
  var REMOVE_OUTPUT_FILE_ENV = "GJI_REMOVE_OUTPUT_FILE";
24538
24724
  function createRemoveCommand(dependencies = {}) {
24539
24725
  const promptForWorktree2 = dependencies.promptForWorktree ?? defaultPromptForWorktree3;
@@ -24639,7 +24825,7 @@ function createRemoveCommand(dependencies = {}) {
24639
24825
  {
24640
24826
  branch: worktree.branch ?? void 0,
24641
24827
  path: worktree.path,
24642
- repo: basename11(repository.repoRoot)
24828
+ repo: basename12(repository.repoRoot)
24643
24829
  },
24644
24830
  options.stderr
24645
24831
  );
@@ -24717,8 +24903,8 @@ async function defaultConfirmRemoval2(worktree) {
24717
24903
  });
24718
24904
  return !pD(choice) && choice;
24719
24905
  }
24720
- async function writeOutput3(repoRoot, stdout2) {
24721
- await writeShellOutput(REMOVE_OUTPUT_FILE_ENV, repoRoot, stdout2);
24906
+ async function writeOutput3(repoRoot, stdout3) {
24907
+ await writeShellOutput(REMOVE_OUTPUT_FILE_ENV, repoRoot, stdout3);
24722
24908
  }
24723
24909
  function emitError3(options, message) {
24724
24910
  if (options.json) {
@@ -25037,11 +25223,11 @@ function resolveConfiguredString2(value) {
25037
25223
  }
25038
25224
 
25039
25225
  // src/sync-files-command.ts
25040
- import { homedir as homedir10 } from "node:os";
25041
- import { join as join18 } from "node:path";
25226
+ import { homedir as homedir9 } from "node:os";
25227
+ import { join as join17 } from "node:path";
25042
25228
  async function runSyncFilesCommand(options) {
25043
25229
  const repository = await detectRepository(options.cwd);
25044
- const home = options.home ?? homedir10();
25230
+ const home = options.home ?? homedir9();
25045
25231
  const loaded = await loadGlobalConfig(home);
25046
25232
  const repoEntry = findRepoConfigEntry(
25047
25233
  loaded.config,
@@ -25085,9 +25271,9 @@ async function runSyncFilesCommand(options) {
25085
25271
  }
25086
25272
  function findRepoConfigEntry(config, repoRoot, home) {
25087
25273
  const repos = config.repos;
25088
- if (!isPlainObject4(repos)) return null;
25274
+ if (!isPlainObject3(repos)) return null;
25089
25275
  for (const [key, value] of Object.entries(repos)) {
25090
- if (expandTilde3(key, home) === repoRoot && isPlainObject4(value)) {
25276
+ if (expandTilde3(key, home) === repoRoot && isPlainObject3(value)) {
25091
25277
  return { config: value, key };
25092
25278
  }
25093
25279
  }
@@ -25098,17 +25284,17 @@ function readSyncFiles(config) {
25098
25284
  if (!Array.isArray(syncFiles2)) return [];
25099
25285
  return syncFiles2.filter((item) => typeof item === "string");
25100
25286
  }
25101
- function writeSyncFiles(stdout2, files, json) {
25287
+ function writeSyncFiles(stdout3, files, json) {
25102
25288
  if (json) {
25103
- stdout2(`${JSON.stringify(files, null, 2)}
25289
+ stdout3(`${JSON.stringify(files, null, 2)}
25104
25290
  `);
25105
25291
  return;
25106
25292
  }
25107
25293
  if (files.length === 0) {
25108
- stdout2("No sync files configured for this repo.\n");
25294
+ stdout3("No sync files configured for this repo.\n");
25109
25295
  return;
25110
25296
  }
25111
- stdout2(`${files.join("\n")}
25297
+ stdout3(`${files.join("\n")}
25112
25298
  `);
25113
25299
  }
25114
25300
  function validatePaths(paths, options) {
@@ -25144,8 +25330,8 @@ function removeSyncFiles(existing, removals) {
25144
25330
  return existing.filter((path9) => !removalSet.has(path9));
25145
25331
  }
25146
25332
  async function saveRepoSyncFiles(config, repoKey, syncFiles2, home) {
25147
- const repos = isPlainObject4(config.repos) ? { ...config.repos } : {};
25148
- const repoConfig = isPlainObject4(repos[repoKey]) ? repos[repoKey] : {};
25333
+ const repos = isPlainObject3(config.repos) ? { ...config.repos } : {};
25334
+ const repoConfig = isPlainObject3(repos[repoKey]) ? repos[repoKey] : {};
25149
25335
  const nextRepoConfig = { ...repoConfig };
25150
25336
  if (syncFiles2.length > 0) {
25151
25337
  nextRepoConfig.syncFiles = syncFiles2;
@@ -25159,7 +25345,7 @@ async function saveRepoSyncFiles(config, repoKey, syncFiles2, home) {
25159
25345
  }
25160
25346
  await saveGlobalConfig({ ...config, repos }, home);
25161
25347
  }
25162
- function isPlainObject4(value) {
25348
+ function isPlainObject3(value) {
25163
25349
  return typeof value === "object" && value !== null && !Array.isArray(value);
25164
25350
  }
25165
25351
  function writeError(options, message) {
@@ -25173,7 +25359,7 @@ function writeError(options, message) {
25173
25359
  }
25174
25360
  function expandTilde3(value, home) {
25175
25361
  if (value === "~") return home;
25176
- if (value.startsWith("~/")) return join18(home, value.slice(2));
25362
+ if (value.startsWith("~/")) return join17(home, value.slice(2));
25177
25363
  return value;
25178
25364
  }
25179
25365
 
@@ -25353,7 +25539,7 @@ function readPackageMetadata() {
25353
25539
  async function runCli(argv, options = {}) {
25354
25540
  await maybeNotifyForUpdates(argv);
25355
25541
  const cwd = options.cwd ?? process.cwd();
25356
- const stdout2 = options.stdout ?? (() => void 0);
25542
+ const stdout3 = options.stdout ?? (() => void 0);
25357
25543
  const stderr = options.stderr ?? (() => void 0);
25358
25544
  if (shouldRegisterCurrentRepo(argv) || isHubInvocation(argv)) {
25359
25545
  await maybeRegisterCurrentRepo(cwd);
@@ -25361,7 +25547,7 @@ async function runCli(argv, options = {}) {
25361
25547
  const program2 = createProgram();
25362
25548
  program2.configureOutput({
25363
25549
  writeErr: stderr,
25364
- writeOut: stdout2
25550
+ writeOut: stdout3
25365
25551
  });
25366
25552
  program2.exitOverride();
25367
25553
  if (isHubInvocation(argv)) {
@@ -25372,7 +25558,7 @@ async function runCli(argv, options = {}) {
25372
25558
  json: argv.includes("--json"),
25373
25559
  now: options.now,
25374
25560
  stderr,
25375
- stdout: stdout2
25561
+ stdout: stdout3
25376
25562
  },
25377
25563
  options.hubDependencies
25378
25564
  );
@@ -25383,7 +25569,7 @@ async function runCli(argv, options = {}) {
25383
25569
  cwd,
25384
25570
  prOpenDependencies: options.prOpenDependencies,
25385
25571
  stderr,
25386
- stdout: stdout2
25572
+ stdout: stdout3
25387
25573
  });
25388
25574
  await program2.parseAsync(["node", "gji", ...argv], { from: "node" });
25389
25575
  return { exitCode: 0 };
@@ -25992,7 +26178,7 @@ async function main() {
25992
26178
  }
25993
26179
  async function warnIfMissingShellIntegration() {
25994
26180
  try {
25995
- const { config } = await loadGlobalConfig(homedir11());
26181
+ const { config } = await loadGlobalConfig(homedir10());
25996
26182
  if (!config.shellIntegration) {
25997
26183
  const setupCommand = isHeadless() ? legacyShellSetupCommand() : "gji init";
25998
26184
  process.stderr.write(