@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.
Files changed (2) hide show
  1. package/dist/index.js +140 -79
  2. 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 dirname10 = path10.dirname(name24);
3343
- if (dirname10 === name24) {
3342
+ const dirname11 = path10.dirname(name24);
3343
+ if (dirname11 === name24) {
3344
3344
  return original;
3345
3345
  }
3346
- return find(dirname10, original);
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.4";
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 entries = [];
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
- entries.push({
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 entries;
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 entries = [];
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
- entries.push({
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 entries;
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(entries) {
15852
+ function detectDuplicates(entries2) {
15853
15853
  const byClient = /* @__PURE__ */ new Map();
15854
- for (const entry of entries) {
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(entries) {
15882
- const hasLocalClaude = entries.some(
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 entries = Array.isArray(data) ? data : [];
17574
- if (entries.length === 0) {
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 entries) {
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 entries = [];
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
- entries.push(
17929
+ entries2.push(
17930
17930
  ...findGreatArrowEntries(location, content, { hooksInstalled })
17931
17931
  );
17932
17932
  }
17933
- return entries;
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 entries = await scanConnections();
18019
- const duplicates = detectDuplicates(entries);
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 (entries.length === 0) {
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(entries);
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 (entries.length === 0) {
18087
+ if (entries2.length === 0) {
18088
18088
  process.stdout.write(" (none found)\n");
18089
18089
  }
18090
- for (const entry of entries) {
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(entries) {
21013
- const numericValues = Object.values(entries).filter((v) => typeof v === "number");
21014
- const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v);
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 entries;
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
- entries ?? (entries = Reflect.ownKeys(def.shape).map((key) => [key, def.shape[key]]));
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 entries) {
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 entries = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values;
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, entries, params) {
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 entries = Array.isArray(values) ? Object.fromEntries(values.map((v) => [v, v])) : values;
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(entries, params) {
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(entries, read) {
49458
- if (!Array.isArray(entries)) return [];
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 entries) {
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
- function approvalFile(layout) {
50783
- return join12(dirname8(dirname8(layout.worktree)), "approved.json");
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
- approvalFile(layout)
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 UUID5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
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 UUID5.test(id);
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, "approved.json");
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 = join14(runsDir, runId);
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
- if (deps.signal.aborted) return { outcome: "stopped" };
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 entries;
51815
+ function procUsers(root, uid, fs6 = { readdirSync: readdirSync2, statSync: statSync2, readlinkSync }) {
51816
+ let entries2;
51768
51817
  try {
51769
- entries = fs6.readdirSync("/proc").filter((e) => /^\d+$/.test(e));
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 entries) {
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 basename2, dirname as dirname9, isAbsolute as isAbsolute4, join as join18, relative as relative2, sep } from "node:path";
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(dirname9(file2), { recursive: true, mode: 448 });
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(basename2(file2))) {
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(dirname9(file2));
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 UUID6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
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" && UUID6.test(begun.enrollmentId) ? begun.enrollmentId : null;
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" && UUID6.test(done.deviceId) ? done.deviceId : null;
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 UUID7 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
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 || !UUID7.test(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 (!UUID7.test(runId)) {
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" || !UUID7.test(r.id)) return null;
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 basename3 = path3.basename(filePath);
54464
- if (basename3.length <= LIMIT_BASENAME_LENGTH)
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(basename3);
54527
+ const truncable = /^(\.?)(.*?)((?:\.[^.]+)?(?:\.tmp-\d{10}[a-f0-9]{6})?)$/.exec(basename4);
54467
54528
  if (!truncable)
54468
54529
  return filePath;
54469
- const truncationLength = basename3.length - LIMIT_BASENAME_LENGTH;
54470
- return `${filePath.slice(0, -basename3.length)}${truncable[1]}${truncable[2].slice(0, -truncationLength)}${truncable[3]}`;
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@great-arrow/cli",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "GreatArrow.ai CLI tool",
5
5
  "type": "module",
6
6
  "bin": {