agent-shim 8.9.0 → 8.10.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
@@ -268,8 +268,113 @@ var categories_default_default = {
268
268
  };
269
269
 
270
270
  // src/config/schema.ts
271
- var import_node_path = __toESM(require("node:path"), 1);
271
+ var import_node_path2 = __toESM(require("node:path"), 1);
272
272
  var import_zod = require("zod");
273
+
274
+ // src/versionDiscovery.ts
275
+ var import_node_os = __toESM(require("node:os"), 1);
276
+ var import_node_path = __toESM(require("node:path"), 1);
277
+
278
+ // src/cliError.ts
279
+ var EXIT_FAILURE = 1;
280
+ var EXIT_USAGE = 2;
281
+ var CliError = class extends Error {
282
+ /** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
283
+ exitCode = EXIT_FAILURE;
284
+ };
285
+ var UsageError = class extends CliError {
286
+ exitCode = EXIT_USAGE;
287
+ constructor(message) {
288
+ super(message);
289
+ this.name = "UsageError";
290
+ }
291
+ };
292
+
293
+ // src/versionDiscovery.ts
294
+ function defaultVersionsDir() {
295
+ return import_node_path.default.join(import_node_os.default.homedir(), ".local", "share", "claude", "versions");
296
+ }
297
+ var NUMERIC_DOTTED_VERSION_RE = /^\d+(?:\.\d+)*$/;
298
+ function isNumericDottedVersion(name) {
299
+ return NUMERIC_DOTTED_VERSION_RE.test(name);
300
+ }
301
+ function compareVersions(a, b) {
302
+ if (!isNumericDottedVersion(a)) {
303
+ throw new Error(`compareVersions: "${a}" is not a valid plain dotted-numeric version`);
304
+ }
305
+ if (!isNumericDottedVersion(b)) {
306
+ throw new Error(`compareVersions: "${b}" is not a valid plain dotted-numeric version`);
307
+ }
308
+ const segmentsA = a.split(".").map(Number);
309
+ const segmentsB = b.split(".").map(Number);
310
+ const length = Math.max(segmentsA.length, segmentsB.length);
311
+ for (let i = 0; i < length; i += 1) {
312
+ const segmentA = segmentsA[i] ?? 0;
313
+ const segmentB = segmentsB[i] ?? 0;
314
+ if (segmentA !== segmentB) {
315
+ return segmentA - segmentB;
316
+ }
317
+ }
318
+ return 0;
319
+ }
320
+ var ClaudeVersionNotInstalledError = class extends CliError {
321
+ constructor(version, versionsDir, installed) {
322
+ super(
323
+ `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)."
324
+ );
325
+ this.version = version;
326
+ this.versionsDir = versionsDir;
327
+ this.installed = installed;
328
+ this.name = "ClaudeVersionNotInstalledError";
329
+ }
330
+ version;
331
+ versionsDir;
332
+ installed;
333
+ };
334
+ function installedVersions(entries) {
335
+ return entries.filter((entry) => entry.isFile && entry.isExecutable && entry.sizeBytes > 0 && isNumericDottedVersion(entry.name)).map((entry) => entry.name).sort(compareVersions);
336
+ }
337
+ function pickHighestVersion(entries) {
338
+ const candidates = entries.filter(
339
+ (entry) => entry.isFile && entry.isExecutable && entry.sizeBytes > 0 && isNumericDottedVersion(entry.name)
340
+ );
341
+ if (candidates.length === 0) {
342
+ return void 0;
343
+ }
344
+ return candidates.reduce(
345
+ (highest, candidate) => compareVersions(candidate.name, highest.name) > 0 ? candidate : highest
346
+ ).name;
347
+ }
348
+ function discoverClaudeBinary(options) {
349
+ const versionsDir = options.versionsDir ?? defaultVersionsDir();
350
+ const entries = options.listVersionsDir(versionsDir);
351
+ const highestVersion = pickHighestVersion(entries);
352
+ if (options.version !== void 0) {
353
+ const installed = installedVersions(entries);
354
+ if (!installed.includes(options.version)) {
355
+ throw new ClaudeVersionNotInstalledError(options.version, versionsDir, installed);
356
+ }
357
+ return { path: import_node_path.default.join(versionsDir, options.version), source: "versions-dir", version: options.version };
358
+ }
359
+ if (highestVersion !== void 0) {
360
+ return {
361
+ path: import_node_path.default.join(versionsDir, highestVersion),
362
+ source: "versions-dir",
363
+ version: highestVersion
364
+ };
365
+ }
366
+ for (const dir of options.pathDirs) {
367
+ const found = options.findExecutableInDir(dir, "claude");
368
+ if (found !== void 0 && !options.isOwnBinary(found)) {
369
+ return { path: found, source: "path-fallback" };
370
+ }
371
+ }
372
+ throw new Error(
373
+ `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.`
374
+ );
375
+ }
376
+
377
+ // src/config/schema.ts
273
378
  var CATEGORY_NAMES = ["secret", "runtime", "history", "knowledge", "settings"];
274
379
  var OVERRIDABLE_CATEGORIES = ["runtime", "history", "knowledge", "settings"];
275
380
  function isOverridableCategory(name) {
@@ -313,7 +418,9 @@ var LaunchSchema = import_zod.z.strictObject({
313
418
  remoteControl: import_zod.z.boolean().optional(),
314
419
  provider: import_zod.z.string().min(1).optional(),
315
420
  headroom: import_zod.z.boolean().optional(),
316
- trackUsage: import_zod.z.boolean().optional()
421
+ trackUsage: import_zod.z.boolean().optional(),
422
+ /** 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. */
423
+ 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
424
  });
318
425
  var CREDENTIAL_TARGETS = ["bearer", "apiKey", "oauthToken"];
319
426
  var PROVIDER_CREDENTIAL_TARGETS = ["bearer", "apiKey"];
@@ -332,7 +439,7 @@ var CommandSourceOptions = {
332
439
  var CredentialSourceSchema = import_zod.z.union([
333
440
  import_zod.z.strictObject({ env: import_zod.z.string().min(1) }),
334
441
  import_zod.z.strictObject({
335
- file: import_zod.z.string().min(1).refine((filePath) => filePath.startsWith("~/") || import_node_path.default.isAbsolute(filePath), {
442
+ file: import_zod.z.string().min(1).refine((filePath) => filePath.startsWith("~/") || import_node_path2.default.isAbsolute(filePath), {
336
443
  message: "a credential file must be an absolute or ~-rooted path, since a launch can start in any directory"
337
444
  })
338
445
  }),
@@ -511,28 +618,11 @@ var SHIPPED_CATEGORY_DEFAULTS = Object.freeze({
511
618
 
512
619
  // src/config/store.ts
513
620
  var import_node_fs = __toESM(require("node:fs"), 1);
514
- var import_node_path2 = __toESM(require("node:path"), 1);
621
+ var import_node_path3 = __toESM(require("node:path"), 1);
515
622
  var import_node_crypto = require("node:crypto");
516
623
 
517
624
  // src/config/load.ts
518
625
  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
626
  function createExplorer(moduleName = "agent-shim") {
537
627
  return (0, import_cosmiconfig.cosmiconfigSync)(moduleName, { searchPlaces: [] });
538
628
  }
@@ -653,9 +743,9 @@ function readJson(filePath, schema, storeFs = nodeStoreFs) {
653
743
  return result.data;
654
744
  }
655
745
  function writeTextAtomic(filePath, contents, storeFs = nodeStoreFs) {
656
- const dir = import_node_path2.default.dirname(filePath);
746
+ const dir = import_node_path3.default.dirname(filePath);
657
747
  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`);
748
+ const tempPath = import_node_path3.default.join(dir, `.${import_node_path3.default.basename(filePath)}.${String(process.pid)}.${(0, import_node_crypto.randomUUID)()}.tmp`);
659
749
  storeFs.writeFileUtf8(tempPath, contents);
660
750
  try {
661
751
  storeFs.renameSync(tempPath, filePath);
@@ -679,9 +769,9 @@ function applyPatch(filePath, schema, patch, options = {}) {
679
769
  if (!result.success) {
680
770
  throw new ConfigValidationError(filePath, result.error.issues);
681
771
  }
682
- const validated = result.data;
683
- writeJsonAtomic(filePath, validated, storeFs);
684
- return validated;
772
+ const validated2 = result.data;
773
+ writeJsonAtomic(filePath, validated2, storeFs);
774
+ return validated2;
685
775
  }
686
776
 
687
777
  // src/config/classify.ts
@@ -1104,6 +1194,9 @@ function flattenLayers(layers, options) {
1104
1194
  if (layer.launch.trackUsage !== void 0) {
1105
1195
  launch.trackUsage = layer.launch.trackUsage;
1106
1196
  }
1197
+ if (layer.launch.claudeVersion !== void 0) {
1198
+ launch.claudeVersion = layer.launch.claudeVersion;
1199
+ }
1107
1200
  }
1108
1201
  if (layer.entries === void 0) {
1109
1202
  continue;
@@ -1341,7 +1434,7 @@ function dedupeDiagnostics(diagnostics) {
1341
1434
  }
1342
1435
 
1343
1436
  // src/resolve/plan.ts
1344
- var import_node_path3 = __toESM(require("node:path"), 1);
1437
+ var import_node_path4 = __toESM(require("node:path"), 1);
1345
1438
  function parentOf(rel) {
1346
1439
  const index = rel.lastIndexOf("/");
1347
1440
  return index === -1 ? "" : rel.slice(0, index);
@@ -1391,7 +1484,7 @@ function planFarm(params) {
1391
1484
  }
1392
1485
  return value;
1393
1486
  };
1394
- const linkTarget = (rel) => import_node_path3.default.join(params.facts.claudeHome, rel);
1487
+ const linkTarget = (rel) => import_node_path4.default.join(params.facts.claudeHome, rel);
1395
1488
  const visit = (rel) => {
1396
1489
  const fact = params.facts.entries.get(rel);
1397
1490
  const decision = params.decisions.get(rel);
@@ -1469,7 +1562,7 @@ function descendPolicy(rules) {
1469
1562
  }
1470
1563
 
1471
1564
  // src/resolve/walk.ts
1472
- var import_node_path4 = __toESM(require("node:path"), 1);
1565
+ var import_node_path5 = __toESM(require("node:path"), 1);
1473
1566
 
1474
1567
  // src/resolve/extends.ts
1475
1568
  function lineariseProfile(rootName, load) {
@@ -1537,10 +1630,10 @@ function profileLayers(rootName, load, startId) {
1537
1630
 
1538
1631
  // src/resolve/walk.ts
1539
1632
  function walkDirectoryAncestors(cwd, options) {
1540
- const limit = import_node_path4.default.resolve(options.limit ?? options.home);
1633
+ const limit = import_node_path5.default.resolve(options.limit ?? options.home);
1541
1634
  const isReadable = options.isReadable ?? (() => true);
1542
1635
  const collected = [];
1543
- let current = import_node_path4.default.resolve(cwd);
1636
+ let current = import_node_path5.default.resolve(cwd);
1544
1637
  for (; ; ) {
1545
1638
  if (!isReadable(current)) {
1546
1639
  break;
@@ -1549,7 +1642,7 @@ function walkDirectoryAncestors(cwd, options) {
1549
1642
  if (current === limit) {
1550
1643
  break;
1551
1644
  }
1552
- const parent = import_node_path4.default.dirname(current);
1645
+ const parent = import_node_path5.default.dirname(current);
1553
1646
  if (parent === current) {
1554
1647
  break;
1555
1648
  }
@@ -1673,7 +1766,7 @@ function resolveDecisions(input) {
1673
1766
  }
1674
1767
 
1675
1768
  // src/launcher/farm.ts
1676
- var import_node_path6 = __toESM(require("node:path"), 1);
1769
+ var import_node_path7 = __toESM(require("node:path"), 1);
1677
1770
  var import_zod2 = require("zod");
1678
1771
 
1679
1772
  // src/resolve/reconcile.ts
@@ -1777,7 +1870,7 @@ var LEGACY_FARM_MANIFEST_FILENAME = ".claude-use-farm.json";
1777
1870
 
1778
1871
  // src/launcher/lock.ts
1779
1872
  var import_node_crypto2 = require("node:crypto");
1780
- var import_node_path5 = __toESM(require("node:path"), 1);
1873
+ var import_node_path6 = __toESM(require("node:path"), 1);
1781
1874
  var DEFAULT_STALE_AFTER_MS = 12e4;
1782
1875
  var DEFAULT_RETRY_DELAY_MS = 50;
1783
1876
  var DEFAULT_MAX_ATTEMPTS = 200;
@@ -1796,7 +1889,7 @@ var IdentityLockBusyError = class extends CliError {
1796
1889
  holderPid;
1797
1890
  };
1798
1891
  function identityLockPath(dir, identity) {
1799
- return import_node_path5.default.join(dir, `.${identity}.lock`);
1892
+ return import_node_path6.default.join(dir, `.${identity}.lock`);
1800
1893
  }
1801
1894
  function parseLockRecord(raw) {
1802
1895
  if (raw === void 0) {
@@ -1875,7 +1968,7 @@ var FarmManifestSchema = import_zod2.z.strictObject({
1875
1968
  links: import_zod2.z.array(import_zod2.z.strictObject({ rel: import_zod2.z.string(), target: import_zod2.z.string() }))
1876
1969
  });
1877
1970
  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));
1971
+ 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
1972
  if (raw === void 0) {
1880
1973
  return void 0;
1881
1974
  }
@@ -1891,7 +1984,7 @@ function readFarmManifest(fs12, farmRoot) {
1891
1984
  function buildEntryFacts(params) {
1892
1985
  const entries = /* @__PURE__ */ new Map();
1893
1986
  const visit = (rel) => {
1894
- const absolute = import_node_path6.default.join(params.claudeHome, rel);
1987
+ const absolute = import_node_path7.default.join(params.claudeHome, rel);
1895
1988
  const stat = params.fs.lstat(absolute);
1896
1989
  if (stat === void 0) {
1897
1990
  return void 0;
@@ -1934,7 +2027,7 @@ function buildEntryFacts(params) {
1934
2027
  };
1935
2028
  }
1936
2029
  function listSubtree(fs12, root, rel) {
1937
- const absolute = import_node_path6.default.join(root, rel);
2030
+ const absolute = import_node_path7.default.join(root, rel);
1938
2031
  const stat = fs12.lstat(absolute);
1939
2032
  if (stat === void 0) {
1940
2033
  return [];
@@ -1964,7 +2057,7 @@ function reconciliationScope(fs12, farmRoot, manifest) {
1964
2057
  if (manifest !== void 0) {
1965
2058
  return topLevelScopeRoots(manifest.materialised);
1966
2059
  }
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();
2060
+ 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
2061
  }
1969
2062
  function collectFarmListing(fs12, farmRoot, scopeRoots) {
1970
2063
  return scopeRoots.flatMap((root) => listSubtree(fs12, farmRoot, root));
@@ -1972,7 +2065,7 @@ function collectFarmListing(fs12, farmRoot, scopeRoots) {
1972
2065
  function collectCanonicalCounterparts(fs12, claudeHome, farmListing) {
1973
2066
  const out = [];
1974
2067
  for (const entry of farmListing) {
1975
- const absolute = import_node_path6.default.join(claudeHome, entry.rel);
2068
+ const absolute = import_node_path7.default.join(claudeHome, entry.rel);
1976
2069
  const stat = fs12.lstat(absolute);
1977
2070
  if (stat === void 0) {
1978
2071
  continue;
@@ -2002,21 +2095,21 @@ function carryOver(params) {
2002
2095
  if (accounted.has(name)) {
2003
2096
  continue;
2004
2097
  }
2005
- const stat = params.fs.lstat(import_node_path6.default.join(params.previousRoot, name));
2098
+ const stat = params.fs.lstat(import_node_path7.default.join(params.previousRoot, name));
2006
2099
  if (stat === void 0 || stat.kind === "symlink") {
2007
2100
  continue;
2008
2101
  }
2009
- if (params.fs.lstat(import_node_path6.default.join(params.farmRoot, name)) !== void 0) {
2102
+ if (params.fs.lstat(import_node_path7.default.join(params.farmRoot, name)) !== void 0) {
2010
2103
  const category = params.classification === void 0 ? void 0 : classifyEntries([name], params.classification).classification.get(name);
2011
2104
  if (category === "runtime") {
2012
- params.fs.removeRecursive(import_node_path6.default.join(params.previousRoot, name));
2105
+ params.fs.removeRecursive(import_node_path7.default.join(params.previousRoot, name));
2013
2106
  autoResolved.push(name);
2014
2107
  continue;
2015
2108
  }
2016
2109
  collided.push(name);
2017
2110
  continue;
2018
2111
  }
2019
- params.fs.rename(import_node_path6.default.join(params.previousRoot, name), import_node_path6.default.join(params.farmRoot, name));
2112
+ params.fs.rename(import_node_path7.default.join(params.previousRoot, name), import_node_path7.default.join(params.farmRoot, name));
2020
2113
  carried.push(name);
2021
2114
  }
2022
2115
  return { carried, autoResolved, collided };
@@ -2024,9 +2117,9 @@ function carryOver(params) {
2024
2117
  function buildScratchTree(params) {
2025
2118
  params.fs.mkdirp(params.scratchRoot);
2026
2119
  for (const entry of params.plan.entries) {
2027
- const absolute = import_node_path6.default.join(params.scratchRoot, entry.rel);
2120
+ const absolute = import_node_path7.default.join(params.scratchRoot, entry.rel);
2028
2121
  if (entry.kind === "link") {
2029
- params.fs.mkdirp(import_node_path6.default.dirname(absolute));
2122
+ params.fs.mkdirp(import_node_path7.default.dirname(absolute));
2030
2123
  params.fs.symlink(entry.target, absolute);
2031
2124
  continue;
2032
2125
  }
@@ -2035,14 +2128,14 @@ function buildScratchTree(params) {
2035
2128
  }
2036
2129
  }
2037
2130
  params.fs.writeFileUtf8(
2038
- import_node_path6.default.join(params.scratchRoot, FARM_MANIFEST_FILENAME),
2131
+ import_node_path7.default.join(params.scratchRoot, FARM_MANIFEST_FILENAME),
2039
2132
  `${JSON.stringify(params.manifest, null, 2)}
2040
2133
  `
2041
2134
  );
2042
2135
  }
2043
2136
  function swapIn(params) {
2044
2137
  if (params.fs.lstat(params.farmRoot) === void 0) {
2045
- params.fs.mkdirp(import_node_path6.default.dirname(params.farmRoot));
2138
+ params.fs.mkdirp(import_node_path7.default.dirname(params.farmRoot));
2046
2139
  params.fs.rename(params.scratchRoot, params.farmRoot);
2047
2140
  return { carried: [], autoResolved: [], collided: [] };
2048
2141
  }
@@ -2066,14 +2159,14 @@ function recoverInterruptedSwap(params) {
2066
2159
  const names = [...params.fs.readdir(params.identitiesDir)].sort();
2067
2160
  const removedScratch = [];
2068
2161
  for (const name of names.filter((candidate) => candidate.startsWith(scratchPrefix))) {
2069
- params.fs.removeRecursive(import_node_path6.default.join(params.identitiesDir, name));
2162
+ params.fs.removeRecursive(import_node_path7.default.join(params.identitiesDir, name));
2070
2163
  removedScratch.push(name);
2071
2164
  }
2072
2165
  let previous = names.filter((candidate) => candidate.startsWith(previousPrefix));
2073
2166
  let restoredFrom;
2074
2167
  const first = previous[0];
2075
2168
  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);
2169
+ params.fs.rename(import_node_path7.default.join(params.identitiesDir, first), params.farmRoot);
2077
2170
  restoredFrom = first;
2078
2171
  previous = previous.slice(1);
2079
2172
  }
@@ -2081,7 +2174,7 @@ function recoverInterruptedSwap(params) {
2081
2174
  const autoResolved = [];
2082
2175
  const retained = [];
2083
2176
  for (const name of previous) {
2084
- const previousRoot = import_node_path6.default.join(params.identitiesDir, name);
2177
+ const previousRoot = import_node_path7.default.join(params.identitiesDir, name);
2085
2178
  const result = carryOver({
2086
2179
  fs: params.fs,
2087
2180
  previousRoot,
@@ -2106,7 +2199,7 @@ function recoverInterruptedSwap(params) {
2106
2199
  };
2107
2200
  }
2108
2201
  function recoverFarm(params) {
2109
- const farmRoot = import_node_path6.default.join(params.identitiesDir, params.identity);
2202
+ const farmRoot = import_node_path7.default.join(params.identitiesDir, params.identity);
2110
2203
  const lock = acquireIdentityLock({
2111
2204
  identity: params.identity,
2112
2205
  dir: params.identitiesDir,
@@ -2165,16 +2258,16 @@ function executeReconciliation(params) {
2165
2258
  });
2166
2259
  continue;
2167
2260
  }
2168
- const from = import_node_path6.default.join(params.farmRoot, action.rel);
2169
- const canonical = import_node_path6.default.join(params.claudeHome, action.rel);
2261
+ const from = import_node_path7.default.join(params.farmRoot, action.rel);
2262
+ const canonical = import_node_path7.default.join(params.claudeHome, action.rel);
2170
2263
  if (action.kind === "adopt") {
2171
- params.fs.mkdirp(import_node_path6.default.dirname(canonical));
2264
+ params.fs.mkdirp(import_node_path7.default.dirname(canonical));
2172
2265
  params.fs.copyRecursive(from, canonical);
2173
2266
  adopted.push(action.rel);
2174
2267
  continue;
2175
2268
  }
2176
2269
  const preserved = `${canonical}.farm-conflict-${String(params.nowMs)}`;
2177
- params.fs.mkdirp(import_node_path6.default.dirname(canonical));
2270
+ params.fs.mkdirp(import_node_path7.default.dirname(canonical));
2178
2271
  params.fs.copyRecursive(from, preserved);
2179
2272
  conflicts.push(action.rel);
2180
2273
  }
@@ -2199,7 +2292,7 @@ function farmAlreadyMatches(existing, next) {
2199
2292
  return existing.identity === next.identity && existing.claudeHome === next.claudeHome && sameStrings(existing.materialised, next.materialised) && sameLinks(existing.links, next.links);
2200
2293
  }
2201
2294
  function resyncFarm(params) {
2202
- const farmRoot = import_node_path6.default.join(params.identitiesDir, params.identity);
2295
+ const farmRoot = import_node_path7.default.join(params.identitiesDir, params.identity);
2203
2296
  const lock = acquireIdentityLock({
2204
2297
  identity: params.identity,
2205
2298
  dir: params.identitiesDir,
@@ -2279,8 +2372,8 @@ function resyncFarm(params) {
2279
2372
  diagnostics
2280
2373
  };
2281
2374
  }
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}`);
2375
+ const scratchRoot = import_node_path7.default.join(params.identitiesDir, `.${params.identity}.scratch.${params.uniqueSuffix}`);
2376
+ const previousRoot = import_node_path7.default.join(params.identitiesDir, `.${params.identity}.previous.${params.uniqueSuffix}`);
2284
2377
  buildScratchTree({ fs: params.fs, scratchRoot, plan: resolved.farm, manifest });
2285
2378
  const swap = swapIn({ fs: params.fs, farmRoot, scratchRoot, previousRoot, classification: params.classification });
2286
2379
  if (swap.retainedPrevious !== void 0) {
@@ -2709,7 +2802,7 @@ function providerBaseUrl(port, provider) {
2709
2802
  }
2710
2803
 
2711
2804
  // src/frontdoor/state.ts
2712
- var import_node_path7 = __toESM(require("node:path"), 1);
2805
+ var import_node_path8 = __toESM(require("node:path"), 1);
2713
2806
  var import_zod3 = require("zod");
2714
2807
  var FRONT_DOOR_PROTOCOL = 2;
2715
2808
  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 +2854,7 @@ function readFrontDoorState(fs12, stateFile) {
2761
2854
  }
2762
2855
  }
2763
2856
  function writeFrontDoorState(fs12, stateFile, state) {
2764
- fs12.mkdirp(import_node_path7.default.dirname(stateFile));
2857
+ fs12.mkdirp(import_node_path8.default.dirname(stateFile));
2765
2858
  fs12.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
2766
2859
  `);
2767
2860
  }
@@ -2771,7 +2864,7 @@ function frontDoorOrigin(state) {
2771
2864
  }
2772
2865
  function writeFrontDoorSession(fs12, sessionsDir, session) {
2773
2866
  fs12.mkdirPrivate(sessionsDir);
2774
- fs12.writeFilePrivate(import_node_path7.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2867
+ fs12.writeFilePrivate(import_node_path8.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2775
2868
  `);
2776
2869
  }
2777
2870
  function listFrontDoorSessions(fs12, sessionsDir) {
@@ -2781,7 +2874,7 @@ function listFrontDoorSessions(fs12, sessionsDir) {
2781
2874
  continue;
2782
2875
  }
2783
2876
  try {
2784
- const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs12.readFileUtf8(import_node_path7.default.join(sessionsDir, name)) ?? ""));
2877
+ const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs12.readFileUtf8(import_node_path8.default.join(sessionsDir, name)) ?? ""));
2785
2878
  if (parsed.success) {
2786
2879
  sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
2787
2880
  }
@@ -2792,7 +2885,7 @@ function listFrontDoorSessions(fs12, sessionsDir) {
2792
2885
  return sessions.sort((a, b) => a.pid - b.pid);
2793
2886
  }
2794
2887
  function removeFrontDoorSession(fs12, sessionsDir, pid) {
2795
- fs12.removeRecursive(import_node_path7.default.join(sessionsDir, `${String(pid)}.json`));
2888
+ fs12.removeRecursive(import_node_path8.default.join(sessionsDir, `${String(pid)}.json`));
2796
2889
  }
2797
2890
  function pruneDeadFrontDoorSessions(fs12, sessionsDir, isRunning) {
2798
2891
  const removed = [];
@@ -5198,7 +5291,7 @@ var import_node_crypto7 = require("node:crypto");
5198
5291
 
5199
5292
  // src/headroom/state.ts
5200
5293
  var import_node_crypto6 = require("node:crypto");
5201
- var import_node_path8 = __toESM(require("node:path"), 1);
5294
+ var import_node_path9 = __toESM(require("node:path"), 1);
5202
5295
  var import_zod5 = require("zod");
5203
5296
  var HEADROOM_ANTHROPIC_UPSTREAM = "https://api.anthropic.com";
5204
5297
  var HEADROOM_STATE_SCHEMA_VERSION = 2;
@@ -5239,7 +5332,7 @@ function readHeadroomState(fs12, stateFile) {
5239
5332
  }
5240
5333
  }
5241
5334
  function writeHeadroomState(fs12, stateFile, state) {
5242
- fs12.mkdirp(import_node_path8.default.dirname(stateFile));
5335
+ fs12.mkdirp(import_node_path9.default.dirname(stateFile));
5243
5336
  fs12.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
5244
5337
  `);
5245
5338
  }
@@ -5267,7 +5360,7 @@ function readAllProviders(fs12, providersDir) {
5267
5360
  continue;
5268
5361
  }
5269
5362
  try {
5270
- const parsed = parseJson(fs12.readFileUtf8(import_node_path8.default.join(providersDir, name)), ProviderSchema);
5363
+ const parsed = parseJson(fs12.readFileUtf8(import_node_path9.default.join(providersDir, name)), ProviderSchema);
5271
5364
  if (parsed !== void 0) {
5272
5365
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
5273
5366
  }
@@ -5279,11 +5372,11 @@ function readAllProviders(fs12, providersDir) {
5279
5372
  }
5280
5373
  function writeSession(fs12, sessionsDir, session) {
5281
5374
  fs12.mkdirp(sessionsDir);
5282
- fs12.writeFileUtf8(import_node_path8.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
5375
+ fs12.writeFileUtf8(import_node_path9.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
5283
5376
  `);
5284
5377
  }
5285
5378
  function removeSession(fs12, sessionsDir, pid) {
5286
- fs12.removeRecursive(import_node_path8.default.join(sessionsDir, `${String(pid)}.json`));
5379
+ fs12.removeRecursive(import_node_path9.default.join(sessionsDir, `${String(pid)}.json`));
5287
5380
  }
5288
5381
  function listSessions(fs12, sessionsDir) {
5289
5382
  const sessions = [];
@@ -5292,7 +5385,7 @@ function listSessions(fs12, sessionsDir) {
5292
5385
  continue;
5293
5386
  }
5294
5387
  try {
5295
- const parsed = parseJson(fs12.readFileUtf8(import_node_path8.default.join(sessionsDir, name)), HeadroomSessionSchema);
5388
+ const parsed = parseJson(fs12.readFileUtf8(import_node_path9.default.join(sessionsDir, name)), HeadroomSessionSchema);
5296
5389
  if (parsed !== void 0) {
5297
5390
  sessions.push(parsed);
5298
5391
  }
@@ -5397,10 +5490,10 @@ function ensureFrontDoor(params) {
5397
5490
  }
5398
5491
 
5399
5492
  // src/usage/read.ts
5400
- var import_node_path10 = __toESM(require("node:path"), 1);
5493
+ var import_node_path11 = __toESM(require("node:path"), 1);
5401
5494
 
5402
5495
  // src/usage/account.ts
5403
- var import_node_path9 = __toESM(require("node:path"), 1);
5496
+ var import_node_path10 = __toESM(require("node:path"), 1);
5404
5497
 
5405
5498
  // src/usage/schema.ts
5406
5499
  var import_zod6 = require("zod");
@@ -5566,7 +5659,7 @@ function isIdentityName(name) {
5566
5659
  return IdentitySchema.shape.name.safeParse(name).success;
5567
5660
  }
5568
5661
  function claudeJsonPath(identitiesDir, identity) {
5569
- return import_node_path9.default.join(identitiesDir, identity, CLAUDE_JSON);
5662
+ return import_node_path10.default.join(identitiesDir, identity, CLAUDE_JSON);
5570
5663
  }
5571
5664
  function readAccountMetadata(fs12, identitiesDir, identity) {
5572
5665
  if (!isIdentityName(identity)) {
@@ -5625,7 +5718,7 @@ function readUsageLog(fs12, logDir, options = {}) {
5625
5718
  if (sinceMs !== void 0 && segment.endsAt <= sinceMs) {
5626
5719
  continue;
5627
5720
  }
5628
- const contents = fs12.readFileUtf8(import_node_path10.default.join(logDir, segment.name));
5721
+ const contents = fs12.readFileUtf8(import_node_path11.default.join(logDir, segment.name));
5629
5722
  if (contents === void 0) {
5630
5723
  continue;
5631
5724
  }
@@ -5667,7 +5760,7 @@ function snapshotPath(snapshotsDir, identity) {
5667
5760
  if (!isIdentityName(identity)) {
5668
5761
  throw new Error(`"${identity}" is not a valid identity name.`);
5669
5762
  }
5670
- return import_node_path10.default.join(snapshotsDir, `${identity}.json`);
5763
+ return import_node_path11.default.join(snapshotsDir, `${identity}.json`);
5671
5764
  }
5672
5765
  function readUsageSnapshot(fs12, snapshotsDir, identity) {
5673
5766
  const file = snapshotPath(snapshotsDir, identity);
@@ -6001,7 +6094,7 @@ function rankPool(input) {
6001
6094
  }
6002
6095
 
6003
6096
  // src/usage/poolPick.ts
6004
- var import_node_path11 = __toESM(require("node:path"), 1);
6097
+ var import_node_path12 = __toESM(require("node:path"), 1);
6005
6098
  var import_zod9 = require("zod");
6006
6099
 
6007
6100
  // src/usage/store.ts
@@ -6068,13 +6161,13 @@ function recordStickyPick(fs12, picksFile, directory, identity, nowMs) {
6068
6161
  const current = readPicksFile(fs12, picksFile).file.picks;
6069
6162
  const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
6070
6163
  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));
6164
+ fs12.mkdirPrivate(import_node_path12.default.dirname(picksFile));
6072
6165
  fs12.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
6073
6166
  `);
6074
6167
  }
6075
6168
 
6076
6169
  // src/launcher/identity.ts
6077
- var import_node_path12 = __toESM(require("node:path"), 1);
6170
+ var import_node_path13 = __toESM(require("node:path"), 1);
6078
6171
  function poolNameOf(selector) {
6079
6172
  return selector.startsWith(POOL_SELECTOR_PREFIX) ? selector.slice(POOL_SELECTOR_PREFIX.length) : void 0;
6080
6173
  }
@@ -6123,7 +6216,7 @@ function decideConfigProfile(params) {
6123
6216
  return { source: "none" };
6124
6217
  }
6125
6218
  function loadIdentity(identitiesDir, name, fs12) {
6126
- return loadConfigFile(import_node_path12.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
6219
+ return loadConfigFile(import_node_path13.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
6127
6220
  }
6128
6221
 
6129
6222
  // src/launcher/pool.ts
@@ -6338,7 +6431,7 @@ function hashSettings(settings) {
6338
6431
  }
6339
6432
 
6340
6433
  // src/headroom/socket.ts
6341
- var import_node_path13 = __toESM(require("node:path"), 1);
6434
+ var import_node_path14 = __toESM(require("node:path"), 1);
6342
6435
  var GROUP_OR_OTHER_BITS = 63;
6343
6436
  var OCTAL_RADIX = 8;
6344
6437
  var MODE_DIGITS = 4;
@@ -6347,7 +6440,7 @@ var HEADROOM_SOCKET_NAME = /^(\d+)\.sock$/;
6347
6440
  var UNIX_SOCKET_PATH_MAX_BYTES = 103;
6348
6441
  var PLATFORMS_WITHOUT_UNIX_SOCKETS = ["win32"];
6349
6442
  function headroomSocketPath(paths, supervisorPid) {
6350
- return import_node_path13.default.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
6443
+ return import_node_path14.default.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
6351
6444
  }
6352
6445
  function platformRefusal(platform) {
6353
6446
  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 +6489,7 @@ function pruneStaleHeadroomSockets(fs12, paths, isRunning) {
6396
6489
  if (pid === void 0 || isRunning(Number.parseInt(pid, 10))) {
6397
6490
  continue;
6398
6491
  }
6399
- fs12.removeRecursive(import_node_path13.default.join(paths.headroomSocketDir, name));
6492
+ fs12.removeRecursive(import_node_path14.default.join(paths.headroomSocketDir, name));
6400
6493
  removed.push(name);
6401
6494
  }
6402
6495
  return removed;
@@ -6450,7 +6543,7 @@ function versionSatisfies(version, source) {
6450
6543
  if (installed === void 0 || wanted === void 0) {
6451
6544
  return true;
6452
6545
  }
6453
- const cmp = compareVersions(installed, wanted);
6546
+ const cmp = compareVersions2(installed, wanted);
6454
6547
  switch (specifier[0]) {
6455
6548
  case "==":
6456
6549
  return cmp === 0;
@@ -6465,7 +6558,7 @@ function versionSatisfies(version, source) {
6465
6558
  case "<":
6466
6559
  return cmp < 0;
6467
6560
  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;
6561
+ return compareVersions2(installed.slice(0, Math.max(0, wanted.length - 1)), wanted.slice(0, Math.max(0, wanted.length - 1))) === 0 && cmp >= 0;
6469
6562
  default:
6470
6563
  return true;
6471
6564
  }
@@ -6477,7 +6570,7 @@ function parseVersion(input) {
6477
6570
  }
6478
6571
  return match[0].split(".").map((part) => Number.parseInt(part, 10));
6479
6572
  }
6480
- function compareVersions(a, b) {
6573
+ function compareVersions2(a, b) {
6481
6574
  for (let index = 0; index < Math.max(a.length, b.length); index += 1) {
6482
6575
  const left = a[index] ?? 0;
6483
6576
  const right = b[index] ?? 0;
@@ -6719,15 +6812,15 @@ function evaluateAmbientCredentialGuard(params) {
6719
6812
 
6720
6813
  // src/paths.ts
6721
6814
  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) {
6815
+ var import_node_os2 = __toESM(require("node:os"), 1);
6816
+ var import_node_path15 = __toESM(require("node:path"), 1);
6817
+ function resolveAgentShimHome(env = process.env, home = import_node_os2.default.homedir(), isDirectory = isExistingDirectory) {
6725
6818
  const fromEnv = env.AGENT_SHIM_HOME;
6726
6819
  if (fromEnv !== void 0 && fromEnv !== "") {
6727
6820
  return fromEnv;
6728
6821
  }
6729
- const current = import_node_path14.default.join(home, HOME_DIRNAME);
6730
- const legacy = import_node_path14.default.join(home, LEGACY_HOME_DIRNAME);
6822
+ const current = import_node_path15.default.join(home, HOME_DIRNAME);
6823
+ const legacy = import_node_path15.default.join(home, LEGACY_HOME_DIRNAME);
6731
6824
  return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
6732
6825
  }
6733
6826
  function isExistingDirectory(candidate) {
@@ -6738,40 +6831,40 @@ function resolveClaudeHome() {
6738
6831
  if (fromEnv !== void 0 && fromEnv !== "") {
6739
6832
  return fromEnv;
6740
6833
  }
6741
- return import_node_path14.default.join(import_node_os.default.homedir(), ".claude");
6834
+ return import_node_path15.default.join(import_node_os2.default.homedir(), ".claude");
6742
6835
  }
6743
6836
  function buildLayoutPaths(root) {
6744
6837
  return {
6745
6838
  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")
6839
+ identitiesDir: import_node_path15.default.join(root, "identities"),
6840
+ configProfilesDir: import_node_path15.default.join(root, "config-profiles"),
6841
+ providersDir: import_node_path15.default.join(root, "providers"),
6842
+ directoryRulesFile: import_node_path15.default.join(root, "directory-rules.json"),
6843
+ activeIdentityFile: import_node_path15.default.join(root, "active-identity"),
6844
+ globalConfigFile: import_node_path15.default.join(root, "config.json"),
6845
+ categoriesLocalFile: import_node_path15.default.join(root, "categories.local.json"),
6846
+ claudeShimFile: import_node_path15.default.join(root, "claude-shim.json"),
6847
+ headroomDir: import_node_path15.default.join(root, "headroom"),
6848
+ headroomStateFile: import_node_path15.default.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
6849
+ headroomSocketDir: import_node_path15.default.join(root, "headroom", "run"),
6850
+ headroomLockFile: import_node_path15.default.join(root, "headroom", "start.lock"),
6851
+ headroomSessionsDir: import_node_path15.default.join(root, "headroom", "sessions"),
6852
+ logsDir: import_node_path15.default.join(root, "logs"),
6853
+ headroomLogPath: import_node_path15.default.join(root, "logs", "headroom.log"),
6854
+ frontdoorDir: import_node_path15.default.join(root, "frontdoor"),
6855
+ frontdoorCaDir: import_node_path15.default.join(root, "frontdoor", "ca"),
6856
+ frontdoorCaCertFile: import_node_path15.default.join(root, "frontdoor", "ca", "ca.pem"),
6857
+ frontdoorCaKeyFile: import_node_path15.default.join(root, "frontdoor", "ca", "ca.key"),
6858
+ frontdoorCaBundlesDir: import_node_path15.default.join(root, "frontdoor", "ca", "bundles"),
6859
+ frontdoorStateFile: import_node_path15.default.join(root, "frontdoor", "state.json"),
6860
+ frontdoorLockFile: import_node_path15.default.join(root, "frontdoor", "start.lock"),
6861
+ frontdoorControlTokenFile: import_node_path15.default.join(root, "frontdoor", "control-token"),
6862
+ frontdoorSessionsDir: import_node_path15.default.join(root, "frontdoor", "sessions"),
6863
+ frontdoorLogPath: import_node_path15.default.join(root, "logs", "frontdoor.log"),
6864
+ usageDir: import_node_path15.default.join(root, "usage"),
6865
+ usageLogDir: import_node_path15.default.join(root, "usage", "log"),
6866
+ usageSnapshotsDir: import_node_path15.default.join(root, "usage", "snapshots"),
6867
+ usagePicksFile: import_node_path15.default.join(root, "usage", "picks.json")
6775
6868
  };
6776
6869
  }
6777
6870
  function resolveLayoutPaths() {
@@ -6780,11 +6873,11 @@ function resolveLayoutPaths() {
6780
6873
 
6781
6874
  // src/identityStore.ts
6782
6875
  var import_node_fs4 = __toESM(require("node:fs"), 1);
6783
- var import_node_path16 = __toESM(require("node:path"), 1);
6876
+ var import_node_path17 = __toESM(require("node:path"), 1);
6784
6877
 
6785
6878
  // src/configProfilesStore.ts
6786
6879
  var import_node_fs3 = __toESM(require("node:fs"), 1);
6787
- var import_node_path15 = __toESM(require("node:path"), 1);
6880
+ var import_node_path16 = __toESM(require("node:path"), 1);
6788
6881
  var ProfileNotFoundError = class extends CliError {
6789
6882
  constructor(profileName) {
6790
6883
  super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
@@ -6810,7 +6903,7 @@ var InvalidCategoryNameError = class extends CliError {
6810
6903
  categoryName;
6811
6904
  };
6812
6905
  function profileJsonPath(paths, name) {
6813
- return import_node_path15.default.join(paths.configProfilesDir, `${name}.json`);
6906
+ return import_node_path16.default.join(paths.configProfilesDir, `${name}.json`);
6814
6907
  }
6815
6908
  function profileExists(paths, name) {
6816
6909
  return import_node_fs3.default.existsSync(profileJsonPath(paths, name));
@@ -6998,7 +7091,7 @@ var InvalidIdentityNameError = class extends CliError {
6998
7091
  attemptedName;
6999
7092
  };
7000
7093
  function identityJsonPath(paths, name) {
7001
- return import_node_path16.default.join(paths.identitiesDir, name, "identity.json");
7094
+ return import_node_path17.default.join(paths.identitiesDir, name, "identity.json");
7002
7095
  }
7003
7096
  function identityExists(paths, name) {
7004
7097
  return import_node_fs4.default.existsSync(identityJsonPath(paths, name));
@@ -7099,7 +7192,7 @@ function setIdentityCredential(paths, identityName, change) {
7099
7192
  });
7100
7193
  }
7101
7194
  function belongsToIdentity(entry, name) {
7102
- return entry === name || entry === import_node_path16.default.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
7195
+ return entry === name || entry === import_node_path17.default.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
7103
7196
  }
7104
7197
  function removeIdentity(paths, name) {
7105
7198
  if (!identityExists(paths, name)) {
@@ -7107,7 +7200,7 @@ function removeIdentity(paths, name) {
7107
7200
  }
7108
7201
  for (const entry of import_node_fs4.default.readdirSync(paths.identitiesDir)) {
7109
7202
  if (belongsToIdentity(entry, name)) {
7110
- import_node_fs4.default.rmSync(import_node_path16.default.join(paths.identitiesDir, entry), { recursive: true, force: true });
7203
+ import_node_fs4.default.rmSync(import_node_path17.default.join(paths.identitiesDir, entry), { recursive: true, force: true });
7111
7204
  }
7112
7205
  }
7113
7206
  if (readActiveIdentity(paths) === name) {
@@ -7117,7 +7210,7 @@ function removeIdentity(paths, name) {
7117
7210
 
7118
7211
  // src/providersStore.ts
7119
7212
  var import_node_fs5 = __toESM(require("node:fs"), 1);
7120
- var import_node_path17 = __toESM(require("node:path"), 1);
7213
+ var import_node_path18 = __toESM(require("node:path"), 1);
7121
7214
 
7122
7215
  // src/credentialCache.ts
7123
7216
  var import_zod12 = require("zod");
@@ -7382,7 +7475,7 @@ var InvalidProviderNameError = class extends CliError {
7382
7475
  };
7383
7476
  var PROVIDER_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._@-]*$/;
7384
7477
  function providerJsonPath(paths, name) {
7385
- return import_node_path17.default.join(paths.providersDir, `${name}.json`);
7478
+ return import_node_path18.default.join(paths.providersDir, `${name}.json`);
7386
7479
  }
7387
7480
  function providerExists(paths, name) {
7388
7481
  return import_node_fs5.default.existsSync(providerJsonPath(paths, name));
@@ -7458,7 +7551,7 @@ function readProvider(paths, name) {
7458
7551
  return parseProviderFile(filePath, raw);
7459
7552
  }
7460
7553
  function loadProvider(providersDir, name, port) {
7461
- const filePath = import_node_path17.default.join(providersDir, `${name}.json`);
7554
+ const filePath = import_node_path18.default.join(providersDir, `${name}.json`);
7462
7555
  const raw = port.readConfigFile(filePath);
7463
7556
  return raw === void 0 ? void 0 : parseProviderFile(filePath, raw);
7464
7557
  }
@@ -7713,21 +7806,21 @@ function removeDirectoryRule(paths, rulePath) {
7713
7806
  var import_node_os4 = __toESM(require("node:os"), 1);
7714
7807
 
7715
7808
  // src/launcher/cascade.ts
7716
- var import_node_path19 = __toESM(require("node:path"), 1);
7809
+ var import_node_path20 = __toESM(require("node:path"), 1);
7717
7810
 
7718
7811
  // src/pathNorm.ts
7719
- var import_node_path18 = __toESM(require("node:path"), 1);
7812
+ var import_node_path19 = __toESM(require("node:path"), 1);
7720
7813
  function expandTilde(value, home) {
7721
7814
  if (value === "~") {
7722
7815
  return home;
7723
7816
  }
7724
7817
  if (value.startsWith("~/")) {
7725
- return import_node_path18.default.join(home, value.slice(2));
7818
+ return import_node_path19.default.join(home, value.slice(2));
7726
7819
  }
7727
7820
  return value;
7728
7821
  }
7729
7822
  function normaliseRulePath(rulePath, home) {
7730
- return import_node_path18.default.resolve(expandTilde(rulePath, home));
7823
+ return import_node_path19.default.resolve(expandTilde(rulePath, home));
7731
7824
  }
7732
7825
 
7733
7826
  // src/launcher/cascade.ts
@@ -7737,7 +7830,7 @@ function loadCascadeInput(params) {
7737
7830
  const globalConfig = loadConfigFile(params.paths.globalConfigFile, GlobalConfigSchema, params.read);
7738
7831
  const directoryRules = loadConfigFile(params.paths.directoryRulesFile, DirectoryRulesSchema, params.read);
7739
7832
  const loadProfile = (name) => {
7740
- const filepath = import_node_path19.default.join(params.paths.configProfilesDir, `${name}.json`);
7833
+ const filepath = import_node_path20.default.join(params.paths.configProfilesDir, `${name}.json`);
7741
7834
  const loaded = loadConfigFile(filepath, ConfigProfileSchema, params.read);
7742
7835
  if (loaded === void 0) {
7743
7836
  return void 0;
@@ -7752,8 +7845,8 @@ function loadCascadeInput(params) {
7752
7845
  });
7753
7846
  const levels = [];
7754
7847
  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);
7848
+ const portable = loadConfigFile(import_node_path20.default.join(dir, PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path20.default.join(dir, LEGACY_PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read);
7849
+ const portableLocal = loadConfigFile(import_node_path20.default.join(dir, PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path20.default.join(dir, LEGACY_PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read);
7757
7850
  const rules = (directoryRules?.config.rules ?? []).map((rule, index) => ({ rule, index })).filter(({ rule }) => normaliseRulePath(rule.path, params.home) === dir).map(({ rule, index }) => {
7758
7851
  const entryOrder = directoryRules?.ruleEntryOrders[index];
7759
7852
  return {
@@ -7804,7 +7897,7 @@ function readDirectorySelections(loaded) {
7804
7897
  // src/realCredentialCache.ts
7805
7898
  var import_node_child_process = require("node:child_process");
7806
7899
  var import_node_fs6 = __toESM(require("node:fs"), 1);
7807
- var import_node_path20 = __toESM(require("node:path"), 1);
7900
+ var import_node_path21 = __toESM(require("node:path"), 1);
7808
7901
  var KEYCHAIN_CACHE_SERVICE = "agent-shim-credential-cache";
7809
7902
  var CACHE_DIR_MODE = 448;
7810
7903
  var CACHE_FILE_MODE = 384;
@@ -7831,8 +7924,8 @@ function security(args, stdin) {
7831
7924
  return { status: result.status, stdout: result.stdout };
7832
7925
  }
7833
7926
  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));
7927
+ const dir = import_node_path21.default.join(root, "credential-cache");
7928
+ const filePath = (owner) => import_node_path21.default.join(dir, cacheFileNameFor(owner));
7836
7929
  return {
7837
7930
  read(store, owner) {
7838
7931
  if (store === "file") {
@@ -7886,70 +7979,6 @@ var import_node_fs7 = __toESM(require("node:fs"), 1);
7886
7979
  var import_node_os3 = __toESM(require("node:os"), 1);
7887
7980
  var import_node_path22 = __toESM(require("node:path"), 1);
7888
7981
  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
7982
  function isEnoent3(error) {
7954
7983
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
7955
7984
  }
@@ -8351,13 +8380,17 @@ function realContentSourcePath() {
8351
8380
  return resolveContentSourcePath({ isSea: (0, import_node_sea.isSea)(), execPath: process.execPath, argv1: process.argv[1] });
8352
8381
  }
8353
8382
  function realResolveClaudeBinary(isOwnBinary) {
8354
- return () => discoverClaudeBinary({
8383
+ return (request4) => discoverClaudeBinary({
8355
8384
  listVersionsDir,
8356
8385
  pathDirs: (process.env.PATH ?? "").split(import_node_path22.default.delimiter).filter((dir) => dir !== ""),
8357
8386
  findExecutableInDir,
8358
- isOwnBinary
8387
+ isOwnBinary,
8388
+ ...request4?.version === void 0 ? {} : { version: request4.version }
8359
8389
  });
8360
8390
  }
8391
+ function realInstalledClaudeVersions() {
8392
+ return installedVersions(listVersionsDir(defaultVersionsDir()));
8393
+ }
8361
8394
 
8362
8395
  // src/checkReport.ts
8363
8396
  var import_node_path23 = __toESM(require("node:path"), 1);
@@ -8399,6 +8432,34 @@ function parseEnvBool(variable, value) {
8399
8432
  return parsed;
8400
8433
  }
8401
8434
 
8435
+ // src/launcher/claudeVersion.ts
8436
+ var InvalidClaudeVersionError = class extends UsageError {
8437
+ constructor(value, origin) {
8438
+ super(`${origin} names Claude Code version "${value}", which is not an exact dotted-numeric version such as 2.1.220.`);
8439
+ this.value = value;
8440
+ this.origin = origin;
8441
+ this.name = "InvalidClaudeVersionError";
8442
+ }
8443
+ value;
8444
+ origin;
8445
+ };
8446
+ function validated(value, origin) {
8447
+ if (!NUMERIC_DOTTED_VERSION_RE.test(value)) {
8448
+ throw new InvalidClaudeVersionError(value, origin);
8449
+ }
8450
+ return value;
8451
+ }
8452
+ function resolveClaudeVersion(params) {
8453
+ if (params.flag !== void 0) {
8454
+ return { version: validated(params.flag, "--claude-version"), source: "flag" };
8455
+ }
8456
+ const fromEnv = params.env.AGENT_SHIM_CLAUDE_VERSION;
8457
+ if (fromEnv !== void 0 && fromEnv !== "") {
8458
+ return { version: validated(fromEnv, "AGENT_SHIM_CLAUDE_VERSION"), source: "environment" };
8459
+ }
8460
+ return params.cascade === void 0 ? void 0 : { version: params.cascade, source: "cascade" };
8461
+ }
8462
+
8402
8463
  // src/checkReport.ts
8403
8464
  var HISTORY_PROJECTS_KEY_PREFIX = "history/projects/";
8404
8465
  function projectFragmentOf(rawKey) {
@@ -8549,6 +8610,19 @@ function buildCredentialReport(provider, identity, identityName, cacheEnv) {
8549
8610
  ...identityCached === void 0 ? {} : { identityCached }
8550
8611
  };
8551
8612
  }
8613
+ function buildClaudeVersionReport(params, cascadePin) {
8614
+ const installed = params.installedClaudeVersions;
8615
+ if (installed === void 0) {
8616
+ return void 0;
8617
+ }
8618
+ const pin = resolveClaudeVersion({ env: params.env, ...cascadePin === void 0 ? {} : { cascade: cascadePin } });
8619
+ const highestInstalled = installed.at(-1);
8620
+ return {
8621
+ ...pin === void 0 ? {} : { pinned: { ...pin, installed: installed.includes(pin.version) } },
8622
+ ...highestInstalled === void 0 ? {} : { highestInstalled },
8623
+ installed
8624
+ };
8625
+ }
8552
8626
  function runCheck(params) {
8553
8627
  const facts = buildEntryFacts({
8554
8628
  fs: params.farmFs,
@@ -8573,6 +8647,7 @@ function runCheck(params) {
8573
8647
  const settingsShared = resolved.flattened.categories.get("settings") ?? SHIPPED_CATEGORY_DEFAULTS.settings;
8574
8648
  const settingsExposure = inspectSettingsExposure({ settingsShared, files: params.settingsFiles });
8575
8649
  const keychain = params.platform === "darwin" && params.run !== void 0 && params.farmRoot !== void 0 ? lookupKeychainService(params.run, params.farmRoot) : void 0;
8650
+ const claudeVersion = buildClaudeVersionReport(params, resolved.flattened.launch.claudeVersion);
8576
8651
  return {
8577
8652
  ...params.identityName === void 0 ? {} : { identityName: params.identityName },
8578
8653
  identitySource: params.identitySource,
@@ -8585,7 +8660,8 @@ function runCheck(params) {
8585
8660
  ambientCredential,
8586
8661
  ...keychain === void 0 ? {} : { keychain },
8587
8662
  settingsExposure,
8588
- credential: buildCredentialReport(params.provider, params.identity, params.identityName, params.credentialCache)
8663
+ credential: buildCredentialReport(params.provider, params.identity, params.identityName, params.credentialCache),
8664
+ ...claudeVersion === void 0 ? {} : { claudeVersion }
8589
8665
  };
8590
8666
  }
8591
8667
  function formatCheckReport(report) {
@@ -8634,6 +8710,17 @@ function formatCheckReport(report) {
8634
8710
  if (credential.applies === "stored-login") {
8635
8711
  lines.push(" The identity's stored login (no credential block applies).");
8636
8712
  }
8713
+ if (report.claudeVersion !== void 0) {
8714
+ lines.push("", "Claude Code version:");
8715
+ const { pinned, highestInstalled, installed } = report.claudeVersion;
8716
+ if (pinned !== void 0) {
8717
+ lines.push(
8718
+ 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(", ")}`
8719
+ );
8720
+ } else {
8721
+ 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)`);
8722
+ }
8723
+ }
8637
8724
  lines.push("", "Ambient-credential exposure:");
8638
8725
  lines.push(
8639
8726
  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 +8759,12 @@ function checkReportToJson(report) {
8672
8759
  ambientCredential: report.ambientCredential.ok ? { ok: true } : { ok: false, variable: report.ambientCredential.variable, message: report.ambientCredential.message },
8673
8760
  ...report.keychain === void 0 ? {} : { keychain: report.keychain },
8674
8761
  settingsExposure: report.settingsExposure,
8675
- credential: report.credential
8762
+ credential: report.credential,
8763
+ ...report.claudeVersion === void 0 ? {} : { claudeVersion: report.claudeVersion }
8676
8764
  };
8677
8765
  }
8678
8766
  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;
8767
+ 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
8768
  }
8681
8769
  function loadCheckProvider(paths, name) {
8682
8770
  let definition;
@@ -8762,6 +8850,7 @@ function collectCheckReport(params) {
8762
8850
  settingsFiles,
8763
8851
  run: realRunPort,
8764
8852
  credentialCache: realCredentialCacheEnv(paths),
8853
+ installedClaudeVersions: realInstalledClaudeVersions(),
8765
8854
  ...farmRoot === void 0 ? {} : { farmRoot },
8766
8855
  platform: process.platform,
8767
8856
  ...provider === void 0 ? {} : { provider }
@@ -8913,13 +9002,13 @@ function pushProvider(push, entry, cacheEnv) {
8913
9002
  push("provider", "fail", new LegacyProviderFileError(entry.path, conversion).message, entry.name);
8914
9003
  return;
8915
9004
  }
8916
- const validated = ProviderSchema.safeParse(parsed);
8917
- if (!validated.success) {
8918
- push("provider", "fail", new ConfigValidationError(entry.path, validated.error.issues).message, entry.name);
9005
+ const validated2 = ProviderSchema.safeParse(parsed);
9006
+ if (!validated2.success) {
9007
+ push("provider", "fail", new ConfigValidationError(entry.path, validated2.error.issues).message, entry.name);
8919
9008
  return;
8920
9009
  }
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);
9010
+ const cache = cacheClause(cacheEnv, `provider ${entry.name}`, validated2.data.credential);
9011
+ push("provider", cache.unreadable ? "fail" : "pass", `${entry.name} is valid (${describeProviderEndpoint(validated2.data)}, credential ${describeCredential(validated2.data.credential)})${cache.text}.`, entry.name);
8923
9012
  }
8924
9013
  function pushLegacyName(push, params) {
8925
9014
  const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
@@ -8943,6 +9032,13 @@ function runDoctor(params) {
8943
9032
  const push = (section, severity, message, subject) => {
8944
9033
  findings.push({ section, severity, message, ...subject === void 0 ? {} : { subject } });
8945
9034
  };
9035
+ const checkPin = (section, subject, where, version) => {
9036
+ const installed = params.installedClaudeVersions;
9037
+ if (version === void 0 || installed === void 0 || installed.includes(version)) {
9038
+ return;
9039
+ }
9040
+ 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);
9041
+ };
8946
9042
  const ambient = detectAmbientCredential(params.env);
8947
9043
  if (ambient === void 0) {
8948
9044
  push("ambient-credential", "pass", "No ambient-credential environment variable is set.");
@@ -8975,12 +9071,13 @@ function runDoctor(params) {
8975
9071
  pushLegacyName(push, params);
8976
9072
  const profileSources = /* @__PURE__ */ new Map();
8977
9073
  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);
9074
+ const validated2 = validateJson(ConfigProfileSchema, entry);
9075
+ if (!validated2.ok) {
9076
+ push("config-profile", "fail", validated2.message, entry.name);
8981
9077
  continue;
8982
9078
  }
8983
- profileSources.set(entry.name, { name: entry.name, profile: validated.data });
9079
+ profileSources.set(entry.name, { name: entry.name, profile: validated2.data });
9080
+ checkPin("config-profile", entry.name, `Configuration profile "${entry.name}"`, validated2.data.launch?.claudeVersion);
8984
9081
  }
8985
9082
  const loadProfile = (name) => profileSources.get(name);
8986
9083
  for (const name of profileSources.keys()) {
@@ -8996,13 +9093,13 @@ function runDoctor(params) {
8996
9093
  const validProfileNames = new Set(profileSources.keys());
8997
9094
  const validIdentityNames = /* @__PURE__ */ new Set();
8998
9095
  for (const entry of params.identities) {
8999
- const validated = validateJson(IdentitySchema, entry);
9000
- if (!validated.ok) {
9001
- push("identity", "fail", validated.message, entry.name);
9096
+ const validated2 = validateJson(IdentitySchema, entry);
9097
+ if (!validated2.ok) {
9098
+ push("identity", "fail", validated2.message, entry.name);
9002
9099
  continue;
9003
9100
  }
9004
9101
  validIdentityNames.add(entry.name);
9005
- const defaultProfile = validated.data.defaultConfigProfile;
9102
+ const defaultProfile = validated2.data.defaultConfigProfile;
9006
9103
  if (defaultProfile !== void 0 && !validProfileNames.has(defaultProfile)) {
9007
9104
  push(
9008
9105
  "identity",
@@ -9011,7 +9108,7 @@ function runDoctor(params) {
9011
9108
  entry.name
9012
9109
  );
9013
9110
  } else {
9014
- const credential = validated.data.credential;
9111
+ const credential = validated2.data.credential;
9015
9112
  const cache = credential === void 0 ? { text: "", unreadable: false } : cacheClause(params.credentialCache, `identity ${entry.name}`, credential);
9016
9113
  push(
9017
9114
  "identity",
@@ -9049,12 +9146,12 @@ function runDoctor(params) {
9049
9146
  if (params.directoryRules.raw === void 0) {
9050
9147
  push("directory-rules", "pass", "No directory-rules.json configured.");
9051
9148
  } else {
9052
- const validated = validateJson(DirectoryRulesSchema, params.directoryRules);
9053
- if (!validated.ok) {
9054
- push("directory-rules", "fail", validated.message);
9149
+ const validated2 = validateJson(DirectoryRulesSchema, params.directoryRules);
9150
+ if (!validated2.ok) {
9151
+ push("directory-rules", "fail", validated2.message);
9055
9152
  } else {
9056
9153
  push("directory-rules", "pass", `${params.directoryRules.path} is valid.`);
9057
- for (const rule of validated.data.rules) {
9154
+ for (const rule of validated2.data.rules) {
9058
9155
  const badRefs = [];
9059
9156
  if (rule.identity !== void 0 && !selectionExists(rule.identity)) {
9060
9157
  badRefs.push(poolNameOf(rule.identity) === void 0 ? `identity "${rule.identity}"` : `pool "${poolNameOf(rule.identity) ?? ""}"`);
@@ -9062,6 +9159,7 @@ function runDoctor(params) {
9062
9159
  if (rule.configProfile !== void 0 && !validProfileNames.has(rule.configProfile)) {
9063
9160
  badRefs.push(`configuration profile "${rule.configProfile}"`);
9064
9161
  }
9162
+ checkPin("directory-rules", rule.path, `Rule for "${rule.path}"`, rule.launch?.claudeVersion);
9065
9163
  if (badRefs.length > 0) {
9066
9164
  push("directory-rules", "fail", `Rule for "${rule.path}" names ${badRefs.join(" and ")}, which do not exist.`, rule.path);
9067
9165
  } else {
@@ -9073,11 +9171,11 @@ function runDoctor(params) {
9073
9171
  if (params.globalConfig.raw === void 0) {
9074
9172
  push("global-config", "pass", "No config.json configured.");
9075
9173
  } else {
9076
- const validated = validateJson(GlobalConfigSchema, params.globalConfig);
9077
- if (!validated.ok) {
9078
- push("global-config", "fail", validated.message);
9174
+ const validated2 = validateJson(GlobalConfigSchema, params.globalConfig);
9175
+ if (!validated2.ok) {
9176
+ push("global-config", "fail", validated2.message);
9079
9177
  } else {
9080
- const defaultProfile = validated.data.defaultConfigProfile;
9178
+ const defaultProfile = validated2.data.defaultConfigProfile;
9081
9179
  if (defaultProfile !== void 0 && !validProfileNames.has(defaultProfile)) {
9082
9180
  push(
9083
9181
  "global-config",
@@ -9086,27 +9184,28 @@ function runDoctor(params) {
9086
9184
  );
9087
9185
  } else {
9088
9186
  push("global-config", "pass", `${params.globalConfig.path} is valid.`);
9187
+ checkPin("global-config", void 0, "config.json", validated2.data.launch?.claudeVersion);
9089
9188
  }
9090
9189
  }
9091
9190
  }
9092
9191
  if (params.categoriesLocal.raw === void 0) {
9093
9192
  push("categories-local", "pass", "No categories.local.json configured.");
9094
9193
  } else {
9095
- const validated = validateJson(CategoryClassificationOverlaySchema, params.categoriesLocal);
9194
+ const validated2 = validateJson(CategoryClassificationOverlaySchema, params.categoriesLocal);
9096
9195
  push(
9097
9196
  "categories-local",
9098
- validated.ok ? "pass" : "fail",
9099
- validated.ok ? `${params.categoriesLocal.path} is valid.` : validated.message
9197
+ validated2.ok ? "pass" : "fail",
9198
+ validated2.ok ? `${params.categoriesLocal.path} is valid.` : validated2.message
9100
9199
  );
9101
9200
  }
9102
9201
  if (params.headroom.state.raw === void 0) {
9103
9202
  push("headroom", "pass", "No headroom daemon has ever run; nothing to check.");
9104
9203
  } else {
9105
- const validated = validateJson(HeadroomStateSchema, params.headroom.state);
9106
- if (!validated.ok) {
9107
- push("headroom", "fail", validated.message);
9204
+ const validated2 = validateJson(HeadroomStateSchema, params.headroom.state);
9205
+ if (!validated2.ok) {
9206
+ push("headroom", "fail", validated2.message);
9108
9207
  } else {
9109
- const state = validated.data;
9208
+ const state = validated2.data;
9110
9209
  const supervisorAlive = state.supervisorPid !== void 0 && params.headroom.isRunning(state.supervisorPid);
9111
9210
  const headroomAlive = state.headroomPid !== void 0 && params.headroom.isRunning(state.headroomPid);
9112
9211
  if (state.supervisorPid === void 0) {
@@ -9276,6 +9375,7 @@ function collectDoctorReport(params) {
9276
9375
  const report = runDoctor({
9277
9376
  env: params.env,
9278
9377
  credentialCache: realCredentialCacheEnv(paths),
9378
+ installedClaudeVersions: realInstalledClaudeVersions(),
9279
9379
  identities,
9280
9380
  configProfiles,
9281
9381
  providers,
@@ -9325,7 +9425,7 @@ var ConflictingIdentityError = class extends UsageError {
9325
9425
  positional;
9326
9426
  flag;
9327
9427
  };
9328
- var VALUED_FLAGS = ["--identity", "--config-profile", "--provider", "--category", "--share", "--hide"];
9428
+ var VALUED_FLAGS = ["--identity", "--config-profile", "--provider", "--claude-version", "--category", "--share", "--hide"];
9329
9429
  var BOOLEAN_FLAGS = [
9330
9430
  { flag: "--headroom", key: "headroom" },
9331
9431
  { flag: "--track-usage", key: "trackUsage" },
@@ -9371,6 +9471,7 @@ function parseLauncherArgv(argv) {
9371
9471
  let flagIdentity;
9372
9472
  let configProfile;
9373
9473
  let provider;
9474
+ let claudeVersion;
9374
9475
  const booleans = {};
9375
9476
  const categoryFlags = [];
9376
9477
  const shareFlags = [];
@@ -9425,6 +9526,9 @@ function parseLauncherArgv(argv) {
9425
9526
  case "--provider":
9426
9527
  provider = value;
9427
9528
  break;
9529
+ case "--claude-version":
9530
+ claudeVersion = value;
9531
+ break;
9428
9532
  case "--category":
9429
9533
  categoryFlags.push(value);
9430
9534
  break;
@@ -9446,6 +9550,7 @@ function parseLauncherArgv(argv) {
9446
9550
  ...identity === void 0 ? {} : { identity },
9447
9551
  ...configProfile === void 0 ? {} : { configProfile },
9448
9552
  ...provider === void 0 ? {} : { provider },
9553
+ ...claudeVersion === void 0 ? {} : { claudeVersion },
9449
9554
  ...native ? { native: true } : {},
9450
9555
  ...booleans,
9451
9556
  categoryFlags,
@@ -9907,7 +10012,11 @@ function prepareLaunch(params) {
9907
10012
  } else if (params.farm !== void 0) {
9908
10013
  cascadeLaunch = flattenLayers(assembleCascade(params.farm.loadCascade(configProfileDecision.name, cliOverride)).layers, { home: params.farm.home }).launch;
9909
10014
  }
9910
- const discovered = params.resolveClaudeBinary();
10015
+ const pinnedVersion = resolveClaudeVersion({ env, ...parsedArgv.claudeVersion === void 0 ? {} : { flag: parsedArgv.claudeVersion }, ...cascadeLaunch?.claudeVersion === void 0 ? {} : { cascade: cascadeLaunch.claudeVersion } });
10016
+ const discovered = params.resolveClaudeBinary(pinnedVersion === void 0 ? void 0 : { version: pinnedVersion.version });
10017
+ if (pinnedVersion !== void 0) {
10018
+ log.info(`agent-shim: Claude Code ${pinnedVersion.version} (pinned by ${pinnedVersion.source})`);
10019
+ }
9911
10020
  const resolvedFlags = resolveLaunchFlags({
9912
10021
  env,
9913
10022
  // A pool pick reads the usage the front door records, so a pool launch records its own unless something says otherwise.