@indigoai-us/hq-cli 5.98.1 → 5.98.2

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,26 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.98.2] — 2026-08-11
6
+
7
+ ### Fixed
8
+
9
+ - `hq core hq-status-summary` — and through it the `/handoff` status summary —
10
+ no longer crashes, or files a Sentry report, on a mature HQ root (HQ-CLI-N,
11
+ Sentry 7664842324). The shared `command()` helper behind the native `hq core`
12
+ utilities ran `spawnSync` with no `maxBuffer`, so every child inherited Node's
13
+ 1 MiB default. `hq-status-summary` shells out to `git status --porcelain
14
+ --ignored`, whose output exceeds 1 MiB on any HQ root carrying the usual
15
+ individually-ignored files alongside tracked content; Node then killed git with
16
+ SIGTERM, handed back truncated stdout, and surfaced `Error: spawnSync git
17
+ ENOBUFS`, failing the handoff (observed once, from a single user). The helper
18
+ now caps captured output at 512 MiB — the same ceiling the repo already uses
19
+ for git reads — matching the bundled shell oracle, which redirects git straight
20
+ to a temp file and has no ceiling at all. Spawn errors stay fatal, so a
21
+ truncated status is never reported as a real summary, and an ENOBUFS above the
22
+ new ceiling now throws an error naming the command, its args, and the cap
23
+ instead of the opaque original.
24
+
5
25
  ## [5.98.1] — 2026-08-10
6
26
 
7
27
  ### Fixed
@@ -11,4 +11,5 @@
11
11
  * non-interactively.
12
12
  */
13
13
  import "../node-preflight.js";
14
+ import "../node-network-compat.js";
14
15
  //# sourceMappingURL=hq-auth-refresh.d.ts.map
@@ -13,6 +13,7 @@
13
13
  // MUST be first: guard the Node version before any dependency that needs a
14
14
  // Node 20+ API (e.g. util.styleText) or a newer native ABI is evaluated.
15
15
  import "../node-preflight.js";
16
+ import "../node-network-compat.js";
16
17
  import { initSentry, Sentry } from "../sentry.js";
17
18
  import { refreshCachedSession } from "../utils/cognito-session.js";
18
19
  initSentry();
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import "./node-preflight.js";
3
+ import "./node-network-compat.js";
3
4
  declare function isVersionRequest(argv: readonly string[]): boolean;
4
5
  export declare const __test__: {
5
6
  isVersionRequest: typeof isVersionRequest;
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  // MUST be first: guard the Node version before any dependency that needs a
3
3
  // Node 20+ API (e.g. util.styleText) or a newer native ABI is evaluated.
4
4
  import "./node-preflight.js";
5
+ import "./node-network-compat.js";
5
6
  import { CLI_VERSION } from "./cli-version.js";
6
7
  function isVersionRequest(argv) {
7
8
  const args = argv.slice(2);
@@ -9,10 +9,34 @@ export function ioFor(io = {}) {
9
9
  export function line(write, value) {
10
10
  write(`${value}\n`);
11
11
  }
12
+ /**
13
+ * Ceiling for a single child's captured stdout, mirroring the git-read cap the
14
+ * repo already uses (src/utils/large-file-guard.ts:48). spawnSync defaults
15
+ * maxBuffer to 1 MiB; once a child's output crosses that, Node kills it with
16
+ * SIGTERM and hands back TRUNCATED stdout plus an ENOBUFS error. `hq core
17
+ * hq-status-summary` runs `git status --porcelain --ignored`, whose output
18
+ * exceeds 1 MiB on any mature HQ root (the individually-ignored files that sit
19
+ * beside tracked content), so the default turned a routine /handoff status
20
+ * summary into a crash. The bundled shell oracle this module ports
21
+ * (assets/scaffold/core/scripts/hq-status-summary.sh:108) redirects git straight
22
+ * to a temp file and has no ceiling at all; an explicit, generous cap matches it.
23
+ */
24
+ const MAX_SPAWN_BUFFER = 512 * 1024 * 1024;
12
25
  export function command(command, args, cwd) {
13
- const result = spawnSync(command, args, { cwd, encoding: "utf8" });
14
- if (result.error)
15
- throw result.error;
26
+ const result = spawnSync(command, args, { cwd, encoding: "utf8", maxBuffer: MAX_SPAWN_BUFFER });
27
+ // Spawn errors stay fatal: a truncated child result must never be reported as
28
+ // a real one — that would silently under-count a handoff's status instead of
29
+ // failing loudly. Above the new ceiling ENOBUFS is still theoretically
30
+ // reachable, so wrap it to name the command, its args and the cap; a future
31
+ // recurrence then arrives in Sentry self-diagnosed instead of as the opaque
32
+ // "spawnSync <cmd> ENOBUFS".
33
+ if (result.error) {
34
+ const error = result.error;
35
+ if (error.code === "ENOBUFS") {
36
+ throw new Error(`spawnSync ${command} ${args.join(" ")} exceeded the ${MAX_SPAWN_BUFFER}-byte output ceiling`, { cause: error });
37
+ }
38
+ throw error;
39
+ }
16
40
  return { status: result.status ?? 1, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
17
41
  }
18
42
  export function exists(pathname) {
package/dist/main.d.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  * HQ CLI - Module management, package management, and cloud sync for HQ
4
4
  */
5
5
  import "./node-preflight.js";
6
+ import "./node-network-compat.js";
6
7
  import { Sentry } from "./sentry.js";
7
8
  export declare function runCli(): Promise<void>;
8
9
  export type TopLevelErrorDependencies = {
package/dist/main.js CHANGED
@@ -5,6 +5,7 @@
5
5
  // MUST be first: guard the Node version before any dependency that needs a
6
6
  // Node 20+ API (e.g. util.styleText) or a newer native ABI is evaluated.
7
7
  import "./node-preflight.js";
8
+ import "./node-network-compat.js";
8
9
  import { Command } from "commander";
9
10
  import { initSentry, Sentry } from "./sentry.js";
10
11
  import { registerAddCommand } from "./commands/add.js";
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Node network defaults for HQ CLI entry points.
3
+ *
4
+ * Node's default 250 ms address-family attempt window can fail on hosts where
5
+ * IPv6 is advertised but black-holed. On affected WSL installations, undici's
6
+ * fetch() reaches ETIMEDOUT before its usable IPv4 path completes. A 1 second
7
+ * window fixes the connection while retaining Node's automatic family choice.
8
+ *
9
+ * Keep this module dependency-free and import it immediately after the Node
10
+ * version preflight. Operators can retain a custom value through NODE_OPTIONS
11
+ * or a direct Node CLI option; HQ only supplies the compatibility default when
12
+ * neither is present.
13
+ *
14
+ * Use a namespace import of `node:net` (not a static named import of
15
+ * `setDefaultAutoSelectFamilyAttemptTimeout`). Named ESM imports are linked
16
+ * before any entry-module body runs — including `node-preflight` — so importing
17
+ * a Node 18.13+/20.4+ API by name would turn unsupported runtimes into a
18
+ * module-link SyntaxError instead of the preflight's upgrade message.
19
+ */
20
+ export declare const HQ_NETWORK_FAMILY_ATTEMPT_TIMEOUT_MS = 1000;
21
+ export interface NodeNetworkCompatibilityOptions {
22
+ nodeOptions?: string;
23
+ execArgv?: readonly string[];
24
+ /**
25
+ * Inject the net timeout setter (tests). Pass `null` to simulate a runtime
26
+ * that lacks `setDefaultAutoSelectFamilyAttemptTimeout`.
27
+ */
28
+ setAttemptTimeout?: ((milliseconds: number) => void) | null;
29
+ }
30
+ export declare function configureNodeNetworkCompatibility(options?: NodeNetworkCompatibilityOptions): boolean;
31
+ //# sourceMappingURL=node-network-compat.d.ts.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Node network defaults for HQ CLI entry points.
3
+ *
4
+ * Node's default 250 ms address-family attempt window can fail on hosts where
5
+ * IPv6 is advertised but black-holed. On affected WSL installations, undici's
6
+ * fetch() reaches ETIMEDOUT before its usable IPv4 path completes. A 1 second
7
+ * window fixes the connection while retaining Node's automatic family choice.
8
+ *
9
+ * Keep this module dependency-free and import it immediately after the Node
10
+ * version preflight. Operators can retain a custom value through NODE_OPTIONS
11
+ * or a direct Node CLI option; HQ only supplies the compatibility default when
12
+ * neither is present.
13
+ *
14
+ * Use a namespace import of `node:net` (not a static named import of
15
+ * `setDefaultAutoSelectFamilyAttemptTimeout`). Named ESM imports are linked
16
+ * before any entry-module body runs — including `node-preflight` — so importing
17
+ * a Node 18.13+/20.4+ API by name would turn unsupported runtimes into a
18
+ * module-link SyntaxError instead of the preflight's upgrade message.
19
+ */
20
+ import * as nodeNet from "node:net";
21
+ export const HQ_NETWORK_FAMILY_ATTEMPT_TIMEOUT_MS = 1000;
22
+ const ATTEMPT_TIMEOUT_OPTION = "--network-family-autoselection-attempt-timeout";
23
+ function hasExplicitAttemptTimeout(nodeOptions, execArgv) {
24
+ const optionPattern = new RegExp(`(?:^|\\s)${ATTEMPT_TIMEOUT_OPTION}(?:=|\\s|$)`);
25
+ return (optionPattern.test(nodeOptions) ||
26
+ execArgv.some((argument) => argument === ATTEMPT_TIMEOUT_OPTION ||
27
+ argument.startsWith(`${ATTEMPT_TIMEOUT_OPTION}=`)));
28
+ }
29
+ function resolveSetAttemptTimeout(override) {
30
+ if (override === null)
31
+ return undefined;
32
+ if (override)
33
+ return override;
34
+ const fn = nodeNet.setDefaultAutoSelectFamilyAttemptTimeout;
35
+ return typeof fn === "function" ? fn.bind(nodeNet) : undefined;
36
+ }
37
+ export function configureNodeNetworkCompatibility(options = {}) {
38
+ const nodeOptions = options.nodeOptions ?? process.env.NODE_OPTIONS ?? "";
39
+ const execArgv = options.execArgv ?? process.execArgv;
40
+ if (hasExplicitAttemptTimeout(nodeOptions, execArgv)) {
41
+ return false;
42
+ }
43
+ const setAttemptTimeout = resolveSetAttemptTimeout(options.setAttemptTimeout);
44
+ if (!setAttemptTimeout) {
45
+ // Runtime lacks the API (pre-Node 18.13 / preflight should already have exited).
46
+ return false;
47
+ }
48
+ setAttemptTimeout(HQ_NETWORK_FAMILY_ATTEMPT_TIMEOUT_MS);
49
+ return true;
50
+ }
51
+ configureNodeNetworkCompatibility();
52
+ //# sourceMappingURL=node-network-compat.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.98.1",
3
+ "version": "5.98.2",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {