@indigoai-us/hq-cli 5.345.127 → 5.345.128

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 (38) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/assets/scaffold/core/scripts/handoff-knowledge-commit.sh +123 -0
  3. package/assets/scaffold/core/scripts/hq-detach.sh +169 -0
  4. package/dist/command-catalog.generated.d.ts +40 -2
  5. package/dist/command-catalog.generated.js +48 -2
  6. package/dist/commands/auth.js +19 -2
  7. package/dist/commands/core-bucket-c-handoff-knowledge-fast.d.ts +2 -0
  8. package/dist/commands/core-bucket-c-handoff-knowledge-fast.js +10 -0
  9. package/dist/commands/core-bucket-c-handoff-knowledge-native.d.ts +46 -0
  10. package/dist/commands/core-bucket-c-handoff-knowledge-native.js +284 -0
  11. package/dist/commands/core-bucket-c-hq-detach-fast.d.ts +2 -0
  12. package/dist/commands/core-bucket-c-hq-detach-fast.js +10 -0
  13. package/dist/commands/core-bucket-c-hq-detach-native.d.ts +43 -0
  14. package/dist/commands/core-bucket-c-hq-detach-native.js +241 -0
  15. package/dist/commands/core.js +12 -0
  16. package/dist/commands/lanes-accounts.js +3 -1
  17. package/dist/commands/lanes-shared.d.ts +7 -0
  18. package/dist/commands/lanes.js +113 -3
  19. package/dist/commands/skill.js +9 -4
  20. package/dist/fast-scaffold.js +28 -0
  21. package/dist/lib/capacity/lane-login.js +1 -0
  22. package/dist/lib/lanes/accounts.js +2 -2
  23. package/dist/lib/lanes/host-capacity.d.ts +4 -0
  24. package/dist/lib/lanes/host-capacity.js +10 -1
  25. package/dist/lib/lanes/index.d.ts +2 -2
  26. package/dist/lib/lanes/index.js +1 -1
  27. package/dist/lib/lanes/loop.d.ts +8 -0
  28. package/dist/lib/lanes/loop.js +35 -0
  29. package/dist/lib/lanes/quota-notice.d.ts +11 -11
  30. package/dist/lib/lanes/quota-notice.js +20 -29
  31. package/dist/lib/lanes/quota.d.ts +69 -50
  32. package/dist/lib/lanes/quota.js +146 -127
  33. package/dist/lib/lanes/reconcile.d.ts +14 -0
  34. package/dist/lib/lanes/reconcile.js +77 -23
  35. package/dist/lib/lanes/watcher.d.ts +8 -0
  36. package/dist/lib/lanes/watcher.js +62 -20
  37. package/dist/utils/resident-package-preload.js +12 -4
  38. package/package.json +1 -1
@@ -8,7 +8,7 @@
8
8
  import * as fs from "node:fs";
9
9
  import * as path from "node:path";
10
10
  import { parseUserYaml } from "../../utils/user-yaml-error.js";
11
- import { compareLaneQueueOrder, compareLaneQueueOrderWithLeads, freeClaudeAccountSlots, leadLaneIds, hasActiveAdmissionReservation, hasActivePendingResume, laneAdmissionCapReason, laneRunsOnHost, withAllLaneAdmissionLocks, } from "./admission.js";
11
+ import { compareLaneQueueOrder, compareLaneQueueOrderWithLeads, freeClaudeAccountSlots, leadLaneIds, hasActiveAdmissionReservation, hasActivePendingResume, laneAdmissionCapReason, laneOccupiesRunningSlot, laneRunsOnHost, withAllLaneAdmissionLocks, } from "./admission.js";
12
12
  import { accountStatus, isCredentialProven, resolveAccount } from "./accounts.js";
13
13
  import { effectiveAccountHome } from "./account-home.js";
14
14
  import { enforceRegistryApprovalGate } from "./approval-gate.js";
@@ -34,7 +34,7 @@ import { LEAD_LANE_KEEP_ALIVE_FLAG, LEAD_LANE_KEEP_ALIVE_RESUME_BLOCKED_FLAG, LE
34
34
  import { isFailedQuotaKeepAliveLane, providerSupportsSessionResume } from "./delivery.js";
35
35
  import { LANE_PROVIDERS, isIsoDateTime, isTerminalLaneState } from "./types.js";
36
36
  import { applyDefaultQuotaHold, clearAccountQuotaAfterSuccessfulTurnBestEffort, loadQuotaState, readQuotaSignal, recordAccountQuota, } from "./quota.js";
37
- import { deliverQuotaHoldNotice, quotaHoldNotice } from "./quota-notice.js";
37
+ import { deliverQuotaNotice, quotaLaneNotice } from "./quota-notice.js";
38
38
  import { answeredQuestionEntries, questionRecordRefusalCode, raiseEnvelopeQuestions, resolveQuestionCompanyWithFallback, } from "./questions.js";
39
39
  import { SILENCE_MS, appendWatcherEvent, classifyLaneExit, isPidAlive, missingExpectedEnvelopeFile, readLatestEnvelopeFile, readLatestEnvelopeRecord, watcherEventsPath, watcherOutLogPath, writeWatcherDecision, } from "./watcher.js";
40
40
  import { createLaneMesh, emitLaneDecisionEvents, emitLaneTerminalStateEvent, laneMeshCompany, } from "./mesh-events.js";
@@ -1724,32 +1724,16 @@ async function heartbeatAndDeadHosts(hqRoot, lanes, summary, deps, now) {
1724
1724
  ? classifyLaneExit({ envelope: null, hasPartialOutput: false, invalidEnvelope })
1725
1725
  : classification;
1726
1726
  let questionRefusalCode = null;
1727
- const accountRetryReason = quota
1728
- ? "usage_limit"
1729
- : providerRejection && classification.reason === "account_not_logged_in"
1730
- ? "account_unavailable"
1731
- : null;
1727
+ // A usage limit fails only this lane; the senior decides on resume.
1728
+ const accountRetryReason = !quota && providerRejection && classification.reason === "account_not_logged_in"
1729
+ ? "account_unavailable"
1730
+ : null;
1732
1731
  if (!deps.dryRun &&
1733
1732
  quota &&
1734
1733
  classified.account &&
1735
1734
  (classification.reason === "account_quota_exhausted" ||
1736
1735
  classification.reason === "account_model_unavailable")) {
1737
- const quotaState = recordAccountQuota(hqRoot, classified.provider, classified.account, quota, {
1738
- now,
1739
- unconfirmedHoldMs: providerQuotaDefaultHoldMs(loadLanesConfig(hqRoot).providers[classified.provider]),
1740
- });
1741
- if (classification.reason === "account_quota_exhausted") {
1742
- const notice = quotaHoldNotice(quotaState, classified.provider, classified.account, lane.lane_id);
1743
- if (notice) {
1744
- try {
1745
- deliverQuotaHoldNotice(hqRoot, lane, notice, now.toISOString());
1746
- }
1747
- catch (err) {
1748
- const message = err instanceof Error ? err.message : String(err);
1749
- process.stderr.write(`hq lanes reconcile: quota hold notice failed for ${lane.lane_id}: ${message}\n`);
1750
- }
1751
- }
1752
- }
1736
+ recordAccountQuota(hqRoot, classified.provider, classified.account, quota, now);
1753
1737
  }
1754
1738
  if (!deps.dryRun &&
1755
1739
  accountRetryReason &&
@@ -1886,6 +1870,22 @@ async function heartbeatAndDeadHosts(hqRoot, lanes, summary, deps, now) {
1886
1870
  result.record.model) {
1887
1871
  clearAccountQuotaAfterSuccessfulTurnBestEffort(hqRoot, result.record.provider, result.record.account, result.record.model, new Date(nowIso));
1888
1872
  }
1873
+ if (!deps.dryRun &&
1874
+ result.changed &&
1875
+ quota &&
1876
+ (result.record.terminal_reason === "account_quota_exhausted" ||
1877
+ result.record.terminal_reason === "account_model_unavailable")) {
1878
+ // The dead worker's exit is classified here, not in its watcher, so
1879
+ // the senior notice goes out here, once, after the terminal write and
1880
+ // keyed to the new version. No account hold is set.
1881
+ try {
1882
+ deliverQuotaNotice(hqRoot, result.record, quotaLaneNotice(result.record, quota), nowIso);
1883
+ }
1884
+ catch (err) {
1885
+ const message = err instanceof Error ? err.message : String(err);
1886
+ process.stderr.write(`hq lanes reconcile: quota notice failed for ${lane.lane_id}: ${message}\n`);
1887
+ }
1888
+ }
1889
1889
  if (result.changed) {
1890
1890
  summary.dead_host.push({
1891
1891
  id: lane.lane_id,
@@ -3875,4 +3875,58 @@ export async function wakeAnsweredLaneNow(hqRoot, laneId, deps) {
3875
3875
  error: failure?.why ?? `Lane ${laneId} did not leave awaiting_input after its questions were answered`,
3876
3876
  };
3877
3877
  }
3878
+ /**
3879
+ * Run queue admission in-process, without the rest of a reconcile pass.
3880
+ *
3881
+ * Commands that change capacity (create, stop, cancel, clear-quota, a lane
3882
+ * exit) call this so queued lanes start without `hq daemon`. It takes the
3883
+ * reconcile lock and every provider admission lock, so it is safe to run
3884
+ * while a daemon is also reconciling: whichever runs second sees the lanes
3885
+ * the first one already admitted.
3886
+ */
3887
+ export async function admitQueuedNow(hqRoot, deps) {
3888
+ const summary = emptySummary(deps.dryRun);
3889
+ const now = deps.now();
3890
+ // A queued lane is worth an admission attempt only while its provider has
3891
+ // a free running slot here. Account and profile caps are left to
3892
+ // admitQueued, which can move a lane to another free account.
3893
+ const hasAdmittableQueued = (lanes) => {
3894
+ const queued = lanes.filter((lane) => lane.state === "queued" && laneRunsHere(lane, deps.host));
3895
+ if (queued.length === 0)
3896
+ return false;
3897
+ const config = loadLanesConfig(hqRoot);
3898
+ const nowMs = now.getTime();
3899
+ return queued.some((lane) => {
3900
+ const providerRunning = lanes.filter((other) => other.lane_id !== lane.lane_id && other.provider === lane.provider &&
3901
+ laneOccupiesRunningSlot(other, nowMs) && laneRunsHere(other, deps.host)).length;
3902
+ return providerRunning < config.providers[lane.provider].max_running;
3903
+ });
3904
+ };
3905
+ // Skip the lock and the CPU sample when nothing can start here.
3906
+ if (!hasAdmittableQueued(loadLaneRecords(hqRoot, emptySummary(deps.dryRun)))) {
3907
+ return { admitted: [], errors: [] };
3908
+ }
3909
+ const throttleDeps = deps.throttleDeps ?? defaultThrottleDeps(deps.env ?? process.env);
3910
+ await withReconcileLock(hqRoot, async () => {
3911
+ const previousState = readThrottleState(throttleStatePath(hqRoot), throttleDeps);
3912
+ const previousSnapshot = previousState === "missing" || previousState === "unreadable"
3913
+ ? undefined
3914
+ : previousState.cpu_snapshot;
3915
+ const cpuObservation = deps.cpuBusyFraction !== undefined
3916
+ ? undefined
3917
+ : await sampleCpuBusyObservation(throttleDeps, previousSnapshot);
3918
+ const admissionDeps = {
3919
+ ...deps,
3920
+ ...(cpuObservation ? { cpuBusyFraction: cpuObservation.busy, cpuObservation } : {}),
3921
+ skipAdmissionWithoutCpuSample: false,
3922
+ };
3923
+ await withAllLaneAdmissionLocks(hqRoot, async () => {
3924
+ const lanes = loadLaneRecords(hqRoot, summary);
3925
+ if (!hasAdmittableQueued(lanes))
3926
+ return;
3927
+ await admitQueued(hqRoot, lanes, summary, admissionDeps, now);
3928
+ });
3929
+ });
3930
+ return { admitted: summary.admitted, errors: summary.errors };
3931
+ }
3878
3932
  //# sourceMappingURL=reconcile.js.map
@@ -211,6 +211,14 @@ export interface WatcherLoopDeps {
211
211
  retrySpawnDeps?: Omit<SpawnLaneDeps, "admissionHost">;
212
212
  /** Active-company fallback when an unscoped lane asks from its envelope. */
213
213
  resolveQuestionActiveCompany?: () => Promise<LaneCompanyRef>;
214
+ /**
215
+ * Admit queued lanes after this lane's exit frees its slot. Default: the
216
+ * in-process admitter (`admitQueuedNow`), so the queue drains without a
217
+ * daemon. Returns the admitted lane ids.
218
+ */
219
+ admitQueued?: (hqRoot: string) => Promise<string[]>;
220
+ /** Test seam: deliver the one-time usage-limit notice to the lane's senior. */
221
+ deliverQuotaNotice?: (lane: LaneRecord, text: string) => Promise<void>;
214
222
  /** Resume an atomically queued inbox after this watcher wins terminal CAS. */
215
223
  recoverQueuedMessages?: (lane: LaneRecord) => Promise<void>;
216
224
  /** Deliver a lane-senior escalation through the normal lane-message router. */
@@ -43,7 +43,7 @@ import { appendCappedHistory, listQuestionIds, readLane, readQuestion, retryUpda
43
43
  import { enforceRegistryApprovalGate } from "./approval-gate.js";
44
44
  import { readWorkerRunResult } from "./delivery.js";
45
45
  import { applyDefaultQuotaHold, clearAccountQuotaAfterSuccessfulTurnBestEffort, quotaSignalFromFields, readQuotaSignal, recordAccountQuota, } from "./quota.js";
46
- import { deliverQuotaHoldNotice, quotaHoldNotice } from "./quota-notice.js";
46
+ import { deliverQuotaNotice as deliverQuotaNoticeToSenior, quotaLaneNotice } from "./quota-notice.js";
47
47
  import { PROVIDER_REJECTED_REASON, QUOTA_STATUS, isProviderLoginFailure, providerRejectionDetails, readProviderRejection, } from "./provider-rejection.js";
48
48
  import { appendDropboxMessageAtPath, dropboxInboxHasMessages, readToolActivity, toolActivityPath } from "./dropbox.js";
49
49
  import { loadLanesConfig, providerProgressEventMinIntervalMs, providerQuotaDefaultHoldMs } from "./config.js";
@@ -154,14 +154,15 @@ function validFailureOutputTime(value, fallback) {
154
154
  : fallback;
155
155
  }
156
156
  export function routeProviderFailure(failure, readQuota, model, now) {
157
+ const structured = failure && failure.resets_at !== undefined ? { resets_at: failure.resets_at } : {};
157
158
  if (failure && failure.status === QUOTA_STATUS && isAccountQuotaFailure(failure)) {
158
159
  return {
159
- quota: quotaSignalFromFields({ api_error_status: QUOTA_STATUS, is_error: true, result: failure.message }, model, failure.output_at ? validFailureOutputTime(failure.output_at, now) : now),
160
+ quota: quotaSignalFromFields({ api_error_status: QUOTA_STATUS, is_error: true, result: failure.message, ...structured }, model, failure.output_at ? validFailureOutputTime(failure.output_at, now) : now),
160
161
  rejection: null,
161
162
  };
162
163
  }
163
164
  if (failure && failure.status === null && isAccountQuotaFailure(failure)) {
164
- const quota = quotaSignalFromFields({ api_error_status: undefined, is_error: true, result: failure.message }, model, failure.output_at ? validFailureOutputTime(failure.output_at, now) : now);
165
+ const quota = quotaSignalFromFields({ api_error_status: undefined, is_error: true, result: failure.message, ...structured }, model, failure.output_at ? validFailureOutputTime(failure.output_at, now) : now);
165
166
  if (quota)
166
167
  return { quota, rejection: null };
167
168
  }
@@ -1167,6 +1168,28 @@ async function settleKrFreshness(hqRoot, lane, manifestTurnId, at, deps, logDeci
1167
1168
  };
1168
1169
  });
1169
1170
  }
1171
+ /**
1172
+ * Tell the lane's senior once that a usage limit ended this lane. Called
1173
+ * only on the terminal write that changed the lane; the message id (lane id
1174
+ * and version) dedupes a retried append.
1175
+ */
1176
+ async function deliverQuotaNotice(hqRoot, lane, quota, at, deps, logDecision) {
1177
+ const notice = quotaLaneNotice(lane, quota);
1178
+ try {
1179
+ if (deps.deliverQuotaNotice) {
1180
+ await deps.deliverQuotaNotice(lane, notice.text);
1181
+ logDecision({ event: "quota_notice", at, delivered_to: "test_seam" });
1182
+ return;
1183
+ }
1184
+ const deliveredTo = deliverQuotaNoticeToSenior(hqRoot, lane, notice, at);
1185
+ logDecision({ event: "quota_notice", at, delivered_to: deliveredTo });
1186
+ }
1187
+ catch (err) {
1188
+ const message = err instanceof Error ? err.message : String(err);
1189
+ process.stderr.write(`hq lanes watcher: quota notice failed for ${lane.lane_id}: ${message}\n`);
1190
+ logDecision({ event: "quota_notice_failed", at, error: message });
1191
+ }
1192
+ }
1170
1193
  function findBlockerFreshnessSessionInbox(hqRoot, sessionId) {
1171
1194
  let candidates;
1172
1195
  try {
@@ -1457,6 +1480,18 @@ async function runWatcherLoopOwned(hqRoot, laneId, deps) {
1457
1480
  }
1458
1481
  const progressIntervalMs = deps.progressEventMinIntervalMs ?? readProgressIntervalMs(hqRoot, readLaneSoft(hqRoot, laneId));
1459
1482
  const spawnRepair = deps.spawnRepair ?? spawnEnvelopeRepair;
1483
+ const defaultAdmitQueued = async (root) => {
1484
+ const { admitQueuedNow } = await import("./reconcile.js");
1485
+ const host = (deps.resolveAdmissionHost ?? resolveProcessAdmissionHost)();
1486
+ const result = await admitQueuedNow(root, {
1487
+ now: () => new Date(now()),
1488
+ host,
1489
+ dryRun: false,
1490
+ spawnLaneDeps: { ...deps.retrySpawnDeps, admissionHost: host },
1491
+ ...(deps.retrySpawnDeps?.env ? { env: deps.retrySpawnDeps.env } : {}),
1492
+ });
1493
+ return result.admitted.map((entry) => entry.id);
1494
+ };
1460
1495
  const retryAccount = deps.retryAccount ?? ((root, lane, reason) => retryLaneOnAlternateAccount(root, lane, reason, "watcher", {
1461
1496
  ...deps.retrySpawnDeps,
1462
1497
  admissionHost: (deps.resolveAdmissionHost ?? resolveProcessAdmissionHost)(),
@@ -1765,28 +1800,17 @@ async function runWatcherLoopOwned(hqRoot, laneId, deps) {
1765
1800
  (classification.reason === "account_quota_exhausted" ||
1766
1801
  classification.reason === "account_model_unavailable")) {
1767
1802
  try {
1768
- const observedAt = new Date(now());
1769
- const quotaState = recordAccountQuota(hqRoot, quotaLane.provider, quotaLane.account, quota, {
1770
- now: observedAt,
1771
- unconfirmedHoldMs: providerQuotaDefaultHoldMs(loadLanesConfig(hqRoot).providers[quotaLane.provider]),
1772
- });
1773
- if (classification.reason === "account_quota_exhausted") {
1774
- const notice = quotaHoldNotice(quotaState, quotaLane.provider, quotaLane.account, quotaLane.lane_id);
1775
- if (notice) {
1776
- const deliveredTo = deliverQuotaHoldNotice(hqRoot, quotaLane, notice, observedAt.toISOString());
1777
- logDecision({ event: "quota_hold_notice", at: tick.emit.at, account: quotaLane.account, delivered_to: deliveredTo });
1778
- }
1779
- }
1803
+ recordAccountQuota(hqRoot, quotaLane.provider, quotaLane.account, quota, new Date(now()));
1780
1804
  }
1781
1805
  catch (err) {
1782
1806
  process.stderr.write(`hq lanes watcher: quota record failed for ${laneId}: ${err instanceof Error ? err.message : String(err)}\n`);
1783
1807
  }
1784
1808
  }
1785
- const accountRetryReason = quota
1786
- ? "usage_limit"
1787
- : isProviderLoginFailure(providerRejection)
1788
- ? "account_unavailable"
1789
- : null;
1809
+ // A usage limit fails only this lane: no automatic move to another
1810
+ // account. The senior is told and decides (owner decision 2026-10-14).
1811
+ const accountRetryReason = !quota && isProviderLoginFailure(providerRejection)
1812
+ ? "account_unavailable"
1813
+ : null;
1790
1814
  if (accountRetryReason && quotaLane?.account) {
1791
1815
  try {
1792
1816
  const retry = await retryAccount(hqRoot, quotaLane, accountRetryReason);
@@ -1945,6 +1969,24 @@ async function runWatcherLoopOwned(hqRoot, laneId, deps) {
1945
1969
  logDecision({ event: "keep_alive_terminal_trigger_failed", at: tick.emit.at, error: message });
1946
1970
  }
1947
1971
  }
1972
+ if (terminalWrite.changed &&
1973
+ (updated.terminal_reason === "account_quota_exhausted" || updated.terminal_reason === "account_model_unavailable")) {
1974
+ await deliverQuotaNotice(hqRoot, updated, quota ?? null, tick.emit.at, deps, logDecision);
1975
+ }
1976
+ if (terminalWrite.changed && updated.state !== "running" && updated.state !== "queued") {
1977
+ // The exit freed a running slot: admit queued lanes here rather
1978
+ // than waiting for a reconcile pass that may never run.
1979
+ try {
1980
+ const admitted = await (deps.admitQueued ?? defaultAdmitQueued)(hqRoot);
1981
+ if (admitted.length > 0)
1982
+ logDecision({ event: "queue_admitted", at: tick.emit.at, admitted });
1983
+ }
1984
+ catch (err) {
1985
+ const message = err instanceof Error ? err.message : String(err);
1986
+ process.stderr.write(`hq lanes watcher: queue admission failed after ${laneId}: ${message}\n`);
1987
+ logDecision({ event: "queue_admission_failed", at: tick.emit.at, error: message });
1988
+ }
1989
+ }
1948
1990
  }
1949
1991
  }
1950
1992
  lastSignalMs = tick.nextLastSignalMs;
@@ -62,12 +62,12 @@ export const RESIDENT_PACKAGE_MODULES = {
62
62
  ],
63
63
  "daemon-logs-follow": [],
64
64
  "mesh-daemon": ["../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud"],
65
- "lanes-watch": ["../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud"],
66
- "monitor-wait": ["../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud"],
67
- "monitor-run": ["../commands/lanes.js", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud"],
65
+ "lanes-watch": ["../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud", "../lib/lanes/reconcile.js"],
66
+ "monitor-wait": ["../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud", "../lib/lanes/reconcile.js"],
67
+ "monitor-run": ["../commands/lanes.js", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud", "../lib/lanes/reconcile.js"],
68
68
  "agents-message-wait": ["../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud"],
69
69
  "integrations-oauth-wait": ["../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud"],
70
- "outpost-wait": ["../commands/lanes.js", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud"],
70
+ "outpost-wait": ["../commands/lanes.js", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud", "../lib/lanes/reconcile.js"],
71
71
  "secrets-sandbox": [],
72
72
  "pkg-update": ["../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client", "../utils/cognito-session.js", "@indigoai-us/hq-cloud"],
73
73
  "pack-install": [
@@ -255,6 +255,8 @@ const LOADERS = {
255
255
  () => import("../utils/cognito-session.js"),
256
256
  () => import("../lib/first-sync-next-step.js"),
257
257
  () => import("@indigoai-us/hq-cloud"),
258
+ // The watcher admits queued lanes in-process after a lane exits.
259
+ () => import("../lib/lanes/reconcile.js"),
258
260
  ],
259
261
  "monitor-wait": [
260
262
  async () => {
@@ -269,6 +271,8 @@ const LOADERS = {
269
271
  () => import("../utils/cognito-session.js"),
270
272
  () => import("../lib/first-sync-next-step.js"),
271
273
  () => import("@indigoai-us/hq-cloud"),
274
+ // The watcher admits queued lanes in-process after a lane exits.
275
+ () => import("../lib/lanes/reconcile.js"),
272
276
  ],
273
277
  "monitor-run": [
274
278
  () => import("../commands/lanes.js"),
@@ -284,6 +288,8 @@ const LOADERS = {
284
288
  () => import("../utils/cognito-session.js"),
285
289
  () => import("../lib/first-sync-next-step.js"),
286
290
  () => import("@indigoai-us/hq-cloud"),
291
+ // The watcher admits queued lanes in-process after a lane exits.
292
+ () => import("../lib/lanes/reconcile.js"),
287
293
  ],
288
294
  "agents-message-wait": [
289
295
  async () => {
@@ -327,6 +333,8 @@ const LOADERS = {
327
333
  () => import("../utils/cognito-session.js"),
328
334
  () => import("../lib/first-sync-next-step.js"),
329
335
  () => import("@indigoai-us/hq-cloud"),
336
+ // The watcher admits queued lanes in-process after a lane exits.
337
+ () => import("../lib/lanes/reconcile.js"),
330
338
  ],
331
339
  "secrets-sandbox": [],
332
340
  "pkg-update": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.345.127",
3
+ "version": "5.345.128",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {