agent-shim 8.11.3 → 8.13.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/index.cjs CHANGED
@@ -81,6 +81,13 @@ __export(index_exports, {
81
81
  RC_PENDING_DEADLINE_MS: () => RC_PENDING_DEADLINE_MS,
82
82
  RC_PERMISSION_MODES: () => RC_PERMISSION_MODES,
83
83
  RC_REQUEST_PARSE_CAP_BYTES: () => RC_REQUEST_PARSE_CAP_BYTES,
84
+ RC_SELF_HOST_ENV: () => RC_SELF_HOST_ENV,
85
+ RC_SELF_HOST_KEEPALIVE_MS: () => RC_SELF_HOST_KEEPALIVE_MS,
86
+ RC_SELF_HOST_RECORD_DIR: () => RC_SELF_HOST_RECORD_DIR,
87
+ RC_SELF_HOST_RECORD_FILE: () => RC_SELF_HOST_RECORD_FILE,
88
+ RC_SELF_HOST_RETENTION_MS: () => RC_SELF_HOST_RETENTION_MS,
89
+ RC_SELF_HOST_SCOPE_LIST: () => RC_SELF_HOST_SCOPE_LIST,
90
+ RC_SELF_HOST_WORKER_JWT_TTL_SECONDS: () => RC_SELF_HOST_WORKER_JWT_TTL_SECONDS,
84
91
  RC_SESSIONS_PATH_PREFIX: () => RC_SESSIONS_PATH_PREFIX,
85
92
  RC_STREAM_BACKOFF_MS: () => RC_STREAM_BACKOFF_MS,
86
93
  ROUTED_PATH_PREFIX: () => ROUTED_PATH_PREFIX,
@@ -117,6 +124,7 @@ __export(index_exports, {
117
124
  createRcControlHandler: () => createRcControlHandler,
118
125
  createRcCredentialStore: () => createRcCredentialStore,
119
126
  createRcEventFanout: () => createRcEventFanout,
127
+ createRcSelfHostSurface: () => createRcSelfHostSurface,
120
128
  createRcSessionTracker: () => createRcSessionTracker,
121
129
  createRcStreamHub: () => createRcStreamHub,
122
130
  createSseParser: () => createSseParser,
@@ -141,6 +149,8 @@ __export(index_exports, {
141
149
  isIdentityDirectoryName: () => isIdentityDirectoryName,
142
150
  isInterceptedHost: () => isInterceptedHost,
143
151
  isRcPermissionMode: () => isRcPermissionMode,
152
+ lateRcEventDial: () => lateRcEventDial,
153
+ lateRcStreamDial: () => lateRcStreamDial,
144
154
  listDirectoryRules: () => listDirectoryRules,
145
155
  listIdentities: () => listIdentities,
146
156
  listProfiles: () => listProfiles,
@@ -148,6 +158,7 @@ __export(index_exports, {
148
158
  listUsageSnapshots: () => listUsageSnapshots,
149
159
  matchBranch: () => matchBranch,
150
160
  mintLeaf: () => mintLeaf,
161
+ mintRcSelfHostCredential: () => mintRcSelfHostCredential,
151
162
  observingRoutedRoute: () => observingRoutedRoute,
152
163
  parseConnectTarget: () => parseConnectTarget,
153
164
  parseRcStreamEnvelope: () => parseRcStreamEnvelope,
@@ -159,6 +170,7 @@ __export(index_exports, {
159
170
  rankPool: () => rankPool,
160
171
  rcEventWriteResultFromAnswer: () => rcEventWriteResultFromAnswer,
161
172
  rcObserverAsPassthrough: () => rcObserverAsPassthrough,
173
+ rcSelfHostFromEnv: () => rcSelfHostFromEnv,
162
174
  readActiveIdentity: () => readActiveIdentity,
163
175
  readDirectoryRules: () => readDirectoryRules,
164
176
  readFarmManifest: () => readFarmManifest,
@@ -167,6 +179,7 @@ __export(index_exports, {
167
179
  readPools: () => readPools,
168
180
  readProfile: () => readProfile,
169
181
  readProvider: () => readProvider,
182
+ readRcSelfHostRecord: () => readRcSelfHostRecord,
170
183
  readUsageSnapshot: () => readUsageSnapshot,
171
184
  realConnectCertStore: () => realConnectCertStore,
172
185
  realConnectEffects: () => realConnectEffects,
@@ -190,6 +203,7 @@ __export(index_exports, {
190
203
  runCheck: () => runCheck,
191
204
  runDoctor: () => runDoctor,
192
205
  runFrontDoorSupervisor: () => runFrontDoorSupervisor,
206
+ runLauncher: () => runLauncher,
193
207
  runSupervisor: () => runSupervisor,
194
208
  servedByPipeline: () => servedByPipeline,
195
209
  setAllowAmbientCredential: () => setAllowAmbientCredential,
@@ -204,6 +218,7 @@ __export(index_exports, {
204
218
  setRcSessionModel: () => setRcSessionModel,
205
219
  setRcSessionPermissionMode: () => setRcSessionPermissionMode,
206
220
  snapshotPath: () => snapshotPath,
221
+ spawnClaude: () => spawnClaude,
207
222
  startConnectServer: () => startConnectServer,
208
223
  topLevelNames: () => topLevelNames,
209
224
  updateDirectoryRule: () => updateDirectoryRule,
@@ -3030,8 +3045,8 @@ function parseConnectTarget(authority) {
3030
3045
  function isInterceptedHost(host, interceptHosts) {
3031
3046
  return interceptHosts.includes(host);
3032
3047
  }
3033
- function servedByPipeline(path30) {
3034
- return path30?.startsWith(ROUTED_PATH_PREFIX) === true;
3048
+ function servedByPipeline(path31) {
3049
+ return path31?.startsWith(ROUTED_PATH_PREFIX) === true;
3035
3050
  }
3036
3051
  var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
3037
3052
  "connection",
@@ -3113,14 +3128,17 @@ ${request4.rawHeaders.reduce((accumulated, value, index) => index % 2 === 0 ? `$
3113
3128
  pumpTapSession(socket, async (clientAlpn) => await effects.connectTlsUpstream(host, HTTPS_PORT, clientAlpn), config.capture?.tapStream?.(host), Buffer.from(headText, "utf8"));
3114
3129
  };
3115
3130
  const sessions = config.interceptHosts.map((host) => {
3116
- if (config.tapHosts.includes(host)) {
3131
+ if (config.tapHosts.includes(host) && !(config.localSurface?.parsesHost(host) ?? false)) {
3117
3132
  const serveSecure2 = (secure) => {
3118
3133
  pumpTapSession(secure, async (clientAlpn) => await effects.connectTlsUpstream(host, HTTPS_PORT, clientAlpn), config.capture?.tapStream?.(host));
3119
3134
  };
3120
3135
  const tlsAcceptor2 = effects.createTlsAcceptor(config.leafFor(host), serveSecure2, TAP_ALPN_PROTOCOLS);
3121
3136
  return { host, serveSecure: serveSecure2, tlsAcceptor: tlsAcceptor2 };
3122
3137
  }
3123
- const handler = (request4, response) => {
3138
+ const handleHostRequest = async (request4, response) => {
3139
+ if (config.localSurface !== void 0 && await config.localSurface.serve(host, request4, response)) {
3140
+ return;
3141
+ }
3124
3142
  if (host === config.routedHost && servedByPipeline(request4.url)) {
3125
3143
  const tunnelToken = tunnelTokens.get(request4.socket);
3126
3144
  if (tunnelToken !== void 0 && request4.headers[AUTH_HEADER] === void 0) {
@@ -3131,6 +3149,9 @@ ${request4.rawHeaders.reduce((accumulated, value, index) => index % 2 === 0 ? `$
3131
3149
  }
3132
3150
  effects.forwardHttp(config.upstreamFor(host), request4, response, config.capture?.observePassthrough(request4));
3133
3151
  };
3152
+ const handler = (request4, response) => {
3153
+ void handleHostRequest(request4, response);
3154
+ };
3134
3155
  const httpSession = effects.createHttpSession(handler, onUpgrade(host));
3135
3156
  const serveSecure = (secure, capability) => {
3136
3157
  tunnelTokens.set(secure, capability);
@@ -3513,7 +3534,7 @@ function parseRcRequestBody(kind, body) {
3513
3534
  return { controlRequests: [], answeredRequestIds: [], idleSeconds: finiteNumber(parseJsonObject(body), "idle_seconds"), workerStatus: void 0 };
3514
3535
  }
3515
3536
  if (kind === "worker-registration") {
3516
- return { controlRequests: [], answeredRequestIds: [], idleSeconds: void 0, workerStatus: nonEmptyString(parseJsonObject(body), "status") };
3537
+ return { controlRequests: [], answeredRequestIds: [], idleSeconds: void 0, workerStatus: nonEmptyString(parseJsonObject(body), "worker_status") };
3517
3538
  }
3518
3539
  const controlRequests = [];
3519
3540
  const answeredRequestIds = [];
@@ -3562,11 +3583,11 @@ function createRcSessionTracker(deps) {
3562
3583
  };
3563
3584
  const observeExchange = (request4) => {
3564
3585
  const method = (request4.method ?? "").toUpperCase();
3565
- const path30 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
3566
- if (!path30.startsWith(RC_SESSIONS_PATH_PREFIX)) {
3586
+ const path31 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
3587
+ if (!path31.startsWith(RC_SESSIONS_PATH_PREFIX)) {
3567
3588
  return void 0;
3568
3589
  }
3569
- const tail = path30.slice(RC_SESSIONS_PATH_PREFIX.length);
3590
+ const tail = path31.slice(RC_SESSIONS_PATH_PREFIX.length);
3570
3591
  const facts = {
3571
3592
  oauthAuthorization: oauthAuthorizationOf(request4.headers),
3572
3593
  anthropicVersion: singleHeader(request4.headers, "anthropic-version"),
@@ -4327,9 +4348,9 @@ function sequenceNumsOfBody(body) {
4327
4348
  }
4328
4349
  function frontDoorRcControl(transport, token) {
4329
4350
  const headers = { authorization: `Bearer ${token}` };
4330
- const listAnswerOf = async (path30, what) => {
4351
+ const listAnswerOf = async (path31, what) => {
4331
4352
  try {
4332
- return await transport.request({ method: "GET", path: path30, headers });
4353
+ return await transport.request({ method: "GET", path: path31, headers });
4333
4354
  } catch (error) {
4334
4355
  throw new Error(`${what}: could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
4335
4356
  }
@@ -4401,10 +4422,10 @@ function frontDoorRcControl(transport, token) {
4401
4422
  }
4402
4423
  return pending;
4403
4424
  };
4404
- const writeOf = async (path30, body, describeFailure) => {
4425
+ const writeOf = async (path31, body, describeFailure) => {
4405
4426
  let answer;
4406
4427
  try {
4407
- answer = await transport.request({ method: "POST", path: path30, headers: { ...headers, "content-type": "application/json" }, body });
4428
+ answer = await transport.request({ method: "POST", path: path31, headers: { ...headers, "content-type": "application/json" }, body });
4408
4429
  } catch (error) {
4409
4430
  return { ok: false, message: `could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}` };
4410
4431
  }
@@ -4614,14 +4635,41 @@ var NO_CHUNKS = {
4614
4635
  next: async () => await Promise.resolve({ done: true, value: void 0 })
4615
4636
  })
4616
4637
  };
4638
+ function lateRcEventDial(resolve) {
4639
+ let built;
4640
+ const dialFor = () => {
4641
+ const target = resolve();
4642
+ if (built === void 0 || built.for !== target) {
4643
+ built = { for: target, dial: realRcEventDial(target) };
4644
+ }
4645
+ return built.dial;
4646
+ };
4647
+ return {
4648
+ writeEvents: async (sessionId, headers, body) => await dialFor().writeEvents(sessionId, headers, body)
4649
+ };
4650
+ }
4651
+ function lateRcStreamDial(resolve) {
4652
+ let built;
4653
+ const dialFor = () => {
4654
+ const target = resolve();
4655
+ if (built === void 0 || built.for !== target) {
4656
+ built = { for: target, dial: realRcStreamDial(target) };
4657
+ }
4658
+ return built.dial;
4659
+ };
4660
+ return {
4661
+ announcePresence: async (sessionId, headers, clientId) => await dialFor().announcePresence(sessionId, headers, clientId),
4662
+ openStream: async (sessionId, headers, resume, signal) => await dialFor().openStream(sessionId, headers, resume, signal)
4663
+ };
4664
+ }
4617
4665
  function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
4618
4666
  const agent = new ExemptTlsAgent();
4619
- const request4 = async (method, path30, headers, body, signal) => await new Promise((resolve, reject) => {
4667
+ const request4 = async (method, path31, headers, body, signal) => await new Promise((resolve, reject) => {
4620
4668
  const options = {
4621
4669
  host: target.host,
4622
4670
  port: target.port,
4623
4671
  method,
4624
- path: path30,
4672
+ path: path31,
4625
4673
  // The Host header names the host whose API this is, not the address dialled: a redirected test dials a loopback stand-in while still speaking to the API host by name, exactly as the forwarded paths present their SNI.
4626
4674
  headers: { ...headers, host: target.servername ?? target.host, ...body === void 0 ? {} : { "content-length": String(Buffer.byteLength(body, "utf8")) } },
4627
4675
  agent,
@@ -4658,9 +4706,9 @@ function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_P
4658
4706
  return { status, body: await readAll(response) };
4659
4707
  },
4660
4708
  openStream: async (sessionId, headers, resume, signal) => {
4661
- const path30 = resume === void 0 ? `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream` : `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream?from_sequence_num=${String(resume.fromSequenceNum)}`;
4709
+ const path31 = resume === void 0 ? `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream` : `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream?from_sequence_num=${String(resume.fromSequenceNum)}`;
4662
4710
  const streamHeaders = resume === void 0 ? headers : { ...headers, "last-event-id": String(resume.fromSequenceNum) };
4663
- const { status, response } = await request4("GET", path30, streamHeaders, void 0, signal);
4711
+ const { status, response } = await request4("GET", path31, streamHeaders, void 0, signal);
4664
4712
  if (!isSuccessful2(status)) {
4665
4713
  await readAll(response);
4666
4714
  return { status, chunks: NO_CHUNKS };
@@ -5355,37 +5403,930 @@ function createRcStreamHub(deps) {
5355
5403
  await deps.sleep(deps.backoffMs);
5356
5404
  retriedUnauthorized = false;
5357
5405
  }
5358
- };
5359
- return {
5360
- reconcile: () => {
5361
- const live = new Set(deps.trackedSessions());
5362
- for (const [sessionId, attachment] of attachments) {
5363
- if (!live.has(sessionId)) {
5364
- attachment.stop();
5365
- attachments.delete(sessionId);
5366
- }
5367
- }
5368
- for (const sessionId of live) {
5369
- if (attachments.has(sessionId)) {
5370
- continue;
5371
- }
5372
- if (deps.credentialOf(sessionId)?.authorization === void 0) {
5373
- continue;
5374
- }
5375
- const attachment = birth(sessionId);
5376
- attachments.set(sessionId, attachment);
5377
- void runLoop(attachment).catch((error) => {
5378
- deps.log?.(`rc stream ${sessionId}: the attachment loop ended unexpectedly (${error instanceof Error ? error.message : String(error)})`);
5379
- });
5380
- }
5406
+ };
5407
+ return {
5408
+ reconcile: () => {
5409
+ const live = new Set(deps.trackedSessions());
5410
+ for (const [sessionId, attachment] of attachments) {
5411
+ if (!live.has(sessionId)) {
5412
+ attachment.stop();
5413
+ attachments.delete(sessionId);
5414
+ }
5415
+ }
5416
+ for (const sessionId of live) {
5417
+ if (attachments.has(sessionId)) {
5418
+ continue;
5419
+ }
5420
+ if (deps.credentialOf(sessionId)?.authorization === void 0) {
5421
+ continue;
5422
+ }
5423
+ const attachment = birth(sessionId);
5424
+ attachments.set(sessionId, attachment);
5425
+ void runLoop(attachment).catch((error) => {
5426
+ deps.log?.(`rc stream ${sessionId}: the attachment loop ended unexpectedly (${error instanceof Error ? error.message : String(error)})`);
5427
+ });
5428
+ }
5429
+ },
5430
+ close: () => {
5431
+ for (const attachment of attachments.values()) {
5432
+ attachment.stop();
5433
+ }
5434
+ attachments.clear();
5435
+ }
5436
+ };
5437
+ }
5438
+
5439
+ // src/frontdoor/rcSelfHost.ts
5440
+ var RC_SELF_HOST_ENV = "AGENT_SHIM_FRONTDOOR_RC_SELF_HOST";
5441
+ function rcSelfHostFromEnv(env) {
5442
+ return env[RC_SELF_HOST_ENV] === "1";
5443
+ }
5444
+ var RC_SELF_HOST_SCOPE_LIST = ["user:profile", "user:inference", "user:sessions:claude_code", "user:mcp_servers", "user:file_upload"];
5445
+ var RC_SESSIONS_PATH_PREFIX2 = "/v1/code/sessions";
5446
+ var RC_COMPAT_SESSIONS_PATH = "/v1/sessions";
5447
+ var RC_SESSION_ID_PREFIX2 = "cse_";
5448
+ var RC_SELF_HOST_API_BASE_URL = "https://api.anthropic.com";
5449
+ var RC_SELF_HOST_OAUTH_HOST = "platform.claude.com";
5450
+ var HTTP_CONFLICT = 409;
5451
+ var MS_PER_SECOND2 = 1e3;
5452
+ var HTTP_SERVICE_UNAVAILABLE = 503;
5453
+ var RC_SELF_HOST_WORKER_JWT_TTL_SECONDS = 46800;
5454
+ var RC_SELF_HOST_OAUTH_TOKEN_TTL_SECONDS = 3600;
5455
+ var RC_SELF_HOST_KEEPALIVE_MS = 15e3;
5456
+ var RC_SELF_HOST_RETENTION_MS = 6e5;
5457
+ var RC_PRESENCE_REFRESH_SECONDS = 60;
5458
+ var RC_SELF_HOST_MAX_BATCH_EVENTS = 100;
5459
+ var RC_SELF_HOST_WORKER_EPOCH = 1;
5460
+ var RC_STREAM_EVENT_NAME2 = "client_event";
5461
+ var RC_SOURCE_WORKER = "worker";
5462
+ var RC_SOURCE_CLIENT = "client";
5463
+ var CONFLICT_REASON_HEADER2 = "x-ccr-conflict-reason";
5464
+ var CONFLICT_REASON_EPOCH_STALE = "epoch_stale";
5465
+ function isRecord5(value) {
5466
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5467
+ }
5468
+ function nonEmptyString2(record, field) {
5469
+ const value = record === void 0 ? void 0 : record[field];
5470
+ return typeof value === "string" && value !== "" ? value : void 0;
5471
+ }
5472
+ function numberOf(record, field) {
5473
+ const value = record === void 0 ? void 0 : record[field];
5474
+ if (typeof value === "number" && Number.isFinite(value)) {
5475
+ return value;
5476
+ }
5477
+ if (typeof value === "string" && /^[0-9]+$/.test(value)) {
5478
+ return Number(value);
5479
+ }
5480
+ return void 0;
5481
+ }
5482
+ function singleHeader2(headers, name) {
5483
+ const value = headers[name];
5484
+ return typeof value === "string" ? value : void 0;
5485
+ }
5486
+ function bearerOf(headers) {
5487
+ const presented = singleHeader2(headers, "authorization");
5488
+ if (presented === void 0) {
5489
+ return void 0;
5490
+ }
5491
+ return presented.slice(0, "bearer ".length).toLowerCase() === "bearer " ? presented.slice("bearer ".length) : void 0;
5492
+ }
5493
+ async function readBody2(request4, capBytes) {
5494
+ return await new Promise((resolve, reject) => {
5495
+ const chunks = [];
5496
+ let total = 0;
5497
+ request4.on("data", (chunk) => {
5498
+ total += chunk.length;
5499
+ if (total > capBytes) {
5500
+ request4.destroy();
5501
+ reject(new Error("body too large"));
5502
+ return;
5503
+ }
5504
+ chunks.push(chunk);
5505
+ });
5506
+ request4.on("end", () => {
5507
+ resolve(Buffer.concat(chunks).toString("utf8"));
5508
+ });
5509
+ request4.on("error", () => {
5510
+ reject(new Error("the request body ended early"));
5511
+ });
5512
+ });
5513
+ }
5514
+ function parseJsonObject2(body) {
5515
+ let parsed;
5516
+ try {
5517
+ parsed = JSON.parse(body);
5518
+ } catch {
5519
+ return void 0;
5520
+ }
5521
+ return isRecord5(parsed) ? parsed : void 0;
5522
+ }
5523
+ function mintWorkerJwt(randomToken, issuedAt) {
5524
+ const encode = (value) => Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
5525
+ const header = encode({ alg: "HS256", typ: "JWT" });
5526
+ const payload = encode({ exp: Math.floor((issuedAt + RC_SELF_HOST_WORKER_JWT_TTL_SECONDS * MS_PER_SECOND2) / MS_PER_SECOND2), iat: Math.floor(issuedAt / MS_PER_SECOND2) });
5527
+ return `${header}.${payload}.${Buffer.from(randomToken(), "utf8").toString("base64url")}`;
5528
+ }
5529
+ function growthBookFeatures() {
5530
+ return {
5531
+ tengu_ccr_bridge: { defaultValue: true },
5532
+ tengu_bridge_repl_v2: { defaultValue: true },
5533
+ tengu_bridge_repl_v2_cse_shim_enabled: { defaultValue: true },
5534
+ tengu_bridge_min_version: { defaultValue: { minVersion: "0.0.0" } }
5535
+ };
5536
+ }
5537
+ function createRcSelfHostSurface(deps) {
5538
+ const sessions = /* @__PURE__ */ new Map();
5539
+ const sweep = () => {
5540
+ const now = deps.now();
5541
+ for (const session of sessions.values()) {
5542
+ while (session.events[0] !== void 0 && now - session.events[0].storedAt > RC_SELF_HOST_RETENTION_MS) {
5543
+ const dropped = session.events.shift();
5544
+ const uuid = dropped === void 0 ? void 0 : nonEmptyString2(dropped.payload, "uuid");
5545
+ if (uuid !== void 0) {
5546
+ session.seenPayloadUuids.delete(uuid);
5547
+ }
5548
+ }
5549
+ if (session.workerStreams.size === 0 && session.clientStreams.size === 0 && now - session.lastTrafficAt > RC_SELF_HOST_RETENTION_MS) {
5550
+ sessions.delete(session.id);
5551
+ }
5552
+ }
5553
+ };
5554
+ const timer = setInterval(sweep, RC_SELF_HOST_RETENTION_MS);
5555
+ timer.unref();
5556
+ const keepalive = setInterval(() => {
5557
+ for (const session of sessions.values()) {
5558
+ for (const sink of [...session.workerStreams, ...session.clientStreams]) {
5559
+ sink.write(": keep-alive\n\n");
5560
+ }
5561
+ }
5562
+ }, RC_SELF_HOST_KEEPALIVE_MS);
5563
+ keepalive.unref();
5564
+ const presentsCredential = (headers) => {
5565
+ const expected = deps.credentialRecord()?.accessToken;
5566
+ const presented = bearerOf(headers);
5567
+ return expected !== void 0 && presented !== void 0 && isLiveCapability(presented, [expected]);
5568
+ };
5569
+ const presentsWorkerJwt = (headers, session) => {
5570
+ const presented = bearerOf(headers);
5571
+ if (presented === void 0) {
5572
+ return false;
5573
+ }
5574
+ for (const minted of session.workerJwts) {
5575
+ if (isLiveCapability(presented, [minted])) {
5576
+ return true;
5577
+ }
5578
+ }
5579
+ return false;
5580
+ };
5581
+ const frameOf = (event) => {
5582
+ const envelope = {
5583
+ event_id: event.eventId,
5584
+ event_type: nonEmptyString2(event.payload, "type") ?? "event",
5585
+ sequence_num: event.sequenceNum,
5586
+ source: event.source,
5587
+ payload: event.payload,
5588
+ created_at: event.createdAt
5589
+ };
5590
+ return `event: ${RC_STREAM_EVENT_NAME2}
5591
+ id: ${String(event.sequenceNum)}
5592
+ data: ${JSON.stringify(envelope)}
5593
+
5594
+ `;
5595
+ };
5596
+ const holdStream = async (session, which, wantsReplay, request4, response) => {
5597
+ const url = new URL(request4.url, "http://127.0.0.1");
5598
+ const cursor = numberOf({ value: url.searchParams.get("from_sequence_num") }, "value") ?? numberOf({ value: singleHeader2(request4.headers, "last-event-id") }, "value");
5599
+ const replay = cursor === void 0 ? [] : session.events.filter((event) => wantsReplay(event) && event.sequenceNum > cursor);
5600
+ response.start(HTTP_STATUS.ok, { "content-type": "text/event-stream", "cache-control": "no-cache" });
5601
+ response.flush();
5602
+ let pending = Promise.resolve();
5603
+ const sink = {
5604
+ write: (frame) => {
5605
+ pending = pending.then(async () => {
5606
+ await response.write(frame);
5607
+ }).catch(() => {
5608
+ });
5609
+ },
5610
+ retire: () => {
5611
+ session[which].delete(sink);
5612
+ }
5613
+ };
5614
+ session[which].add(sink);
5615
+ session.lastTrafficAt = deps.now();
5616
+ for (const event of replay) {
5617
+ sink.write(frameOf(event));
5618
+ }
5619
+ await new Promise((resolve) => {
5620
+ request4.signal.addEventListener("abort", () => {
5621
+ resolve(void 0);
5622
+ }, { once: true });
5623
+ });
5624
+ sink.retire();
5625
+ response.end();
5626
+ };
5627
+ const publish = (session, source, payload) => {
5628
+ const uuid = nonEmptyString2(payload, "uuid");
5629
+ const duplicate = uuid !== void 0 && session.seenPayloadUuids.has(uuid);
5630
+ session.sequenceNum += 1;
5631
+ const event = {
5632
+ sequenceNum: session.sequenceNum,
5633
+ eventId: uuid ?? deps.newUuid(),
5634
+ source,
5635
+ // The one enrichment the real service was observed making on the live rig's stream: the wall-clock instant it took the write. The worker's handler ignores it; the door's own parser forwards it verbatim.
5636
+ payload: source === RC_SOURCE_CLIENT ? { ...payload, server_received_wall_ms: deps.now() } : payload,
5637
+ createdAt: new Date(deps.now()).toISOString(),
5638
+ toWorker: source === RC_SOURCE_CLIENT,
5639
+ storedAt: deps.now()
5640
+ };
5641
+ session.events.push(event);
5642
+ if (uuid !== void 0) {
5643
+ session.seenPayloadUuids.add(uuid);
5644
+ }
5645
+ session.lastTrafficAt = event.storedAt;
5646
+ const frame = frameOf(event);
5647
+ if (event.toWorker) {
5648
+ for (const sink of [...session.workerStreams]) {
5649
+ sink.write(frame);
5650
+ }
5651
+ }
5652
+ for (const sink of [...session.clientStreams]) {
5653
+ sink.write(frame);
5654
+ }
5655
+ return { sequenceNum: event.sequenceNum, eventId: event.eventId, duplicate };
5656
+ };
5657
+ const answerJson2 = async (response, status, body, extraHeaders = {}) => {
5658
+ const text = JSON.stringify(body);
5659
+ response.start(status, { "content-type": "application/json", "content-length": String(Buffer.byteLength(text, "utf8")), ...extraHeaders });
5660
+ await response.write(text);
5661
+ response.end();
5662
+ };
5663
+ const noCredential = async (response) => {
5664
+ await answerJson2(response, HTTP_SERVICE_UNAVAILABLE, { type: "error", error: { type: "api_error", message: "the front door's self-hosted Remote Control surface is on but no credential has been minted for it; run agent-shim frontdoor rc selfhost mint first" } });
5665
+ };
5666
+ const epochStale = async (response) => {
5667
+ await answerJson2(response, HTTP_CONFLICT, { type: "error", error: { type: "api_error", message: "worker_epoch does not match the session's live epoch" } }, { [CONFLICT_REASON_HEADER2]: CONFLICT_REASON_EPOCH_STALE });
5668
+ };
5669
+ const unauthorized = async (response) => {
5670
+ await answerJson2(response, HTTP_STATUS.unauthorized, { type: "error", error: { type: "authentication_error", message: "the self-hosted Remote Control surface did not recognise the presented credential" } });
5671
+ };
5672
+ const serveSessionPath = async (session, tail, request4, response) => {
5673
+ const method = request4.method.toUpperCase();
5674
+ if (session === void 0) {
5675
+ await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: "no such Remote Control session on this door" } });
5676
+ return;
5677
+ }
5678
+ session.lastTrafficAt = deps.now();
5679
+ if (tail === "") {
5680
+ if (method !== "GET") {
5681
+ await answerJson2(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the session read is a GET" } });
5682
+ return;
5683
+ }
5684
+ await answerJson2(response, HTTP_STATUS.ok, { session: { id: session.id, title: session.title, created_at: new Date(session.createdAt).toISOString(), status: "active" } });
5685
+ return;
5686
+ }
5687
+ if (tail === "bridge" && method === "POST") {
5688
+ if (!presentsCredential(request4.headers)) {
5689
+ await unauthorized(response);
5690
+ return;
5691
+ }
5692
+ const workerJwt = mintWorkerJwt(deps.randomToken, deps.now());
5693
+ session.workerJwts.add(workerJwt);
5694
+ deps.log?.(`rc selfhost ${session.id}: bridge registration minted a worker credential`);
5695
+ await answerJson2(response, HTTP_STATUS.ok, { worker_jwt: workerJwt, expires_in: RC_SELF_HOST_WORKER_JWT_TTL_SECONDS, api_base_url: RC_SELF_HOST_API_BASE_URL, worker_epoch: RC_SELF_HOST_WORKER_EPOCH });
5696
+ return;
5697
+ }
5698
+ if (tail === "archive" && method === "POST") {
5699
+ if (!presentsCredential(request4.headers)) {
5700
+ await unauthorized(response);
5701
+ return;
5702
+ }
5703
+ for (const sink of [...session.workerStreams, ...session.clientStreams]) {
5704
+ sink.retire();
5705
+ }
5706
+ sessions.delete(session.id);
5707
+ deps.log?.(`rc selfhost ${session.id}: archived at its client's request`);
5708
+ await answerJson2(response, HTTP_STATUS.ok, {});
5709
+ return;
5710
+ }
5711
+ if (tail === "worker" || tail.startsWith("worker/")) {
5712
+ if (!presentsWorkerJwt(request4.headers, session)) {
5713
+ await unauthorized(response);
5714
+ return;
5715
+ }
5716
+ const workerTail = tail === "worker" ? "" : tail.slice("worker/".length);
5717
+ if (workerTail === "" && method === "GET") {
5718
+ await answerJson2(response, HTTP_STATUS.ok, { worker: { external_metadata: session.externalMetadata ?? null } });
5719
+ return;
5720
+ }
5721
+ if (workerTail === "" && method === "PUT") {
5722
+ const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
5723
+ const claimedEpoch = numberOf(body, "worker_epoch");
5724
+ if (claimedEpoch !== void 0 && claimedEpoch !== RC_SELF_HOST_WORKER_EPOCH) {
5725
+ await epochStale(response);
5726
+ return;
5727
+ }
5728
+ const status = nonEmptyString2(body, "worker_status");
5729
+ if (status !== void 0) {
5730
+ session.workerStatus = status;
5731
+ }
5732
+ if (isRecord5(body?.external_metadata)) {
5733
+ session.externalMetadata = body.external_metadata;
5734
+ }
5735
+ await answerJson2(response, HTTP_STATUS.ok, {});
5736
+ return;
5737
+ }
5738
+ if (workerTail === "register" && method === "POST") {
5739
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5740
+ await answerJson2(response, HTTP_STATUS.ok, { worker_epoch: RC_SELF_HOST_WORKER_EPOCH });
5741
+ return;
5742
+ }
5743
+ if (workerTail === "heartbeat" && method === "POST") {
5744
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5745
+ await answerJson2(response, HTTP_STATUS.ok, {});
5746
+ return;
5747
+ }
5748
+ if (workerTail === "events" && method === "POST") {
5749
+ const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
5750
+ const claimedEpoch = numberOf(body, "worker_epoch");
5751
+ if (claimedEpoch !== void 0 && claimedEpoch !== RC_SELF_HOST_WORKER_EPOCH) {
5752
+ await epochStale(response);
5753
+ return;
5754
+ }
5755
+ const events = body?.events;
5756
+ if (!Array.isArray(events) || events.length === 0 || events.length > RC_SELF_HOST_MAX_BATCH_EVENTS) {
5757
+ await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: `a worker event batch is a non-empty array of at most ${String(RC_SELF_HOST_MAX_BATCH_EVENTS)} events` } });
5758
+ return;
5759
+ }
5760
+ const results = [];
5761
+ for (const event of events) {
5762
+ if (!isRecord5(event) || !isRecord5(event.payload)) {
5763
+ await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "every event in a batch is an object carrying one payload object" } });
5764
+ return;
5765
+ }
5766
+ const published = publish(session, RC_SOURCE_WORKER, event.payload);
5767
+ results.push({ event_id: published.eventId, sequence_num: String(published.sequenceNum) });
5768
+ }
5769
+ sweep();
5770
+ await answerJson2(response, HTTP_STATUS.ok, { results });
5771
+ return;
5772
+ }
5773
+ if (workerTail === "events/stream" && method === "GET") {
5774
+ await holdStream(session, "workerStreams", (event) => event.toWorker, request4, response);
5775
+ return;
5776
+ }
5777
+ if (workerTail === "events/delivery" && method === "POST") {
5778
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5779
+ await answerJson2(response, HTTP_STATUS.ok, {});
5780
+ return;
5781
+ }
5782
+ if (workerTail === "internal-events" && method === "POST") {
5783
+ const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
5784
+ const claimedEpoch = numberOf(body, "worker_epoch");
5785
+ if (claimedEpoch !== void 0 && claimedEpoch !== RC_SELF_HOST_WORKER_EPOCH) {
5786
+ await epochStale(response);
5787
+ return;
5788
+ }
5789
+ const events = body?.events;
5790
+ if (!Array.isArray(events)) {
5791
+ await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "an internal event batch is an array" } });
5792
+ return;
5793
+ }
5794
+ for (const event of events) {
5795
+ if (isRecord5(event)) {
5796
+ session.internalEvents.push({ cursor: deps.newUuid(), body: event });
5797
+ }
5798
+ }
5799
+ await answerJson2(response, HTTP_STATUS.ok, {});
5800
+ return;
5801
+ }
5802
+ if (workerTail === "internal-events" && method === "GET") {
5803
+ const url = new URL(request4.url, "http://127.0.0.1");
5804
+ const cursor = url.searchParams.get("cursor");
5805
+ const from = cursor === null ? 0 : session.internalEvents.findIndex((event) => event.cursor === cursor) + 1;
5806
+ const page = session.internalEvents.slice(from);
5807
+ await answerJson2(response, HTTP_STATUS.ok, { data: page.map((event) => event.body), next_cursor: page.length === 0 ? void 0 : page[page.length - 1]?.cursor });
5808
+ return;
5809
+ }
5810
+ if (workerTail === "diagnostics" && method === "POST") {
5811
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5812
+ await answerJson2(response, HTTP_STATUS.ok, {});
5813
+ return;
5814
+ }
5815
+ await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `the self-hosted Remote Control surface serves no worker path "${workerTail}"` } });
5816
+ return;
5817
+ }
5818
+ if (!presentsCredential(request4.headers)) {
5819
+ await unauthorized(response);
5820
+ return;
5821
+ }
5822
+ if (tail === "events" && method === "POST") {
5823
+ const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
5824
+ const events = body?.events;
5825
+ if (!Array.isArray(events) || events.length === 0 || events.length > RC_SELF_HOST_MAX_BATCH_EVENTS) {
5826
+ await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: `a client event write is a non-empty array of at most ${String(RC_SELF_HOST_MAX_BATCH_EVENTS)} events` } });
5827
+ return;
5828
+ }
5829
+ const results = [];
5830
+ for (const event of events) {
5831
+ if (!isRecord5(event) || !isRecord5(event.payload)) {
5832
+ await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "every event in a write is an object carrying one payload object" } });
5833
+ return;
5834
+ }
5835
+ const published = publish(session, RC_SOURCE_CLIENT, event.payload);
5836
+ results.push({ sequence_num: String(published.sequenceNum), duplicate: published.duplicate });
5837
+ }
5838
+ sweep();
5839
+ await answerJson2(response, HTTP_STATUS.ok, { results });
5840
+ return;
5841
+ }
5842
+ if (tail === "events" && method === "GET") {
5843
+ await answerJson2(response, HTTP_STATUS.ok, { data: session.events.map((event) => ({ event_id: event.eventId, event_type: nonEmptyString2(event.payload, "type") ?? "event", sequence_num: event.sequenceNum, source: event.source, payload: event.payload, created_at: event.createdAt })) });
5844
+ return;
5845
+ }
5846
+ if (tail === "events/stream" && method === "GET") {
5847
+ await holdStream(session, "clientStreams", () => true, request4, response);
5848
+ return;
5849
+ }
5850
+ if (tail === "client/presence" && method === "POST") {
5851
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5852
+ await answerJson2(response, HTTP_STATUS.ok, { refresh_after_seconds: RC_PRESENCE_REFRESH_SECONDS });
5853
+ return;
5854
+ }
5855
+ if (tail === "mark_read" && method === "POST") {
5856
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5857
+ await answerJson2(response, HTTP_STATUS.ok, {});
5858
+ return;
5859
+ }
5860
+ if (tail === "teleport-events" && method === "POST") {
5861
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5862
+ await answerJson2(response, HTTP_STATUS.ok, {});
5863
+ return;
5864
+ }
5865
+ await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `the self-hosted Remote Control surface serves no path "${tail}"` } });
5866
+ };
5867
+ const recordMissing = () => deps.credentialRecord() === void 0;
5868
+ const route = {
5869
+ name: "rc-selfhost",
5870
+ headroomEligible: false,
5871
+ headroomUpstream: void 0,
5872
+ serve: async (request4, response) => {
5873
+ const method = request4.method.toUpperCase();
5874
+ const pathname = new URL(request4.url, "http://127.0.0.1").pathname;
5875
+ if (recordMissing()) {
5876
+ await noCredential(response);
5877
+ return;
5878
+ }
5879
+ if (pathname === RC_COMPAT_SESSIONS_PATH) {
5880
+ if (method !== "GET") {
5881
+ await answerJson2(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the compatibility session list is a GET" } });
5882
+ return;
5883
+ }
5884
+ if (!presentsCredential(request4.headers)) {
5885
+ await unauthorized(response);
5886
+ return;
5887
+ }
5888
+ await answerJson2(response, HTTP_STATUS.ok, { data: [] });
5889
+ return;
5890
+ }
5891
+ if (pathname !== RC_SESSIONS_PATH_PREFIX2 && !pathname.startsWith(`${RC_SESSIONS_PATH_PREFIX2}/`)) {
5892
+ await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `the self-hosted Remote Control surface serves no path "${pathname}"` } });
5893
+ return;
5894
+ }
5895
+ if (pathname === RC_SESSIONS_PATH_PREFIX2) {
5896
+ if (method === "POST") {
5897
+ if (!presentsCredential(request4.headers)) {
5898
+ await unauthorized(response);
5899
+ return;
5900
+ }
5901
+ const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
5902
+ const session = {
5903
+ id: `${RC_SESSION_ID_PREFIX2}${deps.newUuid()}`,
5904
+ createdAt: deps.now(),
5905
+ title: nonEmptyString2(body, "title"),
5906
+ workerJwts: /* @__PURE__ */ new Set(),
5907
+ sequenceNum: 0,
5908
+ events: [],
5909
+ seenPayloadUuids: /* @__PURE__ */ new Set(),
5910
+ workerStreams: /* @__PURE__ */ new Set(),
5911
+ clientStreams: /* @__PURE__ */ new Set(),
5912
+ internalEvents: [],
5913
+ workerStatus: void 0,
5914
+ externalMetadata: void 0,
5915
+ lastTrafficAt: deps.now()
5916
+ };
5917
+ sessions.set(session.id, session);
5918
+ deps.log?.(`rc selfhost ${session.id}: session created on the door's own surface`);
5919
+ await answerJson2(response, HTTP_STATUS.ok, { session: { id: session.id, title: session.title, created_at: new Date(session.createdAt).toISOString(), status: "active" } });
5920
+ return;
5921
+ }
5922
+ if (method === "GET") {
5923
+ if (!presentsCredential(request4.headers)) {
5924
+ await unauthorized(response);
5925
+ return;
5926
+ }
5927
+ await answerJson2(response, HTTP_STATUS.ok, { data: [...sessions.values()].map((session) => ({ id: session.id, title: session.title, created_at: new Date(session.createdAt).toISOString(), updated_at: new Date(session.lastTrafficAt).toISOString(), session_status: "active" })) });
5928
+ return;
5929
+ }
5930
+ await answerJson2(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the session collection is a POST (create) and a GET (list)" } });
5931
+ return;
5932
+ }
5933
+ const rest = pathname.slice(`${RC_SESSIONS_PATH_PREFIX2}/`.length);
5934
+ const slash = rest.indexOf("/");
5935
+ const id = slash === -1 ? rest : rest.slice(0, slash);
5936
+ const tail = slash === -1 ? "" : rest.slice(slash + 1);
5937
+ if (!id.startsWith(RC_SESSION_ID_PREFIX2)) {
5938
+ await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: "the session family names one cse_-prefixed session id" } });
5939
+ return;
5940
+ }
5941
+ await serveSessionPath(sessions.get(id), tail, request4, response);
5942
+ }
5943
+ };
5944
+ const answerServerJson = (response, status, body) => {
5945
+ const text = JSON.stringify(body);
5946
+ response.writeHead(status, { "content-type": "application/json", "content-length": String(Buffer.byteLength(text, "utf8")) });
5947
+ response.end(text);
5948
+ };
5949
+ const local = {
5950
+ parsesHost: (host) => host === RC_SELF_HOST_OAUTH_HOST,
5951
+ serve: async (host, request4, response) => {
5952
+ const method = (request4.method ?? "").toUpperCase();
5953
+ const pathname = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
5954
+ if (host === RC_SELF_HOST_OAUTH_HOST) {
5955
+ if (method === "POST" && pathname === "/v1/oauth/token") {
5956
+ const body = parseJsonObject2(await readBody2(request4, CONTROL_BODY_CAP_BYTES));
5957
+ const record = deps.credentialRecord();
5958
+ if (record === void 0) {
5959
+ answerServerJson(response, HTTP_SERVICE_UNAVAILABLE, { error: "the front door's self-hosted Remote Control surface is on but no credential has been minted for it" });
5960
+ return true;
5961
+ }
5962
+ if (body?.grant_type !== void 0 && body.grant_type !== "refresh_token") {
5963
+ answerServerJson(response, HTTP_STATUS.badRequest, { error: "unsupported_grant_type" });
5964
+ return true;
5965
+ }
5966
+ answerServerJson(response, HTTP_STATUS.ok, { access_token: record.accessToken, refresh_token: record.refreshToken, expires_in: RC_SELF_HOST_OAUTH_TOKEN_TTL_SECONDS, scope: RC_SELF_HOST_SCOPE_LIST.join(" ") });
5967
+ return true;
5968
+ }
5969
+ if (method === "GET" && pathname === "/v1/oauth/hello") {
5970
+ answerServerJson(response, HTTP_STATUS.ok, {});
5971
+ return true;
5972
+ }
5973
+ return false;
5974
+ }
5975
+ if (method === "POST" && pathname.startsWith("/api/eval/")) {
5976
+ await readBody2(request4, CONTROL_BODY_CAP_BYTES);
5977
+ answerServerJson(response, HTTP_STATUS.ok, { features: growthBookFeatures(), dateUpdated: Math.floor(deps.now() / MS_PER_SECOND2) });
5978
+ return true;
5979
+ }
5980
+ if (method === "GET" && pathname === "/api/oauth/profile") {
5981
+ const record = deps.credentialRecord();
5982
+ if (record === void 0) {
5983
+ answerServerJson(response, HTTP_SERVICE_UNAVAILABLE, { error: "the front door's self-hosted Remote Control surface is on but no credential has been minted for it" });
5984
+ return true;
5985
+ }
5986
+ answerServerJson(response, HTTP_STATUS.ok, {
5987
+ account: { uuid: record.accountUuid, display_name: "agent-shim self-hosted", created_at: (/* @__PURE__ */ new Date(0)).toISOString() },
5988
+ organization: { uuid: record.organizationUuid, organization_type: "claude_max" }
5989
+ });
5990
+ return true;
5991
+ }
5992
+ if (method === "GET" && pathname === "/api/claude_code/policy_limits") {
5993
+ answerServerJson(response, HTTP_STATUS.ok, {});
5994
+ return true;
5995
+ }
5996
+ if (method === "POST" && pathname === "/api/oauth/validate") {
5997
+ await readBody2(request4, CONTROL_BODY_CAP_BYTES);
5998
+ const record = deps.credentialRecord();
5999
+ if (record === void 0) {
6000
+ answerServerJson(response, HTTP_SERVICE_UNAVAILABLE, { error: "the front door's self-hosted Remote Control surface is on but no credential has been minted for it" });
6001
+ return true;
6002
+ }
6003
+ answerServerJson(response, HTTP_STATUS.ok, { scopes: [...RC_SELF_HOST_SCOPE_LIST], expiresAt: null, subscriptionType: "max", account_uuid: record.accountUuid, organization_uuid: record.organizationUuid });
6004
+ return true;
6005
+ }
6006
+ if (method === "POST" && (pathname === "/api/event_logging/v2/batch" || pathname === "/api/claude_code/metrics" || pathname === "/api/claude_cli_feedback")) {
6007
+ await readBody2(request4, CONTROL_BODY_CAP_BYTES);
6008
+ answerServerJson(response, HTTP_STATUS.ok, {});
6009
+ return true;
6010
+ }
6011
+ if (method === "GET" && pathname === "/api/hello") {
6012
+ answerServerJson(response, HTTP_STATUS.ok, {});
6013
+ return true;
6014
+ }
6015
+ return false;
6016
+ }
6017
+ };
6018
+ return {
6019
+ route,
6020
+ local,
6021
+ close: () => {
6022
+ clearInterval(timer);
6023
+ clearInterval(keepalive);
6024
+ for (const session of sessions.values()) {
6025
+ for (const sink of [...session.workerStreams, ...session.clientStreams]) {
6026
+ sink.retire();
6027
+ }
6028
+ }
6029
+ sessions.clear();
6030
+ }
6031
+ };
6032
+ }
6033
+
6034
+ // src/frontdoor/rcSelfHostMint.ts
6035
+ var import_node_path11 = __toESM(require("node:path"), 1);
6036
+
6037
+ // src/usage/account.ts
6038
+ var import_node_path10 = __toESM(require("node:path"), 1);
6039
+
6040
+ // src/usage/schema.ts
6041
+ var import_zod5 = require("zod");
6042
+ var USAGE_SCHEMA_VERSION = 1;
6043
+ var VersionSchema = import_zod5.z.literal(USAGE_SCHEMA_VERSION);
6044
+ var InstantSchema = import_zod5.z.iso.datetime();
6045
+ var TokenCountSchema = import_zod5.z.number().int().nonnegative();
6046
+ var TokenUsageSchema = import_zod5.z.strictObject({
6047
+ inputTokens: TokenCountSchema.optional(),
6048
+ outputTokens: TokenCountSchema.optional(),
6049
+ cacheCreationInputTokens: TokenCountSchema.optional(),
6050
+ cacheReadInputTokens: TokenCountSchema.optional()
6051
+ });
6052
+ var LIMIT_KINDS = ["rate-limited", "quota-exhausted"];
6053
+ var LimitClassificationSchema = import_zod5.z.strictObject({
6054
+ kind: import_zod5.z.enum(LIMIT_KINDS),
6055
+ /** Seconds to wait before retrying, from the response's `retry-after`. */
6056
+ retryAfterSeconds: import_zod5.z.number().nonnegative().optional(),
6057
+ /** When the limiting window resets, from the upstream's own reset header. */
6058
+ resetAt: InstantSchema.optional(),
6059
+ /** The window the upstream named as the binding one (`anthropic-ratelimit-unified-representative-claim`), such as `five_hour` or `seven_day`. */
6060
+ window: import_zod5.z.string().optional(),
6061
+ /** The signals the classification rests on, each `<name>=<value>` from a response header or the error body's `type` or `code`. Never the error message. */
6062
+ evidence: import_zod5.z.array(import_zod5.z.string())
6063
+ });
6064
+ var UsageRecordSchema = import_zod5.z.strictObject({
6065
+ schemaVersion: VersionSchema,
6066
+ /** When the front door received the request. */
6067
+ at: InstantSchema,
6068
+ /** The launching identity, when the launch resolved one. */
6069
+ identity: import_zod5.z.string().optional(),
6070
+ /** `anthropic` for an OAuth session's request to Claude Code's own API, otherwise the provider's name. */
6071
+ provider: import_zod5.z.string(),
6072
+ /** The launch's session id, generated per launch. */
6073
+ sessionId: import_zod5.z.string().optional(),
6074
+ /** The project the launch ran in (its git repository root), when the launch sent one: headroom launches do. */
6075
+ project: import_zod5.z.string().optional(),
6076
+ /** The front-door route that served the request. */
6077
+ route: import_zod5.z.string(),
6078
+ method: import_zod5.z.string(),
6079
+ /** The API path as the upstream sees it (`/v1/messages`), without the provider prefix or a query string. */
6080
+ endpoint: import_zod5.z.string(),
6081
+ /** The model the response named. */
6082
+ model: import_zod5.z.string().optional(),
6083
+ status: import_zod5.z.number().int(),
6084
+ /** Milliseconds from the request's arrival to its response head. */
6085
+ latencyMs: import_zod5.z.number().int().nonnegative(),
6086
+ /** Milliseconds from the request's arrival to the end of its response body. */
6087
+ durationMs: import_zod5.z.number().int().nonnegative(),
6088
+ /** Whether the client received the whole body. */
6089
+ outcome: import_zod5.z.enum(["completed", "aborted"]),
6090
+ usage: TokenUsageSchema.optional(),
6091
+ /** The response's quota and rate-limit headers, by name (see `isRateLimitHeader`). */
6092
+ rateLimitHeaders: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.string()).optional(),
6093
+ limit: LimitClassificationSchema.optional(),
6094
+ /** The upstream's request id (`request-id`), for matching a record to the provider's own logs. */
6095
+ requestId: import_zod5.z.string().optional()
6096
+ });
6097
+ var QuotaWindowSchema = import_zod5.z.strictObject({
6098
+ /** The fraction of the window used, as the upstream reports it (0 to 1). */
6099
+ utilization: import_zod5.z.number().nonnegative().optional(),
6100
+ resetsAt: InstantSchema.optional(),
6101
+ /** The window's own status (`allowed`, `allowed_warning`, `rejected`). */
6102
+ status: import_zod5.z.string().optional()
6103
+ });
6104
+ var UnifiedRateLimitSchema = import_zod5.z.strictObject({
6105
+ /** The overall status: `allowed`, `allowed_warning` or `rejected`. */
6106
+ status: import_zod5.z.string().optional(),
6107
+ fiveHour: QuotaWindowSchema.optional(),
6108
+ sevenDay: QuotaWindowSchema.optional(),
6109
+ /** The window that currently binds. */
6110
+ representativeClaim: import_zod5.z.string().optional(),
6111
+ /** When the binding window resets. */
6112
+ resetAt: InstantSchema.optional(),
6113
+ /** Whether usage beyond the plan (extra usage) is available: `allowed` or `rejected`. */
6114
+ overageStatus: import_zod5.z.string().optional()
6115
+ });
6116
+ var RateLimitStateSchema = import_zod5.z.strictObject({
6117
+ observedAt: InstantSchema,
6118
+ /** Every quota and rate-limit header on that response, by name. */
6119
+ headers: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.string()),
6120
+ unified: UnifiedRateLimitSchema.optional()
6121
+ });
6122
+ var LimitEventSchema = LimitClassificationSchema.extend({
6123
+ observedAt: InstantSchema,
6124
+ status: import_zod5.z.number().int()
6125
+ });
6126
+ var ProviderQuotaWindowSchema = import_zod5.z.strictObject({
6127
+ /** What the window measures, in the provider's terms (`tokens`, `tool-calls`). */
6128
+ measures: import_zod5.z.string(),
6129
+ /** The window's length in milliseconds, when the provider's unit is one this project knows; absent for an unrecognised unit, with `period` carrying the raw code. */
6130
+ periodMs: import_zod5.z.number().int().positive().optional(),
6131
+ /** The provider's own description of the period when `periodMs` could not be derived, such as `unit 4 x 1`. */
6132
+ period: import_zod5.z.string().optional(),
6133
+ /** The fraction of the window used (0 to 1). */
6134
+ utilization: import_zod5.z.number().nonnegative(),
6135
+ resetsAt: InstantSchema.optional(),
6136
+ /** Absolute counts, when the provider reports them for this window. */
6137
+ limit: import_zod5.z.number().nonnegative().optional(),
6138
+ used: import_zod5.z.number().nonnegative().optional(),
6139
+ remaining: import_zod5.z.number().nonnegative().optional()
6140
+ });
6141
+ var ProviderQuotaSchema = import_zod5.z.strictObject({
6142
+ observedAt: InstantSchema,
6143
+ /** Which usage endpoint produced it (`z.ai`). */
6144
+ source: import_zod5.z.string(),
6145
+ /** The subscription level the endpoint reports, when it does. */
6146
+ level: import_zod5.z.string().optional(),
6147
+ windows: import_zod5.z.array(ProviderQuotaWindowSchema)
6148
+ });
6149
+ var ProviderUsageStateSchema = import_zod5.z.strictObject({
6150
+ lastRequestAt: InstantSchema,
6151
+ lastStatus: import_zod5.z.number().int(),
6152
+ lastModel: import_zod5.z.string().optional(),
6153
+ /** The latest rate-limit state, from the last response that carried any rate-limit header. */
6154
+ rateLimit: RateLimitStateSchema.optional(),
6155
+ /** The latest classified refusal. It stays after later successes, so a reader compares its `resetAt` (or `observedAt` plus `retryAfterSeconds`) with the current time. */
6156
+ lastLimit: LimitEventSchema.optional(),
6157
+ /** The latest quota the provider's usage endpoint reported, for providers whose quota is not visible in response headers. */
6158
+ quota: ProviderQuotaSchema.optional()
6159
+ });
6160
+ var AccountMetadataSchema = import_zod5.z.strictObject({
6161
+ accountUuid: import_zod5.z.string().optional(),
6162
+ emailAddress: import_zod5.z.string().optional(),
6163
+ displayName: import_zod5.z.string().optional(),
6164
+ organizationUuid: import_zod5.z.string().optional(),
6165
+ organizationName: import_zod5.z.string().optional(),
6166
+ organizationType: import_zod5.z.string().optional(),
6167
+ organizationRole: import_zod5.z.string().optional(),
6168
+ workspaceRole: import_zod5.z.string().optional(),
6169
+ billingType: import_zod5.z.string().optional(),
6170
+ seatTier: import_zod5.z.string().optional(),
6171
+ organizationRateLimitTier: import_zod5.z.string().optional(),
6172
+ userRateLimitTier: import_zod5.z.string().optional(),
6173
+ hasExtraUsageEnabled: import_zod5.z.boolean().optional(),
6174
+ subscriptionCreatedAt: import_zod5.z.string().optional(),
6175
+ accountCreatedAt: import_zod5.z.string().optional()
6176
+ });
6177
+ var UsageSnapshotSchema = import_zod5.z.strictObject({
6178
+ schemaVersion: VersionSchema,
6179
+ identity: import_zod5.z.string(),
6180
+ updatedAt: InstantSchema,
6181
+ /** The identity's account metadata as of `updatedAt`. */
6182
+ account: AccountMetadataSchema.optional(),
6183
+ /** Latest state per provider, keyed by provider name (`anthropic` for OAuth sessions). */
6184
+ providers: import_zod5.z.record(import_zod5.z.string(), ProviderUsageStateSchema)
6185
+ });
6186
+
6187
+ // src/usage/account.ts
6188
+ var CLAUDE_JSON = ".claude.json";
6189
+ var AccountMetadataError = class extends CliError {
6190
+ constructor(file, detail) {
6191
+ super(`${file}: ${detail}, so its account metadata cannot be read.`);
6192
+ this.file = file;
6193
+ this.name = "AccountMetadataError";
6194
+ }
6195
+ file;
6196
+ };
6197
+ function isObject(value) {
6198
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6199
+ }
6200
+ function isIdentityName(name) {
6201
+ return IdentitySchema.shape.name.safeParse(name).success;
6202
+ }
6203
+ function claudeJsonPath(identitiesDir, identity) {
6204
+ return import_node_path10.default.join(identitiesDir, identity, CLAUDE_JSON);
6205
+ }
6206
+ function readAccountMetadata(fs12, identitiesDir, identity) {
6207
+ if (!isIdentityName(identity)) {
6208
+ throw new Error(`"${identity}" is not a valid identity name.`);
6209
+ }
6210
+ const file = claudeJsonPath(identitiesDir, identity);
6211
+ const raw = fs12.readFileUtf8(file);
6212
+ if (raw === void 0) {
6213
+ return void 0;
6214
+ }
6215
+ let parsed;
6216
+ try {
6217
+ parsed = JSON.parse(raw);
6218
+ } catch {
6219
+ throw new AccountMetadataError(file, "not valid JSON");
6220
+ }
6221
+ if (!isObject(parsed)) {
6222
+ throw new AccountMetadataError(file, "not a JSON object");
6223
+ }
6224
+ const oauthAccount = parsed.oauthAccount;
6225
+ if (!isObject(oauthAccount)) {
6226
+ return void 0;
6227
+ }
6228
+ const picked = {};
6229
+ for (const key of Object.keys(AccountMetadataSchema.shape)) {
6230
+ const value = oauthAccount[key];
6231
+ if (value !== null && value !== void 0) {
6232
+ picked[key] = value;
6233
+ }
6234
+ }
6235
+ const account = AccountMetadataSchema.safeParse(picked);
6236
+ if (!account.success) {
6237
+ throw new AccountMetadataError(file, account.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; "));
6238
+ }
6239
+ return account.data;
6240
+ }
6241
+
6242
+ // src/frontdoor/rcSelfHostMint.ts
6243
+ var CREDENTIALS_FILE = ".credentials.json";
6244
+ var CLAUDE_JSON2 = ".claude.json";
6245
+ var RC_SELF_HOST_RECORD_DIR = "rc-selfhost";
6246
+ var RC_SELF_HOST_RECORD_FILE = "credential.json";
6247
+ var SELF_HOST_EMAIL = "selfhost@agent-shim.invalid";
6248
+ var SELF_HOST_SUBSCRIPTION_TYPE = "max";
6249
+ function isRecord6(value) {
6250
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6251
+ }
6252
+ function readJsonObject(fs12, file) {
6253
+ const raw = fs12.readFileUtf8(file);
6254
+ if (raw === void 0) {
6255
+ return void 0;
6256
+ }
6257
+ let parsed;
6258
+ try {
6259
+ parsed = JSON.parse(raw);
6260
+ } catch {
6261
+ return void 0;
6262
+ }
6263
+ return isRecord6(parsed) ? parsed : void 0;
6264
+ }
6265
+ function readRcSelfHostRecord(fs12, frontdoorDir) {
6266
+ const parsed = readJsonObject(fs12, import_node_path11.default.join(frontdoorDir, RC_SELF_HOST_RECORD_DIR, RC_SELF_HOST_RECORD_FILE));
6267
+ if (parsed === void 0) {
6268
+ return void 0;
6269
+ }
6270
+ const { accessToken, refreshToken, organizationUuid, accountUuid } = parsed;
6271
+ if (typeof accessToken !== "string" || accessToken === "" || typeof refreshToken !== "string" || refreshToken === "" || typeof organizationUuid !== "string" || organizationUuid === "" || typeof accountUuid !== "string" || accountUuid === "") {
6272
+ return void 0;
6273
+ }
6274
+ return { accessToken, refreshToken, organizationUuid, accountUuid };
6275
+ }
6276
+ function mintRcSelfHostCredential(deps) {
6277
+ if (!isIdentityName(deps.identity)) {
6278
+ throw new Error(`"${deps.identity}" is not a valid identity name.`);
6279
+ }
6280
+ const identityDir = import_node_path11.default.join(deps.identitiesDir, deps.identity);
6281
+ const credentialsFile = import_node_path11.default.join(identityDir, CREDENTIALS_FILE);
6282
+ const claudeJsonFile = import_node_path11.default.join(identityDir, CLAUDE_JSON2);
6283
+ const recordDir = import_node_path11.default.join(deps.frontdoorDir, RC_SELF_HOST_RECORD_DIR);
6284
+ const recordFile = import_node_path11.default.join(recordDir, RC_SELF_HOST_RECORD_FILE);
6285
+ const previousRecord = readRcSelfHostRecord(deps.fs, deps.frontdoorDir);
6286
+ const existingCredentials = readJsonObject(deps.fs, credentialsFile);
6287
+ const existingOauth = isRecord6(existingCredentials?.claudeAiOauth) ? existingCredentials.claudeAiOauth : void 0;
6288
+ const existingToken = typeof existingOauth?.accessToken === "string" && existingOauth.accessToken !== "" ? existingOauth.accessToken : void 0;
6289
+ const existingIsOwn = existingToken !== void 0 && previousRecord?.accessToken === existingToken;
6290
+ if (existingToken !== void 0 && !existingIsOwn && !deps.force) {
6291
+ throw new Error(
6292
+ `identity ${deps.identity} already holds an OAuth credential this door did not mint (a real claude.ai login): pass --force to replace it, or mint into an identity with no login. The self-hosted mode expects no Anthropic credential to be in play.`
6293
+ );
6294
+ }
6295
+ const accessToken = `sk-ant-oat${deps.randomToken()}`;
6296
+ const refreshToken = deps.randomToken();
6297
+ const organizationUuid = deps.newUuid();
6298
+ const accountUuid = deps.newUuid();
6299
+ const mintedAt = new Date(deps.now()).toISOString();
6300
+ deps.fs.mkdirPrivate(import_node_path11.default.dirname(credentialsFile));
6301
+ deps.fs.writeFilePrivate(credentialsFile, `${JSON.stringify({ ...existingCredentials, claudeAiOauth: { accessToken, refreshToken, expiresAt: null, scopes: [...RC_SELF_HOST_SCOPE_LIST], subscriptionType: SELF_HOST_SUBSCRIPTION_TYPE, rateLimitTier: null } }, null, 2)}
6302
+ `);
6303
+ const claudeJson = readJsonObject(deps.fs, claudeJsonFile) ?? {};
6304
+ const existingBlock = (value) => isRecord6(value) ? value : {};
6305
+ deps.fs.writeFilePrivate(claudeJsonFile, `${JSON.stringify({
6306
+ ...claudeJson,
6307
+ oauthAccount: {
6308
+ ...existingBlock(claudeJson.oauthAccount),
6309
+ accountUuid,
6310
+ emailAddress: SELF_HOST_EMAIL,
6311
+ organizationUuid,
6312
+ organizationName: "agent-shim self-hosted",
6313
+ // The billing and creation fields exist so the CLI's "populate the account block if it is missing" step finds a complete block and skips its profile fetch; the door answers that fetch locally anyway, so these are the quiet path, not a load-bearing claim.
6314
+ billingType: "stripe_subscription",
6315
+ accountCreatedAt: mintedAt,
6316
+ subscriptionCreatedAt: mintedAt
5381
6317
  },
5382
- close: () => {
5383
- for (const attachment of attachments.values()) {
5384
- attachment.stop();
5385
- }
5386
- attachments.clear();
6318
+ cachedGrowthBookFeatures: {
6319
+ ...existingBlock(claudeJson.cachedGrowthBookFeatures),
6320
+ tengu_ccr_bridge: true,
6321
+ tengu_bridge_repl_v2: true,
6322
+ tengu_bridge_repl_v2_cse_shim_enabled: true
5387
6323
  }
5388
- };
6324
+ }, null, 2)}
6325
+ `);
6326
+ deps.fs.mkdirPrivate(recordDir);
6327
+ deps.fs.writeFilePrivate(recordFile, `${JSON.stringify({ accessToken, refreshToken, organizationUuid, accountUuid }, null, 2)}
6328
+ `);
6329
+ return { identity: deps.identity, organizationUuid, credentialsFile, claudeJsonFile, recordFile, replaced: existingIsOwn };
5389
6330
  }
5390
6331
 
5391
6332
  // src/frontdoor/ensure.ts
@@ -5393,32 +6334,32 @@ var import_node_crypto7 = require("node:crypto");
5393
6334
 
5394
6335
  // src/headroom/state.ts
5395
6336
  var import_node_crypto6 = require("node:crypto");
5396
- var import_node_path10 = __toESM(require("node:path"), 1);
5397
- var import_zod5 = require("zod");
6337
+ var import_node_path12 = __toESM(require("node:path"), 1);
6338
+ var import_zod6 = require("zod");
5398
6339
  var HEADROOM_ANTHROPIC_UPSTREAM = "https://api.anthropic.com";
5399
6340
  var HEADROOM_STATE_SCHEMA_VERSION = 2;
5400
- var HeadroomStateSchema = import_zod5.z.strictObject({
6341
+ var HeadroomStateSchema = import_zod6.z.strictObject({
5401
6342
  /** The supervisor process owning the daemon. Alive means someone is keeping headroom running. */
5402
- supervisorPid: import_zod5.z.number().int().positive().optional(),
6343
+ supervisorPid: import_zod6.z.number().int().positive().optional(),
5403
6344
  /** The headroom proxy process itself. Absent while the supervisor is between restarts. */
5404
- headroomPid: import_zod5.z.number().int().positive().optional(),
6345
+ headroomPid: import_zod6.z.number().int().positive().optional(),
5405
6346
  /**
5406
6347
  * 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.
5407
6348
  */
5408
- socketPath: import_zod5.z.string().min(1).optional(),
6349
+ socketPath: import_zod6.z.string().min(1).optional(),
5409
6350
  /** The `headroom --version` output of the running install. */
5410
- version: import_zod5.z.string().optional(),
6351
+ version: import_zod6.z.string().optional(),
5411
6352
  /** Hash of the allowlist the running proxy was started with, so a provider-file change is detected as drift. */
5412
- allowlistHash: import_zod5.z.string().optional(),
6353
+ allowlistHash: import_zod6.z.string().optional(),
5413
6354
  /** Hash of the token-saving settings the running proxy was started with, so a settings change is detected as drift. */
5414
- settingsHash: import_zod5.z.string().optional(),
6355
+ settingsHash: import_zod6.z.string().optional(),
5415
6356
  /** The install spec the running install was last installed from, so a `source` config change is detected as drift. */
5416
- installedSource: import_zod5.z.string().optional(),
6357
+ installedSource: import_zod6.z.string().optional(),
5417
6358
  /** The last fatal error, kept across shutdowns so `headroom status` can explain a daemon that is not running. */
5418
- lastError: import_zod5.z.string().optional()
6359
+ lastError: import_zod6.z.string().optional()
5419
6360
  });
5420
- var HeadroomSessionSchema = import_zod5.z.strictObject({ pid: import_zod5.z.number().int().positive(), startedAt: import_zod5.z.number(), supervisorPid: import_zod5.z.number().int().positive() });
5421
- var HeadroomLockSchema = import_zod5.z.strictObject({ pid: import_zod5.z.number().int().positive(), at: import_zod5.z.number() });
6361
+ var HeadroomSessionSchema = import_zod6.z.strictObject({ pid: import_zod6.z.number().int().positive(), startedAt: import_zod6.z.number(), supervisorPid: import_zod6.z.number().int().positive() });
6362
+ var HeadroomLockSchema = import_zod6.z.strictObject({ pid: import_zod6.z.number().int().positive(), at: import_zod6.z.number() });
5422
6363
  function parseJson(raw, schema) {
5423
6364
  if (raw === void 0 || raw.trim() === "") {
5424
6365
  return void 0;
@@ -5434,7 +6375,7 @@ function readHeadroomState(fs12, stateFile) {
5434
6375
  }
5435
6376
  }
5436
6377
  function writeHeadroomState(fs12, stateFile, state) {
5437
- fs12.mkdirp(import_node_path10.default.dirname(stateFile));
6378
+ fs12.mkdirp(import_node_path12.default.dirname(stateFile));
5438
6379
  fs12.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
5439
6380
  `);
5440
6381
  }
@@ -5462,7 +6403,7 @@ function readAllProviders(fs12, providersDir) {
5462
6403
  continue;
5463
6404
  }
5464
6405
  try {
5465
- const parsed = parseJson(fs12.readFileUtf8(import_node_path10.default.join(providersDir, name)), ProviderSchema);
6406
+ const parsed = parseJson(fs12.readFileUtf8(import_node_path12.default.join(providersDir, name)), ProviderSchema);
5466
6407
  if (parsed !== void 0) {
5467
6408
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
5468
6409
  }
@@ -5474,11 +6415,11 @@ function readAllProviders(fs12, providersDir) {
5474
6415
  }
5475
6416
  function writeSession(fs12, sessionsDir, session) {
5476
6417
  fs12.mkdirp(sessionsDir);
5477
- fs12.writeFileUtf8(import_node_path10.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
6418
+ fs12.writeFileUtf8(import_node_path12.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
5478
6419
  `);
5479
6420
  }
5480
6421
  function removeSession(fs12, sessionsDir, pid) {
5481
- fs12.removeRecursive(import_node_path10.default.join(sessionsDir, `${String(pid)}.json`));
6422
+ fs12.removeRecursive(import_node_path12.default.join(sessionsDir, `${String(pid)}.json`));
5482
6423
  }
5483
6424
  function listSessions(fs12, sessionsDir) {
5484
6425
  const sessions = [];
@@ -5487,7 +6428,7 @@ function listSessions(fs12, sessionsDir) {
5487
6428
  continue;
5488
6429
  }
5489
6430
  try {
5490
- const parsed = parseJson(fs12.readFileUtf8(import_node_path10.default.join(sessionsDir, name)), HeadroomSessionSchema);
6431
+ const parsed = parseJson(fs12.readFileUtf8(import_node_path12.default.join(sessionsDir, name)), HeadroomSessionSchema);
5491
6432
  if (parsed !== void 0) {
5492
6433
  sessions.push(parsed);
5493
6434
  }
@@ -5592,214 +6533,7 @@ function ensureFrontDoor(params) {
5592
6533
  }
5593
6534
 
5594
6535
  // src/usage/read.ts
5595
- var import_node_path12 = __toESM(require("node:path"), 1);
5596
-
5597
- // src/usage/account.ts
5598
- var import_node_path11 = __toESM(require("node:path"), 1);
5599
-
5600
- // src/usage/schema.ts
5601
- var import_zod6 = require("zod");
5602
- var USAGE_SCHEMA_VERSION = 1;
5603
- var VersionSchema = import_zod6.z.literal(USAGE_SCHEMA_VERSION);
5604
- var InstantSchema = import_zod6.z.iso.datetime();
5605
- var TokenCountSchema = import_zod6.z.number().int().nonnegative();
5606
- var TokenUsageSchema = import_zod6.z.strictObject({
5607
- inputTokens: TokenCountSchema.optional(),
5608
- outputTokens: TokenCountSchema.optional(),
5609
- cacheCreationInputTokens: TokenCountSchema.optional(),
5610
- cacheReadInputTokens: TokenCountSchema.optional()
5611
- });
5612
- var LIMIT_KINDS = ["rate-limited", "quota-exhausted"];
5613
- var LimitClassificationSchema = import_zod6.z.strictObject({
5614
- kind: import_zod6.z.enum(LIMIT_KINDS),
5615
- /** Seconds to wait before retrying, from the response's `retry-after`. */
5616
- retryAfterSeconds: import_zod6.z.number().nonnegative().optional(),
5617
- /** When the limiting window resets, from the upstream's own reset header. */
5618
- resetAt: InstantSchema.optional(),
5619
- /** The window the upstream named as the binding one (`anthropic-ratelimit-unified-representative-claim`), such as `five_hour` or `seven_day`. */
5620
- window: import_zod6.z.string().optional(),
5621
- /** The signals the classification rests on, each `<name>=<value>` from a response header or the error body's `type` or `code`. Never the error message. */
5622
- evidence: import_zod6.z.array(import_zod6.z.string())
5623
- });
5624
- var UsageRecordSchema = import_zod6.z.strictObject({
5625
- schemaVersion: VersionSchema,
5626
- /** When the front door received the request. */
5627
- at: InstantSchema,
5628
- /** The launching identity, when the launch resolved one. */
5629
- identity: import_zod6.z.string().optional(),
5630
- /** `anthropic` for an OAuth session's request to Claude Code's own API, otherwise the provider's name. */
5631
- provider: import_zod6.z.string(),
5632
- /** The launch's session id, generated per launch. */
5633
- sessionId: import_zod6.z.string().optional(),
5634
- /** The project the launch ran in (its git repository root), when the launch sent one: headroom launches do. */
5635
- project: import_zod6.z.string().optional(),
5636
- /** The front-door route that served the request. */
5637
- route: import_zod6.z.string(),
5638
- method: import_zod6.z.string(),
5639
- /** The API path as the upstream sees it (`/v1/messages`), without the provider prefix or a query string. */
5640
- endpoint: import_zod6.z.string(),
5641
- /** The model the response named. */
5642
- model: import_zod6.z.string().optional(),
5643
- status: import_zod6.z.number().int(),
5644
- /** Milliseconds from the request's arrival to its response head. */
5645
- latencyMs: import_zod6.z.number().int().nonnegative(),
5646
- /** Milliseconds from the request's arrival to the end of its response body. */
5647
- durationMs: import_zod6.z.number().int().nonnegative(),
5648
- /** Whether the client received the whole body. */
5649
- outcome: import_zod6.z.enum(["completed", "aborted"]),
5650
- usage: TokenUsageSchema.optional(),
5651
- /** The response's quota and rate-limit headers, by name (see `isRateLimitHeader`). */
5652
- rateLimitHeaders: import_zod6.z.record(import_zod6.z.string(), import_zod6.z.string()).optional(),
5653
- limit: LimitClassificationSchema.optional(),
5654
- /** The upstream's request id (`request-id`), for matching a record to the provider's own logs. */
5655
- requestId: import_zod6.z.string().optional()
5656
- });
5657
- var QuotaWindowSchema = import_zod6.z.strictObject({
5658
- /** The fraction of the window used, as the upstream reports it (0 to 1). */
5659
- utilization: import_zod6.z.number().nonnegative().optional(),
5660
- resetsAt: InstantSchema.optional(),
5661
- /** The window's own status (`allowed`, `allowed_warning`, `rejected`). */
5662
- status: import_zod6.z.string().optional()
5663
- });
5664
- var UnifiedRateLimitSchema = import_zod6.z.strictObject({
5665
- /** The overall status: `allowed`, `allowed_warning` or `rejected`. */
5666
- status: import_zod6.z.string().optional(),
5667
- fiveHour: QuotaWindowSchema.optional(),
5668
- sevenDay: QuotaWindowSchema.optional(),
5669
- /** The window that currently binds. */
5670
- representativeClaim: import_zod6.z.string().optional(),
5671
- /** When the binding window resets. */
5672
- resetAt: InstantSchema.optional(),
5673
- /** Whether usage beyond the plan (extra usage) is available: `allowed` or `rejected`. */
5674
- overageStatus: import_zod6.z.string().optional()
5675
- });
5676
- var RateLimitStateSchema = import_zod6.z.strictObject({
5677
- observedAt: InstantSchema,
5678
- /** Every quota and rate-limit header on that response, by name. */
5679
- headers: import_zod6.z.record(import_zod6.z.string(), import_zod6.z.string()),
5680
- unified: UnifiedRateLimitSchema.optional()
5681
- });
5682
- var LimitEventSchema = LimitClassificationSchema.extend({
5683
- observedAt: InstantSchema,
5684
- status: import_zod6.z.number().int()
5685
- });
5686
- var ProviderQuotaWindowSchema = import_zod6.z.strictObject({
5687
- /** What the window measures, in the provider's terms (`tokens`, `tool-calls`). */
5688
- measures: import_zod6.z.string(),
5689
- /** The window's length in milliseconds, when the provider's unit is one this project knows; absent for an unrecognised unit, with `period` carrying the raw code. */
5690
- periodMs: import_zod6.z.number().int().positive().optional(),
5691
- /** The provider's own description of the period when `periodMs` could not be derived, such as `unit 4 x 1`. */
5692
- period: import_zod6.z.string().optional(),
5693
- /** The fraction of the window used (0 to 1). */
5694
- utilization: import_zod6.z.number().nonnegative(),
5695
- resetsAt: InstantSchema.optional(),
5696
- /** Absolute counts, when the provider reports them for this window. */
5697
- limit: import_zod6.z.number().nonnegative().optional(),
5698
- used: import_zod6.z.number().nonnegative().optional(),
5699
- remaining: import_zod6.z.number().nonnegative().optional()
5700
- });
5701
- var ProviderQuotaSchema = import_zod6.z.strictObject({
5702
- observedAt: InstantSchema,
5703
- /** Which usage endpoint produced it (`z.ai`). */
5704
- source: import_zod6.z.string(),
5705
- /** The subscription level the endpoint reports, when it does. */
5706
- level: import_zod6.z.string().optional(),
5707
- windows: import_zod6.z.array(ProviderQuotaWindowSchema)
5708
- });
5709
- var ProviderUsageStateSchema = import_zod6.z.strictObject({
5710
- lastRequestAt: InstantSchema,
5711
- lastStatus: import_zod6.z.number().int(),
5712
- lastModel: import_zod6.z.string().optional(),
5713
- /** The latest rate-limit state, from the last response that carried any rate-limit header. */
5714
- rateLimit: RateLimitStateSchema.optional(),
5715
- /** The latest classified refusal. It stays after later successes, so a reader compares its `resetAt` (or `observedAt` plus `retryAfterSeconds`) with the current time. */
5716
- lastLimit: LimitEventSchema.optional(),
5717
- /** The latest quota the provider's usage endpoint reported, for providers whose quota is not visible in response headers. */
5718
- quota: ProviderQuotaSchema.optional()
5719
- });
5720
- var AccountMetadataSchema = import_zod6.z.strictObject({
5721
- accountUuid: import_zod6.z.string().optional(),
5722
- emailAddress: import_zod6.z.string().optional(),
5723
- displayName: import_zod6.z.string().optional(),
5724
- organizationUuid: import_zod6.z.string().optional(),
5725
- organizationName: import_zod6.z.string().optional(),
5726
- organizationType: import_zod6.z.string().optional(),
5727
- organizationRole: import_zod6.z.string().optional(),
5728
- workspaceRole: import_zod6.z.string().optional(),
5729
- billingType: import_zod6.z.string().optional(),
5730
- seatTier: import_zod6.z.string().optional(),
5731
- organizationRateLimitTier: import_zod6.z.string().optional(),
5732
- userRateLimitTier: import_zod6.z.string().optional(),
5733
- hasExtraUsageEnabled: import_zod6.z.boolean().optional(),
5734
- subscriptionCreatedAt: import_zod6.z.string().optional(),
5735
- accountCreatedAt: import_zod6.z.string().optional()
5736
- });
5737
- var UsageSnapshotSchema = import_zod6.z.strictObject({
5738
- schemaVersion: VersionSchema,
5739
- identity: import_zod6.z.string(),
5740
- updatedAt: InstantSchema,
5741
- /** The identity's account metadata as of `updatedAt`. */
5742
- account: AccountMetadataSchema.optional(),
5743
- /** Latest state per provider, keyed by provider name (`anthropic` for OAuth sessions). */
5744
- providers: import_zod6.z.record(import_zod6.z.string(), ProviderUsageStateSchema)
5745
- });
5746
-
5747
- // src/usage/account.ts
5748
- var CLAUDE_JSON = ".claude.json";
5749
- var AccountMetadataError = class extends CliError {
5750
- constructor(file, detail) {
5751
- super(`${file}: ${detail}, so its account metadata cannot be read.`);
5752
- this.file = file;
5753
- this.name = "AccountMetadataError";
5754
- }
5755
- file;
5756
- };
5757
- function isObject(value) {
5758
- return typeof value === "object" && value !== null && !Array.isArray(value);
5759
- }
5760
- function isIdentityName(name) {
5761
- return IdentitySchema.shape.name.safeParse(name).success;
5762
- }
5763
- function claudeJsonPath(identitiesDir, identity) {
5764
- return import_node_path11.default.join(identitiesDir, identity, CLAUDE_JSON);
5765
- }
5766
- function readAccountMetadata(fs12, identitiesDir, identity) {
5767
- if (!isIdentityName(identity)) {
5768
- throw new Error(`"${identity}" is not a valid identity name.`);
5769
- }
5770
- const file = claudeJsonPath(identitiesDir, identity);
5771
- const raw = fs12.readFileUtf8(file);
5772
- if (raw === void 0) {
5773
- return void 0;
5774
- }
5775
- let parsed;
5776
- try {
5777
- parsed = JSON.parse(raw);
5778
- } catch {
5779
- throw new AccountMetadataError(file, "not valid JSON");
5780
- }
5781
- if (!isObject(parsed)) {
5782
- throw new AccountMetadataError(file, "not a JSON object");
5783
- }
5784
- const oauthAccount = parsed.oauthAccount;
5785
- if (!isObject(oauthAccount)) {
5786
- return void 0;
5787
- }
5788
- const picked = {};
5789
- for (const key of Object.keys(AccountMetadataSchema.shape)) {
5790
- const value = oauthAccount[key];
5791
- if (value !== null && value !== void 0) {
5792
- picked[key] = value;
5793
- }
5794
- }
5795
- const account = AccountMetadataSchema.safeParse(picked);
5796
- if (!account.success) {
5797
- throw new AccountMetadataError(file, account.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; "));
5798
- }
5799
- return account.data;
5800
- }
5801
-
5802
- // src/usage/read.ts
6536
+ var import_node_path13 = __toESM(require("node:path"), 1);
5803
6537
  var SEGMENT_RE = /^(\d{4}-\d{2}-\d{2})\.(\d+)\.jsonl$/;
5804
6538
  var DAY_MS = 864e5;
5805
6539
  function listLogSegments(fs12, logDir) {
@@ -5820,7 +6554,7 @@ function readUsageLog(fs12, logDir, options = {}) {
5820
6554
  if (sinceMs !== void 0 && segment.endsAt <= sinceMs) {
5821
6555
  continue;
5822
6556
  }
5823
- const contents = fs12.readFileUtf8(import_node_path12.default.join(logDir, segment.name));
6557
+ const contents = fs12.readFileUtf8(import_node_path13.default.join(logDir, segment.name));
5824
6558
  if (contents === void 0) {
5825
6559
  continue;
5826
6560
  }
@@ -5862,7 +6596,7 @@ function snapshotPath(snapshotsDir, identity) {
5862
6596
  if (!isIdentityName(identity)) {
5863
6597
  throw new Error(`"${identity}" is not a valid identity name.`);
5864
6598
  }
5865
- return import_node_path12.default.join(snapshotsDir, `${identity}.json`);
6599
+ return import_node_path13.default.join(snapshotsDir, `${identity}.json`);
5866
6600
  }
5867
6601
  function readUsageSnapshot(fs12, snapshotsDir, identity) {
5868
6602
  const file = snapshotPath(snapshotsDir, identity);
@@ -5897,13 +6631,13 @@ function listUsageSnapshots(fs12, snapshotsDir) {
5897
6631
  }
5898
6632
 
5899
6633
  // src/usage/preflight.ts
5900
- var MS_PER_SECOND2 = 1e3;
6634
+ var MS_PER_SECOND3 = 1e3;
5901
6635
  var SECONDS_PER_MINUTE = 60;
5902
6636
  var MINUTES_PER_HOUR = 60;
5903
6637
  var HOURS_PER_DAY = 24;
5904
6638
  var WARNING_STATUSES = /* @__PURE__ */ new Set(["allowed_warning", "rejected"]);
5905
6639
  function formatAge(ms) {
5906
- const minutes = Math.floor(ms / (MS_PER_SECOND2 * SECONDS_PER_MINUTE));
6640
+ const minutes = Math.floor(ms / (MS_PER_SECOND3 * SECONDS_PER_MINUTE));
5907
6641
  if (minutes < MINUTES_PER_HOUR) {
5908
6642
  return `${String(Math.max(minutes, 0))}m`;
5909
6643
  }
@@ -5981,13 +6715,13 @@ function planOf(account) {
5981
6715
  }
5982
6716
 
5983
6717
  // src/usage/rateLimit.ts
5984
- var MS_PER_SECOND3 = 1e3;
6718
+ var MS_PER_SECOND4 = 1e3;
5985
6719
  function epochSecondsToIso(value) {
5986
6720
  if (value === void 0) {
5987
6721
  return void 0;
5988
6722
  }
5989
6723
  const seconds = Number(value);
5990
- return Number.isFinite(seconds) && seconds > 0 ? new Date(seconds * MS_PER_SECOND3).toISOString() : void 0;
6724
+ return Number.isFinite(seconds) && seconds > 0 ? new Date(seconds * MS_PER_SECOND4).toISOString() : void 0;
5991
6725
  }
5992
6726
  function nonNegativeNumber(value) {
5993
6727
  if (value === void 0 || value.trim() === "") {
@@ -6044,7 +6778,7 @@ var ErrorObjectSchema = import_zod8.z.looseObject({
6044
6778
  var ANTHROPIC_PROVIDER = "anthropic";
6045
6779
 
6046
6780
  // src/usage/pick.ts
6047
- var MS_PER_SECOND4 = 1e3;
6781
+ var MS_PER_SECOND5 = 1e3;
6048
6782
  var MS_PER_HOUR = 36e5;
6049
6783
  var HOURS_PER_DAY2 = 24;
6050
6784
  var FIVE_HOURS = 5;
@@ -6066,7 +6800,7 @@ function limitBlockedUntil(state, nowMs) {
6066
6800
  if (Date.parse(state.lastRequestAt) > Date.parse(limit.observedAt)) {
6067
6801
  return void 0;
6068
6802
  }
6069
- const until = limit.resetAt === void 0 ? limit.retryAfterSeconds === void 0 ? void 0 : Date.parse(limit.observedAt) + limit.retryAfterSeconds * MS_PER_SECOND4 : Date.parse(limit.resetAt);
6803
+ const until = limit.resetAt === void 0 ? limit.retryAfterSeconds === void 0 ? void 0 : Date.parse(limit.observedAt) + limit.retryAfterSeconds * MS_PER_SECOND5 : Date.parse(limit.resetAt);
6070
6804
  return until !== void 0 && until > nowMs ? until : void 0;
6071
6805
  }
6072
6806
  function windowBlockedUntil(windows) {
@@ -6143,10 +6877,10 @@ function assess(member, nowMs) {
6143
6877
  return { candidate: { ...base, class: "unknown", reasons: ["quota windows reported no utilisation", ...windowReasons, ...planReasons] } };
6144
6878
  }
6145
6879
  const remaining = Math.max(0, 1 - basis.window.utilization);
6146
- const untilResetMs = basis.window.resetsAtMs === void 0 ? basis.windowMs : Math.max(basis.window.resetsAtMs - nowMs, MS_PER_SECOND4);
6880
+ const untilResetMs = basis.window.resetsAtMs === void 0 ? basis.windowMs : Math.max(basis.window.resetsAtMs - nowMs, MS_PER_SECOND5);
6147
6881
  const score = remaining * plan.capacity / (untilResetMs / MS_PER_HOUR);
6148
6882
  const fiveRemaining = five?.utilization === void 0 ? void 0 : Math.max(0, 1 - five.utilization);
6149
- const fiveUntil = five?.resetsAtMs === void 0 ? FIVE_HOUR_WINDOW_MS : Math.max(five.resetsAtMs - nowMs, MS_PER_SECOND4);
6883
+ const fiveUntil = five?.resetsAtMs === void 0 ? FIVE_HOUR_WINDOW_MS : Math.max(five.resetsAtMs - nowMs, MS_PER_SECOND5);
6150
6884
  const burn = fiveHourBurn(member.records);
6151
6885
  return {
6152
6886
  candidate: { ...base, class: "scored", score, reasons: [...windowReasons.map((reason, index) => index === windowReasons.length - 1 ? `${reason}${observedAgo}` : reason), ...planReasons] },
@@ -6196,7 +6930,7 @@ function rankPool(input) {
6196
6930
  }
6197
6931
 
6198
6932
  // src/usage/poolPick.ts
6199
- var import_node_path13 = __toESM(require("node:path"), 1);
6933
+ var import_node_path14 = __toESM(require("node:path"), 1);
6200
6934
  var import_zod9 = require("zod");
6201
6935
 
6202
6936
  // src/usage/store.ts
@@ -6263,13 +6997,13 @@ function recordStickyPick(fs12, picksFile, directory, identity, nowMs) {
6263
6997
  const current = readPicksFile(fs12, picksFile).file.picks;
6264
6998
  const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
6265
6999
  const next = { schemaVersion: SCHEMA_VERSION, picks: { ...Object.fromEntries(kept), [directory]: { identity, at: new Date(nowMs).toISOString() } } };
6266
- fs12.mkdirPrivate(import_node_path13.default.dirname(picksFile));
7000
+ fs12.mkdirPrivate(import_node_path14.default.dirname(picksFile));
6267
7001
  fs12.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
6268
7002
  `);
6269
7003
  }
6270
7004
 
6271
7005
  // src/launcher/identity.ts
6272
- var import_node_path14 = __toESM(require("node:path"), 1);
7006
+ var import_node_path15 = __toESM(require("node:path"), 1);
6273
7007
  function poolNameOf(selector) {
6274
7008
  return selector.startsWith(POOL_SELECTOR_PREFIX) ? selector.slice(POOL_SELECTOR_PREFIX.length) : void 0;
6275
7009
  }
@@ -6318,7 +7052,7 @@ function decideConfigProfile(params) {
6318
7052
  return { source: "none" };
6319
7053
  }
6320
7054
  function loadIdentity(identitiesDir, name, fs12) {
6321
- return loadConfigFile(import_node_path14.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
7055
+ return loadConfigFile(import_node_path15.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
6322
7056
  }
6323
7057
 
6324
7058
  // src/launcher/pool.ts
@@ -6533,7 +7267,7 @@ function hashSettings(settings) {
6533
7267
  }
6534
7268
 
6535
7269
  // src/headroom/socket.ts
6536
- var import_node_path15 = __toESM(require("node:path"), 1);
7270
+ var import_node_path16 = __toESM(require("node:path"), 1);
6537
7271
  var GROUP_OR_OTHER_BITS = 63;
6538
7272
  var OCTAL_RADIX = 8;
6539
7273
  var MODE_DIGITS = 4;
@@ -6542,7 +7276,7 @@ var HEADROOM_SOCKET_NAME = /^(\d+)\.sock$/;
6542
7276
  var UNIX_SOCKET_PATH_MAX_BYTES = 103;
6543
7277
  var PLATFORMS_WITHOUT_UNIX_SOCKETS = ["win32"];
6544
7278
  function headroomSocketPath(paths, supervisorPid) {
6545
- return import_node_path15.default.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
7279
+ return import_node_path16.default.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
6546
7280
  }
6547
7281
  function platformRefusal(platform) {
6548
7282
  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;
@@ -6591,7 +7325,7 @@ function pruneStaleHeadroomSockets(fs12, paths, isRunning) {
6591
7325
  if (pid === void 0 || isRunning(Number.parseInt(pid, 10))) {
6592
7326
  continue;
6593
7327
  }
6594
- fs12.removeRecursive(import_node_path15.default.join(paths.headroomSocketDir, name));
7328
+ fs12.removeRecursive(import_node_path16.default.join(paths.headroomSocketDir, name));
6595
7329
  removed.push(name);
6596
7330
  }
6597
7331
  return removed;
@@ -6915,14 +7649,14 @@ function evaluateAmbientCredentialGuard(params) {
6915
7649
  // src/paths.ts
6916
7650
  var import_node_fs2 = __toESM(require("node:fs"), 1);
6917
7651
  var import_node_os2 = __toESM(require("node:os"), 1);
6918
- var import_node_path16 = __toESM(require("node:path"), 1);
7652
+ var import_node_path17 = __toESM(require("node:path"), 1);
6919
7653
  function resolveAgentShimHome(env = process.env, home = import_node_os2.default.homedir(), isDirectory = isExistingDirectory) {
6920
7654
  const fromEnv = env.AGENT_SHIM_HOME;
6921
7655
  if (fromEnv !== void 0 && fromEnv !== "") {
6922
7656
  return fromEnv;
6923
7657
  }
6924
- const current = import_node_path16.default.join(home, HOME_DIRNAME);
6925
- const legacy = import_node_path16.default.join(home, LEGACY_HOME_DIRNAME);
7658
+ const current = import_node_path17.default.join(home, HOME_DIRNAME);
7659
+ const legacy = import_node_path17.default.join(home, LEGACY_HOME_DIRNAME);
6926
7660
  return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
6927
7661
  }
6928
7662
  function isExistingDirectory(candidate) {
@@ -6933,41 +7667,41 @@ function resolveClaudeHome() {
6933
7667
  if (fromEnv !== void 0 && fromEnv !== "") {
6934
7668
  return fromEnv;
6935
7669
  }
6936
- return import_node_path16.default.join(import_node_os2.default.homedir(), ".claude");
7670
+ return import_node_path17.default.join(import_node_os2.default.homedir(), ".claude");
6937
7671
  }
6938
7672
  function buildLayoutPaths(root) {
6939
7673
  return {
6940
7674
  root,
6941
- identitiesDir: import_node_path16.default.join(root, "identities"),
6942
- configProfilesDir: import_node_path16.default.join(root, "config-profiles"),
6943
- providersDir: import_node_path16.default.join(root, "providers"),
6944
- directoryRulesFile: import_node_path16.default.join(root, "directory-rules.json"),
6945
- activeIdentityFile: import_node_path16.default.join(root, "active-identity"),
6946
- globalConfigFile: import_node_path16.default.join(root, "config.json"),
6947
- categoriesLocalFile: import_node_path16.default.join(root, "categories.local.json"),
6948
- claudeShimFile: import_node_path16.default.join(root, "claude-shim.json"),
6949
- headroomDir: import_node_path16.default.join(root, "headroom"),
6950
- headroomStateFile: import_node_path16.default.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
6951
- headroomSocketDir: import_node_path16.default.join(root, "headroom", "run"),
6952
- headroomLockFile: import_node_path16.default.join(root, "headroom", "start.lock"),
6953
- headroomSessionsDir: import_node_path16.default.join(root, "headroom", "sessions"),
6954
- logsDir: import_node_path16.default.join(root, "logs"),
6955
- headroomLogPath: import_node_path16.default.join(root, "logs", "headroom.log"),
6956
- frontdoorDir: import_node_path16.default.join(root, "frontdoor"),
6957
- frontdoorCaDir: import_node_path16.default.join(root, "frontdoor", "ca"),
6958
- frontdoorCaCertFile: import_node_path16.default.join(root, "frontdoor", "ca", "ca.pem"),
6959
- frontdoorCaKeyFile: import_node_path16.default.join(root, "frontdoor", "ca", "ca.key"),
6960
- frontdoorCaBundlesDir: import_node_path16.default.join(root, "frontdoor", "ca", "bundles"),
6961
- frontdoorStateFile: import_node_path16.default.join(root, "frontdoor", "state.json"),
6962
- frontdoorLockFile: import_node_path16.default.join(root, "frontdoor", "start.lock"),
6963
- frontdoorControlTokenFile: import_node_path16.default.join(root, "frontdoor", "control-token"),
6964
- frontdoorSessionsDir: import_node_path16.default.join(root, "frontdoor", "sessions"),
6965
- frontdoorRcCredentialsDir: import_node_path16.default.join(root, "frontdoor", "rc-credentials"),
6966
- frontdoorLogPath: import_node_path16.default.join(root, "logs", "frontdoor.log"),
6967
- usageDir: import_node_path16.default.join(root, "usage"),
6968
- usageLogDir: import_node_path16.default.join(root, "usage", "log"),
6969
- usageSnapshotsDir: import_node_path16.default.join(root, "usage", "snapshots"),
6970
- usagePicksFile: import_node_path16.default.join(root, "usage", "picks.json")
7675
+ identitiesDir: import_node_path17.default.join(root, "identities"),
7676
+ configProfilesDir: import_node_path17.default.join(root, "config-profiles"),
7677
+ providersDir: import_node_path17.default.join(root, "providers"),
7678
+ directoryRulesFile: import_node_path17.default.join(root, "directory-rules.json"),
7679
+ activeIdentityFile: import_node_path17.default.join(root, "active-identity"),
7680
+ globalConfigFile: import_node_path17.default.join(root, "config.json"),
7681
+ categoriesLocalFile: import_node_path17.default.join(root, "categories.local.json"),
7682
+ claudeShimFile: import_node_path17.default.join(root, "claude-shim.json"),
7683
+ headroomDir: import_node_path17.default.join(root, "headroom"),
7684
+ headroomStateFile: import_node_path17.default.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
7685
+ headroomSocketDir: import_node_path17.default.join(root, "headroom", "run"),
7686
+ headroomLockFile: import_node_path17.default.join(root, "headroom", "start.lock"),
7687
+ headroomSessionsDir: import_node_path17.default.join(root, "headroom", "sessions"),
7688
+ logsDir: import_node_path17.default.join(root, "logs"),
7689
+ headroomLogPath: import_node_path17.default.join(root, "logs", "headroom.log"),
7690
+ frontdoorDir: import_node_path17.default.join(root, "frontdoor"),
7691
+ frontdoorCaDir: import_node_path17.default.join(root, "frontdoor", "ca"),
7692
+ frontdoorCaCertFile: import_node_path17.default.join(root, "frontdoor", "ca", "ca.pem"),
7693
+ frontdoorCaKeyFile: import_node_path17.default.join(root, "frontdoor", "ca", "ca.key"),
7694
+ frontdoorCaBundlesDir: import_node_path17.default.join(root, "frontdoor", "ca", "bundles"),
7695
+ frontdoorStateFile: import_node_path17.default.join(root, "frontdoor", "state.json"),
7696
+ frontdoorLockFile: import_node_path17.default.join(root, "frontdoor", "start.lock"),
7697
+ frontdoorControlTokenFile: import_node_path17.default.join(root, "frontdoor", "control-token"),
7698
+ frontdoorSessionsDir: import_node_path17.default.join(root, "frontdoor", "sessions"),
7699
+ frontdoorRcCredentialsDir: import_node_path17.default.join(root, "frontdoor", "rc-credentials"),
7700
+ frontdoorLogPath: import_node_path17.default.join(root, "logs", "frontdoor.log"),
7701
+ usageDir: import_node_path17.default.join(root, "usage"),
7702
+ usageLogDir: import_node_path17.default.join(root, "usage", "log"),
7703
+ usageSnapshotsDir: import_node_path17.default.join(root, "usage", "snapshots"),
7704
+ usagePicksFile: import_node_path17.default.join(root, "usage", "picks.json")
6971
7705
  };
6972
7706
  }
6973
7707
  function resolveLayoutPaths() {
@@ -6976,11 +7710,11 @@ function resolveLayoutPaths() {
6976
7710
 
6977
7711
  // src/identityStore.ts
6978
7712
  var import_node_fs4 = __toESM(require("node:fs"), 1);
6979
- var import_node_path18 = __toESM(require("node:path"), 1);
7713
+ var import_node_path19 = __toESM(require("node:path"), 1);
6980
7714
 
6981
7715
  // src/configProfilesStore.ts
6982
7716
  var import_node_fs3 = __toESM(require("node:fs"), 1);
6983
- var import_node_path17 = __toESM(require("node:path"), 1);
7717
+ var import_node_path18 = __toESM(require("node:path"), 1);
6984
7718
  var ProfileNotFoundError = class extends CliError {
6985
7719
  constructor(profileName) {
6986
7720
  super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
@@ -7006,7 +7740,7 @@ var InvalidCategoryNameError = class extends CliError {
7006
7740
  categoryName;
7007
7741
  };
7008
7742
  function profileJsonPath(paths, name) {
7009
- return import_node_path17.default.join(paths.configProfilesDir, `${name}.json`);
7743
+ return import_node_path18.default.join(paths.configProfilesDir, `${name}.json`);
7010
7744
  }
7011
7745
  function profileExists(paths, name) {
7012
7746
  return import_node_fs3.default.existsSync(profileJsonPath(paths, name));
@@ -7194,7 +7928,7 @@ var InvalidIdentityNameError = class extends CliError {
7194
7928
  attemptedName;
7195
7929
  };
7196
7930
  function identityJsonPath(paths, name) {
7197
- return import_node_path18.default.join(paths.identitiesDir, name, "identity.json");
7931
+ return import_node_path19.default.join(paths.identitiesDir, name, "identity.json");
7198
7932
  }
7199
7933
  function identityExists(paths, name) {
7200
7934
  return import_node_fs4.default.existsSync(identityJsonPath(paths, name));
@@ -7295,7 +8029,7 @@ function setIdentityCredential(paths, identityName, change) {
7295
8029
  });
7296
8030
  }
7297
8031
  function belongsToIdentity(entry, name) {
7298
- return entry === name || entry === import_node_path18.default.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
8032
+ return entry === name || entry === import_node_path19.default.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
7299
8033
  }
7300
8034
  function removeIdentity(paths, name) {
7301
8035
  if (!identityExists(paths, name)) {
@@ -7303,7 +8037,7 @@ function removeIdentity(paths, name) {
7303
8037
  }
7304
8038
  for (const entry of import_node_fs4.default.readdirSync(paths.identitiesDir)) {
7305
8039
  if (belongsToIdentity(entry, name)) {
7306
- import_node_fs4.default.rmSync(import_node_path18.default.join(paths.identitiesDir, entry), { recursive: true, force: true });
8040
+ import_node_fs4.default.rmSync(import_node_path19.default.join(paths.identitiesDir, entry), { recursive: true, force: true });
7307
8041
  }
7308
8042
  }
7309
8043
  if (readActiveIdentity(paths) === name) {
@@ -7313,7 +8047,7 @@ function removeIdentity(paths, name) {
7313
8047
 
7314
8048
  // src/providersStore.ts
7315
8049
  var import_node_fs5 = __toESM(require("node:fs"), 1);
7316
- var import_node_path19 = __toESM(require("node:path"), 1);
8050
+ var import_node_path20 = __toESM(require("node:path"), 1);
7317
8051
 
7318
8052
  // src/credentialCache.ts
7319
8053
  var import_zod12 = require("zod");
@@ -7578,7 +8312,7 @@ var InvalidProviderNameError = class extends CliError {
7578
8312
  };
7579
8313
  var PROVIDER_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._@-]*$/;
7580
8314
  function providerJsonPath(paths, name) {
7581
- return import_node_path19.default.join(paths.providersDir, `${name}.json`);
8315
+ return import_node_path20.default.join(paths.providersDir, `${name}.json`);
7582
8316
  }
7583
8317
  function providerExists(paths, name) {
7584
8318
  return import_node_fs5.default.existsSync(providerJsonPath(paths, name));
@@ -7586,14 +8320,14 @@ function providerExists(paths, name) {
7586
8320
  var LEGACY_PROVIDER_FIELDS = ["tokenEnv", "tokenCommand", "authScheme"];
7587
8321
  var LEGACY_ENV_CREDENTIAL_KEYS = Object.values(CREDENTIAL_TARGET_VARS);
7588
8322
  var LEGACY_LITERAL_PLACEHOLDER = "<the value of env.ANTHROPIC_AUTH_TOKEN>";
7589
- function isRecord5(value) {
8323
+ function isRecord7(value) {
7590
8324
  return typeof value === "object" && value !== null && !Array.isArray(value);
7591
8325
  }
7592
8326
  function legacyProviderConversion(raw) {
7593
- if (!isRecord5(raw) || "credential" in raw) {
8327
+ if (!isRecord7(raw) || "credential" in raw) {
7594
8328
  return void 0;
7595
8329
  }
7596
- const env = isRecord5(raw.env) ? raw.env : void 0;
8330
+ const env = isRecord7(raw.env) ? raw.env : void 0;
7597
8331
  const legacyEnvKeys = env === void 0 ? [] : Object.keys(env).filter((key) => LEGACY_ENV_CREDENTIAL_KEYS.includes(key));
7598
8332
  const fields = [...LEGACY_PROVIDER_FIELDS.filter((field) => field in raw), ...legacyEnvKeys.map((key) => `env.${key}`)];
7599
8333
  if (fields.length === 0) {
@@ -7654,7 +8388,7 @@ function readProvider(paths, name) {
7654
8388
  return parseProviderFile(filePath, raw);
7655
8389
  }
7656
8390
  function loadProvider(providersDir, name, port) {
7657
- const filePath = import_node_path19.default.join(providersDir, `${name}.json`);
8391
+ const filePath = import_node_path20.default.join(providersDir, `${name}.json`);
7658
8392
  const raw = port.readConfigFile(filePath);
7659
8393
  return raw === void 0 ? void 0 : parseProviderFile(filePath, raw);
7660
8394
  }
@@ -7909,21 +8643,21 @@ function removeDirectoryRule(paths, rulePath) {
7909
8643
  var import_node_os4 = __toESM(require("node:os"), 1);
7910
8644
 
7911
8645
  // src/launcher/cascade.ts
7912
- var import_node_path21 = __toESM(require("node:path"), 1);
8646
+ var import_node_path22 = __toESM(require("node:path"), 1);
7913
8647
 
7914
8648
  // src/pathNorm.ts
7915
- var import_node_path20 = __toESM(require("node:path"), 1);
8649
+ var import_node_path21 = __toESM(require("node:path"), 1);
7916
8650
  function expandTilde(value, home) {
7917
8651
  if (value === "~") {
7918
8652
  return home;
7919
8653
  }
7920
8654
  if (value.startsWith("~/")) {
7921
- return import_node_path20.default.join(home, value.slice(2));
8655
+ return import_node_path21.default.join(home, value.slice(2));
7922
8656
  }
7923
8657
  return value;
7924
8658
  }
7925
8659
  function normaliseRulePath(rulePath, home) {
7926
- return import_node_path20.default.resolve(expandTilde(rulePath, home));
8660
+ return import_node_path21.default.resolve(expandTilde(rulePath, home));
7927
8661
  }
7928
8662
 
7929
8663
  // src/launcher/cascade.ts
@@ -7933,7 +8667,7 @@ function loadCascadeInput(params) {
7933
8667
  const globalConfig = loadConfigFile(params.paths.globalConfigFile, GlobalConfigSchema, params.read);
7934
8668
  const directoryRules = loadConfigFile(params.paths.directoryRulesFile, DirectoryRulesSchema, params.read);
7935
8669
  const loadProfile = (name) => {
7936
- const filepath = import_node_path21.default.join(params.paths.configProfilesDir, `${name}.json`);
8670
+ const filepath = import_node_path22.default.join(params.paths.configProfilesDir, `${name}.json`);
7937
8671
  const loaded = loadConfigFile(filepath, ConfigProfileSchema, params.read);
7938
8672
  if (loaded === void 0) {
7939
8673
  return void 0;
@@ -7948,8 +8682,8 @@ function loadCascadeInput(params) {
7948
8682
  });
7949
8683
  const levels = [];
7950
8684
  for (const dir of dirs) {
7951
- const portable = loadConfigFile(import_node_path21.default.join(dir, PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path21.default.join(dir, LEGACY_PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read);
7952
- const portableLocal = loadConfigFile(import_node_path21.default.join(dir, PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path21.default.join(dir, LEGACY_PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read);
8685
+ const portable = loadConfigFile(import_node_path22.default.join(dir, PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path22.default.join(dir, LEGACY_PORTABLE_CONFIG_FILENAME), PortableConfigSchema, params.read);
8686
+ const portableLocal = loadConfigFile(import_node_path22.default.join(dir, PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read) ?? loadConfigFile(import_node_path22.default.join(dir, LEGACY_PORTABLE_LOCAL_CONFIG_FILENAME), PortableConfigSchema, params.read);
7953
8687
  const rules = (directoryRules?.config.rules ?? []).map((rule, index) => ({ rule, index })).filter(({ rule }) => normaliseRulePath(rule.path, params.home) === dir).map(({ rule, index }) => {
7954
8688
  const entryOrder = directoryRules?.ruleEntryOrders[index];
7955
8689
  return {
@@ -8000,7 +8734,7 @@ function readDirectorySelections(loaded) {
8000
8734
  // src/realCredentialCache.ts
8001
8735
  var import_node_child_process = require("node:child_process");
8002
8736
  var import_node_fs6 = __toESM(require("node:fs"), 1);
8003
- var import_node_path22 = __toESM(require("node:path"), 1);
8737
+ var import_node_path23 = __toESM(require("node:path"), 1);
8004
8738
  var KEYCHAIN_CACHE_SERVICE = "agent-shim-credential-cache";
8005
8739
  var CACHE_DIR_MODE = 448;
8006
8740
  var CACHE_FILE_MODE = 384;
@@ -8027,8 +8761,8 @@ function security(args, stdin) {
8027
8761
  return { status: result.status, stdout: result.stdout };
8028
8762
  }
8029
8763
  function createRealCredentialCache(root) {
8030
- const dir = import_node_path22.default.join(root, "credential-cache");
8031
- const filePath = (owner) => import_node_path22.default.join(dir, cacheFileNameFor(owner));
8764
+ const dir = import_node_path23.default.join(root, "credential-cache");
8765
+ const filePath = (owner) => import_node_path23.default.join(dir, cacheFileNameFor(owner));
8032
8766
  return {
8033
8767
  read(store, owner) {
8034
8768
  if (store === "file") {
@@ -8080,7 +8814,7 @@ var import_node_child_process2 = require("node:child_process");
8080
8814
  var import_node_crypto9 = require("node:crypto");
8081
8815
  var import_node_fs7 = __toESM(require("node:fs"), 1);
8082
8816
  var import_node_os3 = __toESM(require("node:os"), 1);
8083
- var import_node_path23 = __toESM(require("node:path"), 1);
8817
+ var import_node_path24 = __toESM(require("node:path"), 1);
8084
8818
  var import_node_sea = require("node:sea");
8085
8819
  function isEnoent3(error) {
8086
8820
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
@@ -8239,7 +8973,7 @@ var realRunPort = {
8239
8973
  }
8240
8974
  };
8241
8975
  function expandHome2(filePath) {
8242
- return filePath.startsWith("~/") ? import_node_path23.default.join(import_node_os3.default.homedir(), filePath.slice(1)) : filePath;
8976
+ return filePath.startsWith("~/") ? import_node_path24.default.join(import_node_os3.default.homedir(), filePath.slice(1)) : filePath;
8243
8977
  }
8244
8978
  var MACOS_GUI_SESSION_MANAGER = "Aqua";
8245
8979
  function hasDesktopSession() {
@@ -8312,7 +9046,7 @@ function spawnDaemonThrough(executable) {
8312
9046
  return (paths, subcommand, logPath) => spawnDetachedDaemon({ command: executable, args: [subcommand] }, paths, subcommand, logPath);
8313
9047
  }
8314
9048
  function spawnDetachedDaemon(invocation, paths, subcommand, logPath) {
8315
- import_node_fs7.default.mkdirSync(import_node_path23.default.dirname(logPath), { recursive: true });
9049
+ import_node_fs7.default.mkdirSync(import_node_path24.default.dirname(logPath), { recursive: true });
8316
9050
  const logFd = import_node_fs7.default.openSync(logPath, "a");
8317
9051
  try {
8318
9052
  const child = (0, import_node_child_process2.spawn)(invocation.command, invocation.args, detachedDaemonSpawnOptions(logFd, { ...process.env, AGENT_SHIM_HOME: paths.root }));
@@ -8394,7 +9128,7 @@ function listVersionsDir(dir) {
8394
9128
  throw error;
8395
9129
  }
8396
9130
  return entries.filter((entry) => entry.isFile()).map((entry) => {
8397
- const fullPath = import_node_path23.default.join(dir, entry.name);
9131
+ const fullPath = import_node_path24.default.join(dir, entry.name);
8398
9132
  const stat = import_node_fs7.default.statSync(fullPath);
8399
9133
  return {
8400
9134
  name: entry.name,
@@ -8409,7 +9143,7 @@ function windowsPathExtensions(pathext) {
8409
9143
  return (pathext ?? WINDOWS_DEFAULT_PATHEXT).split(";").map((ext) => ext.trim()).filter((ext) => ext.length > 0);
8410
9144
  }
8411
9145
  function resolveExecutableCandidate(dir, name, env) {
8412
- const candidate = import_node_path23.default.join(dir, name);
9146
+ const candidate = import_node_path24.default.join(dir, name);
8413
9147
  if (env.platform === "win32") {
8414
9148
  const extensions = windowsPathExtensions(env.pathext);
8415
9149
  const alreadyHasRecognisedExtension = extensions.some((ext) => candidate.toLowerCase().endsWith(ext.toLowerCase()));
@@ -8458,13 +9192,13 @@ function resolveOwnExecutablePath(env) {
8458
9192
  if (env.argv1 !== void 0 && !env.argv1.includes("/") && !env.argv1.includes("\\")) {
8459
9193
  return searchPathForExecutable(env.pathDirs, env.argv1, env.findExecutableInDir) ?? env.execPath;
8460
9194
  }
8461
- const candidate = env.argv1 === void 0 ? env.execPath : import_node_path23.default.resolve(env.cwd, env.argv1);
8462
- const candidateDir = import_node_path23.default.dirname(candidate);
8463
- const candidateDirOnPath = env.pathDirs.some((dir) => import_node_path23.default.resolve(dir) === candidateDir);
9195
+ const candidate = env.argv1 === void 0 ? env.execPath : import_node_path24.default.resolve(env.cwd, env.argv1);
9196
+ const candidateDir = import_node_path24.default.dirname(candidate);
9197
+ const candidateDirOnPath = env.pathDirs.some((dir) => import_node_path24.default.resolve(dir) === candidateDir);
8464
9198
  if (candidateDirOnPath) {
8465
9199
  return candidate;
8466
9200
  }
8467
- const viaPath = searchPathForExecutable(env.pathDirs, import_node_path23.default.basename(candidate), env.findExecutableInDir);
9201
+ const viaPath = searchPathForExecutable(env.pathDirs, import_node_path24.default.basename(candidate), env.findExecutableInDir);
8468
9202
  return viaPath ?? candidate;
8469
9203
  }
8470
9204
  function realOwnExecutablePath() {
@@ -8472,7 +9206,7 @@ function realOwnExecutablePath() {
8472
9206
  argv1: process.argv[1],
8473
9207
  execPath: process.execPath,
8474
9208
  cwd: process.cwd(),
8475
- pathDirs: (process.env.PATH ?? "").split(import_node_path23.default.delimiter).filter((dir) => dir !== ""),
9209
+ pathDirs: (process.env.PATH ?? "").split(import_node_path24.default.delimiter).filter((dir) => dir !== ""),
8476
9210
  findExecutableInDir
8477
9211
  });
8478
9212
  }
@@ -8485,7 +9219,7 @@ function realContentSourcePath() {
8485
9219
  function realResolveClaudeBinary(isOwnBinary) {
8486
9220
  return (request4) => discoverClaudeBinary({
8487
9221
  listVersionsDir,
8488
- pathDirs: (process.env.PATH ?? "").split(import_node_path23.default.delimiter).filter((dir) => dir !== ""),
9222
+ pathDirs: (process.env.PATH ?? "").split(import_node_path24.default.delimiter).filter((dir) => dir !== ""),
8489
9223
  findExecutableInDir,
8490
9224
  isOwnBinary,
8491
9225
  ...request4?.version === void 0 ? {} : { version: request4.version }
@@ -8496,7 +9230,7 @@ function realInstalledClaudeVersions() {
8496
9230
  }
8497
9231
 
8498
9232
  // src/checkReport.ts
8499
- var import_node_path24 = __toESM(require("node:path"), 1);
9233
+ var import_node_path25 = __toESM(require("node:path"), 1);
8500
9234
  var import_zod13 = require("zod");
8501
9235
 
8502
9236
  // src/cli/bool.ts
@@ -8928,10 +9662,10 @@ function collectCheckReport(params) {
8928
9662
  }).input;
8929
9663
  const providerName = cascadeProviderName(cascade);
8930
9664
  const provider = providerName === void 0 ? void 0 : loadCheckProvider(paths, providerName);
8931
- const farmRoot = identityDecision.name === void 0 ? void 0 : import_node_path24.default.join(paths.identitiesDir, identityDecision.name);
9665
+ const farmRoot = identityDecision.name === void 0 ? void 0 : import_node_path25.default.join(paths.identitiesDir, identityDecision.name);
8932
9666
  const settingsFiles = {
8933
- "settings.json": realFsPort.readFileUtf8(import_node_path24.default.join(claudeHome, "settings.json")),
8934
- "settings.local.json": realFsPort.readFileUtf8(import_node_path24.default.join(claudeHome, "settings.local.json"))
9667
+ "settings.json": realFsPort.readFileUtf8(import_node_path25.default.join(claudeHome, "settings.json")),
9668
+ "settings.local.json": realFsPort.readFileUtf8(import_node_path25.default.join(claudeHome, "settings.local.json"))
8935
9669
  };
8936
9670
  const report = runCheck({
8937
9671
  cwd,
@@ -8963,7 +9697,7 @@ function collectCheckReport(params) {
8963
9697
 
8964
9698
  // src/claudeShim.ts
8965
9699
  var import_node_fs8 = __toESM(require("node:fs"), 1);
8966
- var import_node_path25 = __toESM(require("node:path"), 1);
9700
+ var import_node_path26 = __toESM(require("node:path"), 1);
8967
9701
  var import_zod14 = require("zod");
8968
9702
  var ClaudeShimStateSchema = import_zod14.z.strictObject({
8969
9703
  targetPath: import_zod14.z.string().min(1),
@@ -8975,10 +9709,10 @@ function commandFilename(ownExecutablePath, commandName) {
8975
9709
  }
8976
9710
  function resolveOwnBinaryCheck(paths, contentSourcePath) {
8977
9711
  const state = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
8978
- const recordedTarget = state === void 0 ? void 0 : import_node_path25.default.resolve(state.targetPath);
9712
+ const recordedTarget = state === void 0 ? void 0 : import_node_path26.default.resolve(state.targetPath);
8979
9713
  let ownStat;
8980
9714
  return (candidate) => {
8981
- if (recordedTarget !== void 0 && import_node_path25.default.resolve(candidate) === recordedTarget) {
9715
+ if (recordedTarget !== void 0 && import_node_path26.default.resolve(candidate) === recordedTarget) {
8982
9716
  return true;
8983
9717
  }
8984
9718
  ownStat ??= statOrUndefined(contentSourcePath);
@@ -9002,20 +9736,20 @@ function statOrUndefined(target) {
9002
9736
  }
9003
9737
  var nodeLinkFs = { link: import_node_fs8.default.linkSync, copyFile: import_node_fs8.default.copyFileSync, chmod: import_node_fs8.default.chmodSync };
9004
9738
  function findPathShadow(params) {
9005
- const resolvedTargetDir = import_node_path25.default.resolve(params.targetDir);
9739
+ const resolvedTargetDir = import_node_path26.default.resolve(params.targetDir);
9006
9740
  for (const dir of params.pathDirs) {
9007
9741
  const found = params.findExecutableInDir(dir, params.targetFilename);
9008
9742
  if (found === void 0) {
9009
9743
  continue;
9010
9744
  }
9011
- return import_node_path25.default.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
9745
+ return import_node_path26.default.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
9012
9746
  }
9013
- return params.pathDirs.some((dir) => import_node_path25.default.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
9747
+ return params.pathDirs.some((dir) => import_node_path26.default.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
9014
9748
  }
9015
9749
 
9016
9750
  // src/doctorReport.ts
9017
9751
  var import_node_fs9 = __toESM(require("node:fs"), 1);
9018
- var import_node_path26 = __toESM(require("node:path"), 1);
9752
+ var import_node_path27 = __toESM(require("node:path"), 1);
9019
9753
  function refinePathShadow(status, ownExecutablePath, realpath) {
9020
9754
  if (status.status !== "shadowed") {
9021
9755
  return status;
@@ -9039,7 +9773,7 @@ function validateJson(schema, input) {
9039
9773
  return { ok: true, data: result.data };
9040
9774
  }
9041
9775
  function pushPathResolution(push, resolution) {
9042
- const ownDir = import_node_path26.default.dirname(resolution.ownExecutablePath);
9776
+ const ownDir = import_node_path27.default.dirname(resolution.ownExecutablePath);
9043
9777
  switch (resolution.agentShim.status) {
9044
9778
  case "ok":
9045
9779
  push("path-resolution", "pass", `\`agent-shim\` on PATH resolves to this running executable, ${resolution.ownExecutablePath}.`, "agent-shim");
@@ -9118,14 +9852,14 @@ function pushProvider(push, entry, cacheEnv) {
9118
9852
  }
9119
9853
  function pushLegacyName(push, params) {
9120
9854
  const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
9121
- if (legacyVariables.length === 0 && import_node_path26.default.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
9855
+ if (legacyVariables.length === 0 && import_node_path27.default.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
9122
9856
  push("legacy-name", "pass", "Nothing here still uses the former `claude-use` name.");
9123
9857
  return;
9124
9858
  }
9125
9859
  for (const name of legacyVariables) {
9126
9860
  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);
9127
9861
  }
9128
- if (import_node_path26.default.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
9862
+ if (import_node_path27.default.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
9129
9863
  push(
9130
9864
  "legacy-name",
9131
9865
  "warn",
@@ -9444,18 +10178,18 @@ function collectDoctorReport(params) {
9444
10178
  const { paths } = params;
9445
10179
  const identityNames = import_node_fs9.default.existsSync(paths.identitiesDir) ? import_node_fs9.default.readdirSync(paths.identitiesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && isIdentityDirectoryName(entry.name)).map((entry) => entry.name).sort() : [];
9446
10180
  const identities = identityNames.map((name) => {
9447
- const farmRoot = import_node_path26.default.join(paths.identitiesDir, name);
9448
- const identityPath = import_node_path26.default.join(farmRoot, "identity.json");
10181
+ const farmRoot = import_node_path27.default.join(paths.identitiesDir, name);
10182
+ const identityPath = import_node_path27.default.join(farmRoot, "identity.json");
9449
10183
  return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot };
9450
10184
  });
9451
10185
  const profileNames = import_node_fs9.default.existsSync(paths.configProfilesDir) ? import_node_fs9.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
9452
10186
  const configProfiles = profileNames.map((name) => {
9453
- const profilePath = import_node_path26.default.join(paths.configProfilesDir, `${name}.json`);
10187
+ const profilePath = import_node_path27.default.join(paths.configProfilesDir, `${name}.json`);
9454
10188
  return { name, path: profilePath, raw: realFsPort.readFileUtf8(profilePath) };
9455
10189
  });
9456
10190
  const providerNames = import_node_fs9.default.existsSync(paths.providersDir) ? import_node_fs9.default.readdirSync(paths.providersDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
9457
10191
  const providers = providerNames.map((name) => {
9458
- const providerPath = import_node_path26.default.join(paths.providersDir, `${name}.json`);
10192
+ const providerPath = import_node_path27.default.join(paths.providersDir, `${name}.json`);
9459
10193
  return { name, path: providerPath, raw: realFsPort.readFileUtf8(providerPath) };
9460
10194
  });
9461
10195
  const ownExecutablePath = realOwnExecutablePath();
@@ -9467,12 +10201,12 @@ function collectDoctorReport(params) {
9467
10201
  binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
9468
10202
  }
9469
10203
  const shimState = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
9470
- const pathDirs = (params.env.PATH ?? "").split(import_node_path26.default.delimiter).filter((dir) => dir !== "");
10204
+ const pathDirs = (params.env.PATH ?? "").split(import_node_path27.default.delimiter).filter((dir) => dir !== "");
9471
10205
  const claudeShimShadow = shimState === void 0 ? void 0 : refinePathShadow(
9472
10206
  findPathShadow({
9473
10207
  pathDirs,
9474
- targetDir: import_node_path26.default.dirname(shimState.targetPath),
9475
- targetFilename: import_node_path26.default.basename(shimState.targetPath),
10208
+ targetDir: import_node_path27.default.dirname(shimState.targetPath),
10209
+ targetFilename: import_node_path27.default.basename(shimState.targetPath),
9476
10210
  findExecutableInDir
9477
10211
  }),
9478
10212
  shimState.targetPath,
@@ -9497,7 +10231,7 @@ function collectDoctorReport(params) {
9497
10231
  agentShim: refinePathShadow(
9498
10232
  findPathShadow({
9499
10233
  pathDirs,
9500
- targetDir: import_node_path26.default.dirname(ownExecutablePath),
10234
+ targetDir: import_node_path27.default.dirname(ownExecutablePath),
9501
10235
  targetFilename: commandFilename(ownExecutablePath, "agent-shim"),
9502
10236
  findExecutableInDir
9503
10237
  }),
@@ -9518,7 +10252,7 @@ function collectDoctorReport(params) {
9518
10252
 
9519
10253
  // src/launcher.ts
9520
10254
  var import_node_crypto10 = require("node:crypto");
9521
- var import_node_path28 = __toESM(require("node:path"), 1);
10255
+ var import_node_path29 = __toESM(require("node:path"), 1);
9522
10256
 
9523
10257
  // src/launcher/argv.ts
9524
10258
  var ConflictingIdentityError = class extends UsageError {
@@ -9783,7 +10517,7 @@ function buildCliOverride(params) {
9783
10517
  }
9784
10518
 
9785
10519
  // src/launcher/flags.ts
9786
- var import_node_path27 = __toESM(require("node:path"), 1);
10520
+ var import_node_path28 = __toESM(require("node:path"), 1);
9787
10521
 
9788
10522
  // src/headroom/headers.ts
9789
10523
  function mergeAnthropicCustomHeaders(existing, additions) {
@@ -9853,7 +10587,7 @@ function buildEnv(params) {
9853
10587
  const parentCustomHeaders = params.baseEnv.ANTHROPIC_CUSTOM_HEADERS;
9854
10588
  let providerCustomHeaders;
9855
10589
  if (!params.configDirEscapeHatch && params.resolvedIdentityName !== void 0) {
9856
- env.CLAUDE_CONFIG_DIR = import_node_path27.default.join(params.identitiesDir, params.resolvedIdentityName);
10590
+ env.CLAUDE_CONFIG_DIR = import_node_path28.default.join(params.identitiesDir, params.resolvedIdentityName);
9857
10591
  }
9858
10592
  if (params.provider !== void 0) {
9859
10593
  const providerEnv = params.provider.definition.env ?? {};
@@ -9910,6 +10644,29 @@ function splitExtraFlags(value) {
9910
10644
  return trimmed.split(/\s+/);
9911
10645
  }
9912
10646
 
10647
+ // src/launcher/spawn.ts
10648
+ var import_node_os5 = __toESM(require("node:os"), 1);
10649
+ var SIGNAL_EXIT_CODE_OFFSET = 128;
10650
+ function exitCodeFor(result) {
10651
+ if (result.status !== null) {
10652
+ return result.status;
10653
+ }
10654
+ if (result.signal !== null) {
10655
+ return SIGNAL_EXIT_CODE_OFFSET + import_node_os5.default.constants.signals[result.signal];
10656
+ }
10657
+ return 1;
10658
+ }
10659
+ function spawnClaude(params) {
10660
+ const result = params.spawn.spawnSync(params.bin, params.args, { stdio: "inherit", env: params.env });
10661
+ if (result.error !== void 0) {
10662
+ throw result.error;
10663
+ }
10664
+ if (params.beforeExit !== void 0) {
10665
+ params.beforeExit();
10666
+ }
10667
+ return params.proc.exit(exitCodeFor(result));
10668
+ }
10669
+
9913
10670
  // src/launcher.ts
9914
10671
  function resolveIdentityCredential(identity, credential, env, port) {
9915
10672
  if (port === void 0) {
@@ -10014,7 +10771,7 @@ function prepareLaunch(params) {
10014
10771
  identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
10015
10772
  globalDefaultConfigProfile: params.globalDefaultConfigProfile
10016
10773
  });
10017
- if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(import_node_path28.default.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
10774
+ if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(import_node_path29.default.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
10018
10775
  log.error(
10019
10776
  `agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
10020
10777
  );
@@ -10186,9 +10943,17 @@ function prepareLaunch(params) {
10186
10943
  };
10187
10944
  return { bin: discovered.path, args: finalArgv, env: finalEnv, release };
10188
10945
  }
10946
+ function runLauncher(params) {
10947
+ const plan = prepareLaunch(params);
10948
+ try {
10949
+ spawnClaude({ bin: plan.bin, args: plan.args, env: plan.env, spawn: params.spawn, proc: params.proc, beforeExit: plan.release });
10950
+ } finally {
10951
+ plan.release();
10952
+ }
10953
+ }
10189
10954
 
10190
10955
  // src/launchWiring.ts
10191
- var import_node_os5 = __toESM(require("node:os"), 1);
10956
+ var import_node_os6 = __toESM(require("node:os"), 1);
10192
10957
  var import_node_crypto12 = require("node:crypto");
10193
10958
 
10194
10959
  // src/frontdoor/realFrontDoorPort.ts
@@ -10260,11 +11025,11 @@ function probeFrontDoorSync(port, caPem) {
10260
11025
 
10261
11026
  // src/frontdoor/trust.ts
10262
11027
  var import_node_crypto11 = require("node:crypto");
10263
- var import_node_path29 = __toESM(require("node:path"), 1);
11028
+ var import_node_path30 = __toESM(require("node:path"), 1);
10264
11029
  var BUNDLE_NAME_HEX_DIGITS = 16;
10265
11030
  function resolveTrustBundle(params) {
10266
11031
  const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
10267
- if (inherited === void 0 || inherited === "" || import_node_path29.default.resolve(inherited) === import_node_path29.default.resolve(caCertFile)) {
11032
+ if (inherited === void 0 || inherited === "" || import_node_path30.default.resolve(inherited) === import_node_path30.default.resolve(caCertFile)) {
10268
11033
  return { path: caCertFile };
10269
11034
  }
10270
11035
  const caPem = fs12.readFileUtf8(caCertFile);
@@ -10282,7 +11047,7 @@ function resolveTrustBundle(params) {
10282
11047
  }
10283
11048
  const combined = `${inheritedPem.trimEnd()}
10284
11049
  ${caPem}`;
10285
- const bundle = import_node_path29.default.join(bundlesDir, `${(0, import_node_crypto11.createHash)("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
11050
+ const bundle = import_node_path30.default.join(bundlesDir, `${(0, import_node_crypto11.createHash)("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
10286
11051
  if (!fs12.exists(bundle)) {
10287
11052
  fs12.mkdirp(bundlesDir);
10288
11053
  fs12.writeFileAtomic(bundle, combined);
@@ -10337,7 +11102,7 @@ function realFrontDoorPort(paths, spawnDaemon) {
10337
11102
 
10338
11103
  // src/launchWiring.ts
10339
11104
  function buildFarmRuntime(paths, cwd) {
10340
- const home = import_node_os5.default.homedir();
11105
+ const home = import_node_os6.default.homedir();
10341
11106
  const read = cosmiconfigReader();
10342
11107
  const classification = loadClassification(paths);
10343
11108
  const loaded = loadCascadeInput({ paths, home, cwd, read });
@@ -10476,6 +11241,13 @@ function prepareClaudeLaunch(options) {
10476
11241
  RC_PENDING_DEADLINE_MS,
10477
11242
  RC_PERMISSION_MODES,
10478
11243
  RC_REQUEST_PARSE_CAP_BYTES,
11244
+ RC_SELF_HOST_ENV,
11245
+ RC_SELF_HOST_KEEPALIVE_MS,
11246
+ RC_SELF_HOST_RECORD_DIR,
11247
+ RC_SELF_HOST_RECORD_FILE,
11248
+ RC_SELF_HOST_RETENTION_MS,
11249
+ RC_SELF_HOST_SCOPE_LIST,
11250
+ RC_SELF_HOST_WORKER_JWT_TTL_SECONDS,
10479
11251
  RC_SESSIONS_PATH_PREFIX,
10480
11252
  RC_STREAM_BACKOFF_MS,
10481
11253
  ROUTED_PATH_PREFIX,
@@ -10512,6 +11284,7 @@ function prepareClaudeLaunch(options) {
10512
11284
  createRcControlHandler,
10513
11285
  createRcCredentialStore,
10514
11286
  createRcEventFanout,
11287
+ createRcSelfHostSurface,
10515
11288
  createRcSessionTracker,
10516
11289
  createRcStreamHub,
10517
11290
  createSseParser,
@@ -10536,6 +11309,8 @@ function prepareClaudeLaunch(options) {
10536
11309
  isIdentityDirectoryName,
10537
11310
  isInterceptedHost,
10538
11311
  isRcPermissionMode,
11312
+ lateRcEventDial,
11313
+ lateRcStreamDial,
10539
11314
  listDirectoryRules,
10540
11315
  listIdentities,
10541
11316
  listProfiles,
@@ -10543,6 +11318,7 @@ function prepareClaudeLaunch(options) {
10543
11318
  listUsageSnapshots,
10544
11319
  matchBranch,
10545
11320
  mintLeaf,
11321
+ mintRcSelfHostCredential,
10546
11322
  observingRoutedRoute,
10547
11323
  parseConnectTarget,
10548
11324
  parseRcStreamEnvelope,
@@ -10554,6 +11330,7 @@ function prepareClaudeLaunch(options) {
10554
11330
  rankPool,
10555
11331
  rcEventWriteResultFromAnswer,
10556
11332
  rcObserverAsPassthrough,
11333
+ rcSelfHostFromEnv,
10557
11334
  readActiveIdentity,
10558
11335
  readDirectoryRules,
10559
11336
  readFarmManifest,
@@ -10562,6 +11339,7 @@ function prepareClaudeLaunch(options) {
10562
11339
  readPools,
10563
11340
  readProfile,
10564
11341
  readProvider,
11342
+ readRcSelfHostRecord,
10565
11343
  readUsageSnapshot,
10566
11344
  realConnectCertStore,
10567
11345
  realConnectEffects,
@@ -10585,6 +11363,7 @@ function prepareClaudeLaunch(options) {
10585
11363
  runCheck,
10586
11364
  runDoctor,
10587
11365
  runFrontDoorSupervisor,
11366
+ runLauncher,
10588
11367
  runSupervisor,
10589
11368
  servedByPipeline,
10590
11369
  setAllowAmbientCredential,
@@ -10599,6 +11378,7 @@ function prepareClaudeLaunch(options) {
10599
11378
  setRcSessionModel,
10600
11379
  setRcSessionPermissionMode,
10601
11380
  snapshotPath,
11381
+ spawnClaude,
10602
11382
  startConnectServer,
10603
11383
  topLevelNames,
10604
11384
  updateDirectoryRule,