@indigoai-us/hq-cli 5.203.0 → 5.204.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.
- package/CHANGELOG.md +8 -0
- package/dist/command-catalog.generated.d.ts +27 -0
- package/dist/command-catalog.generated.js +35 -0
- package/dist/commands/lanes.d.ts +3 -0
- package/dist/commands/lanes.js +200 -25
- package/dist/lib/lanes/account-home.d.ts +8 -0
- package/dist/lib/lanes/account-home.js +10 -0
- package/dist/lib/lanes/accounts.d.ts +4 -1
- package/dist/lib/lanes/accounts.js +15 -10
- package/dist/lib/lanes/claude-account-balance.d.ts +3 -0
- package/dist/lib/lanes/claude-account-balance.js +19 -4
- package/dist/lib/lanes/config.d.ts +2 -1
- package/dist/lib/lanes/config.js +55 -13
- package/dist/lib/lanes/host-capacity.d.ts +4 -0
- package/dist/lib/lanes/host-capacity.js +8 -1
- package/dist/lib/lanes/index.d.ts +2 -0
- package/dist/lib/lanes/index.js +1 -0
- package/dist/lib/lanes/liveness.d.ts +1 -0
- package/dist/lib/lanes/liveness.js +3 -1
- package/dist/lib/lanes/reconcile.js +20 -9
- package/dist/lib/lanes/spawn.d.ts +1 -0
- package/dist/lib/lanes/spawn.js +30 -14
- package/dist/lib/lanes/types.d.ts +5 -0
- package/package.json +1 -1
package/dist/lib/lanes/spawn.js
CHANGED
|
@@ -12,6 +12,7 @@ import * as fs from "node:fs";
|
|
|
12
12
|
import * as path from "node:path";
|
|
13
13
|
import { fileURLToPath } from "node:url";
|
|
14
14
|
import { PROVIDER_HOME_ENV, accountStatus, isLoggedOut, resolveAccount, selectBalancedAccount, } from "./accounts.js";
|
|
15
|
+
import { effectiveAccountHome } from "./account-home.js";
|
|
15
16
|
import { COMPACTION_PROMPT, compactionAfterUsage, compactionDue, compactLaneSession, } from "./compaction.js";
|
|
16
17
|
import { installDrainHook } from "./hooks-install.js";
|
|
17
18
|
import { loadLanesConfig, providerAutoCompactTokens, providerCompactAfterMs, } from "./config.js";
|
|
@@ -112,7 +113,7 @@ function accountModelForSpawn(provider, accountId, config, pinnedModel, profileM
|
|
|
112
113
|
providerModel: config.providers[provider].model,
|
|
113
114
|
});
|
|
114
115
|
}
|
|
115
|
-
function supportsSpawnModel(provider, accountId, config, pinnedModel, profileModel, modelDeps) {
|
|
116
|
+
function supportsSpawnModel(provider, accountId, config, pinnedModel, profileModel, modelDeps, hostname) {
|
|
116
117
|
const account = config.providers[provider].accounts[accountId];
|
|
117
118
|
if (account === undefined)
|
|
118
119
|
return false;
|
|
@@ -120,7 +121,7 @@ function supportsSpawnModel(provider, accountId, config, pinnedModel, profileMod
|
|
|
120
121
|
if (model === undefined)
|
|
121
122
|
return true;
|
|
122
123
|
try {
|
|
123
|
-
validateLaneModel(provider, model, account.home, modelDeps);
|
|
124
|
+
validateLaneModel(provider, model, effectiveAccountHome(account, hostname).home, modelDeps);
|
|
124
125
|
return true;
|
|
125
126
|
}
|
|
126
127
|
catch (err) {
|
|
@@ -129,7 +130,7 @@ function supportsSpawnModel(provider, accountId, config, pinnedModel, profileMod
|
|
|
129
130
|
throw err;
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
|
-
function spawnModelFailure(provider, accountId, config, pinnedModel, profileModel, profileId, modelDeps) {
|
|
133
|
+
function spawnModelFailure(provider, accountId, config, pinnedModel, profileModel, profileId, modelDeps, hostname) {
|
|
133
134
|
const account = config.providers[provider].accounts[accountId];
|
|
134
135
|
if (account === undefined)
|
|
135
136
|
return new LanesError("unknown_account", `Unknown account ${accountId} for ${provider}`, { provider, account: accountId });
|
|
@@ -137,7 +138,7 @@ function spawnModelFailure(provider, accountId, config, pinnedModel, profileMode
|
|
|
137
138
|
if (model === undefined)
|
|
138
139
|
return null;
|
|
139
140
|
try {
|
|
140
|
-
validateLaneModel(provider, model, account.home, modelDeps);
|
|
141
|
+
validateLaneModel(provider, model, effectiveAccountHome(account, hostname).home, modelDeps);
|
|
141
142
|
return null;
|
|
142
143
|
}
|
|
143
144
|
catch (err) {
|
|
@@ -155,17 +156,18 @@ function spawnModelFailure(provider, accountId, config, pinnedModel, profileMode
|
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
function selectSpawnAccount(input) {
|
|
158
|
-
const { hqRoot, lane, config, existsSync, accountDeps, modelDeps, pinnedModel, profileModel, currentModelValidated } = input;
|
|
159
|
+
const { hqRoot, lane, config, existsSync, accountDeps, modelDeps, pinnedModel, profileModel, currentModelValidated, hostname } = input;
|
|
159
160
|
const context = {
|
|
160
161
|
hqRoot,
|
|
161
162
|
existsSync,
|
|
162
163
|
accountDeps,
|
|
164
|
+
hostname,
|
|
163
165
|
...(pinnedModel ?? profileModel ? { model: pinnedModel ?? profileModel } : {}),
|
|
164
166
|
};
|
|
165
167
|
if (lane.account === undefined) {
|
|
166
168
|
const modelSpecified = pinnedModel !== undefined || profileModel !== undefined;
|
|
167
169
|
const allowedAccounts = modelSpecified
|
|
168
|
-
? Object.keys(config.providers[lane.provider].accounts).filter((id) => supportsSpawnModel(lane.provider, id, config, pinnedModel, profileModel, modelDeps))
|
|
170
|
+
? Object.keys(config.providers[lane.provider].accounts).filter((id) => supportsSpawnModel(lane.provider, id, config, pinnedModel, profileModel, modelDeps, hostname))
|
|
169
171
|
: undefined;
|
|
170
172
|
return {
|
|
171
173
|
account: selectBalancedAccount(lane.provider, config, {
|
|
@@ -188,6 +190,7 @@ function selectSpawnAccount(input) {
|
|
|
188
190
|
else {
|
|
189
191
|
const status = accountStatus(lane.provider, lane.account, config, {
|
|
190
192
|
existsSync,
|
|
193
|
+
hostname,
|
|
191
194
|
...(accountDeps?.probe ? { probe: accountDeps.probe } : {}),
|
|
192
195
|
...(accountDeps?.env ? { env: accountDeps.env } : {}),
|
|
193
196
|
});
|
|
@@ -200,7 +203,7 @@ function selectSpawnAccount(input) {
|
|
|
200
203
|
resolveAccount(lane.provider, lane.account, config, context);
|
|
201
204
|
const modelFailure = currentModelValidated
|
|
202
205
|
? null
|
|
203
|
-
: spawnModelFailure(lane.provider, lane.account, config, pinnedModel, profileModel, lane.worker_profile, modelDeps);
|
|
206
|
+
: spawnModelFailure(lane.provider, lane.account, config, pinnedModel, profileModel, lane.worker_profile, modelDeps, hostname);
|
|
204
207
|
if (modelFailure !== null) {
|
|
205
208
|
reason = "model_change";
|
|
206
209
|
refusal = modelFailure;
|
|
@@ -240,10 +243,11 @@ function selectSpawnAccount(input) {
|
|
|
240
243
|
.filter(([id, account]) => id !== lane.account && account.enabled)
|
|
241
244
|
.filter(([id]) => accountStatus(lane.provider, id, config, {
|
|
242
245
|
existsSync,
|
|
246
|
+
hostname,
|
|
243
247
|
...(accountDeps?.probe ? { probe: accountDeps.probe } : {}),
|
|
244
248
|
...(accountDeps?.env ? { env: accountDeps.env } : {}),
|
|
245
249
|
}).logged_in === true)
|
|
246
|
-
.filter(([id]) => supportsSpawnModel(lane.provider, id, config, pinnedModel, profileModel, modelDeps))
|
|
250
|
+
.filter(([id]) => supportsSpawnModel(lane.provider, id, config, pinnedModel, profileModel, modelDeps, hostname))
|
|
247
251
|
.map(([id]) => id);
|
|
248
252
|
try {
|
|
249
253
|
return {
|
|
@@ -345,6 +349,8 @@ export async function retryLaneOnAlternateAccount(hqRoot, lane, reason, writer =
|
|
|
345
349
|
const config = loadLanesConfig(hqRoot);
|
|
346
350
|
const existsSync = deps.existsSync ?? ((p) => fs.existsSync(p));
|
|
347
351
|
const env = deps.env ?? process.env;
|
|
352
|
+
const admissionHost = deps.admissionHost ?? resolveAdmissionHost();
|
|
353
|
+
const hostname = deps.hostname?.trim() || admissionHost.hostname.trim() || resolveAdmissionHost().hostname;
|
|
348
354
|
const modelDeps = {
|
|
349
355
|
...deps.modelDeps,
|
|
350
356
|
env: deps.modelDeps?.env ?? env,
|
|
@@ -353,7 +359,6 @@ export async function retryLaneOnAlternateAccount(hqRoot, lane, reason, writer =
|
|
|
353
359
|
probe: modelDeps.probe ?? defaultProbe,
|
|
354
360
|
env,
|
|
355
361
|
};
|
|
356
|
-
const admissionHost = deps.admissionHost ?? resolveAdmissionHost();
|
|
357
362
|
const profile = lane.worker_profile ? loadWorkerProfile(hqRoot, lane.worker_profile) : undefined;
|
|
358
363
|
const profileModel = profile?.meta.provider === lane.provider ? profile.meta.model : undefined;
|
|
359
364
|
const pinnedModel = lane.model_source === undefined || lane.model_source === "cli" ? lane.model : undefined;
|
|
@@ -362,15 +367,17 @@ export async function retryLaneOnAlternateAccount(hqRoot, lane, reason, writer =
|
|
|
362
367
|
.filter(([id, account]) => id !== lane.account && !unavailableAccounts.has(id) && account.enabled)
|
|
363
368
|
.filter(([id]) => accountStatus(lane.provider, id, config, {
|
|
364
369
|
existsSync,
|
|
370
|
+
hostname,
|
|
365
371
|
...(accountDeps?.probe ? { probe: accountDeps.probe } : {}),
|
|
366
372
|
...(accountDeps?.env ? { env: accountDeps.env } : {}),
|
|
367
373
|
}).logged_in === true)
|
|
368
|
-
.filter(([id]) => supportsSpawnModel(lane.provider, id, config, pinnedModel, profileModel, modelDeps))
|
|
374
|
+
.filter(([id]) => supportsSpawnModel(lane.provider, id, config, pinnedModel, profileModel, modelDeps, hostname))
|
|
369
375
|
.map(([id]) => id);
|
|
370
376
|
const modelContext = {
|
|
371
377
|
hqRoot,
|
|
372
378
|
existsSync,
|
|
373
379
|
accountDeps,
|
|
380
|
+
hostname,
|
|
374
381
|
...(pinnedModel ?? profileModel ? { model: pinnedModel ?? profileModel } : {}),
|
|
375
382
|
allowedAccounts,
|
|
376
383
|
};
|
|
@@ -392,7 +399,7 @@ export async function retryLaneOnAlternateAccount(hqRoot, lane, reason, writer =
|
|
|
392
399
|
: undefined;
|
|
393
400
|
if (source && sessionId) {
|
|
394
401
|
copySessionFiles(planSessionCopy(lane.provider, {
|
|
395
|
-
sourceHome: source.home,
|
|
402
|
+
sourceHome: lane.provider_home_at_spawn ?? effectiveAccountHome(source, hostname).home,
|
|
396
403
|
targetHome: target.home,
|
|
397
404
|
cwd: hqRoot,
|
|
398
405
|
sessionId,
|
|
@@ -535,6 +542,11 @@ function appendCodexWorkerPolicyDirFlag(provider, args, workerPolicyDir) {
|
|
|
535
542
|
return [...args, "-c", setting];
|
|
536
543
|
return [...args.slice(0, separator), "-c", setting, ...args.slice(separator)];
|
|
537
544
|
}
|
|
545
|
+
function accountHomeHostname(deps) {
|
|
546
|
+
return (deps.hostname?.trim() ||
|
|
547
|
+
deps.admissionHost?.hostname.trim() ||
|
|
548
|
+
resolveAdmissionHost().hostname);
|
|
549
|
+
}
|
|
538
550
|
export const PID_LIVENESS_DECISIONS = [
|
|
539
551
|
"esrch",
|
|
540
552
|
"starttime_mismatch",
|
|
@@ -1527,6 +1539,7 @@ function inferTrigger(lane) {
|
|
|
1527
1539
|
*/
|
|
1528
1540
|
export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
|
|
1529
1541
|
const env = deps.env ?? process.env;
|
|
1542
|
+
const hostname = accountHomeHostname(deps);
|
|
1530
1543
|
const modelDeps = {
|
|
1531
1544
|
...deps.modelDeps,
|
|
1532
1545
|
env: deps.modelDeps?.env ?? env,
|
|
@@ -1644,6 +1657,7 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
|
|
|
1644
1657
|
pinnedModel,
|
|
1645
1658
|
profileModel,
|
|
1646
1659
|
currentModelValidated: deps.currentModelValidated === true,
|
|
1660
|
+
hostname,
|
|
1647
1661
|
});
|
|
1648
1662
|
}
|
|
1649
1663
|
catch (err) {
|
|
@@ -1659,7 +1673,7 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
|
|
|
1659
1673
|
throw err;
|
|
1660
1674
|
}
|
|
1661
1675
|
const resolved = selection.account;
|
|
1662
|
-
const status = accountStatus(lane.provider, resolved.id, config, { existsSync });
|
|
1676
|
+
const status = accountStatus(lane.provider, resolved.id, config, { existsSync, hostname });
|
|
1663
1677
|
if (isLoggedOut(status)) {
|
|
1664
1678
|
const failed = markPreSpawnFailure
|
|
1665
1679
|
? markSpawnFailure(hqRoot, lane.lane_id, "account_not_logged_in", {
|
|
@@ -1677,7 +1691,7 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
|
|
|
1677
1691
|
existing.provider_session_id &&
|
|
1678
1692
|
providerSupportsSessionResume(existing.provider)) {
|
|
1679
1693
|
copySessionFiles(planSessionCopy(existing.provider, {
|
|
1680
|
-
sourceHome: source.home,
|
|
1694
|
+
sourceHome: existing.provider_home_at_spawn ?? effectiveAccountHome(source, hostname).home,
|
|
1681
1695
|
targetHome: resolved.home,
|
|
1682
1696
|
cwd: hqRoot,
|
|
1683
1697
|
sessionId: existing.provider_session_id,
|
|
@@ -1691,7 +1705,7 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
|
|
|
1691
1705
|
cwd: hqRoot,
|
|
1692
1706
|
targetHome: resolved.home,
|
|
1693
1707
|
registeredHomes: Object.values(config.providers[existing.provider].accounts)
|
|
1694
|
-
.map((account) => account.home),
|
|
1708
|
+
.map((account) => effectiveAccountHome(account, hostname).home),
|
|
1695
1709
|
providerHomeAtSpawn: existing.provider_home_at_spawn,
|
|
1696
1710
|
});
|
|
1697
1711
|
}
|
|
@@ -2095,6 +2109,7 @@ export function envelopeRepairMode(provider) {
|
|
|
2095
2109
|
*/
|
|
2096
2110
|
export function spawnEnvelopeRepair(hqRoot, lane, input, deps = {}) {
|
|
2097
2111
|
const env = deps.env ?? process.env;
|
|
2112
|
+
const hostname = accountHomeHostname(deps);
|
|
2098
2113
|
const existsSync = deps.existsSync ?? ((p) => fs.existsSync(p));
|
|
2099
2114
|
const spawnProcess = deps.spawnProcess ?? defaultSpawnProcess;
|
|
2100
2115
|
const proveDetached = deps.proveDetached ?? defaultProveDetached;
|
|
@@ -2141,6 +2156,7 @@ export function spawnEnvelopeRepair(hqRoot, lane, input, deps = {}) {
|
|
|
2141
2156
|
const resolved = resolveAccount(lane.provider, lane.account, config, {
|
|
2142
2157
|
hqRoot,
|
|
2143
2158
|
existsSync,
|
|
2159
|
+
hostname,
|
|
2144
2160
|
model: pinnedModel ?? profileModel,
|
|
2145
2161
|
});
|
|
2146
2162
|
if (profileDefaultsApply && profileModel !== undefined && pinnedModel === undefined) {
|
|
@@ -645,6 +645,8 @@ export interface LaneEnvelope {
|
|
|
645
645
|
}
|
|
646
646
|
export interface AccountConfig {
|
|
647
647
|
home: string;
|
|
648
|
+
/** Optional account home overrides keyed by the owning host's hostname. */
|
|
649
|
+
hosts?: Record<string, AccountHostHome>;
|
|
648
650
|
enabled: boolean;
|
|
649
651
|
disabled_reason?: string;
|
|
650
652
|
max_running?: number;
|
|
@@ -653,6 +655,9 @@ export interface AccountConfig {
|
|
|
653
655
|
/** Default effort for this account. Beats the provider default; beaten by --effort. */
|
|
654
656
|
effort?: string;
|
|
655
657
|
}
|
|
658
|
+
export interface AccountHostHome {
|
|
659
|
+
home: string;
|
|
660
|
+
}
|
|
656
661
|
export interface ProviderConfig {
|
|
657
662
|
max_running: number;
|
|
658
663
|
max_queued: number;
|