@indigoai-us/hq-cli 5.119.4 → 5.119.5

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,22 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.119.5] — 2026-09-17
6
+
7
+ ### Fixed
8
+
9
+ - When a new Slack agent is waiting for a Socket Mode app-level token, `hq
10
+ agents status` now shows a link to create the token and a direct link to the
11
+ HQ form where it can be pasted. The same links are included in JSON output.
12
+
13
+ ### Changed
14
+
15
+ - Starter now includes 1 integration instead of none, and the lock copy says
16
+ so. The notice reads "too many integrations", quotes "Integrations allowed
17
+ on Starter: 1", and tells you to "disconnect integrations until you are at 1
18
+ or fewer"; the per-turn line reads "over its 1-integration limit". Nothing in
19
+ the CLI says Starter has no integrations any more.
20
+
5
21
  ## [5.119.4] — 2026-09-17
6
22
 
7
23
  ### Fixed
@@ -445,6 +445,26 @@ function currentDeviceSignInAction(status) {
445
445
  }
446
446
  function pendingSlackAction(status) {
447
447
  const agent = recordValue(status.agent);
448
+ const configuredSlack = recordValue(recordValue(agent?.channels)?.slack);
449
+ const appId = nonEmptyString(configuredSlack?.appId);
450
+ const agentUid = nonEmptyString(agent?.uid);
451
+ const companyUid = nonEmptyString(agent?.companyUid);
452
+ const tokenPage = safeActionUrl(configuredSlack?.appTokenPendingUrl);
453
+ if (tokenPage &&
454
+ appId && /^A[A-Z0-9]+$/.test(appId) &&
455
+ new URL(tokenPage).hostname === "api.slack.com" &&
456
+ agentUid && AGENT_UID_PATTERN.test(agentUid) &&
457
+ companyUid && /^cmp_[A-Za-z0-9_-]+$/.test(companyUid)) {
458
+ return {
459
+ type: "slack-app-token",
460
+ title: `Finish ${nonEmptyString(agent?.name) ?? "the agent"}'s Slack connection`,
461
+ summary: "connect it to Slack",
462
+ instruction: "Create an app-level token with the connections:write scope, then paste it into HQ. HQ verifies the token and resumes setup; if Slack asks you to install the app, follow the install link shown there.",
463
+ url: `https://api.slack.com/apps/${appId}/general`,
464
+ urlLabel: "Get token",
465
+ pasteUrl: `https://hq.computer/companies/${encodeURIComponent(companyUid)}/agents?setup=${encodeURIComponent(agentUid)}`,
466
+ };
467
+ }
448
468
  const diagnostics = recordValue(agent?.channelDiagnostics);
449
469
  const slack = recordValue(diagnostics?.slack);
450
470
  const url = safeActionUrl(slack?.pendingInstallUrl);
@@ -483,11 +503,12 @@ function pendingOperatorActions(status) {
483
503
  ].filter((action) => action !== null);
484
504
  }
485
505
  function pendingActionsJson(actions) {
486
- return actions.map(({ type, title, instruction, url, code }) => ({
506
+ return actions.map(({ type, title, instruction, url, pasteUrl, code }) => ({
487
507
  type,
488
508
  title,
489
509
  instruction,
490
510
  ...(url ? { url } : {}),
511
+ ...(pasteUrl ? { pasteUrl } : {}),
491
512
  ...(code ? { code } : {}),
492
513
  }));
493
514
  }
@@ -514,6 +535,8 @@ function printPendingOperatorActions(slug, actions) {
514
535
  console.log(action.instruction);
515
536
  if (action.url)
516
537
  console.log(chalk.cyan(`${action.urlLabel ?? "Open"}: ${action.url}`));
538
+ if (action.pasteUrl)
539
+ console.log(chalk.cyan(`Paste token: ${action.pasteUrl}`));
517
540
  if (action.code)
518
541
  console.log(chalk.bold(`Code: ${action.code}`));
519
542
  }
@@ -41,6 +41,7 @@ export interface PlanLock {
41
41
  export interface PlanLockFixOptions {
42
42
  removeMembersTo: number;
43
43
  disconnectIntegrations: boolean;
44
+ disconnectIntegrationsTo?: number;
44
45
  removeSecretsTo?: number;
45
46
  deprovisionAgentsTo?: number;
46
47
  }
@@ -64,6 +65,12 @@ export interface PlanLockStatus {
64
65
  }
65
66
  /** Starter member cap quoted when the server did not send `removeMembersTo`. */
66
67
  export declare const STARTER_MEMBER_TARGET = 5;
68
+ /**
69
+ * Starter integration cap quoted when the server did not send
70
+ * `disconnectIntegrationsTo`. One: Starter includes a single integration
71
+ * (US-020 owner decision 11, 2026-09-17 — it was zero before that).
72
+ */
73
+ export declare const STARTER_INTEGRATION_TARGET = 1;
67
74
  /** Starter secret cap quoted when the server did not send `removeSecretsTo`. */
68
75
  export declare const STARTER_SECRET_TARGET = 10;
69
76
  /** Starter agent cap quoted when the server did not send `deprovisionAgentsTo`. */
@@ -36,6 +36,12 @@ function isPlanLockReason(value) {
36
36
  }
37
37
  /** Starter member cap quoted when the server did not send `removeMembersTo`. */
38
38
  export const STARTER_MEMBER_TARGET = 5;
39
+ /**
40
+ * Starter integration cap quoted when the server did not send
41
+ * `disconnectIntegrationsTo`. One: Starter includes a single integration
42
+ * (US-020 owner decision 11, 2026-09-17 — it was zero before that).
43
+ */
44
+ export const STARTER_INTEGRATION_TARGET = 1;
39
45
  /** Starter secret cap quoted when the server did not send `removeSecretsTo`. */
40
46
  export const STARTER_SECRET_TARGET = 10;
41
47
  /** Starter agent cap quoted when the server did not send `deprovisionAgentsTo`. */
@@ -73,6 +79,7 @@ export function parsePlanLock(value) {
73
79
  }
74
80
  const fix = asRecord(rec.fixOptions);
75
81
  const removeMembersTo = finiteNumber(fix?.removeMembersTo) ?? STARTER_MEMBER_TARGET;
82
+ const disconnectIntegrationsTo = finiteNumber(fix?.disconnectIntegrationsTo);
76
83
  const removeSecretsTo = finiteNumber(fix?.removeSecretsTo);
77
84
  const deprovisionAgentsTo = finiteNumber(fix?.deprovisionAgentsTo);
78
85
  const fixOptions = {
@@ -81,6 +88,9 @@ export function parsePlanLock(value) {
81
88
  };
82
89
  // Absent stays absent: an omitted remedy target is UNKNOWN, and the renderer
83
90
  // quotes the published Starter cap rather than inventing a server answer.
91
+ if (disconnectIntegrationsTo !== null) {
92
+ fixOptions.disconnectIntegrationsTo = disconnectIntegrationsTo;
93
+ }
84
94
  if (removeSecretsTo !== null)
85
95
  fixOptions.removeSecretsTo = removeSecretsTo;
86
96
  if (deprovisionAgentsTo !== null) {
@@ -200,13 +210,16 @@ export function reasonLabel(reason) {
200
210
  case "users":
201
211
  return "too many members";
202
212
  case "integrations":
203
- return "integrations are not included on Starter";
213
+ return "too many integrations";
204
214
  case "secrets":
205
215
  return "too many secrets";
206
216
  case "agents":
207
217
  return "agents are not included on Starter";
208
218
  }
209
219
  }
220
+ function integrationTarget(lock) {
221
+ return lock.fixOptions.disconnectIntegrationsTo ?? STARTER_INTEGRATION_TARGET;
222
+ }
210
223
  function secretTarget(lock) {
211
224
  return lock.fixOptions.removeSecretsTo ?? STARTER_SECRET_TARGET;
212
225
  }
@@ -219,7 +232,7 @@ function reasonRemedy(reason, lock) {
219
232
  case "users":
220
233
  return `remove members until you are at ${lock.fixOptions.removeMembersTo} or fewer`;
221
234
  case "integrations":
222
- return "disconnect the workspace's integrations";
235
+ return `disconnect integrations until you are at ${integrationTarget(lock)} or fewer`;
223
236
  case "secrets":
224
237
  return `delete secrets until you are at ${secretTarget(lock)} or fewer`;
225
238
  case "agents": {
@@ -241,7 +254,7 @@ function reasonDetail(reason, status) {
241
254
  : `over its ${target}-member limit`;
242
255
  }
243
256
  case "integrations":
244
- return "integrations are not included on Starter";
257
+ return `over its ${integrationTarget(status.lock)}-integration limit`;
245
258
  case "secrets":
246
259
  return `over its ${secretTarget(status.lock)}-secret limit`;
247
260
  case "agents":
@@ -275,6 +288,9 @@ export function renderPlanLockNotice(status) {
275
288
  ? ` Members: ${members.used} of ${target}.`
276
289
  : ` Members allowed on Starter: ${target}.`);
277
290
  }
291
+ if (lock.reasons.includes("integrations")) {
292
+ lines.push(` Integrations allowed on Starter: ${integrationTarget(lock)}.`);
293
+ }
278
294
  if (lock.reasons.includes("secrets")) {
279
295
  lines.push(` Secrets allowed on Starter: ${secretTarget(lock)}.`);
280
296
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.119.4",
3
+ "version": "5.119.5",
4
4
  "description": "HQ by Indigo management CLI \u2014 modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {