@indigoai-us/hq-cli 5.345.107 → 5.345.109
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 +15 -0
- package/dist/command-catalog.generated.d.ts +40 -1
- package/dist/command-catalog.generated.js +48 -1
- package/dist/commands/capacity.d.ts +1 -1
- package/dist/commands/capacity.js +74 -11
- package/dist/commands/core-checkpoint-stop-gate-native.js +17 -5
- package/dist/commands/lanes.js +72 -12
- package/dist/hq-cloud-sync-runner/bin/sync-runner.js +612 -460
- package/dist/hq-cloud-sync-runner/package.json +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +38 -1
- package/dist/lib/capacity/ledger.d.ts +1 -0
- package/dist/lib/capacity/ledger.js +10 -0
- package/dist/lib/capacity/route.d.ts +146 -0
- package/dist/lib/capacity/route.js +452 -0
- package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
- package/dist/lib/flag-registry-worker-source.generated.js +1 -1
- package/dist/lib/lanes/store.js +4 -4
- package/dist/lib/lanes/types.d.ts +20 -4
- package/dist/lib/lanes/types.js +1 -1
- package/dist/utils/package-use-lease.d.ts +15 -1
- package/dist/utils/package-use-lease.js +45 -2
- package/package.json +2 -2
package/dist/lib/lanes/store.js
CHANGED
|
@@ -742,15 +742,15 @@ export function parseLaneRecord(raw, filePath) {
|
|
|
742
742
|
if (!isLaneProvider(raw.provider)) {
|
|
743
743
|
throw new LaneSchemaError(`Unknown provider ${JSON.stringify(raw.provider)}`, { path: filePath, value: raw.provider });
|
|
744
744
|
}
|
|
745
|
-
if (raw.provider_source !== undefined && !["cli", "profile", "default"].includes(String(raw.provider_source))) {
|
|
746
|
-
throw new LaneSchemaError("provider_source must be cli, profile, or
|
|
745
|
+
if (raw.provider_source !== undefined && !["cli", "profile", "default", "auto"].includes(String(raw.provider_source))) {
|
|
746
|
+
throw new LaneSchemaError("provider_source must be cli, profile, default, or auto", {
|
|
747
747
|
path: filePath,
|
|
748
748
|
field: "provider_source",
|
|
749
749
|
value: raw.provider_source,
|
|
750
750
|
});
|
|
751
751
|
}
|
|
752
|
-
if (raw.account_source !== undefined && !["cli", "profile", "balanced"].includes(String(raw.account_source))) {
|
|
753
|
-
throw new LaneSchemaError("account_source must be cli, profile, or
|
|
752
|
+
if (raw.account_source !== undefined && !["cli", "profile", "balanced", "auto"].includes(String(raw.account_source))) {
|
|
753
|
+
throw new LaneSchemaError("account_source must be cli, profile, balanced, or auto", {
|
|
754
754
|
path: filePath,
|
|
755
755
|
field: "account_source",
|
|
756
756
|
value: raw.account_source,
|
|
@@ -614,15 +614,31 @@ export interface LaneRecord {
|
|
|
614
614
|
provider: LaneProvider;
|
|
615
615
|
/** Open each Claude turn as a named Remote Control session using account a's login. */
|
|
616
616
|
remote_control?: boolean;
|
|
617
|
-
/** Whether provider came from an explicit create override or the worker profile/default. */
|
|
618
|
-
provider_source?: "cli" | "profile" | "default";
|
|
617
|
+
/** Whether provider came from an explicit create override, the router (`--account auto`), or the worker profile/default. */
|
|
618
|
+
provider_source?: "cli" | "profile" | "default" | "auto";
|
|
619
619
|
account?: string;
|
|
620
|
-
/** Explicit create account choices remain pinned during profile refreshes. */
|
|
621
|
-
account_source?: "cli" | "profile" | "balanced";
|
|
620
|
+
/** Explicit create account choices remain pinned during profile refreshes. `auto` means the router picked the account. */
|
|
621
|
+
account_source?: "cli" | "profile" | "balanced" | "auto";
|
|
622
622
|
/** Reuse snapshots the worker profile's resolved settings for the new story. */
|
|
623
623
|
profile_settings_pinned?: boolean;
|
|
624
624
|
/** Recent Claude account-selection evidence for a create or automatic resume move. */
|
|
625
625
|
account_selection?: LaneAccountSelection;
|
|
626
|
+
/**
|
|
627
|
+
* Router evidence recorded when `--account auto` picked this lane's account
|
|
628
|
+
* via `pickAccount` (src/lib/capacity/route.ts). Written once at creation.
|
|
629
|
+
*/
|
|
630
|
+
account_pick?: {
|
|
631
|
+
/**
|
|
632
|
+
* Semicolon-joined reason parts from pickAccount, e.g.
|
|
633
|
+
* `"82% left on claude weekly; 1 live lane already on it"`
|
|
634
|
+
* or `"nothing used yet on any limit"`.
|
|
635
|
+
*/
|
|
636
|
+
why: string;
|
|
637
|
+
/** Headroom percent of the binding limit at pick time (0-100). */
|
|
638
|
+
headroom: number;
|
|
639
|
+
/** Composite score at pick time: headroom - live*penalty + resetSoonBonus - oldReadingPenalty. */
|
|
640
|
+
score: number;
|
|
641
|
+
};
|
|
626
642
|
/** Eligible accounts for a queue entry created without an explicit account. */
|
|
627
643
|
admission_accounts?: string[];
|
|
628
644
|
/**
|
package/dist/lib/lanes/types.js
CHANGED
|
@@ -235,7 +235,7 @@ export const LANE_FIELD_WRITERS = {
|
|
|
235
235
|
pickup_validation_pending_since: ["creator", "command", "spawn", "reconcile"],
|
|
236
236
|
priority: ["command"], worker: ["creator", "command"], worker_path: ["creator", "command"], worker_pack: ["creator", "command"], worker_profile: ["creator", "command"], worker_profile_hash: ["creator", "command", "spawn"], registry_worker: ["creator", "command", "spawn"], registry_worker_approval_history: ["command", "watcher", "reconcile"], worker_profile_repin_history: ["command"], worker_profile_ignored: ["creator", "command", "spawn"], worker_policy_delivery: ["command", "spawn"],
|
|
237
237
|
keep_alive: ["creator", "command"], keep_alive_standing: ["command"], keep_alive_opted_in_at: ["creator", "command"], keep_alive_blocked_reason: ["command", "reconcile"], keep_alive_resume_count: ["command", "reconcile", "spawn"], keep_alive_history: ["reconcile"], keep_alive_blocked_resume_streak: ["reconcile", "spawn", "watcher"], keep_alive_last_resume_at: ["command", "reconcile", "spawn"], keep_alive_next_eligible_at: ["command", "reconcile", "spawn"], keep_alive_exhausted_at: ["command", "reconcile", "spawn"], loop_mode: ["creator"],
|
|
238
|
-
provider: ["creator", "command"], remote_control: ["creator"], provider_source: ["creator", "command"], account: ["creator", "spawn", "command", "watcher", "reconcile"], account_source: ["creator", "command"], profile_settings_pinned: ["command"], account_selection: ["creator", "command"], admission_accounts: ["creator", "command"], account_history: ["command", "spawn", "watcher", "reconcile"], failed_resume_history: ["command"], fallback_question_cancellation_failures: ["command"], pending_resume: ["command", "spawn", "watcher", "reconcile"], placement_default: ["creator"], host: ["creator", "command"], origin_host: ["creator"], origin_host_source: ["creator"],
|
|
238
|
+
provider: ["creator", "command"], remote_control: ["creator"], provider_source: ["creator", "command"], account: ["creator", "spawn", "command", "watcher", "reconcile"], account_source: ["creator", "command"], profile_settings_pinned: ["command"], account_selection: ["creator", "command"], account_pick: ["creator"], admission_accounts: ["creator", "command"], account_history: ["command", "spawn", "watcher", "reconcile"], failed_resume_history: ["command"], fallback_question_cancellation_failures: ["command"], pending_resume: ["command", "spawn", "watcher", "reconcile"], placement_default: ["creator"], host: ["creator", "command"], origin_host: ["creator"], origin_host_source: ["creator"],
|
|
239
239
|
version: ["creator"], created_at: ["creator"], updated_at: ["creator"], ended_at: ["reconcile"], envelope_summary: ["reconcile"], attribution_history: ["command", "watcher", "reconcile"], story_switch_pending: ["command", "watcher", "reconcile"], story_switch_unacknowledged: ["command", "watcher", "reconcile"],
|
|
240
240
|
last_envelope: ["watcher", "reconcile"], model: ["creator", "spawn", "command"], model_source: ["creator", "spawn", "command"], effort: ["creator", "spawn", "command"], effort_source: ["creator", "spawn", "command"], fast_mode: ["spawn"],
|
|
241
241
|
last_message_at: ["creator", "command"], status_gate: ["spawn", "watcher"], status_gate_history: ["watcher", "reconcile"], blocker_freshness_state: ["watcher"], kr_freshness_state: ["watcher"], last_compaction: ["spawn"], story_complete: ["watcher", "reconcile"], story_complete_reason: ["watcher", "reconcile"], story_status: ["watcher", "reconcile"],
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
export declare const PACKAGE_USE_LEASE_HANDOFF_ENV = "HQ_CLI_PACKAGE_USE_LEASE_HANDOFF";
|
|
2
|
+
/**
|
|
3
|
+
* How long a command waits for a live updater before giving up. A desktop
|
|
4
|
+
* `npm install -g` after a reboot routinely runs for minutes (seen ~3 min on
|
|
5
|
+
* 2026-10-13), so a 30s bound made ordinary commands fail mid-session.
|
|
6
|
+
* Override with HQ_CLI_UPDATE_WAIT_MS (0 disables waiting).
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_UPDATE_WAIT_MS = 240000;
|
|
9
|
+
export declare function updateWaitTimeoutMs(env?: NodeJS.ProcessEnv): number;
|
|
2
10
|
export declare const PACKAGE_USE_LEASE_PURPOSES: readonly ["command", "resident-preload", "mcp-serve", "hook", "daemon"];
|
|
3
11
|
export type PackageUseLeasePurpose = (typeof PACKAGE_USE_LEASE_PURPOSES)[number];
|
|
4
12
|
export declare class PackageUseUpdatePendingError extends Error {
|
|
@@ -17,7 +25,7 @@ export interface PackageUseLeaseHandoff {
|
|
|
17
25
|
}
|
|
18
26
|
export declare function npmPrefix(root: string, platform?: NodeJS.Platform): string | null;
|
|
19
27
|
export declare function packageUseLeaseDirectory(prefix: string, stateDirectory?: string): string;
|
|
20
|
-
declare function waitForUpdateRequest(requestPath: string, timeoutMs: number): void;
|
|
28
|
+
declare function waitForUpdateRequest(requestPath: string, timeoutMs: number, notify?: (() => void) | null): void;
|
|
21
29
|
export declare function acquirePackageUseLease(prefix: string, hqVersion: string, stateDirectory?: string, purpose?: PackageUseLeasePurpose): PackageUseLease;
|
|
22
30
|
/**
|
|
23
31
|
* Create a bounded, per-reexec rendezvous in the current lease directory.
|
|
@@ -42,6 +50,12 @@ export declare function releasePackageUseLeaseAfterCommandLoad(_argv?: readonly
|
|
|
42
50
|
export declare function releasePackageUseLeaseAfterResidentPreload(preload: () => Promise<void>, reportFailure: (error: unknown) => void, release?: () => void): Promise<void>;
|
|
43
51
|
/** True only when a valid update request belongs to a live updater process. */
|
|
44
52
|
export declare function packageUseUpdatePending(prefix: string, stateDirectory?: string): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Block (bounded) until a live updater's request for this install clears.
|
|
55
|
+
* Returns true when no update is pending any more, false on timeout or when
|
|
56
|
+
* this is not a lease-managed install.
|
|
57
|
+
*/
|
|
58
|
+
export declare function waitForCurrentPackageUseUpdate(timeoutMs?: number): boolean;
|
|
45
59
|
/** True while the desktop updater owns the per-prefix update request. */
|
|
46
60
|
export declare function currentPackageUseUpdatePending(): boolean;
|
|
47
61
|
/** True while the desktop updater owns the per-prefix update request. */
|
|
@@ -9,6 +9,19 @@ const CLI_NAME = "@indigoai-us/hq-cli";
|
|
|
9
9
|
const UPDATE_REQUEST = "update.pending.json";
|
|
10
10
|
export const PACKAGE_USE_LEASE_HANDOFF_ENV = "HQ_CLI_PACKAGE_USE_LEASE_HANDOFF";
|
|
11
11
|
const HANDOFF_TIMEOUT_MS = 2_000;
|
|
12
|
+
/**
|
|
13
|
+
* How long a command waits for a live updater before giving up. A desktop
|
|
14
|
+
* `npm install -g` after a reboot routinely runs for minutes (seen ~3 min on
|
|
15
|
+
* 2026-10-13), so a 30s bound made ordinary commands fail mid-session.
|
|
16
|
+
* Override with HQ_CLI_UPDATE_WAIT_MS (0 disables waiting).
|
|
17
|
+
*/
|
|
18
|
+
export const DEFAULT_UPDATE_WAIT_MS = 240_000;
|
|
19
|
+
export function updateWaitTimeoutMs(env = process.env) {
|
|
20
|
+
const raw = env.HQ_CLI_UPDATE_WAIT_MS?.trim();
|
|
21
|
+
if (!raw || !/^\d+$/.test(raw))
|
|
22
|
+
return DEFAULT_UPDATE_WAIT_MS;
|
|
23
|
+
return Math.min(Number(raw), 30 * 60 * 1000);
|
|
24
|
+
}
|
|
12
25
|
const PACKAGE_USE_LEASE_HEARTBEAT_INTERVAL_MS = 5 * 60 * 1000;
|
|
13
26
|
let packageUseLeaseHeartbeatIntervalMs = PACKAGE_USE_LEASE_HEARTBEAT_INTERVAL_MS;
|
|
14
27
|
export const PACKAGE_USE_LEASE_PURPOSES = [
|
|
@@ -139,8 +152,9 @@ export function packageUseLeaseDirectory(prefix, stateDirectory = packageUseStat
|
|
|
139
152
|
function packageUseUpdateRequestPath(prefix, stateDirectory) {
|
|
140
153
|
return path.join(packageUseLeaseDirectory(prefix, stateDirectory), UPDATE_REQUEST);
|
|
141
154
|
}
|
|
142
|
-
function waitForUpdateRequest(requestPath, timeoutMs) {
|
|
155
|
+
function waitForUpdateRequest(requestPath, timeoutMs, notify = null) {
|
|
143
156
|
const started = Date.now();
|
|
157
|
+
let notified = false;
|
|
144
158
|
const sleeper = new Int32Array(new SharedArrayBuffer(4));
|
|
145
159
|
while (true) {
|
|
146
160
|
try {
|
|
@@ -167,9 +181,16 @@ function waitForUpdateRequest(requestPath, timeoutMs) {
|
|
|
167
181
|
if (Date.now() - started >= timeoutMs) {
|
|
168
182
|
throw new PackageUseUpdatePendingError("The HQ CLI package is being updated; retry after the update finishes");
|
|
169
183
|
}
|
|
184
|
+
if (!notified && notify) {
|
|
185
|
+
notified = true;
|
|
186
|
+
notify();
|
|
187
|
+
}
|
|
170
188
|
Atomics.wait(sleeper, 0, 0, 100);
|
|
171
189
|
}
|
|
172
190
|
}
|
|
191
|
+
function notifyWaitingForUpdate() {
|
|
192
|
+
process.stderr.write("hq-cli: waiting for the HQ CLI update to finish...\n");
|
|
193
|
+
}
|
|
173
194
|
export function acquirePackageUseLease(prefix, hqVersion, stateDirectory, purpose = "command") {
|
|
174
195
|
const directory = packageUseLeaseDirectory(prefix, stateDirectory);
|
|
175
196
|
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
@@ -219,7 +240,7 @@ export function acquirePackageUseLease(prefix, hqVersion, stateDirectory, purpos
|
|
|
219
240
|
};
|
|
220
241
|
const releaseOnExit = () => release();
|
|
221
242
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
222
|
-
waitForUpdateRequest(requestPath,
|
|
243
|
+
waitForUpdateRequest(requestPath, updateWaitTimeoutMs(), notifyWaitingForUpdate);
|
|
223
244
|
try {
|
|
224
245
|
writeFileSync(tempPath, `${JSON.stringify(record)}\n`, { flag: "wx", mode: 0o600 });
|
|
225
246
|
renameSync(tempPath, leasePath);
|
|
@@ -407,6 +428,28 @@ export function packageUseUpdatePending(prefix, stateDirectory) {
|
|
|
407
428
|
throw error;
|
|
408
429
|
}
|
|
409
430
|
}
|
|
431
|
+
/**
|
|
432
|
+
* Block (bounded) until a live updater's request for this install clears.
|
|
433
|
+
* Returns true when no update is pending any more, false on timeout or when
|
|
434
|
+
* this is not a lease-managed install.
|
|
435
|
+
*/
|
|
436
|
+
export function waitForCurrentPackageUseUpdate(timeoutMs = updateWaitTimeoutMs()) {
|
|
437
|
+
const pkg = findCliPackage(path.dirname(fileURLToPath(import.meta.url)));
|
|
438
|
+
if (!pkg || isPnpmGlobal(pkg.root) || isBunGlobal(pkg.root))
|
|
439
|
+
return false;
|
|
440
|
+
const prefix = npmPrefix(pkg.root);
|
|
441
|
+
if (!prefix)
|
|
442
|
+
return false;
|
|
443
|
+
try {
|
|
444
|
+
waitForUpdateRequest(packageUseUpdateRequestPath(prefix), timeoutMs, notifyWaitingForUpdate);
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
catch (error) {
|
|
448
|
+
if (error instanceof PackageUseUpdatePendingError)
|
|
449
|
+
return false;
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
410
453
|
/** True while the desktop updater owns the per-prefix update request. */
|
|
411
454
|
export function currentPackageUseUpdatePending() {
|
|
412
455
|
const pkg = findCliPackage(path.dirname(fileURLToPath(import.meta.url)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indigoai-us/hq-cli",
|
|
3
|
-
"version": "5.345.
|
|
3
|
+
"version": "5.345.109",
|
|
4
4
|
"description": "HQ by Indigo management CLI — modules and cloud sync",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"@aws-sdk/client-iot-data-plane": "^3.1096.0",
|
|
49
49
|
"@aws-sdk/client-s3": "^3.1049.0",
|
|
50
50
|
"@aws-sdk/dsql-signer": "^3.1146.0",
|
|
51
|
-
"@indigoai-us/hq-cloud": "~6.18.
|
|
51
|
+
"@indigoai-us/hq-cloud": "~6.18.67",
|
|
52
52
|
"@indigoai-us/hq-flags-client": "^0.1.2",
|
|
53
53
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
54
54
|
"@sentry/node": "^10.49.0",
|