@indigoai-us/hq-cli 5.309.0 → 5.309.1

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.
Files changed (75) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/command-catalog.generated.d.ts +4 -1
  3. package/dist/command-catalog.generated.js +5 -1
  4. package/dist/commands/agents.js +6 -0
  5. package/dist/commands/core-checkpoint-gate-setting.d.ts +0 -10
  6. package/dist/commands/core-checkpoint-gate-setting.js +3 -3
  7. package/dist/commands/core-ontology.d.ts +1 -9
  8. package/dist/commands/core-ontology.js +4 -4
  9. package/dist/commands/core-policy.d.ts +0 -3
  10. package/dist/commands/core-policy.js +3 -3
  11. package/dist/commands/files.js +1 -1
  12. package/dist/commands/index-cmd.js +1 -1
  13. package/dist/commands/integrations-api.d.ts +9 -4
  14. package/dist/commands/integrations-api.js +9 -6
  15. package/dist/commands/integrations-manage.js +11 -3
  16. package/dist/commands/integrations.d.ts +8 -0
  17. package/dist/commands/integrations.js +83 -0
  18. package/dist/commands/lanes-checks.d.ts +0 -2
  19. package/dist/commands/lanes-checks.js +2 -2
  20. package/dist/commands/lanes.d.ts +0 -11
  21. package/dist/commands/lanes.js +6 -6
  22. package/dist/commands/mcp-registration.d.ts +5 -11
  23. package/dist/commands/mcp-registration.js +2 -6
  24. package/dist/lib/core-utils/sentry-report.d.ts +5 -11
  25. package/dist/lib/core-utils/sentry-report.js +2 -2
  26. package/dist/lib/db/local.d.ts +0 -5
  27. package/dist/lib/db/local.js +1 -1
  28. package/dist/lib/db/migrate.d.ts +0 -12
  29. package/dist/lib/db/migrate.js +5 -5
  30. package/dist/lib/db/sql.d.ts +0 -10
  31. package/dist/lib/db/sql.js +4 -8
  32. package/dist/lib/doctor/checks/codex-wiring.js +1 -33
  33. package/dist/lib/doctor/checks/grok-wiring.js +1 -34
  34. package/dist/lib/doctor/deep/effects.js +1 -3
  35. package/dist/lib/doctor/deep/sandbox.js +1 -3
  36. package/dist/lib/doctor/fixtures/schema.js +1 -3
  37. package/dist/lib/doctor/shared.d.ts +8 -0
  38. package/dist/lib/doctor/shared.js +38 -0
  39. package/dist/lib/lanes/autopilot.js +6 -4
  40. package/dist/lib/monitor.d.ts +2 -6
  41. package/dist/lib/monitor.js +5 -5
  42. package/dist/lib/report-publish.d.ts +1 -10
  43. package/dist/lib/report-publish.js +3 -9
  44. package/dist/lib/search-index/index.d.ts +7 -0
  45. package/dist/lib/search-index/index.js +21 -2
  46. package/dist/lib/search-index/qmd-exit-diagnostics.d.ts +5 -0
  47. package/dist/lib/search-index/qmd-exit-diagnostics.js +40 -0
  48. package/dist/lib/service-manager/launchd.d.ts +0 -7
  49. package/dist/lib/service-manager/launchd.js +2 -2
  50. package/dist/main.js +7 -2
  51. package/dist/startup-registration.js +9 -1
  52. package/dist/utils/client-health.d.ts +0 -4
  53. package/dist/utils/client-health.js +2 -2
  54. package/dist/utils/feedback-diagnostics.d.ts +2 -1
  55. package/dist/utils/feedback-log-bundle.d.ts +0 -25
  56. package/dist/utils/feedback-log-bundle.js +5 -5
  57. package/dist/utils/feedback-logs.d.ts +4 -38
  58. package/dist/utils/feedback-logs.js +7 -7
  59. package/dist/utils/feedback-screenshots.d.ts +0 -1
  60. package/dist/utils/feedback-screenshots.js +1 -1
  61. package/dist/utils/install-tree-torn.d.ts +19 -13
  62. package/dist/utils/install-tree-torn.js +77 -2
  63. package/dist/utils/local-files-overview.d.ts +0 -6
  64. package/dist/utils/local-files-overview.js +1 -1
  65. package/dist/utils/qmd-model-download-error.d.ts +0 -8
  66. package/dist/utils/qmd-model-download-error.js +1 -1
  67. package/dist/utils/qmd-query-document-error.d.ts +0 -6
  68. package/dist/utils/qmd-query-document-error.js +1 -1
  69. package/dist/utils/scaffold-fast-import-guard.d.ts +0 -1
  70. package/dist/utils/scaffold-fast-import-guard.js +1 -1
  71. package/dist/utils/scaffold-sibling-references.d.ts +3 -2
  72. package/dist/utils/sentry-fingerprint.js +17 -0
  73. package/dist/utils/version-gate.d.ts +4 -0
  74. package/dist/utils/version-gate.js +13 -0
  75. package/package.json +1 -1
@@ -609,7 +609,7 @@ export function installTargetPresent(target, fs = nodeInstallTreeFs) {
609
609
  * exactly as long as the contract legitimises holding the lock, and never longer.
610
610
  * Overridable by the seam (env HQ_INSTALL_SETTLE_LOCK_TIMEOUT_MS).
611
611
  */
612
- export const DEFAULT_INSTALL_SETTLE_LOCK_WAIT_MS = UPDATE_LOCK_STALE_MS;
612
+ const DEFAULT_INSTALL_SETTLE_LOCK_WAIT_MS = UPDATE_LOCK_STALE_MS;
613
613
  /** The scope/leaf split of CLI_NAME, e.g. `@indigoai-us` / `hq-cli`. */
614
614
  function cliNameParts() {
615
615
  const slash = CLI_NAME.indexOf("/");
@@ -652,6 +652,68 @@ function retiredSiblingPresent(packageRoot, fs) {
652
652
  const entries = fs.readdirSync(parent); // caller treats a throw as "not ready"
653
653
  return entries.some((entry) => entry.startsWith(stagingPrefix));
654
654
  }
655
+ /** Reduce an observed sibling basename to a closed kind without retaining it. */
656
+ function retiredSiblingKind(packageRoot, fs) {
657
+ if (!packageRoot)
658
+ return "unknown";
659
+ try {
660
+ const { leaf } = cliNameParts();
661
+ const prefix = "." + leaf + "-";
662
+ const siblings = fs
663
+ .readdirSync(path.dirname(packageRoot))
664
+ .filter((entry) => entry.startsWith(prefix))
665
+ .sort();
666
+ if (siblings.length === 0)
667
+ return "unknown";
668
+ const name = siblings[0];
669
+ if (/^\.hq-cli-staging-[A-Za-z0-9-]+$/.test(name))
670
+ return "hq_staging";
671
+ if (/^\.hq-cli-backup-[A-Za-z0-9-]+$/.test(name))
672
+ return "hq_backup";
673
+ if (/^\.hq-cli-[A-Za-z0-9]{8}$/.test(name))
674
+ return "npm_hash_retired";
675
+ return "other";
676
+ }
677
+ catch {
678
+ return "unknown";
679
+ }
680
+ }
681
+ /** Classify current target/manifest state without retaining paths or file contents. */
682
+ function installTargetState(target, packageRoot, fs) {
683
+ if (target.kind === "unknown")
684
+ return "unknown";
685
+ if (!installTargetPresent(target, fs))
686
+ return "missing";
687
+ if (!packageRoot)
688
+ return "unknown";
689
+ try {
690
+ const raw = fs.readFileSync(path.join(packageRoot, "package.json"), "utf-8");
691
+ let manifest;
692
+ try {
693
+ manifest = JSON.parse(raw);
694
+ }
695
+ catch {
696
+ return "manifest_invalid";
697
+ }
698
+ return manifest.name === CLI_NAME ? "manifest_valid" : "manifest_invalid";
699
+ }
700
+ catch (error) {
701
+ return error?.code === "ENOENT" ? "missing" : "unreadable";
702
+ }
703
+ }
704
+ /** Read only the lock's recorded owner PID; never retain or report the PID. */
705
+ function updaterPidAlive(lockPath, fs, isPidAlive) {
706
+ try {
707
+ const lock = JSON.parse(fs.readFileSync(lockPath, "utf-8"));
708
+ if (typeof lock.pid !== "number" || !Number.isSafeInteger(lock.pid) || lock.pid <= 0) {
709
+ return "unknown";
710
+ }
711
+ return isPidAlive(lock.pid) ? "true" : "false";
712
+ }
713
+ catch {
714
+ return "unknown";
715
+ }
716
+ }
655
717
  /** Snapshot retired sibling trees so changes below their root stay observable. */
656
718
  function retiredSiblingActivitySignature(packageRoot, fs) {
657
719
  const { leaf } = cliNameParts();
@@ -851,7 +913,7 @@ function canProbeUnsettledRetiredSibling(snapshot) {
851
913
  return snapshot.observed ||
852
914
  (snapshot.nonRetiredObserved && snapshot.retiredSiblingPresent === true);
853
915
  }
854
- export const DEFAULT_INSTALL_TREE_STALE_PROBE_MS = 1_500;
916
+ const DEFAULT_INSTALL_TREE_STALE_PROBE_MS = 1_500;
855
917
  /**
856
918
  * Poll until the install tree has been continuously READY for `quietMs`, or the
857
919
  * wait exhausts its bounds. READY means: (i) no FRESH update lock held by another
@@ -986,6 +1048,9 @@ export async function waitForInstallTreeSettled(args) {
986
1048
  sawTreeChange,
987
1049
  staleTree: false,
988
1050
  retiredSiblingPresent: retiredPresent,
1051
+ retiredSiblingKind: retiredSiblingKind(args.packageRoot, fs),
1052
+ installTargetState: installTargetState(args.target, args.packageRoot, fs),
1053
+ updaterPidAlive: updaterPidAlive(args.lockPath, fs, isPidAlive),
989
1054
  };
990
1055
  }
991
1056
  if (!ready &&
@@ -1007,6 +1072,9 @@ export async function waitForInstallTreeSettled(args) {
1007
1072
  staleTree: lastActivitySnapshot.observed,
1008
1073
  retiredSiblingPresent: retiredPresent,
1009
1074
  retiredSiblingUnverified: !lastActivitySnapshot.observed && lastActivitySnapshot.retiredSiblingPresent === true,
1075
+ retiredSiblingKind: retiredSiblingKind(args.packageRoot, fs),
1076
+ installTargetState: installTargetState(args.target, args.packageRoot, fs),
1077
+ updaterPidAlive: updaterPidAlive(args.lockPath, fs, isPidAlive),
1010
1078
  };
1011
1079
  }
1012
1080
  // Give up when the TREE has had a full unlocked budget with no writer visible,
@@ -1029,6 +1097,9 @@ export async function waitForInstallTreeSettled(args) {
1029
1097
  sawTreeChange,
1030
1098
  staleTree: false,
1031
1099
  retiredSiblingPresent: retiredPresent,
1100
+ retiredSiblingKind: retiredSiblingKind(args.packageRoot, fs),
1101
+ installTargetState: installTargetState(args.target, args.packageRoot, fs),
1102
+ updaterPidAlive: updaterPidAlive(args.lockPath, fs, isPidAlive),
1032
1103
  };
1033
1104
  }
1034
1105
  // The first poll at which the wait has reached `deadlineMs` while a lock is
@@ -1129,6 +1200,10 @@ export class InstallTreeTornError extends Error {
1129
1200
  lockTool: boundedDiagnosticValue(init.lockTool ?? "", LOCK_TOOL_BYTES),
1130
1201
  node: process.version,
1131
1202
  errorName: boundedDiagnosticValue(init.classified.errorName ?? "", ERRORNAME_BYTES),
1203
+ retiredSiblingKind: init.retiredSiblingKind ?? "unknown",
1204
+ installTargetState: init.installTargetState ?? "unknown",
1205
+ versionGatePhase: init.versionGatePhase ?? "unknown",
1206
+ updaterPidAlive: init.updaterPidAlive ?? "unknown",
1132
1207
  };
1133
1208
  if (typeof init.retiredSiblingPresent === "boolean") {
1134
1209
  diagnostics.retiredSiblingPresent = init.retiredSiblingPresent;
@@ -26,12 +26,6 @@
26
26
  * must never break a heartbeat, let alone a CLI command.
27
27
  */
28
28
  import { type ClientHealthLocalFilesOverview } from "./client-health-contract.js";
29
- /**
30
- * Only the last N bytes of the sync log are read for error-line counting —
31
- * this bounds memory/CPU regardless of how large the on-disk log has grown.
32
- * Metadata (size/age) still reflects the FULL file via `fs.stat`.
33
- */
34
- export declare const LOCAL_FILES_OVERVIEW_TAIL_READ_BYTES: number;
35
29
  /**
36
30
  * Count lines that look like an error marker in the last
37
31
  * {@link LOCAL_FILES_OVERVIEW_TAIL_READ_BYTES} of `filePath`, capped at
@@ -36,7 +36,7 @@ import { CLIENT_HEALTH_MAX_ERROR_LINE_COUNT, CLIENT_HEALTH_MAX_FILE_AGE_SECONDS,
36
36
  * this bounds memory/CPU regardless of how large the on-disk log has grown.
37
37
  * Metadata (size/age) still reflects the FULL file via `fs.stat`.
38
38
  */
39
- export const LOCAL_FILES_OVERVIEW_TAIL_READ_BYTES = 2 * 1024 * 1024; // 2 MiB
39
+ const LOCAL_FILES_OVERVIEW_TAIL_READ_BYTES = 2 * 1024 * 1024; // 2 MiB
40
40
  /** Case-insensitive marker matched against each line (or JSON-lines `level`). */
41
41
  const ERROR_MARKER = /error/i;
42
42
  const JSON_LEVEL_ERROR = /"level"\s*:\s*"error"\s*(?=[,}])/i;
@@ -1,11 +1,3 @@
1
- /**
2
- * The actionable remedy shown to the caller. Input-free — nothing is
3
- * interpolated from the error, the argv, or qmd's output — so there is no
4
- * injection surface. The disposition holds for every reading of a vanished
5
- * `.ipull` partial (a concurrent finisher, a cache eviction, a partially-written
6
- * file): it is transient and retryable, and re-running resumes the download.
7
- */
8
- export declare const QMD_MODEL_DOWNLOAD_REMEDY: string;
9
1
  /**
10
2
  * True when `err` is a qmd interrupted-model-download failure: qmd's OWN captured
11
3
  * streams carry BOTH an ENOENT-rename signature AND a `.ipull` partial-download
@@ -50,7 +50,7 @@ const MODEL_FETCH_READS = new Set(["query", "vsearch", "embed"]);
50
50
  * `.ipull` partial (a concurrent finisher, a cache eviction, a partially-written
51
51
  * file): it is transient and retryable, and re-running resumes the download.
52
52
  */
53
- export const QMD_MODEL_DOWNLOAD_REMEDY = "hq's local search couldn't finish downloading a model it needs: the partial " +
53
+ const QMD_MODEL_DOWNLOAD_REMEDY = "hq's local search couldn't finish downloading a model it needs: the partial " +
54
54
  "download file disappeared before it could be saved, which usually means " +
55
55
  "another hq or qmd process on this machine finished or cleared the same " +
56
56
  "download. Re-run the command — the download resumes.";
@@ -1,9 +1,3 @@
1
- /**
2
- * The actionable remedy shown to the caller. Input-free: nothing is interpolated
3
- * from the error, the argv, or qmd's output, so there is no injection surface —
4
- * matching the bounded-fingerprint discipline of its siblings.
5
- */
6
- export declare const QMD_QUERY_DOCUMENT_REMEDY: string;
7
1
  /**
8
2
  * True when `err` carries, in qmd's OWN captured streams, a query-document
9
3
  * syntax diagnostic — i.e. qmd's `query` parser rejected the positional as a
@@ -61,7 +61,7 @@ const QUERY_DOCUMENT_READS = new Set(["query"]);
61
61
  * from the error, the argv, or qmd's output, so there is no injection surface —
62
62
  * matching the bounded-fingerprint discipline of its siblings.
63
63
  */
64
- export const QMD_QUERY_DOCUMENT_REMEDY = "Hybrid search was given a multi-line query, and qmd read it as a structured " +
64
+ const QMD_QUERY_DOCUMENT_REMEDY = "Hybrid search was given a multi-line query, and qmd read it as a structured " +
65
65
  "query document whose lines must each begin with a lex:, vec:, hyde:, or " +
66
66
  "intent: prefix. Put your search terms on a single line, or prefix every line, " +
67
67
  "then run the command again.";
@@ -1,3 +1,2 @@
1
- export declare function forbiddenFastPathModules(loadedModules: readonly string[], distDirectory: string, allowedCommandModules?: readonly string[]): string[];
2
1
  export declare function assertFastPathStaysCommandGraphFree(loadedModules: readonly string[], distDirectory: string, allowedCommandModules?: readonly string[]): void;
3
2
  //# sourceMappingURL=scaffold-fast-import-guard.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import * as path from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
- export function forbiddenFastPathModules(loadedModules, distDirectory, allowedCommandModules = []) {
3
+ function forbiddenFastPathModules(loadedModules, distDirectory, allowedCommandModules = []) {
4
4
  const dist = path.resolve(distDirectory);
5
5
  const main = path.join(dist, "main.js");
6
6
  const commands = `${path.join(dist, "commands")}${path.sep}`;
@@ -1,8 +1,8 @@
1
- export type SiblingAssetReference = {
1
+ type SiblingAssetReference = {
2
2
  referringAsset: string;
3
3
  targetAsset: string;
4
4
  };
5
- export type HqRootAssetReference = {
5
+ type HqRootAssetReference = {
6
6
  referringAsset: string;
7
7
  reference: string;
8
8
  };
@@ -18,4 +18,5 @@ export type ScaffoldReferenceScan = {
18
18
  */
19
19
  export declare function scanScaffoldSiblingReferences(scaffoldRoot: string): ScaffoldReferenceScan;
20
20
  export declare function assertNoMissingScaffoldSiblings(scan: ScaffoldReferenceScan): void;
21
+ export {};
21
22
  //# sourceMappingURL=scaffold-sibling-references.d.ts.map
@@ -250,6 +250,23 @@ export function installTreeTornSentryTagsFor(err) {
250
250
  if (typeof diagnostics.retiredSiblingPresent === "boolean") {
251
251
  tags.retired_sibling = diagnostics.retiredSiblingPresent ? "present" : "absent";
252
252
  }
253
+ const retiredSiblingKind = diagnostics.retiredSiblingKind;
254
+ tags.retired_sibling_kind = typeof retiredSiblingKind === "string" &&
255
+ ["npm_hash_retired", "hq_staging", "hq_backup", "other", "unknown"].includes(retiredSiblingKind)
256
+ ? retiredSiblingKind
257
+ : "unknown";
258
+ const targetState = diagnostics.installTargetState;
259
+ tags.install_target_state = typeof targetState === "string" &&
260
+ ["missing", "manifest_valid", "manifest_invalid", "unreadable", "unknown"].includes(targetState)
261
+ ? targetState
262
+ : "unknown";
263
+ const gatePhase = diagnostics.versionGatePhase;
264
+ tags.version_gate_phase = typeof gatePhase === "string" &&
265
+ ["preflight", "lock_acquired", "installer_running", "verifying", "rollback", "complete", "failed", "unknown"].includes(gatePhase)
266
+ ? gatePhase
267
+ : "unknown";
268
+ const pidAlive = diagnostics.updaterPidAlive;
269
+ tags.updater_pid_alive = pidAlive === "true" || pidAlive === "false" ? pidAlive : "unknown";
253
270
  if (recoveryOutcome)
254
271
  tags.recovery_outcome = recoveryOutcome;
255
272
  const lockTool = diagnostics.lockTool;
@@ -29,6 +29,9 @@
29
29
  */
30
30
  import { buildSpawnPlan, quoteForWindowsShell } from "./windows-spawn.js";
31
31
  import { type UpdateLockHandle } from "./update-lock.js";
32
+ export type VersionGatePhase = "preflight" | "lock_acquired" | "installer_running" | "verifying" | "rollback" | "complete" | "failed" | "unknown";
33
+ /** The last closed version-gate phase observed in this process. */
34
+ export declare function getVersionGatePhase(): VersionGatePhase;
32
35
  /** Which package manager owns the running global install. */
33
36
  export type InstallManager = "npm" | "pnpm" | "bun";
34
37
  export interface VersionCheckResponse {
@@ -489,6 +492,7 @@ export declare function enforceVersionGate(onUpdateRecommended?: (decision: Vers
489
492
  export declare function shouldSkipGate(argv: readonly string[]): boolean;
490
493
  export declare const __test__: {
491
494
  CLIENT_ID: string;
495
+ getVersionGatePhase: typeof getVersionGatePhase;
492
496
  CONVERGENCE_TIMEOUT_MS: number;
493
497
  DEFAULT_UPDATE_TIMEOUT_MS: number;
494
498
  ENDPOINT_PATH: string;
@@ -45,6 +45,11 @@ const CLIENT_ID = "hq-cli";
45
45
  const ENDPOINT_PATH = "/v1/client-version/check";
46
46
  const FETCH_TIMEOUT_MS = 3_000;
47
47
  const LATEST_PACKAGE_SPEC = `${CLI_NAME}@latest`;
48
+ let currentVersionGatePhase = "unknown";
49
+ /** The last closed version-gate phase observed in this process. */
50
+ export function getVersionGatePhase() {
51
+ return currentVersionGatePhase;
52
+ }
48
53
  function isOptedOut() {
49
54
  return process.env.HQ_NO_UPDATE_CHECK === "1";
50
55
  }
@@ -1291,6 +1296,7 @@ export function checkUpdateConvergence(targetVersion, deps = {}) {
1291
1296
  * gate returns and lets the user's command run on the current version.
1292
1297
  */
1293
1298
  function enforceUpdateRequired(decision, deps = {}) {
1299
+ currentVersionGatePhase = "preflight";
1294
1300
  const banner = chalk.red.bold(`✗ hq-cli ${CLI_VERSION} is below the minimum required version (${decision.minVersion}).`);
1295
1301
  console.error(banner);
1296
1302
  if (decision.message)
@@ -1341,6 +1347,7 @@ function enforceUpdateRequired(decision, deps = {}) {
1341
1347
  console.error(chalk.dim(" Another hq updater is already installing (update lock held); continuing on the current version."));
1342
1348
  return;
1343
1349
  }
1350
+ currentVersionGatePhase = "lock_acquired";
1344
1351
  let attempt;
1345
1352
  try {
1346
1353
  attempt = attemptRequiredUpdate(decision, deps, install);
@@ -1406,6 +1413,7 @@ function attemptRequiredUpdate(decision, deps, install) {
1406
1413
  const updateEnv = pnpmUpdateEnv(install);
1407
1414
  let result;
1408
1415
  let noticeFlush = null;
1416
+ currentVersionGatePhase = "installer_running";
1409
1417
  if (isManagedOutsideNpm) {
1410
1418
  console.error(chalk.dim(` Detected a ${install.manager}-managed global install; updating with ${install.manager}`));
1411
1419
  console.error(chalk.dim(` Running: ${primaryCmd} ${primaryArgs.join(" ")}`));
@@ -1475,6 +1483,7 @@ function attemptRequiredUpdate(decision, deps, install) {
1475
1483
  result = sudoResult;
1476
1484
  }
1477
1485
  if (!result.ok) {
1486
+ currentVersionGatePhase = "failed";
1478
1487
  console.error(chalk.red(`✗ Update failed${result.detail ? `: ${result.detail}` : ""}.`));
1479
1488
  // If the npm prefix is still unwritable after the unprivileged and sudo
1480
1489
  // attempts, explain the permission wall plainly instead of leaving exit 75
@@ -1524,11 +1533,14 @@ function attemptRequiredUpdate(decision, deps, install) {
1524
1533
  // install shadowing the copy we just wrote is reported as the failed update
1525
1534
  // it is rather than as a success the caller will keep retrying — see
1526
1535
  // checkUpdateConvergence.
1536
+ currentVersionGatePhase = "verifying";
1527
1537
  const converged = (deps.checkConvergence ?? checkUpdateConvergence)(decision.latestVersion);
1528
1538
  if (converged === false) {
1539
+ currentVersionGatePhase = "failed";
1529
1540
  console.error(chalk.red(`✗ Update did not take effect: \`hq\` on PATH still resolves a different build than ${decision.latestVersion}.`));
1530
1541
  return 75;
1531
1542
  }
1543
+ currentVersionGatePhase = "complete";
1532
1544
  console.error(chalk.green(`✓ Updated to hq-cli ${decision.latestVersion}. Rerun your command.`));
1533
1545
  return 0;
1534
1546
  }
@@ -1585,6 +1597,7 @@ export function shouldSkipGate(argv) {
1585
1597
  }
1586
1598
  export const __test__ = {
1587
1599
  CLIENT_ID,
1600
+ getVersionGatePhase,
1588
1601
  CONVERGENCE_TIMEOUT_MS,
1589
1602
  DEFAULT_UPDATE_TIMEOUT_MS,
1590
1603
  ENDPOINT_PATH,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.309.0",
3
+ "version": "5.309.1",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {