agent-shim 8.5.0 → 8.5.2
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 +101 -37
- package/dist/index.cjs +108 -35
- package/dist/index.mjs +107 -34
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -55107,18 +55107,14 @@ function discoverClaudeBinary(options) {
|
|
|
55107
55107
|
version: highestVersion
|
|
55108
55108
|
};
|
|
55109
55109
|
}
|
|
55110
|
-
const ownInstallDirs = new Set(options.ownInstallDirs.map((dir) => import_node_path3.default.resolve(dir)));
|
|
55111
55110
|
for (const dir of options.pathDirs) {
|
|
55112
|
-
if (ownInstallDirs.has(import_node_path3.default.resolve(dir))) {
|
|
55113
|
-
continue;
|
|
55114
|
-
}
|
|
55115
55111
|
const found = options.findExecutableInDir(dir, "claude");
|
|
55116
|
-
if (found !== void 0) {
|
|
55112
|
+
if (found !== void 0 && !options.isOwnBinary(found)) {
|
|
55117
55113
|
return { path: found, source: "path-fallback" };
|
|
55118
55114
|
}
|
|
55119
55115
|
}
|
|
55120
55116
|
throw new Error(
|
|
55121
|
-
`Could not find a claude binary. Looked for genuinely-executable versioned binaries under "${versionsDir}" (missing, empty, or containing nothing executable) and for a "claude" executable on PATH (
|
|
55117
|
+
`Could not find a claude binary. Looked for genuinely-executable versioned binaries under "${versionsDir}" (missing, empty, or containing nothing executable) and for a "claude" executable on PATH (never this tool's own binary). Install Claude Code, or set the versions directory / PATH correctly, then try again.`
|
|
55122
55118
|
);
|
|
55123
55119
|
}
|
|
55124
55120
|
|
|
@@ -55970,12 +55966,12 @@ function resolveContentSourcePath(env) {
|
|
|
55970
55966
|
function realContentSourcePath() {
|
|
55971
55967
|
return resolveContentSourcePath({ isSea: (0, import_node_sea.isSea)(), execPath: process.execPath, argv1: process.argv[1] });
|
|
55972
55968
|
}
|
|
55973
|
-
function realResolveClaudeBinary(
|
|
55969
|
+
function realResolveClaudeBinary(isOwnBinary) {
|
|
55974
55970
|
return () => discoverClaudeBinary({
|
|
55975
55971
|
listVersionsDir,
|
|
55976
55972
|
pathDirs: (process.env.PATH ?? "").split(import_node_path6.default.delimiter).filter((dir) => dir !== ""),
|
|
55977
55973
|
findExecutableInDir,
|
|
55978
|
-
|
|
55974
|
+
isOwnBinary
|
|
55979
55975
|
});
|
|
55980
55976
|
}
|
|
55981
55977
|
|
|
@@ -56017,13 +56013,19 @@ function commandFilename(ownExecutablePath, commandName) {
|
|
|
56017
56013
|
function isInvokedAsClaude(invokedName) {
|
|
56018
56014
|
return invokedName === "claude" || invokedName.toLowerCase() === "claude.exe";
|
|
56019
56015
|
}
|
|
56020
|
-
function
|
|
56021
|
-
const dirs = [import_node_path7.default.dirname(ownExecutablePath)];
|
|
56016
|
+
function resolveOwnBinaryCheck(paths, contentSourcePath) {
|
|
56022
56017
|
const state = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
|
|
56023
|
-
|
|
56024
|
-
|
|
56025
|
-
|
|
56026
|
-
|
|
56018
|
+
const recordedTarget = state === void 0 ? void 0 : import_node_path7.default.resolve(state.targetPath);
|
|
56019
|
+
let ownStat;
|
|
56020
|
+
return (candidate) => {
|
|
56021
|
+
if (recordedTarget !== void 0 && import_node_path7.default.resolve(candidate) === recordedTarget) {
|
|
56022
|
+
return true;
|
|
56023
|
+
}
|
|
56024
|
+
ownStat ??= statOrUndefined(contentSourcePath);
|
|
56025
|
+
const candidateStat = statOrUndefined(candidate);
|
|
56026
|
+
return ownStat !== void 0 && candidateStat !== void 0 && // A platform reporting no inode number for either file must not read every candidate as this tool.
|
|
56027
|
+
ownStat.ino !== 0 && candidateStat.ino !== 0 && candidateStat.dev === ownStat.dev && candidateStat.ino === ownStat.ino;
|
|
56028
|
+
};
|
|
56027
56029
|
}
|
|
56028
56030
|
function resolveClaudeTargetPath(ownExecutablePath, dir) {
|
|
56029
56031
|
return import_node_path7.default.join(dir ?? import_node_path7.default.dirname(ownExecutablePath), claudeTargetFilename(ownExecutablePath));
|
|
@@ -56044,6 +56046,16 @@ function lstatOrUndefined(target) {
|
|
|
56044
56046
|
throw error62;
|
|
56045
56047
|
}
|
|
56046
56048
|
}
|
|
56049
|
+
function statOrUndefined(target) {
|
|
56050
|
+
try {
|
|
56051
|
+
return import_node_fs4.default.statSync(target);
|
|
56052
|
+
} catch (error62) {
|
|
56053
|
+
if (isEnoent3(error62)) {
|
|
56054
|
+
return void 0;
|
|
56055
|
+
}
|
|
56056
|
+
throw error62;
|
|
56057
|
+
}
|
|
56058
|
+
}
|
|
56047
56059
|
var nodeLinkFs = { link: import_node_fs4.default.linkSync, copyFile: import_node_fs4.default.copyFileSync, chmod: import_node_fs4.default.chmodSync };
|
|
56048
56060
|
function enableClaudeShim(params, linkFs = nodeLinkFs) {
|
|
56049
56061
|
const realContentPath = import_node_fs4.default.realpathSync(params.contentSourcePath);
|
|
@@ -61040,7 +61052,7 @@ function registerIdentityCommand(program2, deps) {
|
|
|
61040
61052
|
// package.json
|
|
61041
61053
|
var package_default = {
|
|
61042
61054
|
name: "agent-shim",
|
|
61043
|
-
version: "8.5.
|
|
61055
|
+
version: "8.5.2",
|
|
61044
61056
|
description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
|
|
61045
61057
|
license: "MIT",
|
|
61046
61058
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -64924,13 +64936,14 @@ function realConnectCertStore(paths) {
|
|
|
64924
64936
|
}
|
|
64925
64937
|
|
|
64926
64938
|
// src/frontdoor/connectEffects.ts
|
|
64927
|
-
var
|
|
64939
|
+
var import_node_dns = __toESM(require("node:dns"), 1);
|
|
64928
64940
|
var http = __toESM(require("node:http"), 1);
|
|
64929
64941
|
var https = __toESM(require("node:https"), 1);
|
|
64930
64942
|
var net2 = __toESM(require("node:net"), 1);
|
|
64931
64943
|
var tls = __toESM(require("node:tls"), 1);
|
|
64932
64944
|
var UPSTREAM_LOCAL_PORT_START = 47900;
|
|
64933
64945
|
var UPSTREAM_LOCAL_PORT_END = 47919;
|
|
64946
|
+
var UPSTREAM_LOCAL_PORT_COUNT = UPSTREAM_LOCAL_PORT_END - UPSTREAM_LOCAL_PORT_START + 1;
|
|
64934
64947
|
var nextUpstreamLocalPort = UPSTREAM_LOCAL_PORT_START;
|
|
64935
64948
|
function upstreamLocalPort() {
|
|
64936
64949
|
const port = nextUpstreamLocalPort;
|
|
@@ -64942,42 +64955,93 @@ var realAddressLookup = (host, _options, callback) => {
|
|
|
64942
64955
|
callback(null, [{ address: host, family: net2.isIP(host) }]);
|
|
64943
64956
|
return;
|
|
64944
64957
|
}
|
|
64945
|
-
|
|
64958
|
+
import_node_dns.default.resolve4(host, (error62, addresses) => {
|
|
64959
|
+
if (error62 !== null) {
|
|
64960
|
+
callback(error62, [{ address: "", family: 4 }]);
|
|
64961
|
+
return;
|
|
64962
|
+
}
|
|
64946
64963
|
const first = addresses[0];
|
|
64947
|
-
if (
|
|
64948
|
-
callback(
|
|
64964
|
+
if (first === void 0) {
|
|
64965
|
+
callback(new Error(`no A record for ${host}`), [{ address: "", family: 4 }]);
|
|
64949
64966
|
return;
|
|
64950
64967
|
}
|
|
64951
64968
|
callback(null, [{ address: first, family: 4 }]);
|
|
64952
64969
|
});
|
|
64953
64970
|
};
|
|
64954
64971
|
var HTTP_PORT = 80;
|
|
64955
|
-
|
|
64956
|
-
|
|
64957
|
-
|
|
64958
|
-
|
|
64972
|
+
var HELD_PORT_ERRNOS = /* @__PURE__ */ new Set(["EADDRINUSE", "EADDRNOTAVAIL"]);
|
|
64973
|
+
async function dialOnce(connectOptions) {
|
|
64974
|
+
return await new Promise((resolve) => {
|
|
64975
|
+
const socket = net2.connect(connectOptions);
|
|
64976
|
+
socket.once("connect", () => {
|
|
64977
|
+
resolve({ error: null, socket });
|
|
64978
|
+
});
|
|
64979
|
+
socket.once("error", (error62) => {
|
|
64980
|
+
resolve({ error: error62, socket });
|
|
64981
|
+
});
|
|
64982
|
+
});
|
|
64983
|
+
}
|
|
64984
|
+
function dialTarget(options, defaultPort) {
|
|
64985
|
+
return { host: typeof options.host === "string" ? options.host : "", port: typeof options.port === "number" ? options.port : defaultPort };
|
|
64986
|
+
}
|
|
64987
|
+
function literalDial(target) {
|
|
64988
|
+
return net2.connect({ host: target.host, port: target.port });
|
|
64989
|
+
}
|
|
64990
|
+
async function reservedDial(target) {
|
|
64991
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
64992
|
+
const outcome = await dialOnce({ host: target.host, port: target.port, localPort: upstreamLocalPort(), lookup: realAddressLookup });
|
|
64993
|
+
if (outcome.error === null) {
|
|
64994
|
+
return outcome;
|
|
64995
|
+
}
|
|
64996
|
+
const held = outcome.error.code !== void 0 && HELD_PORT_ERRNOS.has(outcome.error.code);
|
|
64997
|
+
if (!held || attempt === UPSTREAM_LOCAL_PORT_COUNT - 1) {
|
|
64998
|
+
return outcome;
|
|
64999
|
+
}
|
|
65000
|
+
}
|
|
64959
65001
|
}
|
|
64960
65002
|
function requestServername(options, fallback) {
|
|
64961
65003
|
return "servername" in options && typeof options.servername === "string" && options.servername !== "" ? options.servername : fallback;
|
|
64962
65004
|
}
|
|
64963
65005
|
var ExemptHttpAgent = class extends http.Agent {
|
|
64964
|
-
createConnection
|
|
64965
|
-
|
|
65006
|
+
// A reserved-port dial that has to retry cannot produce its socket synchronously, so it settles first and arrives through the callback (node's documented asynchronous createConnection form); a literal dial has nothing to retry and keeps node's own synchronous shape.
|
|
65007
|
+
createConnection(options, oncreate) {
|
|
65008
|
+
const target = dialTarget(options, HTTP_PORT);
|
|
65009
|
+
if (net2.isIP(target.host) !== 0) {
|
|
65010
|
+
return literalDial(target);
|
|
65011
|
+
}
|
|
65012
|
+
void reservedDial(target).then((outcome) => {
|
|
65013
|
+
oncreate?.(outcome.error, outcome.socket);
|
|
65014
|
+
});
|
|
65015
|
+
return void 0;
|
|
64966
65016
|
}
|
|
64967
65017
|
};
|
|
64968
65018
|
var ExemptTlsAgent = class extends https.Agent {
|
|
64969
|
-
|
|
64970
|
-
|
|
64971
|
-
const
|
|
64972
|
-
if (
|
|
64973
|
-
|
|
64974
|
-
}
|
|
64975
|
-
|
|
64976
|
-
|
|
64977
|
-
|
|
64978
|
-
|
|
65019
|
+
// The same split as the plain sibling: a literal dial wraps TLS around the socket node's own agent would have returned, a reserved dial settles (retries included) first and arrives through the callback, which is exactly where node's own agent wraps its own dials.
|
|
65020
|
+
createConnection(options, oncreate) {
|
|
65021
|
+
const target = dialTarget(options, HTTPS_PORT);
|
|
65022
|
+
if (net2.isIP(target.host) !== 0) {
|
|
65023
|
+
return tls.connect({ socket: literalDial(target), servername: requestServername(options, target.host), ...tlsFacts(options) });
|
|
65024
|
+
}
|
|
65025
|
+
void reservedDial(target).then((outcome) => {
|
|
65026
|
+
if (outcome.error !== null) {
|
|
65027
|
+
oncreate?.(outcome.error, outcome.socket);
|
|
65028
|
+
return;
|
|
65029
|
+
}
|
|
65030
|
+
oncreate?.(null, tls.connect({ socket: outcome.socket, servername: requestServername(options, target.host), ...tlsFacts(options) }));
|
|
65031
|
+
});
|
|
65032
|
+
return void 0;
|
|
64979
65033
|
}
|
|
64980
65034
|
};
|
|
65035
|
+
function tlsFacts(options) {
|
|
65036
|
+
const facts = {};
|
|
65037
|
+
if ("ca" in options && Array.isArray(options.ca)) {
|
|
65038
|
+
facts.ca = options.ca;
|
|
65039
|
+
}
|
|
65040
|
+
if ("rejectUnauthorized" in options && typeof options.rejectUnauthorized === "boolean") {
|
|
65041
|
+
facts.rejectUnauthorized = options.rejectUnauthorized;
|
|
65042
|
+
}
|
|
65043
|
+
return facts;
|
|
65044
|
+
}
|
|
64981
65045
|
function realRcEventDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
64982
65046
|
const agent = new ExemptTlsAgent();
|
|
64983
65047
|
return {
|
|
@@ -68982,7 +69046,7 @@ function collectDoctorReport(params) {
|
|
|
68982
69046
|
const ownExecutablePath = realOwnExecutablePath();
|
|
68983
69047
|
let binaryDiscovery;
|
|
68984
69048
|
try {
|
|
68985
|
-
const binary = realResolveClaudeBinary(
|
|
69049
|
+
const binary = realResolveClaudeBinary(resolveOwnBinaryCheck(paths, realContentSourcePath()))();
|
|
68986
69050
|
binaryDiscovery = { ok: true, binary };
|
|
68987
69051
|
} catch (error62) {
|
|
68988
69052
|
binaryDiscovery = { ok: false, message: error62 instanceof Error ? error62.message : String(error62) };
|
|
@@ -71062,7 +71126,7 @@ function realPrepareLaunchParams(paths, options) {
|
|
|
71062
71126
|
fs: realFsPort,
|
|
71063
71127
|
proc: options.proc,
|
|
71064
71128
|
log: options.log,
|
|
71065
|
-
resolveClaudeBinary: realResolveClaudeBinary(
|
|
71129
|
+
resolveClaudeBinary: realResolveClaudeBinary(resolveOwnBinaryCheck(paths, realContentSourcePath())),
|
|
71066
71130
|
farm: farm.runtime,
|
|
71067
71131
|
headroom: realHeadroomPort(paths, { spawnDaemon: options.spawnDaemon, cwd: farm.runtime.cwd }),
|
|
71068
71132
|
frontdoor: realFrontDoorPort(paths, options.spawnDaemon),
|
package/dist/index.cjs
CHANGED
|
@@ -3248,13 +3248,14 @@ function realConnectCertStore(paths) {
|
|
|
3248
3248
|
}
|
|
3249
3249
|
|
|
3250
3250
|
// src/frontdoor/connectEffects.ts
|
|
3251
|
-
var
|
|
3251
|
+
var import_node_dns = __toESM(require("node:dns"), 1);
|
|
3252
3252
|
var http = __toESM(require("node:http"), 1);
|
|
3253
3253
|
var https = __toESM(require("node:https"), 1);
|
|
3254
3254
|
var net2 = __toESM(require("node:net"), 1);
|
|
3255
3255
|
var tls = __toESM(require("node:tls"), 1);
|
|
3256
3256
|
var UPSTREAM_LOCAL_PORT_START = 47900;
|
|
3257
3257
|
var UPSTREAM_LOCAL_PORT_END = 47919;
|
|
3258
|
+
var UPSTREAM_LOCAL_PORT_COUNT = UPSTREAM_LOCAL_PORT_END - UPSTREAM_LOCAL_PORT_START + 1;
|
|
3258
3259
|
var nextUpstreamLocalPort = UPSTREAM_LOCAL_PORT_START;
|
|
3259
3260
|
function upstreamLocalPort() {
|
|
3260
3261
|
const port = nextUpstreamLocalPort;
|
|
@@ -3266,42 +3267,93 @@ var realAddressLookup = (host, _options, callback) => {
|
|
|
3266
3267
|
callback(null, [{ address: host, family: net2.isIP(host) }]);
|
|
3267
3268
|
return;
|
|
3268
3269
|
}
|
|
3269
|
-
|
|
3270
|
+
import_node_dns.default.resolve4(host, (error, addresses) => {
|
|
3271
|
+
if (error !== null) {
|
|
3272
|
+
callback(error, [{ address: "", family: 4 }]);
|
|
3273
|
+
return;
|
|
3274
|
+
}
|
|
3270
3275
|
const first = addresses[0];
|
|
3271
|
-
if (
|
|
3272
|
-
callback(
|
|
3276
|
+
if (first === void 0) {
|
|
3277
|
+
callback(new Error(`no A record for ${host}`), [{ address: "", family: 4 }]);
|
|
3273
3278
|
return;
|
|
3274
3279
|
}
|
|
3275
3280
|
callback(null, [{ address: first, family: 4 }]);
|
|
3276
3281
|
});
|
|
3277
3282
|
};
|
|
3278
3283
|
var HTTP_PORT = 80;
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3284
|
+
var HELD_PORT_ERRNOS = /* @__PURE__ */ new Set(["EADDRINUSE", "EADDRNOTAVAIL"]);
|
|
3285
|
+
async function dialOnce(connectOptions) {
|
|
3286
|
+
return await new Promise((resolve) => {
|
|
3287
|
+
const socket = net2.connect(connectOptions);
|
|
3288
|
+
socket.once("connect", () => {
|
|
3289
|
+
resolve({ error: null, socket });
|
|
3290
|
+
});
|
|
3291
|
+
socket.once("error", (error) => {
|
|
3292
|
+
resolve({ error, socket });
|
|
3293
|
+
});
|
|
3294
|
+
});
|
|
3295
|
+
}
|
|
3296
|
+
function dialTarget(options, defaultPort) {
|
|
3297
|
+
return { host: typeof options.host === "string" ? options.host : "", port: typeof options.port === "number" ? options.port : defaultPort };
|
|
3298
|
+
}
|
|
3299
|
+
function literalDial(target) {
|
|
3300
|
+
return net2.connect({ host: target.host, port: target.port });
|
|
3301
|
+
}
|
|
3302
|
+
async function reservedDial(target) {
|
|
3303
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
3304
|
+
const outcome = await dialOnce({ host: target.host, port: target.port, localPort: upstreamLocalPort(), lookup: realAddressLookup });
|
|
3305
|
+
if (outcome.error === null) {
|
|
3306
|
+
return outcome;
|
|
3307
|
+
}
|
|
3308
|
+
const held = outcome.error.code !== void 0 && HELD_PORT_ERRNOS.has(outcome.error.code);
|
|
3309
|
+
if (!held || attempt === UPSTREAM_LOCAL_PORT_COUNT - 1) {
|
|
3310
|
+
return outcome;
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3283
3313
|
}
|
|
3284
3314
|
function requestServername(options, fallback) {
|
|
3285
3315
|
return "servername" in options && typeof options.servername === "string" && options.servername !== "" ? options.servername : fallback;
|
|
3286
3316
|
}
|
|
3287
3317
|
var ExemptHttpAgent = class extends http.Agent {
|
|
3288
|
-
createConnection
|
|
3289
|
-
|
|
3318
|
+
// A reserved-port dial that has to retry cannot produce its socket synchronously, so it settles first and arrives through the callback (node's documented asynchronous createConnection form); a literal dial has nothing to retry and keeps node's own synchronous shape.
|
|
3319
|
+
createConnection(options, oncreate) {
|
|
3320
|
+
const target = dialTarget(options, HTTP_PORT);
|
|
3321
|
+
if (net2.isIP(target.host) !== 0) {
|
|
3322
|
+
return literalDial(target);
|
|
3323
|
+
}
|
|
3324
|
+
void reservedDial(target).then((outcome) => {
|
|
3325
|
+
oncreate?.(outcome.error, outcome.socket);
|
|
3326
|
+
});
|
|
3327
|
+
return void 0;
|
|
3290
3328
|
}
|
|
3291
3329
|
};
|
|
3292
3330
|
var ExemptTlsAgent = class extends https.Agent {
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
const
|
|
3296
|
-
if (
|
|
3297
|
-
|
|
3298
|
-
}
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3331
|
+
// The same split as the plain sibling: a literal dial wraps TLS around the socket node's own agent would have returned, a reserved dial settles (retries included) first and arrives through the callback, which is exactly where node's own agent wraps its own dials.
|
|
3332
|
+
createConnection(options, oncreate) {
|
|
3333
|
+
const target = dialTarget(options, HTTPS_PORT);
|
|
3334
|
+
if (net2.isIP(target.host) !== 0) {
|
|
3335
|
+
return tls.connect({ socket: literalDial(target), servername: requestServername(options, target.host), ...tlsFacts(options) });
|
|
3336
|
+
}
|
|
3337
|
+
void reservedDial(target).then((outcome) => {
|
|
3338
|
+
if (outcome.error !== null) {
|
|
3339
|
+
oncreate?.(outcome.error, outcome.socket);
|
|
3340
|
+
return;
|
|
3341
|
+
}
|
|
3342
|
+
oncreate?.(null, tls.connect({ socket: outcome.socket, servername: requestServername(options, target.host), ...tlsFacts(options) }));
|
|
3343
|
+
});
|
|
3344
|
+
return void 0;
|
|
3303
3345
|
}
|
|
3304
3346
|
};
|
|
3347
|
+
function tlsFacts(options) {
|
|
3348
|
+
const facts = {};
|
|
3349
|
+
if ("ca" in options && Array.isArray(options.ca)) {
|
|
3350
|
+
facts.ca = options.ca;
|
|
3351
|
+
}
|
|
3352
|
+
if ("rejectUnauthorized" in options && typeof options.rejectUnauthorized === "boolean") {
|
|
3353
|
+
facts.rejectUnauthorized = options.rejectUnauthorized;
|
|
3354
|
+
}
|
|
3355
|
+
return facts;
|
|
3356
|
+
}
|
|
3305
3357
|
function realRcEventDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
3306
3358
|
const agent = new ExemptTlsAgent();
|
|
3307
3359
|
return {
|
|
@@ -6935,18 +6987,14 @@ function discoverClaudeBinary(options) {
|
|
|
6935
6987
|
version: highestVersion
|
|
6936
6988
|
};
|
|
6937
6989
|
}
|
|
6938
|
-
const ownInstallDirs = new Set(options.ownInstallDirs.map((dir) => import_node_path20.default.resolve(dir)));
|
|
6939
6990
|
for (const dir of options.pathDirs) {
|
|
6940
|
-
if (ownInstallDirs.has(import_node_path20.default.resolve(dir))) {
|
|
6941
|
-
continue;
|
|
6942
|
-
}
|
|
6943
6991
|
const found = options.findExecutableInDir(dir, "claude");
|
|
6944
|
-
if (found !== void 0) {
|
|
6992
|
+
if (found !== void 0 && !options.isOwnBinary(found)) {
|
|
6945
6993
|
return { path: found, source: "path-fallback" };
|
|
6946
6994
|
}
|
|
6947
6995
|
}
|
|
6948
6996
|
throw new Error(
|
|
6949
|
-
`Could not find a claude binary. Looked for genuinely-executable versioned binaries under "${versionsDir}" (missing, empty, or containing nothing executable) and for a "claude" executable on PATH (
|
|
6997
|
+
`Could not find a claude binary. Looked for genuinely-executable versioned binaries under "${versionsDir}" (missing, empty, or containing nothing executable) and for a "claude" executable on PATH (never this tool's own binary). Install Claude Code, or set the versions directory / PATH correctly, then try again.`
|
|
6950
6998
|
);
|
|
6951
6999
|
}
|
|
6952
7000
|
|
|
@@ -7344,12 +7392,18 @@ function realOwnExecutablePath() {
|
|
|
7344
7392
|
findExecutableInDir
|
|
7345
7393
|
});
|
|
7346
7394
|
}
|
|
7347
|
-
function
|
|
7395
|
+
function resolveContentSourcePath(env) {
|
|
7396
|
+
return env.isSea ? env.execPath : env.argv1 ?? env.execPath;
|
|
7397
|
+
}
|
|
7398
|
+
function realContentSourcePath() {
|
|
7399
|
+
return resolveContentSourcePath({ isSea: (0, import_node_sea.isSea)(), execPath: process.execPath, argv1: process.argv[1] });
|
|
7400
|
+
}
|
|
7401
|
+
function realResolveClaudeBinary(isOwnBinary) {
|
|
7348
7402
|
return () => discoverClaudeBinary({
|
|
7349
7403
|
listVersionsDir,
|
|
7350
7404
|
pathDirs: (process.env.PATH ?? "").split(import_node_path21.default.delimiter).filter((dir) => dir !== ""),
|
|
7351
7405
|
findExecutableInDir,
|
|
7352
|
-
|
|
7406
|
+
isOwnBinary
|
|
7353
7407
|
});
|
|
7354
7408
|
}
|
|
7355
7409
|
|
|
@@ -7765,13 +7819,32 @@ var ClaudeShimStateSchema = import_zod11.z.strictObject({
|
|
|
7765
7819
|
function commandFilename(ownExecutablePath, commandName) {
|
|
7766
7820
|
return ownExecutablePath.toLowerCase().endsWith(".exe") ? `${commandName}.exe` : commandName;
|
|
7767
7821
|
}
|
|
7768
|
-
function
|
|
7769
|
-
const dirs = [import_node_path23.default.dirname(ownExecutablePath)];
|
|
7822
|
+
function resolveOwnBinaryCheck(paths, contentSourcePath) {
|
|
7770
7823
|
const state = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
|
|
7771
|
-
|
|
7772
|
-
|
|
7824
|
+
const recordedTarget = state === void 0 ? void 0 : import_node_path23.default.resolve(state.targetPath);
|
|
7825
|
+
let ownStat;
|
|
7826
|
+
return (candidate) => {
|
|
7827
|
+
if (recordedTarget !== void 0 && import_node_path23.default.resolve(candidate) === recordedTarget) {
|
|
7828
|
+
return true;
|
|
7829
|
+
}
|
|
7830
|
+
ownStat ??= statOrUndefined(contentSourcePath);
|
|
7831
|
+
const candidateStat = statOrUndefined(candidate);
|
|
7832
|
+
return ownStat !== void 0 && candidateStat !== void 0 && // A platform reporting no inode number for either file must not read every candidate as this tool.
|
|
7833
|
+
ownStat.ino !== 0 && candidateStat.ino !== 0 && candidateStat.dev === ownStat.dev && candidateStat.ino === ownStat.ino;
|
|
7834
|
+
};
|
|
7835
|
+
}
|
|
7836
|
+
function isEnoent4(error) {
|
|
7837
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
7838
|
+
}
|
|
7839
|
+
function statOrUndefined(target) {
|
|
7840
|
+
try {
|
|
7841
|
+
return import_node_fs7.default.statSync(target);
|
|
7842
|
+
} catch (error) {
|
|
7843
|
+
if (isEnoent4(error)) {
|
|
7844
|
+
return void 0;
|
|
7845
|
+
}
|
|
7846
|
+
throw error;
|
|
7773
7847
|
}
|
|
7774
|
-
return dirs;
|
|
7775
7848
|
}
|
|
7776
7849
|
var nodeLinkFs = { link: import_node_fs7.default.linkSync, copyFile: import_node_fs7.default.copyFileSync, chmod: import_node_fs7.default.chmodSync };
|
|
7777
7850
|
function findPathShadow(params) {
|
|
@@ -8212,7 +8285,7 @@ function collectDoctorReport(params) {
|
|
|
8212
8285
|
const ownExecutablePath = realOwnExecutablePath();
|
|
8213
8286
|
let binaryDiscovery;
|
|
8214
8287
|
try {
|
|
8215
|
-
const binary = realResolveClaudeBinary(
|
|
8288
|
+
const binary = realResolveClaudeBinary(resolveOwnBinaryCheck(paths, realContentSourcePath()))();
|
|
8216
8289
|
binaryDiscovery = { ok: true, binary };
|
|
8217
8290
|
} catch (error) {
|
|
8218
8291
|
binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
@@ -9188,7 +9261,7 @@ function realPrepareLaunchParams(paths, options) {
|
|
|
9188
9261
|
fs: realFsPort,
|
|
9189
9262
|
proc: options.proc,
|
|
9190
9263
|
log: options.log,
|
|
9191
|
-
resolveClaudeBinary: realResolveClaudeBinary(
|
|
9264
|
+
resolveClaudeBinary: realResolveClaudeBinary(resolveOwnBinaryCheck(paths, realContentSourcePath())),
|
|
9192
9265
|
farm: farm.runtime,
|
|
9193
9266
|
headroom: realHeadroomPort(paths, { spawnDaemon: options.spawnDaemon, cwd: farm.runtime.cwd }),
|
|
9194
9267
|
frontdoor: realFrontDoorPort(paths, options.spawnDaemon),
|
package/dist/index.mjs
CHANGED
|
@@ -3064,13 +3064,14 @@ function realConnectCertStore(paths) {
|
|
|
3064
3064
|
}
|
|
3065
3065
|
|
|
3066
3066
|
// src/frontdoor/connectEffects.ts
|
|
3067
|
-
import
|
|
3067
|
+
import dns from "node:dns";
|
|
3068
3068
|
import * as http from "node:http";
|
|
3069
3069
|
import * as https from "node:https";
|
|
3070
3070
|
import * as net2 from "node:net";
|
|
3071
3071
|
import * as tls from "node:tls";
|
|
3072
3072
|
var UPSTREAM_LOCAL_PORT_START = 47900;
|
|
3073
3073
|
var UPSTREAM_LOCAL_PORT_END = 47919;
|
|
3074
|
+
var UPSTREAM_LOCAL_PORT_COUNT = UPSTREAM_LOCAL_PORT_END - UPSTREAM_LOCAL_PORT_START + 1;
|
|
3074
3075
|
var nextUpstreamLocalPort = UPSTREAM_LOCAL_PORT_START;
|
|
3075
3076
|
function upstreamLocalPort() {
|
|
3076
3077
|
const port = nextUpstreamLocalPort;
|
|
@@ -3083,41 +3084,92 @@ var realAddressLookup = (host, _options, callback) => {
|
|
|
3083
3084
|
return;
|
|
3084
3085
|
}
|
|
3085
3086
|
dns.resolve4(host, (error, addresses) => {
|
|
3087
|
+
if (error !== null) {
|
|
3088
|
+
callback(error, [{ address: "", family: 4 }]);
|
|
3089
|
+
return;
|
|
3090
|
+
}
|
|
3086
3091
|
const first = addresses[0];
|
|
3087
|
-
if (
|
|
3088
|
-
callback(
|
|
3092
|
+
if (first === void 0) {
|
|
3093
|
+
callback(new Error(`no A record for ${host}`), [{ address: "", family: 4 }]);
|
|
3089
3094
|
return;
|
|
3090
3095
|
}
|
|
3091
3096
|
callback(null, [{ address: first, family: 4 }]);
|
|
3092
3097
|
});
|
|
3093
3098
|
};
|
|
3094
3099
|
var HTTP_PORT = 80;
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3100
|
+
var HELD_PORT_ERRNOS = /* @__PURE__ */ new Set(["EADDRINUSE", "EADDRNOTAVAIL"]);
|
|
3101
|
+
async function dialOnce(connectOptions) {
|
|
3102
|
+
return await new Promise((resolve) => {
|
|
3103
|
+
const socket = net2.connect(connectOptions);
|
|
3104
|
+
socket.once("connect", () => {
|
|
3105
|
+
resolve({ error: null, socket });
|
|
3106
|
+
});
|
|
3107
|
+
socket.once("error", (error) => {
|
|
3108
|
+
resolve({ error, socket });
|
|
3109
|
+
});
|
|
3110
|
+
});
|
|
3111
|
+
}
|
|
3112
|
+
function dialTarget(options, defaultPort) {
|
|
3113
|
+
return { host: typeof options.host === "string" ? options.host : "", port: typeof options.port === "number" ? options.port : defaultPort };
|
|
3114
|
+
}
|
|
3115
|
+
function literalDial(target) {
|
|
3116
|
+
return net2.connect({ host: target.host, port: target.port });
|
|
3117
|
+
}
|
|
3118
|
+
async function reservedDial(target) {
|
|
3119
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
3120
|
+
const outcome = await dialOnce({ host: target.host, port: target.port, localPort: upstreamLocalPort(), lookup: realAddressLookup });
|
|
3121
|
+
if (outcome.error === null) {
|
|
3122
|
+
return outcome;
|
|
3123
|
+
}
|
|
3124
|
+
const held = outcome.error.code !== void 0 && HELD_PORT_ERRNOS.has(outcome.error.code);
|
|
3125
|
+
if (!held || attempt === UPSTREAM_LOCAL_PORT_COUNT - 1) {
|
|
3126
|
+
return outcome;
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3099
3129
|
}
|
|
3100
3130
|
function requestServername(options, fallback) {
|
|
3101
3131
|
return "servername" in options && typeof options.servername === "string" && options.servername !== "" ? options.servername : fallback;
|
|
3102
3132
|
}
|
|
3103
3133
|
var ExemptHttpAgent = class extends http.Agent {
|
|
3104
|
-
createConnection
|
|
3105
|
-
|
|
3134
|
+
// A reserved-port dial that has to retry cannot produce its socket synchronously, so it settles first and arrives through the callback (node's documented asynchronous createConnection form); a literal dial has nothing to retry and keeps node's own synchronous shape.
|
|
3135
|
+
createConnection(options, oncreate) {
|
|
3136
|
+
const target = dialTarget(options, HTTP_PORT);
|
|
3137
|
+
if (net2.isIP(target.host) !== 0) {
|
|
3138
|
+
return literalDial(target);
|
|
3139
|
+
}
|
|
3140
|
+
void reservedDial(target).then((outcome) => {
|
|
3141
|
+
oncreate?.(outcome.error, outcome.socket);
|
|
3142
|
+
});
|
|
3143
|
+
return void 0;
|
|
3106
3144
|
}
|
|
3107
3145
|
};
|
|
3108
3146
|
var ExemptTlsAgent = class extends https.Agent {
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
const
|
|
3112
|
-
if (
|
|
3113
|
-
|
|
3114
|
-
}
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3147
|
+
// The same split as the plain sibling: a literal dial wraps TLS around the socket node's own agent would have returned, a reserved dial settles (retries included) first and arrives through the callback, which is exactly where node's own agent wraps its own dials.
|
|
3148
|
+
createConnection(options, oncreate) {
|
|
3149
|
+
const target = dialTarget(options, HTTPS_PORT);
|
|
3150
|
+
if (net2.isIP(target.host) !== 0) {
|
|
3151
|
+
return tls.connect({ socket: literalDial(target), servername: requestServername(options, target.host), ...tlsFacts(options) });
|
|
3152
|
+
}
|
|
3153
|
+
void reservedDial(target).then((outcome) => {
|
|
3154
|
+
if (outcome.error !== null) {
|
|
3155
|
+
oncreate?.(outcome.error, outcome.socket);
|
|
3156
|
+
return;
|
|
3157
|
+
}
|
|
3158
|
+
oncreate?.(null, tls.connect({ socket: outcome.socket, servername: requestServername(options, target.host), ...tlsFacts(options) }));
|
|
3159
|
+
});
|
|
3160
|
+
return void 0;
|
|
3119
3161
|
}
|
|
3120
3162
|
};
|
|
3163
|
+
function tlsFacts(options) {
|
|
3164
|
+
const facts = {};
|
|
3165
|
+
if ("ca" in options && Array.isArray(options.ca)) {
|
|
3166
|
+
facts.ca = options.ca;
|
|
3167
|
+
}
|
|
3168
|
+
if ("rejectUnauthorized" in options && typeof options.rejectUnauthorized === "boolean") {
|
|
3169
|
+
facts.rejectUnauthorized = options.rejectUnauthorized;
|
|
3170
|
+
}
|
|
3171
|
+
return facts;
|
|
3172
|
+
}
|
|
3121
3173
|
function realRcEventDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
3122
3174
|
const agent = new ExemptTlsAgent();
|
|
3123
3175
|
return {
|
|
@@ -6751,18 +6803,14 @@ function discoverClaudeBinary(options) {
|
|
|
6751
6803
|
version: highestVersion
|
|
6752
6804
|
};
|
|
6753
6805
|
}
|
|
6754
|
-
const ownInstallDirs = new Set(options.ownInstallDirs.map((dir) => path20.resolve(dir)));
|
|
6755
6806
|
for (const dir of options.pathDirs) {
|
|
6756
|
-
if (ownInstallDirs.has(path20.resolve(dir))) {
|
|
6757
|
-
continue;
|
|
6758
|
-
}
|
|
6759
6807
|
const found = options.findExecutableInDir(dir, "claude");
|
|
6760
|
-
if (found !== void 0) {
|
|
6808
|
+
if (found !== void 0 && !options.isOwnBinary(found)) {
|
|
6761
6809
|
return { path: found, source: "path-fallback" };
|
|
6762
6810
|
}
|
|
6763
6811
|
}
|
|
6764
6812
|
throw new Error(
|
|
6765
|
-
`Could not find a claude binary. Looked for genuinely-executable versioned binaries under "${versionsDir}" (missing, empty, or containing nothing executable) and for a "claude" executable on PATH (
|
|
6813
|
+
`Could not find a claude binary. Looked for genuinely-executable versioned binaries under "${versionsDir}" (missing, empty, or containing nothing executable) and for a "claude" executable on PATH (never this tool's own binary). Install Claude Code, or set the versions directory / PATH correctly, then try again.`
|
|
6766
6814
|
);
|
|
6767
6815
|
}
|
|
6768
6816
|
|
|
@@ -7160,12 +7208,18 @@ function realOwnExecutablePath() {
|
|
|
7160
7208
|
findExecutableInDir
|
|
7161
7209
|
});
|
|
7162
7210
|
}
|
|
7163
|
-
function
|
|
7211
|
+
function resolveContentSourcePath(env) {
|
|
7212
|
+
return env.isSea ? env.execPath : env.argv1 ?? env.execPath;
|
|
7213
|
+
}
|
|
7214
|
+
function realContentSourcePath() {
|
|
7215
|
+
return resolveContentSourcePath({ isSea: isSea(), execPath: process.execPath, argv1: process.argv[1] });
|
|
7216
|
+
}
|
|
7217
|
+
function realResolveClaudeBinary(isOwnBinary) {
|
|
7164
7218
|
return () => discoverClaudeBinary({
|
|
7165
7219
|
listVersionsDir,
|
|
7166
7220
|
pathDirs: (process.env.PATH ?? "").split(path21.delimiter).filter((dir) => dir !== ""),
|
|
7167
7221
|
findExecutableInDir,
|
|
7168
|
-
|
|
7222
|
+
isOwnBinary
|
|
7169
7223
|
});
|
|
7170
7224
|
}
|
|
7171
7225
|
|
|
@@ -7581,13 +7635,32 @@ var ClaudeShimStateSchema = z11.strictObject({
|
|
|
7581
7635
|
function commandFilename(ownExecutablePath, commandName) {
|
|
7582
7636
|
return ownExecutablePath.toLowerCase().endsWith(".exe") ? `${commandName}.exe` : commandName;
|
|
7583
7637
|
}
|
|
7584
|
-
function
|
|
7585
|
-
const dirs = [path23.dirname(ownExecutablePath)];
|
|
7638
|
+
function resolveOwnBinaryCheck(paths, contentSourcePath) {
|
|
7586
7639
|
const state = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
|
|
7587
|
-
|
|
7588
|
-
|
|
7640
|
+
const recordedTarget = state === void 0 ? void 0 : path23.resolve(state.targetPath);
|
|
7641
|
+
let ownStat;
|
|
7642
|
+
return (candidate) => {
|
|
7643
|
+
if (recordedTarget !== void 0 && path23.resolve(candidate) === recordedTarget) {
|
|
7644
|
+
return true;
|
|
7645
|
+
}
|
|
7646
|
+
ownStat ??= statOrUndefined(contentSourcePath);
|
|
7647
|
+
const candidateStat = statOrUndefined(candidate);
|
|
7648
|
+
return ownStat !== void 0 && candidateStat !== void 0 && // A platform reporting no inode number for either file must not read every candidate as this tool.
|
|
7649
|
+
ownStat.ino !== 0 && candidateStat.ino !== 0 && candidateStat.dev === ownStat.dev && candidateStat.ino === ownStat.ino;
|
|
7650
|
+
};
|
|
7651
|
+
}
|
|
7652
|
+
function isEnoent4(error) {
|
|
7653
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
7654
|
+
}
|
|
7655
|
+
function statOrUndefined(target) {
|
|
7656
|
+
try {
|
|
7657
|
+
return fs8.statSync(target);
|
|
7658
|
+
} catch (error) {
|
|
7659
|
+
if (isEnoent4(error)) {
|
|
7660
|
+
return void 0;
|
|
7661
|
+
}
|
|
7662
|
+
throw error;
|
|
7589
7663
|
}
|
|
7590
|
-
return dirs;
|
|
7591
7664
|
}
|
|
7592
7665
|
var nodeLinkFs = { link: fs8.linkSync, copyFile: fs8.copyFileSync, chmod: fs8.chmodSync };
|
|
7593
7666
|
function findPathShadow(params) {
|
|
@@ -8028,7 +8101,7 @@ function collectDoctorReport(params) {
|
|
|
8028
8101
|
const ownExecutablePath = realOwnExecutablePath();
|
|
8029
8102
|
let binaryDiscovery;
|
|
8030
8103
|
try {
|
|
8031
|
-
const binary = realResolveClaudeBinary(
|
|
8104
|
+
const binary = realResolveClaudeBinary(resolveOwnBinaryCheck(paths, realContentSourcePath()))();
|
|
8032
8105
|
binaryDiscovery = { ok: true, binary };
|
|
8033
8106
|
} catch (error) {
|
|
8034
8107
|
binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
@@ -9004,7 +9077,7 @@ function realPrepareLaunchParams(paths, options) {
|
|
|
9004
9077
|
fs: realFsPort,
|
|
9005
9078
|
proc: options.proc,
|
|
9006
9079
|
log: options.log,
|
|
9007
|
-
resolveClaudeBinary: realResolveClaudeBinary(
|
|
9080
|
+
resolveClaudeBinary: realResolveClaudeBinary(resolveOwnBinaryCheck(paths, realContentSourcePath())),
|
|
9008
9081
|
farm: farm.runtime,
|
|
9009
9082
|
headroom: realHeadroomPort(paths, { spawnDaemon: options.spawnDaemon, cwd: farm.runtime.cwd }),
|
|
9010
9083
|
frontdoor: realFrontDoorPort(paths, options.spawnDaemon),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-shim",
|
|
3
|
-
"version": "8.5.
|
|
3
|
+
"version": "8.5.2",
|
|
4
4
|
"description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Joseph Mearman <joseph@mearman.co.uk>",
|