@great-arrow/cli 0.10.4 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +216 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4031,11 +4031,11 @@ var require_clean = __commonJS({
|
|
|
4031
4031
|
"node_modules/.pnpm/semver@7.8.1/node_modules/semver/functions/clean.js"(exports, module) {
|
|
4032
4032
|
"use strict";
|
|
4033
4033
|
var parse3 = require_parse();
|
|
4034
|
-
var
|
|
4034
|
+
var clean3 = (version2, options) => {
|
|
4035
4035
|
const s2 = parse3(version2.trim().replace(/^[=v]+/, ""), options);
|
|
4036
4036
|
return s2 ? s2.version : null;
|
|
4037
4037
|
};
|
|
4038
|
-
module.exports =
|
|
4038
|
+
module.exports = clean3;
|
|
4039
4039
|
}
|
|
4040
4040
|
});
|
|
4041
4041
|
|
|
@@ -5363,7 +5363,7 @@ var require_semver2 = __commonJS({
|
|
|
5363
5363
|
var identifiers = require_identifiers();
|
|
5364
5364
|
var parse3 = require_parse();
|
|
5365
5365
|
var valid = require_valid();
|
|
5366
|
-
var
|
|
5366
|
+
var clean3 = require_clean();
|
|
5367
5367
|
var inc = require_inc();
|
|
5368
5368
|
var diff = require_diff();
|
|
5369
5369
|
var major = require_major();
|
|
@@ -5402,7 +5402,7 @@ var require_semver2 = __commonJS({
|
|
|
5402
5402
|
module.exports = {
|
|
5403
5403
|
parse: parse3,
|
|
5404
5404
|
valid,
|
|
5405
|
-
clean:
|
|
5405
|
+
clean: clean3,
|
|
5406
5406
|
inc,
|
|
5407
5407
|
diff,
|
|
5408
5408
|
major,
|
|
@@ -10011,7 +10011,7 @@ async function clearStoredCredential() {
|
|
|
10011
10011
|
|
|
10012
10012
|
// src/lib/version.ts
|
|
10013
10013
|
var CLI_PACKAGE_NAME = "@great-arrow/cli";
|
|
10014
|
-
var CLI_VERSION = "0.
|
|
10014
|
+
var CLI_VERSION = "0.11.2";
|
|
10015
10015
|
var GAD_INSTALL_VERSION = "2026.08.08";
|
|
10016
10016
|
var GAD_INSTALL_MIN_VERSION = "2026.06.22";
|
|
10017
10017
|
var GAD_INSTALL_HEADER = "X-GAD-Install-Version";
|
|
@@ -32522,8 +32522,8 @@ function readStdin(stream) {
|
|
|
32522
32522
|
// src/lib/sources.ts
|
|
32523
32523
|
function nonEmpty2(value) {
|
|
32524
32524
|
if (typeof value !== "string") return null;
|
|
32525
|
-
const
|
|
32526
|
-
return
|
|
32525
|
+
const clean3 = stripControlChars(value).trim();
|
|
32526
|
+
return clean3 === "" ? null : clean3;
|
|
32527
32527
|
}
|
|
32528
32528
|
function httpUrl2(value) {
|
|
32529
32529
|
const raw = nonEmpty2(value);
|
|
@@ -38604,6 +38604,82 @@ var agentsCommand = new Command("agents").description(
|
|
|
38604
38604
|
process.stdout.write(renderAgentsNow(result) + "\n");
|
|
38605
38605
|
});
|
|
38606
38606
|
|
|
38607
|
+
// src/commands/ci-status.ts
|
|
38608
|
+
function ciStatusParams(pr, opts) {
|
|
38609
|
+
return {
|
|
38610
|
+
...opts.repo ? { repo: opts.repo } : {},
|
|
38611
|
+
...pr ? { pr } : {},
|
|
38612
|
+
...opts.branch ? { branch: opts.branch } : {},
|
|
38613
|
+
...opts.sha ? { sha: opts.sha } : {},
|
|
38614
|
+
...opts.queue ? { queue: "1" } : {}
|
|
38615
|
+
};
|
|
38616
|
+
}
|
|
38617
|
+
var clean = (v) => stripControlChars(String(v ?? ""));
|
|
38618
|
+
function ageOf(iso, now) {
|
|
38619
|
+
const min = Math.max(0, Math.round((now - Date.parse(iso)) / 6e4));
|
|
38620
|
+
return min < 1 ? "<1m ago" : `${min}m ago`;
|
|
38621
|
+
}
|
|
38622
|
+
function checkMark(c) {
|
|
38623
|
+
if (c.status !== "completed") return c.status;
|
|
38624
|
+
return c.conclusion ?? "completed";
|
|
38625
|
+
}
|
|
38626
|
+
function renderCiStatus(s2, now = Date.now()) {
|
|
38627
|
+
const lines = [];
|
|
38628
|
+
const head = s2.asOf ? `Board as of ${ageOf(s2.asOf, now)}: ${s2.verdict}` : `Board is empty: ${s2.verdict}`;
|
|
38629
|
+
lines.push(s2.reason ? `${head} (${clean(s2.reason)})` : head);
|
|
38630
|
+
if (s2.verdict === "unverified")
|
|
38631
|
+
lines.push("Verify on GitHub before acting on this.");
|
|
38632
|
+
const checks = s2.checks ?? [];
|
|
38633
|
+
for (const pr of s2.prs ?? []) {
|
|
38634
|
+
const flags = [
|
|
38635
|
+
pr.state,
|
|
38636
|
+
pr.isDraft ? "draft" : null,
|
|
38637
|
+
pr.queueState !== "none" ? pr.queueState : null,
|
|
38638
|
+
pr.mergeable ? clean(pr.mergeable).toLowerCase() : null
|
|
38639
|
+
].filter(Boolean);
|
|
38640
|
+
lines.push("");
|
|
38641
|
+
const where = s2.repo ? "" : `${clean(pr.repo)}`;
|
|
38642
|
+
lines.push(
|
|
38643
|
+
`${where}#${pr.prNumber} ${clean(pr.headRef)} [${flags.join(", ")}]`
|
|
38644
|
+
);
|
|
38645
|
+
for (const c of checks.filter((x) => x.headSha === pr.headSha)) {
|
|
38646
|
+
lines.push(
|
|
38647
|
+
` ${checkMark(c).padEnd(12)} ${clean(c.checkName)}${c.isRequired ? " (required)" : ""}`
|
|
38648
|
+
);
|
|
38649
|
+
}
|
|
38650
|
+
}
|
|
38651
|
+
if (s2.queue && s2.queue.length > 0) {
|
|
38652
|
+
lines.push("", "Merge queue");
|
|
38653
|
+
for (const q of s2.queue) {
|
|
38654
|
+
lines.push(
|
|
38655
|
+
` ${q.position ?? "?"}. #${q.prNumber} ${q.queueState} (position seen ${ageOf(q.observedAt, now)})`
|
|
38656
|
+
);
|
|
38657
|
+
}
|
|
38658
|
+
}
|
|
38659
|
+
if (s2.budget) {
|
|
38660
|
+
lines.push(
|
|
38661
|
+
"",
|
|
38662
|
+
`GitHub budget: REST ${s2.budget.restRemaining}, GraphQL ${s2.budget.graphqlRemaining}`
|
|
38663
|
+
);
|
|
38664
|
+
}
|
|
38665
|
+
return lines.join("\n");
|
|
38666
|
+
}
|
|
38667
|
+
var ciCommand = new Command("ci").description(
|
|
38668
|
+
"CI status from the Great Arrow board, with no GitHub call"
|
|
38669
|
+
);
|
|
38670
|
+
ciCommand.command("status [pr]").description("PR checks and merge-queue state; unverified exits 0").option("--repo <owner/name>", "Repository (default: the workspace's repo)").option("--queue", "Show the merge queue").option("--branch <branch>", "Pull request by head branch").option("--sha <sha>", "Checks for a commit").option("--json", "Output as JSON").action(async (pr, opts, command) => {
|
|
38671
|
+
const g = globalOutputOpts(command);
|
|
38672
|
+
const auth = await resolveAuth();
|
|
38673
|
+
const client2 = new GadClient({ token: auth.token, apiUrl: auth.apiUrl });
|
|
38674
|
+
const result = await client2.get(
|
|
38675
|
+
"/api/ci/status",
|
|
38676
|
+
ciStatusParams(pr, opts)
|
|
38677
|
+
);
|
|
38678
|
+
process.stdout.write(
|
|
38679
|
+
(g.json ? JSON.stringify(result, null, 2) : renderCiStatus(result)) + "\n"
|
|
38680
|
+
);
|
|
38681
|
+
});
|
|
38682
|
+
|
|
38607
38683
|
// src/commands/inbox.ts
|
|
38608
38684
|
var BACKOFF_BASE_MS = 15e3;
|
|
38609
38685
|
var BACKOFF_MAX_MS = 12e4;
|
|
@@ -52367,7 +52443,7 @@ function parseRaw(out2) {
|
|
|
52367
52443
|
}
|
|
52368
52444
|
return changes;
|
|
52369
52445
|
}
|
|
52370
|
-
function
|
|
52446
|
+
function clean2(name23) {
|
|
52371
52447
|
return [...name23].filter((c) => !new RegExp("\\p{Cc}", "u").test(c)).slice(0, 200).join("");
|
|
52372
52448
|
}
|
|
52373
52449
|
async function scanChanges(layout, changes, maxFile, opts = {}) {
|
|
@@ -52385,7 +52461,7 @@ async function scanChanges(layout, changes, maxFile, opts = {}) {
|
|
|
52385
52461
|
if (size2.code !== 0 || !Number.isSafeInteger(bytes))
|
|
52386
52462
|
throw new Refusal("commit_failed");
|
|
52387
52463
|
if (bytes > maxFile)
|
|
52388
|
-
throw new Refusal("file_too_large",
|
|
52464
|
+
throw new Refusal("file_too_large", clean2(change.path));
|
|
52389
52465
|
const blob = await worktreeGitBytes(
|
|
52390
52466
|
layout,
|
|
52391
52467
|
["cat-file", "blob", change.newSha],
|
|
@@ -52394,7 +52470,7 @@ async function scanChanges(layout, changes, maxFile, opts = {}) {
|
|
|
52394
52470
|
if (blob.code !== 0) throw new Refusal("commit_failed");
|
|
52395
52471
|
const line = secretLine(blob.stdout);
|
|
52396
52472
|
if (line !== null)
|
|
52397
|
-
throw new Refusal("secret_in_diff", `${
|
|
52473
|
+
throw new Refusal("secret_in_diff", `${clean2(change.path)} line ${line}`);
|
|
52398
52474
|
}
|
|
52399
52475
|
}
|
|
52400
52476
|
function linkTextStaysInside(rel, target) {
|
|
@@ -52512,9 +52588,9 @@ function readVerified(root, rel, max, probe = {}) {
|
|
|
52512
52588
|
const fst = fstatSync(fd);
|
|
52513
52589
|
if (!fst.isFile()) throw new Refusal("unsupported_file");
|
|
52514
52590
|
if (fst.nlink !== 1) throw new Refusal("hardlink_in_worktree");
|
|
52515
|
-
if (fst.size > max) throw new Refusal("file_too_large",
|
|
52591
|
+
if (fst.size > max) throw new Refusal("file_too_large", clean2(rel));
|
|
52516
52592
|
const bytes = readUpTo(fd, max + 1);
|
|
52517
|
-
if (bytes.length > max) throw new Refusal("file_too_large",
|
|
52593
|
+
if (bytes.length > max) throw new Refusal("file_too_large", clean2(rel));
|
|
52518
52594
|
probe.afterRead?.(rel);
|
|
52519
52595
|
recheck();
|
|
52520
52596
|
return { kind: "file", bytes, executable: (fst.mode & 64) !== 0 };
|
|
@@ -53280,6 +53356,130 @@ function boardCommand() {
|
|
|
53280
53356
|
return new Command("board").description("Clear the board: tidy cards and run the safe ones").addCommand(clear).addCommand(boardRunCommand());
|
|
53281
53357
|
}
|
|
53282
53358
|
|
|
53359
|
+
// src/commands/bill.ts
|
|
53360
|
+
var BILL_COLUMNS = [
|
|
53361
|
+
{ key: "vendor", header: "Vendor", width: 24 },
|
|
53362
|
+
{ key: "amount", header: "Amount", width: 12 },
|
|
53363
|
+
{ key: "status", header: "Status", width: 11 },
|
|
53364
|
+
{ key: "id", header: "ID", width: 36 }
|
|
53365
|
+
];
|
|
53366
|
+
function money(amountMinor, currency) {
|
|
53367
|
+
if (typeof amountMinor !== "number") return "\u2014";
|
|
53368
|
+
const cur = typeof currency === "string" ? currency.toUpperCase() : "";
|
|
53369
|
+
return `${(amountMinor / 100).toFixed(2)} ${cur}`.trim();
|
|
53370
|
+
}
|
|
53371
|
+
function billRow(bill) {
|
|
53372
|
+
return {
|
|
53373
|
+
id: bill.id,
|
|
53374
|
+
vendor: bill.vendor,
|
|
53375
|
+
status: bill.status,
|
|
53376
|
+
amount: money(bill.amountMinor, bill.currency)
|
|
53377
|
+
};
|
|
53378
|
+
}
|
|
53379
|
+
function payMessage(r) {
|
|
53380
|
+
if (r.approved) {
|
|
53381
|
+
const attempt = r.attempt ?? {};
|
|
53382
|
+
return attempt.testMode ? "Approved in Link. Test mode: no money moved. The bill stays paying until you run gad bill cancel." : "Approved in Link.";
|
|
53383
|
+
}
|
|
53384
|
+
if (r.ended) return `Link ended this attempt: ${String(r.ended)}.`;
|
|
53385
|
+
if (r.proposed) {
|
|
53386
|
+
return "Proposal recorded. The owner must tap Pay in Great Arrow to send it; nothing was charged.";
|
|
53387
|
+
}
|
|
53388
|
+
if (typeof r.approvalUrl === "string" && r.approvalUrl) {
|
|
53389
|
+
return `Payment sent to Link and waiting for approval. Approve it here: ${r.approvalUrl}`;
|
|
53390
|
+
}
|
|
53391
|
+
return "Payment sent to Link and waiting for approval in the Link app.";
|
|
53392
|
+
}
|
|
53393
|
+
async function makeClient2() {
|
|
53394
|
+
const auth = await resolveAuth();
|
|
53395
|
+
return new GadClient({
|
|
53396
|
+
token: auth.token,
|
|
53397
|
+
getToken: auth.getToken,
|
|
53398
|
+
apiUrl: auth.apiUrl
|
|
53399
|
+
});
|
|
53400
|
+
}
|
|
53401
|
+
function formatterFor(options, cmd) {
|
|
53402
|
+
const parent = cmd.optsWithGlobals();
|
|
53403
|
+
return createFormatter({
|
|
53404
|
+
json: options.json || parent.json || false,
|
|
53405
|
+
quiet: parent.quiet || false,
|
|
53406
|
+
isTTY: isTTY(),
|
|
53407
|
+
noColor: parent.noColor || false
|
|
53408
|
+
});
|
|
53409
|
+
}
|
|
53410
|
+
var listCommand4 = new Command("list").description("List bills").option("--status <status>", "Filter by status").option("--json", "Output as JSON").action(
|
|
53411
|
+
async (options, cmd) => {
|
|
53412
|
+
const fmt = formatterFor(options, cmd);
|
|
53413
|
+
const client2 = await makeClient2();
|
|
53414
|
+
const result = await client2.get(
|
|
53415
|
+
"/api/bills",
|
|
53416
|
+
options.status ? { status: options.status } : void 0
|
|
53417
|
+
);
|
|
53418
|
+
const bills = result.bills ?? [];
|
|
53419
|
+
fmt.table(
|
|
53420
|
+
cmd.optsWithGlobals().json || options.json ? bills : bills.map(billRow),
|
|
53421
|
+
BILL_COLUMNS
|
|
53422
|
+
);
|
|
53423
|
+
}
|
|
53424
|
+
);
|
|
53425
|
+
var getCommand2 = new Command("get").description("Show one bill with its payment attempts and wallet status").argument("<id>", "Bill ID").option("--json", "Output as JSON").action(async (id, options, cmd) => {
|
|
53426
|
+
const fmt = formatterFor(options, cmd);
|
|
53427
|
+
const client2 = await makeClient2();
|
|
53428
|
+
const detail = await client2.get(
|
|
53429
|
+
`/api/bills/${encodeURIComponent(id)}`
|
|
53430
|
+
);
|
|
53431
|
+
if (options.json || cmd.optsWithGlobals().json) {
|
|
53432
|
+
fmt.detail(detail, [{ key: "bill", header: "Bill" }]);
|
|
53433
|
+
return;
|
|
53434
|
+
}
|
|
53435
|
+
const lines = [
|
|
53436
|
+
`${String(detail.bill.vendor)} \xB7 ${money(detail.bill.amountMinor, detail.bill.currency)} \xB7 ${String(detail.bill.status)}`,
|
|
53437
|
+
`Wallet: ${detail.wallet.connected ? "connected" : "not connected"}`,
|
|
53438
|
+
`Attempts: ${detail.attempts.length}`,
|
|
53439
|
+
...detail.attempts.map(
|
|
53440
|
+
(a) => ` ${String(a.outcome)} \xB7 ${String(a.linkStatus ?? "\u2014")}`
|
|
53441
|
+
)
|
|
53442
|
+
];
|
|
53443
|
+
process.stdout.write(`${brandedBlock("Bill", lines)}
|
|
53444
|
+
`);
|
|
53445
|
+
});
|
|
53446
|
+
var payCommand = new Command("pay").description("Pay a bill from your Link wallet").argument("<id>", "Bill ID").action(async (id) => {
|
|
53447
|
+
const client2 = await makeClient2();
|
|
53448
|
+
const path10 = `/api/bills/${encodeURIComponent(id)}`;
|
|
53449
|
+
const detail = await client2.get(path10);
|
|
53450
|
+
const result = await client2.post(`${path10}/pay`, {
|
|
53451
|
+
expectedVersion: detail.bill.version
|
|
53452
|
+
});
|
|
53453
|
+
process.stdout.write(`${brandedBlock("Bill pay", [payMessage(result)])}
|
|
53454
|
+
`);
|
|
53455
|
+
});
|
|
53456
|
+
var cancelCommand = new Command("cancel").description("Cancel a bill's payment in progress (waiting or approved)").argument("<id>", "Bill ID").action(async (id) => {
|
|
53457
|
+
const client2 = await makeClient2();
|
|
53458
|
+
const path10 = `/api/bills/${encodeURIComponent(id)}`;
|
|
53459
|
+
const detail = await client2.get(path10);
|
|
53460
|
+
const live = (detail.attempts ?? []).find(
|
|
53461
|
+
(a) => a.outcome === "pending" || a.outcome === "approved"
|
|
53462
|
+
);
|
|
53463
|
+
if (!live || typeof live.id !== "string") {
|
|
53464
|
+
process.stdout.write(
|
|
53465
|
+
`${brandedBlock("Bill pay", ["No payment in progress for this bill; nothing to cancel."])}
|
|
53466
|
+
`
|
|
53467
|
+
);
|
|
53468
|
+
return;
|
|
53469
|
+
}
|
|
53470
|
+
await client2.post(
|
|
53471
|
+
`${path10}/attempts/${encodeURIComponent(live.id)}/cancel`,
|
|
53472
|
+
{}
|
|
53473
|
+
);
|
|
53474
|
+
process.stdout.write(
|
|
53475
|
+
`${brandedBlock("Bill pay", ["Payment cancelled. The bill is unpaid; nothing was charged."])}
|
|
53476
|
+
`
|
|
53477
|
+
);
|
|
53478
|
+
});
|
|
53479
|
+
function billCommand() {
|
|
53480
|
+
return new Command("bill").description("List, read, pay and cancel bills").addCommand(listCommand4).addCommand(getCommand2).addCommand(payCommand).addCommand(cancelCommand);
|
|
53481
|
+
}
|
|
53482
|
+
|
|
53283
53483
|
// src/commands/keys.ts
|
|
53284
53484
|
import { createInterface as createInterface5 } from "node:readline";
|
|
53285
53485
|
import { Writable } from "node:stream";
|
|
@@ -53952,7 +54152,7 @@ function err(line) {
|
|
|
53952
54152
|
process.stderr.write(`${line}
|
|
53953
54153
|
`);
|
|
53954
54154
|
}
|
|
53955
|
-
function
|
|
54155
|
+
function listCommand5() {
|
|
53956
54156
|
return new Command("list").description("List the credentials registered for key rotation").action(async (_opts, command) => {
|
|
53957
54157
|
const g = globalOutputOpts(command);
|
|
53958
54158
|
const { client: client2 } = await keysContext();
|
|
@@ -54332,7 +54532,7 @@ function approveCommand() {
|
|
|
54332
54532
|
});
|
|
54333
54533
|
}
|
|
54334
54534
|
function keysCommand() {
|
|
54335
|
-
return new Command("keys").description("Rotate leaked or expiring keys (GreatArrow.ai key rotation)").addCommand(
|
|
54535
|
+
return new Command("keys").description("Rotate leaked or expiring keys (GreatArrow.ai key rotation)").addCommand(listCommand5()).addCommand(statusCommand4()).addCommand(enrollCommand()).addCommand(pendingCommand()).addCommand(applyCommand()).addCommand(pasteCommand()).addCommand(approveCommand());
|
|
54336
54536
|
}
|
|
54337
54537
|
|
|
54338
54538
|
// src/lib/completions.ts
|
|
@@ -58023,6 +58223,7 @@ program2.addCommand(nextCommand());
|
|
|
58023
58223
|
program2.addCommand(discoverCommand());
|
|
58024
58224
|
program2.addCommand(callCommand());
|
|
58025
58225
|
program2.addCommand(boardCommand());
|
|
58226
|
+
program2.addCommand(billCommand());
|
|
58026
58227
|
program2.addCommand(claim_default);
|
|
58027
58228
|
program2.addCommand(work_default());
|
|
58028
58229
|
program2.addCommand(worktree_default);
|
|
@@ -58034,6 +58235,7 @@ program2.addCommand(integrations_default);
|
|
|
58034
58235
|
program2.addCommand(mcp_default);
|
|
58035
58236
|
program2.addCommand(agentCommand);
|
|
58036
58237
|
program2.addCommand(agentsCommand);
|
|
58238
|
+
program2.addCommand(ciCommand);
|
|
58037
58239
|
program2.addCommand(inboxCommand);
|
|
58038
58240
|
program2.addCommand(presenceCommand);
|
|
58039
58241
|
program2.addCommand(askCommand());
|