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/README.md +3 -1
- package/dist/cli.cjs +159 -45
- package/dist/index.cjs +348 -239
- package/dist/index.mjs +350 -241
- package/dist/types/index.d.ts +35 -1
- package/package.json +1 -1
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
|
|
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("~/") ||
|
|
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
|
|
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 =
|
|
746
|
+
const dir = import_node_path3.default.dirname(filePath);
|
|
657
747
|
storeFs.mkdirSync(dir);
|
|
658
|
-
const tempPath =
|
|
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
|
|
683
|
-
writeJsonAtomic(filePath,
|
|
684
|
-
return
|
|
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
|
|
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) =>
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
2120
|
+
const absolute = import_node_path7.default.join(params.scratchRoot, entry.rel);
|
|
2028
2121
|
if (entry.kind === "link") {
|
|
2029
|
-
params.fs.mkdirp(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2169
|
-
const canonical =
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
2283
|
-
const previousRoot =
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
5493
|
+
var import_node_path11 = __toESM(require("node:path"), 1);
|
|
5401
5494
|
|
|
5402
5495
|
// src/usage/account.ts
|
|
5403
|
-
var
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
6723
|
-
var
|
|
6724
|
-
function resolveAgentShimHome(env = process.env, home =
|
|
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 =
|
|
6730
|
-
const legacy =
|
|
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
|
|
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:
|
|
6747
|
-
configProfilesDir:
|
|
6748
|
-
providersDir:
|
|
6749
|
-
directoryRulesFile:
|
|
6750
|
-
activeIdentityFile:
|
|
6751
|
-
globalConfigFile:
|
|
6752
|
-
categoriesLocalFile:
|
|
6753
|
-
claudeShimFile:
|
|
6754
|
-
headroomDir:
|
|
6755
|
-
headroomStateFile:
|
|
6756
|
-
headroomSocketDir:
|
|
6757
|
-
headroomLockFile:
|
|
6758
|
-
headroomSessionsDir:
|
|
6759
|
-
logsDir:
|
|
6760
|
-
headroomLogPath:
|
|
6761
|
-
frontdoorDir:
|
|
6762
|
-
frontdoorCaDir:
|
|
6763
|
-
frontdoorCaCertFile:
|
|
6764
|
-
frontdoorCaKeyFile:
|
|
6765
|
-
frontdoorCaBundlesDir:
|
|
6766
|
-
frontdoorStateFile:
|
|
6767
|
-
frontdoorLockFile:
|
|
6768
|
-
frontdoorControlTokenFile:
|
|
6769
|
-
frontdoorSessionsDir:
|
|
6770
|
-
frontdoorLogPath:
|
|
6771
|
-
usageDir:
|
|
6772
|
-
usageLogDir:
|
|
6773
|
-
usageSnapshotsDir:
|
|
6774
|
-
usagePicksFile:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 ===
|
|
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(
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
7809
|
+
var import_node_path20 = __toESM(require("node:path"), 1);
|
|
7717
7810
|
|
|
7718
7811
|
// src/pathNorm.ts
|
|
7719
|
-
var
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
7756
|
-
const portableLocal = loadConfigFile(
|
|
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
|
|
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 =
|
|
7835
|
-
const filePath = (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
|
|
8917
|
-
if (!
|
|
8918
|
-
push("provider", "fail", new ConfigValidationError(entry.path,
|
|
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}`,
|
|
8922
|
-
push("provider", cache.unreadable ? "fail" : "pass", `${entry.name} is valid (${describeProviderEndpoint(
|
|
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
|
|
8979
|
-
if (!
|
|
8980
|
-
push("config-profile", "fail",
|
|
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:
|
|
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
|
|
9000
|
-
if (!
|
|
9001
|
-
push("identity", "fail",
|
|
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 =
|
|
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 =
|
|
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
|
|
9053
|
-
if (!
|
|
9054
|
-
push("directory-rules", "fail",
|
|
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
|
|
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
|
|
9077
|
-
if (!
|
|
9078
|
-
push("global-config", "fail",
|
|
9174
|
+
const validated2 = validateJson(GlobalConfigSchema, params.globalConfig);
|
|
9175
|
+
if (!validated2.ok) {
|
|
9176
|
+
push("global-config", "fail", validated2.message);
|
|
9079
9177
|
} else {
|
|
9080
|
-
const defaultProfile =
|
|
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
|
|
9194
|
+
const validated2 = validateJson(CategoryClassificationOverlaySchema, params.categoriesLocal);
|
|
9096
9195
|
push(
|
|
9097
9196
|
"categories-local",
|
|
9098
|
-
|
|
9099
|
-
|
|
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
|
|
9106
|
-
if (!
|
|
9107
|
-
push("headroom", "fail",
|
|
9204
|
+
const validated2 = validateJson(HeadroomStateSchema, params.headroom.state);
|
|
9205
|
+
if (!validated2.ok) {
|
|
9206
|
+
push("headroom", "fail", validated2.message);
|
|
9108
9207
|
} else {
|
|
9109
|
-
const state =
|
|
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
|
|
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.
|