agent-shim 7.14.0 → 8.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +661 -572
- package/dist/index.cjs +226 -150
- package/dist/index.mjs +226 -150
- package/dist/types/index.d.ts +36 -18
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -413,7 +413,7 @@ var HeadroomGlobalConfigSchema = HeadroomGlobalConfigObjectSchema.superRefine((c
|
|
|
413
413
|
context.addIssue({ code: "custom", path: ["readMaturation"], message: "readMaturation needs rolloutChannel beta or dev" });
|
|
414
414
|
}
|
|
415
415
|
});
|
|
416
|
-
var HEADROOM_DEFAULT_SOURCE = "headroom-ai[proxy] @ git+https://github.com/ExaDev/headroom@
|
|
416
|
+
var HEADROOM_DEFAULT_SOURCE = "headroom-ai[proxy] @ git+https://github.com/ExaDev/headroom@53525f479f2f48e8ef6b08cf729601feab7d2382";
|
|
417
417
|
var HEADROOM_DEFAULT_IDLE_SHUTDOWN_MINUTES = 15;
|
|
418
418
|
var FrontDoorGlobalConfigSchema = import_zod.z.strictObject({
|
|
419
419
|
/** How long the front door may sit with no registered sessions before it closes and exits. Defaults to FRONTDOOR_DEFAULT_IDLE_SHUTDOWN_MINUTES. */
|
|
@@ -2650,7 +2650,7 @@ function providerBaseUrl(port, provider) {
|
|
|
2650
2650
|
// src/frontdoor/state.ts
|
|
2651
2651
|
var import_node_path7 = __toESM(require("node:path"), 1);
|
|
2652
2652
|
var import_zod3 = require("zod");
|
|
2653
|
-
var FRONT_DOOR_PROTOCOL =
|
|
2653
|
+
var FRONT_DOOR_PROTOCOL = 2;
|
|
2654
2654
|
var FrontDoorSessionSchema = import_zod3.z.strictObject({ pid: import_zod3.z.number().int().positive(), startedAt: import_zod3.z.number(), token: import_zod3.z.string().min(1) });
|
|
2655
2655
|
var FrontDoorStateSchema = import_zod3.z.strictObject({
|
|
2656
2656
|
/**
|
|
@@ -2875,8 +2875,8 @@ function parseConnectTarget(authority) {
|
|
|
2875
2875
|
function isInterceptedHost(host, interceptHosts) {
|
|
2876
2876
|
return interceptHosts.includes(host);
|
|
2877
2877
|
}
|
|
2878
|
-
function servedByPipeline(
|
|
2879
|
-
return
|
|
2878
|
+
function servedByPipeline(path29) {
|
|
2879
|
+
return path29?.startsWith(ROUTED_PATH_PREFIX) === true;
|
|
2880
2880
|
}
|
|
2881
2881
|
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
2882
2882
|
"connection",
|
|
@@ -3442,17 +3442,16 @@ var import_node_crypto5 = require("node:crypto");
|
|
|
3442
3442
|
var import_node_path8 = __toESM(require("node:path"), 1);
|
|
3443
3443
|
var import_zod4 = require("zod");
|
|
3444
3444
|
var HEADROOM_ANTHROPIC_UPSTREAM = "https://api.anthropic.com";
|
|
3445
|
+
var HEADROOM_STATE_SCHEMA_VERSION = 2;
|
|
3445
3446
|
var HeadroomStateSchema = import_zod4.z.strictObject({
|
|
3446
3447
|
/** The supervisor process owning the daemon. Alive means someone is keeping headroom running. */
|
|
3447
3448
|
supervisorPid: import_zod4.z.number().int().positive().optional(),
|
|
3448
3449
|
/** The headroom proxy process itself. Absent while the supervisor is between restarts. */
|
|
3449
3450
|
headroomPid: import_zod4.z.number().int().positive().optional(),
|
|
3450
|
-
/** The loopback port the proxy listens on. Absent until the proxy has passed its readiness check, so "port is set" is itself the ready signal a launcher polls for. */
|
|
3451
|
-
port: import_zod4.z.number().int().positive().optional(),
|
|
3452
3451
|
/**
|
|
3453
|
-
* The
|
|
3452
|
+
* The unix socket the proxy serves on, inside the owner-only socket directory. Absent until the proxy has passed its readiness check, so "socketPath is set" is itself the ready signal a launcher polls for. The front door reads it on every hop, so a restart (which keeps the generation's path) is followed without anything being relaunched.
|
|
3454
3453
|
*/
|
|
3455
|
-
|
|
3454
|
+
socketPath: import_zod4.z.string().min(1).optional(),
|
|
3456
3455
|
/** The `headroom --version` output of the running install. */
|
|
3457
3456
|
version: import_zod4.z.string().optional(),
|
|
3458
3457
|
/** Hash of the allowlist the running proxy was started with, so a provider-file change is detected as drift. */
|
|
@@ -3959,10 +3958,10 @@ function ensureHeadroom(params) {
|
|
|
3959
3958
|
for (; ; ) {
|
|
3960
3959
|
const state = readHeadroomState(ports.fs, paths.headroomStateFile);
|
|
3961
3960
|
if (state?.supervisorPid !== void 0 && ports.isRunning(state.supervisorPid)) {
|
|
3962
|
-
const daemonUp = state.
|
|
3963
|
-
if (daemonUp && state.
|
|
3961
|
+
const daemonUp = state.socketPath !== void 0 && state.headroomPid !== void 0 && ports.isRunning(state.headroomPid);
|
|
3962
|
+
if (daemonUp && state.socketPath !== void 0) {
|
|
3964
3963
|
writeSession(ports.fs, paths.headroomSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), supervisorPid: state.supervisorPid });
|
|
3965
|
-
return {
|
|
3964
|
+
return { socketPath: state.socketPath };
|
|
3966
3965
|
}
|
|
3967
3966
|
if (state.lastError !== void 0) {
|
|
3968
3967
|
throw new HeadroomStartError(
|
|
@@ -4026,6 +4025,71 @@ function hashSettings(settings) {
|
|
|
4026
4025
|
return (0, import_node_crypto7.createHash)("sha256").update(JSON.stringify([...settingsArgs(settings), JSON.stringify(settingsEnv(settings))])).digest("hex");
|
|
4027
4026
|
}
|
|
4028
4027
|
|
|
4028
|
+
// src/headroom/socket.ts
|
|
4029
|
+
var import_node_path11 = __toESM(require("node:path"), 1);
|
|
4030
|
+
var GROUP_OR_OTHER_BITS = 63;
|
|
4031
|
+
var OCTAL_RADIX = 8;
|
|
4032
|
+
var MODE_DIGITS = 4;
|
|
4033
|
+
var HEADROOM_SOCKET_SUFFIX = ".sock";
|
|
4034
|
+
var HEADROOM_SOCKET_NAME = /^(\d+)\.sock$/;
|
|
4035
|
+
var UNIX_SOCKET_PATH_MAX_BYTES = 103;
|
|
4036
|
+
var PLATFORMS_WITHOUT_UNIX_SOCKETS = ["win32"];
|
|
4037
|
+
function headroomSocketPath(paths, supervisorPid) {
|
|
4038
|
+
return import_node_path11.default.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
|
|
4039
|
+
}
|
|
4040
|
+
function platformRefusal(platform) {
|
|
4041
|
+
return PLATFORMS_WITHOUT_UNIX_SOCKETS.includes(platform) ? `headroom routing needs a unix domain socket, which headroom cannot serve on ${platform}; agent-shim never falls back to a TCP port for this hop` : void 0;
|
|
4042
|
+
}
|
|
4043
|
+
function ownerOnlyRefusal(label, target, stat, expected, uid) {
|
|
4044
|
+
if (stat === void 0) {
|
|
4045
|
+
return `the headroom ${label} ${target} does not exist`;
|
|
4046
|
+
}
|
|
4047
|
+
if (stat.kind === "symlink") {
|
|
4048
|
+
return `the headroom ${label} ${target} is a symlink; it must be the real ${expected === "dir" ? "directory" : "socket"}`;
|
|
4049
|
+
}
|
|
4050
|
+
if (stat.kind !== expected) {
|
|
4051
|
+
return `the headroom ${label} ${target} is not a ${expected === "dir" ? "directory" : "socket"}`;
|
|
4052
|
+
}
|
|
4053
|
+
if (stat.uid !== uid) {
|
|
4054
|
+
return `the headroom ${label} ${target} is owned by uid ${String(stat.uid)}, not by this user (uid ${String(uid)})`;
|
|
4055
|
+
}
|
|
4056
|
+
if ((stat.mode & GROUP_OR_OTHER_BITS) !== 0) {
|
|
4057
|
+
return `the headroom ${label} ${target} has mode ${stat.mode.toString(OCTAL_RADIX).padStart(MODE_DIGITS, "0")}, which lets other users reach it; it must be accessible to its owner only`;
|
|
4058
|
+
}
|
|
4059
|
+
return void 0;
|
|
4060
|
+
}
|
|
4061
|
+
function prepareHeadroomSocket(fs12, ports, paths, supervisorPid) {
|
|
4062
|
+
const unsupported = platformRefusal(ports.platform);
|
|
4063
|
+
if (unsupported !== void 0) {
|
|
4064
|
+
return { refused: unsupported };
|
|
4065
|
+
}
|
|
4066
|
+
const socketPath = headroomSocketPath(paths, supervisorPid);
|
|
4067
|
+
const length = Buffer.byteLength(socketPath, "utf8");
|
|
4068
|
+
if (length > UNIX_SOCKET_PATH_MAX_BYTES) {
|
|
4069
|
+
return {
|
|
4070
|
+
refused: `the headroom socket path ${socketPath} is ${String(length)} bytes, longer than the ${String(UNIX_SOCKET_PATH_MAX_BYTES)} a unix socket path can hold; set AGENT_SHIM_HOME to a shorter directory`
|
|
4071
|
+
};
|
|
4072
|
+
}
|
|
4073
|
+
if (ports.lstat(paths.headroomSocketDir)?.kind === "symlink") {
|
|
4074
|
+
return { refused: `the headroom socket directory ${paths.headroomSocketDir} is a symlink; it must be the real directory` };
|
|
4075
|
+
}
|
|
4076
|
+
fs12.mkdirPrivate(paths.headroomSocketDir);
|
|
4077
|
+
const refusal = ownerOnlyRefusal("socket directory", paths.headroomSocketDir, ports.lstat(paths.headroomSocketDir), "dir", ports.currentUid());
|
|
4078
|
+
return refusal === void 0 ? { socketPath } : { refused: refusal };
|
|
4079
|
+
}
|
|
4080
|
+
function pruneStaleHeadroomSockets(fs12, paths, isRunning) {
|
|
4081
|
+
const removed = [];
|
|
4082
|
+
for (const name of fs12.readdir(paths.headroomSocketDir)) {
|
|
4083
|
+
const pid = HEADROOM_SOCKET_NAME.exec(name)?.[1];
|
|
4084
|
+
if (pid === void 0 || isRunning(Number.parseInt(pid, 10))) {
|
|
4085
|
+
continue;
|
|
4086
|
+
}
|
|
4087
|
+
fs12.removeRecursive(import_node_path11.default.join(paths.headroomSocketDir, name));
|
|
4088
|
+
removed.push(name);
|
|
4089
|
+
}
|
|
4090
|
+
return removed;
|
|
4091
|
+
}
|
|
4092
|
+
|
|
4029
4093
|
// src/headroom/source.ts
|
|
4030
4094
|
var import_zod6 = require("zod");
|
|
4031
4095
|
var GIT_SPEC_RE = /git\+[^@\s]+(?:@([^\s#]+))?/;
|
|
@@ -4121,8 +4185,6 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
4121
4185
|
return 0;
|
|
4122
4186
|
}
|
|
4123
4187
|
let installedSource = previousState?.installedSource;
|
|
4124
|
-
let lastPort = previousState?.lastPort;
|
|
4125
|
-
const sticky = () => lastPort === void 0 ? {} : { lastPort };
|
|
4126
4188
|
const ownsState = () => {
|
|
4127
4189
|
const owner = readHeadroomState(fs12, paths.headroomStateFile)?.supervisorPid;
|
|
4128
4190
|
return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
|
|
@@ -4135,7 +4197,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
4135
4197
|
return true;
|
|
4136
4198
|
};
|
|
4137
4199
|
const fail = (message) => {
|
|
4138
|
-
if (writeOwnState({ lastError: message
|
|
4200
|
+
if (writeOwnState({ lastError: message })) {
|
|
4139
4201
|
fs12.removeRecursive(paths.headroomLockFile);
|
|
4140
4202
|
}
|
|
4141
4203
|
ports.log(`agent-shim headroom supervisor: ${message}`);
|
|
@@ -4158,11 +4220,17 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
4158
4220
|
installedSource = config.source;
|
|
4159
4221
|
return true;
|
|
4160
4222
|
};
|
|
4223
|
+
const socket = prepareHeadroomSocket(fs12, ports.socketTrust, paths, ports.ownPid);
|
|
4224
|
+
if (socket.refused !== void 0) {
|
|
4225
|
+
return fail(socket.refused);
|
|
4226
|
+
}
|
|
4227
|
+
const { socketPath } = socket;
|
|
4228
|
+
pruneStaleHeadroomSockets(fs12, paths, ports.isRunning);
|
|
4161
4229
|
if (!ensureInstalled()) {
|
|
4162
4230
|
return fail(`could not install headroom from ${config.source}: install failed (is uv installed and on PATH?)`);
|
|
4163
4231
|
}
|
|
4164
4232
|
const version = ports.headroomVersion() ?? "unknown";
|
|
4165
|
-
writeOwnState({ supervisorPid: ports.ownPid, version, installedSource
|
|
4233
|
+
writeOwnState({ supervisorPid: ports.ownPid, version, installedSource });
|
|
4166
4234
|
ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: managing headroom on allowlist [${allowlistOf(ports).join(", ")}]`);
|
|
4167
4235
|
const orphanPid = previousState?.headroomPid;
|
|
4168
4236
|
if (orphanPid !== void 0 && ports.isRunning(orphanPid)) {
|
|
@@ -4188,7 +4256,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
4188
4256
|
pruneDeadSessions(fs12, paths.headroomSessionsDir, ports.isRunning);
|
|
4189
4257
|
const ownsNow = ownsState();
|
|
4190
4258
|
if (!ownsNow && !superseded) {
|
|
4191
|
-
ports.log("agent-shim headroom supervisor: another supervisor now owns state
|
|
4259
|
+
ports.log("agent-shim headroom supervisor: another supervisor now owns the state file; serving this daemon's own sessions until they end");
|
|
4192
4260
|
}
|
|
4193
4261
|
superseded = !ownsNow;
|
|
4194
4262
|
const crashed = headroomPid !== void 0 && !ports.isRunning(headroomPid);
|
|
@@ -4201,8 +4269,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
4201
4269
|
writeOwnState({
|
|
4202
4270
|
supervisorPid: ports.ownPid,
|
|
4203
4271
|
version,
|
|
4204
|
-
installedSource
|
|
4205
|
-
...sticky()
|
|
4272
|
+
installedSource
|
|
4206
4273
|
});
|
|
4207
4274
|
}
|
|
4208
4275
|
if (consecutiveFailures >= HEADROOM_START_RETRY_BUDGET) {
|
|
@@ -4211,41 +4278,32 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
4211
4278
|
if (installedSource !== config.source && !ensureInstalled()) {
|
|
4212
4279
|
return fail(`could not install headroom from ${config.source}: install failed (is uv installed and on PATH?)`);
|
|
4213
4280
|
}
|
|
4214
|
-
const
|
|
4215
|
-
const
|
|
4216
|
-
const pid = ports.spawnHeadroom(port, allowlist, config.settings);
|
|
4217
|
-
const ready = await waitUntilReady(ports, port);
|
|
4281
|
+
const pid = ports.spawnHeadroom(socketPath, allowlist, config.settings);
|
|
4282
|
+
const ready = await waitUntilReady(ports, socketPath);
|
|
4218
4283
|
if (ready) {
|
|
4219
4284
|
consecutiveFailures = 0;
|
|
4220
4285
|
headroomPid = pid;
|
|
4221
4286
|
runningHash = allowlistHash;
|
|
4222
4287
|
runningSettingsHash = settingsHash;
|
|
4223
|
-
lastPort = port;
|
|
4224
|
-
if (previousSticky !== void 0 && port !== previousSticky) {
|
|
4225
|
-
ports.log(
|
|
4226
|
-
`agent-shim headroom supervisor: sticky port ${String(previousSticky)} was occupied; moving to ${String(port)} (sessions launched against the old port are stale until they relaunch)`
|
|
4227
|
-
);
|
|
4228
|
-
}
|
|
4229
4288
|
const recorded = writeOwnState({
|
|
4230
4289
|
supervisorPid: ports.ownPid,
|
|
4231
4290
|
headroomPid: pid,
|
|
4232
|
-
|
|
4291
|
+
socketPath,
|
|
4233
4292
|
version,
|
|
4234
4293
|
allowlistHash,
|
|
4235
4294
|
settingsHash,
|
|
4236
|
-
installedSource: config.source
|
|
4237
|
-
...sticky()
|
|
4295
|
+
installedSource: config.source
|
|
4238
4296
|
});
|
|
4239
4297
|
if (recorded) {
|
|
4240
4298
|
fs12.removeRecursive(paths.headroomLockFile);
|
|
4241
4299
|
}
|
|
4242
4300
|
idleSince = void 0;
|
|
4243
|
-
ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on
|
|
4301
|
+
ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on unix socket ${socketPath}`);
|
|
4244
4302
|
} else {
|
|
4245
4303
|
ports.stopProcess(pid);
|
|
4246
4304
|
consecutiveFailures += 1;
|
|
4247
4305
|
ports.log(
|
|
4248
|
-
`agent-shim headroom supervisor: headroom did not become ready on
|
|
4306
|
+
`agent-shim headroom supervisor: headroom did not become ready on unix socket ${socketPath} (attempt ${String(consecutiveFailures)} of ${String(HEADROOM_START_RETRY_BUDGET)})`
|
|
4249
4307
|
);
|
|
4250
4308
|
await ports.sleep(backoffForAttempt(consecutiveFailures));
|
|
4251
4309
|
continue;
|
|
@@ -4270,10 +4328,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
4270
4328
|
`agent-shim headroom supervisor: no sessions for ${String(config.idleShutdownMinutes)} minute(s); stopping headroom and exiting`
|
|
4271
4329
|
);
|
|
4272
4330
|
ports.stopProcess(headroomPid);
|
|
4273
|
-
writeOwnState({
|
|
4274
|
-
version,
|
|
4275
|
-
...sticky()
|
|
4276
|
-
});
|
|
4331
|
+
writeOwnState({ version });
|
|
4277
4332
|
return 0;
|
|
4278
4333
|
}
|
|
4279
4334
|
} else {
|
|
@@ -4290,10 +4345,10 @@ function currentHeadroomAllowlist(fs12, paths) {
|
|
|
4290
4345
|
function allowlistOf(ports) {
|
|
4291
4346
|
return currentHeadroomAllowlist(ports.fs, ports.paths);
|
|
4292
4347
|
}
|
|
4293
|
-
async function waitUntilReady(ports,
|
|
4348
|
+
async function waitUntilReady(ports, socketPath) {
|
|
4294
4349
|
const deadline = ports.now() + HEADROOM_READY_TIMEOUT_MS;
|
|
4295
4350
|
for (; ; ) {
|
|
4296
|
-
if (await ports.ready(
|
|
4351
|
+
if (await ports.ready(socketPath)) {
|
|
4297
4352
|
return true;
|
|
4298
4353
|
}
|
|
4299
4354
|
if (ports.now() >= deadline) {
|
|
@@ -4353,14 +4408,14 @@ function evaluateAmbientCredentialGuard(params) {
|
|
|
4353
4408
|
// src/paths.ts
|
|
4354
4409
|
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
4355
4410
|
var import_node_os = __toESM(require("node:os"), 1);
|
|
4356
|
-
var
|
|
4411
|
+
var import_node_path12 = __toESM(require("node:path"), 1);
|
|
4357
4412
|
function resolveAgentShimHome(env = process.env, home = import_node_os.default.homedir(), isDirectory = isExistingDirectory) {
|
|
4358
4413
|
const fromEnv = env.AGENT_SHIM_HOME;
|
|
4359
4414
|
if (fromEnv !== void 0 && fromEnv !== "") {
|
|
4360
4415
|
return fromEnv;
|
|
4361
4416
|
}
|
|
4362
|
-
const current =
|
|
4363
|
-
const legacy =
|
|
4417
|
+
const current = import_node_path12.default.join(home, HOME_DIRNAME);
|
|
4418
|
+
const legacy = import_node_path12.default.join(home, LEGACY_HOME_DIRNAME);
|
|
4364
4419
|
return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
|
|
4365
4420
|
}
|
|
4366
4421
|
function isExistingDirectory(candidate) {
|
|
@@ -4371,38 +4426,39 @@ function resolveClaudeHome() {
|
|
|
4371
4426
|
if (fromEnv !== void 0 && fromEnv !== "") {
|
|
4372
4427
|
return fromEnv;
|
|
4373
4428
|
}
|
|
4374
|
-
return
|
|
4429
|
+
return import_node_path12.default.join(import_node_os.default.homedir(), ".claude");
|
|
4375
4430
|
}
|
|
4376
4431
|
function buildLayoutPaths(root) {
|
|
4377
4432
|
return {
|
|
4378
4433
|
root,
|
|
4379
|
-
identitiesDir:
|
|
4380
|
-
configProfilesDir:
|
|
4381
|
-
providersDir:
|
|
4382
|
-
directoryRulesFile:
|
|
4383
|
-
activeIdentityFile:
|
|
4384
|
-
globalConfigFile:
|
|
4385
|
-
categoriesLocalFile:
|
|
4386
|
-
claudeShimFile:
|
|
4387
|
-
headroomDir:
|
|
4388
|
-
headroomStateFile:
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4434
|
+
identitiesDir: import_node_path12.default.join(root, "identities"),
|
|
4435
|
+
configProfilesDir: import_node_path12.default.join(root, "config-profiles"),
|
|
4436
|
+
providersDir: import_node_path12.default.join(root, "providers"),
|
|
4437
|
+
directoryRulesFile: import_node_path12.default.join(root, "directory-rules.json"),
|
|
4438
|
+
activeIdentityFile: import_node_path12.default.join(root, "active-identity"),
|
|
4439
|
+
globalConfigFile: import_node_path12.default.join(root, "config.json"),
|
|
4440
|
+
categoriesLocalFile: import_node_path12.default.join(root, "categories.local.json"),
|
|
4441
|
+
claudeShimFile: import_node_path12.default.join(root, "claude-shim.json"),
|
|
4442
|
+
headroomDir: import_node_path12.default.join(root, "headroom"),
|
|
4443
|
+
headroomStateFile: import_node_path12.default.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
|
|
4444
|
+
headroomSocketDir: import_node_path12.default.join(root, "headroom", "run"),
|
|
4445
|
+
headroomLockFile: import_node_path12.default.join(root, "headroom", "start.lock"),
|
|
4446
|
+
headroomSessionsDir: import_node_path12.default.join(root, "headroom", "sessions"),
|
|
4447
|
+
logsDir: import_node_path12.default.join(root, "logs"),
|
|
4448
|
+
headroomLogPath: import_node_path12.default.join(root, "logs", "headroom.log"),
|
|
4449
|
+
frontdoorDir: import_node_path12.default.join(root, "frontdoor"),
|
|
4450
|
+
frontdoorCaDir: import_node_path12.default.join(root, "frontdoor", "ca"),
|
|
4451
|
+
frontdoorCaCertFile: import_node_path12.default.join(root, "frontdoor", "ca", "ca.pem"),
|
|
4452
|
+
frontdoorCaKeyFile: import_node_path12.default.join(root, "frontdoor", "ca", "ca.key"),
|
|
4453
|
+
frontdoorCaBundlesDir: import_node_path12.default.join(root, "frontdoor", "ca", "bundles"),
|
|
4454
|
+
frontdoorStateFile: import_node_path12.default.join(root, "frontdoor", "state.json"),
|
|
4455
|
+
frontdoorLockFile: import_node_path12.default.join(root, "frontdoor", "start.lock"),
|
|
4456
|
+
frontdoorSessionsDir: import_node_path12.default.join(root, "frontdoor", "sessions"),
|
|
4457
|
+
frontdoorLogPath: import_node_path12.default.join(root, "logs", "frontdoor.log"),
|
|
4458
|
+
usageDir: import_node_path12.default.join(root, "usage"),
|
|
4459
|
+
usageLogDir: import_node_path12.default.join(root, "usage", "log"),
|
|
4460
|
+
usageSnapshotsDir: import_node_path12.default.join(root, "usage", "snapshots"),
|
|
4461
|
+
usagePicksFile: import_node_path12.default.join(root, "usage", "picks.json")
|
|
4406
4462
|
};
|
|
4407
4463
|
}
|
|
4408
4464
|
function resolveLayoutPaths() {
|
|
@@ -4411,10 +4467,10 @@ function resolveLayoutPaths() {
|
|
|
4411
4467
|
|
|
4412
4468
|
// src/identityStore.ts
|
|
4413
4469
|
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
|
4414
|
-
var
|
|
4470
|
+
var import_node_path15 = __toESM(require("node:path"), 1);
|
|
4415
4471
|
|
|
4416
4472
|
// src/launcher/identity.ts
|
|
4417
|
-
var
|
|
4473
|
+
var import_node_path13 = __toESM(require("node:path"), 1);
|
|
4418
4474
|
function poolNameOf(selector) {
|
|
4419
4475
|
return selector.startsWith(POOL_SELECTOR_PREFIX) ? selector.slice(POOL_SELECTOR_PREFIX.length) : void 0;
|
|
4420
4476
|
}
|
|
@@ -4463,12 +4519,12 @@ function decideConfigProfile(params) {
|
|
|
4463
4519
|
return { source: "none" };
|
|
4464
4520
|
}
|
|
4465
4521
|
function loadIdentity(identitiesDir, name, fs12) {
|
|
4466
|
-
return loadConfigFile(
|
|
4522
|
+
return loadConfigFile(import_node_path13.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
|
|
4467
4523
|
}
|
|
4468
4524
|
|
|
4469
4525
|
// src/configProfilesStore.ts
|
|
4470
4526
|
var import_node_fs3 = __toESM(require("node:fs"), 1);
|
|
4471
|
-
var
|
|
4527
|
+
var import_node_path14 = __toESM(require("node:path"), 1);
|
|
4472
4528
|
var ProfileNotFoundError = class extends CliError {
|
|
4473
4529
|
constructor(profileName) {
|
|
4474
4530
|
super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
|
|
@@ -4494,7 +4550,7 @@ var InvalidCategoryNameError = class extends CliError {
|
|
|
4494
4550
|
categoryName;
|
|
4495
4551
|
};
|
|
4496
4552
|
function profileJsonPath(paths, name) {
|
|
4497
|
-
return
|
|
4553
|
+
return import_node_path14.default.join(paths.configProfilesDir, `${name}.json`);
|
|
4498
4554
|
}
|
|
4499
4555
|
function profileExists(paths, name) {
|
|
4500
4556
|
return import_node_fs3.default.existsSync(profileJsonPath(paths, name));
|
|
@@ -4682,7 +4738,7 @@ var InvalidIdentityNameError = class extends CliError {
|
|
|
4682
4738
|
attemptedName;
|
|
4683
4739
|
};
|
|
4684
4740
|
function identityJsonPath(paths, name) {
|
|
4685
|
-
return
|
|
4741
|
+
return import_node_path15.default.join(paths.identitiesDir, name, "identity.json");
|
|
4686
4742
|
}
|
|
4687
4743
|
function identityExists(paths, name) {
|
|
4688
4744
|
return import_node_fs4.default.existsSync(identityJsonPath(paths, name));
|
|
@@ -4783,7 +4839,7 @@ function setIdentityCredential(paths, identityName, change) {
|
|
|
4783
4839
|
});
|
|
4784
4840
|
}
|
|
4785
4841
|
function belongsToIdentity(entry, name) {
|
|
4786
|
-
return entry === name || entry ===
|
|
4842
|
+
return entry === name || entry === import_node_path15.default.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
|
|
4787
4843
|
}
|
|
4788
4844
|
function removeIdentity(paths, name) {
|
|
4789
4845
|
if (!identityExists(paths, name)) {
|
|
@@ -4791,7 +4847,7 @@ function removeIdentity(paths, name) {
|
|
|
4791
4847
|
}
|
|
4792
4848
|
for (const entry of import_node_fs4.default.readdirSync(paths.identitiesDir)) {
|
|
4793
4849
|
if (belongsToIdentity(entry, name)) {
|
|
4794
|
-
import_node_fs4.default.rmSync(
|
|
4850
|
+
import_node_fs4.default.rmSync(import_node_path15.default.join(paths.identitiesDir, entry), { recursive: true, force: true });
|
|
4795
4851
|
}
|
|
4796
4852
|
}
|
|
4797
4853
|
if (readActiveIdentity(paths) === name) {
|
|
@@ -4801,7 +4857,7 @@ function removeIdentity(paths, name) {
|
|
|
4801
4857
|
|
|
4802
4858
|
// src/providersStore.ts
|
|
4803
4859
|
var import_node_fs5 = __toESM(require("node:fs"), 1);
|
|
4804
|
-
var
|
|
4860
|
+
var import_node_path16 = __toESM(require("node:path"), 1);
|
|
4805
4861
|
|
|
4806
4862
|
// src/credentialCache.ts
|
|
4807
4863
|
var import_zod7 = require("zod");
|
|
@@ -4838,7 +4894,7 @@ var CREDENTIAL_COMMAND_TIMEOUT_MS = 1e4;
|
|
|
4838
4894
|
var CREDENTIAL_INTERACTIVE_TIMEOUT_MS = 12e4;
|
|
4839
4895
|
var GROUP_OTHER_PERMISSION_BITS = 63;
|
|
4840
4896
|
var PERMISSION_BITS = 511;
|
|
4841
|
-
var
|
|
4897
|
+
var OCTAL_RADIX2 = 8;
|
|
4842
4898
|
function commandArgv(source) {
|
|
4843
4899
|
if ("command" in source) {
|
|
4844
4900
|
return source.command;
|
|
@@ -4931,7 +4987,7 @@ function trySource(source, params) {
|
|
|
4931
4987
|
}
|
|
4932
4988
|
if (read.mode !== void 0 && (read.mode & GROUP_OTHER_PERMISSION_BITS) !== 0) {
|
|
4933
4989
|
return none(
|
|
4934
|
-
`is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS).toString(
|
|
4990
|
+
`is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS).toString(OCTAL_RADIX2)}); run \`chmod 600 ${source.file}\``,
|
|
4935
4991
|
true
|
|
4936
4992
|
);
|
|
4937
4993
|
}
|
|
@@ -5027,7 +5083,7 @@ var InvalidProviderNameError = class extends CliError {
|
|
|
5027
5083
|
};
|
|
5028
5084
|
var PROVIDER_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._@-]*$/;
|
|
5029
5085
|
function providerJsonPath(paths, name) {
|
|
5030
|
-
return
|
|
5086
|
+
return import_node_path16.default.join(paths.providersDir, `${name}.json`);
|
|
5031
5087
|
}
|
|
5032
5088
|
function providerExists(paths, name) {
|
|
5033
5089
|
return import_node_fs5.default.existsSync(providerJsonPath(paths, name));
|
|
@@ -5103,7 +5159,7 @@ function readProvider(paths, name) {
|
|
|
5103
5159
|
return parseProviderFile(filePath, raw);
|
|
5104
5160
|
}
|
|
5105
5161
|
function loadProvider(providersDir, name, port) {
|
|
5106
|
-
const filePath =
|
|
5162
|
+
const filePath = import_node_path16.default.join(providersDir, `${name}.json`);
|
|
5107
5163
|
const raw = port.readConfigFile(filePath);
|
|
5108
5164
|
return raw === void 0 ? void 0 : parseProviderFile(filePath, raw);
|
|
5109
5165
|
}
|
|
@@ -5358,21 +5414,21 @@ function removeDirectoryRule(paths, rulePath) {
|
|
|
5358
5414
|
var import_node_os4 = __toESM(require("node:os"), 1);
|
|
5359
5415
|
|
|
5360
5416
|
// src/launcher/cascade.ts
|
|
5361
|
-
var
|
|
5417
|
+
var import_node_path18 = __toESM(require("node:path"), 1);
|
|
5362
5418
|
|
|
5363
5419
|
// src/pathNorm.ts
|
|
5364
|
-
var
|
|
5420
|
+
var import_node_path17 = __toESM(require("node:path"), 1);
|
|
5365
5421
|
function expandTilde(value, home) {
|
|
5366
5422
|
if (value === "~") {
|
|
5367
5423
|
return home;
|
|
5368
5424
|
}
|
|
5369
5425
|
if (value.startsWith("~/")) {
|
|
5370
|
-
return
|
|
5426
|
+
return import_node_path17.default.join(home, value.slice(2));
|
|
5371
5427
|
}
|
|
5372
5428
|
return value;
|
|
5373
5429
|
}
|
|
5374
5430
|
function normaliseRulePath(rulePath, home) {
|
|
5375
|
-
return
|
|
5431
|
+
return import_node_path17.default.resolve(expandTilde(rulePath, home));
|
|
5376
5432
|
}
|
|
5377
5433
|
|
|
5378
5434
|
// src/launcher/cascade.ts
|
|
@@ -5382,7 +5438,7 @@ function loadCascadeInput(params) {
|
|
|
5382
5438
|
const globalConfig = loadConfigFile(params.paths.globalConfigFile, GlobalConfigSchema, params.read);
|
|
5383
5439
|
const directoryRules = loadConfigFile(params.paths.directoryRulesFile, DirectoryRulesSchema, params.read);
|
|
5384
5440
|
const loadProfile = (name) => {
|
|
5385
|
-
const filepath =
|
|
5441
|
+
const filepath = import_node_path18.default.join(params.paths.configProfilesDir, `${name}.json`);
|
|
5386
5442
|
const loaded = loadConfigFile(filepath, ConfigProfileSchema, params.read);
|
|
5387
5443
|
if (loaded === void 0) {
|
|
5388
5444
|
return void 0;
|
|
@@ -5397,8 +5453,8 @@ function loadCascadeInput(params) {
|
|
|
5397
5453
|
});
|
|
5398
5454
|
const levels = [];
|
|
5399
5455
|
for (const dir of dirs) {
|
|
5400
|
-
const portable = loadConfigFile(
|
|
5401
|
-
const portableLocal = loadConfigFile(
|
|
5456
|
+
const portable = loadConfigFile(import_node_path18.default.join(dir, PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path18.default.join(dir, LEGACY_PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read);
|
|
5457
|
+
const portableLocal = loadConfigFile(import_node_path18.default.join(dir, PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path18.default.join(dir, LEGACY_PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read);
|
|
5402
5458
|
const rules = (directoryRules?.config.rules ?? []).map((rule, index) => ({ rule, index })).filter(({ rule }) => normaliseRulePath(rule.path, params.home) === dir).map(({ rule, index }) => {
|
|
5403
5459
|
const entryOrder = directoryRules?.ruleEntryOrders[index];
|
|
5404
5460
|
return {
|
|
@@ -5495,7 +5551,7 @@ function quotaWarnings(snapshot, provider, nowMs) {
|
|
|
5495
5551
|
}
|
|
5496
5552
|
|
|
5497
5553
|
// src/usage/poolPick.ts
|
|
5498
|
-
var
|
|
5554
|
+
var import_node_path19 = __toESM(require("node:path"), 1);
|
|
5499
5555
|
var import_zod9 = require("zod");
|
|
5500
5556
|
|
|
5501
5557
|
// src/usage/plan.ts
|
|
@@ -5797,7 +5853,7 @@ function recordStickyPick(fs12, picksFile, directory, identity, nowMs) {
|
|
|
5797
5853
|
const current = readPicksFile(fs12, picksFile).file.picks;
|
|
5798
5854
|
const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
|
|
5799
5855
|
const next = { schemaVersion: SCHEMA_VERSION, picks: { ...Object.fromEntries(kept), [directory]: { identity, at: new Date(nowMs).toISOString() } } };
|
|
5800
|
-
fs12.mkdirPrivate(
|
|
5856
|
+
fs12.mkdirPrivate(import_node_path19.default.dirname(picksFile));
|
|
5801
5857
|
fs12.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
|
|
5802
5858
|
`);
|
|
5803
5859
|
}
|
|
@@ -5894,14 +5950,14 @@ var import_node_child_process = require("node:child_process");
|
|
|
5894
5950
|
var import_node_crypto8 = require("node:crypto");
|
|
5895
5951
|
var import_node_fs6 = __toESM(require("node:fs"), 1);
|
|
5896
5952
|
var import_node_os3 = __toESM(require("node:os"), 1);
|
|
5897
|
-
var
|
|
5953
|
+
var import_node_path21 = __toESM(require("node:path"), 1);
|
|
5898
5954
|
var import_node_sea = require("node:sea");
|
|
5899
5955
|
|
|
5900
5956
|
// src/versionDiscovery.ts
|
|
5901
5957
|
var import_node_os2 = __toESM(require("node:os"), 1);
|
|
5902
|
-
var
|
|
5958
|
+
var import_node_path20 = __toESM(require("node:path"), 1);
|
|
5903
5959
|
function defaultVersionsDir() {
|
|
5904
|
-
return
|
|
5960
|
+
return import_node_path20.default.join(import_node_os2.default.homedir(), ".local", "share", "claude", "versions");
|
|
5905
5961
|
}
|
|
5906
5962
|
var NUMERIC_DOTTED_VERSION_RE = /^\d+(?:\.\d+)*$/;
|
|
5907
5963
|
function isNumericDottedVersion(name) {
|
|
@@ -5943,14 +5999,14 @@ function discoverClaudeBinary(options) {
|
|
|
5943
5999
|
const highestVersion = pickHighestVersion(entries);
|
|
5944
6000
|
if (highestVersion !== void 0) {
|
|
5945
6001
|
return {
|
|
5946
|
-
path:
|
|
6002
|
+
path: import_node_path20.default.join(versionsDir, highestVersion),
|
|
5947
6003
|
source: "versions-dir",
|
|
5948
6004
|
version: highestVersion
|
|
5949
6005
|
};
|
|
5950
6006
|
}
|
|
5951
|
-
const ownInstallDirs = new Set(options.ownInstallDirs.map((dir) =>
|
|
6007
|
+
const ownInstallDirs = new Set(options.ownInstallDirs.map((dir) => import_node_path20.default.resolve(dir)));
|
|
5952
6008
|
for (const dir of options.pathDirs) {
|
|
5953
|
-
if (ownInstallDirs.has(
|
|
6009
|
+
if (ownInstallDirs.has(import_node_path20.default.resolve(dir))) {
|
|
5954
6010
|
continue;
|
|
5955
6011
|
}
|
|
5956
6012
|
const found = options.findExecutableInDir(dir, "claude");
|
|
@@ -6121,7 +6177,7 @@ var realRunPort = {
|
|
|
6121
6177
|
}
|
|
6122
6178
|
};
|
|
6123
6179
|
function expandHome2(filePath) {
|
|
6124
|
-
return filePath.startsWith("~/") ?
|
|
6180
|
+
return filePath.startsWith("~/") ? import_node_path21.default.join(import_node_os3.default.homedir(), filePath.slice(1)) : filePath;
|
|
6125
6181
|
}
|
|
6126
6182
|
var MACOS_GUI_SESSION_MANAGER = "Aqua";
|
|
6127
6183
|
function hasDesktopSession() {
|
|
@@ -6194,7 +6250,7 @@ function spawnDaemonThrough(executable) {
|
|
|
6194
6250
|
return (paths, subcommand, logPath) => spawnDetachedDaemon({ command: executable, args: [subcommand] }, paths, subcommand, logPath);
|
|
6195
6251
|
}
|
|
6196
6252
|
function spawnDetachedDaemon(invocation, paths, subcommand, logPath) {
|
|
6197
|
-
import_node_fs6.default.mkdirSync(
|
|
6253
|
+
import_node_fs6.default.mkdirSync(import_node_path21.default.dirname(logPath), { recursive: true });
|
|
6198
6254
|
const logFd = import_node_fs6.default.openSync(logPath, "a");
|
|
6199
6255
|
try {
|
|
6200
6256
|
const child = (0, import_node_child_process.spawn)(invocation.command, invocation.args, detachedDaemonSpawnOptions(logFd, { ...process.env, AGENT_SHIM_HOME: paths.root }));
|
|
@@ -6210,6 +6266,29 @@ function spawnDetachedDaemon(invocation, paths, subcommand, logPath) {
|
|
|
6210
6266
|
function spawnHeadroomSupervisor(paths, spawnDaemon) {
|
|
6211
6267
|
return spawnDaemon(paths, "__headroom-supervisor", paths.headroomLogPath);
|
|
6212
6268
|
}
|
|
6269
|
+
var SOCKET_PERMISSION_BITS = 511;
|
|
6270
|
+
var realHeadroomSocketTrust = {
|
|
6271
|
+
platform: process.platform,
|
|
6272
|
+
currentUid: () => {
|
|
6273
|
+
if (process.getuid === void 0) {
|
|
6274
|
+
throw new Error(`no POSIX user id on ${process.platform}`);
|
|
6275
|
+
}
|
|
6276
|
+
return process.getuid();
|
|
6277
|
+
},
|
|
6278
|
+
lstat: (target) => {
|
|
6279
|
+
let stat;
|
|
6280
|
+
try {
|
|
6281
|
+
stat = import_node_fs6.default.lstatSync(target);
|
|
6282
|
+
} catch (error) {
|
|
6283
|
+
if (isEnoent3(error)) {
|
|
6284
|
+
return void 0;
|
|
6285
|
+
}
|
|
6286
|
+
throw error;
|
|
6287
|
+
}
|
|
6288
|
+
const kind = stat.isSymbolicLink() ? "symlink" : stat.isDirectory() ? "dir" : stat.isSocket() ? "socket" : "other";
|
|
6289
|
+
return { kind, uid: stat.uid, mode: stat.mode & SOCKET_PERMISSION_BITS };
|
|
6290
|
+
}
|
|
6291
|
+
};
|
|
6213
6292
|
function realHeadroomPort(paths, options) {
|
|
6214
6293
|
return {
|
|
6215
6294
|
ensure: () => {
|
|
@@ -6226,7 +6305,7 @@ function realHeadroomPort(paths, options) {
|
|
|
6226
6305
|
}
|
|
6227
6306
|
});
|
|
6228
6307
|
return {
|
|
6229
|
-
|
|
6308
|
+
socketPath: up.socketPath,
|
|
6230
6309
|
projectId: resolveGitRoot(realRunPort, options.cwd) ?? options.cwd
|
|
6231
6310
|
};
|
|
6232
6311
|
},
|
|
@@ -6252,7 +6331,7 @@ function listVersionsDir(dir) {
|
|
|
6252
6331
|
throw error;
|
|
6253
6332
|
}
|
|
6254
6333
|
return entries.filter((entry) => entry.isFile()).map((entry) => {
|
|
6255
|
-
const fullPath =
|
|
6334
|
+
const fullPath = import_node_path21.default.join(dir, entry.name);
|
|
6256
6335
|
const stat = import_node_fs6.default.statSync(fullPath);
|
|
6257
6336
|
return {
|
|
6258
6337
|
name: entry.name,
|
|
@@ -6267,7 +6346,7 @@ function windowsPathExtensions(pathext) {
|
|
|
6267
6346
|
return (pathext ?? WINDOWS_DEFAULT_PATHEXT).split(";").map((ext) => ext.trim()).filter((ext) => ext.length > 0);
|
|
6268
6347
|
}
|
|
6269
6348
|
function resolveExecutableCandidate(dir, name, env) {
|
|
6270
|
-
const candidate =
|
|
6349
|
+
const candidate = import_node_path21.default.join(dir, name);
|
|
6271
6350
|
if (env.platform === "win32") {
|
|
6272
6351
|
const extensions = windowsPathExtensions(env.pathext);
|
|
6273
6352
|
const alreadyHasRecognisedExtension = extensions.some((ext) => candidate.toLowerCase().endsWith(ext.toLowerCase()));
|
|
@@ -6316,13 +6395,13 @@ function resolveOwnExecutablePath(env) {
|
|
|
6316
6395
|
if (env.argv1 !== void 0 && !env.argv1.includes("/") && !env.argv1.includes("\\")) {
|
|
6317
6396
|
return searchPathForExecutable(env.pathDirs, env.argv1, env.findExecutableInDir) ?? env.execPath;
|
|
6318
6397
|
}
|
|
6319
|
-
const candidate = env.argv1 === void 0 ? env.execPath :
|
|
6320
|
-
const candidateDir =
|
|
6321
|
-
const candidateDirOnPath = env.pathDirs.some((dir) =>
|
|
6398
|
+
const candidate = env.argv1 === void 0 ? env.execPath : import_node_path21.default.resolve(env.cwd, env.argv1);
|
|
6399
|
+
const candidateDir = import_node_path21.default.dirname(candidate);
|
|
6400
|
+
const candidateDirOnPath = env.pathDirs.some((dir) => import_node_path21.default.resolve(dir) === candidateDir);
|
|
6322
6401
|
if (candidateDirOnPath) {
|
|
6323
6402
|
return candidate;
|
|
6324
6403
|
}
|
|
6325
|
-
const viaPath = searchPathForExecutable(env.pathDirs,
|
|
6404
|
+
const viaPath = searchPathForExecutable(env.pathDirs, import_node_path21.default.basename(candidate), env.findExecutableInDir);
|
|
6326
6405
|
return viaPath ?? candidate;
|
|
6327
6406
|
}
|
|
6328
6407
|
function realOwnExecutablePath() {
|
|
@@ -6330,21 +6409,21 @@ function realOwnExecutablePath() {
|
|
|
6330
6409
|
argv1: process.argv[1],
|
|
6331
6410
|
execPath: process.execPath,
|
|
6332
6411
|
cwd: process.cwd(),
|
|
6333
|
-
pathDirs: (process.env.PATH ?? "").split(
|
|
6412
|
+
pathDirs: (process.env.PATH ?? "").split(import_node_path21.default.delimiter).filter((dir) => dir !== ""),
|
|
6334
6413
|
findExecutableInDir
|
|
6335
6414
|
});
|
|
6336
6415
|
}
|
|
6337
6416
|
function realResolveClaudeBinary(ownInstallDirs) {
|
|
6338
6417
|
return () => discoverClaudeBinary({
|
|
6339
6418
|
listVersionsDir,
|
|
6340
|
-
pathDirs: (process.env.PATH ?? "").split(
|
|
6419
|
+
pathDirs: (process.env.PATH ?? "").split(import_node_path21.default.delimiter).filter((dir) => dir !== ""),
|
|
6341
6420
|
findExecutableInDir,
|
|
6342
6421
|
ownInstallDirs: [...ownInstallDirs]
|
|
6343
6422
|
});
|
|
6344
6423
|
}
|
|
6345
6424
|
|
|
6346
6425
|
// src/checkReport.ts
|
|
6347
|
-
var
|
|
6426
|
+
var import_node_path22 = __toESM(require("node:path"), 1);
|
|
6348
6427
|
var import_zod10 = require("zod");
|
|
6349
6428
|
|
|
6350
6429
|
// src/cli/bool.ts
|
|
@@ -6712,10 +6791,10 @@ function collectCheckReport(params) {
|
|
|
6712
6791
|
}).input;
|
|
6713
6792
|
const providerName = cascadeProviderName(cascade);
|
|
6714
6793
|
const provider = providerName === void 0 ? void 0 : loadCheckProvider(paths, providerName);
|
|
6715
|
-
const farmRoot = identityDecision.name === void 0 ? void 0 :
|
|
6794
|
+
const farmRoot = identityDecision.name === void 0 ? void 0 : import_node_path22.default.join(paths.identitiesDir, identityDecision.name);
|
|
6716
6795
|
const settingsFiles = {
|
|
6717
|
-
"settings.json": realFsPort.readFileUtf8(
|
|
6718
|
-
"settings.local.json": realFsPort.readFileUtf8(
|
|
6796
|
+
"settings.json": realFsPort.readFileUtf8(import_node_path22.default.join(claudeHome, "settings.json")),
|
|
6797
|
+
"settings.local.json": realFsPort.readFileUtf8(import_node_path22.default.join(claudeHome, "settings.local.json"))
|
|
6719
6798
|
};
|
|
6720
6799
|
const report = runCheck({
|
|
6721
6800
|
cwd,
|
|
@@ -6745,7 +6824,7 @@ function collectCheckReport(params) {
|
|
|
6745
6824
|
|
|
6746
6825
|
// src/claudeShim.ts
|
|
6747
6826
|
var import_node_fs7 = __toESM(require("node:fs"), 1);
|
|
6748
|
-
var
|
|
6827
|
+
var import_node_path23 = __toESM(require("node:path"), 1);
|
|
6749
6828
|
var import_zod11 = require("zod");
|
|
6750
6829
|
var ClaudeShimStateSchema = import_zod11.z.strictObject({
|
|
6751
6830
|
targetPath: import_zod11.z.string().min(1),
|
|
@@ -6756,29 +6835,29 @@ function commandFilename(ownExecutablePath, commandName) {
|
|
|
6756
6835
|
return ownExecutablePath.toLowerCase().endsWith(".exe") ? `${commandName}.exe` : commandName;
|
|
6757
6836
|
}
|
|
6758
6837
|
function resolveOwnInstallDirs(paths, ownExecutablePath) {
|
|
6759
|
-
const dirs = [
|
|
6838
|
+
const dirs = [import_node_path23.default.dirname(ownExecutablePath)];
|
|
6760
6839
|
const state = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
|
|
6761
6840
|
if (state !== void 0) {
|
|
6762
|
-
dirs.push(
|
|
6841
|
+
dirs.push(import_node_path23.default.dirname(state.targetPath));
|
|
6763
6842
|
}
|
|
6764
6843
|
return dirs;
|
|
6765
6844
|
}
|
|
6766
6845
|
var nodeLinkFs = { link: import_node_fs7.default.linkSync, copyFile: import_node_fs7.default.copyFileSync, chmod: import_node_fs7.default.chmodSync };
|
|
6767
6846
|
function findPathShadow(params) {
|
|
6768
|
-
const resolvedTargetDir =
|
|
6847
|
+
const resolvedTargetDir = import_node_path23.default.resolve(params.targetDir);
|
|
6769
6848
|
for (const dir of params.pathDirs) {
|
|
6770
6849
|
const found = params.findExecutableInDir(dir, params.targetFilename);
|
|
6771
6850
|
if (found === void 0) {
|
|
6772
6851
|
continue;
|
|
6773
6852
|
}
|
|
6774
|
-
return
|
|
6853
|
+
return import_node_path23.default.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
|
|
6775
6854
|
}
|
|
6776
|
-
return params.pathDirs.some((dir) =>
|
|
6855
|
+
return params.pathDirs.some((dir) => import_node_path23.default.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
|
|
6777
6856
|
}
|
|
6778
6857
|
|
|
6779
6858
|
// src/doctorReport.ts
|
|
6780
6859
|
var import_node_fs8 = __toESM(require("node:fs"), 1);
|
|
6781
|
-
var
|
|
6860
|
+
var import_node_path24 = __toESM(require("node:path"), 1);
|
|
6782
6861
|
function refinePathShadow(status, ownExecutablePath, realpath) {
|
|
6783
6862
|
if (status.status !== "shadowed") {
|
|
6784
6863
|
return status;
|
|
@@ -6802,7 +6881,7 @@ function validateJson(schema, input) {
|
|
|
6802
6881
|
return { ok: true, data: result.data };
|
|
6803
6882
|
}
|
|
6804
6883
|
function pushPathResolution(push, resolution) {
|
|
6805
|
-
const ownDir =
|
|
6884
|
+
const ownDir = import_node_path24.default.dirname(resolution.ownExecutablePath);
|
|
6806
6885
|
switch (resolution.agentShim.status) {
|
|
6807
6886
|
case "ok":
|
|
6808
6887
|
push("path-resolution", "pass", `\`agent-shim\` on PATH resolves to this running executable, ${resolution.ownExecutablePath}.`, "agent-shim");
|
|
@@ -6870,14 +6949,14 @@ function pushProvider(push, entry) {
|
|
|
6870
6949
|
}
|
|
6871
6950
|
function pushLegacyName(push, params) {
|
|
6872
6951
|
const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
|
|
6873
|
-
if (legacyVariables.length === 0 &&
|
|
6952
|
+
if (legacyVariables.length === 0 && import_node_path24.default.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
|
|
6874
6953
|
push("legacy-name", "pass", "Nothing here still uses the former `claude-use` name.");
|
|
6875
6954
|
return;
|
|
6876
6955
|
}
|
|
6877
6956
|
for (const name of legacyVariables) {
|
|
6878
6957
|
push("legacy-name", "warn", `${name} is the former name of ${name.replace(LEGACY_ENV_PREFIX, ENV_PREFIX)}. Rename it; the old name still works but is only a fallback.`, name);
|
|
6879
6958
|
}
|
|
6880
|
-
if (
|
|
6959
|
+
if (import_node_path24.default.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
|
|
6881
6960
|
push(
|
|
6882
6961
|
"legacy-name",
|
|
6883
6962
|
"warn",
|
|
@@ -7067,7 +7146,7 @@ function runDoctor(params) {
|
|
|
7067
7146
|
"warn",
|
|
7068
7147
|
`Headroom state names supervisor pid ${String(state.supervisorPid)}, which is not running; the next launch through headroom will start a replacement.`
|
|
7069
7148
|
);
|
|
7070
|
-
} else if (state.headroomPid === void 0 || state.
|
|
7149
|
+
} else if (state.headroomPid === void 0 || state.socketPath === void 0) {
|
|
7071
7150
|
push(
|
|
7072
7151
|
"headroom",
|
|
7073
7152
|
"warn",
|
|
@@ -7083,7 +7162,7 @@ function runDoctor(params) {
|
|
|
7083
7162
|
push(
|
|
7084
7163
|
"headroom",
|
|
7085
7164
|
"pass",
|
|
7086
|
-
`Headroom daemon is up on
|
|
7165
|
+
`Headroom daemon is up on unix socket ${state.socketPath} (supervisor ${String(state.supervisorPid)}, daemon ${String(state.headroomPid)}).`
|
|
7087
7166
|
);
|
|
7088
7167
|
}
|
|
7089
7168
|
if (state.lastError !== void 0 && supervisorAlive) {
|
|
@@ -7185,18 +7264,18 @@ function collectDoctorReport(params) {
|
|
|
7185
7264
|
const { paths } = params;
|
|
7186
7265
|
const identityNames = import_node_fs8.default.existsSync(paths.identitiesDir) ? import_node_fs8.default.readdirSync(paths.identitiesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && isIdentityDirectoryName(entry.name)).map((entry) => entry.name).sort() : [];
|
|
7187
7266
|
const identities = identityNames.map((name) => {
|
|
7188
|
-
const farmRoot =
|
|
7189
|
-
const identityPath =
|
|
7267
|
+
const farmRoot = import_node_path24.default.join(paths.identitiesDir, name);
|
|
7268
|
+
const identityPath = import_node_path24.default.join(farmRoot, "identity.json");
|
|
7190
7269
|
return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot };
|
|
7191
7270
|
});
|
|
7192
7271
|
const profileNames = import_node_fs8.default.existsSync(paths.configProfilesDir) ? import_node_fs8.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
|
|
7193
7272
|
const configProfiles = profileNames.map((name) => {
|
|
7194
|
-
const profilePath =
|
|
7273
|
+
const profilePath = import_node_path24.default.join(paths.configProfilesDir, `${name}.json`);
|
|
7195
7274
|
return { name, path: profilePath, raw: realFsPort.readFileUtf8(profilePath) };
|
|
7196
7275
|
});
|
|
7197
7276
|
const providerNames = import_node_fs8.default.existsSync(paths.providersDir) ? import_node_fs8.default.readdirSync(paths.providersDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
|
|
7198
7277
|
const providers = providerNames.map((name) => {
|
|
7199
|
-
const providerPath =
|
|
7278
|
+
const providerPath = import_node_path24.default.join(paths.providersDir, `${name}.json`);
|
|
7200
7279
|
return { name, path: providerPath, raw: realFsPort.readFileUtf8(providerPath) };
|
|
7201
7280
|
});
|
|
7202
7281
|
const ownExecutablePath = realOwnExecutablePath();
|
|
@@ -7208,12 +7287,12 @@ function collectDoctorReport(params) {
|
|
|
7208
7287
|
binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
7209
7288
|
}
|
|
7210
7289
|
const shimState = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
|
|
7211
|
-
const pathDirs = (params.env.PATH ?? "").split(
|
|
7290
|
+
const pathDirs = (params.env.PATH ?? "").split(import_node_path24.default.delimiter).filter((dir) => dir !== "");
|
|
7212
7291
|
const claudeShimShadow = shimState === void 0 ? void 0 : refinePathShadow(
|
|
7213
7292
|
findPathShadow({
|
|
7214
7293
|
pathDirs,
|
|
7215
|
-
targetDir:
|
|
7216
|
-
targetFilename:
|
|
7294
|
+
targetDir: import_node_path24.default.dirname(shimState.targetPath),
|
|
7295
|
+
targetFilename: import_node_path24.default.basename(shimState.targetPath),
|
|
7217
7296
|
findExecutableInDir
|
|
7218
7297
|
}),
|
|
7219
7298
|
shimState.targetPath,
|
|
@@ -7236,7 +7315,7 @@ function collectDoctorReport(params) {
|
|
|
7236
7315
|
agentShim: refinePathShadow(
|
|
7237
7316
|
findPathShadow({
|
|
7238
7317
|
pathDirs,
|
|
7239
|
-
targetDir:
|
|
7318
|
+
targetDir: import_node_path24.default.dirname(ownExecutablePath),
|
|
7240
7319
|
targetFilename: commandFilename(ownExecutablePath, "agent-shim"),
|
|
7241
7320
|
findExecutableInDir
|
|
7242
7321
|
}),
|
|
@@ -7257,7 +7336,7 @@ function collectDoctorReport(params) {
|
|
|
7257
7336
|
|
|
7258
7337
|
// src/launcher.ts
|
|
7259
7338
|
var import_node_crypto9 = require("node:crypto");
|
|
7260
|
-
var
|
|
7339
|
+
var import_node_path26 = __toESM(require("node:path"), 1);
|
|
7261
7340
|
|
|
7262
7341
|
// src/launcher/argv.ts
|
|
7263
7342
|
var ConflictingIdentityError = class extends UsageError {
|
|
@@ -7509,7 +7588,7 @@ function buildCliOverride(params) {
|
|
|
7509
7588
|
}
|
|
7510
7589
|
|
|
7511
7590
|
// src/launcher/flags.ts
|
|
7512
|
-
var
|
|
7591
|
+
var import_node_path25 = __toESM(require("node:path"), 1);
|
|
7513
7592
|
|
|
7514
7593
|
// src/headroom/headers.ts
|
|
7515
7594
|
function mergeAnthropicCustomHeaders(existing, additions) {
|
|
@@ -7579,7 +7658,7 @@ function buildEnv(params) {
|
|
|
7579
7658
|
const parentCustomHeaders = params.baseEnv.ANTHROPIC_CUSTOM_HEADERS;
|
|
7580
7659
|
let providerCustomHeaders;
|
|
7581
7660
|
if (!params.configDirEscapeHatch && params.resolvedIdentityName !== void 0) {
|
|
7582
|
-
env.CLAUDE_CONFIG_DIR =
|
|
7661
|
+
env.CLAUDE_CONFIG_DIR = import_node_path25.default.join(params.identitiesDir, params.resolvedIdentityName);
|
|
7583
7662
|
}
|
|
7584
7663
|
if (params.provider !== void 0) {
|
|
7585
7664
|
const providerEnv = params.provider.definition.env ?? {};
|
|
@@ -7600,9 +7679,6 @@ function buildEnv(params) {
|
|
|
7600
7679
|
env[variable] = value;
|
|
7601
7680
|
}
|
|
7602
7681
|
}
|
|
7603
|
-
if (params.headroom !== void 0) {
|
|
7604
|
-
env.HEADROOM_PROXY_URL = `http://127.0.0.1:${String(params.headroom.port)}`;
|
|
7605
|
-
}
|
|
7606
7682
|
if (params.frontdoor !== void 0) {
|
|
7607
7683
|
env.ANTHROPIC_CUSTOM_HEADERS = mergeAnthropicCustomHeaders(
|
|
7608
7684
|
[
|
|
@@ -7743,7 +7819,7 @@ function prepareLaunch(params) {
|
|
|
7743
7819
|
identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
|
|
7744
7820
|
globalDefaultConfigProfile: params.globalDefaultConfigProfile
|
|
7745
7821
|
});
|
|
7746
|
-
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(
|
|
7822
|
+
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(import_node_path26.default.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
|
|
7747
7823
|
log.error(
|
|
7748
7824
|
`agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
|
|
7749
7825
|
);
|
|
@@ -7879,7 +7955,7 @@ function prepareLaunch(params) {
|
|
|
7879
7955
|
if (resolvedFlags.headroom && headroomPort !== void 0) {
|
|
7880
7956
|
headroom = headroomPort.ensure();
|
|
7881
7957
|
const via = resolvedProvider === void 0 ? `OAuth via the door's CONNECT surface on 127.0.0.1:${String(frontDoor?.connectPort ?? 0)}` : `provider ${resolvedProvider.name}`;
|
|
7882
|
-
log.info(`agent-shim: routing through the front door on 127.0.0.1:${String(frontDoor?.port ?? 0)} with headroom on
|
|
7958
|
+
log.info(`agent-shim: routing through the front door on 127.0.0.1:${String(frontDoor?.port ?? 0)} with headroom on unix socket ${headroom.socketPath} (${via}, project ${headroom.projectId})`);
|
|
7883
7959
|
} else if (resolvedFlags.headroom) {
|
|
7884
7960
|
log.error("agent-shim: headroom routing was requested but this launcher has no headroom port wired; refusing to launch without it.");
|
|
7885
7961
|
proc.exit(1);
|
|
@@ -7919,7 +7995,7 @@ var import_node_crypto11 = require("node:crypto");
|
|
|
7919
7995
|
// src/realCredentialCache.ts
|
|
7920
7996
|
var import_node_child_process2 = require("node:child_process");
|
|
7921
7997
|
var import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
7922
|
-
var
|
|
7998
|
+
var import_node_path27 = __toESM(require("node:path"), 1);
|
|
7923
7999
|
var KEYCHAIN_CACHE_SERVICE = "agent-shim-credential-cache";
|
|
7924
8000
|
var CACHE_DIR_MODE = 448;
|
|
7925
8001
|
var CACHE_FILE_MODE = 384;
|
|
@@ -7946,8 +8022,8 @@ function security(args, stdin) {
|
|
|
7946
8022
|
return { status: result.status, stdout: result.stdout };
|
|
7947
8023
|
}
|
|
7948
8024
|
function createRealCredentialCache(root) {
|
|
7949
|
-
const dir =
|
|
7950
|
-
const filePath = (owner) =>
|
|
8025
|
+
const dir = import_node_path27.default.join(root, "credential-cache");
|
|
8026
|
+
const filePath = (owner) => import_node_path27.default.join(dir, cacheFileNameFor(owner));
|
|
7951
8027
|
return {
|
|
7952
8028
|
read(store, owner) {
|
|
7953
8029
|
if (store === "file") {
|
|
@@ -8063,11 +8139,11 @@ function probeFrontDoorSync(port, caPem) {
|
|
|
8063
8139
|
|
|
8064
8140
|
// src/frontdoor/trust.ts
|
|
8065
8141
|
var import_node_crypto10 = require("node:crypto");
|
|
8066
|
-
var
|
|
8142
|
+
var import_node_path28 = __toESM(require("node:path"), 1);
|
|
8067
8143
|
var BUNDLE_NAME_HEX_DIGITS = 16;
|
|
8068
8144
|
function resolveTrustBundle(params) {
|
|
8069
|
-
const { caCertFile, bundlesDir, inherited, fs: fs12 } = params;
|
|
8070
|
-
if (inherited === void 0 || inherited === "" ||
|
|
8145
|
+
const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
|
|
8146
|
+
if (inherited === void 0 || inherited === "" || import_node_path28.default.resolve(inherited) === import_node_path28.default.resolve(caCertFile)) {
|
|
8071
8147
|
return { path: caCertFile };
|
|
8072
8148
|
}
|
|
8073
8149
|
const caPem = fs12.readFileUtf8(caCertFile);
|
|
@@ -8077,7 +8153,7 @@ function resolveTrustBundle(params) {
|
|
|
8077
8153
|
} catch (error) {
|
|
8078
8154
|
return {
|
|
8079
8155
|
path: caCertFile,
|
|
8080
|
-
warning: `agent-shim:
|
|
8156
|
+
warning: `agent-shim: ${variable} names ${inherited}, which could not be read (${error instanceof Error ? error.message : String(error)}); the child trusts agent-shim's front-door CA on top of the system store, and nothing from that file`
|
|
8081
8157
|
};
|
|
8082
8158
|
}
|
|
8083
8159
|
if (inheritedPem.includes(caPem.trim())) {
|
|
@@ -8085,7 +8161,7 @@ function resolveTrustBundle(params) {
|
|
|
8085
8161
|
}
|
|
8086
8162
|
const combined = `${inheritedPem.trimEnd()}
|
|
8087
8163
|
${caPem}`;
|
|
8088
|
-
const bundle =
|
|
8164
|
+
const bundle = import_node_path28.default.join(bundlesDir, `${(0, import_node_crypto10.createHash)("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
|
|
8089
8165
|
if (!fs12.exists(bundle)) {
|
|
8090
8166
|
fs12.mkdirp(bundlesDir);
|
|
8091
8167
|
fs12.writeFileAtomic(bundle, combined);
|
|
@@ -8123,7 +8199,7 @@ function realFrontDoorPort(paths, spawnDaemon) {
|
|
|
8123
8199
|
verifyListener: (port) => probeFrontDoorSync(port, import_node_fs10.default.readFileSync(paths.frontdoorCaCertFile, "utf8"))
|
|
8124
8200
|
}
|
|
8125
8201
|
});
|
|
8126
|
-
const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
|
|
8202
|
+
const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, variable: "NODE_EXTRA_CA_CERTS", inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
|
|
8127
8203
|
return {
|
|
8128
8204
|
port: up.port,
|
|
8129
8205
|
connectPort: up.connectPort,
|