@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.
- package/dist/bootstrap-output.js +0 -1
- package/dist/dependency-bootstrap.d.ts +10 -17
- package/dist/dependency-bootstrap.js +343 -108
- package/dist/dir-clone.d.ts +1 -2
- package/dist/dir-clone.js +303 -167
- package/dist/gji-bundle.mjs +985 -799
- package/dist/hub.js +13 -1
- package/dist/safe-destination.js +10 -0
- package/dist/sync-directories.d.ts +0 -4
- package/dist/sync-directories.js +6 -26
- package/dist/worktree-bootstrap.js +0 -2
- package/dist/worktree-picker.js +13 -0
- package/man/man1/gji-back.1 +1 -1
- package/man/man1/gji-clean.1 +1 -1
- package/man/man1/gji-completion.1 +1 -1
- package/man/man1/gji-config.1 +1 -1
- package/man/man1/gji-doctor.1 +1 -1
- package/man/man1/gji-done.1 +1 -1
- package/man/man1/gji-go.1 +1 -1
- package/man/man1/gji-history.1 +1 -1
- package/man/man1/gji-init.1 +1 -1
- package/man/man1/gji-ls.1 +1 -1
- package/man/man1/gji-new.1 +1 -1
- package/man/man1/gji-open.1 +1 -1
- package/man/man1/gji-pr.1 +1 -1
- package/man/man1/gji-remove.1 +1 -1
- package/man/man1/gji-root.1 +1 -1
- package/man/man1/gji-run-hook.1 +1 -1
- package/man/man1/gji-status.1 +1 -1
- package/man/man1/gji-sync-files.1 +1 -1
- package/man/man1/gji-sync.1 +1 -1
- package/man/man1/gji-task.1 +1 -1
- package/man/man1/gji-undo.1 +1 -1
- package/man/man1/gji-warp.1 +1 -1
- package/man/man1/gji.1 +1 -1
- package/package.json +1 -1
- package/dist/clone-failure-store.d.ts +0 -18
- package/dist/clone-failure-store.js +0 -230
package/dist/gji-bundle.mjs
CHANGED
|
@@ -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
|
|
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 (
|
|
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
|
|
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(
|
|
3550
|
-
return
|
|
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
|
-
|
|
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,
|
|
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 (
|
|
3627
|
+
if (constants10.hasOwnProperty("O_SYMLINK") && fs6.futimes) {
|
|
3628
3628
|
fs6.lutimes = function(path9, at, mt, cb) {
|
|
3629
|
-
fs6.open(path9,
|
|
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,
|
|
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 =
|
|
3955
|
-
function
|
|
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 =
|
|
3972
|
-
function
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
4169
|
-
function
|
|
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
|
|
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
|
-
|
|
5415
|
-
|
|
5414
|
+
join18(etc, name, "config"),
|
|
5415
|
+
join18(etc, name + "rc")
|
|
5416
5416
|
].forEach(addConfigFile);
|
|
5417
5417
|
if (home)
|
|
5418
5418
|
[
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
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
|
|
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 (
|
|
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
|
|
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(
|
|
5524
|
-
return
|
|
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
|
-
|
|
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,
|
|
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 (
|
|
5601
|
+
if (constants10.hasOwnProperty("O_SYMLINK") && fs6.futimes) {
|
|
5602
5602
|
fs6.lutimes = function(path9, at, mt, cb) {
|
|
5603
|
-
fs6.open(path9,
|
|
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,
|
|
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 =
|
|
5929
|
-
function
|
|
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 =
|
|
5946
|
-
function
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
6143
|
-
function
|
|
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
|
|
6994
|
-
this[
|
|
6993
|
+
const g2 = this.get("global");
|
|
6994
|
+
this[g2 ? "globalPrefix" : "localPrefix"] = prefix;
|
|
6995
6995
|
},
|
|
6996
6996
|
get: () => {
|
|
6997
|
-
const
|
|
6998
|
-
return
|
|
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
|
|
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:
|
|
8815
|
-
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 = (
|
|
9360
|
-
let string = "" + input, index = string.indexOf(close,
|
|
9361
|
-
return ~index ?
|
|
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
|
|
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
|
|
9785
|
-
if (
|
|
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(
|
|
9787
|
+
const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(basename13);
|
|
9788
9788
|
if (!truncable)
|
|
9789
9789
|
return filePath;
|
|
9790
|
-
const truncationLength =
|
|
9791
|
-
return `${filePath.slice(0, -
|
|
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 = (
|
|
10620
|
+
var createStyler = (open4, close, parent) => {
|
|
10621
10621
|
let openAll;
|
|
10622
10622
|
let closeAll;
|
|
10623
10623
|
if (parent === void 0) {
|
|
10624
|
-
openAll =
|
|
10624
|
+
openAll = open4;
|
|
10625
10625
|
closeAll = close;
|
|
10626
10626
|
} else {
|
|
10627
|
-
openAll = parent.openAll +
|
|
10627
|
+
openAll = parent.openAll + open4;
|
|
10628
10628
|
closeAll = close + parent.closeAll;
|
|
10629
10629
|
}
|
|
10630
10630
|
return {
|
|
10631
|
-
open:
|
|
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:
|
|
12323
|
-
if (
|
|
12324
|
-
return
|
|
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,
|
|
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,
|
|
13211
|
+
await runArgvHook(hookCmd, cwd, context, stderr, stdout3);
|
|
13212
13212
|
return;
|
|
13213
13213
|
}
|
|
13214
|
-
await runShellHook(hookCmd, cwd, context, stderr,
|
|
13214
|
+
await runShellHook(hookCmd, cwd, context, stderr, stdout3);
|
|
13215
13215
|
}
|
|
13216
|
-
async function runArgvHook(hookCmd, cwd, context, stderr,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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:
|
|
13342
|
-
return
|
|
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:
|
|
13349
|
+
const { stdout: stdout3 } = await execFileAsync(
|
|
13350
13350
|
"git",
|
|
13351
13351
|
["status", "--porcelain=v2", "--branch"],
|
|
13352
13352
|
{ cwd }
|
|
13353
13353
|
);
|
|
13354
|
-
return parseWorktreeHealth(
|
|
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:
|
|
13374
|
+
const { stdout: stdout3 } = await execFileAsync(
|
|
13375
13375
|
"git",
|
|
13376
13376
|
["ls-remote", "--symref", remote, "HEAD"],
|
|
13377
13377
|
{ cwd }
|
|
13378
13378
|
);
|
|
13379
|
-
const refLine =
|
|
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:
|
|
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(
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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 &&
|
|
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,
|
|
15267
|
-
const payload = JSON.parse(
|
|
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(
|
|
16197
|
+
function color(open4, close, value) {
|
|
16117
16198
|
if (env4.NO_COLOR !== void 0) return value;
|
|
16118
|
-
return `${
|
|
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(
|
|
17585
|
-
|
|
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:
|
|
18088
|
-
const version = parseGitVersion(
|
|
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
|
|
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
|
|
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 {
|
|
18686
|
-
import {
|
|
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
|
-
|
|
18693
|
-
|
|
18694
|
-
|
|
18695
|
-
|
|
18696
|
-
|
|
18697
|
-
|
|
18698
|
-
|
|
18699
|
-
|
|
18700
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
18971
|
-
mkdtemp
|
|
18824
|
+
mkdir as mkdir7,
|
|
18825
|
+
mkdtemp,
|
|
18972
18826
|
opendir,
|
|
18973
|
-
readdir
|
|
18974
|
-
readFile as
|
|
18827
|
+
readdir,
|
|
18828
|
+
readFile as readFile8,
|
|
18975
18829
|
readlink,
|
|
18976
18830
|
realpath as realpath2,
|
|
18977
|
-
rename as
|
|
18978
|
-
rm as
|
|
18979
|
-
rmdir
|
|
18831
|
+
rename as rename3,
|
|
18832
|
+
rm as rm3,
|
|
18833
|
+
rmdir,
|
|
18980
18834
|
symlink,
|
|
18981
|
-
unlink as
|
|
18982
|
-
utimes
|
|
18983
|
-
writeFile as
|
|
18835
|
+
unlink as unlink3,
|
|
18836
|
+
utimes,
|
|
18837
|
+
writeFile as writeFile8
|
|
18984
18838
|
} from "node:fs/promises";
|
|
18985
|
-
import { basename as basename6, dirname as
|
|
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
|
|
19015
|
-
import { isAbsolute as isAbsolute3, join as
|
|
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
|
-
|
|
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 =
|
|
18889
|
+
const childPath = join10(fileDescriptorPath(handle.fd), segment);
|
|
19026
18890
|
try {
|
|
19027
|
-
await
|
|
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 =
|
|
19046
|
-
const resolvedRoot =
|
|
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 =
|
|
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 =
|
|
19105
|
-
const resolvedPath =
|
|
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 =
|
|
19124
|
-
const resolvedPath =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
19174
|
-
|
|
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 =
|
|
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
|
|
19059
|
+
await mkdir7(parent, { recursive: true });
|
|
19194
19060
|
}
|
|
19195
19061
|
const operationParent = safeParent?.path ?? parent;
|
|
19196
|
-
const operationDestination =
|
|
19197
|
-
|
|
19198
|
-
|
|
19199
|
-
|
|
19200
|
-
|
|
19201
|
-
const
|
|
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
|
|
19205
|
-
const
|
|
19069
|
+
let reservation;
|
|
19070
|
+
const publishedEntries = [];
|
|
19206
19071
|
try {
|
|
19207
|
-
|
|
19208
|
-
|
|
19209
|
-
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
19233
|
-
(entry) =>
|
|
19097
|
+
reservation.path,
|
|
19098
|
+
(entry) => publishedEntries.push(entry),
|
|
19234
19099
|
options.copyFile ?? runForcedCloneFileCopy
|
|
19235
19100
|
);
|
|
19236
|
-
|
|
19101
|
+
reservation = void 0;
|
|
19237
19102
|
} finally {
|
|
19238
19103
|
stopLockHeartbeat();
|
|
19239
|
-
if (
|
|
19104
|
+
if (reservation) {
|
|
19240
19105
|
await cleanupReservedDestination(
|
|
19241
19106
|
operationDestination,
|
|
19242
|
-
|
|
19243
|
-
|
|
19107
|
+
reservation,
|
|
19108
|
+
publishedEntries
|
|
19244
19109
|
);
|
|
19245
19110
|
}
|
|
19246
|
-
|
|
19247
|
-
|
|
19248
|
-
|
|
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
|
-
|
|
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
|
|
19264
|
-
|
|
19265
|
-
|
|
19266
|
-
|
|
19267
|
-
|
|
19268
|
-
|
|
19269
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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() -
|
|
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-${
|
|
19270
|
+
const stalePath = `${lockPath}.stale-${randomUUID2()}`;
|
|
19393
19271
|
try {
|
|
19394
|
-
await
|
|
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
|
|
19401
|
-
|
|
19402
|
-
await
|
|
19403
|
-
|
|
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
|
|
19284
|
+
await cleanupStaleCloneLock(stalePath, staleLock);
|
|
19416
19285
|
} catch (cleanupError) {
|
|
19417
|
-
await
|
|
19286
|
+
await releaseCloneLockWithGuard(replacement).catch(() => void 0);
|
|
19418
19287
|
throw cleanupError;
|
|
19419
19288
|
}
|
|
19420
|
-
return
|
|
19289
|
+
return replacement;
|
|
19421
19290
|
} catch (error) {
|
|
19422
|
-
await
|
|
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
|
|
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
|
|
19434
|
-
|
|
19435
|
-
|
|
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
|
|
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
|
|
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
|
|
19446
|
+
const temporaryEntries = await readdir(temporaryDestination);
|
|
19448
19447
|
for (const entry of temporaryEntries) {
|
|
19449
19448
|
await publishCloneEntry(
|
|
19450
|
-
|
|
19451
|
-
|
|
19452
|
-
() => onEntryPublished(
|
|
19449
|
+
join11(temporaryDestination, entry),
|
|
19450
|
+
join11(destination, entry),
|
|
19451
|
+
(entry2) => onEntryPublished(entry2),
|
|
19453
19452
|
copyFileEntry
|
|
19454
19453
|
);
|
|
19455
19454
|
}
|
|
19456
|
-
await
|
|
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
|
|
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
|
|
19468
|
+
onCreated(await inspectOwnedCloneEntry(destination, "directory"));
|
|
19469
|
+
for (const entry of await readdir(source)) {
|
|
19471
19470
|
await publishCloneEntry(
|
|
19472
|
-
|
|
19473
|
-
|
|
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
|
|
19519
|
+
await utimes(destination, sourceStats.atime, sourceStats.mtime);
|
|
19521
19520
|
}
|
|
19522
19521
|
async function reserveDestination(destination) {
|
|
19523
19522
|
try {
|
|
19524
|
-
await
|
|
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 =
|
|
19530
|
+
const reservationPath = join11(
|
|
19532
19531
|
destination,
|
|
19533
|
-
`.gji-clone-reservation-${
|
|
19532
|
+
`.gji-clone-reservation-${randomUUID2()}`
|
|
19534
19533
|
);
|
|
19535
19534
|
try {
|
|
19536
|
-
await
|
|
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
|
|
19540
|
+
await rmdir(destination).catch(() => void 0);
|
|
19542
19541
|
throw error;
|
|
19543
19542
|
}
|
|
19544
19543
|
}
|
|
19545
|
-
async function cleanupReservedDestination(destination,
|
|
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
|
|
19548
|
-
|
|
19549
|
-
|
|
19550
|
-
|
|
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(
|
|
19572
|
+
function startLockHeartbeat(lock) {
|
|
19568
19573
|
const timer = setInterval(() => {
|
|
19569
|
-
void refreshCloneLock(
|
|
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(
|
|
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
|
|
19582
|
+
await utimes(lock.markerPath, now, now);
|
|
19580
19583
|
} catch {
|
|
19581
19584
|
}
|
|
19582
19585
|
}
|
|
19583
|
-
async function releaseCloneLock(
|
|
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
|
-
|
|
19586
|
-
await unlink4(ownerPath);
|
|
19587
|
-
await rmdir2(lockPath);
|
|
19604
|
+
await rmdir(lock.lockPath);
|
|
19588
19605
|
} catch (error) {
|
|
19589
|
-
|
|
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 /
|
|
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
|
|
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 = {
|
|
19648
|
-
|
|
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 ??
|
|
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
|
|
19668
|
-
kind: planned.
|
|
19669
|
-
lockfile: planned.
|
|
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(({
|
|
19679
|
-
adapter:
|
|
19680
|
-
kind:
|
|
19681
|
-
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 {
|
|
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,
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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: "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19863
|
-
|
|
19864
|
-
|
|
19865
|
-
|
|
19866
|
-
|
|
19867
|
-
|
|
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-
|
|
19874
|
-
state: "
|
|
19870
|
+
reason: "cow-seed-failed",
|
|
19871
|
+
state: "repair-only",
|
|
19875
19872
|
target: target.relativePath,
|
|
19876
|
-
message: `CoW seed failed; repairing from
|
|
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: "
|
|
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,
|
|
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
|
|
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:
|
|
19912
|
+
message: repairSuccessMessage(target, effectiveInput)
|
|
19924
19913
|
});
|
|
19925
19914
|
} catch (firstError) {
|
|
19926
19915
|
const firstFailureContext = {
|
|
19927
|
-
|
|
19928
|
-
|
|
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: "
|
|
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
|
|
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:
|
|
19977
|
+
message: repairSuccessMessage(target, retryInput)
|
|
19990
19978
|
});
|
|
19991
19979
|
} catch (secondError) {
|
|
19992
19980
|
const cleanupError2 = await adapter.cleanupAfterRepairFailure({
|
|
19993
|
-
|
|
19994
|
-
|
|
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 (
|
|
20043
|
-
await
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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(
|
|
20128
|
-
const sourcePath =
|
|
20129
|
-
const targetPath =
|
|
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
|
-
|
|
20161
|
+
shell: this.shell,
|
|
20162
|
+
initialInput
|
|
20145
20163
|
};
|
|
20146
20164
|
return {
|
|
20147
20165
|
...target,
|
|
20148
|
-
repairCommand: this.
|
|
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
|
-
|
|
20176
|
+
repairCommand,
|
|
20158
20177
|
target.worktreePath,
|
|
20159
20178
|
context.stderr,
|
|
20160
20179
|
context.stdout,
|
|
20161
20180
|
{
|
|
20162
20181
|
...this.commandOptions?.(target),
|
|
20163
|
-
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.
|
|
20193
|
+
return context.input === "seed";
|
|
20182
20194
|
}
|
|
20183
20195
|
async cleanupAfterRepairFailure(context) {
|
|
20184
|
-
if (context.
|
|
20185
|
-
|
|
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
|
|
20211
|
-
|
|
20214
|
+
const config = await readFile9(
|
|
20215
|
+
join12(target.sourcePath, "pyvenv.cfg"),
|
|
20212
20216
|
"utf8"
|
|
20213
20217
|
);
|
|
20214
|
-
const expected = config.match(/^version
|
|
20218
|
+
const expected = config.match(/^version(?:_info)?\s*=\s*(\d+\.\d+)/mu)?.[1];
|
|
20215
20219
|
if (!expected) return false;
|
|
20216
|
-
const
|
|
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.
|
|
20221
|
-
const
|
|
20222
|
-
|
|
20223
|
-
|
|
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
|
|
20227
|
-
return
|
|
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
|
|
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
|
-
|
|
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 =
|
|
20255
|
-
return distance === "" || distance !== ".." && !distance.startsWith(`..${
|
|
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
|
|
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,
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
20528
|
-
return relativePath !== "" && !
|
|
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
|
|
20758
|
+
import { basename as basename9 } from "node:path";
|
|
20536
20759
|
|
|
20537
20760
|
// src/file-sync.ts
|
|
20538
|
-
import { constants as
|
|
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
|
|
20764
|
+
basename as basename8,
|
|
20542
20765
|
dirname as dirname10,
|
|
20543
|
-
isAbsolute as
|
|
20544
|
-
join as
|
|
20766
|
+
isAbsolute as isAbsolute6,
|
|
20767
|
+
join as join14,
|
|
20545
20768
|
normalize as normalize2,
|
|
20546
|
-
relative as
|
|
20769
|
+
relative as relative5,
|
|
20547
20770
|
resolve as resolve11,
|
|
20548
|
-
sep as
|
|
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 =
|
|
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 =
|
|
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,
|
|
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 (
|
|
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(
|
|
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: ${
|
|
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 =
|
|
20641
|
-
return distance === "" || !
|
|
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
|
|
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(
|
|
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 =
|
|
20892
|
-
const perRepo =
|
|
20893
|
-
return
|
|
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
|
|
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
|
|
21239
|
+
function recordSkipped(outcomes, reporter, dir, reason) {
|
|
21058
21240
|
outcomes.push({ kind: "skipped", dir, reason });
|
|
21059
|
-
if (
|
|
21060
|
-
|
|
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:
|
|
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
|
|
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,
|
|
21511
|
-
await writeShellOutput(outputEnv ?? PR_OUTPUT_FILE_ENV, worktreePath,
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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 =
|
|
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:
|
|
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,
|
|
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,
|
|
22641
|
+
async function writeOutput2(worktreePath, stdout3, outputEnv) {
|
|
22464
22642
|
await writeShellOutput(
|
|
22465
22643
|
outputEnv ?? NEW_OUTPUT_FILE_ENV,
|
|
22466
22644
|
worktreePath,
|
|
22467
|
-
|
|
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:
|
|
22681
|
+
const { stdout: stdout3 } = await execFileAsync8(
|
|
22504
22682
|
"git",
|
|
22505
22683
|
["status", "--porcelain=v1"],
|
|
22506
22684
|
{ cwd }
|
|
22507
22685
|
);
|
|
22508
|
-
return
|
|
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:
|
|
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
|
|
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:
|
|
22706
|
+
const { stdout: stdout3 } = await execFileAsync8("git", ["ls-files", "--stage"], {
|
|
22529
22707
|
cwd
|
|
22530
22708
|
});
|
|
22531
22709
|
const submodules = new Set(
|
|
22532
|
-
|
|
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:
|
|
22719
|
+
const { stdout: stdout3 } = await execFileAsync8(
|
|
22542
22720
|
"git",
|
|
22543
22721
|
["status", "--porcelain=v1", "--untracked-files=all"],
|
|
22544
22722
|
{ cwd }
|
|
22545
22723
|
);
|
|
22546
|
-
return
|
|
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:
|
|
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 =
|
|
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:
|
|
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
|
|
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 ||
|
|
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
|
|
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
|
|
23286
|
-
import { access as access10, mkdir as
|
|
23287
|
-
import { homedir as
|
|
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 ??
|
|
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
|
|
23413
|
-
await
|
|
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
|
|
23506
|
-
await
|
|
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
|
|
23707
|
+
await mkdir10(dirname13(rcPath), { recursive: true });
|
|
23522
23708
|
const current = await readExistingConfig(rcPath);
|
|
23523
23709
|
if (shell === "fish") {
|
|
23524
|
-
await
|
|
23710
|
+
await writeFile9(
|
|
23525
23711
|
rcPath,
|
|
23526
23712
|
upsertShellIntegration(current, renderShellIntegration(shell)),
|
|
23527
23713
|
"utf8"
|
|
23528
23714
|
);
|
|
23529
23715
|
return;
|
|
23530
23716
|
}
|
|
23531
|
-
await
|
|
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
|
|
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,
|
|
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 ??
|
|
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
|
|
23795
|
+
await mkdir10(dirname13(rcPath), { recursive: true });
|
|
23610
23796
|
const current = await readExistingConfig(rcPath);
|
|
23611
23797
|
const next = upsertShellIntegration(current, script);
|
|
23612
|
-
await
|
|
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
|
|
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
|
|
23954
|
-
import { join as
|
|
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 =
|
|
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
|
|
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
|
|
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:
|
|
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,
|
|
24721
|
-
await writeShellOutput(REMOVE_OUTPUT_FILE_ENV, repoRoot,
|
|
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
|
|
25041
|
-
import { join as
|
|
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 ??
|
|
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 (!
|
|
25274
|
+
if (!isPlainObject3(repos)) return null;
|
|
25089
25275
|
for (const [key, value] of Object.entries(repos)) {
|
|
25090
|
-
if (expandTilde3(key, home) === repoRoot &&
|
|
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(
|
|
25287
|
+
function writeSyncFiles(stdout3, files, json) {
|
|
25102
25288
|
if (json) {
|
|
25103
|
-
|
|
25289
|
+
stdout3(`${JSON.stringify(files, null, 2)}
|
|
25104
25290
|
`);
|
|
25105
25291
|
return;
|
|
25106
25292
|
}
|
|
25107
25293
|
if (files.length === 0) {
|
|
25108
|
-
|
|
25294
|
+
stdout3("No sync files configured for this repo.\n");
|
|
25109
25295
|
return;
|
|
25110
25296
|
}
|
|
25111
|
-
|
|
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 =
|
|
25148
|
-
const repoConfig =
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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(
|
|
26181
|
+
const { config } = await loadGlobalConfig(homedir10());
|
|
25996
26182
|
if (!config.shellIntegration) {
|
|
25997
26183
|
const setupCommand = isHeadless() ? legacyShellSetupCommand() : "gji init";
|
|
25998
26184
|
process.stderr.write(
|