@indigoai-us/hq-cli 5.111.2 → 5.112.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.
@@ -1,32 +1,7 @@
1
1
  /**
2
- * The full hq command graph every `register*Command` call, moved here verbatim
3
- * from main.ts.
4
- *
5
- * WHY IT IS ITS OWN MODULE: these 54 imports pull ~60 command modules and their
6
- * dependency subtrees, and main.ts used to load all of them at module scope. On
7
- * an outpost that cost real CPU, because the agent fleet calls `hq secrets`
8
- * about 39 times a minute and each invocation paid for the entire graph before
9
- * running one command. Measured on Outpost 2 (i-09424eff61920a4ac), CPU-seconds
10
- * per process:
11
- *
12
- * node -e "" 0.03
13
- * dist/commands/secrets.js 1.13 <- what `hq secrets` actually needs
14
- * dist/main.js (full graph) 1.88 <- what it used to pay
15
- *
16
- * So ~0.75 CPU-seconds of every `hq secrets` was spent importing commands it
17
- * never ran. At 39 invocations/minute that is ~0.5 of a core, continuously.
18
- *
19
- * Splitting the graph out lets the entrypoint import ONE command module for the
20
- * hot paths named in lazy-commands.ts, and fall back to this module — the
21
- * complete, unchanged registration — for everything else: `--help`, a bare
22
- * `hq`, an unknown command, and every command not in that manifest. Anything
23
- * not on the manifest therefore behaves exactly as before.
24
- *
25
- * Keep this list and lazy-commands.ts in sync through the parity test in
26
- * lazy-commands.test.ts, which registers both ways and compares the resulting
27
- * command shapes. Same discipline as commands/scaffold-fast.ts and core.ts.
2
+ * Complete command registration, retained as the eager reference used by the
3
+ * generated-catalog check and parity tests. Runtime dispatch uses the same
4
+ * plan one root at a time through lazy-commands.ts.
28
5
  */
29
- import type { Command } from "commander";
30
- /** Register the complete hq command graph onto `program`. */
31
- export declare function registerAllCommands(program: Command): void;
6
+ export { registerAllCommands, registerCommandRoot } from "./command-registration-plan.js";
32
7
  //# sourceMappingURL=register-all.d.ts.map
@@ -1,238 +1,7 @@
1
1
  /**
2
- * The full hq command graph every `register*Command` call, moved here verbatim
3
- * from main.ts.
4
- *
5
- * WHY IT IS ITS OWN MODULE: these 54 imports pull ~60 command modules and their
6
- * dependency subtrees, and main.ts used to load all of them at module scope. On
7
- * an outpost that cost real CPU, because the agent fleet calls `hq secrets`
8
- * about 39 times a minute and each invocation paid for the entire graph before
9
- * running one command. Measured on Outpost 2 (i-09424eff61920a4ac), CPU-seconds
10
- * per process:
11
- *
12
- * node -e "" 0.03
13
- * dist/commands/secrets.js 1.13 <- what `hq secrets` actually needs
14
- * dist/main.js (full graph) 1.88 <- what it used to pay
15
- *
16
- * So ~0.75 CPU-seconds of every `hq secrets` was spent importing commands it
17
- * never ran. At 39 invocations/minute that is ~0.5 of a core, continuously.
18
- *
19
- * Splitting the graph out lets the entrypoint import ONE command module for the
20
- * hot paths named in lazy-commands.ts, and fall back to this module — the
21
- * complete, unchanged registration — for everything else: `--help`, a bare
22
- * `hq`, an unknown command, and every command not in that manifest. Anything
23
- * not on the manifest therefore behaves exactly as before.
24
- *
25
- * Keep this list and lazy-commands.ts in sync through the parity test in
26
- * lazy-commands.test.ts, which registers both ways and compares the resulting
27
- * command shapes. Same discipline as commands/scaffold-fast.ts and core.ts.
2
+ * Complete command registration, retained as the eager reference used by the
3
+ * generated-catalog check and parity tests. Runtime dispatch uses the same
4
+ * plan one root at a time through lazy-commands.ts.
28
5
  */
29
- import { registerAddCommand } from "./commands/add.js";
30
- import { registerSyncCommand } from "./commands/sync.js";
31
- import { registerListCommand } from "./commands/list.js";
32
- import { registerUpdateCommand } from "./commands/update.js";
33
- import { registerCloudCommands } from "./commands/cloud.js";
34
- import { registerSyncModeCommand } from "./commands/sync-mode.js";
35
- import { registerSyncNarrowCommand } from "./commands/sync-narrow.js";
36
- import { registerSyncManifestCommand } from "./commands/sync-manifest.js";
37
- import { registerCloudProvisionCommands } from "./commands/cloud-provision.js";
38
- import { registerCloudDemoteCommands } from "./commands/cloud-demote.js";
39
- import { registerLoginCommand } from "./commands/login.js";
40
- import { registerLogoutCommand } from "./commands/logout.js";
41
- import { registerWhoamiCommand } from "./commands/whoami.js";
42
- import { registerOnboardCommand } from "./commands/onboard.js";
43
- import { registerPackageInstallCommand } from "./commands/pkg-install.js";
44
- import { registerPackageRemoveCommand } from "./commands/pkg-remove.js";
45
- import { registerPackageUpdateCommand } from "./commands/pkg-update.js";
46
- import { registerPackageListCommand } from "./commands/pkg-list.js";
47
- import { registerPacksCommand } from "./commands/packs.js";
48
- import { registerPublishCommand } from "./commands/publish.js";
49
- import { registerCreatorsCommand } from "./commands/creators.js";
50
- import { registerTeamSyncCommand } from "./commands/team-sync.js";
51
- import { registerAuthCommands } from "./commands/auth.js";
52
- import { registerApiKeysCommand } from "./commands/api-keys.js";
53
- import { registerSecretsCommand } from "./commands/secrets.js";
54
- import { registerRunCommand } from "./commands/run.js";
55
- import { registerGroupsCommand } from "./commands/groups.js";
56
- import { registerWorkersCommand } from "./commands/workers.js";
57
- import { registerGroupGrantsCommand } from "./commands/group-grants.js";
58
- import { registerFilesCommand } from "./commands/files.js";
59
- import { registerFilesBrowseCommands } from "./commands/files-browse.js";
60
- import { registerAccessCommand } from "./commands/access.js";
61
- import { registerSkillCommand } from "./commands/skill.js";
62
- import { registerMembersCommand } from "./commands/members.js";
63
- import { registerPeopleCommand } from "./commands/people.js";
64
- import { registerDmCommand } from "./commands/dm.js";
65
- import { registerChannelsCommand } from "./commands/channels.js";
66
- import { registerFeedbackCommand } from "./commands/feedback.js";
67
- import { registerMeetingsCommand } from "./commands/meetings.js";
68
- import { registerSourcesCommand } from "./commands/sources.js";
69
- import { registerSignalsCommand } from "./commands/signals.js";
70
- import { registerIntegrationsCommand } from "./commands/integrations.js";
71
- import { registerReindexCommand } from "./commands/reindex.js";
72
- import { registerRescueCommand } from "./commands/rescue.js";
73
- import { registerMcpCommand } from "./commands/mcp-status.js";
74
- import { registerCrmCommand } from "./commands/crm.js";
75
- import { registerCompanyCommand } from "./commands/company.js";
76
- import { registerAgentsCommand } from "./commands/agents.js";
77
- import { registerOutpostsCommand } from "./commands/outposts.js";
78
- import { registerBillingCommand } from "./commands/billing.js";
79
- import { registerDbCommand } from "./commands/db.js";
80
- import { registerCoreCommands } from "./commands/core.js";
81
- import { registerSearchCommand } from "./commands/search.js";
82
- import { registerIndexCommand } from "./commands/index-cmd.js";
83
- import { registerDoctorCommand } from "./commands/doctor.js";
84
- import { registerMeshCommand } from "./commands/mesh.js";
85
- import { registerBotCommand } from "./commands/bot.js";
86
- /** Register the complete hq command graph onto `program`. */
87
- export function registerAllCommands(program) {
88
- // Module management subcommand group
89
- const modulesCmd = program
90
- .command("modules")
91
- .description("Module management commands");
92
- registerAddCommand(modulesCmd);
93
- registerSyncCommand(modulesCmd);
94
- registerListCommand(modulesCmd);
95
- registerUpdateCommand(modulesCmd);
96
- // Package management subcommand group
97
- const packagesCmd = program
98
- .command("packages")
99
- .description("Package management commands");
100
- registerPackageInstallCommand(packagesCmd);
101
- registerPackageRemoveCommand(packagesCmd);
102
- registerPackageUpdateCommand(packagesCmd);
103
- registerPackageListCommand(packagesCmd);
104
- // Content-pack lifecycle (core/packages/hq-pack-*). Distinct from the registry
105
- // `packages` system above. Available as both `hq packages packs …` (grouped)
106
- // and `hq packs …` (top-level convenience).
107
- registerPacksCommand(packagesCmd);
108
- registerPacksCommand(program);
109
- // Top-level shortcuts for package commands
110
- // "hq install <slug>" = "hq packages install <slug>"
111
- // "hq remove <slug>" = "hq packages remove <slug>"
112
- registerPackageInstallCommand(program);
113
- registerPackageRemoveCommand(program);
114
- // Marketplace publish (top-level — packer + authenticated upload, US-004)
115
- // "hq publish <skill-or-worker-path>" packages and submits a pack to the
116
- // marketplace via POST /v1/listings.
117
- registerPublishCommand(program);
118
- // `hq creators apply` — request verified-creator access (required to publish).
119
- registerCreatorsCommand(program);
120
- // Cloud sync subcommand group
121
- const syncCmd = program
122
- .command("sync")
123
- .description("Cloud sync commands — sync HQ to S3 for mobile access");
124
- registerCloudCommands(syncCmd);
125
- registerSyncModeCommand(syncCmd);
126
- registerSyncNarrowCommand(syncCmd);
127
- registerSyncManifestCommand(syncCmd);
128
- // Cloud provisioning subcommand group (entity + bucket + initial sync)
129
- // Distinct from `hq sync` which assumes provisioning has already happened.
130
- const cloudCmd = program
131
- .command("cloud")
132
- .description("Cloud commands — provision entities and manage cloud-backed companies");
133
- registerCloudProvisionCommands(cloudCmd);
134
- registerCloudDemoteCommands(cloudCmd);
135
- // Team commands (top-level)
136
- registerTeamSyncCommand(program);
137
- // Auth commands (top-level — Cognito OAuth)
138
- registerLoginCommand(program);
139
- registerLogoutCommand(program);
140
- registerWhoamiCommand(program);
141
- registerAuthCommands(program);
142
- // Secrets management (subcommand group — hq secrets set|get|list|delete|exec|generate-link|cache)
143
- registerSecretsCommand(program);
144
- // Vault databases (subcommand group — hq db status|sql|migrate|provision)
145
- registerDbCommand(program);
146
- // API key management (subcommand group — hq api-keys create|list|revoke)
147
- registerApiKeysCommand(program);
148
- // Schema-driven dev runner — hq run [options] -- <cmd>
149
- registerRunCommand(program);
150
- // Groups management (subcommand group — hq groups create|delete|add|remove|list|members)
151
- registerGroupsCommand(program);
152
- // Worker discovery + sharing (subcommand group — hq workers list|share)
153
- registerWorkersCommand(program);
154
- // Cross-company group grants (subcommand group —
155
- // hq group-grants grant|revoke|outbound|inbound)
156
- registerGroupGrantsCommand(program);
157
- // Files ACL management (subcommand group — hq files share|unshare|acl)
158
- // `registerFilesCommand` returns the `files` group so we can attach the
159
- // browse-vs-sync subcommands (`hq files browse`/`cat`) onto the same group.
160
- const filesCmd = registerFilesCommand(program);
161
- registerFilesBrowseCommands(filesCmd);
162
- // Top-level `hq access` — vault existence + ACL probe (self-healing ladder).
163
- registerAccessCommand(program);
164
- // Comment-only skill improvement loop. Structured suggestion/review commands are
165
- // intentionally absent; live content changes remain governed by FILE_ACL sync.
166
- registerSkillCommand(program);
167
- // Membership management (subcommand group — hq members invite|list|revoke)
168
- registerMembersCommand(program);
169
- // People directory (subcommand group — hq people list|search|resolve), reading
170
- // the local companies/<co>/people store scoped to one company.
171
- registerPeopleCommand(program);
172
- registerDmCommand(program);
173
- registerChannelsCommand(program);
174
- // Onboarding (top-level — Cognito + vault-service provisioning)
175
- registerOnboardCommand(program);
176
- // Feedback (subcommand group — hq feedback bug|feature)
177
- registerFeedbackCommand(program);
178
- // Meetings (subcommand group — hq meetings list|get|search|transcript|notes)
179
- registerMeetingsCommand(program);
180
- // Sources read surface (subcommand group — hq sources list|get|channels|entities)
181
- registerSourcesCommand(program);
182
- // Signals read surface (subcommand group — hq signals list|get|types|entities)
183
- registerSignalsCommand(program);
184
- // Company-connected apps via the governed integration gateway
185
- // (subcommand group — hq integrations list|tools|call|approve|reject)
186
- registerIntegrationsCommand(program);
187
- // Skill/personal-overlay mirroring + workers-registry regen. Invoked by the
188
- // hq-core reindex hook shim (Stop / PostToolUse) and by sync()/rescue() after
189
- // they change on-disk sources. Keeps a `master-sync` alias for one release.
190
- // Implementation lives in @indigoai-us/hq-cloud.
191
- registerReindexCommand(program);
192
- // Drift-preserving HQ-core re-sync (top-level — `hq rescue`). CLI sibling of
193
- // the HQ Sync app's "Update / Restore" pill; drives the same replace-rescue.sh
194
- // shipped from @indigoai-us/hq-cloud.
195
- registerRescueCommand(program);
196
- // MCP pack observability (subcommand group — `hq mcp status`). Read-only
197
- // provenance-based status across BOTH Claude + Codex runtimes (reads `_hqPack`
198
- // off the configs, NOT linkStatus), with secret-redacted output + `--json`.
199
- registerMcpCommand(program);
200
- // Native CRM entity upsert (subcommand group — `hq crm entity upsert`). Wraps
201
- // POST /crm/entities (the ontology write gate) so an authenticated company
202
- // member can create/update canonical CRM entities in the company vault.
203
- registerCrmCommand(program);
204
- // Company settings (subcommand group — `hq company settings set`). Owner-only
205
- // toggles for crmEnabled / ontologyEnabled via PUT /company-settings.
206
- registerCompanyCommand(program);
207
- // Cloud agent management (subcommand group — `hq agents …`). Rename, reconfigure,
208
- // start/stop, and tear down a company's fleet agents via the hq-pro /v1/agents
209
- // control plane — the same routes the web console's agents panel calls.
210
- registerAgentsCommand(program);
211
- // Personal Outpost management (subcommand group — `hq outposts …`). List, inspect,
212
- // enable Codex on, refresh login for, and destroy your EC2 boxes via the hq-pro
213
- // /outpost/* control plane.
214
- registerOutpostsCommand(program);
215
- // Billing (subcommand group — `hq billing …`). Check subscription/card state and
216
- // mint a shareable Stripe card-capture link — the client side of the paid-
217
- // provisioning gate for agents & Outposts.
218
- registerBillingCommand(program);
219
- // HQ scaffold scripts hosted by the CLI (hidden group — `hq core …`). Not a
220
- // public surface: every entry is invoked by an HQ skill, hook, or forwarder, and
221
- // the source-root entries are maintainer tools that must never touch a live
222
- // install. Registered from a manifest in the module, not wired per script here.
223
- registerCoreCommands(program);
224
- // Local qmd search and index management. Kept distinct from `hq reindex`,
225
- // which converges scaffold-owned files and hooks rather than search data.
226
- registerSearchCommand(program);
227
- registerIndexCommand(program);
228
- // Hook guardrail diagnostics (top-level — `hq doctor`). Read-only, offline
229
- // verification that HQ's hooks are wired and firing, backed by an extensible
230
- // check registry so later check families (vault, sync, MCP, …) plug in without
231
- // engine changes.
232
- registerDoctorCommand(program);
233
- // Work mesh (subcommand group — `hq mesh …`). Native REST + cache. Distinct
234
- // from `hq doctor` (hook guardrails). Does not start MQTT listen.
235
- registerMeshCommand(program);
236
- registerBotCommand(program);
237
- }
6
+ export { registerAllCommands, registerCommandRoot } from "./command-registration-plan.js";
238
7
  //# sourceMappingURL=register-all.js.map
package/dist/sentry.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as Sentry from "@sentry/node";
2
- import type { ErrorEvent, EventHint } from "@sentry/node";
2
+ import type { ErrorEvent, EventHint, NodeOptions } from "@sentry/node";
3
3
  /**
4
4
  * Drop broken-pipe (EPIPE) crashes before scrubbing/send. A closed downstream
5
5
  * reader (`hq … | head`, `source <(hq …)`, a parent that exited) is normal
@@ -11,6 +11,12 @@ import type { ErrorEvent, EventHint } from "@sentry/node";
11
11
  * Consistent with the swallow-EPIPE posture established in #138.
12
12
  */
13
13
  export declare function epipeAwareBeforeSend(event: ErrorEvent, hint: EventHint): ErrorEvent | null;
14
- export declare function initSentry(): void;
14
+ /**
15
+ * Tests substitute only the transport so the real SDK lifecycle can be
16
+ * exercised without an ingest request. Production callers pass nothing.
17
+ */
18
+ export declare function initSentry(overrides?: Partial<Pick<NodeOptions, "transport">>): void;
19
+ /** Finish HQ's one per-invocation release-health session. */
20
+ export declare function finishSentrySession(): void;
15
21
  export { Sentry };
16
22
  //# sourceMappingURL=sentry.d.ts.map
package/dist/sentry.js CHANGED
@@ -78,12 +78,20 @@ export function epipeAwareBeforeSend(event, hint) {
78
78
  event.fingerprint = fingerprint;
79
79
  return beforeSend(event, hint);
80
80
  }
81
- export function initSentry() {
81
+ /**
82
+ * Tests substitute only the transport so the real SDK lifecycle can be
83
+ * exercised without an ingest request. Production callers pass nothing.
84
+ */
85
+ export function initSentry(overrides = {}) {
82
86
  const dsn = BUNDLED_DSN || process.env.SENTRY_DSN;
83
87
  if (!dsn)
84
88
  return;
85
89
  Sentry.init({
86
90
  dsn,
91
+ // import-in-the-middle's async ESM loader makes every later CLI import
92
+ // substantially slower. Keep HQ's explicit breadcrumbs, but give up
93
+ // automatic ESM third-party instrumentation (its spans/breadcrumbs).
94
+ registerEsmLoaderHooks: false,
87
95
  // CLI_VERSION reads package.json at runtime; npm_package_version is only
88
96
  // set under `npm run`, so an installed `hq` binary would always report
89
97
  // 0.0.0 and never match the uploaded source maps.
@@ -94,6 +102,10 @@ export function initSentry() {
94
102
  },
95
103
  beforeSend: epipeAwareBeforeSend,
96
104
  beforeBreadcrumb,
105
+ // HQ owns this short-lived CLI session explicitly below and closes it from
106
+ // main.ts. Leaving the SDK default enabled starts a competing session.
107
+ integrations: (defaults) => defaults.filter((integration) => integration.name !== "ProcessSession"),
108
+ ...overrides,
97
109
  });
98
110
  // Attribute events to the logged-in HQ identity (best-effort; null when not
99
111
  // logged in). A CLI process is one user, so global setUser is correct here.
@@ -105,5 +117,9 @@ export function initSentry() {
105
117
  // "errored", so crash-free numbers per release stay accurate.
106
118
  Sentry.startSession();
107
119
  }
120
+ /** Finish HQ's one per-invocation release-health session. */
121
+ export function finishSentrySession() {
122
+ Sentry.endSession();
123
+ }
108
124
  export { Sentry };
109
125
  //# sourceMappingURL=sentry.js.map
@@ -1,6 +1,7 @@
1
+ export declare const TELEMETRY_TIMEOUT_MS = 1200;
1
2
  /**
2
3
  * Emit the authenticated CLI session signal using an already-cached token.
3
4
  * This deliberately never refreshes a session or opens a browser.
4
5
  */
5
- export declare function emitCliSessionStarted(): Promise<void>;
6
+ export declare function emitCliSessionStarted(timeoutMs?: number): Promise<void>;
6
7
  //# sourceMappingURL=cli-telemetry.d.ts.map
@@ -1,17 +1,17 @@
1
1
  import { CLI_VERSION } from "../cli-version.js";
2
2
  import { isExpiring, isMachineIdentity, loadCachedTokens, } from "./cognito-session.js";
3
3
  import { vaultApiFetch } from "./vault-api.js";
4
- const TELEMETRY_TIMEOUT_MS = 1_200;
4
+ export const TELEMETRY_TIMEOUT_MS = 1_200;
5
5
  let cliSessionStartedPromise;
6
6
  /**
7
7
  * Emit the authenticated CLI session signal using an already-cached token.
8
8
  * This deliberately never refreshes a session or opens a browser.
9
9
  */
10
- export function emitCliSessionStarted() {
11
- cliSessionStartedPromise ??= emitCachedCliSessionStarted();
10
+ export function emitCliSessionStarted(timeoutMs = TELEMETRY_TIMEOUT_MS) {
11
+ cliSessionStartedPromise ??= emitCachedCliSessionStarted(timeoutMs);
12
12
  return cliSessionStartedPromise;
13
13
  }
14
- async function emitCachedCliSessionStarted() {
14
+ async function emitCachedCliSessionStarted(timeoutMs) {
15
15
  try {
16
16
  const cached = loadCachedTokens();
17
17
  if (!cached || isExpiring(cached, 120))
@@ -20,7 +20,7 @@ async function emitCachedCliSessionStarted() {
20
20
  if (!token)
21
21
  return;
22
22
  const controller = new AbortController();
23
- const timeout = setTimeout(() => controller.abort(), TELEMETRY_TIMEOUT_MS);
23
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
24
24
  try {
25
25
  const response = await vaultApiFetch({
26
26
  token,
@@ -99,5 +99,5 @@ export declare const CONTRIBUTION_KEYS: ContributionKey[];
99
99
  */
100
100
  export declare function payloadFor(key: ContributionKey, item: string): string;
101
101
  /** Keys whose contributions are wired by a host symlink (skip `merge` rows). */
102
- export declare const SYMLINK_KEYS: ("workers" | "knowledge" | "skills" | "commands" | "hooks" | "policies" | "scripts" | "mcp")[];
102
+ export declare const SYMLINK_KEYS: ("workers" | "mcp" | "knowledge" | "skills" | "commands" | "hooks" | "policies" | "scripts")[];
103
103
  //# sourceMappingURL=contribution-table.d.ts.map
@@ -17,7 +17,10 @@ export declare function staleAgainstCachedLatest(now?: number): string | null;
17
17
  * means the loop guard is skipped this once, never a broken CLI.
18
18
  */
19
19
  export declare function markLatestIneffective(version: string, now?: number): void;
20
- export declare function refreshVersionCache(): Promise<void>;
20
+ export interface RefreshVersionCacheOptions {
21
+ timeoutMs?: number;
22
+ }
23
+ export declare function refreshVersionCache(options?: RefreshVersionCacheOptions): Promise<void>;
21
24
  export declare const __test__: {
22
25
  CACHE_TTL_MS: number;
23
26
  isKnownNoninteractiveStatusProbe: typeof isKnownNoninteractiveStatusProbe;
@@ -166,7 +166,7 @@ export function markLatestIneffective(version, now = Date.now()) {
166
166
  ineffectiveAt: now,
167
167
  });
168
168
  }
169
- export async function refreshVersionCache() {
169
+ export async function refreshVersionCache(options = {}) {
170
170
  if (isOptedOut())
171
171
  return;
172
172
  if (isKnownNoninteractiveStatusProbe())
@@ -183,7 +183,7 @@ export async function refreshVersionCache() {
183
183
  return;
184
184
  const res = await fetch(REGISTRY_URL, {
185
185
  headers: { Accept: "application/json" },
186
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
186
+ signal: AbortSignal.timeout(options.timeoutMs ?? FETCH_TIMEOUT_MS),
187
187
  });
188
188
  if (!res.ok)
189
189
  return;
@@ -404,7 +404,11 @@ declare function enforceUpdateRequired(decision: VersionCheckResponse, deps?: En
404
404
  * must exit rather than running the command a second time.
405
405
  */
406
406
  export type VersionGateOutcome = "continue" | "reexec";
407
- export declare function enforceVersionGate(onUpdateRecommended?: (decision: VersionCheckResponse, install: RunningInstall) => Promise<boolean>): Promise<VersionGateOutcome>;
407
+ /** Optional caller-owned bound for the network-only version decision. */
408
+ export interface VersionGateOptions {
409
+ timeoutMs?: number;
410
+ }
411
+ export declare function enforceVersionGate(onUpdateRecommended?: (decision: VersionCheckResponse, install: RunningInstall) => Promise<boolean>, options?: VersionGateOptions): Promise<VersionGateOutcome>;
408
412
  /**
409
413
  * Cheap argv pre-check: skip the gate for `--version` / `-V` so users
410
414
  * inspecting a broken install can still see what they have without being
@@ -470,7 +470,7 @@ export function cleanStalePartialInstall(prefix, fs = nodeStaleInstallFs) {
470
470
  * `null` on any failure (caller treats as "no gate"). Tight 3s timeout —
471
471
  * a hung server must not delay CLI startup.
472
472
  */
473
- async function fetchVersionDecision() {
473
+ async function fetchVersionDecision(timeoutMs = FETCH_TIMEOUT_MS) {
474
474
  try {
475
475
  const url = `${DEFAULT_VAULT_API_URL}${ENDPOINT_PATH}`;
476
476
  const res = await fetch(url, {
@@ -484,7 +484,7 @@ async function fetchVersionDecision() {
484
484
  currentVersion: CLI_VERSION,
485
485
  platform: `${process.platform}-${process.arch}`,
486
486
  }),
487
- signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
487
+ signal: AbortSignal.timeout(timeoutMs),
488
488
  });
489
489
  if (!res.ok)
490
490
  return null;
@@ -988,10 +988,10 @@ function attemptRequiredUpdate(decision, deps, install) {
988
988
  console.error(chalk.green(`✓ Updated to hq-cli ${decision.latestVersion}. Rerun your command.`));
989
989
  return 0;
990
990
  }
991
- export async function enforceVersionGate(onUpdateRecommended) {
991
+ export async function enforceVersionGate(onUpdateRecommended, options = {}) {
992
992
  if (isOptedOut())
993
993
  return "continue";
994
- const decision = await fetchVersionDecision();
994
+ const decision = await fetchVersionDecision(options.timeoutMs);
995
995
  if (!decision)
996
996
  return "continue"; // best-effort: silent on any failure
997
997
  if (!decision.updateRequired && !decision.updateRecommended)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.111.2",
3
+ "version": "5.112.0",
4
4
  "description": "HQ by Indigo management CLI \u2014 modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -16,10 +16,11 @@
16
16
  "CHANGELOG.md"
17
17
  ],
18
18
  "scripts": {
19
- "build": "node scripts/generate-dsn.mjs && tsc && node scripts/copy-schemas.mjs && node scripts/chmod-bins.mjs",
19
+ "build": "node scripts/generate-dsn.mjs && tsc && node scripts/generate-command-catalog.mjs --check && node scripts/copy-schemas.mjs && node scripts/chmod-bins.mjs",
20
20
  "prepublishOnly": "npm run build",
21
21
  "typecheck": "tsc --noEmit",
22
22
  "gen:scan-golden": "node scripts/generate-scan-packages-table.mjs > src/utils/__fixtures__/scan-packages.generated-block.sh",
23
+ "gen:command-catalog": "tsc && node scripts/generate-command-catalog.mjs",
23
24
  "lint": "eslint .",
24
25
  "test": "vitest run",
25
26
  "test:db": "vitest run src/lib/db test/commands/db.test.ts test/commands/db-tenant-isolation.test.ts",