@great-arrow/cli 0.6.5 → 0.7.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.
Files changed (2) hide show
  1. package/dist/index.js +250 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -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.6.5";
9486
+ var CLI_VERSION = "0.7.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";
@@ -10965,11 +10965,11 @@ var EXIT_SESSION_EXPIRED = 2;
10965
10965
  var EXIT_NOT_OAUTH = 3;
10966
10966
  function authCommand() {
10967
10967
  const cmd = new Command("auth").description("Authentication helpers");
10968
- cmd.command("token").description("Print a fresh OAuth access token, refreshing it if needed").option("--json", "Output {accessToken, accessExpiresAt, apiUrl} as JSON").action(async (options, actionCommand) => {
10968
+ cmd.command("token").description("Print a fresh OAuth access token, refreshing it if needed").option("--json", "Output {accessToken, accessExpiresAt, apiUrl} as JSON").action(async (options, actionCommand2) => {
10969
10969
  try {
10970
10970
  const t = await getFreshOAuthAccessToken();
10971
10971
  writeCliLocator();
10972
- const jsonOutput = options.json || actionCommand.optsWithGlobals().json;
10972
+ const jsonOutput = options.json || actionCommand2.optsWithGlobals().json;
10973
10973
  process.stdout.write(
10974
10974
  jsonOutput ? `${JSON.stringify(t)}
10975
10975
  ` : `${t.accessToken}
@@ -40894,9 +40894,9 @@ var ZodString2 = class _ZodString2 extends ZodType2 {
40894
40894
  }
40895
40895
  return { status: status.value, value: input2.data };
40896
40896
  }
40897
- _regex(regex2, validation, message) {
40897
+ _regex(regex2, validation2, message) {
40898
40898
  return this.refinement((data) => regex2.test(data), {
40899
- validation,
40899
+ validation: validation2,
40900
40900
  code: ZodIssueCode2.invalid_string,
40901
40901
  ...errorUtil.errToObj(message)
40902
40902
  });
@@ -50236,6 +50236,248 @@ function callCommand() {
50236
50236
  });
50237
50237
  }
50238
50238
 
50239
+ // src/commands/board.ts
50240
+ var TOOL = "board_autopilot";
50241
+ function asObject4(json3) {
50242
+ if (!json3.startsWith("{")) return null;
50243
+ try {
50244
+ const data = JSON.parse(json3);
50245
+ return data && typeof data === "object" && !Array.isArray(data) ? data : null;
50246
+ } catch (error62) {
50247
+ void error62;
50248
+ return null;
50249
+ }
50250
+ }
50251
+ function parseToolResult(result) {
50252
+ if (result && typeof result === "object" && !Array.isArray(result)) {
50253
+ return { text: "", data: result };
50254
+ }
50255
+ if (typeof result !== "string") return { text: "", data: null };
50256
+ const cut = result.lastIndexOf("\n");
50257
+ const tail = result.slice(cut + 1).trim();
50258
+ const candidates = [
50259
+ [result.slice(0, Math.max(cut, 0)), tail],
50260
+ ["", result.trim()]
50261
+ ];
50262
+ for (const [text3, json3] of candidates) {
50263
+ const data = asObject4(json3);
50264
+ if (data) return { text: text3, data };
50265
+ }
50266
+ return { text: result, data: null };
50267
+ }
50268
+ function validation(message, hint) {
50269
+ return new CliError(message, 3 /* VALIDATION_ERROR */, hint);
50270
+ }
50271
+ function hostedP90(plan) {
50272
+ const q = plan?.quotes?.find((x) => x.executor === "hosted");
50273
+ return typeof q?.p90Usd === "number" ? q.p90Usd : null;
50274
+ }
50275
+ function buildStartArgs(runId, plan, opts) {
50276
+ if (!opts.healthUrl)
50277
+ throw validation(
50278
+ "--yes needs --health-url <url>.",
50279
+ "The run watches this URL after every merge and rolls back when it fails."
50280
+ );
50281
+ if (!opts.versionUrl)
50282
+ throw validation(
50283
+ "--yes needs --version-url <url>.",
50284
+ "The run reads the serving version here to know a merge reached production."
50285
+ );
50286
+ let cap;
50287
+ if (opts.cap !== void 0) {
50288
+ cap = Number(opts.cap);
50289
+ if (!Number.isFinite(cap) || cap <= 0)
50290
+ throw validation("--cap must be a positive dollar amount.");
50291
+ } else {
50292
+ cap = hostedP90(plan);
50293
+ }
50294
+ if (cap === null)
50295
+ throw validation(
50296
+ "The plan carried no hosted quote to default the cap from.",
50297
+ "Pass --cap <usd>."
50298
+ );
50299
+ if (cap <= 0)
50300
+ throw validation(
50301
+ "The hosted quote is $0, so there is no cap to default to.",
50302
+ "Pass --cap <usd>."
50303
+ );
50304
+ const rejected = new Set(opts.reject ?? []);
50305
+ if (plan?.findings) {
50306
+ const known = new Set(plan.findings.map((f) => f.id));
50307
+ const unknown2 = [...rejected].filter((id) => !known.has(id));
50308
+ if (unknown2.length > 0)
50309
+ throw validation(
50310
+ `--reject: unknown finding id(s): ${unknown2.join(", ")}.`,
50311
+ "Run without --yes to list finding ids."
50312
+ );
50313
+ }
50314
+ const args = {
50315
+ action: "start",
50316
+ run_id: runId,
50317
+ accepted_finding_ids: (plan?.findings ?? []).map((f) => f.id).filter((id) => !rejected.has(id)),
50318
+ cap_usd: cap,
50319
+ notify: { email: opts.email !== false, push: opts.push !== false },
50320
+ health_check_url: opts.healthUrl,
50321
+ version_url: opts.versionUrl
50322
+ };
50323
+ if (opts.types)
50324
+ args.card_types = opts.types.split(",").map((t) => t.trim()).filter(Boolean);
50325
+ return args;
50326
+ }
50327
+ async function callBoard(client2, args) {
50328
+ let result;
50329
+ try {
50330
+ result = await client2.mcpCall("gad_call", gadCallArgs(TOOL, args));
50331
+ } catch (error62) {
50332
+ if (!(error62 instanceof McpToolError)) throw error62;
50333
+ throw validation(`${TOOL}: ${error62.message}`, error62.hint);
50334
+ }
50335
+ const failure2 = callFailure(result);
50336
+ if (failure2) {
50337
+ throw new CliError(
50338
+ `${TOOL}: ${failure2.message}`,
50339
+ failure2.code === "feature_disabled" || failure2.code === "insufficient_scope" ? 1 /* AUTH_ERROR */ : 3 /* VALIDATION_ERROR */
50340
+ );
50341
+ }
50342
+ return result;
50343
+ }
50344
+ function printPlan(fmt, plan) {
50345
+ const row = (r) => r;
50346
+ const f = plan.findings ?? [];
50347
+ const c = plan.cards ?? [];
50348
+ const q = plan.quotes ?? [];
50349
+ process.stdout.write(`
50350
+ Board cleanups (${f.length})
50351
+ `);
50352
+ fmt.table(f.map(row), [
50353
+ { key: "id", header: "Finding" },
50354
+ { key: "kind", header: "Kind" },
50355
+ { key: "todoId", header: "Card" }
50356
+ ]);
50357
+ process.stdout.write(`
50358
+ Cards (${c.length})
50359
+ `);
50360
+ fmt.table(
50361
+ c.map((x) => row({ ...x, completable: x.completable ? "yes" : "no" })),
50362
+ [
50363
+ { key: "title", header: "Title" },
50364
+ { key: "type", header: "Type" },
50365
+ { key: "completable", header: "Runs alone" },
50366
+ { key: "reason", header: "Why" }
50367
+ ]
50368
+ );
50369
+ process.stdout.write("\nQuotes (USD)\n");
50370
+ fmt.table(
50371
+ q.map(
50372
+ (x) => row({
50373
+ ...x,
50374
+ status: x.available ? "available" : x.comingSoon ? "soon" : "n/a"
50375
+ })
50376
+ ),
50377
+ [
50378
+ { key: "label", header: "Executor" },
50379
+ { key: "status", header: "Status" },
50380
+ { key: "p50Usd", header: "p50" },
50381
+ { key: "p90Usd", header: "p90" }
50382
+ ]
50383
+ );
50384
+ }
50385
+ function makeFormatter(command) {
50386
+ const g = globalOutputOpts(command);
50387
+ return {
50388
+ g,
50389
+ fmt: createFormatter({
50390
+ json: g.json,
50391
+ quiet: g.quiet,
50392
+ isTTY: isTTY(),
50393
+ noColor: g.noColor
50394
+ })
50395
+ };
50396
+ }
50397
+ async function makeClient() {
50398
+ const auth = await resolveAuth();
50399
+ return new GadClient({
50400
+ token: auth.token,
50401
+ getToken: auth.getToken,
50402
+ apiUrl: auth.apiUrl
50403
+ });
50404
+ }
50405
+ function emit(result, json3, quiet = false) {
50406
+ const { text: text3, data } = parseToolResult(result);
50407
+ if (json3) {
50408
+ process.stdout.write(
50409
+ `${typeof result === "string" ? result : JSON.stringify(result)}
50410
+ `
50411
+ );
50412
+ } else if (text3 && !quiet) {
50413
+ process.stdout.write(`${text3}
50414
+ `);
50415
+ }
50416
+ return data;
50417
+ }
50418
+ async function runClear(opts, command) {
50419
+ if (opts.yes)
50420
+ buildStartArgs(
50421
+ "pending",
50422
+ { quotes: [{ executor: "hosted", p90Usd: 1 }] },
50423
+ opts
50424
+ );
50425
+ const { g, fmt } = makeFormatter(command);
50426
+ const client2 = await makeClient();
50427
+ const planResult = await callBoard(client2, {
50428
+ action: "plan",
50429
+ ...opts.goal ? { goal_id: opts.goal } : {}
50430
+ });
50431
+ const data = emit(planResult, g.json && !opts.yes, g.quiet);
50432
+ const run4 = data?.run ?? null;
50433
+ if (!g.json && !g.quiet && run4?.plan) printPlan(fmt, run4.plan);
50434
+ if (!opts.yes) {
50435
+ if (!g.json && !g.quiet && run4?.id)
50436
+ process.stdout.write(
50437
+ `
50438
+ Nothing has changed. Start with: gad board clear${opts.goal ? ` --goal ${opts.goal}` : ""} --yes --health-url <url> --version-url <url>
50439
+ `
50440
+ );
50441
+ return;
50442
+ }
50443
+ if (!run4?.id) throw validation("The plan reply carried no run id.");
50444
+ const startResult = await callBoard(
50445
+ client2,
50446
+ buildStartArgs(run4.id, run4.plan, opts)
50447
+ );
50448
+ emit(startResult, g.json, g.quiet);
50449
+ }
50450
+ function actionCommand(action) {
50451
+ 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) => {
50452
+ if (action !== "status" && !opts.run)
50453
+ throw validation(`${action} needs --run <id>.`);
50454
+ if (opts.card && action !== "undo")
50455
+ throw validation("--card only applies to undo.");
50456
+ const { g } = makeFormatter(command);
50457
+ const client2 = await makeClient();
50458
+ const result = await callBoard(client2, {
50459
+ action,
50460
+ ...opts.run ? { run_id: opts.run } : {},
50461
+ ...opts.card ? { card_id: opts.card } : {}
50462
+ });
50463
+ emit(result, g.json, g.quiet);
50464
+ });
50465
+ }
50466
+ function boardCommand() {
50467
+ const clear = new Command("clear").description("Preview, start, watch, stop or undo a clear-the-board run").option("--goal <id>", "Limit the run to one Goal").option("--yes", "Start the run after planning").option("--health-url <url>", "URL probed after each merge (needs --yes)").option(
50468
+ "--version-url <url>",
50469
+ "URL that reports the serving sha (needs --yes)"
50470
+ ).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(
50471
+ "--reject <findingId...>",
50472
+ "Finding ids to leave out of the accepted set"
50473
+ ).option("--json", "Output the raw tool result");
50474
+ clear.action(runClear);
50475
+ clear.addCommand(actionCommand("status"));
50476
+ clear.addCommand(actionCommand("stop"));
50477
+ clear.addCommand(actionCommand("undo"));
50478
+ return new Command("board").description("Clear the board: tidy cards and run the safe ones").addCommand(clear);
50479
+ }
50480
+
50239
50481
  // src/commands/keys.ts
50240
50482
  import { createInterface as createInterface3 } from "node:readline";
50241
50483
  import { Writable } from "node:stream";
@@ -55061,8 +55303,8 @@ var program2 = new Command().name("gad").description("Great Arrow Digital CLI \u
55061
55303
  );
55062
55304
  program2.hook(
55063
55305
  "preAction",
55064
- async (_thisCommand, actionCommand) => {
55065
- const options = actionCommand.optsWithGlobals();
55306
+ async (_thisCommand, actionCommand2) => {
55307
+ const options = actionCommand2.optsWithGlobals();
55066
55308
  const config2 = await loadConfig();
55067
55309
  setCommandWorkspaceTarget(options.workspace, config2.default_workspace);
55068
55310
  }
@@ -55082,6 +55324,7 @@ program2.addCommand(todo_default);
55082
55324
  program2.addCommand(nextCommand());
55083
55325
  program2.addCommand(discoverCommand());
55084
55326
  program2.addCommand(callCommand());
55327
+ program2.addCommand(boardCommand());
55085
55328
  program2.addCommand(claim_default);
55086
55329
  program2.addCommand(work_default());
55087
55330
  program2.addCommand(worktree_default);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@great-arrow/cli",
3
- "version": "0.6.5",
3
+ "version": "0.7.0",
4
4
  "description": "GreatArrow.ai CLI tool",
5
5
  "type": "module",
6
6
  "bin": {