agent-shim 8.9.0 → 8.11.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/dist/index.cjs CHANGED
@@ -115,6 +115,7 @@ __export(index_exports, {
115
115
  createRcApiNodeHandler: () => createRcApiNodeHandler,
116
116
  createRcApiRouter: () => createRcApiRouter,
117
117
  createRcControlHandler: () => createRcControlHandler,
118
+ createRcCredentialStore: () => createRcCredentialStore,
118
119
  createRcEventFanout: () => createRcEventFanout,
119
120
  createRcSessionTracker: () => createRcSessionTracker,
120
121
  createRcStreamHub: () => createRcStreamHub,
@@ -268,8 +269,113 @@ var categories_default_default = {
268
269
  };
269
270
 
270
271
  // src/config/schema.ts
271
- var import_node_path = __toESM(require("node:path"), 1);
272
+ var import_node_path2 = __toESM(require("node:path"), 1);
272
273
  var import_zod = require("zod");
274
+
275
+ // src/versionDiscovery.ts
276
+ var import_node_os = __toESM(require("node:os"), 1);
277
+ var import_node_path = __toESM(require("node:path"), 1);
278
+
279
+ // src/cliError.ts
280
+ var EXIT_FAILURE = 1;
281
+ var EXIT_USAGE = 2;
282
+ var CliError = class extends Error {
283
+ /** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
284
+ exitCode = EXIT_FAILURE;
285
+ };
286
+ var UsageError = class extends CliError {
287
+ exitCode = EXIT_USAGE;
288
+ constructor(message) {
289
+ super(message);
290
+ this.name = "UsageError";
291
+ }
292
+ };
293
+
294
+ // src/versionDiscovery.ts
295
+ function defaultVersionsDir() {
296
+ return import_node_path.default.join(import_node_os.default.homedir(), ".local", "share", "claude", "versions");
297
+ }
298
+ var NUMERIC_DOTTED_VERSION_RE = /^\d+(?:\.\d+)*$/;
299
+ function isNumericDottedVersion(name) {
300
+ return NUMERIC_DOTTED_VERSION_RE.test(name);
301
+ }
302
+ function compareVersions(a, b) {
303
+ if (!isNumericDottedVersion(a)) {
304
+ throw new Error(`compareVersions: "${a}" is not a valid plain dotted-numeric version`);
305
+ }
306
+ if (!isNumericDottedVersion(b)) {
307
+ throw new Error(`compareVersions: "${b}" is not a valid plain dotted-numeric version`);
308
+ }
309
+ const segmentsA = a.split(".").map(Number);
310
+ const segmentsB = b.split(".").map(Number);
311
+ const length = Math.max(segmentsA.length, segmentsB.length);
312
+ for (let i = 0; i < length; i += 1) {
313
+ const segmentA = segmentsA[i] ?? 0;
314
+ const segmentB = segmentsB[i] ?? 0;
315
+ if (segmentA !== segmentB) {
316
+ return segmentA - segmentB;
317
+ }
318
+ }
319
+ return 0;
320
+ }
321
+ var ClaudeVersionNotInstalledError = class extends CliError {
322
+ constructor(version, versionsDir, installed) {
323
+ super(
324
+ `Claude Code ${version} is pinned for this launch but is not installed under "${versionsDir}"` + (installed.length === 0 ? " (no versions are installed there)." : `. Installed: ${installed.join(", ")}.`) + " Install it, or change or remove the pin (--claude-version, AGENT_SHIM_CLAUDE_VERSION, or launch.claudeVersion)."
325
+ );
326
+ this.version = version;
327
+ this.versionsDir = versionsDir;
328
+ this.installed = installed;
329
+ this.name = "ClaudeVersionNotInstalledError";
330
+ }
331
+ version;
332
+ versionsDir;
333
+ installed;
334
+ };
335
+ function installedVersions(entries) {
336
+ return entries.filter((entry) => entry.isFile && entry.isExecutable && entry.sizeBytes > 0 && isNumericDottedVersion(entry.name)).map((entry) => entry.name).sort(compareVersions);
337
+ }
338
+ function pickHighestVersion(entries) {
339
+ const candidates = entries.filter(
340
+ (entry) => entry.isFile && entry.isExecutable && entry.sizeBytes > 0 && isNumericDottedVersion(entry.name)
341
+ );
342
+ if (candidates.length === 0) {
343
+ return void 0;
344
+ }
345
+ return candidates.reduce(
346
+ (highest, candidate) => compareVersions(candidate.name, highest.name) > 0 ? candidate : highest
347
+ ).name;
348
+ }
349
+ function discoverClaudeBinary(options) {
350
+ const versionsDir = options.versionsDir ?? defaultVersionsDir();
351
+ const entries = options.listVersionsDir(versionsDir);
352
+ const highestVersion = pickHighestVersion(entries);
353
+ if (options.version !== void 0) {
354
+ const installed = installedVersions(entries);
355
+ if (!installed.includes(options.version)) {
356
+ throw new ClaudeVersionNotInstalledError(options.version, versionsDir, installed);
357
+ }
358
+ return { path: import_node_path.default.join(versionsDir, options.version), source: "versions-dir", version: options.version };
359
+ }
360
+ if (highestVersion !== void 0) {
361
+ return {
362
+ path: import_node_path.default.join(versionsDir, highestVersion),
363
+ source: "versions-dir",
364
+ version: highestVersion
365
+ };
366
+ }
367
+ for (const dir of options.pathDirs) {
368
+ const found = options.findExecutableInDir(dir, "claude");
369
+ if (found !== void 0 && !options.isOwnBinary(found)) {
370
+ return { path: found, source: "path-fallback" };
371
+ }
372
+ }
373
+ throw new Error(
374
+ `Could not find a claude binary. Looked for genuinely-executable versioned binaries under "${versionsDir}" (missing, empty, or containing nothing executable) and for a "claude" executable on PATH (never this tool's own binary). Install Claude Code, or set the versions directory / PATH correctly, then try again.`
375
+ );
376
+ }
377
+
378
+ // src/config/schema.ts
273
379
  var CATEGORY_NAMES = ["secret", "runtime", "history", "knowledge", "settings"];
274
380
  var OVERRIDABLE_CATEGORIES = ["runtime", "history", "knowledge", "settings"];
275
381
  function isOverridableCategory(name) {
@@ -313,7 +419,9 @@ var LaunchSchema = import_zod.z.strictObject({
313
419
  remoteControl: import_zod.z.boolean().optional(),
314
420
  provider: import_zod.z.string().min(1).optional(),
315
421
  headroom: import_zod.z.boolean().optional(),
316
- trackUsage: import_zod.z.boolean().optional()
422
+ trackUsage: import_zod.z.boolean().optional(),
423
+ /** The exact Claude Code version to run, as it is named in Claude Code's versions directory (`2.1.220`). A pin that is not installed fails the launch; it never falls back to the highest version. */
424
+ claudeVersion: import_zod.z.string().regex(NUMERIC_DOTTED_VERSION_RE, "must be an exact dotted-numeric Claude Code version such as 2.1.220").optional()
317
425
  });
318
426
  var CREDENTIAL_TARGETS = ["bearer", "apiKey", "oauthToken"];
319
427
  var PROVIDER_CREDENTIAL_TARGETS = ["bearer", "apiKey"];
@@ -332,7 +440,7 @@ var CommandSourceOptions = {
332
440
  var CredentialSourceSchema = import_zod.z.union([
333
441
  import_zod.z.strictObject({ env: import_zod.z.string().min(1) }),
334
442
  import_zod.z.strictObject({
335
- file: import_zod.z.string().min(1).refine((filePath) => filePath.startsWith("~/") || import_node_path.default.isAbsolute(filePath), {
443
+ file: import_zod.z.string().min(1).refine((filePath) => filePath.startsWith("~/") || import_node_path2.default.isAbsolute(filePath), {
336
444
  message: "a credential file must be an absolute or ~-rooted path, since a launch can start in any directory"
337
445
  })
338
446
  }),
@@ -511,28 +619,11 @@ var SHIPPED_CATEGORY_DEFAULTS = Object.freeze({
511
619
 
512
620
  // src/config/store.ts
513
621
  var import_node_fs = __toESM(require("node:fs"), 1);
514
- var import_node_path2 = __toESM(require("node:path"), 1);
622
+ var import_node_path3 = __toESM(require("node:path"), 1);
515
623
  var import_node_crypto = require("node:crypto");
516
624
 
517
625
  // src/config/load.ts
518
626
  var import_cosmiconfig = require("cosmiconfig");
519
-
520
- // src/cliError.ts
521
- var EXIT_FAILURE = 1;
522
- var EXIT_USAGE = 2;
523
- var CliError = class extends Error {
524
- /** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
525
- exitCode = EXIT_FAILURE;
526
- };
527
- var UsageError = class extends CliError {
528
- exitCode = EXIT_USAGE;
529
- constructor(message) {
530
- super(message);
531
- this.name = "UsageError";
532
- }
533
- };
534
-
535
- // src/config/load.ts
536
627
  function createExplorer(moduleName = "agent-shim") {
537
628
  return (0, import_cosmiconfig.cosmiconfigSync)(moduleName, { searchPlaces: [] });
538
629
  }
@@ -653,9 +744,9 @@ function readJson(filePath, schema, storeFs = nodeStoreFs) {
653
744
  return result.data;
654
745
  }
655
746
  function writeTextAtomic(filePath, contents, storeFs = nodeStoreFs) {
656
- const dir = import_node_path2.default.dirname(filePath);
747
+ const dir = import_node_path3.default.dirname(filePath);
657
748
  storeFs.mkdirSync(dir);
658
- const tempPath = import_node_path2.default.join(dir, `.${import_node_path2.default.basename(filePath)}.${String(process.pid)}.${(0, import_node_crypto.randomUUID)()}.tmp`);
749
+ const tempPath = import_node_path3.default.join(dir, `.${import_node_path3.default.basename(filePath)}.${String(process.pid)}.${(0, import_node_crypto.randomUUID)()}.tmp`);
659
750
  storeFs.writeFileUtf8(tempPath, contents);
660
751
  try {
661
752
  storeFs.renameSync(tempPath, filePath);
@@ -679,9 +770,9 @@ function applyPatch(filePath, schema, patch, options = {}) {
679
770
  if (!result.success) {
680
771
  throw new ConfigValidationError(filePath, result.error.issues);
681
772
  }
682
- const validated = result.data;
683
- writeJsonAtomic(filePath, validated, storeFs);
684
- return validated;
773
+ const validated2 = result.data;
774
+ writeJsonAtomic(filePath, validated2, storeFs);
775
+ return validated2;
685
776
  }
686
777
 
687
778
  // src/config/classify.ts
@@ -1104,6 +1195,9 @@ function flattenLayers(layers, options) {
1104
1195
  if (layer.launch.trackUsage !== void 0) {
1105
1196
  launch.trackUsage = layer.launch.trackUsage;
1106
1197
  }
1198
+ if (layer.launch.claudeVersion !== void 0) {
1199
+ launch.claudeVersion = layer.launch.claudeVersion;
1200
+ }
1107
1201
  }
1108
1202
  if (layer.entries === void 0) {
1109
1203
  continue;
@@ -1341,7 +1435,7 @@ function dedupeDiagnostics(diagnostics) {
1341
1435
  }
1342
1436
 
1343
1437
  // src/resolve/plan.ts
1344
- var import_node_path3 = __toESM(require("node:path"), 1);
1438
+ var import_node_path4 = __toESM(require("node:path"), 1);
1345
1439
  function parentOf(rel) {
1346
1440
  const index = rel.lastIndexOf("/");
1347
1441
  return index === -1 ? "" : rel.slice(0, index);
@@ -1391,7 +1485,7 @@ function planFarm(params) {
1391
1485
  }
1392
1486
  return value;
1393
1487
  };
1394
- const linkTarget = (rel) => import_node_path3.default.join(params.facts.claudeHome, rel);
1488
+ const linkTarget = (rel) => import_node_path4.default.join(params.facts.claudeHome, rel);
1395
1489
  const visit = (rel) => {
1396
1490
  const fact = params.facts.entries.get(rel);
1397
1491
  const decision = params.decisions.get(rel);
@@ -1469,7 +1563,7 @@ function descendPolicy(rules) {
1469
1563
  }
1470
1564
 
1471
1565
  // src/resolve/walk.ts
1472
- var import_node_path4 = __toESM(require("node:path"), 1);
1566
+ var import_node_path5 = __toESM(require("node:path"), 1);
1473
1567
 
1474
1568
  // src/resolve/extends.ts
1475
1569
  function lineariseProfile(rootName, load) {
@@ -1537,10 +1631,10 @@ function profileLayers(rootName, load, startId) {
1537
1631
 
1538
1632
  // src/resolve/walk.ts
1539
1633
  function walkDirectoryAncestors(cwd, options) {
1540
- const limit = import_node_path4.default.resolve(options.limit ?? options.home);
1634
+ const limit = import_node_path5.default.resolve(options.limit ?? options.home);
1541
1635
  const isReadable = options.isReadable ?? (() => true);
1542
1636
  const collected = [];
1543
- let current = import_node_path4.default.resolve(cwd);
1637
+ let current = import_node_path5.default.resolve(cwd);
1544
1638
  for (; ; ) {
1545
1639
  if (!isReadable(current)) {
1546
1640
  break;
@@ -1549,7 +1643,7 @@ function walkDirectoryAncestors(cwd, options) {
1549
1643
  if (current === limit) {
1550
1644
  break;
1551
1645
  }
1552
- const parent = import_node_path4.default.dirname(current);
1646
+ const parent = import_node_path5.default.dirname(current);
1553
1647
  if (parent === current) {
1554
1648
  break;
1555
1649
  }
@@ -1673,7 +1767,7 @@ function resolveDecisions(input) {
1673
1767
  }
1674
1768
 
1675
1769
  // src/launcher/farm.ts
1676
- var import_node_path6 = __toESM(require("node:path"), 1);
1770
+ var import_node_path7 = __toESM(require("node:path"), 1);
1677
1771
  var import_zod2 = require("zod");
1678
1772
 
1679
1773
  // src/resolve/reconcile.ts
@@ -1777,7 +1871,7 @@ var LEGACY_FARM_MANIFEST_FILENAME = ".claude-use-farm.json";
1777
1871
 
1778
1872
  // src/launcher/lock.ts
1779
1873
  var import_node_crypto2 = require("node:crypto");
1780
- var import_node_path5 = __toESM(require("node:path"), 1);
1874
+ var import_node_path6 = __toESM(require("node:path"), 1);
1781
1875
  var DEFAULT_STALE_AFTER_MS = 12e4;
1782
1876
  var DEFAULT_RETRY_DELAY_MS = 50;
1783
1877
  var DEFAULT_MAX_ATTEMPTS = 200;
@@ -1796,7 +1890,7 @@ var IdentityLockBusyError = class extends CliError {
1796
1890
  holderPid;
1797
1891
  };
1798
1892
  function identityLockPath(dir, identity) {
1799
- return import_node_path5.default.join(dir, `.${identity}.lock`);
1893
+ return import_node_path6.default.join(dir, `.${identity}.lock`);
1800
1894
  }
1801
1895
  function parseLockRecord(raw) {
1802
1896
  if (raw === void 0) {
@@ -1875,7 +1969,7 @@ var FarmManifestSchema = import_zod2.z.strictObject({
1875
1969
  links: import_zod2.z.array(import_zod2.z.strictObject({ rel: import_zod2.z.string(), target: import_zod2.z.string() }))
1876
1970
  });
1877
1971
  function readFarmManifest(fs12, farmRoot) {
1878
- const raw = fs12.readFileUtf8(import_node_path6.default.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs12.readFileUtf8(import_node_path6.default.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1972
+ const raw = fs12.readFileUtf8(import_node_path7.default.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs12.readFileUtf8(import_node_path7.default.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1879
1973
  if (raw === void 0) {
1880
1974
  return void 0;
1881
1975
  }
@@ -1891,7 +1985,7 @@ function readFarmManifest(fs12, farmRoot) {
1891
1985
  function buildEntryFacts(params) {
1892
1986
  const entries = /* @__PURE__ */ new Map();
1893
1987
  const visit = (rel) => {
1894
- const absolute = import_node_path6.default.join(params.claudeHome, rel);
1988
+ const absolute = import_node_path7.default.join(params.claudeHome, rel);
1895
1989
  const stat = params.fs.lstat(absolute);
1896
1990
  if (stat === void 0) {
1897
1991
  return void 0;
@@ -1934,7 +2028,7 @@ function buildEntryFacts(params) {
1934
2028
  };
1935
2029
  }
1936
2030
  function listSubtree(fs12, root, rel) {
1937
- const absolute = import_node_path6.default.join(root, rel);
2031
+ const absolute = import_node_path7.default.join(root, rel);
1938
2032
  const stat = fs12.lstat(absolute);
1939
2033
  if (stat === void 0) {
1940
2034
  return [];
@@ -1964,7 +2058,7 @@ function reconciliationScope(fs12, farmRoot, manifest) {
1964
2058
  if (manifest !== void 0) {
1965
2059
  return topLevelScopeRoots(manifest.materialised);
1966
2060
  }
1967
- return [...fs12.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs12.lstat(import_node_path6.default.join(farmRoot, name))?.kind === "dir").sort();
2061
+ return [...fs12.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs12.lstat(import_node_path7.default.join(farmRoot, name))?.kind === "dir").sort();
1968
2062
  }
1969
2063
  function collectFarmListing(fs12, farmRoot, scopeRoots) {
1970
2064
  return scopeRoots.flatMap((root) => listSubtree(fs12, farmRoot, root));
@@ -1972,7 +2066,7 @@ function collectFarmListing(fs12, farmRoot, scopeRoots) {
1972
2066
  function collectCanonicalCounterparts(fs12, claudeHome, farmListing) {
1973
2067
  const out = [];
1974
2068
  for (const entry of farmListing) {
1975
- const absolute = import_node_path6.default.join(claudeHome, entry.rel);
2069
+ const absolute = import_node_path7.default.join(claudeHome, entry.rel);
1976
2070
  const stat = fs12.lstat(absolute);
1977
2071
  if (stat === void 0) {
1978
2072
  continue;
@@ -2002,21 +2096,21 @@ function carryOver(params) {
2002
2096
  if (accounted.has(name)) {
2003
2097
  continue;
2004
2098
  }
2005
- const stat = params.fs.lstat(import_node_path6.default.join(params.previousRoot, name));
2099
+ const stat = params.fs.lstat(import_node_path7.default.join(params.previousRoot, name));
2006
2100
  if (stat === void 0 || stat.kind === "symlink") {
2007
2101
  continue;
2008
2102
  }
2009
- if (params.fs.lstat(import_node_path6.default.join(params.farmRoot, name)) !== void 0) {
2103
+ if (params.fs.lstat(import_node_path7.default.join(params.farmRoot, name)) !== void 0) {
2010
2104
  const category = params.classification === void 0 ? void 0 : classifyEntries([name], params.classification).classification.get(name);
2011
2105
  if (category === "runtime") {
2012
- params.fs.removeRecursive(import_node_path6.default.join(params.previousRoot, name));
2106
+ params.fs.removeRecursive(import_node_path7.default.join(params.previousRoot, name));
2013
2107
  autoResolved.push(name);
2014
2108
  continue;
2015
2109
  }
2016
2110
  collided.push(name);
2017
2111
  continue;
2018
2112
  }
2019
- params.fs.rename(import_node_path6.default.join(params.previousRoot, name), import_node_path6.default.join(params.farmRoot, name));
2113
+ params.fs.rename(import_node_path7.default.join(params.previousRoot, name), import_node_path7.default.join(params.farmRoot, name));
2020
2114
  carried.push(name);
2021
2115
  }
2022
2116
  return { carried, autoResolved, collided };
@@ -2024,9 +2118,9 @@ function carryOver(params) {
2024
2118
  function buildScratchTree(params) {
2025
2119
  params.fs.mkdirp(params.scratchRoot);
2026
2120
  for (const entry of params.plan.entries) {
2027
- const absolute = import_node_path6.default.join(params.scratchRoot, entry.rel);
2121
+ const absolute = import_node_path7.default.join(params.scratchRoot, entry.rel);
2028
2122
  if (entry.kind === "link") {
2029
- params.fs.mkdirp(import_node_path6.default.dirname(absolute));
2123
+ params.fs.mkdirp(import_node_path7.default.dirname(absolute));
2030
2124
  params.fs.symlink(entry.target, absolute);
2031
2125
  continue;
2032
2126
  }
@@ -2035,14 +2129,14 @@ function buildScratchTree(params) {
2035
2129
  }
2036
2130
  }
2037
2131
  params.fs.writeFileUtf8(
2038
- import_node_path6.default.join(params.scratchRoot, FARM_MANIFEST_FILENAME),
2132
+ import_node_path7.default.join(params.scratchRoot, FARM_MANIFEST_FILENAME),
2039
2133
  `${JSON.stringify(params.manifest, null, 2)}
2040
2134
  `
2041
2135
  );
2042
2136
  }
2043
2137
  function swapIn(params) {
2044
2138
  if (params.fs.lstat(params.farmRoot) === void 0) {
2045
- params.fs.mkdirp(import_node_path6.default.dirname(params.farmRoot));
2139
+ params.fs.mkdirp(import_node_path7.default.dirname(params.farmRoot));
2046
2140
  params.fs.rename(params.scratchRoot, params.farmRoot);
2047
2141
  return { carried: [], autoResolved: [], collided: [] };
2048
2142
  }
@@ -2066,14 +2160,14 @@ function recoverInterruptedSwap(params) {
2066
2160
  const names = [...params.fs.readdir(params.identitiesDir)].sort();
2067
2161
  const removedScratch = [];
2068
2162
  for (const name of names.filter((candidate) => candidate.startsWith(scratchPrefix))) {
2069
- params.fs.removeRecursive(import_node_path6.default.join(params.identitiesDir, name));
2163
+ params.fs.removeRecursive(import_node_path7.default.join(params.identitiesDir, name));
2070
2164
  removedScratch.push(name);
2071
2165
  }
2072
2166
  let previous = names.filter((candidate) => candidate.startsWith(previousPrefix));
2073
2167
  let restoredFrom;
2074
2168
  const first = previous[0];
2075
2169
  if (first !== void 0 && params.fs.lstat(params.farmRoot) === void 0) {
2076
- params.fs.rename(import_node_path6.default.join(params.identitiesDir, first), params.farmRoot);
2170
+ params.fs.rename(import_node_path7.default.join(params.identitiesDir, first), params.farmRoot);
2077
2171
  restoredFrom = first;
2078
2172
  previous = previous.slice(1);
2079
2173
  }
@@ -2081,7 +2175,7 @@ function recoverInterruptedSwap(params) {
2081
2175
  const autoResolved = [];
2082
2176
  const retained = [];
2083
2177
  for (const name of previous) {
2084
- const previousRoot = import_node_path6.default.join(params.identitiesDir, name);
2178
+ const previousRoot = import_node_path7.default.join(params.identitiesDir, name);
2085
2179
  const result = carryOver({
2086
2180
  fs: params.fs,
2087
2181
  previousRoot,
@@ -2106,7 +2200,7 @@ function recoverInterruptedSwap(params) {
2106
2200
  };
2107
2201
  }
2108
2202
  function recoverFarm(params) {
2109
- const farmRoot = import_node_path6.default.join(params.identitiesDir, params.identity);
2203
+ const farmRoot = import_node_path7.default.join(params.identitiesDir, params.identity);
2110
2204
  const lock = acquireIdentityLock({
2111
2205
  identity: params.identity,
2112
2206
  dir: params.identitiesDir,
@@ -2165,16 +2259,16 @@ function executeReconciliation(params) {
2165
2259
  });
2166
2260
  continue;
2167
2261
  }
2168
- const from = import_node_path6.default.join(params.farmRoot, action.rel);
2169
- const canonical = import_node_path6.default.join(params.claudeHome, action.rel);
2262
+ const from = import_node_path7.default.join(params.farmRoot, action.rel);
2263
+ const canonical = import_node_path7.default.join(params.claudeHome, action.rel);
2170
2264
  if (action.kind === "adopt") {
2171
- params.fs.mkdirp(import_node_path6.default.dirname(canonical));
2265
+ params.fs.mkdirp(import_node_path7.default.dirname(canonical));
2172
2266
  params.fs.copyRecursive(from, canonical);
2173
2267
  adopted.push(action.rel);
2174
2268
  continue;
2175
2269
  }
2176
2270
  const preserved = `${canonical}.farm-conflict-${String(params.nowMs)}`;
2177
- params.fs.mkdirp(import_node_path6.default.dirname(canonical));
2271
+ params.fs.mkdirp(import_node_path7.default.dirname(canonical));
2178
2272
  params.fs.copyRecursive(from, preserved);
2179
2273
  conflicts.push(action.rel);
2180
2274
  }
@@ -2199,7 +2293,7 @@ function farmAlreadyMatches(existing, next) {
2199
2293
  return existing.identity === next.identity && existing.claudeHome === next.claudeHome && sameStrings(existing.materialised, next.materialised) && sameLinks(existing.links, next.links);
2200
2294
  }
2201
2295
  function resyncFarm(params) {
2202
- const farmRoot = import_node_path6.default.join(params.identitiesDir, params.identity);
2296
+ const farmRoot = import_node_path7.default.join(params.identitiesDir, params.identity);
2203
2297
  const lock = acquireIdentityLock({
2204
2298
  identity: params.identity,
2205
2299
  dir: params.identitiesDir,
@@ -2279,8 +2373,8 @@ function resyncFarm(params) {
2279
2373
  diagnostics
2280
2374
  };
2281
2375
  }
2282
- const scratchRoot = import_node_path6.default.join(params.identitiesDir, `.${params.identity}.scratch.${params.uniqueSuffix}`);
2283
- const previousRoot = import_node_path6.default.join(params.identitiesDir, `.${params.identity}.previous.${params.uniqueSuffix}`);
2376
+ const scratchRoot = import_node_path7.default.join(params.identitiesDir, `.${params.identity}.scratch.${params.uniqueSuffix}`);
2377
+ const previousRoot = import_node_path7.default.join(params.identitiesDir, `.${params.identity}.previous.${params.uniqueSuffix}`);
2284
2378
  buildScratchTree({ fs: params.fs, scratchRoot, plan: resolved.farm, manifest });
2285
2379
  const swap = swapIn({ fs: params.fs, farmRoot, scratchRoot, previousRoot, classification: params.classification });
2286
2380
  if (swap.retainedPrevious !== void 0) {
@@ -2709,7 +2803,7 @@ function providerBaseUrl(port, provider) {
2709
2803
  }
2710
2804
 
2711
2805
  // src/frontdoor/state.ts
2712
- var import_node_path7 = __toESM(require("node:path"), 1);
2806
+ var import_node_path8 = __toESM(require("node:path"), 1);
2713
2807
  var import_zod3 = require("zod");
2714
2808
  var FRONT_DOOR_PROTOCOL = 2;
2715
2809
  var FrontDoorSessionSchema = import_zod3.z.strictObject({ pid: import_zod3.z.number().int().positive(), startedAt: import_zod3.z.number(), token: import_zod3.z.string().min(1) });
@@ -2761,7 +2855,7 @@ function readFrontDoorState(fs12, stateFile) {
2761
2855
  }
2762
2856
  }
2763
2857
  function writeFrontDoorState(fs12, stateFile, state) {
2764
- fs12.mkdirp(import_node_path7.default.dirname(stateFile));
2858
+ fs12.mkdirp(import_node_path8.default.dirname(stateFile));
2765
2859
  fs12.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
2766
2860
  `);
2767
2861
  }
@@ -2771,7 +2865,7 @@ function frontDoorOrigin(state) {
2771
2865
  }
2772
2866
  function writeFrontDoorSession(fs12, sessionsDir, session) {
2773
2867
  fs12.mkdirPrivate(sessionsDir);
2774
- fs12.writeFilePrivate(import_node_path7.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2868
+ fs12.writeFilePrivate(import_node_path8.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2775
2869
  `);
2776
2870
  }
2777
2871
  function listFrontDoorSessions(fs12, sessionsDir) {
@@ -2781,7 +2875,7 @@ function listFrontDoorSessions(fs12, sessionsDir) {
2781
2875
  continue;
2782
2876
  }
2783
2877
  try {
2784
- const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs12.readFileUtf8(import_node_path7.default.join(sessionsDir, name)) ?? ""));
2878
+ const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs12.readFileUtf8(import_node_path8.default.join(sessionsDir, name)) ?? ""));
2785
2879
  if (parsed.success) {
2786
2880
  sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
2787
2881
  }
@@ -2792,7 +2886,7 @@ function listFrontDoorSessions(fs12, sessionsDir) {
2792
2886
  return sessions.sort((a, b) => a.pid - b.pid);
2793
2887
  }
2794
2888
  function removeFrontDoorSession(fs12, sessionsDir, pid) {
2795
- fs12.removeRecursive(import_node_path7.default.join(sessionsDir, `${String(pid)}.json`));
2889
+ fs12.removeRecursive(import_node_path8.default.join(sessionsDir, `${String(pid)}.json`));
2796
2890
  }
2797
2891
  function pruneDeadFrontDoorSessions(fs12, sessionsDir, isRunning) {
2798
2892
  const removed = [];
@@ -2936,8 +3030,8 @@ function parseConnectTarget(authority) {
2936
3030
  function isInterceptedHost(host, interceptHosts) {
2937
3031
  return interceptHosts.includes(host);
2938
3032
  }
2939
- function servedByPipeline(path29) {
2940
- return path29?.startsWith(ROUTED_PATH_PREFIX) === true;
3033
+ function servedByPipeline(path30) {
3034
+ return path30?.startsWith(ROUTED_PATH_PREFIX) === true;
2941
3035
  }
2942
3036
  var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
2943
3037
  "connection",
@@ -3461,13 +3555,18 @@ function createRcSessionTracker(deps) {
3461
3555
  entries.set(id, record);
3462
3556
  return record;
3463
3557
  };
3558
+ const persistCredential = (entry) => {
3559
+ if (entry.oauthAuthorization !== void 0) {
3560
+ deps.credentialStore?.write(entry.id, { authorization: entry.oauthAuthorization, anthropicVersion: entry.anthropicVersion, anthropicClientPlatform: entry.anthropicClientPlatform });
3561
+ }
3562
+ };
3464
3563
  const observeExchange = (request4) => {
3465
3564
  const method = (request4.method ?? "").toUpperCase();
3466
- const path29 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
3467
- if (!path29.startsWith(RC_SESSIONS_PATH_PREFIX)) {
3565
+ const path30 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
3566
+ if (!path30.startsWith(RC_SESSIONS_PATH_PREFIX)) {
3468
3567
  return void 0;
3469
3568
  }
3470
- const tail = path29.slice(RC_SESSIONS_PATH_PREFIX.length);
3569
+ const tail = path30.slice(RC_SESSIONS_PATH_PREFIX.length);
3471
3570
  const facts = {
3472
3571
  oauthAuthorization: oauthAuthorizationOf(request4.headers),
3473
3572
  anthropicVersion: singleHeader(request4.headers, "anthropic-version"),
@@ -3500,7 +3599,7 @@ function createRcSessionTracker(deps) {
3500
3599
  if (id2 === void 0) {
3501
3600
  return;
3502
3601
  }
3503
- birth(id2, facts);
3602
+ persistCredential(birth(id2, facts));
3504
3603
  }
3505
3604
  };
3506
3605
  }
@@ -3514,6 +3613,7 @@ function createRcSessionTracker(deps) {
3514
3613
  entry.oauthAuthorization = facts.oauthAuthorization ?? entry.oauthAuthorization;
3515
3614
  entry.anthropicVersion = facts.anthropicVersion ?? entry.anthropicVersion;
3516
3615
  entry.anthropicClientPlatform = facts.anthropicClientPlatform ?? entry.anthropicClientPlatform;
3616
+ persistCredential(entry);
3517
3617
  const bodyKind = method === "POST" && rest === `${id}/worker/events` ? "worker-events" : method === "POST" && rest === `${id}/events` ? "client-events" : method === "POST" && rest === `${id}/worker/heartbeat` ? "heartbeat" : method === "PUT" && rest === `${id}/worker` ? "worker-registration" : void 0;
3518
3618
  let chunks = [];
3519
3619
  let buffered = 0;
@@ -3567,6 +3667,7 @@ function createRcSessionTracker(deps) {
3567
3667
  },
3568
3668
  onResponse: (status, headers) => {
3569
3669
  if (singleHeader(headers, CONFLICT_REASON_HEADER) !== void 0 || archiving && isSuccessful(status)) {
3670
+ deps.credentialStore?.remove(id);
3570
3671
  expire(id);
3571
3672
  return;
3572
3673
  }
@@ -3599,7 +3700,18 @@ function createRcSessionTracker(deps) {
3599
3700
  },
3600
3701
  credentialOf: (sessionId) => {
3601
3702
  const entry = entries.get(sessionId);
3602
- return entry === void 0 ? void 0 : { authorization: entry.oauthAuthorization, anthropicVersion: entry.anthropicVersion, anthropicClientPlatform: entry.anthropicClientPlatform };
3703
+ if (entry === void 0) {
3704
+ return void 0;
3705
+ }
3706
+ if (entry.oauthAuthorization === void 0 && deps.credentialStore !== void 0) {
3707
+ const persisted = deps.credentialStore.read(sessionId);
3708
+ if (persisted?.authorization !== void 0) {
3709
+ entry.oauthAuthorization = persisted.authorization;
3710
+ entry.anthropicVersion = entry.anthropicVersion ?? persisted.anthropicVersion;
3711
+ entry.anthropicClientPlatform = entry.anthropicClientPlatform ?? persisted.anthropicClientPlatform;
3712
+ }
3713
+ }
3714
+ return { authorization: entry.oauthAuthorization, anthropicVersion: entry.anthropicVersion, anthropicClientPlatform: entry.anthropicClientPlatform };
3603
3715
  },
3604
3716
  noteSequenceNums: (sessionId, sequenceNums) => {
3605
3717
  const entry = entries.get(sessionId);
@@ -4215,9 +4327,9 @@ function sequenceNumsOfBody(body) {
4215
4327
  }
4216
4328
  function frontDoorRcControl(transport, token) {
4217
4329
  const headers = { authorization: `Bearer ${token}` };
4218
- const listAnswerOf = async (path29, what) => {
4330
+ const listAnswerOf = async (path30, what) => {
4219
4331
  try {
4220
- return await transport.request({ method: "GET", path: path29, headers });
4332
+ return await transport.request({ method: "GET", path: path30, headers });
4221
4333
  } catch (error) {
4222
4334
  throw new Error(`${what}: could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
4223
4335
  }
@@ -4289,10 +4401,10 @@ function frontDoorRcControl(transport, token) {
4289
4401
  }
4290
4402
  return pending;
4291
4403
  };
4292
- const writeOf = async (path29, body, describeFailure) => {
4404
+ const writeOf = async (path30, body, describeFailure) => {
4293
4405
  let answer;
4294
4406
  try {
4295
- answer = await transport.request({ method: "POST", path: path29, headers: { ...headers, "content-type": "application/json" }, body });
4407
+ answer = await transport.request({ method: "POST", path: path30, headers: { ...headers, "content-type": "application/json" }, body });
4296
4408
  } catch (error) {
4297
4409
  return { ok: false, message: `could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}` };
4298
4410
  }
@@ -4340,15 +4452,27 @@ var SUCCESS_STATUS_MAX_EXCLUSIVE2 = 300;
4340
4452
  function isSuccessful2(status) {
4341
4453
  return status >= HTTP_STATUS.ok && status < SUCCESS_STATUS_MAX_EXCLUSIVE2;
4342
4454
  }
4343
- var UPSTREAM_LOCAL_PORT_START = 47900;
4344
- var UPSTREAM_LOCAL_PORT_END = 47919;
4345
- var UPSTREAM_LOCAL_PORT_COUNT = UPSTREAM_LOCAL_PORT_END - UPSTREAM_LOCAL_PORT_START + 1;
4346
- var nextUpstreamLocalPort = UPSTREAM_LOCAL_PORT_START;
4347
- function upstreamLocalPort() {
4348
- const port = nextUpstreamLocalPort;
4349
- nextUpstreamLocalPort = nextUpstreamLocalPort === UPSTREAM_LOCAL_PORT_END ? UPSTREAM_LOCAL_PORT_START : nextUpstreamLocalPort + 1;
4350
- return port;
4351
- }
4455
+ var SourcePortRange = class {
4456
+ constructor(start, end) {
4457
+ this.start = start;
4458
+ this.end = end;
4459
+ this.count = end - start + 1;
4460
+ this.next = start;
4461
+ }
4462
+ start;
4463
+ end;
4464
+ count;
4465
+ next;
4466
+ /** The next port in rotation, wrapping from the end back to the start. */
4467
+ take() {
4468
+ const port = this.next;
4469
+ this.next = this.next === this.end ? this.start : this.next + 1;
4470
+ return port;
4471
+ }
4472
+ };
4473
+ var DOOR_SOURCE_PORT_START = 47900;
4474
+ var DOOR_SOURCE_PORT_END = 47919;
4475
+ var DOOR_SOURCE_PORTS = new SourcePortRange(DOOR_SOURCE_PORT_START, DOOR_SOURCE_PORT_END);
4352
4476
  var realAddressLookup = (host, _options, callback) => {
4353
4477
  if (net2.isIP(host) !== 0) {
4354
4478
  callback(null, [{ address: host, family: net2.isIP(host) }]);
@@ -4386,14 +4510,14 @@ function dialTarget(options, defaultPort) {
4386
4510
  function literalDial(target) {
4387
4511
  return net2.connect({ host: target.host, port: target.port });
4388
4512
  }
4389
- async function reservedDial(target) {
4513
+ async function reservedDial(target, ports) {
4390
4514
  for (let attempt = 0; ; attempt += 1) {
4391
- const outcome = await dialOnce({ host: target.host, port: target.port, localPort: upstreamLocalPort(), lookup: realAddressLookup });
4515
+ const outcome = await dialOnce({ host: target.host, port: target.port, localPort: ports.take(), lookup: realAddressLookup });
4392
4516
  if (outcome.error === null) {
4393
4517
  return outcome;
4394
4518
  }
4395
4519
  const held = outcome.error.code !== void 0 && HELD_PORT_ERRNOS.has(outcome.error.code);
4396
- if (!held || attempt === UPSTREAM_LOCAL_PORT_COUNT - 1) {
4520
+ if (!held || attempt === ports.count - 1) {
4397
4521
  return outcome;
4398
4522
  }
4399
4523
  }
@@ -4402,26 +4526,36 @@ function requestServername(options, fallback) {
4402
4526
  return "servername" in options && typeof options.servername === "string" && options.servername !== "" ? options.servername : fallback;
4403
4527
  }
4404
4528
  var ExemptHttpAgent = class extends http.Agent {
4529
+ constructor(ports = DOOR_SOURCE_PORTS) {
4530
+ super();
4531
+ this.ports = ports;
4532
+ }
4533
+ ports;
4405
4534
  // A reserved-port dial that has to retry cannot produce its socket synchronously, so it settles first and arrives through the callback (node's documented asynchronous createConnection form); a literal dial has nothing to retry and keeps node's own synchronous shape.
4406
4535
  createConnection(options, oncreate) {
4407
4536
  const target = dialTarget(options, HTTP_PORT);
4408
4537
  if (net2.isIP(target.host) !== 0) {
4409
4538
  return literalDial(target);
4410
4539
  }
4411
- void reservedDial(target).then((outcome) => {
4540
+ void reservedDial(target, this.ports).then((outcome) => {
4412
4541
  oncreate?.(outcome.error, outcome.socket);
4413
4542
  });
4414
4543
  return void 0;
4415
4544
  }
4416
4545
  };
4417
4546
  var ExemptTlsAgent = class extends https2.Agent {
4547
+ constructor(ports = DOOR_SOURCE_PORTS) {
4548
+ super();
4549
+ this.ports = ports;
4550
+ }
4551
+ ports;
4418
4552
  // The same split as the plain sibling: a literal dial wraps TLS around the socket node's own agent would have returned, a reserved dial settles (retries included) first and arrives through the callback, which is exactly where node's own agent wraps its own dials.
4419
4553
  createConnection(options, oncreate) {
4420
4554
  const target = dialTarget(options, HTTPS_PORT);
4421
4555
  if (net2.isIP(target.host) !== 0) {
4422
4556
  return tls.connect({ socket: literalDial(target), servername: requestServername(options, target.host), ...tlsFacts(options) });
4423
4557
  }
4424
- void reservedDial(target).then((outcome) => {
4558
+ void reservedDial(target, this.ports).then((outcome) => {
4425
4559
  if (outcome.error !== null) {
4426
4560
  oncreate?.(outcome.error, outcome.socket);
4427
4561
  return;
@@ -4482,12 +4616,12 @@ var NO_CHUNKS = {
4482
4616
  };
4483
4617
  function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
4484
4618
  const agent = new ExemptTlsAgent();
4485
- const request4 = async (method, path29, headers, body, signal) => await new Promise((resolve, reject) => {
4619
+ const request4 = async (method, path30, headers, body, signal) => await new Promise((resolve, reject) => {
4486
4620
  const options = {
4487
4621
  host: target.host,
4488
4622
  port: target.port,
4489
4623
  method,
4490
- path: path29,
4624
+ path: path30,
4491
4625
  // The Host header names the host whose API this is, not the address dialled: a redirected test dials a loopback stand-in while still speaking to the API host by name, exactly as the forwarded paths present their SNI.
4492
4626
  headers: { ...headers, host: target.servername ?? target.host, ...body === void 0 ? {} : { "content-length": String(Buffer.byteLength(body, "utf8")) } },
4493
4627
  agent,
@@ -4524,9 +4658,9 @@ function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_P
4524
4658
  return { status, body: await readAll(response) };
4525
4659
  },
4526
4660
  openStream: async (sessionId, headers, resume, signal) => {
4527
- const path29 = resume === void 0 ? `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream` : `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream?from_sequence_num=${String(resume.fromSequenceNum)}`;
4661
+ const path30 = resume === void 0 ? `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream` : `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream?from_sequence_num=${String(resume.fromSequenceNum)}`;
4528
4662
  const streamHeaders = resume === void 0 ? headers : { ...headers, "last-event-id": String(resume.fromSequenceNum) };
4529
- const { status, response } = await request4("GET", path29, streamHeaders, void 0, signal);
4663
+ const { status, response } = await request4("GET", path30, streamHeaders, void 0, signal);
4530
4664
  if (!isSuccessful2(status)) {
4531
4665
  await readAll(response);
4532
4666
  return { status, chunks: NO_CHUNKS };
@@ -4535,9 +4669,9 @@ function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_P
4535
4669
  }
4536
4670
  };
4537
4671
  }
4538
- function realConnectEffects() {
4539
- const plainAgent = new ExemptHttpAgent();
4540
- const tlsAgent = new ExemptTlsAgent();
4672
+ function realConnectEffects(ports = DOOR_SOURCE_PORTS) {
4673
+ const plainAgent = new ExemptHttpAgent(ports);
4674
+ const tlsAgent = new ExemptTlsAgent(ports);
4541
4675
  const listenOnce = async (port, onSocket) => await new Promise((resolve, reject) => {
4542
4676
  const accepted = /* @__PURE__ */ new Set();
4543
4677
  const server = net2.createServer((socket) => {
@@ -4655,7 +4789,7 @@ function realConnectEffects() {
4655
4789
  };
4656
4790
  },
4657
4791
  connectTlsUpstream: async (host, port, clientAlpn) => {
4658
- const dialled = await reservedDial({ host, port });
4792
+ const dialled = await reservedDial({ host, port }, ports);
4659
4793
  if (dialled.error !== null) {
4660
4794
  throw dialled.error;
4661
4795
  }
@@ -4737,6 +4871,64 @@ function realConnectEffects() {
4737
4871
  };
4738
4872
  }
4739
4873
 
4874
+ // src/frontdoor/rcCredentialStore.ts
4875
+ var import_node_path9 = __toESM(require("node:path"), 1);
4876
+ function isSafeSessionId(sessionId) {
4877
+ return /^[A-Za-z0-9_-]+$/.test(sessionId);
4878
+ }
4879
+ function isRecord3(value) {
4880
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4881
+ }
4882
+ function credentialOfJson(parsed) {
4883
+ if (!isRecord3(parsed)) {
4884
+ return void 0;
4885
+ }
4886
+ const { authorization, anthropicVersion, anthropicClientPlatform } = parsed;
4887
+ if (typeof authorization !== "string" || authorization === "") {
4888
+ return void 0;
4889
+ }
4890
+ return {
4891
+ authorization,
4892
+ anthropicVersion: typeof anthropicVersion === "string" ? anthropicVersion : void 0,
4893
+ anthropicClientPlatform: typeof anthropicClientPlatform === "string" ? anthropicClientPlatform : void 0
4894
+ };
4895
+ }
4896
+ function createRcCredentialStore(fs12, dir) {
4897
+ fs12.mkdirPrivate(dir);
4898
+ const fileFor = (sessionId) => import_node_path9.default.join(dir, `${sessionId}.json`);
4899
+ return {
4900
+ read: (sessionId) => {
4901
+ if (!isSafeSessionId(sessionId)) {
4902
+ return void 0;
4903
+ }
4904
+ const raw = fs12.readFileUtf8(fileFor(sessionId));
4905
+ if (raw === void 0) {
4906
+ return void 0;
4907
+ }
4908
+ let parsed;
4909
+ try {
4910
+ parsed = JSON.parse(raw);
4911
+ } catch {
4912
+ return void 0;
4913
+ }
4914
+ return credentialOfJson(parsed);
4915
+ },
4916
+ write: (sessionId, credential) => {
4917
+ if (!isSafeSessionId(sessionId)) {
4918
+ return;
4919
+ }
4920
+ fs12.writeFilePrivate(fileFor(sessionId), `${JSON.stringify(credential, null, 2)}
4921
+ `);
4922
+ },
4923
+ remove: (sessionId) => {
4924
+ if (!isSafeSessionId(sessionId)) {
4925
+ return;
4926
+ }
4927
+ fs12.removeRecursive(fileFor(sessionId));
4928
+ }
4929
+ };
4930
+ }
4931
+
4740
4932
  // src/frontdoor/rcApi.ts
4741
4933
  var import_client = require("@orpc/client");
4742
4934
  var import_fetch = require("@orpc/client/fetch");
@@ -4994,7 +5186,7 @@ function createSseParser() {
4994
5186
  }
4995
5187
  };
4996
5188
  }
4997
- function isRecord3(value) {
5189
+ function isRecord4(value) {
4998
5190
  return typeof value === "object" && value !== null && !Array.isArray(value);
4999
5191
  }
5000
5192
  function sequenceNumOf(value) {
@@ -5016,7 +5208,7 @@ function parseRcStreamEnvelope(parsed) {
5016
5208
  } catch {
5017
5209
  return void 0;
5018
5210
  }
5019
- if (!isRecord3(data)) {
5211
+ if (!isRecord4(data)) {
5020
5212
  return void 0;
5021
5213
  }
5022
5214
  const eventType = data.event_type;
@@ -5105,6 +5297,7 @@ function createRcStreamHub(deps) {
5105
5297
  if (!isSuccessful3(answer.status)) {
5106
5298
  throw new Error(`the client read stream answered HTTP ${String(answer.status)}`);
5107
5299
  }
5300
+ deps.log?.(`rc stream ${attachment.sessionId}: attached as client ${attachment.clientId}${resume === void 0 ? ", reading from the stream's own head" : `, resuming after sequence number ${String(resume.fromSequenceNum)}`}`);
5108
5301
  const parser = createSseParser();
5109
5302
  for await (const chunk of answer.chunks) {
5110
5303
  attachment.controller.signal.throwIfAborted();
@@ -5128,6 +5321,7 @@ function createRcStreamHub(deps) {
5128
5321
  const live = deps.trackedSessions().includes(attachment.sessionId);
5129
5322
  const credential = deps.credentialOf(attachment.sessionId);
5130
5323
  if (!live || credential?.authorization === void 0) {
5324
+ deps.log?.(`rc stream ${attachment.sessionId}: the attachment ended (${live ? "the session's client credential is no longer known" : "the tracker gave up on the session"})`);
5131
5325
  if (attachments.get(attachment.sessionId) === attachment) {
5132
5326
  attachments.delete(attachment.sessionId);
5133
5327
  }
@@ -5149,6 +5343,7 @@ function createRcStreamHub(deps) {
5149
5343
  return;
5150
5344
  }
5151
5345
  if (outcome === "dropped") {
5346
+ deps.log?.(`rc stream ${attachment.sessionId}: the stream ended of its own accord, reconnecting`);
5152
5347
  retriedUnauthorized = false;
5153
5348
  continue;
5154
5349
  }
@@ -5198,7 +5393,7 @@ var import_node_crypto7 = require("node:crypto");
5198
5393
 
5199
5394
  // src/headroom/state.ts
5200
5395
  var import_node_crypto6 = require("node:crypto");
5201
- var import_node_path8 = __toESM(require("node:path"), 1);
5396
+ var import_node_path10 = __toESM(require("node:path"), 1);
5202
5397
  var import_zod5 = require("zod");
5203
5398
  var HEADROOM_ANTHROPIC_UPSTREAM = "https://api.anthropic.com";
5204
5399
  var HEADROOM_STATE_SCHEMA_VERSION = 2;
@@ -5239,7 +5434,7 @@ function readHeadroomState(fs12, stateFile) {
5239
5434
  }
5240
5435
  }
5241
5436
  function writeHeadroomState(fs12, stateFile, state) {
5242
- fs12.mkdirp(import_node_path8.default.dirname(stateFile));
5437
+ fs12.mkdirp(import_node_path10.default.dirname(stateFile));
5243
5438
  fs12.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
5244
5439
  `);
5245
5440
  }
@@ -5267,7 +5462,7 @@ function readAllProviders(fs12, providersDir) {
5267
5462
  continue;
5268
5463
  }
5269
5464
  try {
5270
- const parsed = parseJson(fs12.readFileUtf8(import_node_path8.default.join(providersDir, name)), ProviderSchema);
5465
+ const parsed = parseJson(fs12.readFileUtf8(import_node_path10.default.join(providersDir, name)), ProviderSchema);
5271
5466
  if (parsed !== void 0) {
5272
5467
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
5273
5468
  }
@@ -5279,11 +5474,11 @@ function readAllProviders(fs12, providersDir) {
5279
5474
  }
5280
5475
  function writeSession(fs12, sessionsDir, session) {
5281
5476
  fs12.mkdirp(sessionsDir);
5282
- fs12.writeFileUtf8(import_node_path8.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
5477
+ fs12.writeFileUtf8(import_node_path10.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
5283
5478
  `);
5284
5479
  }
5285
5480
  function removeSession(fs12, sessionsDir, pid) {
5286
- fs12.removeRecursive(import_node_path8.default.join(sessionsDir, `${String(pid)}.json`));
5481
+ fs12.removeRecursive(import_node_path10.default.join(sessionsDir, `${String(pid)}.json`));
5287
5482
  }
5288
5483
  function listSessions(fs12, sessionsDir) {
5289
5484
  const sessions = [];
@@ -5292,7 +5487,7 @@ function listSessions(fs12, sessionsDir) {
5292
5487
  continue;
5293
5488
  }
5294
5489
  try {
5295
- const parsed = parseJson(fs12.readFileUtf8(import_node_path8.default.join(sessionsDir, name)), HeadroomSessionSchema);
5490
+ const parsed = parseJson(fs12.readFileUtf8(import_node_path10.default.join(sessionsDir, name)), HeadroomSessionSchema);
5296
5491
  if (parsed !== void 0) {
5297
5492
  sessions.push(parsed);
5298
5493
  }
@@ -5397,10 +5592,10 @@ function ensureFrontDoor(params) {
5397
5592
  }
5398
5593
 
5399
5594
  // src/usage/read.ts
5400
- var import_node_path10 = __toESM(require("node:path"), 1);
5595
+ var import_node_path12 = __toESM(require("node:path"), 1);
5401
5596
 
5402
5597
  // src/usage/account.ts
5403
- var import_node_path9 = __toESM(require("node:path"), 1);
5598
+ var import_node_path11 = __toESM(require("node:path"), 1);
5404
5599
 
5405
5600
  // src/usage/schema.ts
5406
5601
  var import_zod6 = require("zod");
@@ -5566,7 +5761,7 @@ function isIdentityName(name) {
5566
5761
  return IdentitySchema.shape.name.safeParse(name).success;
5567
5762
  }
5568
5763
  function claudeJsonPath(identitiesDir, identity) {
5569
- return import_node_path9.default.join(identitiesDir, identity, CLAUDE_JSON);
5764
+ return import_node_path11.default.join(identitiesDir, identity, CLAUDE_JSON);
5570
5765
  }
5571
5766
  function readAccountMetadata(fs12, identitiesDir, identity) {
5572
5767
  if (!isIdentityName(identity)) {
@@ -5625,7 +5820,7 @@ function readUsageLog(fs12, logDir, options = {}) {
5625
5820
  if (sinceMs !== void 0 && segment.endsAt <= sinceMs) {
5626
5821
  continue;
5627
5822
  }
5628
- const contents = fs12.readFileUtf8(import_node_path10.default.join(logDir, segment.name));
5823
+ const contents = fs12.readFileUtf8(import_node_path12.default.join(logDir, segment.name));
5629
5824
  if (contents === void 0) {
5630
5825
  continue;
5631
5826
  }
@@ -5667,7 +5862,7 @@ function snapshotPath(snapshotsDir, identity) {
5667
5862
  if (!isIdentityName(identity)) {
5668
5863
  throw new Error(`"${identity}" is not a valid identity name.`);
5669
5864
  }
5670
- return import_node_path10.default.join(snapshotsDir, `${identity}.json`);
5865
+ return import_node_path12.default.join(snapshotsDir, `${identity}.json`);
5671
5866
  }
5672
5867
  function readUsageSnapshot(fs12, snapshotsDir, identity) {
5673
5868
  const file = snapshotPath(snapshotsDir, identity);
@@ -6001,7 +6196,7 @@ function rankPool(input) {
6001
6196
  }
6002
6197
 
6003
6198
  // src/usage/poolPick.ts
6004
- var import_node_path11 = __toESM(require("node:path"), 1);
6199
+ var import_node_path13 = __toESM(require("node:path"), 1);
6005
6200
  var import_zod9 = require("zod");
6006
6201
 
6007
6202
  // src/usage/store.ts
@@ -6068,13 +6263,13 @@ function recordStickyPick(fs12, picksFile, directory, identity, nowMs) {
6068
6263
  const current = readPicksFile(fs12, picksFile).file.picks;
6069
6264
  const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
6070
6265
  const next = { schemaVersion: SCHEMA_VERSION, picks: { ...Object.fromEntries(kept), [directory]: { identity, at: new Date(nowMs).toISOString() } } };
6071
- fs12.mkdirPrivate(import_node_path11.default.dirname(picksFile));
6266
+ fs12.mkdirPrivate(import_node_path13.default.dirname(picksFile));
6072
6267
  fs12.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
6073
6268
  `);
6074
6269
  }
6075
6270
 
6076
6271
  // src/launcher/identity.ts
6077
- var import_node_path12 = __toESM(require("node:path"), 1);
6272
+ var import_node_path14 = __toESM(require("node:path"), 1);
6078
6273
  function poolNameOf(selector) {
6079
6274
  return selector.startsWith(POOL_SELECTOR_PREFIX) ? selector.slice(POOL_SELECTOR_PREFIX.length) : void 0;
6080
6275
  }
@@ -6123,7 +6318,7 @@ function decideConfigProfile(params) {
6123
6318
  return { source: "none" };
6124
6319
  }
6125
6320
  function loadIdentity(identitiesDir, name, fs12) {
6126
- return loadConfigFile(import_node_path12.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
6321
+ return loadConfigFile(import_node_path14.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
6127
6322
  }
6128
6323
 
6129
6324
  // src/launcher/pool.ts
@@ -6338,7 +6533,7 @@ function hashSettings(settings) {
6338
6533
  }
6339
6534
 
6340
6535
  // src/headroom/socket.ts
6341
- var import_node_path13 = __toESM(require("node:path"), 1);
6536
+ var import_node_path15 = __toESM(require("node:path"), 1);
6342
6537
  var GROUP_OR_OTHER_BITS = 63;
6343
6538
  var OCTAL_RADIX = 8;
6344
6539
  var MODE_DIGITS = 4;
@@ -6347,7 +6542,7 @@ var HEADROOM_SOCKET_NAME = /^(\d+)\.sock$/;
6347
6542
  var UNIX_SOCKET_PATH_MAX_BYTES = 103;
6348
6543
  var PLATFORMS_WITHOUT_UNIX_SOCKETS = ["win32"];
6349
6544
  function headroomSocketPath(paths, supervisorPid) {
6350
- return import_node_path13.default.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
6545
+ return import_node_path15.default.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
6351
6546
  }
6352
6547
  function platformRefusal(platform) {
6353
6548
  return PLATFORMS_WITHOUT_UNIX_SOCKETS.includes(platform) ? `headroom routing needs a unix domain socket, which headroom cannot serve on ${platform}; agent-shim never falls back to a TCP port for this hop` : void 0;
@@ -6396,7 +6591,7 @@ function pruneStaleHeadroomSockets(fs12, paths, isRunning) {
6396
6591
  if (pid === void 0 || isRunning(Number.parseInt(pid, 10))) {
6397
6592
  continue;
6398
6593
  }
6399
- fs12.removeRecursive(import_node_path13.default.join(paths.headroomSocketDir, name));
6594
+ fs12.removeRecursive(import_node_path15.default.join(paths.headroomSocketDir, name));
6400
6595
  removed.push(name);
6401
6596
  }
6402
6597
  return removed;
@@ -6450,7 +6645,7 @@ function versionSatisfies(version, source) {
6450
6645
  if (installed === void 0 || wanted === void 0) {
6451
6646
  return true;
6452
6647
  }
6453
- const cmp = compareVersions(installed, wanted);
6648
+ const cmp = compareVersions2(installed, wanted);
6454
6649
  switch (specifier[0]) {
6455
6650
  case "==":
6456
6651
  return cmp === 0;
@@ -6465,7 +6660,7 @@ function versionSatisfies(version, source) {
6465
6660
  case "<":
6466
6661
  return cmp < 0;
6467
6662
  case "~=":
6468
- return compareVersions(installed.slice(0, Math.max(0, wanted.length - 1)), wanted.slice(0, Math.max(0, wanted.length - 1))) === 0 && cmp >= 0;
6663
+ return compareVersions2(installed.slice(0, Math.max(0, wanted.length - 1)), wanted.slice(0, Math.max(0, wanted.length - 1))) === 0 && cmp >= 0;
6469
6664
  default:
6470
6665
  return true;
6471
6666
  }
@@ -6477,7 +6672,7 @@ function parseVersion(input) {
6477
6672
  }
6478
6673
  return match[0].split(".").map((part) => Number.parseInt(part, 10));
6479
6674
  }
6480
- function compareVersions(a, b) {
6675
+ function compareVersions2(a, b) {
6481
6676
  for (let index = 0; index < Math.max(a.length, b.length); index += 1) {
6482
6677
  const left = a[index] ?? 0;
6483
6678
  const right = b[index] ?? 0;
@@ -6719,15 +6914,15 @@ function evaluateAmbientCredentialGuard(params) {
6719
6914
 
6720
6915
  // src/paths.ts
6721
6916
  var import_node_fs2 = __toESM(require("node:fs"), 1);
6722
- var import_node_os = __toESM(require("node:os"), 1);
6723
- var import_node_path14 = __toESM(require("node:path"), 1);
6724
- function resolveAgentShimHome(env = process.env, home = import_node_os.default.homedir(), isDirectory = isExistingDirectory) {
6917
+ var import_node_os2 = __toESM(require("node:os"), 1);
6918
+ var import_node_path16 = __toESM(require("node:path"), 1);
6919
+ function resolveAgentShimHome(env = process.env, home = import_node_os2.default.homedir(), isDirectory = isExistingDirectory) {
6725
6920
  const fromEnv = env.AGENT_SHIM_HOME;
6726
6921
  if (fromEnv !== void 0 && fromEnv !== "") {
6727
6922
  return fromEnv;
6728
6923
  }
6729
- const current = import_node_path14.default.join(home, HOME_DIRNAME);
6730
- const legacy = import_node_path14.default.join(home, LEGACY_HOME_DIRNAME);
6924
+ const current = import_node_path16.default.join(home, HOME_DIRNAME);
6925
+ const legacy = import_node_path16.default.join(home, LEGACY_HOME_DIRNAME);
6731
6926
  return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
6732
6927
  }
6733
6928
  function isExistingDirectory(candidate) {
@@ -6738,40 +6933,41 @@ function resolveClaudeHome() {
6738
6933
  if (fromEnv !== void 0 && fromEnv !== "") {
6739
6934
  return fromEnv;
6740
6935
  }
6741
- return import_node_path14.default.join(import_node_os.default.homedir(), ".claude");
6936
+ return import_node_path16.default.join(import_node_os2.default.homedir(), ".claude");
6742
6937
  }
6743
6938
  function buildLayoutPaths(root) {
6744
6939
  return {
6745
6940
  root,
6746
- identitiesDir: import_node_path14.default.join(root, "identities"),
6747
- configProfilesDir: import_node_path14.default.join(root, "config-profiles"),
6748
- providersDir: import_node_path14.default.join(root, "providers"),
6749
- directoryRulesFile: import_node_path14.default.join(root, "directory-rules.json"),
6750
- activeIdentityFile: import_node_path14.default.join(root, "active-identity"),
6751
- globalConfigFile: import_node_path14.default.join(root, "config.json"),
6752
- categoriesLocalFile: import_node_path14.default.join(root, "categories.local.json"),
6753
- claudeShimFile: import_node_path14.default.join(root, "claude-shim.json"),
6754
- headroomDir: import_node_path14.default.join(root, "headroom"),
6755
- headroomStateFile: import_node_path14.default.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
6756
- headroomSocketDir: import_node_path14.default.join(root, "headroom", "run"),
6757
- headroomLockFile: import_node_path14.default.join(root, "headroom", "start.lock"),
6758
- headroomSessionsDir: import_node_path14.default.join(root, "headroom", "sessions"),
6759
- logsDir: import_node_path14.default.join(root, "logs"),
6760
- headroomLogPath: import_node_path14.default.join(root, "logs", "headroom.log"),
6761
- frontdoorDir: import_node_path14.default.join(root, "frontdoor"),
6762
- frontdoorCaDir: import_node_path14.default.join(root, "frontdoor", "ca"),
6763
- frontdoorCaCertFile: import_node_path14.default.join(root, "frontdoor", "ca", "ca.pem"),
6764
- frontdoorCaKeyFile: import_node_path14.default.join(root, "frontdoor", "ca", "ca.key"),
6765
- frontdoorCaBundlesDir: import_node_path14.default.join(root, "frontdoor", "ca", "bundles"),
6766
- frontdoorStateFile: import_node_path14.default.join(root, "frontdoor", "state.json"),
6767
- frontdoorLockFile: import_node_path14.default.join(root, "frontdoor", "start.lock"),
6768
- frontdoorControlTokenFile: import_node_path14.default.join(root, "frontdoor", "control-token"),
6769
- frontdoorSessionsDir: import_node_path14.default.join(root, "frontdoor", "sessions"),
6770
- frontdoorLogPath: import_node_path14.default.join(root, "logs", "frontdoor.log"),
6771
- usageDir: import_node_path14.default.join(root, "usage"),
6772
- usageLogDir: import_node_path14.default.join(root, "usage", "log"),
6773
- usageSnapshotsDir: import_node_path14.default.join(root, "usage", "snapshots"),
6774
- usagePicksFile: import_node_path14.default.join(root, "usage", "picks.json")
6941
+ identitiesDir: import_node_path16.default.join(root, "identities"),
6942
+ configProfilesDir: import_node_path16.default.join(root, "config-profiles"),
6943
+ providersDir: import_node_path16.default.join(root, "providers"),
6944
+ directoryRulesFile: import_node_path16.default.join(root, "directory-rules.json"),
6945
+ activeIdentityFile: import_node_path16.default.join(root, "active-identity"),
6946
+ globalConfigFile: import_node_path16.default.join(root, "config.json"),
6947
+ categoriesLocalFile: import_node_path16.default.join(root, "categories.local.json"),
6948
+ claudeShimFile: import_node_path16.default.join(root, "claude-shim.json"),
6949
+ headroomDir: import_node_path16.default.join(root, "headroom"),
6950
+ headroomStateFile: import_node_path16.default.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
6951
+ headroomSocketDir: import_node_path16.default.join(root, "headroom", "run"),
6952
+ headroomLockFile: import_node_path16.default.join(root, "headroom", "start.lock"),
6953
+ headroomSessionsDir: import_node_path16.default.join(root, "headroom", "sessions"),
6954
+ logsDir: import_node_path16.default.join(root, "logs"),
6955
+ headroomLogPath: import_node_path16.default.join(root, "logs", "headroom.log"),
6956
+ frontdoorDir: import_node_path16.default.join(root, "frontdoor"),
6957
+ frontdoorCaDir: import_node_path16.default.join(root, "frontdoor", "ca"),
6958
+ frontdoorCaCertFile: import_node_path16.default.join(root, "frontdoor", "ca", "ca.pem"),
6959
+ frontdoorCaKeyFile: import_node_path16.default.join(root, "frontdoor", "ca", "ca.key"),
6960
+ frontdoorCaBundlesDir: import_node_path16.default.join(root, "frontdoor", "ca", "bundles"),
6961
+ frontdoorStateFile: import_node_path16.default.join(root, "frontdoor", "state.json"),
6962
+ frontdoorLockFile: import_node_path16.default.join(root, "frontdoor", "start.lock"),
6963
+ frontdoorControlTokenFile: import_node_path16.default.join(root, "frontdoor", "control-token"),
6964
+ frontdoorSessionsDir: import_node_path16.default.join(root, "frontdoor", "sessions"),
6965
+ frontdoorRcCredentialsDir: import_node_path16.default.join(root, "frontdoor", "rc-credentials"),
6966
+ frontdoorLogPath: import_node_path16.default.join(root, "logs", "frontdoor.log"),
6967
+ usageDir: import_node_path16.default.join(root, "usage"),
6968
+ usageLogDir: import_node_path16.default.join(root, "usage", "log"),
6969
+ usageSnapshotsDir: import_node_path16.default.join(root, "usage", "snapshots"),
6970
+ usagePicksFile: import_node_path16.default.join(root, "usage", "picks.json")
6775
6971
  };
6776
6972
  }
6777
6973
  function resolveLayoutPaths() {
@@ -6780,11 +6976,11 @@ function resolveLayoutPaths() {
6780
6976
 
6781
6977
  // src/identityStore.ts
6782
6978
  var import_node_fs4 = __toESM(require("node:fs"), 1);
6783
- var import_node_path16 = __toESM(require("node:path"), 1);
6979
+ var import_node_path18 = __toESM(require("node:path"), 1);
6784
6980
 
6785
6981
  // src/configProfilesStore.ts
6786
6982
  var import_node_fs3 = __toESM(require("node:fs"), 1);
6787
- var import_node_path15 = __toESM(require("node:path"), 1);
6983
+ var import_node_path17 = __toESM(require("node:path"), 1);
6788
6984
  var ProfileNotFoundError = class extends CliError {
6789
6985
  constructor(profileName) {
6790
6986
  super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
@@ -6810,7 +7006,7 @@ var InvalidCategoryNameError = class extends CliError {
6810
7006
  categoryName;
6811
7007
  };
6812
7008
  function profileJsonPath(paths, name) {
6813
- return import_node_path15.default.join(paths.configProfilesDir, `${name}.json`);
7009
+ return import_node_path17.default.join(paths.configProfilesDir, `${name}.json`);
6814
7010
  }
6815
7011
  function profileExists(paths, name) {
6816
7012
  return import_node_fs3.default.existsSync(profileJsonPath(paths, name));
@@ -6998,7 +7194,7 @@ var InvalidIdentityNameError = class extends CliError {
6998
7194
  attemptedName;
6999
7195
  };
7000
7196
  function identityJsonPath(paths, name) {
7001
- return import_node_path16.default.join(paths.identitiesDir, name, "identity.json");
7197
+ return import_node_path18.default.join(paths.identitiesDir, name, "identity.json");
7002
7198
  }
7003
7199
  function identityExists(paths, name) {
7004
7200
  return import_node_fs4.default.existsSync(identityJsonPath(paths, name));
@@ -7099,7 +7295,7 @@ function setIdentityCredential(paths, identityName, change) {
7099
7295
  });
7100
7296
  }
7101
7297
  function belongsToIdentity(entry, name) {
7102
- return entry === name || entry === import_node_path16.default.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
7298
+ return entry === name || entry === import_node_path18.default.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
7103
7299
  }
7104
7300
  function removeIdentity(paths, name) {
7105
7301
  if (!identityExists(paths, name)) {
@@ -7107,7 +7303,7 @@ function removeIdentity(paths, name) {
7107
7303
  }
7108
7304
  for (const entry of import_node_fs4.default.readdirSync(paths.identitiesDir)) {
7109
7305
  if (belongsToIdentity(entry, name)) {
7110
- import_node_fs4.default.rmSync(import_node_path16.default.join(paths.identitiesDir, entry), { recursive: true, force: true });
7306
+ import_node_fs4.default.rmSync(import_node_path18.default.join(paths.identitiesDir, entry), { recursive: true, force: true });
7111
7307
  }
7112
7308
  }
7113
7309
  if (readActiveIdentity(paths) === name) {
@@ -7117,7 +7313,7 @@ function removeIdentity(paths, name) {
7117
7313
 
7118
7314
  // src/providersStore.ts
7119
7315
  var import_node_fs5 = __toESM(require("node:fs"), 1);
7120
- var import_node_path17 = __toESM(require("node:path"), 1);
7316
+ var import_node_path19 = __toESM(require("node:path"), 1);
7121
7317
 
7122
7318
  // src/credentialCache.ts
7123
7319
  var import_zod12 = require("zod");
@@ -7382,7 +7578,7 @@ var InvalidProviderNameError = class extends CliError {
7382
7578
  };
7383
7579
  var PROVIDER_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._@-]*$/;
7384
7580
  function providerJsonPath(paths, name) {
7385
- return import_node_path17.default.join(paths.providersDir, `${name}.json`);
7581
+ return import_node_path19.default.join(paths.providersDir, `${name}.json`);
7386
7582
  }
7387
7583
  function providerExists(paths, name) {
7388
7584
  return import_node_fs5.default.existsSync(providerJsonPath(paths, name));
@@ -7390,14 +7586,14 @@ function providerExists(paths, name) {
7390
7586
  var LEGACY_PROVIDER_FIELDS = ["tokenEnv", "tokenCommand", "authScheme"];
7391
7587
  var LEGACY_ENV_CREDENTIAL_KEYS = Object.values(CREDENTIAL_TARGET_VARS);
7392
7588
  var LEGACY_LITERAL_PLACEHOLDER = "<the value of env.ANTHROPIC_AUTH_TOKEN>";
7393
- function isRecord4(value) {
7589
+ function isRecord5(value) {
7394
7590
  return typeof value === "object" && value !== null && !Array.isArray(value);
7395
7591
  }
7396
7592
  function legacyProviderConversion(raw) {
7397
- if (!isRecord4(raw) || "credential" in raw) {
7593
+ if (!isRecord5(raw) || "credential" in raw) {
7398
7594
  return void 0;
7399
7595
  }
7400
- const env = isRecord4(raw.env) ? raw.env : void 0;
7596
+ const env = isRecord5(raw.env) ? raw.env : void 0;
7401
7597
  const legacyEnvKeys = env === void 0 ? [] : Object.keys(env).filter((key) => LEGACY_ENV_CREDENTIAL_KEYS.includes(key));
7402
7598
  const fields = [...LEGACY_PROVIDER_FIELDS.filter((field) => field in raw), ...legacyEnvKeys.map((key) => `env.${key}`)];
7403
7599
  if (fields.length === 0) {
@@ -7458,7 +7654,7 @@ function readProvider(paths, name) {
7458
7654
  return parseProviderFile(filePath, raw);
7459
7655
  }
7460
7656
  function loadProvider(providersDir, name, port) {
7461
- const filePath = import_node_path17.default.join(providersDir, `${name}.json`);
7657
+ const filePath = import_node_path19.default.join(providersDir, `${name}.json`);
7462
7658
  const raw = port.readConfigFile(filePath);
7463
7659
  return raw === void 0 ? void 0 : parseProviderFile(filePath, raw);
7464
7660
  }
@@ -7713,21 +7909,21 @@ function removeDirectoryRule(paths, rulePath) {
7713
7909
  var import_node_os4 = __toESM(require("node:os"), 1);
7714
7910
 
7715
7911
  // src/launcher/cascade.ts
7716
- var import_node_path19 = __toESM(require("node:path"), 1);
7912
+ var import_node_path21 = __toESM(require("node:path"), 1);
7717
7913
 
7718
7914
  // src/pathNorm.ts
7719
- var import_node_path18 = __toESM(require("node:path"), 1);
7915
+ var import_node_path20 = __toESM(require("node:path"), 1);
7720
7916
  function expandTilde(value, home) {
7721
7917
  if (value === "~") {
7722
7918
  return home;
7723
7919
  }
7724
7920
  if (value.startsWith("~/")) {
7725
- return import_node_path18.default.join(home, value.slice(2));
7921
+ return import_node_path20.default.join(home, value.slice(2));
7726
7922
  }
7727
7923
  return value;
7728
7924
  }
7729
7925
  function normaliseRulePath(rulePath, home) {
7730
- return import_node_path18.default.resolve(expandTilde(rulePath, home));
7926
+ return import_node_path20.default.resolve(expandTilde(rulePath, home));
7731
7927
  }
7732
7928
 
7733
7929
  // src/launcher/cascade.ts
@@ -7737,7 +7933,7 @@ function loadCascadeInput(params) {
7737
7933
  const globalConfig = loadConfigFile(params.paths.globalConfigFile, GlobalConfigSchema, params.read);
7738
7934
  const directoryRules = loadConfigFile(params.paths.directoryRulesFile, DirectoryRulesSchema, params.read);
7739
7935
  const loadProfile = (name) => {
7740
- const filepath = import_node_path19.default.join(params.paths.configProfilesDir, `${name}.json`);
7936
+ const filepath = import_node_path21.default.join(params.paths.configProfilesDir, `${name}.json`);
7741
7937
  const loaded = loadConfigFile(filepath, ConfigProfileSchema, params.read);
7742
7938
  if (loaded === void 0) {
7743
7939
  return void 0;
@@ -7752,8 +7948,8 @@ function loadCascadeInput(params) {
7752
7948
  });
7753
7949
  const levels = [];
7754
7950
  for (const dir of dirs) {
7755
- const portable = loadConfigFile(import_node_path19.default.join(dir, PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path19.default.join(dir, LEGACY_PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read);
7756
- const portableLocal = loadConfigFile(import_node_path19.default.join(dir, PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path19.default.join(dir, LEGACY_PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read);
7951
+ const portable = loadConfigFile(import_node_path21.default.join(dir, PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path21.default.join(dir, LEGACY_PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read);
7952
+ const portableLocal = loadConfigFile(import_node_path21.default.join(dir, PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path21.default.join(dir, LEGACY_PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read);
7757
7953
  const rules = (directoryRules?.config.rules ?? []).map((rule, index) => ({ rule, index })).filter(({ rule }) => normaliseRulePath(rule.path, params.home) === dir).map(({ rule, index }) => {
7758
7954
  const entryOrder = directoryRules?.ruleEntryOrders[index];
7759
7955
  return {
@@ -7804,7 +8000,7 @@ function readDirectorySelections(loaded) {
7804
8000
  // src/realCredentialCache.ts
7805
8001
  var import_node_child_process = require("node:child_process");
7806
8002
  var import_node_fs6 = __toESM(require("node:fs"), 1);
7807
- var import_node_path20 = __toESM(require("node:path"), 1);
8003
+ var import_node_path22 = __toESM(require("node:path"), 1);
7808
8004
  var KEYCHAIN_CACHE_SERVICE = "agent-shim-credential-cache";
7809
8005
  var CACHE_DIR_MODE = 448;
7810
8006
  var CACHE_FILE_MODE = 384;
@@ -7831,8 +8027,8 @@ function security(args, stdin) {
7831
8027
  return { status: result.status, stdout: result.stdout };
7832
8028
  }
7833
8029
  function createRealCredentialCache(root) {
7834
- const dir = import_node_path20.default.join(root, "credential-cache");
7835
- const filePath = (owner) => import_node_path20.default.join(dir, cacheFileNameFor(owner));
8030
+ const dir = import_node_path22.default.join(root, "credential-cache");
8031
+ const filePath = (owner) => import_node_path22.default.join(dir, cacheFileNameFor(owner));
7836
8032
  return {
7837
8033
  read(store, owner) {
7838
8034
  if (store === "file") {
@@ -7884,72 +8080,8 @@ var import_node_child_process2 = require("node:child_process");
7884
8080
  var import_node_crypto9 = require("node:crypto");
7885
8081
  var import_node_fs7 = __toESM(require("node:fs"), 1);
7886
8082
  var import_node_os3 = __toESM(require("node:os"), 1);
7887
- var import_node_path22 = __toESM(require("node:path"), 1);
8083
+ var import_node_path23 = __toESM(require("node:path"), 1);
7888
8084
  var import_node_sea = require("node:sea");
7889
-
7890
- // src/versionDiscovery.ts
7891
- var import_node_os2 = __toESM(require("node:os"), 1);
7892
- var import_node_path21 = __toESM(require("node:path"), 1);
7893
- function defaultVersionsDir() {
7894
- return import_node_path21.default.join(import_node_os2.default.homedir(), ".local", "share", "claude", "versions");
7895
- }
7896
- var NUMERIC_DOTTED_VERSION_RE = /^\d+(?:\.\d+)*$/;
7897
- function isNumericDottedVersion(name) {
7898
- return NUMERIC_DOTTED_VERSION_RE.test(name);
7899
- }
7900
- function compareVersions2(a, b) {
7901
- if (!isNumericDottedVersion(a)) {
7902
- throw new Error(`compareVersions: "${a}" is not a valid plain dotted-numeric version`);
7903
- }
7904
- if (!isNumericDottedVersion(b)) {
7905
- throw new Error(`compareVersions: "${b}" is not a valid plain dotted-numeric version`);
7906
- }
7907
- const segmentsA = a.split(".").map(Number);
7908
- const segmentsB = b.split(".").map(Number);
7909
- const length = Math.max(segmentsA.length, segmentsB.length);
7910
- for (let i = 0; i < length; i += 1) {
7911
- const segmentA = segmentsA[i] ?? 0;
7912
- const segmentB = segmentsB[i] ?? 0;
7913
- if (segmentA !== segmentB) {
7914
- return segmentA - segmentB;
7915
- }
7916
- }
7917
- return 0;
7918
- }
7919
- function pickHighestVersion(entries) {
7920
- const candidates = entries.filter(
7921
- (entry) => entry.isFile && entry.isExecutable && entry.sizeBytes > 0 && isNumericDottedVersion(entry.name)
7922
- );
7923
- if (candidates.length === 0) {
7924
- return void 0;
7925
- }
7926
- return candidates.reduce(
7927
- (highest, candidate) => compareVersions2(candidate.name, highest.name) > 0 ? candidate : highest
7928
- ).name;
7929
- }
7930
- function discoverClaudeBinary(options) {
7931
- const versionsDir = options.versionsDir ?? defaultVersionsDir();
7932
- const entries = options.listVersionsDir(versionsDir);
7933
- const highestVersion = pickHighestVersion(entries);
7934
- if (highestVersion !== void 0) {
7935
- return {
7936
- path: import_node_path21.default.join(versionsDir, highestVersion),
7937
- source: "versions-dir",
7938
- version: highestVersion
7939
- };
7940
- }
7941
- for (const dir of options.pathDirs) {
7942
- const found = options.findExecutableInDir(dir, "claude");
7943
- if (found !== void 0 && !options.isOwnBinary(found)) {
7944
- return { path: found, source: "path-fallback" };
7945
- }
7946
- }
7947
- throw new Error(
7948
- `Could not find a claude binary. Looked for genuinely-executable versioned binaries under "${versionsDir}" (missing, empty, or containing nothing executable) and for a "claude" executable on PATH (never this tool's own binary). Install Claude Code, or set the versions directory / PATH correctly, then try again.`
7949
- );
7950
- }
7951
-
7952
- // src/realPorts.ts
7953
8085
  function isEnoent3(error) {
7954
8086
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
7955
8087
  }
@@ -8107,7 +8239,7 @@ var realRunPort = {
8107
8239
  }
8108
8240
  };
8109
8241
  function expandHome2(filePath) {
8110
- return filePath.startsWith("~/") ? import_node_path22.default.join(import_node_os3.default.homedir(), filePath.slice(1)) : filePath;
8242
+ return filePath.startsWith("~/") ? import_node_path23.default.join(import_node_os3.default.homedir(), filePath.slice(1)) : filePath;
8111
8243
  }
8112
8244
  var MACOS_GUI_SESSION_MANAGER = "Aqua";
8113
8245
  function hasDesktopSession() {
@@ -8180,7 +8312,7 @@ function spawnDaemonThrough(executable) {
8180
8312
  return (paths, subcommand, logPath) => spawnDetachedDaemon({ command: executable, args: [subcommand] }, paths, subcommand, logPath);
8181
8313
  }
8182
8314
  function spawnDetachedDaemon(invocation, paths, subcommand, logPath) {
8183
- import_node_fs7.default.mkdirSync(import_node_path22.default.dirname(logPath), { recursive: true });
8315
+ import_node_fs7.default.mkdirSync(import_node_path23.default.dirname(logPath), { recursive: true });
8184
8316
  const logFd = import_node_fs7.default.openSync(logPath, "a");
8185
8317
  try {
8186
8318
  const child = (0, import_node_child_process2.spawn)(invocation.command, invocation.args, detachedDaemonSpawnOptions(logFd, { ...process.env, AGENT_SHIM_HOME: paths.root }));
@@ -8262,7 +8394,7 @@ function listVersionsDir(dir) {
8262
8394
  throw error;
8263
8395
  }
8264
8396
  return entries.filter((entry) => entry.isFile()).map((entry) => {
8265
- const fullPath = import_node_path22.default.join(dir, entry.name);
8397
+ const fullPath = import_node_path23.default.join(dir, entry.name);
8266
8398
  const stat = import_node_fs7.default.statSync(fullPath);
8267
8399
  return {
8268
8400
  name: entry.name,
@@ -8277,7 +8409,7 @@ function windowsPathExtensions(pathext) {
8277
8409
  return (pathext ?? WINDOWS_DEFAULT_PATHEXT).split(";").map((ext) => ext.trim()).filter((ext) => ext.length > 0);
8278
8410
  }
8279
8411
  function resolveExecutableCandidate(dir, name, env) {
8280
- const candidate = import_node_path22.default.join(dir, name);
8412
+ const candidate = import_node_path23.default.join(dir, name);
8281
8413
  if (env.platform === "win32") {
8282
8414
  const extensions = windowsPathExtensions(env.pathext);
8283
8415
  const alreadyHasRecognisedExtension = extensions.some((ext) => candidate.toLowerCase().endsWith(ext.toLowerCase()));
@@ -8326,13 +8458,13 @@ function resolveOwnExecutablePath(env) {
8326
8458
  if (env.argv1 !== void 0 && !env.argv1.includes("/") && !env.argv1.includes("\\")) {
8327
8459
  return searchPathForExecutable(env.pathDirs, env.argv1, env.findExecutableInDir) ?? env.execPath;
8328
8460
  }
8329
- const candidate = env.argv1 === void 0 ? env.execPath : import_node_path22.default.resolve(env.cwd, env.argv1);
8330
- const candidateDir = import_node_path22.default.dirname(candidate);
8331
- const candidateDirOnPath = env.pathDirs.some((dir) => import_node_path22.default.resolve(dir) === candidateDir);
8461
+ const candidate = env.argv1 === void 0 ? env.execPath : import_node_path23.default.resolve(env.cwd, env.argv1);
8462
+ const candidateDir = import_node_path23.default.dirname(candidate);
8463
+ const candidateDirOnPath = env.pathDirs.some((dir) => import_node_path23.default.resolve(dir) === candidateDir);
8332
8464
  if (candidateDirOnPath) {
8333
8465
  return candidate;
8334
8466
  }
8335
- const viaPath = searchPathForExecutable(env.pathDirs, import_node_path22.default.basename(candidate), env.findExecutableInDir);
8467
+ const viaPath = searchPathForExecutable(env.pathDirs, import_node_path23.default.basename(candidate), env.findExecutableInDir);
8336
8468
  return viaPath ?? candidate;
8337
8469
  }
8338
8470
  function realOwnExecutablePath() {
@@ -8340,7 +8472,7 @@ function realOwnExecutablePath() {
8340
8472
  argv1: process.argv[1],
8341
8473
  execPath: process.execPath,
8342
8474
  cwd: process.cwd(),
8343
- pathDirs: (process.env.PATH ?? "").split(import_node_path22.default.delimiter).filter((dir) => dir !== ""),
8475
+ pathDirs: (process.env.PATH ?? "").split(import_node_path23.default.delimiter).filter((dir) => dir !== ""),
8344
8476
  findExecutableInDir
8345
8477
  });
8346
8478
  }
@@ -8351,16 +8483,20 @@ function realContentSourcePath() {
8351
8483
  return resolveContentSourcePath({ isSea: (0, import_node_sea.isSea)(), execPath: process.execPath, argv1: process.argv[1] });
8352
8484
  }
8353
8485
  function realResolveClaudeBinary(isOwnBinary) {
8354
- return () => discoverClaudeBinary({
8486
+ return (request4) => discoverClaudeBinary({
8355
8487
  listVersionsDir,
8356
- pathDirs: (process.env.PATH ?? "").split(import_node_path22.default.delimiter).filter((dir) => dir !== ""),
8488
+ pathDirs: (process.env.PATH ?? "").split(import_node_path23.default.delimiter).filter((dir) => dir !== ""),
8357
8489
  findExecutableInDir,
8358
- isOwnBinary
8490
+ isOwnBinary,
8491
+ ...request4?.version === void 0 ? {} : { version: request4.version }
8359
8492
  });
8360
8493
  }
8494
+ function realInstalledClaudeVersions() {
8495
+ return installedVersions(listVersionsDir(defaultVersionsDir()));
8496
+ }
8361
8497
 
8362
8498
  // src/checkReport.ts
8363
- var import_node_path23 = __toESM(require("node:path"), 1);
8499
+ var import_node_path24 = __toESM(require("node:path"), 1);
8364
8500
  var import_zod13 = require("zod");
8365
8501
 
8366
8502
  // src/cli/bool.ts
@@ -8399,6 +8535,34 @@ function parseEnvBool(variable, value) {
8399
8535
  return parsed;
8400
8536
  }
8401
8537
 
8538
+ // src/launcher/claudeVersion.ts
8539
+ var InvalidClaudeVersionError = class extends UsageError {
8540
+ constructor(value, origin) {
8541
+ super(`${origin} names Claude Code version "${value}", which is not an exact dotted-numeric version such as 2.1.220.`);
8542
+ this.value = value;
8543
+ this.origin = origin;
8544
+ this.name = "InvalidClaudeVersionError";
8545
+ }
8546
+ value;
8547
+ origin;
8548
+ };
8549
+ function validated(value, origin) {
8550
+ if (!NUMERIC_DOTTED_VERSION_RE.test(value)) {
8551
+ throw new InvalidClaudeVersionError(value, origin);
8552
+ }
8553
+ return value;
8554
+ }
8555
+ function resolveClaudeVersion(params) {
8556
+ if (params.flag !== void 0) {
8557
+ return { version: validated(params.flag, "--claude-version"), source: "flag" };
8558
+ }
8559
+ const fromEnv = params.env.AGENT_SHIM_CLAUDE_VERSION;
8560
+ if (fromEnv !== void 0 && fromEnv !== "") {
8561
+ return { version: validated(fromEnv, "AGENT_SHIM_CLAUDE_VERSION"), source: "environment" };
8562
+ }
8563
+ return params.cascade === void 0 ? void 0 : { version: params.cascade, source: "cascade" };
8564
+ }
8565
+
8402
8566
  // src/checkReport.ts
8403
8567
  var HISTORY_PROJECTS_KEY_PREFIX = "history/projects/";
8404
8568
  function projectFragmentOf(rawKey) {
@@ -8549,6 +8713,19 @@ function buildCredentialReport(provider, identity, identityName, cacheEnv) {
8549
8713
  ...identityCached === void 0 ? {} : { identityCached }
8550
8714
  };
8551
8715
  }
8716
+ function buildClaudeVersionReport(params, cascadePin) {
8717
+ const installed = params.installedClaudeVersions;
8718
+ if (installed === void 0) {
8719
+ return void 0;
8720
+ }
8721
+ const pin = resolveClaudeVersion({ env: params.env, ...cascadePin === void 0 ? {} : { cascade: cascadePin } });
8722
+ const highestInstalled = installed.at(-1);
8723
+ return {
8724
+ ...pin === void 0 ? {} : { pinned: { ...pin, installed: installed.includes(pin.version) } },
8725
+ ...highestInstalled === void 0 ? {} : { highestInstalled },
8726
+ installed
8727
+ };
8728
+ }
8552
8729
  function runCheck(params) {
8553
8730
  const facts = buildEntryFacts({
8554
8731
  fs: params.farmFs,
@@ -8573,6 +8750,7 @@ function runCheck(params) {
8573
8750
  const settingsShared = resolved.flattened.categories.get("settings") ?? SHIPPED_CATEGORY_DEFAULTS.settings;
8574
8751
  const settingsExposure = inspectSettingsExposure({ settingsShared, files: params.settingsFiles });
8575
8752
  const keychain = params.platform === "darwin" && params.run !== void 0 && params.farmRoot !== void 0 ? lookupKeychainService(params.run, params.farmRoot) : void 0;
8753
+ const claudeVersion = buildClaudeVersionReport(params, resolved.flattened.launch.claudeVersion);
8576
8754
  return {
8577
8755
  ...params.identityName === void 0 ? {} : { identityName: params.identityName },
8578
8756
  identitySource: params.identitySource,
@@ -8585,7 +8763,8 @@ function runCheck(params) {
8585
8763
  ambientCredential,
8586
8764
  ...keychain === void 0 ? {} : { keychain },
8587
8765
  settingsExposure,
8588
- credential: buildCredentialReport(params.provider, params.identity, params.identityName, params.credentialCache)
8766
+ credential: buildCredentialReport(params.provider, params.identity, params.identityName, params.credentialCache),
8767
+ ...claudeVersion === void 0 ? {} : { claudeVersion }
8589
8768
  };
8590
8769
  }
8591
8770
  function formatCheckReport(report) {
@@ -8634,6 +8813,17 @@ function formatCheckReport(report) {
8634
8813
  if (credential.applies === "stored-login") {
8635
8814
  lines.push(" The identity's stored login (no credential block applies).");
8636
8815
  }
8816
+ if (report.claudeVersion !== void 0) {
8817
+ lines.push("", "Claude Code version:");
8818
+ const { pinned, highestInstalled, installed } = report.claudeVersion;
8819
+ if (pinned !== void 0) {
8820
+ lines.push(
8821
+ pinned.installed ? ` ${pinned.version}, pinned by the ${pinned.source} (installed)` : ` ${pinned.version}, pinned by the ${pinned.source}, but NOT installed; a launch here fails. Installed: ${installed.length === 0 ? "none" : installed.join(", ")}`
8822
+ );
8823
+ } else {
8824
+ lines.push(highestInstalled === void 0 ? " none installed in the versions directory (a launch falls back to a claude on PATH)" : ` ${highestInstalled} (the highest installed; nothing pins a version)`);
8825
+ }
8826
+ }
8637
8827
  lines.push("", "Ambient-credential exposure:");
8638
8828
  lines.push(
8639
8829
  report.ambientCredential.ok ? ` OK \u2014 none of ${AMBIENT_CREDENTIAL_VARS.join(", ")} is set to a non-empty value.` : report.ambientCredential.message.split("\n").map((line) => ` ${line}`).join("\n")
@@ -8672,11 +8862,12 @@ function checkReportToJson(report) {
8672
8862
  ambientCredential: report.ambientCredential.ok ? { ok: true } : { ok: false, variable: report.ambientCredential.variable, message: report.ambientCredential.message },
8673
8863
  ...report.keychain === void 0 ? {} : { keychain: report.keychain },
8674
8864
  settingsExposure: report.settingsExposure,
8675
- credential: report.credential
8865
+ credential: report.credential,
8866
+ ...report.claudeVersion === void 0 ? {} : { claudeVersion: report.claudeVersion }
8676
8867
  };
8677
8868
  }
8678
8869
  function checkReportHasWarnings(report) {
8679
- return report.resolved.diagnostics.some((diagnostic) => diagnostic.severity !== "info") || report.projectEncodingAmbiguities.length > 0 || !report.ambientCredential.ok || report.credential.provider?.problem !== void 0;
8870
+ return report.resolved.diagnostics.some((diagnostic) => diagnostic.severity !== "info") || report.projectEncodingAmbiguities.length > 0 || !report.ambientCredential.ok || report.credential.provider?.problem !== void 0 || report.claudeVersion?.pinned?.installed === false;
8680
8871
  }
8681
8872
  function loadCheckProvider(paths, name) {
8682
8873
  let definition;
@@ -8737,10 +8928,10 @@ function collectCheckReport(params) {
8737
8928
  }).input;
8738
8929
  const providerName = cascadeProviderName(cascade);
8739
8930
  const provider = providerName === void 0 ? void 0 : loadCheckProvider(paths, providerName);
8740
- const farmRoot = identityDecision.name === void 0 ? void 0 : import_node_path23.default.join(paths.identitiesDir, identityDecision.name);
8931
+ const farmRoot = identityDecision.name === void 0 ? void 0 : import_node_path24.default.join(paths.identitiesDir, identityDecision.name);
8741
8932
  const settingsFiles = {
8742
- "settings.json": realFsPort.readFileUtf8(import_node_path23.default.join(claudeHome, "settings.json")),
8743
- "settings.local.json": realFsPort.readFileUtf8(import_node_path23.default.join(claudeHome, "settings.local.json"))
8933
+ "settings.json": realFsPort.readFileUtf8(import_node_path24.default.join(claudeHome, "settings.json")),
8934
+ "settings.local.json": realFsPort.readFileUtf8(import_node_path24.default.join(claudeHome, "settings.local.json"))
8744
8935
  };
8745
8936
  const report = runCheck({
8746
8937
  cwd,
@@ -8762,6 +8953,7 @@ function collectCheckReport(params) {
8762
8953
  settingsFiles,
8763
8954
  run: realRunPort,
8764
8955
  credentialCache: realCredentialCacheEnv(paths),
8956
+ installedClaudeVersions: realInstalledClaudeVersions(),
8765
8957
  ...farmRoot === void 0 ? {} : { farmRoot },
8766
8958
  platform: process.platform,
8767
8959
  ...provider === void 0 ? {} : { provider }
@@ -8771,7 +8963,7 @@ function collectCheckReport(params) {
8771
8963
 
8772
8964
  // src/claudeShim.ts
8773
8965
  var import_node_fs8 = __toESM(require("node:fs"), 1);
8774
- var import_node_path24 = __toESM(require("node:path"), 1);
8966
+ var import_node_path25 = __toESM(require("node:path"), 1);
8775
8967
  var import_zod14 = require("zod");
8776
8968
  var ClaudeShimStateSchema = import_zod14.z.strictObject({
8777
8969
  targetPath: import_zod14.z.string().min(1),
@@ -8783,10 +8975,10 @@ function commandFilename(ownExecutablePath, commandName) {
8783
8975
  }
8784
8976
  function resolveOwnBinaryCheck(paths, contentSourcePath) {
8785
8977
  const state = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
8786
- const recordedTarget = state === void 0 ? void 0 : import_node_path24.default.resolve(state.targetPath);
8978
+ const recordedTarget = state === void 0 ? void 0 : import_node_path25.default.resolve(state.targetPath);
8787
8979
  let ownStat;
8788
8980
  return (candidate) => {
8789
- if (recordedTarget !== void 0 && import_node_path24.default.resolve(candidate) === recordedTarget) {
8981
+ if (recordedTarget !== void 0 && import_node_path25.default.resolve(candidate) === recordedTarget) {
8790
8982
  return true;
8791
8983
  }
8792
8984
  ownStat ??= statOrUndefined(contentSourcePath);
@@ -8810,20 +9002,20 @@ function statOrUndefined(target) {
8810
9002
  }
8811
9003
  var nodeLinkFs = { link: import_node_fs8.default.linkSync, copyFile: import_node_fs8.default.copyFileSync, chmod: import_node_fs8.default.chmodSync };
8812
9004
  function findPathShadow(params) {
8813
- const resolvedTargetDir = import_node_path24.default.resolve(params.targetDir);
9005
+ const resolvedTargetDir = import_node_path25.default.resolve(params.targetDir);
8814
9006
  for (const dir of params.pathDirs) {
8815
9007
  const found = params.findExecutableInDir(dir, params.targetFilename);
8816
9008
  if (found === void 0) {
8817
9009
  continue;
8818
9010
  }
8819
- return import_node_path24.default.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
9011
+ return import_node_path25.default.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
8820
9012
  }
8821
- return params.pathDirs.some((dir) => import_node_path24.default.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
9013
+ return params.pathDirs.some((dir) => import_node_path25.default.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
8822
9014
  }
8823
9015
 
8824
9016
  // src/doctorReport.ts
8825
9017
  var import_node_fs9 = __toESM(require("node:fs"), 1);
8826
- var import_node_path25 = __toESM(require("node:path"), 1);
9018
+ var import_node_path26 = __toESM(require("node:path"), 1);
8827
9019
  function refinePathShadow(status, ownExecutablePath, realpath) {
8828
9020
  if (status.status !== "shadowed") {
8829
9021
  return status;
@@ -8847,7 +9039,7 @@ function validateJson(schema, input) {
8847
9039
  return { ok: true, data: result.data };
8848
9040
  }
8849
9041
  function pushPathResolution(push, resolution) {
8850
- const ownDir = import_node_path25.default.dirname(resolution.ownExecutablePath);
9042
+ const ownDir = import_node_path26.default.dirname(resolution.ownExecutablePath);
8851
9043
  switch (resolution.agentShim.status) {
8852
9044
  case "ok":
8853
9045
  push("path-resolution", "pass", `\`agent-shim\` on PATH resolves to this running executable, ${resolution.ownExecutablePath}.`, "agent-shim");
@@ -8913,24 +9105,24 @@ function pushProvider(push, entry, cacheEnv) {
8913
9105
  push("provider", "fail", new LegacyProviderFileError(entry.path, conversion).message, entry.name);
8914
9106
  return;
8915
9107
  }
8916
- const validated = ProviderSchema.safeParse(parsed);
8917
- if (!validated.success) {
8918
- push("provider", "fail", new ConfigValidationError(entry.path, validated.error.issues).message, entry.name);
9108
+ const validated2 = ProviderSchema.safeParse(parsed);
9109
+ if (!validated2.success) {
9110
+ push("provider", "fail", new ConfigValidationError(entry.path, validated2.error.issues).message, entry.name);
8919
9111
  return;
8920
9112
  }
8921
- const cache = cacheClause(cacheEnv, `provider ${entry.name}`, validated.data.credential);
8922
- push("provider", cache.unreadable ? "fail" : "pass", `${entry.name} is valid (${describeProviderEndpoint(validated.data)}, credential ${describeCredential(validated.data.credential)})${cache.text}.`, entry.name);
9113
+ const cache = cacheClause(cacheEnv, `provider ${entry.name}`, validated2.data.credential);
9114
+ push("provider", cache.unreadable ? "fail" : "pass", `${entry.name} is valid (${describeProviderEndpoint(validated2.data)}, credential ${describeCredential(validated2.data.credential)})${cache.text}.`, entry.name);
8923
9115
  }
8924
9116
  function pushLegacyName(push, params) {
8925
9117
  const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
8926
- if (legacyVariables.length === 0 && import_node_path25.default.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
9118
+ if (legacyVariables.length === 0 && import_node_path26.default.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
8927
9119
  push("legacy-name", "pass", "Nothing here still uses the former `claude-use` name.");
8928
9120
  return;
8929
9121
  }
8930
9122
  for (const name of legacyVariables) {
8931
9123
  push("legacy-name", "warn", `${name} is the former name of ${name.replace(LEGACY_ENV_PREFIX, ENV_PREFIX)}. Rename it; the old name still works but is only a fallback.`, name);
8932
9124
  }
8933
- if (import_node_path25.default.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
9125
+ if (import_node_path26.default.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
8934
9126
  push(
8935
9127
  "legacy-name",
8936
9128
  "warn",
@@ -8943,6 +9135,13 @@ function runDoctor(params) {
8943
9135
  const push = (section, severity, message, subject) => {
8944
9136
  findings.push({ section, severity, message, ...subject === void 0 ? {} : { subject } });
8945
9137
  };
9138
+ const checkPin = (section, subject, where, version) => {
9139
+ const installed = params.installedClaudeVersions;
9140
+ if (version === void 0 || installed === void 0 || installed.includes(version)) {
9141
+ return;
9142
+ }
9143
+ push(section, "warn", `${where} pins Claude Code ${version}, which is not installed (installed: ${installed.length === 0 ? "none" : installed.join(", ")}); a launch that resolves to it fails.`, subject);
9144
+ };
8946
9145
  const ambient = detectAmbientCredential(params.env);
8947
9146
  if (ambient === void 0) {
8948
9147
  push("ambient-credential", "pass", "No ambient-credential environment variable is set.");
@@ -8975,12 +9174,13 @@ function runDoctor(params) {
8975
9174
  pushLegacyName(push, params);
8976
9175
  const profileSources = /* @__PURE__ */ new Map();
8977
9176
  for (const entry of params.configProfiles) {
8978
- const validated = validateJson(ConfigProfileSchema, entry);
8979
- if (!validated.ok) {
8980
- push("config-profile", "fail", validated.message, entry.name);
9177
+ const validated2 = validateJson(ConfigProfileSchema, entry);
9178
+ if (!validated2.ok) {
9179
+ push("config-profile", "fail", validated2.message, entry.name);
8981
9180
  continue;
8982
9181
  }
8983
- profileSources.set(entry.name, { name: entry.name, profile: validated.data });
9182
+ profileSources.set(entry.name, { name: entry.name, profile: validated2.data });
9183
+ checkPin("config-profile", entry.name, `Configuration profile "${entry.name}"`, validated2.data.launch?.claudeVersion);
8984
9184
  }
8985
9185
  const loadProfile = (name) => profileSources.get(name);
8986
9186
  for (const name of profileSources.keys()) {
@@ -8996,13 +9196,13 @@ function runDoctor(params) {
8996
9196
  const validProfileNames = new Set(profileSources.keys());
8997
9197
  const validIdentityNames = /* @__PURE__ */ new Set();
8998
9198
  for (const entry of params.identities) {
8999
- const validated = validateJson(IdentitySchema, entry);
9000
- if (!validated.ok) {
9001
- push("identity", "fail", validated.message, entry.name);
9199
+ const validated2 = validateJson(IdentitySchema, entry);
9200
+ if (!validated2.ok) {
9201
+ push("identity", "fail", validated2.message, entry.name);
9002
9202
  continue;
9003
9203
  }
9004
9204
  validIdentityNames.add(entry.name);
9005
- const defaultProfile = validated.data.defaultConfigProfile;
9205
+ const defaultProfile = validated2.data.defaultConfigProfile;
9006
9206
  if (defaultProfile !== void 0 && !validProfileNames.has(defaultProfile)) {
9007
9207
  push(
9008
9208
  "identity",
@@ -9011,7 +9211,7 @@ function runDoctor(params) {
9011
9211
  entry.name
9012
9212
  );
9013
9213
  } else {
9014
- const credential = validated.data.credential;
9214
+ const credential = validated2.data.credential;
9015
9215
  const cache = credential === void 0 ? { text: "", unreadable: false } : cacheClause(params.credentialCache, `identity ${entry.name}`, credential);
9016
9216
  push(
9017
9217
  "identity",
@@ -9049,12 +9249,12 @@ function runDoctor(params) {
9049
9249
  if (params.directoryRules.raw === void 0) {
9050
9250
  push("directory-rules", "pass", "No directory-rules.json configured.");
9051
9251
  } else {
9052
- const validated = validateJson(DirectoryRulesSchema, params.directoryRules);
9053
- if (!validated.ok) {
9054
- push("directory-rules", "fail", validated.message);
9252
+ const validated2 = validateJson(DirectoryRulesSchema, params.directoryRules);
9253
+ if (!validated2.ok) {
9254
+ push("directory-rules", "fail", validated2.message);
9055
9255
  } else {
9056
9256
  push("directory-rules", "pass", `${params.directoryRules.path} is valid.`);
9057
- for (const rule of validated.data.rules) {
9257
+ for (const rule of validated2.data.rules) {
9058
9258
  const badRefs = [];
9059
9259
  if (rule.identity !== void 0 && !selectionExists(rule.identity)) {
9060
9260
  badRefs.push(poolNameOf(rule.identity) === void 0 ? `identity "${rule.identity}"` : `pool "${poolNameOf(rule.identity) ?? ""}"`);
@@ -9062,6 +9262,7 @@ function runDoctor(params) {
9062
9262
  if (rule.configProfile !== void 0 && !validProfileNames.has(rule.configProfile)) {
9063
9263
  badRefs.push(`configuration profile "${rule.configProfile}"`);
9064
9264
  }
9265
+ checkPin("directory-rules", rule.path, `Rule for "${rule.path}"`, rule.launch?.claudeVersion);
9065
9266
  if (badRefs.length > 0) {
9066
9267
  push("directory-rules", "fail", `Rule for "${rule.path}" names ${badRefs.join(" and ")}, which do not exist.`, rule.path);
9067
9268
  } else {
@@ -9073,11 +9274,11 @@ function runDoctor(params) {
9073
9274
  if (params.globalConfig.raw === void 0) {
9074
9275
  push("global-config", "pass", "No config.json configured.");
9075
9276
  } else {
9076
- const validated = validateJson(GlobalConfigSchema, params.globalConfig);
9077
- if (!validated.ok) {
9078
- push("global-config", "fail", validated.message);
9277
+ const validated2 = validateJson(GlobalConfigSchema, params.globalConfig);
9278
+ if (!validated2.ok) {
9279
+ push("global-config", "fail", validated2.message);
9079
9280
  } else {
9080
- const defaultProfile = validated.data.defaultConfigProfile;
9281
+ const defaultProfile = validated2.data.defaultConfigProfile;
9081
9282
  if (defaultProfile !== void 0 && !validProfileNames.has(defaultProfile)) {
9082
9283
  push(
9083
9284
  "global-config",
@@ -9086,27 +9287,28 @@ function runDoctor(params) {
9086
9287
  );
9087
9288
  } else {
9088
9289
  push("global-config", "pass", `${params.globalConfig.path} is valid.`);
9290
+ checkPin("global-config", void 0, "config.json", validated2.data.launch?.claudeVersion);
9089
9291
  }
9090
9292
  }
9091
9293
  }
9092
9294
  if (params.categoriesLocal.raw === void 0) {
9093
9295
  push("categories-local", "pass", "No categories.local.json configured.");
9094
9296
  } else {
9095
- const validated = validateJson(CategoryClassificationOverlaySchema, params.categoriesLocal);
9297
+ const validated2 = validateJson(CategoryClassificationOverlaySchema, params.categoriesLocal);
9096
9298
  push(
9097
9299
  "categories-local",
9098
- validated.ok ? "pass" : "fail",
9099
- validated.ok ? `${params.categoriesLocal.path} is valid.` : validated.message
9300
+ validated2.ok ? "pass" : "fail",
9301
+ validated2.ok ? `${params.categoriesLocal.path} is valid.` : validated2.message
9100
9302
  );
9101
9303
  }
9102
9304
  if (params.headroom.state.raw === void 0) {
9103
9305
  push("headroom", "pass", "No headroom daemon has ever run; nothing to check.");
9104
9306
  } else {
9105
- const validated = validateJson(HeadroomStateSchema, params.headroom.state);
9106
- if (!validated.ok) {
9107
- push("headroom", "fail", validated.message);
9307
+ const validated2 = validateJson(HeadroomStateSchema, params.headroom.state);
9308
+ if (!validated2.ok) {
9309
+ push("headroom", "fail", validated2.message);
9108
9310
  } else {
9109
- const state = validated.data;
9311
+ const state = validated2.data;
9110
9312
  const supervisorAlive = state.supervisorPid !== void 0 && params.headroom.isRunning(state.supervisorPid);
9111
9313
  const headroomAlive = state.headroomPid !== void 0 && params.headroom.isRunning(state.headroomPid);
9112
9314
  if (state.supervisorPid === void 0) {
@@ -9239,18 +9441,18 @@ function collectDoctorReport(params) {
9239
9441
  const { paths } = params;
9240
9442
  const identityNames = import_node_fs9.default.existsSync(paths.identitiesDir) ? import_node_fs9.default.readdirSync(paths.identitiesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && isIdentityDirectoryName(entry.name)).map((entry) => entry.name).sort() : [];
9241
9443
  const identities = identityNames.map((name) => {
9242
- const farmRoot = import_node_path25.default.join(paths.identitiesDir, name);
9243
- const identityPath = import_node_path25.default.join(farmRoot, "identity.json");
9444
+ const farmRoot = import_node_path26.default.join(paths.identitiesDir, name);
9445
+ const identityPath = import_node_path26.default.join(farmRoot, "identity.json");
9244
9446
  return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot };
9245
9447
  });
9246
9448
  const profileNames = import_node_fs9.default.existsSync(paths.configProfilesDir) ? import_node_fs9.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
9247
9449
  const configProfiles = profileNames.map((name) => {
9248
- const profilePath = import_node_path25.default.join(paths.configProfilesDir, `${name}.json`);
9450
+ const profilePath = import_node_path26.default.join(paths.configProfilesDir, `${name}.json`);
9249
9451
  return { name, path: profilePath, raw: realFsPort.readFileUtf8(profilePath) };
9250
9452
  });
9251
9453
  const providerNames = import_node_fs9.default.existsSync(paths.providersDir) ? import_node_fs9.default.readdirSync(paths.providersDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
9252
9454
  const providers = providerNames.map((name) => {
9253
- const providerPath = import_node_path25.default.join(paths.providersDir, `${name}.json`);
9455
+ const providerPath = import_node_path26.default.join(paths.providersDir, `${name}.json`);
9254
9456
  return { name, path: providerPath, raw: realFsPort.readFileUtf8(providerPath) };
9255
9457
  });
9256
9458
  const ownExecutablePath = realOwnExecutablePath();
@@ -9262,12 +9464,12 @@ function collectDoctorReport(params) {
9262
9464
  binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
9263
9465
  }
9264
9466
  const shimState = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
9265
- const pathDirs = (params.env.PATH ?? "").split(import_node_path25.default.delimiter).filter((dir) => dir !== "");
9467
+ const pathDirs = (params.env.PATH ?? "").split(import_node_path26.default.delimiter).filter((dir) => dir !== "");
9266
9468
  const claudeShimShadow = shimState === void 0 ? void 0 : refinePathShadow(
9267
9469
  findPathShadow({
9268
9470
  pathDirs,
9269
- targetDir: import_node_path25.default.dirname(shimState.targetPath),
9270
- targetFilename: import_node_path25.default.basename(shimState.targetPath),
9471
+ targetDir: import_node_path26.default.dirname(shimState.targetPath),
9472
+ targetFilename: import_node_path26.default.basename(shimState.targetPath),
9271
9473
  findExecutableInDir
9272
9474
  }),
9273
9475
  shimState.targetPath,
@@ -9276,6 +9478,7 @@ function collectDoctorReport(params) {
9276
9478
  const report = runDoctor({
9277
9479
  env: params.env,
9278
9480
  credentialCache: realCredentialCacheEnv(paths),
9481
+ installedClaudeVersions: realInstalledClaudeVersions(),
9279
9482
  identities,
9280
9483
  configProfiles,
9281
9484
  providers,
@@ -9291,7 +9494,7 @@ function collectDoctorReport(params) {
9291
9494
  agentShim: refinePathShadow(
9292
9495
  findPathShadow({
9293
9496
  pathDirs,
9294
- targetDir: import_node_path25.default.dirname(ownExecutablePath),
9497
+ targetDir: import_node_path26.default.dirname(ownExecutablePath),
9295
9498
  targetFilename: commandFilename(ownExecutablePath, "agent-shim"),
9296
9499
  findExecutableInDir
9297
9500
  }),
@@ -9312,7 +9515,7 @@ function collectDoctorReport(params) {
9312
9515
 
9313
9516
  // src/launcher.ts
9314
9517
  var import_node_crypto10 = require("node:crypto");
9315
- var import_node_path27 = __toESM(require("node:path"), 1);
9518
+ var import_node_path28 = __toESM(require("node:path"), 1);
9316
9519
 
9317
9520
  // src/launcher/argv.ts
9318
9521
  var ConflictingIdentityError = class extends UsageError {
@@ -9325,7 +9528,7 @@ var ConflictingIdentityError = class extends UsageError {
9325
9528
  positional;
9326
9529
  flag;
9327
9530
  };
9328
- var VALUED_FLAGS = ["--identity", "--config-profile", "--provider", "--category", "--share", "--hide"];
9531
+ var VALUED_FLAGS = ["--identity", "--config-profile", "--provider", "--claude-version", "--category", "--share", "--hide"];
9329
9532
  var BOOLEAN_FLAGS = [
9330
9533
  { flag: "--headroom", key: "headroom" },
9331
9534
  { flag: "--track-usage", key: "trackUsage" },
@@ -9371,6 +9574,7 @@ function parseLauncherArgv(argv) {
9371
9574
  let flagIdentity;
9372
9575
  let configProfile;
9373
9576
  let provider;
9577
+ let claudeVersion;
9374
9578
  const booleans = {};
9375
9579
  const categoryFlags = [];
9376
9580
  const shareFlags = [];
@@ -9425,6 +9629,9 @@ function parseLauncherArgv(argv) {
9425
9629
  case "--provider":
9426
9630
  provider = value;
9427
9631
  break;
9632
+ case "--claude-version":
9633
+ claudeVersion = value;
9634
+ break;
9428
9635
  case "--category":
9429
9636
  categoryFlags.push(value);
9430
9637
  break;
@@ -9446,6 +9653,7 @@ function parseLauncherArgv(argv) {
9446
9653
  ...identity === void 0 ? {} : { identity },
9447
9654
  ...configProfile === void 0 ? {} : { configProfile },
9448
9655
  ...provider === void 0 ? {} : { provider },
9656
+ ...claudeVersion === void 0 ? {} : { claudeVersion },
9449
9657
  ...native ? { native: true } : {},
9450
9658
  ...booleans,
9451
9659
  categoryFlags,
@@ -9572,7 +9780,7 @@ function buildCliOverride(params) {
9572
9780
  }
9573
9781
 
9574
9782
  // src/launcher/flags.ts
9575
- var import_node_path26 = __toESM(require("node:path"), 1);
9783
+ var import_node_path27 = __toESM(require("node:path"), 1);
9576
9784
 
9577
9785
  // src/headroom/headers.ts
9578
9786
  function mergeAnthropicCustomHeaders(existing, additions) {
@@ -9642,7 +9850,7 @@ function buildEnv(params) {
9642
9850
  const parentCustomHeaders = params.baseEnv.ANTHROPIC_CUSTOM_HEADERS;
9643
9851
  let providerCustomHeaders;
9644
9852
  if (!params.configDirEscapeHatch && params.resolvedIdentityName !== void 0) {
9645
- env.CLAUDE_CONFIG_DIR = import_node_path26.default.join(params.identitiesDir, params.resolvedIdentityName);
9853
+ env.CLAUDE_CONFIG_DIR = import_node_path27.default.join(params.identitiesDir, params.resolvedIdentityName);
9646
9854
  }
9647
9855
  if (params.provider !== void 0) {
9648
9856
  const providerEnv = params.provider.definition.env ?? {};
@@ -9803,7 +10011,7 @@ function prepareLaunch(params) {
9803
10011
  identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
9804
10012
  globalDefaultConfigProfile: params.globalDefaultConfigProfile
9805
10013
  });
9806
- if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(import_node_path27.default.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
10014
+ if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(import_node_path28.default.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
9807
10015
  log.error(
9808
10016
  `agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
9809
10017
  );
@@ -9907,7 +10115,11 @@ function prepareLaunch(params) {
9907
10115
  } else if (params.farm !== void 0) {
9908
10116
  cascadeLaunch = flattenLayers(assembleCascade(params.farm.loadCascade(configProfileDecision.name, cliOverride)).layers, { home: params.farm.home }).launch;
9909
10117
  }
9910
- const discovered = params.resolveClaudeBinary();
10118
+ const pinnedVersion = resolveClaudeVersion({ env, ...parsedArgv.claudeVersion === void 0 ? {} : { flag: parsedArgv.claudeVersion }, ...cascadeLaunch?.claudeVersion === void 0 ? {} : { cascade: cascadeLaunch.claudeVersion } });
10119
+ const discovered = params.resolveClaudeBinary(pinnedVersion === void 0 ? void 0 : { version: pinnedVersion.version });
10120
+ if (pinnedVersion !== void 0) {
10121
+ log.info(`agent-shim: Claude Code ${pinnedVersion.version} (pinned by ${pinnedVersion.source})`);
10122
+ }
9911
10123
  const resolvedFlags = resolveLaunchFlags({
9912
10124
  env,
9913
10125
  // A pool pick reads the usage the front door records, so a pool launch records its own unless something says otherwise.
@@ -10045,11 +10257,11 @@ function probeFrontDoorSync(port, caPem) {
10045
10257
 
10046
10258
  // src/frontdoor/trust.ts
10047
10259
  var import_node_crypto11 = require("node:crypto");
10048
- var import_node_path28 = __toESM(require("node:path"), 1);
10260
+ var import_node_path29 = __toESM(require("node:path"), 1);
10049
10261
  var BUNDLE_NAME_HEX_DIGITS = 16;
10050
10262
  function resolveTrustBundle(params) {
10051
10263
  const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
10052
- if (inherited === void 0 || inherited === "" || import_node_path28.default.resolve(inherited) === import_node_path28.default.resolve(caCertFile)) {
10264
+ if (inherited === void 0 || inherited === "" || import_node_path29.default.resolve(inherited) === import_node_path29.default.resolve(caCertFile)) {
10053
10265
  return { path: caCertFile };
10054
10266
  }
10055
10267
  const caPem = fs12.readFileUtf8(caCertFile);
@@ -10067,7 +10279,7 @@ function resolveTrustBundle(params) {
10067
10279
  }
10068
10280
  const combined = `${inheritedPem.trimEnd()}
10069
10281
  ${caPem}`;
10070
- const bundle = import_node_path28.default.join(bundlesDir, `${(0, import_node_crypto11.createHash)("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
10282
+ const bundle = import_node_path29.default.join(bundlesDir, `${(0, import_node_crypto11.createHash)("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
10071
10283
  if (!fs12.exists(bundle)) {
10072
10284
  fs12.mkdirp(bundlesDir);
10073
10285
  fs12.writeFileAtomic(bundle, combined);
@@ -10295,6 +10507,7 @@ function prepareClaudeLaunch(options) {
10295
10507
  createRcApiNodeHandler,
10296
10508
  createRcApiRouter,
10297
10509
  createRcControlHandler,
10510
+ createRcCredentialStore,
10298
10511
  createRcEventFanout,
10299
10512
  createRcSessionTracker,
10300
10513
  createRcStreamHub,