@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.
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.203.0",
3
+ "version": "5.204.0",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {