@indigoai-us/hq-cli 5.312.1 → 5.313.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/command-catalog.generated.d.ts +15 -0
  3. package/dist/command-catalog.generated.js +19 -0
  4. package/dist/commands/core-knowledge-prefs.d.ts +0 -1
  5. package/dist/commands/core-knowledge-prefs.js +1 -1
  6. package/dist/commands/core-worker-share-native.d.ts +0 -1
  7. package/dist/commands/core-worker-share-native.js +1 -1
  8. package/dist/commands/lanes-message.js +3 -0
  9. package/dist/commands/lanes-questions.js +2 -1
  10. package/dist/commands/lanes-resume.js +3 -0
  11. package/dist/commands/lanes.js +151 -21
  12. package/dist/lib/lanes/config.d.ts +3 -0
  13. package/dist/lib/lanes/config.js +14 -0
  14. package/dist/lib/lanes/disk-guard.d.ts +66 -0
  15. package/dist/lib/lanes/disk-guard.js +172 -0
  16. package/dist/lib/lanes/flag-keys.d.ts +2 -0
  17. package/dist/lib/lanes/flag-keys.js +2 -0
  18. package/dist/lib/lanes/grants.d.ts +4 -3
  19. package/dist/lib/lanes/grants.js +12 -7
  20. package/dist/lib/lanes/hire-grant-dispatch.js +2 -3
  21. package/dist/lib/lanes/index.d.ts +1 -1
  22. package/dist/lib/lanes/index.js +1 -1
  23. package/dist/lib/lanes/reconcile.d.ts +7 -1
  24. package/dist/lib/lanes/reconcile.js +142 -11
  25. package/dist/lib/lanes/registry-flag.d.ts +6 -0
  26. package/dist/lib/lanes/registry-flag.js +25 -0
  27. package/dist/lib/lanes/spawn.d.ts +5 -0
  28. package/dist/lib/lanes/spawn.js +26 -1
  29. package/dist/lib/lanes/store.js +11 -0
  30. package/dist/lib/lanes/types.d.ts +11 -1
  31. package/dist/lib/lanes/types.js +1 -0
  32. package/dist/utils/pack-contributions.d.ts +0 -5
  33. package/dist/utils/pack-contributions.js +1 -1
  34. package/dist/utils/redact-error-text.d.ts +0 -2
  35. package/dist/utils/redact-error-text.js +1 -1
  36. package/dist/utils/sandbox-runner-client.d.ts +2 -1
  37. package/package.json +1 -1
@@ -14,6 +14,7 @@ import { type KnownModelsDeps } from "./models.js";
14
14
  import { type LaunchTrigger } from "./delivery.js";
15
15
  import { type MachineIdentity } from "./machine-identity.js";
16
16
  import { type AdmissionHost } from "./admission.js";
17
+ import { type StatFs } from "./disk-guard.js";
17
18
  import { type LaneCompanyRef, type LaneProvider, type LaneRecord, type AccountHistoryEntry } from "./types.js";
18
19
  export declare const LANES_RUNS_REL: string;
19
20
  /** Written by reconcile before a resume spawn; the worker prompt names this path. */
@@ -74,6 +75,10 @@ export interface SpawnLaneDeps {
74
75
  hostname?: string;
75
76
  /** The caller's host scope for admission checks; reconcile supplies its resolved host. */
76
77
  admissionHost?: AdmissionHost;
78
+ /** Resolved per-company by the async command/reconcile boundary. */
79
+ lowDiskGuardEnabled?: boolean;
80
+ /** Injected statfs boundary; production uses node:fs.statfsSync. */
81
+ statfs?: StatFs;
77
82
  /** Provider model catalog dependencies, shared with create in tests. */
78
83
  modelDeps?: KnownModelsDeps;
79
84
  /** Create validated this exact account/model candidate before its admission lock. */
@@ -36,6 +36,7 @@ import { MESSAGE_REPLAY_STATE_NAME } from "./message-replay.js";
36
36
  import { markAnsweredQuestionsDelivered } from "./questions.js";
37
37
  import { hasEarlierEligibleQueuedLane, laneAdmissionCapReason, withLaneAdmissionLock, } from "./admission.js";
38
38
  import { resolveAdmissionHost } from "./admission-host.js";
39
+ import { checkLaneDiskSpace, lowDiskGuardEnabledForLane } from "./disk-guard.js";
39
40
  import { LANE_ENVELOPE_JSON_SCHEMA, ENVELOPE_INVALID_REASON, parseLaneProvider, } from "./types.js";
40
41
  export const LANES_RUNS_REL = path.join("workspace", "lanes-runs");
41
42
  /** Written by reconcile before a resume spawn; the worker prompt names this path. */
@@ -539,7 +540,10 @@ export async function retryLaneOnAlternateAccount(hqRoot, lane, reason, writer =
539
540
  });
540
541
  if (capacityReason !== undefined || earlierEligibleLane)
541
542
  return moved;
542
- return spawnLaneWorker(hqRoot, moved, deps);
543
+ return spawnLaneWorker(hqRoot, moved, {
544
+ ...deps,
545
+ lowDiskGuardEnabled: deps.lowDiskGuardEnabled ?? await lowDiskGuardEnabledForLane(hqRoot, moved),
546
+ });
543
547
  });
544
548
  }
545
549
  export function appendModelFlag(provider, args, model) {
@@ -1802,6 +1806,27 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
1802
1806
  if (preservedAccountModel !== undefined)
1803
1807
  pinnedModel = preservedAccountModel;
1804
1808
  const resolved = selection.account;
1809
+ if (deps.lowDiskGuardEnabled === true) {
1810
+ const free = checkLaneDiskSpace(hqRoot, resolved.home, deps.statfs, config.low_disk_min_free_bytes);
1811
+ if (free.low) {
1812
+ const measuredAt = (deps.now ?? (() => new Date()))().toISOString();
1813
+ return retryUpdateLane(hqRoot, lane.lane_id, "spawn", (current) => ({
1814
+ ...current,
1815
+ state: "queued",
1816
+ queued_reason: "low_disk",
1817
+ queued_details: {
1818
+ reason: "low_disk",
1819
+ hq_free_bytes: free.hq.free_bytes,
1820
+ provider_free_bytes: free.provider.free_bytes,
1821
+ measured_at: measuredAt,
1822
+ },
1823
+ queued_at: current.queued_at ?? measuredAt,
1824
+ admission_reserved_at: undefined,
1825
+ terminal_reason: undefined,
1826
+ terminal_details: undefined,
1827
+ }));
1828
+ }
1829
+ }
1805
1830
  const status = accountStatus(lane.provider, resolved.id, config, { existsSync, hostname });
1806
1831
  if (isLoggedOut(status)) {
1807
1832
  const failed = markPreSpawnFailure
@@ -612,6 +612,17 @@ export function parseLaneRecord(raw, filePath) {
612
612
  });
613
613
  }
614
614
  }
615
+ else if (detailsRecord.reason === "low_disk") {
616
+ if (raw.state !== "queued" || raw.queued_reason !== "low_disk" ||
617
+ !Number.isSafeInteger(detailsRecord.hq_free_bytes) || detailsRecord.hq_free_bytes < 0 ||
618
+ !Number.isSafeInteger(detailsRecord.provider_free_bytes) || detailsRecord.provider_free_bytes < 0) {
619
+ throw new LaneSchemaError("queued_details must describe measured low-disk queue state", {
620
+ path: filePath,
621
+ field: "queued_details",
622
+ });
623
+ }
624
+ requireTimestamp(detailsRecord.measured_at, "queued_details.measured_at", filePath);
625
+ }
615
626
  else {
616
627
  throw new LaneSchemaError("queued_details must describe a supported queue condition", {
617
628
  path: filePath,
@@ -177,7 +177,7 @@ export declare const TERMINAL_LANE_STATES: readonly ["done", "failed", "interrup
177
177
  export type TerminalLaneState = (typeof TERMINAL_LANE_STATES)[number];
178
178
  export declare const LANE_PROVIDERS: readonly ["claude", "codex", "grok"];
179
179
  export type LaneProvider = (typeof LANE_PROVIDERS)[number];
180
- export declare const QUEUED_REASONS: readonly ["cap", "provider_cap", "account_cap", "profile_cap", "queue_position", "throttle", "provider_binary_missing", "account_retry", "worker_profile_changed"];
180
+ export declare const QUEUED_REASONS: readonly ["cap", "provider_cap", "account_cap", "profile_cap", "queue_position", "throttle", "provider_binary_missing", "account_retry", "worker_profile_changed", "low_disk"];
181
181
  export type QueuedReason = (typeof QUEUED_REASONS)[number];
182
182
  export type QueuedDetails = {
183
183
  reason: "worker_profile_changed";
@@ -188,6 +188,11 @@ export type QueuedDetails = {
188
188
  reason: "outpost_dispatch_unknown";
189
189
  outcome_unknown: true;
190
190
  command_id: string | null;
191
+ } | {
192
+ reason: "low_disk";
193
+ hq_free_bytes: number;
194
+ provider_free_bytes: number;
195
+ measured_at: string;
191
196
  };
192
197
  export declare function isQueuedReason(value: unknown): value is QueuedReason;
193
198
  export declare const HOST_KINDS: readonly ["local", "outpost"];
@@ -1007,6 +1012,11 @@ export interface LanesConfig {
1007
1012
  checks: TrackerChecksConfig;
1008
1013
  };
1009
1014
  runaway_search_guard?: RunawaySearchGuardConfig;
1015
+ /** Optional free-space threshold override for the low-disk admission gate. */
1016
+ low_disk_min_free_bytes?: number;
1017
+ /** Retention ages for Codex session rollout maintenance. */
1018
+ codex_rollout_compress_after_hours?: number;
1019
+ codex_rollout_delete_after_days?: number;
1010
1020
  /** Seconds an unanswered question waits at a session audience before advancing. */
1011
1021
  session_question_timeout_secs: number;
1012
1022
  /** Age in hours after which an open manager blocker must be re-verified. */
@@ -112,6 +112,7 @@ export const QUEUED_REASONS = [
112
112
  "provider_binary_missing",
113
113
  "account_retry",
114
114
  "worker_profile_changed",
115
+ "low_disk",
115
116
  ];
116
117
  export function isQueuedReason(value) {
117
118
  return typeof value === "string" && QUEUED_REASONS.includes(value);
@@ -77,11 +77,6 @@ export type LinkStatus = 'live' | 'broken' | 'missing' | 'foreign';
77
77
  * effect (a config merge) is handled separately (US-004/US-005).
78
78
  */
79
79
  export declare function contributionLinks(hqRoot: string, packDir: string, contributes: Partial<Record<PackContributeKey, string[]>>): WiredLink[];
80
- /**
81
- * Canonical absolute path — resolves symlinks and platform aliases such as
82
- * macOS `/var` ↔ `/private/var` so equivalent paths compare equal.
83
- */
84
- export declare function canonicalPath(p: string): string;
85
80
  /** Classify a host path against the link that should own it. */
86
81
  export declare function linkStatus(link: WiredLink, packDir?: string): LinkStatus;
87
82
  /** A content pack's manifest plus the install-time stamped source. */
@@ -137,7 +137,7 @@ export function contributionLinks(hqRoot, packDir, contributes) {
137
137
  * Canonical absolute path — resolves symlinks and platform aliases such as
138
138
  * macOS `/var` ↔ `/private/var` so equivalent paths compare equal.
139
139
  */
140
- export function canonicalPath(p) {
140
+ function canonicalPath(p) {
141
141
  try {
142
142
  return fs.realpathSync.native(p);
143
143
  }
@@ -1,5 +1,3 @@
1
- /** Upper bound on any redacted diagnostic — a message, not a payload dump. */
2
- export declare const REDACTED_TEXT_MAX_LENGTH = 1000;
3
1
  /**
4
2
  * Strip credentials from `text`, flatten control characters/whitespace, and
5
3
  * bound the length. Idempotent, so applying it at both the throw site and the
@@ -11,7 +11,7 @@
11
11
  // share it: provider-minted text is untrusted and must never be printed raw.
12
12
  import { redactUrlsInText } from "./redact-url.js";
13
13
  /** Upper bound on any redacted diagnostic — a message, not a payload dump. */
14
- export const REDACTED_TEXT_MAX_LENGTH = 1_000;
14
+ const REDACTED_TEXT_MAX_LENGTH = 1_000;
15
15
  /**
16
16
  * Strip credentials from `text`, flatten control characters/whitespace, and
17
17
  * bound the length. Idempotent, so applying it at both the throw site and the
@@ -1,4 +1,4 @@
1
- export type SandboxRunnerState = "queued" | "running" | "succeeded" | "failed";
1
+ type SandboxRunnerState = "queued" | "running" | "succeeded" | "failed";
2
2
  export interface SandboxRunnerStartRequest {
3
3
  companyUid: string;
4
4
  secretNames: string[];
@@ -45,4 +45,5 @@ export declare class SandboxRunnerClient {
45
45
  getJob(token: string, jobId: string): Promise<SandboxRunnerJob>;
46
46
  pollJob(token: string, jobId: string, options?: SandboxRunnerPollOptions): Promise<SandboxRunnerJob>;
47
47
  }
48
+ export {};
48
49
  //# sourceMappingURL=sandbox-runner-client.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.312.1",
3
+ "version": "5.313.0",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {