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.mjs
CHANGED
|
@@ -247,7 +247,7 @@ var HeadroomGlobalConfigSchema = HeadroomGlobalConfigObjectSchema.superRefine((c
|
|
|
247
247
|
context.addIssue({ code: "custom", path: ["readMaturation"], message: "readMaturation needs rolloutChannel beta or dev" });
|
|
248
248
|
}
|
|
249
249
|
});
|
|
250
|
-
var HEADROOM_DEFAULT_SOURCE = "headroom-ai[proxy] @ git+https://github.com/ExaDev/headroom@
|
|
250
|
+
var HEADROOM_DEFAULT_SOURCE = "headroom-ai[proxy] @ git+https://github.com/ExaDev/headroom@53525f479f2f48e8ef6b08cf729601feab7d2382";
|
|
251
251
|
var HEADROOM_DEFAULT_IDLE_SHUTDOWN_MINUTES = 15;
|
|
252
252
|
var FrontDoorGlobalConfigSchema = z.strictObject({
|
|
253
253
|
/** How long the front door may sit with no registered sessions before it closes and exits. Defaults to FRONTDOOR_DEFAULT_IDLE_SHUTDOWN_MINUTES. */
|
|
@@ -2484,7 +2484,7 @@ function providerBaseUrl(port, provider) {
|
|
|
2484
2484
|
// src/frontdoor/state.ts
|
|
2485
2485
|
import path7 from "node:path";
|
|
2486
2486
|
import { z as z3 } from "zod";
|
|
2487
|
-
var FRONT_DOOR_PROTOCOL =
|
|
2487
|
+
var FRONT_DOOR_PROTOCOL = 2;
|
|
2488
2488
|
var FrontDoorSessionSchema = z3.strictObject({ pid: z3.number().int().positive(), startedAt: z3.number(), token: z3.string().min(1) });
|
|
2489
2489
|
var FrontDoorStateSchema = z3.strictObject({
|
|
2490
2490
|
/**
|
|
@@ -2709,8 +2709,8 @@ function parseConnectTarget(authority) {
|
|
|
2709
2709
|
function isInterceptedHost(host, interceptHosts) {
|
|
2710
2710
|
return interceptHosts.includes(host);
|
|
2711
2711
|
}
|
|
2712
|
-
function servedByPipeline(
|
|
2713
|
-
return
|
|
2712
|
+
function servedByPipeline(path29) {
|
|
2713
|
+
return path29?.startsWith(ROUTED_PATH_PREFIX) === true;
|
|
2714
2714
|
}
|
|
2715
2715
|
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
2716
2716
|
"connection",
|
|
@@ -3276,17 +3276,16 @@ import { createHash as createHash2 } from "node:crypto";
|
|
|
3276
3276
|
import path8 from "node:path";
|
|
3277
3277
|
import { z as z4 } from "zod";
|
|
3278
3278
|
var HEADROOM_ANTHROPIC_UPSTREAM = "https://api.anthropic.com";
|
|
3279
|
+
var HEADROOM_STATE_SCHEMA_VERSION = 2;
|
|
3279
3280
|
var HeadroomStateSchema = z4.strictObject({
|
|
3280
3281
|
/** The supervisor process owning the daemon. Alive means someone is keeping headroom running. */
|
|
3281
3282
|
supervisorPid: z4.number().int().positive().optional(),
|
|
3282
3283
|
/** The headroom proxy process itself. Absent while the supervisor is between restarts. */
|
|
3283
3284
|
headroomPid: z4.number().int().positive().optional(),
|
|
3284
|
-
/** 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. */
|
|
3285
|
-
port: z4.number().int().positive().optional(),
|
|
3286
3285
|
/**
|
|
3287
|
-
* The
|
|
3286
|
+
* 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.
|
|
3288
3287
|
*/
|
|
3289
|
-
|
|
3288
|
+
socketPath: z4.string().min(1).optional(),
|
|
3290
3289
|
/** The `headroom --version` output of the running install. */
|
|
3291
3290
|
version: z4.string().optional(),
|
|
3292
3291
|
/** Hash of the allowlist the running proxy was started with, so a provider-file change is detected as drift. */
|
|
@@ -3793,10 +3792,10 @@ function ensureHeadroom(params) {
|
|
|
3793
3792
|
for (; ; ) {
|
|
3794
3793
|
const state = readHeadroomState(ports.fs, paths.headroomStateFile);
|
|
3795
3794
|
if (state?.supervisorPid !== void 0 && ports.isRunning(state.supervisorPid)) {
|
|
3796
|
-
const daemonUp = state.
|
|
3797
|
-
if (daemonUp && state.
|
|
3795
|
+
const daemonUp = state.socketPath !== void 0 && state.headroomPid !== void 0 && ports.isRunning(state.headroomPid);
|
|
3796
|
+
if (daemonUp && state.socketPath !== void 0) {
|
|
3798
3797
|
writeSession(ports.fs, paths.headroomSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), supervisorPid: state.supervisorPid });
|
|
3799
|
-
return {
|
|
3798
|
+
return { socketPath: state.socketPath };
|
|
3800
3799
|
}
|
|
3801
3800
|
if (state.lastError !== void 0) {
|
|
3802
3801
|
throw new HeadroomStartError(
|
|
@@ -3860,6 +3859,71 @@ function hashSettings(settings) {
|
|
|
3860
3859
|
return createHash3("sha256").update(JSON.stringify([...settingsArgs(settings), JSON.stringify(settingsEnv(settings))])).digest("hex");
|
|
3861
3860
|
}
|
|
3862
3861
|
|
|
3862
|
+
// src/headroom/socket.ts
|
|
3863
|
+
import path11 from "node:path";
|
|
3864
|
+
var GROUP_OR_OTHER_BITS = 63;
|
|
3865
|
+
var OCTAL_RADIX = 8;
|
|
3866
|
+
var MODE_DIGITS = 4;
|
|
3867
|
+
var HEADROOM_SOCKET_SUFFIX = ".sock";
|
|
3868
|
+
var HEADROOM_SOCKET_NAME = /^(\d+)\.sock$/;
|
|
3869
|
+
var UNIX_SOCKET_PATH_MAX_BYTES = 103;
|
|
3870
|
+
var PLATFORMS_WITHOUT_UNIX_SOCKETS = ["win32"];
|
|
3871
|
+
function headroomSocketPath(paths, supervisorPid) {
|
|
3872
|
+
return path11.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
|
|
3873
|
+
}
|
|
3874
|
+
function platformRefusal(platform) {
|
|
3875
|
+
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;
|
|
3876
|
+
}
|
|
3877
|
+
function ownerOnlyRefusal(label, target, stat, expected, uid) {
|
|
3878
|
+
if (stat === void 0) {
|
|
3879
|
+
return `the headroom ${label} ${target} does not exist`;
|
|
3880
|
+
}
|
|
3881
|
+
if (stat.kind === "symlink") {
|
|
3882
|
+
return `the headroom ${label} ${target} is a symlink; it must be the real ${expected === "dir" ? "directory" : "socket"}`;
|
|
3883
|
+
}
|
|
3884
|
+
if (stat.kind !== expected) {
|
|
3885
|
+
return `the headroom ${label} ${target} is not a ${expected === "dir" ? "directory" : "socket"}`;
|
|
3886
|
+
}
|
|
3887
|
+
if (stat.uid !== uid) {
|
|
3888
|
+
return `the headroom ${label} ${target} is owned by uid ${String(stat.uid)}, not by this user (uid ${String(uid)})`;
|
|
3889
|
+
}
|
|
3890
|
+
if ((stat.mode & GROUP_OR_OTHER_BITS) !== 0) {
|
|
3891
|
+
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`;
|
|
3892
|
+
}
|
|
3893
|
+
return void 0;
|
|
3894
|
+
}
|
|
3895
|
+
function prepareHeadroomSocket(fs12, ports, paths, supervisorPid) {
|
|
3896
|
+
const unsupported = platformRefusal(ports.platform);
|
|
3897
|
+
if (unsupported !== void 0) {
|
|
3898
|
+
return { refused: unsupported };
|
|
3899
|
+
}
|
|
3900
|
+
const socketPath = headroomSocketPath(paths, supervisorPid);
|
|
3901
|
+
const length = Buffer.byteLength(socketPath, "utf8");
|
|
3902
|
+
if (length > UNIX_SOCKET_PATH_MAX_BYTES) {
|
|
3903
|
+
return {
|
|
3904
|
+
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`
|
|
3905
|
+
};
|
|
3906
|
+
}
|
|
3907
|
+
if (ports.lstat(paths.headroomSocketDir)?.kind === "symlink") {
|
|
3908
|
+
return { refused: `the headroom socket directory ${paths.headroomSocketDir} is a symlink; it must be the real directory` };
|
|
3909
|
+
}
|
|
3910
|
+
fs12.mkdirPrivate(paths.headroomSocketDir);
|
|
3911
|
+
const refusal = ownerOnlyRefusal("socket directory", paths.headroomSocketDir, ports.lstat(paths.headroomSocketDir), "dir", ports.currentUid());
|
|
3912
|
+
return refusal === void 0 ? { socketPath } : { refused: refusal };
|
|
3913
|
+
}
|
|
3914
|
+
function pruneStaleHeadroomSockets(fs12, paths, isRunning) {
|
|
3915
|
+
const removed = [];
|
|
3916
|
+
for (const name of fs12.readdir(paths.headroomSocketDir)) {
|
|
3917
|
+
const pid = HEADROOM_SOCKET_NAME.exec(name)?.[1];
|
|
3918
|
+
if (pid === void 0 || isRunning(Number.parseInt(pid, 10))) {
|
|
3919
|
+
continue;
|
|
3920
|
+
}
|
|
3921
|
+
fs12.removeRecursive(path11.join(paths.headroomSocketDir, name));
|
|
3922
|
+
removed.push(name);
|
|
3923
|
+
}
|
|
3924
|
+
return removed;
|
|
3925
|
+
}
|
|
3926
|
+
|
|
3863
3927
|
// src/headroom/source.ts
|
|
3864
3928
|
import { z as z6 } from "zod";
|
|
3865
3929
|
var GIT_SPEC_RE = /git\+[^@\s]+(?:@([^\s#]+))?/;
|
|
@@ -3955,8 +4019,6 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3955
4019
|
return 0;
|
|
3956
4020
|
}
|
|
3957
4021
|
let installedSource = previousState?.installedSource;
|
|
3958
|
-
let lastPort = previousState?.lastPort;
|
|
3959
|
-
const sticky = () => lastPort === void 0 ? {} : { lastPort };
|
|
3960
4022
|
const ownsState = () => {
|
|
3961
4023
|
const owner = readHeadroomState(fs12, paths.headroomStateFile)?.supervisorPid;
|
|
3962
4024
|
return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
|
|
@@ -3969,7 +4031,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3969
4031
|
return true;
|
|
3970
4032
|
};
|
|
3971
4033
|
const fail = (message) => {
|
|
3972
|
-
if (writeOwnState({ lastError: message
|
|
4034
|
+
if (writeOwnState({ lastError: message })) {
|
|
3973
4035
|
fs12.removeRecursive(paths.headroomLockFile);
|
|
3974
4036
|
}
|
|
3975
4037
|
ports.log(`agent-shim headroom supervisor: ${message}`);
|
|
@@ -3992,11 +4054,17 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
3992
4054
|
installedSource = config.source;
|
|
3993
4055
|
return true;
|
|
3994
4056
|
};
|
|
4057
|
+
const socket = prepareHeadroomSocket(fs12, ports.socketTrust, paths, ports.ownPid);
|
|
4058
|
+
if (socket.refused !== void 0) {
|
|
4059
|
+
return fail(socket.refused);
|
|
4060
|
+
}
|
|
4061
|
+
const { socketPath } = socket;
|
|
4062
|
+
pruneStaleHeadroomSockets(fs12, paths, ports.isRunning);
|
|
3995
4063
|
if (!ensureInstalled()) {
|
|
3996
4064
|
return fail(`could not install headroom from ${config.source}: install failed (is uv installed and on PATH?)`);
|
|
3997
4065
|
}
|
|
3998
4066
|
const version = ports.headroomVersion() ?? "unknown";
|
|
3999
|
-
writeOwnState({ supervisorPid: ports.ownPid, version, installedSource
|
|
4067
|
+
writeOwnState({ supervisorPid: ports.ownPid, version, installedSource });
|
|
4000
4068
|
ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: managing headroom on allowlist [${allowlistOf(ports).join(", ")}]`);
|
|
4001
4069
|
const orphanPid = previousState?.headroomPid;
|
|
4002
4070
|
if (orphanPid !== void 0 && ports.isRunning(orphanPid)) {
|
|
@@ -4022,7 +4090,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
4022
4090
|
pruneDeadSessions(fs12, paths.headroomSessionsDir, ports.isRunning);
|
|
4023
4091
|
const ownsNow = ownsState();
|
|
4024
4092
|
if (!ownsNow && !superseded) {
|
|
4025
|
-
ports.log("agent-shim headroom supervisor: another supervisor now owns state
|
|
4093
|
+
ports.log("agent-shim headroom supervisor: another supervisor now owns the state file; serving this daemon's own sessions until they end");
|
|
4026
4094
|
}
|
|
4027
4095
|
superseded = !ownsNow;
|
|
4028
4096
|
const crashed = headroomPid !== void 0 && !ports.isRunning(headroomPid);
|
|
@@ -4035,8 +4103,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
4035
4103
|
writeOwnState({
|
|
4036
4104
|
supervisorPid: ports.ownPid,
|
|
4037
4105
|
version,
|
|
4038
|
-
installedSource
|
|
4039
|
-
...sticky()
|
|
4106
|
+
installedSource
|
|
4040
4107
|
});
|
|
4041
4108
|
}
|
|
4042
4109
|
if (consecutiveFailures >= HEADROOM_START_RETRY_BUDGET) {
|
|
@@ -4045,41 +4112,32 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
4045
4112
|
if (installedSource !== config.source && !ensureInstalled()) {
|
|
4046
4113
|
return fail(`could not install headroom from ${config.source}: install failed (is uv installed and on PATH?)`);
|
|
4047
4114
|
}
|
|
4048
|
-
const
|
|
4049
|
-
const
|
|
4050
|
-
const pid = ports.spawnHeadroom(port, allowlist, config.settings);
|
|
4051
|
-
const ready = await waitUntilReady(ports, port);
|
|
4115
|
+
const pid = ports.spawnHeadroom(socketPath, allowlist, config.settings);
|
|
4116
|
+
const ready = await waitUntilReady(ports, socketPath);
|
|
4052
4117
|
if (ready) {
|
|
4053
4118
|
consecutiveFailures = 0;
|
|
4054
4119
|
headroomPid = pid;
|
|
4055
4120
|
runningHash = allowlistHash;
|
|
4056
4121
|
runningSettingsHash = settingsHash;
|
|
4057
|
-
lastPort = port;
|
|
4058
|
-
if (previousSticky !== void 0 && port !== previousSticky) {
|
|
4059
|
-
ports.log(
|
|
4060
|
-
`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)`
|
|
4061
|
-
);
|
|
4062
|
-
}
|
|
4063
4122
|
const recorded = writeOwnState({
|
|
4064
4123
|
supervisorPid: ports.ownPid,
|
|
4065
4124
|
headroomPid: pid,
|
|
4066
|
-
|
|
4125
|
+
socketPath,
|
|
4067
4126
|
version,
|
|
4068
4127
|
allowlistHash,
|
|
4069
4128
|
settingsHash,
|
|
4070
|
-
installedSource: config.source
|
|
4071
|
-
...sticky()
|
|
4129
|
+
installedSource: config.source
|
|
4072
4130
|
});
|
|
4073
4131
|
if (recorded) {
|
|
4074
4132
|
fs12.removeRecursive(paths.headroomLockFile);
|
|
4075
4133
|
}
|
|
4076
4134
|
idleSince = void 0;
|
|
4077
|
-
ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on
|
|
4135
|
+
ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on unix socket ${socketPath}`);
|
|
4078
4136
|
} else {
|
|
4079
4137
|
ports.stopProcess(pid);
|
|
4080
4138
|
consecutiveFailures += 1;
|
|
4081
4139
|
ports.log(
|
|
4082
|
-
`agent-shim headroom supervisor: headroom did not become ready on
|
|
4140
|
+
`agent-shim headroom supervisor: headroom did not become ready on unix socket ${socketPath} (attempt ${String(consecutiveFailures)} of ${String(HEADROOM_START_RETRY_BUDGET)})`
|
|
4083
4141
|
);
|
|
4084
4142
|
await ports.sleep(backoffForAttempt(consecutiveFailures));
|
|
4085
4143
|
continue;
|
|
@@ -4104,10 +4162,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
|
|
|
4104
4162
|
`agent-shim headroom supervisor: no sessions for ${String(config.idleShutdownMinutes)} minute(s); stopping headroom and exiting`
|
|
4105
4163
|
);
|
|
4106
4164
|
ports.stopProcess(headroomPid);
|
|
4107
|
-
writeOwnState({
|
|
4108
|
-
version,
|
|
4109
|
-
...sticky()
|
|
4110
|
-
});
|
|
4165
|
+
writeOwnState({ version });
|
|
4111
4166
|
return 0;
|
|
4112
4167
|
}
|
|
4113
4168
|
} else {
|
|
@@ -4124,10 +4179,10 @@ function currentHeadroomAllowlist(fs12, paths) {
|
|
|
4124
4179
|
function allowlistOf(ports) {
|
|
4125
4180
|
return currentHeadroomAllowlist(ports.fs, ports.paths);
|
|
4126
4181
|
}
|
|
4127
|
-
async function waitUntilReady(ports,
|
|
4182
|
+
async function waitUntilReady(ports, socketPath) {
|
|
4128
4183
|
const deadline = ports.now() + HEADROOM_READY_TIMEOUT_MS;
|
|
4129
4184
|
for (; ; ) {
|
|
4130
|
-
if (await ports.ready(
|
|
4185
|
+
if (await ports.ready(socketPath)) {
|
|
4131
4186
|
return true;
|
|
4132
4187
|
}
|
|
4133
4188
|
if (ports.now() >= deadline) {
|
|
@@ -4187,14 +4242,14 @@ function evaluateAmbientCredentialGuard(params) {
|
|
|
4187
4242
|
// src/paths.ts
|
|
4188
4243
|
import fs3 from "node:fs";
|
|
4189
4244
|
import os from "node:os";
|
|
4190
|
-
import
|
|
4245
|
+
import path12 from "node:path";
|
|
4191
4246
|
function resolveAgentShimHome(env = process.env, home = os.homedir(), isDirectory = isExistingDirectory) {
|
|
4192
4247
|
const fromEnv = env.AGENT_SHIM_HOME;
|
|
4193
4248
|
if (fromEnv !== void 0 && fromEnv !== "") {
|
|
4194
4249
|
return fromEnv;
|
|
4195
4250
|
}
|
|
4196
|
-
const current =
|
|
4197
|
-
const legacy =
|
|
4251
|
+
const current = path12.join(home, HOME_DIRNAME);
|
|
4252
|
+
const legacy = path12.join(home, LEGACY_HOME_DIRNAME);
|
|
4198
4253
|
return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
|
|
4199
4254
|
}
|
|
4200
4255
|
function isExistingDirectory(candidate) {
|
|
@@ -4205,38 +4260,39 @@ function resolveClaudeHome() {
|
|
|
4205
4260
|
if (fromEnv !== void 0 && fromEnv !== "") {
|
|
4206
4261
|
return fromEnv;
|
|
4207
4262
|
}
|
|
4208
|
-
return
|
|
4263
|
+
return path12.join(os.homedir(), ".claude");
|
|
4209
4264
|
}
|
|
4210
4265
|
function buildLayoutPaths(root) {
|
|
4211
4266
|
return {
|
|
4212
4267
|
root,
|
|
4213
|
-
identitiesDir:
|
|
4214
|
-
configProfilesDir:
|
|
4215
|
-
providersDir:
|
|
4216
|
-
directoryRulesFile:
|
|
4217
|
-
activeIdentityFile:
|
|
4218
|
-
globalConfigFile:
|
|
4219
|
-
categoriesLocalFile:
|
|
4220
|
-
claudeShimFile:
|
|
4221
|
-
headroomDir:
|
|
4222
|
-
headroomStateFile:
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4268
|
+
identitiesDir: path12.join(root, "identities"),
|
|
4269
|
+
configProfilesDir: path12.join(root, "config-profiles"),
|
|
4270
|
+
providersDir: path12.join(root, "providers"),
|
|
4271
|
+
directoryRulesFile: path12.join(root, "directory-rules.json"),
|
|
4272
|
+
activeIdentityFile: path12.join(root, "active-identity"),
|
|
4273
|
+
globalConfigFile: path12.join(root, "config.json"),
|
|
4274
|
+
categoriesLocalFile: path12.join(root, "categories.local.json"),
|
|
4275
|
+
claudeShimFile: path12.join(root, "claude-shim.json"),
|
|
4276
|
+
headroomDir: path12.join(root, "headroom"),
|
|
4277
|
+
headroomStateFile: path12.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
|
|
4278
|
+
headroomSocketDir: path12.join(root, "headroom", "run"),
|
|
4279
|
+
headroomLockFile: path12.join(root, "headroom", "start.lock"),
|
|
4280
|
+
headroomSessionsDir: path12.join(root, "headroom", "sessions"),
|
|
4281
|
+
logsDir: path12.join(root, "logs"),
|
|
4282
|
+
headroomLogPath: path12.join(root, "logs", "headroom.log"),
|
|
4283
|
+
frontdoorDir: path12.join(root, "frontdoor"),
|
|
4284
|
+
frontdoorCaDir: path12.join(root, "frontdoor", "ca"),
|
|
4285
|
+
frontdoorCaCertFile: path12.join(root, "frontdoor", "ca", "ca.pem"),
|
|
4286
|
+
frontdoorCaKeyFile: path12.join(root, "frontdoor", "ca", "ca.key"),
|
|
4287
|
+
frontdoorCaBundlesDir: path12.join(root, "frontdoor", "ca", "bundles"),
|
|
4288
|
+
frontdoorStateFile: path12.join(root, "frontdoor", "state.json"),
|
|
4289
|
+
frontdoorLockFile: path12.join(root, "frontdoor", "start.lock"),
|
|
4290
|
+
frontdoorSessionsDir: path12.join(root, "frontdoor", "sessions"),
|
|
4291
|
+
frontdoorLogPath: path12.join(root, "logs", "frontdoor.log"),
|
|
4292
|
+
usageDir: path12.join(root, "usage"),
|
|
4293
|
+
usageLogDir: path12.join(root, "usage", "log"),
|
|
4294
|
+
usageSnapshotsDir: path12.join(root, "usage", "snapshots"),
|
|
4295
|
+
usagePicksFile: path12.join(root, "usage", "picks.json")
|
|
4240
4296
|
};
|
|
4241
4297
|
}
|
|
4242
4298
|
function resolveLayoutPaths() {
|
|
@@ -4245,10 +4301,10 @@ function resolveLayoutPaths() {
|
|
|
4245
4301
|
|
|
4246
4302
|
// src/identityStore.ts
|
|
4247
4303
|
import fs5 from "node:fs";
|
|
4248
|
-
import
|
|
4304
|
+
import path15 from "node:path";
|
|
4249
4305
|
|
|
4250
4306
|
// src/launcher/identity.ts
|
|
4251
|
-
import
|
|
4307
|
+
import path13 from "node:path";
|
|
4252
4308
|
function poolNameOf(selector) {
|
|
4253
4309
|
return selector.startsWith(POOL_SELECTOR_PREFIX) ? selector.slice(POOL_SELECTOR_PREFIX.length) : void 0;
|
|
4254
4310
|
}
|
|
@@ -4297,12 +4353,12 @@ function decideConfigProfile(params) {
|
|
|
4297
4353
|
return { source: "none" };
|
|
4298
4354
|
}
|
|
4299
4355
|
function loadIdentity(identitiesDir, name, fs12) {
|
|
4300
|
-
return loadConfigFile(
|
|
4356
|
+
return loadConfigFile(path13.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
|
|
4301
4357
|
}
|
|
4302
4358
|
|
|
4303
4359
|
// src/configProfilesStore.ts
|
|
4304
4360
|
import fs4 from "node:fs";
|
|
4305
|
-
import
|
|
4361
|
+
import path14 from "node:path";
|
|
4306
4362
|
var ProfileNotFoundError = class extends CliError {
|
|
4307
4363
|
constructor(profileName) {
|
|
4308
4364
|
super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
|
|
@@ -4328,7 +4384,7 @@ var InvalidCategoryNameError = class extends CliError {
|
|
|
4328
4384
|
categoryName;
|
|
4329
4385
|
};
|
|
4330
4386
|
function profileJsonPath(paths, name) {
|
|
4331
|
-
return
|
|
4387
|
+
return path14.join(paths.configProfilesDir, `${name}.json`);
|
|
4332
4388
|
}
|
|
4333
4389
|
function profileExists(paths, name) {
|
|
4334
4390
|
return fs4.existsSync(profileJsonPath(paths, name));
|
|
@@ -4516,7 +4572,7 @@ var InvalidIdentityNameError = class extends CliError {
|
|
|
4516
4572
|
attemptedName;
|
|
4517
4573
|
};
|
|
4518
4574
|
function identityJsonPath(paths, name) {
|
|
4519
|
-
return
|
|
4575
|
+
return path15.join(paths.identitiesDir, name, "identity.json");
|
|
4520
4576
|
}
|
|
4521
4577
|
function identityExists(paths, name) {
|
|
4522
4578
|
return fs5.existsSync(identityJsonPath(paths, name));
|
|
@@ -4617,7 +4673,7 @@ function setIdentityCredential(paths, identityName, change) {
|
|
|
4617
4673
|
});
|
|
4618
4674
|
}
|
|
4619
4675
|
function belongsToIdentity(entry, name) {
|
|
4620
|
-
return entry === name || entry ===
|
|
4676
|
+
return entry === name || entry === path15.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
|
|
4621
4677
|
}
|
|
4622
4678
|
function removeIdentity(paths, name) {
|
|
4623
4679
|
if (!identityExists(paths, name)) {
|
|
@@ -4625,7 +4681,7 @@ function removeIdentity(paths, name) {
|
|
|
4625
4681
|
}
|
|
4626
4682
|
for (const entry of fs5.readdirSync(paths.identitiesDir)) {
|
|
4627
4683
|
if (belongsToIdentity(entry, name)) {
|
|
4628
|
-
fs5.rmSync(
|
|
4684
|
+
fs5.rmSync(path15.join(paths.identitiesDir, entry), { recursive: true, force: true });
|
|
4629
4685
|
}
|
|
4630
4686
|
}
|
|
4631
4687
|
if (readActiveIdentity(paths) === name) {
|
|
@@ -4635,7 +4691,7 @@ function removeIdentity(paths, name) {
|
|
|
4635
4691
|
|
|
4636
4692
|
// src/providersStore.ts
|
|
4637
4693
|
import fs6 from "node:fs";
|
|
4638
|
-
import
|
|
4694
|
+
import path16 from "node:path";
|
|
4639
4695
|
|
|
4640
4696
|
// src/credentialCache.ts
|
|
4641
4697
|
import { z as z7 } from "zod";
|
|
@@ -4672,7 +4728,7 @@ var CREDENTIAL_COMMAND_TIMEOUT_MS = 1e4;
|
|
|
4672
4728
|
var CREDENTIAL_INTERACTIVE_TIMEOUT_MS = 12e4;
|
|
4673
4729
|
var GROUP_OTHER_PERMISSION_BITS = 63;
|
|
4674
4730
|
var PERMISSION_BITS = 511;
|
|
4675
|
-
var
|
|
4731
|
+
var OCTAL_RADIX2 = 8;
|
|
4676
4732
|
function commandArgv(source) {
|
|
4677
4733
|
if ("command" in source) {
|
|
4678
4734
|
return source.command;
|
|
@@ -4765,7 +4821,7 @@ function trySource(source, params) {
|
|
|
4765
4821
|
}
|
|
4766
4822
|
if (read.mode !== void 0 && (read.mode & GROUP_OTHER_PERMISSION_BITS) !== 0) {
|
|
4767
4823
|
return none(
|
|
4768
|
-
`is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS).toString(
|
|
4824
|
+
`is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS).toString(OCTAL_RADIX2)}); run \`chmod 600 ${source.file}\``,
|
|
4769
4825
|
true
|
|
4770
4826
|
);
|
|
4771
4827
|
}
|
|
@@ -4861,7 +4917,7 @@ var InvalidProviderNameError = class extends CliError {
|
|
|
4861
4917
|
};
|
|
4862
4918
|
var PROVIDER_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._@-]*$/;
|
|
4863
4919
|
function providerJsonPath(paths, name) {
|
|
4864
|
-
return
|
|
4920
|
+
return path16.join(paths.providersDir, `${name}.json`);
|
|
4865
4921
|
}
|
|
4866
4922
|
function providerExists(paths, name) {
|
|
4867
4923
|
return fs6.existsSync(providerJsonPath(paths, name));
|
|
@@ -4937,7 +4993,7 @@ function readProvider(paths, name) {
|
|
|
4937
4993
|
return parseProviderFile(filePath, raw);
|
|
4938
4994
|
}
|
|
4939
4995
|
function loadProvider(providersDir, name, port) {
|
|
4940
|
-
const filePath =
|
|
4996
|
+
const filePath = path16.join(providersDir, `${name}.json`);
|
|
4941
4997
|
const raw = port.readConfigFile(filePath);
|
|
4942
4998
|
return raw === void 0 ? void 0 : parseProviderFile(filePath, raw);
|
|
4943
4999
|
}
|
|
@@ -5192,21 +5248,21 @@ function removeDirectoryRule(paths, rulePath) {
|
|
|
5192
5248
|
import os4 from "node:os";
|
|
5193
5249
|
|
|
5194
5250
|
// src/launcher/cascade.ts
|
|
5195
|
-
import
|
|
5251
|
+
import path18 from "node:path";
|
|
5196
5252
|
|
|
5197
5253
|
// src/pathNorm.ts
|
|
5198
|
-
import
|
|
5254
|
+
import path17 from "node:path";
|
|
5199
5255
|
function expandTilde(value, home) {
|
|
5200
5256
|
if (value === "~") {
|
|
5201
5257
|
return home;
|
|
5202
5258
|
}
|
|
5203
5259
|
if (value.startsWith("~/")) {
|
|
5204
|
-
return
|
|
5260
|
+
return path17.join(home, value.slice(2));
|
|
5205
5261
|
}
|
|
5206
5262
|
return value;
|
|
5207
5263
|
}
|
|
5208
5264
|
function normaliseRulePath(rulePath, home) {
|
|
5209
|
-
return
|
|
5265
|
+
return path17.resolve(expandTilde(rulePath, home));
|
|
5210
5266
|
}
|
|
5211
5267
|
|
|
5212
5268
|
// src/launcher/cascade.ts
|
|
@@ -5216,7 +5272,7 @@ function loadCascadeInput(params) {
|
|
|
5216
5272
|
const globalConfig = loadConfigFile(params.paths.globalConfigFile, GlobalConfigSchema, params.read);
|
|
5217
5273
|
const directoryRules = loadConfigFile(params.paths.directoryRulesFile, DirectoryRulesSchema, params.read);
|
|
5218
5274
|
const loadProfile = (name) => {
|
|
5219
|
-
const filepath =
|
|
5275
|
+
const filepath = path18.join(params.paths.configProfilesDir, `${name}.json`);
|
|
5220
5276
|
const loaded = loadConfigFile(filepath, ConfigProfileSchema, params.read);
|
|
5221
5277
|
if (loaded === void 0) {
|
|
5222
5278
|
return void 0;
|
|
@@ -5231,8 +5287,8 @@ function loadCascadeInput(params) {
|
|
|
5231
5287
|
});
|
|
5232
5288
|
const levels = [];
|
|
5233
5289
|
for (const dir of dirs) {
|
|
5234
|
-
const portable = loadConfigFile(
|
|
5235
|
-
const portableLocal = loadConfigFile(
|
|
5290
|
+
const portable = loadConfigFile(path18.join(dir, PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(path18.join(dir, LEGACY_PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read);
|
|
5291
|
+
const portableLocal = loadConfigFile(path18.join(dir, PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(path18.join(dir, LEGACY_PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read);
|
|
5236
5292
|
const rules = (directoryRules?.config.rules ?? []).map((rule, index) => ({ rule, index })).filter(({ rule }) => normaliseRulePath(rule.path, params.home) === dir).map(({ rule, index }) => {
|
|
5237
5293
|
const entryOrder = directoryRules?.ruleEntryOrders[index];
|
|
5238
5294
|
return {
|
|
@@ -5329,7 +5385,7 @@ function quotaWarnings(snapshot, provider, nowMs) {
|
|
|
5329
5385
|
}
|
|
5330
5386
|
|
|
5331
5387
|
// src/usage/poolPick.ts
|
|
5332
|
-
import
|
|
5388
|
+
import path19 from "node:path";
|
|
5333
5389
|
import { z as z9 } from "zod";
|
|
5334
5390
|
|
|
5335
5391
|
// src/usage/plan.ts
|
|
@@ -5631,7 +5687,7 @@ function recordStickyPick(fs12, picksFile, directory, identity, nowMs) {
|
|
|
5631
5687
|
const current = readPicksFile(fs12, picksFile).file.picks;
|
|
5632
5688
|
const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
|
|
5633
5689
|
const next = { schemaVersion: SCHEMA_VERSION, picks: { ...Object.fromEntries(kept), [directory]: { identity, at: new Date(nowMs).toISOString() } } };
|
|
5634
|
-
fs12.mkdirPrivate(
|
|
5690
|
+
fs12.mkdirPrivate(path19.dirname(picksFile));
|
|
5635
5691
|
fs12.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
|
|
5636
5692
|
`);
|
|
5637
5693
|
}
|
|
@@ -5728,14 +5784,14 @@ import { spawn, spawnSync } from "node:child_process";
|
|
|
5728
5784
|
import { createHash as createHash4 } from "node:crypto";
|
|
5729
5785
|
import fs7 from "node:fs";
|
|
5730
5786
|
import os3 from "node:os";
|
|
5731
|
-
import
|
|
5787
|
+
import path21 from "node:path";
|
|
5732
5788
|
import { isSea } from "node:sea";
|
|
5733
5789
|
|
|
5734
5790
|
// src/versionDiscovery.ts
|
|
5735
5791
|
import os2 from "node:os";
|
|
5736
|
-
import
|
|
5792
|
+
import path20 from "node:path";
|
|
5737
5793
|
function defaultVersionsDir() {
|
|
5738
|
-
return
|
|
5794
|
+
return path20.join(os2.homedir(), ".local", "share", "claude", "versions");
|
|
5739
5795
|
}
|
|
5740
5796
|
var NUMERIC_DOTTED_VERSION_RE = /^\d+(?:\.\d+)*$/;
|
|
5741
5797
|
function isNumericDottedVersion(name) {
|
|
@@ -5777,14 +5833,14 @@ function discoverClaudeBinary(options) {
|
|
|
5777
5833
|
const highestVersion = pickHighestVersion(entries);
|
|
5778
5834
|
if (highestVersion !== void 0) {
|
|
5779
5835
|
return {
|
|
5780
|
-
path:
|
|
5836
|
+
path: path20.join(versionsDir, highestVersion),
|
|
5781
5837
|
source: "versions-dir",
|
|
5782
5838
|
version: highestVersion
|
|
5783
5839
|
};
|
|
5784
5840
|
}
|
|
5785
|
-
const ownInstallDirs = new Set(options.ownInstallDirs.map((dir) =>
|
|
5841
|
+
const ownInstallDirs = new Set(options.ownInstallDirs.map((dir) => path20.resolve(dir)));
|
|
5786
5842
|
for (const dir of options.pathDirs) {
|
|
5787
|
-
if (ownInstallDirs.has(
|
|
5843
|
+
if (ownInstallDirs.has(path20.resolve(dir))) {
|
|
5788
5844
|
continue;
|
|
5789
5845
|
}
|
|
5790
5846
|
const found = options.findExecutableInDir(dir, "claude");
|
|
@@ -5955,7 +6011,7 @@ var realRunPort = {
|
|
|
5955
6011
|
}
|
|
5956
6012
|
};
|
|
5957
6013
|
function expandHome2(filePath) {
|
|
5958
|
-
return filePath.startsWith("~/") ?
|
|
6014
|
+
return filePath.startsWith("~/") ? path21.join(os3.homedir(), filePath.slice(1)) : filePath;
|
|
5959
6015
|
}
|
|
5960
6016
|
var MACOS_GUI_SESSION_MANAGER = "Aqua";
|
|
5961
6017
|
function hasDesktopSession() {
|
|
@@ -6028,7 +6084,7 @@ function spawnDaemonThrough(executable) {
|
|
|
6028
6084
|
return (paths, subcommand, logPath) => spawnDetachedDaemon({ command: executable, args: [subcommand] }, paths, subcommand, logPath);
|
|
6029
6085
|
}
|
|
6030
6086
|
function spawnDetachedDaemon(invocation, paths, subcommand, logPath) {
|
|
6031
|
-
fs7.mkdirSync(
|
|
6087
|
+
fs7.mkdirSync(path21.dirname(logPath), { recursive: true });
|
|
6032
6088
|
const logFd = fs7.openSync(logPath, "a");
|
|
6033
6089
|
try {
|
|
6034
6090
|
const child = spawn(invocation.command, invocation.args, detachedDaemonSpawnOptions(logFd, { ...process.env, AGENT_SHIM_HOME: paths.root }));
|
|
@@ -6044,6 +6100,29 @@ function spawnDetachedDaemon(invocation, paths, subcommand, logPath) {
|
|
|
6044
6100
|
function spawnHeadroomSupervisor(paths, spawnDaemon) {
|
|
6045
6101
|
return spawnDaemon(paths, "__headroom-supervisor", paths.headroomLogPath);
|
|
6046
6102
|
}
|
|
6103
|
+
var SOCKET_PERMISSION_BITS = 511;
|
|
6104
|
+
var realHeadroomSocketTrust = {
|
|
6105
|
+
platform: process.platform,
|
|
6106
|
+
currentUid: () => {
|
|
6107
|
+
if (process.getuid === void 0) {
|
|
6108
|
+
throw new Error(`no POSIX user id on ${process.platform}`);
|
|
6109
|
+
}
|
|
6110
|
+
return process.getuid();
|
|
6111
|
+
},
|
|
6112
|
+
lstat: (target) => {
|
|
6113
|
+
let stat;
|
|
6114
|
+
try {
|
|
6115
|
+
stat = fs7.lstatSync(target);
|
|
6116
|
+
} catch (error) {
|
|
6117
|
+
if (isEnoent3(error)) {
|
|
6118
|
+
return void 0;
|
|
6119
|
+
}
|
|
6120
|
+
throw error;
|
|
6121
|
+
}
|
|
6122
|
+
const kind = stat.isSymbolicLink() ? "symlink" : stat.isDirectory() ? "dir" : stat.isSocket() ? "socket" : "other";
|
|
6123
|
+
return { kind, uid: stat.uid, mode: stat.mode & SOCKET_PERMISSION_BITS };
|
|
6124
|
+
}
|
|
6125
|
+
};
|
|
6047
6126
|
function realHeadroomPort(paths, options) {
|
|
6048
6127
|
return {
|
|
6049
6128
|
ensure: () => {
|
|
@@ -6060,7 +6139,7 @@ function realHeadroomPort(paths, options) {
|
|
|
6060
6139
|
}
|
|
6061
6140
|
});
|
|
6062
6141
|
return {
|
|
6063
|
-
|
|
6142
|
+
socketPath: up.socketPath,
|
|
6064
6143
|
projectId: resolveGitRoot(realRunPort, options.cwd) ?? options.cwd
|
|
6065
6144
|
};
|
|
6066
6145
|
},
|
|
@@ -6086,7 +6165,7 @@ function listVersionsDir(dir) {
|
|
|
6086
6165
|
throw error;
|
|
6087
6166
|
}
|
|
6088
6167
|
return entries.filter((entry) => entry.isFile()).map((entry) => {
|
|
6089
|
-
const fullPath =
|
|
6168
|
+
const fullPath = path21.join(dir, entry.name);
|
|
6090
6169
|
const stat = fs7.statSync(fullPath);
|
|
6091
6170
|
return {
|
|
6092
6171
|
name: entry.name,
|
|
@@ -6101,7 +6180,7 @@ function windowsPathExtensions(pathext) {
|
|
|
6101
6180
|
return (pathext ?? WINDOWS_DEFAULT_PATHEXT).split(";").map((ext) => ext.trim()).filter((ext) => ext.length > 0);
|
|
6102
6181
|
}
|
|
6103
6182
|
function resolveExecutableCandidate(dir, name, env) {
|
|
6104
|
-
const candidate =
|
|
6183
|
+
const candidate = path21.join(dir, name);
|
|
6105
6184
|
if (env.platform === "win32") {
|
|
6106
6185
|
const extensions = windowsPathExtensions(env.pathext);
|
|
6107
6186
|
const alreadyHasRecognisedExtension = extensions.some((ext) => candidate.toLowerCase().endsWith(ext.toLowerCase()));
|
|
@@ -6150,13 +6229,13 @@ function resolveOwnExecutablePath(env) {
|
|
|
6150
6229
|
if (env.argv1 !== void 0 && !env.argv1.includes("/") && !env.argv1.includes("\\")) {
|
|
6151
6230
|
return searchPathForExecutable(env.pathDirs, env.argv1, env.findExecutableInDir) ?? env.execPath;
|
|
6152
6231
|
}
|
|
6153
|
-
const candidate = env.argv1 === void 0 ? env.execPath :
|
|
6154
|
-
const candidateDir =
|
|
6155
|
-
const candidateDirOnPath = env.pathDirs.some((dir) =>
|
|
6232
|
+
const candidate = env.argv1 === void 0 ? env.execPath : path21.resolve(env.cwd, env.argv1);
|
|
6233
|
+
const candidateDir = path21.dirname(candidate);
|
|
6234
|
+
const candidateDirOnPath = env.pathDirs.some((dir) => path21.resolve(dir) === candidateDir);
|
|
6156
6235
|
if (candidateDirOnPath) {
|
|
6157
6236
|
return candidate;
|
|
6158
6237
|
}
|
|
6159
|
-
const viaPath = searchPathForExecutable(env.pathDirs,
|
|
6238
|
+
const viaPath = searchPathForExecutable(env.pathDirs, path21.basename(candidate), env.findExecutableInDir);
|
|
6160
6239
|
return viaPath ?? candidate;
|
|
6161
6240
|
}
|
|
6162
6241
|
function realOwnExecutablePath() {
|
|
@@ -6164,21 +6243,21 @@ function realOwnExecutablePath() {
|
|
|
6164
6243
|
argv1: process.argv[1],
|
|
6165
6244
|
execPath: process.execPath,
|
|
6166
6245
|
cwd: process.cwd(),
|
|
6167
|
-
pathDirs: (process.env.PATH ?? "").split(
|
|
6246
|
+
pathDirs: (process.env.PATH ?? "").split(path21.delimiter).filter((dir) => dir !== ""),
|
|
6168
6247
|
findExecutableInDir
|
|
6169
6248
|
});
|
|
6170
6249
|
}
|
|
6171
6250
|
function realResolveClaudeBinary(ownInstallDirs) {
|
|
6172
6251
|
return () => discoverClaudeBinary({
|
|
6173
6252
|
listVersionsDir,
|
|
6174
|
-
pathDirs: (process.env.PATH ?? "").split(
|
|
6253
|
+
pathDirs: (process.env.PATH ?? "").split(path21.delimiter).filter((dir) => dir !== ""),
|
|
6175
6254
|
findExecutableInDir,
|
|
6176
6255
|
ownInstallDirs: [...ownInstallDirs]
|
|
6177
6256
|
});
|
|
6178
6257
|
}
|
|
6179
6258
|
|
|
6180
6259
|
// src/checkReport.ts
|
|
6181
|
-
import
|
|
6260
|
+
import path22 from "node:path";
|
|
6182
6261
|
import { z as z10 } from "zod";
|
|
6183
6262
|
|
|
6184
6263
|
// src/cli/bool.ts
|
|
@@ -6546,10 +6625,10 @@ function collectCheckReport(params) {
|
|
|
6546
6625
|
}).input;
|
|
6547
6626
|
const providerName = cascadeProviderName(cascade);
|
|
6548
6627
|
const provider = providerName === void 0 ? void 0 : loadCheckProvider(paths, providerName);
|
|
6549
|
-
const farmRoot = identityDecision.name === void 0 ? void 0 :
|
|
6628
|
+
const farmRoot = identityDecision.name === void 0 ? void 0 : path22.join(paths.identitiesDir, identityDecision.name);
|
|
6550
6629
|
const settingsFiles = {
|
|
6551
|
-
"settings.json": realFsPort.readFileUtf8(
|
|
6552
|
-
"settings.local.json": realFsPort.readFileUtf8(
|
|
6630
|
+
"settings.json": realFsPort.readFileUtf8(path22.join(claudeHome, "settings.json")),
|
|
6631
|
+
"settings.local.json": realFsPort.readFileUtf8(path22.join(claudeHome, "settings.local.json"))
|
|
6553
6632
|
};
|
|
6554
6633
|
const report = runCheck({
|
|
6555
6634
|
cwd,
|
|
@@ -6579,7 +6658,7 @@ function collectCheckReport(params) {
|
|
|
6579
6658
|
|
|
6580
6659
|
// src/claudeShim.ts
|
|
6581
6660
|
import fs8 from "node:fs";
|
|
6582
|
-
import
|
|
6661
|
+
import path23 from "node:path";
|
|
6583
6662
|
import { z as z11 } from "zod";
|
|
6584
6663
|
var ClaudeShimStateSchema = z11.strictObject({
|
|
6585
6664
|
targetPath: z11.string().min(1),
|
|
@@ -6590,29 +6669,29 @@ function commandFilename(ownExecutablePath, commandName) {
|
|
|
6590
6669
|
return ownExecutablePath.toLowerCase().endsWith(".exe") ? `${commandName}.exe` : commandName;
|
|
6591
6670
|
}
|
|
6592
6671
|
function resolveOwnInstallDirs(paths, ownExecutablePath) {
|
|
6593
|
-
const dirs = [
|
|
6672
|
+
const dirs = [path23.dirname(ownExecutablePath)];
|
|
6594
6673
|
const state = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
|
|
6595
6674
|
if (state !== void 0) {
|
|
6596
|
-
dirs.push(
|
|
6675
|
+
dirs.push(path23.dirname(state.targetPath));
|
|
6597
6676
|
}
|
|
6598
6677
|
return dirs;
|
|
6599
6678
|
}
|
|
6600
6679
|
var nodeLinkFs = { link: fs8.linkSync, copyFile: fs8.copyFileSync, chmod: fs8.chmodSync };
|
|
6601
6680
|
function findPathShadow(params) {
|
|
6602
|
-
const resolvedTargetDir =
|
|
6681
|
+
const resolvedTargetDir = path23.resolve(params.targetDir);
|
|
6603
6682
|
for (const dir of params.pathDirs) {
|
|
6604
6683
|
const found = params.findExecutableInDir(dir, params.targetFilename);
|
|
6605
6684
|
if (found === void 0) {
|
|
6606
6685
|
continue;
|
|
6607
6686
|
}
|
|
6608
|
-
return
|
|
6687
|
+
return path23.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
|
|
6609
6688
|
}
|
|
6610
|
-
return params.pathDirs.some((dir) =>
|
|
6689
|
+
return params.pathDirs.some((dir) => path23.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
|
|
6611
6690
|
}
|
|
6612
6691
|
|
|
6613
6692
|
// src/doctorReport.ts
|
|
6614
6693
|
import fs9 from "node:fs";
|
|
6615
|
-
import
|
|
6694
|
+
import path24 from "node:path";
|
|
6616
6695
|
function refinePathShadow(status, ownExecutablePath, realpath) {
|
|
6617
6696
|
if (status.status !== "shadowed") {
|
|
6618
6697
|
return status;
|
|
@@ -6636,7 +6715,7 @@ function validateJson(schema, input) {
|
|
|
6636
6715
|
return { ok: true, data: result.data };
|
|
6637
6716
|
}
|
|
6638
6717
|
function pushPathResolution(push, resolution) {
|
|
6639
|
-
const ownDir =
|
|
6718
|
+
const ownDir = path24.dirname(resolution.ownExecutablePath);
|
|
6640
6719
|
switch (resolution.agentShim.status) {
|
|
6641
6720
|
case "ok":
|
|
6642
6721
|
push("path-resolution", "pass", `\`agent-shim\` on PATH resolves to this running executable, ${resolution.ownExecutablePath}.`, "agent-shim");
|
|
@@ -6704,14 +6783,14 @@ function pushProvider(push, entry) {
|
|
|
6704
6783
|
}
|
|
6705
6784
|
function pushLegacyName(push, params) {
|
|
6706
6785
|
const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
|
|
6707
|
-
if (legacyVariables.length === 0 &&
|
|
6786
|
+
if (legacyVariables.length === 0 && path24.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
|
|
6708
6787
|
push("legacy-name", "pass", "Nothing here still uses the former `claude-use` name.");
|
|
6709
6788
|
return;
|
|
6710
6789
|
}
|
|
6711
6790
|
for (const name of legacyVariables) {
|
|
6712
6791
|
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);
|
|
6713
6792
|
}
|
|
6714
|
-
if (
|
|
6793
|
+
if (path24.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
|
|
6715
6794
|
push(
|
|
6716
6795
|
"legacy-name",
|
|
6717
6796
|
"warn",
|
|
@@ -6901,7 +6980,7 @@ function runDoctor(params) {
|
|
|
6901
6980
|
"warn",
|
|
6902
6981
|
`Headroom state names supervisor pid ${String(state.supervisorPid)}, which is not running; the next launch through headroom will start a replacement.`
|
|
6903
6982
|
);
|
|
6904
|
-
} else if (state.headroomPid === void 0 || state.
|
|
6983
|
+
} else if (state.headroomPid === void 0 || state.socketPath === void 0) {
|
|
6905
6984
|
push(
|
|
6906
6985
|
"headroom",
|
|
6907
6986
|
"warn",
|
|
@@ -6917,7 +6996,7 @@ function runDoctor(params) {
|
|
|
6917
6996
|
push(
|
|
6918
6997
|
"headroom",
|
|
6919
6998
|
"pass",
|
|
6920
|
-
`Headroom daemon is up on
|
|
6999
|
+
`Headroom daemon is up on unix socket ${state.socketPath} (supervisor ${String(state.supervisorPid)}, daemon ${String(state.headroomPid)}).`
|
|
6921
7000
|
);
|
|
6922
7001
|
}
|
|
6923
7002
|
if (state.lastError !== void 0 && supervisorAlive) {
|
|
@@ -7019,18 +7098,18 @@ function collectDoctorReport(params) {
|
|
|
7019
7098
|
const { paths } = params;
|
|
7020
7099
|
const identityNames = fs9.existsSync(paths.identitiesDir) ? fs9.readdirSync(paths.identitiesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && isIdentityDirectoryName(entry.name)).map((entry) => entry.name).sort() : [];
|
|
7021
7100
|
const identities = identityNames.map((name) => {
|
|
7022
|
-
const farmRoot =
|
|
7023
|
-
const identityPath =
|
|
7101
|
+
const farmRoot = path24.join(paths.identitiesDir, name);
|
|
7102
|
+
const identityPath = path24.join(farmRoot, "identity.json");
|
|
7024
7103
|
return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot };
|
|
7025
7104
|
});
|
|
7026
7105
|
const profileNames = fs9.existsSync(paths.configProfilesDir) ? fs9.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
|
|
7027
7106
|
const configProfiles = profileNames.map((name) => {
|
|
7028
|
-
const profilePath =
|
|
7107
|
+
const profilePath = path24.join(paths.configProfilesDir, `${name}.json`);
|
|
7029
7108
|
return { name, path: profilePath, raw: realFsPort.readFileUtf8(profilePath) };
|
|
7030
7109
|
});
|
|
7031
7110
|
const providerNames = fs9.existsSync(paths.providersDir) ? fs9.readdirSync(paths.providersDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
|
|
7032
7111
|
const providers = providerNames.map((name) => {
|
|
7033
|
-
const providerPath =
|
|
7112
|
+
const providerPath = path24.join(paths.providersDir, `${name}.json`);
|
|
7034
7113
|
return { name, path: providerPath, raw: realFsPort.readFileUtf8(providerPath) };
|
|
7035
7114
|
});
|
|
7036
7115
|
const ownExecutablePath = realOwnExecutablePath();
|
|
@@ -7042,12 +7121,12 @@ function collectDoctorReport(params) {
|
|
|
7042
7121
|
binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
7043
7122
|
}
|
|
7044
7123
|
const shimState = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
|
|
7045
|
-
const pathDirs = (params.env.PATH ?? "").split(
|
|
7124
|
+
const pathDirs = (params.env.PATH ?? "").split(path24.delimiter).filter((dir) => dir !== "");
|
|
7046
7125
|
const claudeShimShadow = shimState === void 0 ? void 0 : refinePathShadow(
|
|
7047
7126
|
findPathShadow({
|
|
7048
7127
|
pathDirs,
|
|
7049
|
-
targetDir:
|
|
7050
|
-
targetFilename:
|
|
7128
|
+
targetDir: path24.dirname(shimState.targetPath),
|
|
7129
|
+
targetFilename: path24.basename(shimState.targetPath),
|
|
7051
7130
|
findExecutableInDir
|
|
7052
7131
|
}),
|
|
7053
7132
|
shimState.targetPath,
|
|
@@ -7070,7 +7149,7 @@ function collectDoctorReport(params) {
|
|
|
7070
7149
|
agentShim: refinePathShadow(
|
|
7071
7150
|
findPathShadow({
|
|
7072
7151
|
pathDirs,
|
|
7073
|
-
targetDir:
|
|
7152
|
+
targetDir: path24.dirname(ownExecutablePath),
|
|
7074
7153
|
targetFilename: commandFilename(ownExecutablePath, "agent-shim"),
|
|
7075
7154
|
findExecutableInDir
|
|
7076
7155
|
}),
|
|
@@ -7091,7 +7170,7 @@ function collectDoctorReport(params) {
|
|
|
7091
7170
|
|
|
7092
7171
|
// src/launcher.ts
|
|
7093
7172
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
7094
|
-
import
|
|
7173
|
+
import path26 from "node:path";
|
|
7095
7174
|
|
|
7096
7175
|
// src/launcher/argv.ts
|
|
7097
7176
|
var ConflictingIdentityError = class extends UsageError {
|
|
@@ -7343,7 +7422,7 @@ function buildCliOverride(params) {
|
|
|
7343
7422
|
}
|
|
7344
7423
|
|
|
7345
7424
|
// src/launcher/flags.ts
|
|
7346
|
-
import
|
|
7425
|
+
import path25 from "node:path";
|
|
7347
7426
|
|
|
7348
7427
|
// src/headroom/headers.ts
|
|
7349
7428
|
function mergeAnthropicCustomHeaders(existing, additions) {
|
|
@@ -7413,7 +7492,7 @@ function buildEnv(params) {
|
|
|
7413
7492
|
const parentCustomHeaders = params.baseEnv.ANTHROPIC_CUSTOM_HEADERS;
|
|
7414
7493
|
let providerCustomHeaders;
|
|
7415
7494
|
if (!params.configDirEscapeHatch && params.resolvedIdentityName !== void 0) {
|
|
7416
|
-
env.CLAUDE_CONFIG_DIR =
|
|
7495
|
+
env.CLAUDE_CONFIG_DIR = path25.join(params.identitiesDir, params.resolvedIdentityName);
|
|
7417
7496
|
}
|
|
7418
7497
|
if (params.provider !== void 0) {
|
|
7419
7498
|
const providerEnv = params.provider.definition.env ?? {};
|
|
@@ -7434,9 +7513,6 @@ function buildEnv(params) {
|
|
|
7434
7513
|
env[variable] = value;
|
|
7435
7514
|
}
|
|
7436
7515
|
}
|
|
7437
|
-
if (params.headroom !== void 0) {
|
|
7438
|
-
env.HEADROOM_PROXY_URL = `http://127.0.0.1:${String(params.headroom.port)}`;
|
|
7439
|
-
}
|
|
7440
7516
|
if (params.frontdoor !== void 0) {
|
|
7441
7517
|
env.ANTHROPIC_CUSTOM_HEADERS = mergeAnthropicCustomHeaders(
|
|
7442
7518
|
[
|
|
@@ -7577,7 +7653,7 @@ function prepareLaunch(params) {
|
|
|
7577
7653
|
identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
|
|
7578
7654
|
globalDefaultConfigProfile: params.globalDefaultConfigProfile
|
|
7579
7655
|
});
|
|
7580
|
-
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(
|
|
7656
|
+
if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(path26.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
|
|
7581
7657
|
log.error(
|
|
7582
7658
|
`agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
|
|
7583
7659
|
);
|
|
@@ -7713,7 +7789,7 @@ function prepareLaunch(params) {
|
|
|
7713
7789
|
if (resolvedFlags.headroom && headroomPort !== void 0) {
|
|
7714
7790
|
headroom = headroomPort.ensure();
|
|
7715
7791
|
const via = resolvedProvider === void 0 ? `OAuth via the door's CONNECT surface on 127.0.0.1:${String(frontDoor?.connectPort ?? 0)}` : `provider ${resolvedProvider.name}`;
|
|
7716
|
-
log.info(`agent-shim: routing through the front door on 127.0.0.1:${String(frontDoor?.port ?? 0)} with headroom on
|
|
7792
|
+
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})`);
|
|
7717
7793
|
} else if (resolvedFlags.headroom) {
|
|
7718
7794
|
log.error("agent-shim: headroom routing was requested but this launcher has no headroom port wired; refusing to launch without it.");
|
|
7719
7795
|
proc.exit(1);
|
|
@@ -7753,7 +7829,7 @@ import { randomUUID as randomUUID5 } from "node:crypto";
|
|
|
7753
7829
|
// src/realCredentialCache.ts
|
|
7754
7830
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
7755
7831
|
import fs10 from "node:fs";
|
|
7756
|
-
import
|
|
7832
|
+
import path27 from "node:path";
|
|
7757
7833
|
var KEYCHAIN_CACHE_SERVICE = "agent-shim-credential-cache";
|
|
7758
7834
|
var CACHE_DIR_MODE = 448;
|
|
7759
7835
|
var CACHE_FILE_MODE = 384;
|
|
@@ -7780,8 +7856,8 @@ function security(args, stdin) {
|
|
|
7780
7856
|
return { status: result.status, stdout: result.stdout };
|
|
7781
7857
|
}
|
|
7782
7858
|
function createRealCredentialCache(root) {
|
|
7783
|
-
const dir =
|
|
7784
|
-
const filePath = (owner) =>
|
|
7859
|
+
const dir = path27.join(root, "credential-cache");
|
|
7860
|
+
const filePath = (owner) => path27.join(dir, cacheFileNameFor(owner));
|
|
7785
7861
|
return {
|
|
7786
7862
|
read(store, owner) {
|
|
7787
7863
|
if (store === "file") {
|
|
@@ -7897,11 +7973,11 @@ function probeFrontDoorSync(port, caPem) {
|
|
|
7897
7973
|
|
|
7898
7974
|
// src/frontdoor/trust.ts
|
|
7899
7975
|
import { createHash as createHash5 } from "node:crypto";
|
|
7900
|
-
import
|
|
7976
|
+
import path28 from "node:path";
|
|
7901
7977
|
var BUNDLE_NAME_HEX_DIGITS = 16;
|
|
7902
7978
|
function resolveTrustBundle(params) {
|
|
7903
|
-
const { caCertFile, bundlesDir, inherited, fs: fs12 } = params;
|
|
7904
|
-
if (inherited === void 0 || inherited === "" ||
|
|
7979
|
+
const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
|
|
7980
|
+
if (inherited === void 0 || inherited === "" || path28.resolve(inherited) === path28.resolve(caCertFile)) {
|
|
7905
7981
|
return { path: caCertFile };
|
|
7906
7982
|
}
|
|
7907
7983
|
const caPem = fs12.readFileUtf8(caCertFile);
|
|
@@ -7911,7 +7987,7 @@ function resolveTrustBundle(params) {
|
|
|
7911
7987
|
} catch (error) {
|
|
7912
7988
|
return {
|
|
7913
7989
|
path: caCertFile,
|
|
7914
|
-
warning: `agent-shim:
|
|
7990
|
+
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`
|
|
7915
7991
|
};
|
|
7916
7992
|
}
|
|
7917
7993
|
if (inheritedPem.includes(caPem.trim())) {
|
|
@@ -7919,7 +7995,7 @@ function resolveTrustBundle(params) {
|
|
|
7919
7995
|
}
|
|
7920
7996
|
const combined = `${inheritedPem.trimEnd()}
|
|
7921
7997
|
${caPem}`;
|
|
7922
|
-
const bundle =
|
|
7998
|
+
const bundle = path28.join(bundlesDir, `${createHash5("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
|
|
7923
7999
|
if (!fs12.exists(bundle)) {
|
|
7924
8000
|
fs12.mkdirp(bundlesDir);
|
|
7925
8001
|
fs12.writeFileAtomic(bundle, combined);
|
|
@@ -7957,7 +8033,7 @@ function realFrontDoorPort(paths, spawnDaemon) {
|
|
|
7957
8033
|
verifyListener: (port) => probeFrontDoorSync(port, fs11.readFileSync(paths.frontdoorCaCertFile, "utf8"))
|
|
7958
8034
|
}
|
|
7959
8035
|
});
|
|
7960
|
-
const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
|
|
8036
|
+
const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, variable: "NODE_EXTRA_CA_CERTS", inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
|
|
7961
8037
|
return {
|
|
7962
8038
|
port: up.port,
|
|
7963
8039
|
connectPort: up.connectPort,
|