@great-arrow/cli 0.9.4 → 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +140 -79
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -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 dirname11 = path10.dirname(name24);
|
|
3343
|
+
if (dirname11 === name24) {
|
|
3344
3344
|
return original;
|
|
3345
3345
|
}
|
|
3346
|
-
return find(
|
|
3346
|
+
return find(dirname11, original);
|
|
3347
3347
|
} catch (error62) {
|
|
3348
3348
|
if (name24 === original) {
|
|
3349
3349
|
if (error62.code === "ENOENT") {
|
|
@@ -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.9.
|
|
9486
|
+
var CLI_VERSION = "0.9.6";
|
|
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";
|
|
@@ -15755,7 +15755,7 @@ function serverMapsFromJson(parsed, serversKey) {
|
|
|
15755
15755
|
return maps;
|
|
15756
15756
|
}
|
|
15757
15757
|
function findCodexEntries(location, content) {
|
|
15758
|
-
const
|
|
15758
|
+
const entries2 = [];
|
|
15759
15759
|
const sections = content.split(/^\s*\[/m).slice(1);
|
|
15760
15760
|
const seen = /* @__PURE__ */ new Set();
|
|
15761
15761
|
for (const raw of sections) {
|
|
@@ -15769,7 +15769,7 @@ function findCodexEntries(location, content) {
|
|
|
15769
15769
|
const transport = codexTransportFields(body);
|
|
15770
15770
|
if (!isGreatArrowServer(name23, transport)) continue;
|
|
15771
15771
|
seen.add(name23);
|
|
15772
|
-
|
|
15772
|
+
entries2.push({
|
|
15773
15773
|
clientId: location.clientId,
|
|
15774
15774
|
client: location.client,
|
|
15775
15775
|
scope: location.scope,
|
|
@@ -15778,7 +15778,7 @@ function findCodexEntries(location, content) {
|
|
|
15778
15778
|
surface: typeof transport.command === "string" ? "stdio" : "http"
|
|
15779
15779
|
});
|
|
15780
15780
|
}
|
|
15781
|
-
return
|
|
15781
|
+
return entries2;
|
|
15782
15782
|
}
|
|
15783
15783
|
function findGreatArrowEntries(location, content, options = {}) {
|
|
15784
15784
|
if (location.format === "toml") return findCodexEntries(location, content);
|
|
@@ -15790,7 +15790,7 @@ function findGreatArrowEntries(location, content, options = {}) {
|
|
|
15790
15790
|
}
|
|
15791
15791
|
if (!parsed) return [];
|
|
15792
15792
|
const serversKey = location.serversKey ?? "mcpServers";
|
|
15793
|
-
const
|
|
15793
|
+
const entries2 = [];
|
|
15794
15794
|
for (const { servers, projectDir } of serverMapsFromJson(
|
|
15795
15795
|
parsed,
|
|
15796
15796
|
serversKey
|
|
@@ -15799,7 +15799,7 @@ function findGreatArrowEntries(location, content, options = {}) {
|
|
|
15799
15799
|
const entry = asObject3(value);
|
|
15800
15800
|
if (!entry) continue;
|
|
15801
15801
|
if (!isGreatArrowServer(name23, entry)) continue;
|
|
15802
|
-
|
|
15802
|
+
entries2.push({
|
|
15803
15803
|
clientId: location.clientId,
|
|
15804
15804
|
client: location.client,
|
|
15805
15805
|
scope: projectDir ? "project" : location.scope,
|
|
@@ -15814,7 +15814,7 @@ function findGreatArrowEntries(location, content, options = {}) {
|
|
|
15814
15814
|
});
|
|
15815
15815
|
}
|
|
15816
15816
|
}
|
|
15817
|
-
return
|
|
15817
|
+
return entries2;
|
|
15818
15818
|
}
|
|
15819
15819
|
function hasGreatArrowHooks(settingsContent) {
|
|
15820
15820
|
let parsed = null;
|
|
@@ -15849,9 +15849,9 @@ function compareEntries(a, b) {
|
|
|
15849
15849
|
if (a.scope !== b.scope) return a.scope === "user" ? -1 : 1;
|
|
15850
15850
|
return a.path.localeCompare(b.path);
|
|
15851
15851
|
}
|
|
15852
|
-
function detectDuplicates(
|
|
15852
|
+
function detectDuplicates(entries2) {
|
|
15853
15853
|
const byClient = /* @__PURE__ */ new Map();
|
|
15854
|
-
for (const entry of
|
|
15854
|
+
for (const entry of entries2) {
|
|
15855
15855
|
const list = byClient.get(entry.clientId) ?? [];
|
|
15856
15856
|
list.push(entry);
|
|
15857
15857
|
byClient.set(entry.clientId, list);
|
|
@@ -15878,8 +15878,8 @@ function detectDuplicates(entries) {
|
|
|
15878
15878
|
}
|
|
15879
15879
|
return findings.sort((a, b) => a.clientId.localeCompare(b.clientId));
|
|
15880
15880
|
}
|
|
15881
|
-
function connectorGuidance(
|
|
15882
|
-
const hasLocalClaude =
|
|
15881
|
+
function connectorGuidance(entries2) {
|
|
15882
|
+
const hasLocalClaude = entries2.some(
|
|
15883
15883
|
(entry) => entry.clientId === "claude-code" || entry.clientId === "claude-desktop"
|
|
15884
15884
|
);
|
|
15885
15885
|
if (!hasLocalClaude) return null;
|
|
@@ -17570,12 +17570,12 @@ var logsCommand = new Command("logs").description("Tail MCP connection log with
|
|
|
17570
17570
|
]);
|
|
17571
17571
|
return;
|
|
17572
17572
|
}
|
|
17573
|
-
const
|
|
17574
|
-
if (
|
|
17573
|
+
const entries2 = Array.isArray(data) ? data : [];
|
|
17574
|
+
if (entries2.length === 0) {
|
|
17575
17575
|
fmt.info("No recent MCP connection events.");
|
|
17576
17576
|
return;
|
|
17577
17577
|
}
|
|
17578
|
-
for (const entry of
|
|
17578
|
+
for (const entry of entries2) {
|
|
17579
17579
|
renderLogEntry(entry, c);
|
|
17580
17580
|
}
|
|
17581
17581
|
} catch {
|
|
@@ -17922,15 +17922,15 @@ async function scanConnections() {
|
|
|
17922
17922
|
join19(home, ".claude", "settings.json")
|
|
17923
17923
|
);
|
|
17924
17924
|
const hooksInstalled = hookSettings ? hasGreatArrowHooks(hookSettings) : false;
|
|
17925
|
-
const
|
|
17925
|
+
const entries2 = [];
|
|
17926
17926
|
for (const location of knownConfigLocations(home, process.cwd())) {
|
|
17927
17927
|
const content = await readIfExists(location.path);
|
|
17928
17928
|
if (content === null) continue;
|
|
17929
|
-
|
|
17929
|
+
entries2.push(
|
|
17930
17930
|
...findGreatArrowEntries(location, content, { hooksInstalled })
|
|
17931
17931
|
);
|
|
17932
17932
|
}
|
|
17933
|
-
return
|
|
17933
|
+
return entries2;
|
|
17934
17934
|
}
|
|
17935
17935
|
async function probeEndpoint() {
|
|
17936
17936
|
try {
|
|
@@ -18015,8 +18015,8 @@ var doctorSubcommand = new Command("doctor").description(
|
|
|
18015
18015
|
const home = homedir12();
|
|
18016
18016
|
const proxyPath = await resolveProxyScript(options.proxy);
|
|
18017
18017
|
const diagnostics = proxyPath ? await runProxyDiagnostics(proxyPath) : null;
|
|
18018
|
-
const
|
|
18019
|
-
const duplicates = detectDuplicates(
|
|
18018
|
+
const entries2 = await scanConnections();
|
|
18019
|
+
const duplicates = detectDuplicates(entries2);
|
|
18020
18020
|
const credentialFile = await readIfExists(
|
|
18021
18021
|
join19(home, ".great-arrow", "credential")
|
|
18022
18022
|
);
|
|
@@ -18039,7 +18039,7 @@ var doctorSubcommand = new Command("doctor").description(
|
|
|
18039
18039
|
}),
|
|
18040
18040
|
await probeEndpoint()
|
|
18041
18041
|
];
|
|
18042
|
-
if (
|
|
18042
|
+
if (entries2.length === 0) {
|
|
18043
18043
|
findings.push({
|
|
18044
18044
|
code: "no_connections",
|
|
18045
18045
|
level: "warn",
|
|
@@ -18064,14 +18064,14 @@ var doctorSubcommand = new Command("doctor").description(
|
|
|
18064
18064
|
now: Date.now()
|
|
18065
18065
|
});
|
|
18066
18066
|
const applied = options.migrate ? await applyMigration(plan) : [];
|
|
18067
|
-
const guidance = connectorGuidance(
|
|
18067
|
+
const guidance = connectorGuidance(entries2);
|
|
18068
18068
|
if (jsonFlag) {
|
|
18069
18069
|
process.stdout.write(
|
|
18070
18070
|
JSON.stringify(
|
|
18071
18071
|
{
|
|
18072
18072
|
proxyPath,
|
|
18073
18073
|
diagnostics,
|
|
18074
|
-
entries,
|
|
18074
|
+
entries: entries2,
|
|
18075
18075
|
duplicates,
|
|
18076
18076
|
findings,
|
|
18077
18077
|
migration: { plan, applied, migrated: Boolean(options.migrate) },
|
|
@@ -18084,10 +18084,10 @@ var doctorSubcommand = new Command("doctor").description(
|
|
|
18084
18084
|
} else {
|
|
18085
18085
|
process.stdout.write(`${c.dim("Connections")}
|
|
18086
18086
|
`);
|
|
18087
|
-
if (
|
|
18087
|
+
if (entries2.length === 0) {
|
|
18088
18088
|
process.stdout.write(" (none found)\n");
|
|
18089
18089
|
}
|
|
18090
|
-
for (const entry of
|
|
18090
|
+
for (const entry of entries2) {
|
|
18091
18091
|
process.stdout.write(` ${entry.client}: ${describeEntry(entry)}
|
|
18092
18092
|
`);
|
|
18093
18093
|
}
|
|
@@ -21009,9 +21009,9 @@ function assertNever(_x) {
|
|
|
21009
21009
|
}
|
|
21010
21010
|
function assert(_) {
|
|
21011
21011
|
}
|
|
21012
|
-
function getEnumValues(
|
|
21013
|
-
const numericValues = Object.values(
|
|
21014
|
-
const values = Object.entries(
|
|
21012
|
+
function getEnumValues(entries2) {
|
|
21013
|
+
const numericValues = Object.values(entries2).filter((v) => typeof v === "number");
|
|
21014
|
+
const values = Object.entries(entries2).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v);
|
|
21015
21015
|
return values;
|
|
21016
21016
|
}
|
|
21017
21017
|
function joinValues(array3, separator = "|") {
|
|
@@ -22846,16 +22846,16 @@ var $ZodCheckProperties = /* @__PURE__ */ $constructor("$ZodCheckProperties", (i
|
|
|
22846
22846
|
hide(inst, Symbol.iterator, function* () {
|
|
22847
22847
|
yield inst;
|
|
22848
22848
|
});
|
|
22849
|
-
let
|
|
22849
|
+
let entries2;
|
|
22850
22850
|
inst._zod.check = (payload) => {
|
|
22851
22851
|
if (payload.value == null) {
|
|
22852
22852
|
payload.issues.push({ expected: "object", code: "invalid_type", input: payload.value, inst });
|
|
22853
22853
|
return void 0;
|
|
22854
22854
|
}
|
|
22855
|
-
|
|
22855
|
+
entries2 ?? (entries2 = Reflect.ownKeys(def.shape).map((key) => [key, def.shape[key]]));
|
|
22856
22856
|
const input2 = payload.value;
|
|
22857
22857
|
let proms;
|
|
22858
|
-
for (const [key, schema] of
|
|
22858
|
+
for (const [key, schema] of entries2) {
|
|
22859
22859
|
const result = schema._zod.run({ value: input2[key], issues: [] }, {});
|
|
22860
22860
|
if (result instanceof Promise) {
|
|
22861
22861
|
proms ?? (proms = []);
|
|
@@ -35673,18 +35673,18 @@ function _set(Class2, valueType, params) {
|
|
|
35673
35673
|
}
|
|
35674
35674
|
// @__NO_SIDE_EFFECTS__
|
|
35675
35675
|
function _enum(Class2, values, params) {
|
|
35676
|
-
const
|
|
35676
|
+
const entries2 = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values;
|
|
35677
35677
|
return new Class2({
|
|
35678
35678
|
type: "enum",
|
|
35679
|
-
entries,
|
|
35679
|
+
entries: entries2,
|
|
35680
35680
|
...normalizeParams(params)
|
|
35681
35681
|
});
|
|
35682
35682
|
}
|
|
35683
35683
|
// @__NO_SIDE_EFFECTS__
|
|
35684
|
-
function _nativeEnum(Class2,
|
|
35684
|
+
function _nativeEnum(Class2, entries2, params) {
|
|
35685
35685
|
return new Class2({
|
|
35686
35686
|
type: "enum",
|
|
35687
|
-
entries,
|
|
35687
|
+
entries: entries2,
|
|
35688
35688
|
...normalizeParams(params)
|
|
35689
35689
|
});
|
|
35690
35690
|
}
|
|
@@ -38667,17 +38667,17 @@ var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
|
|
|
38667
38667
|
};
|
|
38668
38668
|
});
|
|
38669
38669
|
function _enum2(values, params) {
|
|
38670
|
-
const
|
|
38670
|
+
const entries2 = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values;
|
|
38671
38671
|
return new ZodEnum({
|
|
38672
38672
|
type: "enum",
|
|
38673
|
-
entries,
|
|
38673
|
+
entries: entries2,
|
|
38674
38674
|
...util_exports.normalizeParams(params)
|
|
38675
38675
|
});
|
|
38676
38676
|
}
|
|
38677
|
-
function nativeEnum(
|
|
38677
|
+
function nativeEnum(entries2, params) {
|
|
38678
38678
|
return new ZodEnum({
|
|
38679
38679
|
type: "enum",
|
|
38680
|
-
entries,
|
|
38680
|
+
entries: entries2,
|
|
38681
38681
|
...util_exports.normalizeParams(params)
|
|
38682
38682
|
});
|
|
38683
38683
|
}
|
|
@@ -49454,11 +49454,11 @@ function firstString(...candidates) {
|
|
|
49454
49454
|
}
|
|
49455
49455
|
return void 0;
|
|
49456
49456
|
}
|
|
49457
|
-
function collect(
|
|
49458
|
-
if (!Array.isArray(
|
|
49457
|
+
function collect(entries2, read) {
|
|
49458
|
+
if (!Array.isArray(entries2)) return [];
|
|
49459
49459
|
const out2 = [];
|
|
49460
49460
|
const seen = /* @__PURE__ */ new Set();
|
|
49461
|
-
for (const entry of
|
|
49461
|
+
for (const entry of entries2) {
|
|
49462
49462
|
if (out2.length >= MAX_LOCAL_MODELS) break;
|
|
49463
49463
|
if (!entry || typeof entry !== "object") continue;
|
|
49464
49464
|
const { id, label, contextLength } = read(entry);
|
|
@@ -50518,7 +50518,7 @@ function callCommand() {
|
|
|
50518
50518
|
// src/lib/runner/approval.ts
|
|
50519
50519
|
import { createHash as createHash6 } from "node:crypto";
|
|
50520
50520
|
import { chmod as chmod4, mkdir as mkdir9, readFile as readFile8, rename as rename3, writeFile as writeFile7 } from "node:fs/promises";
|
|
50521
|
-
import { join as join14 } from "node:path";
|
|
50521
|
+
import { dirname as dirname9, join as join14 } from "node:path";
|
|
50522
50522
|
|
|
50523
50523
|
// src/lib/runner/repo.ts
|
|
50524
50524
|
import { chmod as chmod3, mkdir as mkdir8, realpath as realpath2, writeFile as writeFile6 } from "node:fs/promises";
|
|
@@ -50648,11 +50648,12 @@ function worktreeGitBytes(layout, args, opts = {}) {
|
|
|
50648
50648
|
}
|
|
50649
50649
|
|
|
50650
50650
|
// src/lib/runner/text.ts
|
|
50651
|
+
var FORMAT = new RegExp("(?!\\u200d)\\p{Cf}", "gu");
|
|
50651
50652
|
function cleanLine(text3) {
|
|
50652
|
-
return text3.replace(/[\u0000-\u001f\u007f-\u009f]+/g, " ").trim();
|
|
50653
|
+
return text3.replace(FORMAT, "").replace(/[\u0000-\u001f\u007f-\u009f]+/g, " ").trim();
|
|
50653
50654
|
}
|
|
50654
50655
|
function cleanText(text3) {
|
|
50655
|
-
return text3.replace(/\r\n?/g, "\n").replace(/\t/g, " ").replace(/[\u0000-\u0009\u000b-\u001f\u007f-\u009f]+/g, " ");
|
|
50656
|
+
return text3.replace(FORMAT, "").replace(/\r\n?/g, "\n").replace(/\t/g, " ").replace(/[\u0000-\u0009\u000b-\u001f\u007f-\u009f]+/g, " ");
|
|
50656
50657
|
}
|
|
50657
50658
|
var PREVIEW_LINES = 3;
|
|
50658
50659
|
var PREVIEW_CHARS = 240;
|
|
@@ -50677,8 +50678,9 @@ function preview(text3) {
|
|
|
50677
50678
|
}
|
|
50678
50679
|
|
|
50679
50680
|
// src/lib/runner/sandbox.ts
|
|
50681
|
+
import { readdirSync } from "node:fs";
|
|
50680
50682
|
import { lstat, readFile as readFile7, realpath } from "node:fs/promises";
|
|
50681
|
-
import { dirname as dirname8, join as join12, resolve as resolve4 } from "node:path";
|
|
50683
|
+
import { basename as basename2, dirname as dirname8, join as join12, resolve as resolve4 } from "node:path";
|
|
50682
50684
|
var TASK_FILE = ".gad/task.md";
|
|
50683
50685
|
var CLAUDE_ALLOWED_DOMAINS = [
|
|
50684
50686
|
"api.anthropic.com",
|
|
@@ -50779,13 +50781,44 @@ var CLI_READ_HARDENING = [
|
|
|
50779
50781
|
".cargo/credentials.toml",
|
|
50780
50782
|
".terraform.d/credentials.tfrc.json"
|
|
50781
50783
|
];
|
|
50782
|
-
|
|
50783
|
-
|
|
50784
|
+
var CLI_ONLY_READ_HARDENING = ["Library/Keychains"];
|
|
50785
|
+
function runsDirOf(layout) {
|
|
50786
|
+
return dirname8(dirname8(dirname8(layout.worktree)));
|
|
50787
|
+
}
|
|
50788
|
+
function approvalsDir(layout) {
|
|
50789
|
+
return join12(dirname8(runsDirOf(layout)), "approvals");
|
|
50790
|
+
}
|
|
50791
|
+
function entries(dir) {
|
|
50792
|
+
try {
|
|
50793
|
+
return readdirSync(dir);
|
|
50794
|
+
} catch {
|
|
50795
|
+
return [];
|
|
50796
|
+
}
|
|
50797
|
+
}
|
|
50798
|
+
var UUID5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
50799
|
+
function siblingPaths(layout) {
|
|
50800
|
+
const wtDir = dirname8(layout.worktree);
|
|
50801
|
+
const runDir = dirname8(wtDir);
|
|
50802
|
+
const runsDir = dirname8(runDir);
|
|
50803
|
+
if (basename2(wtDir) !== "wt" || !UUID5.test(basename2(runDir))) return [];
|
|
50804
|
+
const others = (dir, keep) => entries(dir).map((name23) => join12(dir, name23)).filter((path10) => path10 !== keep);
|
|
50805
|
+
return [
|
|
50806
|
+
...others(runsDir, runDir),
|
|
50807
|
+
...others(runDir, wtDir),
|
|
50808
|
+
...others(wtDir, layout.worktree)
|
|
50809
|
+
];
|
|
50810
|
+
}
|
|
50811
|
+
function cliOnlyDenyRead(layout) {
|
|
50812
|
+
return [
|
|
50813
|
+
...CLI_ONLY_READ_HARDENING.map((rel) => join12(layout.home, rel)),
|
|
50814
|
+
approvalsDir(layout),
|
|
50815
|
+
...siblingPaths(layout)
|
|
50816
|
+
];
|
|
50784
50817
|
}
|
|
50785
50818
|
function denyRead(layout) {
|
|
50786
50819
|
return [
|
|
50787
50820
|
...CLI_READ_HARDENING.map((rel) => join12(layout.home, rel)),
|
|
50788
|
-
|
|
50821
|
+
...cliOnlyDenyRead(layout)
|
|
50789
50822
|
];
|
|
50790
50823
|
}
|
|
50791
50824
|
var CREDENTIAL_SET = new Set(
|
|
@@ -50925,14 +50958,14 @@ function kickoff(runId, todoId) {
|
|
|
50925
50958
|
}
|
|
50926
50959
|
|
|
50927
50960
|
// src/lib/runner/repo.ts
|
|
50928
|
-
var
|
|
50961
|
+
var UUID6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
50929
50962
|
var BRANCH_NAME = /^(?!-)(?!.*\.\.)[A-Za-z0-9._/-]+$/;
|
|
50930
50963
|
var GITHUB_REMOTE = /^(?:https?:\/\/(?:[^@/]+@)?github\.com\/|ssh:\/\/git@github\.com(?::\d+)?\/|git@github\.com:)([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?\/?$/;
|
|
50931
50964
|
function runsRoot() {
|
|
50932
50965
|
return join13(homedir10(), ".gad", "runs");
|
|
50933
50966
|
}
|
|
50934
50967
|
function isRunId(id) {
|
|
50935
|
-
return
|
|
50968
|
+
return UUID6.test(id);
|
|
50936
50969
|
}
|
|
50937
50970
|
var short = (id) => id.slice(0, 8);
|
|
50938
50971
|
function runnerBranch(runId, todoId) {
|
|
@@ -51043,9 +51076,12 @@ function sha256(text3) {
|
|
|
51043
51076
|
return createHash6("sha256").update(text3, "utf8").digest("hex");
|
|
51044
51077
|
}
|
|
51045
51078
|
var plainTitle = cleanLine;
|
|
51079
|
+
function approvalsDir2(runsDir) {
|
|
51080
|
+
return join14(dirname9(runsDir), "approvals");
|
|
51081
|
+
}
|
|
51046
51082
|
function approvedFile(runsDir, runId) {
|
|
51047
51083
|
if (!isRunId(runId)) throw new Error("run id must be a UUID");
|
|
51048
|
-
return join14(runsDir, runId
|
|
51084
|
+
return join14(approvalsDir2(runsDir), `${runId}.json`);
|
|
51049
51085
|
}
|
|
51050
51086
|
function approveShown(cards) {
|
|
51051
51087
|
return new Map(
|
|
@@ -51057,9 +51093,8 @@ function approveShown(cards) {
|
|
|
51057
51093
|
}
|
|
51058
51094
|
async function saveApproved(runsDir, runId, approved) {
|
|
51059
51095
|
const file2 = approvedFile(runsDir, runId);
|
|
51060
|
-
const dir =
|
|
51096
|
+
const dir = approvalsDir2(runsDir);
|
|
51061
51097
|
await mkdir9(dir, { recursive: true, mode: 448 });
|
|
51062
|
-
await chmod4(runsDir, 448);
|
|
51063
51098
|
await chmod4(dir, 448);
|
|
51064
51099
|
const body = [...approved].map(([todoId, c]) => ({ todoId, ...c }));
|
|
51065
51100
|
const tmp = `${file2}.tmp`;
|
|
@@ -51161,13 +51196,19 @@ async function workCard(deps, todoId, card) {
|
|
|
51161
51196
|
if (ran.exit !== 0)
|
|
51162
51197
|
return { outcome: "failed", detail: `agent_exit_${ran.exit ?? "signal"}` };
|
|
51163
51198
|
const result = await deps.publish(prepared, todoId, card.title, deps.signal).catch(() => ({ failed: "publish_failed" }));
|
|
51164
|
-
|
|
51199
|
+
const takeBack = (sha) => () => deps.unpublish(prepared, sha).catch(() => false);
|
|
51200
|
+
if (deps.signal.aborted) {
|
|
51201
|
+
if (typeof result === "object" && "pushed" in result)
|
|
51202
|
+
await sayTakenBack(deps, prepared.branch, takeBack(result.pushed));
|
|
51203
|
+
return { outcome: "stopped" };
|
|
51204
|
+
}
|
|
51165
51205
|
if (result === "no_changes") return { outcome: "no_changes" };
|
|
51166
51206
|
if ("pushed" in result)
|
|
51167
51207
|
return {
|
|
51168
51208
|
outcome: "pushed",
|
|
51169
51209
|
branch: prepared.branch,
|
|
51170
|
-
headSha: result.pushed
|
|
51210
|
+
headSha: result.pushed,
|
|
51211
|
+
takeBack: takeBack(result.pushed)
|
|
51171
51212
|
};
|
|
51172
51213
|
return {
|
|
51173
51214
|
outcome: "failed",
|
|
@@ -51177,6 +51218,12 @@ async function workCard(deps, todoId, card) {
|
|
|
51177
51218
|
} : {}
|
|
51178
51219
|
};
|
|
51179
51220
|
}
|
|
51221
|
+
async function sayTakenBack(deps, branch, takeBack) {
|
|
51222
|
+
if (!await takeBack())
|
|
51223
|
+
deps.print(
|
|
51224
|
+
` Could not delete the pushed branch ${branch}; delete it on GitHub if you do not want it.`
|
|
51225
|
+
);
|
|
51226
|
+
}
|
|
51180
51227
|
function reportFields(o) {
|
|
51181
51228
|
if (o.outcome === "pushed")
|
|
51182
51229
|
return { outcome: o.outcome, branch: o.branch, head_sha: o.headSha };
|
|
@@ -51289,6 +51336,8 @@ async function runLoop(deps, input2) {
|
|
|
51289
51336
|
if (!(error62 instanceof RunnerCallError && error62.code === "card_released"))
|
|
51290
51337
|
throw error62;
|
|
51291
51338
|
deps.print(`${label} \u2026 taken back on the board`);
|
|
51339
|
+
if (outcome.outcome === "pushed")
|
|
51340
|
+
await sayTakenBack(deps, outcome.branch, outcome.takeBack);
|
|
51292
51341
|
continue;
|
|
51293
51342
|
} finally {
|
|
51294
51343
|
if (claimed) await release(deps, next.todoId);
|
|
@@ -51650,7 +51699,7 @@ async function reapGroup(pgid, waitMs = REAP_WAIT_MS) {
|
|
|
51650
51699
|
|
|
51651
51700
|
// src/lib/runner/holders.ts
|
|
51652
51701
|
import { execFile as execFile5 } from "node:child_process";
|
|
51653
|
-
import { readdirSync, readlinkSync, statSync as statSync2 } from "node:fs";
|
|
51702
|
+
import { readdirSync as readdirSync2, readlinkSync, statSync as statSync2 } from "node:fs";
|
|
51654
51703
|
var LSOF_DEADLINE_MS = 2e4;
|
|
51655
51704
|
var CHECKS = 5;
|
|
51656
51705
|
var PAUSE_MS = 250;
|
|
@@ -51763,15 +51812,15 @@ async function lsofUsers(root, uid, exec2 = run3) {
|
|
|
51763
51812
|
return users;
|
|
51764
51813
|
}
|
|
51765
51814
|
var errno = (error62) => error62.code;
|
|
51766
|
-
function procUsers(root, uid, fs6 = { readdirSync, statSync: statSync2, readlinkSync }) {
|
|
51767
|
-
let
|
|
51815
|
+
function procUsers(root, uid, fs6 = { readdirSync: readdirSync2, statSync: statSync2, readlinkSync }) {
|
|
51816
|
+
let entries2;
|
|
51768
51817
|
try {
|
|
51769
|
-
|
|
51818
|
+
entries2 = fs6.readdirSync("/proc").filter((e) => /^\d+$/.test(e));
|
|
51770
51819
|
} catch {
|
|
51771
51820
|
return null;
|
|
51772
51821
|
}
|
|
51773
51822
|
const users = [];
|
|
51774
|
-
for (const pid of
|
|
51823
|
+
for (const pid of entries2) {
|
|
51775
51824
|
try {
|
|
51776
51825
|
if (fs6.statSync(`/proc/${pid}`).uid !== uid) continue;
|
|
51777
51826
|
} catch (error62) {
|
|
@@ -52277,6 +52326,17 @@ async function publishBranch(layout, branch, base, message, signal, options = {}
|
|
|
52277
52326
|
throw error62;
|
|
52278
52327
|
}
|
|
52279
52328
|
}
|
|
52329
|
+
async function unpublishBranch(layout, branch, sha) {
|
|
52330
|
+
if (!RUNNER_BRANCH.test(branch) || !SHA.test(sha)) return false;
|
|
52331
|
+
const push = await worktreeGit(layout, [
|
|
52332
|
+
"push",
|
|
52333
|
+
"--quiet",
|
|
52334
|
+
`--force-with-lease=refs/heads/${branch}:${sha}`,
|
|
52335
|
+
"origin",
|
|
52336
|
+
`:refs/heads/${branch}`
|
|
52337
|
+
]);
|
|
52338
|
+
return push.code === 0;
|
|
52339
|
+
}
|
|
52280
52340
|
|
|
52281
52341
|
// src/commands/board-run.ts
|
|
52282
52342
|
function parseData(result) {
|
|
@@ -52383,6 +52443,7 @@ var work = ({
|
|
|
52383
52443
|
commitMessage(title, view.runId, todoId),
|
|
52384
52444
|
signal
|
|
52385
52445
|
),
|
|
52446
|
+
unpublish: (prepared, headSha2) => unpublishBranch(prepared, prepared.branch, headSha2),
|
|
52386
52447
|
sleep: sleep2,
|
|
52387
52448
|
note: (todoId, line) => {
|
|
52388
52449
|
try {
|
|
@@ -52805,7 +52866,7 @@ import {
|
|
|
52805
52866
|
writeFile as writeFile9
|
|
52806
52867
|
} from "node:fs/promises";
|
|
52807
52868
|
import { homedir as homedir11 } from "node:os";
|
|
52808
|
-
import { basename as
|
|
52869
|
+
import { basename as basename3, dirname as dirname10, isAbsolute as isAbsolute4, join as join18, relative as relative2, sep } from "node:path";
|
|
52809
52870
|
var GH_APPLY_TIMEOUT_MS = 3e4;
|
|
52810
52871
|
var GIT_APPLY_TIMEOUT_MS = 3e4;
|
|
52811
52872
|
function runWithStdin(file2, args, input2, timeoutMs) {
|
|
@@ -52962,7 +53023,7 @@ async function applySshKey(path10, privatePem) {
|
|
|
52962
53023
|
const content = privatePem.endsWith("\n") ? privatePem : `${privatePem}
|
|
52963
53024
|
`;
|
|
52964
53025
|
try {
|
|
52965
|
-
await mkdir10(
|
|
53026
|
+
await mkdir10(dirname10(file2), { recursive: true, mode: 448 });
|
|
52966
53027
|
await writeAtomic(file2, content, 384);
|
|
52967
53028
|
} catch {
|
|
52968
53029
|
return { ok: false, code: "ssh_write_failed" };
|
|
@@ -52983,14 +53044,14 @@ var SSH_NOT_A_KEY = /* @__PURE__ */ new Set([
|
|
|
52983
53044
|
async function sshTargetRefusal(path10, sshDir = join18(homedir11(), ".ssh")) {
|
|
52984
53045
|
const file2 = expandHome(path10);
|
|
52985
53046
|
if (!isAbsolute4(file2)) return { ok: false, code: "target_invalid" };
|
|
52986
|
-
if (SSH_NOT_A_KEY.has(
|
|
53047
|
+
if (SSH_NOT_A_KEY.has(basename3(file2))) {
|
|
52987
53048
|
return { ok: false, code: "target_not_a_key" };
|
|
52988
53049
|
}
|
|
52989
53050
|
let root;
|
|
52990
53051
|
let parent;
|
|
52991
53052
|
try {
|
|
52992
53053
|
root = await realpath3(sshDir);
|
|
52993
|
-
parent = await realpath3(
|
|
53054
|
+
parent = await realpath3(dirname10(file2));
|
|
52994
53055
|
} catch {
|
|
52995
53056
|
return { ok: false, code: "target_outside_ssh_dir" };
|
|
52996
53057
|
}
|
|
@@ -53145,7 +53206,7 @@ var REPORT_KEY = /^[A-Z_][A-Z0-9_]{0,127}$/;
|
|
|
53145
53206
|
var REPORT_PATH = /^[ -~]{1,200}$/;
|
|
53146
53207
|
var TOKEN_SHAPED = /[A-Za-z0-9]{33,}/;
|
|
53147
53208
|
var SECRET_PREFIX = /(gh[pousr]_|github_pat_|-----BEGIN)/;
|
|
53148
|
-
var
|
|
53209
|
+
var UUID7 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
53149
53210
|
function deviceSlot(workspaceId) {
|
|
53150
53211
|
return `key-rotation-device:${workspaceId}`;
|
|
53151
53212
|
}
|
|
@@ -53323,7 +53384,7 @@ async function enroll(client2, workspaceId, opts = {}) {
|
|
|
53323
53384
|
publicKey: pair.publicKey,
|
|
53324
53385
|
report
|
|
53325
53386
|
});
|
|
53326
|
-
const enrollmentId = typeof begun?.enrollmentId === "string" &&
|
|
53387
|
+
const enrollmentId = typeof begun?.enrollmentId === "string" && UUID7.test(begun.enrollmentId) ? begun.enrollmentId : null;
|
|
53327
53388
|
if (!enrollmentId) {
|
|
53328
53389
|
throw new CliError(
|
|
53329
53390
|
"The server did not start the enrollment.",
|
|
@@ -53341,7 +53402,7 @@ async function enroll(client2, workspaceId, opts = {}) {
|
|
|
53341
53402
|
action: "enroll",
|
|
53342
53403
|
approvalToken
|
|
53343
53404
|
});
|
|
53344
|
-
const deviceId = typeof done?.deviceId === "string" &&
|
|
53405
|
+
const deviceId = typeof done?.deviceId === "string" && UUID7.test(done.deviceId) ? done.deviceId : null;
|
|
53345
53406
|
if (!deviceId) {
|
|
53346
53407
|
throw new CliError(
|
|
53347
53408
|
"The server did not complete the enrollment.",
|
|
@@ -53370,7 +53431,7 @@ async function enroll(client2, workspaceId, opts = {}) {
|
|
|
53370
53431
|
}
|
|
53371
53432
|
|
|
53372
53433
|
// src/commands/keys.ts
|
|
53373
|
-
var
|
|
53434
|
+
var UUID8 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
53374
53435
|
function patRequired(apiUrl) {
|
|
53375
53436
|
return authError(
|
|
53376
53437
|
"gad keys needs a personal access token; this sign-in is an OAuth session.",
|
|
@@ -53423,7 +53484,7 @@ async function keysContext() {
|
|
|
53423
53484
|
});
|
|
53424
53485
|
const value = await probe.mcpCall("workspace_introspect", {}, 5e3);
|
|
53425
53486
|
const workspaceId = value?.workspace?.id;
|
|
53426
|
-
if (value?.error || !workspaceId || !
|
|
53487
|
+
if (value?.error || !workspaceId || !UUID8.test(workspaceId)) {
|
|
53427
53488
|
throw validationError(
|
|
53428
53489
|
"GreatArrow.ai could not confirm your workspace.",
|
|
53429
53490
|
"Run 'gad whoami', or choose one with 'gad --workspace <id>'."
|
|
@@ -53444,7 +53505,7 @@ async function keysContext() {
|
|
|
53444
53505
|
};
|
|
53445
53506
|
}
|
|
53446
53507
|
function requireRunId(runId) {
|
|
53447
|
-
if (!
|
|
53508
|
+
if (!UUID8.test(runId)) {
|
|
53448
53509
|
throw validationError(
|
|
53449
53510
|
`'${stripControlChars(runId)}' is not a run id.`,
|
|
53450
53511
|
"Copy the run id from 'gad keys list' or the run page."
|
|
@@ -53573,7 +53634,7 @@ function enrollCommand() {
|
|
|
53573
53634
|
function toUpdateRow(v) {
|
|
53574
53635
|
if (typeof v !== "object" || v === null) return null;
|
|
53575
53636
|
const r = v;
|
|
53576
|
-
if (typeof r.id !== "string" || !
|
|
53637
|
+
if (typeof r.id !== "string" || !UUID8.test(r.id)) return null;
|
|
53577
53638
|
const ref = {};
|
|
53578
53639
|
if (typeof r.targetRef === "object" && r.targetRef !== null) {
|
|
53579
53640
|
for (const [k, val] of Object.entries(r.targetRef)) {
|
|
@@ -54460,14 +54521,14 @@ var Temp = {
|
|
|
54460
54521
|
}
|
|
54461
54522
|
},
|
|
54462
54523
|
truncate: (filePath) => {
|
|
54463
|
-
const
|
|
54464
|
-
if (
|
|
54524
|
+
const basename4 = path3.basename(filePath);
|
|
54525
|
+
if (basename4.length <= LIMIT_BASENAME_LENGTH)
|
|
54465
54526
|
return filePath;
|
|
54466
|
-
const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(
|
|
54527
|
+
const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(basename4);
|
|
54467
54528
|
if (!truncable)
|
|
54468
54529
|
return filePath;
|
|
54469
|
-
const truncationLength =
|
|
54470
|
-
return `${filePath.slice(0, -
|
|
54530
|
+
const truncationLength = basename4.length - LIMIT_BASENAME_LENGTH;
|
|
54531
|
+
return `${filePath.slice(0, -basename4.length)}${truncable[1]}${truncable[2].slice(0, -truncationLength)}${truncable[3]}`;
|
|
54471
54532
|
}
|
|
54472
54533
|
};
|
|
54473
54534
|
node_default(Temp.purgeSyncAll);
|