@great-arrow/cli 0.1.50 → 0.1.52

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 +47 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9327,6 +9327,7 @@ function mapErrorToExitCode(error) {
9327
9327
  return 2 /* NETWORK_ERROR */;
9328
9328
  }
9329
9329
  var FAILURE_HINTS = {
9330
+ permission: "Review this connection's scopes and workspace permissions at /account/connections.",
9330
9331
  auth: "Run `gad login`, then reconnect the client: /mcp \u2192 great-arrow \u2192 reconnect.",
9331
9332
  network: "Check this machine's connectivity (VPN, proxy, DNS), then try again.",
9332
9333
  timeout: "The request timed out. Check connectivity and retry; if it persists, see https://www.greatarrow.ai/status.",
@@ -9337,9 +9338,11 @@ var FAILURE_HINTS = {
9337
9338
  function classifyRequestFailure(error) {
9338
9339
  const message = error instanceof Error ? error.message : String(error ?? "unknown error");
9339
9340
  let kind = "unknown";
9340
- if (error instanceof CliError && error.code === 1 /* AUTH_ERROR */) {
9341
+ if (/\b403\b/.test(message)) {
9342
+ kind = "permission";
9343
+ } else if (error instanceof CliError && error.code === 1 /* AUTH_ERROR */) {
9341
9344
  kind = "auth";
9342
- } else if (/\b(401|403)\b/.test(message)) {
9345
+ } else if (/\b401\b/.test(message)) {
9343
9346
  kind = "auth";
9344
9347
  } else if (/HTTP 5\d\d|Server error/i.test(message)) {
9345
9348
  kind = "server";
@@ -9399,7 +9402,7 @@ function isNodeError(value) {
9399
9402
 
9400
9403
  // src/lib/version.ts
9401
9404
  var CLI_PACKAGE_NAME = "@great-arrow/cli";
9402
- var CLI_VERSION = "0.1.50";
9405
+ var CLI_VERSION = "0.1.52";
9403
9406
  var GAD_INSTALL_VERSION = "2026.08.08";
9404
9407
  var GAD_INSTALL_MIN_VERSION = "2026.06.22";
9405
9408
  var GAD_INSTALL_HEADER = "X-GAD-Install-Version";
@@ -10414,14 +10417,14 @@ async function storedPairOtherThan(ours) {
10414
10417
  debugSwallow("refresh.reread", err);
10415
10418
  }
10416
10419
  if (stored?.kind !== "oauth") return null;
10420
+ if (stored.credential.clientId !== ours.clientId || stored.credential.apiUrl.replace(/\/$/, "") !== ours.apiUrl.replace(/\/$/, "")) {
10421
+ throw networkError(
10422
+ "The stored session changed while renewing it.",
10423
+ "Retry the command with the current session."
10424
+ );
10425
+ }
10417
10426
  return stored.credential.refreshToken === ours.refreshToken ? null : stored.credential;
10418
10427
  }
10419
- async function rotatedByAnotherProcess(ours) {
10420
- const theirs = await storedPairOtherThan(ours);
10421
- if (!theirs) return null;
10422
- if (Date.now() >= theirs.accessExpiresAt - REFRESH_SKEW_MS) return null;
10423
- return theirs;
10424
- }
10425
10428
  async function resolveAuth() {
10426
10429
  const config = await loadConfig();
10427
10430
  const configApiUrl = config.api_url || DEFAULT_API_URL;
@@ -10512,20 +10515,37 @@ async function ensureFreshAccessToken(credential) {
10512
10515
  }
10513
10516
  async function doRefresh(credential) {
10514
10517
  const held = await acquireRefreshLock();
10518
+ let current = credential;
10515
10519
  try {
10516
- const theirs = await rotatedByAnotherProcess(credential);
10517
- if (theirs) return theirs;
10520
+ const theirs = await storedPairOtherThan(credential);
10521
+ if (theirs) {
10522
+ current = theirs;
10523
+ if (Date.now() < current.accessExpiresAt - REFRESH_SKEW_MS)
10524
+ return current;
10525
+ }
10526
+ if (!held) {
10527
+ throw networkError(
10528
+ "Session renewal is already in progress.",
10529
+ "Retry shortly; your saved session has been kept."
10530
+ );
10531
+ }
10518
10532
  const refreshed = await refreshTokens({
10519
- apiUrl: credential.apiUrl,
10520
- clientId: credential.clientId,
10521
- refreshToken: credential.refreshToken
10533
+ apiUrl: current.apiUrl,
10534
+ clientId: current.clientId,
10535
+ refreshToken: current.refreshToken
10522
10536
  });
10523
10537
  await saveOAuthCredential(refreshed);
10524
10538
  return refreshed;
10525
10539
  } catch (err) {
10526
10540
  if (err instanceof RefreshRejected) {
10527
- const theirs = await storedPairOtherThan(credential);
10528
- if (theirs) return theirs;
10541
+ const theirs = await storedPairOtherThan(current);
10542
+ if (theirs) {
10543
+ if (Date.now() < theirs.accessExpiresAt) return theirs;
10544
+ throw networkError(
10545
+ "Another process updated the session during renewal.",
10546
+ "Retry shortly; your saved session has been kept."
10547
+ );
10548
+ }
10529
10549
  await clearStoredCredential();
10530
10550
  throw sessionExpired();
10531
10551
  }
@@ -10904,7 +10924,14 @@ var GadClient = class {
10904
10924
  }
10905
10925
  const status = response.status;
10906
10926
  const body = await response.text().catch(() => "");
10907
- if (status === 401 || status === 403) {
10927
+ if (status === 403) {
10928
+ throw new CliError(
10929
+ "Permission denied (HTTP 403).",
10930
+ 1 /* AUTH_ERROR */,
10931
+ "Check this connection's scopes and workspace permissions at /account/connections."
10932
+ );
10933
+ }
10934
+ if (status === 401) {
10908
10935
  throw authError(
10909
10936
  `Authentication failed (HTTP ${status}).`,
10910
10937
  "Run 'gad login' to re-authenticate, or check your GAD_TOKEN."
@@ -14193,7 +14220,8 @@ function codexTransportFields(body) {
14193
14220
 
14194
14221
  // src/lib/mcp-doctor.ts
14195
14222
  var MCP_FAILURE_MESSAGE = {
14196
- auth: "MCP rejected this machine's credential (401/403)",
14223
+ auth: "MCP rejected this machine's credential (401)",
14224
+ permission: "MCP denied this connection's scopes or workspace access (403)",
14197
14225
  network: "Could not reach the MCP endpoint",
14198
14226
  timeout: "The MCP endpoint did not answer in time",
14199
14227
  server: "The MCP endpoint returned a server error",
@@ -14202,6 +14230,7 @@ var MCP_FAILURE_MESSAGE = {
14202
14230
  };
14203
14231
  var MCP_STATUS_WORD = {
14204
14232
  auth: "unauthenticated",
14233
+ permission: "forbidden",
14205
14234
  network: "unreachable",
14206
14235
  timeout: "timeout",
14207
14236
  server: "server error",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@great-arrow/cli",
3
- "version": "0.1.50",
3
+ "version": "0.1.52",
4
4
  "description": "GreatArrow.ai CLI tool",
5
5
  "type": "module",
6
6
  "bin": {