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.mjs CHANGED
@@ -54,8 +54,113 @@ var categories_default_default = {
54
54
  };
55
55
 
56
56
  // src/config/schema.ts
57
- import path from "node:path";
57
+ import path2 from "node:path";
58
58
  import { z } from "zod";
59
+
60
+ // src/versionDiscovery.ts
61
+ import os from "node:os";
62
+ import path from "node:path";
63
+
64
+ // src/cliError.ts
65
+ var EXIT_FAILURE = 1;
66
+ var EXIT_USAGE = 2;
67
+ var CliError = class extends Error {
68
+ /** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
69
+ exitCode = EXIT_FAILURE;
70
+ };
71
+ var UsageError = class extends CliError {
72
+ exitCode = EXIT_USAGE;
73
+ constructor(message) {
74
+ super(message);
75
+ this.name = "UsageError";
76
+ }
77
+ };
78
+
79
+ // src/versionDiscovery.ts
80
+ function defaultVersionsDir() {
81
+ return path.join(os.homedir(), ".local", "share", "claude", "versions");
82
+ }
83
+ var NUMERIC_DOTTED_VERSION_RE = /^\d+(?:\.\d+)*$/;
84
+ function isNumericDottedVersion(name) {
85
+ return NUMERIC_DOTTED_VERSION_RE.test(name);
86
+ }
87
+ function compareVersions(a, b) {
88
+ if (!isNumericDottedVersion(a)) {
89
+ throw new Error(`compareVersions: "${a}" is not a valid plain dotted-numeric version`);
90
+ }
91
+ if (!isNumericDottedVersion(b)) {
92
+ throw new Error(`compareVersions: "${b}" is not a valid plain dotted-numeric version`);
93
+ }
94
+ const segmentsA = a.split(".").map(Number);
95
+ const segmentsB = b.split(".").map(Number);
96
+ const length = Math.max(segmentsA.length, segmentsB.length);
97
+ for (let i = 0; i < length; i += 1) {
98
+ const segmentA = segmentsA[i] ?? 0;
99
+ const segmentB = segmentsB[i] ?? 0;
100
+ if (segmentA !== segmentB) {
101
+ return segmentA - segmentB;
102
+ }
103
+ }
104
+ return 0;
105
+ }
106
+ var ClaudeVersionNotInstalledError = class extends CliError {
107
+ constructor(version, versionsDir, installed) {
108
+ super(
109
+ `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)."
110
+ );
111
+ this.version = version;
112
+ this.versionsDir = versionsDir;
113
+ this.installed = installed;
114
+ this.name = "ClaudeVersionNotInstalledError";
115
+ }
116
+ version;
117
+ versionsDir;
118
+ installed;
119
+ };
120
+ function installedVersions(entries) {
121
+ return entries.filter((entry) => entry.isFile && entry.isExecutable && entry.sizeBytes > 0 && isNumericDottedVersion(entry.name)).map((entry) => entry.name).sort(compareVersions);
122
+ }
123
+ function pickHighestVersion(entries) {
124
+ const candidates = entries.filter(
125
+ (entry) => entry.isFile && entry.isExecutable && entry.sizeBytes > 0 && isNumericDottedVersion(entry.name)
126
+ );
127
+ if (candidates.length === 0) {
128
+ return void 0;
129
+ }
130
+ return candidates.reduce(
131
+ (highest, candidate) => compareVersions(candidate.name, highest.name) > 0 ? candidate : highest
132
+ ).name;
133
+ }
134
+ function discoverClaudeBinary(options) {
135
+ const versionsDir = options.versionsDir ?? defaultVersionsDir();
136
+ const entries = options.listVersionsDir(versionsDir);
137
+ const highestVersion = pickHighestVersion(entries);
138
+ if (options.version !== void 0) {
139
+ const installed = installedVersions(entries);
140
+ if (!installed.includes(options.version)) {
141
+ throw new ClaudeVersionNotInstalledError(options.version, versionsDir, installed);
142
+ }
143
+ return { path: path.join(versionsDir, options.version), source: "versions-dir", version: options.version };
144
+ }
145
+ if (highestVersion !== void 0) {
146
+ return {
147
+ path: path.join(versionsDir, highestVersion),
148
+ source: "versions-dir",
149
+ version: highestVersion
150
+ };
151
+ }
152
+ for (const dir of options.pathDirs) {
153
+ const found = options.findExecutableInDir(dir, "claude");
154
+ if (found !== void 0 && !options.isOwnBinary(found)) {
155
+ return { path: found, source: "path-fallback" };
156
+ }
157
+ }
158
+ throw new Error(
159
+ `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.`
160
+ );
161
+ }
162
+
163
+ // src/config/schema.ts
59
164
  var CATEGORY_NAMES = ["secret", "runtime", "history", "knowledge", "settings"];
60
165
  var OVERRIDABLE_CATEGORIES = ["runtime", "history", "knowledge", "settings"];
61
166
  function isOverridableCategory(name) {
@@ -99,7 +204,9 @@ var LaunchSchema = z.strictObject({
99
204
  remoteControl: z.boolean().optional(),
100
205
  provider: z.string().min(1).optional(),
101
206
  headroom: z.boolean().optional(),
102
- trackUsage: z.boolean().optional()
207
+ trackUsage: z.boolean().optional(),
208
+ /** 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. */
209
+ claudeVersion: z.string().regex(NUMERIC_DOTTED_VERSION_RE, "must be an exact dotted-numeric Claude Code version such as 2.1.220").optional()
103
210
  });
104
211
  var CREDENTIAL_TARGETS = ["bearer", "apiKey", "oauthToken"];
105
212
  var PROVIDER_CREDENTIAL_TARGETS = ["bearer", "apiKey"];
@@ -118,7 +225,7 @@ var CommandSourceOptions = {
118
225
  var CredentialSourceSchema = z.union([
119
226
  z.strictObject({ env: z.string().min(1) }),
120
227
  z.strictObject({
121
- file: z.string().min(1).refine((filePath) => filePath.startsWith("~/") || path.isAbsolute(filePath), {
228
+ file: z.string().min(1).refine((filePath) => filePath.startsWith("~/") || path2.isAbsolute(filePath), {
122
229
  message: "a credential file must be an absolute or ~-rooted path, since a launch can start in any directory"
123
230
  })
124
231
  }),
@@ -297,28 +404,11 @@ var SHIPPED_CATEGORY_DEFAULTS = Object.freeze({
297
404
 
298
405
  // src/config/store.ts
299
406
  import fs from "node:fs";
300
- import path2 from "node:path";
407
+ import path3 from "node:path";
301
408
  import { randomUUID } from "node:crypto";
302
409
 
303
410
  // src/config/load.ts
304
411
  import { cosmiconfigSync } from "cosmiconfig";
305
-
306
- // src/cliError.ts
307
- var EXIT_FAILURE = 1;
308
- var EXIT_USAGE = 2;
309
- var CliError = class extends Error {
310
- /** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
311
- exitCode = EXIT_FAILURE;
312
- };
313
- var UsageError = class extends CliError {
314
- exitCode = EXIT_USAGE;
315
- constructor(message) {
316
- super(message);
317
- this.name = "UsageError";
318
- }
319
- };
320
-
321
- // src/config/load.ts
322
412
  function createExplorer(moduleName = "agent-shim") {
323
413
  return cosmiconfigSync(moduleName, { searchPlaces: [] });
324
414
  }
@@ -439,9 +529,9 @@ function readJson(filePath, schema, storeFs = nodeStoreFs) {
439
529
  return result.data;
440
530
  }
441
531
  function writeTextAtomic(filePath, contents, storeFs = nodeStoreFs) {
442
- const dir = path2.dirname(filePath);
532
+ const dir = path3.dirname(filePath);
443
533
  storeFs.mkdirSync(dir);
444
- const tempPath = path2.join(dir, `.${path2.basename(filePath)}.${String(process.pid)}.${randomUUID()}.tmp`);
534
+ const tempPath = path3.join(dir, `.${path3.basename(filePath)}.${String(process.pid)}.${randomUUID()}.tmp`);
445
535
  storeFs.writeFileUtf8(tempPath, contents);
446
536
  try {
447
537
  storeFs.renameSync(tempPath, filePath);
@@ -465,9 +555,9 @@ function applyPatch(filePath, schema, patch, options = {}) {
465
555
  if (!result.success) {
466
556
  throw new ConfigValidationError(filePath, result.error.issues);
467
557
  }
468
- const validated = result.data;
469
- writeJsonAtomic(filePath, validated, storeFs);
470
- return validated;
558
+ const validated2 = result.data;
559
+ writeJsonAtomic(filePath, validated2, storeFs);
560
+ return validated2;
471
561
  }
472
562
 
473
563
  // src/config/classify.ts
@@ -890,6 +980,9 @@ function flattenLayers(layers, options) {
890
980
  if (layer.launch.trackUsage !== void 0) {
891
981
  launch.trackUsage = layer.launch.trackUsage;
892
982
  }
983
+ if (layer.launch.claudeVersion !== void 0) {
984
+ launch.claudeVersion = layer.launch.claudeVersion;
985
+ }
893
986
  }
894
987
  if (layer.entries === void 0) {
895
988
  continue;
@@ -1127,7 +1220,7 @@ function dedupeDiagnostics(diagnostics) {
1127
1220
  }
1128
1221
 
1129
1222
  // src/resolve/plan.ts
1130
- import path3 from "node:path";
1223
+ import path4 from "node:path";
1131
1224
  function parentOf(rel) {
1132
1225
  const index = rel.lastIndexOf("/");
1133
1226
  return index === -1 ? "" : rel.slice(0, index);
@@ -1177,7 +1270,7 @@ function planFarm(params) {
1177
1270
  }
1178
1271
  return value;
1179
1272
  };
1180
- const linkTarget = (rel) => path3.join(params.facts.claudeHome, rel);
1273
+ const linkTarget = (rel) => path4.join(params.facts.claudeHome, rel);
1181
1274
  const visit = (rel) => {
1182
1275
  const fact = params.facts.entries.get(rel);
1183
1276
  const decision = params.decisions.get(rel);
@@ -1255,7 +1348,7 @@ function descendPolicy(rules) {
1255
1348
  }
1256
1349
 
1257
1350
  // src/resolve/walk.ts
1258
- import path4 from "node:path";
1351
+ import path5 from "node:path";
1259
1352
 
1260
1353
  // src/resolve/extends.ts
1261
1354
  function lineariseProfile(rootName, load) {
@@ -1323,10 +1416,10 @@ function profileLayers(rootName, load, startId) {
1323
1416
 
1324
1417
  // src/resolve/walk.ts
1325
1418
  function walkDirectoryAncestors(cwd, options) {
1326
- const limit = path4.resolve(options.limit ?? options.home);
1419
+ const limit = path5.resolve(options.limit ?? options.home);
1327
1420
  const isReadable = options.isReadable ?? (() => true);
1328
1421
  const collected = [];
1329
- let current = path4.resolve(cwd);
1422
+ let current = path5.resolve(cwd);
1330
1423
  for (; ; ) {
1331
1424
  if (!isReadable(current)) {
1332
1425
  break;
@@ -1335,7 +1428,7 @@ function walkDirectoryAncestors(cwd, options) {
1335
1428
  if (current === limit) {
1336
1429
  break;
1337
1430
  }
1338
- const parent = path4.dirname(current);
1431
+ const parent = path5.dirname(current);
1339
1432
  if (parent === current) {
1340
1433
  break;
1341
1434
  }
@@ -1459,7 +1552,7 @@ function resolveDecisions(input) {
1459
1552
  }
1460
1553
 
1461
1554
  // src/launcher/farm.ts
1462
- import path6 from "node:path";
1555
+ import path7 from "node:path";
1463
1556
  import { z as z2 } from "zod";
1464
1557
 
1465
1558
  // src/resolve/reconcile.ts
@@ -1563,7 +1656,7 @@ var LEGACY_FARM_MANIFEST_FILENAME = ".claude-use-farm.json";
1563
1656
 
1564
1657
  // src/launcher/lock.ts
1565
1658
  import { randomUUID as randomUUID2 } from "node:crypto";
1566
- import path5 from "node:path";
1659
+ import path6 from "node:path";
1567
1660
  var DEFAULT_STALE_AFTER_MS = 12e4;
1568
1661
  var DEFAULT_RETRY_DELAY_MS = 50;
1569
1662
  var DEFAULT_MAX_ATTEMPTS = 200;
@@ -1582,7 +1675,7 @@ var IdentityLockBusyError = class extends CliError {
1582
1675
  holderPid;
1583
1676
  };
1584
1677
  function identityLockPath(dir, identity) {
1585
- return path5.join(dir, `.${identity}.lock`);
1678
+ return path6.join(dir, `.${identity}.lock`);
1586
1679
  }
1587
1680
  function parseLockRecord(raw) {
1588
1681
  if (raw === void 0) {
@@ -1661,7 +1754,7 @@ var FarmManifestSchema = z2.strictObject({
1661
1754
  links: z2.array(z2.strictObject({ rel: z2.string(), target: z2.string() }))
1662
1755
  });
1663
1756
  function readFarmManifest(fs12, farmRoot) {
1664
- const raw = fs12.readFileUtf8(path6.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs12.readFileUtf8(path6.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1757
+ const raw = fs12.readFileUtf8(path7.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs12.readFileUtf8(path7.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1665
1758
  if (raw === void 0) {
1666
1759
  return void 0;
1667
1760
  }
@@ -1677,7 +1770,7 @@ function readFarmManifest(fs12, farmRoot) {
1677
1770
  function buildEntryFacts(params) {
1678
1771
  const entries = /* @__PURE__ */ new Map();
1679
1772
  const visit = (rel) => {
1680
- const absolute = path6.join(params.claudeHome, rel);
1773
+ const absolute = path7.join(params.claudeHome, rel);
1681
1774
  const stat = params.fs.lstat(absolute);
1682
1775
  if (stat === void 0) {
1683
1776
  return void 0;
@@ -1720,7 +1813,7 @@ function buildEntryFacts(params) {
1720
1813
  };
1721
1814
  }
1722
1815
  function listSubtree(fs12, root, rel) {
1723
- const absolute = path6.join(root, rel);
1816
+ const absolute = path7.join(root, rel);
1724
1817
  const stat = fs12.lstat(absolute);
1725
1818
  if (stat === void 0) {
1726
1819
  return [];
@@ -1750,7 +1843,7 @@ function reconciliationScope(fs12, farmRoot, manifest) {
1750
1843
  if (manifest !== void 0) {
1751
1844
  return topLevelScopeRoots(manifest.materialised);
1752
1845
  }
1753
- return [...fs12.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs12.lstat(path6.join(farmRoot, name))?.kind === "dir").sort();
1846
+ return [...fs12.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs12.lstat(path7.join(farmRoot, name))?.kind === "dir").sort();
1754
1847
  }
1755
1848
  function collectFarmListing(fs12, farmRoot, scopeRoots) {
1756
1849
  return scopeRoots.flatMap((root) => listSubtree(fs12, farmRoot, root));
@@ -1758,7 +1851,7 @@ function collectFarmListing(fs12, farmRoot, scopeRoots) {
1758
1851
  function collectCanonicalCounterparts(fs12, claudeHome, farmListing) {
1759
1852
  const out = [];
1760
1853
  for (const entry of farmListing) {
1761
- const absolute = path6.join(claudeHome, entry.rel);
1854
+ const absolute = path7.join(claudeHome, entry.rel);
1762
1855
  const stat = fs12.lstat(absolute);
1763
1856
  if (stat === void 0) {
1764
1857
  continue;
@@ -1788,21 +1881,21 @@ function carryOver(params) {
1788
1881
  if (accounted.has(name)) {
1789
1882
  continue;
1790
1883
  }
1791
- const stat = params.fs.lstat(path6.join(params.previousRoot, name));
1884
+ const stat = params.fs.lstat(path7.join(params.previousRoot, name));
1792
1885
  if (stat === void 0 || stat.kind === "symlink") {
1793
1886
  continue;
1794
1887
  }
1795
- if (params.fs.lstat(path6.join(params.farmRoot, name)) !== void 0) {
1888
+ if (params.fs.lstat(path7.join(params.farmRoot, name)) !== void 0) {
1796
1889
  const category = params.classification === void 0 ? void 0 : classifyEntries([name], params.classification).classification.get(name);
1797
1890
  if (category === "runtime") {
1798
- params.fs.removeRecursive(path6.join(params.previousRoot, name));
1891
+ params.fs.removeRecursive(path7.join(params.previousRoot, name));
1799
1892
  autoResolved.push(name);
1800
1893
  continue;
1801
1894
  }
1802
1895
  collided.push(name);
1803
1896
  continue;
1804
1897
  }
1805
- params.fs.rename(path6.join(params.previousRoot, name), path6.join(params.farmRoot, name));
1898
+ params.fs.rename(path7.join(params.previousRoot, name), path7.join(params.farmRoot, name));
1806
1899
  carried.push(name);
1807
1900
  }
1808
1901
  return { carried, autoResolved, collided };
@@ -1810,9 +1903,9 @@ function carryOver(params) {
1810
1903
  function buildScratchTree(params) {
1811
1904
  params.fs.mkdirp(params.scratchRoot);
1812
1905
  for (const entry of params.plan.entries) {
1813
- const absolute = path6.join(params.scratchRoot, entry.rel);
1906
+ const absolute = path7.join(params.scratchRoot, entry.rel);
1814
1907
  if (entry.kind === "link") {
1815
- params.fs.mkdirp(path6.dirname(absolute));
1908
+ params.fs.mkdirp(path7.dirname(absolute));
1816
1909
  params.fs.symlink(entry.target, absolute);
1817
1910
  continue;
1818
1911
  }
@@ -1821,14 +1914,14 @@ function buildScratchTree(params) {
1821
1914
  }
1822
1915
  }
1823
1916
  params.fs.writeFileUtf8(
1824
- path6.join(params.scratchRoot, FARM_MANIFEST_FILENAME),
1917
+ path7.join(params.scratchRoot, FARM_MANIFEST_FILENAME),
1825
1918
  `${JSON.stringify(params.manifest, null, 2)}
1826
1919
  `
1827
1920
  );
1828
1921
  }
1829
1922
  function swapIn(params) {
1830
1923
  if (params.fs.lstat(params.farmRoot) === void 0) {
1831
- params.fs.mkdirp(path6.dirname(params.farmRoot));
1924
+ params.fs.mkdirp(path7.dirname(params.farmRoot));
1832
1925
  params.fs.rename(params.scratchRoot, params.farmRoot);
1833
1926
  return { carried: [], autoResolved: [], collided: [] };
1834
1927
  }
@@ -1852,14 +1945,14 @@ function recoverInterruptedSwap(params) {
1852
1945
  const names = [...params.fs.readdir(params.identitiesDir)].sort();
1853
1946
  const removedScratch = [];
1854
1947
  for (const name of names.filter((candidate) => candidate.startsWith(scratchPrefix))) {
1855
- params.fs.removeRecursive(path6.join(params.identitiesDir, name));
1948
+ params.fs.removeRecursive(path7.join(params.identitiesDir, name));
1856
1949
  removedScratch.push(name);
1857
1950
  }
1858
1951
  let previous = names.filter((candidate) => candidate.startsWith(previousPrefix));
1859
1952
  let restoredFrom;
1860
1953
  const first = previous[0];
1861
1954
  if (first !== void 0 && params.fs.lstat(params.farmRoot) === void 0) {
1862
- params.fs.rename(path6.join(params.identitiesDir, first), params.farmRoot);
1955
+ params.fs.rename(path7.join(params.identitiesDir, first), params.farmRoot);
1863
1956
  restoredFrom = first;
1864
1957
  previous = previous.slice(1);
1865
1958
  }
@@ -1867,7 +1960,7 @@ function recoverInterruptedSwap(params) {
1867
1960
  const autoResolved = [];
1868
1961
  const retained = [];
1869
1962
  for (const name of previous) {
1870
- const previousRoot = path6.join(params.identitiesDir, name);
1963
+ const previousRoot = path7.join(params.identitiesDir, name);
1871
1964
  const result = carryOver({
1872
1965
  fs: params.fs,
1873
1966
  previousRoot,
@@ -1892,7 +1985,7 @@ function recoverInterruptedSwap(params) {
1892
1985
  };
1893
1986
  }
1894
1987
  function recoverFarm(params) {
1895
- const farmRoot = path6.join(params.identitiesDir, params.identity);
1988
+ const farmRoot = path7.join(params.identitiesDir, params.identity);
1896
1989
  const lock = acquireIdentityLock({
1897
1990
  identity: params.identity,
1898
1991
  dir: params.identitiesDir,
@@ -1951,16 +2044,16 @@ function executeReconciliation(params) {
1951
2044
  });
1952
2045
  continue;
1953
2046
  }
1954
- const from = path6.join(params.farmRoot, action.rel);
1955
- const canonical = path6.join(params.claudeHome, action.rel);
2047
+ const from = path7.join(params.farmRoot, action.rel);
2048
+ const canonical = path7.join(params.claudeHome, action.rel);
1956
2049
  if (action.kind === "adopt") {
1957
- params.fs.mkdirp(path6.dirname(canonical));
2050
+ params.fs.mkdirp(path7.dirname(canonical));
1958
2051
  params.fs.copyRecursive(from, canonical);
1959
2052
  adopted.push(action.rel);
1960
2053
  continue;
1961
2054
  }
1962
2055
  const preserved = `${canonical}.farm-conflict-${String(params.nowMs)}`;
1963
- params.fs.mkdirp(path6.dirname(canonical));
2056
+ params.fs.mkdirp(path7.dirname(canonical));
1964
2057
  params.fs.copyRecursive(from, preserved);
1965
2058
  conflicts.push(action.rel);
1966
2059
  }
@@ -1985,7 +2078,7 @@ function farmAlreadyMatches(existing, next) {
1985
2078
  return existing.identity === next.identity && existing.claudeHome === next.claudeHome && sameStrings(existing.materialised, next.materialised) && sameLinks(existing.links, next.links);
1986
2079
  }
1987
2080
  function resyncFarm(params) {
1988
- const farmRoot = path6.join(params.identitiesDir, params.identity);
2081
+ const farmRoot = path7.join(params.identitiesDir, params.identity);
1989
2082
  const lock = acquireIdentityLock({
1990
2083
  identity: params.identity,
1991
2084
  dir: params.identitiesDir,
@@ -2065,8 +2158,8 @@ function resyncFarm(params) {
2065
2158
  diagnostics
2066
2159
  };
2067
2160
  }
2068
- const scratchRoot = path6.join(params.identitiesDir, `.${params.identity}.scratch.${params.uniqueSuffix}`);
2069
- const previousRoot = path6.join(params.identitiesDir, `.${params.identity}.previous.${params.uniqueSuffix}`);
2161
+ const scratchRoot = path7.join(params.identitiesDir, `.${params.identity}.scratch.${params.uniqueSuffix}`);
2162
+ const previousRoot = path7.join(params.identitiesDir, `.${params.identity}.previous.${params.uniqueSuffix}`);
2070
2163
  buildScratchTree({ fs: params.fs, scratchRoot, plan: resolved.farm, manifest });
2071
2164
  const swap = swapIn({ fs: params.fs, farmRoot, scratchRoot, previousRoot, classification: params.classification });
2072
2165
  if (swap.retainedPrevious !== void 0) {
@@ -2495,7 +2588,7 @@ function providerBaseUrl(port, provider) {
2495
2588
  }
2496
2589
 
2497
2590
  // src/frontdoor/state.ts
2498
- import path7 from "node:path";
2591
+ import path8 from "node:path";
2499
2592
  import { z as z3 } from "zod";
2500
2593
  var FRONT_DOOR_PROTOCOL = 2;
2501
2594
  var FrontDoorSessionSchema = z3.strictObject({ pid: z3.number().int().positive(), startedAt: z3.number(), token: z3.string().min(1) });
@@ -2547,7 +2640,7 @@ function readFrontDoorState(fs12, stateFile) {
2547
2640
  }
2548
2641
  }
2549
2642
  function writeFrontDoorState(fs12, stateFile, state) {
2550
- fs12.mkdirp(path7.dirname(stateFile));
2643
+ fs12.mkdirp(path8.dirname(stateFile));
2551
2644
  fs12.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
2552
2645
  `);
2553
2646
  }
@@ -2557,7 +2650,7 @@ function frontDoorOrigin(state) {
2557
2650
  }
2558
2651
  function writeFrontDoorSession(fs12, sessionsDir, session) {
2559
2652
  fs12.mkdirPrivate(sessionsDir);
2560
- fs12.writeFilePrivate(path7.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2653
+ fs12.writeFilePrivate(path8.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2561
2654
  `);
2562
2655
  }
2563
2656
  function listFrontDoorSessions(fs12, sessionsDir) {
@@ -2567,7 +2660,7 @@ function listFrontDoorSessions(fs12, sessionsDir) {
2567
2660
  continue;
2568
2661
  }
2569
2662
  try {
2570
- const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs12.readFileUtf8(path7.join(sessionsDir, name)) ?? ""));
2663
+ const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs12.readFileUtf8(path8.join(sessionsDir, name)) ?? ""));
2571
2664
  if (parsed.success) {
2572
2665
  sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
2573
2666
  }
@@ -2578,7 +2671,7 @@ function listFrontDoorSessions(fs12, sessionsDir) {
2578
2671
  return sessions.sort((a, b) => a.pid - b.pid);
2579
2672
  }
2580
2673
  function removeFrontDoorSession(fs12, sessionsDir, pid) {
2581
- fs12.removeRecursive(path7.join(sessionsDir, `${String(pid)}.json`));
2674
+ fs12.removeRecursive(path8.join(sessionsDir, `${String(pid)}.json`));
2582
2675
  }
2583
2676
  function pruneDeadFrontDoorSessions(fs12, sessionsDir, isRunning) {
2584
2677
  const removed = [];
@@ -4526,7 +4619,7 @@ function realConnectEffects() {
4526
4619
  // src/frontdoor/rcApi.ts
4527
4620
  import { createORPCClient, ORPCError } from "@orpc/client";
4528
4621
  import { RPCLink } from "@orpc/client/fetch";
4529
- import { eventIterator, os, withEventMeta } from "@orpc/server";
4622
+ import { eventIterator, os as os2, withEventMeta } from "@orpc/server";
4530
4623
  import { BodyLimitPlugin, RPCHandler } from "@orpc/server/node";
4531
4624
  import { Agent as Agent3, fetch as undiciFetch } from "undici";
4532
4625
 
@@ -4613,7 +4706,7 @@ var RcAnswerOutputSchema = z4.strictObject({
4613
4706
  var RC_ORPC_PATH_PREFIX = "/__agent-shim/orpc";
4614
4707
  var RC_SUBSCRIBER_BUFFER_EVENTS = 100;
4615
4708
  function createRcApiRouter(deps) {
4616
- const authed = os.$context().use(({ context, next }) => {
4709
+ const authed = os2.$context().use(({ context, next }) => {
4617
4710
  const presented = context.headers.authorization;
4618
4711
  const bearerPrefix = "bearer ".length;
4619
4712
  const token = typeof presented === "string" && presented.slice(0, bearerPrefix).toLowerCase() === "bearer " ? presented.slice(bearerPrefix) : void 0;
@@ -4984,7 +5077,7 @@ import { randomUUID as randomUUID3 } from "node:crypto";
4984
5077
 
4985
5078
  // src/headroom/state.ts
4986
5079
  import { createHash as createHash3 } from "node:crypto";
4987
- import path8 from "node:path";
5080
+ import path9 from "node:path";
4988
5081
  import { z as z5 } from "zod";
4989
5082
  var HEADROOM_ANTHROPIC_UPSTREAM = "https://api.anthropic.com";
4990
5083
  var HEADROOM_STATE_SCHEMA_VERSION = 2;
@@ -5025,7 +5118,7 @@ function readHeadroomState(fs12, stateFile) {
5025
5118
  }
5026
5119
  }
5027
5120
  function writeHeadroomState(fs12, stateFile, state) {
5028
- fs12.mkdirp(path8.dirname(stateFile));
5121
+ fs12.mkdirp(path9.dirname(stateFile));
5029
5122
  fs12.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
5030
5123
  `);
5031
5124
  }
@@ -5053,7 +5146,7 @@ function readAllProviders(fs12, providersDir) {
5053
5146
  continue;
5054
5147
  }
5055
5148
  try {
5056
- const parsed = parseJson(fs12.readFileUtf8(path8.join(providersDir, name)), ProviderSchema);
5149
+ const parsed = parseJson(fs12.readFileUtf8(path9.join(providersDir, name)), ProviderSchema);
5057
5150
  if (parsed !== void 0) {
5058
5151
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
5059
5152
  }
@@ -5065,11 +5158,11 @@ function readAllProviders(fs12, providersDir) {
5065
5158
  }
5066
5159
  function writeSession(fs12, sessionsDir, session) {
5067
5160
  fs12.mkdirp(sessionsDir);
5068
- fs12.writeFileUtf8(path8.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
5161
+ fs12.writeFileUtf8(path9.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
5069
5162
  `);
5070
5163
  }
5071
5164
  function removeSession(fs12, sessionsDir, pid) {
5072
- fs12.removeRecursive(path8.join(sessionsDir, `${String(pid)}.json`));
5165
+ fs12.removeRecursive(path9.join(sessionsDir, `${String(pid)}.json`));
5073
5166
  }
5074
5167
  function listSessions(fs12, sessionsDir) {
5075
5168
  const sessions = [];
@@ -5078,7 +5171,7 @@ function listSessions(fs12, sessionsDir) {
5078
5171
  continue;
5079
5172
  }
5080
5173
  try {
5081
- const parsed = parseJson(fs12.readFileUtf8(path8.join(sessionsDir, name)), HeadroomSessionSchema);
5174
+ const parsed = parseJson(fs12.readFileUtf8(path9.join(sessionsDir, name)), HeadroomSessionSchema);
5082
5175
  if (parsed !== void 0) {
5083
5176
  sessions.push(parsed);
5084
5177
  }
@@ -5183,10 +5276,10 @@ function ensureFrontDoor(params) {
5183
5276
  }
5184
5277
 
5185
5278
  // src/usage/read.ts
5186
- import path10 from "node:path";
5279
+ import path11 from "node:path";
5187
5280
 
5188
5281
  // src/usage/account.ts
5189
- import path9 from "node:path";
5282
+ import path10 from "node:path";
5190
5283
 
5191
5284
  // src/usage/schema.ts
5192
5285
  import { z as z6 } from "zod";
@@ -5352,7 +5445,7 @@ function isIdentityName(name) {
5352
5445
  return IdentitySchema.shape.name.safeParse(name).success;
5353
5446
  }
5354
5447
  function claudeJsonPath(identitiesDir, identity) {
5355
- return path9.join(identitiesDir, identity, CLAUDE_JSON);
5448
+ return path10.join(identitiesDir, identity, CLAUDE_JSON);
5356
5449
  }
5357
5450
  function readAccountMetadata(fs12, identitiesDir, identity) {
5358
5451
  if (!isIdentityName(identity)) {
@@ -5411,7 +5504,7 @@ function readUsageLog(fs12, logDir, options = {}) {
5411
5504
  if (sinceMs !== void 0 && segment.endsAt <= sinceMs) {
5412
5505
  continue;
5413
5506
  }
5414
- const contents = fs12.readFileUtf8(path10.join(logDir, segment.name));
5507
+ const contents = fs12.readFileUtf8(path11.join(logDir, segment.name));
5415
5508
  if (contents === void 0) {
5416
5509
  continue;
5417
5510
  }
@@ -5453,7 +5546,7 @@ function snapshotPath(snapshotsDir, identity) {
5453
5546
  if (!isIdentityName(identity)) {
5454
5547
  throw new Error(`"${identity}" is not a valid identity name.`);
5455
5548
  }
5456
- return path10.join(snapshotsDir, `${identity}.json`);
5549
+ return path11.join(snapshotsDir, `${identity}.json`);
5457
5550
  }
5458
5551
  function readUsageSnapshot(fs12, snapshotsDir, identity) {
5459
5552
  const file = snapshotPath(snapshotsDir, identity);
@@ -5787,7 +5880,7 @@ function rankPool(input) {
5787
5880
  }
5788
5881
 
5789
5882
  // src/usage/poolPick.ts
5790
- import path11 from "node:path";
5883
+ import path12 from "node:path";
5791
5884
  import { z as z9 } from "zod";
5792
5885
 
5793
5886
  // src/usage/store.ts
@@ -5854,13 +5947,13 @@ function recordStickyPick(fs12, picksFile, directory, identity, nowMs) {
5854
5947
  const current = readPicksFile(fs12, picksFile).file.picks;
5855
5948
  const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
5856
5949
  const next = { schemaVersion: SCHEMA_VERSION, picks: { ...Object.fromEntries(kept), [directory]: { identity, at: new Date(nowMs).toISOString() } } };
5857
- fs12.mkdirPrivate(path11.dirname(picksFile));
5950
+ fs12.mkdirPrivate(path12.dirname(picksFile));
5858
5951
  fs12.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
5859
5952
  `);
5860
5953
  }
5861
5954
 
5862
5955
  // src/launcher/identity.ts
5863
- import path12 from "node:path";
5956
+ import path13 from "node:path";
5864
5957
  function poolNameOf(selector) {
5865
5958
  return selector.startsWith(POOL_SELECTOR_PREFIX) ? selector.slice(POOL_SELECTOR_PREFIX.length) : void 0;
5866
5959
  }
@@ -5909,7 +6002,7 @@ function decideConfigProfile(params) {
5909
6002
  return { source: "none" };
5910
6003
  }
5911
6004
  function loadIdentity(identitiesDir, name, fs12) {
5912
- return loadConfigFile(path12.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
6005
+ return loadConfigFile(path13.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
5913
6006
  }
5914
6007
 
5915
6008
  // src/launcher/pool.ts
@@ -6124,7 +6217,7 @@ function hashSettings(settings) {
6124
6217
  }
6125
6218
 
6126
6219
  // src/headroom/socket.ts
6127
- import path13 from "node:path";
6220
+ import path14 from "node:path";
6128
6221
  var GROUP_OR_OTHER_BITS = 63;
6129
6222
  var OCTAL_RADIX = 8;
6130
6223
  var MODE_DIGITS = 4;
@@ -6133,7 +6226,7 @@ var HEADROOM_SOCKET_NAME = /^(\d+)\.sock$/;
6133
6226
  var UNIX_SOCKET_PATH_MAX_BYTES = 103;
6134
6227
  var PLATFORMS_WITHOUT_UNIX_SOCKETS = ["win32"];
6135
6228
  function headroomSocketPath(paths, supervisorPid) {
6136
- return path13.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
6229
+ return path14.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
6137
6230
  }
6138
6231
  function platformRefusal(platform) {
6139
6232
  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;
@@ -6182,7 +6275,7 @@ function pruneStaleHeadroomSockets(fs12, paths, isRunning) {
6182
6275
  if (pid === void 0 || isRunning(Number.parseInt(pid, 10))) {
6183
6276
  continue;
6184
6277
  }
6185
- fs12.removeRecursive(path13.join(paths.headroomSocketDir, name));
6278
+ fs12.removeRecursive(path14.join(paths.headroomSocketDir, name));
6186
6279
  removed.push(name);
6187
6280
  }
6188
6281
  return removed;
@@ -6236,7 +6329,7 @@ function versionSatisfies(version, source) {
6236
6329
  if (installed === void 0 || wanted === void 0) {
6237
6330
  return true;
6238
6331
  }
6239
- const cmp = compareVersions(installed, wanted);
6332
+ const cmp = compareVersions2(installed, wanted);
6240
6333
  switch (specifier[0]) {
6241
6334
  case "==":
6242
6335
  return cmp === 0;
@@ -6251,7 +6344,7 @@ function versionSatisfies(version, source) {
6251
6344
  case "<":
6252
6345
  return cmp < 0;
6253
6346
  case "~=":
6254
- return compareVersions(installed.slice(0, Math.max(0, wanted.length - 1)), wanted.slice(0, Math.max(0, wanted.length - 1))) === 0 && cmp >= 0;
6347
+ return compareVersions2(installed.slice(0, Math.max(0, wanted.length - 1)), wanted.slice(0, Math.max(0, wanted.length - 1))) === 0 && cmp >= 0;
6255
6348
  default:
6256
6349
  return true;
6257
6350
  }
@@ -6263,7 +6356,7 @@ function parseVersion(input) {
6263
6356
  }
6264
6357
  return match[0].split(".").map((part) => Number.parseInt(part, 10));
6265
6358
  }
6266
- function compareVersions(a, b) {
6359
+ function compareVersions2(a, b) {
6267
6360
  for (let index = 0; index < Math.max(a.length, b.length); index += 1) {
6268
6361
  const left = a[index] ?? 0;
6269
6362
  const right = b[index] ?? 0;
@@ -6505,15 +6598,15 @@ function evaluateAmbientCredentialGuard(params) {
6505
6598
 
6506
6599
  // src/paths.ts
6507
6600
  import fs3 from "node:fs";
6508
- import os2 from "node:os";
6509
- import path14 from "node:path";
6510
- function resolveAgentShimHome(env = process.env, home = os2.homedir(), isDirectory = isExistingDirectory) {
6601
+ import os3 from "node:os";
6602
+ import path15 from "node:path";
6603
+ function resolveAgentShimHome(env = process.env, home = os3.homedir(), isDirectory = isExistingDirectory) {
6511
6604
  const fromEnv = env.AGENT_SHIM_HOME;
6512
6605
  if (fromEnv !== void 0 && fromEnv !== "") {
6513
6606
  return fromEnv;
6514
6607
  }
6515
- const current = path14.join(home, HOME_DIRNAME);
6516
- const legacy = path14.join(home, LEGACY_HOME_DIRNAME);
6608
+ const current = path15.join(home, HOME_DIRNAME);
6609
+ const legacy = path15.join(home, LEGACY_HOME_DIRNAME);
6517
6610
  return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
6518
6611
  }
6519
6612
  function isExistingDirectory(candidate) {
@@ -6524,40 +6617,40 @@ function resolveClaudeHome() {
6524
6617
  if (fromEnv !== void 0 && fromEnv !== "") {
6525
6618
  return fromEnv;
6526
6619
  }
6527
- return path14.join(os2.homedir(), ".claude");
6620
+ return path15.join(os3.homedir(), ".claude");
6528
6621
  }
6529
6622
  function buildLayoutPaths(root) {
6530
6623
  return {
6531
6624
  root,
6532
- identitiesDir: path14.join(root, "identities"),
6533
- configProfilesDir: path14.join(root, "config-profiles"),
6534
- providersDir: path14.join(root, "providers"),
6535
- directoryRulesFile: path14.join(root, "directory-rules.json"),
6536
- activeIdentityFile: path14.join(root, "active-identity"),
6537
- globalConfigFile: path14.join(root, "config.json"),
6538
- categoriesLocalFile: path14.join(root, "categories.local.json"),
6539
- claudeShimFile: path14.join(root, "claude-shim.json"),
6540
- headroomDir: path14.join(root, "headroom"),
6541
- headroomStateFile: path14.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
6542
- headroomSocketDir: path14.join(root, "headroom", "run"),
6543
- headroomLockFile: path14.join(root, "headroom", "start.lock"),
6544
- headroomSessionsDir: path14.join(root, "headroom", "sessions"),
6545
- logsDir: path14.join(root, "logs"),
6546
- headroomLogPath: path14.join(root, "logs", "headroom.log"),
6547
- frontdoorDir: path14.join(root, "frontdoor"),
6548
- frontdoorCaDir: path14.join(root, "frontdoor", "ca"),
6549
- frontdoorCaCertFile: path14.join(root, "frontdoor", "ca", "ca.pem"),
6550
- frontdoorCaKeyFile: path14.join(root, "frontdoor", "ca", "ca.key"),
6551
- frontdoorCaBundlesDir: path14.join(root, "frontdoor", "ca", "bundles"),
6552
- frontdoorStateFile: path14.join(root, "frontdoor", "state.json"),
6553
- frontdoorLockFile: path14.join(root, "frontdoor", "start.lock"),
6554
- frontdoorControlTokenFile: path14.join(root, "frontdoor", "control-token"),
6555
- frontdoorSessionsDir: path14.join(root, "frontdoor", "sessions"),
6556
- frontdoorLogPath: path14.join(root, "logs", "frontdoor.log"),
6557
- usageDir: path14.join(root, "usage"),
6558
- usageLogDir: path14.join(root, "usage", "log"),
6559
- usageSnapshotsDir: path14.join(root, "usage", "snapshots"),
6560
- usagePicksFile: path14.join(root, "usage", "picks.json")
6625
+ identitiesDir: path15.join(root, "identities"),
6626
+ configProfilesDir: path15.join(root, "config-profiles"),
6627
+ providersDir: path15.join(root, "providers"),
6628
+ directoryRulesFile: path15.join(root, "directory-rules.json"),
6629
+ activeIdentityFile: path15.join(root, "active-identity"),
6630
+ globalConfigFile: path15.join(root, "config.json"),
6631
+ categoriesLocalFile: path15.join(root, "categories.local.json"),
6632
+ claudeShimFile: path15.join(root, "claude-shim.json"),
6633
+ headroomDir: path15.join(root, "headroom"),
6634
+ headroomStateFile: path15.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
6635
+ headroomSocketDir: path15.join(root, "headroom", "run"),
6636
+ headroomLockFile: path15.join(root, "headroom", "start.lock"),
6637
+ headroomSessionsDir: path15.join(root, "headroom", "sessions"),
6638
+ logsDir: path15.join(root, "logs"),
6639
+ headroomLogPath: path15.join(root, "logs", "headroom.log"),
6640
+ frontdoorDir: path15.join(root, "frontdoor"),
6641
+ frontdoorCaDir: path15.join(root, "frontdoor", "ca"),
6642
+ frontdoorCaCertFile: path15.join(root, "frontdoor", "ca", "ca.pem"),
6643
+ frontdoorCaKeyFile: path15.join(root, "frontdoor", "ca", "ca.key"),
6644
+ frontdoorCaBundlesDir: path15.join(root, "frontdoor", "ca", "bundles"),
6645
+ frontdoorStateFile: path15.join(root, "frontdoor", "state.json"),
6646
+ frontdoorLockFile: path15.join(root, "frontdoor", "start.lock"),
6647
+ frontdoorControlTokenFile: path15.join(root, "frontdoor", "control-token"),
6648
+ frontdoorSessionsDir: path15.join(root, "frontdoor", "sessions"),
6649
+ frontdoorLogPath: path15.join(root, "logs", "frontdoor.log"),
6650
+ usageDir: path15.join(root, "usage"),
6651
+ usageLogDir: path15.join(root, "usage", "log"),
6652
+ usageSnapshotsDir: path15.join(root, "usage", "snapshots"),
6653
+ usagePicksFile: path15.join(root, "usage", "picks.json")
6561
6654
  };
6562
6655
  }
6563
6656
  function resolveLayoutPaths() {
@@ -6566,11 +6659,11 @@ function resolveLayoutPaths() {
6566
6659
 
6567
6660
  // src/identityStore.ts
6568
6661
  import fs5 from "node:fs";
6569
- import path16 from "node:path";
6662
+ import path17 from "node:path";
6570
6663
 
6571
6664
  // src/configProfilesStore.ts
6572
6665
  import fs4 from "node:fs";
6573
- import path15 from "node:path";
6666
+ import path16 from "node:path";
6574
6667
  var ProfileNotFoundError = class extends CliError {
6575
6668
  constructor(profileName) {
6576
6669
  super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
@@ -6596,7 +6689,7 @@ var InvalidCategoryNameError = class extends CliError {
6596
6689
  categoryName;
6597
6690
  };
6598
6691
  function profileJsonPath(paths, name) {
6599
- return path15.join(paths.configProfilesDir, `${name}.json`);
6692
+ return path16.join(paths.configProfilesDir, `${name}.json`);
6600
6693
  }
6601
6694
  function profileExists(paths, name) {
6602
6695
  return fs4.existsSync(profileJsonPath(paths, name));
@@ -6784,7 +6877,7 @@ var InvalidIdentityNameError = class extends CliError {
6784
6877
  attemptedName;
6785
6878
  };
6786
6879
  function identityJsonPath(paths, name) {
6787
- return path16.join(paths.identitiesDir, name, "identity.json");
6880
+ return path17.join(paths.identitiesDir, name, "identity.json");
6788
6881
  }
6789
6882
  function identityExists(paths, name) {
6790
6883
  return fs5.existsSync(identityJsonPath(paths, name));
@@ -6885,7 +6978,7 @@ function setIdentityCredential(paths, identityName, change) {
6885
6978
  });
6886
6979
  }
6887
6980
  function belongsToIdentity(entry, name) {
6888
- return entry === name || entry === path16.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
6981
+ return entry === name || entry === path17.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
6889
6982
  }
6890
6983
  function removeIdentity(paths, name) {
6891
6984
  if (!identityExists(paths, name)) {
@@ -6893,7 +6986,7 @@ function removeIdentity(paths, name) {
6893
6986
  }
6894
6987
  for (const entry of fs5.readdirSync(paths.identitiesDir)) {
6895
6988
  if (belongsToIdentity(entry, name)) {
6896
- fs5.rmSync(path16.join(paths.identitiesDir, entry), { recursive: true, force: true });
6989
+ fs5.rmSync(path17.join(paths.identitiesDir, entry), { recursive: true, force: true });
6897
6990
  }
6898
6991
  }
6899
6992
  if (readActiveIdentity(paths) === name) {
@@ -6903,7 +6996,7 @@ function removeIdentity(paths, name) {
6903
6996
 
6904
6997
  // src/providersStore.ts
6905
6998
  import fs6 from "node:fs";
6906
- import path17 from "node:path";
6999
+ import path18 from "node:path";
6907
7000
 
6908
7001
  // src/credentialCache.ts
6909
7002
  import { z as z12 } from "zod";
@@ -7168,7 +7261,7 @@ var InvalidProviderNameError = class extends CliError {
7168
7261
  };
7169
7262
  var PROVIDER_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._@-]*$/;
7170
7263
  function providerJsonPath(paths, name) {
7171
- return path17.join(paths.providersDir, `${name}.json`);
7264
+ return path18.join(paths.providersDir, `${name}.json`);
7172
7265
  }
7173
7266
  function providerExists(paths, name) {
7174
7267
  return fs6.existsSync(providerJsonPath(paths, name));
@@ -7244,7 +7337,7 @@ function readProvider(paths, name) {
7244
7337
  return parseProviderFile(filePath, raw);
7245
7338
  }
7246
7339
  function loadProvider(providersDir, name, port) {
7247
- const filePath = path17.join(providersDir, `${name}.json`);
7340
+ const filePath = path18.join(providersDir, `${name}.json`);
7248
7341
  const raw = port.readConfigFile(filePath);
7249
7342
  return raw === void 0 ? void 0 : parseProviderFile(filePath, raw);
7250
7343
  }
@@ -7499,21 +7592,21 @@ function removeDirectoryRule(paths, rulePath) {
7499
7592
  import os5 from "node:os";
7500
7593
 
7501
7594
  // src/launcher/cascade.ts
7502
- import path19 from "node:path";
7595
+ import path20 from "node:path";
7503
7596
 
7504
7597
  // src/pathNorm.ts
7505
- import path18 from "node:path";
7598
+ import path19 from "node:path";
7506
7599
  function expandTilde(value, home) {
7507
7600
  if (value === "~") {
7508
7601
  return home;
7509
7602
  }
7510
7603
  if (value.startsWith("~/")) {
7511
- return path18.join(home, value.slice(2));
7604
+ return path19.join(home, value.slice(2));
7512
7605
  }
7513
7606
  return value;
7514
7607
  }
7515
7608
  function normaliseRulePath(rulePath, home) {
7516
- return path18.resolve(expandTilde(rulePath, home));
7609
+ return path19.resolve(expandTilde(rulePath, home));
7517
7610
  }
7518
7611
 
7519
7612
  // src/launcher/cascade.ts
@@ -7523,7 +7616,7 @@ function loadCascadeInput(params) {
7523
7616
  const globalConfig = loadConfigFile(params.paths.globalConfigFile, GlobalConfigSchema, params.read);
7524
7617
  const directoryRules = loadConfigFile(params.paths.directoryRulesFile, DirectoryRulesSchema, params.read);
7525
7618
  const loadProfile = (name) => {
7526
- const filepath = path19.join(params.paths.configProfilesDir, `${name}.json`);
7619
+ const filepath = path20.join(params.paths.configProfilesDir, `${name}.json`);
7527
7620
  const loaded = loadConfigFile(filepath, ConfigProfileSchema, params.read);
7528
7621
  if (loaded === void 0) {
7529
7622
  return void 0;
@@ -7538,8 +7631,8 @@ function loadCascadeInput(params) {
7538
7631
  });
7539
7632
  const levels = [];
7540
7633
  for (const dir of dirs) {
7541
- const portable = loadConfigFile(path19.join(dir, PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(path19.join(dir, LEGACY_PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read);
7542
- const portableLocal = loadConfigFile(path19.join(dir, PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(path19.join(dir, LEGACY_PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read);
7634
+ const portable = loadConfigFile(path20.join(dir, PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(path20.join(dir, LEGACY_PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read);
7635
+ const portableLocal = loadConfigFile(path20.join(dir, PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(path20.join(dir, LEGACY_PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read);
7543
7636
  const rules = (directoryRules?.config.rules ?? []).map((rule, index) => ({ rule, index })).filter(({ rule }) => normaliseRulePath(rule.path, params.home) === dir).map(({ rule, index }) => {
7544
7637
  const entryOrder = directoryRules?.ruleEntryOrders[index];
7545
7638
  return {
@@ -7590,7 +7683,7 @@ function readDirectorySelections(loaded) {
7590
7683
  // src/realCredentialCache.ts
7591
7684
  import { spawnSync } from "node:child_process";
7592
7685
  import fs7 from "node:fs";
7593
- import path20 from "node:path";
7686
+ import path21 from "node:path";
7594
7687
  var KEYCHAIN_CACHE_SERVICE = "agent-shim-credential-cache";
7595
7688
  var CACHE_DIR_MODE = 448;
7596
7689
  var CACHE_FILE_MODE = 384;
@@ -7617,8 +7710,8 @@ function security(args, stdin) {
7617
7710
  return { status: result.status, stdout: result.stdout };
7618
7711
  }
7619
7712
  function createRealCredentialCache(root) {
7620
- const dir = path20.join(root, "credential-cache");
7621
- const filePath = (owner) => path20.join(dir, cacheFileNameFor(owner));
7713
+ const dir = path21.join(root, "credential-cache");
7714
+ const filePath = (owner) => path21.join(dir, cacheFileNameFor(owner));
7622
7715
  return {
7623
7716
  read(store, owner) {
7624
7717
  if (store === "file") {
@@ -7672,70 +7765,6 @@ import fs8 from "node:fs";
7672
7765
  import os4 from "node:os";
7673
7766
  import path22 from "node:path";
7674
7767
  import { isSea } from "node:sea";
7675
-
7676
- // src/versionDiscovery.ts
7677
- import os3 from "node:os";
7678
- import path21 from "node:path";
7679
- function defaultVersionsDir() {
7680
- return path21.join(os3.homedir(), ".local", "share", "claude", "versions");
7681
- }
7682
- var NUMERIC_DOTTED_VERSION_RE = /^\d+(?:\.\d+)*$/;
7683
- function isNumericDottedVersion(name) {
7684
- return NUMERIC_DOTTED_VERSION_RE.test(name);
7685
- }
7686
- function compareVersions2(a, b) {
7687
- if (!isNumericDottedVersion(a)) {
7688
- throw new Error(`compareVersions: "${a}" is not a valid plain dotted-numeric version`);
7689
- }
7690
- if (!isNumericDottedVersion(b)) {
7691
- throw new Error(`compareVersions: "${b}" is not a valid plain dotted-numeric version`);
7692
- }
7693
- const segmentsA = a.split(".").map(Number);
7694
- const segmentsB = b.split(".").map(Number);
7695
- const length = Math.max(segmentsA.length, segmentsB.length);
7696
- for (let i = 0; i < length; i += 1) {
7697
- const segmentA = segmentsA[i] ?? 0;
7698
- const segmentB = segmentsB[i] ?? 0;
7699
- if (segmentA !== segmentB) {
7700
- return segmentA - segmentB;
7701
- }
7702
- }
7703
- return 0;
7704
- }
7705
- function pickHighestVersion(entries) {
7706
- const candidates = entries.filter(
7707
- (entry) => entry.isFile && entry.isExecutable && entry.sizeBytes > 0 && isNumericDottedVersion(entry.name)
7708
- );
7709
- if (candidates.length === 0) {
7710
- return void 0;
7711
- }
7712
- return candidates.reduce(
7713
- (highest, candidate) => compareVersions2(candidate.name, highest.name) > 0 ? candidate : highest
7714
- ).name;
7715
- }
7716
- function discoverClaudeBinary(options) {
7717
- const versionsDir = options.versionsDir ?? defaultVersionsDir();
7718
- const entries = options.listVersionsDir(versionsDir);
7719
- const highestVersion = pickHighestVersion(entries);
7720
- if (highestVersion !== void 0) {
7721
- return {
7722
- path: path21.join(versionsDir, highestVersion),
7723
- source: "versions-dir",
7724
- version: highestVersion
7725
- };
7726
- }
7727
- for (const dir of options.pathDirs) {
7728
- const found = options.findExecutableInDir(dir, "claude");
7729
- if (found !== void 0 && !options.isOwnBinary(found)) {
7730
- return { path: found, source: "path-fallback" };
7731
- }
7732
- }
7733
- throw new Error(
7734
- `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.`
7735
- );
7736
- }
7737
-
7738
- // src/realPorts.ts
7739
7768
  function isEnoent3(error) {
7740
7769
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
7741
7770
  }
@@ -8137,13 +8166,17 @@ function realContentSourcePath() {
8137
8166
  return resolveContentSourcePath({ isSea: isSea(), execPath: process.execPath, argv1: process.argv[1] });
8138
8167
  }
8139
8168
  function realResolveClaudeBinary(isOwnBinary) {
8140
- return () => discoverClaudeBinary({
8169
+ return (request4) => discoverClaudeBinary({
8141
8170
  listVersionsDir,
8142
8171
  pathDirs: (process.env.PATH ?? "").split(path22.delimiter).filter((dir) => dir !== ""),
8143
8172
  findExecutableInDir,
8144
- isOwnBinary
8173
+ isOwnBinary,
8174
+ ...request4?.version === void 0 ? {} : { version: request4.version }
8145
8175
  });
8146
8176
  }
8177
+ function realInstalledClaudeVersions() {
8178
+ return installedVersions(listVersionsDir(defaultVersionsDir()));
8179
+ }
8147
8180
 
8148
8181
  // src/checkReport.ts
8149
8182
  import path23 from "node:path";
@@ -8185,6 +8218,34 @@ function parseEnvBool(variable, value) {
8185
8218
  return parsed;
8186
8219
  }
8187
8220
 
8221
+ // src/launcher/claudeVersion.ts
8222
+ var InvalidClaudeVersionError = class extends UsageError {
8223
+ constructor(value, origin) {
8224
+ super(`${origin} names Claude Code version "${value}", which is not an exact dotted-numeric version such as 2.1.220.`);
8225
+ this.value = value;
8226
+ this.origin = origin;
8227
+ this.name = "InvalidClaudeVersionError";
8228
+ }
8229
+ value;
8230
+ origin;
8231
+ };
8232
+ function validated(value, origin) {
8233
+ if (!NUMERIC_DOTTED_VERSION_RE.test(value)) {
8234
+ throw new InvalidClaudeVersionError(value, origin);
8235
+ }
8236
+ return value;
8237
+ }
8238
+ function resolveClaudeVersion(params) {
8239
+ if (params.flag !== void 0) {
8240
+ return { version: validated(params.flag, "--claude-version"), source: "flag" };
8241
+ }
8242
+ const fromEnv = params.env.AGENT_SHIM_CLAUDE_VERSION;
8243
+ if (fromEnv !== void 0 && fromEnv !== "") {
8244
+ return { version: validated(fromEnv, "AGENT_SHIM_CLAUDE_VERSION"), source: "environment" };
8245
+ }
8246
+ return params.cascade === void 0 ? void 0 : { version: params.cascade, source: "cascade" };
8247
+ }
8248
+
8188
8249
  // src/checkReport.ts
8189
8250
  var HISTORY_PROJECTS_KEY_PREFIX = "history/projects/";
8190
8251
  function projectFragmentOf(rawKey) {
@@ -8335,6 +8396,19 @@ function buildCredentialReport(provider, identity, identityName, cacheEnv) {
8335
8396
  ...identityCached === void 0 ? {} : { identityCached }
8336
8397
  };
8337
8398
  }
8399
+ function buildClaudeVersionReport(params, cascadePin) {
8400
+ const installed = params.installedClaudeVersions;
8401
+ if (installed === void 0) {
8402
+ return void 0;
8403
+ }
8404
+ const pin = resolveClaudeVersion({ env: params.env, ...cascadePin === void 0 ? {} : { cascade: cascadePin } });
8405
+ const highestInstalled = installed.at(-1);
8406
+ return {
8407
+ ...pin === void 0 ? {} : { pinned: { ...pin, installed: installed.includes(pin.version) } },
8408
+ ...highestInstalled === void 0 ? {} : { highestInstalled },
8409
+ installed
8410
+ };
8411
+ }
8338
8412
  function runCheck(params) {
8339
8413
  const facts = buildEntryFacts({
8340
8414
  fs: params.farmFs,
@@ -8359,6 +8433,7 @@ function runCheck(params) {
8359
8433
  const settingsShared = resolved.flattened.categories.get("settings") ?? SHIPPED_CATEGORY_DEFAULTS.settings;
8360
8434
  const settingsExposure = inspectSettingsExposure({ settingsShared, files: params.settingsFiles });
8361
8435
  const keychain = params.platform === "darwin" && params.run !== void 0 && params.farmRoot !== void 0 ? lookupKeychainService(params.run, params.farmRoot) : void 0;
8436
+ const claudeVersion = buildClaudeVersionReport(params, resolved.flattened.launch.claudeVersion);
8362
8437
  return {
8363
8438
  ...params.identityName === void 0 ? {} : { identityName: params.identityName },
8364
8439
  identitySource: params.identitySource,
@@ -8371,7 +8446,8 @@ function runCheck(params) {
8371
8446
  ambientCredential,
8372
8447
  ...keychain === void 0 ? {} : { keychain },
8373
8448
  settingsExposure,
8374
- credential: buildCredentialReport(params.provider, params.identity, params.identityName, params.credentialCache)
8449
+ credential: buildCredentialReport(params.provider, params.identity, params.identityName, params.credentialCache),
8450
+ ...claudeVersion === void 0 ? {} : { claudeVersion }
8375
8451
  };
8376
8452
  }
8377
8453
  function formatCheckReport(report) {
@@ -8420,6 +8496,17 @@ function formatCheckReport(report) {
8420
8496
  if (credential.applies === "stored-login") {
8421
8497
  lines.push(" The identity's stored login (no credential block applies).");
8422
8498
  }
8499
+ if (report.claudeVersion !== void 0) {
8500
+ lines.push("", "Claude Code version:");
8501
+ const { pinned, highestInstalled, installed } = report.claudeVersion;
8502
+ if (pinned !== void 0) {
8503
+ lines.push(
8504
+ 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(", ")}`
8505
+ );
8506
+ } else {
8507
+ 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)`);
8508
+ }
8509
+ }
8423
8510
  lines.push("", "Ambient-credential exposure:");
8424
8511
  lines.push(
8425
8512
  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")
@@ -8458,11 +8545,12 @@ function checkReportToJson(report) {
8458
8545
  ambientCredential: report.ambientCredential.ok ? { ok: true } : { ok: false, variable: report.ambientCredential.variable, message: report.ambientCredential.message },
8459
8546
  ...report.keychain === void 0 ? {} : { keychain: report.keychain },
8460
8547
  settingsExposure: report.settingsExposure,
8461
- credential: report.credential
8548
+ credential: report.credential,
8549
+ ...report.claudeVersion === void 0 ? {} : { claudeVersion: report.claudeVersion }
8462
8550
  };
8463
8551
  }
8464
8552
  function checkReportHasWarnings(report) {
8465
- return report.resolved.diagnostics.some((diagnostic) => diagnostic.severity !== "info") || report.projectEncodingAmbiguities.length > 0 || !report.ambientCredential.ok || report.credential.provider?.problem !== void 0;
8553
+ 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;
8466
8554
  }
8467
8555
  function loadCheckProvider(paths, name) {
8468
8556
  let definition;
@@ -8548,6 +8636,7 @@ function collectCheckReport(params) {
8548
8636
  settingsFiles,
8549
8637
  run: realRunPort,
8550
8638
  credentialCache: realCredentialCacheEnv(paths),
8639
+ installedClaudeVersions: realInstalledClaudeVersions(),
8551
8640
  ...farmRoot === void 0 ? {} : { farmRoot },
8552
8641
  platform: process.platform,
8553
8642
  ...provider === void 0 ? {} : { provider }
@@ -8699,13 +8788,13 @@ function pushProvider(push, entry, cacheEnv) {
8699
8788
  push("provider", "fail", new LegacyProviderFileError(entry.path, conversion).message, entry.name);
8700
8789
  return;
8701
8790
  }
8702
- const validated = ProviderSchema.safeParse(parsed);
8703
- if (!validated.success) {
8704
- push("provider", "fail", new ConfigValidationError(entry.path, validated.error.issues).message, entry.name);
8791
+ const validated2 = ProviderSchema.safeParse(parsed);
8792
+ if (!validated2.success) {
8793
+ push("provider", "fail", new ConfigValidationError(entry.path, validated2.error.issues).message, entry.name);
8705
8794
  return;
8706
8795
  }
8707
- const cache = cacheClause(cacheEnv, `provider ${entry.name}`, validated.data.credential);
8708
- push("provider", cache.unreadable ? "fail" : "pass", `${entry.name} is valid (${describeProviderEndpoint(validated.data)}, credential ${describeCredential(validated.data.credential)})${cache.text}.`, entry.name);
8796
+ const cache = cacheClause(cacheEnv, `provider ${entry.name}`, validated2.data.credential);
8797
+ push("provider", cache.unreadable ? "fail" : "pass", `${entry.name} is valid (${describeProviderEndpoint(validated2.data)}, credential ${describeCredential(validated2.data.credential)})${cache.text}.`, entry.name);
8709
8798
  }
8710
8799
  function pushLegacyName(push, params) {
8711
8800
  const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
@@ -8729,6 +8818,13 @@ function runDoctor(params) {
8729
8818
  const push = (section, severity, message, subject) => {
8730
8819
  findings.push({ section, severity, message, ...subject === void 0 ? {} : { subject } });
8731
8820
  };
8821
+ const checkPin = (section, subject, where, version) => {
8822
+ const installed = params.installedClaudeVersions;
8823
+ if (version === void 0 || installed === void 0 || installed.includes(version)) {
8824
+ return;
8825
+ }
8826
+ 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);
8827
+ };
8732
8828
  const ambient = detectAmbientCredential(params.env);
8733
8829
  if (ambient === void 0) {
8734
8830
  push("ambient-credential", "pass", "No ambient-credential environment variable is set.");
@@ -8761,12 +8857,13 @@ function runDoctor(params) {
8761
8857
  pushLegacyName(push, params);
8762
8858
  const profileSources = /* @__PURE__ */ new Map();
8763
8859
  for (const entry of params.configProfiles) {
8764
- const validated = validateJson(ConfigProfileSchema, entry);
8765
- if (!validated.ok) {
8766
- push("config-profile", "fail", validated.message, entry.name);
8860
+ const validated2 = validateJson(ConfigProfileSchema, entry);
8861
+ if (!validated2.ok) {
8862
+ push("config-profile", "fail", validated2.message, entry.name);
8767
8863
  continue;
8768
8864
  }
8769
- profileSources.set(entry.name, { name: entry.name, profile: validated.data });
8865
+ profileSources.set(entry.name, { name: entry.name, profile: validated2.data });
8866
+ checkPin("config-profile", entry.name, `Configuration profile "${entry.name}"`, validated2.data.launch?.claudeVersion);
8770
8867
  }
8771
8868
  const loadProfile = (name) => profileSources.get(name);
8772
8869
  for (const name of profileSources.keys()) {
@@ -8782,13 +8879,13 @@ function runDoctor(params) {
8782
8879
  const validProfileNames = new Set(profileSources.keys());
8783
8880
  const validIdentityNames = /* @__PURE__ */ new Set();
8784
8881
  for (const entry of params.identities) {
8785
- const validated = validateJson(IdentitySchema, entry);
8786
- if (!validated.ok) {
8787
- push("identity", "fail", validated.message, entry.name);
8882
+ const validated2 = validateJson(IdentitySchema, entry);
8883
+ if (!validated2.ok) {
8884
+ push("identity", "fail", validated2.message, entry.name);
8788
8885
  continue;
8789
8886
  }
8790
8887
  validIdentityNames.add(entry.name);
8791
- const defaultProfile = validated.data.defaultConfigProfile;
8888
+ const defaultProfile = validated2.data.defaultConfigProfile;
8792
8889
  if (defaultProfile !== void 0 && !validProfileNames.has(defaultProfile)) {
8793
8890
  push(
8794
8891
  "identity",
@@ -8797,7 +8894,7 @@ function runDoctor(params) {
8797
8894
  entry.name
8798
8895
  );
8799
8896
  } else {
8800
- const credential = validated.data.credential;
8897
+ const credential = validated2.data.credential;
8801
8898
  const cache = credential === void 0 ? { text: "", unreadable: false } : cacheClause(params.credentialCache, `identity ${entry.name}`, credential);
8802
8899
  push(
8803
8900
  "identity",
@@ -8835,12 +8932,12 @@ function runDoctor(params) {
8835
8932
  if (params.directoryRules.raw === void 0) {
8836
8933
  push("directory-rules", "pass", "No directory-rules.json configured.");
8837
8934
  } else {
8838
- const validated = validateJson(DirectoryRulesSchema, params.directoryRules);
8839
- if (!validated.ok) {
8840
- push("directory-rules", "fail", validated.message);
8935
+ const validated2 = validateJson(DirectoryRulesSchema, params.directoryRules);
8936
+ if (!validated2.ok) {
8937
+ push("directory-rules", "fail", validated2.message);
8841
8938
  } else {
8842
8939
  push("directory-rules", "pass", `${params.directoryRules.path} is valid.`);
8843
- for (const rule of validated.data.rules) {
8940
+ for (const rule of validated2.data.rules) {
8844
8941
  const badRefs = [];
8845
8942
  if (rule.identity !== void 0 && !selectionExists(rule.identity)) {
8846
8943
  badRefs.push(poolNameOf(rule.identity) === void 0 ? `identity "${rule.identity}"` : `pool "${poolNameOf(rule.identity) ?? ""}"`);
@@ -8848,6 +8945,7 @@ function runDoctor(params) {
8848
8945
  if (rule.configProfile !== void 0 && !validProfileNames.has(rule.configProfile)) {
8849
8946
  badRefs.push(`configuration profile "${rule.configProfile}"`);
8850
8947
  }
8948
+ checkPin("directory-rules", rule.path, `Rule for "${rule.path}"`, rule.launch?.claudeVersion);
8851
8949
  if (badRefs.length > 0) {
8852
8950
  push("directory-rules", "fail", `Rule for "${rule.path}" names ${badRefs.join(" and ")}, which do not exist.`, rule.path);
8853
8951
  } else {
@@ -8859,11 +8957,11 @@ function runDoctor(params) {
8859
8957
  if (params.globalConfig.raw === void 0) {
8860
8958
  push("global-config", "pass", "No config.json configured.");
8861
8959
  } else {
8862
- const validated = validateJson(GlobalConfigSchema, params.globalConfig);
8863
- if (!validated.ok) {
8864
- push("global-config", "fail", validated.message);
8960
+ const validated2 = validateJson(GlobalConfigSchema, params.globalConfig);
8961
+ if (!validated2.ok) {
8962
+ push("global-config", "fail", validated2.message);
8865
8963
  } else {
8866
- const defaultProfile = validated.data.defaultConfigProfile;
8964
+ const defaultProfile = validated2.data.defaultConfigProfile;
8867
8965
  if (defaultProfile !== void 0 && !validProfileNames.has(defaultProfile)) {
8868
8966
  push(
8869
8967
  "global-config",
@@ -8872,27 +8970,28 @@ function runDoctor(params) {
8872
8970
  );
8873
8971
  } else {
8874
8972
  push("global-config", "pass", `${params.globalConfig.path} is valid.`);
8973
+ checkPin("global-config", void 0, "config.json", validated2.data.launch?.claudeVersion);
8875
8974
  }
8876
8975
  }
8877
8976
  }
8878
8977
  if (params.categoriesLocal.raw === void 0) {
8879
8978
  push("categories-local", "pass", "No categories.local.json configured.");
8880
8979
  } else {
8881
- const validated = validateJson(CategoryClassificationOverlaySchema, params.categoriesLocal);
8980
+ const validated2 = validateJson(CategoryClassificationOverlaySchema, params.categoriesLocal);
8882
8981
  push(
8883
8982
  "categories-local",
8884
- validated.ok ? "pass" : "fail",
8885
- validated.ok ? `${params.categoriesLocal.path} is valid.` : validated.message
8983
+ validated2.ok ? "pass" : "fail",
8984
+ validated2.ok ? `${params.categoriesLocal.path} is valid.` : validated2.message
8886
8985
  );
8887
8986
  }
8888
8987
  if (params.headroom.state.raw === void 0) {
8889
8988
  push("headroom", "pass", "No headroom daemon has ever run; nothing to check.");
8890
8989
  } else {
8891
- const validated = validateJson(HeadroomStateSchema, params.headroom.state);
8892
- if (!validated.ok) {
8893
- push("headroom", "fail", validated.message);
8990
+ const validated2 = validateJson(HeadroomStateSchema, params.headroom.state);
8991
+ if (!validated2.ok) {
8992
+ push("headroom", "fail", validated2.message);
8894
8993
  } else {
8895
- const state = validated.data;
8994
+ const state = validated2.data;
8896
8995
  const supervisorAlive = state.supervisorPid !== void 0 && params.headroom.isRunning(state.supervisorPid);
8897
8996
  const headroomAlive = state.headroomPid !== void 0 && params.headroom.isRunning(state.headroomPid);
8898
8997
  if (state.supervisorPid === void 0) {
@@ -9062,6 +9161,7 @@ function collectDoctorReport(params) {
9062
9161
  const report = runDoctor({
9063
9162
  env: params.env,
9064
9163
  credentialCache: realCredentialCacheEnv(paths),
9164
+ installedClaudeVersions: realInstalledClaudeVersions(),
9065
9165
  identities,
9066
9166
  configProfiles,
9067
9167
  providers,
@@ -9111,7 +9211,7 @@ var ConflictingIdentityError = class extends UsageError {
9111
9211
  positional;
9112
9212
  flag;
9113
9213
  };
9114
- var VALUED_FLAGS = ["--identity", "--config-profile", "--provider", "--category", "--share", "--hide"];
9214
+ var VALUED_FLAGS = ["--identity", "--config-profile", "--provider", "--claude-version", "--category", "--share", "--hide"];
9115
9215
  var BOOLEAN_FLAGS = [
9116
9216
  { flag: "--headroom", key: "headroom" },
9117
9217
  { flag: "--track-usage", key: "trackUsage" },
@@ -9157,6 +9257,7 @@ function parseLauncherArgv(argv) {
9157
9257
  let flagIdentity;
9158
9258
  let configProfile;
9159
9259
  let provider;
9260
+ let claudeVersion;
9160
9261
  const booleans = {};
9161
9262
  const categoryFlags = [];
9162
9263
  const shareFlags = [];
@@ -9211,6 +9312,9 @@ function parseLauncherArgv(argv) {
9211
9312
  case "--provider":
9212
9313
  provider = value;
9213
9314
  break;
9315
+ case "--claude-version":
9316
+ claudeVersion = value;
9317
+ break;
9214
9318
  case "--category":
9215
9319
  categoryFlags.push(value);
9216
9320
  break;
@@ -9232,6 +9336,7 @@ function parseLauncherArgv(argv) {
9232
9336
  ...identity === void 0 ? {} : { identity },
9233
9337
  ...configProfile === void 0 ? {} : { configProfile },
9234
9338
  ...provider === void 0 ? {} : { provider },
9339
+ ...claudeVersion === void 0 ? {} : { claudeVersion },
9235
9340
  ...native ? { native: true } : {},
9236
9341
  ...booleans,
9237
9342
  categoryFlags,
@@ -9693,7 +9798,11 @@ function prepareLaunch(params) {
9693
9798
  } else if (params.farm !== void 0) {
9694
9799
  cascadeLaunch = flattenLayers(assembleCascade(params.farm.loadCascade(configProfileDecision.name, cliOverride)).layers, { home: params.farm.home }).launch;
9695
9800
  }
9696
- const discovered = params.resolveClaudeBinary();
9801
+ const pinnedVersion = resolveClaudeVersion({ env, ...parsedArgv.claudeVersion === void 0 ? {} : { flag: parsedArgv.claudeVersion }, ...cascadeLaunch?.claudeVersion === void 0 ? {} : { cascade: cascadeLaunch.claudeVersion } });
9802
+ const discovered = params.resolveClaudeBinary(pinnedVersion === void 0 ? void 0 : { version: pinnedVersion.version });
9803
+ if (pinnedVersion !== void 0) {
9804
+ log.info(`agent-shim: Claude Code ${pinnedVersion.version} (pinned by ${pinnedVersion.source})`);
9805
+ }
9697
9806
  const resolvedFlags = resolveLaunchFlags({
9698
9807
  env,
9699
9808
  // A pool pick reads the usage the front door records, so a pool launch records its own unless something says otherwise.