@indigoai-us/hq-cli 5.242.0 → 5.243.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.243.0] — 2026-09-27
6
+ ### Added
7
+
8
+ - `hq auth login` remembers the last provider used on this computer and shows the Cognito provider choice page on first login. Only the provider name is stored locally.
9
+
10
+ ### Changed
11
+
12
+ - Internal: moved the accounts, sessions and questions subcommands out of src/commands/lanes.ts; no behaviour change
13
+
14
+ ### Fixed
15
+
16
+ - Removed the unused `cli.network.force-ipv4` hq-flags lookup and forced IPv4
17
+ startup path. The existing Node family-attempt timeout remains unchanged.
18
+ - `hq auth login` continues when it cannot read or save the remembered provider. It prints a dim warning with the state path and error code; a save failure does not turn a successful sign-in into a login failure.
19
+
5
20
  ## [5.242.0] — 2026-09-27
6
21
 
7
22
  ### Changed
@@ -14,6 +29,10 @@
14
29
  company selection when `--company` is omitted; explicit `--company` values
15
30
  remain validated.
16
31
 
32
+ ### Fixed
33
+
34
+ - The `cli.install-path-compatibility` hq-flags key enables pnpm v11+ global-path recognition. On Windows, it also passes drive-path tarballs to tar by filename from the archive directory. The flag defaults to off.
35
+
17
36
  ## [5.241.0] — 2026-09-27
18
37
 
19
38
  ### Fixed
@@ -16,31 +16,70 @@
16
16
  import chalk from "chalk";
17
17
  import { browserLogin, clearCachedTokens, loadCachedTokens, isExpiring, loadMachineCreds, CognitoAuthError, } from "@indigoai-us/hq-cloud";
18
18
  import { DEFAULT_COGNITO, refreshCachedSession, resolveCognitoTokenSource, } from "../utils/cognito-session.js";
19
- import { cognitoConfigForLoginProvider } from "../utils/login-provider.js";
19
+ import { resolveLoginProviderSelection, } from "../utils/login-provider.js";
20
+ import { getLastLoginProviderStatePath, loadLastLoginProvider, storeLastLoginProvider, } from "../lib/auth-login-provider-state.js";
20
21
  import { callbackPortBusyGuidance, DEFAULT_CALLBACK_PORT, isCallbackPortBusy, } from "../utils/callback-port-busy.js";
21
- /**
22
- * Decode the (unverified) ID token payload for display purposes only.
23
- * The token was just returned by Cognito's token endpoint, so its contents
24
- * are trusted enough to print — we never use these claims for authorization.
25
- */
26
- function peekIdToken(idToken) {
22
+ /** Decode token claims for local display and provider-memory purposes only. */
23
+ function decodeIdTokenClaims(idToken) {
27
24
  try {
28
25
  const payload = idToken.split(".")[1];
29
26
  if (!payload)
30
- return {};
27
+ return undefined;
31
28
  const pad = payload.length % 4 === 0 ? "" : "=".repeat(4 - (payload.length % 4));
32
29
  const normalized = payload.replace(/-/g, "+").replace(/_/g, "/") + pad;
33
30
  const decoded = JSON.parse(Buffer.from(normalized, "base64").toString("utf-8"));
34
- return {
35
- email: decoded.email,
36
- sub: decoded.sub,
37
- entityType: decoded["custom:entityType"],
38
- entityUid: decoded["custom:entityUid"],
39
- };
31
+ return decoded && typeof decoded === "object" && !Array.isArray(decoded)
32
+ ? decoded
33
+ : undefined;
40
34
  }
41
35
  catch {
42
- return {};
36
+ return undefined;
37
+ }
38
+ }
39
+ function peekIdToken(idToken) {
40
+ const claims = decodeIdTokenClaims(idToken);
41
+ return {
42
+ email: typeof claims?.email === "string" ? claims.email : undefined,
43
+ sub: typeof claims?.sub === "string" ? claims.sub : undefined,
44
+ entityType: typeof claims?.["custom:entityType"] === "string"
45
+ ? claims["custom:entityType"]
46
+ : undefined,
47
+ entityUid: typeof claims?.["custom:entityUid"] === "string"
48
+ ? claims["custom:entityUid"]
49
+ : undefined,
50
+ };
51
+ }
52
+ function errorCode(error) {
53
+ if (error
54
+ && typeof error === "object"
55
+ && "code" in error
56
+ && typeof error.code === "string") {
57
+ return error.code;
43
58
  }
59
+ return "UNKNOWN";
60
+ }
61
+ function providerFromIdToken(idToken) {
62
+ const identities = decodeIdTokenClaims(idToken)?.identities;
63
+ if (!Array.isArray(identities))
64
+ return undefined;
65
+ const providers = new Set();
66
+ for (const identity of identities) {
67
+ if (!identity || typeof identity !== "object" || Array.isArray(identity))
68
+ continue;
69
+ const item = identity;
70
+ const providerName = typeof item.providerName === "string"
71
+ ? item.providerName
72
+ : item.providerType;
73
+ if (typeof providerName !== "string")
74
+ continue;
75
+ const normalized = providerName.trim().toLowerCase();
76
+ if (normalized === "google")
77
+ providers.add("google");
78
+ if (normalized === "microsoft" || normalized === "microsoftpersonal") {
79
+ providers.add("microsoft");
80
+ }
81
+ }
82
+ return providers.size === 1 ? providers.values().next().value : undefined;
44
83
  }
45
84
  /** Display label for the local machine identity (company agents). */
46
85
  function machineIdentityLabel() {
@@ -67,7 +106,25 @@ export function registerAuthCommands(program) {
67
106
  return;
68
107
  }
69
108
  try {
70
- const tokens = await browserLogin(cognitoConfigForLoginProvider(options.provider));
109
+ const canUseRememberedProvider = options.provider === undefined
110
+ && process.env.HQ_COGNITO_IDENTITY_PROVIDER === undefined;
111
+ let rememberedProvider;
112
+ if (canUseRememberedProvider) {
113
+ try {
114
+ rememberedProvider = loadLastLoginProvider();
115
+ }
116
+ catch (error) {
117
+ console.error(chalk.dim(`Could not read provider state at ${getLastLoginProviderStatePath()} (${errorCode(error)}). Continuing to the provider choice page.`));
118
+ }
119
+ }
120
+ const selection = resolveLoginProviderSelection(options.provider, process.env, rememberedProvider);
121
+ const tokens = await browserLogin(selection.config);
122
+ try {
123
+ storeLastLoginProvider(providerFromIdToken(tokens.idToken) ?? selection.providerToRemember);
124
+ }
125
+ catch (error) {
126
+ console.error(chalk.dim(`Could not save provider state at ${getLastLoginProviderStatePath()} (${errorCode(error)}). The provider choice was not saved.`));
127
+ }
71
128
  const who = peekIdToken(tokens.idToken).email ?? "HQ";
72
129
  console.log(chalk.green(`Signed in as ${who}`));
73
130
  console.log(chalk.dim(` Token cached at ~/.hq/cognito-tokens.json (expires ${tokens.expiresAt})`));
@@ -0,0 +1,25 @@
1
+ import type { Ctx, LaneAccountsHandlerDeps } from "./lanes-shared.js";
2
+ export declare function createLaneAccountsHandlers(deps: LaneAccountsHandlerDeps): {
3
+ runAccountsList: (ctx: Ctx, opts: {
4
+ provider?: string;
5
+ }) => Promise<void>;
6
+ runAccountsBalance: (ctx: Ctx, opts: {
7
+ provider?: string;
8
+ apply?: boolean;
9
+ json?: boolean;
10
+ }) => Promise<void>;
11
+ runAccountsLogin: (ctx: Ctx, providerRaw: string, accountId: string, opts: {
12
+ home?: string;
13
+ deviceAuth?: boolean;
14
+ company?: string;
15
+ }) => Promise<void>;
16
+ runAccountsSetHome: (ctx: Ctx, providerRaw: string, accountIdRaw: string, homeRaw: string, opts: {
17
+ host?: string;
18
+ company?: string;
19
+ }) => Promise<void>;
20
+ runAccountsEnable: (ctx: Ctx, providerRaw: string, accountId: string) => Promise<void>;
21
+ runAccountsDisable: (ctx: Ctx, providerRaw: string, accountId: string, opts: {
22
+ reason?: string;
23
+ }) => Promise<void>;
24
+ };
25
+ //# sourceMappingURL=lanes-accounts.d.ts.map