agent-shim 7.4.0 → 7.5.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 +1 -0
- package/dist/cli.cjs +1 -1
- package/dist/index.cjs +200 -81
- package/dist/index.mjs +175 -81
- package/dist/types/config/schema.d.ts +1 -1
- package/dist/types/index.d.ts +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -226,6 +226,7 @@ Issues and pull requests are welcome. Please keep the tool itself free of assump
|
|
|
226
226
|
- [docs/architecture.md](docs/architecture.md): the source layout file by file, error reporting design, schema rationale, and resolver mechanics.
|
|
227
227
|
- [docs/release-process.md](docs/release-process.md): the semantic-release pipeline, the Node SEA build, its macOS x64 limitation, and npm/GitHub Packages publishing.
|
|
228
228
|
- [docs/testing.md](docs/testing.md): the full list of cases the test suites cover.
|
|
229
|
+
- [docs/library.md](docs/library.md): using agent-shim in process: what the library exposes, and what stays CLI-only.
|
|
229
230
|
- [docs/installation.md](docs/installation.md): every install channel in full, with the platform support matrix.
|
|
230
231
|
- [docs/development.md](docs/development.md): test isolation, commit hooks, and the secret-redaction filter rationale.
|
|
231
232
|
|
package/dist/cli.cjs
CHANGED
|
@@ -61051,7 +61051,7 @@ function resolveLaunchIdentity(paths, cwd) {
|
|
|
61051
61051
|
// package.json
|
|
61052
61052
|
var package_default = {
|
|
61053
61053
|
name: "agent-shim",
|
|
61054
|
-
version: "7.
|
|
61054
|
+
version: "7.5.0",
|
|
61055
61055
|
description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
|
|
61056
61056
|
license: "MIT",
|
|
61057
61057
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
package/dist/index.cjs
CHANGED
|
@@ -34,13 +34,35 @@ __export(index_exports, {
|
|
|
34
34
|
CONNECT_INTERCEPT_HOST: () => CONNECT_INTERCEPT_HOST,
|
|
35
35
|
CONNECT_INTERCEPT_HOSTS: () => CONNECT_INTERCEPT_HOSTS,
|
|
36
36
|
CONNECT_LIMITS: () => CONNECT_LIMITS,
|
|
37
|
+
CategoryClassificationOverlaySchema: () => CategoryClassificationOverlaySchema,
|
|
38
|
+
CategoryClassificationSchema: () => CategoryClassificationSchema,
|
|
39
|
+
CategoryMapSchema: () => CategoryMapSchema,
|
|
40
|
+
CliError: () => CliError,
|
|
41
|
+
ConfigProfileSchema: () => ConfigProfileSchema,
|
|
42
|
+
CredentialCacheSchema: () => CredentialCacheSchema,
|
|
43
|
+
CredentialSchema: () => CredentialSchema,
|
|
44
|
+
CredentialSourceSchema: () => CredentialSourceSchema,
|
|
45
|
+
DirectoryRuleSchema: () => DirectoryRuleSchema,
|
|
46
|
+
DirectoryRulesSchema: () => DirectoryRulesSchema,
|
|
47
|
+
EXIT_FAILURE: () => EXIT_FAILURE,
|
|
48
|
+
EXIT_USAGE: () => EXIT_USAGE,
|
|
49
|
+
EntryValueSchema: () => EntryValueSchema,
|
|
37
50
|
FARM_MANIFEST_FILENAME: () => FARM_MANIFEST_FILENAME,
|
|
38
51
|
FrontDoorStartError: () => FrontDoorStartError,
|
|
52
|
+
GlobalConfigSchema: () => GlobalConfigSchema,
|
|
39
53
|
HeadroomStartError: () => HeadroomStartError,
|
|
54
|
+
IdentitySchema: () => IdentitySchema,
|
|
55
|
+
PoolNameSchema: () => PoolNameSchema,
|
|
56
|
+
PoolSchema: () => PoolSchema,
|
|
57
|
+
PortableConfigSchema: () => PortableConfigSchema,
|
|
58
|
+
ProviderSchema: () => ProviderSchema,
|
|
40
59
|
ROUTED_PATH_PREFIX: () => ROUTED_PATH_PREFIX,
|
|
60
|
+
UsageError: () => UsageError,
|
|
41
61
|
UsageSnapshotError: () => UsageSnapshotError,
|
|
42
62
|
UsageSnapshotSchema: () => UsageSnapshotSchema,
|
|
63
|
+
WhenSchema: () => WhenSchema,
|
|
43
64
|
buildEntryFacts: () => buildEntryFacts,
|
|
65
|
+
buildLayoutPaths: () => buildLayoutPaths,
|
|
44
66
|
carryOver: () => carryOver,
|
|
45
67
|
createLeafCache: () => createLeafCache,
|
|
46
68
|
detectAmbientCredential: () => detectAmbientCredential,
|
|
@@ -61,7 +83,10 @@ __export(index_exports, {
|
|
|
61
83
|
realConnectEffects: () => realConnectEffects,
|
|
62
84
|
recoverFarm: () => recoverFarm,
|
|
63
85
|
recoveryDiagnostics: () => recoveryDiagnostics,
|
|
86
|
+
resolveAgentShimHome: () => resolveAgentShimHome,
|
|
87
|
+
resolveClaudeHome: () => resolveClaudeHome,
|
|
64
88
|
resolveDecisions: () => resolveDecisions,
|
|
89
|
+
resolveLayoutPaths: () => resolveLayoutPaths,
|
|
65
90
|
resolveSupervisorConfig: () => resolveSupervisorConfig,
|
|
66
91
|
resyncFarm: () => resyncFarm,
|
|
67
92
|
runFrontDoorSupervisor: () => runFrontDoorSupervisor,
|
|
@@ -323,10 +348,18 @@ var import_cosmiconfig = require("cosmiconfig");
|
|
|
323
348
|
|
|
324
349
|
// src/cliError.ts
|
|
325
350
|
var EXIT_FAILURE = 1;
|
|
351
|
+
var EXIT_USAGE = 2;
|
|
326
352
|
var CliError = class extends Error {
|
|
327
353
|
/** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
|
|
328
354
|
exitCode = EXIT_FAILURE;
|
|
329
355
|
};
|
|
356
|
+
var UsageError = class extends CliError {
|
|
357
|
+
exitCode = EXIT_USAGE;
|
|
358
|
+
constructor(message) {
|
|
359
|
+
super(message);
|
|
360
|
+
this.name = "UsageError";
|
|
361
|
+
}
|
|
362
|
+
};
|
|
330
363
|
|
|
331
364
|
// src/config/classify.ts
|
|
332
365
|
var GLOB_METACHARACTERS = /[*?[\]{}!()]/;
|
|
@@ -1287,6 +1320,8 @@ function planReconciliation(params) {
|
|
|
1287
1320
|
}
|
|
1288
1321
|
|
|
1289
1322
|
// src/legacy.ts
|
|
1323
|
+
var HOME_DIRNAME = ".agent-shim";
|
|
1324
|
+
var LEGACY_HOME_DIRNAME = ".claude-use";
|
|
1290
1325
|
var LEGACY_FARM_MANIFEST_FILENAME = ".claude-use-farm.json";
|
|
1291
1326
|
|
|
1292
1327
|
// src/launcher/lock.ts
|
|
@@ -1388,8 +1423,8 @@ var FarmManifestSchema = import_zod2.z.strictObject({
|
|
|
1388
1423
|
materialised: import_zod2.z.array(import_zod2.z.string()),
|
|
1389
1424
|
links: import_zod2.z.array(import_zod2.z.strictObject({ rel: import_zod2.z.string(), target: import_zod2.z.string() }))
|
|
1390
1425
|
});
|
|
1391
|
-
function readFarmManifest(
|
|
1392
|
-
const raw =
|
|
1426
|
+
function readFarmManifest(fs3, farmRoot) {
|
|
1427
|
+
const raw = fs3.readFileUtf8(import_node_path4.default.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs3.readFileUtf8(import_node_path4.default.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
|
|
1393
1428
|
if (raw === void 0) {
|
|
1394
1429
|
return void 0;
|
|
1395
1430
|
}
|
|
@@ -1447,9 +1482,9 @@ function buildEntryFacts(params) {
|
|
|
1447
1482
|
entries
|
|
1448
1483
|
};
|
|
1449
1484
|
}
|
|
1450
|
-
function listSubtree(
|
|
1485
|
+
function listSubtree(fs3, root, rel) {
|
|
1451
1486
|
const absolute = import_node_path4.default.join(root, rel);
|
|
1452
|
-
const stat =
|
|
1487
|
+
const stat = fs3.lstat(absolute);
|
|
1453
1488
|
if (stat === void 0) {
|
|
1454
1489
|
return [];
|
|
1455
1490
|
}
|
|
@@ -1457,10 +1492,10 @@ function listSubtree(fs2, root, rel) {
|
|
|
1457
1492
|
return [{ rel, kind: "symlink" }];
|
|
1458
1493
|
}
|
|
1459
1494
|
if (stat.kind === "dir") {
|
|
1460
|
-
const children = [...
|
|
1495
|
+
const children = [...fs3.readdir(absolute)].sort().flatMap((name) => listSubtree(fs3, root, `${rel}/${name}`));
|
|
1461
1496
|
return [{ rel, kind: "dir" }, ...children];
|
|
1462
1497
|
}
|
|
1463
|
-
const contentHash =
|
|
1498
|
+
const contentHash = fs3.hashFile(absolute);
|
|
1464
1499
|
return [{ rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } }];
|
|
1465
1500
|
}
|
|
1466
1501
|
function topLevelScopeRoots(roots) {
|
|
@@ -1474,25 +1509,25 @@ function topLevelScopeRoots(roots) {
|
|
|
1474
1509
|
}
|
|
1475
1510
|
return kept;
|
|
1476
1511
|
}
|
|
1477
|
-
function reconciliationScope(
|
|
1512
|
+
function reconciliationScope(fs3, farmRoot, manifest) {
|
|
1478
1513
|
if (manifest !== void 0) {
|
|
1479
1514
|
return topLevelScopeRoots(manifest.materialised);
|
|
1480
1515
|
}
|
|
1481
|
-
return [...
|
|
1516
|
+
return [...fs3.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs3.lstat(import_node_path4.default.join(farmRoot, name))?.kind === "dir").sort();
|
|
1482
1517
|
}
|
|
1483
|
-
function collectFarmListing(
|
|
1484
|
-
return scopeRoots.flatMap((root) => listSubtree(
|
|
1518
|
+
function collectFarmListing(fs3, farmRoot, scopeRoots) {
|
|
1519
|
+
return scopeRoots.flatMap((root) => listSubtree(fs3, farmRoot, root));
|
|
1485
1520
|
}
|
|
1486
|
-
function collectCanonicalCounterparts(
|
|
1521
|
+
function collectCanonicalCounterparts(fs3, claudeHome, farmListing) {
|
|
1487
1522
|
const out = [];
|
|
1488
1523
|
for (const entry of farmListing) {
|
|
1489
1524
|
const absolute = import_node_path4.default.join(claudeHome, entry.rel);
|
|
1490
|
-
const stat =
|
|
1525
|
+
const stat = fs3.lstat(absolute);
|
|
1491
1526
|
if (stat === void 0) {
|
|
1492
1527
|
continue;
|
|
1493
1528
|
}
|
|
1494
1529
|
if (stat.kind === "file") {
|
|
1495
|
-
const contentHash =
|
|
1530
|
+
const contentHash = fs3.hashFile(absolute);
|
|
1496
1531
|
out.push({ rel: entry.rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } });
|
|
1497
1532
|
continue;
|
|
1498
1533
|
}
|
|
@@ -2176,10 +2211,10 @@ var FrontDoorStateSchema = import_zod3.z.strictObject({
|
|
|
2176
2211
|
/** The last fatal error, kept across shutdowns so `frontdoor status` can explain a front door that is not running. */
|
|
2177
2212
|
lastError: import_zod3.z.string().optional()
|
|
2178
2213
|
});
|
|
2179
|
-
function readFrontDoorState(
|
|
2214
|
+
function readFrontDoorState(fs3, stateFile) {
|
|
2180
2215
|
let raw;
|
|
2181
2216
|
try {
|
|
2182
|
-
raw =
|
|
2217
|
+
raw = fs3.readFileUtf8(stateFile);
|
|
2183
2218
|
} catch {
|
|
2184
2219
|
return void 0;
|
|
2185
2220
|
}
|
|
@@ -2193,28 +2228,28 @@ function readFrontDoorState(fs2, stateFile) {
|
|
|
2193
2228
|
return void 0;
|
|
2194
2229
|
}
|
|
2195
2230
|
}
|
|
2196
|
-
function writeFrontDoorState(
|
|
2197
|
-
|
|
2198
|
-
|
|
2231
|
+
function writeFrontDoorState(fs3, stateFile, state) {
|
|
2232
|
+
fs3.mkdirp(import_node_path5.default.dirname(stateFile));
|
|
2233
|
+
fs3.writeFileUtf8(stateFile, `${JSON.stringify(state, null, 2)}
|
|
2199
2234
|
`);
|
|
2200
2235
|
}
|
|
2201
2236
|
function frontDoorOrigin(state) {
|
|
2202
2237
|
const port = state?.directPort ?? state?.lastDirectPort;
|
|
2203
2238
|
return port === void 0 ? void 0 : `http://127.0.0.1:${String(port)}`;
|
|
2204
2239
|
}
|
|
2205
|
-
function writeFrontDoorSession(
|
|
2206
|
-
|
|
2207
|
-
|
|
2240
|
+
function writeFrontDoorSession(fs3, sessionsDir, session) {
|
|
2241
|
+
fs3.mkdirPrivate(sessionsDir);
|
|
2242
|
+
fs3.writeFilePrivate(import_node_path5.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
|
|
2208
2243
|
`);
|
|
2209
2244
|
}
|
|
2210
|
-
function listFrontDoorSessions(
|
|
2245
|
+
function listFrontDoorSessions(fs3, sessionsDir) {
|
|
2211
2246
|
const sessions = [];
|
|
2212
|
-
for (const name of
|
|
2247
|
+
for (const name of fs3.readdir(sessionsDir)) {
|
|
2213
2248
|
if (!name.endsWith(".json")) {
|
|
2214
2249
|
continue;
|
|
2215
2250
|
}
|
|
2216
2251
|
try {
|
|
2217
|
-
const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(
|
|
2252
|
+
const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs3.readFileUtf8(import_node_path5.default.join(sessionsDir, name)) ?? ""));
|
|
2218
2253
|
if (parsed.success) {
|
|
2219
2254
|
sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
|
|
2220
2255
|
}
|
|
@@ -2224,14 +2259,14 @@ function listFrontDoorSessions(fs2, sessionsDir) {
|
|
|
2224
2259
|
}
|
|
2225
2260
|
return sessions.sort((a, b) => a.pid - b.pid);
|
|
2226
2261
|
}
|
|
2227
|
-
function removeFrontDoorSession(
|
|
2228
|
-
|
|
2262
|
+
function removeFrontDoorSession(fs3, sessionsDir, pid) {
|
|
2263
|
+
fs3.removeRecursive(import_node_path5.default.join(sessionsDir, `${String(pid)}.json`));
|
|
2229
2264
|
}
|
|
2230
|
-
function pruneDeadFrontDoorSessions(
|
|
2265
|
+
function pruneDeadFrontDoorSessions(fs3, sessionsDir, isRunning) {
|
|
2231
2266
|
const removed = [];
|
|
2232
|
-
for (const session of listFrontDoorSessions(
|
|
2267
|
+
for (const session of listFrontDoorSessions(fs3, sessionsDir)) {
|
|
2233
2268
|
if (!isRunning(session.pid)) {
|
|
2234
|
-
removeFrontDoorSession(
|
|
2269
|
+
removeFrontDoorSession(fs3, sessionsDir, session.pid);
|
|
2235
2270
|
removed.push(session.pid);
|
|
2236
2271
|
}
|
|
2237
2272
|
}
|
|
@@ -2243,8 +2278,8 @@ var FRONTDOOR_SUPERVISOR_STILL_RUNNING = -1;
|
|
|
2243
2278
|
var FRONTDOOR_POLL_MS = 1e3;
|
|
2244
2279
|
var MS_PER_MINUTE = 6e4;
|
|
2245
2280
|
async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {}) {
|
|
2246
|
-
const { fs:
|
|
2247
|
-
const previous = readFrontDoorState(
|
|
2281
|
+
const { fs: fs3, paths } = ports;
|
|
2282
|
+
const previous = readFrontDoorState(fs3, paths.frontdoorStateFile);
|
|
2248
2283
|
let lastPort = previous?.lastPort;
|
|
2249
2284
|
let lastConnectPort = previous?.lastConnectPort;
|
|
2250
2285
|
let lastDirectPort = previous?.lastDirectPort;
|
|
@@ -2254,12 +2289,12 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
2254
2289
|
...lastDirectPort === void 0 ? {} : { lastDirectPort }
|
|
2255
2290
|
});
|
|
2256
2291
|
const fail = (message) => {
|
|
2257
|
-
writeFrontDoorState(
|
|
2258
|
-
|
|
2292
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, { lastError: message, ...sticky() });
|
|
2293
|
+
fs3.removeRecursive(paths.frontdoorLockFile);
|
|
2259
2294
|
ports.log(`agent-shim frontdoor supervisor: ${message}`);
|
|
2260
2295
|
return 1;
|
|
2261
2296
|
};
|
|
2262
|
-
writeFrontDoorState(
|
|
2297
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
|
|
2263
2298
|
const previousSticky = lastPort;
|
|
2264
2299
|
let http2;
|
|
2265
2300
|
try {
|
|
@@ -2296,8 +2331,8 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
2296
2331
|
ports.log(`agent-shim frontdoor supervisor: sticky direct port ${String(previousStickyDirect)} was occupied; moving to ${String(direct.port)} (headroom must be restarted to admit the new address)`);
|
|
2297
2332
|
}
|
|
2298
2333
|
lastDirectPort = direct.port;
|
|
2299
|
-
writeFrontDoorState(
|
|
2300
|
-
|
|
2334
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, port: http2.port, connectPort: connect2.port, directPort: direct.port, ...sticky() });
|
|
2335
|
+
fs3.removeRecursive(paths.frontdoorLockFile);
|
|
2301
2336
|
ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: front door on 127.0.0.1:${String(http2.port)}, CONNECT surface on 127.0.0.1:${String(connect2.port)}`);
|
|
2302
2337
|
let idleSince;
|
|
2303
2338
|
let ticks = 0;
|
|
@@ -2306,15 +2341,15 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
2306
2341
|
return FRONTDOOR_SUPERVISOR_STILL_RUNNING;
|
|
2307
2342
|
}
|
|
2308
2343
|
ticks += 1;
|
|
2309
|
-
pruneDeadFrontDoorSessions(
|
|
2310
|
-
if (listFrontDoorSessions(
|
|
2344
|
+
pruneDeadFrontDoorSessions(fs3, paths.frontdoorSessionsDir, ports.isRunning);
|
|
2345
|
+
if (listFrontDoorSessions(fs3, paths.frontdoorSessionsDir).length === 0) {
|
|
2311
2346
|
idleSince ??= ports.now();
|
|
2312
2347
|
if (ports.now() - idleSince >= idleShutdownMinutes * MS_PER_MINUTE) {
|
|
2313
2348
|
ports.log(`agent-shim frontdoor supervisor: no sessions for ${String(idleShutdownMinutes)} minute(s); closing the front door and exiting`);
|
|
2314
2349
|
await direct.close();
|
|
2315
2350
|
await connect2.close();
|
|
2316
2351
|
await http2.close();
|
|
2317
|
-
writeFrontDoorState(
|
|
2352
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, sticky());
|
|
2318
2353
|
return 0;
|
|
2319
2354
|
}
|
|
2320
2355
|
} else {
|
|
@@ -2369,8 +2404,8 @@ function parseConnectTarget(authority) {
|
|
|
2369
2404
|
function isInterceptedHost(host, interceptHosts) {
|
|
2370
2405
|
return interceptHosts.includes(host);
|
|
2371
2406
|
}
|
|
2372
|
-
function servedByPipeline(
|
|
2373
|
-
return
|
|
2407
|
+
function servedByPipeline(path9) {
|
|
2408
|
+
return path9?.startsWith(ROUTED_PATH_PREFIX) === true;
|
|
2374
2409
|
}
|
|
2375
2410
|
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
2376
2411
|
"connection",
|
|
@@ -2853,16 +2888,16 @@ function parseJson(raw, schema) {
|
|
|
2853
2888
|
const parsed = schema.safeParse(JSON.parse(raw));
|
|
2854
2889
|
return parsed.success ? parsed.data : void 0;
|
|
2855
2890
|
}
|
|
2856
|
-
function readHeadroomState(
|
|
2891
|
+
function readHeadroomState(fs3, stateFile) {
|
|
2857
2892
|
try {
|
|
2858
|
-
return parseJson(
|
|
2893
|
+
return parseJson(fs3.readFileUtf8(stateFile), HeadroomStateSchema);
|
|
2859
2894
|
} catch {
|
|
2860
2895
|
return void 0;
|
|
2861
2896
|
}
|
|
2862
2897
|
}
|
|
2863
|
-
function writeHeadroomState(
|
|
2864
|
-
|
|
2865
|
-
|
|
2898
|
+
function writeHeadroomState(fs3, stateFile, state) {
|
|
2899
|
+
fs3.mkdirp(import_node_path6.default.dirname(stateFile));
|
|
2900
|
+
fs3.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
|
|
2866
2901
|
`);
|
|
2867
2902
|
}
|
|
2868
2903
|
function headroomAllowlist(providers) {
|
|
@@ -2882,14 +2917,14 @@ function headroomUpstreams(providers, frontDoorOrigin2) {
|
|
|
2882
2917
|
function hashAllowlist(allowlist) {
|
|
2883
2918
|
return (0, import_node_crypto4.createHash)("sha256").update(allowlist.join("\n")).digest("hex");
|
|
2884
2919
|
}
|
|
2885
|
-
function readAllProviders(
|
|
2920
|
+
function readAllProviders(fs3, providersDir) {
|
|
2886
2921
|
const result = [];
|
|
2887
|
-
for (const name of
|
|
2922
|
+
for (const name of fs3.readdir(providersDir)) {
|
|
2888
2923
|
if (!name.endsWith(".json")) {
|
|
2889
2924
|
continue;
|
|
2890
2925
|
}
|
|
2891
2926
|
try {
|
|
2892
|
-
const parsed = parseJson(
|
|
2927
|
+
const parsed = parseJson(fs3.readFileUtf8(import_node_path6.default.join(providersDir, name)), ProviderSchema);
|
|
2893
2928
|
if (parsed !== void 0) {
|
|
2894
2929
|
result.push({ name: name.slice(0, -".json".length), provider: parsed });
|
|
2895
2930
|
}
|
|
@@ -2899,22 +2934,22 @@ function readAllProviders(fs2, providersDir) {
|
|
|
2899
2934
|
}
|
|
2900
2935
|
return result;
|
|
2901
2936
|
}
|
|
2902
|
-
function writeSession(
|
|
2903
|
-
|
|
2904
|
-
|
|
2937
|
+
function writeSession(fs3, sessionsDir, session) {
|
|
2938
|
+
fs3.mkdirp(sessionsDir);
|
|
2939
|
+
fs3.writeFileUtf8(import_node_path6.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
|
|
2905
2940
|
`);
|
|
2906
2941
|
}
|
|
2907
|
-
function removeSession(
|
|
2908
|
-
|
|
2942
|
+
function removeSession(fs3, sessionsDir, pid) {
|
|
2943
|
+
fs3.removeRecursive(import_node_path6.default.join(sessionsDir, `${String(pid)}.json`));
|
|
2909
2944
|
}
|
|
2910
|
-
function listSessions(
|
|
2945
|
+
function listSessions(fs3, sessionsDir) {
|
|
2911
2946
|
const sessions = [];
|
|
2912
|
-
for (const name of
|
|
2947
|
+
for (const name of fs3.readdir(sessionsDir)) {
|
|
2913
2948
|
if (!name.endsWith(".json")) {
|
|
2914
2949
|
continue;
|
|
2915
2950
|
}
|
|
2916
2951
|
try {
|
|
2917
|
-
const parsed = parseJson(
|
|
2952
|
+
const parsed = parseJson(fs3.readFileUtf8(import_node_path6.default.join(sessionsDir, name)), HeadroomSessionSchema);
|
|
2918
2953
|
if (parsed !== void 0) {
|
|
2919
2954
|
sessions.push(parsed);
|
|
2920
2955
|
}
|
|
@@ -2924,22 +2959,22 @@ function listSessions(fs2, sessionsDir) {
|
|
|
2924
2959
|
}
|
|
2925
2960
|
return sessions.sort((a, b) => a.pid - b.pid);
|
|
2926
2961
|
}
|
|
2927
|
-
function sessionsForSupervisor(
|
|
2928
|
-
return listSessions(
|
|
2962
|
+
function sessionsForSupervisor(fs3, sessionsDir, supervisorPid) {
|
|
2963
|
+
return listSessions(fs3, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
|
|
2929
2964
|
}
|
|
2930
|
-
function pruneDeadSessions(
|
|
2965
|
+
function pruneDeadSessions(fs3, sessionsDir, isRunning) {
|
|
2931
2966
|
const removed = [];
|
|
2932
|
-
for (const session of listSessions(
|
|
2967
|
+
for (const session of listSessions(fs3, sessionsDir)) {
|
|
2933
2968
|
if (!isRunning(session.pid)) {
|
|
2934
|
-
removeSession(
|
|
2969
|
+
removeSession(fs3, sessionsDir, session.pid);
|
|
2935
2970
|
removed.push(session.pid);
|
|
2936
2971
|
}
|
|
2937
2972
|
}
|
|
2938
2973
|
return removed;
|
|
2939
2974
|
}
|
|
2940
|
-
function readStartLock(
|
|
2975
|
+
function readStartLock(fs3, lockFile) {
|
|
2941
2976
|
try {
|
|
2942
|
-
return parseJson(
|
|
2977
|
+
return parseJson(fs3.readFileUtf8(lockFile), HeadroomLockSchema);
|
|
2943
2978
|
} catch {
|
|
2944
2979
|
return void 0;
|
|
2945
2980
|
}
|
|
@@ -3176,9 +3211,9 @@ function snapshotPath(snapshotsDir, identity) {
|
|
|
3176
3211
|
}
|
|
3177
3212
|
return import_node_path7.default.join(snapshotsDir, `${identity}.json`);
|
|
3178
3213
|
}
|
|
3179
|
-
function readUsageSnapshot(
|
|
3214
|
+
function readUsageSnapshot(fs3, snapshotsDir, identity) {
|
|
3180
3215
|
const file = snapshotPath(snapshotsDir, identity);
|
|
3181
|
-
const raw =
|
|
3216
|
+
const raw = fs3.readFileUtf8(file);
|
|
3182
3217
|
if (raw === void 0) {
|
|
3183
3218
|
return void 0;
|
|
3184
3219
|
}
|
|
@@ -3194,8 +3229,8 @@ function readUsageSnapshot(fs2, snapshotsDir, identity) {
|
|
|
3194
3229
|
}
|
|
3195
3230
|
return snapshot.data;
|
|
3196
3231
|
}
|
|
3197
|
-
function listUsageSnapshots(
|
|
3198
|
-
return
|
|
3232
|
+
function listUsageSnapshots(fs3, snapshotsDir) {
|
|
3233
|
+
return fs3.readdir(snapshotsDir).flatMap((name) => {
|
|
3199
3234
|
if (!name.endsWith(".json")) {
|
|
3200
3235
|
return [];
|
|
3201
3236
|
}
|
|
@@ -3203,7 +3238,7 @@ function listUsageSnapshots(fs2, snapshotsDir) {
|
|
|
3203
3238
|
if (!isIdentityName(identity)) {
|
|
3204
3239
|
return [];
|
|
3205
3240
|
}
|
|
3206
|
-
const snapshot = readUsageSnapshot(
|
|
3241
|
+
const snapshot = readUsageSnapshot(fs3, snapshotsDir, identity);
|
|
3207
3242
|
return snapshot === void 0 ? [] : [snapshot];
|
|
3208
3243
|
}).sort((left, right) => left.identity.localeCompare(right.identity));
|
|
3209
3244
|
}
|
|
@@ -3370,9 +3405,9 @@ function compareVersions(a, b) {
|
|
|
3370
3405
|
}
|
|
3371
3406
|
var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
|
|
3372
3407
|
async function runSupervisor(initialConfig, ports, options = {}) {
|
|
3373
|
-
const { fs:
|
|
3408
|
+
const { fs: fs3, paths } = ports;
|
|
3374
3409
|
let config = initialConfig;
|
|
3375
|
-
const previousState = readHeadroomState(
|
|
3410
|
+
const previousState = readHeadroomState(fs3, paths.headroomStateFile);
|
|
3376
3411
|
if (previousState?.supervisorPid !== void 0 && previousState.supervisorPid !== ports.ownPid && ports.isRunning(previousState.supervisorPid)) {
|
|
3377
3412
|
ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: supervisor ${String(previousState.supervisorPid)} already owns the daemon; exiting`);
|
|
3378
3413
|
return 0;
|
|
@@ -3381,19 +3416,19 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3381
3416
|
let lastPort = previousState?.lastPort;
|
|
3382
3417
|
const sticky = () => lastPort === void 0 ? {} : { lastPort };
|
|
3383
3418
|
const ownsState = () => {
|
|
3384
|
-
const owner = readHeadroomState(
|
|
3419
|
+
const owner = readHeadroomState(fs3, paths.headroomStateFile)?.supervisorPid;
|
|
3385
3420
|
return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
|
|
3386
3421
|
};
|
|
3387
3422
|
const writeOwnState = (state) => {
|
|
3388
3423
|
if (!ownsState()) {
|
|
3389
3424
|
return false;
|
|
3390
3425
|
}
|
|
3391
|
-
writeHeadroomState(
|
|
3426
|
+
writeHeadroomState(fs3, paths.headroomStateFile, state);
|
|
3392
3427
|
return true;
|
|
3393
3428
|
};
|
|
3394
3429
|
const fail = (message) => {
|
|
3395
3430
|
if (writeOwnState({ lastError: message, ...sticky() })) {
|
|
3396
|
-
|
|
3431
|
+
fs3.removeRecursive(paths.headroomLockFile);
|
|
3397
3432
|
}
|
|
3398
3433
|
ports.log(`agent-shim headroom supervisor: ${message}`);
|
|
3399
3434
|
return 1;
|
|
@@ -3442,7 +3477,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3442
3477
|
const settingsHash = hashSettings(config.settings);
|
|
3443
3478
|
const allowlist = allowlistOf(ports);
|
|
3444
3479
|
const allowlistHash = hashAllowlist(allowlist);
|
|
3445
|
-
pruneDeadSessions(
|
|
3480
|
+
pruneDeadSessions(fs3, paths.headroomSessionsDir, ports.isRunning);
|
|
3446
3481
|
const ownsNow = ownsState();
|
|
3447
3482
|
if (!ownsNow && !superseded) {
|
|
3448
3483
|
ports.log("agent-shim headroom supervisor: another supervisor now owns state.json; serving this daemon's own sessions until they end");
|
|
@@ -3494,7 +3529,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3494
3529
|
...sticky()
|
|
3495
3530
|
});
|
|
3496
3531
|
if (recorded) {
|
|
3497
|
-
|
|
3532
|
+
fs3.removeRecursive(paths.headroomLockFile);
|
|
3498
3533
|
}
|
|
3499
3534
|
idleSince = void 0;
|
|
3500
3535
|
ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on 127.0.0.1:${String(port)}`);
|
|
@@ -3509,7 +3544,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3509
3544
|
}
|
|
3510
3545
|
} else {
|
|
3511
3546
|
if (runningHash !== allowlistHash || runningSettingsHash !== settingsHash || installedSource !== config.source) {
|
|
3512
|
-
if (sessionsForSupervisor(
|
|
3547
|
+
if (sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid).length === 0) {
|
|
3513
3548
|
ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
|
|
3514
3549
|
ports.stopProcess(headroomPid);
|
|
3515
3550
|
headroomPid = void 0;
|
|
@@ -3518,7 +3553,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3518
3553
|
continue;
|
|
3519
3554
|
}
|
|
3520
3555
|
}
|
|
3521
|
-
const sessions = sessionsForSupervisor(
|
|
3556
|
+
const sessions = sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid);
|
|
3522
3557
|
if (sessions.length === 0) {
|
|
3523
3558
|
idleSince ??= ports.now();
|
|
3524
3559
|
const idleMs = ports.now() - idleSince;
|
|
@@ -3540,9 +3575,9 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3540
3575
|
await ports.sleep(HEADROOM_POLL_MS);
|
|
3541
3576
|
}
|
|
3542
3577
|
}
|
|
3543
|
-
function currentHeadroomAllowlist(
|
|
3544
|
-
const providers = readAllProviders(
|
|
3545
|
-
return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(
|
|
3578
|
+
function currentHeadroomAllowlist(fs3, paths) {
|
|
3579
|
+
const providers = readAllProviders(fs3, paths.providersDir).map((entry) => entry.provider);
|
|
3580
|
+
return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs3, paths.frontdoorStateFile))));
|
|
3546
3581
|
}
|
|
3547
3582
|
function allowlistOf(ports) {
|
|
3548
3583
|
return currentHeadroomAllowlist(ports.fs, ports.paths);
|
|
@@ -3606,19 +3641,100 @@ function evaluateAmbientCredentialGuard(params) {
|
|
|
3606
3641
|
message: formatAmbientCredentialGuardMessage(detected.variable, params.identityName)
|
|
3607
3642
|
};
|
|
3608
3643
|
}
|
|
3644
|
+
|
|
3645
|
+
// src/paths.ts
|
|
3646
|
+
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
3647
|
+
var import_node_os = __toESM(require("node:os"), 1);
|
|
3648
|
+
var import_node_path8 = __toESM(require("node:path"), 1);
|
|
3649
|
+
function resolveAgentShimHome(env = process.env, home = import_node_os.default.homedir(), isDirectory = isExistingDirectory) {
|
|
3650
|
+
const fromEnv = env.AGENT_SHIM_HOME;
|
|
3651
|
+
if (fromEnv !== void 0 && fromEnv !== "") {
|
|
3652
|
+
return fromEnv;
|
|
3653
|
+
}
|
|
3654
|
+
const current = import_node_path8.default.join(home, HOME_DIRNAME);
|
|
3655
|
+
const legacy = import_node_path8.default.join(home, LEGACY_HOME_DIRNAME);
|
|
3656
|
+
return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
|
|
3657
|
+
}
|
|
3658
|
+
function isExistingDirectory(candidate) {
|
|
3659
|
+
return import_node_fs.default.statSync(candidate, { throwIfNoEntry: false })?.isDirectory() ?? false;
|
|
3660
|
+
}
|
|
3661
|
+
function resolveClaudeHome() {
|
|
3662
|
+
const fromEnv = process.env.AGENT_SHIM_CLAUDE_HOME;
|
|
3663
|
+
if (fromEnv !== void 0 && fromEnv !== "") {
|
|
3664
|
+
return fromEnv;
|
|
3665
|
+
}
|
|
3666
|
+
return import_node_path8.default.join(import_node_os.default.homedir(), ".claude");
|
|
3667
|
+
}
|
|
3668
|
+
function buildLayoutPaths(root) {
|
|
3669
|
+
return {
|
|
3670
|
+
root,
|
|
3671
|
+
identitiesDir: import_node_path8.default.join(root, "identities"),
|
|
3672
|
+
configProfilesDir: import_node_path8.default.join(root, "config-profiles"),
|
|
3673
|
+
providersDir: import_node_path8.default.join(root, "providers"),
|
|
3674
|
+
directoryRulesFile: import_node_path8.default.join(root, "directory-rules.json"),
|
|
3675
|
+
activeIdentityFile: import_node_path8.default.join(root, "active-identity"),
|
|
3676
|
+
globalConfigFile: import_node_path8.default.join(root, "config.json"),
|
|
3677
|
+
categoriesLocalFile: import_node_path8.default.join(root, "categories.local.json"),
|
|
3678
|
+
claudeShimFile: import_node_path8.default.join(root, "claude-shim.json"),
|
|
3679
|
+
headroomDir: import_node_path8.default.join(root, "headroom"),
|
|
3680
|
+
headroomStateFile: import_node_path8.default.join(root, "headroom", "state.json"),
|
|
3681
|
+
headroomLockFile: import_node_path8.default.join(root, "headroom", "start.lock"),
|
|
3682
|
+
headroomSessionsDir: import_node_path8.default.join(root, "headroom", "sessions"),
|
|
3683
|
+
logsDir: import_node_path8.default.join(root, "logs"),
|
|
3684
|
+
headroomLogPath: import_node_path8.default.join(root, "logs", "headroom.log"),
|
|
3685
|
+
frontdoorDir: import_node_path8.default.join(root, "frontdoor"),
|
|
3686
|
+
frontdoorCaDir: import_node_path8.default.join(root, "frontdoor", "ca"),
|
|
3687
|
+
frontdoorCaCertFile: import_node_path8.default.join(root, "frontdoor", "ca", "ca.pem"),
|
|
3688
|
+
frontdoorCaKeyFile: import_node_path8.default.join(root, "frontdoor", "ca", "ca.key"),
|
|
3689
|
+
frontdoorCaBundlesDir: import_node_path8.default.join(root, "frontdoor", "ca", "bundles"),
|
|
3690
|
+
frontdoorStateFile: import_node_path8.default.join(root, "frontdoor", "state.json"),
|
|
3691
|
+
frontdoorLockFile: import_node_path8.default.join(root, "frontdoor", "start.lock"),
|
|
3692
|
+
frontdoorSessionsDir: import_node_path8.default.join(root, "frontdoor", "sessions"),
|
|
3693
|
+
frontdoorLogPath: import_node_path8.default.join(root, "logs", "frontdoor.log"),
|
|
3694
|
+
usageDir: import_node_path8.default.join(root, "usage"),
|
|
3695
|
+
usageLogDir: import_node_path8.default.join(root, "usage", "log"),
|
|
3696
|
+
usageSnapshotsDir: import_node_path8.default.join(root, "usage", "snapshots"),
|
|
3697
|
+
usagePicksFile: import_node_path8.default.join(root, "usage", "picks.json")
|
|
3698
|
+
};
|
|
3699
|
+
}
|
|
3700
|
+
function resolveLayoutPaths() {
|
|
3701
|
+
return buildLayoutPaths(resolveAgentShimHome());
|
|
3702
|
+
}
|
|
3609
3703
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3610
3704
|
0 && (module.exports = {
|
|
3611
3705
|
AMBIENT_CREDENTIAL_VARS,
|
|
3612
3706
|
CONNECT_INTERCEPT_HOST,
|
|
3613
3707
|
CONNECT_INTERCEPT_HOSTS,
|
|
3614
3708
|
CONNECT_LIMITS,
|
|
3709
|
+
CategoryClassificationOverlaySchema,
|
|
3710
|
+
CategoryClassificationSchema,
|
|
3711
|
+
CategoryMapSchema,
|
|
3712
|
+
CliError,
|
|
3713
|
+
ConfigProfileSchema,
|
|
3714
|
+
CredentialCacheSchema,
|
|
3715
|
+
CredentialSchema,
|
|
3716
|
+
CredentialSourceSchema,
|
|
3717
|
+
DirectoryRuleSchema,
|
|
3718
|
+
DirectoryRulesSchema,
|
|
3719
|
+
EXIT_FAILURE,
|
|
3720
|
+
EXIT_USAGE,
|
|
3721
|
+
EntryValueSchema,
|
|
3615
3722
|
FARM_MANIFEST_FILENAME,
|
|
3616
3723
|
FrontDoorStartError,
|
|
3724
|
+
GlobalConfigSchema,
|
|
3617
3725
|
HeadroomStartError,
|
|
3726
|
+
IdentitySchema,
|
|
3727
|
+
PoolNameSchema,
|
|
3728
|
+
PoolSchema,
|
|
3729
|
+
PortableConfigSchema,
|
|
3730
|
+
ProviderSchema,
|
|
3618
3731
|
ROUTED_PATH_PREFIX,
|
|
3732
|
+
UsageError,
|
|
3619
3733
|
UsageSnapshotError,
|
|
3620
3734
|
UsageSnapshotSchema,
|
|
3735
|
+
WhenSchema,
|
|
3621
3736
|
buildEntryFacts,
|
|
3737
|
+
buildLayoutPaths,
|
|
3622
3738
|
carryOver,
|
|
3623
3739
|
createLeafCache,
|
|
3624
3740
|
detectAmbientCredential,
|
|
@@ -3639,7 +3755,10 @@ function evaluateAmbientCredentialGuard(params) {
|
|
|
3639
3755
|
realConnectEffects,
|
|
3640
3756
|
recoverFarm,
|
|
3641
3757
|
recoveryDiagnostics,
|
|
3758
|
+
resolveAgentShimHome,
|
|
3759
|
+
resolveClaudeHome,
|
|
3642
3760
|
resolveDecisions,
|
|
3761
|
+
resolveLayoutPaths,
|
|
3643
3762
|
resolveSupervisorConfig,
|
|
3644
3763
|
resyncFarm,
|
|
3645
3764
|
runFrontDoorSupervisor,
|
package/dist/index.mjs
CHANGED
|
@@ -248,10 +248,18 @@ import { cosmiconfigSync } from "cosmiconfig";
|
|
|
248
248
|
|
|
249
249
|
// src/cliError.ts
|
|
250
250
|
var EXIT_FAILURE = 1;
|
|
251
|
+
var EXIT_USAGE = 2;
|
|
251
252
|
var CliError = class extends Error {
|
|
252
253
|
/** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
|
|
253
254
|
exitCode = EXIT_FAILURE;
|
|
254
255
|
};
|
|
256
|
+
var UsageError = class extends CliError {
|
|
257
|
+
exitCode = EXIT_USAGE;
|
|
258
|
+
constructor(message) {
|
|
259
|
+
super(message);
|
|
260
|
+
this.name = "UsageError";
|
|
261
|
+
}
|
|
262
|
+
};
|
|
255
263
|
|
|
256
264
|
// src/config/classify.ts
|
|
257
265
|
var GLOB_METACHARACTERS = /[*?[\]{}!()]/;
|
|
@@ -1212,6 +1220,8 @@ function planReconciliation(params) {
|
|
|
1212
1220
|
}
|
|
1213
1221
|
|
|
1214
1222
|
// src/legacy.ts
|
|
1223
|
+
var HOME_DIRNAME = ".agent-shim";
|
|
1224
|
+
var LEGACY_HOME_DIRNAME = ".claude-use";
|
|
1215
1225
|
var LEGACY_FARM_MANIFEST_FILENAME = ".claude-use-farm.json";
|
|
1216
1226
|
|
|
1217
1227
|
// src/launcher/lock.ts
|
|
@@ -1313,8 +1323,8 @@ var FarmManifestSchema = z2.strictObject({
|
|
|
1313
1323
|
materialised: z2.array(z2.string()),
|
|
1314
1324
|
links: z2.array(z2.strictObject({ rel: z2.string(), target: z2.string() }))
|
|
1315
1325
|
});
|
|
1316
|
-
function readFarmManifest(
|
|
1317
|
-
const raw =
|
|
1326
|
+
function readFarmManifest(fs3, farmRoot) {
|
|
1327
|
+
const raw = fs3.readFileUtf8(path4.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs3.readFileUtf8(path4.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
|
|
1318
1328
|
if (raw === void 0) {
|
|
1319
1329
|
return void 0;
|
|
1320
1330
|
}
|
|
@@ -1372,9 +1382,9 @@ function buildEntryFacts(params) {
|
|
|
1372
1382
|
entries
|
|
1373
1383
|
};
|
|
1374
1384
|
}
|
|
1375
|
-
function listSubtree(
|
|
1385
|
+
function listSubtree(fs3, root, rel) {
|
|
1376
1386
|
const absolute = path4.join(root, rel);
|
|
1377
|
-
const stat =
|
|
1387
|
+
const stat = fs3.lstat(absolute);
|
|
1378
1388
|
if (stat === void 0) {
|
|
1379
1389
|
return [];
|
|
1380
1390
|
}
|
|
@@ -1382,10 +1392,10 @@ function listSubtree(fs2, root, rel) {
|
|
|
1382
1392
|
return [{ rel, kind: "symlink" }];
|
|
1383
1393
|
}
|
|
1384
1394
|
if (stat.kind === "dir") {
|
|
1385
|
-
const children = [...
|
|
1395
|
+
const children = [...fs3.readdir(absolute)].sort().flatMap((name) => listSubtree(fs3, root, `${rel}/${name}`));
|
|
1386
1396
|
return [{ rel, kind: "dir" }, ...children];
|
|
1387
1397
|
}
|
|
1388
|
-
const contentHash =
|
|
1398
|
+
const contentHash = fs3.hashFile(absolute);
|
|
1389
1399
|
return [{ rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } }];
|
|
1390
1400
|
}
|
|
1391
1401
|
function topLevelScopeRoots(roots) {
|
|
@@ -1399,25 +1409,25 @@ function topLevelScopeRoots(roots) {
|
|
|
1399
1409
|
}
|
|
1400
1410
|
return kept;
|
|
1401
1411
|
}
|
|
1402
|
-
function reconciliationScope(
|
|
1412
|
+
function reconciliationScope(fs3, farmRoot, manifest) {
|
|
1403
1413
|
if (manifest !== void 0) {
|
|
1404
1414
|
return topLevelScopeRoots(manifest.materialised);
|
|
1405
1415
|
}
|
|
1406
|
-
return [...
|
|
1416
|
+
return [...fs3.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs3.lstat(path4.join(farmRoot, name))?.kind === "dir").sort();
|
|
1407
1417
|
}
|
|
1408
|
-
function collectFarmListing(
|
|
1409
|
-
return scopeRoots.flatMap((root) => listSubtree(
|
|
1418
|
+
function collectFarmListing(fs3, farmRoot, scopeRoots) {
|
|
1419
|
+
return scopeRoots.flatMap((root) => listSubtree(fs3, farmRoot, root));
|
|
1410
1420
|
}
|
|
1411
|
-
function collectCanonicalCounterparts(
|
|
1421
|
+
function collectCanonicalCounterparts(fs3, claudeHome, farmListing) {
|
|
1412
1422
|
const out = [];
|
|
1413
1423
|
for (const entry of farmListing) {
|
|
1414
1424
|
const absolute = path4.join(claudeHome, entry.rel);
|
|
1415
|
-
const stat =
|
|
1425
|
+
const stat = fs3.lstat(absolute);
|
|
1416
1426
|
if (stat === void 0) {
|
|
1417
1427
|
continue;
|
|
1418
1428
|
}
|
|
1419
1429
|
if (stat.kind === "file") {
|
|
1420
|
-
const contentHash =
|
|
1430
|
+
const contentHash = fs3.hashFile(absolute);
|
|
1421
1431
|
out.push({ rel: entry.rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } });
|
|
1422
1432
|
continue;
|
|
1423
1433
|
}
|
|
@@ -2101,10 +2111,10 @@ var FrontDoorStateSchema = z3.strictObject({
|
|
|
2101
2111
|
/** The last fatal error, kept across shutdowns so `frontdoor status` can explain a front door that is not running. */
|
|
2102
2112
|
lastError: z3.string().optional()
|
|
2103
2113
|
});
|
|
2104
|
-
function readFrontDoorState(
|
|
2114
|
+
function readFrontDoorState(fs3, stateFile) {
|
|
2105
2115
|
let raw;
|
|
2106
2116
|
try {
|
|
2107
|
-
raw =
|
|
2117
|
+
raw = fs3.readFileUtf8(stateFile);
|
|
2108
2118
|
} catch {
|
|
2109
2119
|
return void 0;
|
|
2110
2120
|
}
|
|
@@ -2118,28 +2128,28 @@ function readFrontDoorState(fs2, stateFile) {
|
|
|
2118
2128
|
return void 0;
|
|
2119
2129
|
}
|
|
2120
2130
|
}
|
|
2121
|
-
function writeFrontDoorState(
|
|
2122
|
-
|
|
2123
|
-
|
|
2131
|
+
function writeFrontDoorState(fs3, stateFile, state) {
|
|
2132
|
+
fs3.mkdirp(path5.dirname(stateFile));
|
|
2133
|
+
fs3.writeFileUtf8(stateFile, `${JSON.stringify(state, null, 2)}
|
|
2124
2134
|
`);
|
|
2125
2135
|
}
|
|
2126
2136
|
function frontDoorOrigin(state) {
|
|
2127
2137
|
const port = state?.directPort ?? state?.lastDirectPort;
|
|
2128
2138
|
return port === void 0 ? void 0 : `http://127.0.0.1:${String(port)}`;
|
|
2129
2139
|
}
|
|
2130
|
-
function writeFrontDoorSession(
|
|
2131
|
-
|
|
2132
|
-
|
|
2140
|
+
function writeFrontDoorSession(fs3, sessionsDir, session) {
|
|
2141
|
+
fs3.mkdirPrivate(sessionsDir);
|
|
2142
|
+
fs3.writeFilePrivate(path5.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
|
|
2133
2143
|
`);
|
|
2134
2144
|
}
|
|
2135
|
-
function listFrontDoorSessions(
|
|
2145
|
+
function listFrontDoorSessions(fs3, sessionsDir) {
|
|
2136
2146
|
const sessions = [];
|
|
2137
|
-
for (const name of
|
|
2147
|
+
for (const name of fs3.readdir(sessionsDir)) {
|
|
2138
2148
|
if (!name.endsWith(".json")) {
|
|
2139
2149
|
continue;
|
|
2140
2150
|
}
|
|
2141
2151
|
try {
|
|
2142
|
-
const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(
|
|
2152
|
+
const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs3.readFileUtf8(path5.join(sessionsDir, name)) ?? ""));
|
|
2143
2153
|
if (parsed.success) {
|
|
2144
2154
|
sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
|
|
2145
2155
|
}
|
|
@@ -2149,14 +2159,14 @@ function listFrontDoorSessions(fs2, sessionsDir) {
|
|
|
2149
2159
|
}
|
|
2150
2160
|
return sessions.sort((a, b) => a.pid - b.pid);
|
|
2151
2161
|
}
|
|
2152
|
-
function removeFrontDoorSession(
|
|
2153
|
-
|
|
2162
|
+
function removeFrontDoorSession(fs3, sessionsDir, pid) {
|
|
2163
|
+
fs3.removeRecursive(path5.join(sessionsDir, `${String(pid)}.json`));
|
|
2154
2164
|
}
|
|
2155
|
-
function pruneDeadFrontDoorSessions(
|
|
2165
|
+
function pruneDeadFrontDoorSessions(fs3, sessionsDir, isRunning) {
|
|
2156
2166
|
const removed = [];
|
|
2157
|
-
for (const session of listFrontDoorSessions(
|
|
2167
|
+
for (const session of listFrontDoorSessions(fs3, sessionsDir)) {
|
|
2158
2168
|
if (!isRunning(session.pid)) {
|
|
2159
|
-
removeFrontDoorSession(
|
|
2169
|
+
removeFrontDoorSession(fs3, sessionsDir, session.pid);
|
|
2160
2170
|
removed.push(session.pid);
|
|
2161
2171
|
}
|
|
2162
2172
|
}
|
|
@@ -2168,8 +2178,8 @@ var FRONTDOOR_SUPERVISOR_STILL_RUNNING = -1;
|
|
|
2168
2178
|
var FRONTDOOR_POLL_MS = 1e3;
|
|
2169
2179
|
var MS_PER_MINUTE = 6e4;
|
|
2170
2180
|
async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {}) {
|
|
2171
|
-
const { fs:
|
|
2172
|
-
const previous = readFrontDoorState(
|
|
2181
|
+
const { fs: fs3, paths } = ports;
|
|
2182
|
+
const previous = readFrontDoorState(fs3, paths.frontdoorStateFile);
|
|
2173
2183
|
let lastPort = previous?.lastPort;
|
|
2174
2184
|
let lastConnectPort = previous?.lastConnectPort;
|
|
2175
2185
|
let lastDirectPort = previous?.lastDirectPort;
|
|
@@ -2179,12 +2189,12 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
2179
2189
|
...lastDirectPort === void 0 ? {} : { lastDirectPort }
|
|
2180
2190
|
});
|
|
2181
2191
|
const fail = (message) => {
|
|
2182
|
-
writeFrontDoorState(
|
|
2183
|
-
|
|
2192
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, { lastError: message, ...sticky() });
|
|
2193
|
+
fs3.removeRecursive(paths.frontdoorLockFile);
|
|
2184
2194
|
ports.log(`agent-shim frontdoor supervisor: ${message}`);
|
|
2185
2195
|
return 1;
|
|
2186
2196
|
};
|
|
2187
|
-
writeFrontDoorState(
|
|
2197
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
|
|
2188
2198
|
const previousSticky = lastPort;
|
|
2189
2199
|
let http2;
|
|
2190
2200
|
try {
|
|
@@ -2221,8 +2231,8 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
2221
2231
|
ports.log(`agent-shim frontdoor supervisor: sticky direct port ${String(previousStickyDirect)} was occupied; moving to ${String(direct.port)} (headroom must be restarted to admit the new address)`);
|
|
2222
2232
|
}
|
|
2223
2233
|
lastDirectPort = direct.port;
|
|
2224
|
-
writeFrontDoorState(
|
|
2225
|
-
|
|
2234
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, port: http2.port, connectPort: connect2.port, directPort: direct.port, ...sticky() });
|
|
2235
|
+
fs3.removeRecursive(paths.frontdoorLockFile);
|
|
2226
2236
|
ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: front door on 127.0.0.1:${String(http2.port)}, CONNECT surface on 127.0.0.1:${String(connect2.port)}`);
|
|
2227
2237
|
let idleSince;
|
|
2228
2238
|
let ticks = 0;
|
|
@@ -2231,15 +2241,15 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
2231
2241
|
return FRONTDOOR_SUPERVISOR_STILL_RUNNING;
|
|
2232
2242
|
}
|
|
2233
2243
|
ticks += 1;
|
|
2234
|
-
pruneDeadFrontDoorSessions(
|
|
2235
|
-
if (listFrontDoorSessions(
|
|
2244
|
+
pruneDeadFrontDoorSessions(fs3, paths.frontdoorSessionsDir, ports.isRunning);
|
|
2245
|
+
if (listFrontDoorSessions(fs3, paths.frontdoorSessionsDir).length === 0) {
|
|
2236
2246
|
idleSince ??= ports.now();
|
|
2237
2247
|
if (ports.now() - idleSince >= idleShutdownMinutes * MS_PER_MINUTE) {
|
|
2238
2248
|
ports.log(`agent-shim frontdoor supervisor: no sessions for ${String(idleShutdownMinutes)} minute(s); closing the front door and exiting`);
|
|
2239
2249
|
await direct.close();
|
|
2240
2250
|
await connect2.close();
|
|
2241
2251
|
await http2.close();
|
|
2242
|
-
writeFrontDoorState(
|
|
2252
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, sticky());
|
|
2243
2253
|
return 0;
|
|
2244
2254
|
}
|
|
2245
2255
|
} else {
|
|
@@ -2294,8 +2304,8 @@ function parseConnectTarget(authority) {
|
|
|
2294
2304
|
function isInterceptedHost(host, interceptHosts) {
|
|
2295
2305
|
return interceptHosts.includes(host);
|
|
2296
2306
|
}
|
|
2297
|
-
function servedByPipeline(
|
|
2298
|
-
return
|
|
2307
|
+
function servedByPipeline(path9) {
|
|
2308
|
+
return path9?.startsWith(ROUTED_PATH_PREFIX) === true;
|
|
2299
2309
|
}
|
|
2300
2310
|
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
2301
2311
|
"connection",
|
|
@@ -2778,16 +2788,16 @@ function parseJson(raw, schema) {
|
|
|
2778
2788
|
const parsed = schema.safeParse(JSON.parse(raw));
|
|
2779
2789
|
return parsed.success ? parsed.data : void 0;
|
|
2780
2790
|
}
|
|
2781
|
-
function readHeadroomState(
|
|
2791
|
+
function readHeadroomState(fs3, stateFile) {
|
|
2782
2792
|
try {
|
|
2783
|
-
return parseJson(
|
|
2793
|
+
return parseJson(fs3.readFileUtf8(stateFile), HeadroomStateSchema);
|
|
2784
2794
|
} catch {
|
|
2785
2795
|
return void 0;
|
|
2786
2796
|
}
|
|
2787
2797
|
}
|
|
2788
|
-
function writeHeadroomState(
|
|
2789
|
-
|
|
2790
|
-
|
|
2798
|
+
function writeHeadroomState(fs3, stateFile, state) {
|
|
2799
|
+
fs3.mkdirp(path6.dirname(stateFile));
|
|
2800
|
+
fs3.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
|
|
2791
2801
|
`);
|
|
2792
2802
|
}
|
|
2793
2803
|
function headroomAllowlist(providers) {
|
|
@@ -2807,14 +2817,14 @@ function headroomUpstreams(providers, frontDoorOrigin2) {
|
|
|
2807
2817
|
function hashAllowlist(allowlist) {
|
|
2808
2818
|
return createHash2("sha256").update(allowlist.join("\n")).digest("hex");
|
|
2809
2819
|
}
|
|
2810
|
-
function readAllProviders(
|
|
2820
|
+
function readAllProviders(fs3, providersDir) {
|
|
2811
2821
|
const result = [];
|
|
2812
|
-
for (const name of
|
|
2822
|
+
for (const name of fs3.readdir(providersDir)) {
|
|
2813
2823
|
if (!name.endsWith(".json")) {
|
|
2814
2824
|
continue;
|
|
2815
2825
|
}
|
|
2816
2826
|
try {
|
|
2817
|
-
const parsed = parseJson(
|
|
2827
|
+
const parsed = parseJson(fs3.readFileUtf8(path6.join(providersDir, name)), ProviderSchema);
|
|
2818
2828
|
if (parsed !== void 0) {
|
|
2819
2829
|
result.push({ name: name.slice(0, -".json".length), provider: parsed });
|
|
2820
2830
|
}
|
|
@@ -2824,22 +2834,22 @@ function readAllProviders(fs2, providersDir) {
|
|
|
2824
2834
|
}
|
|
2825
2835
|
return result;
|
|
2826
2836
|
}
|
|
2827
|
-
function writeSession(
|
|
2828
|
-
|
|
2829
|
-
|
|
2837
|
+
function writeSession(fs3, sessionsDir, session) {
|
|
2838
|
+
fs3.mkdirp(sessionsDir);
|
|
2839
|
+
fs3.writeFileUtf8(path6.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
|
|
2830
2840
|
`);
|
|
2831
2841
|
}
|
|
2832
|
-
function removeSession(
|
|
2833
|
-
|
|
2842
|
+
function removeSession(fs3, sessionsDir, pid) {
|
|
2843
|
+
fs3.removeRecursive(path6.join(sessionsDir, `${String(pid)}.json`));
|
|
2834
2844
|
}
|
|
2835
|
-
function listSessions(
|
|
2845
|
+
function listSessions(fs3, sessionsDir) {
|
|
2836
2846
|
const sessions = [];
|
|
2837
|
-
for (const name of
|
|
2847
|
+
for (const name of fs3.readdir(sessionsDir)) {
|
|
2838
2848
|
if (!name.endsWith(".json")) {
|
|
2839
2849
|
continue;
|
|
2840
2850
|
}
|
|
2841
2851
|
try {
|
|
2842
|
-
const parsed = parseJson(
|
|
2852
|
+
const parsed = parseJson(fs3.readFileUtf8(path6.join(sessionsDir, name)), HeadroomSessionSchema);
|
|
2843
2853
|
if (parsed !== void 0) {
|
|
2844
2854
|
sessions.push(parsed);
|
|
2845
2855
|
}
|
|
@@ -2849,22 +2859,22 @@ function listSessions(fs2, sessionsDir) {
|
|
|
2849
2859
|
}
|
|
2850
2860
|
return sessions.sort((a, b) => a.pid - b.pid);
|
|
2851
2861
|
}
|
|
2852
|
-
function sessionsForSupervisor(
|
|
2853
|
-
return listSessions(
|
|
2862
|
+
function sessionsForSupervisor(fs3, sessionsDir, supervisorPid) {
|
|
2863
|
+
return listSessions(fs3, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
|
|
2854
2864
|
}
|
|
2855
|
-
function pruneDeadSessions(
|
|
2865
|
+
function pruneDeadSessions(fs3, sessionsDir, isRunning) {
|
|
2856
2866
|
const removed = [];
|
|
2857
|
-
for (const session of listSessions(
|
|
2867
|
+
for (const session of listSessions(fs3, sessionsDir)) {
|
|
2858
2868
|
if (!isRunning(session.pid)) {
|
|
2859
|
-
removeSession(
|
|
2869
|
+
removeSession(fs3, sessionsDir, session.pid);
|
|
2860
2870
|
removed.push(session.pid);
|
|
2861
2871
|
}
|
|
2862
2872
|
}
|
|
2863
2873
|
return removed;
|
|
2864
2874
|
}
|
|
2865
|
-
function readStartLock(
|
|
2875
|
+
function readStartLock(fs3, lockFile) {
|
|
2866
2876
|
try {
|
|
2867
|
-
return parseJson(
|
|
2877
|
+
return parseJson(fs3.readFileUtf8(lockFile), HeadroomLockSchema);
|
|
2868
2878
|
} catch {
|
|
2869
2879
|
return void 0;
|
|
2870
2880
|
}
|
|
@@ -3101,9 +3111,9 @@ function snapshotPath(snapshotsDir, identity) {
|
|
|
3101
3111
|
}
|
|
3102
3112
|
return path7.join(snapshotsDir, `${identity}.json`);
|
|
3103
3113
|
}
|
|
3104
|
-
function readUsageSnapshot(
|
|
3114
|
+
function readUsageSnapshot(fs3, snapshotsDir, identity) {
|
|
3105
3115
|
const file = snapshotPath(snapshotsDir, identity);
|
|
3106
|
-
const raw =
|
|
3116
|
+
const raw = fs3.readFileUtf8(file);
|
|
3107
3117
|
if (raw === void 0) {
|
|
3108
3118
|
return void 0;
|
|
3109
3119
|
}
|
|
@@ -3119,8 +3129,8 @@ function readUsageSnapshot(fs2, snapshotsDir, identity) {
|
|
|
3119
3129
|
}
|
|
3120
3130
|
return snapshot.data;
|
|
3121
3131
|
}
|
|
3122
|
-
function listUsageSnapshots(
|
|
3123
|
-
return
|
|
3132
|
+
function listUsageSnapshots(fs3, snapshotsDir) {
|
|
3133
|
+
return fs3.readdir(snapshotsDir).flatMap((name) => {
|
|
3124
3134
|
if (!name.endsWith(".json")) {
|
|
3125
3135
|
return [];
|
|
3126
3136
|
}
|
|
@@ -3128,7 +3138,7 @@ function listUsageSnapshots(fs2, snapshotsDir) {
|
|
|
3128
3138
|
if (!isIdentityName(identity)) {
|
|
3129
3139
|
return [];
|
|
3130
3140
|
}
|
|
3131
|
-
const snapshot = readUsageSnapshot(
|
|
3141
|
+
const snapshot = readUsageSnapshot(fs3, snapshotsDir, identity);
|
|
3132
3142
|
return snapshot === void 0 ? [] : [snapshot];
|
|
3133
3143
|
}).sort((left, right) => left.identity.localeCompare(right.identity));
|
|
3134
3144
|
}
|
|
@@ -3295,9 +3305,9 @@ function compareVersions(a, b) {
|
|
|
3295
3305
|
}
|
|
3296
3306
|
var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
|
|
3297
3307
|
async function runSupervisor(initialConfig, ports, options = {}) {
|
|
3298
|
-
const { fs:
|
|
3308
|
+
const { fs: fs3, paths } = ports;
|
|
3299
3309
|
let config = initialConfig;
|
|
3300
|
-
const previousState = readHeadroomState(
|
|
3310
|
+
const previousState = readHeadroomState(fs3, paths.headroomStateFile);
|
|
3301
3311
|
if (previousState?.supervisorPid !== void 0 && previousState.supervisorPid !== ports.ownPid && ports.isRunning(previousState.supervisorPid)) {
|
|
3302
3312
|
ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: supervisor ${String(previousState.supervisorPid)} already owns the daemon; exiting`);
|
|
3303
3313
|
return 0;
|
|
@@ -3306,19 +3316,19 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3306
3316
|
let lastPort = previousState?.lastPort;
|
|
3307
3317
|
const sticky = () => lastPort === void 0 ? {} : { lastPort };
|
|
3308
3318
|
const ownsState = () => {
|
|
3309
|
-
const owner = readHeadroomState(
|
|
3319
|
+
const owner = readHeadroomState(fs3, paths.headroomStateFile)?.supervisorPid;
|
|
3310
3320
|
return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
|
|
3311
3321
|
};
|
|
3312
3322
|
const writeOwnState = (state) => {
|
|
3313
3323
|
if (!ownsState()) {
|
|
3314
3324
|
return false;
|
|
3315
3325
|
}
|
|
3316
|
-
writeHeadroomState(
|
|
3326
|
+
writeHeadroomState(fs3, paths.headroomStateFile, state);
|
|
3317
3327
|
return true;
|
|
3318
3328
|
};
|
|
3319
3329
|
const fail = (message) => {
|
|
3320
3330
|
if (writeOwnState({ lastError: message, ...sticky() })) {
|
|
3321
|
-
|
|
3331
|
+
fs3.removeRecursive(paths.headroomLockFile);
|
|
3322
3332
|
}
|
|
3323
3333
|
ports.log(`agent-shim headroom supervisor: ${message}`);
|
|
3324
3334
|
return 1;
|
|
@@ -3367,7 +3377,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3367
3377
|
const settingsHash = hashSettings(config.settings);
|
|
3368
3378
|
const allowlist = allowlistOf(ports);
|
|
3369
3379
|
const allowlistHash = hashAllowlist(allowlist);
|
|
3370
|
-
pruneDeadSessions(
|
|
3380
|
+
pruneDeadSessions(fs3, paths.headroomSessionsDir, ports.isRunning);
|
|
3371
3381
|
const ownsNow = ownsState();
|
|
3372
3382
|
if (!ownsNow && !superseded) {
|
|
3373
3383
|
ports.log("agent-shim headroom supervisor: another supervisor now owns state.json; serving this daemon's own sessions until they end");
|
|
@@ -3419,7 +3429,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3419
3429
|
...sticky()
|
|
3420
3430
|
});
|
|
3421
3431
|
if (recorded) {
|
|
3422
|
-
|
|
3432
|
+
fs3.removeRecursive(paths.headroomLockFile);
|
|
3423
3433
|
}
|
|
3424
3434
|
idleSince = void 0;
|
|
3425
3435
|
ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on 127.0.0.1:${String(port)}`);
|
|
@@ -3434,7 +3444,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3434
3444
|
}
|
|
3435
3445
|
} else {
|
|
3436
3446
|
if (runningHash !== allowlistHash || runningSettingsHash !== settingsHash || installedSource !== config.source) {
|
|
3437
|
-
if (sessionsForSupervisor(
|
|
3447
|
+
if (sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid).length === 0) {
|
|
3438
3448
|
ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
|
|
3439
3449
|
ports.stopProcess(headroomPid);
|
|
3440
3450
|
headroomPid = void 0;
|
|
@@ -3443,7 +3453,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3443
3453
|
continue;
|
|
3444
3454
|
}
|
|
3445
3455
|
}
|
|
3446
|
-
const sessions = sessionsForSupervisor(
|
|
3456
|
+
const sessions = sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid);
|
|
3447
3457
|
if (sessions.length === 0) {
|
|
3448
3458
|
idleSince ??= ports.now();
|
|
3449
3459
|
const idleMs = ports.now() - idleSince;
|
|
@@ -3465,9 +3475,9 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3465
3475
|
await ports.sleep(HEADROOM_POLL_MS);
|
|
3466
3476
|
}
|
|
3467
3477
|
}
|
|
3468
|
-
function currentHeadroomAllowlist(
|
|
3469
|
-
const providers = readAllProviders(
|
|
3470
|
-
return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(
|
|
3478
|
+
function currentHeadroomAllowlist(fs3, paths) {
|
|
3479
|
+
const providers = readAllProviders(fs3, paths.providersDir).map((entry) => entry.provider);
|
|
3480
|
+
return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs3, paths.frontdoorStateFile))));
|
|
3471
3481
|
}
|
|
3472
3482
|
function allowlistOf(ports) {
|
|
3473
3483
|
return currentHeadroomAllowlist(ports.fs, ports.paths);
|
|
@@ -3531,18 +3541,99 @@ function evaluateAmbientCredentialGuard(params) {
|
|
|
3531
3541
|
message: formatAmbientCredentialGuardMessage(detected.variable, params.identityName)
|
|
3532
3542
|
};
|
|
3533
3543
|
}
|
|
3544
|
+
|
|
3545
|
+
// src/paths.ts
|
|
3546
|
+
import fs2 from "node:fs";
|
|
3547
|
+
import os from "node:os";
|
|
3548
|
+
import path8 from "node:path";
|
|
3549
|
+
function resolveAgentShimHome(env = process.env, home = os.homedir(), isDirectory = isExistingDirectory) {
|
|
3550
|
+
const fromEnv = env.AGENT_SHIM_HOME;
|
|
3551
|
+
if (fromEnv !== void 0 && fromEnv !== "") {
|
|
3552
|
+
return fromEnv;
|
|
3553
|
+
}
|
|
3554
|
+
const current = path8.join(home, HOME_DIRNAME);
|
|
3555
|
+
const legacy = path8.join(home, LEGACY_HOME_DIRNAME);
|
|
3556
|
+
return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
|
|
3557
|
+
}
|
|
3558
|
+
function isExistingDirectory(candidate) {
|
|
3559
|
+
return fs2.statSync(candidate, { throwIfNoEntry: false })?.isDirectory() ?? false;
|
|
3560
|
+
}
|
|
3561
|
+
function resolveClaudeHome() {
|
|
3562
|
+
const fromEnv = process.env.AGENT_SHIM_CLAUDE_HOME;
|
|
3563
|
+
if (fromEnv !== void 0 && fromEnv !== "") {
|
|
3564
|
+
return fromEnv;
|
|
3565
|
+
}
|
|
3566
|
+
return path8.join(os.homedir(), ".claude");
|
|
3567
|
+
}
|
|
3568
|
+
function buildLayoutPaths(root) {
|
|
3569
|
+
return {
|
|
3570
|
+
root,
|
|
3571
|
+
identitiesDir: path8.join(root, "identities"),
|
|
3572
|
+
configProfilesDir: path8.join(root, "config-profiles"),
|
|
3573
|
+
providersDir: path8.join(root, "providers"),
|
|
3574
|
+
directoryRulesFile: path8.join(root, "directory-rules.json"),
|
|
3575
|
+
activeIdentityFile: path8.join(root, "active-identity"),
|
|
3576
|
+
globalConfigFile: path8.join(root, "config.json"),
|
|
3577
|
+
categoriesLocalFile: path8.join(root, "categories.local.json"),
|
|
3578
|
+
claudeShimFile: path8.join(root, "claude-shim.json"),
|
|
3579
|
+
headroomDir: path8.join(root, "headroom"),
|
|
3580
|
+
headroomStateFile: path8.join(root, "headroom", "state.json"),
|
|
3581
|
+
headroomLockFile: path8.join(root, "headroom", "start.lock"),
|
|
3582
|
+
headroomSessionsDir: path8.join(root, "headroom", "sessions"),
|
|
3583
|
+
logsDir: path8.join(root, "logs"),
|
|
3584
|
+
headroomLogPath: path8.join(root, "logs", "headroom.log"),
|
|
3585
|
+
frontdoorDir: path8.join(root, "frontdoor"),
|
|
3586
|
+
frontdoorCaDir: path8.join(root, "frontdoor", "ca"),
|
|
3587
|
+
frontdoorCaCertFile: path8.join(root, "frontdoor", "ca", "ca.pem"),
|
|
3588
|
+
frontdoorCaKeyFile: path8.join(root, "frontdoor", "ca", "ca.key"),
|
|
3589
|
+
frontdoorCaBundlesDir: path8.join(root, "frontdoor", "ca", "bundles"),
|
|
3590
|
+
frontdoorStateFile: path8.join(root, "frontdoor", "state.json"),
|
|
3591
|
+
frontdoorLockFile: path8.join(root, "frontdoor", "start.lock"),
|
|
3592
|
+
frontdoorSessionsDir: path8.join(root, "frontdoor", "sessions"),
|
|
3593
|
+
frontdoorLogPath: path8.join(root, "logs", "frontdoor.log"),
|
|
3594
|
+
usageDir: path8.join(root, "usage"),
|
|
3595
|
+
usageLogDir: path8.join(root, "usage", "log"),
|
|
3596
|
+
usageSnapshotsDir: path8.join(root, "usage", "snapshots"),
|
|
3597
|
+
usagePicksFile: path8.join(root, "usage", "picks.json")
|
|
3598
|
+
};
|
|
3599
|
+
}
|
|
3600
|
+
function resolveLayoutPaths() {
|
|
3601
|
+
return buildLayoutPaths(resolveAgentShimHome());
|
|
3602
|
+
}
|
|
3534
3603
|
export {
|
|
3535
3604
|
AMBIENT_CREDENTIAL_VARS,
|
|
3536
3605
|
CONNECT_INTERCEPT_HOST,
|
|
3537
3606
|
CONNECT_INTERCEPT_HOSTS,
|
|
3538
3607
|
CONNECT_LIMITS,
|
|
3608
|
+
CategoryClassificationOverlaySchema,
|
|
3609
|
+
CategoryClassificationSchema,
|
|
3610
|
+
CategoryMapSchema,
|
|
3611
|
+
CliError,
|
|
3612
|
+
ConfigProfileSchema,
|
|
3613
|
+
CredentialCacheSchema,
|
|
3614
|
+
CredentialSchema,
|
|
3615
|
+
CredentialSourceSchema,
|
|
3616
|
+
DirectoryRuleSchema,
|
|
3617
|
+
DirectoryRulesSchema,
|
|
3618
|
+
EXIT_FAILURE,
|
|
3619
|
+
EXIT_USAGE,
|
|
3620
|
+
EntryValueSchema,
|
|
3539
3621
|
FARM_MANIFEST_FILENAME,
|
|
3540
3622
|
FrontDoorStartError,
|
|
3623
|
+
GlobalConfigSchema,
|
|
3541
3624
|
HeadroomStartError,
|
|
3625
|
+
IdentitySchema,
|
|
3626
|
+
PoolNameSchema,
|
|
3627
|
+
PoolSchema,
|
|
3628
|
+
PortableConfigSchema,
|
|
3629
|
+
ProviderSchema,
|
|
3542
3630
|
ROUTED_PATH_PREFIX,
|
|
3631
|
+
UsageError,
|
|
3543
3632
|
UsageSnapshotError,
|
|
3544
3633
|
UsageSnapshotSchema,
|
|
3634
|
+
WhenSchema,
|
|
3545
3635
|
buildEntryFacts,
|
|
3636
|
+
buildLayoutPaths,
|
|
3546
3637
|
carryOver,
|
|
3547
3638
|
createLeafCache,
|
|
3548
3639
|
detectAmbientCredential,
|
|
@@ -3563,7 +3654,10 @@ export {
|
|
|
3563
3654
|
realConnectEffects,
|
|
3564
3655
|
recoverFarm,
|
|
3565
3656
|
recoveryDiagnostics,
|
|
3657
|
+
resolveAgentShimHome,
|
|
3658
|
+
resolveClaudeHome,
|
|
3566
3659
|
resolveDecisions,
|
|
3660
|
+
resolveLayoutPaths,
|
|
3567
3661
|
resolveSupervisorConfig,
|
|
3568
3662
|
resyncFarm,
|
|
3569
3663
|
runFrontDoorSupervisor,
|
|
@@ -427,7 +427,7 @@ export declare const POOL_SELECTOR_PREFIX = "pool:";
|
|
|
427
427
|
/** A pool's own name: the identity alphabet minus `@`, since a pool is never an email address. */
|
|
428
428
|
export declare const PoolNameSchema: z.ZodString;
|
|
429
429
|
/** A named, explicit set of identities to choose among at launch. Never implicit: a pool lists its members, so an identity that bills a client is only ever picked when someone put it there. */
|
|
430
|
-
declare const PoolSchema: z.ZodObject<{
|
|
430
|
+
export declare const PoolSchema: z.ZodObject<{
|
|
431
431
|
identities: z.ZodArray<z.ZodString>;
|
|
432
432
|
}, z.core.$strict>;
|
|
433
433
|
export type Pool = z.infer<typeof PoolSchema>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* - identity and configuration-profile resolution and farm sync (`resolveDecisions`, `resyncFarm`, `buildEntryFacts`, ...), pure over facts and ports passed in;
|
|
5
5
|
* - routing: the front door's Remote-Control-preserving, capability-authenticated CONNECT surface and its certificate authority, the front-door supervisor and ensure lifecycle, and the headroom supervisor and ensure lifecycle, each pure over its injected ports;
|
|
6
6
|
* - the ambient-credential guard;
|
|
7
|
-
* - the per-identity usage snapshot a statusline or launcher reads: its schema and the reader over an injected filesystem
|
|
7
|
+
* - the per-identity usage snapshot a statusline or launcher reads: its schema and the reader over an injected filesystem;
|
|
8
|
+
* - the state root's layout (`resolveAgentShimHome`, `resolveLayoutPaths`, `buildLayoutPaths`), which includes adopting an existing `~/.claude-use` in place, and the Zod schema and inferred type of every configuration file (identity, configuration profile, provider, pool, directory rules, global config, credential), so a tool can validate or generate them with the same definitions the CLI uses.
|
|
8
9
|
*
|
|
9
10
|
* Everything the CLI alone needs (commander wiring, prompts, `doctor`, `check`) is deliberately not exported here.
|
|
10
11
|
*/
|
|
@@ -19,3 +20,6 @@ export { UsageSnapshotSchema, type UsageSnapshot } from "./usage/schema";
|
|
|
19
20
|
export { ensureHeadroom, HeadroomStartError, type EnsureHeadroomPorts } from "./headroom/ensure";
|
|
20
21
|
export { resolveSupervisorConfig, runSupervisor, type HeadroomSupervisorConfig, type RunSupervisorOptions, type SupervisorPorts } from "./headroom/supervisor";
|
|
21
22
|
export { AMBIENT_CREDENTIAL_VARS, detectAmbientCredential, evaluateAmbientCredentialGuard, formatAmbientCredentialGuardMessage, type AmbientCredentialDetection, type AmbientCredentialGuardResult, type AmbientCredentialVar, type EvaluateAmbientCredentialGuardParams, type InjectedCredential, } from "./launcher/guard";
|
|
23
|
+
export { buildLayoutPaths, resolveAgentShimHome, resolveClaudeHome, resolveLayoutPaths, type LayoutPaths } from "./paths";
|
|
24
|
+
export { CliError, EXIT_FAILURE, EXIT_USAGE, UsageError } from "./cliError";
|
|
25
|
+
export { CategoryClassificationOverlaySchema, CategoryClassificationSchema, CategoryMapSchema, ConfigProfileSchema, CredentialCacheSchema, CredentialSchema, CredentialSourceSchema, DirectoryRuleSchema, DirectoryRulesSchema, EntryValueSchema, GlobalConfigSchema, IdentitySchema, PoolNameSchema, PoolSchema, PortableConfigSchema, ProviderSchema, WhenSchema, type CategoryMap, type ConfigProfile, type Credential, type CredentialSource, type DirectoryRule, type DirectoryRules, type EntryValue, type GlobalConfig, type Identity, type Pool, type PortableConfig, type Provider, type WhenCondition, } from "./config/schema";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-shim",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.5.0",
|
|
4
4
|
"description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Joseph Mearman <joseph@mearman.co.uk>",
|