@great-arrow/cli 0.1.65 → 0.1.66

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 (3) hide show
  1. package/README.md +3 -1
  2. package/dist/index.js +277 -43
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -31,7 +31,9 @@ gad login
31
31
  gad login --no-browser
32
32
 
33
33
  # Direct personal token (CI/CD, headless). Stored as-is; no auto-refresh.
34
- gad login --token gad_xxxxx
34
+ # Over a signed-in OAuth session it takes a gad_v1_ token, keeps the session
35
+ # when handed the session's own access token, and otherwise needs --force.
36
+ gad login --token gad_v1_xxxxx
35
37
 
36
38
  # Check who you are (shows auth type + access-token expiry)
37
39
  gad whoami
package/dist/index.js CHANGED
@@ -9437,7 +9437,7 @@ function isNodeError(value) {
9437
9437
 
9438
9438
  // src/lib/version.ts
9439
9439
  var CLI_PACKAGE_NAME = "@great-arrow/cli";
9440
- var CLI_VERSION = "0.1.65";
9440
+ var CLI_VERSION = "0.1.66";
9441
9441
  var GAD_INSTALL_VERSION = "2026.08.08";
9442
9442
  var GAD_INSTALL_MIN_VERSION = "2026.06.22";
9443
9443
  var GAD_INSTALL_HEADER = "X-GAD-Install-Version";
@@ -9594,6 +9594,17 @@ async function clearStoredCredential() {
9594
9594
  await deleteToken();
9595
9595
  }
9596
9596
 
9597
+ // src/lib/token-login-guard.ts
9598
+ function decideTokenLogin(input2) {
9599
+ const { token, stored, force } = input2;
9600
+ if (stored?.kind !== "oauth") return { action: "store" };
9601
+ if (token === stored.credential.accessToken) {
9602
+ return { action: "keep-oauth", reason: "same-access-token" };
9603
+ }
9604
+ if (token.startsWith("gad_v1_") || force) return { action: "store" };
9605
+ return { action: "refuse", reason: "would-replace-oauth" };
9606
+ }
9607
+
9597
9608
  // src/lib/cli-locator.ts
9598
9609
  import {
9599
9610
  chmodSync,
@@ -10369,7 +10380,10 @@ var loginCommand = new Command("login").description("Authenticate the CLI with y
10369
10380
  ).option(
10370
10381
  "--no-browser",
10371
10382
  "Print the authorize URL instead of opening a browser"
10372
- ).option("--scope <list>", "OAuth scope to request", "mcp").action(
10383
+ ).option("--scope <list>", "OAuth scope to request", "mcp").option(
10384
+ "--force",
10385
+ "With --token: replace a signed-in OAuth session even if the token may be short-lived"
10386
+ ).action(
10373
10387
  async (options) => {
10374
10388
  const fmt = createFormatter({
10375
10389
  json: false,
@@ -10380,6 +10394,24 @@ var loginCommand = new Command("login").description("Authenticate the CLI with y
10380
10394
  const config2 = await loadConfig();
10381
10395
  const apiUrl = DEFAULT_API_URL;
10382
10396
  if (options.token) {
10397
+ const decision = decideTokenLogin({
10398
+ token: options.token,
10399
+ stored: await loadStoredCredential(),
10400
+ force: options.force === true
10401
+ });
10402
+ if (decision.action === "keep-oauth") {
10403
+ fmt.success(
10404
+ "Already signed in: that is your OAuth session's current access token. Keeping the self-refreshing session."
10405
+ );
10406
+ return;
10407
+ }
10408
+ if (decision.action === "refuse") {
10409
+ fmt.error(
10410
+ "You are signed in with a self-refreshing OAuth session, and this token is not a personal API token (gad_v1_\u2026). Storing it would replace the session, and if it is an OAuth access token it stops working within the hour. Use a gad_v1_ token, or pass --force to replace the session anyway."
10411
+ );
10412
+ process.exitCode = 1;
10413
+ return;
10414
+ }
10383
10415
  const stored = await savePatToken(options.token);
10384
10416
  if (!stored) {
10385
10417
  fmt.error(
@@ -11072,7 +11104,7 @@ function getCommandWorkspaceTarget(options = {}) {
11072
11104
  }
11073
11105
 
11074
11106
  // ../local-runtime/src/abortable.ts
11075
- function abortable(run3, signal) {
11107
+ function abortable(run4, signal) {
11076
11108
  return new Promise((resolve5, reject) => {
11077
11109
  const abort = () => {
11078
11110
  signal.removeEventListener("abort", abort);
@@ -11082,11 +11114,11 @@ function abortable(run3, signal) {
11082
11114
  signal.addEventListener("abort", abort, { once: true });
11083
11115
  Promise.resolve().then(() => {
11084
11116
  signal.throwIfAborted();
11085
- return run3();
11117
+ return run4();
11086
11118
  }).then(resolve5, reject).finally(() => signal.removeEventListener("abort", abort));
11087
11119
  });
11088
11120
  }
11089
- async function withLocalDeadline(deadlineMs, run3, parentSignal) {
11121
+ async function withLocalDeadline(deadlineMs, run4, parentSignal) {
11090
11122
  if (!Number.isSafeInteger(deadlineMs) || deadlineMs <= 0 || deadlineMs > 36e5)
11091
11123
  throw new Error("Invalid local operation deadline");
11092
11124
  const controller = new AbortController();
@@ -11096,7 +11128,7 @@ async function withLocalDeadline(deadlineMs, run3, parentSignal) {
11096
11128
  deadlineMs
11097
11129
  );
11098
11130
  try {
11099
- return await abortable(() => run3(signal), signal);
11131
+ return await abortable(() => run4(signal), signal);
11100
11132
  } finally {
11101
11133
  clearTimeout(timer);
11102
11134
  }
@@ -11258,6 +11290,7 @@ async function withNativeResponse(context2, path10, init, consume, parentSignal)
11258
11290
 
11259
11291
  // src/lib/client.ts
11260
11292
  var DEFAULT_TIMEOUT_MS2 = 3e4;
11293
+ var PRESENCE_TIMEOUT_MS = 4e4;
11261
11294
  var MAX_RETRIES = 5;
11262
11295
  var BASE_DELAY_MS = 1e3;
11263
11296
  function detectGitOrigin() {
@@ -11649,6 +11682,47 @@ var GadClient = class {
11649
11682
  })();
11650
11683
  }
11651
11684
  }
11685
+ /**
11686
+ * One request with NO retry, bounded by `AbortSignal.timeout`. For the
11687
+ * agent-presence routes: a replayed long-poll doubles a hold and the caller
11688
+ * already owns the loop and its backoff. Returns the status and parsed body
11689
+ * (null when not JSON) so the caller can read a 404 itself; a timeout or
11690
+ * network failure throws.
11691
+ */
11692
+ async requestOnce(method, path10, opts = {}) {
11693
+ const qs = opts.params && Object.keys(opts.params).length > 0 ? `?${new URLSearchParams(opts.params).toString()}` : "";
11694
+ const signal = AbortSignal.timeout(opts.timeoutMs ?? PRESENCE_TIMEOUT_MS);
11695
+ const headers = this.buildHeaders();
11696
+ if (method === "GET") delete headers["Content-Type"];
11697
+ if (this.getToken) {
11698
+ const getToken2 = this.getToken;
11699
+ headers.Authorization = `Bearer ${await new Promise(
11700
+ (resolve5, reject) => {
11701
+ signal.addEventListener(
11702
+ "abort",
11703
+ () => reject(networkError("Session renewal timed out.")),
11704
+ { once: true }
11705
+ );
11706
+ getToken2().then(resolve5, reject);
11707
+ }
11708
+ )}`;
11709
+ }
11710
+ const response = await fetch(`${this.apiUrl}${path10}${qs}`, {
11711
+ method,
11712
+ headers,
11713
+ ...opts.body !== void 0 && { body: JSON.stringify(opts.body) },
11714
+ redirect: "error",
11715
+ cache: "no-store",
11716
+ signal
11717
+ });
11718
+ let body = null;
11719
+ try {
11720
+ body = await response.json();
11721
+ } catch {
11722
+ body = null;
11723
+ }
11724
+ return { status: response.status, body };
11725
+ }
11652
11726
  /**
11653
11727
  * Make a GET request to a REST API endpoint.
11654
11728
  *
@@ -12393,8 +12467,8 @@ function text(value) {
12393
12467
  }
12394
12468
  function formatTodoDetail(todo) {
12395
12469
  const assignees = Array.isArray(todo.assignees) ? todo.assignees.map((a) => `${text(a.displayName)} (${text(a.type)})`).join(", ") : "";
12396
- const run3 = todo.lastRun ?? null;
12397
- const lastRun = run3 ? `${text(run3.status)} \u2014 ${text(run3.agentName)}` : "";
12470
+ const run4 = todo.lastRun ?? null;
12471
+ const lastRun = run4 ? `${text(run4.status)} \u2014 ${text(run4.agentName)}` : "";
12398
12472
  return {
12399
12473
  id: text(todo.id),
12400
12474
  title: text(todo.title),
@@ -16668,10 +16742,10 @@ async function mcpJsonAtRiskOfCommit(dir) {
16668
16742
  try {
16669
16743
  const { execFile: execFile5 } = await import("node:child_process");
16670
16744
  const { promisify: promisify2 } = await import("node:util");
16671
- const run3 = promisify2(execFile5);
16672
- await run3("git", ["rev-parse", "--is-inside-work-tree"], { cwd: dir });
16745
+ const run4 = promisify2(execFile5);
16746
+ await run4("git", ["rev-parse", "--is-inside-work-tree"], { cwd: dir });
16673
16747
  try {
16674
- await run3("git", ["check-ignore", "-q", ".mcp.json"], { cwd: dir });
16748
+ await run4("git", ["check-ignore", "-q", ".mcp.json"], { cwd: dir });
16675
16749
  return false;
16676
16750
  } catch {
16677
16751
  return true;
@@ -17191,9 +17265,9 @@ async function resolveProxyScript(override) {
17191
17265
  async function runProxyDiagnostics(scriptPath) {
17192
17266
  const { execFile: execFile5 } = await import("node:child_process");
17193
17267
  const { promisify: promisify2 } = await import("node:util");
17194
- const run3 = promisify2(execFile5);
17268
+ const run4 = promisify2(execFile5);
17195
17269
  try {
17196
- const { stdout } = await run3(
17270
+ const { stdout } = await run4(
17197
17271
  process.execPath,
17198
17272
  [scriptPath, "--print-diagnostics"],
17199
17273
  { timeout: 1e4, maxBuffer: 1024 * 1024 }
@@ -17219,8 +17293,8 @@ async function findLegacyStores(cwd) {
17219
17293
  try {
17220
17294
  const { execFile: execFile5 } = await import("node:child_process");
17221
17295
  const { promisify: promisify2 } = await import("node:util");
17222
- const run3 = promisify2(execFile5);
17223
- const { stdout } = await run3("git", ["worktree", "list", "--porcelain"], {
17296
+ const run4 = promisify2(execFile5);
17297
+ const { stdout } = await run4("git", ["worktree", "list", "--porcelain"], {
17224
17298
  cwd,
17225
17299
  timeout: 5e3
17226
17300
  });
@@ -17749,6 +17823,137 @@ var agentsCommand = new Command("agents").description(
17749
17823
  process.stdout.write(renderAgentsNow(result) + "\n");
17750
17824
  });
17751
17825
 
17826
+ // src/commands/inbox.ts
17827
+ var BACKOFF_BASE_MS = 15e3;
17828
+ var BACKOFF_MAX_MS = 12e4;
17829
+ var DEFAULT_MAX_MINUTES = 50;
17830
+ var PRESENCE_NOT_ENABLED = "Agent presence is not enabled.";
17831
+ function waitBackoffMs(emptyHolds) {
17832
+ if (emptyHolds < 3) return 0;
17833
+ return Math.min(2 ** (emptyHolds - 3) * BACKOFF_BASE_MS, BACKOFF_MAX_MS);
17834
+ }
17835
+ function asMessage(body) {
17836
+ if (!body || typeof body !== "object") return null;
17837
+ const b = body;
17838
+ return b.status === "message" && typeof b.messageId === "string" && typeof b.block === "string" ? { messageId: b.messageId, block: b.block } : null;
17839
+ }
17840
+ async function runInboxWait(o) {
17841
+ const sleep2 = o.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
17842
+ const now = o.now ?? Date.now;
17843
+ const write = o.write ?? ((t) => void process.stdout.write(t));
17844
+ const writeErr = o.writeErr ?? ((t) => void process.stderr.write(t));
17845
+ const stopAt = now() + (o.maxMinutes ?? DEFAULT_MAX_MINUTES) * 6e4;
17846
+ let emptyHolds = 0;
17847
+ while (now() < stopAt) {
17848
+ const params = { as: o.as };
17849
+ if (o.after) params.after = o.after;
17850
+ if (o.waitingOn !== void 0) params.waiting_on = o.waitingOn;
17851
+ let res = null;
17852
+ try {
17853
+ res = await o.request(params);
17854
+ } catch {
17855
+ res = null;
17856
+ }
17857
+ if (res?.status === 404) {
17858
+ writeErr(`${PRESENCE_NOT_ENABLED}
17859
+ `);
17860
+ return 2;
17861
+ }
17862
+ const msg = res && res.status === 200 ? asMessage(res.body) : null;
17863
+ if (msg) {
17864
+ const block = msg.block.endsWith("\n") ? msg.block : `${msg.block}
17865
+ `;
17866
+ write(`${block}after=${msg.messageId}
17867
+ `);
17868
+ return 0;
17869
+ }
17870
+ const gap = Math.min(waitBackoffMs(emptyHolds++), stopAt - now());
17871
+ if (gap > 0) await sleep2(gap);
17872
+ }
17873
+ return 3;
17874
+ }
17875
+ function parseMaxMinutes(raw) {
17876
+ const n = Number(raw);
17877
+ return Number.isFinite(n) && n > 0 ? n : DEFAULT_MAX_MINUTES;
17878
+ }
17879
+ var waitCommand = new Command("wait").description(
17880
+ "Wait for a peer's message to this connection; run as a background task"
17881
+ ).requiredOption("--as <id>", "Your connection id (from agent_inbox)").option("--after <id>", "Only wake for messages newer than this id").option("--waiting-on <text>", "What you are waiting on, shown to peers").option("--max-minutes <n>", "Give up after this many minutes", "50").action(
17882
+ async (opts) => {
17883
+ const auth = await resolveAuth();
17884
+ const client2 = new GadClient({
17885
+ token: auth.token,
17886
+ getToken: auth.getToken,
17887
+ apiUrl: auth.apiUrl
17888
+ });
17889
+ process.exitCode = await runInboxWait({
17890
+ request: (params) => client2.requestOnce("GET", "/api/agent-comms/wait", { params }),
17891
+ as: opts.as,
17892
+ after: opts.after,
17893
+ waitingOn: opts.waitingOn,
17894
+ maxMinutes: parseMaxMinutes(opts.maxMinutes)
17895
+ });
17896
+ }
17897
+ );
17898
+ var inboxCommand = new Command("inbox").description("Agent inbox \u2014 wait for a peer's message").addCommand(waitCommand);
17899
+
17900
+ // src/commands/presence.ts
17901
+ function doNotDisturbBody(raw, as) {
17902
+ if (raw.trim().toLowerCase() === "off") {
17903
+ return { action: "do_not_disturb", as, minutes: null };
17904
+ }
17905
+ const minutes = Number(raw);
17906
+ if (!Number.isFinite(minutes) || minutes <= 0) {
17907
+ throw new CliError(
17908
+ `Expected a number of minutes or "off", got "${raw}".`,
17909
+ 3 /* VALIDATION_ERROR */
17910
+ );
17911
+ }
17912
+ return { action: "do_not_disturb", as, minutes };
17913
+ }
17914
+ async function sendPresence(o) {
17915
+ const write = o.write ?? ((t) => void process.stdout.write(t));
17916
+ const writeErr = o.writeErr ?? ((t) => void process.stderr.write(t));
17917
+ const res = await o.request(o.body);
17918
+ if (res.status === 404) {
17919
+ writeErr(`${PRESENCE_NOT_ENABLED}
17920
+ `);
17921
+ return 2;
17922
+ }
17923
+ if (res.status < 200 || res.status >= 300) {
17924
+ writeErr(`Presence update failed (HTTP ${res.status}).
17925
+ `);
17926
+ return res.status === 401 || res.status === 403 ? 1 /* AUTH_ERROR */ : res.status === 400 ? 3 /* VALIDATION_ERROR */ : 2 /* NETWORK_ERROR */;
17927
+ }
17928
+ const b = o.body;
17929
+ write(
17930
+ b.action === "sign_off" ? "Signed off.\n" : b.minutes === null ? "Do not disturb is off.\n" : `Do not disturb for ${b.minutes} minutes.
17931
+ `
17932
+ );
17933
+ return 0;
17934
+ }
17935
+ async function run2(body) {
17936
+ const auth = await resolveAuth();
17937
+ const client2 = new GadClient({
17938
+ token: auth.token,
17939
+ getToken: auth.getToken,
17940
+ apiUrl: auth.apiUrl
17941
+ });
17942
+ process.exitCode = await sendPresence({
17943
+ request: (b) => client2.requestOnce("POST", "/api/agent-comms/presence", { body: b }),
17944
+ body
17945
+ });
17946
+ }
17947
+ var presenceCommand = new Command("presence").description("Tell peers you are away: do not disturb, or sign off").addCommand(
17948
+ new Command("do-not-disturb").description("Tell peers not to disturb you for a while, or turn it off").argument("<minutes|off>", "Minutes (up to 480), or off").requiredOption("--as <id>", "Your connection id (from agent_inbox)").action(async (raw, opts) => {
17949
+ await run2(doNotDisturbBody(raw, opts.as));
17950
+ })
17951
+ ).addCommand(
17952
+ new Command("sign-off").description("Mark this connection as signed off").requiredOption("--as <id>", "Your connection id (from agent_inbox)").action(async (opts) => {
17953
+ await run2({ action: "sign_off", as: opts.as });
17954
+ })
17955
+ );
17956
+
17752
17957
  // src/commands/ask.ts
17753
17958
  var ORCHESTRATOR_TIMEOUT_MS = 9e4;
17754
17959
  var ANSWER_FIELDS = [
@@ -38970,7 +39175,7 @@ function visit(schema, fnOrHandlers) {
38970
39175
  return h ? h(node2, rewritten) : node2;
38971
39176
  };
38972
39177
  const cache = /* @__PURE__ */ new Map();
38973
- function run3(s2) {
39178
+ function run4(s2) {
38974
39179
  const cached2 = cache.get(s2);
38975
39180
  if (cached2 === RESOLVING) {
38976
39181
  return new $ZodLazy({
@@ -38996,21 +39201,21 @@ function visit(schema, fnOrHandlers) {
38996
39201
  let changed = false;
38997
39202
  const newShape = {};
38998
39203
  for (const k of keys) {
38999
- const mapped = run3(oldShape[k]);
39204
+ const mapped = run4(oldShape[k]);
39000
39205
  if (mapped !== oldShape[k])
39001
39206
  changed = true;
39002
39207
  newShape[k] = mapped;
39003
39208
  }
39004
39209
  let newCatchall = def.catchall;
39005
39210
  if (def.catchall) {
39006
- newCatchall = run3(def.catchall);
39211
+ newCatchall = run4(def.catchall);
39007
39212
  if (newCatchall !== def.catchall)
39008
39213
  changed = true;
39009
39214
  }
39010
39215
  return changed ? clone(s2, { ...def, shape: newShape, catchall: newCatchall }) : s2;
39011
39216
  }
39012
39217
  case "array": {
39013
- const mapped = run3(def.element);
39218
+ const mapped = run4(def.element);
39014
39219
  return mapped === def.element ? s2 : clone(s2, { ...def, element: mapped });
39015
39220
  }
39016
39221
  case "tuple": {
@@ -39018,14 +39223,14 @@ function visit(schema, fnOrHandlers) {
39018
39223
  let changed = false;
39019
39224
  const newItems = [];
39020
39225
  for (const item of oldItems) {
39021
- const mapped = run3(item);
39226
+ const mapped = run4(item);
39022
39227
  if (mapped !== item)
39023
39228
  changed = true;
39024
39229
  newItems.push(mapped);
39025
39230
  }
39026
39231
  let newRest = def.rest;
39027
39232
  if (def.rest) {
39028
- newRest = run3(def.rest);
39233
+ newRest = run4(def.rest);
39029
39234
  if (newRest !== def.rest)
39030
39235
  changed = true;
39031
39236
  }
@@ -39033,12 +39238,12 @@ function visit(schema, fnOrHandlers) {
39033
39238
  }
39034
39239
  case "record":
39035
39240
  case "map": {
39036
- const newKey = run3(def.keyType);
39037
- const newVal = run3(def.valueType);
39241
+ const newKey = run4(def.keyType);
39242
+ const newVal = run4(def.valueType);
39038
39243
  return newKey === def.keyType && newVal === def.valueType ? s2 : clone(s2, { ...def, keyType: newKey, valueType: newVal });
39039
39244
  }
39040
39245
  case "set": {
39041
- const newVal = run3(def.valueType);
39246
+ const newVal = run4(def.valueType);
39042
39247
  return newVal === def.valueType ? s2 : clone(s2, { ...def, valueType: newVal });
39043
39248
  }
39044
39249
  case "union": {
@@ -39046,7 +39251,7 @@ function visit(schema, fnOrHandlers) {
39046
39251
  let changed = false;
39047
39252
  const newOptions = [];
39048
39253
  for (const opt of oldOptions) {
39049
- const mapped = run3(opt);
39254
+ const mapped = run4(opt);
39050
39255
  if (mapped !== opt)
39051
39256
  changed = true;
39052
39257
  newOptions.push(mapped);
@@ -39054,8 +39259,8 @@ function visit(schema, fnOrHandlers) {
39054
39259
  return changed ? clone(s2, { ...def, options: newOptions }) : s2;
39055
39260
  }
39056
39261
  case "intersection": {
39057
- const newLeft = run3(def.left);
39058
- const newRight = run3(def.right);
39262
+ const newLeft = run4(def.left);
39263
+ const newRight = run4(def.right);
39059
39264
  return newLeft === def.left && newRight === def.right ? s2 : clone(s2, { ...def, left: newLeft, right: newRight });
39060
39265
  }
39061
39266
  case "optional":
@@ -39067,23 +39272,23 @@ function visit(schema, fnOrHandlers) {
39067
39272
  case "nonoptional":
39068
39273
  case "promise":
39069
39274
  case "success": {
39070
- const newInner = run3(def.innerType);
39275
+ const newInner = run4(def.innerType);
39071
39276
  return newInner === def.innerType ? s2 : clone(s2, { ...def, innerType: newInner });
39072
39277
  }
39073
39278
  case "pipe": {
39074
- const newIn = run3(def.in);
39075
- const newOut = run3(def.out);
39279
+ const newIn = run4(def.in);
39280
+ const newOut = run4(def.out);
39076
39281
  return newIn === def.in && newOut === def.out ? s2 : clone(s2, { ...def, in: newIn, out: newOut });
39077
39282
  }
39078
39283
  case "function": {
39079
- const newInput = run3(def.input);
39080
- const newOutput = run3(def.output);
39284
+ const newInput = run4(def.input);
39285
+ const newOutput = run4(def.output);
39081
39286
  return newInput === def.input && newOutput === def.output ? s2 : clone(s2, { ...def, input: newInput, output: newOutput });
39082
39287
  }
39083
39288
  case "lazy": {
39084
39289
  const original = def.getter;
39085
39290
  const { _cachedInner, ...rest } = def;
39086
- return clone(s2, { ...rest, getter: () => run3(original()) });
39291
+ return clone(s2, { ...rest, getter: () => run4(original()) });
39087
39292
  }
39088
39293
  // A leaf by choice: `parts` are regex fragments, not data positions.
39089
39294
  case "template_literal":
@@ -39114,7 +39319,7 @@ function visit(schema, fnOrHandlers) {
39114
39319
  }
39115
39320
  }
39116
39321
  }
39117
- return run3(schema);
39322
+ return run4(schema);
39118
39323
  }
39119
39324
 
39120
39325
  // ../../node_modules/zod/v4/classic/deep-partial.js
@@ -50304,7 +50509,7 @@ function helperKind(raw) {
50304
50509
  if (/^store\b/.test(v)) return "store";
50305
50510
  return "other";
50306
50511
  }
50307
- function run2(file2, args) {
50512
+ function run3(file2, args) {
50308
50513
  return new Promise((done) => {
50309
50514
  execFile4(
50310
50515
  file2,
@@ -50315,10 +50520,10 @@ function run2(file2, args) {
50315
50520
  });
50316
50521
  }
50317
50522
  async function detectGhCli() {
50318
- return await run2("gh", ["--version"]) !== null;
50523
+ return await run3("gh", ["--version"]) !== null;
50319
50524
  }
50320
50525
  async function detectGitHelper() {
50321
- const out2 = await run2("git", [
50526
+ const out2 = await run3("git", [
50322
50527
  "config",
50323
50528
  "--get-urlmatch",
50324
50529
  "credential.helper",
@@ -50547,29 +50752,29 @@ function statusCommand4() {
50547
50752
  const runId = requireRunId(runArg);
50548
50753
  const { client: client2, apiUrl } = await keysContext();
50549
50754
  const res = await client2.get(`/api/key-rotation/runs/${runId}`);
50550
- const run3 = res?.run ?? {};
50755
+ const run4 = res?.run ?? {};
50551
50756
  if (g.json) {
50552
- out(JSON.stringify(run3));
50757
+ out(JSON.stringify(run4));
50553
50758
  return;
50554
50759
  }
50555
50760
  const c = createColor(g.noColor || g.quiet);
50556
50761
  out(
50557
- `${c.bold(`Run ${runId}`)} ${s(run3.state)}` + (s(run3.waitingOn) ? c.dim(` waiting on ${s(run3.waitingOn)}`) : "")
50762
+ `${c.bold(`Run ${runId}`)} ${s(run4.state)}` + (s(run4.waitingOn) ? c.dim(` waiting on ${s(run4.waitingOn)}`) : "")
50558
50763
  );
50559
- for (const st of run3.steps ?? []) {
50764
+ for (const st of run4.steps ?? []) {
50560
50765
  const detail = s(st.detailCode);
50561
50766
  out(
50562
50767
  ` ${s(st.step)} ${c.dim(s(st.targetKind))} ${s(st.status)}` + (detail ? c.dim(` (${detail})`) : "")
50563
50768
  );
50564
50769
  }
50565
- const open4 = (run3.checklist ?? []).filter((i) => i.ticked !== true);
50770
+ const open4 = (run4.checklist ?? []).filter((i) => i.ticked !== true);
50566
50771
  if (open4.length > 0) {
50567
50772
  out(c.yellow("Checklist (tick these in the browser):"));
50568
50773
  for (const item of open4) {
50569
50774
  out(` \u2610 ${s(item.label)} ${c.cyan(s(item.href))}`);
50570
50775
  }
50571
50776
  }
50572
- for (const d of run3.devices ?? []) {
50777
+ for (const d of run4.devices ?? []) {
50573
50778
  out(` device ${s(d.label)} ${s(d.state)}`);
50574
50779
  }
50575
50780
  out(c.dim(`${apiUrl}${keyRotationRunPath(runId)}`));
@@ -50910,6 +51115,8 @@ var COMMANDS = [
50910
51115
  "smoke",
50911
51116
  "agent",
50912
51117
  "ask",
51118
+ "inbox",
51119
+ "presence",
50913
51120
  "runtime",
50914
51121
  "open",
50915
51122
  "completions"
@@ -50951,6 +51158,12 @@ _gad_completions() {
50951
51158
  agent)
50952
51159
  COMPREPLY=( $(compgen -W "list invoke" -- "\${cur}") )
50953
51160
  ;;
51161
+ inbox)
51162
+ COMPREPLY=( $(compgen -W "wait" -- "\${cur}") )
51163
+ ;;
51164
+ presence)
51165
+ COMPREPLY=( $(compgen -W "do-not-disturb sign-off" -- "\${cur}") )
51166
+ ;;
50954
51167
  runtime)
50955
51168
  COMPREPLY=( $(compgen -W "status set sync policy" -- "\${cur}") )
50956
51169
  ;;
@@ -50986,6 +51199,8 @@ _gad() {
50986
51199
  'smoke:Run smoke tests'
50987
51200
  'agent:Manage agents (list, invoke)'
50988
51201
  'ask:Ask the orchestrator a question'
51202
+ 'inbox:Agent inbox (wait)'
51203
+ 'presence:Agent presence (do-not-disturb, sign-off)'
50989
51204
  'runtime:Choose your computer or the cloud per lane'
50990
51205
  'open:Open an app surface in the browser'
50991
51206
  'completions:Generate shell completions'
@@ -51021,6 +51236,14 @@ _gad() {
51021
51236
  subcommands=('list:List agents' 'invoke:Invoke an agent')
51022
51237
  _describe -t subcommands 'agent subcommands' subcommands
51023
51238
  ;;
51239
+ inbox)
51240
+ subcommands=('wait:Wait for a peer message')
51241
+ _describe -t subcommands 'inbox subcommands' subcommands
51242
+ ;;
51243
+ presence)
51244
+ subcommands=('do-not-disturb:Do not disturb for a while, or off' 'sign-off:Sign off this connection')
51245
+ _describe -t subcommands 'presence subcommands' subcommands
51246
+ ;;
51024
51247
  runtime)
51025
51248
  subcommands=('status:Where each lane runs' 'set:Set a lane' 'sync:Apply to this checkout' 'policy:Workspace policy')
51026
51249
  _describe -t subcommands 'runtime subcommands' subcommands
@@ -51049,6 +51272,8 @@ function generateFish() {
51049
51272
  smoke: "Run smoke tests",
51050
51273
  agent: "Manage agents",
51051
51274
  ask: "Ask the orchestrator a question",
51275
+ inbox: "Agent inbox",
51276
+ presence: "Agent presence",
51052
51277
  runtime: "Choose your computer or the cloud per lane",
51053
51278
  open: "Open an app surface in the browser",
51054
51279
  completions: "Generate shell completions"
@@ -51087,6 +51312,13 @@ function generateFish() {
51087
51312
  list: "List agents",
51088
51313
  invoke: "Invoke an agent"
51089
51314
  },
51315
+ inbox: {
51316
+ wait: "Wait for a peer message"
51317
+ },
51318
+ presence: {
51319
+ "do-not-disturb": "Do not disturb for a while, or off",
51320
+ "sign-off": "Sign off this connection"
51321
+ },
51090
51322
  runtime: {
51091
51323
  status: "Where each lane runs",
51092
51324
  set: "Set a lane",
@@ -54566,6 +54798,8 @@ program2.addCommand(integrations_default);
54566
54798
  program2.addCommand(mcp_default);
54567
54799
  program2.addCommand(agentCommand);
54568
54800
  program2.addCommand(agentsCommand);
54801
+ program2.addCommand(inboxCommand);
54802
+ program2.addCommand(presenceCommand);
54569
54803
  program2.addCommand(askCommand());
54570
54804
  program2.addCommand(localCommand());
54571
54805
  program2.addCommand(runtimeCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@great-arrow/cli",
3
- "version": "0.1.65",
3
+ "version": "0.1.66",
4
4
  "description": "GreatArrow.ai CLI tool",
5
5
  "type": "module",
6
6
  "bin": {