@indigoai-us/hq-cli 5.185.0 → 5.185.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.185.1] — 2026-09-25
6
+
7
+ ### Fixed
8
+
9
+ - `lanes.hire-grants` resolves its company-scoped hq-flags value before gating.
10
+ A valid local override wins; missing rows or failed reads leave enforcement
11
+ off. Backfills check the unscoped value and each target company's value
12
+ before writing. `hire_grant_exhausted` names the grantor and includes the
13
+ same recovery message in JSON and on stderr.
14
+
5
15
  ## [5.185.0] — 2026-09-25
6
16
 
7
17
  ### Fixed
@@ -79,7 +79,7 @@ export interface LanesCommandDeps {
79
79
  /** Test seam for the default-off outpost placement rollout flag. */
80
80
  lanePlacementEnabled?: () => boolean;
81
81
  /** Test seam for the default-off lane hire-grants rollout gate. */
82
- laneHireGrantsEnabled?: () => boolean;
82
+ laneHireGrantsEnabled?: (company?: LaneCompanyRef | null) => boolean | Promise<boolean>;
83
83
  }
84
84
  export declare const LANE_OUTPOST_LOAD_BALANCING_FLAG = "lanes.outpost-load-balancing";
85
85
  export declare function parseSeniorRef(raw: string): SeniorRef;
@@ -13,6 +13,7 @@ import * as path from "node:path";
13
13
  import { registerOutpostPrunerCommand } from "./outpost-pruner.js";
14
14
  import { ensureCognitoToken } from "../utils/cognito-session.js";
15
15
  import { resolveLanesHqRoot } from "../lib/lanes/hq-root.js";
16
+ import { readLanesRegistryFlag } from "../lib/lanes/registry-flag.js";
16
17
  import { resolveProcessFlagGate } from "../lib/flag-registry.js";
17
18
  import { OUTPOST_DIR, OUTPOST_ID_PATH, readOutpostIdentity, resolveAdmissionHost, } from "../lib/lanes/admission-host.js";
18
19
  export { OUTPOST_DIR, OUTPOST_ID_PATH, readOutpostIdentity } from "../lib/lanes/admission-host.js";
@@ -52,8 +53,8 @@ export const LANE_OUTPOST_LOAD_BALANCING_FLAG = "lanes.outpost-load-balancing";
52
53
  function defaultLanePlacementEnabled() {
53
54
  return resolveProcessFlagGate(LANE_OUTPOST_LOAD_BALANCING_FLAG, { fallback: false }, () => false);
54
55
  }
55
- function defaultLaneHireGrantsEnabled() {
56
- return resolveProcessFlagGate(LANE_HIRE_GRANTS_FLAG, { fallback: false }, () => false);
56
+ function defaultLaneHireGrantsEnabled(company) {
57
+ return readLanesRegistryFlag(LANE_HIRE_GRANTS_FLAG, { company });
57
58
  }
58
59
  function withoutProviderHome(value) {
59
60
  if (Array.isArray(value))
@@ -73,6 +74,9 @@ function printJson(value) {
73
74
  }
74
75
  function failJson(err) {
75
76
  if (isLanesError(err)) {
77
+ if (err.error === "hire_grant_exhausted") {
78
+ process.stderr.write(`hq lanes: ${err.message}\n`);
79
+ }
76
80
  printJson(err.toJSON());
77
81
  process.exit(1);
78
82
  }
@@ -515,12 +519,14 @@ const OUTPOST_HIRE_SUMMARY_WAIT_MS = 15_000;
515
519
  const OUTPOST_HIRE_SUMMARY_CONCURRENCY = 4;
516
520
  async function laneHirePresentation(ctx, lane, lanes) {
517
521
  const local = laneHireFields(lane, lanes);
518
- if (!ctx.laneHireGrantsEnabled() ||
519
- lane.host.kind !== "outpost" ||
522
+ if (lane.host.kind !== "outpost" ||
520
523
  isTerminalLaneState(lane.state) ||
521
524
  laneRunsHere(lane, reconcileHostFromCtx(ctx))) {
522
525
  return { ...local, hire_source: "local" };
523
526
  }
527
+ if (!await ctx.laneHireGrantsEnabled(lane.company)) {
528
+ return { ...local, hire_source: "local" };
529
+ }
524
530
  try {
525
531
  return { ...(await ownerLaneHireFields(ctx, lane)), hire_source: "owner" };
526
532
  }
@@ -548,14 +554,15 @@ async function mapWithConcurrency(values, concurrency, map) {
548
554
  await Promise.all(workers);
549
555
  return results;
550
556
  }
551
- function withResumeHireAdmission(ctx, lane, fn) {
557
+ async function withResumeHireAdmission(ctx, lane, fn) {
552
558
  const hqRoot = ctx.hqRoot();
553
- if (!ctx.laneHireGrantsEnabled() ||
554
- !isTerminalLaneState(lane.state) ||
559
+ if (!isTerminalLaneState(lane.state) ||
555
560
  lane.senior.kind !== "lane" ||
556
561
  !lane.senior.id) {
557
562
  return fn();
558
563
  }
564
+ if (!await ctx.laneHireGrantsEnabled(lane.company))
565
+ return fn();
559
566
  return withHireGrantAdmission(hqRoot, lane.senior.id, ({ parent, children, parentGrant, availableChildGrant }) => {
560
567
  const current = readLane(hqRoot, lane.lane_id);
561
568
  // A different resume already reactivated this lane; it occupies the slot
@@ -588,11 +595,33 @@ function withResumeHireAdmission(ctx, lane, fn) {
588
595
  }
589
596
  function hireGrantCapacityError(parent, children) {
590
597
  const grant = parent.hire_grant ?? 0;
591
- return new LanesError("hire_grant_exhausted", `Senior lane ${parent.lane_id} has hire grant ${grant} and ${children.length} alive direct children (${children.map((child) => child.lane_id).join(", ") || "none"}). Ask its senior for more: write an ask envelope with the desired total grant and why; the senior runs hq lanes grant ${parent.lane_id} --hire <n>.`, {
598
+ const grantor = (parent.senior.kind === "lane" || parent.senior.kind === "session") &&
599
+ parent.senior.id
600
+ ? { kind: parent.senior.kind, id: parent.senior.id }
601
+ : null;
602
+ const grantorReason = grantor
603
+ ? undefined
604
+ : parent.senior.kind === "user"
605
+ ? "senior_is_user"
606
+ : "parent_senior_missing_id";
607
+ const capacity = children.length === grant
608
+ ? `is at its hire grant (${children.length} of ${grant} alive children)`
609
+ : `has exhausted its hire grant (${children.length} alive children; grant ${grant})`;
610
+ const grantCommand = `hq lanes grant ${parent.lane_id} --hire <n>`;
611
+ const authorityGuidance = grantor
612
+ ? `Its senior ${grantor.kind} ${grantor.id} can raise it with: ${grantCommand}`
613
+ : parent.senior.kind === "user"
614
+ ? `Its senior is the user and can raise it with: ${grantCommand}`
615
+ : `No senior is recorded, so an operator must resolve ownership before running: ${grantCommand}`;
616
+ const message = `Lane ${parent.lane_id} ${capacity}. ${authorityGuidance}`;
617
+ return new LanesError("hire_grant_exhausted", message, {
592
618
  senior_lane_id: parent.lane_id,
593
619
  parent_grant: grant,
594
620
  alive_children: children.map((child) => child.lane_id),
595
621
  alive_child_count: children.length,
622
+ grantor,
623
+ ...(grantorReason ? { grantor_reason: grantorReason } : {}),
624
+ message,
596
625
  ask_guidance: {
597
626
  envelope: "decision=ask; include the desired total grant and the reason",
598
627
  senior_command: `hq lanes grant ${parent.lane_id} --hire <n>`,
@@ -1858,7 +1887,12 @@ async function runCreate(ctx, opts) {
1858
1887
  }
1859
1888
  const senior = opts.senior ? parseSeniorRef(opts.senior) : defaultSenior(ctx);
1860
1889
  assertSeniorExists(hqRoot, senior, ctx);
1861
- const hireGrantsEnabled = ctx.laneHireGrantsEnabled();
1890
+ // Resolve tenant context before the registry read so the flag evaluator
1891
+ // applies the same company scope as this lane.
1892
+ const company = companyFlag
1893
+ ? await ctx.resolveCompany(companyFlag)
1894
+ : null;
1895
+ const hireGrantsEnabled = await ctx.laneHireGrantsEnabled(company);
1862
1896
  if (requestedHireGrant !== undefined &&
1863
1897
  !callerMatchesSenior(ctx, senior)) {
1864
1898
  throw new LanesError("hire_grant_unauthorized", `Only senior ${seniorKey(senior)} may set a lane's hire grant`, { senior, hire_grant: requestedHireGrant });
@@ -1874,9 +1908,6 @@ async function runCreate(ctx, opts) {
1874
1908
  throw new LanesError("max_lane_depth", `Lane depth ${laneDepth} exceeds cap ${MAX_LANE_DEPTH}`, { depth: laneDepth, max: MAX_LANE_DEPTH });
1875
1909
  }
1876
1910
  // A no-company lane must not call company resolution (openMeshTransport).
1877
- const company = companyFlag
1878
- ? await ctx.resolveCompany(companyFlag)
1879
- : null;
1880
1911
  let meshCompany = company;
1881
1912
  if (meshCompanyFlag) {
1882
1913
  const resolvedMeshCompany = await ctx.resolveCompany(meshCompanyFlag);
@@ -3024,6 +3055,17 @@ async function runList(ctx, opts) {
3024
3055
  return true;
3025
3056
  })
3026
3057
  .sort(compareLaneQueueOrder);
3058
+ const companyContexts = new Map();
3059
+ for (const lane of selectedLanes) {
3060
+ if (lane.host.kind !== "outpost" ||
3061
+ isTerminalLaneState(lane.state) ||
3062
+ laneRunsHere(lane, host)) {
3063
+ continue;
3064
+ }
3065
+ const company = lane.company;
3066
+ companyContexts.set(JSON.stringify([company?.uid ?? null, company?.slug ?? null]), company);
3067
+ }
3068
+ await Promise.all([...companyContexts.values()].map((company) => ctx.laneHireGrantsEnabled(company)));
3027
3069
  const hireByLane = new Map(await mapWithConcurrency(selectedLanes, OUTPOST_HIRE_SUMMARY_CONCURRENCY, async (lane) => [
3028
3070
  lane.lane_id,
3029
3071
  await laneHirePresentation(ctx, lane, allLanes),
@@ -3545,6 +3587,7 @@ async function runGrant(ctx, laneId, opts) {
3545
3587
  await dispatchOutpostLaneCommand(ctx, initial, "grant", { hire: String(hireGrant) });
3546
3588
  return;
3547
3589
  }
3590
+ const enforce = await ctx.laneHireGrantsEnabled(initial.company);
3548
3591
  const lockedLaneIds = [
3549
3592
  laneId,
3550
3593
  ...(initial.senior.kind === "lane" && initial.senior.id
@@ -3557,7 +3600,6 @@ async function runGrant(ctx, laneId, opts) {
3557
3600
  throw new LanesError("hire_grant_unauthorized", `Only senior ${seniorKey(current.senior)} may change lane ${laneId}'s hire grant`, { lane_id: laneId, senior: current.senior });
3558
3601
  }
3559
3602
  const hierarchy = loadAllLanes(hqRoot);
3560
- const enforce = ctx.laneHireGrantsEnabled();
3561
3603
  if (enforce && current.senior.kind === "lane") {
3562
3604
  if (!current.senior.id) {
3563
3605
  throw new LanesError("hire_grant_senior_invalid", `Lane ${laneId} has a lane senior without an id`, {
@@ -3611,7 +3653,7 @@ async function runBackfillGrants(ctx, opts) {
3611
3653
  }
3612
3654
  const apply = Boolean(opts.apply);
3613
3655
  const hqRoot = ctx.hqRoot();
3614
- if (apply && ctx.laneHireGrantsEnabled()) {
3656
+ if (apply && await ctx.laneHireGrantsEnabled(null)) {
3615
3657
  throw new LanesError("hire_grant_backfill_gate_enabled", "Backfill must be applied and verified before lanes.hire-grants is enabled", { flag: LANE_HIRE_GRANTS_FLAG });
3616
3658
  }
3617
3659
  if (apply && ctx.env.HQ_LANE_ID?.trim()) {
@@ -3642,6 +3684,24 @@ async function runBackfillGrants(ctx, opts) {
3642
3684
  }
3643
3685
  let rows = planHireGrantBackfill(allLanes, profileMaxConcurrent);
3644
3686
  if (apply) {
3687
+ const lanesById = new Map(allLanes.map((lane) => [lane.lane_id, lane]));
3688
+ const targetCompanies = new Map();
3689
+ for (const row of rows) {
3690
+ if (row.action === "unchanged")
3691
+ continue;
3692
+ const lane = lanesById.get(row.lane_id);
3693
+ if (!lane) {
3694
+ throw new LanesError("hire_grant_backfill_target_changed", `Backfill target lane ${row.lane_id} is unavailable`, { lane_id: row.lane_id });
3695
+ }
3696
+ const company = lane.company;
3697
+ if (!company)
3698
+ continue;
3699
+ targetCompanies.set(JSON.stringify([company.uid ?? null, company.slug ?? null]), company);
3700
+ }
3701
+ const companyGates = await Promise.all([...targetCompanies.values()].map((company) => ctx.laneHireGrantsEnabled(company)));
3702
+ if (companyGates.some(Boolean)) {
3703
+ throw new LanesError("hire_grant_backfill_gate_enabled", "Backfill must be applied and verified before lanes.hire-grants is enabled", { flag: LANE_HIRE_GRANTS_FLAG });
3704
+ }
3645
3705
  const shortfalls = rows.filter((row) => row.grant_shortfall > 0);
3646
3706
  if (shortfalls.length > 0) {
3647
3707
  throw new LanesError("hire_grant_backfill_allocation_shortfall", "Existing parent grants do not cover the grants allocated to alive children; resolve these rows before applying the backfill", { lanes: shortfalls });
@@ -4009,7 +4069,7 @@ async function prepareAccountMove(ctx, lane, input) {
4009
4069
  if (admission.action === "refuse" && admission.error)
4010
4070
  throw admission.error;
4011
4071
  const queued = admission.action === "queue";
4012
- const moved = withResumeHireAdmission(ctx, lane, () => casUpdateLane(hqRoot, laneId, (current) => {
4072
+ const moved = await withResumeHireAdmission(ctx, lane, () => casUpdateLane(hqRoot, laneId, (current) => {
4013
4073
  // The copy and every check above were made from `lane`; a record
4014
4074
  // that moved on since (another move, a spawn, a cancel) invalidates
4015
4075
  // them, so the write is refused rather than applied to a state it
@@ -4061,7 +4121,7 @@ async function runMessage(ctx, laneId, opts) {
4061
4121
  assertLaneRunsHereForOperatorMutation(ctx, lane, "message");
4062
4122
  // Check before transcript recovery, account probing, or message writes.
4063
4123
  // The final state transition repeats this check under the senior lock.
4064
- withResumeHireAdmission(ctx, lane, () => undefined);
4124
+ await withResumeHireAdmission(ctx, lane, () => undefined);
4065
4125
  lane = laneWithRecoveredProviderSession(hqRoot, lane);
4066
4126
  // An account move is refused on its own terms first: a running lane and a
4067
4127
  // provider without session resume get the move's named errors, not the
@@ -4341,7 +4401,7 @@ async function runResume(ctx, laneId, opts) {
4341
4401
  }
4342
4402
  // Fail before provider/session work if a terminal child would consume a
4343
4403
  // slot that its senior has already assigned elsewhere.
4344
- withResumeHireAdmission(ctx, lane, () => undefined);
4404
+ await withResumeHireAdmission(ctx, lane, () => undefined);
4345
4405
  assertLaneRunsHereForOperatorMutation(ctx, lane, "resume");
4346
4406
  lane = laneWithRecoveredProviderSession(hqRoot, lane);
4347
4407
  if (opts.model !== undefined && opts.account === undefined) {
@@ -4913,14 +4973,19 @@ async function runReparent(ctx, laneId, opts) {
4913
4973
  const nextSenior = parseSeniorRef(opts.senior);
4914
4974
  assertSeniorExists(hqRoot, nextSenior, ctx);
4915
4975
  const initial = readLane(hqRoot, laneId);
4976
+ const needsHireGrantGate = nextSenior.kind === "lane" &&
4977
+ seniorKey(initial.senior) !== seniorKey(nextSenior);
4978
+ const hireGrantsEnabled = needsHireGrantGate
4979
+ ? await ctx.laneHireGrantsEnabled(initial.company)
4980
+ : false;
4916
4981
  const lockIds = [
4917
4982
  laneId,
4918
4983
  ...(initial.senior.kind === "lane" && initial.senior.id ? [initial.senior.id] : []),
4919
4984
  ...(nextSenior.kind === "lane" && nextSenior.id ? [nextSenior.id] : []),
4920
4985
  ];
4921
- withLaneHireLocks(hqRoot, lockIds, () => runReparentLocked(ctx, laneId, opts));
4986
+ withLaneHireLocks(hqRoot, lockIds, () => runReparentLocked(ctx, laneId, opts, hireGrantsEnabled));
4922
4987
  }
4923
- function runReparentLocked(ctx, laneId, opts) {
4988
+ function runReparentLocked(ctx, laneId, opts, hireGrantsEnabled) {
4924
4989
  const hqRoot = ctx.hqRoot();
4925
4990
  if (!opts.senior) {
4926
4991
  throw new LanesError("missing_senior", "--senior is required", {});
@@ -4934,7 +4999,7 @@ function runReparentLocked(ctx, laneId, opts) {
4934
4999
  }
4935
5000
  const seniorCompany = companyOfSenior(hqRoot, nextSenior, ctx);
4936
5001
  assertSameTenant(lane.company, nextSenior, seniorCompany, { lane_id: laneId });
4937
- if (ctx.laneHireGrantsEnabled() &&
5002
+ if (hireGrantsEnabled &&
4938
5003
  nextSenior.kind === "lane" &&
4939
5004
  seniorKey(lane.senior) !== seniorKey(nextSenior)) {
4940
5005
  const parent = readLane(hqRoot, nextSenior.id);
@@ -0,0 +1,27 @@
1
+ import { type FlagClientOptions, type FlagResolution } from "@indigoai-us/hq-flags-client";
2
+ import type { LaneCompanyRef } from "./types.js";
3
+ export declare const LANES_FLAG_API_DEFAULT_ENDPOINT = "https://hqapi.hq.computer";
4
+ export declare const LANES_FLAG_READ_TIMEOUT_MS = 5000;
5
+ export interface LanesFlagClient {
6
+ ready(): Promise<void>;
7
+ explain(flagKey: string, options?: {
8
+ fallback?: boolean;
9
+ }): FlagResolution;
10
+ close(): void;
11
+ }
12
+ export type LanesFlagClientFactory = (options: FlagClientOptions) => LanesFlagClient;
13
+ export interface ReadLanesFlagOptions {
14
+ company?: LaneCompanyRef | null;
15
+ env?: NodeJS.ProcessEnv;
16
+ createClient?: LanesFlagClientFactory;
17
+ getToken?: () => string | Promise<string>;
18
+ reportFailure?: (error: unknown) => void;
19
+ }
20
+ /**
21
+ * Read a lanes flag once for each company identity in this CLI process. The
22
+ * cache contains only an in-flight or settled boolean promise; it is never
23
+ * written to disk. A local override is checked on every call and wins first.
24
+ */
25
+ export declare function readLanesRegistryFlag(flagKey: string, options?: ReadLanesFlagOptions): Promise<boolean>;
26
+ export declare function _resetLanesRegistryFlagCacheForTests(): void;
27
+ //# sourceMappingURL=registry-flag.d.ts.map
@@ -0,0 +1,129 @@
1
+ import { createFlagClient, readLocalOverride, } from "@indigoai-us/hq-flags-client";
2
+ import { ensureCognitoIdToken } from "../../utils/cognito-session.js";
3
+ export const LANES_FLAG_API_DEFAULT_ENDPOINT = "https://hqapi.hq.computer";
4
+ export const LANES_FLAG_READ_TIMEOUT_MS = 5_000;
5
+ const registryReads = new Map();
6
+ class MissingFlagTokenError extends Error {
7
+ constructor() {
8
+ super("No cached HQ identity token is available");
9
+ this.name = "MissingFlagTokenError";
10
+ }
11
+ }
12
+ class MissingFlagRowError extends Error {
13
+ constructor(flagKey) {
14
+ super(`The hq-flags registry did not resolve ${flagKey}`);
15
+ this.name = "MissingFlagRowError";
16
+ }
17
+ }
18
+ function errorClass(error) {
19
+ return error instanceof Error ? error.name : "UnknownError";
20
+ }
21
+ function reportReadFailure(flagKey, error) {
22
+ const suffix = flagKey.replace(/^lanes\./, "").replaceAll(/[^a-zA-Z0-9]+/g, "_");
23
+ process.stderr.write(`${JSON.stringify({
24
+ event: `lanes.${suffix}.flag_read_failed`,
25
+ flag: flagKey,
26
+ error: errorClass(error),
27
+ fallback: false,
28
+ })}\n`);
29
+ }
30
+ function cacheKey(flagKey, company, endpoint) {
31
+ return JSON.stringify([
32
+ flagKey,
33
+ endpoint,
34
+ company?.uid ?? null,
35
+ company?.slug ?? null,
36
+ ]);
37
+ }
38
+ /**
39
+ * Read a lanes flag once for each company identity in this CLI process. The
40
+ * cache contains only an in-flight or settled boolean promise; it is never
41
+ * written to disk. A local override is checked on every call and wins first.
42
+ */
43
+ export async function readLanesRegistryFlag(flagKey, options = {}) {
44
+ const env = options.env ?? process.env;
45
+ const localOverride = readLocalOverride(flagKey, env);
46
+ if (localOverride !== null)
47
+ return localOverride;
48
+ const endpoint = env.HQ_FLAGS_API_URL?.trim() || LANES_FLAG_API_DEFAULT_ENDPOINT;
49
+ const key = cacheKey(flagKey, options.company, endpoint);
50
+ const cached = registryReads.get(key);
51
+ if (cached)
52
+ return cached;
53
+ const pending = readRegistryValue(flagKey, endpoint, options);
54
+ registryReads.set(key, pending);
55
+ return pending;
56
+ }
57
+ async function readRegistryValue(flagKey, endpoint, options) {
58
+ const company = options.company;
59
+ const companyUid = company?.uid?.trim();
60
+ const companySlug = company?.slug?.trim();
61
+ let client;
62
+ let enabled = false;
63
+ let failed = false;
64
+ let reported = false;
65
+ const reportFailure = (error) => {
66
+ failed = true;
67
+ if (reported)
68
+ return;
69
+ reported = true;
70
+ (options.reportFailure ?? ((cause) => reportReadFailure(flagKey, cause)))(error);
71
+ };
72
+ try {
73
+ const acquireToken = options.getToken ?? (async () => {
74
+ try {
75
+ return await ensureCognitoIdToken({ interactive: false });
76
+ }
77
+ catch (error) {
78
+ if (error instanceof Error &&
79
+ error.message.startsWith("No valid HQ session")) {
80
+ throw new MissingFlagTokenError();
81
+ }
82
+ throw error;
83
+ }
84
+ });
85
+ const getToken = async () => {
86
+ const token = await acquireToken();
87
+ if (typeof token !== "string" || token.trim().length === 0) {
88
+ throw new MissingFlagTokenError();
89
+ }
90
+ return token;
91
+ };
92
+ client = (options.createClient ?? createFlagClient)({
93
+ endpoint,
94
+ getToken,
95
+ env: {},
96
+ refreshIntervalMs: 0,
97
+ requestTimeoutMs: LANES_FLAG_READ_TIMEOUT_MS,
98
+ ...(companyUid ? { companyUid } : {}),
99
+ ...(companySlug ? { companyIdentifiers: [companySlug] } : {}),
100
+ onError: reportFailure,
101
+ });
102
+ await client.ready();
103
+ const resolution = client.explain(flagKey, { fallback: false });
104
+ if (failed)
105
+ return false;
106
+ if (resolution.source !== "snapshot" && resolution.source !== "local-override") {
107
+ reportFailure(new MissingFlagRowError(flagKey));
108
+ }
109
+ else {
110
+ enabled = resolution.value;
111
+ }
112
+ }
113
+ catch (error) {
114
+ reportFailure(error);
115
+ }
116
+ finally {
117
+ try {
118
+ client?.close();
119
+ }
120
+ catch (error) {
121
+ reportFailure(error);
122
+ }
123
+ }
124
+ return failed ? false : enabled;
125
+ }
126
+ export function _resetLanesRegistryFlagCacheForTests() {
127
+ registryReads.clear();
128
+ }
129
+ //# sourceMappingURL=registry-flag.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.185.0",
3
+ "version": "5.185.1",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {