agent-shim 8.11.2 → 8.12.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,
@@ -3030,8 +3043,8 @@ function parseConnectTarget(authority) {
3030
3043
  function isInterceptedHost(host, interceptHosts) {
3031
3044
  return interceptHosts.includes(host);
3032
3045
  }
3033
- function servedByPipeline(path30) {
3034
- return path30?.startsWith(ROUTED_PATH_PREFIX) === true;
3046
+ function servedByPipeline(path31) {
3047
+ return path31?.startsWith(ROUTED_PATH_PREFIX) === true;
3035
3048
  }
3036
3049
  var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
3037
3050
  "connection",
@@ -3113,14 +3126,17 @@ ${request4.rawHeaders.reduce((accumulated, value, index) => index % 2 === 0 ? `$
3113
3126
  pumpTapSession(socket, async (clientAlpn) => await effects.connectTlsUpstream(host, HTTPS_PORT, clientAlpn), config.capture?.tapStream?.(host), Buffer.from(headText, "utf8"));
3114
3127
  };
3115
3128
  const sessions = config.interceptHosts.map((host) => {
3116
- if (config.tapHosts.includes(host)) {
3129
+ if (config.tapHosts.includes(host) && !(config.localSurface?.parsesHost(host) ?? false)) {
3117
3130
  const serveSecure2 = (secure) => {
3118
3131
  pumpTapSession(secure, async (clientAlpn) => await effects.connectTlsUpstream(host, HTTPS_PORT, clientAlpn), config.capture?.tapStream?.(host));
3119
3132
  };
3120
3133
  const tlsAcceptor2 = effects.createTlsAcceptor(config.leafFor(host), serveSecure2, TAP_ALPN_PROTOCOLS);
3121
3134
  return { host, serveSecure: serveSecure2, tlsAcceptor: tlsAcceptor2 };
3122
3135
  }
3123
- const handler = (request4, response) => {
3136
+ const handleHostRequest = async (request4, response) => {
3137
+ if (config.localSurface !== void 0 && await config.localSurface.serve(host, request4, response)) {
3138
+ return;
3139
+ }
3124
3140
  if (host === config.routedHost && servedByPipeline(request4.url)) {
3125
3141
  const tunnelToken = tunnelTokens.get(request4.socket);
3126
3142
  if (tunnelToken !== void 0 && request4.headers[AUTH_HEADER] === void 0) {
@@ -3131,6 +3147,9 @@ ${request4.rawHeaders.reduce((accumulated, value, index) => index % 2 === 0 ? `$
3131
3147
  }
3132
3148
  effects.forwardHttp(config.upstreamFor(host), request4, response, config.capture?.observePassthrough(request4));
3133
3149
  };
3150
+ const handler = (request4, response) => {
3151
+ void handleHostRequest(request4, response);
3152
+ };
3134
3153
  const httpSession = effects.createHttpSession(handler, onUpgrade(host));
3135
3154
  const serveSecure = (secure, capability) => {
3136
3155
  tunnelTokens.set(secure, capability);
@@ -3513,7 +3532,7 @@ function parseRcRequestBody(kind, body) {
3513
3532
  return { controlRequests: [], answeredRequestIds: [], idleSeconds: finiteNumber(parseJsonObject(body), "idle_seconds"), workerStatus: void 0 };
3514
3533
  }
3515
3534
  if (kind === "worker-registration") {
3516
- return { controlRequests: [], answeredRequestIds: [], idleSeconds: void 0, workerStatus: nonEmptyString(parseJsonObject(body), "status") };
3535
+ return { controlRequests: [], answeredRequestIds: [], idleSeconds: void 0, workerStatus: nonEmptyString(parseJsonObject(body), "worker_status") };
3517
3536
  }
3518
3537
  const controlRequests = [];
3519
3538
  const answeredRequestIds = [];
@@ -3562,11 +3581,11 @@ function createRcSessionTracker(deps) {
3562
3581
  };
3563
3582
  const observeExchange = (request4) => {
3564
3583
  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)) {
3584
+ const path31 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
3585
+ if (!path31.startsWith(RC_SESSIONS_PATH_PREFIX)) {
3567
3586
  return void 0;
3568
3587
  }
3569
- const tail = path30.slice(RC_SESSIONS_PATH_PREFIX.length);
3588
+ const tail = path31.slice(RC_SESSIONS_PATH_PREFIX.length);
3570
3589
  const facts = {
3571
3590
  oauthAuthorization: oauthAuthorizationOf(request4.headers),
3572
3591
  anthropicVersion: singleHeader(request4.headers, "anthropic-version"),
@@ -4327,9 +4346,9 @@ function sequenceNumsOfBody(body) {
4327
4346
  }
4328
4347
  function frontDoorRcControl(transport, token) {
4329
4348
  const headers = { authorization: `Bearer ${token}` };
4330
- const listAnswerOf = async (path30, what) => {
4349
+ const listAnswerOf = async (path31, what) => {
4331
4350
  try {
4332
- return await transport.request({ method: "GET", path: path30, headers });
4351
+ return await transport.request({ method: "GET", path: path31, headers });
4333
4352
  } catch (error) {
4334
4353
  throw new Error(`${what}: could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
4335
4354
  }
@@ -4401,10 +4420,10 @@ function frontDoorRcControl(transport, token) {
4401
4420
  }
4402
4421
  return pending;
4403
4422
  };
4404
- const writeOf = async (path30, body, describeFailure) => {
4423
+ const writeOf = async (path31, body, describeFailure) => {
4405
4424
  let answer;
4406
4425
  try {
4407
- answer = await transport.request({ method: "POST", path: path30, headers: { ...headers, "content-type": "application/json" }, body });
4426
+ answer = await transport.request({ method: "POST", path: path31, headers: { ...headers, "content-type": "application/json" }, body });
4408
4427
  } catch (error) {
4409
4428
  return { ok: false, message: `could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}` };
4410
4429
  }
@@ -4614,14 +4633,41 @@ var NO_CHUNKS = {
4614
4633
  next: async () => await Promise.resolve({ done: true, value: void 0 })
4615
4634
  })
4616
4635
  };
4636
+ function lateRcEventDial(resolve) {
4637
+ let built;
4638
+ const dialFor = () => {
4639
+ const target = resolve();
4640
+ if (built === void 0 || built.for !== target) {
4641
+ built = { for: target, dial: realRcEventDial(target) };
4642
+ }
4643
+ return built.dial;
4644
+ };
4645
+ return {
4646
+ writeEvents: async (sessionId, headers, body) => await dialFor().writeEvents(sessionId, headers, body)
4647
+ };
4648
+ }
4649
+ function lateRcStreamDial(resolve) {
4650
+ let built;
4651
+ const dialFor = () => {
4652
+ const target = resolve();
4653
+ if (built === void 0 || built.for !== target) {
4654
+ built = { for: target, dial: realRcStreamDial(target) };
4655
+ }
4656
+ return built.dial;
4657
+ };
4658
+ return {
4659
+ announcePresence: async (sessionId, headers, clientId) => await dialFor().announcePresence(sessionId, headers, clientId),
4660
+ openStream: async (sessionId, headers, resume, signal) => await dialFor().openStream(sessionId, headers, resume, signal)
4661
+ };
4662
+ }
4617
4663
  function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
4618
4664
  const agent = new ExemptTlsAgent();
4619
- const request4 = async (method, path30, headers, body, signal) => await new Promise((resolve, reject) => {
4665
+ const request4 = async (method, path31, headers, body, signal) => await new Promise((resolve, reject) => {
4620
4666
  const options = {
4621
4667
  host: target.host,
4622
4668
  port: target.port,
4623
4669
  method,
4624
- path: path30,
4670
+ path: path31,
4625
4671
  // 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
4672
  headers: { ...headers, host: target.servername ?? target.host, ...body === void 0 ? {} : { "content-length": String(Buffer.byteLength(body, "utf8")) } },
4627
4673
  agent,
@@ -4658,9 +4704,9 @@ function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_P
4658
4704
  return { status, body: await readAll(response) };
4659
4705
  },
4660
4706
  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)}`;
4707
+ 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
4708
  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);
4709
+ const { status, response } = await request4("GET", path31, streamHeaders, void 0, signal);
4664
4710
  if (!isSuccessful2(status)) {
4665
4711
  await readAll(response);
4666
4712
  return { status, chunks: NO_CHUNKS };
@@ -5355,37 +5401,930 @@ function createRcStreamHub(deps) {
5355
5401
  await deps.sleep(deps.backoffMs);
5356
5402
  retriedUnauthorized = false;
5357
5403
  }
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
- }
5404
+ };
5405
+ return {
5406
+ reconcile: () => {
5407
+ const live = new Set(deps.trackedSessions());
5408
+ for (const [sessionId, attachment] of attachments) {
5409
+ if (!live.has(sessionId)) {
5410
+ attachment.stop();
5411
+ attachments.delete(sessionId);
5412
+ }
5413
+ }
5414
+ for (const sessionId of live) {
5415
+ if (attachments.has(sessionId)) {
5416
+ continue;
5417
+ }
5418
+ if (deps.credentialOf(sessionId)?.authorization === void 0) {
5419
+ continue;
5420
+ }
5421
+ const attachment = birth(sessionId);
5422
+ attachments.set(sessionId, attachment);
5423
+ void runLoop(attachment).catch((error) => {
5424
+ deps.log?.(`rc stream ${sessionId}: the attachment loop ended unexpectedly (${error instanceof Error ? error.message : String(error)})`);
5425
+ });
5426
+ }
5427
+ },
5428
+ close: () => {
5429
+ for (const attachment of attachments.values()) {
5430
+ attachment.stop();
5431
+ }
5432
+ attachments.clear();
5433
+ }
5434
+ };
5435
+ }
5436
+
5437
+ // src/frontdoor/rcSelfHost.ts
5438
+ var RC_SELF_HOST_ENV = "AGENT_SHIM_FRONTDOOR_RC_SELF_HOST";
5439
+ function rcSelfHostFromEnv(env) {
5440
+ return env[RC_SELF_HOST_ENV] === "1";
5441
+ }
5442
+ var RC_SELF_HOST_SCOPE_LIST = ["user:profile", "user:inference", "user:sessions:claude_code", "user:mcp_servers", "user:file_upload"];
5443
+ var RC_SESSIONS_PATH_PREFIX2 = "/v1/code/sessions";
5444
+ var RC_COMPAT_SESSIONS_PATH = "/v1/sessions";
5445
+ var RC_SESSION_ID_PREFIX2 = "cse_";
5446
+ var RC_SELF_HOST_API_BASE_URL = "https://api.anthropic.com";
5447
+ var RC_SELF_HOST_OAUTH_HOST = "platform.claude.com";
5448
+ var HTTP_CONFLICT = 409;
5449
+ var MS_PER_SECOND2 = 1e3;
5450
+ var HTTP_SERVICE_UNAVAILABLE = 503;
5451
+ var RC_SELF_HOST_WORKER_JWT_TTL_SECONDS = 46800;
5452
+ var RC_SELF_HOST_OAUTH_TOKEN_TTL_SECONDS = 3600;
5453
+ var RC_SELF_HOST_KEEPALIVE_MS = 15e3;
5454
+ var RC_SELF_HOST_RETENTION_MS = 6e5;
5455
+ var RC_PRESENCE_REFRESH_SECONDS = 60;
5456
+ var RC_SELF_HOST_MAX_BATCH_EVENTS = 100;
5457
+ var RC_SELF_HOST_WORKER_EPOCH = 1;
5458
+ var RC_STREAM_EVENT_NAME2 = "client_event";
5459
+ var RC_SOURCE_WORKER = "worker";
5460
+ var RC_SOURCE_CLIENT = "client";
5461
+ var CONFLICT_REASON_HEADER2 = "x-ccr-conflict-reason";
5462
+ var CONFLICT_REASON_EPOCH_STALE = "epoch_stale";
5463
+ function isRecord5(value) {
5464
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5465
+ }
5466
+ function nonEmptyString2(record, field) {
5467
+ const value = record === void 0 ? void 0 : record[field];
5468
+ return typeof value === "string" && value !== "" ? value : void 0;
5469
+ }
5470
+ function numberOf(record, field) {
5471
+ const value = record === void 0 ? void 0 : record[field];
5472
+ if (typeof value === "number" && Number.isFinite(value)) {
5473
+ return value;
5474
+ }
5475
+ if (typeof value === "string" && /^[0-9]+$/.test(value)) {
5476
+ return Number(value);
5477
+ }
5478
+ return void 0;
5479
+ }
5480
+ function singleHeader2(headers, name) {
5481
+ const value = headers[name];
5482
+ return typeof value === "string" ? value : void 0;
5483
+ }
5484
+ function bearerOf(headers) {
5485
+ const presented = singleHeader2(headers, "authorization");
5486
+ if (presented === void 0) {
5487
+ return void 0;
5488
+ }
5489
+ return presented.slice(0, "bearer ".length).toLowerCase() === "bearer " ? presented.slice("bearer ".length) : void 0;
5490
+ }
5491
+ async function readBody2(request4, capBytes) {
5492
+ return await new Promise((resolve, reject) => {
5493
+ const chunks = [];
5494
+ let total = 0;
5495
+ request4.on("data", (chunk) => {
5496
+ total += chunk.length;
5497
+ if (total > capBytes) {
5498
+ request4.destroy();
5499
+ reject(new Error("body too large"));
5500
+ return;
5501
+ }
5502
+ chunks.push(chunk);
5503
+ });
5504
+ request4.on("end", () => {
5505
+ resolve(Buffer.concat(chunks).toString("utf8"));
5506
+ });
5507
+ request4.on("error", () => {
5508
+ reject(new Error("the request body ended early"));
5509
+ });
5510
+ });
5511
+ }
5512
+ function parseJsonObject2(body) {
5513
+ let parsed;
5514
+ try {
5515
+ parsed = JSON.parse(body);
5516
+ } catch {
5517
+ return void 0;
5518
+ }
5519
+ return isRecord5(parsed) ? parsed : void 0;
5520
+ }
5521
+ function mintWorkerJwt(randomToken, issuedAt) {
5522
+ const encode = (value) => Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
5523
+ const header = encode({ alg: "HS256", typ: "JWT" });
5524
+ 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) });
5525
+ return `${header}.${payload}.${Buffer.from(randomToken(), "utf8").toString("base64url")}`;
5526
+ }
5527
+ function growthBookFeatures() {
5528
+ return {
5529
+ tengu_ccr_bridge: { defaultValue: true },
5530
+ tengu_bridge_repl_v2: { defaultValue: true },
5531
+ tengu_bridge_repl_v2_cse_shim_enabled: { defaultValue: true },
5532
+ tengu_bridge_min_version: { defaultValue: { minVersion: "0.0.0" } }
5533
+ };
5534
+ }
5535
+ function createRcSelfHostSurface(deps) {
5536
+ const sessions = /* @__PURE__ */ new Map();
5537
+ const sweep = () => {
5538
+ const now = deps.now();
5539
+ for (const session of sessions.values()) {
5540
+ while (session.events[0] !== void 0 && now - session.events[0].storedAt > RC_SELF_HOST_RETENTION_MS) {
5541
+ const dropped = session.events.shift();
5542
+ const uuid = dropped === void 0 ? void 0 : nonEmptyString2(dropped.payload, "uuid");
5543
+ if (uuid !== void 0) {
5544
+ session.seenPayloadUuids.delete(uuid);
5545
+ }
5546
+ }
5547
+ if (session.workerStreams.size === 0 && session.clientStreams.size === 0 && now - session.lastTrafficAt > RC_SELF_HOST_RETENTION_MS) {
5548
+ sessions.delete(session.id);
5549
+ }
5550
+ }
5551
+ };
5552
+ const timer = setInterval(sweep, RC_SELF_HOST_RETENTION_MS);
5553
+ timer.unref();
5554
+ const keepalive = setInterval(() => {
5555
+ for (const session of sessions.values()) {
5556
+ for (const sink of [...session.workerStreams, ...session.clientStreams]) {
5557
+ sink.write(": keep-alive\n\n");
5558
+ }
5559
+ }
5560
+ }, RC_SELF_HOST_KEEPALIVE_MS);
5561
+ keepalive.unref();
5562
+ const presentsCredential = (headers) => {
5563
+ const expected = deps.credentialRecord()?.accessToken;
5564
+ const presented = bearerOf(headers);
5565
+ return expected !== void 0 && presented !== void 0 && isLiveCapability(presented, [expected]);
5566
+ };
5567
+ const presentsWorkerJwt = (headers, session) => {
5568
+ const presented = bearerOf(headers);
5569
+ if (presented === void 0) {
5570
+ return false;
5571
+ }
5572
+ for (const minted of session.workerJwts) {
5573
+ if (isLiveCapability(presented, [minted])) {
5574
+ return true;
5575
+ }
5576
+ }
5577
+ return false;
5578
+ };
5579
+ const frameOf = (event) => {
5580
+ const envelope = {
5581
+ event_id: event.eventId,
5582
+ event_type: nonEmptyString2(event.payload, "type") ?? "event",
5583
+ sequence_num: event.sequenceNum,
5584
+ source: event.source,
5585
+ payload: event.payload,
5586
+ created_at: event.createdAt
5587
+ };
5588
+ return `event: ${RC_STREAM_EVENT_NAME2}
5589
+ id: ${String(event.sequenceNum)}
5590
+ data: ${JSON.stringify(envelope)}
5591
+
5592
+ `;
5593
+ };
5594
+ const holdStream = async (session, which, wantsReplay, request4, response) => {
5595
+ const url = new URL(request4.url, "http://127.0.0.1");
5596
+ const cursor = numberOf({ value: url.searchParams.get("from_sequence_num") }, "value") ?? numberOf({ value: singleHeader2(request4.headers, "last-event-id") }, "value");
5597
+ const replay = cursor === void 0 ? [] : session.events.filter((event) => wantsReplay(event) && event.sequenceNum > cursor);
5598
+ response.start(HTTP_STATUS.ok, { "content-type": "text/event-stream", "cache-control": "no-cache" });
5599
+ response.flush();
5600
+ let pending = Promise.resolve();
5601
+ const sink = {
5602
+ write: (frame) => {
5603
+ pending = pending.then(async () => {
5604
+ await response.write(frame);
5605
+ }).catch(() => {
5606
+ });
5607
+ },
5608
+ retire: () => {
5609
+ session[which].delete(sink);
5610
+ }
5611
+ };
5612
+ session[which].add(sink);
5613
+ session.lastTrafficAt = deps.now();
5614
+ for (const event of replay) {
5615
+ sink.write(frameOf(event));
5616
+ }
5617
+ await new Promise((resolve) => {
5618
+ request4.signal.addEventListener("abort", () => {
5619
+ resolve(void 0);
5620
+ }, { once: true });
5621
+ });
5622
+ sink.retire();
5623
+ response.end();
5624
+ };
5625
+ const publish = (session, source, payload) => {
5626
+ const uuid = nonEmptyString2(payload, "uuid");
5627
+ const duplicate = uuid !== void 0 && session.seenPayloadUuids.has(uuid);
5628
+ session.sequenceNum += 1;
5629
+ const event = {
5630
+ sequenceNum: session.sequenceNum,
5631
+ eventId: uuid ?? deps.newUuid(),
5632
+ source,
5633
+ // 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.
5634
+ payload: source === RC_SOURCE_CLIENT ? { ...payload, server_received_wall_ms: deps.now() } : payload,
5635
+ createdAt: new Date(deps.now()).toISOString(),
5636
+ toWorker: source === RC_SOURCE_CLIENT,
5637
+ storedAt: deps.now()
5638
+ };
5639
+ session.events.push(event);
5640
+ if (uuid !== void 0) {
5641
+ session.seenPayloadUuids.add(uuid);
5642
+ }
5643
+ session.lastTrafficAt = event.storedAt;
5644
+ const frame = frameOf(event);
5645
+ if (event.toWorker) {
5646
+ for (const sink of [...session.workerStreams]) {
5647
+ sink.write(frame);
5648
+ }
5649
+ }
5650
+ for (const sink of [...session.clientStreams]) {
5651
+ sink.write(frame);
5652
+ }
5653
+ return { sequenceNum: event.sequenceNum, eventId: event.eventId, duplicate };
5654
+ };
5655
+ const answerJson2 = async (response, status, body, extraHeaders = {}) => {
5656
+ const text = JSON.stringify(body);
5657
+ response.start(status, { "content-type": "application/json", "content-length": String(Buffer.byteLength(text, "utf8")), ...extraHeaders });
5658
+ await response.write(text);
5659
+ response.end();
5660
+ };
5661
+ const noCredential = async (response) => {
5662
+ 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" } });
5663
+ };
5664
+ const epochStale = async (response) => {
5665
+ 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 });
5666
+ };
5667
+ const unauthorized = async (response) => {
5668
+ 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" } });
5669
+ };
5670
+ const serveSessionPath = async (session, tail, request4, response) => {
5671
+ const method = request4.method.toUpperCase();
5672
+ if (session === void 0) {
5673
+ await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: "no such Remote Control session on this door" } });
5674
+ return;
5675
+ }
5676
+ session.lastTrafficAt = deps.now();
5677
+ if (tail === "") {
5678
+ if (method !== "GET") {
5679
+ await answerJson2(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the session read is a GET" } });
5680
+ return;
5681
+ }
5682
+ await answerJson2(response, HTTP_STATUS.ok, { session: { id: session.id, title: session.title, created_at: new Date(session.createdAt).toISOString(), status: "active" } });
5683
+ return;
5684
+ }
5685
+ if (tail === "bridge" && method === "POST") {
5686
+ if (!presentsCredential(request4.headers)) {
5687
+ await unauthorized(response);
5688
+ return;
5689
+ }
5690
+ const workerJwt = mintWorkerJwt(deps.randomToken, deps.now());
5691
+ session.workerJwts.add(workerJwt);
5692
+ deps.log?.(`rc selfhost ${session.id}: bridge registration minted a worker credential`);
5693
+ 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 });
5694
+ return;
5695
+ }
5696
+ if (tail === "archive" && method === "POST") {
5697
+ if (!presentsCredential(request4.headers)) {
5698
+ await unauthorized(response);
5699
+ return;
5700
+ }
5701
+ for (const sink of [...session.workerStreams, ...session.clientStreams]) {
5702
+ sink.retire();
5703
+ }
5704
+ sessions.delete(session.id);
5705
+ deps.log?.(`rc selfhost ${session.id}: archived at its client's request`);
5706
+ await answerJson2(response, HTTP_STATUS.ok, {});
5707
+ return;
5708
+ }
5709
+ if (tail === "worker" || tail.startsWith("worker/")) {
5710
+ if (!presentsWorkerJwt(request4.headers, session)) {
5711
+ await unauthorized(response);
5712
+ return;
5713
+ }
5714
+ const workerTail = tail === "worker" ? "" : tail.slice("worker/".length);
5715
+ if (workerTail === "" && method === "GET") {
5716
+ await answerJson2(response, HTTP_STATUS.ok, { worker: { external_metadata: session.externalMetadata ?? null } });
5717
+ return;
5718
+ }
5719
+ if (workerTail === "" && method === "PUT") {
5720
+ const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
5721
+ const claimedEpoch = numberOf(body, "worker_epoch");
5722
+ if (claimedEpoch !== void 0 && claimedEpoch !== RC_SELF_HOST_WORKER_EPOCH) {
5723
+ await epochStale(response);
5724
+ return;
5725
+ }
5726
+ const status = nonEmptyString2(body, "worker_status");
5727
+ if (status !== void 0) {
5728
+ session.workerStatus = status;
5729
+ }
5730
+ if (isRecord5(body?.external_metadata)) {
5731
+ session.externalMetadata = body.external_metadata;
5732
+ }
5733
+ await answerJson2(response, HTTP_STATUS.ok, {});
5734
+ return;
5735
+ }
5736
+ if (workerTail === "register" && method === "POST") {
5737
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5738
+ await answerJson2(response, HTTP_STATUS.ok, { worker_epoch: RC_SELF_HOST_WORKER_EPOCH });
5739
+ return;
5740
+ }
5741
+ if (workerTail === "heartbeat" && method === "POST") {
5742
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5743
+ await answerJson2(response, HTTP_STATUS.ok, {});
5744
+ return;
5745
+ }
5746
+ if (workerTail === "events" && method === "POST") {
5747
+ const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
5748
+ const claimedEpoch = numberOf(body, "worker_epoch");
5749
+ if (claimedEpoch !== void 0 && claimedEpoch !== RC_SELF_HOST_WORKER_EPOCH) {
5750
+ await epochStale(response);
5751
+ return;
5752
+ }
5753
+ const events = body?.events;
5754
+ if (!Array.isArray(events) || events.length === 0 || events.length > RC_SELF_HOST_MAX_BATCH_EVENTS) {
5755
+ 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` } });
5756
+ return;
5757
+ }
5758
+ const results = [];
5759
+ for (const event of events) {
5760
+ if (!isRecord5(event) || !isRecord5(event.payload)) {
5761
+ 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" } });
5762
+ return;
5763
+ }
5764
+ const published = publish(session, RC_SOURCE_WORKER, event.payload);
5765
+ results.push({ event_id: published.eventId, sequence_num: String(published.sequenceNum) });
5766
+ }
5767
+ sweep();
5768
+ await answerJson2(response, HTTP_STATUS.ok, { results });
5769
+ return;
5770
+ }
5771
+ if (workerTail === "events/stream" && method === "GET") {
5772
+ await holdStream(session, "workerStreams", (event) => event.toWorker, request4, response);
5773
+ return;
5774
+ }
5775
+ if (workerTail === "events/delivery" && method === "POST") {
5776
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5777
+ await answerJson2(response, HTTP_STATUS.ok, {});
5778
+ return;
5779
+ }
5780
+ if (workerTail === "internal-events" && method === "POST") {
5781
+ const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
5782
+ const claimedEpoch = numberOf(body, "worker_epoch");
5783
+ if (claimedEpoch !== void 0 && claimedEpoch !== RC_SELF_HOST_WORKER_EPOCH) {
5784
+ await epochStale(response);
5785
+ return;
5786
+ }
5787
+ const events = body?.events;
5788
+ if (!Array.isArray(events)) {
5789
+ await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "an internal event batch is an array" } });
5790
+ return;
5791
+ }
5792
+ for (const event of events) {
5793
+ if (isRecord5(event)) {
5794
+ session.internalEvents.push({ cursor: deps.newUuid(), body: event });
5795
+ }
5796
+ }
5797
+ await answerJson2(response, HTTP_STATUS.ok, {});
5798
+ return;
5799
+ }
5800
+ if (workerTail === "internal-events" && method === "GET") {
5801
+ const url = new URL(request4.url, "http://127.0.0.1");
5802
+ const cursor = url.searchParams.get("cursor");
5803
+ const from = cursor === null ? 0 : session.internalEvents.findIndex((event) => event.cursor === cursor) + 1;
5804
+ const page = session.internalEvents.slice(from);
5805
+ await answerJson2(response, HTTP_STATUS.ok, { data: page.map((event) => event.body), next_cursor: page.length === 0 ? void 0 : page[page.length - 1]?.cursor });
5806
+ return;
5807
+ }
5808
+ if (workerTail === "diagnostics" && method === "POST") {
5809
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5810
+ await answerJson2(response, HTTP_STATUS.ok, {});
5811
+ return;
5812
+ }
5813
+ await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `the self-hosted Remote Control surface serves no worker path "${workerTail}"` } });
5814
+ return;
5815
+ }
5816
+ if (!presentsCredential(request4.headers)) {
5817
+ await unauthorized(response);
5818
+ return;
5819
+ }
5820
+ if (tail === "events" && method === "POST") {
5821
+ const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
5822
+ const events = body?.events;
5823
+ if (!Array.isArray(events) || events.length === 0 || events.length > RC_SELF_HOST_MAX_BATCH_EVENTS) {
5824
+ 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` } });
5825
+ return;
5826
+ }
5827
+ const results = [];
5828
+ for (const event of events) {
5829
+ if (!isRecord5(event) || !isRecord5(event.payload)) {
5830
+ 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" } });
5831
+ return;
5832
+ }
5833
+ const published = publish(session, RC_SOURCE_CLIENT, event.payload);
5834
+ results.push({ sequence_num: String(published.sequenceNum), duplicate: published.duplicate });
5835
+ }
5836
+ sweep();
5837
+ await answerJson2(response, HTTP_STATUS.ok, { results });
5838
+ return;
5839
+ }
5840
+ if (tail === "events" && method === "GET") {
5841
+ 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 })) });
5842
+ return;
5843
+ }
5844
+ if (tail === "events/stream" && method === "GET") {
5845
+ await holdStream(session, "clientStreams", () => true, request4, response);
5846
+ return;
5847
+ }
5848
+ if (tail === "client/presence" && method === "POST") {
5849
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5850
+ await answerJson2(response, HTTP_STATUS.ok, { refresh_after_seconds: RC_PRESENCE_REFRESH_SECONDS });
5851
+ return;
5852
+ }
5853
+ if (tail === "mark_read" && method === "POST") {
5854
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5855
+ await answerJson2(response, HTTP_STATUS.ok, {});
5856
+ return;
5857
+ }
5858
+ if (tail === "teleport-events" && method === "POST") {
5859
+ await readBody2(request4.body, CONTROL_BODY_CAP_BYTES);
5860
+ await answerJson2(response, HTTP_STATUS.ok, {});
5861
+ return;
5862
+ }
5863
+ await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `the self-hosted Remote Control surface serves no path "${tail}"` } });
5864
+ };
5865
+ const recordMissing = () => deps.credentialRecord() === void 0;
5866
+ const route = {
5867
+ name: "rc-selfhost",
5868
+ headroomEligible: false,
5869
+ headroomUpstream: void 0,
5870
+ serve: async (request4, response) => {
5871
+ const method = request4.method.toUpperCase();
5872
+ const pathname = new URL(request4.url, "http://127.0.0.1").pathname;
5873
+ if (recordMissing()) {
5874
+ await noCredential(response);
5875
+ return;
5876
+ }
5877
+ if (pathname === RC_COMPAT_SESSIONS_PATH) {
5878
+ if (method !== "GET") {
5879
+ await answerJson2(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the compatibility session list is a GET" } });
5880
+ return;
5881
+ }
5882
+ if (!presentsCredential(request4.headers)) {
5883
+ await unauthorized(response);
5884
+ return;
5885
+ }
5886
+ await answerJson2(response, HTTP_STATUS.ok, { data: [] });
5887
+ return;
5888
+ }
5889
+ if (pathname !== RC_SESSIONS_PATH_PREFIX2 && !pathname.startsWith(`${RC_SESSIONS_PATH_PREFIX2}/`)) {
5890
+ await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `the self-hosted Remote Control surface serves no path "${pathname}"` } });
5891
+ return;
5892
+ }
5893
+ if (pathname === RC_SESSIONS_PATH_PREFIX2) {
5894
+ if (method === "POST") {
5895
+ if (!presentsCredential(request4.headers)) {
5896
+ await unauthorized(response);
5897
+ return;
5898
+ }
5899
+ const body = parseJsonObject2(await readBody2(request4.body, CONTROL_BODY_CAP_BYTES));
5900
+ const session = {
5901
+ id: `${RC_SESSION_ID_PREFIX2}${deps.newUuid()}`,
5902
+ createdAt: deps.now(),
5903
+ title: nonEmptyString2(body, "title"),
5904
+ workerJwts: /* @__PURE__ */ new Set(),
5905
+ sequenceNum: 0,
5906
+ events: [],
5907
+ seenPayloadUuids: /* @__PURE__ */ new Set(),
5908
+ workerStreams: /* @__PURE__ */ new Set(),
5909
+ clientStreams: /* @__PURE__ */ new Set(),
5910
+ internalEvents: [],
5911
+ workerStatus: void 0,
5912
+ externalMetadata: void 0,
5913
+ lastTrafficAt: deps.now()
5914
+ };
5915
+ sessions.set(session.id, session);
5916
+ deps.log?.(`rc selfhost ${session.id}: session created on the door's own surface`);
5917
+ await answerJson2(response, HTTP_STATUS.ok, { session: { id: session.id, title: session.title, created_at: new Date(session.createdAt).toISOString(), status: "active" } });
5918
+ return;
5919
+ }
5920
+ if (method === "GET") {
5921
+ if (!presentsCredential(request4.headers)) {
5922
+ await unauthorized(response);
5923
+ return;
5924
+ }
5925
+ 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" })) });
5926
+ return;
5927
+ }
5928
+ await answerJson2(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the session collection is a POST (create) and a GET (list)" } });
5929
+ return;
5930
+ }
5931
+ const rest = pathname.slice(`${RC_SESSIONS_PATH_PREFIX2}/`.length);
5932
+ const slash = rest.indexOf("/");
5933
+ const id = slash === -1 ? rest : rest.slice(0, slash);
5934
+ const tail = slash === -1 ? "" : rest.slice(slash + 1);
5935
+ if (!id.startsWith(RC_SESSION_ID_PREFIX2)) {
5936
+ await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: "the session family names one cse_-prefixed session id" } });
5937
+ return;
5938
+ }
5939
+ await serveSessionPath(sessions.get(id), tail, request4, response);
5940
+ }
5941
+ };
5942
+ const answerServerJson = (response, status, body) => {
5943
+ const text = JSON.stringify(body);
5944
+ response.writeHead(status, { "content-type": "application/json", "content-length": String(Buffer.byteLength(text, "utf8")) });
5945
+ response.end(text);
5946
+ };
5947
+ const local = {
5948
+ parsesHost: (host) => host === RC_SELF_HOST_OAUTH_HOST,
5949
+ serve: async (host, request4, response) => {
5950
+ const method = (request4.method ?? "").toUpperCase();
5951
+ const pathname = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
5952
+ if (host === RC_SELF_HOST_OAUTH_HOST) {
5953
+ if (method === "POST" && pathname === "/v1/oauth/token") {
5954
+ const body = parseJsonObject2(await readBody2(request4, CONTROL_BODY_CAP_BYTES));
5955
+ const record = deps.credentialRecord();
5956
+ if (record === void 0) {
5957
+ 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" });
5958
+ return true;
5959
+ }
5960
+ if (body?.grant_type !== void 0 && body.grant_type !== "refresh_token") {
5961
+ answerServerJson(response, HTTP_STATUS.badRequest, { error: "unsupported_grant_type" });
5962
+ return true;
5963
+ }
5964
+ 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(" ") });
5965
+ return true;
5966
+ }
5967
+ if (method === "GET" && pathname === "/v1/oauth/hello") {
5968
+ answerServerJson(response, HTTP_STATUS.ok, {});
5969
+ return true;
5970
+ }
5971
+ return false;
5972
+ }
5973
+ if (method === "POST" && pathname.startsWith("/api/eval/")) {
5974
+ await readBody2(request4, CONTROL_BODY_CAP_BYTES);
5975
+ answerServerJson(response, HTTP_STATUS.ok, { features: growthBookFeatures(), dateUpdated: Math.floor(deps.now() / MS_PER_SECOND2) });
5976
+ return true;
5977
+ }
5978
+ if (method === "GET" && pathname === "/api/oauth/profile") {
5979
+ const record = deps.credentialRecord();
5980
+ if (record === void 0) {
5981
+ 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" });
5982
+ return true;
5983
+ }
5984
+ answerServerJson(response, HTTP_STATUS.ok, {
5985
+ account: { uuid: record.accountUuid, display_name: "agent-shim self-hosted", created_at: (/* @__PURE__ */ new Date(0)).toISOString() },
5986
+ organization: { uuid: record.organizationUuid, organization_type: "claude_max" }
5987
+ });
5988
+ return true;
5989
+ }
5990
+ if (method === "GET" && pathname === "/api/claude_code/policy_limits") {
5991
+ answerServerJson(response, HTTP_STATUS.ok, {});
5992
+ return true;
5993
+ }
5994
+ if (method === "POST" && pathname === "/api/oauth/validate") {
5995
+ await readBody2(request4, CONTROL_BODY_CAP_BYTES);
5996
+ const record = deps.credentialRecord();
5997
+ if (record === void 0) {
5998
+ 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" });
5999
+ return true;
6000
+ }
6001
+ answerServerJson(response, HTTP_STATUS.ok, { scopes: [...RC_SELF_HOST_SCOPE_LIST], expiresAt: null, subscriptionType: "max", account_uuid: record.accountUuid, organization_uuid: record.organizationUuid });
6002
+ return true;
6003
+ }
6004
+ if (method === "POST" && (pathname === "/api/event_logging/v2/batch" || pathname === "/api/claude_code/metrics" || pathname === "/api/claude_cli_feedback")) {
6005
+ await readBody2(request4, CONTROL_BODY_CAP_BYTES);
6006
+ answerServerJson(response, HTTP_STATUS.ok, {});
6007
+ return true;
6008
+ }
6009
+ if (method === "GET" && pathname === "/api/hello") {
6010
+ answerServerJson(response, HTTP_STATUS.ok, {});
6011
+ return true;
6012
+ }
6013
+ return false;
6014
+ }
6015
+ };
6016
+ return {
6017
+ route,
6018
+ local,
6019
+ close: () => {
6020
+ clearInterval(timer);
6021
+ clearInterval(keepalive);
6022
+ for (const session of sessions.values()) {
6023
+ for (const sink of [...session.workerStreams, ...session.clientStreams]) {
6024
+ sink.retire();
6025
+ }
6026
+ }
6027
+ sessions.clear();
6028
+ }
6029
+ };
6030
+ }
6031
+
6032
+ // src/frontdoor/rcSelfHostMint.ts
6033
+ var import_node_path11 = __toESM(require("node:path"), 1);
6034
+
6035
+ // src/usage/account.ts
6036
+ var import_node_path10 = __toESM(require("node:path"), 1);
6037
+
6038
+ // src/usage/schema.ts
6039
+ var import_zod5 = require("zod");
6040
+ var USAGE_SCHEMA_VERSION = 1;
6041
+ var VersionSchema = import_zod5.z.literal(USAGE_SCHEMA_VERSION);
6042
+ var InstantSchema = import_zod5.z.iso.datetime();
6043
+ var TokenCountSchema = import_zod5.z.number().int().nonnegative();
6044
+ var TokenUsageSchema = import_zod5.z.strictObject({
6045
+ inputTokens: TokenCountSchema.optional(),
6046
+ outputTokens: TokenCountSchema.optional(),
6047
+ cacheCreationInputTokens: TokenCountSchema.optional(),
6048
+ cacheReadInputTokens: TokenCountSchema.optional()
6049
+ });
6050
+ var LIMIT_KINDS = ["rate-limited", "quota-exhausted"];
6051
+ var LimitClassificationSchema = import_zod5.z.strictObject({
6052
+ kind: import_zod5.z.enum(LIMIT_KINDS),
6053
+ /** Seconds to wait before retrying, from the response's `retry-after`. */
6054
+ retryAfterSeconds: import_zod5.z.number().nonnegative().optional(),
6055
+ /** When the limiting window resets, from the upstream's own reset header. */
6056
+ resetAt: InstantSchema.optional(),
6057
+ /** The window the upstream named as the binding one (`anthropic-ratelimit-unified-representative-claim`), such as `five_hour` or `seven_day`. */
6058
+ window: import_zod5.z.string().optional(),
6059
+ /** 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. */
6060
+ evidence: import_zod5.z.array(import_zod5.z.string())
6061
+ });
6062
+ var UsageRecordSchema = import_zod5.z.strictObject({
6063
+ schemaVersion: VersionSchema,
6064
+ /** When the front door received the request. */
6065
+ at: InstantSchema,
6066
+ /** The launching identity, when the launch resolved one. */
6067
+ identity: import_zod5.z.string().optional(),
6068
+ /** `anthropic` for an OAuth session's request to Claude Code's own API, otherwise the provider's name. */
6069
+ provider: import_zod5.z.string(),
6070
+ /** The launch's session id, generated per launch. */
6071
+ sessionId: import_zod5.z.string().optional(),
6072
+ /** The project the launch ran in (its git repository root), when the launch sent one: headroom launches do. */
6073
+ project: import_zod5.z.string().optional(),
6074
+ /** The front-door route that served the request. */
6075
+ route: import_zod5.z.string(),
6076
+ method: import_zod5.z.string(),
6077
+ /** The API path as the upstream sees it (`/v1/messages`), without the provider prefix or a query string. */
6078
+ endpoint: import_zod5.z.string(),
6079
+ /** The model the response named. */
6080
+ model: import_zod5.z.string().optional(),
6081
+ status: import_zod5.z.number().int(),
6082
+ /** Milliseconds from the request's arrival to its response head. */
6083
+ latencyMs: import_zod5.z.number().int().nonnegative(),
6084
+ /** Milliseconds from the request's arrival to the end of its response body. */
6085
+ durationMs: import_zod5.z.number().int().nonnegative(),
6086
+ /** Whether the client received the whole body. */
6087
+ outcome: import_zod5.z.enum(["completed", "aborted"]),
6088
+ usage: TokenUsageSchema.optional(),
6089
+ /** The response's quota and rate-limit headers, by name (see `isRateLimitHeader`). */
6090
+ rateLimitHeaders: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.string()).optional(),
6091
+ limit: LimitClassificationSchema.optional(),
6092
+ /** The upstream's request id (`request-id`), for matching a record to the provider's own logs. */
6093
+ requestId: import_zod5.z.string().optional()
6094
+ });
6095
+ var QuotaWindowSchema = import_zod5.z.strictObject({
6096
+ /** The fraction of the window used, as the upstream reports it (0 to 1). */
6097
+ utilization: import_zod5.z.number().nonnegative().optional(),
6098
+ resetsAt: InstantSchema.optional(),
6099
+ /** The window's own status (`allowed`, `allowed_warning`, `rejected`). */
6100
+ status: import_zod5.z.string().optional()
6101
+ });
6102
+ var UnifiedRateLimitSchema = import_zod5.z.strictObject({
6103
+ /** The overall status: `allowed`, `allowed_warning` or `rejected`. */
6104
+ status: import_zod5.z.string().optional(),
6105
+ fiveHour: QuotaWindowSchema.optional(),
6106
+ sevenDay: QuotaWindowSchema.optional(),
6107
+ /** The window that currently binds. */
6108
+ representativeClaim: import_zod5.z.string().optional(),
6109
+ /** When the binding window resets. */
6110
+ resetAt: InstantSchema.optional(),
6111
+ /** Whether usage beyond the plan (extra usage) is available: `allowed` or `rejected`. */
6112
+ overageStatus: import_zod5.z.string().optional()
6113
+ });
6114
+ var RateLimitStateSchema = import_zod5.z.strictObject({
6115
+ observedAt: InstantSchema,
6116
+ /** Every quota and rate-limit header on that response, by name. */
6117
+ headers: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.string()),
6118
+ unified: UnifiedRateLimitSchema.optional()
6119
+ });
6120
+ var LimitEventSchema = LimitClassificationSchema.extend({
6121
+ observedAt: InstantSchema,
6122
+ status: import_zod5.z.number().int()
6123
+ });
6124
+ var ProviderQuotaWindowSchema = import_zod5.z.strictObject({
6125
+ /** What the window measures, in the provider's terms (`tokens`, `tool-calls`). */
6126
+ measures: import_zod5.z.string(),
6127
+ /** 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. */
6128
+ periodMs: import_zod5.z.number().int().positive().optional(),
6129
+ /** The provider's own description of the period when `periodMs` could not be derived, such as `unit 4 x 1`. */
6130
+ period: import_zod5.z.string().optional(),
6131
+ /** The fraction of the window used (0 to 1). */
6132
+ utilization: import_zod5.z.number().nonnegative(),
6133
+ resetsAt: InstantSchema.optional(),
6134
+ /** Absolute counts, when the provider reports them for this window. */
6135
+ limit: import_zod5.z.number().nonnegative().optional(),
6136
+ used: import_zod5.z.number().nonnegative().optional(),
6137
+ remaining: import_zod5.z.number().nonnegative().optional()
6138
+ });
6139
+ var ProviderQuotaSchema = import_zod5.z.strictObject({
6140
+ observedAt: InstantSchema,
6141
+ /** Which usage endpoint produced it (`z.ai`). */
6142
+ source: import_zod5.z.string(),
6143
+ /** The subscription level the endpoint reports, when it does. */
6144
+ level: import_zod5.z.string().optional(),
6145
+ windows: import_zod5.z.array(ProviderQuotaWindowSchema)
6146
+ });
6147
+ var ProviderUsageStateSchema = import_zod5.z.strictObject({
6148
+ lastRequestAt: InstantSchema,
6149
+ lastStatus: import_zod5.z.number().int(),
6150
+ lastModel: import_zod5.z.string().optional(),
6151
+ /** The latest rate-limit state, from the last response that carried any rate-limit header. */
6152
+ rateLimit: RateLimitStateSchema.optional(),
6153
+ /** The latest classified refusal. It stays after later successes, so a reader compares its `resetAt` (or `observedAt` plus `retryAfterSeconds`) with the current time. */
6154
+ lastLimit: LimitEventSchema.optional(),
6155
+ /** The latest quota the provider's usage endpoint reported, for providers whose quota is not visible in response headers. */
6156
+ quota: ProviderQuotaSchema.optional()
6157
+ });
6158
+ var AccountMetadataSchema = import_zod5.z.strictObject({
6159
+ accountUuid: import_zod5.z.string().optional(),
6160
+ emailAddress: import_zod5.z.string().optional(),
6161
+ displayName: import_zod5.z.string().optional(),
6162
+ organizationUuid: import_zod5.z.string().optional(),
6163
+ organizationName: import_zod5.z.string().optional(),
6164
+ organizationType: import_zod5.z.string().optional(),
6165
+ organizationRole: import_zod5.z.string().optional(),
6166
+ workspaceRole: import_zod5.z.string().optional(),
6167
+ billingType: import_zod5.z.string().optional(),
6168
+ seatTier: import_zod5.z.string().optional(),
6169
+ organizationRateLimitTier: import_zod5.z.string().optional(),
6170
+ userRateLimitTier: import_zod5.z.string().optional(),
6171
+ hasExtraUsageEnabled: import_zod5.z.boolean().optional(),
6172
+ subscriptionCreatedAt: import_zod5.z.string().optional(),
6173
+ accountCreatedAt: import_zod5.z.string().optional()
6174
+ });
6175
+ var UsageSnapshotSchema = import_zod5.z.strictObject({
6176
+ schemaVersion: VersionSchema,
6177
+ identity: import_zod5.z.string(),
6178
+ updatedAt: InstantSchema,
6179
+ /** The identity's account metadata as of `updatedAt`. */
6180
+ account: AccountMetadataSchema.optional(),
6181
+ /** Latest state per provider, keyed by provider name (`anthropic` for OAuth sessions). */
6182
+ providers: import_zod5.z.record(import_zod5.z.string(), ProviderUsageStateSchema)
6183
+ });
6184
+
6185
+ // src/usage/account.ts
6186
+ var CLAUDE_JSON = ".claude.json";
6187
+ var AccountMetadataError = class extends CliError {
6188
+ constructor(file, detail) {
6189
+ super(`${file}: ${detail}, so its account metadata cannot be read.`);
6190
+ this.file = file;
6191
+ this.name = "AccountMetadataError";
6192
+ }
6193
+ file;
6194
+ };
6195
+ function isObject(value) {
6196
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6197
+ }
6198
+ function isIdentityName(name) {
6199
+ return IdentitySchema.shape.name.safeParse(name).success;
6200
+ }
6201
+ function claudeJsonPath(identitiesDir, identity) {
6202
+ return import_node_path10.default.join(identitiesDir, identity, CLAUDE_JSON);
6203
+ }
6204
+ function readAccountMetadata(fs12, identitiesDir, identity) {
6205
+ if (!isIdentityName(identity)) {
6206
+ throw new Error(`"${identity}" is not a valid identity name.`);
6207
+ }
6208
+ const file = claudeJsonPath(identitiesDir, identity);
6209
+ const raw = fs12.readFileUtf8(file);
6210
+ if (raw === void 0) {
6211
+ return void 0;
6212
+ }
6213
+ let parsed;
6214
+ try {
6215
+ parsed = JSON.parse(raw);
6216
+ } catch {
6217
+ throw new AccountMetadataError(file, "not valid JSON");
6218
+ }
6219
+ if (!isObject(parsed)) {
6220
+ throw new AccountMetadataError(file, "not a JSON object");
6221
+ }
6222
+ const oauthAccount = parsed.oauthAccount;
6223
+ if (!isObject(oauthAccount)) {
6224
+ return void 0;
6225
+ }
6226
+ const picked = {};
6227
+ for (const key of Object.keys(AccountMetadataSchema.shape)) {
6228
+ const value = oauthAccount[key];
6229
+ if (value !== null && value !== void 0) {
6230
+ picked[key] = value;
6231
+ }
6232
+ }
6233
+ const account = AccountMetadataSchema.safeParse(picked);
6234
+ if (!account.success) {
6235
+ throw new AccountMetadataError(file, account.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; "));
6236
+ }
6237
+ return account.data;
6238
+ }
6239
+
6240
+ // src/frontdoor/rcSelfHostMint.ts
6241
+ var CREDENTIALS_FILE = ".credentials.json";
6242
+ var CLAUDE_JSON2 = ".claude.json";
6243
+ var RC_SELF_HOST_RECORD_DIR = "rc-selfhost";
6244
+ var RC_SELF_HOST_RECORD_FILE = "credential.json";
6245
+ var SELF_HOST_EMAIL = "selfhost@agent-shim.invalid";
6246
+ var SELF_HOST_SUBSCRIPTION_TYPE = "max";
6247
+ function isRecord6(value) {
6248
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6249
+ }
6250
+ function readJsonObject(fs12, file) {
6251
+ const raw = fs12.readFileUtf8(file);
6252
+ if (raw === void 0) {
6253
+ return void 0;
6254
+ }
6255
+ let parsed;
6256
+ try {
6257
+ parsed = JSON.parse(raw);
6258
+ } catch {
6259
+ return void 0;
6260
+ }
6261
+ return isRecord6(parsed) ? parsed : void 0;
6262
+ }
6263
+ function readRcSelfHostRecord(fs12, frontdoorDir) {
6264
+ const parsed = readJsonObject(fs12, import_node_path11.default.join(frontdoorDir, RC_SELF_HOST_RECORD_DIR, RC_SELF_HOST_RECORD_FILE));
6265
+ if (parsed === void 0) {
6266
+ return void 0;
6267
+ }
6268
+ const { accessToken, refreshToken, organizationUuid, accountUuid } = parsed;
6269
+ if (typeof accessToken !== "string" || accessToken === "" || typeof refreshToken !== "string" || refreshToken === "" || typeof organizationUuid !== "string" || organizationUuid === "" || typeof accountUuid !== "string" || accountUuid === "") {
6270
+ return void 0;
6271
+ }
6272
+ return { accessToken, refreshToken, organizationUuid, accountUuid };
6273
+ }
6274
+ function mintRcSelfHostCredential(deps) {
6275
+ if (!isIdentityName(deps.identity)) {
6276
+ throw new Error(`"${deps.identity}" is not a valid identity name.`);
6277
+ }
6278
+ const identityDir = import_node_path11.default.join(deps.identitiesDir, deps.identity);
6279
+ const credentialsFile = import_node_path11.default.join(identityDir, CREDENTIALS_FILE);
6280
+ const claudeJsonFile = import_node_path11.default.join(identityDir, CLAUDE_JSON2);
6281
+ const recordDir = import_node_path11.default.join(deps.frontdoorDir, RC_SELF_HOST_RECORD_DIR);
6282
+ const recordFile = import_node_path11.default.join(recordDir, RC_SELF_HOST_RECORD_FILE);
6283
+ const previousRecord = readRcSelfHostRecord(deps.fs, deps.frontdoorDir);
6284
+ const existingCredentials = readJsonObject(deps.fs, credentialsFile);
6285
+ const existingOauth = isRecord6(existingCredentials?.claudeAiOauth) ? existingCredentials.claudeAiOauth : void 0;
6286
+ const existingToken = typeof existingOauth?.accessToken === "string" && existingOauth.accessToken !== "" ? existingOauth.accessToken : void 0;
6287
+ const existingIsOwn = existingToken !== void 0 && previousRecord?.accessToken === existingToken;
6288
+ if (existingToken !== void 0 && !existingIsOwn && !deps.force) {
6289
+ throw new Error(
6290
+ `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.`
6291
+ );
6292
+ }
6293
+ const accessToken = `sk-ant-oat${deps.randomToken()}`;
6294
+ const refreshToken = deps.randomToken();
6295
+ const organizationUuid = deps.newUuid();
6296
+ const accountUuid = deps.newUuid();
6297
+ const mintedAt = new Date(deps.now()).toISOString();
6298
+ deps.fs.mkdirPrivate(import_node_path11.default.dirname(credentialsFile));
6299
+ 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)}
6300
+ `);
6301
+ const claudeJson = readJsonObject(deps.fs, claudeJsonFile) ?? {};
6302
+ const existingBlock = (value) => isRecord6(value) ? value : {};
6303
+ deps.fs.writeFilePrivate(claudeJsonFile, `${JSON.stringify({
6304
+ ...claudeJson,
6305
+ oauthAccount: {
6306
+ ...existingBlock(claudeJson.oauthAccount),
6307
+ accountUuid,
6308
+ emailAddress: SELF_HOST_EMAIL,
6309
+ organizationUuid,
6310
+ organizationName: "agent-shim self-hosted",
6311
+ // 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.
6312
+ billingType: "stripe_subscription",
6313
+ accountCreatedAt: mintedAt,
6314
+ subscriptionCreatedAt: mintedAt
5381
6315
  },
5382
- close: () => {
5383
- for (const attachment of attachments.values()) {
5384
- attachment.stop();
5385
- }
5386
- attachments.clear();
6316
+ cachedGrowthBookFeatures: {
6317
+ ...existingBlock(claudeJson.cachedGrowthBookFeatures),
6318
+ tengu_ccr_bridge: true,
6319
+ tengu_bridge_repl_v2: true,
6320
+ tengu_bridge_repl_v2_cse_shim_enabled: true
5387
6321
  }
5388
- };
6322
+ }, null, 2)}
6323
+ `);
6324
+ deps.fs.mkdirPrivate(recordDir);
6325
+ deps.fs.writeFilePrivate(recordFile, `${JSON.stringify({ accessToken, refreshToken, organizationUuid, accountUuid }, null, 2)}
6326
+ `);
6327
+ return { identity: deps.identity, organizationUuid, credentialsFile, claudeJsonFile, recordFile, replaced: existingIsOwn };
5389
6328
  }
5390
6329
 
5391
6330
  // src/frontdoor/ensure.ts
@@ -5393,32 +6332,32 @@ var import_node_crypto7 = require("node:crypto");
5393
6332
 
5394
6333
  // src/headroom/state.ts
5395
6334
  var import_node_crypto6 = require("node:crypto");
5396
- var import_node_path10 = __toESM(require("node:path"), 1);
5397
- var import_zod5 = require("zod");
6335
+ var import_node_path12 = __toESM(require("node:path"), 1);
6336
+ var import_zod6 = require("zod");
5398
6337
  var HEADROOM_ANTHROPIC_UPSTREAM = "https://api.anthropic.com";
5399
6338
  var HEADROOM_STATE_SCHEMA_VERSION = 2;
5400
- var HeadroomStateSchema = import_zod5.z.strictObject({
6339
+ var HeadroomStateSchema = import_zod6.z.strictObject({
5401
6340
  /** The supervisor process owning the daemon. Alive means someone is keeping headroom running. */
5402
- supervisorPid: import_zod5.z.number().int().positive().optional(),
6341
+ supervisorPid: import_zod6.z.number().int().positive().optional(),
5403
6342
  /** The headroom proxy process itself. Absent while the supervisor is between restarts. */
5404
- headroomPid: import_zod5.z.number().int().positive().optional(),
6343
+ headroomPid: import_zod6.z.number().int().positive().optional(),
5405
6344
  /**
5406
6345
  * 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
6346
  */
5408
- socketPath: import_zod5.z.string().min(1).optional(),
6347
+ socketPath: import_zod6.z.string().min(1).optional(),
5409
6348
  /** The `headroom --version` output of the running install. */
5410
- version: import_zod5.z.string().optional(),
6349
+ version: import_zod6.z.string().optional(),
5411
6350
  /** 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(),
6351
+ allowlistHash: import_zod6.z.string().optional(),
5413
6352
  /** 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(),
6353
+ settingsHash: import_zod6.z.string().optional(),
5415
6354
  /** 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(),
6355
+ installedSource: import_zod6.z.string().optional(),
5417
6356
  /** 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()
6357
+ lastError: import_zod6.z.string().optional()
5419
6358
  });
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() });
6359
+ 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() });
6360
+ var HeadroomLockSchema = import_zod6.z.strictObject({ pid: import_zod6.z.number().int().positive(), at: import_zod6.z.number() });
5422
6361
  function parseJson(raw, schema) {
5423
6362
  if (raw === void 0 || raw.trim() === "") {
5424
6363
  return void 0;
@@ -5434,7 +6373,7 @@ function readHeadroomState(fs12, stateFile) {
5434
6373
  }
5435
6374
  }
5436
6375
  function writeHeadroomState(fs12, stateFile, state) {
5437
- fs12.mkdirp(import_node_path10.default.dirname(stateFile));
6376
+ fs12.mkdirp(import_node_path12.default.dirname(stateFile));
5438
6377
  fs12.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
5439
6378
  `);
5440
6379
  }
@@ -5462,7 +6401,7 @@ function readAllProviders(fs12, providersDir) {
5462
6401
  continue;
5463
6402
  }
5464
6403
  try {
5465
- const parsed = parseJson(fs12.readFileUtf8(import_node_path10.default.join(providersDir, name)), ProviderSchema);
6404
+ const parsed = parseJson(fs12.readFileUtf8(import_node_path12.default.join(providersDir, name)), ProviderSchema);
5466
6405
  if (parsed !== void 0) {
5467
6406
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
5468
6407
  }
@@ -5474,11 +6413,11 @@ function readAllProviders(fs12, providersDir) {
5474
6413
  }
5475
6414
  function writeSession(fs12, sessionsDir, session) {
5476
6415
  fs12.mkdirp(sessionsDir);
5477
- fs12.writeFileUtf8(import_node_path10.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
6416
+ fs12.writeFileUtf8(import_node_path12.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
5478
6417
  `);
5479
6418
  }
5480
6419
  function removeSession(fs12, sessionsDir, pid) {
5481
- fs12.removeRecursive(import_node_path10.default.join(sessionsDir, `${String(pid)}.json`));
6420
+ fs12.removeRecursive(import_node_path12.default.join(sessionsDir, `${String(pid)}.json`));
5482
6421
  }
5483
6422
  function listSessions(fs12, sessionsDir) {
5484
6423
  const sessions = [];
@@ -5487,7 +6426,7 @@ function listSessions(fs12, sessionsDir) {
5487
6426
  continue;
5488
6427
  }
5489
6428
  try {
5490
- const parsed = parseJson(fs12.readFileUtf8(import_node_path10.default.join(sessionsDir, name)), HeadroomSessionSchema);
6429
+ const parsed = parseJson(fs12.readFileUtf8(import_node_path12.default.join(sessionsDir, name)), HeadroomSessionSchema);
5491
6430
  if (parsed !== void 0) {
5492
6431
  sessions.push(parsed);
5493
6432
  }
@@ -5592,214 +6531,7 @@ function ensureFrontDoor(params) {
5592
6531
  }
5593
6532
 
5594
6533
  // 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
6534
+ var import_node_path13 = __toESM(require("node:path"), 1);
5803
6535
  var SEGMENT_RE = /^(\d{4}-\d{2}-\d{2})\.(\d+)\.jsonl$/;
5804
6536
  var DAY_MS = 864e5;
5805
6537
  function listLogSegments(fs12, logDir) {
@@ -5820,7 +6552,7 @@ function readUsageLog(fs12, logDir, options = {}) {
5820
6552
  if (sinceMs !== void 0 && segment.endsAt <= sinceMs) {
5821
6553
  continue;
5822
6554
  }
5823
- const contents = fs12.readFileUtf8(import_node_path12.default.join(logDir, segment.name));
6555
+ const contents = fs12.readFileUtf8(import_node_path13.default.join(logDir, segment.name));
5824
6556
  if (contents === void 0) {
5825
6557
  continue;
5826
6558
  }
@@ -5862,7 +6594,7 @@ function snapshotPath(snapshotsDir, identity) {
5862
6594
  if (!isIdentityName(identity)) {
5863
6595
  throw new Error(`"${identity}" is not a valid identity name.`);
5864
6596
  }
5865
- return import_node_path12.default.join(snapshotsDir, `${identity}.json`);
6597
+ return import_node_path13.default.join(snapshotsDir, `${identity}.json`);
5866
6598
  }
5867
6599
  function readUsageSnapshot(fs12, snapshotsDir, identity) {
5868
6600
  const file = snapshotPath(snapshotsDir, identity);
@@ -5897,13 +6629,13 @@ function listUsageSnapshots(fs12, snapshotsDir) {
5897
6629
  }
5898
6630
 
5899
6631
  // src/usage/preflight.ts
5900
- var MS_PER_SECOND2 = 1e3;
6632
+ var MS_PER_SECOND3 = 1e3;
5901
6633
  var SECONDS_PER_MINUTE = 60;
5902
6634
  var MINUTES_PER_HOUR = 60;
5903
6635
  var HOURS_PER_DAY = 24;
5904
6636
  var WARNING_STATUSES = /* @__PURE__ */ new Set(["allowed_warning", "rejected"]);
5905
6637
  function formatAge(ms) {
5906
- const minutes = Math.floor(ms / (MS_PER_SECOND2 * SECONDS_PER_MINUTE));
6638
+ const minutes = Math.floor(ms / (MS_PER_SECOND3 * SECONDS_PER_MINUTE));
5907
6639
  if (minutes < MINUTES_PER_HOUR) {
5908
6640
  return `${String(Math.max(minutes, 0))}m`;
5909
6641
  }
@@ -5981,13 +6713,13 @@ function planOf(account) {
5981
6713
  }
5982
6714
 
5983
6715
  // src/usage/rateLimit.ts
5984
- var MS_PER_SECOND3 = 1e3;
6716
+ var MS_PER_SECOND4 = 1e3;
5985
6717
  function epochSecondsToIso(value) {
5986
6718
  if (value === void 0) {
5987
6719
  return void 0;
5988
6720
  }
5989
6721
  const seconds = Number(value);
5990
- return Number.isFinite(seconds) && seconds > 0 ? new Date(seconds * MS_PER_SECOND3).toISOString() : void 0;
6722
+ return Number.isFinite(seconds) && seconds > 0 ? new Date(seconds * MS_PER_SECOND4).toISOString() : void 0;
5991
6723
  }
5992
6724
  function nonNegativeNumber(value) {
5993
6725
  if (value === void 0 || value.trim() === "") {
@@ -6044,7 +6776,7 @@ var ErrorObjectSchema = import_zod8.z.looseObject({
6044
6776
  var ANTHROPIC_PROVIDER = "anthropic";
6045
6777
 
6046
6778
  // src/usage/pick.ts
6047
- var MS_PER_SECOND4 = 1e3;
6779
+ var MS_PER_SECOND5 = 1e3;
6048
6780
  var MS_PER_HOUR = 36e5;
6049
6781
  var HOURS_PER_DAY2 = 24;
6050
6782
  var FIVE_HOURS = 5;
@@ -6066,7 +6798,7 @@ function limitBlockedUntil(state, nowMs) {
6066
6798
  if (Date.parse(state.lastRequestAt) > Date.parse(limit.observedAt)) {
6067
6799
  return void 0;
6068
6800
  }
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);
6801
+ 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
6802
  return until !== void 0 && until > nowMs ? until : void 0;
6071
6803
  }
6072
6804
  function windowBlockedUntil(windows) {
@@ -6143,10 +6875,10 @@ function assess(member, nowMs) {
6143
6875
  return { candidate: { ...base, class: "unknown", reasons: ["quota windows reported no utilisation", ...windowReasons, ...planReasons] } };
6144
6876
  }
6145
6877
  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);
6878
+ const untilResetMs = basis.window.resetsAtMs === void 0 ? basis.windowMs : Math.max(basis.window.resetsAtMs - nowMs, MS_PER_SECOND5);
6147
6879
  const score = remaining * plan.capacity / (untilResetMs / MS_PER_HOUR);
6148
6880
  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);
6881
+ const fiveUntil = five?.resetsAtMs === void 0 ? FIVE_HOUR_WINDOW_MS : Math.max(five.resetsAtMs - nowMs, MS_PER_SECOND5);
6150
6882
  const burn = fiveHourBurn(member.records);
6151
6883
  return {
6152
6884
  candidate: { ...base, class: "scored", score, reasons: [...windowReasons.map((reason, index) => index === windowReasons.length - 1 ? `${reason}${observedAgo}` : reason), ...planReasons] },
@@ -6196,7 +6928,7 @@ function rankPool(input) {
6196
6928
  }
6197
6929
 
6198
6930
  // src/usage/poolPick.ts
6199
- var import_node_path13 = __toESM(require("node:path"), 1);
6931
+ var import_node_path14 = __toESM(require("node:path"), 1);
6200
6932
  var import_zod9 = require("zod");
6201
6933
 
6202
6934
  // src/usage/store.ts
@@ -6263,13 +6995,13 @@ function recordStickyPick(fs12, picksFile, directory, identity, nowMs) {
6263
6995
  const current = readPicksFile(fs12, picksFile).file.picks;
6264
6996
  const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
6265
6997
  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));
6998
+ fs12.mkdirPrivate(import_node_path14.default.dirname(picksFile));
6267
6999
  fs12.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
6268
7000
  `);
6269
7001
  }
6270
7002
 
6271
7003
  // src/launcher/identity.ts
6272
- var import_node_path14 = __toESM(require("node:path"), 1);
7004
+ var import_node_path15 = __toESM(require("node:path"), 1);
6273
7005
  function poolNameOf(selector) {
6274
7006
  return selector.startsWith(POOL_SELECTOR_PREFIX) ? selector.slice(POOL_SELECTOR_PREFIX.length) : void 0;
6275
7007
  }
@@ -6318,7 +7050,7 @@ function decideConfigProfile(params) {
6318
7050
  return { source: "none" };
6319
7051
  }
6320
7052
  function loadIdentity(identitiesDir, name, fs12) {
6321
- return loadConfigFile(import_node_path14.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
7053
+ return loadConfigFile(import_node_path15.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
6322
7054
  }
6323
7055
 
6324
7056
  // src/launcher/pool.ts
@@ -6533,7 +7265,7 @@ function hashSettings(settings) {
6533
7265
  }
6534
7266
 
6535
7267
  // src/headroom/socket.ts
6536
- var import_node_path15 = __toESM(require("node:path"), 1);
7268
+ var import_node_path16 = __toESM(require("node:path"), 1);
6537
7269
  var GROUP_OR_OTHER_BITS = 63;
6538
7270
  var OCTAL_RADIX = 8;
6539
7271
  var MODE_DIGITS = 4;
@@ -6542,7 +7274,7 @@ var HEADROOM_SOCKET_NAME = /^(\d+)\.sock$/;
6542
7274
  var UNIX_SOCKET_PATH_MAX_BYTES = 103;
6543
7275
  var PLATFORMS_WITHOUT_UNIX_SOCKETS = ["win32"];
6544
7276
  function headroomSocketPath(paths, supervisorPid) {
6545
- return import_node_path15.default.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
7277
+ return import_node_path16.default.join(paths.headroomSocketDir, `${String(supervisorPid)}${HEADROOM_SOCKET_SUFFIX}`);
6546
7278
  }
6547
7279
  function platformRefusal(platform) {
6548
7280
  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 +7323,7 @@ function pruneStaleHeadroomSockets(fs12, paths, isRunning) {
6591
7323
  if (pid === void 0 || isRunning(Number.parseInt(pid, 10))) {
6592
7324
  continue;
6593
7325
  }
6594
- fs12.removeRecursive(import_node_path15.default.join(paths.headroomSocketDir, name));
7326
+ fs12.removeRecursive(import_node_path16.default.join(paths.headroomSocketDir, name));
6595
7327
  removed.push(name);
6596
7328
  }
6597
7329
  return removed;
@@ -6915,14 +7647,14 @@ function evaluateAmbientCredentialGuard(params) {
6915
7647
  // src/paths.ts
6916
7648
  var import_node_fs2 = __toESM(require("node:fs"), 1);
6917
7649
  var import_node_os2 = __toESM(require("node:os"), 1);
6918
- var import_node_path16 = __toESM(require("node:path"), 1);
7650
+ var import_node_path17 = __toESM(require("node:path"), 1);
6919
7651
  function resolveAgentShimHome(env = process.env, home = import_node_os2.default.homedir(), isDirectory = isExistingDirectory) {
6920
7652
  const fromEnv = env.AGENT_SHIM_HOME;
6921
7653
  if (fromEnv !== void 0 && fromEnv !== "") {
6922
7654
  return fromEnv;
6923
7655
  }
6924
- const current = import_node_path16.default.join(home, HOME_DIRNAME);
6925
- const legacy = import_node_path16.default.join(home, LEGACY_HOME_DIRNAME);
7656
+ const current = import_node_path17.default.join(home, HOME_DIRNAME);
7657
+ const legacy = import_node_path17.default.join(home, LEGACY_HOME_DIRNAME);
6926
7658
  return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
6927
7659
  }
6928
7660
  function isExistingDirectory(candidate) {
@@ -6933,41 +7665,41 @@ function resolveClaudeHome() {
6933
7665
  if (fromEnv !== void 0 && fromEnv !== "") {
6934
7666
  return fromEnv;
6935
7667
  }
6936
- return import_node_path16.default.join(import_node_os2.default.homedir(), ".claude");
7668
+ return import_node_path17.default.join(import_node_os2.default.homedir(), ".claude");
6937
7669
  }
6938
7670
  function buildLayoutPaths(root) {
6939
7671
  return {
6940
7672
  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")
7673
+ identitiesDir: import_node_path17.default.join(root, "identities"),
7674
+ configProfilesDir: import_node_path17.default.join(root, "config-profiles"),
7675
+ providersDir: import_node_path17.default.join(root, "providers"),
7676
+ directoryRulesFile: import_node_path17.default.join(root, "directory-rules.json"),
7677
+ activeIdentityFile: import_node_path17.default.join(root, "active-identity"),
7678
+ globalConfigFile: import_node_path17.default.join(root, "config.json"),
7679
+ categoriesLocalFile: import_node_path17.default.join(root, "categories.local.json"),
7680
+ claudeShimFile: import_node_path17.default.join(root, "claude-shim.json"),
7681
+ headroomDir: import_node_path17.default.join(root, "headroom"),
7682
+ headroomStateFile: import_node_path17.default.join(root, "headroom", `state.v${String(HEADROOM_STATE_SCHEMA_VERSION)}.json`),
7683
+ headroomSocketDir: import_node_path17.default.join(root, "headroom", "run"),
7684
+ headroomLockFile: import_node_path17.default.join(root, "headroom", "start.lock"),
7685
+ headroomSessionsDir: import_node_path17.default.join(root, "headroom", "sessions"),
7686
+ logsDir: import_node_path17.default.join(root, "logs"),
7687
+ headroomLogPath: import_node_path17.default.join(root, "logs", "headroom.log"),
7688
+ frontdoorDir: import_node_path17.default.join(root, "frontdoor"),
7689
+ frontdoorCaDir: import_node_path17.default.join(root, "frontdoor", "ca"),
7690
+ frontdoorCaCertFile: import_node_path17.default.join(root, "frontdoor", "ca", "ca.pem"),
7691
+ frontdoorCaKeyFile: import_node_path17.default.join(root, "frontdoor", "ca", "ca.key"),
7692
+ frontdoorCaBundlesDir: import_node_path17.default.join(root, "frontdoor", "ca", "bundles"),
7693
+ frontdoorStateFile: import_node_path17.default.join(root, "frontdoor", "state.json"),
7694
+ frontdoorLockFile: import_node_path17.default.join(root, "frontdoor", "start.lock"),
7695
+ frontdoorControlTokenFile: import_node_path17.default.join(root, "frontdoor", "control-token"),
7696
+ frontdoorSessionsDir: import_node_path17.default.join(root, "frontdoor", "sessions"),
7697
+ frontdoorRcCredentialsDir: import_node_path17.default.join(root, "frontdoor", "rc-credentials"),
7698
+ frontdoorLogPath: import_node_path17.default.join(root, "logs", "frontdoor.log"),
7699
+ usageDir: import_node_path17.default.join(root, "usage"),
7700
+ usageLogDir: import_node_path17.default.join(root, "usage", "log"),
7701
+ usageSnapshotsDir: import_node_path17.default.join(root, "usage", "snapshots"),
7702
+ usagePicksFile: import_node_path17.default.join(root, "usage", "picks.json")
6971
7703
  };
6972
7704
  }
6973
7705
  function resolveLayoutPaths() {
@@ -6976,11 +7708,11 @@ function resolveLayoutPaths() {
6976
7708
 
6977
7709
  // src/identityStore.ts
6978
7710
  var import_node_fs4 = __toESM(require("node:fs"), 1);
6979
- var import_node_path18 = __toESM(require("node:path"), 1);
7711
+ var import_node_path19 = __toESM(require("node:path"), 1);
6980
7712
 
6981
7713
  // src/configProfilesStore.ts
6982
7714
  var import_node_fs3 = __toESM(require("node:fs"), 1);
6983
- var import_node_path17 = __toESM(require("node:path"), 1);
7715
+ var import_node_path18 = __toESM(require("node:path"), 1);
6984
7716
  var ProfileNotFoundError = class extends CliError {
6985
7717
  constructor(profileName) {
6986
7718
  super(`No configuration profile named "${profileName}". Run \`agent-shim profile add ${profileName}\` first.`);
@@ -7006,7 +7738,7 @@ var InvalidCategoryNameError = class extends CliError {
7006
7738
  categoryName;
7007
7739
  };
7008
7740
  function profileJsonPath(paths, name) {
7009
- return import_node_path17.default.join(paths.configProfilesDir, `${name}.json`);
7741
+ return import_node_path18.default.join(paths.configProfilesDir, `${name}.json`);
7010
7742
  }
7011
7743
  function profileExists(paths, name) {
7012
7744
  return import_node_fs3.default.existsSync(profileJsonPath(paths, name));
@@ -7194,7 +7926,7 @@ var InvalidIdentityNameError = class extends CliError {
7194
7926
  attemptedName;
7195
7927
  };
7196
7928
  function identityJsonPath(paths, name) {
7197
- return import_node_path18.default.join(paths.identitiesDir, name, "identity.json");
7929
+ return import_node_path19.default.join(paths.identitiesDir, name, "identity.json");
7198
7930
  }
7199
7931
  function identityExists(paths, name) {
7200
7932
  return import_node_fs4.default.existsSync(identityJsonPath(paths, name));
@@ -7295,7 +8027,7 @@ function setIdentityCredential(paths, identityName, change) {
7295
8027
  });
7296
8028
  }
7297
8029
  function belongsToIdentity(entry, name) {
7298
- return entry === name || entry === import_node_path18.default.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
8030
+ return entry === name || entry === import_node_path19.default.basename(identityLockPath("", name)) || entry.startsWith(`.${name}.scratch.`) || entry.startsWith(`.${name}.previous.`);
7299
8031
  }
7300
8032
  function removeIdentity(paths, name) {
7301
8033
  if (!identityExists(paths, name)) {
@@ -7303,7 +8035,7 @@ function removeIdentity(paths, name) {
7303
8035
  }
7304
8036
  for (const entry of import_node_fs4.default.readdirSync(paths.identitiesDir)) {
7305
8037
  if (belongsToIdentity(entry, name)) {
7306
- import_node_fs4.default.rmSync(import_node_path18.default.join(paths.identitiesDir, entry), { recursive: true, force: true });
8038
+ import_node_fs4.default.rmSync(import_node_path19.default.join(paths.identitiesDir, entry), { recursive: true, force: true });
7307
8039
  }
7308
8040
  }
7309
8041
  if (readActiveIdentity(paths) === name) {
@@ -7313,7 +8045,7 @@ function removeIdentity(paths, name) {
7313
8045
 
7314
8046
  // src/providersStore.ts
7315
8047
  var import_node_fs5 = __toESM(require("node:fs"), 1);
7316
- var import_node_path19 = __toESM(require("node:path"), 1);
8048
+ var import_node_path20 = __toESM(require("node:path"), 1);
7317
8049
 
7318
8050
  // src/credentialCache.ts
7319
8051
  var import_zod12 = require("zod");
@@ -7578,7 +8310,7 @@ var InvalidProviderNameError = class extends CliError {
7578
8310
  };
7579
8311
  var PROVIDER_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._@-]*$/;
7580
8312
  function providerJsonPath(paths, name) {
7581
- return import_node_path19.default.join(paths.providersDir, `${name}.json`);
8313
+ return import_node_path20.default.join(paths.providersDir, `${name}.json`);
7582
8314
  }
7583
8315
  function providerExists(paths, name) {
7584
8316
  return import_node_fs5.default.existsSync(providerJsonPath(paths, name));
@@ -7586,14 +8318,14 @@ function providerExists(paths, name) {
7586
8318
  var LEGACY_PROVIDER_FIELDS = ["tokenEnv", "tokenCommand", "authScheme"];
7587
8319
  var LEGACY_ENV_CREDENTIAL_KEYS = Object.values(CREDENTIAL_TARGET_VARS);
7588
8320
  var LEGACY_LITERAL_PLACEHOLDER = "<the value of env.ANTHROPIC_AUTH_TOKEN>";
7589
- function isRecord5(value) {
8321
+ function isRecord7(value) {
7590
8322
  return typeof value === "object" && value !== null && !Array.isArray(value);
7591
8323
  }
7592
8324
  function legacyProviderConversion(raw) {
7593
- if (!isRecord5(raw) || "credential" in raw) {
8325
+ if (!isRecord7(raw) || "credential" in raw) {
7594
8326
  return void 0;
7595
8327
  }
7596
- const env = isRecord5(raw.env) ? raw.env : void 0;
8328
+ const env = isRecord7(raw.env) ? raw.env : void 0;
7597
8329
  const legacyEnvKeys = env === void 0 ? [] : Object.keys(env).filter((key) => LEGACY_ENV_CREDENTIAL_KEYS.includes(key));
7598
8330
  const fields = [...LEGACY_PROVIDER_FIELDS.filter((field) => field in raw), ...legacyEnvKeys.map((key) => `env.${key}`)];
7599
8331
  if (fields.length === 0) {
@@ -7654,7 +8386,7 @@ function readProvider(paths, name) {
7654
8386
  return parseProviderFile(filePath, raw);
7655
8387
  }
7656
8388
  function loadProvider(providersDir, name, port) {
7657
- const filePath = import_node_path19.default.join(providersDir, `${name}.json`);
8389
+ const filePath = import_node_path20.default.join(providersDir, `${name}.json`);
7658
8390
  const raw = port.readConfigFile(filePath);
7659
8391
  return raw === void 0 ? void 0 : parseProviderFile(filePath, raw);
7660
8392
  }
@@ -7909,21 +8641,21 @@ function removeDirectoryRule(paths, rulePath) {
7909
8641
  var import_node_os4 = __toESM(require("node:os"), 1);
7910
8642
 
7911
8643
  // src/launcher/cascade.ts
7912
- var import_node_path21 = __toESM(require("node:path"), 1);
8644
+ var import_node_path22 = __toESM(require("node:path"), 1);
7913
8645
 
7914
8646
  // src/pathNorm.ts
7915
- var import_node_path20 = __toESM(require("node:path"), 1);
8647
+ var import_node_path21 = __toESM(require("node:path"), 1);
7916
8648
  function expandTilde(value, home) {
7917
8649
  if (value === "~") {
7918
8650
  return home;
7919
8651
  }
7920
8652
  if (value.startsWith("~/")) {
7921
- return import_node_path20.default.join(home, value.slice(2));
8653
+ return import_node_path21.default.join(home, value.slice(2));
7922
8654
  }
7923
8655
  return value;
7924
8656
  }
7925
8657
  function normaliseRulePath(rulePath, home) {
7926
- return import_node_path20.default.resolve(expandTilde(rulePath, home));
8658
+ return import_node_path21.default.resolve(expandTilde(rulePath, home));
7927
8659
  }
7928
8660
 
7929
8661
  // src/launcher/cascade.ts
@@ -7933,7 +8665,7 @@ function loadCascadeInput(params) {
7933
8665
  const globalConfig = loadConfigFile(params.paths.globalConfigFile, GlobalConfigSchema, params.read);
7934
8666
  const directoryRules = loadConfigFile(params.paths.directoryRulesFile, DirectoryRulesSchema, params.read);
7935
8667
  const loadProfile = (name) => {
7936
- const filepath = import_node_path21.default.join(params.paths.configProfilesDir, `${name}.json`);
8668
+ const filepath = import_node_path22.default.join(params.paths.configProfilesDir, `${name}.json`);
7937
8669
  const loaded = loadConfigFile(filepath, ConfigProfileSchema, params.read);
7938
8670
  if (loaded === void 0) {
7939
8671
  return void 0;
@@ -7948,8 +8680,8 @@ function loadCascadeInput(params) {
7948
8680
  });
7949
8681
  const levels = [];
7950
8682
  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);
8683
+ 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);
8684
+ 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
8685
  const rules = (directoryRules?.config.rules ?? []).map((rule, index) => ({ rule, index })).filter(({ rule }) => normaliseRulePath(rule.path, params.home) === dir).map(({ rule, index }) => {
7954
8686
  const entryOrder = directoryRules?.ruleEntryOrders[index];
7955
8687
  return {
@@ -8000,7 +8732,7 @@ function readDirectorySelections(loaded) {
8000
8732
  // src/realCredentialCache.ts
8001
8733
  var import_node_child_process = require("node:child_process");
8002
8734
  var import_node_fs6 = __toESM(require("node:fs"), 1);
8003
- var import_node_path22 = __toESM(require("node:path"), 1);
8735
+ var import_node_path23 = __toESM(require("node:path"), 1);
8004
8736
  var KEYCHAIN_CACHE_SERVICE = "agent-shim-credential-cache";
8005
8737
  var CACHE_DIR_MODE = 448;
8006
8738
  var CACHE_FILE_MODE = 384;
@@ -8027,8 +8759,8 @@ function security(args, stdin) {
8027
8759
  return { status: result.status, stdout: result.stdout };
8028
8760
  }
8029
8761
  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));
8762
+ const dir = import_node_path23.default.join(root, "credential-cache");
8763
+ const filePath = (owner) => import_node_path23.default.join(dir, cacheFileNameFor(owner));
8032
8764
  return {
8033
8765
  read(store, owner) {
8034
8766
  if (store === "file") {
@@ -8080,7 +8812,7 @@ var import_node_child_process2 = require("node:child_process");
8080
8812
  var import_node_crypto9 = require("node:crypto");
8081
8813
  var import_node_fs7 = __toESM(require("node:fs"), 1);
8082
8814
  var import_node_os3 = __toESM(require("node:os"), 1);
8083
- var import_node_path23 = __toESM(require("node:path"), 1);
8815
+ var import_node_path24 = __toESM(require("node:path"), 1);
8084
8816
  var import_node_sea = require("node:sea");
8085
8817
  function isEnoent3(error) {
8086
8818
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
@@ -8239,7 +8971,7 @@ var realRunPort = {
8239
8971
  }
8240
8972
  };
8241
8973
  function expandHome2(filePath) {
8242
- return filePath.startsWith("~/") ? import_node_path23.default.join(import_node_os3.default.homedir(), filePath.slice(1)) : filePath;
8974
+ return filePath.startsWith("~/") ? import_node_path24.default.join(import_node_os3.default.homedir(), filePath.slice(1)) : filePath;
8243
8975
  }
8244
8976
  var MACOS_GUI_SESSION_MANAGER = "Aqua";
8245
8977
  function hasDesktopSession() {
@@ -8312,7 +9044,7 @@ function spawnDaemonThrough(executable) {
8312
9044
  return (paths, subcommand, logPath) => spawnDetachedDaemon({ command: executable, args: [subcommand] }, paths, subcommand, logPath);
8313
9045
  }
8314
9046
  function spawnDetachedDaemon(invocation, paths, subcommand, logPath) {
8315
- import_node_fs7.default.mkdirSync(import_node_path23.default.dirname(logPath), { recursive: true });
9047
+ import_node_fs7.default.mkdirSync(import_node_path24.default.dirname(logPath), { recursive: true });
8316
9048
  const logFd = import_node_fs7.default.openSync(logPath, "a");
8317
9049
  try {
8318
9050
  const child = (0, import_node_child_process2.spawn)(invocation.command, invocation.args, detachedDaemonSpawnOptions(logFd, { ...process.env, AGENT_SHIM_HOME: paths.root }));
@@ -8394,7 +9126,7 @@ function listVersionsDir(dir) {
8394
9126
  throw error;
8395
9127
  }
8396
9128
  return entries.filter((entry) => entry.isFile()).map((entry) => {
8397
- const fullPath = import_node_path23.default.join(dir, entry.name);
9129
+ const fullPath = import_node_path24.default.join(dir, entry.name);
8398
9130
  const stat = import_node_fs7.default.statSync(fullPath);
8399
9131
  return {
8400
9132
  name: entry.name,
@@ -8409,7 +9141,7 @@ function windowsPathExtensions(pathext) {
8409
9141
  return (pathext ?? WINDOWS_DEFAULT_PATHEXT).split(";").map((ext) => ext.trim()).filter((ext) => ext.length > 0);
8410
9142
  }
8411
9143
  function resolveExecutableCandidate(dir, name, env) {
8412
- const candidate = import_node_path23.default.join(dir, name);
9144
+ const candidate = import_node_path24.default.join(dir, name);
8413
9145
  if (env.platform === "win32") {
8414
9146
  const extensions = windowsPathExtensions(env.pathext);
8415
9147
  const alreadyHasRecognisedExtension = extensions.some((ext) => candidate.toLowerCase().endsWith(ext.toLowerCase()));
@@ -8458,13 +9190,13 @@ function resolveOwnExecutablePath(env) {
8458
9190
  if (env.argv1 !== void 0 && !env.argv1.includes("/") && !env.argv1.includes("\\")) {
8459
9191
  return searchPathForExecutable(env.pathDirs, env.argv1, env.findExecutableInDir) ?? env.execPath;
8460
9192
  }
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);
9193
+ const candidate = env.argv1 === void 0 ? env.execPath : import_node_path24.default.resolve(env.cwd, env.argv1);
9194
+ const candidateDir = import_node_path24.default.dirname(candidate);
9195
+ const candidateDirOnPath = env.pathDirs.some((dir) => import_node_path24.default.resolve(dir) === candidateDir);
8464
9196
  if (candidateDirOnPath) {
8465
9197
  return candidate;
8466
9198
  }
8467
- const viaPath = searchPathForExecutable(env.pathDirs, import_node_path23.default.basename(candidate), env.findExecutableInDir);
9199
+ const viaPath = searchPathForExecutable(env.pathDirs, import_node_path24.default.basename(candidate), env.findExecutableInDir);
8468
9200
  return viaPath ?? candidate;
8469
9201
  }
8470
9202
  function realOwnExecutablePath() {
@@ -8472,7 +9204,7 @@ function realOwnExecutablePath() {
8472
9204
  argv1: process.argv[1],
8473
9205
  execPath: process.execPath,
8474
9206
  cwd: process.cwd(),
8475
- pathDirs: (process.env.PATH ?? "").split(import_node_path23.default.delimiter).filter((dir) => dir !== ""),
9207
+ pathDirs: (process.env.PATH ?? "").split(import_node_path24.default.delimiter).filter((dir) => dir !== ""),
8476
9208
  findExecutableInDir
8477
9209
  });
8478
9210
  }
@@ -8485,7 +9217,7 @@ function realContentSourcePath() {
8485
9217
  function realResolveClaudeBinary(isOwnBinary) {
8486
9218
  return (request4) => discoverClaudeBinary({
8487
9219
  listVersionsDir,
8488
- pathDirs: (process.env.PATH ?? "").split(import_node_path23.default.delimiter).filter((dir) => dir !== ""),
9220
+ pathDirs: (process.env.PATH ?? "").split(import_node_path24.default.delimiter).filter((dir) => dir !== ""),
8489
9221
  findExecutableInDir,
8490
9222
  isOwnBinary,
8491
9223
  ...request4?.version === void 0 ? {} : { version: request4.version }
@@ -8496,7 +9228,7 @@ function realInstalledClaudeVersions() {
8496
9228
  }
8497
9229
 
8498
9230
  // src/checkReport.ts
8499
- var import_node_path24 = __toESM(require("node:path"), 1);
9231
+ var import_node_path25 = __toESM(require("node:path"), 1);
8500
9232
  var import_zod13 = require("zod");
8501
9233
 
8502
9234
  // src/cli/bool.ts
@@ -8928,10 +9660,10 @@ function collectCheckReport(params) {
8928
9660
  }).input;
8929
9661
  const providerName = cascadeProviderName(cascade);
8930
9662
  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);
9663
+ const farmRoot = identityDecision.name === void 0 ? void 0 : import_node_path25.default.join(paths.identitiesDir, identityDecision.name);
8932
9664
  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"))
9665
+ "settings.json": realFsPort.readFileUtf8(import_node_path25.default.join(claudeHome, "settings.json")),
9666
+ "settings.local.json": realFsPort.readFileUtf8(import_node_path25.default.join(claudeHome, "settings.local.json"))
8935
9667
  };
8936
9668
  const report = runCheck({
8937
9669
  cwd,
@@ -8963,7 +9695,7 @@ function collectCheckReport(params) {
8963
9695
 
8964
9696
  // src/claudeShim.ts
8965
9697
  var import_node_fs8 = __toESM(require("node:fs"), 1);
8966
- var import_node_path25 = __toESM(require("node:path"), 1);
9698
+ var import_node_path26 = __toESM(require("node:path"), 1);
8967
9699
  var import_zod14 = require("zod");
8968
9700
  var ClaudeShimStateSchema = import_zod14.z.strictObject({
8969
9701
  targetPath: import_zod14.z.string().min(1),
@@ -8975,10 +9707,10 @@ function commandFilename(ownExecutablePath, commandName) {
8975
9707
  }
8976
9708
  function resolveOwnBinaryCheck(paths, contentSourcePath) {
8977
9709
  const state = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
8978
- const recordedTarget = state === void 0 ? void 0 : import_node_path25.default.resolve(state.targetPath);
9710
+ const recordedTarget = state === void 0 ? void 0 : import_node_path26.default.resolve(state.targetPath);
8979
9711
  let ownStat;
8980
9712
  return (candidate) => {
8981
- if (recordedTarget !== void 0 && import_node_path25.default.resolve(candidate) === recordedTarget) {
9713
+ if (recordedTarget !== void 0 && import_node_path26.default.resolve(candidate) === recordedTarget) {
8982
9714
  return true;
8983
9715
  }
8984
9716
  ownStat ??= statOrUndefined(contentSourcePath);
@@ -9002,20 +9734,20 @@ function statOrUndefined(target) {
9002
9734
  }
9003
9735
  var nodeLinkFs = { link: import_node_fs8.default.linkSync, copyFile: import_node_fs8.default.copyFileSync, chmod: import_node_fs8.default.chmodSync };
9004
9736
  function findPathShadow(params) {
9005
- const resolvedTargetDir = import_node_path25.default.resolve(params.targetDir);
9737
+ const resolvedTargetDir = import_node_path26.default.resolve(params.targetDir);
9006
9738
  for (const dir of params.pathDirs) {
9007
9739
  const found = params.findExecutableInDir(dir, params.targetFilename);
9008
9740
  if (found === void 0) {
9009
9741
  continue;
9010
9742
  }
9011
- return import_node_path25.default.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
9743
+ return import_node_path26.default.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
9012
9744
  }
9013
- return params.pathDirs.some((dir) => import_node_path25.default.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
9745
+ return params.pathDirs.some((dir) => import_node_path26.default.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
9014
9746
  }
9015
9747
 
9016
9748
  // src/doctorReport.ts
9017
9749
  var import_node_fs9 = __toESM(require("node:fs"), 1);
9018
- var import_node_path26 = __toESM(require("node:path"), 1);
9750
+ var import_node_path27 = __toESM(require("node:path"), 1);
9019
9751
  function refinePathShadow(status, ownExecutablePath, realpath) {
9020
9752
  if (status.status !== "shadowed") {
9021
9753
  return status;
@@ -9039,7 +9771,7 @@ function validateJson(schema, input) {
9039
9771
  return { ok: true, data: result.data };
9040
9772
  }
9041
9773
  function pushPathResolution(push, resolution) {
9042
- const ownDir = import_node_path26.default.dirname(resolution.ownExecutablePath);
9774
+ const ownDir = import_node_path27.default.dirname(resolution.ownExecutablePath);
9043
9775
  switch (resolution.agentShim.status) {
9044
9776
  case "ok":
9045
9777
  push("path-resolution", "pass", `\`agent-shim\` on PATH resolves to this running executable, ${resolution.ownExecutablePath}.`, "agent-shim");
@@ -9112,17 +9844,20 @@ function pushProvider(push, entry, cacheEnv) {
9112
9844
  }
9113
9845
  const cache = cacheClause(cacheEnv, `provider ${entry.name}`, validated2.data.credential);
9114
9846
  push("provider", cache.unreadable ? "fail" : "pass", `${entry.name} is valid (${describeProviderEndpoint(validated2.data)}, credential ${describeCredential(validated2.data.credential)})${cache.text}.`, entry.name);
9847
+ if (validated2.data.env?.ENABLE_TOOL_SEARCH === void 0) {
9848
+ push("provider", "warn", `${entry.name} does not set ENABLE_TOOL_SEARCH: a session on this provider loads MCP tools upfront rather than deferring them, because its base URL is the front door, which Claude Code treats as a non-first-party host. Set ENABLE_TOOL_SEARCH in the provider's env block to restore deferred loading, when the upstream backend supports the tool_reference payloads it sends.`, entry.name);
9849
+ }
9115
9850
  }
9116
9851
  function pushLegacyName(push, params) {
9117
9852
  const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
9118
- if (legacyVariables.length === 0 && import_node_path26.default.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
9853
+ if (legacyVariables.length === 0 && import_node_path27.default.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
9119
9854
  push("legacy-name", "pass", "Nothing here still uses the former `claude-use` name.");
9120
9855
  return;
9121
9856
  }
9122
9857
  for (const name of legacyVariables) {
9123
9858
  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);
9124
9859
  }
9125
- if (import_node_path26.default.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
9860
+ if (import_node_path27.default.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
9126
9861
  push(
9127
9862
  "legacy-name",
9128
9863
  "warn",
@@ -9441,18 +10176,18 @@ function collectDoctorReport(params) {
9441
10176
  const { paths } = params;
9442
10177
  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() : [];
9443
10178
  const identities = identityNames.map((name) => {
9444
- const farmRoot = import_node_path26.default.join(paths.identitiesDir, name);
9445
- const identityPath = import_node_path26.default.join(farmRoot, "identity.json");
10179
+ const farmRoot = import_node_path27.default.join(paths.identitiesDir, name);
10180
+ const identityPath = import_node_path27.default.join(farmRoot, "identity.json");
9446
10181
  return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot };
9447
10182
  });
9448
10183
  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() : [];
9449
10184
  const configProfiles = profileNames.map((name) => {
9450
- const profilePath = import_node_path26.default.join(paths.configProfilesDir, `${name}.json`);
10185
+ const profilePath = import_node_path27.default.join(paths.configProfilesDir, `${name}.json`);
9451
10186
  return { name, path: profilePath, raw: realFsPort.readFileUtf8(profilePath) };
9452
10187
  });
9453
10188
  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() : [];
9454
10189
  const providers = providerNames.map((name) => {
9455
- const providerPath = import_node_path26.default.join(paths.providersDir, `${name}.json`);
10190
+ const providerPath = import_node_path27.default.join(paths.providersDir, `${name}.json`);
9456
10191
  return { name, path: providerPath, raw: realFsPort.readFileUtf8(providerPath) };
9457
10192
  });
9458
10193
  const ownExecutablePath = realOwnExecutablePath();
@@ -9464,12 +10199,12 @@ function collectDoctorReport(params) {
9464
10199
  binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
9465
10200
  }
9466
10201
  const shimState = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
9467
- const pathDirs = (params.env.PATH ?? "").split(import_node_path26.default.delimiter).filter((dir) => dir !== "");
10202
+ const pathDirs = (params.env.PATH ?? "").split(import_node_path27.default.delimiter).filter((dir) => dir !== "");
9468
10203
  const claudeShimShadow = shimState === void 0 ? void 0 : refinePathShadow(
9469
10204
  findPathShadow({
9470
10205
  pathDirs,
9471
- targetDir: import_node_path26.default.dirname(shimState.targetPath),
9472
- targetFilename: import_node_path26.default.basename(shimState.targetPath),
10206
+ targetDir: import_node_path27.default.dirname(shimState.targetPath),
10207
+ targetFilename: import_node_path27.default.basename(shimState.targetPath),
9473
10208
  findExecutableInDir
9474
10209
  }),
9475
10210
  shimState.targetPath,
@@ -9494,7 +10229,7 @@ function collectDoctorReport(params) {
9494
10229
  agentShim: refinePathShadow(
9495
10230
  findPathShadow({
9496
10231
  pathDirs,
9497
- targetDir: import_node_path26.default.dirname(ownExecutablePath),
10232
+ targetDir: import_node_path27.default.dirname(ownExecutablePath),
9498
10233
  targetFilename: commandFilename(ownExecutablePath, "agent-shim"),
9499
10234
  findExecutableInDir
9500
10235
  }),
@@ -9515,7 +10250,7 @@ function collectDoctorReport(params) {
9515
10250
 
9516
10251
  // src/launcher.ts
9517
10252
  var import_node_crypto10 = require("node:crypto");
9518
- var import_node_path28 = __toESM(require("node:path"), 1);
10253
+ var import_node_path29 = __toESM(require("node:path"), 1);
9519
10254
 
9520
10255
  // src/launcher/argv.ts
9521
10256
  var ConflictingIdentityError = class extends UsageError {
@@ -9780,7 +10515,7 @@ function buildCliOverride(params) {
9780
10515
  }
9781
10516
 
9782
10517
  // src/launcher/flags.ts
9783
- var import_node_path27 = __toESM(require("node:path"), 1);
10518
+ var import_node_path28 = __toESM(require("node:path"), 1);
9784
10519
 
9785
10520
  // src/headroom/headers.ts
9786
10521
  function mergeAnthropicCustomHeaders(existing, additions) {
@@ -9850,7 +10585,7 @@ function buildEnv(params) {
9850
10585
  const parentCustomHeaders = params.baseEnv.ANTHROPIC_CUSTOM_HEADERS;
9851
10586
  let providerCustomHeaders;
9852
10587
  if (!params.configDirEscapeHatch && params.resolvedIdentityName !== void 0) {
9853
- env.CLAUDE_CONFIG_DIR = import_node_path27.default.join(params.identitiesDir, params.resolvedIdentityName);
10588
+ env.CLAUDE_CONFIG_DIR = import_node_path28.default.join(params.identitiesDir, params.resolvedIdentityName);
9854
10589
  }
9855
10590
  if (params.provider !== void 0) {
9856
10591
  const providerEnv = params.provider.definition.env ?? {};
@@ -10011,7 +10746,7 @@ function prepareLaunch(params) {
10011
10746
  identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
10012
10747
  globalDefaultConfigProfile: params.globalDefaultConfigProfile
10013
10748
  });
10014
- if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(import_node_path28.default.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
10749
+ if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(import_node_path29.default.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
10015
10750
  log.error(
10016
10751
  `agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
10017
10752
  );
@@ -10257,11 +10992,11 @@ function probeFrontDoorSync(port, caPem) {
10257
10992
 
10258
10993
  // src/frontdoor/trust.ts
10259
10994
  var import_node_crypto11 = require("node:crypto");
10260
- var import_node_path29 = __toESM(require("node:path"), 1);
10995
+ var import_node_path30 = __toESM(require("node:path"), 1);
10261
10996
  var BUNDLE_NAME_HEX_DIGITS = 16;
10262
10997
  function resolveTrustBundle(params) {
10263
10998
  const { caCertFile, bundlesDir, variable, inherited, fs: fs12 } = params;
10264
- if (inherited === void 0 || inherited === "" || import_node_path29.default.resolve(inherited) === import_node_path29.default.resolve(caCertFile)) {
10999
+ if (inherited === void 0 || inherited === "" || import_node_path30.default.resolve(inherited) === import_node_path30.default.resolve(caCertFile)) {
10265
11000
  return { path: caCertFile };
10266
11001
  }
10267
11002
  const caPem = fs12.readFileUtf8(caCertFile);
@@ -10279,7 +11014,7 @@ function resolveTrustBundle(params) {
10279
11014
  }
10280
11015
  const combined = `${inheritedPem.trimEnd()}
10281
11016
  ${caPem}`;
10282
- 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`);
11017
+ 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`);
10283
11018
  if (!fs12.exists(bundle)) {
10284
11019
  fs12.mkdirp(bundlesDir);
10285
11020
  fs12.writeFileAtomic(bundle, combined);
@@ -10473,6 +11208,13 @@ function prepareClaudeLaunch(options) {
10473
11208
  RC_PENDING_DEADLINE_MS,
10474
11209
  RC_PERMISSION_MODES,
10475
11210
  RC_REQUEST_PARSE_CAP_BYTES,
11211
+ RC_SELF_HOST_ENV,
11212
+ RC_SELF_HOST_KEEPALIVE_MS,
11213
+ RC_SELF_HOST_RECORD_DIR,
11214
+ RC_SELF_HOST_RECORD_FILE,
11215
+ RC_SELF_HOST_RETENTION_MS,
11216
+ RC_SELF_HOST_SCOPE_LIST,
11217
+ RC_SELF_HOST_WORKER_JWT_TTL_SECONDS,
10476
11218
  RC_SESSIONS_PATH_PREFIX,
10477
11219
  RC_STREAM_BACKOFF_MS,
10478
11220
  ROUTED_PATH_PREFIX,
@@ -10509,6 +11251,7 @@ function prepareClaudeLaunch(options) {
10509
11251
  createRcControlHandler,
10510
11252
  createRcCredentialStore,
10511
11253
  createRcEventFanout,
11254
+ createRcSelfHostSurface,
10512
11255
  createRcSessionTracker,
10513
11256
  createRcStreamHub,
10514
11257
  createSseParser,
@@ -10533,6 +11276,8 @@ function prepareClaudeLaunch(options) {
10533
11276
  isIdentityDirectoryName,
10534
11277
  isInterceptedHost,
10535
11278
  isRcPermissionMode,
11279
+ lateRcEventDial,
11280
+ lateRcStreamDial,
10536
11281
  listDirectoryRules,
10537
11282
  listIdentities,
10538
11283
  listProfiles,
@@ -10540,6 +11285,7 @@ function prepareClaudeLaunch(options) {
10540
11285
  listUsageSnapshots,
10541
11286
  matchBranch,
10542
11287
  mintLeaf,
11288
+ mintRcSelfHostCredential,
10543
11289
  observingRoutedRoute,
10544
11290
  parseConnectTarget,
10545
11291
  parseRcStreamEnvelope,
@@ -10551,6 +11297,7 @@ function prepareClaudeLaunch(options) {
10551
11297
  rankPool,
10552
11298
  rcEventWriteResultFromAnswer,
10553
11299
  rcObserverAsPassthrough,
11300
+ rcSelfHostFromEnv,
10554
11301
  readActiveIdentity,
10555
11302
  readDirectoryRules,
10556
11303
  readFarmManifest,
@@ -10559,6 +11306,7 @@ function prepareClaudeLaunch(options) {
10559
11306
  readPools,
10560
11307
  readProfile,
10561
11308
  readProvider,
11309
+ readRcSelfHostRecord,
10562
11310
  readUsageSnapshot,
10563
11311
  realConnectCertStore,
10564
11312
  realConnectEffects,