agent-shim 7.3.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 +29 -23
- package/dist/index.cjs +229 -100
- package/dist/index.mjs +203 -100
- package/dist/types/config/schema.d.ts +1 -1
- package/dist/types/frontdoor/connect.d.ts +17 -9
- package/dist/types/index.d.ts +6 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -32,14 +32,37 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
AMBIENT_CREDENTIAL_VARS: () => AMBIENT_CREDENTIAL_VARS,
|
|
34
34
|
CONNECT_INTERCEPT_HOST: () => CONNECT_INTERCEPT_HOST,
|
|
35
|
+
CONNECT_INTERCEPT_HOSTS: () => CONNECT_INTERCEPT_HOSTS,
|
|
35
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,
|
|
36
50
|
FARM_MANIFEST_FILENAME: () => FARM_MANIFEST_FILENAME,
|
|
37
51
|
FrontDoorStartError: () => FrontDoorStartError,
|
|
52
|
+
GlobalConfigSchema: () => GlobalConfigSchema,
|
|
38
53
|
HeadroomStartError: () => HeadroomStartError,
|
|
54
|
+
IdentitySchema: () => IdentitySchema,
|
|
55
|
+
PoolNameSchema: () => PoolNameSchema,
|
|
56
|
+
PoolSchema: () => PoolSchema,
|
|
57
|
+
PortableConfigSchema: () => PortableConfigSchema,
|
|
58
|
+
ProviderSchema: () => ProviderSchema,
|
|
39
59
|
ROUTED_PATH_PREFIX: () => ROUTED_PATH_PREFIX,
|
|
60
|
+
UsageError: () => UsageError,
|
|
40
61
|
UsageSnapshotError: () => UsageSnapshotError,
|
|
41
62
|
UsageSnapshotSchema: () => UsageSnapshotSchema,
|
|
63
|
+
WhenSchema: () => WhenSchema,
|
|
42
64
|
buildEntryFacts: () => buildEntryFacts,
|
|
65
|
+
buildLayoutPaths: () => buildLayoutPaths,
|
|
43
66
|
carryOver: () => carryOver,
|
|
44
67
|
createLeafCache: () => createLeafCache,
|
|
45
68
|
detectAmbientCredential: () => detectAmbientCredential,
|
|
@@ -60,7 +83,10 @@ __export(index_exports, {
|
|
|
60
83
|
realConnectEffects: () => realConnectEffects,
|
|
61
84
|
recoverFarm: () => recoverFarm,
|
|
62
85
|
recoveryDiagnostics: () => recoveryDiagnostics,
|
|
86
|
+
resolveAgentShimHome: () => resolveAgentShimHome,
|
|
87
|
+
resolveClaudeHome: () => resolveClaudeHome,
|
|
63
88
|
resolveDecisions: () => resolveDecisions,
|
|
89
|
+
resolveLayoutPaths: () => resolveLayoutPaths,
|
|
64
90
|
resolveSupervisorConfig: () => resolveSupervisorConfig,
|
|
65
91
|
resyncFarm: () => resyncFarm,
|
|
66
92
|
runFrontDoorSupervisor: () => runFrontDoorSupervisor,
|
|
@@ -322,10 +348,18 @@ var import_cosmiconfig = require("cosmiconfig");
|
|
|
322
348
|
|
|
323
349
|
// src/cliError.ts
|
|
324
350
|
var EXIT_FAILURE = 1;
|
|
351
|
+
var EXIT_USAGE = 2;
|
|
325
352
|
var CliError = class extends Error {
|
|
326
353
|
/** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
|
|
327
354
|
exitCode = EXIT_FAILURE;
|
|
328
355
|
};
|
|
356
|
+
var UsageError = class extends CliError {
|
|
357
|
+
exitCode = EXIT_USAGE;
|
|
358
|
+
constructor(message) {
|
|
359
|
+
super(message);
|
|
360
|
+
this.name = "UsageError";
|
|
361
|
+
}
|
|
362
|
+
};
|
|
329
363
|
|
|
330
364
|
// src/config/classify.ts
|
|
331
365
|
var GLOB_METACHARACTERS = /[*?[\]{}!()]/;
|
|
@@ -1286,6 +1320,8 @@ function planReconciliation(params) {
|
|
|
1286
1320
|
}
|
|
1287
1321
|
|
|
1288
1322
|
// src/legacy.ts
|
|
1323
|
+
var HOME_DIRNAME = ".agent-shim";
|
|
1324
|
+
var LEGACY_HOME_DIRNAME = ".claude-use";
|
|
1289
1325
|
var LEGACY_FARM_MANIFEST_FILENAME = ".claude-use-farm.json";
|
|
1290
1326
|
|
|
1291
1327
|
// src/launcher/lock.ts
|
|
@@ -1387,8 +1423,8 @@ var FarmManifestSchema = import_zod2.z.strictObject({
|
|
|
1387
1423
|
materialised: import_zod2.z.array(import_zod2.z.string()),
|
|
1388
1424
|
links: import_zod2.z.array(import_zod2.z.strictObject({ rel: import_zod2.z.string(), target: import_zod2.z.string() }))
|
|
1389
1425
|
});
|
|
1390
|
-
function readFarmManifest(
|
|
1391
|
-
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));
|
|
1392
1428
|
if (raw === void 0) {
|
|
1393
1429
|
return void 0;
|
|
1394
1430
|
}
|
|
@@ -1446,9 +1482,9 @@ function buildEntryFacts(params) {
|
|
|
1446
1482
|
entries
|
|
1447
1483
|
};
|
|
1448
1484
|
}
|
|
1449
|
-
function listSubtree(
|
|
1485
|
+
function listSubtree(fs3, root, rel) {
|
|
1450
1486
|
const absolute = import_node_path4.default.join(root, rel);
|
|
1451
|
-
const stat =
|
|
1487
|
+
const stat = fs3.lstat(absolute);
|
|
1452
1488
|
if (stat === void 0) {
|
|
1453
1489
|
return [];
|
|
1454
1490
|
}
|
|
@@ -1456,10 +1492,10 @@ function listSubtree(fs2, root, rel) {
|
|
|
1456
1492
|
return [{ rel, kind: "symlink" }];
|
|
1457
1493
|
}
|
|
1458
1494
|
if (stat.kind === "dir") {
|
|
1459
|
-
const children = [...
|
|
1495
|
+
const children = [...fs3.readdir(absolute)].sort().flatMap((name) => listSubtree(fs3, root, `${rel}/${name}`));
|
|
1460
1496
|
return [{ rel, kind: "dir" }, ...children];
|
|
1461
1497
|
}
|
|
1462
|
-
const contentHash =
|
|
1498
|
+
const contentHash = fs3.hashFile(absolute);
|
|
1463
1499
|
return [{ rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } }];
|
|
1464
1500
|
}
|
|
1465
1501
|
function topLevelScopeRoots(roots) {
|
|
@@ -1473,25 +1509,25 @@ function topLevelScopeRoots(roots) {
|
|
|
1473
1509
|
}
|
|
1474
1510
|
return kept;
|
|
1475
1511
|
}
|
|
1476
|
-
function reconciliationScope(
|
|
1512
|
+
function reconciliationScope(fs3, farmRoot, manifest) {
|
|
1477
1513
|
if (manifest !== void 0) {
|
|
1478
1514
|
return topLevelScopeRoots(manifest.materialised);
|
|
1479
1515
|
}
|
|
1480
|
-
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();
|
|
1481
1517
|
}
|
|
1482
|
-
function collectFarmListing(
|
|
1483
|
-
return scopeRoots.flatMap((root) => listSubtree(
|
|
1518
|
+
function collectFarmListing(fs3, farmRoot, scopeRoots) {
|
|
1519
|
+
return scopeRoots.flatMap((root) => listSubtree(fs3, farmRoot, root));
|
|
1484
1520
|
}
|
|
1485
|
-
function collectCanonicalCounterparts(
|
|
1521
|
+
function collectCanonicalCounterparts(fs3, claudeHome, farmListing) {
|
|
1486
1522
|
const out = [];
|
|
1487
1523
|
for (const entry of farmListing) {
|
|
1488
1524
|
const absolute = import_node_path4.default.join(claudeHome, entry.rel);
|
|
1489
|
-
const stat =
|
|
1525
|
+
const stat = fs3.lstat(absolute);
|
|
1490
1526
|
if (stat === void 0) {
|
|
1491
1527
|
continue;
|
|
1492
1528
|
}
|
|
1493
1529
|
if (stat.kind === "file") {
|
|
1494
|
-
const contentHash =
|
|
1530
|
+
const contentHash = fs3.hashFile(absolute);
|
|
1495
1531
|
out.push({ rel: entry.rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } });
|
|
1496
1532
|
continue;
|
|
1497
1533
|
}
|
|
@@ -2175,10 +2211,10 @@ var FrontDoorStateSchema = import_zod3.z.strictObject({
|
|
|
2175
2211
|
/** The last fatal error, kept across shutdowns so `frontdoor status` can explain a front door that is not running. */
|
|
2176
2212
|
lastError: import_zod3.z.string().optional()
|
|
2177
2213
|
});
|
|
2178
|
-
function readFrontDoorState(
|
|
2214
|
+
function readFrontDoorState(fs3, stateFile) {
|
|
2179
2215
|
let raw;
|
|
2180
2216
|
try {
|
|
2181
|
-
raw =
|
|
2217
|
+
raw = fs3.readFileUtf8(stateFile);
|
|
2182
2218
|
} catch {
|
|
2183
2219
|
return void 0;
|
|
2184
2220
|
}
|
|
@@ -2192,28 +2228,28 @@ function readFrontDoorState(fs2, stateFile) {
|
|
|
2192
2228
|
return void 0;
|
|
2193
2229
|
}
|
|
2194
2230
|
}
|
|
2195
|
-
function writeFrontDoorState(
|
|
2196
|
-
|
|
2197
|
-
|
|
2231
|
+
function writeFrontDoorState(fs3, stateFile, state) {
|
|
2232
|
+
fs3.mkdirp(import_node_path5.default.dirname(stateFile));
|
|
2233
|
+
fs3.writeFileUtf8(stateFile, `${JSON.stringify(state, null, 2)}
|
|
2198
2234
|
`);
|
|
2199
2235
|
}
|
|
2200
2236
|
function frontDoorOrigin(state) {
|
|
2201
2237
|
const port = state?.directPort ?? state?.lastDirectPort;
|
|
2202
2238
|
return port === void 0 ? void 0 : `http://127.0.0.1:${String(port)}`;
|
|
2203
2239
|
}
|
|
2204
|
-
function writeFrontDoorSession(
|
|
2205
|
-
|
|
2206
|
-
|
|
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)}
|
|
2207
2243
|
`);
|
|
2208
2244
|
}
|
|
2209
|
-
function listFrontDoorSessions(
|
|
2245
|
+
function listFrontDoorSessions(fs3, sessionsDir) {
|
|
2210
2246
|
const sessions = [];
|
|
2211
|
-
for (const name of
|
|
2247
|
+
for (const name of fs3.readdir(sessionsDir)) {
|
|
2212
2248
|
if (!name.endsWith(".json")) {
|
|
2213
2249
|
continue;
|
|
2214
2250
|
}
|
|
2215
2251
|
try {
|
|
2216
|
-
const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(
|
|
2252
|
+
const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs3.readFileUtf8(import_node_path5.default.join(sessionsDir, name)) ?? ""));
|
|
2217
2253
|
if (parsed.success) {
|
|
2218
2254
|
sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
|
|
2219
2255
|
}
|
|
@@ -2223,14 +2259,14 @@ function listFrontDoorSessions(fs2, sessionsDir) {
|
|
|
2223
2259
|
}
|
|
2224
2260
|
return sessions.sort((a, b) => a.pid - b.pid);
|
|
2225
2261
|
}
|
|
2226
|
-
function removeFrontDoorSession(
|
|
2227
|
-
|
|
2262
|
+
function removeFrontDoorSession(fs3, sessionsDir, pid) {
|
|
2263
|
+
fs3.removeRecursive(import_node_path5.default.join(sessionsDir, `${String(pid)}.json`));
|
|
2228
2264
|
}
|
|
2229
|
-
function pruneDeadFrontDoorSessions(
|
|
2265
|
+
function pruneDeadFrontDoorSessions(fs3, sessionsDir, isRunning) {
|
|
2230
2266
|
const removed = [];
|
|
2231
|
-
for (const session of listFrontDoorSessions(
|
|
2267
|
+
for (const session of listFrontDoorSessions(fs3, sessionsDir)) {
|
|
2232
2268
|
if (!isRunning(session.pid)) {
|
|
2233
|
-
removeFrontDoorSession(
|
|
2269
|
+
removeFrontDoorSession(fs3, sessionsDir, session.pid);
|
|
2234
2270
|
removed.push(session.pid);
|
|
2235
2271
|
}
|
|
2236
2272
|
}
|
|
@@ -2242,8 +2278,8 @@ var FRONTDOOR_SUPERVISOR_STILL_RUNNING = -1;
|
|
|
2242
2278
|
var FRONTDOOR_POLL_MS = 1e3;
|
|
2243
2279
|
var MS_PER_MINUTE = 6e4;
|
|
2244
2280
|
async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {}) {
|
|
2245
|
-
const { fs:
|
|
2246
|
-
const previous = readFrontDoorState(
|
|
2281
|
+
const { fs: fs3, paths } = ports;
|
|
2282
|
+
const previous = readFrontDoorState(fs3, paths.frontdoorStateFile);
|
|
2247
2283
|
let lastPort = previous?.lastPort;
|
|
2248
2284
|
let lastConnectPort = previous?.lastConnectPort;
|
|
2249
2285
|
let lastDirectPort = previous?.lastDirectPort;
|
|
@@ -2253,12 +2289,12 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
2253
2289
|
...lastDirectPort === void 0 ? {} : { lastDirectPort }
|
|
2254
2290
|
});
|
|
2255
2291
|
const fail = (message) => {
|
|
2256
|
-
writeFrontDoorState(
|
|
2257
|
-
|
|
2292
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, { lastError: message, ...sticky() });
|
|
2293
|
+
fs3.removeRecursive(paths.frontdoorLockFile);
|
|
2258
2294
|
ports.log(`agent-shim frontdoor supervisor: ${message}`);
|
|
2259
2295
|
return 1;
|
|
2260
2296
|
};
|
|
2261
|
-
writeFrontDoorState(
|
|
2297
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
|
|
2262
2298
|
const previousSticky = lastPort;
|
|
2263
2299
|
let http2;
|
|
2264
2300
|
try {
|
|
@@ -2295,8 +2331,8 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
2295
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)`);
|
|
2296
2332
|
}
|
|
2297
2333
|
lastDirectPort = direct.port;
|
|
2298
|
-
writeFrontDoorState(
|
|
2299
|
-
|
|
2334
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, port: http2.port, connectPort: connect2.port, directPort: direct.port, ...sticky() });
|
|
2335
|
+
fs3.removeRecursive(paths.frontdoorLockFile);
|
|
2300
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)}`);
|
|
2301
2337
|
let idleSince;
|
|
2302
2338
|
let ticks = 0;
|
|
@@ -2305,15 +2341,15 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
2305
2341
|
return FRONTDOOR_SUPERVISOR_STILL_RUNNING;
|
|
2306
2342
|
}
|
|
2307
2343
|
ticks += 1;
|
|
2308
|
-
pruneDeadFrontDoorSessions(
|
|
2309
|
-
if (listFrontDoorSessions(
|
|
2344
|
+
pruneDeadFrontDoorSessions(fs3, paths.frontdoorSessionsDir, ports.isRunning);
|
|
2345
|
+
if (listFrontDoorSessions(fs3, paths.frontdoorSessionsDir).length === 0) {
|
|
2310
2346
|
idleSince ??= ports.now();
|
|
2311
2347
|
if (ports.now() - idleSince >= idleShutdownMinutes * MS_PER_MINUTE) {
|
|
2312
2348
|
ports.log(`agent-shim frontdoor supervisor: no sessions for ${String(idleShutdownMinutes)} minute(s); closing the front door and exiting`);
|
|
2313
2349
|
await direct.close();
|
|
2314
2350
|
await connect2.close();
|
|
2315
2351
|
await http2.close();
|
|
2316
|
-
writeFrontDoorState(
|
|
2352
|
+
writeFrontDoorState(fs3, paths.frontdoorStateFile, sticky());
|
|
2317
2353
|
return 0;
|
|
2318
2354
|
}
|
|
2319
2355
|
} else {
|
|
@@ -2325,6 +2361,7 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
|
|
|
2325
2361
|
|
|
2326
2362
|
// src/frontdoor/connect.ts
|
|
2327
2363
|
var CONNECT_INTERCEPT_HOST = "api.anthropic.com";
|
|
2364
|
+
var CONNECT_INTERCEPT_HOSTS = [CONNECT_INTERCEPT_HOST, "platform.claude.com"];
|
|
2328
2365
|
var ROUTED_PATH_PREFIX = "/v1/";
|
|
2329
2366
|
var HTTPS_PORT = 443;
|
|
2330
2367
|
var MAX_PORT = 65535;
|
|
@@ -2364,11 +2401,11 @@ function parseConnectTarget(authority) {
|
|
|
2364
2401
|
}
|
|
2365
2402
|
return { host, port };
|
|
2366
2403
|
}
|
|
2367
|
-
function isInterceptedHost(host,
|
|
2368
|
-
return host
|
|
2404
|
+
function isInterceptedHost(host, interceptHosts) {
|
|
2405
|
+
return interceptHosts.includes(host);
|
|
2369
2406
|
}
|
|
2370
|
-
function servedByPipeline(
|
|
2371
|
-
return
|
|
2407
|
+
function servedByPipeline(path9) {
|
|
2408
|
+
return path9?.startsWith(ROUTED_PATH_PREFIX) === true;
|
|
2372
2409
|
}
|
|
2373
2410
|
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
2374
2411
|
"connection",
|
|
@@ -2435,28 +2472,34 @@ function caParses(ca) {
|
|
|
2435
2472
|
}
|
|
2436
2473
|
}
|
|
2437
2474
|
async function startConnectServer(config, effects, preferredPort) {
|
|
2438
|
-
const
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
httpSession.
|
|
2475
|
+
const onUpgrade = config.capture === void 0 ? void 0 : (request3) => config.capture?.upgrade(request3);
|
|
2476
|
+
const sessions = config.interceptHosts.map((host) => {
|
|
2477
|
+
const handler = (request3, response) => {
|
|
2478
|
+
if (host === config.routedHost && servedByPipeline(request3.url)) {
|
|
2479
|
+
config.serveRouted(request3, response);
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
effects.forwardHttp(config.upstreamFor(host), request3, response, config.capture?.observePassthrough(request3));
|
|
2483
|
+
};
|
|
2484
|
+
const httpSession = effects.createHttpSession(handler, onUpgrade);
|
|
2485
|
+
const tlsAcceptor = effects.createTlsAcceptor(config.leafFor(host), (secure) => {
|
|
2486
|
+
httpSession.serve(secure);
|
|
2487
|
+
});
|
|
2488
|
+
return { host, httpSession, tlsAcceptor };
|
|
2448
2489
|
});
|
|
2449
2490
|
const ledger = createConnectionLedger(config.limits, config.isLiveCapability);
|
|
2450
2491
|
const listener = await effects.listenLoopback(preferredPort, (socket) => {
|
|
2451
|
-
handleConnect(socket, { config, effects,
|
|
2492
|
+
handleConnect(socket, { config, effects, sessions, ledger });
|
|
2452
2493
|
});
|
|
2453
2494
|
return {
|
|
2454
2495
|
port: listener.port,
|
|
2455
2496
|
close: async () => {
|
|
2456
2497
|
ledger.close();
|
|
2457
2498
|
await listener.close();
|
|
2458
|
-
tlsAcceptor
|
|
2459
|
-
|
|
2499
|
+
for (const { httpSession, tlsAcceptor } of sessions) {
|
|
2500
|
+
tlsAcceptor.close();
|
|
2501
|
+
httpSession.close();
|
|
2502
|
+
}
|
|
2460
2503
|
}
|
|
2461
2504
|
};
|
|
2462
2505
|
}
|
|
@@ -2576,7 +2619,7 @@ function proxyAuthorizationOf(head) {
|
|
|
2576
2619
|
return values.length === 1 ? value : void 0;
|
|
2577
2620
|
}
|
|
2578
2621
|
function routeConnect(socket, head, context) {
|
|
2579
|
-
const { config, effects,
|
|
2622
|
+
const { config, effects, sessions, ledger } = context;
|
|
2580
2623
|
const credential = proxyAuthorizationOf(head);
|
|
2581
2624
|
const capability = credential === void 0 ? void 0 : capabilityFromProxyAuthorization(credential);
|
|
2582
2625
|
if (capability === void 0 || !config.isLiveCapability(capability)) {
|
|
@@ -2595,10 +2638,11 @@ function routeConnect(socket, head, context) {
|
|
|
2595
2638
|
refuse(socket, REFUSAL.serviceUnavailable);
|
|
2596
2639
|
return;
|
|
2597
2640
|
}
|
|
2598
|
-
|
|
2641
|
+
const session = sessions.find((entry) => entry.host === target.host);
|
|
2642
|
+
config.capture?.connect(target, session !== void 0);
|
|
2599
2643
|
socket.write(CONNECT_ESTABLISHED);
|
|
2600
|
-
if (
|
|
2601
|
-
tlsAcceptor.accept(socket);
|
|
2644
|
+
if (session !== void 0) {
|
|
2645
|
+
session.tlsAcceptor.accept(socket);
|
|
2602
2646
|
return;
|
|
2603
2647
|
}
|
|
2604
2648
|
void blindTunnel(socket, target, effects);
|
|
@@ -2844,16 +2888,16 @@ function parseJson(raw, schema) {
|
|
|
2844
2888
|
const parsed = schema.safeParse(JSON.parse(raw));
|
|
2845
2889
|
return parsed.success ? parsed.data : void 0;
|
|
2846
2890
|
}
|
|
2847
|
-
function readHeadroomState(
|
|
2891
|
+
function readHeadroomState(fs3, stateFile) {
|
|
2848
2892
|
try {
|
|
2849
|
-
return parseJson(
|
|
2893
|
+
return parseJson(fs3.readFileUtf8(stateFile), HeadroomStateSchema);
|
|
2850
2894
|
} catch {
|
|
2851
2895
|
return void 0;
|
|
2852
2896
|
}
|
|
2853
2897
|
}
|
|
2854
|
-
function writeHeadroomState(
|
|
2855
|
-
|
|
2856
|
-
|
|
2898
|
+
function writeHeadroomState(fs3, stateFile, state) {
|
|
2899
|
+
fs3.mkdirp(import_node_path6.default.dirname(stateFile));
|
|
2900
|
+
fs3.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
|
|
2857
2901
|
`);
|
|
2858
2902
|
}
|
|
2859
2903
|
function headroomAllowlist(providers) {
|
|
@@ -2873,14 +2917,14 @@ function headroomUpstreams(providers, frontDoorOrigin2) {
|
|
|
2873
2917
|
function hashAllowlist(allowlist) {
|
|
2874
2918
|
return (0, import_node_crypto4.createHash)("sha256").update(allowlist.join("\n")).digest("hex");
|
|
2875
2919
|
}
|
|
2876
|
-
function readAllProviders(
|
|
2920
|
+
function readAllProviders(fs3, providersDir) {
|
|
2877
2921
|
const result = [];
|
|
2878
|
-
for (const name of
|
|
2922
|
+
for (const name of fs3.readdir(providersDir)) {
|
|
2879
2923
|
if (!name.endsWith(".json")) {
|
|
2880
2924
|
continue;
|
|
2881
2925
|
}
|
|
2882
2926
|
try {
|
|
2883
|
-
const parsed = parseJson(
|
|
2927
|
+
const parsed = parseJson(fs3.readFileUtf8(import_node_path6.default.join(providersDir, name)), ProviderSchema);
|
|
2884
2928
|
if (parsed !== void 0) {
|
|
2885
2929
|
result.push({ name: name.slice(0, -".json".length), provider: parsed });
|
|
2886
2930
|
}
|
|
@@ -2890,22 +2934,22 @@ function readAllProviders(fs2, providersDir) {
|
|
|
2890
2934
|
}
|
|
2891
2935
|
return result;
|
|
2892
2936
|
}
|
|
2893
|
-
function writeSession(
|
|
2894
|
-
|
|
2895
|
-
|
|
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)}
|
|
2896
2940
|
`);
|
|
2897
2941
|
}
|
|
2898
|
-
function removeSession(
|
|
2899
|
-
|
|
2942
|
+
function removeSession(fs3, sessionsDir, pid) {
|
|
2943
|
+
fs3.removeRecursive(import_node_path6.default.join(sessionsDir, `${String(pid)}.json`));
|
|
2900
2944
|
}
|
|
2901
|
-
function listSessions(
|
|
2945
|
+
function listSessions(fs3, sessionsDir) {
|
|
2902
2946
|
const sessions = [];
|
|
2903
|
-
for (const name of
|
|
2947
|
+
for (const name of fs3.readdir(sessionsDir)) {
|
|
2904
2948
|
if (!name.endsWith(".json")) {
|
|
2905
2949
|
continue;
|
|
2906
2950
|
}
|
|
2907
2951
|
try {
|
|
2908
|
-
const parsed = parseJson(
|
|
2952
|
+
const parsed = parseJson(fs3.readFileUtf8(import_node_path6.default.join(sessionsDir, name)), HeadroomSessionSchema);
|
|
2909
2953
|
if (parsed !== void 0) {
|
|
2910
2954
|
sessions.push(parsed);
|
|
2911
2955
|
}
|
|
@@ -2915,22 +2959,22 @@ function listSessions(fs2, sessionsDir) {
|
|
|
2915
2959
|
}
|
|
2916
2960
|
return sessions.sort((a, b) => a.pid - b.pid);
|
|
2917
2961
|
}
|
|
2918
|
-
function sessionsForSupervisor(
|
|
2919
|
-
return listSessions(
|
|
2962
|
+
function sessionsForSupervisor(fs3, sessionsDir, supervisorPid) {
|
|
2963
|
+
return listSessions(fs3, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
|
|
2920
2964
|
}
|
|
2921
|
-
function pruneDeadSessions(
|
|
2965
|
+
function pruneDeadSessions(fs3, sessionsDir, isRunning) {
|
|
2922
2966
|
const removed = [];
|
|
2923
|
-
for (const session of listSessions(
|
|
2967
|
+
for (const session of listSessions(fs3, sessionsDir)) {
|
|
2924
2968
|
if (!isRunning(session.pid)) {
|
|
2925
|
-
removeSession(
|
|
2969
|
+
removeSession(fs3, sessionsDir, session.pid);
|
|
2926
2970
|
removed.push(session.pid);
|
|
2927
2971
|
}
|
|
2928
2972
|
}
|
|
2929
2973
|
return removed;
|
|
2930
2974
|
}
|
|
2931
|
-
function readStartLock(
|
|
2975
|
+
function readStartLock(fs3, lockFile) {
|
|
2932
2976
|
try {
|
|
2933
|
-
return parseJson(
|
|
2977
|
+
return parseJson(fs3.readFileUtf8(lockFile), HeadroomLockSchema);
|
|
2934
2978
|
} catch {
|
|
2935
2979
|
return void 0;
|
|
2936
2980
|
}
|
|
@@ -3167,9 +3211,9 @@ function snapshotPath(snapshotsDir, identity) {
|
|
|
3167
3211
|
}
|
|
3168
3212
|
return import_node_path7.default.join(snapshotsDir, `${identity}.json`);
|
|
3169
3213
|
}
|
|
3170
|
-
function readUsageSnapshot(
|
|
3214
|
+
function readUsageSnapshot(fs3, snapshotsDir, identity) {
|
|
3171
3215
|
const file = snapshotPath(snapshotsDir, identity);
|
|
3172
|
-
const raw =
|
|
3216
|
+
const raw = fs3.readFileUtf8(file);
|
|
3173
3217
|
if (raw === void 0) {
|
|
3174
3218
|
return void 0;
|
|
3175
3219
|
}
|
|
@@ -3185,8 +3229,8 @@ function readUsageSnapshot(fs2, snapshotsDir, identity) {
|
|
|
3185
3229
|
}
|
|
3186
3230
|
return snapshot.data;
|
|
3187
3231
|
}
|
|
3188
|
-
function listUsageSnapshots(
|
|
3189
|
-
return
|
|
3232
|
+
function listUsageSnapshots(fs3, snapshotsDir) {
|
|
3233
|
+
return fs3.readdir(snapshotsDir).flatMap((name) => {
|
|
3190
3234
|
if (!name.endsWith(".json")) {
|
|
3191
3235
|
return [];
|
|
3192
3236
|
}
|
|
@@ -3194,7 +3238,7 @@ function listUsageSnapshots(fs2, snapshotsDir) {
|
|
|
3194
3238
|
if (!isIdentityName(identity)) {
|
|
3195
3239
|
return [];
|
|
3196
3240
|
}
|
|
3197
|
-
const snapshot = readUsageSnapshot(
|
|
3241
|
+
const snapshot = readUsageSnapshot(fs3, snapshotsDir, identity);
|
|
3198
3242
|
return snapshot === void 0 ? [] : [snapshot];
|
|
3199
3243
|
}).sort((left, right) => left.identity.localeCompare(right.identity));
|
|
3200
3244
|
}
|
|
@@ -3361,9 +3405,9 @@ function compareVersions(a, b) {
|
|
|
3361
3405
|
}
|
|
3362
3406
|
var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
|
|
3363
3407
|
async function runSupervisor(initialConfig, ports, options = {}) {
|
|
3364
|
-
const { fs:
|
|
3408
|
+
const { fs: fs3, paths } = ports;
|
|
3365
3409
|
let config = initialConfig;
|
|
3366
|
-
const previousState = readHeadroomState(
|
|
3410
|
+
const previousState = readHeadroomState(fs3, paths.headroomStateFile);
|
|
3367
3411
|
if (previousState?.supervisorPid !== void 0 && previousState.supervisorPid !== ports.ownPid && ports.isRunning(previousState.supervisorPid)) {
|
|
3368
3412
|
ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: supervisor ${String(previousState.supervisorPid)} already owns the daemon; exiting`);
|
|
3369
3413
|
return 0;
|
|
@@ -3372,19 +3416,19 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3372
3416
|
let lastPort = previousState?.lastPort;
|
|
3373
3417
|
const sticky = () => lastPort === void 0 ? {} : { lastPort };
|
|
3374
3418
|
const ownsState = () => {
|
|
3375
|
-
const owner = readHeadroomState(
|
|
3419
|
+
const owner = readHeadroomState(fs3, paths.headroomStateFile)?.supervisorPid;
|
|
3376
3420
|
return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
|
|
3377
3421
|
};
|
|
3378
3422
|
const writeOwnState = (state) => {
|
|
3379
3423
|
if (!ownsState()) {
|
|
3380
3424
|
return false;
|
|
3381
3425
|
}
|
|
3382
|
-
writeHeadroomState(
|
|
3426
|
+
writeHeadroomState(fs3, paths.headroomStateFile, state);
|
|
3383
3427
|
return true;
|
|
3384
3428
|
};
|
|
3385
3429
|
const fail = (message) => {
|
|
3386
3430
|
if (writeOwnState({ lastError: message, ...sticky() })) {
|
|
3387
|
-
|
|
3431
|
+
fs3.removeRecursive(paths.headroomLockFile);
|
|
3388
3432
|
}
|
|
3389
3433
|
ports.log(`agent-shim headroom supervisor: ${message}`);
|
|
3390
3434
|
return 1;
|
|
@@ -3433,7 +3477,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3433
3477
|
const settingsHash = hashSettings(config.settings);
|
|
3434
3478
|
const allowlist = allowlistOf(ports);
|
|
3435
3479
|
const allowlistHash = hashAllowlist(allowlist);
|
|
3436
|
-
pruneDeadSessions(
|
|
3480
|
+
pruneDeadSessions(fs3, paths.headroomSessionsDir, ports.isRunning);
|
|
3437
3481
|
const ownsNow = ownsState();
|
|
3438
3482
|
if (!ownsNow && !superseded) {
|
|
3439
3483
|
ports.log("agent-shim headroom supervisor: another supervisor now owns state.json; serving this daemon's own sessions until they end");
|
|
@@ -3485,7 +3529,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3485
3529
|
...sticky()
|
|
3486
3530
|
});
|
|
3487
3531
|
if (recorded) {
|
|
3488
|
-
|
|
3532
|
+
fs3.removeRecursive(paths.headroomLockFile);
|
|
3489
3533
|
}
|
|
3490
3534
|
idleSince = void 0;
|
|
3491
3535
|
ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on 127.0.0.1:${String(port)}`);
|
|
@@ -3500,7 +3544,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3500
3544
|
}
|
|
3501
3545
|
} else {
|
|
3502
3546
|
if (runningHash !== allowlistHash || runningSettingsHash !== settingsHash || installedSource !== config.source) {
|
|
3503
|
-
if (sessionsForSupervisor(
|
|
3547
|
+
if (sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid).length === 0) {
|
|
3504
3548
|
ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
|
|
3505
3549
|
ports.stopProcess(headroomPid);
|
|
3506
3550
|
headroomPid = void 0;
|
|
@@ -3509,7 +3553,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3509
3553
|
continue;
|
|
3510
3554
|
}
|
|
3511
3555
|
}
|
|
3512
|
-
const sessions = sessionsForSupervisor(
|
|
3556
|
+
const sessions = sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid);
|
|
3513
3557
|
if (sessions.length === 0) {
|
|
3514
3558
|
idleSince ??= ports.now();
|
|
3515
3559
|
const idleMs = ports.now() - idleSince;
|
|
@@ -3531,9 +3575,9 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3531
3575
|
await ports.sleep(HEADROOM_POLL_MS);
|
|
3532
3576
|
}
|
|
3533
3577
|
}
|
|
3534
|
-
function currentHeadroomAllowlist(
|
|
3535
|
-
const providers = readAllProviders(
|
|
3536
|
-
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))));
|
|
3537
3581
|
}
|
|
3538
3582
|
function allowlistOf(ports) {
|
|
3539
3583
|
return currentHeadroomAllowlist(ports.fs, ports.paths);
|
|
@@ -3597,18 +3641,100 @@ function evaluateAmbientCredentialGuard(params) {
|
|
|
3597
3641
|
message: formatAmbientCredentialGuardMessage(detected.variable, params.identityName)
|
|
3598
3642
|
};
|
|
3599
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
|
+
}
|
|
3600
3703
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3601
3704
|
0 && (module.exports = {
|
|
3602
3705
|
AMBIENT_CREDENTIAL_VARS,
|
|
3603
3706
|
CONNECT_INTERCEPT_HOST,
|
|
3707
|
+
CONNECT_INTERCEPT_HOSTS,
|
|
3604
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,
|
|
3605
3722
|
FARM_MANIFEST_FILENAME,
|
|
3606
3723
|
FrontDoorStartError,
|
|
3724
|
+
GlobalConfigSchema,
|
|
3607
3725
|
HeadroomStartError,
|
|
3726
|
+
IdentitySchema,
|
|
3727
|
+
PoolNameSchema,
|
|
3728
|
+
PoolSchema,
|
|
3729
|
+
PortableConfigSchema,
|
|
3730
|
+
ProviderSchema,
|
|
3608
3731
|
ROUTED_PATH_PREFIX,
|
|
3732
|
+
UsageError,
|
|
3609
3733
|
UsageSnapshotError,
|
|
3610
3734
|
UsageSnapshotSchema,
|
|
3735
|
+
WhenSchema,
|
|
3611
3736
|
buildEntryFacts,
|
|
3737
|
+
buildLayoutPaths,
|
|
3612
3738
|
carryOver,
|
|
3613
3739
|
createLeafCache,
|
|
3614
3740
|
detectAmbientCredential,
|
|
@@ -3629,7 +3755,10 @@ function evaluateAmbientCredentialGuard(params) {
|
|
|
3629
3755
|
realConnectEffects,
|
|
3630
3756
|
recoverFarm,
|
|
3631
3757
|
recoveryDiagnostics,
|
|
3758
|
+
resolveAgentShimHome,
|
|
3759
|
+
resolveClaudeHome,
|
|
3632
3760
|
resolveDecisions,
|
|
3761
|
+
resolveLayoutPaths,
|
|
3633
3762
|
resolveSupervisorConfig,
|
|
3634
3763
|
resyncFarm,
|
|
3635
3764
|
runFrontDoorSupervisor,
|