agent-shim 7.13.2 → 7.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -15625,7 +15625,7 @@ var require_agent = __commonJS({
15625
15625
  function defaultFactory(origin, opts) {
15626
15626
  return opts && opts.connections === 1 ? new Client(origin, opts) : new Pool(origin, opts);
15627
15627
  }
15628
- var Agent7 = class extends DispatcherBase {
15628
+ var Agent5 = class extends DispatcherBase {
15629
15629
  constructor({ factory = defaultFactory, maxOrigins = Infinity, connect: connect3, ...options } = {}) {
15630
15630
  if (typeof factory !== "function") {
15631
15631
  throw new InvalidArgumentError2("factory must be a function.");
@@ -15734,7 +15734,7 @@ var require_agent = __commonJS({
15734
15734
  return allClientStats;
15735
15735
  }
15736
15736
  };
15737
- module2.exports = Agent7;
15737
+ module2.exports = Agent5;
15738
15738
  }
15739
15739
  });
15740
15740
 
@@ -16440,7 +16440,7 @@ var require_proxy_agent = __commonJS({
16440
16440
  "node_modules/.pnpm/undici@7.29.1/node_modules/undici/lib/dispatcher/proxy-agent.js"(exports2, module2) {
16441
16441
  "use strict";
16442
16442
  var { kProxy, kClose, kDestroy, kDispatch } = require_symbols();
16443
- var Agent7 = require_agent();
16443
+ var Agent5 = require_agent();
16444
16444
  var Pool = require_pool();
16445
16445
  var DispatcherBase = require_dispatcher_base();
16446
16446
  var { InvalidArgumentError: InvalidArgumentError2, RequestAbortedError, SecureProxyConnectionError } = require_errors();
@@ -16571,7 +16571,7 @@ var require_proxy_agent = __commonJS({
16571
16571
  } else {
16572
16572
  this[kClient] = clientFactory(url2, { connect: connect3 });
16573
16573
  }
16574
- this[kAgent] = new Agent7({
16574
+ this[kAgent] = new Agent5({
16575
16575
  ...opts,
16576
16576
  factory,
16577
16577
  connect: async (opts2, callback) => {
@@ -16699,7 +16699,7 @@ var require_env_http_proxy_agent = __commonJS({
16699
16699
  var DispatcherBase = require_dispatcher_base();
16700
16700
  var { kClose, kDestroy, kClosed, kDestroyed, kDispatch, kNoProxyAgent, kHttpProxyAgent, kHttpsProxyAgent } = require_symbols();
16701
16701
  var ProxyAgent = require_proxy_agent();
16702
- var Agent7 = require_agent();
16702
+ var Agent5 = require_agent();
16703
16703
  var DEFAULT_PORTS = {
16704
16704
  "http:": 80,
16705
16705
  "https:": 443
@@ -16712,7 +16712,7 @@ var require_env_http_proxy_agent = __commonJS({
16712
16712
  super();
16713
16713
  this.#opts = opts;
16714
16714
  const { httpProxy, httpsProxy, noProxy, ...agentOpts } = opts;
16715
- this[kNoProxyAgent] = new Agent7(agentOpts);
16715
+ this[kNoProxyAgent] = new Agent5(agentOpts);
16716
16716
  const HTTP_PROXY = httpProxy ?? process.env.http_proxy ?? process.env.HTTP_PROXY;
16717
16717
  if (HTTP_PROXY) {
16718
16718
  this[kHttpProxyAgent] = new ProxyAgent({ ...agentOpts, uri: HTTP_PROXY });
@@ -19410,7 +19410,7 @@ var require_mock_agent = __commonJS({
19410
19410
  "node_modules/.pnpm/undici@7.29.1/node_modules/undici/lib/mock/mock-agent.js"(exports2, module2) {
19411
19411
  "use strict";
19412
19412
  var { kClients } = require_symbols();
19413
- var Agent7 = require_agent();
19413
+ var Agent5 = require_agent();
19414
19414
  var {
19415
19415
  kAgent,
19416
19416
  kMockAgentSet,
@@ -19448,7 +19448,7 @@ var require_mock_agent = __commonJS({
19448
19448
  if (opts?.agent && typeof opts.agent.dispatch !== "function") {
19449
19449
  throw new InvalidArgumentError2("Argument opts.agent must implement Agent");
19450
19450
  }
19451
- const agent = opts?.agent ? opts.agent : new Agent7(opts);
19451
+ const agent = opts?.agent ? opts.agent : new Agent5(opts);
19452
19452
  this[kAgent] = agent;
19453
19453
  this[kClients] = agent[kClients];
19454
19454
  this[kOptions] = mockOptions;
@@ -20055,7 +20055,7 @@ var require_snapshot_recorder = __commonJS({
20055
20055
  var require_snapshot_agent = __commonJS({
20056
20056
  "node_modules/.pnpm/undici@7.29.1/node_modules/undici/lib/mock/snapshot-agent.js"(exports2, module2) {
20057
20057
  "use strict";
20058
- var Agent7 = require_agent();
20058
+ var Agent5 = require_agent();
20059
20059
  var MockAgent = require_mock_agent();
20060
20060
  var { SnapshotRecorder } = require_snapshot_recorder();
20061
20061
  var WrapHandler = require_wrap_handler();
@@ -20106,7 +20106,7 @@ var require_snapshot_agent = __commonJS({
20106
20106
  });
20107
20107
  this[kSnapshotLoaded] = false;
20108
20108
  if (this[kSnapshotMode] === "record" || this[kSnapshotMode] === "update" || this[kSnapshotMode] === "playback" && opts.excludeUrls && opts.excludeUrls.length > 0) {
20109
- this[kRealAgent] = new Agent7(opts);
20109
+ this[kRealAgent] = new Agent5(opts);
20110
20110
  }
20111
20111
  if ((this[kSnapshotMode] === "playback" || this[kSnapshotMode] === "update") && this[kSnapshotPath]) {
20112
20112
  this.loadSnapshots().catch(() => {
@@ -20345,9 +20345,9 @@ var require_global2 = __commonJS({
20345
20345
  var globalDispatcher = /* @__PURE__ */ Symbol.for("undici.globalDispatcher.2");
20346
20346
  var legacyGlobalDispatcher = /* @__PURE__ */ Symbol.for("undici.globalDispatcher.1");
20347
20347
  var { InvalidArgumentError: InvalidArgumentError2 } = require_errors();
20348
- var Agent7 = require_agent();
20348
+ var Agent5 = require_agent();
20349
20349
  if (getGlobalDispatcher() === void 0) {
20350
- setGlobalDispatcher(new Agent7());
20350
+ setGlobalDispatcher(new Agent5());
20351
20351
  }
20352
20352
  function setGlobalDispatcher(agent) {
20353
20353
  if (!agent || typeof agent.dispatch !== "function") {
@@ -20817,7 +20817,7 @@ var require_dump = __commonJS({
20817
20817
  var require_dns = __commonJS({
20818
20818
  "node_modules/.pnpm/undici@7.29.1/node_modules/undici/lib/interceptor/dns.js"(exports2, module2) {
20819
20819
  "use strict";
20820
- var { isIP } = require("node:net");
20820
+ var { isIP: isIP2 } = require("node:net");
20821
20821
  var { lookup } = require("node:dns");
20822
20822
  var DecoratorHandler = require_decorator_handler();
20823
20823
  var { InvalidArgumentError: InvalidArgumentError2, InformationalError } = require_errors();
@@ -21223,7 +21223,7 @@ var require_dns = __commonJS({
21223
21223
  return (dispatch) => {
21224
21224
  return function dnsInterceptor(origDispatchOpts, handler) {
21225
21225
  const origin = origDispatchOpts.origin.constructor === URL ? origDispatchOpts.origin : new URL(origDispatchOpts.origin);
21226
- if (isIP(origin.hostname) !== 0) {
21226
+ if (isIP2(origin.hostname) !== 0) {
21227
21227
  return dispatch(origDispatchOpts, handler);
21228
21228
  }
21229
21229
  instance.runLookup(origin, origDispatchOpts, (err, newOrigin) => {
@@ -31562,7 +31562,7 @@ var require_undici = __commonJS({
31562
31562
  var Pool = require_pool();
31563
31563
  var BalancedPool = require_balanced_pool();
31564
31564
  var RoundRobinPool = require_round_robin_pool();
31565
- var Agent7 = require_agent();
31565
+ var Agent5 = require_agent();
31566
31566
  var ProxyAgent = require_proxy_agent();
31567
31567
  var Socks5ProxyAgent = require_socks5_proxy_agent();
31568
31568
  var EnvHttpProxyAgent = require_env_http_proxy_agent();
@@ -31589,7 +31589,7 @@ var require_undici = __commonJS({
31589
31589
  module2.exports.Pool = Pool;
31590
31590
  module2.exports.BalancedPool = BalancedPool;
31591
31591
  module2.exports.RoundRobinPool = RoundRobinPool;
31592
- module2.exports.Agent = Agent7;
31592
+ module2.exports.Agent = Agent5;
31593
31593
  module2.exports.ProxyAgent = ProxyAgent;
31594
31594
  module2.exports.Socks5ProxyAgent = Socks5ProxyAgent;
31595
31595
  module2.exports.EnvHttpProxyAgent = EnvHttpProxyAgent;
@@ -61032,7 +61032,7 @@ function registerIdentityCommand(program2, deps) {
61032
61032
  // package.json
61033
61033
  var package_default = {
61034
61034
  name: "agent-shim",
61035
- version: "7.13.2",
61035
+ version: "7.14.0",
61036
61036
  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.",
61037
61037
  license: "MIT",
61038
61038
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -64833,13 +64833,63 @@ function realConnectCertStore(paths) {
64833
64833
  }
64834
64834
 
64835
64835
  // src/frontdoor/connectEffects.ts
64836
+ var dns = __toESM(require("node:dns"), 1);
64836
64837
  var http = __toESM(require("node:http"), 1);
64837
64838
  var https = __toESM(require("node:https"), 1);
64838
64839
  var net3 = __toESM(require("node:net"), 1);
64839
64840
  var tls = __toESM(require("node:tls"), 1);
64841
+ var UPSTREAM_LOCAL_PORT_START = 47900;
64842
+ var UPSTREAM_LOCAL_PORT_END = 47919;
64843
+ var nextUpstreamLocalPort = UPSTREAM_LOCAL_PORT_START;
64844
+ function upstreamLocalPort() {
64845
+ const port = nextUpstreamLocalPort;
64846
+ nextUpstreamLocalPort = nextUpstreamLocalPort === UPSTREAM_LOCAL_PORT_END ? UPSTREAM_LOCAL_PORT_START : nextUpstreamLocalPort + 1;
64847
+ return port;
64848
+ }
64849
+ var realAddressLookup = (host, _options, callback) => {
64850
+ if (net3.isIP(host) !== 0) {
64851
+ callback(null, [{ address: host, family: net3.isIP(host) }]);
64852
+ return;
64853
+ }
64854
+ dns.resolve4(host, (error62, addresses) => {
64855
+ const first = addresses[0];
64856
+ if (error62 !== null || first === void 0) {
64857
+ callback(error62 ?? new Error(`no A record for ${host}`), [{ address: "", family: 4 }]);
64858
+ return;
64859
+ }
64860
+ callback(null, [{ address: first, family: 4 }]);
64861
+ });
64862
+ };
64863
+ var HTTP_PORT = 80;
64864
+ function exemptDial(options, defaultPort) {
64865
+ const host = typeof options.host === "string" ? options.host : "";
64866
+ const port = typeof options.port === "number" ? options.port : defaultPort;
64867
+ return net3.connect(net3.isIP(host) === 0 ? { host, port, localPort: upstreamLocalPort(), lookup: realAddressLookup } : { host, port });
64868
+ }
64869
+ function requestServername(options, fallback) {
64870
+ return "servername" in options && typeof options.servername === "string" && options.servername !== "" ? options.servername : fallback;
64871
+ }
64872
+ var ExemptHttpAgent = class extends http.Agent {
64873
+ createConnection(options) {
64874
+ return exemptDial(options, HTTP_PORT);
64875
+ }
64876
+ };
64877
+ var ExemptTlsAgent = class extends https.Agent {
64878
+ createConnection(options) {
64879
+ const host = typeof options.host === "string" ? options.host : "";
64880
+ const tlsOptions = { socket: exemptDial(options, HTTPS_PORT), servername: requestServername(options, host) };
64881
+ if ("ca" in options && Array.isArray(options.ca)) {
64882
+ tlsOptions.ca = options.ca;
64883
+ }
64884
+ if ("rejectUnauthorized" in options && typeof options.rejectUnauthorized === "boolean") {
64885
+ tlsOptions.rejectUnauthorized = options.rejectUnauthorized;
64886
+ }
64887
+ return tls.connect(tlsOptions);
64888
+ }
64889
+ };
64840
64890
  function realConnectEffects() {
64841
- const plainAgent = new http.Agent({ keepAlive: true });
64842
- const tlsAgent = new https.Agent({ keepAlive: true });
64891
+ const plainAgent = new ExemptHttpAgent();
64892
+ const tlsAgent = new ExemptTlsAgent();
64843
64893
  const listenOnce = async (port, onSocket) => await new Promise((resolve, reject) => {
64844
64894
  const accepted = /* @__PURE__ */ new Set();
64845
64895
  const server = net3.createServer((socket) => {
@@ -64925,11 +64975,23 @@ function realConnectEffects() {
64925
64975
  };
64926
64976
  },
64927
64977
  connectTlsUpstream: async (host, port, clientAlpn) => await new Promise((resolve, reject) => {
64928
- const socket = tls.connect({ host, port, servername: host, ...clientAlpn === void 0 ? {} : { ALPNProtocols: [clientAlpn] } });
64929
- socket.once("secureConnect", () => {
64930
- resolve(socket);
64931
- });
64932
- socket.once("error", reject);
64978
+ const dial = (localPort) => {
64979
+ const raw = net3.connect({ host, port, localPort, lookup: realAddressLookup });
64980
+ return tls.connect({ socket: raw, servername: host, ...clientAlpn === void 0 ? {} : { ALPNProtocols: [clientAlpn] } });
64981
+ };
64982
+ const settle2 = (candidate) => {
64983
+ candidate.once("secureConnect", () => {
64984
+ resolve(candidate);
64985
+ });
64986
+ candidate.once("error", (error62) => {
64987
+ if ("code" in error62 && error62.code === "EADDRINUSE") {
64988
+ settle2(dial(upstreamLocalPort()));
64989
+ return;
64990
+ }
64991
+ reject(error62);
64992
+ });
64993
+ };
64994
+ settle2(dial(upstreamLocalPort()));
64933
64995
  }),
64934
64996
  connectTcp: async (host, port) => await new Promise((resolve, reject) => {
64935
64997
  const socket = net3.connect({ host, port });
@@ -64943,6 +65005,7 @@ function realConnectEffects() {
64943
65005
  const options = {
64944
65006
  host: target.host,
64945
65007
  port: target.port,
65008
+ lookup: realAddressLookup,
64946
65009
  method: request6.method,
64947
65010
  path: request6.url,
64948
65011
  headers,
@@ -66222,7 +66285,7 @@ function createPassthroughRoute(name, target) {
66222
66285
  const base = new URL(target.baseUrl);
66223
66286
  const tls2 = base.protocol === "https:";
66224
66287
  const basePath = base.pathname.replace(/\/+$/, "");
66225
- const agent = tls2 ? new https3.Agent({ keepAlive: true }) : new http4.Agent({ keepAlive: true });
66288
+ const agent = tls2 ? new ExemptTlsAgent() : new ExemptHttpAgent();
66226
66289
  return {
66227
66290
  name,
66228
66291
  headroomEligible: true,
@@ -68281,11 +68344,13 @@ var READY_FETCH_TIMEOUT_MS = 2e3;
68281
68344
  function headroomPidRunning(pid) {
68282
68345
  return !exitedHeadroom.has(pid) && realIsProcessRunning(pid);
68283
68346
  }
68284
- function headroomSpawnEnv(parentEnv, allowlist, settings2) {
68347
+ function headroomSpawnEnv(parentEnv, allowlist, settings2, caBundle) {
68285
68348
  return {
68286
68349
  ...parentEnv,
68287
68350
  HEADROOM_ALLOWED_BASE_URLS: allowlist.join(","),
68288
68351
  HEADROOM_HTTP2: parentEnv.HEADROOM_HTTP2 ?? "0",
68352
+ // A transparent-interception deployment redirects the API host's address machine-wide, so headroom's own Python dials reach the front door's leaf instead of the origin's public certificate, and Python trusts only the system store: point its two trust variables (urllib3/httpx read both) at the door's combined bundle, which carries the system-equivalent anchors alongside the door's CA. An explicit value in the parent environment always wins, exactly like HEADROOM_HTTP2.
68353
+ ...caBundle === void 0 || parentEnv.REQUESTS_CA_BUNDLE !== void 0 || parentEnv.SSL_CERT_FILE !== void 0 ? {} : { REQUESTS_CA_BUNDLE: caBundle, SSL_CERT_FILE: caBundle },
68289
68354
  ...settingsEnv(settings2)
68290
68355
  };
68291
68356
  }
@@ -68324,13 +68389,14 @@ function realSupervisorPorts(paths) {
68324
68389
  isPortFree: realIsPortFree,
68325
68390
  readConfig: () => resolveSupervisorConfig(readGlobalConfig(paths)?.headroom ?? {}),
68326
68391
  spawnHeadroom: (port, allowlist, settings2) => {
68392
+ const caBundle = import_node_fs15.default.existsSync(paths.frontdoorCaCertFile) ? import_node_fs15.default.readFileSync(paths.frontdoorCaCertFile, "utf8") : void 0;
68327
68393
  import_node_fs15.default.mkdirSync(paths.logsDir, { recursive: true });
68328
68394
  const logFd = import_node_fs15.default.openSync(paths.headroomLogPath, "a");
68329
68395
  try {
68330
68396
  const child = (0, import_node_child_process5.spawn)("headroom", ["proxy", "--host", "127.0.0.1", "--port", String(port), ...settingsArgs(settings2)], {
68331
68397
  detached: true,
68332
68398
  stdio: ["ignore", logFd, logFd],
68333
- env: headroomSpawnEnv(process.env, allowlist, settings2)
68399
+ env: headroomSpawnEnv(process.env, allowlist, settings2, caBundle)
68334
68400
  });
68335
68401
  if (child.pid === void 0) {
68336
68402
  throw new Error("spawning headroom returned no pid");
package/dist/index.cjs CHANGED
@@ -3209,13 +3209,63 @@ function realConnectCertStore(paths) {
3209
3209
  }
3210
3210
 
3211
3211
  // src/frontdoor/connectEffects.ts
3212
+ var dns = __toESM(require("node:dns"), 1);
3212
3213
  var http = __toESM(require("node:http"), 1);
3213
3214
  var https = __toESM(require("node:https"), 1);
3214
3215
  var net2 = __toESM(require("node:net"), 1);
3215
3216
  var tls = __toESM(require("node:tls"), 1);
3217
+ var UPSTREAM_LOCAL_PORT_START = 47900;
3218
+ var UPSTREAM_LOCAL_PORT_END = 47919;
3219
+ var nextUpstreamLocalPort = UPSTREAM_LOCAL_PORT_START;
3220
+ function upstreamLocalPort() {
3221
+ const port = nextUpstreamLocalPort;
3222
+ nextUpstreamLocalPort = nextUpstreamLocalPort === UPSTREAM_LOCAL_PORT_END ? UPSTREAM_LOCAL_PORT_START : nextUpstreamLocalPort + 1;
3223
+ return port;
3224
+ }
3225
+ var realAddressLookup = (host, _options, callback) => {
3226
+ if (net2.isIP(host) !== 0) {
3227
+ callback(null, [{ address: host, family: net2.isIP(host) }]);
3228
+ return;
3229
+ }
3230
+ dns.resolve4(host, (error, addresses) => {
3231
+ const first = addresses[0];
3232
+ if (error !== null || first === void 0) {
3233
+ callback(error ?? new Error(`no A record for ${host}`), [{ address: "", family: 4 }]);
3234
+ return;
3235
+ }
3236
+ callback(null, [{ address: first, family: 4 }]);
3237
+ });
3238
+ };
3239
+ var HTTP_PORT = 80;
3240
+ function exemptDial(options, defaultPort) {
3241
+ const host = typeof options.host === "string" ? options.host : "";
3242
+ const port = typeof options.port === "number" ? options.port : defaultPort;
3243
+ return net2.connect(net2.isIP(host) === 0 ? { host, port, localPort: upstreamLocalPort(), lookup: realAddressLookup } : { host, port });
3244
+ }
3245
+ function requestServername(options, fallback) {
3246
+ return "servername" in options && typeof options.servername === "string" && options.servername !== "" ? options.servername : fallback;
3247
+ }
3248
+ var ExemptHttpAgent = class extends http.Agent {
3249
+ createConnection(options) {
3250
+ return exemptDial(options, HTTP_PORT);
3251
+ }
3252
+ };
3253
+ var ExemptTlsAgent = class extends https.Agent {
3254
+ createConnection(options) {
3255
+ const host = typeof options.host === "string" ? options.host : "";
3256
+ const tlsOptions = { socket: exemptDial(options, HTTPS_PORT), servername: requestServername(options, host) };
3257
+ if ("ca" in options && Array.isArray(options.ca)) {
3258
+ tlsOptions.ca = options.ca;
3259
+ }
3260
+ if ("rejectUnauthorized" in options && typeof options.rejectUnauthorized === "boolean") {
3261
+ tlsOptions.rejectUnauthorized = options.rejectUnauthorized;
3262
+ }
3263
+ return tls.connect(tlsOptions);
3264
+ }
3265
+ };
3216
3266
  function realConnectEffects() {
3217
- const plainAgent = new http.Agent({ keepAlive: true });
3218
- const tlsAgent = new https.Agent({ keepAlive: true });
3267
+ const plainAgent = new ExemptHttpAgent();
3268
+ const tlsAgent = new ExemptTlsAgent();
3219
3269
  const listenOnce = async (port, onSocket) => await new Promise((resolve, reject) => {
3220
3270
  const accepted = /* @__PURE__ */ new Set();
3221
3271
  const server = net2.createServer((socket) => {
@@ -3301,11 +3351,23 @@ function realConnectEffects() {
3301
3351
  };
3302
3352
  },
3303
3353
  connectTlsUpstream: async (host, port, clientAlpn) => await new Promise((resolve, reject) => {
3304
- const socket = tls.connect({ host, port, servername: host, ...clientAlpn === void 0 ? {} : { ALPNProtocols: [clientAlpn] } });
3305
- socket.once("secureConnect", () => {
3306
- resolve(socket);
3307
- });
3308
- socket.once("error", reject);
3354
+ const dial = (localPort) => {
3355
+ const raw = net2.connect({ host, port, localPort, lookup: realAddressLookup });
3356
+ return tls.connect({ socket: raw, servername: host, ...clientAlpn === void 0 ? {} : { ALPNProtocols: [clientAlpn] } });
3357
+ };
3358
+ const settle = (candidate) => {
3359
+ candidate.once("secureConnect", () => {
3360
+ resolve(candidate);
3361
+ });
3362
+ candidate.once("error", (error) => {
3363
+ if ("code" in error && error.code === "EADDRINUSE") {
3364
+ settle(dial(upstreamLocalPort()));
3365
+ return;
3366
+ }
3367
+ reject(error);
3368
+ });
3369
+ };
3370
+ settle(dial(upstreamLocalPort()));
3309
3371
  }),
3310
3372
  connectTcp: async (host, port) => await new Promise((resolve, reject) => {
3311
3373
  const socket = net2.connect({ host, port });
@@ -3319,6 +3381,7 @@ function realConnectEffects() {
3319
3381
  const options = {
3320
3382
  host: target.host,
3321
3383
  port: target.port,
3384
+ lookup: realAddressLookup,
3322
3385
  method: request3.method,
3323
3386
  path: request3.url,
3324
3387
  headers,
package/dist/index.mjs CHANGED
@@ -3043,13 +3043,63 @@ function realConnectCertStore(paths) {
3043
3043
  }
3044
3044
 
3045
3045
  // src/frontdoor/connectEffects.ts
3046
+ import * as dns from "node:dns";
3046
3047
  import * as http from "node:http";
3047
3048
  import * as https from "node:https";
3048
3049
  import * as net2 from "node:net";
3049
3050
  import * as tls from "node:tls";
3051
+ var UPSTREAM_LOCAL_PORT_START = 47900;
3052
+ var UPSTREAM_LOCAL_PORT_END = 47919;
3053
+ var nextUpstreamLocalPort = UPSTREAM_LOCAL_PORT_START;
3054
+ function upstreamLocalPort() {
3055
+ const port = nextUpstreamLocalPort;
3056
+ nextUpstreamLocalPort = nextUpstreamLocalPort === UPSTREAM_LOCAL_PORT_END ? UPSTREAM_LOCAL_PORT_START : nextUpstreamLocalPort + 1;
3057
+ return port;
3058
+ }
3059
+ var realAddressLookup = (host, _options, callback) => {
3060
+ if (net2.isIP(host) !== 0) {
3061
+ callback(null, [{ address: host, family: net2.isIP(host) }]);
3062
+ return;
3063
+ }
3064
+ dns.resolve4(host, (error, addresses) => {
3065
+ const first = addresses[0];
3066
+ if (error !== null || first === void 0) {
3067
+ callback(error ?? new Error(`no A record for ${host}`), [{ address: "", family: 4 }]);
3068
+ return;
3069
+ }
3070
+ callback(null, [{ address: first, family: 4 }]);
3071
+ });
3072
+ };
3073
+ var HTTP_PORT = 80;
3074
+ function exemptDial(options, defaultPort) {
3075
+ const host = typeof options.host === "string" ? options.host : "";
3076
+ const port = typeof options.port === "number" ? options.port : defaultPort;
3077
+ return net2.connect(net2.isIP(host) === 0 ? { host, port, localPort: upstreamLocalPort(), lookup: realAddressLookup } : { host, port });
3078
+ }
3079
+ function requestServername(options, fallback) {
3080
+ return "servername" in options && typeof options.servername === "string" && options.servername !== "" ? options.servername : fallback;
3081
+ }
3082
+ var ExemptHttpAgent = class extends http.Agent {
3083
+ createConnection(options) {
3084
+ return exemptDial(options, HTTP_PORT);
3085
+ }
3086
+ };
3087
+ var ExemptTlsAgent = class extends https.Agent {
3088
+ createConnection(options) {
3089
+ const host = typeof options.host === "string" ? options.host : "";
3090
+ const tlsOptions = { socket: exemptDial(options, HTTPS_PORT), servername: requestServername(options, host) };
3091
+ if ("ca" in options && Array.isArray(options.ca)) {
3092
+ tlsOptions.ca = options.ca;
3093
+ }
3094
+ if ("rejectUnauthorized" in options && typeof options.rejectUnauthorized === "boolean") {
3095
+ tlsOptions.rejectUnauthorized = options.rejectUnauthorized;
3096
+ }
3097
+ return tls.connect(tlsOptions);
3098
+ }
3099
+ };
3050
3100
  function realConnectEffects() {
3051
- const plainAgent = new http.Agent({ keepAlive: true });
3052
- const tlsAgent = new https.Agent({ keepAlive: true });
3101
+ const plainAgent = new ExemptHttpAgent();
3102
+ const tlsAgent = new ExemptTlsAgent();
3053
3103
  const listenOnce = async (port, onSocket) => await new Promise((resolve, reject) => {
3054
3104
  const accepted = /* @__PURE__ */ new Set();
3055
3105
  const server = net2.createServer((socket) => {
@@ -3135,11 +3185,23 @@ function realConnectEffects() {
3135
3185
  };
3136
3186
  },
3137
3187
  connectTlsUpstream: async (host, port, clientAlpn) => await new Promise((resolve, reject) => {
3138
- const socket = tls.connect({ host, port, servername: host, ...clientAlpn === void 0 ? {} : { ALPNProtocols: [clientAlpn] } });
3139
- socket.once("secureConnect", () => {
3140
- resolve(socket);
3141
- });
3142
- socket.once("error", reject);
3188
+ const dial = (localPort) => {
3189
+ const raw = net2.connect({ host, port, localPort, lookup: realAddressLookup });
3190
+ return tls.connect({ socket: raw, servername: host, ...clientAlpn === void 0 ? {} : { ALPNProtocols: [clientAlpn] } });
3191
+ };
3192
+ const settle = (candidate) => {
3193
+ candidate.once("secureConnect", () => {
3194
+ resolve(candidate);
3195
+ });
3196
+ candidate.once("error", (error) => {
3197
+ if ("code" in error && error.code === "EADDRINUSE") {
3198
+ settle(dial(upstreamLocalPort()));
3199
+ return;
3200
+ }
3201
+ reject(error);
3202
+ });
3203
+ };
3204
+ settle(dial(upstreamLocalPort()));
3143
3205
  }),
3144
3206
  connectTcp: async (host, port) => await new Promise((resolve, reject) => {
3145
3207
  const socket = net2.connect({ host, port });
@@ -3153,6 +3215,7 @@ function realConnectEffects() {
3153
3215
  const options = {
3154
3216
  host: target.host,
3155
3217
  port: target.port,
3218
+ lookup: realAddressLookup,
3156
3219
  method: request3.method,
3157
3220
  path: request3.url,
3158
3221
  headers,
@@ -1583,7 +1583,6 @@ declare function realConnectCertStore(paths: {
1583
1583
  readonly frontdoorCaKeyFile: string;
1584
1584
  }): ConnectCertStore;
1585
1585
 
1586
- /** The real `ConnectEffects` over node's own net, tls, and http. `connectTcp` opens real connections to the CONNECTed host, so tests that want a blind tunnel redirect it. */
1587
1586
  declare function realConnectEffects(): ConnectEffects;
1588
1587
 
1589
1588
  /** The filesystem operations headroom coordination needs: the same shape as `FarmFs`, injected so every decision over state, sessions, and the start lock runs against an in-memory fake in tests. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-shim",
3
- "version": "7.13.2",
3
+ "version": "7.14.0",
4
4
  "description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
5
5
  "license": "MIT",
6
6
  "author": "Joseph Mearman <joseph@mearman.co.uk>",