@indigoai-us/hq-cli 5.103.23 → 5.103.24

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/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.103.24] — 2026-08-27
6
+
5
7
  ## [5.103.23] — 2026-08-26
6
8
 
7
9
  ### Changed
package/dist/main.js CHANGED
@@ -72,6 +72,7 @@ import { isExpectedUserError } from "./utils/expected-cli-error.js";
72
72
  import { isEpipe } from "./utils/epipe.js";
73
73
  import { isInterceptedProcessExit } from "./utils/intercepted-process-exit.js";
74
74
  import { isAuthError } from "./utils/auth-error.js";
75
+ import { browserLoginAbandonedMessage } from "./utils/browser-login-abandoned.js";
75
76
  import { isCompanySelectionError } from "./utils/company-selection-error.js";
76
77
  import { canOfferTeamUpgrade, formatPlanGateError, isPlanGateError, offerTeamUpgrade, } from "./utils/plan-gate-error.js";
77
78
  import { upgradeToTeam } from "./utils/team-upgrade.js";
@@ -394,6 +395,21 @@ export async function handleTopLevelError(err, deps = defaultTopLevelErrorDepend
394
395
  deps.stderr.write(`hq: ${err.message}\n`);
395
396
  deps.setExitCode(1);
396
397
  }
398
+ else if (browserLoginAbandonedMessage(err)) {
399
+ // HQ-CLI-V: the caller triggered the implicit browser sign-in fallback
400
+ // (an expiring/absent HQ session) and then never completed it —
401
+ // @indigoai-us/hq-cloud's browserLogin rejected either at its 15-minute
402
+ // deadline or because the user declined at the IdP (access_denied). A
403
+ // human walking away from an OAuth prompt is expected auth state the user
404
+ // fixes with `hq login`, not an hq-cli defect. Print the fixed actionable
405
+ // remedy and skip Sentry so one abandoned login doesn't file a permanent
406
+ // high-priority "crash". Placed with the auth carve-out (both mean "your
407
+ // HQ session isn't usable; run hq login"); every genuine browser-login or
408
+ // token-exchange fault stays outside the closed allowlist and still
409
+ // captures below.
410
+ deps.stderr.write(`hq: ${browserLoginAbandonedMessage(err)}\n`);
411
+ deps.setExitCode(1);
412
+ }
397
413
  else if (isPlanGateError(err)) {
398
414
  // hq-pro's plan denials are expected product limits, never a CLI crash.
399
415
  // The shared vault client has already decoded and typed the small safe
@@ -0,0 +1,12 @@
1
+ /**
2
+ * If `err` is an abandoned implicit browser sign-in, return a short, fixed
3
+ * user-facing remedy; otherwise return `null`.
4
+ *
5
+ * A non-null result means the caller should print the message and SKIP Sentry
6
+ * capture — a user who walked away from an OAuth prompt is not an hq-cli defect.
7
+ * A null result means "handle as usual (capture to Sentry)". CognitoRefreshError
8
+ * is a refresh fault, never an abandonment, so it is excluded structurally even
9
+ * though it extends CognitoAuthError.
10
+ */
11
+ export declare function browserLoginAbandonedMessage(err: unknown): string | null;
12
+ //# sourceMappingURL=browser-login-abandoned.d.ts.map
@@ -0,0 +1,70 @@
1
+ // src/utils/browser-login-abandoned.ts
2
+ //
3
+ // Classify an ABANDONED implicit browser sign-in — the caller triggered the
4
+ // fallback OAuth flow (an expiring/absent HQ session on any of the ~100
5
+ // ensureCognitoToken/ensureCognitoIdToken call sites) and then never completed
6
+ // it. @indigoai-us/hq-cloud's browserLogin arms a 15-minute deadline and also
7
+ // rejects when the identity provider reports the user declined; both mint a
8
+ // bare CognitoAuthError. A human walking away from an OAuth prompt is expected
9
+ // auth state the user fixes with `hq login`, NOT an hq-cli defect — so the
10
+ // top-level handler prints an actionable line and exits non-zero but SKIPS
11
+ // Sentry capture, mirroring the auth (HQ-CLI-8), company-selection (HQ-CLI-7),
12
+ // expected-user-error (HQ-CLI-6), and environmental-FS (HQ-CLI-2) carve-outs.
13
+ //
14
+ // HQ-CLI-V (Sentry indigo-d0/hq-cli 7685055900): `hq integrations list
15
+ // --company <slug> --json` tried to refresh an expiring session, the refresh
16
+ // 400'd (invalid_grant), and it fell back to browserLogin(). Nobody finished
17
+ // the sign-in, so exactly 15 minutes later browserLogin rejected with
18
+ // `CognitoAuthError("Login timed out after 15 minutes")`. That error carries no
19
+ // `code`, no `expected` flag, and is not an AuthError/CompanySelectionError/…,
20
+ // so every predicate in handleTopLevelError returned false and the abandoned
21
+ // login was captured as a high-priority, unfixable "crash".
22
+ //
23
+ // The allowlist is CLOSED at the two upstream-minted human-abandonment
24
+ // signatures and defaults to null (capture). Every other CognitoAuthError — a
25
+ // state-parameter mismatch (possible CSRF), a missing callback code, a
26
+ // non-access_denied IdP error, a token-exchange failure — and every
27
+ // CognitoRefreshError (a refresh fault, not an abandonment) still reaches
28
+ // Sentry.
29
+ import { CognitoAuthError, CognitoRefreshError } from "@indigoai-us/hq-cloud";
30
+ /**
31
+ * Fixed, actionable remedy. Deliberately interpolates NO upstream error text,
32
+ * so this carve-out can never widen disclosure and needs no redaction pass.
33
+ */
34
+ const BROWSER_LOGIN_ABANDONED_MESSAGE = "Browser sign-in was not completed. Run `hq login`, finish the sign-in in " +
35
+ "your browser, then re-run your command.";
36
+ /**
37
+ * The 15-minute login-deadline signature (@indigoai-us/hq-cloud cognito-auth
38
+ * `waitForAuthCode`). The minute count is tolerated (`\d+`) so an upstream
39
+ * retune of the deadline turns the contract test red rather than silently
40
+ * restoring the Sentry noise.
41
+ */
42
+ const LOGIN_TIMED_OUT = /^Login timed out after \d+ minutes?$/;
43
+ /**
44
+ * The user declined at the identity provider. Matched EXACTLY — other
45
+ * `Cognito returned error: <x>` values (server_error, …) are not abandonment
46
+ * and stay reportable.
47
+ */
48
+ const ACCESS_DENIED = "Cognito returned error: access_denied";
49
+ /**
50
+ * If `err` is an abandoned implicit browser sign-in, return a short, fixed
51
+ * user-facing remedy; otherwise return `null`.
52
+ *
53
+ * A non-null result means the caller should print the message and SKIP Sentry
54
+ * capture — a user who walked away from an OAuth prompt is not an hq-cli defect.
55
+ * A null result means "handle as usual (capture to Sentry)". CognitoRefreshError
56
+ * is a refresh fault, never an abandonment, so it is excluded structurally even
57
+ * though it extends CognitoAuthError.
58
+ */
59
+ export function browserLoginAbandonedMessage(err) {
60
+ if (!(err instanceof CognitoAuthError))
61
+ return null;
62
+ if (err instanceof CognitoRefreshError)
63
+ return null;
64
+ const { message } = err;
65
+ if (LOGIN_TIMED_OUT.test(message) || message === ACCESS_DENIED) {
66
+ return BROWSER_LOGIN_ABANDONED_MESSAGE;
67
+ }
68
+ return null;
69
+ }
70
+ //# sourceMappingURL=browser-login-abandoned.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.103.23",
3
+ "version": "5.103.24",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {