@indigoai-us/hq-cli 5.345.128 → 5.345.130

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 (63) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/assets/scaffold/core/scripts/lib/codex-output-schema.mjs +304 -0
  3. package/assets/scaffold/core/scripts/workflow-runner.mjs +2890 -0
  4. package/dist/command-catalog.generated.d.ts +29 -0
  5. package/dist/command-catalog.generated.js +34 -0
  6. package/dist/commands/core-bucket-c-work-mesh-offer-native.js +8 -2
  7. package/dist/commands/core-pipeline-workflow-runner-native.d.ts +175 -0
  8. package/dist/commands/core-pipeline-workflow-runner-native.js +3237 -0
  9. package/dist/commands/core-workflow-run-command.d.ts +4 -0
  10. package/dist/commands/core-workflow-run-command.js +41 -0
  11. package/dist/commands/core.js +4 -0
  12. package/dist/commands/daemon.js +2 -0
  13. package/dist/commands/lanes-accounts.js +0 -1
  14. package/dist/commands/lanes.js +26 -14
  15. package/dist/commands/mesh.js +32 -19
  16. package/dist/lib/bot/inbox-poll-backoff-flag.d.ts +3 -5
  17. package/dist/lib/bot/inbox-poll-backoff-flag.js +20 -12
  18. package/dist/lib/bot/inbox-wake.d.ts +18 -0
  19. package/dist/lib/bot/inbox-wake.js +125 -0
  20. package/dist/lib/bot/run.d.ts +8 -0
  21. package/dist/lib/bot/run.js +51 -7
  22. package/dist/lib/bot/runtime/messages-stream.js +31 -3
  23. package/dist/lib/core-utils/workflow-runner-schema.d.ts +7 -0
  24. package/dist/lib/core-utils/workflow-runner-schema.js +259 -0
  25. package/dist/lib/daemon/catalog.d.ts +4 -0
  26. package/dist/lib/daemon/catalog.js +6 -3
  27. package/dist/lib/daemon/flag-monitor.d.ts +4 -1
  28. package/dist/lib/daemon/flag-monitor.js +12 -6
  29. package/dist/lib/daemon/flag.d.ts +2 -0
  30. package/dist/lib/daemon/flag.js +11 -5
  31. package/dist/lib/daemon/hq-child-bootstrap.mjs +47 -7
  32. package/dist/lib/daemon/kill-switch-flags.d.ts +5 -0
  33. package/dist/lib/daemon/kill-switch-flags.js +5 -0
  34. package/dist/lib/daemon/lanes-reconcile-loader.d.ts +7 -0
  35. package/dist/lib/daemon/lanes-reconcile-loader.js +24 -0
  36. package/dist/lib/daemon/lanes-reconcile-watcher.d.ts +17 -0
  37. package/dist/lib/daemon/lanes-reconcile-watcher.js +80 -0
  38. package/dist/lib/daemon/remote-control.d.ts +8 -5
  39. package/dist/lib/daemon/remote-control.js +8 -7
  40. package/dist/lib/daemon/run.d.ts +4 -1
  41. package/dist/lib/daemon/run.js +133 -20
  42. package/dist/lib/doctor/json-output.d.ts +15 -3
  43. package/dist/lib/doctor/json-output.js +13 -1
  44. package/dist/lib/lanes/config.d.ts +8 -4
  45. package/dist/lib/lanes/config.js +30 -36
  46. package/dist/lib/lanes/daemon-reconcile.d.ts +3 -0
  47. package/dist/lib/lanes/daemon-reconcile.js +8 -0
  48. package/dist/lib/lanes/index.d.ts +1 -1
  49. package/dist/lib/lanes/index.js +1 -1
  50. package/dist/lib/lanes/reconcile-result.d.ts +10 -0
  51. package/dist/lib/lanes/reconcile-result.js +11 -0
  52. package/dist/lib/lanes/reconcile.js +3 -26
  53. package/dist/lib/lanes/throttle.js +5 -9
  54. package/dist/lib/lanes/types.d.ts +4 -5
  55. package/dist/lib/lanes/types.js +1 -0
  56. package/dist/lib/mesh/live/daemon/work-subscribe.d.ts +1 -1
  57. package/dist/lib/mesh/live/daemon/work-subscribe.js +8 -1
  58. package/dist/lib/mesh/live/paths.d.ts +2 -0
  59. package/dist/lib/mesh/live/paths.js +2 -0
  60. package/dist/lib/mesh/story-status.d.ts +2 -2
  61. package/dist/lib/mesh/story-status.js +2 -1
  62. package/dist/utils/resident-package-preload.js +6 -0
  63. package/package.json +1 -1
@@ -13,10 +13,14 @@ import { parseConfigEffort } from "./effort.js";
13
13
  import { LanesConfigError } from "./errors.js";
14
14
  import { CONFIG_SCHEMA_VERSION, LANE_PROVIDERS, isLaneProvider, parseMajorSchema, } from "./types.js";
15
15
  export const LANES_CONFIG_REL = path.join("personal", "lanes", "config.json");
16
- export const DEFAULT_MAX_QUEUED = 3;
17
- export const DEFAULT_CPU_BUSY_PAUSE = 0.85;
18
- export const DEFAULT_CPU_BUSY_RESUME = 0.7;
19
- export const DEFAULT_MIN_AVAILABLE_MEM_MB = 1024;
16
+ /**
17
+ * Owner directive 2026-10-14: no default lane caps or CPU/memory admission
18
+ * gates. A provider has no running or queued limit unless the operator sets
19
+ * `max_running` / `max_queued` explicitly; this value stands for "no limit"
20
+ * and stays a finite integer so it survives JSON output.
21
+ */
22
+ export const UNLIMITED_LANES = Number.MAX_SAFE_INTEGER;
23
+ export const DEFAULT_MAX_QUEUED = UNLIMITED_LANES;
20
24
  /**
21
25
  * Owner directive 2026-09-22: "if it's been an hour since last msg, always
22
26
  * run compact". Override per provider with `compact_after_ms`.
@@ -69,9 +73,9 @@ export const DEFAULT_LIVENESS_WINDOWS = {
69
73
  silent_lost_ms: DEFAULT_SILENT_LOST_MS,
70
74
  };
71
75
  export const DEFAULT_PROVIDER_MAX_RUNNING = {
72
- claude: 2,
73
- codex: 4,
74
- grok: 4,
76
+ claude: UNLIMITED_LANES,
77
+ codex: UNLIMITED_LANES,
78
+ grok: UNLIMITED_LANES,
75
79
  };
76
80
  export const DEFAULT_ACCOUNT_HOMES = {
77
81
  claude: "~/.claude",
@@ -152,14 +156,6 @@ function positiveInt(value, field, fallback) {
152
156
  }
153
157
  return value;
154
158
  }
155
- function nonNegativeInt(value, field, fallback) {
156
- if (value === undefined)
157
- return fallback;
158
- if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
159
- throw new LanesConfigError("invalid_config", `${field} must be a non-negative integer`, { field, value });
160
- }
161
- return value;
162
- }
163
159
  function positiveNumber(value, field, fallback) {
164
160
  if (value === undefined)
165
161
  return fallback;
@@ -168,9 +164,9 @@ function positiveNumber(value, field, fallback) {
168
164
  }
169
165
  return value;
170
166
  }
171
- function unitInterval(value, field, fallback) {
167
+ function optionalUnitInterval(value, field) {
172
168
  if (value === undefined)
173
- return fallback;
169
+ return undefined;
174
170
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1) {
175
171
  throw new LanesConfigError("invalid_config", `${field} must be a number in [0, 1]`, { field, value });
176
172
  }
@@ -377,30 +373,35 @@ function parseProvider(provider, raw, deps) {
377
373
  }
378
374
  return parsed;
379
375
  }
376
+ /**
377
+ * CPU and memory admission gates are opt-in. With no `throttle` keys set,
378
+ * admission never waits on CPU load or free memory.
379
+ */
380
380
  function parseThrottle(raw) {
381
381
  const obj = raw === undefined ? {} : raw;
382
382
  if (!isPlainObject(obj)) {
383
383
  throw new LanesConfigError("invalid_config", "throttle must be an object");
384
384
  }
385
- const pause = unitInterval(obj.cpu_busy_pause, "throttle.cpu_busy_pause", DEFAULT_CPU_BUSY_PAUSE);
386
- const resume = unitInterval(obj.cpu_busy_resume, "throttle.cpu_busy_resume", DEFAULT_CPU_BUSY_RESUME);
387
- if (resume > pause) {
388
- throw new LanesConfigError("invalid_config", "throttle.cpu_busy_resume must be <= throttle.cpu_busy_pause", { cpu_busy_pause: pause, cpu_busy_resume: resume });
385
+ const result = {};
386
+ const pause = optionalUnitInterval(obj.cpu_busy_pause, "throttle.cpu_busy_pause");
387
+ const resumeRaw = optionalUnitInterval(obj.cpu_busy_resume, "throttle.cpu_busy_resume");
388
+ if (pause !== undefined) {
389
+ const resume = resumeRaw ?? pause;
390
+ if (resume > pause) {
391
+ throw new LanesConfigError("invalid_config", "throttle.cpu_busy_resume must be <= throttle.cpu_busy_pause", { cpu_busy_pause: pause, cpu_busy_resume: resume });
392
+ }
393
+ result.cpu_busy_pause = pause;
394
+ result.cpu_busy_resume = resume;
389
395
  }
390
- let minMem = DEFAULT_MIN_AVAILABLE_MEM_MB;
391
396
  if (obj.min_available_mem_mb !== undefined) {
392
397
  if (typeof obj.min_available_mem_mb !== "number" ||
393
398
  !Number.isFinite(obj.min_available_mem_mb) ||
394
399
  obj.min_available_mem_mb < 0) {
395
400
  throw new LanesConfigError("invalid_config", "throttle.min_available_mem_mb must be a non-negative number", { value: obj.min_available_mem_mb });
396
401
  }
397
- minMem = obj.min_available_mem_mb;
402
+ result.min_available_mem_mb = obj.min_available_mem_mb;
398
403
  }
399
- return {
400
- cpu_busy_pause: pause,
401
- cpu_busy_resume: resume,
402
- min_available_mem_mb: minMem,
403
- };
404
+ return result;
404
405
  }
405
406
  function parseLiveness(raw) {
406
407
  const obj = raw === undefined ? {} : raw;
@@ -458,16 +459,11 @@ export function documentedDefaultConfig(deps = defaultDeps()) {
458
459
  return {
459
460
  schema_version: CONFIG_SCHEMA_VERSION,
460
461
  providers,
461
- throttle: {
462
- cpu_busy_pause: DEFAULT_CPU_BUSY_PAUSE,
463
- cpu_busy_resume: DEFAULT_CPU_BUSY_RESUME,
464
- min_available_mem_mb: DEFAULT_MIN_AVAILABLE_MEM_MB,
465
- },
462
+ throttle: {},
466
463
  liveness: { ...DEFAULT_LIVENESS_WINDOWS },
467
464
  tracker: { checks: { ...DEFAULT_TRACKER_CHECKS } },
468
465
  runaway_search_guard: { ...DEFAULT_RUNAWAY_SEARCH_GUARD_CONFIG },
469
466
  low_disk_min_free_bytes: DEFAULT_LOW_DISK_MIN_FREE_BYTES,
470
- lead_reserve_per_host: 1,
471
467
  codex_rollout_compress_after_hours: DEFAULT_CODEX_ROLLOUT_COMPRESS_AFTER_HOURS,
472
468
  codex_rollout_delete_after_days: DEFAULT_CODEX_ROLLOUT_DELETE_AFTER_DAYS,
473
469
  session_question_timeout_secs: DEFAULT_SESSION_QUESTION_TIMEOUT_SECS,
@@ -508,7 +504,6 @@ export function parseLanesConfig(raw, deps = defaultDeps()) {
508
504
  }
509
505
  const compressAfterHours = positiveInt(raw.codex_rollout_compress_after_hours, "codex_rollout_compress_after_hours", DEFAULT_CODEX_ROLLOUT_COMPRESS_AFTER_HOURS);
510
506
  const deleteAfterDays = positiveInt(raw.codex_rollout_delete_after_days, "codex_rollout_delete_after_days", DEFAULT_CODEX_ROLLOUT_DELETE_AFTER_DAYS);
511
- const leadReservePerHost = nonNegativeInt(raw.lead_reserve_per_host, "lead_reserve_per_host", 1);
512
507
  if (deleteAfterDays * 24 < compressAfterHours) {
513
508
  throw new LanesConfigError("invalid_config", "codex_rollout_delete_after_days must be at least codex_rollout_compress_after_hours / 24", { codex_rollout_compress_after_hours: compressAfterHours, codex_rollout_delete_after_days: deleteAfterDays });
514
509
  }
@@ -522,7 +517,6 @@ export function parseLanesConfig(raw, deps = defaultDeps()) {
522
517
  tracker: { checks: parseTrackerChecks(raw.tracker) },
523
518
  runaway_search_guard: parseRunawaySearchGuard(raw.runaway_search_guard),
524
519
  low_disk_min_free_bytes: positiveInt(raw.low_disk_min_free_bytes, "low_disk_min_free_bytes", DEFAULT_LOW_DISK_MIN_FREE_BYTES),
525
- lead_reserve_per_host: leadReservePerHost,
526
520
  codex_rollout_compress_after_hours: compressAfterHours,
527
521
  codex_rollout_delete_after_days: deleteAfterDays,
528
522
  session_question_timeout_secs: positiveInt(raw.session_question_timeout_secs, "session_question_timeout_secs", DEFAULT_SESSION_QUESTION_TIMEOUT_SECS),
@@ -0,0 +1,3 @@
1
+ export declare function registerDaemonLanesReconcileHandler(handler: () => Promise<void>): void;
2
+ export declare function daemonLanesReconcileHandler(): (() => Promise<void>) | null;
3
+ //# sourceMappingURL=daemon-reconcile.d.ts.map
@@ -0,0 +1,8 @@
1
+ let daemonReconcileHandler = null;
2
+ export function registerDaemonLanesReconcileHandler(handler) {
3
+ daemonReconcileHandler = handler;
4
+ }
5
+ export function daemonLanesReconcileHandler() {
6
+ return daemonReconcileHandler;
7
+ }
8
+ //# sourceMappingURL=daemon-reconcile.js.map
@@ -12,7 +12,7 @@ export type { HostCapacityAccount, HostCapacityProvider, HostCapacitySnapshot, H
12
12
  export { CONFIG_SCHEMA_VERSION, ENVELOPE_DECISIONS, ENVELOPE_SCHEMA_VERSION, HISTORY_CAP, HOST_KINDS, LANE_PROVIDERS, LANE_SCHEMA_VERSION, LANE_STORY_STATUSES, LANE_STATES, LIVENESS_STATES, QUESTION_BODY_STORES, QUESTION_SCHEMA_VERSION, QUESTION_STATUSES, QUEUED_REASONS, RAISED_VIA, ROUTING_REASONS, SENIOR_KINDS, STORY_STATUSES, TERMINAL_LANE_STATES, isEnvelopeDecision, isHostKind, isLaneProvider, isLaneState, isLivenessState, isQuestionStatus, isSeniorKind, isTerminalLaneState, parseLaneEnvelope, parseLaneProvider, parseLaneState, parseLivenessState, parseMajorSchema, parseQuestionStatus, parseSeniorKind, } from "./types.js";
13
13
  export type { AccountConfig, AttributionHistoryEntry, EnvelopeDecision, EnvelopeQuestion, HostKind, LaneCompanyRef, LaneAccountSelection, LaneAccountSelectionConsidered, LaneAccountSelectionHostCount, LaneEnvelope, LaneHost, LaneProvider, LanePlacementPolicy, LaneRecord, LaneStory, LaneStoryStatus, PendingResume, AccountHistoryEntry, LaneState, LanesConfig, LastEnvelopeRef, LivenessState, LivenessWindows, ProviderConfig, QuestionAnswer, QuestionBodyRef, QuestionPriority, QuestionRecord, QuestionStatus, QueuedReason, RaisedVia, RoutingHistoryEntry, RoutingReason, SeniorHistoryEntry, SeniorKind, SeniorRef, WorkerProfileRepinHistoryEntry, LaneSettingsHistoryEntry, StoryStatus, TerminalLaneState, ThrottleConfig, } from "./types.js";
14
14
  export { ACTIVE_LANE_STORY_STATUSES, activeLaneStories, laneStories, laneStory, storyKey, storyStatusForEnvelope, storyWarning, withCurrentStory, withLaneStories, } from "./stories.js";
15
- export { DEFAULT_ACCOUNT_HOMES, DEFAULT_AUTO_COMPACT_TOKENS, DEFAULT_COMPACT_AFTER_MS, DEFAULT_CPU_BUSY_PAUSE, DEFAULT_CPU_BUSY_RESUME, DEFAULT_LIVE_WITHIN_MS, DEFAULT_LIVENESS_WINDOWS, DEFAULT_MAX_QUEUED, DEFAULT_MIN_AVAILABLE_MEM_MB, DEFAULT_PROVIDER_MAX_RUNNING, DEFAULT_SILENT_LOST_MS, DEFAULT_TURN_START_LOST_MS, LANES_CONFIG_REL, accountMaxRunning, canonicalizeHome, documentedDefaultConfig, expandHome, lanesConfigPath, loadLanesConfig, parseLanesConfig, providerCompactAfterMs, providerAutoCompactTokens, providerQuotaDefaultHoldMs, DEFAULT_QUOTA_HOLD_MS, writeLanesConfig, } from "./config.js";
15
+ export { DEFAULT_ACCOUNT_HOMES, DEFAULT_AUTO_COMPACT_TOKENS, DEFAULT_COMPACT_AFTER_MS, DEFAULT_LIVE_WITHIN_MS, DEFAULT_LIVENESS_WINDOWS, DEFAULT_MAX_QUEUED, DEFAULT_PROVIDER_MAX_RUNNING, DEFAULT_SILENT_LOST_MS, DEFAULT_TURN_START_LOST_MS, LANES_CONFIG_REL, accountMaxRunning, canonicalizeHome, documentedDefaultConfig, expandHome, lanesConfigPath, loadLanesConfig, parseLanesConfig, providerCompactAfterMs, providerAutoCompactTokens, providerQuotaDefaultHoldMs, DEFAULT_QUOTA_HOLD_MS, writeLanesConfig, } from "./config.js";
16
16
  export type { ConfigLoadDeps, ConfigWriteDeps } from "./config.js";
17
17
  export { resolveLanesHqRoot } from "./hq-root.js";
18
18
  export type { LanesHqRootOpts } from "./hq-root.js";
@@ -8,7 +8,7 @@ export { compareLaneQueueOrder, hasActiveAdmissionReservation, hasActivePendingR
8
8
  export { buildHostCapacitySnapshot, chooseHostForLane, parseHostCapacitySnapshot, } from "./host-capacity.js";
9
9
  export { CONFIG_SCHEMA_VERSION, ENVELOPE_DECISIONS, ENVELOPE_SCHEMA_VERSION, HISTORY_CAP, HOST_KINDS, LANE_PROVIDERS, LANE_SCHEMA_VERSION, LANE_STORY_STATUSES, LANE_STATES, LIVENESS_STATES, QUESTION_BODY_STORES, QUESTION_SCHEMA_VERSION, QUESTION_STATUSES, QUEUED_REASONS, RAISED_VIA, ROUTING_REASONS, SENIOR_KINDS, STORY_STATUSES, TERMINAL_LANE_STATES, isEnvelopeDecision, isHostKind, isLaneProvider, isLaneState, isLivenessState, isQuestionStatus, isSeniorKind, isTerminalLaneState, parseLaneEnvelope, parseLaneProvider, parseLaneState, parseLivenessState, parseMajorSchema, parseQuestionStatus, parseSeniorKind, } from "./types.js";
10
10
  export { ACTIVE_LANE_STORY_STATUSES, activeLaneStories, laneStories, laneStory, storyKey, storyStatusForEnvelope, storyWarning, withCurrentStory, withLaneStories, } from "./stories.js";
11
- export { DEFAULT_ACCOUNT_HOMES, DEFAULT_AUTO_COMPACT_TOKENS, DEFAULT_COMPACT_AFTER_MS, DEFAULT_CPU_BUSY_PAUSE, DEFAULT_CPU_BUSY_RESUME, DEFAULT_LIVE_WITHIN_MS, DEFAULT_LIVENESS_WINDOWS, DEFAULT_MAX_QUEUED, DEFAULT_MIN_AVAILABLE_MEM_MB, DEFAULT_PROVIDER_MAX_RUNNING, DEFAULT_SILENT_LOST_MS, DEFAULT_TURN_START_LOST_MS, LANES_CONFIG_REL, accountMaxRunning, canonicalizeHome, documentedDefaultConfig, expandHome, lanesConfigPath, loadLanesConfig, parseLanesConfig, providerCompactAfterMs, providerAutoCompactTokens, providerQuotaDefaultHoldMs, DEFAULT_QUOTA_HOLD_MS, writeLanesConfig, } from "./config.js";
11
+ export { DEFAULT_ACCOUNT_HOMES, DEFAULT_AUTO_COMPACT_TOKENS, DEFAULT_COMPACT_AFTER_MS, DEFAULT_LIVE_WITHIN_MS, DEFAULT_LIVENESS_WINDOWS, DEFAULT_MAX_QUEUED, DEFAULT_PROVIDER_MAX_RUNNING, DEFAULT_SILENT_LOST_MS, DEFAULT_TURN_START_LOST_MS, LANES_CONFIG_REL, accountMaxRunning, canonicalizeHome, documentedDefaultConfig, expandHome, lanesConfigPath, loadLanesConfig, parseLanesConfig, providerCompactAfterMs, providerAutoCompactTokens, providerQuotaDefaultHoldMs, DEFAULT_QUOTA_HOLD_MS, writeLanesConfig, } from "./config.js";
12
12
  export { resolveLanesHqRoot } from "./hq-root.js";
13
13
  export { LANE_STORY_LEDGER_FLAG, buildLaneStatusSnapshot, formatLaneStatusHuman, laneStoryLedgerEnabled, resolveProjectStoryLedger, syncLaneToProjectStoryLedger, removeLaneFromProjectStoryLedger, validateProjectStories, } from "./story-ledger.js";
14
14
  export { buildOutpostPickupCommand, parseOutpostPickupPayload, } from "./outpost-dispatch.js";
@@ -0,0 +1,10 @@
1
+ export interface ReconcilePassResult {
2
+ ok: boolean;
3
+ errors?: readonly {
4
+ code?: string;
5
+ message: string;
6
+ }[];
7
+ }
8
+ /** Preserve CLI exit semantics while letting the daemon report failures to its watcher. */
9
+ export declare function finishReconcilePass(summary: ReconcilePassResult, mode: "cli" | "daemon", exit?: (code: number) => void): void;
10
+ //# sourceMappingURL=reconcile-result.d.ts.map
@@ -0,0 +1,11 @@
1
+ /** Preserve CLI exit semantics while letting the daemon report failures to its watcher. */
2
+ export function finishReconcilePass(summary, mode, exit = (code) => process.exit(code)) {
3
+ if (summary.ok)
4
+ return;
5
+ if (mode === "daemon") {
6
+ const detail = summary.errors?.map((error) => `${error.code ?? "unknown"}: ${error.message}`).join("; ") ?? "unknown reconcile error";
7
+ throw new Error(`In-process lanes reconcile failed: ${detail}`);
8
+ }
9
+ exit(1);
10
+ }
11
+ //# sourceMappingURL=reconcile-result.js.map
@@ -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, laneOccupiesRunningSlot, laneRunsOnHost, withAllLaneAdmissionLocks, } from "./admission.js";
11
+ import { compareLaneQueueOrder, compareLaneQueueOrderWithLeads, 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";
@@ -33,7 +33,7 @@ import { DEFAULT_RUNAWAY_SEARCH_GUARD_CONFIG, listHostProcesses, runRunawayToolG
33
33
  import { LEAD_LANE_KEEP_ALIVE_FLAG, LEAD_LANE_KEEP_ALIVE_RESUME_BLOCKED_FLAG, LEAD_LANE_KEEP_ALIVE_IMMEDIATE_FIRST_RESUME_FLAG, LEAD_LANE_KEEP_ALIVE_FIRST_RESUME_SETTLE_MS, LEAD_LANE_KEEP_ALIVE_BLOCKED_GRACE_MS, LEAD_LANE_KEEP_ALIVE_BLOCKED_RESUME_TEXT, queueLaneTerminalResume, LEAD_LANE_KEEP_ALIVE_INTERRUPTED_RESUME_TEXT, LEAD_LANE_KEEP_ALIVE_MAX_RESUMES, LEAD_LANE_KEEP_ALIVE_RESUME_TEXT, LANE_SUPERSESSION_LINEAGE_AWARE_FLAG, doneKeepAliveVerdict, dueKeepAliveNextCheckMs, hasPendingKeepAliveWork, keepAliveNextCheckAtMs, keepAliveExclusion, loadRetiredLaneIds, leadLaneKeepAliveBackoffMs, undeliveredAnsweredQuestions, } from "./keep-alive.js";
34
34
  import { isFailedQuotaKeepAliveLane, providerSupportsSessionResume } from "./delivery.js";
35
35
  import { LANE_PROVIDERS, isIsoDateTime, isTerminalLaneState } from "./types.js";
36
- import { applyDefaultQuotaHold, clearAccountQuotaAfterSuccessfulTurnBestEffort, loadQuotaState, readQuotaSignal, recordAccountQuota, } from "./quota.js";
36
+ import { applyDefaultQuotaHold, clearAccountQuotaAfterSuccessfulTurnBestEffort, readQuotaSignal, recordAccountQuota, } from "./quota.js";
37
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";
@@ -2045,7 +2045,6 @@ async function admitQueued(hqRoot, lanes, summary, deps, now, onlyLaneIds, exclu
2045
2045
  if (localQueued.length === 0 || deps.skipAdmissionWithoutCpuSample === true)
2046
2046
  return;
2047
2047
  const config = loadLanesConfig(hqRoot);
2048
- const admissionQuotaState = loadQuotaState(hqRoot);
2049
2048
  const candidateLeadIds = leadLaneIds(lanes);
2050
2049
  const flagReader = deps.readRegistryFlag ?? readLanesRegistryFlag;
2051
2050
  const leadAdmissionEnabledById = new Map();
@@ -2140,25 +2139,6 @@ async function admitQueued(hqRoot, lanes, summary, deps, now, onlyLaneIds, exclu
2140
2139
  }
2141
2140
  }
2142
2141
  const projected = [...running, ...spawned];
2143
- const laneResolution = lane.provider === "claude" ? resolveLaneCompany(hqRoot, lane) : undefined;
2144
- const laneCompany = laneResolution?.company ?? undefined;
2145
- const laneCompanyKey = laneCompany?.uid ?? laneCompany?.slug ?? lane.company?.uid ?? lane.company?.slug;
2146
- let reserveEnabled = false;
2147
- if (lane.provider === "claude" && laneCompanyKey) {
2148
- let enabled = leadFlagByCompany.get(laneCompanyKey);
2149
- if (!enabled) {
2150
- enabled = readLanesRegistryFlagFailOff(LANE_LEAD_ADMISSION_PRIORITY_FLAG, {
2151
- company: laneCompany,
2152
- ...(laneCompany && laneResolution ? { companyUidSource: laneCompanyUidSource(laneResolution.source) } : {}),
2153
- env: deps.env,
2154
- }, flagReader);
2155
- leadFlagByCompany.set(laneCompanyKey, enabled);
2156
- }
2157
- reserveEnabled = await enabled;
2158
- }
2159
- const reserveBlocked = reserveEnabled && lane.provider === "claude" &&
2160
- !priorityLeads.has(lane.lane_id) &&
2161
- freeClaudeAccountSlots(projected, config, deps.host, now.getTime(), admissionQuotaState) <= config.lead_reserve_per_host;
2162
2142
  const alternateAccount = availableBalancedAccount(hqRoot, lane, projected, config, deps.host, profileMaxConcurrent, now.getTime());
2163
2143
  const admittedLane = alternateAccount !== undefined
2164
2144
  ? writeAdmissionAccount(hqRoot, lane, alternateAccount, deps.dryRun)
@@ -2166,10 +2146,7 @@ async function admitQueued(hqRoot, lanes, summary, deps, now, onlyLaneIds, exclu
2166
2146
  const baseCap = laneAdmissionCapReason(running, admittedLane, config, deps.host, profileMaxConcurrent, now.getTime());
2167
2147
  const currentCap = laneAdmissionCapReason([...running, ...spawned], admittedLane, config, deps.host, profileMaxConcurrent, now.getTime());
2168
2148
  let blockedBy;
2169
- if (reserveBlocked) {
2170
- blockedBy = "lead_reserve";
2171
- }
2172
- else if (currentCap !== undefined) {
2149
+ if (currentCap !== undefined) {
2173
2150
  blockedBy = baseCap ?? "queue_position";
2174
2151
  }
2175
2152
  if (!blockedBy && !decision.admit)
@@ -13,7 +13,6 @@ import { execFileSync as nodeExecFileSync } from "node:child_process";
13
13
  import * as fs from "node:fs";
14
14
  import * as os from "node:os";
15
15
  import * as path from "node:path";
16
- import { DEFAULT_CPU_BUSY_PAUSE, DEFAULT_CPU_BUSY_RESUME, DEFAULT_MIN_AVAILABLE_MEM_MB, } from "./config.js";
17
16
  // Reconcile normally measures the interval between cumulative CPU snapshots.
18
17
  // A five-second window establishes a baseline or recovers from stale counters.
19
18
  export const CPU_SAMPLE_MS = 5_000;
@@ -294,17 +293,18 @@ export function evaluateThrottle(input) {
294
293
  const pause = input.throttle.cpu_busy_pause;
295
294
  const resume = input.throttle.cpu_busy_resume;
296
295
  const minMem = input.throttle.min_available_mem_mb;
296
+ // Each gate is opt-in: an unset threshold never blocks admission.
297
297
  let cpuBlocks = false;
298
- if (input.cpuCheckEnabled && input.busy !== null) {
298
+ if (pause !== undefined && input.cpuCheckEnabled && input.busy !== null) {
299
299
  if (input.state.cpuPaused) {
300
- cpuBlocks = input.busy > resume;
300
+ cpuBlocks = input.busy > (resume ?? pause);
301
301
  }
302
302
  else {
303
303
  cpuBlocks = input.busy >= pause;
304
304
  }
305
305
  }
306
306
  let memBlocks = false;
307
- if (input.availableMemMb !== null) {
307
+ if (minMem !== undefined && input.availableMemMb !== null) {
308
308
  memBlocks = input.availableMemMb < minMem;
309
309
  }
310
310
  if (!cpuBlocks && !memBlocks) {
@@ -448,11 +448,7 @@ export function writeThrottleState(filePath, state, deps = defaultThrottleDeps()
448
448
  throw err;
449
449
  }
450
450
  }
451
- export async function decideAdmission(hqRoot, throttle = {
452
- cpu_busy_pause: DEFAULT_CPU_BUSY_PAUSE,
453
- cpu_busy_resume: DEFAULT_CPU_BUSY_RESUME,
454
- min_available_mem_mb: DEFAULT_MIN_AVAILABLE_MEM_MB,
455
- }, deps = defaultThrottleDeps(), cpuBusyFraction, cpuObservation) {
451
+ export async function decideAdmission(hqRoot, throttle = {}, deps = defaultThrottleDeps(), cpuBusyFraction, cpuObservation) {
456
452
  const filePath = throttleStatePath(hqRoot);
457
453
  const loaded = readThrottleState(filePath, deps);
458
454
  if (loaded === "unreadable") {
@@ -1055,10 +1055,11 @@ export interface ProviderConfig {
1055
1055
  quota_default_hold_ms?: number;
1056
1056
  accounts: Record<string, AccountConfig>;
1057
1057
  }
1058
+ /** Opt-in admission gates. An unset key means that gate is off. */
1058
1059
  export interface ThrottleConfig {
1059
- cpu_busy_pause: number;
1060
- cpu_busy_resume: number;
1061
- min_available_mem_mb: number;
1060
+ cpu_busy_pause?: number;
1061
+ cpu_busy_resume?: number;
1062
+ min_available_mem_mb?: number;
1062
1063
  }
1063
1064
  /** Session liveness windows from spec §9. Missing keys keep these documented defaults. */
1064
1065
  export interface LivenessWindows {
@@ -1096,8 +1097,6 @@ export interface LanesConfig {
1096
1097
  runaway_search_guard?: RunawaySearchGuardConfig;
1097
1098
  /** Optional free-space threshold override for the low-disk admission gate. */
1098
1099
  low_disk_min_free_bytes?: number;
1099
- /** Claude account slots kept available per host for senior lead lanes. */
1100
- lead_reserve_per_host: number;
1101
1100
  /** Retention ages for Codex session rollout maintenance. */
1102
1101
  codex_rollout_compress_after_hours?: number;
1103
1102
  codex_rollout_delete_after_days?: number;
@@ -111,6 +111,7 @@ export const QUEUED_REASONS = [
111
111
  "throttle",
112
112
  "provider_binary_missing",
113
113
  "account_retry",
114
+ // Retired with lead_reserve_per_host; kept so older lane records still parse.
114
115
  "lead_reserve",
115
116
  "worker_profile_changed",
116
117
  "low_disk",
@@ -14,7 +14,7 @@ export interface WorkCacheMqtt extends MeshMqttEventClient {
14
14
  export interface WorkCacheSubscriber {
15
15
  stop: () => Promise<void>;
16
16
  }
17
- export declare const AGENT_INBOX_PUSH_STATE_BASENAME = "agent-inbox-push.json";
17
+ export { AGENT_INBOX_PUSH_STATE_BASENAME } from "../paths.js";
18
18
  export declare function startWorkCacheSubscriber(opts: {
19
19
  meshRoot: string;
20
20
  fetchCredentials?: PersonalCredentialsFetcher;
@@ -8,7 +8,8 @@ import { createPersonalRealtimeFetcher, } from "./credentials.js";
8
8
  import { presignIotWssUrl } from "./presign.js";
9
9
  import { applyProjectViewPush, parseProjectViewPush } from "./live-cache.js";
10
10
  import { backoffDelayMs, RECONNECT_MIN_DELAY_MS } from "./presence.js";
11
- export const AGENT_INBOX_PUSH_STATE_BASENAME = "agent-inbox-push.json";
11
+ import { AGENT_INBOX_PUSH_STATE_BASENAME } from "../paths.js";
12
+ export { AGENT_INBOX_PUSH_STATE_BASENAME } from "../paths.js";
12
13
  const INBOX_PUSH_HEARTBEAT_MS = 5_000;
13
14
  function readInboxWakeSequence(meshRoot, onInfo) {
14
15
  const target = path.join(meshRoot, AGENT_INBOX_PUSH_STATE_BASENAME);
@@ -78,6 +79,7 @@ export async function startWorkCacheSubscriber(opts) {
78
79
  let heartbeatTimer = null;
79
80
  let generation = 0;
80
81
  let inboxSubscribed = false;
82
+ let inboxAgentUid;
81
83
  // Carry the sequence forward from the last state marker so a daemon restart
82
84
  // cannot reuse a value the watcher has already consumed.
83
85
  let wakeSequence = readInboxWakeSequence(opts.meshRoot, opts.onInfo);
@@ -92,6 +94,7 @@ export async function startWorkCacheSubscriber(opts) {
92
94
  connected,
93
95
  heartbeatAtMs: now().getTime(),
94
96
  wakeSequence,
97
+ ...(connected && inboxAgentUid ? { agentUid: inboxAgentUid } : {}),
95
98
  });
96
99
  }
97
100
  catch (error) {
@@ -115,6 +118,7 @@ export async function startWorkCacheSubscriber(opts) {
115
118
  if (stopped)
116
119
  return;
117
120
  inboxSubscribed = false;
121
+ inboxAgentUid = undefined;
118
122
  clearInboxHeartbeat();
119
123
  persistInboxState(false);
120
124
  const gen = ++generation;
@@ -133,6 +137,7 @@ export async function startWorkCacheSubscriber(opts) {
133
137
  bundle.topics.inbox === `hq/${bundle.actorUid}/inbox`
134
138
  ? bundle.topics.inbox
135
139
  : undefined;
140
+ inboxAgentUid = inboxTopic ? bundle.actorUid : undefined;
136
141
  if (!topic && !inboxTopic) {
137
142
  opts.onInfo?.("work cache subscribe skipped: credentials have no supported topic");
138
143
  return;
@@ -175,6 +180,7 @@ export async function startWorkCacheSubscriber(opts) {
175
180
  return;
176
181
  if (err) {
177
182
  inboxSubscribed = false;
183
+ inboxAgentUid = undefined;
178
184
  clearInboxHeartbeat();
179
185
  persistInboxState(false);
180
186
  opts.onInfo?.("agent inbox push subscribe failed");
@@ -212,6 +218,7 @@ export async function startWorkCacheSubscriber(opts) {
212
218
  if (stopped || gen !== generation)
213
219
  return;
214
220
  inboxSubscribed = false;
221
+ inboxAgentUid = undefined;
215
222
  clearInboxHeartbeat();
216
223
  persistInboxState(false);
217
224
  schedule();
@@ -2,6 +2,8 @@
2
2
  * Local Work Mesh Live paths under ~/.hq/work-mesh/.
3
3
  * Injectable root for tests (never touch the real HOME in unit tests).
4
4
  */
5
+ /** Content-free sequence file written by the mesh MQTT inbox subscriber. */
6
+ export declare const AGENT_INBOX_PUSH_STATE_BASENAME = "agent-inbox-push.json";
5
7
  export declare function workMeshRoot(home?: string, env?: NodeJS.ProcessEnv): string;
6
8
  export declare function workMeshSpoolPath(root?: string): string;
7
9
  export declare function workMeshHeldPath(root?: string): string;
@@ -5,6 +5,8 @@
5
5
  import * as os from "node:os";
6
6
  import * as path from "node:path";
7
7
  const WORK_MESH_DIRNAME = "work-mesh";
8
+ /** Content-free sequence file written by the mesh MQTT inbox subscriber. */
9
+ export const AGENT_INBOX_PUSH_STATE_BASENAME = "agent-inbox-push.json";
8
10
  export function workMeshRoot(home = os.homedir(), env = process.env) {
9
11
  const override = env.HQ_WORK_MESH_ROOT?.trim();
10
12
  if (override)
@@ -5,8 +5,8 @@ export type BoardStoryStatus = (typeof BOARD_STORY_STATUSES)[number];
5
5
  * need attention, while `dropped` is terminal; the Board has only one terminal
6
6
  * column (`done`).
7
7
  */
8
- export declare const LEDGER_STATES: readonly ["todo", "in_progress", "review", "waiting", "blocked", "done", "dropped"];
9
- export declare const ACCEPTED_LEDGER_STATES: readonly ["todo", "in_progress", "review", "waiting", "blocked", "done", "dropped", "in_review", "verification"];
8
+ export declare const LEDGER_STATES: readonly ["todo", "queued", "in_progress", "review", "waiting", "blocked", "done", "dropped"];
9
+ export declare const ACCEPTED_LEDGER_STATES: readonly ["todo", "queued", "in_progress", "review", "waiting", "blocked", "done", "dropped", "in_review", "verification"];
10
10
  export declare class UnknownProjectStoryStateError extends Error {
11
11
  readonly source: string;
12
12
  readonly storyId: string;
@@ -6,10 +6,11 @@ const boardStoryStatusSet = new Set(BOARD_STORY_STATUSES);
6
6
  * column (`done`).
7
7
  */
8
8
  export const LEDGER_STATES = [
9
- "todo", "in_progress", "review", "waiting", "blocked", "done", "dropped",
9
+ "todo", "queued", "in_progress", "review", "waiting", "blocked", "done", "dropped",
10
10
  ];
11
11
  const LEDGER_STATE_TO_BOARD_STATUS = {
12
12
  todo: "queued",
13
+ queued: "queued",
13
14
  in_progress: "in_progress",
14
15
  review: "review",
15
16
  // The four-column Board cannot represent waiting separately. Preserve the
@@ -53,12 +53,15 @@ export const RESIDENT_PACKAGE_MODULES = {
53
53
  "../lib/plan-limit-nag.js",
54
54
  "../utils/plan-gate-error.js",
55
55
  "../lib/daemon/mcp-oauth.js",
56
+ "../commands/lanes.js",
57
+ "commander",
56
58
  "@modelcontextprotocol/sdk/client/index.js",
57
59
  "@modelcontextprotocol/sdk/client/streamableHttp.js",
58
60
  "../utils/staged-npm-install.js",
59
61
  "open",
60
62
  "../lib/first-sync-next-step.js",
61
63
  "@indigoai-us/hq-cloud",
64
+ "../lib/lanes/reconcile.js",
62
65
  ],
63
66
  "daemon-logs-follow": [],
64
67
  "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"],
@@ -220,12 +223,15 @@ const LOADERS = {
220
223
  () => import("../lib/plan-limit-nag.js"),
221
224
  () => import("../utils/plan-gate-error.js"),
222
225
  () => import("../lib/daemon/mcp-oauth.js"),
226
+ () => import("../commands/lanes.js"),
227
+ () => import("commander"),
223
228
  () => import("@modelcontextprotocol/sdk/client/index.js"),
224
229
  () => import("@modelcontextprotocol/sdk/client/streamableHttp.js"),
225
230
  () => import("../utils/staged-npm-install.js"),
226
231
  () => import("open"),
227
232
  () => import("../lib/first-sync-next-step.js"),
228
233
  () => import("@indigoai-us/hq-cloud"),
234
+ () => import("../lib/lanes/reconcile.js"),
229
235
  ],
230
236
  "daemon-logs-follow": [],
231
237
  "mesh-daemon": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.345.128",
3
+ "version": "5.345.130",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {