@great-arrow/cli 0.7.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/index.js +1584 -262
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -44,7 +44,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
44
44
|
// node_modules/.pnpm/graceful-fs@4.2.11/node_modules/graceful-fs/polyfills.js
|
|
45
45
|
var require_polyfills = __commonJS({
|
|
46
46
|
"node_modules/.pnpm/graceful-fs@4.2.11/node_modules/graceful-fs/polyfills.js"(exports, module) {
|
|
47
|
-
var
|
|
47
|
+
var constants3 = __require("constants");
|
|
48
48
|
var origCwd = process.cwd;
|
|
49
49
|
var cwd = null;
|
|
50
50
|
var platform2 = process.env.GRACEFUL_FS_PLATFORM || process.platform;
|
|
@@ -68,7 +68,7 @@ var require_polyfills = __commonJS({
|
|
|
68
68
|
var chdir;
|
|
69
69
|
module.exports = patch;
|
|
70
70
|
function patch(fs6) {
|
|
71
|
-
if (
|
|
71
|
+
if (constants3.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
|
72
72
|
patchLchmod(fs6);
|
|
73
73
|
}
|
|
74
74
|
if (!fs6.lutimes) {
|
|
@@ -108,7 +108,7 @@ var require_polyfills = __commonJS({
|
|
|
108
108
|
}
|
|
109
109
|
if (platform2 === "win32") {
|
|
110
110
|
fs6.rename = typeof fs6.rename !== "function" ? fs6.rename : (function(fs$rename) {
|
|
111
|
-
function
|
|
111
|
+
function rename5(from, to, cb) {
|
|
112
112
|
var start = Date.now();
|
|
113
113
|
var backoff = 0;
|
|
114
114
|
fs$rename(from, to, function CB(er) {
|
|
@@ -128,8 +128,8 @@ var require_polyfills = __commonJS({
|
|
|
128
128
|
if (cb) cb(er);
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
|
-
if (Object.setPrototypeOf) Object.setPrototypeOf(
|
|
132
|
-
return
|
|
131
|
+
if (Object.setPrototypeOf) Object.setPrototypeOf(rename5, fs$rename);
|
|
132
|
+
return rename5;
|
|
133
133
|
})(fs6.rename);
|
|
134
134
|
}
|
|
135
135
|
fs6.read = typeof fs6.read !== "function" ? fs6.read : (function(fs$read) {
|
|
@@ -170,7 +170,7 @@ var require_polyfills = __commonJS({
|
|
|
170
170
|
fs7.lchmod = function(path10, mode, callback) {
|
|
171
171
|
fs7.open(
|
|
172
172
|
path10,
|
|
173
|
-
|
|
173
|
+
constants3.O_WRONLY | constants3.O_SYMLINK,
|
|
174
174
|
mode,
|
|
175
175
|
function(err2, fd) {
|
|
176
176
|
if (err2) {
|
|
@@ -186,7 +186,7 @@ var require_polyfills = __commonJS({
|
|
|
186
186
|
);
|
|
187
187
|
};
|
|
188
188
|
fs7.lchmodSync = function(path10, mode) {
|
|
189
|
-
var fd = fs7.openSync(path10,
|
|
189
|
+
var fd = fs7.openSync(path10, constants3.O_WRONLY | constants3.O_SYMLINK, mode);
|
|
190
190
|
var threw = true;
|
|
191
191
|
var ret;
|
|
192
192
|
try {
|
|
@@ -206,9 +206,9 @@ var require_polyfills = __commonJS({
|
|
|
206
206
|
};
|
|
207
207
|
}
|
|
208
208
|
function patchLutimes(fs7) {
|
|
209
|
-
if (
|
|
209
|
+
if (constants3.hasOwnProperty("O_SYMLINK") && fs7.futimes) {
|
|
210
210
|
fs7.lutimes = function(path10, at, mt, cb) {
|
|
211
|
-
fs7.open(path10,
|
|
211
|
+
fs7.open(path10, constants3.O_SYMLINK, function(er, fd) {
|
|
212
212
|
if (er) {
|
|
213
213
|
if (cb) cb(er);
|
|
214
214
|
return;
|
|
@@ -221,7 +221,7 @@ var require_polyfills = __commonJS({
|
|
|
221
221
|
});
|
|
222
222
|
};
|
|
223
223
|
fs7.lutimesSync = function(path10, at, mt) {
|
|
224
|
-
var fd = fs7.openSync(path10,
|
|
224
|
+
var fd = fs7.openSync(path10, constants3.O_SYMLINK);
|
|
225
225
|
var ret;
|
|
226
226
|
var threw = true;
|
|
227
227
|
try {
|
|
@@ -502,14 +502,14 @@ var require_graceful_fs = __commonJS({
|
|
|
502
502
|
return close;
|
|
503
503
|
})(fs6.close);
|
|
504
504
|
fs6.closeSync = (function(fs$closeSync) {
|
|
505
|
-
function
|
|
505
|
+
function closeSync2(fd) {
|
|
506
506
|
fs$closeSync.apply(fs6, arguments);
|
|
507
507
|
resetQueue();
|
|
508
508
|
}
|
|
509
|
-
Object.defineProperty(
|
|
509
|
+
Object.defineProperty(closeSync2, previousSymbol, {
|
|
510
510
|
value: fs$closeSync
|
|
511
511
|
});
|
|
512
|
-
return
|
|
512
|
+
return closeSync2;
|
|
513
513
|
})(fs6.closeSync);
|
|
514
514
|
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
|
|
515
515
|
process.on("exit", function() {
|
|
@@ -533,8 +533,8 @@ var require_graceful_fs = __commonJS({
|
|
|
533
533
|
fs7.createReadStream = createReadStream;
|
|
534
534
|
fs7.createWriteStream = createWriteStream;
|
|
535
535
|
var fs$readFile = fs7.readFile;
|
|
536
|
-
fs7.readFile =
|
|
537
|
-
function
|
|
536
|
+
fs7.readFile = readFile11;
|
|
537
|
+
function readFile11(path10, options, cb) {
|
|
538
538
|
if (typeof options === "function")
|
|
539
539
|
cb = options, options = null;
|
|
540
540
|
return go$readFile(path10, options, cb);
|
|
@@ -550,8 +550,8 @@ var require_graceful_fs = __commonJS({
|
|
|
550
550
|
}
|
|
551
551
|
}
|
|
552
552
|
var fs$writeFile = fs7.writeFile;
|
|
553
|
-
fs7.writeFile =
|
|
554
|
-
function
|
|
553
|
+
fs7.writeFile = writeFile10;
|
|
554
|
+
function writeFile10(path10, data, options, cb) {
|
|
555
555
|
if (typeof options === "function")
|
|
556
556
|
cb = options, options = null;
|
|
557
557
|
return go$writeFile(path10, data, options, cb);
|
|
@@ -1155,8 +1155,8 @@ var require_semver = __commonJS({
|
|
|
1155
1155
|
}
|
|
1156
1156
|
// preminor will bump the version up to the next minor release, and immediately
|
|
1157
1157
|
// down to pre-release. premajor and prepatch work the same way.
|
|
1158
|
-
inc(
|
|
1159
|
-
if (
|
|
1158
|
+
inc(release2, identifier, identifierBase) {
|
|
1159
|
+
if (release2.startsWith("pre")) {
|
|
1160
1160
|
if (!identifier && identifierBase === false) {
|
|
1161
1161
|
throw new Error("invalid increment argument: identifier is empty");
|
|
1162
1162
|
}
|
|
@@ -1167,7 +1167,7 @@ var require_semver = __commonJS({
|
|
|
1167
1167
|
}
|
|
1168
1168
|
}
|
|
1169
1169
|
}
|
|
1170
|
-
switch (
|
|
1170
|
+
switch (release2) {
|
|
1171
1171
|
case "premajor":
|
|
1172
1172
|
this.prerelease.length = 0;
|
|
1173
1173
|
this.patch = 0;
|
|
@@ -1258,7 +1258,7 @@ var require_semver = __commonJS({
|
|
|
1258
1258
|
break;
|
|
1259
1259
|
}
|
|
1260
1260
|
default:
|
|
1261
|
-
throw new Error(`invalid increment argument: ${
|
|
1261
|
+
throw new Error(`invalid increment argument: ${release2}`);
|
|
1262
1262
|
}
|
|
1263
1263
|
this.raw = this.format();
|
|
1264
1264
|
if (this.build.length) {
|
|
@@ -1968,7 +1968,7 @@ var require_minimist = __commonJS({
|
|
|
1968
1968
|
var require_rc = __commonJS({
|
|
1969
1969
|
"node_modules/.pnpm/rc@1.2.8/node_modules/rc/index.js"(exports, module) {
|
|
1970
1970
|
var cc = require_utils();
|
|
1971
|
-
var
|
|
1971
|
+
var join18 = __require("path").join;
|
|
1972
1972
|
var deepExtend = require_deep_extend();
|
|
1973
1973
|
var etc = "/etc";
|
|
1974
1974
|
var win = process.platform === "win32";
|
|
@@ -1993,15 +1993,15 @@ var require_rc = __commonJS({
|
|
|
1993
1993
|
}
|
|
1994
1994
|
if (!win)
|
|
1995
1995
|
[
|
|
1996
|
-
|
|
1997
|
-
|
|
1996
|
+
join18(etc, name23, "config"),
|
|
1997
|
+
join18(etc, name23 + "rc")
|
|
1998
1998
|
].forEach(addConfigFile);
|
|
1999
1999
|
if (home)
|
|
2000
2000
|
[
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2001
|
+
join18(home, ".config", name23, "config"),
|
|
2002
|
+
join18(home, ".config", name23),
|
|
2003
|
+
join18(home, "." + name23, "config"),
|
|
2004
|
+
join18(home, "." + name23 + "rc")
|
|
2005
2005
|
].forEach(addConfigFile);
|
|
2006
2006
|
addConfigFile(cc.find("." + name23 + "rc"));
|
|
2007
2007
|
if (env4.config) addConfigFile(env4.config);
|
|
@@ -2018,7 +2018,7 @@ var require_rc = __commonJS({
|
|
|
2018
2018
|
// node_modules/.pnpm/graceful-fs@4.2.10/node_modules/graceful-fs/polyfills.js
|
|
2019
2019
|
var require_polyfills2 = __commonJS({
|
|
2020
2020
|
"node_modules/.pnpm/graceful-fs@4.2.10/node_modules/graceful-fs/polyfills.js"(exports, module) {
|
|
2021
|
-
var
|
|
2021
|
+
var constants3 = __require("constants");
|
|
2022
2022
|
var origCwd = process.cwd;
|
|
2023
2023
|
var cwd = null;
|
|
2024
2024
|
var platform2 = process.env.GRACEFUL_FS_PLATFORM || process.platform;
|
|
@@ -2042,7 +2042,7 @@ var require_polyfills2 = __commonJS({
|
|
|
2042
2042
|
var chdir;
|
|
2043
2043
|
module.exports = patch;
|
|
2044
2044
|
function patch(fs6) {
|
|
2045
|
-
if (
|
|
2045
|
+
if (constants3.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
|
2046
2046
|
patchLchmod(fs6);
|
|
2047
2047
|
}
|
|
2048
2048
|
if (!fs6.lutimes) {
|
|
@@ -2082,7 +2082,7 @@ var require_polyfills2 = __commonJS({
|
|
|
2082
2082
|
}
|
|
2083
2083
|
if (platform2 === "win32") {
|
|
2084
2084
|
fs6.rename = typeof fs6.rename !== "function" ? fs6.rename : (function(fs$rename) {
|
|
2085
|
-
function
|
|
2085
|
+
function rename5(from, to, cb) {
|
|
2086
2086
|
var start = Date.now();
|
|
2087
2087
|
var backoff = 0;
|
|
2088
2088
|
fs$rename(from, to, function CB(er) {
|
|
@@ -2102,8 +2102,8 @@ var require_polyfills2 = __commonJS({
|
|
|
2102
2102
|
if (cb) cb(er);
|
|
2103
2103
|
});
|
|
2104
2104
|
}
|
|
2105
|
-
if (Object.setPrototypeOf) Object.setPrototypeOf(
|
|
2106
|
-
return
|
|
2105
|
+
if (Object.setPrototypeOf) Object.setPrototypeOf(rename5, fs$rename);
|
|
2106
|
+
return rename5;
|
|
2107
2107
|
})(fs6.rename);
|
|
2108
2108
|
}
|
|
2109
2109
|
fs6.read = typeof fs6.read !== "function" ? fs6.read : (function(fs$read) {
|
|
@@ -2144,7 +2144,7 @@ var require_polyfills2 = __commonJS({
|
|
|
2144
2144
|
fs7.lchmod = function(path10, mode, callback) {
|
|
2145
2145
|
fs7.open(
|
|
2146
2146
|
path10,
|
|
2147
|
-
|
|
2147
|
+
constants3.O_WRONLY | constants3.O_SYMLINK,
|
|
2148
2148
|
mode,
|
|
2149
2149
|
function(err2, fd) {
|
|
2150
2150
|
if (err2) {
|
|
@@ -2160,7 +2160,7 @@ var require_polyfills2 = __commonJS({
|
|
|
2160
2160
|
);
|
|
2161
2161
|
};
|
|
2162
2162
|
fs7.lchmodSync = function(path10, mode) {
|
|
2163
|
-
var fd = fs7.openSync(path10,
|
|
2163
|
+
var fd = fs7.openSync(path10, constants3.O_WRONLY | constants3.O_SYMLINK, mode);
|
|
2164
2164
|
var threw = true;
|
|
2165
2165
|
var ret;
|
|
2166
2166
|
try {
|
|
@@ -2180,9 +2180,9 @@ var require_polyfills2 = __commonJS({
|
|
|
2180
2180
|
};
|
|
2181
2181
|
}
|
|
2182
2182
|
function patchLutimes(fs7) {
|
|
2183
|
-
if (
|
|
2183
|
+
if (constants3.hasOwnProperty("O_SYMLINK") && fs7.futimes) {
|
|
2184
2184
|
fs7.lutimes = function(path10, at, mt, cb) {
|
|
2185
|
-
fs7.open(path10,
|
|
2185
|
+
fs7.open(path10, constants3.O_SYMLINK, function(er, fd) {
|
|
2186
2186
|
if (er) {
|
|
2187
2187
|
if (cb) cb(er);
|
|
2188
2188
|
return;
|
|
@@ -2195,7 +2195,7 @@ var require_polyfills2 = __commonJS({
|
|
|
2195
2195
|
});
|
|
2196
2196
|
};
|
|
2197
2197
|
fs7.lutimesSync = function(path10, at, mt) {
|
|
2198
|
-
var fd = fs7.openSync(path10,
|
|
2198
|
+
var fd = fs7.openSync(path10, constants3.O_SYMLINK);
|
|
2199
2199
|
var ret;
|
|
2200
2200
|
var threw = true;
|
|
2201
2201
|
try {
|
|
@@ -2476,14 +2476,14 @@ var require_graceful_fs2 = __commonJS({
|
|
|
2476
2476
|
return close;
|
|
2477
2477
|
})(fs6.close);
|
|
2478
2478
|
fs6.closeSync = (function(fs$closeSync) {
|
|
2479
|
-
function
|
|
2479
|
+
function closeSync2(fd) {
|
|
2480
2480
|
fs$closeSync.apply(fs6, arguments);
|
|
2481
2481
|
resetQueue();
|
|
2482
2482
|
}
|
|
2483
|
-
Object.defineProperty(
|
|
2483
|
+
Object.defineProperty(closeSync2, previousSymbol, {
|
|
2484
2484
|
value: fs$closeSync
|
|
2485
2485
|
});
|
|
2486
|
-
return
|
|
2486
|
+
return closeSync2;
|
|
2487
2487
|
})(fs6.closeSync);
|
|
2488
2488
|
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
|
|
2489
2489
|
process.on("exit", function() {
|
|
@@ -2507,8 +2507,8 @@ var require_graceful_fs2 = __commonJS({
|
|
|
2507
2507
|
fs7.createReadStream = createReadStream;
|
|
2508
2508
|
fs7.createWriteStream = createWriteStream;
|
|
2509
2509
|
var fs$readFile = fs7.readFile;
|
|
2510
|
-
fs7.readFile =
|
|
2511
|
-
function
|
|
2510
|
+
fs7.readFile = readFile11;
|
|
2511
|
+
function readFile11(path10, options, cb) {
|
|
2512
2512
|
if (typeof options === "function")
|
|
2513
2513
|
cb = options, options = null;
|
|
2514
2514
|
return go$readFile(path10, options, cb);
|
|
@@ -2524,8 +2524,8 @@ var require_graceful_fs2 = __commonJS({
|
|
|
2524
2524
|
}
|
|
2525
2525
|
}
|
|
2526
2526
|
var fs$writeFile = fs7.writeFile;
|
|
2527
|
-
fs7.writeFile =
|
|
2528
|
-
function
|
|
2527
|
+
fs7.writeFile = writeFile10;
|
|
2528
|
+
function writeFile10(path10, data, options, cb) {
|
|
2529
2529
|
if (typeof options === "function")
|
|
2530
2530
|
cb = options, options = null;
|
|
2531
2531
|
return go$writeFile(path10, data, options, cb);
|
|
@@ -3339,11 +3339,11 @@ var require_util = __commonJS({
|
|
|
3339
3339
|
if (files.includes("node_modules") || files.includes("package.json") || files.includes("package.json5") || files.includes("package.yaml") || files.includes("pnpm-workspace.yaml")) {
|
|
3340
3340
|
return name24;
|
|
3341
3341
|
}
|
|
3342
|
-
const
|
|
3343
|
-
if (
|
|
3342
|
+
const dirname10 = path10.dirname(name24);
|
|
3343
|
+
if (dirname10 === name24) {
|
|
3344
3344
|
return original;
|
|
3345
3345
|
}
|
|
3346
|
-
return find(
|
|
3346
|
+
return find(dirname10, original);
|
|
3347
3347
|
} catch (error62) {
|
|
3348
3348
|
if (name24 === original) {
|
|
3349
3349
|
if (error62.code === "ENOENT") {
|
|
@@ -4044,7 +4044,7 @@ var require_inc = __commonJS({
|
|
|
4044
4044
|
"node_modules/.pnpm/semver@7.8.1/node_modules/semver/functions/inc.js"(exports, module) {
|
|
4045
4045
|
"use strict";
|
|
4046
4046
|
var SemVer = require_semver();
|
|
4047
|
-
var inc = (version2,
|
|
4047
|
+
var inc = (version2, release2, options, identifier, identifierBase) => {
|
|
4048
4048
|
if (typeof options === "string") {
|
|
4049
4049
|
identifierBase = identifier;
|
|
4050
4050
|
identifier = options;
|
|
@@ -4054,7 +4054,7 @@ var require_inc = __commonJS({
|
|
|
4054
4054
|
return new SemVer(
|
|
4055
4055
|
version2 instanceof SemVer ? version2.version : version2,
|
|
4056
4056
|
options
|
|
4057
|
-
).inc(
|
|
4057
|
+
).inc(release2, identifier, identifierBase).version;
|
|
4058
4058
|
} catch (er) {
|
|
4059
4059
|
return null;
|
|
4060
4060
|
}
|
|
@@ -4311,10 +4311,10 @@ var require_truncate = __commonJS({
|
|
|
4311
4311
|
"node_modules/.pnpm/semver@7.8.1/node_modules/semver/functions/truncate.js"(exports, module) {
|
|
4312
4312
|
"use strict";
|
|
4313
4313
|
var parse3 = require_parse();
|
|
4314
|
-
var
|
|
4314
|
+
var constants3 = require_constants();
|
|
4315
4315
|
var SemVer = require_semver();
|
|
4316
4316
|
var truncate = (version2, truncation, options) => {
|
|
4317
|
-
if (!
|
|
4317
|
+
if (!constants3.RELEASE_TYPES.includes(truncation)) {
|
|
4318
4318
|
return null;
|
|
4319
4319
|
}
|
|
4320
4320
|
const clonedVersion = cloneInputVersion(version2, options);
|
|
@@ -5358,7 +5358,7 @@ var require_semver2 = __commonJS({
|
|
|
5358
5358
|
"node_modules/.pnpm/semver@7.8.1/node_modules/semver/index.js"(exports, module) {
|
|
5359
5359
|
"use strict";
|
|
5360
5360
|
var internalRe = require_re();
|
|
5361
|
-
var
|
|
5361
|
+
var constants3 = require_constants();
|
|
5362
5362
|
var SemVer = require_semver();
|
|
5363
5363
|
var identifiers = require_identifiers();
|
|
5364
5364
|
var parse3 = require_parse();
|
|
@@ -5442,8 +5442,8 @@ var require_semver2 = __commonJS({
|
|
|
5442
5442
|
re: internalRe.re,
|
|
5443
5443
|
src: internalRe.src,
|
|
5444
5444
|
tokens: internalRe.t,
|
|
5445
|
-
SEMVER_SPEC_VERSION:
|
|
5446
|
-
RELEASE_TYPES:
|
|
5445
|
+
SEMVER_SPEC_VERSION: constants3.SEMVER_SPEC_VERSION,
|
|
5446
|
+
RELEASE_TYPES: constants3.RELEASE_TYPES,
|
|
5447
5447
|
compareIdentifiers: identifiers.compareIdentifiers,
|
|
5448
5448
|
rcompareIdentifiers: identifiers.rcompareIdentifiers
|
|
5449
5449
|
};
|
|
@@ -8515,7 +8515,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
8515
8515
|
const negativeNumberArg = (arg) => {
|
|
8516
8516
|
if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg)) return false;
|
|
8517
8517
|
return !this._getCommandAndAncestors().some(
|
|
8518
|
-
(cmd) => cmd.options.map((opt) => opt.short).some((
|
|
8518
|
+
(cmd) => cmd.options.map((opt) => opt.short).some((short2) => /^-\d$/.test(short2))
|
|
8519
8519
|
);
|
|
8520
8520
|
};
|
|
8521
8521
|
let activeVariadicOption = null;
|
|
@@ -9483,7 +9483,7 @@ function isNodeError(value) {
|
|
|
9483
9483
|
|
|
9484
9484
|
// src/lib/version.ts
|
|
9485
9485
|
var CLI_PACKAGE_NAME = "@great-arrow/cli";
|
|
9486
|
-
var CLI_VERSION = "0.
|
|
9486
|
+
var CLI_VERSION = "0.8.0";
|
|
9487
9487
|
var GAD_INSTALL_VERSION = "2026.08.08";
|
|
9488
9488
|
var GAD_INSTALL_MIN_VERSION = "2026.06.22";
|
|
9489
9489
|
var GAD_INSTALL_HEADER = "X-GAD-Install-Version";
|
|
@@ -10056,12 +10056,12 @@ h1{font-size:1.25rem;margin:0 0 .5rem}p{color:#9a9aa3;margin:0}</style></head>
|
|
|
10056
10056
|
<body><div class="card"><h1>${ok ? "\u2713 Signed in to Great Arrow" : "\u2717 Sign-in failed"}</h1>
|
|
10057
10057
|
<p>${escapeHtml(detail)}</p></div></body></html>`;
|
|
10058
10058
|
function listen(port) {
|
|
10059
|
-
return new Promise((
|
|
10059
|
+
return new Promise((resolve7, reject) => {
|
|
10060
10060
|
const server = createServer();
|
|
10061
10061
|
server.on("error", reject);
|
|
10062
10062
|
server.listen(port, LOOPBACK_HOST, () => {
|
|
10063
10063
|
const addr = server.address();
|
|
10064
|
-
|
|
10064
|
+
resolve7({ server, port: addr.port });
|
|
10065
10065
|
});
|
|
10066
10066
|
});
|
|
10067
10067
|
}
|
|
@@ -10086,7 +10086,7 @@ async function startLoopbackServer(opts) {
|
|
|
10086
10086
|
port,
|
|
10087
10087
|
close: () => server.close(),
|
|
10088
10088
|
waitForCallback({ timeoutMs = DEFAULT_TIMEOUT_MS } = {}) {
|
|
10089
|
-
return new Promise((
|
|
10089
|
+
return new Promise((resolve7, reject) => {
|
|
10090
10090
|
const timer = setTimeout(() => {
|
|
10091
10091
|
server.close();
|
|
10092
10092
|
reject(new Error("Timed out waiting for the browser callback."));
|
|
@@ -10126,7 +10126,7 @@ async function startLoopbackServer(opts) {
|
|
|
10126
10126
|
"You can close this tab and return to your terminal."
|
|
10127
10127
|
)
|
|
10128
10128
|
);
|
|
10129
|
-
settle2(() =>
|
|
10129
|
+
settle2(() => resolve7({ code, state }));
|
|
10130
10130
|
});
|
|
10131
10131
|
});
|
|
10132
10132
|
}
|
|
@@ -10411,11 +10411,11 @@ async function confirm(message) {
|
|
|
10411
10411
|
input: process.stdin,
|
|
10412
10412
|
output: process.stdout
|
|
10413
10413
|
});
|
|
10414
|
-
return new Promise((
|
|
10414
|
+
return new Promise((resolve7) => {
|
|
10415
10415
|
rl.question(`${message} [y/N] `, (answer) => {
|
|
10416
10416
|
rl.close();
|
|
10417
10417
|
const normalized = answer.trim().toLowerCase();
|
|
10418
|
-
|
|
10418
|
+
resolve7(normalized === "y" || normalized === "yes");
|
|
10419
10419
|
});
|
|
10420
10420
|
});
|
|
10421
10421
|
}
|
|
@@ -10590,8 +10590,8 @@ function createFormatter(options) {
|
|
|
10590
10590
|
var DEFAULT_API_URL = "https://www.greatarrow.ai";
|
|
10591
10591
|
function isLegacyApiUrl(value) {
|
|
10592
10592
|
try {
|
|
10593
|
-
const
|
|
10594
|
-
return
|
|
10593
|
+
const hostname7 = new URL(value).hostname.toLowerCase();
|
|
10594
|
+
return hostname7 === "www.greatarrowdigital.com" || hostname7 === "greatarrowdigital.com";
|
|
10595
10595
|
} catch {
|
|
10596
10596
|
return false;
|
|
10597
10597
|
}
|
|
@@ -10611,10 +10611,10 @@ function maskToken(token) {
|
|
|
10611
10611
|
}
|
|
10612
10612
|
function openBrowser(url2) {
|
|
10613
10613
|
if (!/^https?:\/\//i.test(url2)) return Promise.resolve(false);
|
|
10614
|
-
return new Promise((
|
|
10614
|
+
return new Promise((resolve7) => {
|
|
10615
10615
|
const platform2 = process.platform;
|
|
10616
10616
|
const [cmd, args] = platform2 === "darwin" ? ["open", [url2]] : platform2 === "win32" ? ["cmd", ["/c", "start", "", url2]] : ["xdg-open", [url2]];
|
|
10617
|
-
execFile(cmd, args, (error62) =>
|
|
10617
|
+
execFile(cmd, args, (error62) => resolve7(!error62));
|
|
10618
10618
|
});
|
|
10619
10619
|
}
|
|
10620
10620
|
var loginCommand = new Command("login").description("Authenticate the CLI with your Great Arrow Digital account").option(
|
|
@@ -11364,7 +11364,7 @@ function getCommandWorkspaceTarget(options = {}) {
|
|
|
11364
11364
|
|
|
11365
11365
|
// ../local-runtime/src/abortable.ts
|
|
11366
11366
|
function abortable(run4, signal) {
|
|
11367
|
-
return new Promise((
|
|
11367
|
+
return new Promise((resolve7, reject) => {
|
|
11368
11368
|
const abort = () => {
|
|
11369
11369
|
signal.removeEventListener("abort", abort);
|
|
11370
11370
|
reject(signal.reason ?? new Error("Local operation stopped"));
|
|
@@ -11374,7 +11374,7 @@ function abortable(run4, signal) {
|
|
|
11374
11374
|
Promise.resolve().then(() => {
|
|
11375
11375
|
signal.throwIfAborted();
|
|
11376
11376
|
return run4();
|
|
11377
|
-
}).then(
|
|
11377
|
+
}).then(resolve7, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
11378
11378
|
});
|
|
11379
11379
|
}
|
|
11380
11380
|
async function withLocalDeadline(deadlineMs, run4, parentSignal) {
|
|
@@ -11634,7 +11634,7 @@ function describeError(error62) {
|
|
|
11634
11634
|
return String(error62);
|
|
11635
11635
|
}
|
|
11636
11636
|
function sleep(ms) {
|
|
11637
|
-
return new Promise((
|
|
11637
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
11638
11638
|
}
|
|
11639
11639
|
var GadClient = class {
|
|
11640
11640
|
token;
|
|
@@ -11759,11 +11759,11 @@ var GadClient = class {
|
|
|
11759
11759
|
const status = response.status;
|
|
11760
11760
|
const body = await response.text().catch(() => "");
|
|
11761
11761
|
if (status === 403) {
|
|
11762
|
-
const
|
|
11763
|
-
if (
|
|
11762
|
+
const refusal3 = policyRefusal(body, this.apiUrl);
|
|
11763
|
+
if (refusal3) {
|
|
11764
11764
|
throw withServerCode(
|
|
11765
|
-
new CliError(
|
|
11766
|
-
JSON.stringify({ error:
|
|
11765
|
+
new CliError(refusal3.message, 1 /* AUTH_ERROR */, refusal3.hint),
|
|
11766
|
+
JSON.stringify({ error: refusal3.code })
|
|
11767
11767
|
);
|
|
11768
11768
|
}
|
|
11769
11769
|
throw withServerCode(
|
|
@@ -11858,9 +11858,9 @@ var GadClient = class {
|
|
|
11858
11858
|
message: data.error.message
|
|
11859
11859
|
}
|
|
11860
11860
|
});
|
|
11861
|
-
const
|
|
11862
|
-
if (
|
|
11863
|
-
throw new CliError(
|
|
11861
|
+
const refusal3 = policyRefusal(data, this.apiUrl);
|
|
11862
|
+
if (refusal3) {
|
|
11863
|
+
throw new CliError(refusal3.message, 1 /* AUTH_ERROR */, refusal3.hint);
|
|
11864
11864
|
}
|
|
11865
11865
|
const code = data.error.code === -32001 ? 1 /* AUTH_ERROR */ : 2 /* NETWORK_ERROR */;
|
|
11866
11866
|
throw new CliError(
|
|
@@ -11967,13 +11967,13 @@ var GadClient = class {
|
|
|
11967
11967
|
if (this.getToken) {
|
|
11968
11968
|
const getToken2 = this.getToken;
|
|
11969
11969
|
headers.Authorization = `Bearer ${await new Promise(
|
|
11970
|
-
(
|
|
11970
|
+
(resolve7, reject) => {
|
|
11971
11971
|
signal.addEventListener(
|
|
11972
11972
|
"abort",
|
|
11973
11973
|
() => reject(networkError("Session renewal timed out.")),
|
|
11974
11974
|
{ once: true }
|
|
11975
11975
|
);
|
|
11976
|
-
getToken2().then(
|
|
11976
|
+
getToken2().then(resolve7, reject);
|
|
11977
11977
|
}
|
|
11978
11978
|
)}`;
|
|
11979
11979
|
}
|
|
@@ -12192,10 +12192,10 @@ ${tryThese.map((t) => ` \u2022 ${t}`).join("\n")}`
|
|
|
12192
12192
|
|
|
12193
12193
|
// src/lib/stdin.ts
|
|
12194
12194
|
function readStream(stream) {
|
|
12195
|
-
return new Promise((
|
|
12195
|
+
return new Promise((resolve7, reject) => {
|
|
12196
12196
|
const chunks = [];
|
|
12197
12197
|
stream.on("data", (chunk) => chunks.push(chunk));
|
|
12198
|
-
stream.on("end", () =>
|
|
12198
|
+
stream.on("end", () => resolve7(Buffer.concat(chunks).toString("utf8")));
|
|
12199
12199
|
stream.on("error", reject);
|
|
12200
12200
|
});
|
|
12201
12201
|
}
|
|
@@ -13130,7 +13130,7 @@ function git(args, cwd) {
|
|
|
13130
13130
|
var WORKTREE_STATUS_CONCURRENCY = 8;
|
|
13131
13131
|
var WORKTREE_STATUS_TIMEOUT_MS = 2e3;
|
|
13132
13132
|
function gitAsync(args, cwd) {
|
|
13133
|
-
return new Promise((
|
|
13133
|
+
return new Promise((resolve7) => {
|
|
13134
13134
|
execFile2(
|
|
13135
13135
|
"git",
|
|
13136
13136
|
args,
|
|
@@ -13141,7 +13141,7 @@ function gitAsync(args, cwd) {
|
|
|
13141
13141
|
timeout: WORKTREE_STATUS_TIMEOUT_MS
|
|
13142
13142
|
},
|
|
13143
13143
|
(error62, stdout, stderr) => {
|
|
13144
|
-
|
|
13144
|
+
resolve7({
|
|
13145
13145
|
status: error62 ? 1 : 0,
|
|
13146
13146
|
stdout: stdout ?? "",
|
|
13147
13147
|
stderr: stderr ?? "",
|
|
@@ -16941,8 +16941,8 @@ async function runStdioBridge(options) {
|
|
|
16941
16941
|
if (response) writeLine(response);
|
|
16942
16942
|
});
|
|
16943
16943
|
});
|
|
16944
|
-
await new Promise((
|
|
16945
|
-
rl.on("close", () =>
|
|
16944
|
+
await new Promise((resolve7) => {
|
|
16945
|
+
rl.on("close", () => resolve7());
|
|
16946
16946
|
});
|
|
16947
16947
|
}
|
|
16948
16948
|
|
|
@@ -17065,9 +17065,9 @@ var CLIENT_IDS = {
|
|
|
17065
17065
|
};
|
|
17066
17066
|
async function mcpJsonAtRiskOfCommit(dir) {
|
|
17067
17067
|
try {
|
|
17068
|
-
const { execFile:
|
|
17068
|
+
const { execFile: execFile6 } = await import("node:child_process");
|
|
17069
17069
|
const { promisify: promisify2 } = await import("node:util");
|
|
17070
|
-
const run4 = promisify2(
|
|
17070
|
+
const run4 = promisify2(execFile6);
|
|
17071
17071
|
await run4("git", ["rev-parse", "--is-inside-work-tree"], { cwd: dir });
|
|
17072
17072
|
try {
|
|
17073
17073
|
await run4("git", ["check-ignore", "-q", ".mcp.json"], { cwd: dir });
|
|
@@ -17160,33 +17160,33 @@ async function pathExists(path10) {
|
|
|
17160
17160
|
}
|
|
17161
17161
|
}
|
|
17162
17162
|
async function installCodexConfig(apiUrl, token, repoUrl) {
|
|
17163
|
-
const { homedir:
|
|
17164
|
-
const { join:
|
|
17165
|
-
const { chmod:
|
|
17166
|
-
const codexDir =
|
|
17167
|
-
const configPath =
|
|
17168
|
-
const envPath =
|
|
17163
|
+
const { homedir: homedir12 } = await import("node:os");
|
|
17164
|
+
const { join: join18 } = await import("node:path");
|
|
17165
|
+
const { chmod: chmod7, copyFile: copyFile3, mkdir: mkdir11, readFile: readFile11, writeFile: writeFile10 } = await import("node:fs/promises");
|
|
17166
|
+
const codexDir = join18(homedir12(), ".codex");
|
|
17167
|
+
const configPath = join18(codexDir, "config.toml");
|
|
17168
|
+
const envPath = join18(codexDir, ".env");
|
|
17169
17169
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
17170
|
-
await
|
|
17171
|
-
const existingConfig = await pathExists(configPath) ? await
|
|
17170
|
+
await mkdir11(codexDir, { recursive: true });
|
|
17171
|
+
const existingConfig = await pathExists(configPath) ? await readFile11(configPath, "utf8") : "";
|
|
17172
17172
|
if (existingConfig.trim()) {
|
|
17173
17173
|
await copyFile3(configPath, `${configPath}.bak.${timestamp}`);
|
|
17174
17174
|
}
|
|
17175
|
-
await
|
|
17175
|
+
await writeFile10(
|
|
17176
17176
|
configPath,
|
|
17177
17177
|
upsertCodexServerBlock(existingConfig, apiUrl, repoUrl),
|
|
17178
17178
|
"utf8"
|
|
17179
17179
|
);
|
|
17180
|
-
const existingEnv = await pathExists(envPath) ? await
|
|
17180
|
+
const existingEnv = await pathExists(envPath) ? await readFile11(envPath, "utf8") : "";
|
|
17181
17181
|
if (existingEnv.trim()) {
|
|
17182
17182
|
await copyFile3(envPath, `${envPath}.bak.${timestamp}`);
|
|
17183
17183
|
}
|
|
17184
|
-
await
|
|
17184
|
+
await writeFile10(
|
|
17185
17185
|
envPath,
|
|
17186
17186
|
upsertEnvValue(existingEnv, "GREAT_ARROW_TOKEN", token),
|
|
17187
17187
|
"utf8"
|
|
17188
17188
|
);
|
|
17189
|
-
await
|
|
17189
|
+
await chmod7(envPath, 384);
|
|
17190
17190
|
return { configPath, envPath };
|
|
17191
17191
|
}
|
|
17192
17192
|
var startCommand = new Command("start").description(
|
|
@@ -17474,15 +17474,15 @@ var installCommand = new Command("install").description("Generate MCP configurat
|
|
|
17474
17474
|
process.stdout.write(configJson2 + "\n");
|
|
17475
17475
|
return;
|
|
17476
17476
|
}
|
|
17477
|
-
const { homedir:
|
|
17478
|
-
const { join:
|
|
17479
|
-
const { mkdir:
|
|
17480
|
-
const geminiDir =
|
|
17481
|
-
const mcpPath =
|
|
17482
|
-
await
|
|
17477
|
+
const { homedir: homedir12 } = await import("node:os");
|
|
17478
|
+
const { join: join19 } = await import("node:path");
|
|
17479
|
+
const { mkdir: mkdir11, readFile: readFile11, writeFile: writeFile11 } = await import("node:fs/promises");
|
|
17480
|
+
const geminiDir = join19(homedir12(), ".gemini");
|
|
17481
|
+
const mcpPath = join19(geminiDir, "settings.json");
|
|
17482
|
+
await mkdir11(geminiDir, { recursive: true });
|
|
17483
17483
|
let existingConfig = {};
|
|
17484
17484
|
try {
|
|
17485
|
-
const content = await
|
|
17485
|
+
const content = await readFile11(mcpPath, "utf-8");
|
|
17486
17486
|
existingConfig = JSON.parse(content);
|
|
17487
17487
|
} catch {
|
|
17488
17488
|
existingConfig = {};
|
|
@@ -17494,20 +17494,20 @@ var installCommand = new Command("install").description("Generate MCP configurat
|
|
|
17494
17494
|
...config3.mcpServers
|
|
17495
17495
|
}
|
|
17496
17496
|
};
|
|
17497
|
-
await
|
|
17497
|
+
await writeFile11(
|
|
17498
17498
|
mcpPath,
|
|
17499
17499
|
JSON.stringify(existingConfig, null, 2) + "\n",
|
|
17500
17500
|
"utf-8"
|
|
17501
17501
|
);
|
|
17502
17502
|
fmt.success(`Wrote gemini MCP config to ${mcpPath}`);
|
|
17503
|
-
const agyMcpDir =
|
|
17503
|
+
const agyMcpDir = join19(
|
|
17504
17504
|
geminiDir,
|
|
17505
17505
|
"antigravity-cli",
|
|
17506
17506
|
"mcp",
|
|
17507
17507
|
MCP_SERVER_NAME
|
|
17508
17508
|
);
|
|
17509
|
-
await
|
|
17510
|
-
const instructionsPath =
|
|
17509
|
+
await mkdir11(agyMcpDir, { recursive: true });
|
|
17510
|
+
const instructionsPath = join19(agyMcpDir, "instructions.md");
|
|
17511
17511
|
const instructionsContent = `You are connected to greatarrow.ai - the user's private workspace memory + integrations brain.
|
|
17512
17512
|
|
|
17513
17513
|
CRITICAL DIRECTIVE (MANDATORY STANDARD):
|
|
@@ -17523,7 +17523,7 @@ THREE-LAYER LIVE TASK TRACKING:
|
|
|
17523
17523
|
- Maintain client-native harness plans, Great Arrow Kanban cards (\`todo_create\`, \`todo_update\`), and resume states.
|
|
17524
17524
|
|
|
17525
17525
|
Always assume full autonomy to leverage these tools to their maximum extent.`;
|
|
17526
|
-
await
|
|
17526
|
+
await writeFile11(instructionsPath, instructionsContent, "utf-8");
|
|
17527
17527
|
fmt.success(`Wrote gemini MCP instructions to ${instructionsPath}`);
|
|
17528
17528
|
return;
|
|
17529
17529
|
}
|
|
@@ -17538,10 +17538,10 @@ Always assume full autonomy to leverage these tools to their maximum extent.`;
|
|
|
17538
17538
|
process.stdout.write(configJson + "\n");
|
|
17539
17539
|
return;
|
|
17540
17540
|
}
|
|
17541
|
-
const { writeFile:
|
|
17542
|
-
const { join:
|
|
17543
|
-
const outputPath =
|
|
17544
|
-
await
|
|
17541
|
+
const { writeFile: writeFile10 } = await import("node:fs/promises");
|
|
17542
|
+
const { join: join18 } = await import("node:path");
|
|
17543
|
+
const outputPath = join18(process.cwd(), ".mcp.json");
|
|
17544
|
+
await writeFile10(outputPath, configJson + "\n", { mode: 384 });
|
|
17545
17545
|
fmt.success(`Wrote ${clientName} MCP config to .mcp.json`);
|
|
17546
17546
|
if (await mcpJsonAtRiskOfCommit(process.cwd())) {
|
|
17547
17547
|
fmt.warn(
|
|
@@ -17557,9 +17557,9 @@ var KEYCHAIN_SERVICE = "GreatArrowDigital";
|
|
|
17557
17557
|
var KEYCHAIN_ACCOUNT = "api-token";
|
|
17558
17558
|
var OAUTH_CRED_FILENAME = "oauth-credential.json";
|
|
17559
17559
|
async function readIfExists(path10) {
|
|
17560
|
-
const { readFile:
|
|
17560
|
+
const { readFile: readFile11 } = await import("node:fs/promises");
|
|
17561
17561
|
try {
|
|
17562
|
-
return await
|
|
17562
|
+
return await readFile11(path10, "utf8");
|
|
17563
17563
|
} catch {
|
|
17564
17564
|
return null;
|
|
17565
17565
|
}
|
|
@@ -17574,13 +17574,13 @@ async function readKeychainOnly() {
|
|
|
17574
17574
|
}
|
|
17575
17575
|
}
|
|
17576
17576
|
async function resolveProxyScript(override) {
|
|
17577
|
-
const { homedir:
|
|
17578
|
-
const { join:
|
|
17577
|
+
const { homedir: homedir12 } = await import("node:os");
|
|
17578
|
+
const { join: join18 } = await import("node:path");
|
|
17579
17579
|
const candidates = [
|
|
17580
17580
|
override,
|
|
17581
17581
|
process.env.GAD_PROXY_SCRIPT,
|
|
17582
|
-
|
|
17583
|
-
|
|
17582
|
+
join18(homedir12(), ".great-arrow", "mcp-server.mjs"),
|
|
17583
|
+
join18(process.cwd(), "scripts", "mcp-server.mjs")
|
|
17584
17584
|
].filter((c) => Boolean(c));
|
|
17585
17585
|
for (const candidate of candidates) {
|
|
17586
17586
|
if (await pathExists(candidate)) return candidate;
|
|
@@ -17588,9 +17588,9 @@ async function resolveProxyScript(override) {
|
|
|
17588
17588
|
return null;
|
|
17589
17589
|
}
|
|
17590
17590
|
async function runProxyDiagnostics(scriptPath) {
|
|
17591
|
-
const { execFile:
|
|
17591
|
+
const { execFile: execFile6 } = await import("node:child_process");
|
|
17592
17592
|
const { promisify: promisify2 } = await import("node:util");
|
|
17593
|
-
const run4 = promisify2(
|
|
17593
|
+
const run4 = promisify2(execFile6);
|
|
17594
17594
|
try {
|
|
17595
17595
|
const { stdout } = await run4(
|
|
17596
17596
|
process.execPath,
|
|
@@ -17604,21 +17604,21 @@ async function runProxyDiagnostics(scriptPath) {
|
|
|
17604
17604
|
}
|
|
17605
17605
|
}
|
|
17606
17606
|
async function findLegacyStores(cwd) {
|
|
17607
|
-
const { join:
|
|
17607
|
+
const { join: join18 } = await import("node:path");
|
|
17608
17608
|
const { readdir } = await import("node:fs/promises");
|
|
17609
17609
|
const dirs = /* @__PURE__ */ new Set([cwd]);
|
|
17610
17610
|
try {
|
|
17611
|
-
const worktreeRoot =
|
|
17611
|
+
const worktreeRoot = join18(cwd, ".claude", "worktrees");
|
|
17612
17612
|
for (const entry of await readdir(worktreeRoot, { withFileTypes: true })) {
|
|
17613
|
-
if (entry.isDirectory()) dirs.add(
|
|
17613
|
+
if (entry.isDirectory()) dirs.add(join18(worktreeRoot, entry.name));
|
|
17614
17614
|
}
|
|
17615
17615
|
} catch (err2) {
|
|
17616
17616
|
debugSwallow("mcp.findLegacyStores(worktrees)", err2);
|
|
17617
17617
|
}
|
|
17618
17618
|
try {
|
|
17619
|
-
const { execFile:
|
|
17619
|
+
const { execFile: execFile6 } = await import("node:child_process");
|
|
17620
17620
|
const { promisify: promisify2 } = await import("node:util");
|
|
17621
|
-
const run4 = promisify2(
|
|
17621
|
+
const run4 = promisify2(execFile6);
|
|
17622
17622
|
const { stdout } = await run4("git", ["worktree", "list", "--porcelain"], {
|
|
17623
17623
|
cwd,
|
|
17624
17624
|
timeout: 5e3
|
|
@@ -17632,18 +17632,18 @@ async function findLegacyStores(cwd) {
|
|
|
17632
17632
|
}
|
|
17633
17633
|
const stores = [];
|
|
17634
17634
|
for (const dir of dirs) {
|
|
17635
|
-
const path10 =
|
|
17635
|
+
const path10 = join18(dir, ".mcp", OAUTH_CRED_FILENAME);
|
|
17636
17636
|
const raw = await readIfExists(path10);
|
|
17637
17637
|
if (raw !== null) stores.push({ path: path10, raw });
|
|
17638
17638
|
}
|
|
17639
17639
|
return stores;
|
|
17640
17640
|
}
|
|
17641
17641
|
async function scanConnections() {
|
|
17642
|
-
const { homedir:
|
|
17643
|
-
const { join:
|
|
17644
|
-
const home =
|
|
17642
|
+
const { homedir: homedir12 } = await import("node:os");
|
|
17643
|
+
const { join: join18 } = await import("node:path");
|
|
17644
|
+
const home = homedir12();
|
|
17645
17645
|
const hookSettings = await readIfExists(
|
|
17646
|
-
|
|
17646
|
+
join18(home, ".claude", "settings.json")
|
|
17647
17647
|
);
|
|
17648
17648
|
const hooksInstalled = hookSettings ? hasGreatArrowHooks(hookSettings) : false;
|
|
17649
17649
|
const entries = [];
|
|
@@ -17676,19 +17676,19 @@ async function probeEndpoint() {
|
|
|
17676
17676
|
}
|
|
17677
17677
|
}
|
|
17678
17678
|
async function applyMigration(plan) {
|
|
17679
|
-
const { homedir:
|
|
17680
|
-
const { join:
|
|
17681
|
-
const { chmod:
|
|
17679
|
+
const { homedir: homedir12 } = await import("node:os");
|
|
17680
|
+
const { join: join18 } = await import("node:path");
|
|
17681
|
+
const { chmod: chmod7, mkdir: mkdir11, rename: rename5, unlink: unlink3, writeFile: writeFile10 } = await import("node:fs/promises");
|
|
17682
17682
|
const applied = [];
|
|
17683
|
-
const dir =
|
|
17684
|
-
await
|
|
17685
|
-
await
|
|
17683
|
+
const dir = join18(homedir12(), ".great-arrow");
|
|
17684
|
+
await mkdir11(dir, { recursive: true, mode: 448 });
|
|
17685
|
+
await chmod7(dir, 448);
|
|
17686
17686
|
const writeAtomic0600 = async (target, raw) => {
|
|
17687
17687
|
const tmp = `${target}.tmp.${process.pid}.${Date.now()}`;
|
|
17688
17688
|
try {
|
|
17689
|
-
await
|
|
17690
|
-
await
|
|
17691
|
-
await
|
|
17689
|
+
await writeFile10(tmp, raw, { mode: 384, flag: "wx" });
|
|
17690
|
+
await chmod7(tmp, 384);
|
|
17691
|
+
await rename5(tmp, target);
|
|
17692
17692
|
} catch (err2) {
|
|
17693
17693
|
try {
|
|
17694
17694
|
await unlink3(tmp);
|
|
@@ -17701,7 +17701,7 @@ async function applyMigration(plan) {
|
|
|
17701
17701
|
if (plan.seedFrom) {
|
|
17702
17702
|
const raw = await readIfExists(plan.seedFrom);
|
|
17703
17703
|
if (raw !== null) {
|
|
17704
|
-
const target =
|
|
17704
|
+
const target = join18(dir, OAUTH_CRED_FILENAME);
|
|
17705
17705
|
await writeAtomic0600(target, raw);
|
|
17706
17706
|
applied.push(`Copied ${plan.seedFrom} \u2192 ${target}`);
|
|
17707
17707
|
}
|
|
@@ -17709,9 +17709,9 @@ async function applyMigration(plan) {
|
|
|
17709
17709
|
if (plan.syncKeychainToFile) {
|
|
17710
17710
|
const raw = await readKeychainOnly();
|
|
17711
17711
|
if (raw) {
|
|
17712
|
-
const target =
|
|
17712
|
+
const target = join18(dir, "credential");
|
|
17713
17713
|
await writeAtomic0600(target, raw);
|
|
17714
|
-
await writeAtomic0600(
|
|
17714
|
+
await writeAtomic0600(join18(dir, "credential.migrated"), "1");
|
|
17715
17715
|
applied.push(`Wrote the keychain credential to ${target}`);
|
|
17716
17716
|
}
|
|
17717
17717
|
}
|
|
@@ -17734,23 +17734,23 @@ var doctorSubcommand = new Command("doctor").description(
|
|
|
17734
17734
|
noColor: false
|
|
17735
17735
|
});
|
|
17736
17736
|
const c = createColor(jsonFlag);
|
|
17737
|
-
const { homedir:
|
|
17738
|
-
const { join:
|
|
17739
|
-
const home =
|
|
17737
|
+
const { homedir: homedir12 } = await import("node:os");
|
|
17738
|
+
const { join: join18 } = await import("node:path");
|
|
17739
|
+
const home = homedir12();
|
|
17740
17740
|
const proxyPath = await resolveProxyScript(options.proxy);
|
|
17741
17741
|
const diagnostics = proxyPath ? await runProxyDiagnostics(proxyPath) : null;
|
|
17742
17742
|
const entries = await scanConnections();
|
|
17743
17743
|
const duplicates = detectDuplicates(entries);
|
|
17744
17744
|
const credentialFile = await readIfExists(
|
|
17745
|
-
|
|
17745
|
+
join18(home, ".great-arrow", "credential")
|
|
17746
17746
|
);
|
|
17747
17747
|
const credentialMigrated = await readIfExists(
|
|
17748
|
-
|
|
17748
|
+
join18(home, ".great-arrow", "credential.migrated")
|
|
17749
17749
|
) !== null;
|
|
17750
17750
|
const fileAuthoritative = credentialFile?.trim() === "LOGGED_OUT" || credentialMigrated || process.platform === "darwin" && credentialFile !== null;
|
|
17751
17751
|
const keychain = fileAuthoritative ? null : await readKeychainOnly();
|
|
17752
17752
|
const userStore = await readIfExists(
|
|
17753
|
-
|
|
17753
|
+
join18(home, ".great-arrow", OAUTH_CRED_FILENAME)
|
|
17754
17754
|
);
|
|
17755
17755
|
const legacyStores = await findLegacyStores(process.cwd());
|
|
17756
17756
|
const findings = [
|
|
@@ -18202,7 +18202,7 @@ function asMessage(body) {
|
|
|
18202
18202
|
return b.status === "message" && typeof b.messageId === "string" && typeof b.block === "string" ? { messageId: b.messageId, block: b.block } : null;
|
|
18203
18203
|
}
|
|
18204
18204
|
async function runInboxWait(o) {
|
|
18205
|
-
const
|
|
18205
|
+
const sleep3 = o.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
18206
18206
|
const now = o.now ?? Date.now;
|
|
18207
18207
|
const write = o.write ?? ((t) => void process.stdout.write(t));
|
|
18208
18208
|
const writeErr = o.writeErr ?? ((t) => void process.stderr.write(t));
|
|
@@ -18232,7 +18232,7 @@ async function runInboxWait(o) {
|
|
|
18232
18232
|
return 0;
|
|
18233
18233
|
}
|
|
18234
18234
|
const gap = Math.min(waitBackoffMs(emptyHolds++), stopAt - now());
|
|
18235
|
-
if (gap > 0) await
|
|
18235
|
+
if (gap > 0) await sleep3(gap);
|
|
18236
18236
|
}
|
|
18237
18237
|
return 3;
|
|
18238
18238
|
}
|
|
@@ -19144,10 +19144,10 @@ async function exclusive(slot, action) {
|
|
|
19144
19144
|
const controller = new AbortController();
|
|
19145
19145
|
let timer;
|
|
19146
19146
|
const operation = Promise.resolve().then(() => action(controller.signal));
|
|
19147
|
-
const
|
|
19147
|
+
const release2 = () => {
|
|
19148
19148
|
if (!controller.signal.aborted) busy.delete(slot);
|
|
19149
19149
|
};
|
|
19150
|
-
void operation.then(
|
|
19150
|
+
void operation.then(release2, release2);
|
|
19151
19151
|
const timeout2 = new Promise((_resolve, reject) => {
|
|
19152
19152
|
timer = setTimeout(() => {
|
|
19153
19153
|
controller.abort();
|
|
@@ -22067,8 +22067,8 @@ function emoji() {
|
|
|
22067
22067
|
}
|
|
22068
22068
|
var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
22069
22069
|
var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
22070
|
-
var mac = (
|
|
22071
|
-
const escapedDelim = escapeRegex(
|
|
22070
|
+
var mac = (delimiter2) => {
|
|
22071
|
+
const escapedDelim = escapeRegex(delimiter2 ?? ":");
|
|
22072
22072
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
22073
22073
|
};
|
|
22074
22074
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -22883,9 +22883,9 @@ var asciiTabOrNewline = /[\t\n\r]/g;
|
|
|
22883
22883
|
function stripTabAndNewline(value) {
|
|
22884
22884
|
return value.replace(asciiTabOrNewline, "");
|
|
22885
22885
|
}
|
|
22886
|
-
function urlHostnameOk(url2,
|
|
22887
|
-
|
|
22888
|
-
return
|
|
22886
|
+
function urlHostnameOk(url2, hostname7) {
|
|
22887
|
+
hostname7.lastIndex = 0;
|
|
22888
|
+
return hostname7.test(url2.hostname);
|
|
22889
22889
|
}
|
|
22890
22890
|
function urlProtocolOk(url2, protocol) {
|
|
22891
22891
|
protocol.lastIndex = 0;
|
|
@@ -25124,7 +25124,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
25124
25124
|
var NONE = 0;
|
|
25125
25125
|
var ASSUMED = 1;
|
|
25126
25126
|
var PROVEN = 2;
|
|
25127
|
-
function isRecursive(inst, stack,
|
|
25127
|
+
function isRecursive(inst, stack, resolve7) {
|
|
25128
25128
|
const cached2 = recursive.get(inst);
|
|
25129
25129
|
if (cached2 !== void 0)
|
|
25130
25130
|
return cached2 ? PROVEN : NONE;
|
|
@@ -25134,7 +25134,7 @@ function isRecursive(inst, stack, resolve5) {
|
|
|
25134
25134
|
let result = NONE;
|
|
25135
25135
|
const check2 = (child) => {
|
|
25136
25136
|
if (result !== PROVEN && child?._zod) {
|
|
25137
|
-
const answer = isRecursive(child, stack,
|
|
25137
|
+
const answer = isRecursive(child, stack, resolve7);
|
|
25138
25138
|
if (answer > result)
|
|
25139
25139
|
result = answer;
|
|
25140
25140
|
}
|
|
@@ -25145,7 +25145,7 @@ function isRecursive(inst, stack, resolve5) {
|
|
|
25145
25145
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
25146
25146
|
if (spread && !desc.enumerable)
|
|
25147
25147
|
continue;
|
|
25148
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
25148
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve7) : NONE;
|
|
25149
25149
|
if (child > answer)
|
|
25150
25150
|
answer = child;
|
|
25151
25151
|
}
|
|
@@ -25209,7 +25209,7 @@ function isRecursive(inst, stack, resolve5) {
|
|
|
25209
25209
|
break;
|
|
25210
25210
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
25211
25211
|
case "lazy": {
|
|
25212
|
-
const inner = def._cachedInner ?? (
|
|
25212
|
+
const inner = def._cachedInner ?? (resolve7 ? inst._zod.innerType : void 0);
|
|
25213
25213
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
25214
25214
|
break;
|
|
25215
25215
|
}
|
|
@@ -43931,34 +43931,34 @@ function validateDownloadUrl(url2) {
|
|
|
43931
43931
|
message: `URL scheme must be http, https, or data, got ${parsed.protocol}`
|
|
43932
43932
|
});
|
|
43933
43933
|
}
|
|
43934
|
-
const
|
|
43935
|
-
if (!
|
|
43934
|
+
const hostname7 = parsed.hostname.toLowerCase().replace(/\.+$/, "");
|
|
43935
|
+
if (!hostname7) {
|
|
43936
43936
|
throw new DownloadError({
|
|
43937
43937
|
url: url2,
|
|
43938
43938
|
message: `URL must have a hostname`
|
|
43939
43939
|
});
|
|
43940
43940
|
}
|
|
43941
|
-
if (
|
|
43941
|
+
if (hostname7 === "localhost" || hostname7.endsWith(".local") || hostname7.endsWith(".localhost") || hostname7.endsWith(".internal")) {
|
|
43942
43942
|
throw new DownloadError({
|
|
43943
43943
|
url: url2,
|
|
43944
|
-
message: `URL with hostname ${
|
|
43944
|
+
message: `URL with hostname ${hostname7} is not allowed`
|
|
43945
43945
|
});
|
|
43946
43946
|
}
|
|
43947
|
-
if (
|
|
43948
|
-
const ipv63 =
|
|
43947
|
+
if (hostname7.startsWith("[") && hostname7.endsWith("]")) {
|
|
43948
|
+
const ipv63 = hostname7.slice(1, -1);
|
|
43949
43949
|
if (isPrivateIPv6(ipv63)) {
|
|
43950
43950
|
throw new DownloadError({
|
|
43951
43951
|
url: url2,
|
|
43952
|
-
message: `URL with IPv6 address ${
|
|
43952
|
+
message: `URL with IPv6 address ${hostname7} is not allowed`
|
|
43953
43953
|
});
|
|
43954
43954
|
}
|
|
43955
43955
|
return;
|
|
43956
43956
|
}
|
|
43957
|
-
if (isIPv4(
|
|
43958
|
-
if (isPrivateIPv4(
|
|
43957
|
+
if (isIPv4(hostname7)) {
|
|
43958
|
+
if (isPrivateIPv4(hostname7)) {
|
|
43959
43959
|
throw new DownloadError({
|
|
43960
43960
|
url: url2,
|
|
43961
|
-
message: `URL with IP address ${
|
|
43961
|
+
message: `URL with IP address ${hostname7} is not allowed`
|
|
43962
43962
|
});
|
|
43963
43963
|
}
|
|
43964
43964
|
}
|
|
@@ -43966,18 +43966,18 @@ function validateDownloadUrl(url2) {
|
|
|
43966
43966
|
function validateDownloadAddress({
|
|
43967
43967
|
address,
|
|
43968
43968
|
family,
|
|
43969
|
-
hostname:
|
|
43969
|
+
hostname: hostname7
|
|
43970
43970
|
}) {
|
|
43971
43971
|
const isUnsafe = family === 4 ? !isIPv4(address) || isPrivateIPv4(address) : family === 6 ? isPrivateIPv6(address) : true;
|
|
43972
43972
|
if (isUnsafe) {
|
|
43973
43973
|
throw new DownloadError({
|
|
43974
|
-
url:
|
|
43975
|
-
message: `Hostname ${
|
|
43974
|
+
url: hostname7,
|
|
43975
|
+
message: `Hostname ${hostname7} resolved to disallowed IP address ${address}`
|
|
43976
43976
|
});
|
|
43977
43977
|
}
|
|
43978
43978
|
}
|
|
43979
|
-
function isIPv4(
|
|
43980
|
-
const parts =
|
|
43979
|
+
function isIPv4(hostname7) {
|
|
43980
|
+
const parts = hostname7.split(".");
|
|
43981
43981
|
if (parts.length !== 4) return false;
|
|
43982
43982
|
return parts.every((part) => {
|
|
43983
43983
|
const num = Number(part);
|
|
@@ -44062,8 +44062,8 @@ function isPrivateIPv6(ip) {
|
|
|
44062
44062
|
return false;
|
|
44063
44063
|
}
|
|
44064
44064
|
function createSafeLookup(lookup) {
|
|
44065
|
-
return ((
|
|
44066
|
-
lookup(
|
|
44065
|
+
return ((hostname7, options, callback) => {
|
|
44066
|
+
lookup(hostname7, { ...options, all: true }, (error62, addresses) => {
|
|
44067
44067
|
if (error62) {
|
|
44068
44068
|
callback(error62);
|
|
44069
44069
|
return;
|
|
@@ -44071,10 +44071,10 @@ function createSafeLookup(lookup) {
|
|
|
44071
44071
|
try {
|
|
44072
44072
|
const [firstAddress] = addresses;
|
|
44073
44073
|
if (firstAddress == null) {
|
|
44074
|
-
throw new Error(`Hostname ${
|
|
44074
|
+
throw new Error(`Hostname ${hostname7} did not resolve to an address`);
|
|
44075
44075
|
}
|
|
44076
44076
|
for (const { address, family } of addresses) {
|
|
44077
|
-
validateDownloadAddress({ address, family, hostname:
|
|
44077
|
+
validateDownloadAddress({ address, family, hostname: hostname7 });
|
|
44078
44078
|
}
|
|
44079
44079
|
if (options.all === true) {
|
|
44080
44080
|
callback(null, addresses);
|
|
@@ -48219,7 +48219,7 @@ async function readCloudConversationReply(options) {
|
|
|
48219
48219
|
let bytes = 0;
|
|
48220
48220
|
let lineBytes = 0;
|
|
48221
48221
|
let released = false;
|
|
48222
|
-
const
|
|
48222
|
+
const release2 = () => {
|
|
48223
48223
|
if (!released) {
|
|
48224
48224
|
released = true;
|
|
48225
48225
|
source.releaseLock();
|
|
@@ -48228,14 +48228,14 @@ async function readCloudConversationReply(options) {
|
|
|
48228
48228
|
const cancel = () => {
|
|
48229
48229
|
if (released) return;
|
|
48230
48230
|
void source.cancel().catch((error62) => logger.warn(error62));
|
|
48231
|
-
|
|
48231
|
+
release2();
|
|
48232
48232
|
};
|
|
48233
48233
|
const bounded3 = new ReadableStream({
|
|
48234
48234
|
async pull(controller) {
|
|
48235
48235
|
try {
|
|
48236
48236
|
const chunk = await abortable(() => source.read(), signal);
|
|
48237
48237
|
if (chunk.done) {
|
|
48238
|
-
|
|
48238
|
+
release2();
|
|
48239
48239
|
controller.close();
|
|
48240
48240
|
return;
|
|
48241
48241
|
}
|
|
@@ -48382,9 +48382,9 @@ function platformFetch(apiUrl, transport, engineFetch) {
|
|
|
48382
48382
|
if (input2 instanceof Request)
|
|
48383
48383
|
throw new Error("Local turn transport requires an explicit request path");
|
|
48384
48384
|
const raw = String(input2);
|
|
48385
|
-
const
|
|
48385
|
+
const relative3 = raw.startsWith("/");
|
|
48386
48386
|
const target = new URL(raw, platform2);
|
|
48387
|
-
if (!
|
|
48387
|
+
if (!relative3 && target.origin !== platform2.origin)
|
|
48388
48388
|
return engineFetch(input2, init);
|
|
48389
48389
|
if (target.origin !== platform2.origin || !target.pathname.startsWith("/api/") || target.username || target.password || target.hash)
|
|
48390
48390
|
throw new Error("Local turn requests must use a platform API path");
|
|
@@ -48855,11 +48855,11 @@ function origin(apiUrl) {
|
|
|
48855
48855
|
function appAwareFetch(apiUrl, token, base, getToken2) {
|
|
48856
48856
|
return async (input2, init) => {
|
|
48857
48857
|
const target = typeof input2 === "string" ? input2 : String(input2);
|
|
48858
|
-
const
|
|
48859
|
-
if (!
|
|
48858
|
+
const relative3 = target.startsWith("/") && !target.startsWith("//");
|
|
48859
|
+
if (!relative3 && !target.startsWith(`${origin(apiUrl)}/`))
|
|
48860
48860
|
return base(input2, init);
|
|
48861
48861
|
const currentToken = getToken2 ? await renewToken(getToken2) : token;
|
|
48862
|
-
return base(
|
|
48862
|
+
return base(relative3 ? `${origin(apiUrl)}${target}` : target, {
|
|
48863
48863
|
...init,
|
|
48864
48864
|
headers: {
|
|
48865
48865
|
...init?.headers,
|
|
@@ -50072,8 +50072,8 @@ function browserLaunchCommand(url2, platform2 = process.platform) {
|
|
|
50072
50072
|
function openBrowser2(url2) {
|
|
50073
50073
|
const command = browserLaunchCommand(url2);
|
|
50074
50074
|
if (!command) return Promise.resolve(false);
|
|
50075
|
-
return new Promise((
|
|
50076
|
-
execFile3(command.file, command.args, (error62) =>
|
|
50075
|
+
return new Promise((resolve7) => {
|
|
50076
|
+
execFile3(command.file, command.args, (error62) => resolve7(!error62));
|
|
50077
50077
|
});
|
|
50078
50078
|
}
|
|
50079
50079
|
function toSurfaceRow(value) {
|
|
@@ -50331,6 +50331,1312 @@ function callCommand() {
|
|
|
50331
50331
|
});
|
|
50332
50332
|
}
|
|
50333
50333
|
|
|
50334
|
+
// src/lib/runner/approval.ts
|
|
50335
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
50336
|
+
import { chmod as chmod4, mkdir as mkdir9, readFile as readFile8, rename as rename3, writeFile as writeFile7 } from "node:fs/promises";
|
|
50337
|
+
import { join as join14 } from "node:path";
|
|
50338
|
+
|
|
50339
|
+
// src/lib/runner/repo.ts
|
|
50340
|
+
import { chmod as chmod3, mkdir as mkdir8, realpath as realpath2, writeFile as writeFile6 } from "node:fs/promises";
|
|
50341
|
+
import { homedir as homedir10 } from "node:os";
|
|
50342
|
+
import { isAbsolute as isAbsolute3, join as join13, relative, resolve as resolve5 } from "node:path";
|
|
50343
|
+
|
|
50344
|
+
// src/lib/runner/git.ts
|
|
50345
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
50346
|
+
var GIT_DEADLINE_MS = 12e4;
|
|
50347
|
+
var REDIRECT_ENV = /* @__PURE__ */ new Set([
|
|
50348
|
+
"GIT_DIR",
|
|
50349
|
+
"GIT_WORK_TREE",
|
|
50350
|
+
"GIT_INDEX_FILE",
|
|
50351
|
+
"GIT_COMMON_DIR",
|
|
50352
|
+
"GIT_OBJECT_DIRECTORY",
|
|
50353
|
+
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
50354
|
+
"GIT_CONFIG",
|
|
50355
|
+
"GIT_CONFIG_PARAMETERS",
|
|
50356
|
+
"GIT_CONFIG_COUNT",
|
|
50357
|
+
"GIT_CEILING_DIRECTORIES"
|
|
50358
|
+
]);
|
|
50359
|
+
function gitEnv() {
|
|
50360
|
+
const env4 = {};
|
|
50361
|
+
for (const [name23, value] of Object.entries(process.env)) {
|
|
50362
|
+
if (REDIRECT_ENV.has(name23) || /^GIT_CONFIG_(KEY|VALUE)_/.test(name23))
|
|
50363
|
+
continue;
|
|
50364
|
+
env4[name23] = value;
|
|
50365
|
+
}
|
|
50366
|
+
env4.GIT_TERMINAL_PROMPT = "0";
|
|
50367
|
+
return env4;
|
|
50368
|
+
}
|
|
50369
|
+
function safeGit(cwd, args, opts = {}) {
|
|
50370
|
+
const argv = [
|
|
50371
|
+
"-c",
|
|
50372
|
+
"core.hooksPath=/dev/null",
|
|
50373
|
+
"-c",
|
|
50374
|
+
"core.fsmonitor=false",
|
|
50375
|
+
...args
|
|
50376
|
+
];
|
|
50377
|
+
return new Promise((resolve7) => {
|
|
50378
|
+
execFile4(
|
|
50379
|
+
"git",
|
|
50380
|
+
argv,
|
|
50381
|
+
{
|
|
50382
|
+
cwd,
|
|
50383
|
+
env: gitEnv(),
|
|
50384
|
+
timeout: opts.timeoutMs ?? GIT_DEADLINE_MS,
|
|
50385
|
+
killSignal: "SIGKILL",
|
|
50386
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
50387
|
+
...opts.signal ? { signal: opts.signal } : {}
|
|
50388
|
+
},
|
|
50389
|
+
(error62, stdout, stderr) => {
|
|
50390
|
+
const status = error62?.code;
|
|
50391
|
+
const code = !error62 ? 0 : typeof status === "number" ? status : 1;
|
|
50392
|
+
resolve7({ code, stdout: String(stdout), stderr: String(stderr) });
|
|
50393
|
+
}
|
|
50394
|
+
);
|
|
50395
|
+
});
|
|
50396
|
+
}
|
|
50397
|
+
function worktreeGit(layout, args, opts = {}) {
|
|
50398
|
+
return safeGit(
|
|
50399
|
+
layout.worktree,
|
|
50400
|
+
[
|
|
50401
|
+
`--git-dir=${layout.worktreeGitDir}`,
|
|
50402
|
+
`--work-tree=${layout.worktree}`,
|
|
50403
|
+
...args
|
|
50404
|
+
],
|
|
50405
|
+
opts
|
|
50406
|
+
);
|
|
50407
|
+
}
|
|
50408
|
+
|
|
50409
|
+
// src/lib/runner/text.ts
|
|
50410
|
+
function cleanLine(text3) {
|
|
50411
|
+
return text3.replace(/[\u0000-\u001f\u007f-\u009f]+/g, " ").trim();
|
|
50412
|
+
}
|
|
50413
|
+
function cleanText(text3) {
|
|
50414
|
+
return text3.replace(/\r\n?/g, "\n").replace(/\t/g, " ").replace(/[\u0000-\u0009\u000b-\u001f\u007f-\u009f]+/g, " ");
|
|
50415
|
+
}
|
|
50416
|
+
var PREVIEW_LINES = 3;
|
|
50417
|
+
var PREVIEW_CHARS = 240;
|
|
50418
|
+
function preview(text3) {
|
|
50419
|
+
const lines = cleanText(text3).split("\n").map((l) => l.trimEnd()).filter((l) => l.trim() !== "");
|
|
50420
|
+
const out2 = [];
|
|
50421
|
+
let used = 0;
|
|
50422
|
+
for (const line of lines) {
|
|
50423
|
+
if (out2.length === PREVIEW_LINES) {
|
|
50424
|
+
out2[out2.length - 1] = `${out2[out2.length - 1]} \u2026`;
|
|
50425
|
+
break;
|
|
50426
|
+
}
|
|
50427
|
+
const room = PREVIEW_CHARS - used;
|
|
50428
|
+
if (line.length > room) {
|
|
50429
|
+
out2.push(`${line.slice(0, Math.max(room - 1, 0))}\u2026`);
|
|
50430
|
+
break;
|
|
50431
|
+
}
|
|
50432
|
+
out2.push(line);
|
|
50433
|
+
used += line.length;
|
|
50434
|
+
}
|
|
50435
|
+
return out2;
|
|
50436
|
+
}
|
|
50437
|
+
|
|
50438
|
+
// src/lib/runner/sandbox.ts
|
|
50439
|
+
import { lstat, readFile as readFile7, realpath } from "node:fs/promises";
|
|
50440
|
+
import { dirname as dirname8, join as join12, resolve as resolve4 } from "node:path";
|
|
50441
|
+
var TASK_FILE = ".gad/task.md";
|
|
50442
|
+
var CLAUDE_ALLOWED_DOMAINS = [
|
|
50443
|
+
"api.anthropic.com",
|
|
50444
|
+
"www.greatarrow.ai",
|
|
50445
|
+
"registry.npmjs.org",
|
|
50446
|
+
"registry.yarnpkg.com",
|
|
50447
|
+
"pypi.org",
|
|
50448
|
+
"files.pythonhosted.org",
|
|
50449
|
+
"crates.io",
|
|
50450
|
+
"index.crates.io",
|
|
50451
|
+
"static.crates.io"
|
|
50452
|
+
];
|
|
50453
|
+
var DENY_RULES = [
|
|
50454
|
+
"Bash(git push)",
|
|
50455
|
+
"Bash(git push:*)",
|
|
50456
|
+
"Bash(git remote:*)",
|
|
50457
|
+
"Bash(git config:*)",
|
|
50458
|
+
"Bash(gh:*)",
|
|
50459
|
+
"Bash(gh)"
|
|
50460
|
+
];
|
|
50461
|
+
var CREDENTIAL_ENV = [
|
|
50462
|
+
"GH_TOKEN",
|
|
50463
|
+
"GITHUB_TOKEN",
|
|
50464
|
+
"GH_ENTERPRISE_TOKEN",
|
|
50465
|
+
"GITHUB_ENTERPRISE_TOKEN",
|
|
50466
|
+
"GITLAB_TOKEN",
|
|
50467
|
+
"SSH_AUTH_SOCK",
|
|
50468
|
+
"SSH_ASKPASS",
|
|
50469
|
+
"GIT_ASKPASS",
|
|
50470
|
+
"GIT_SSH",
|
|
50471
|
+
"GIT_SSH_COMMAND",
|
|
50472
|
+
"GIT_CONFIG_PARAMETERS",
|
|
50473
|
+
"GIT_CREDENTIAL_HELPER"
|
|
50474
|
+
];
|
|
50475
|
+
var HOME_DENY = [
|
|
50476
|
+
".gitconfig",
|
|
50477
|
+
".config",
|
|
50478
|
+
".ssh",
|
|
50479
|
+
".aws",
|
|
50480
|
+
".gnupg",
|
|
50481
|
+
".zshrc",
|
|
50482
|
+
".zshenv",
|
|
50483
|
+
".zprofile",
|
|
50484
|
+
".zlogin",
|
|
50485
|
+
".bashrc",
|
|
50486
|
+
".bash_profile",
|
|
50487
|
+
".bash_login",
|
|
50488
|
+
".profile",
|
|
50489
|
+
".netrc",
|
|
50490
|
+
".git-credentials",
|
|
50491
|
+
"Library",
|
|
50492
|
+
".docker"
|
|
50493
|
+
];
|
|
50494
|
+
var CLI_CREDENTIAL_ENV = [
|
|
50495
|
+
"GIT_CONFIG_COUNT",
|
|
50496
|
+
"GIT_DIR",
|
|
50497
|
+
"GIT_WORK_TREE",
|
|
50498
|
+
"GIT_INDEX_FILE",
|
|
50499
|
+
"NPM_TOKEN",
|
|
50500
|
+
"NODE_AUTH_TOKEN",
|
|
50501
|
+
"AWS_ACCESS_KEY_ID",
|
|
50502
|
+
"AWS_SECRET_ACCESS_KEY",
|
|
50503
|
+
"AWS_SESSION_TOKEN",
|
|
50504
|
+
"GOOGLE_APPLICATION_CREDENTIALS",
|
|
50505
|
+
"VERCEL_TOKEN",
|
|
50506
|
+
"SUPABASE_ACCESS_TOKEN",
|
|
50507
|
+
"OP_SERVICE_ACCOUNT_TOKEN"
|
|
50508
|
+
];
|
|
50509
|
+
var CLI_CREDENTIAL_ENV_PREFIXES = [
|
|
50510
|
+
"GAD_",
|
|
50511
|
+
"GREAT_ARROW_",
|
|
50512
|
+
"GIT_CONFIG_KEY_",
|
|
50513
|
+
"GIT_CONFIG_VALUE_",
|
|
50514
|
+
"AZURE_",
|
|
50515
|
+
"OP_SESSION_"
|
|
50516
|
+
];
|
|
50517
|
+
var CLI_HARDENING = [".git"];
|
|
50518
|
+
var CLI_READ_HARDENING = [
|
|
50519
|
+
".gadrc",
|
|
50520
|
+
".great-arrow",
|
|
50521
|
+
".claude.json",
|
|
50522
|
+
".claude/.credentials.json",
|
|
50523
|
+
".codex/auth.json",
|
|
50524
|
+
".npmrc",
|
|
50525
|
+
".config/configstore",
|
|
50526
|
+
".config/gh",
|
|
50527
|
+
".netrc",
|
|
50528
|
+
".git-credentials",
|
|
50529
|
+
".ssh",
|
|
50530
|
+
".gnupg",
|
|
50531
|
+
".config/gcloud",
|
|
50532
|
+
".aws",
|
|
50533
|
+
".azure",
|
|
50534
|
+
".kube",
|
|
50535
|
+
".docker/config.json",
|
|
50536
|
+
".config/op",
|
|
50537
|
+
".config/1Password",
|
|
50538
|
+
".pypirc",
|
|
50539
|
+
".cargo/credentials.toml",
|
|
50540
|
+
".terraform.d/credentials.tfrc.json"
|
|
50541
|
+
];
|
|
50542
|
+
function approvalFile(layout) {
|
|
50543
|
+
return join12(dirname8(dirname8(layout.worktree)), "approved.json");
|
|
50544
|
+
}
|
|
50545
|
+
function denyRead(layout) {
|
|
50546
|
+
return [
|
|
50547
|
+
...CLI_READ_HARDENING.map((rel) => join12(layout.home, rel)),
|
|
50548
|
+
approvalFile(layout)
|
|
50549
|
+
];
|
|
50550
|
+
}
|
|
50551
|
+
var CREDENTIAL_SET = new Set(
|
|
50552
|
+
[...CREDENTIAL_ENV, ...CLI_CREDENTIAL_ENV].map((n) => n.toLowerCase())
|
|
50553
|
+
);
|
|
50554
|
+
function isCredentialEnv(name23) {
|
|
50555
|
+
const lower = name23.toLowerCase();
|
|
50556
|
+
return CREDENTIAL_SET.has(lower) || CLI_CREDENTIAL_ENV_PREFIXES.some(
|
|
50557
|
+
(prefix) => lower.startsWith(prefix.toLowerCase())
|
|
50558
|
+
);
|
|
50559
|
+
}
|
|
50560
|
+
function stripCredentialEnv(env4) {
|
|
50561
|
+
const out2 = {};
|
|
50562
|
+
for (const [name23, value] of Object.entries(env4)) {
|
|
50563
|
+
if (!isCredentialEnv(name23)) out2[name23] = value;
|
|
50564
|
+
}
|
|
50565
|
+
return out2;
|
|
50566
|
+
}
|
|
50567
|
+
function arrowdeckCommitWrites(layout) {
|
|
50568
|
+
const wt = layout.worktreeGitDir;
|
|
50569
|
+
return [
|
|
50570
|
+
{ path: join12(layout.commonDir, "objects"), dir: true },
|
|
50571
|
+
{ path: join12(layout.commonDir, "refs"), dir: true },
|
|
50572
|
+
{ path: join12(layout.commonDir, "logs"), dir: true },
|
|
50573
|
+
{ path: join12(wt, "HEAD"), dir: false },
|
|
50574
|
+
{ path: join12(wt, "HEAD.lock"), dir: false },
|
|
50575
|
+
{ path: join12(wt, "index"), dir: false },
|
|
50576
|
+
{ path: join12(wt, "index.lock"), dir: false },
|
|
50577
|
+
{ path: join12(wt, "logs"), dir: true },
|
|
50578
|
+
{ path: join12(wt, "ORIG_HEAD"), dir: false },
|
|
50579
|
+
{ path: join12(wt, "COMMIT_EDITMSG"), dir: false },
|
|
50580
|
+
{ path: join12(wt, "AUTO_MERGE"), dir: false }
|
|
50581
|
+
];
|
|
50582
|
+
}
|
|
50583
|
+
function allowWrite(layout) {
|
|
50584
|
+
return [layout.worktree];
|
|
50585
|
+
}
|
|
50586
|
+
function denyWrite(layout) {
|
|
50587
|
+
return [
|
|
50588
|
+
join12(layout.commonDir, "hooks"),
|
|
50589
|
+
join12(layout.commonDir, "config"),
|
|
50590
|
+
join12(layout.commonDir, "info"),
|
|
50591
|
+
join12(layout.commonDir, "modules"),
|
|
50592
|
+
join12(layout.commonDir, "packed-refs"),
|
|
50593
|
+
join12(layout.worktreeGitDir, "config.worktree"),
|
|
50594
|
+
join12(layout.worktreeGitDir, "commondir"),
|
|
50595
|
+
join12(layout.worktreeGitDir, "gitdir"),
|
|
50596
|
+
layout.hooksDir,
|
|
50597
|
+
...HOME_DENY.map((rel) => join12(layout.home, rel)),
|
|
50598
|
+
...CLI_HARDENING.map((rel) => join12(layout.worktree, rel)),
|
|
50599
|
+
...arrowdeckCommitWrites(layout).map((w) => w.path)
|
|
50600
|
+
];
|
|
50601
|
+
}
|
|
50602
|
+
function claudeSettings(layout) {
|
|
50603
|
+
const deny = denyWrite(layout);
|
|
50604
|
+
const unreadable = denyRead(layout);
|
|
50605
|
+
const rules = [...DENY_RULES];
|
|
50606
|
+
for (const path10 of deny) {
|
|
50607
|
+
rules.push(`Edit(/${path10}/**)`);
|
|
50608
|
+
rules.push(`Edit(/${path10})`);
|
|
50609
|
+
}
|
|
50610
|
+
for (const path10 of unreadable) {
|
|
50611
|
+
rules.push(`Read(/${path10}/**)`);
|
|
50612
|
+
rules.push(`Read(/${path10})`);
|
|
50613
|
+
}
|
|
50614
|
+
return JSON.stringify(
|
|
50615
|
+
{
|
|
50616
|
+
permissions: { defaultMode: "acceptEdits", deny: rules },
|
|
50617
|
+
sandbox: {
|
|
50618
|
+
allowUnsandboxedCommands: false,
|
|
50619
|
+
autoAllowBashIfSandboxed: true,
|
|
50620
|
+
enabled: true,
|
|
50621
|
+
failIfUnavailable: true,
|
|
50622
|
+
filesystem: {
|
|
50623
|
+
allowWrite: allowWrite(layout),
|
|
50624
|
+
denyRead: unreadable,
|
|
50625
|
+
denyWrite: deny
|
|
50626
|
+
},
|
|
50627
|
+
network: { allowedDomains: [...CLAUDE_ALLOWED_DOMAINS] }
|
|
50628
|
+
}
|
|
50629
|
+
},
|
|
50630
|
+
null,
|
|
50631
|
+
2
|
|
50632
|
+
);
|
|
50633
|
+
}
|
|
50634
|
+
var CLAUDE_NO_MCP = [
|
|
50635
|
+
"--strict-mcp-config",
|
|
50636
|
+
"--mcp-config",
|
|
50637
|
+
'{"mcpServers":{}}'
|
|
50638
|
+
];
|
|
50639
|
+
function claudeArgs(settingsPath) {
|
|
50640
|
+
return [
|
|
50641
|
+
"--settings",
|
|
50642
|
+
settingsPath,
|
|
50643
|
+
"--permission-mode",
|
|
50644
|
+
"acceptEdits",
|
|
50645
|
+
...CLAUDE_NO_MCP
|
|
50646
|
+
];
|
|
50647
|
+
}
|
|
50648
|
+
var CODEX_PROFILE = "gad_runner";
|
|
50649
|
+
function codexArgs(layout) {
|
|
50650
|
+
const filesystem = [
|
|
50651
|
+
...denyRead(layout).map((p) => `${JSON.stringify(p)}="none"`),
|
|
50652
|
+
...CLI_HARDENING.map(
|
|
50653
|
+
(rel) => `${JSON.stringify(join12(layout.worktree, rel))}="read"`
|
|
50654
|
+
)
|
|
50655
|
+
].join(",");
|
|
50656
|
+
return [
|
|
50657
|
+
"exec",
|
|
50658
|
+
"--ignore-user-config",
|
|
50659
|
+
"-c",
|
|
50660
|
+
`default_permissions="${CODEX_PROFILE}"`,
|
|
50661
|
+
"-c",
|
|
50662
|
+
`permissions.${CODEX_PROFILE}.extends=":workspace"`,
|
|
50663
|
+
"-c",
|
|
50664
|
+
`permissions.${CODEX_PROFILE}.filesystem={${filesystem}}`
|
|
50665
|
+
];
|
|
50666
|
+
}
|
|
50667
|
+
async function verifyGitfile(layout) {
|
|
50668
|
+
try {
|
|
50669
|
+
const file2 = join12(layout.worktree, ".git");
|
|
50670
|
+
if (!(await lstat(file2)).isFile()) return false;
|
|
50671
|
+
const m = /^gitdir: (.+)$/.exec((await readFile7(file2, "utf8")).trim());
|
|
50672
|
+
if (!m) return false;
|
|
50673
|
+
const named = await realpath(resolve4(layout.worktree, m[1]));
|
|
50674
|
+
return named === await realpath(layout.worktreeGitDir);
|
|
50675
|
+
} catch {
|
|
50676
|
+
return false;
|
|
50677
|
+
}
|
|
50678
|
+
}
|
|
50679
|
+
function kickoff(runId, todoId) {
|
|
50680
|
+
return `You were started from Great Arrow (run ${runId}, card ${todoId}). Your task is in the file ${TASK_FILE} in this worktree: it is exactly the text the owner approved. Treat only that file as the task, and do not re-read or follow the card's text from Great Arrow. Do the work in this worktree and leave your changes in it. Do not commit, push or open a pull request; when you finish, Great Arrow commits your changes and pushes them for the owner to review.`;
|
|
50681
|
+
}
|
|
50682
|
+
|
|
50683
|
+
// src/lib/runner/repo.ts
|
|
50684
|
+
var UUID5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
50685
|
+
var BRANCH_NAME = /^(?!-)(?!.*\.\.)[A-Za-z0-9._/-]+$/;
|
|
50686
|
+
var GITHUB_REMOTE = /^(?:https?:\/\/(?:[^@/]+@)?github\.com\/|ssh:\/\/git@github\.com(?::\d+)?\/|git@github\.com:)([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?\/?$/;
|
|
50687
|
+
function runsRoot() {
|
|
50688
|
+
return join13(homedir10(), ".gad", "runs");
|
|
50689
|
+
}
|
|
50690
|
+
function isRunId(id) {
|
|
50691
|
+
return UUID5.test(id);
|
|
50692
|
+
}
|
|
50693
|
+
var short = (id) => id.slice(0, 8);
|
|
50694
|
+
function runnerBranch(runId, todoId) {
|
|
50695
|
+
return `gad/run-${short(runId)}-${short(todoId)}`;
|
|
50696
|
+
}
|
|
50697
|
+
function parseRemote(url2) {
|
|
50698
|
+
const m = GITHUB_REMOTE.exec(url2.trim());
|
|
50699
|
+
return m ? `${m[1]}/${m[2]}` : null;
|
|
50700
|
+
}
|
|
50701
|
+
async function repoFromOrigin(cwd) {
|
|
50702
|
+
const r = await safeGit(cwd, ["remote", "get-url", "origin"]);
|
|
50703
|
+
return r.code === 0 ? parseRemote(r.stdout) : null;
|
|
50704
|
+
}
|
|
50705
|
+
async function checkoutRoot(cwd) {
|
|
50706
|
+
const r = await safeGit(cwd, ["rev-parse", "--show-toplevel"]);
|
|
50707
|
+
return r.code === 0 && r.stdout.trim() ? realpath2(r.stdout.trim()) : null;
|
|
50708
|
+
}
|
|
50709
|
+
async function gitPath(cwd, flag) {
|
|
50710
|
+
const r = await safeGit(cwd, ["rev-parse", flag]);
|
|
50711
|
+
if (r.code !== 0) throw new PrepareError("layout", r.stderr);
|
|
50712
|
+
const out2 = r.stdout.trim();
|
|
50713
|
+
return realpath2(isAbsolute3(out2) ? out2 : resolve5(cwd, out2));
|
|
50714
|
+
}
|
|
50715
|
+
async function privateDir(path10) {
|
|
50716
|
+
await mkdir8(path10, { recursive: true, mode: 448 });
|
|
50717
|
+
await chmod3(path10, 448);
|
|
50718
|
+
}
|
|
50719
|
+
var PrepareError = class extends Error {
|
|
50720
|
+
constructor(step, stderr) {
|
|
50721
|
+
const first = cleanLine(stderr.split("\n").find((l) => l.trim()) ?? "");
|
|
50722
|
+
super(first ? `${step}: ${first.slice(0, 200)}` : step);
|
|
50723
|
+
this.step = step;
|
|
50724
|
+
this.name = "PrepareError";
|
|
50725
|
+
this.gitLine = first.slice(0, 200);
|
|
50726
|
+
}
|
|
50727
|
+
step;
|
|
50728
|
+
gitLine;
|
|
50729
|
+
};
|
|
50730
|
+
function hooksPathSetting(stdout) {
|
|
50731
|
+
const own2 = stdout.split("\n").filter((l) => l.trim() && !l.startsWith("command ")).pop();
|
|
50732
|
+
return own2 ? own2.slice(own2.indexOf(" ") + 1).trim() : null;
|
|
50733
|
+
}
|
|
50734
|
+
async function resolveHooksPath(raw, base) {
|
|
50735
|
+
const path10 = raw.startsWith("~/") ? join13(homedir10(), raw.slice(2)) : raw;
|
|
50736
|
+
const abs = isAbsolute3(path10) ? path10 : resolve5(base, path10);
|
|
50737
|
+
return realpath2(abs).catch(() => abs);
|
|
50738
|
+
}
|
|
50739
|
+
var readHooksPath = (cwd) => safeGit(cwd, ["config", "--show-scope", "--get-all", "core.hooksPath"]);
|
|
50740
|
+
async function configuredHooksDir(worktree, commonDir) {
|
|
50741
|
+
const raw = hooksPathSetting((await readHooksPath(worktree)).stdout);
|
|
50742
|
+
return raw ? resolveHooksPath(raw, worktree) : join13(commonDir, "hooks");
|
|
50743
|
+
}
|
|
50744
|
+
async function repoHooksDir(root) {
|
|
50745
|
+
const raw = hooksPathSetting((await readHooksPath(root)).stdout);
|
|
50746
|
+
if (!raw) return null;
|
|
50747
|
+
const abs = await resolveHooksPath(raw, root);
|
|
50748
|
+
const rel = relative(root, abs);
|
|
50749
|
+
return rel && !rel.startsWith("..") && !isAbsolute3(rel) ? rel : null;
|
|
50750
|
+
}
|
|
50751
|
+
async function prepareWorktree(input2) {
|
|
50752
|
+
const { repoRoot, runId, todoId, base, text: text3 } = input2;
|
|
50753
|
+
if (!isRunId(runId) || !isRunId(todoId))
|
|
50754
|
+
throw new Error("run and card ids must be UUIDs");
|
|
50755
|
+
if (!BRANCH_NAME.test(base)) throw new Error(`bad base branch: ${base}`);
|
|
50756
|
+
const runDir = join13(input2.runsDir ?? runsRoot(), runId);
|
|
50757
|
+
await privateDir(runDir);
|
|
50758
|
+
await privateDir(join13(runDir, "wt"));
|
|
50759
|
+
const path10 = join13(runDir, "wt", short(todoId));
|
|
50760
|
+
const branch = runnerBranch(runId, todoId);
|
|
50761
|
+
const fetch2 = await safeGit(repoRoot, [
|
|
50762
|
+
"fetch",
|
|
50763
|
+
"--no-tags",
|
|
50764
|
+
"origin",
|
|
50765
|
+
`+refs/heads/${base}:refs/remotes/origin/${base}`
|
|
50766
|
+
]);
|
|
50767
|
+
if (fetch2.code !== 0) throw new PrepareError("fetch", fetch2.stderr);
|
|
50768
|
+
const add = await safeGit(repoRoot, [
|
|
50769
|
+
"worktree",
|
|
50770
|
+
"add",
|
|
50771
|
+
"--no-track",
|
|
50772
|
+
"-b",
|
|
50773
|
+
branch,
|
|
50774
|
+
path10,
|
|
50775
|
+
`refs/remotes/origin/${base}`
|
|
50776
|
+
]);
|
|
50777
|
+
if (add.code !== 0) throw new PrepareError("worktree", add.stderr);
|
|
50778
|
+
const worktree = await realpath2(path10);
|
|
50779
|
+
const commonDir = await gitPath(worktree, "--git-common-dir");
|
|
50780
|
+
const layout = {
|
|
50781
|
+
worktree,
|
|
50782
|
+
commonDir,
|
|
50783
|
+
worktreeGitDir: await gitPath(worktree, "--absolute-git-dir"),
|
|
50784
|
+
home: homedir10(),
|
|
50785
|
+
hooksDir: await configuredHooksDir(worktree, commonDir),
|
|
50786
|
+
branch
|
|
50787
|
+
};
|
|
50788
|
+
const gad = join13(worktree, ".gad");
|
|
50789
|
+
await privateDir(gad);
|
|
50790
|
+
await writeFile6(join13(gad, ".gitignore"), "*\n", { mode: 384 });
|
|
50791
|
+
const task = join13(worktree, TASK_FILE);
|
|
50792
|
+
await writeFile6(task, text3, { mode: 384 });
|
|
50793
|
+
await chmod3(task, 384);
|
|
50794
|
+
return layout;
|
|
50795
|
+
}
|
|
50796
|
+
|
|
50797
|
+
// src/lib/runner/approval.ts
|
|
50798
|
+
function sha256(text3) {
|
|
50799
|
+
return createHash6("sha256").update(text3, "utf8").digest("hex");
|
|
50800
|
+
}
|
|
50801
|
+
var plainTitle = cleanLine;
|
|
50802
|
+
function approvedFile(runsDir, runId) {
|
|
50803
|
+
if (!isRunId(runId)) throw new Error("run id must be a UUID");
|
|
50804
|
+
return join14(runsDir, runId, "approved.json");
|
|
50805
|
+
}
|
|
50806
|
+
function approveShown(cards) {
|
|
50807
|
+
return new Map(
|
|
50808
|
+
cards.map((c) => [
|
|
50809
|
+
c.todoId,
|
|
50810
|
+
{ title: plainTitle(c.title), text: c.text, sha: sha256(c.text) }
|
|
50811
|
+
])
|
|
50812
|
+
);
|
|
50813
|
+
}
|
|
50814
|
+
async function saveApproved(runsDir, runId, approved) {
|
|
50815
|
+
const file2 = approvedFile(runsDir, runId);
|
|
50816
|
+
const dir = join14(runsDir, runId);
|
|
50817
|
+
await mkdir9(dir, { recursive: true, mode: 448 });
|
|
50818
|
+
await chmod4(runsDir, 448);
|
|
50819
|
+
await chmod4(dir, 448);
|
|
50820
|
+
const body = [...approved].map(([todoId, c]) => ({ todoId, ...c }));
|
|
50821
|
+
const tmp = `${file2}.tmp`;
|
|
50822
|
+
await writeFile7(tmp, JSON.stringify(body, null, 2), { mode: 384 });
|
|
50823
|
+
await chmod4(tmp, 384);
|
|
50824
|
+
await rename3(tmp, file2);
|
|
50825
|
+
}
|
|
50826
|
+
async function loadApproved(runsDir, runId) {
|
|
50827
|
+
let raw;
|
|
50828
|
+
try {
|
|
50829
|
+
raw = JSON.parse(await readFile8(approvedFile(runsDir, runId), "utf8"));
|
|
50830
|
+
} catch {
|
|
50831
|
+
return null;
|
|
50832
|
+
}
|
|
50833
|
+
if (!Array.isArray(raw)) return null;
|
|
50834
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
50835
|
+
for (const entry of raw) {
|
|
50836
|
+
const { todoId, title, text: text3, sha } = entry ?? {};
|
|
50837
|
+
if (typeof todoId !== "string" || typeof title !== "string" || typeof text3 !== "string" || sha !== sha256(text3))
|
|
50838
|
+
continue;
|
|
50839
|
+
out2.set(todoId, { title: plainTitle(title), text: text3, sha });
|
|
50840
|
+
}
|
|
50841
|
+
return out2;
|
|
50842
|
+
}
|
|
50843
|
+
function canResume(saved, runner, now) {
|
|
50844
|
+
if (!saved || !runner || new Date(runner.expiresAt).getTime() <= now)
|
|
50845
|
+
return false;
|
|
50846
|
+
return runner.cards.length > 0 && runner.cards.every((c) => saved.get(c.todoId)?.sha === c.contentSha256);
|
|
50847
|
+
}
|
|
50848
|
+
|
|
50849
|
+
// src/lib/runner/loop.ts
|
|
50850
|
+
var RUNNER_CARD_DEADLINE_MS = 2 * 60 * 6e4;
|
|
50851
|
+
var AGENT_DEADLINE_MS = RUNNER_CARD_DEADLINE_MS - 10 * 6e4;
|
|
50852
|
+
var POLL_MS = 1e4;
|
|
50853
|
+
var HEARTBEAT_MS = 3e4;
|
|
50854
|
+
var CLAIM_TTL_MINUTES = 125;
|
|
50855
|
+
var PUSH_HINT = 'Git could not push from this terminal. Run "gh auth login" (or set up your git credentials) and run the command again.';
|
|
50856
|
+
var FETCH_HINT = 'Git could not fetch from this terminal. Run "gh auth login" (or set up your git credentials) and run the command again.';
|
|
50857
|
+
var AUTH_FAILURE = /authentication|permission denied|could not read (username|password)|terminal prompts disabled|publickey|(?:HTTP|returned error|status)[: ]+(?:code )?\b(?:401|403)\b/i;
|
|
50858
|
+
var DETAIL_CODE = /^(?:[a-z_]+|prepare_failed: (?:fetch|worktree|layout)|agent_exit_(?:\d{1,3}|signal))$/;
|
|
50859
|
+
var RunnerCallError = class extends Error {
|
|
50860
|
+
constructor(code, message) {
|
|
50861
|
+
super(message);
|
|
50862
|
+
this.code = code;
|
|
50863
|
+
this.name = "RunnerCallError";
|
|
50864
|
+
}
|
|
50865
|
+
code;
|
|
50866
|
+
};
|
|
50867
|
+
function asNext(data) {
|
|
50868
|
+
const kind = data.kind;
|
|
50869
|
+
if (kind === "card" && typeof data.todoId === "string")
|
|
50870
|
+
return {
|
|
50871
|
+
kind,
|
|
50872
|
+
todoId: data.todoId,
|
|
50873
|
+
contentSha256: String(data.contentSha256 ?? "")
|
|
50874
|
+
};
|
|
50875
|
+
if (kind === "stop") return { kind, reason: String(data.reason ?? "") };
|
|
50876
|
+
if (kind === "wait" || kind === "done") return { kind };
|
|
50877
|
+
throw new Error("Great Arrow sent an answer this CLI does not understand.");
|
|
50878
|
+
}
|
|
50879
|
+
function describe3(o) {
|
|
50880
|
+
if (o.outcome === "pushed") return "PR opened";
|
|
50881
|
+
if (o.outcome === "no_changes") return "no changes";
|
|
50882
|
+
if (o.outcome === "stopped") return "stopped";
|
|
50883
|
+
if (o.outcome === "card_edited") return "failed: card_edited";
|
|
50884
|
+
return `failed: ${o.detail}`;
|
|
50885
|
+
}
|
|
50886
|
+
async function claimCard(call, todoId) {
|
|
50887
|
+
const claim2 = await call("work_claim", {
|
|
50888
|
+
claim_key: `board-run:${todoId}`,
|
|
50889
|
+
card_id: todoId,
|
|
50890
|
+
ttl_minutes: CLAIM_TTL_MINUTES
|
|
50891
|
+
}).catch(() => null);
|
|
50892
|
+
if (!claim2) return { outcome: "failed", detail: "claim_failed" };
|
|
50893
|
+
return claim2.granted === true ? null : { outcome: "failed", detail: "claimed_elsewhere" };
|
|
50894
|
+
}
|
|
50895
|
+
async function workCard(deps, todoId, card) {
|
|
50896
|
+
let prepared;
|
|
50897
|
+
try {
|
|
50898
|
+
prepared = await deps.prepare(todoId, card.text);
|
|
50899
|
+
} catch (error62) {
|
|
50900
|
+
if (!(error62 instanceof PrepareError))
|
|
50901
|
+
return { outcome: "failed", detail: "prepare_failed" };
|
|
50902
|
+
return {
|
|
50903
|
+
outcome: "failed",
|
|
50904
|
+
detail: `prepare_failed: ${error62.step}`,
|
|
50905
|
+
...error62.gitLine ? { local: error62.gitLine } : {}
|
|
50906
|
+
};
|
|
50907
|
+
}
|
|
50908
|
+
let ran;
|
|
50909
|
+
try {
|
|
50910
|
+
ran = await deps.launch(prepared, todoId, deps.signal);
|
|
50911
|
+
} catch {
|
|
50912
|
+
return { outcome: "failed", detail: "agent_did_not_start" };
|
|
50913
|
+
}
|
|
50914
|
+
if (deps.signal.aborted) return { outcome: "stopped" };
|
|
50915
|
+
if (!ran.groupGone) return { outcome: "failed", detail: "sandbox_tampered" };
|
|
50916
|
+
if (ran.killed) return { outcome: "failed", detail: "timed_out" };
|
|
50917
|
+
if (ran.exit !== 0)
|
|
50918
|
+
return { outcome: "failed", detail: `agent_exit_${ran.exit ?? "signal"}` };
|
|
50919
|
+
const result = await deps.publish(prepared, todoId, card.title, deps.signal).catch(() => ({ failed: "publish_failed" }));
|
|
50920
|
+
if (deps.signal.aborted) return { outcome: "stopped" };
|
|
50921
|
+
if (result === "no_changes") return { outcome: "no_changes" };
|
|
50922
|
+
if ("pushed" in result)
|
|
50923
|
+
return {
|
|
50924
|
+
outcome: "pushed",
|
|
50925
|
+
branch: prepared.branch,
|
|
50926
|
+
headSha: result.pushed
|
|
50927
|
+
};
|
|
50928
|
+
return {
|
|
50929
|
+
outcome: "failed",
|
|
50930
|
+
detail: result.failed,
|
|
50931
|
+
...result.file ? {
|
|
50932
|
+
say: `A possible secret was found in ${cleanLine(result.file)}; nothing was committed or pushed.`
|
|
50933
|
+
} : {}
|
|
50934
|
+
};
|
|
50935
|
+
}
|
|
50936
|
+
function reportFields(o) {
|
|
50937
|
+
if (o.outcome === "pushed")
|
|
50938
|
+
return { outcome: o.outcome, branch: o.branch, head_sha: o.headSha };
|
|
50939
|
+
if (o.outcome === "failed")
|
|
50940
|
+
return {
|
|
50941
|
+
outcome: "failed",
|
|
50942
|
+
detail: DETAIL_CODE.test(o.detail) ? o.detail : "failed"
|
|
50943
|
+
};
|
|
50944
|
+
return { outcome: o.outcome };
|
|
50945
|
+
}
|
|
50946
|
+
async function release(deps, todoId) {
|
|
50947
|
+
try {
|
|
50948
|
+
await deps.call("work_release", { card_id: todoId });
|
|
50949
|
+
} catch {
|
|
50950
|
+
deps.print(
|
|
50951
|
+
`Could not release the claim on card ${short(todoId)}; it lapses on its own.`
|
|
50952
|
+
);
|
|
50953
|
+
}
|
|
50954
|
+
}
|
|
50955
|
+
function heartbeat(deps, runId, runEnded) {
|
|
50956
|
+
let inFlight = false;
|
|
50957
|
+
let missed = 0;
|
|
50958
|
+
const stop2 = deps.every(HEARTBEAT_MS, () => {
|
|
50959
|
+
if (inFlight) return;
|
|
50960
|
+
inFlight = true;
|
|
50961
|
+
deps.call("board_autopilot", { action: "runner_get" }).then(
|
|
50962
|
+
(view) => {
|
|
50963
|
+
missed = 0;
|
|
50964
|
+
if (view.runId !== runId || view.status !== "running") runEnded();
|
|
50965
|
+
},
|
|
50966
|
+
(error62) => {
|
|
50967
|
+
if (error62 instanceof RunnerCallError && error62.code === "no_runner_run")
|
|
50968
|
+
runEnded();
|
|
50969
|
+
else missed += 1;
|
|
50970
|
+
}
|
|
50971
|
+
).finally(() => {
|
|
50972
|
+
inFlight = false;
|
|
50973
|
+
});
|
|
50974
|
+
});
|
|
50975
|
+
return () => {
|
|
50976
|
+
stop2();
|
|
50977
|
+
if (missed > 0)
|
|
50978
|
+
deps.print(
|
|
50979
|
+
`(Great Arrow did not hear from this terminal ${missed} times.)`
|
|
50980
|
+
);
|
|
50981
|
+
};
|
|
50982
|
+
}
|
|
50983
|
+
async function runLoop(deps, input2) {
|
|
50984
|
+
const { runId, approved } = input2;
|
|
50985
|
+
const board = (action, extra = {}) => deps.call("board_autopilot", { action, run_id: runId, ...extra });
|
|
50986
|
+
const total = approved.size;
|
|
50987
|
+
const result = {
|
|
50988
|
+
pushed: 0,
|
|
50989
|
+
noChanges: 0,
|
|
50990
|
+
failed: 0,
|
|
50991
|
+
stopped: false
|
|
50992
|
+
};
|
|
50993
|
+
const numbers = /* @__PURE__ */ new Map();
|
|
50994
|
+
while (!deps.signal.aborted) {
|
|
50995
|
+
const next = asNext(await board("runner_next"));
|
|
50996
|
+
if (next.kind === "done") break;
|
|
50997
|
+
if (next.kind === "stop") {
|
|
50998
|
+
deps.print(`Great Arrow ended the run (${cleanLine(next.reason)}).`);
|
|
50999
|
+
break;
|
|
51000
|
+
}
|
|
51001
|
+
if (next.kind === "wait") {
|
|
51002
|
+
await deps.sleep(POLL_MS, deps.signal);
|
|
51003
|
+
continue;
|
|
51004
|
+
}
|
|
51005
|
+
const card = approved.get(next.todoId);
|
|
51006
|
+
if (card && !numbers.has(next.todoId))
|
|
51007
|
+
numbers.set(next.todoId, numbers.size + 1);
|
|
51008
|
+
const label = card ? `[${numbers.get(next.todoId)}/${total}] ${card.title}` : `[-] card ${short(next.todoId)}`;
|
|
51009
|
+
let claimed = false;
|
|
51010
|
+
let outcome;
|
|
51011
|
+
if (!card) outcome = { outcome: "failed", detail: "not_approved" };
|
|
51012
|
+
else if (next.contentSha256 !== card.sha)
|
|
51013
|
+
outcome = { outcome: "card_edited" };
|
|
51014
|
+
else {
|
|
51015
|
+
const refused = await claimCard(deps.call, next.todoId);
|
|
51016
|
+
claimed = refused === null;
|
|
51017
|
+
if (refused) outcome = refused;
|
|
51018
|
+
else {
|
|
51019
|
+
const cardStop = new AbortController();
|
|
51020
|
+
const abort = () => cardStop.abort();
|
|
51021
|
+
deps.signal.addEventListener("abort", abort, { once: true });
|
|
51022
|
+
const stopBeat = heartbeat(deps, runId, () => {
|
|
51023
|
+
if (!cardStop.signal.aborted)
|
|
51024
|
+
deps.print("The run was stopped on the board. Stopping the agent\u2026");
|
|
51025
|
+
abort();
|
|
51026
|
+
});
|
|
51027
|
+
try {
|
|
51028
|
+
outcome = await workCard(
|
|
51029
|
+
{ ...deps, signal: cardStop.signal },
|
|
51030
|
+
next.todoId,
|
|
51031
|
+
card
|
|
51032
|
+
);
|
|
51033
|
+
} finally {
|
|
51034
|
+
stopBeat();
|
|
51035
|
+
deps.signal.removeEventListener("abort", abort);
|
|
51036
|
+
}
|
|
51037
|
+
}
|
|
51038
|
+
}
|
|
51039
|
+
try {
|
|
51040
|
+
await board("runner_report", {
|
|
51041
|
+
card_id: next.todoId,
|
|
51042
|
+
runner: reportFields(outcome)
|
|
51043
|
+
});
|
|
51044
|
+
} catch (error62) {
|
|
51045
|
+
if (!(error62 instanceof RunnerCallError && error62.code === "card_released"))
|
|
51046
|
+
throw error62;
|
|
51047
|
+
deps.print(`${label} \u2026 taken back on the board`);
|
|
51048
|
+
continue;
|
|
51049
|
+
} finally {
|
|
51050
|
+
if (claimed) await release(deps, next.todoId);
|
|
51051
|
+
}
|
|
51052
|
+
if (outcome.outcome === "stopped") {
|
|
51053
|
+
if (deps.signal.aborted) return { ...result, stopped: true };
|
|
51054
|
+
deps.print(`${label} \u2026 stopped`);
|
|
51055
|
+
continue;
|
|
51056
|
+
}
|
|
51057
|
+
deps.print(`${label} \u2026 ${describe3(outcome)}`);
|
|
51058
|
+
if (outcome.outcome === "failed") {
|
|
51059
|
+
if (outcome.say) deps.print(` ${outcome.say}`);
|
|
51060
|
+
if (outcome.local) {
|
|
51061
|
+
deps.print(` git said: ${outcome.local}`);
|
|
51062
|
+
deps.note(next.todoId, `git said: ${outcome.local}`);
|
|
51063
|
+
}
|
|
51064
|
+
if (outcome.detail === "push_failed") deps.print(PUSH_HINT);
|
|
51065
|
+
if (outcome.detail === "prepare_failed: fetch" && AUTH_FAILURE.test(outcome.local ?? ""))
|
|
51066
|
+
deps.print(FETCH_HINT);
|
|
51067
|
+
}
|
|
51068
|
+
if (outcome.outcome === "pushed") result.pushed += 1;
|
|
51069
|
+
else if (outcome.outcome === "no_changes") result.noChanges += 1;
|
|
51070
|
+
else result.failed += 1;
|
|
51071
|
+
}
|
|
51072
|
+
return { ...result, stopped: deps.signal.aborted };
|
|
51073
|
+
}
|
|
51074
|
+
|
|
51075
|
+
// src/lib/runner/command.ts
|
|
51076
|
+
var STOPPED_MESSAGE = "Stopped. This card is closed for this run; run the same command to go on with the remaining cards.";
|
|
51077
|
+
var AGENT_NAME = {
|
|
51078
|
+
claude: "Claude Code",
|
|
51079
|
+
codex: "Codex"
|
|
51080
|
+
};
|
|
51081
|
+
function agentOf(raw) {
|
|
51082
|
+
const agent = raw ?? "claude";
|
|
51083
|
+
return agent === "claude" || agent === "codex" ? agent : null;
|
|
51084
|
+
}
|
|
51085
|
+
function skippedCount(raw) {
|
|
51086
|
+
const n = raw?.notOwnerAuthored;
|
|
51087
|
+
return typeof n === "number" && Number.isInteger(n) && n > 0 ? n : 0;
|
|
51088
|
+
}
|
|
51089
|
+
function skippedMessage(n) {
|
|
51090
|
+
return `${n} ${n === 1 ? "card was" : "cards were"} skipped: someone else or an agent last edited ${n === 1 ? "it" : "them"}. Open and save a card yourself to run it here.`;
|
|
51091
|
+
}
|
|
51092
|
+
function asView(data) {
|
|
51093
|
+
if (typeof data.runId !== "string" || !isRunId(data.runId)) return null;
|
|
51094
|
+
const cards = Array.isArray(data.cards) ? data.cards : [];
|
|
51095
|
+
return {
|
|
51096
|
+
runId: data.runId,
|
|
51097
|
+
repo: typeof data.repo === "string" ? data.repo : "",
|
|
51098
|
+
base: typeof data.base === "string" ? data.base : "",
|
|
51099
|
+
cards: cards.filter(
|
|
51100
|
+
(c) => !!c && typeof c.todoId === "string" && typeof c.title === "string" && typeof c.text === "string"
|
|
51101
|
+
),
|
|
51102
|
+
runner: data.runner ?? null,
|
|
51103
|
+
skippedNotOwnerAuthored: skippedCount(data.skipped)
|
|
51104
|
+
};
|
|
51105
|
+
}
|
|
51106
|
+
function refusal2(deps, error62) {
|
|
51107
|
+
if (error62 instanceof RunnerCallError)
|
|
51108
|
+
deps.exit(
|
|
51109
|
+
1,
|
|
51110
|
+
cleanLine(error62.message) || `Great Arrow refused (${cleanLine(error62.code)}).`
|
|
51111
|
+
);
|
|
51112
|
+
throw error62;
|
|
51113
|
+
}
|
|
51114
|
+
async function checkFolder(deps, repo) {
|
|
51115
|
+
const { root, origin: origin2 } = await deps.checkout();
|
|
51116
|
+
if (!repo || !root || origin2?.toLowerCase() !== repo.toLowerCase())
|
|
51117
|
+
deps.exit(
|
|
51118
|
+
1,
|
|
51119
|
+
`Run this inside your ${cleanLine(repo) || "code repository"} checkout.`
|
|
51120
|
+
);
|
|
51121
|
+
return root;
|
|
51122
|
+
}
|
|
51123
|
+
async function consent(deps, view, shown, agent, yes) {
|
|
51124
|
+
deps.print("");
|
|
51125
|
+
deps.print(
|
|
51126
|
+
`Clear the board in ${cleanLine(view.repo)}, worked by ${AGENT_NAME[agent]} on this computer:`
|
|
51127
|
+
);
|
|
51128
|
+
[...shown.values()].forEach((c, i) => {
|
|
51129
|
+
deps.print(` ${i + 1}. ${c.title}`);
|
|
51130
|
+
for (const line of preview(c.text)) deps.print(` ${line}`);
|
|
51131
|
+
});
|
|
51132
|
+
deps.print("Approval lasts 24 hours.");
|
|
51133
|
+
deps.print("");
|
|
51134
|
+
if (yes) return;
|
|
51135
|
+
if (!deps.interactive)
|
|
51136
|
+
deps.exit(1, "Run this in a terminal to approve the cards, or pass --yes.");
|
|
51137
|
+
for (; ; ) {
|
|
51138
|
+
const answer = (await deps.ask(
|
|
51139
|
+
`Run these ${shown.size} cards here? [y/N, v to view them in full] `
|
|
51140
|
+
)).trim().toLowerCase();
|
|
51141
|
+
if (answer === "y" || answer === "yes") return;
|
|
51142
|
+
if (answer !== "v") deps.exit(0, "Nothing was run.");
|
|
51143
|
+
[...shown.values()].forEach((c, i) => {
|
|
51144
|
+
deps.print(`--- ${i + 1}. ${c.title} ---`);
|
|
51145
|
+
for (const line of cleanText(c.text).split("\n")) deps.print(line);
|
|
51146
|
+
deps.print("");
|
|
51147
|
+
});
|
|
51148
|
+
}
|
|
51149
|
+
}
|
|
51150
|
+
async function approve(deps, view, agent, yes) {
|
|
51151
|
+
const shown = approveShown(view.cards);
|
|
51152
|
+
await consent(deps, view, shown, agent, yes);
|
|
51153
|
+
let state;
|
|
51154
|
+
try {
|
|
51155
|
+
const data = await deps.call("board_autopilot", {
|
|
51156
|
+
action: "runner_approve",
|
|
51157
|
+
run_id: view.runId,
|
|
51158
|
+
runner: {
|
|
51159
|
+
machine: deps.machine.slice(0, 200),
|
|
51160
|
+
agent,
|
|
51161
|
+
cards: [...shown].map(([todoId, c]) => ({
|
|
51162
|
+
todoId,
|
|
51163
|
+
contentSha256: c.sha
|
|
51164
|
+
}))
|
|
51165
|
+
}
|
|
51166
|
+
});
|
|
51167
|
+
state = data.runner;
|
|
51168
|
+
} catch (error62) {
|
|
51169
|
+
refusal2(deps, error62);
|
|
51170
|
+
}
|
|
51171
|
+
const agreed = new Set(
|
|
51172
|
+
(state?.cards ?? []).map((c) => `${c.todoId}:${c.contentSha256}`)
|
|
51173
|
+
);
|
|
51174
|
+
for (const [todoId, c] of shown)
|
|
51175
|
+
if (!agreed.has(`${todoId}:${c.sha}`)) shown.delete(todoId);
|
|
51176
|
+
if (shown.size === 0)
|
|
51177
|
+
deps.exit(
|
|
51178
|
+
1,
|
|
51179
|
+
"None of the cards shown here are the ones approved for this run. Run the command again to see the current cards."
|
|
51180
|
+
);
|
|
51181
|
+
return shown;
|
|
51182
|
+
}
|
|
51183
|
+
async function runBoardWith(deps, opts) {
|
|
51184
|
+
const agent = agentOf(opts.agent);
|
|
51185
|
+
if (!agent) deps.exit(1, "--agent must be claude or codex.");
|
|
51186
|
+
const check2 = await deps.preflight(agent);
|
|
51187
|
+
if (!check2.ok) deps.exit(1, check2.message);
|
|
51188
|
+
let view = null;
|
|
51189
|
+
try {
|
|
51190
|
+
view = asView(await deps.call("board_autopilot", { action: "runner_get" }));
|
|
51191
|
+
} catch (error62) {
|
|
51192
|
+
refusal2(deps, error62);
|
|
51193
|
+
}
|
|
51194
|
+
if (!view) deps.exit(1, "Great Arrow sent a run this CLI cannot use.");
|
|
51195
|
+
const repoRoot = await checkFolder(deps, view.repo);
|
|
51196
|
+
const hooks = await deps.repoHooksDir(repoRoot);
|
|
51197
|
+
if (hooks)
|
|
51198
|
+
deps.print(
|
|
51199
|
+
`The agent can't change files in ${cleanLine(hooks)} (git hooks) on this computer.`
|
|
51200
|
+
);
|
|
51201
|
+
const saved = await loadApproved(deps.runsDir, view.runId);
|
|
51202
|
+
let approved;
|
|
51203
|
+
if (saved && canResume(saved, view.runner, deps.now())) {
|
|
51204
|
+
approved = saved;
|
|
51205
|
+
deps.print(
|
|
51206
|
+
`Picking up run ${short(view.runId)} where it left off (${saved.size} cards approved).`
|
|
51207
|
+
);
|
|
51208
|
+
} else {
|
|
51209
|
+
if (view.skippedNotOwnerAuthored > 0)
|
|
51210
|
+
deps.print(skippedMessage(view.skippedNotOwnerAuthored));
|
|
51211
|
+
if (view.cards.length === 0)
|
|
51212
|
+
deps.exit(
|
|
51213
|
+
0,
|
|
51214
|
+
view.skippedNotOwnerAuthored > 0 ? "Nothing was run." : "No cards are ready to run."
|
|
51215
|
+
);
|
|
51216
|
+
approved = await approve(deps, view, agent, opts.yes === true);
|
|
51217
|
+
await saveApproved(deps.runsDir, view.runId, approved);
|
|
51218
|
+
}
|
|
51219
|
+
const controller = new AbortController();
|
|
51220
|
+
let group = null;
|
|
51221
|
+
deps.onInterrupt(() => {
|
|
51222
|
+
if (controller.signal.aborted) {
|
|
51223
|
+
if (group !== null) deps.killGroup(group);
|
|
51224
|
+
deps.exit(130, STOPPED_MESSAGE);
|
|
51225
|
+
}
|
|
51226
|
+
deps.print("Stopping the agent\u2026");
|
|
51227
|
+
controller.abort();
|
|
51228
|
+
});
|
|
51229
|
+
const work2 = deps.work({
|
|
51230
|
+
view,
|
|
51231
|
+
repoRoot,
|
|
51232
|
+
agent,
|
|
51233
|
+
bin: check2.bin,
|
|
51234
|
+
onSpawn: (pgid) => {
|
|
51235
|
+
group = pgid;
|
|
51236
|
+
},
|
|
51237
|
+
onReaped: () => {
|
|
51238
|
+
group = null;
|
|
51239
|
+
}
|
|
51240
|
+
});
|
|
51241
|
+
let result;
|
|
51242
|
+
try {
|
|
51243
|
+
result = await runLoop(
|
|
51244
|
+
{
|
|
51245
|
+
...work2,
|
|
51246
|
+
call: deps.call,
|
|
51247
|
+
signal: controller.signal,
|
|
51248
|
+
print: deps.print
|
|
51249
|
+
},
|
|
51250
|
+
{ runId: view.runId, approved }
|
|
51251
|
+
);
|
|
51252
|
+
} catch (error62) {
|
|
51253
|
+
refusal2(deps, error62);
|
|
51254
|
+
}
|
|
51255
|
+
if (result.stopped) deps.exit(130, STOPPED_MESSAGE);
|
|
51256
|
+
deps.print("");
|
|
51257
|
+
deps.print(
|
|
51258
|
+
`Finished: ${result.pushed} PRs opened, ${result.noChanges} with no changes, ${result.failed} not done. Logs are in ${deps.runsDir}/${view.runId}.`
|
|
51259
|
+
);
|
|
51260
|
+
}
|
|
51261
|
+
|
|
51262
|
+
// src/commands/board-run.ts
|
|
51263
|
+
import { appendFileSync } from "node:fs";
|
|
51264
|
+
import { chmod as chmod5, writeFile as writeFile8 } from "node:fs/promises";
|
|
51265
|
+
import { hostname as hostname5 } from "node:os";
|
|
51266
|
+
import { join as join16 } from "node:path";
|
|
51267
|
+
import { createInterface as createInterface3 } from "node:readline";
|
|
51268
|
+
|
|
51269
|
+
// src/lib/runner/agent.ts
|
|
51270
|
+
import { spawn } from "node:child_process";
|
|
51271
|
+
import { accessSync, chmodSync as chmodSync3, closeSync, constants as constants2, openSync } from "node:fs";
|
|
51272
|
+
import { delimiter, join as join15 } from "node:path";
|
|
51273
|
+
var KILL_GRACE_MS = 5e3;
|
|
51274
|
+
var INSTALL_MESSAGE = {
|
|
51275
|
+
claude: "Install Claude Code (https://claude.com/claude-code), then run the command again.",
|
|
51276
|
+
codex: "Install Codex (npm install -g @openai/codex), then run the command again.",
|
|
51277
|
+
bwrap: "Install bubblewrap (for example: sudo apt install bubblewrap), then run the command again."
|
|
51278
|
+
};
|
|
51279
|
+
function onPath(name23, env4) {
|
|
51280
|
+
for (const dir of (env4.PATH ?? "").split(delimiter)) {
|
|
51281
|
+
if (!dir) continue;
|
|
51282
|
+
const candidate = join15(dir, name23);
|
|
51283
|
+
try {
|
|
51284
|
+
accessSync(candidate, constants2.X_OK);
|
|
51285
|
+
return candidate;
|
|
51286
|
+
} catch {
|
|
51287
|
+
continue;
|
|
51288
|
+
}
|
|
51289
|
+
}
|
|
51290
|
+
return null;
|
|
51291
|
+
}
|
|
51292
|
+
async function preflightAgent(agent, platform2, env4 = process.env) {
|
|
51293
|
+
if (platform2 === "win32") {
|
|
51294
|
+
return {
|
|
51295
|
+
ok: false,
|
|
51296
|
+
message: "Clear the board runs on macOS, Linux or WSL."
|
|
51297
|
+
};
|
|
51298
|
+
}
|
|
51299
|
+
const bin = onPath(agent, env4);
|
|
51300
|
+
if (!bin) return { ok: false, message: INSTALL_MESSAGE[agent] };
|
|
51301
|
+
if (platform2 === "linux" && !onPath("bwrap", env4)) {
|
|
51302
|
+
return { ok: false, message: INSTALL_MESSAGE.bwrap };
|
|
51303
|
+
}
|
|
51304
|
+
return { ok: true, bin };
|
|
51305
|
+
}
|
|
51306
|
+
function agentArgv(input2) {
|
|
51307
|
+
return input2.agent === "claude" ? [...claudeArgs(input2.settingsPath), "-p", input2.kickoff] : [...codexArgs(input2.layout), input2.kickoff];
|
|
51308
|
+
}
|
|
51309
|
+
async function runAgent(input2) {
|
|
51310
|
+
if (input2.signal.aborted) return { exit: null, killed: true, pgid: null };
|
|
51311
|
+
const fd = openSync(input2.logPath, "a", 384);
|
|
51312
|
+
chmodSync3(input2.logPath, 384);
|
|
51313
|
+
const env4 = { ...stripCredentialEnv(process.env), GIT_TERMINAL_PROMPT: "0" };
|
|
51314
|
+
let child;
|
|
51315
|
+
try {
|
|
51316
|
+
child = spawn(input2.bin, agentArgv(input2), {
|
|
51317
|
+
cwd: input2.layout.worktree,
|
|
51318
|
+
detached: true,
|
|
51319
|
+
stdio: ["ignore", fd, fd],
|
|
51320
|
+
env: env4
|
|
51321
|
+
});
|
|
51322
|
+
} finally {
|
|
51323
|
+
closeSync(fd);
|
|
51324
|
+
}
|
|
51325
|
+
const pid = child.pid;
|
|
51326
|
+
if (pid !== void 0) input2.onSpawn?.(pid);
|
|
51327
|
+
return new Promise((resolve7, reject) => {
|
|
51328
|
+
let killed = false;
|
|
51329
|
+
let killTimer;
|
|
51330
|
+
const signalGroup = (sig) => {
|
|
51331
|
+
if (pid === void 0) return;
|
|
51332
|
+
try {
|
|
51333
|
+
process.kill(-pid, sig);
|
|
51334
|
+
} catch {
|
|
51335
|
+
return;
|
|
51336
|
+
}
|
|
51337
|
+
};
|
|
51338
|
+
const terminate = () => {
|
|
51339
|
+
if (killed) return;
|
|
51340
|
+
killed = true;
|
|
51341
|
+
signalGroup("SIGTERM");
|
|
51342
|
+
killTimer = setTimeout(() => signalGroup("SIGKILL"), KILL_GRACE_MS);
|
|
51343
|
+
};
|
|
51344
|
+
const deadline = setTimeout(terminate, input2.deadlineMs);
|
|
51345
|
+
input2.signal.addEventListener("abort", terminate, { once: true });
|
|
51346
|
+
const cleanup = () => {
|
|
51347
|
+
clearTimeout(deadline);
|
|
51348
|
+
if (killTimer) clearTimeout(killTimer);
|
|
51349
|
+
input2.signal.removeEventListener("abort", terminate);
|
|
51350
|
+
};
|
|
51351
|
+
child.once("error", (err2) => {
|
|
51352
|
+
cleanup();
|
|
51353
|
+
reject(err2);
|
|
51354
|
+
});
|
|
51355
|
+
child.once("close", (code) => {
|
|
51356
|
+
cleanup();
|
|
51357
|
+
if (killed) signalGroup("SIGKILL");
|
|
51358
|
+
resolve7({ exit: code, killed, pgid: pid ?? null });
|
|
51359
|
+
});
|
|
51360
|
+
});
|
|
51361
|
+
}
|
|
51362
|
+
var REAP_WAIT_MS = 2e3;
|
|
51363
|
+
function groupAlive(pgid) {
|
|
51364
|
+
try {
|
|
51365
|
+
process.kill(-pgid, 0);
|
|
51366
|
+
return true;
|
|
51367
|
+
} catch (error62) {
|
|
51368
|
+
return error62.code !== "ESRCH";
|
|
51369
|
+
}
|
|
51370
|
+
}
|
|
51371
|
+
async function reapGroup(pgid, waitMs = REAP_WAIT_MS) {
|
|
51372
|
+
try {
|
|
51373
|
+
process.kill(-pgid, "SIGKILL");
|
|
51374
|
+
} catch (error62) {
|
|
51375
|
+
if (error62.code === "ESRCH") return true;
|
|
51376
|
+
}
|
|
51377
|
+
const until = Date.now() + waitMs;
|
|
51378
|
+
while (groupAlive(pgid)) {
|
|
51379
|
+
if (Date.now() >= until) return false;
|
|
51380
|
+
await new Promise((resolve7) => setTimeout(resolve7, 25));
|
|
51381
|
+
}
|
|
51382
|
+
return true;
|
|
51383
|
+
}
|
|
51384
|
+
|
|
51385
|
+
// src/lib/runner/secrets.ts
|
|
51386
|
+
var SECRET_PATTERNS = [
|
|
51387
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/,
|
|
51388
|
+
/gh[pousr]_[A-Za-z0-9]{36,}/,
|
|
51389
|
+
/github_pat_[A-Za-z0-9_]{60,}/,
|
|
51390
|
+
/sk_live_[A-Za-z0-9]{20,}/,
|
|
51391
|
+
/AKIA[0-9A-Z]{16}/,
|
|
51392
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/,
|
|
51393
|
+
/gad_v1_[A-Za-z0-9_-]{20,}/
|
|
51394
|
+
];
|
|
51395
|
+
function fileWithSecret(diff) {
|
|
51396
|
+
let file2 = null;
|
|
51397
|
+
for (const line of diff.split("\n")) {
|
|
51398
|
+
if (line.startsWith("+++ ")) {
|
|
51399
|
+
file2 = line.startsWith("+++ b/") ? line.slice(6) : line.slice(4);
|
|
51400
|
+
continue;
|
|
51401
|
+
}
|
|
51402
|
+
if (!line.startsWith("+")) continue;
|
|
51403
|
+
if (SECRET_PATTERNS.some((p) => p.test(line))) return file2 ?? "a file";
|
|
51404
|
+
}
|
|
51405
|
+
return null;
|
|
51406
|
+
}
|
|
51407
|
+
|
|
51408
|
+
// src/lib/runner/publish.ts
|
|
51409
|
+
var RUNNER_BRANCH = /^gad\/run-[0-9a-f]{8}-[0-9a-f]{8}$/;
|
|
51410
|
+
function commitMessage(title, runId, todoId) {
|
|
51411
|
+
const subject = title.replace(/\s+/g, " ").trim() || "Clear the board card";
|
|
51412
|
+
return `${subject}
|
|
51413
|
+
|
|
51414
|
+
Clear the board run ${short(runId)}, card ${short(todoId)}`;
|
|
51415
|
+
}
|
|
51416
|
+
async function publishBranch(layout, branch, base, message, signal) {
|
|
51417
|
+
if (!await verifyGitfile(layout)) return { failed: "sandbox_tampered" };
|
|
51418
|
+
if (!RUNNER_BRANCH.test(branch) || branch === base)
|
|
51419
|
+
return { failed: "bad_branch" };
|
|
51420
|
+
const git2 = (args) => worktreeGit(layout, args, signal ? { signal } : {});
|
|
51421
|
+
if ((await git2(["add", "-A"])).code !== 0) return { failed: "commit_failed" };
|
|
51422
|
+
if ((await git2(["reset", "-q", "--", ".gad"])).code !== 0)
|
|
51423
|
+
return { failed: "commit_failed" };
|
|
51424
|
+
const diff = await git2([
|
|
51425
|
+
"diff",
|
|
51426
|
+
"--cached",
|
|
51427
|
+
"-U0",
|
|
51428
|
+
"--no-color",
|
|
51429
|
+
"--no-ext-diff",
|
|
51430
|
+
"--no-textconv"
|
|
51431
|
+
]);
|
|
51432
|
+
if (diff.code !== 0) return { failed: "commit_failed" };
|
|
51433
|
+
const leaked = fileWithSecret(diff.stdout);
|
|
51434
|
+
if (leaked) return { failed: "secret_in_diff", file: leaked };
|
|
51435
|
+
const staged = await git2(["diff", "--cached", "--quiet"]);
|
|
51436
|
+
if (staged.code > 1) return { failed: "commit_failed" };
|
|
51437
|
+
if (staged.code === 1 && (await git2(["commit", "-q", "-m", message])).code !== 0)
|
|
51438
|
+
return { failed: "commit_failed" };
|
|
51439
|
+
const ahead = await git2([
|
|
51440
|
+
"rev-list",
|
|
51441
|
+
"--count",
|
|
51442
|
+
`refs/remotes/origin/${base}..HEAD`
|
|
51443
|
+
]);
|
|
51444
|
+
if (ahead.code !== 0) return { failed: "commit_failed" };
|
|
51445
|
+
if (Number(ahead.stdout.trim()) === 0) return "no_changes";
|
|
51446
|
+
const task = await git2([
|
|
51447
|
+
"ls-tree",
|
|
51448
|
+
"-r",
|
|
51449
|
+
"--name-only",
|
|
51450
|
+
"HEAD",
|
|
51451
|
+
"--",
|
|
51452
|
+
".gad"
|
|
51453
|
+
]);
|
|
51454
|
+
if (task.code !== 0 || task.stdout.trim() !== "")
|
|
51455
|
+
return { failed: "task_file_committed" };
|
|
51456
|
+
const head = await git2(["rev-parse", "HEAD"]);
|
|
51457
|
+
const sha = head.stdout.trim();
|
|
51458
|
+
if (head.code !== 0 || !/^[0-9a-f]{40}$/.test(sha))
|
|
51459
|
+
return { failed: "commit_failed" };
|
|
51460
|
+
const push = await git2(["push", "origin", `${sha}:refs/heads/${branch}`]);
|
|
51461
|
+
return push.code === 0 ? { pushed: sha } : { failed: "push_failed" };
|
|
51462
|
+
}
|
|
51463
|
+
|
|
51464
|
+
// src/commands/board-run.ts
|
|
51465
|
+
function parseData(result) {
|
|
51466
|
+
if (result && typeof result === "object" && !Array.isArray(result))
|
|
51467
|
+
return result;
|
|
51468
|
+
if (typeof result !== "string") return {};
|
|
51469
|
+
const tail = result.slice(result.lastIndexOf("\n") + 1).trim();
|
|
51470
|
+
try {
|
|
51471
|
+
const data = JSON.parse(tail);
|
|
51472
|
+
return data && typeof data === "object" ? data : {};
|
|
51473
|
+
} catch {
|
|
51474
|
+
return {};
|
|
51475
|
+
}
|
|
51476
|
+
}
|
|
51477
|
+
function makeCall(client2) {
|
|
51478
|
+
return async (tool2, args) => {
|
|
51479
|
+
const heartbeat2 = args.action === "runner_get";
|
|
51480
|
+
let result;
|
|
51481
|
+
try {
|
|
51482
|
+
result = tool2 === "board_autopilot" ? await client2.mcpCall(
|
|
51483
|
+
"gad_call",
|
|
51484
|
+
gadCallArgs(tool2, args),
|
|
51485
|
+
heartbeat2 ? 2e4 : 6e4
|
|
51486
|
+
) : await client2.mcpCall(tool2, args, 3e4);
|
|
51487
|
+
} catch (error62) {
|
|
51488
|
+
if (error62 instanceof McpToolError)
|
|
51489
|
+
throw new RunnerCallError(error62.toolCode, error62.message);
|
|
51490
|
+
throw error62;
|
|
51491
|
+
}
|
|
51492
|
+
const failure2 = callFailure(result);
|
|
51493
|
+
if (failure2) throw new RunnerCallError(failure2.code, failure2.message);
|
|
51494
|
+
return parseData(result);
|
|
51495
|
+
};
|
|
51496
|
+
}
|
|
51497
|
+
function exit(code, message) {
|
|
51498
|
+
if (message)
|
|
51499
|
+
(code === 1 ? process.stderr : process.stdout).write(`${message}
|
|
51500
|
+
`);
|
|
51501
|
+
process.exit(code);
|
|
51502
|
+
}
|
|
51503
|
+
function ask2(question) {
|
|
51504
|
+
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
51505
|
+
return new Promise(
|
|
51506
|
+
(resolve7) => rl.question(question, (answer) => {
|
|
51507
|
+
rl.close();
|
|
51508
|
+
resolve7(answer);
|
|
51509
|
+
})
|
|
51510
|
+
);
|
|
51511
|
+
}
|
|
51512
|
+
function sleep2(ms, signal) {
|
|
51513
|
+
return new Promise((resolve7) => {
|
|
51514
|
+
if (signal.aborted) return resolve7();
|
|
51515
|
+
const timer = setTimeout(done, ms);
|
|
51516
|
+
function done() {
|
|
51517
|
+
clearTimeout(timer);
|
|
51518
|
+
signal.removeEventListener("abort", done);
|
|
51519
|
+
resolve7();
|
|
51520
|
+
}
|
|
51521
|
+
signal.addEventListener("abort", done, { once: true });
|
|
51522
|
+
});
|
|
51523
|
+
}
|
|
51524
|
+
var work = ({
|
|
51525
|
+
view,
|
|
51526
|
+
repoRoot,
|
|
51527
|
+
agent,
|
|
51528
|
+
bin,
|
|
51529
|
+
onSpawn,
|
|
51530
|
+
onReaped
|
|
51531
|
+
}) => {
|
|
51532
|
+
const runsDir = runsRoot();
|
|
51533
|
+
const runDir = join16(runsDir, view.runId);
|
|
51534
|
+
const deps = {
|
|
51535
|
+
prepare: (todoId, text3) => prepareWorktree({
|
|
51536
|
+
repoRoot,
|
|
51537
|
+
runId: view.runId,
|
|
51538
|
+
todoId,
|
|
51539
|
+
base: view.base,
|
|
51540
|
+
text: text3,
|
|
51541
|
+
runsDir
|
|
51542
|
+
}),
|
|
51543
|
+
launch: async (prepared, todoId, signal) => {
|
|
51544
|
+
const settingsPath = join16(runDir, `${short(todoId)}.settings.json`);
|
|
51545
|
+
await writeFile8(settingsPath, claudeSettings(prepared), { mode: 384 });
|
|
51546
|
+
await chmod5(settingsPath, 384);
|
|
51547
|
+
const ran = await runAgent({
|
|
51548
|
+
agent,
|
|
51549
|
+
bin,
|
|
51550
|
+
layout: prepared,
|
|
51551
|
+
settingsPath,
|
|
51552
|
+
kickoff: kickoff(view.runId, todoId),
|
|
51553
|
+
logPath: join16(runDir, `${short(todoId)}.log`),
|
|
51554
|
+
deadlineMs: AGENT_DEADLINE_MS,
|
|
51555
|
+
signal,
|
|
51556
|
+
onSpawn
|
|
51557
|
+
});
|
|
51558
|
+
const groupGone = ran.pgid === null ? true : await reapGroup(ran.pgid);
|
|
51559
|
+
if (groupGone) onReaped();
|
|
51560
|
+
return { exit: ran.exit, killed: ran.killed, groupGone };
|
|
51561
|
+
},
|
|
51562
|
+
publish: (prepared, todoId, title, signal) => publishBranch(
|
|
51563
|
+
prepared,
|
|
51564
|
+
prepared.branch,
|
|
51565
|
+
view.base,
|
|
51566
|
+
commitMessage(title, view.runId, todoId),
|
|
51567
|
+
signal
|
|
51568
|
+
),
|
|
51569
|
+
sleep: sleep2,
|
|
51570
|
+
note: (todoId, line) => {
|
|
51571
|
+
try {
|
|
51572
|
+
appendFileSync(join16(runDir, `${short(todoId)}.log`), `${line}
|
|
51573
|
+
`, {
|
|
51574
|
+
mode: 384
|
|
51575
|
+
});
|
|
51576
|
+
} catch (error62) {
|
|
51577
|
+
process.stderr.write(
|
|
51578
|
+
`Could not write the card's log: ${error62.message}
|
|
51579
|
+
`
|
|
51580
|
+
);
|
|
51581
|
+
}
|
|
51582
|
+
},
|
|
51583
|
+
every: (ms, tick) => {
|
|
51584
|
+
const timer = setInterval(tick, ms);
|
|
51585
|
+
return () => clearInterval(timer);
|
|
51586
|
+
}
|
|
51587
|
+
};
|
|
51588
|
+
return deps;
|
|
51589
|
+
};
|
|
51590
|
+
async function commandDeps() {
|
|
51591
|
+
const auth = await resolveAuth();
|
|
51592
|
+
const call = makeCall(
|
|
51593
|
+
new GadClient({
|
|
51594
|
+
token: auth.token,
|
|
51595
|
+
getToken: auth.getToken,
|
|
51596
|
+
apiUrl: auth.apiUrl
|
|
51597
|
+
})
|
|
51598
|
+
);
|
|
51599
|
+
return {
|
|
51600
|
+
preflight: (agent) => preflightAgent(agent, process.platform),
|
|
51601
|
+
checkout: async () => {
|
|
51602
|
+
const cwd = process.cwd();
|
|
51603
|
+
const [root, origin2] = await Promise.all([
|
|
51604
|
+
checkoutRoot(cwd),
|
|
51605
|
+
repoFromOrigin(cwd)
|
|
51606
|
+
]);
|
|
51607
|
+
return { root, origin: origin2 };
|
|
51608
|
+
},
|
|
51609
|
+
repoHooksDir,
|
|
51610
|
+
call,
|
|
51611
|
+
ask: ask2,
|
|
51612
|
+
interactive: process.stdin.isTTY === true && process.stdout.isTTY === true,
|
|
51613
|
+
print: (line) => process.stdout.write(`${line}
|
|
51614
|
+
`),
|
|
51615
|
+
exit,
|
|
51616
|
+
now: () => Date.now(),
|
|
51617
|
+
runsDir: runsRoot(),
|
|
51618
|
+
machine: hostname5(),
|
|
51619
|
+
onInterrupt: (handler) => {
|
|
51620
|
+
process.on("SIGINT", handler);
|
|
51621
|
+
process.on("SIGTERM", handler);
|
|
51622
|
+
},
|
|
51623
|
+
killGroup: (pgid) => {
|
|
51624
|
+
try {
|
|
51625
|
+
process.kill(-pgid, "SIGKILL");
|
|
51626
|
+
} catch (error62) {
|
|
51627
|
+
if (error62.code !== "ESRCH") throw error62;
|
|
51628
|
+
}
|
|
51629
|
+
},
|
|
51630
|
+
work
|
|
51631
|
+
};
|
|
51632
|
+
}
|
|
51633
|
+
async function runBoard(opts) {
|
|
51634
|
+
await runBoardWith(await commandDeps(), opts);
|
|
51635
|
+
}
|
|
51636
|
+
function boardRunCommand() {
|
|
51637
|
+
return new Command("run").description("Work the cards of a Clear the board run on this computer").option("--agent <name>", "claude or codex (default: claude)").option("--yes", "Approve the listed cards without asking").action((opts) => runBoard(opts));
|
|
51638
|
+
}
|
|
51639
|
+
|
|
50334
51640
|
// src/commands/board.ts
|
|
50335
51641
|
var TOOL = "board_autopilot";
|
|
50336
51642
|
function asObject4(json3) {
|
|
@@ -50511,7 +51817,16 @@ function emit(result, json3, quiet = false) {
|
|
|
50511
51817
|
return data;
|
|
50512
51818
|
}
|
|
50513
51819
|
async function runClear(opts, command) {
|
|
50514
|
-
|
|
51820
|
+
const here = opts.here === true;
|
|
51821
|
+
let runner = null;
|
|
51822
|
+
if (here) {
|
|
51823
|
+
const agent = agentOf(opts.agent);
|
|
51824
|
+
if (!agent) throw validation("--agent must be claude or codex.");
|
|
51825
|
+
runner = await commandDeps();
|
|
51826
|
+
const check2 = await runner.preflight(agent);
|
|
51827
|
+
if (!check2.ok) runner.exit(1, check2.message);
|
|
51828
|
+
}
|
|
51829
|
+
if (opts.yes || here)
|
|
50515
51830
|
buildStartArgs(
|
|
50516
51831
|
"pending",
|
|
50517
51832
|
{ quotes: [{ executor: "hosted", p90Usd: 1 }] },
|
|
@@ -50523,10 +51838,10 @@ async function runClear(opts, command) {
|
|
|
50523
51838
|
action: "plan",
|
|
50524
51839
|
...opts.goal ? { goal_id: opts.goal } : {}
|
|
50525
51840
|
});
|
|
50526
|
-
const data = emit(planResult, g.json && !opts.yes, g.quiet);
|
|
51841
|
+
const data = emit(planResult, g.json && !opts.yes && !here, g.quiet);
|
|
50527
51842
|
const run4 = data?.run ?? null;
|
|
50528
51843
|
if (!g.json && !g.quiet && run4?.plan) printPlan(fmt, run4.plan);
|
|
50529
|
-
if (!opts.yes) {
|
|
51844
|
+
if (!opts.yes && !here) {
|
|
50530
51845
|
if (!g.json && !g.quiet && run4?.id)
|
|
50531
51846
|
process.stdout.write(
|
|
50532
51847
|
`
|
|
@@ -50536,11 +51851,18 @@ Nothing has changed. Start with: gad board clear${opts.goal ? ` --goal ${opts.go
|
|
|
50536
51851
|
return;
|
|
50537
51852
|
}
|
|
50538
51853
|
if (!run4?.id) throw validation("The plan reply carried no run id.");
|
|
50539
|
-
|
|
50540
|
-
|
|
50541
|
-
|
|
50542
|
-
|
|
51854
|
+
if (runner) {
|
|
51855
|
+
await checkFolder(runner, run4.plan?.repo ?? "");
|
|
51856
|
+
process.stdout.write(
|
|
51857
|
+
opts.yes ? "Starting the run on Great Arrow.\n" : "Starting the run on Great Arrow; nothing runs on this computer until you type y.\n"
|
|
51858
|
+
);
|
|
51859
|
+
}
|
|
51860
|
+
const startResult = await callBoard(client2, {
|
|
51861
|
+
...buildStartArgs(run4.id, run4.plan, opts),
|
|
51862
|
+
...here ? { executor: "runner" } : {}
|
|
51863
|
+
});
|
|
50543
51864
|
emit(startResult, g.json, g.quiet);
|
|
51865
|
+
if (runner) await runBoardWith(runner, { agent: opts.agent, yes: opts.yes });
|
|
50544
51866
|
}
|
|
50545
51867
|
function actionCommand(action) {
|
|
50546
51868
|
return new Command(action).description(`${action} a clear-the-board run`).option("--run <id>", "Run id (status defaults to the latest run)").option("--card <id>", "Undo only this card (undo)").action(async (opts, command) => {
|
|
@@ -50565,47 +51887,47 @@ function boardCommand() {
|
|
|
50565
51887
|
).option("--cap <usd>", "Spend cap in USD (default: hosted p90 quote)").option("--types <list>", "Comma-separated card types, e.g. code").option("--no-email", "Do not email when the run finishes").option("--no-push", "Do not push-notify when the run finishes").option(
|
|
50566
51888
|
"--reject <findingId...>",
|
|
50567
51889
|
"Finding ids to leave out of the accepted set"
|
|
50568
|
-
).option("--json", "Output the raw tool result");
|
|
51890
|
+
).option("--here", "Start the run and work its cards in this terminal").option("--agent <name>", "With --here: claude or codex (default: claude)").option("--json", "Output the raw tool result");
|
|
50569
51891
|
clear.action(runClear);
|
|
50570
51892
|
clear.addCommand(actionCommand("status"));
|
|
50571
51893
|
clear.addCommand(actionCommand("stop"));
|
|
50572
51894
|
clear.addCommand(actionCommand("undo"));
|
|
50573
|
-
return new Command("board").description("Clear the board: tidy cards and run the safe ones").addCommand(clear);
|
|
51895
|
+
return new Command("board").description("Clear the board: tidy cards and run the safe ones").addCommand(clear).addCommand(boardRunCommand());
|
|
50574
51896
|
}
|
|
50575
51897
|
|
|
50576
51898
|
// src/commands/keys.ts
|
|
50577
|
-
import { createInterface as
|
|
51899
|
+
import { createInterface as createInterface4 } from "node:readline";
|
|
50578
51900
|
import { Writable } from "node:stream";
|
|
50579
51901
|
|
|
50580
51902
|
// src/lib/keys-apply.ts
|
|
50581
|
-
import { spawn } from "node:child_process";
|
|
51903
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
50582
51904
|
import {
|
|
50583
|
-
chmod as
|
|
50584
|
-
mkdir as
|
|
50585
|
-
readFile as
|
|
50586
|
-
realpath,
|
|
50587
|
-
rename as
|
|
51905
|
+
chmod as chmod6,
|
|
51906
|
+
mkdir as mkdir10,
|
|
51907
|
+
readFile as readFile9,
|
|
51908
|
+
realpath as realpath3,
|
|
51909
|
+
rename as rename4,
|
|
50588
51910
|
stat as stat2,
|
|
50589
|
-
writeFile as
|
|
51911
|
+
writeFile as writeFile9
|
|
50590
51912
|
} from "node:fs/promises";
|
|
50591
|
-
import { homedir as
|
|
50592
|
-
import { basename as basename2, dirname as
|
|
51913
|
+
import { homedir as homedir11 } from "node:os";
|
|
51914
|
+
import { basename as basename2, dirname as dirname9, isAbsolute as isAbsolute4, join as join17, relative as relative2, sep } from "node:path";
|
|
50593
51915
|
var GH_APPLY_TIMEOUT_MS = 3e4;
|
|
50594
51916
|
var GIT_APPLY_TIMEOUT_MS = 3e4;
|
|
50595
51917
|
function runWithStdin(file2, args, input2, timeoutMs) {
|
|
50596
|
-
return new Promise((
|
|
51918
|
+
return new Promise((resolve7) => {
|
|
50597
51919
|
let settled = false;
|
|
50598
51920
|
const done = (o) => {
|
|
50599
51921
|
if (settled) return;
|
|
50600
51922
|
settled = true;
|
|
50601
51923
|
clearTimeout(timer);
|
|
50602
|
-
|
|
51924
|
+
resolve7(o);
|
|
50603
51925
|
};
|
|
50604
51926
|
let child;
|
|
50605
51927
|
try {
|
|
50606
|
-
child =
|
|
51928
|
+
child = spawn2(file2, args, { stdio: ["pipe", "ignore", "ignore"] });
|
|
50607
51929
|
} catch {
|
|
50608
|
-
|
|
51930
|
+
resolve7("not_found");
|
|
50609
51931
|
return;
|
|
50610
51932
|
}
|
|
50611
51933
|
const timer = setTimeout(() => {
|
|
@@ -50659,8 +51981,8 @@ password=${value}
|
|
|
50659
51981
|
return { ok: false, code: `git_${approved}` };
|
|
50660
51982
|
}
|
|
50661
51983
|
function expandHome(path10) {
|
|
50662
|
-
if (path10 === "~") return
|
|
50663
|
-
if (path10.startsWith("~/")) return
|
|
51984
|
+
if (path10 === "~") return homedir11();
|
|
51985
|
+
if (path10.startsWith("~/")) return join17(homedir11(), path10.slice(2));
|
|
50664
51986
|
return path10;
|
|
50665
51987
|
}
|
|
50666
51988
|
function escapeRegExp(s2) {
|
|
@@ -50689,16 +52011,16 @@ function formatEnvValue(value, quote) {
|
|
|
50689
52011
|
}
|
|
50690
52012
|
async function writeAtomic(path10, content, mode) {
|
|
50691
52013
|
const tmp = `${path10}.tmp`;
|
|
50692
|
-
await
|
|
50693
|
-
await
|
|
50694
|
-
await
|
|
52014
|
+
await writeFile9(tmp, content, { mode });
|
|
52015
|
+
await chmod6(tmp, mode);
|
|
52016
|
+
await rename4(tmp, path10);
|
|
50695
52017
|
}
|
|
50696
52018
|
async function applyEnvFile(path10, key, value) {
|
|
50697
52019
|
const file2 = expandHome(path10);
|
|
50698
52020
|
let original;
|
|
50699
52021
|
let mode = 384;
|
|
50700
52022
|
try {
|
|
50701
|
-
original = await
|
|
52023
|
+
original = await readFile9(file2, "utf8");
|
|
50702
52024
|
mode = (await stat2(file2)).mode & 511;
|
|
50703
52025
|
} catch (err2) {
|
|
50704
52026
|
if (err2?.code !== "ENOENT") {
|
|
@@ -50746,7 +52068,7 @@ async function applySshKey(path10, privatePem) {
|
|
|
50746
52068
|
const content = privatePem.endsWith("\n") ? privatePem : `${privatePem}
|
|
50747
52069
|
`;
|
|
50748
52070
|
try {
|
|
50749
|
-
await
|
|
52071
|
+
await mkdir10(dirname9(file2), { recursive: true, mode: 448 });
|
|
50750
52072
|
await writeAtomic(file2, content, 384);
|
|
50751
52073
|
} catch {
|
|
50752
52074
|
return { ok: false, code: "ssh_write_failed" };
|
|
@@ -50754,7 +52076,7 @@ async function applySshKey(path10, privatePem) {
|
|
|
50754
52076
|
return { ok: true, code: "applied" };
|
|
50755
52077
|
}
|
|
50756
52078
|
function envTargetRefusal(path10, key, reported) {
|
|
50757
|
-
if (!
|
|
52079
|
+
if (!isAbsolute4(path10)) return { ok: false, code: "target_invalid" };
|
|
50758
52080
|
const known = reported.some((r) => r.path === path10 && r.key === key);
|
|
50759
52081
|
return known ? null : { ok: false, code: "target_not_reported" };
|
|
50760
52082
|
}
|
|
@@ -50764,22 +52086,22 @@ var SSH_NOT_A_KEY = /* @__PURE__ */ new Set([
|
|
|
50764
52086
|
"config",
|
|
50765
52087
|
"known_hosts"
|
|
50766
52088
|
]);
|
|
50767
|
-
async function sshTargetRefusal(path10, sshDir =
|
|
52089
|
+
async function sshTargetRefusal(path10, sshDir = join17(homedir11(), ".ssh")) {
|
|
50768
52090
|
const file2 = expandHome(path10);
|
|
50769
|
-
if (!
|
|
52091
|
+
if (!isAbsolute4(file2)) return { ok: false, code: "target_invalid" };
|
|
50770
52092
|
if (SSH_NOT_A_KEY.has(basename2(file2))) {
|
|
50771
52093
|
return { ok: false, code: "target_not_a_key" };
|
|
50772
52094
|
}
|
|
50773
52095
|
let root;
|
|
50774
52096
|
let parent;
|
|
50775
52097
|
try {
|
|
50776
|
-
root = await
|
|
50777
|
-
parent = await
|
|
52098
|
+
root = await realpath3(sshDir);
|
|
52099
|
+
parent = await realpath3(dirname9(file2));
|
|
50778
52100
|
} catch {
|
|
50779
52101
|
return { ok: false, code: "target_outside_ssh_dir" };
|
|
50780
52102
|
}
|
|
50781
|
-
const rel =
|
|
50782
|
-
if (rel === ".." || rel.startsWith(`..${sep}`) ||
|
|
52103
|
+
const rel = relative2(root, parent);
|
|
52104
|
+
if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute4(rel)) {
|
|
50783
52105
|
return { ok: false, code: "target_outside_ssh_dir" };
|
|
50784
52106
|
}
|
|
50785
52107
|
return null;
|
|
@@ -50818,10 +52140,10 @@ async function applyUpdate(targetKind, targetRef, value, scope) {
|
|
|
50818
52140
|
}
|
|
50819
52141
|
|
|
50820
52142
|
// src/lib/keys-device.ts
|
|
50821
|
-
import { execFile as
|
|
50822
|
-
import { readFile as
|
|
50823
|
-
import { hostname as
|
|
50824
|
-
import { resolve as
|
|
52143
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
52144
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
52145
|
+
import { hostname as hostname6 } from "node:os";
|
|
52146
|
+
import { resolve as resolve6 } from "node:path";
|
|
50825
52147
|
|
|
50826
52148
|
// src/lib/keys-envelope.ts
|
|
50827
52149
|
import {
|
|
@@ -50922,7 +52244,7 @@ function openFromServer(sealed, devicePrivateKeyB64) {
|
|
|
50922
52244
|
}
|
|
50923
52245
|
|
|
50924
52246
|
// src/lib/keys-handoff.ts
|
|
50925
|
-
import { spawn as
|
|
52247
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
50926
52248
|
|
|
50927
52249
|
// src/lib/keys-paths.ts
|
|
50928
52250
|
function keyRotationPath() {
|
|
@@ -50942,18 +52264,18 @@ var BROWSER_LAUNCH_TIMEOUT_MS = 5e3;
|
|
|
50942
52264
|
function openInBrowser(url2) {
|
|
50943
52265
|
const command = browserLaunchCommand(url2);
|
|
50944
52266
|
if (!command) return Promise.resolve(false);
|
|
50945
|
-
return new Promise((
|
|
52267
|
+
return new Promise((resolve7) => {
|
|
50946
52268
|
let settled = false;
|
|
50947
52269
|
const done = (ok) => {
|
|
50948
52270
|
if (settled) return;
|
|
50949
52271
|
settled = true;
|
|
50950
52272
|
clearTimeout(timer);
|
|
50951
|
-
|
|
52273
|
+
resolve7(ok);
|
|
50952
52274
|
};
|
|
50953
52275
|
const timer = setTimeout(() => done(false), BROWSER_LAUNCH_TIMEOUT_MS);
|
|
50954
52276
|
timer.unref?.();
|
|
50955
52277
|
try {
|
|
50956
|
-
const child =
|
|
52278
|
+
const child = spawn3(command.file, command.args, {
|
|
50957
52279
|
detached: true,
|
|
50958
52280
|
stdio: "ignore"
|
|
50959
52281
|
});
|
|
@@ -50967,7 +52289,7 @@ function openInBrowser(url2) {
|
|
|
50967
52289
|
}
|
|
50968
52290
|
});
|
|
50969
52291
|
}
|
|
50970
|
-
var defaultSleep = (ms) => new Promise((
|
|
52292
|
+
var defaultSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
50971
52293
|
function stepUpError(message, hint) {
|
|
50972
52294
|
return new CliError(message, 1 /* AUTH_ERROR */, hint);
|
|
50973
52295
|
}
|
|
@@ -50975,7 +52297,7 @@ async function requestBrowserStepUp(client2, kind, subjectId, opts = {}) {
|
|
|
50975
52297
|
const openUrl = opts.openUrl ?? openInBrowser;
|
|
50976
52298
|
const notify = opts.notify ?? ((line) => process.stderr.write(`${line}
|
|
50977
52299
|
`));
|
|
50978
|
-
const
|
|
52300
|
+
const sleep3 = opts.sleep ?? defaultSleep;
|
|
50979
52301
|
const now = opts.now ?? Date.now;
|
|
50980
52302
|
const interval = opts.pollIntervalMs ?? HANDOFF_POLL_INTERVAL_MS;
|
|
50981
52303
|
const deadline = now() + (opts.deadlineMs ?? HANDOFF_DEADLINE_MS);
|
|
@@ -51018,7 +52340,7 @@ async function requestBrowserStepUp(client2, kind, subjectId, opts = {}) {
|
|
|
51018
52340
|
"Run the command again and approve within 5 minutes."
|
|
51019
52341
|
);
|
|
51020
52342
|
}
|
|
51021
|
-
await
|
|
52343
|
+
await sleep3(interval);
|
|
51022
52344
|
}
|
|
51023
52345
|
throw stepUpError(
|
|
51024
52346
|
"Timed out waiting for the browser approval.",
|
|
@@ -51034,7 +52356,7 @@ var REPORT_KEY = /^[A-Z_][A-Z0-9_]{0,127}$/;
|
|
|
51034
52356
|
var REPORT_PATH = /^[ -~]{1,200}$/;
|
|
51035
52357
|
var TOKEN_SHAPED = /[A-Za-z0-9]{33,}/;
|
|
51036
52358
|
var SECRET_PREFIX = /(gh[pousr]_|github_pat_|-----BEGIN)/;
|
|
51037
|
-
var
|
|
52359
|
+
var UUID6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
51038
52360
|
function deviceSlot(workspaceId) {
|
|
51039
52361
|
return `key-rotation-device:${workspaceId}`;
|
|
51040
52362
|
}
|
|
@@ -51111,13 +52433,13 @@ async function scanEnvKeys(paths) {
|
|
|
51111
52433
|
const out2 = [];
|
|
51112
52434
|
const seen = /* @__PURE__ */ new Set();
|
|
51113
52435
|
for (const p of paths) {
|
|
51114
|
-
const path10 =
|
|
52436
|
+
const path10 = resolve6(p);
|
|
51115
52437
|
if (seen.has(path10)) continue;
|
|
51116
52438
|
seen.add(path10);
|
|
51117
52439
|
if (!REPORT_PATH.test(path10) || !nameOk(path10)) continue;
|
|
51118
52440
|
let text3;
|
|
51119
52441
|
try {
|
|
51120
|
-
text3 = await
|
|
52442
|
+
text3 = await readFile10(path10, "utf8");
|
|
51121
52443
|
} catch {
|
|
51122
52444
|
continue;
|
|
51123
52445
|
}
|
|
@@ -51143,7 +52465,7 @@ function helperKind(raw) {
|
|
|
51143
52465
|
}
|
|
51144
52466
|
function run3(file2, args) {
|
|
51145
52467
|
return new Promise((done) => {
|
|
51146
|
-
|
|
52468
|
+
execFile5(
|
|
51147
52469
|
file2,
|
|
51148
52470
|
args,
|
|
51149
52471
|
{ timeout: DETECT_TIMEOUT_MS, encoding: "utf8" },
|
|
@@ -51172,7 +52494,7 @@ async function buildDeviceReport(envFiles) {
|
|
|
51172
52494
|
return { envKeys, ghCli, gitHelper };
|
|
51173
52495
|
}
|
|
51174
52496
|
function defaultDeviceLabel() {
|
|
51175
|
-
const label =
|
|
52497
|
+
const label = hostname6().replace(/[^ -~]/g, "-").slice(0, 80).trim();
|
|
51176
52498
|
return label && nameOk(label) ? label : "this machine";
|
|
51177
52499
|
}
|
|
51178
52500
|
async function enroll(client2, workspaceId, opts = {}) {
|
|
@@ -51212,7 +52534,7 @@ async function enroll(client2, workspaceId, opts = {}) {
|
|
|
51212
52534
|
publicKey: pair.publicKey,
|
|
51213
52535
|
report
|
|
51214
52536
|
});
|
|
51215
|
-
const enrollmentId = typeof begun?.enrollmentId === "string" &&
|
|
52537
|
+
const enrollmentId = typeof begun?.enrollmentId === "string" && UUID6.test(begun.enrollmentId) ? begun.enrollmentId : null;
|
|
51216
52538
|
if (!enrollmentId) {
|
|
51217
52539
|
throw new CliError(
|
|
51218
52540
|
"The server did not start the enrollment.",
|
|
@@ -51230,7 +52552,7 @@ async function enroll(client2, workspaceId, opts = {}) {
|
|
|
51230
52552
|
action: "enroll",
|
|
51231
52553
|
approvalToken
|
|
51232
52554
|
});
|
|
51233
|
-
const deviceId = typeof done?.deviceId === "string" &&
|
|
52555
|
+
const deviceId = typeof done?.deviceId === "string" && UUID6.test(done.deviceId) ? done.deviceId : null;
|
|
51234
52556
|
if (!deviceId) {
|
|
51235
52557
|
throw new CliError(
|
|
51236
52558
|
"The server did not complete the enrollment.",
|
|
@@ -51259,7 +52581,7 @@ async function enroll(client2, workspaceId, opts = {}) {
|
|
|
51259
52581
|
}
|
|
51260
52582
|
|
|
51261
52583
|
// src/commands/keys.ts
|
|
51262
|
-
var
|
|
52584
|
+
var UUID7 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
51263
52585
|
function patRequired(apiUrl) {
|
|
51264
52586
|
return authError(
|
|
51265
52587
|
"gad keys needs a personal access token; this sign-in is an OAuth session.",
|
|
@@ -51312,7 +52634,7 @@ async function keysContext() {
|
|
|
51312
52634
|
});
|
|
51313
52635
|
const value = await probe.mcpCall("workspace_introspect", {}, 5e3);
|
|
51314
52636
|
const workspaceId = value?.workspace?.id;
|
|
51315
|
-
if (value?.error || !workspaceId || !
|
|
52637
|
+
if (value?.error || !workspaceId || !UUID7.test(workspaceId)) {
|
|
51316
52638
|
throw validationError(
|
|
51317
52639
|
"GreatArrow.ai could not confirm your workspace.",
|
|
51318
52640
|
"Run 'gad whoami', or choose one with 'gad --workspace <id>'."
|
|
@@ -51333,7 +52655,7 @@ async function keysContext() {
|
|
|
51333
52655
|
};
|
|
51334
52656
|
}
|
|
51335
52657
|
function requireRunId(runId) {
|
|
51336
|
-
if (!
|
|
52658
|
+
if (!UUID7.test(runId)) {
|
|
51337
52659
|
throw validationError(
|
|
51338
52660
|
`'${stripControlChars(runId)}' is not a run id.`,
|
|
51339
52661
|
"Copy the run id from 'gad keys list' or the run page."
|
|
@@ -51462,7 +52784,7 @@ function enrollCommand() {
|
|
|
51462
52784
|
function toUpdateRow(v) {
|
|
51463
52785
|
if (typeof v !== "object" || v === null) return null;
|
|
51464
52786
|
const r = v;
|
|
51465
|
-
if (typeof r.id !== "string" || !
|
|
52787
|
+
if (typeof r.id !== "string" || !UUID7.test(r.id)) return null;
|
|
51466
52788
|
const ref = {};
|
|
51467
52789
|
if (typeof r.targetRef === "object" && r.targetRef !== null) {
|
|
51468
52790
|
for (const [k, val] of Object.entries(r.targetRef)) {
|
|
@@ -51645,20 +52967,20 @@ function readHiddenFromTty(prompt, io = {
|
|
|
51645
52967
|
callback();
|
|
51646
52968
|
}
|
|
51647
52969
|
});
|
|
51648
|
-
const rl =
|
|
52970
|
+
const rl = createInterface4({
|
|
51649
52971
|
input: io.input,
|
|
51650
52972
|
output: sink,
|
|
51651
52973
|
terminal: true
|
|
51652
52974
|
});
|
|
51653
52975
|
io.output.write(prompt);
|
|
51654
52976
|
muted = true;
|
|
51655
|
-
return new Promise((
|
|
52977
|
+
return new Promise((resolve7, reject) => {
|
|
51656
52978
|
const lines = [];
|
|
51657
52979
|
let pem = false;
|
|
51658
52980
|
const finish = () => {
|
|
51659
52981
|
rl.close();
|
|
51660
52982
|
io.output.write("\n");
|
|
51661
|
-
|
|
52983
|
+
resolve7(lines.join("\n"));
|
|
51662
52984
|
};
|
|
51663
52985
|
rl.on("line", (line) => {
|
|
51664
52986
|
if (lines.length === 0) pem = /^-----BEGIN /.test(line.trim());
|
|
@@ -52014,7 +53336,7 @@ function completionsCommand() {
|
|
|
52014
53336
|
|
|
52015
53337
|
// node_modules/.pnpm/update-notifier@7.3.1/node_modules/update-notifier/update-notifier.js
|
|
52016
53338
|
import process11 from "node:process";
|
|
52017
|
-
import { spawn as
|
|
53339
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
52018
53340
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
52019
53341
|
import path9 from "node:path";
|
|
52020
53342
|
import { format } from "node:util";
|
|
@@ -52090,7 +53412,7 @@ var retryifyAsync = (fn, options) => {
|
|
|
52090
53412
|
throw error62;
|
|
52091
53413
|
const delay2 = Math.round(interval * Math.random());
|
|
52092
53414
|
if (delay2 > 0) {
|
|
52093
|
-
const delayPromise = new Promise((
|
|
53415
|
+
const delayPromise = new Promise((resolve7) => setTimeout(resolve7, delay2));
|
|
52094
53416
|
return delayPromise.then(() => attempt.apply(void 0, args));
|
|
52095
53417
|
} else {
|
|
52096
53418
|
return attempt.apply(void 0, args);
|
|
@@ -53656,14 +54978,14 @@ var TimeoutError = class extends Error {
|
|
|
53656
54978
|
|
|
53657
54979
|
// node_modules/.pnpm/ky@1.14.3/node_modules/ky/distribution/utils/timeout.js
|
|
53658
54980
|
async function timeout(request, init, abortController, options) {
|
|
53659
|
-
return new Promise((
|
|
54981
|
+
return new Promise((resolve7, reject) => {
|
|
53660
54982
|
const timeoutId = setTimeout(() => {
|
|
53661
54983
|
if (abortController) {
|
|
53662
54984
|
abortController.abort();
|
|
53663
54985
|
}
|
|
53664
54986
|
reject(new TimeoutError(request));
|
|
53665
54987
|
}, options.timeout);
|
|
53666
|
-
void options.fetch(request, init).then(
|
|
54988
|
+
void options.fetch(request, init).then(resolve7).catch(reject).then(() => {
|
|
53667
54989
|
clearTimeout(timeoutId);
|
|
53668
54990
|
});
|
|
53669
54991
|
});
|
|
@@ -53671,7 +54993,7 @@ async function timeout(request, init, abortController, options) {
|
|
|
53671
54993
|
|
|
53672
54994
|
// node_modules/.pnpm/ky@1.14.3/node_modules/ky/distribution/utils/delay.js
|
|
53673
54995
|
async function delay(ms, { signal }) {
|
|
53674
|
-
return new Promise((
|
|
54996
|
+
return new Promise((resolve7, reject) => {
|
|
53675
54997
|
if (signal) {
|
|
53676
54998
|
signal.throwIfAborted();
|
|
53677
54999
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
@@ -53682,7 +55004,7 @@ async function delay(ms, { signal }) {
|
|
|
53682
55004
|
}
|
|
53683
55005
|
const timeoutId = setTimeout(() => {
|
|
53684
55006
|
signal?.removeEventListener("abort", abortHandler);
|
|
53685
|
-
|
|
55007
|
+
resolve7();
|
|
53686
55008
|
}, ms);
|
|
53687
55009
|
});
|
|
53688
55010
|
}
|
|
@@ -55311,7 +56633,7 @@ var UpdateNotifier = class {
|
|
|
55311
56633
|
if (Date.now() - this.config.get("lastUpdateCheck") < this.#updateCheckInterval) {
|
|
55312
56634
|
return;
|
|
55313
56635
|
}
|
|
55314
|
-
|
|
56636
|
+
spawn4(process11.execPath, [path9.join(__dirname3, "check.js"), JSON.stringify(this.#options)], {
|
|
55315
56637
|
detached: true,
|
|
55316
56638
|
stdio: "ignore"
|
|
55317
56639
|
}).unref();
|