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