@indigoai-us/hq-cli 5.345.42 → 5.345.43

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 CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.345.43] — 2026-10-07
6
+ - The published core-command E2E workflow now retries the exact npm release install for up to 10 minutes while registry propagation completes.
7
+
8
+ - HQ Anywhere resolves person-level flags in unlinked folders. The daemon refreshes the flag and person setting every 60 seconds, then opens or closes its socket when either changes.
9
+ - Claude and Codex global installs use one skill prefix, keep company skills out of global scope, remove old company links during upgrades, and skip broken sources. Dry runs use `~/.hq/root` when run outside a checkout.
10
+ - Doctor checks for a live desktop-hosted daemon instead of treating the sync LaunchAgent as proof. Registry refreshes retain the daemon's machine scope and ID token.
11
+ - Let a failed lane's ancestors or same-company manager resume it, and backfill missing company attribution when reparenting it to a company senior.
12
+ - Let Claude lanes fall back to eligible accounts when every profile-pinned account is unavailable, behind the default-off `lanes.profile-pin-exhausted-fallback` flag.
13
+
5
14
  ## [5.345.42] — 2026-10-07
6
15
  - `hq db usage --app <name>` shows one database app's included amounts, use, overage, read-only ceiling and estimated monthly charge.
7
16
 
@@ -12464,7 +12464,7 @@ export declare const COMMAND_CATALOG: readonly [{
12464
12464
  readonly subcommands: readonly [];
12465
12465
  }, {
12466
12466
  readonly name: "resume";
12467
- readonly description: "Resume an interrupted, done or blocked lane, or an awaiting_input lane with no answerable question; recover failed lanes with the senior-only --from-failed option";
12467
+ readonly description: "Resume an interrupted, done or blocked lane, or an awaiting_input lane with no answerable question; recover failed lanes with --from-failed as a senior ancestor or same-company manager";
12468
12468
  readonly aliases: readonly [];
12469
12469
  readonly hidden: false;
12470
12470
  readonly helpOption: true;
@@ -12483,7 +12483,7 @@ export declare const COMMAND_CATALOG: readonly [{
12483
12483
  readonly hidden: false;
12484
12484
  }, {
12485
12485
  readonly flags: "--from-failed";
12486
- readonly description: "Explicitly resume a failed lane as its senior";
12486
+ readonly description: "Explicitly resume a failed lane as an ancestor or same-company manager";
12487
12487
  readonly hidden: false;
12488
12488
  }, {
12489
12489
  readonly flags: "--reason <text>";
@@ -15156,7 +15156,7 @@ export const COMMAND_CATALOG = [
15156
15156
  },
15157
15157
  {
15158
15158
  "name": "resume",
15159
- "description": "Resume an interrupted, done or blocked lane, or an awaiting_input lane with no answerable question; recover failed lanes with the senior-only --from-failed option",
15159
+ "description": "Resume an interrupted, done or blocked lane, or an awaiting_input lane with no answerable question; recover failed lanes with --from-failed as a senior ancestor or same-company manager",
15160
15160
  "aliases": [],
15161
15161
  "hidden": false,
15162
15162
  "helpOption": true,
@@ -15179,7 +15179,7 @@ export const COMMAND_CATALOG = [
15179
15179
  },
15180
15180
  {
15181
15181
  "flags": "--from-failed",
15182
- "description": "Explicitly resume a failed lane as its senior",
15182
+ "description": "Explicitly resume a failed lane as an ancestor or same-company manager",
15183
15183
  "hidden": false
15184
15184
  },
15185
15185
  {
@@ -75,8 +75,15 @@ export interface GlobalCommandOpts {
75
75
  log?: (line: string) => void;
76
76
  /** Test seam for the hq-pro person preference read. */
77
77
  personSettingReader?: () => Promise<boolean | null>;
78
+ /** Root-discovery seams used by command tests and wrappers. */
79
+ home?: string;
80
+ cwd?: string;
78
81
  }
79
- export declare function resolveInstallRoot(explicit: string | undefined): string;
82
+ export declare function resolveInstallRoot(explicit: string | undefined, options?: {
83
+ env?: NodeJS.ProcessEnv;
84
+ cwd?: string;
85
+ home?: string;
86
+ }): string;
80
87
  /** Entry used by `hq install --global` (wired from pkg-install.ts). */
81
88
  export declare function runInstallGlobal(opts: GlobalCommandOpts): Promise<void>;
82
89
  export declare function registerUninstallCommand(program: Command): void;
@@ -9,6 +9,7 @@
9
9
  * ~/.hq/anywhere/claude-install.json so uninstall can restore files byte-for-byte.
10
10
  */
11
11
  import * as fs from 'fs';
12
+ import * as os from 'node:os';
12
13
  import * as path from 'path';
13
14
  import { spawnSync } from 'node:child_process';
14
15
  import { buildCodexServerDef, claudeConfigFormat, codexConfigFormat, codexRemovalFormat, isCodexInstalled, jsonFormat, mergeCodexServer, removeCodexServer, registerCodexServer, unregisterCodexServer, mergeClaudeServer, readConfigDoc, realpathOrSelf, registerClaudeServer, resolveEnv, unregisterClaudeServer, writeConfigAtomic, } from './mcp-registration.js';
@@ -20,6 +21,8 @@ import { chatgptConnectorInstructions } from '../lib/install/chatgpt-targets.js'
20
21
  import { anywhereRuntimeAllowed } from '../lib/anywhere-person-setting.js';
21
22
  import { grokConnectorInstructions } from '../lib/install/grok-targets.js';
22
23
  import { readRegistry, registryDir, registryFile, writeRegistry } from '../lib/registry/registry.js';
24
+ import { readCompaniesManifestMap } from '../lib/work-context/repo-remote.js';
25
+ import { resolveDefaultHqRoot } from '../utils/hq-root-resolver.js';
23
26
  import { DAEMON_LAUNCHD_LABEL, DAEMON_SYSTEMD_UNIT, DAEMON_WINDOWS_TASK, SYSTEM_UNIT_DIR } from '../lib/daemon/install.js';
24
27
  import { readDaemonConfig } from '../lib/daemon/config.js';
25
28
  import { daemonPaths } from '../lib/daemon/paths.js';
@@ -201,9 +204,13 @@ function mcpManifest(opts) {
201
204
  }
202
205
  return { type: 'stdio', command, args: [entry, 'mcp', 'serve'], env: { PATH: MCP_SUBPROCESS_PATH } };
203
206
  }
207
+ function skillLinkName(name) {
208
+ return name.startsWith(SKILL_LINK_PREFIX) ? name : `${SKILL_LINK_PREFIX}${name}`;
209
+ }
204
210
  function planSkills(hqRoot, t) {
205
211
  const source = hqSkillsSource(hqRoot);
206
- const plan = { link: [], already: [], skipped: [] };
212
+ const plan = { link: [], already: [], skipped: [], unresolved: [], companyScoped: [] };
213
+ const companySlugs = new Set(Object.keys(readCompaniesManifestMap(hqRoot) ?? {}));
207
214
  let names;
208
215
  try {
209
216
  names = fs
@@ -218,8 +225,23 @@ function planSkills(hqRoot, t) {
218
225
  throw e;
219
226
  }
220
227
  for (const name of names) {
221
- const link = path.join(t.skillsDir, `${SKILL_LINK_PREFIX}${name}`);
228
+ const namespace = name.includes(':') ? name.slice(0, name.indexOf(':')) : '';
229
+ if (namespace && companySlugs.has(namespace)) {
230
+ plan.companyScoped.push(name);
231
+ continue;
232
+ }
222
233
  const target = path.join(source, name);
234
+ try {
235
+ if (!fs.statSync(target).isDirectory()) {
236
+ plan.unresolved.push(name);
237
+ continue;
238
+ }
239
+ }
240
+ catch {
241
+ plan.unresolved.push(name);
242
+ continue;
243
+ }
244
+ const link = path.join(t.skillsDir, skillLinkName(name));
223
245
  let st = null;
224
246
  try {
225
247
  st = fs.lstatSync(link);
@@ -237,6 +259,15 @@ function planSkills(hqRoot, t) {
237
259
  }
238
260
  return plan;
239
261
  }
262
+ function reportSkippedSkills(plan, log, dryRun) {
263
+ const prefix = dryRun ? 'Would skip' : 'Skipped';
264
+ if (plan.unresolved.length > 0) {
265
+ log(`${prefix} skill source(s) that do not resolve to directories: ${plan.unresolved.join(', ')}`);
266
+ }
267
+ if (plan.companyScoped.length > 0) {
268
+ log(`${prefix} company-scoped skill(s) at global scope: ${plan.companyScoped.join(', ')}`);
269
+ }
270
+ }
240
271
  function hqSkillLinksForRoot(skillsDir, hqRoot) {
241
272
  let names;
242
273
  try {
@@ -261,6 +292,27 @@ function hqSkillLinksForRoot(skillsDir, hqRoot) {
261
292
  }
262
293
  }).map((name) => path.join(skillsDir, name));
263
294
  }
295
+ function hqCompanySkillLinksForRoot(skillsDir, hqRoot) {
296
+ const companySlugs = new Set(Object.keys(readCompaniesManifestMap(hqRoot) ?? {}));
297
+ if (companySlugs.size === 0)
298
+ return [];
299
+ const source = hqSkillsSource(hqRoot);
300
+ return hqSkillLinksForRoot(skillsDir, hqRoot).filter((link) => {
301
+ try {
302
+ const target = path.resolve(skillsDir, fs.readlinkSync(link));
303
+ if (path.dirname(target) !== source)
304
+ return false;
305
+ const sourceName = path.basename(target);
306
+ const separator = sourceName.indexOf(':');
307
+ return separator > 0 && companySlugs.has(sourceName.slice(0, separator));
308
+ }
309
+ catch (error) {
310
+ if (error.code === 'ENOENT')
311
+ return false;
312
+ throw error;
313
+ }
314
+ });
315
+ }
264
316
  function removeSeeded(seeded, regFile) {
265
317
  if (seeded.length === 0 || !fs.existsSync(regFile))
266
318
  return;
@@ -320,7 +372,13 @@ export function installGlobalClaude(opts) {
320
372
  : mdOld === null ? null : (removeClaudeMdBlock(mdOld) || null))
321
373
  : prior ? prior.claudeMd.original : mdOld;
322
374
  const mdNew = pluginSource ? mdOriginal : addClaudeMdBlock(mdOld, hqRoot);
323
- const skills = pluginSource ? { link: [], already: [], skipped: [] } : planSkills(hqRoot, t);
375
+ const skills = pluginSource ? {
376
+ link: [],
377
+ already: [],
378
+ skipped: [],
379
+ unresolved: [],
380
+ companyScoped: [],
381
+ } : planSkills(hqRoot, t);
324
382
  const settingsOld = readOrNull(t.settingsJson);
325
383
  const settingsDoc = readConfigDoc(t.settingsJson, jsonFormat).doc;
326
384
  const directHooksRemoved = pluginSource
@@ -347,7 +405,9 @@ export function installGlobalClaude(opts) {
347
405
  const settingsNext = pluginSource
348
406
  ? cleanupRoots.reduce((doc, root) => removeHqHooks(doc, root), settingsDoc)
349
407
  : addHqHooks(settingsDoc, hqRoot, hookTarget);
350
- const skillLinksToRemove = pluginSource ? cleanupRoots.flatMap((root) => hqSkillLinksForRoot(t.skillsDir, root)) : [];
408
+ const skillLinksToRemove = [...new Set(pluginSource
409
+ ? cleanupRoots.flatMap((root) => hqSkillLinksForRoot(t.skillsDir, root))
410
+ : cleanupRoots.flatMap((root) => hqCompanySkillLinksForRoot(t.skillsDir, root)))];
351
411
  const claudeDoc = readConfigDoc(t.claudeJson, claudeConfigFormat).doc;
352
412
  // Collision check runs here too, so a dry run surfaces a conflicting "hq" server.
353
413
  const claudeNext = pluginSource ? claudeDoc : mergeClaudeServer(HQ_MCP_SERVER_NAME, {
@@ -359,7 +419,7 @@ export function installGlobalClaude(opts) {
359
419
  if (mdOld !== mdNew)
360
420
  touched.push(t.claudeMd);
361
421
  for (const s of skills.link)
362
- touched.push(path.join(t.skillsDir, `${SKILL_LINK_PREFIX}${s}`));
422
+ touched.push(path.join(t.skillsDir, skillLinkName(s)));
363
423
  touched.push(...skillLinksToRemove);
364
424
  if (settingsNext !== settingsDoc)
365
425
  touched.push(t.settingsJson);
@@ -374,8 +434,12 @@ export function installGlobalClaude(opts) {
374
434
  for (const f of touched)
375
435
  log(` ${f}`);
376
436
  if (skills.skipped.length > 0) {
377
- log(`Would skip ${skills.skipped.length} skill(s) whose hq-<name> already exists and is not an HQ link: ${skills.skipped.join(', ')}`);
437
+ log(`Would skip ${skills.skipped.length} skill(s) whose target already exists and is not an HQ link: ${skills.skipped.join(', ')}`);
378
438
  }
439
+ if (!pluginSource && skillLinksToRemove.length > 0) {
440
+ log(`Would remove ${skillLinksToRemove.length} previous company-scoped skill link(s)`);
441
+ }
442
+ reportSkippedSkills(skills, log, true);
379
443
  log(`\n--- ${t.settingsJson}`);
380
444
  log(lineDiff(jsonFormat.serialize(settingsDoc), jsonFormat.serialize(settingsNext)));
381
445
  log(`\n--- ${t.claudeJson}`);
@@ -429,11 +493,10 @@ export function installGlobalClaude(opts) {
429
493
  if (!pluginSource)
430
494
  fs.mkdirSync(t.skillsDir, { recursive: true });
431
495
  for (const name of skills.link) {
432
- fs.symlinkSync(path.join(hqSkillsSource(hqRoot), name), path.join(t.skillsDir, `${SKILL_LINK_PREFIX}${name}`));
496
+ fs.symlinkSync(path.join(hqSkillsSource(hqRoot), name), path.join(t.skillsDir, skillLinkName(name)));
433
497
  }
434
- if (pluginSource)
435
- for (const link of skillLinksToRemove)
436
- fs.unlinkSync(link);
498
+ for (const link of skillLinksToRemove)
499
+ fs.unlinkSync(link);
437
500
  if (pluginSource) {
438
501
  // Migrate a prior direct install: remove only our old hook/MCP entries while
439
502
  // retaining the original user settings for a later uninstall restore.
@@ -498,6 +561,7 @@ export function installGlobalClaude(opts) {
498
561
  writeFileAtomic(t.stateFile, `${JSON.stringify(state, null, 2)}\n`);
499
562
  log(`HQ installed for Claude Code from ${hqRoot}.`);
500
563
  log(` skills linked: ${skills.link.length} new, ${skills.already.length} already present, ${skills.skipped.length} skipped`);
564
+ reportSkippedSkills(skills, log, false);
501
565
  if (pluginSource)
502
566
  log(` plugin: ${pluginSource.pluginId} installed from ${pluginSource.sourceDir}; direct hooks and MCP entries removed`);
503
567
  else {
@@ -691,6 +755,7 @@ export function installGlobalCodex(opts) {
691
755
  const charter = fs.readFileSync(codexCharterSource(hqRoot), 'utf-8');
692
756
  const mdOld = readOrNull(t.agentsMd);
693
757
  const mdNew = addAgentsMdBlock(mdOld, charter);
758
+ const cleanupRoots = [...new Set([hqRoot, ...(prior?.hqRoot ? [prior.hqRoot] : [])])];
694
759
  const legacy = classifyLegacySkills(t.skillsDir, hqRoot);
695
760
  const legacyPath = path.join(t.skillsDir, LEGACY_SKILLS_NAME);
696
761
  const legacyBackupPath = path.join(t.skillsDir, LEGACY_BACKUP_NAME);
@@ -698,6 +763,7 @@ export function installGlobalCodex(opts) {
698
763
  throw new Error(`${legacyBackupPath} already exists; move it away before installing.`);
699
764
  }
700
765
  const skills = planSkills(hqRoot, t);
766
+ const companySkillLinksToRemove = [...new Set(cleanupRoots.flatMap((root) => hqCompanySkillLinksForRoot(t.skillsDir, root)))];
701
767
  const hooksOld = readOrNull(t.hooksJson);
702
768
  const hooksDoc = readConfigDoc(t.hooksJson, jsonFormat).doc;
703
769
  const hookTarget = hookTargetFor(hqRoot, home, opts.daemonInstalled, env);
@@ -719,7 +785,8 @@ export function installGlobalCodex(opts) {
719
785
  if (legacy.kind === 'hq-symlink' || legacy.kind === 'hq-dir')
720
786
  touched.push(path.join(t.skillsDir, LEGACY_SKILLS_NAME));
721
787
  for (const s of skills.link)
722
- touched.push(path.join(t.skillsDir, `${SKILL_LINK_PREFIX}${s}`));
788
+ touched.push(path.join(t.skillsDir, skillLinkName(s)));
789
+ touched.push(...companySkillLinksToRemove);
723
790
  if (hooksNext !== hooksDoc)
724
791
  touched.push(t.hooksJson);
725
792
  if (tomlNext !== tomlDoc || legacyPackServerPresent)
@@ -736,8 +803,12 @@ export function installGlobalCodex(opts) {
736
803
  else if (legacy.kind === 'foreign')
737
804
  log(legacyWarning(t.skillsDir));
738
805
  if (skills.skipped.length > 0) {
739
- log(`Would skip ${skills.skipped.length} skill(s) whose hq-<name> already exists and is not an HQ link: ${skills.skipped.join(', ')}`);
806
+ log(`Would skip ${skills.skipped.length} skill(s) whose target already exists and is not an HQ link: ${skills.skipped.join(', ')}`);
807
+ }
808
+ if (companySkillLinksToRemove.length > 0) {
809
+ log(`Would remove ${companySkillLinksToRemove.length} previous company-scoped skill link(s)`);
740
810
  }
811
+ reportSkippedSkills(skills, log, true);
741
812
  log(`\n--- ${t.hooksJson}`);
742
813
  log(lineDiff(jsonFormat.serialize(hooksDoc), jsonFormat.serialize(hooksNext)));
743
814
  log(`\n--- ${t.configToml}`);
@@ -761,8 +832,10 @@ export function installGlobalCodex(opts) {
761
832
  log(legacyWarning(t.skillsDir));
762
833
  fs.mkdirSync(t.skillsDir, { recursive: true });
763
834
  for (const name of skills.link) {
764
- fs.symlinkSync(path.join(hqSkillsSource(hqRoot), name), path.join(t.skillsDir, `${SKILL_LINK_PREFIX}${name}`));
835
+ fs.symlinkSync(path.join(hqSkillsSource(hqRoot), name), path.join(t.skillsDir, skillLinkName(name)));
765
836
  }
837
+ for (const link of companySkillLinksToRemove)
838
+ fs.unlinkSync(link);
766
839
  writeConfigAtomic({
767
840
  target: t.hooksJson,
768
841
  pack: HQ_ANYWHERE_PACK,
@@ -803,6 +876,7 @@ export function installGlobalCodex(opts) {
803
876
  writeFileAtomic(t.stateFile, `${JSON.stringify(state, null, 2)}\n`);
804
877
  log(`HQ installed for Codex from ${hqRoot}.`);
805
878
  log(` skills linked: ${skills.link.length} new, ${skills.already.length} already present, ${skills.skipped.length} skipped`);
879
+ reportSkippedSkills(skills, log, false);
806
880
  log(` hooks: ${hookTarget === 'shim' ? shimPath(hqRoot) : codexAdapterPath(hqRoot)} registered in ${t.hooksJson}`);
807
881
  log(` MCP: "${HQ_MCP_SERVER_NAME}" registered in ${t.configToml}`);
808
882
  return touched;
@@ -946,34 +1020,63 @@ function assertRuntime(runtime) {
946
1020
  }
947
1021
  return r;
948
1022
  }
949
- export function resolveInstallRoot(explicit) {
950
- const fromFlag = explicit?.trim() || process.env.HQ_ROOT?.trim();
951
- const root = fromFlag ? path.resolve(fromFlag) : resolveHqRoot();
952
- if (!root) {
1023
+ export function resolveInstallRoot(explicit, options = {}) {
1024
+ const env = options.env ?? process.env;
1025
+ const fromFlag = explicit?.trim() || env.HQ_ROOT?.trim();
1026
+ if (fromFlag)
1027
+ return path.resolve(fromFlag);
1028
+ const cwdRoot = resolveHqRoot(options.cwd ?? process.cwd());
1029
+ if (cwdRoot)
1030
+ return cwdRoot;
1031
+ const home = options.home?.trim() || env.HOME?.trim() || os.homedir();
1032
+ try {
1033
+ const pointer = fs.readFileSync(path.join(home, '.hq', 'root'), 'utf8').trim();
1034
+ if (pointer) {
1035
+ const pointedRoot = resolveHqRoot(pointer);
1036
+ if (pointedRoot)
1037
+ return pointedRoot;
1038
+ }
1039
+ }
1040
+ catch {
1041
+ // Fall through to the regular installer/config root discovery.
1042
+ }
1043
+ try {
1044
+ const rootEnv = { ...env };
1045
+ delete rootEnv.HQ_ROOT;
1046
+ return resolveDefaultHqRoot({
1047
+ onMissing: 'throw',
1048
+ env: rootEnv,
1049
+ cwd: options.cwd,
1050
+ home,
1051
+ });
1052
+ }
1053
+ catch {
953
1054
  throw Object.assign(new Error('Run from inside your HQ checkout, or pass --hq-root <dir>.'), { expected: true });
954
1055
  }
955
- return root;
956
1056
  }
957
1057
  /** Entry used by `hq install --global` (wired from pkg-install.ts). */
958
1058
  export async function runInstallGlobal(opts) {
959
1059
  const runtime = assertRuntime(opts.runtime);
960
1060
  const env = opts.env ?? process.env;
961
- if (runtime === 'chatgpt' || runtime === 'grok') {
1061
+ if (runtime === 'chatgpt' || runtime === 'grok' || opts.dryRun) {
962
1062
  const enabled = await anywhereRuntimeAllowed(env, {
963
1063
  ...(opts.personSettingReader ? { readSetting: opts.personSettingReader } : {}),
964
1064
  onError: (name) => (opts.log ?? console.log)(`HQ Anywhere person setting unavailable (${name}); access remains off.`),
965
1065
  });
966
1066
  if (!enabled)
967
1067
  throw new AnywhereRuntimeDisabledError();
968
- const endpoint = resolveHqMcpEndpoint(opts.env ?? process.env).toString();
969
- const lines = runtime === 'chatgpt' ? chatgptConnectorInstructions(endpoint) : grokConnectorInstructions(endpoint);
970
- for (const line of lines)
971
- (opts.log ?? console.log)(line);
972
- return;
1068
+ if (runtime === 'chatgpt' || runtime === 'grok') {
1069
+ const endpoint = resolveHqMcpEndpoint(env).toString();
1070
+ const lines = runtime === 'chatgpt' ? chatgptConnectorInstructions(endpoint) : grokConnectorInstructions(endpoint);
1071
+ for (const line of lines)
1072
+ (opts.log ?? console.log)(line);
1073
+ return;
1074
+ }
973
1075
  }
974
1076
  const install = runtime === 'codex' ? installGlobalCodex : installGlobalClaude;
975
1077
  install({
976
- hqRoot: resolveInstallRoot(opts.hqRoot),
1078
+ hqRoot: resolveInstallRoot(opts.hqRoot, { env, cwd: opts.cwd, home: opts.home }),
1079
+ home: opts.home,
977
1080
  dryRun: opts.dryRun,
978
1081
  via: opts.via,
979
1082
  marketplaceDir: opts.marketplaceDir,
@@ -738,6 +738,7 @@ export function createLaneMessageHandlers(deps) {
738
738
  ...(automatic.preservedModel !== undefined ? { preservedModel: automatic.preservedModel } : {}),
739
739
  ...(resumeProfile !== undefined ? { workerProfile: resumeProfile } : {}),
740
740
  ...(refreshProfileSettings ? { refreshProfileSettings: true, accountSource: "balanced" } : {}),
741
+ ...(automatic.historyReason === "profile_pin_exhausted" ? { preserveAdmissionAccounts: true } : {}),
741
742
  ...(resumeEffort !== undefined ? { effort: resumeEffort } : {}),
742
743
  ...(hireGrantContext !== undefined ? { grantContext: hireGrantContext } : {}),
743
744
  pending: {
@@ -409,6 +409,9 @@ export function createLaneResumeHandlers(deps) {
409
409
  : {}),
410
410
  ...(resumeProfile !== undefined ? { workerProfile: resumeProfile } : {}),
411
411
  ...(refreshProfileSettings ? { refreshProfileSettings: true, accountSource: "balanced" } : {}),
412
+ ...(automaticAccountSelection.historyReason === "profile_pin_exhausted"
413
+ ? { preserveAdmissionAccounts: true }
414
+ : {}),
412
415
  ...(profileRepin !== undefined ? { profileRepin } : {}),
413
416
  ...(resumeEffort !== undefined ? { effort: resumeEffort } : {}),
414
417
  ...(hireGrantContext !== undefined ? { grantContext: hireGrantContext } : {}),