@indigoai-us/hq-cli 5.345.165 → 5.345.166

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,15 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.345.166] — 2026-10-24
6
+ - `hq integrations approve` now says why an approved call did not run. When an app refuses it, the CLI prints the app's own reason, such as Slack's refusal to send into a Slack Connect channel. Before this it printed only "failed (rejected)". With an older server it prints the rejection code instead. `hq integrations pending --history` adds a `Why:` line for decided calls that did not run. The approve command printed after a queued call keeps `--company` when you passed it. Before printing, the reason is cleaned of terminal escape codes, credentials and credential-bearing links, and it is capped at 500 characters. Feedback 15e7593c-50e5-4e6a-ae3a-342d618363c0.
7
+ - The bundled sync engine now uses hq-cloud 6.18.101, the current npm `latest`.
8
+ A 403 from the flags endpoint (for example a stale company in the local
9
+ manifest) is now held as `false` for an hour instead of being re-read and
10
+ logged on every telemetry pass (hq-cloud #1046).
11
+ - `hq doctor` no longer counts runner telemetry errors as sync receiver permission refusals. A failed outcome-flag read ("hq-flags: resolve returned 403") for a company you are not a member of used to inflate `sync.runtime.receiver-permission`; only the receiver's own events are counted now.
12
+ - The bundled shell fallbacks for `rebuild-index` all, orchestrator, public-knowledge, reports, social-drafts, threads, and workers now print the same usage as the native command for `--help`/`-h` and exit without writing. Before, they ignored the flag and rebuilt the index, which failed the published core command parity check.
13
+
5
14
  ## [5.345.165] — 2026-10-23
6
15
  - `hq billing sponsor grant <email|prs_id> --company <slug>` lets a company owner or admin put a member's personal plan on the company bill without a request first; `--all-members` does it for every active member and reports each person as covered, already covered, or skipped. `hq billing sponsor ungrant <email|prs_id>` takes it off again. hq-pro checks the owner/admin role and active membership.
7
16
  - `hq scan secrets <files...>` takes `--repo <dir>`, which applies that repo's committed `.gitleaks.toml` allowlists to a file scan, matching each file by its path relative to the repo, as a staged scan does. `--snapshot-root <dir>` (with `--repo`) matches files laid out as `<dir>/<commit>/<repo path>`, the history copies `commit-secret-scan.sh pr-check` writes, as `<repo path>`. Findings still name the files as given. Before this, a file scan ignored the repo's allowlists, so pr-check failed on false positives the commit gate already allowed. Without `--repo` a file scan is unchanged.
@@ -11,6 +11,17 @@
11
11
 
12
12
  set -uo pipefail
13
13
 
14
+ # Help must never write: print the same usage as `hq core rebuild-index all --help`.
15
+ for arg in "$@"; do
16
+ if [[ "$arg" == "--help" || "$arg" == "-h" ]]; then
17
+ printf '%s\n' \
18
+ 'Usage: hq core rebuild-index all [--accept]' \
19
+ '' \
20
+ 'Regenerate every INDEX.md across the HQ tree. Help performs no writes.'
21
+ exit 0
22
+ fi
23
+ done
24
+
14
25
  HQ_ROOT="${HQ_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
15
26
  cd "$HQ_ROOT"
16
27
 
@@ -12,6 +12,17 @@
12
12
 
13
13
  set -euo pipefail
14
14
 
15
+ # Help must never write: print the same usage as `hq core rebuild-index orchestrator --help`.
16
+ for arg in "$@"; do
17
+ if [[ "$arg" == "--help" || "$arg" == "-h" ]]; then
18
+ printf '%s\n' \
19
+ 'Usage: hq core rebuild-index orchestrator [--accept]' \
20
+ '' \
21
+ 'Regenerate the orchestrator workspace INDEX.md. Help performs no writes.'
22
+ exit 0
23
+ fi
24
+ done
25
+
15
26
  HQ_ROOT="${HQ_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
16
27
  cd "$HQ_ROOT"
17
28
 
@@ -7,6 +7,17 @@
7
7
 
8
8
  set -euo pipefail
9
9
 
10
+ # Help must never write: print the same usage as `hq core rebuild-index public-knowledge --help`.
11
+ for arg in "$@"; do
12
+ if [[ "$arg" == "--help" || "$arg" == "-h" ]]; then
13
+ printf '%s\n' \
14
+ 'Usage: hq core rebuild-index public-knowledge [--accept]' \
15
+ '' \
16
+ 'Regenerate core/knowledge/public/INDEX.md. Help performs no writes.'
17
+ exit 0
18
+ fi
19
+ done
20
+
10
21
  HQ_ROOT="${HQ_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
11
22
  cd "$HQ_ROOT"
12
23
 
@@ -8,6 +8,17 @@
8
8
 
9
9
  set -euo pipefail
10
10
 
11
+ # Help must never write: print the same usage as `hq core rebuild-index reports --help`.
12
+ for arg in "$@"; do
13
+ if [[ "$arg" == "--help" || "$arg" == "-h" ]]; then
14
+ printf '%s\n' \
15
+ 'Usage: hq core rebuild-index reports [--accept]' \
16
+ '' \
17
+ 'Regenerate the reports INDEX.md. Help performs no writes.'
18
+ exit 0
19
+ fi
20
+ done
21
+
11
22
  HQ_ROOT="${HQ_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
12
23
  cd "$HQ_ROOT"
13
24
 
@@ -8,6 +8,17 @@
8
8
 
9
9
  set -euo pipefail
10
10
 
11
+ # Help must never write: print the same usage as `hq core rebuild-index social-drafts --help`.
12
+ for arg in "$@"; do
13
+ if [[ "$arg" == "--help" || "$arg" == "-h" ]]; then
14
+ printf '%s\n' \
15
+ 'Usage: hq core rebuild-index social-drafts [--accept]' \
16
+ '' \
17
+ 'Regenerate workspace/social-drafts/INDEX.md. Help performs no writes.'
18
+ exit 0
19
+ fi
20
+ done
21
+
11
22
  HQ_ROOT="${HQ_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
12
23
  # shellcheck source=core/scripts/lib/portable.sh
13
24
  . "$HQ_ROOT/core/scripts/lib/portable.sh"
@@ -11,6 +11,17 @@
11
11
 
12
12
  set -euo pipefail
13
13
 
14
+ # Help must never write: print the same usage as `hq core rebuild-index threads --help`.
15
+ for arg in "$@"; do
16
+ if [[ "$arg" == "--help" || "$arg" == "-h" ]]; then
17
+ printf '%s\n' \
18
+ 'Usage: hq core rebuild-index threads [--accept]' \
19
+ '' \
20
+ 'Regenerate the session-threads INDEX.md. Help performs no writes.'
21
+ exit 0
22
+ fi
23
+ done
24
+
14
25
  HQ_ROOT="${HQ_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
15
26
  cd "$HQ_ROOT"
16
27
 
@@ -7,6 +7,17 @@
7
7
 
8
8
  set -euo pipefail
9
9
 
10
+ # Help must never write: print the same usage as `hq core rebuild-index workers --help`.
11
+ for arg in "$@"; do
12
+ if [[ "$arg" == "--help" || "$arg" == "-h" ]]; then
13
+ printf '%s\n' \
14
+ 'Usage: hq core rebuild-index workers [--accept]' \
15
+ '' \
16
+ 'Regenerate the workers INDEX.md. Help performs no writes.'
17
+ exit 0
18
+ fi
19
+ done
20
+
10
21
  HQ_ROOT="${HQ_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
11
22
  cd "$HQ_ROOT"
12
23
 
@@ -292,6 +292,10 @@ export interface PendingApproval {
292
292
  status?: string;
293
293
  /** Owner-facing outcome projected by hq-pro for decided rows. */
294
294
  outcome?: string;
295
+ /** Closed rejection code for a rejected row (e.g. provider_tool_error); older servers omit it. */
296
+ rejectionReason?: string | null;
297
+ /** Plain reason a decided row did not run, such as the app's own refusal text; older servers omit it. */
298
+ failureMessage?: string | null;
295
299
  }
296
300
  /**
297
301
  * Read open approvals from hq-pro's confirm-queue state (not the audit feed).
@@ -307,4 +311,15 @@ export declare function mutateConnectionAccess(token: string, companyUid: string
307
311
  granteeId?: string;
308
312
  permission?: Permission;
309
313
  }): Promise<ConnectionAccess>;
314
+ /** Same cap the server applies to a failure reason; the CLI enforces it for older or malformed responses. */
315
+ export declare const TERMINAL_REASON_MAX_CHARS = 500;
316
+ /**
317
+ * Server-supplied text that reaches the terminal (a failure reason quoting an
318
+ * app's error). ANSI escapes, control and invisible formatting characters are
319
+ * removed, then the same credential-redaction chain the gateway diagnostics use
320
+ * (`redactErrorText`: credential URLs, bearer values, token assignments, known
321
+ * token shapes) is applied, and the result is capped. The server redacts too;
322
+ * this keeps an older or misbehaving server from printing a secret.
323
+ */
324
+ export declare function terminalSafeText(text: string): string;
310
325
  //# sourceMappingURL=integrations-api.d.ts.map
@@ -8,6 +8,7 @@
8
8
  * is optional and read defensively.
9
9
  */
10
10
  import { vaultApiFetch } from "../utils/vault-api.js";
11
+ import { redactErrorText } from "../utils/redact-error-text.js";
11
12
  import { IntegrationsCliError, raiseForResponse, } from "./integrations-core.js";
12
13
  export async function listCatalog(token, companyUid, opts = {}) {
13
14
  const query = {
@@ -188,4 +189,30 @@ export async function mutateConnectionAccess(token, companyUid, action, input) {
188
189
  }
189
190
  return (await res.json());
190
191
  }
192
+ // eslint-disable-next-line no-control-regex
193
+ const TERMINAL_ESCAPES = /\u001b\[[0-?]*[ -/]*[@-~]|\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)?|\u001b[@-_]/g;
194
+ // eslint-disable-next-line no-control-regex
195
+ const TERMINAL_CONTROL_CHARS = /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g;
196
+ /** Bidirectional overrides, isolates, marks and zero-width characters, which can reorder or hide text. */
197
+ const TERMINAL_INVISIBLE_FORMAT_CHARS = /[\u200b-\u200f\u202a-\u202e\u2060-\u2069\ufeff]/g;
198
+ /** Same cap the server applies to a failure reason; the CLI enforces it for older or malformed responses. */
199
+ export const TERMINAL_REASON_MAX_CHARS = 500;
200
+ /**
201
+ * Server-supplied text that reaches the terminal (a failure reason quoting an
202
+ * app's error). ANSI escapes, control and invisible formatting characters are
203
+ * removed, then the same credential-redaction chain the gateway diagnostics use
204
+ * (`redactErrorText`: credential URLs, bearer values, token assignments, known
205
+ * token shapes) is applied, and the result is capped. The server redacts too;
206
+ * this keeps an older or misbehaving server from printing a secret.
207
+ */
208
+ export function terminalSafeText(text) {
209
+ const visible = text
210
+ .replace(TERMINAL_ESCAPES, "")
211
+ .replace(TERMINAL_CONTROL_CHARS, "")
212
+ .replace(TERMINAL_INVISIBLE_FORMAT_CHARS, "");
213
+ const redacted = redactErrorText(visible);
214
+ return redacted.length > TERMINAL_REASON_MAX_CHARS
215
+ ? `${redacted.slice(0, TERMINAL_REASON_MAX_CHARS - 1)}…`
216
+ : redacted;
217
+ }
191
218
  //# sourceMappingURL=integrations-api.js.map
@@ -18,7 +18,7 @@ import { ensureCognitoIdToken } from "../utils/cognito-session.js";
18
18
  import { getCompanyUid } from "../utils/vault-api.js";
19
19
  import { redactSensitiveUrl, redactUrlsInText } from "../utils/redact-url.js";
20
20
  import { IntegrationsCliError, bareProvider, printHealthNotice, fetchConnections, fetchAdminSurface, fetchAuditPage, AUDIT_PAGE_MAX, printJson, revokedConnectionDetails, resolveConnection, selectConnection, } from "./integrations-core.js";
21
- import { fetchPendingApprovals, getConnectionAccess, mutateConnectionAccess, purgeConnection, setReadSafe, uninstallIntegration, updateGovernance, } from "./integrations-api.js";
21
+ import { fetchPendingApprovals, getConnectionAccess, mutateConnectionAccess, purgeConnection, setReadSafe, terminalSafeText, uninstallIntegration, updateGovernance, } from "./integrations-api.js";
22
22
  const WRITE_POLICIES = ["auto-allow", "confirm", "deny"];
23
23
  const PERMISSIONS = ["read", "write", "admin"];
24
24
  /** Plain-English gloss for each write policy, used in every policy readout. */
@@ -617,9 +617,11 @@ export function registerManageCommands(integrations) {
617
617
  console.log(`${chalk.bold(label)} ${chalk.dim(`${who} · ${row.createdAt}`)}`);
618
618
  if (opts.history) {
619
619
  console.log(chalk.dim(` ${row.queueId} · ${row.status ?? row.outcome ?? "status unavailable"}`));
620
+ if (row.failureMessage)
621
+ console.log(chalk.dim(` Why: ${terminalSafeText(row.failureMessage)}`));
620
622
  }
621
623
  else {
622
- console.log(chalk.dim(` hq integrations approve ${row.queueId}${row.provider ? ` --provider ${bareProvider(row.provider)}` : ""}`));
624
+ console.log(chalk.dim(` hq integrations approve ${row.queueId}${row.provider ? ` --provider ${bareProvider(row.provider)}` : ""}${opts.company ? ` --company ${opts.company}` : ""}`));
623
625
  }
624
626
  }
625
627
  });
@@ -61,7 +61,7 @@ import { registerConnectCommands } from "./integrations-connect.js";
61
61
  import { registerImportCommands } from "./integrations-import.js";
62
62
  import { registerManageCommands } from "./integrations-manage.js";
63
63
  import { registerSlackCommands } from "./integrations-slack.js";
64
- import { fetchPendingApprovals } from "./integrations-api.js";
64
+ import { fetchPendingApprovals, terminalSafeText } from "./integrations-api.js";
65
65
  const CALL_ARGS_EXAMPLE = `--args '{"assignee":"me"}' or --args-file args.json`;
66
66
  function readStream(stream) {
67
67
  return new Promise((resolve, reject) => {
@@ -533,7 +533,7 @@ export function registerIntegrationsCommand(program) {
533
533
  return;
534
534
  }
535
535
  console.log(chalk.yellow("Queued for approval — this call can change the app, so a company owner decides first."));
536
- console.log(`Approve with:\n hq integrations approve ${queued.queueId} --provider ${bareProvider(connection.provider)}`);
536
+ console.log(`Approve with:\n hq integrations approve ${queued.queueId} --provider ${bareProvider(connection.provider)}${opts.company ? ` --company ${opts.company}` : ""}`);
537
537
  if (queued.expiresAt) {
538
538
  console.log(chalk.dim(`Expires ${queued.expiresAt}`));
539
539
  }
@@ -606,7 +606,9 @@ export function registerIntegrationsCommand(program) {
606
606
  const unknown = terminal.status === "write_unknown" || terminal.outcome === "unknown";
607
607
  console.log(chalk.red(unknown
608
608
  ? `The provider outcome is unknown for ${queueId}. Check the provider before taking any action; ${historyCommand} shows the latest queue state.`
609
- : `The approved call failed (${terminal.status ?? terminal.outcome}). See ${historyCommand} for its status.`));
609
+ : terminal.failureMessage
610
+ ? `The approved call did not run: ${terminalSafeText(terminal.failureMessage)}`
611
+ : `The approved call failed (${terminal.rejectionReason ?? terminal.status ?? terminal.outcome}). See ${historyCommand} for its status.`));
610
612
  }
611
613
  else if (terminal.status === "resumed" || terminal.status === "completed" || terminal.outcome === "ran") {
612
614
  console.log(chalk.green("Approved — the call completed."));
@@ -614,7 +616,7 @@ export function registerIntegrationsCommand(program) {
614
616
  printJson(unwrapGatewayResult(stored.result));
615
617
  }
616
618
  else if (ran) {
617
- console.log(chalk.yellow(`The call's result could not be read back. Run \`hq integrations approve ${queueId}\` again to fetch it; the call will not run twice.`));
619
+ console.log(chalk.yellow(`The call's result could not be read back. Run \`hq integrations approve ${queueId} --provider ${bareProvider(connection.provider)}${opts.company ? ` --company ${opts.company}` : ""}\` again to fetch it; the call will not run twice.`));
618
620
  }
619
621
  }
620
622
  else {
@@ -649,7 +651,9 @@ export function registerIntegrationsCommand(program) {
649
651
  if (failed) {
650
652
  const reason = body.rejectionReason ??
651
653
  (toolError ? "provider_tool_error" : body.outcome ?? body.status ?? "failed");
652
- console.log(chalk.red(`The approved call failed at the provider (${reason}).`));
654
+ console.log(chalk.red(body.failureMessage
655
+ ? `The approved call did not run: ${terminalSafeText(body.failureMessage)}`
656
+ : `The approved call failed at the provider (${reason}).`));
653
657
  }
654
658
  else if (body.status === "resumed" || body.status === "completed" || body.outcome === "ran") {
655
659
  console.log(chalk.green(`Approved — the call ran (status: ${body.status ?? body.outcome}).`));