agent-shim 8.8.0 → 8.9.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
@@ -77,11 +77,16 @@ __export(index_exports, {
77
77
  ProviderNotFoundError: () => ProviderNotFoundError,
78
78
  ProviderSchema: () => ProviderSchema,
79
79
  RC_IDLE_EXPIRY_MS: () => RC_IDLE_EXPIRY_MS,
80
+ RC_ORPC_PATH_PREFIX: () => RC_ORPC_PATH_PREFIX,
80
81
  RC_PENDING_DEADLINE_MS: () => RC_PENDING_DEADLINE_MS,
81
82
  RC_PERMISSION_MODES: () => RC_PERMISSION_MODES,
82
83
  RC_REQUEST_PARSE_CAP_BYTES: () => RC_REQUEST_PARSE_CAP_BYTES,
83
84
  RC_SESSIONS_PATH_PREFIX: () => RC_SESSIONS_PATH_PREFIX,
85
+ RC_STREAM_BACKOFF_MS: () => RC_STREAM_BACKOFF_MS,
84
86
  ROUTED_PATH_PREFIX: () => ROUTED_PATH_PREFIX,
87
+ RcPermissionModeSchema: () => RcPermissionModeSchema,
88
+ RcStreamEnvelopeSchema: () => RcStreamEnvelopeSchema,
89
+ RcStreamEventSchema: () => RcStreamEventSchema,
85
90
  UsageError: () => UsageError,
86
91
  UsageSnapshotError: () => UsageSnapshotError,
87
92
  UsageSnapshotSchema: () => UsageSnapshotSchema,
@@ -107,8 +112,13 @@ __export(index_exports, {
107
112
  collectPoolPick: () => collectPoolPick,
108
113
  createLeafCache: () => createLeafCache,
109
114
  createProfile: () => createProfile,
115
+ createRcApiNodeHandler: () => createRcApiNodeHandler,
116
+ createRcApiRouter: () => createRcApiRouter,
110
117
  createRcControlHandler: () => createRcControlHandler,
118
+ createRcEventFanout: () => createRcEventFanout,
111
119
  createRcSessionTracker: () => createRcSessionTracker,
120
+ createRcStreamHub: () => createRcStreamHub,
121
+ createSseParser: () => createSseParser,
112
122
  describeProviderEndpoint: () => describeProviderEndpoint,
113
123
  detectAmbientCredential: () => detectAmbientCredential,
114
124
  effectiveWindow: () => effectiveWindow,
@@ -121,6 +131,7 @@ __export(index_exports, {
121
131
  formatCheckReport: () => formatCheckReport,
122
132
  formatDoctorReport: () => formatDoctorReport,
123
133
  forwardableHeaders: () => forwardableHeaders,
134
+ frontDoorRcApiClient: () => frontDoorRcApiClient,
124
135
  frontDoorRcControl: () => frontDoorRcControl,
125
136
  generateCa: () => generateCa,
126
137
  identityExists: () => identityExists,
@@ -138,6 +149,7 @@ __export(index_exports, {
138
149
  mintLeaf: () => mintLeaf,
139
150
  observingRoutedRoute: () => observingRoutedRoute,
140
151
  parseConnectTarget: () => parseConnectTarget,
152
+ parseRcStreamEnvelope: () => parseRcStreamEnvelope,
141
153
  planOf: () => planOf,
142
154
  prepareClaudeLaunch: () => prepareClaudeLaunch,
143
155
  prepareLaunch: () => prepareLaunch,
@@ -159,6 +171,7 @@ __export(index_exports, {
159
171
  realConnectEffects: () => realConnectEffects,
160
172
  realRcControlTransport: () => realRcControlTransport,
161
173
  realRcEventDial: () => realRcEventDial,
174
+ realRcStreamDial: () => realRcStreamDial,
162
175
  recoverFarm: () => recoverFarm,
163
176
  recoveryDiagnostics: () => recoveryDiagnostics,
164
177
  removeDirectoryRule: () => removeDirectoryRule,
@@ -3267,1326 +3280,1916 @@ function realConnectCertStore(paths) {
3267
3280
  // src/frontdoor/connectEffects.ts
3268
3281
  var import_node_dns = __toESM(require("node:dns"), 1);
3269
3282
  var http = __toESM(require("node:http"), 1);
3270
- var https = __toESM(require("node:https"), 1);
3283
+ var https2 = __toESM(require("node:https"), 1);
3271
3284
  var net2 = __toESM(require("node:net"), 1);
3272
3285
  var tls = __toESM(require("node:tls"), 1);
3273
- var UPSTREAM_LOCAL_PORT_START = 47900;
3274
- var UPSTREAM_LOCAL_PORT_END = 47919;
3275
- var UPSTREAM_LOCAL_PORT_COUNT = UPSTREAM_LOCAL_PORT_END - UPSTREAM_LOCAL_PORT_START + 1;
3276
- var nextUpstreamLocalPort = UPSTREAM_LOCAL_PORT_START;
3277
- function upstreamLocalPort() {
3278
- const port = nextUpstreamLocalPort;
3279
- nextUpstreamLocalPort = nextUpstreamLocalPort === UPSTREAM_LOCAL_PORT_END ? UPSTREAM_LOCAL_PORT_START : nextUpstreamLocalPort + 1;
3280
- return port;
3286
+
3287
+ // src/codex/http.ts
3288
+ var HTTP_STATUS = {
3289
+ ok: 200,
3290
+ badRequest: 400,
3291
+ unauthorized: 401,
3292
+ forbidden: 403,
3293
+ notFound: 404,
3294
+ methodNotAllowed: 405,
3295
+ payloadTooLarge: 413,
3296
+ tooManyRequests: 429,
3297
+ /** Not sent to anyone: the client is gone. Recorded for a response abandoned because the client disconnected, following the convention nginx uses for the same case. */
3298
+ clientClosedRequest: 499,
3299
+ internalServerError: 500,
3300
+ badGateway: 502
3301
+ };
3302
+
3303
+ // src/frontdoor/rcControl.ts
3304
+ var https = __toESM(require("node:https"), 1);
3305
+
3306
+ // src/frontdoor/rcSessions.ts
3307
+ var RC_SESSIONS_PATH_PREFIX = "/v1/code/sessions";
3308
+ var RC_SESSION_ID_PREFIX = "cse_";
3309
+ var RC_IDLE_EXPIRY_MS = 45e3;
3310
+ var RC_CREATE_RESPONSE_CAP_BYTES = 8192;
3311
+ var CONFLICT_REASON_HEADER = "x-ccr-conflict-reason";
3312
+ var RC_STREAM_WORKER_SOURCE = "worker";
3313
+ var RC_PENDING_DEADLINE_MS = 14e3;
3314
+ var RC_REQUEST_PARSE_CAP_BYTES = 262144;
3315
+ var RC_PENDING_SUMMARY_EXCERPT_CHARS = 300;
3316
+ var SUCCESS_STATUS_MAX_EXCLUSIVE = 300;
3317
+ function isSuccessful(status) {
3318
+ return status >= HTTP_STATUS.ok && status < SUCCESS_STATUS_MAX_EXCLUSIVE;
3281
3319
  }
3282
- var realAddressLookup = (host, _options, callback) => {
3283
- if (net2.isIP(host) !== 0) {
3284
- callback(null, [{ address: host, family: net2.isIP(host) }]);
3285
- return;
3320
+ function singleHeader(headers, name) {
3321
+ const value = headers[name];
3322
+ return typeof value === "string" ? value : void 0;
3323
+ }
3324
+ var OAUTH_AUTHORIZATION_PREFIX = "Bearer sk-ant-oat";
3325
+ function oauthAuthorizationOf(headers) {
3326
+ const value = singleHeader(headers, "authorization");
3327
+ return value?.startsWith(OAUTH_AUTHORIZATION_PREFIX) === true ? value : void 0;
3328
+ }
3329
+ function sessionCreateId(body) {
3330
+ let parsed;
3331
+ try {
3332
+ parsed = JSON.parse(body);
3333
+ } catch {
3334
+ return void 0;
3286
3335
  }
3287
- import_node_dns.default.resolve4(host, (error, addresses) => {
3288
- if (error !== null) {
3289
- callback(error, [{ address: "", family: 4 }]);
3290
- return;
3291
- }
3292
- const first = addresses[0];
3293
- if (first === void 0) {
3294
- callback(new Error(`no A record for ${host}`), [{ address: "", family: 4 }]);
3295
- return;
3296
- }
3297
- callback(null, [{ address: first, family: 4 }]);
3298
- });
3299
- };
3300
- var HTTP_PORT = 80;
3301
- var HELD_PORT_ERRNOS = /* @__PURE__ */ new Set(["EADDRINUSE", "EADDRNOTAVAIL"]);
3302
- async function dialOnce(connectOptions) {
3303
- return await new Promise((resolve) => {
3304
- const socket = net2.connect(connectOptions);
3305
- socket.once("connect", () => {
3306
- resolve({ error: null, socket });
3307
- });
3308
- socket.once("error", (error) => {
3309
- resolve({ error, socket });
3310
- });
3311
- });
3336
+ if (typeof parsed !== "object" || parsed === null || !("session" in parsed)) {
3337
+ return void 0;
3338
+ }
3339
+ const session = parsed.session;
3340
+ if (typeof session !== "object" || session === null || !("id" in session)) {
3341
+ return void 0;
3342
+ }
3343
+ const id = session.id;
3344
+ return typeof id === "string" && id.startsWith(RC_SESSION_ID_PREFIX) ? id : void 0;
3312
3345
  }
3313
- function dialTarget(options, defaultPort) {
3314
- return { host: typeof options.host === "string" ? options.host : "", port: typeof options.port === "number" ? options.port : defaultPort };
3346
+ function isRecord2(value) {
3347
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3315
3348
  }
3316
- function literalDial(target) {
3317
- return net2.connect({ host: target.host, port: target.port });
3349
+ function parseJsonObject(body) {
3350
+ let parsed;
3351
+ try {
3352
+ parsed = JSON.parse(body);
3353
+ } catch {
3354
+ return void 0;
3355
+ }
3356
+ return isRecord2(parsed) ? parsed : void 0;
3318
3357
  }
3319
- async function reservedDial(target) {
3320
- for (let attempt = 0; ; attempt += 1) {
3321
- const outcome = await dialOnce({ host: target.host, port: target.port, localPort: upstreamLocalPort(), lookup: realAddressLookup });
3322
- if (outcome.error === null) {
3323
- return outcome;
3358
+ function nonEmptyString(record, field) {
3359
+ const value = record === void 0 ? void 0 : record[field];
3360
+ return typeof value === "string" && value !== "" ? value : void 0;
3361
+ }
3362
+ function finiteNumber(record, field) {
3363
+ const value = record === void 0 ? void 0 : record[field];
3364
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
3365
+ }
3366
+ function excerpt(text) {
3367
+ return text.length <= RC_PENDING_SUMMARY_EXCERPT_CHARS ? text : `${text.slice(0, RC_PENDING_SUMMARY_EXCERPT_CHARS)}...`;
3368
+ }
3369
+ function payloadEventsOf(body) {
3370
+ const parsed = parseJsonObject(body);
3371
+ const events = parsed === void 0 ? void 0 : parsed.events;
3372
+ if (!Array.isArray(events)) {
3373
+ return [];
3374
+ }
3375
+ const payloads = [];
3376
+ for (const event of events) {
3377
+ if (!isRecord2(event)) {
3378
+ continue;
3324
3379
  }
3325
- const held = outcome.error.code !== void 0 && HELD_PORT_ERRNOS.has(outcome.error.code);
3326
- if (!held || attempt === UPSTREAM_LOCAL_PORT_COUNT - 1) {
3327
- return outcome;
3380
+ const payload = event.payload;
3381
+ if (!isRecord2(payload)) {
3382
+ continue;
3328
3383
  }
3384
+ payloads.push(payload);
3329
3385
  }
3386
+ return payloads;
3330
3387
  }
3331
- function requestServername(options, fallback) {
3332
- return "servername" in options && typeof options.servername === "string" && options.servername !== "" ? options.servername : fallback;
3333
- }
3334
- var ExemptHttpAgent = class extends http.Agent {
3335
- // A reserved-port dial that has to retry cannot produce its socket synchronously, so it settles first and arrives through the callback (node's documented asynchronous createConnection form); a literal dial has nothing to retry and keeps node's own synchronous shape.
3336
- createConnection(options, oncreate) {
3337
- const target = dialTarget(options, HTTP_PORT);
3338
- if (net2.isIP(target.host) !== 0) {
3339
- return literalDial(target);
3340
- }
3341
- void reservedDial(target).then((outcome) => {
3342
- oncreate?.(outcome.error, outcome.socket);
3343
- });
3388
+ function pendingOfControlRequestPayload(payload) {
3389
+ if (payload.type !== "control_request") {
3344
3390
  return void 0;
3345
3391
  }
3346
- };
3347
- var ExemptTlsAgent = class extends https.Agent {
3348
- // The same split as the plain sibling: a literal dial wraps TLS around the socket node's own agent would have returned, a reserved dial settles (retries included) first and arrives through the callback, which is exactly where node's own agent wraps its own dials.
3349
- createConnection(options, oncreate) {
3350
- const target = dialTarget(options, HTTPS_PORT);
3351
- if (net2.isIP(target.host) !== 0) {
3352
- return tls.connect({ socket: literalDial(target), servername: requestServername(options, target.host), ...tlsFacts(options) });
3353
- }
3354
- void reservedDial(target).then((outcome) => {
3355
- if (outcome.error !== null) {
3356
- oncreate?.(outcome.error, outcome.socket);
3357
- return;
3358
- }
3359
- oncreate?.(null, tls.connect({ socket: outcome.socket, servername: requestServername(options, target.host), ...tlsFacts(options) }));
3360
- });
3392
+ const requestId = nonEmptyString(payload, "request_id") ?? nonEmptyString(payload, "uuid");
3393
+ if (requestId === void 0) {
3361
3394
  return void 0;
3362
3395
  }
3363
- };
3364
- function tlsFacts(options) {
3365
- const facts = {};
3366
- if ("ca" in options && Array.isArray(options.ca)) {
3367
- facts.ca = options.ca;
3396
+ const request4 = isRecord2(payload.request) ? payload.request : void 0;
3397
+ const subtype = nonEmptyString(request4, "subtype");
3398
+ const type = subtype ?? "control_request";
3399
+ let summary = "";
3400
+ if (subtype === "can_use_tool") {
3401
+ const toolName = nonEmptyString(request4, "tool_name") ?? "unknown tool";
3402
+ const input = request4 === void 0 ? void 0 : request4.input;
3403
+ summary = input === void 0 ? toolName : `${toolName} ${excerpt(JSON.stringify(input))}`;
3404
+ } else if (request4 !== void 0) {
3405
+ summary = excerpt(JSON.stringify(request4));
3368
3406
  }
3369
- if ("rejectUnauthorized" in options && typeof options.rejectUnauthorized === "boolean") {
3370
- facts.rejectUnauthorized = options.rejectUnauthorized;
3407
+ return { requestId, type, summary };
3408
+ }
3409
+ function answeredRequestIdsOfControlResponsePayload(payload) {
3410
+ if (payload.type !== "control_response") {
3411
+ return [];
3371
3412
  }
3372
- return facts;
3413
+ const response = isRecord2(payload.response) ? payload.response : void 0;
3414
+ const id = nonEmptyString(response, "request_id") ?? nonEmptyString(payload, "request_id") ?? nonEmptyString(payload, "uuid");
3415
+ return id === void 0 ? [] : [id];
3373
3416
  }
3374
- function realRcEventDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
3375
- const agent = new ExemptTlsAgent();
3376
- return {
3377
- writeEvents: async (sessionId, headers, body) => await new Promise((resolve, reject) => {
3378
- const options = {
3379
- host: target.host,
3380
- port: target.port,
3381
- method: "POST",
3382
- path: `/v1/code/sessions/${encodeURIComponent(sessionId)}/events`,
3383
- // 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.
3384
- headers: { ...headers, host: target.servername ?? target.host, "content-length": String(Buffer.byteLength(body, "utf8")) },
3385
- agent
3386
- };
3387
- options.servername = target.servername ?? target.host;
3388
- if (target.ca !== void 0) {
3389
- options.ca = [...target.ca];
3417
+ function parseRcRequestBody(kind, body) {
3418
+ if (kind === "heartbeat") {
3419
+ return { controlRequests: [], answeredRequestIds: [], idleSeconds: finiteNumber(parseJsonObject(body), "idle_seconds"), workerStatus: void 0 };
3420
+ }
3421
+ if (kind === "worker-registration") {
3422
+ return { controlRequests: [], answeredRequestIds: [], idleSeconds: void 0, workerStatus: nonEmptyString(parseJsonObject(body), "status") };
3423
+ }
3424
+ const controlRequests = [];
3425
+ const answeredRequestIds = [];
3426
+ for (const payload of payloadEventsOf(body)) {
3427
+ const pending = pendingOfControlRequestPayload(payload);
3428
+ if (pending !== void 0) {
3429
+ controlRequests.push({ requestId: pending.requestId, type: pending.type, summary: pending.summary });
3430
+ continue;
3431
+ }
3432
+ answeredRequestIds.push(...answeredRequestIdsOfControlResponsePayload(payload));
3433
+ }
3434
+ return { controlRequests, answeredRequestIds, idleSeconds: void 0, workerStatus: void 0 };
3435
+ }
3436
+ function createRcSessionTracker(deps) {
3437
+ const entries = /* @__PURE__ */ new Map();
3438
+ const expire = (id) => {
3439
+ entries.delete(id);
3440
+ };
3441
+ const expirePendings = (entry, now) => {
3442
+ for (const [requestId, pending] of entry.pending) {
3443
+ if (now - pending.observedAt >= RC_PENDING_DEADLINE_MS) {
3444
+ entry.pending.delete(requestId);
3390
3445
  }
3391
- if (target.rejectUnauthorized !== void 0) {
3392
- options.rejectUnauthorized = target.rejectUnauthorized;
3446
+ }
3447
+ };
3448
+ const sweep = () => {
3449
+ for (const [id, entry] of entries) {
3450
+ if (deps.now() - entry.lastSeenAt >= deps.idleMs) {
3451
+ expire(id);
3452
+ continue;
3393
3453
  }
3394
- const request4 = https.request(options, (response) => {
3395
- const chunks = [];
3396
- response.on("data", (chunk) => {
3397
- chunks.push(chunk);
3454
+ expirePendings(entry, deps.now());
3455
+ }
3456
+ };
3457
+ const timer = setInterval(sweep, deps.idleMs);
3458
+ timer.unref();
3459
+ const birth = (id, facts) => {
3460
+ const record = { id, createdAt: deps.now(), lastSeenAt: deps.now(), ...facts, pending: /* @__PURE__ */ new Map(), workerState: void 0, workerIdleSeconds: void 0, sequenceNum: void 0 };
3461
+ entries.set(id, record);
3462
+ return record;
3463
+ };
3464
+ const observeExchange = (request4) => {
3465
+ const method = (request4.method ?? "").toUpperCase();
3466
+ const path29 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
3467
+ if (!path29.startsWith(RC_SESSIONS_PATH_PREFIX)) {
3468
+ return void 0;
3469
+ }
3470
+ const tail = path29.slice(RC_SESSIONS_PATH_PREFIX.length);
3471
+ const facts = {
3472
+ oauthAuthorization: oauthAuthorizationOf(request4.headers),
3473
+ anthropicVersion: singleHeader(request4.headers, "anthropic-version"),
3474
+ anthropicClientPlatform: singleHeader(request4.headers, "anthropic-client-platform")
3475
+ };
3476
+ if (tail === "") {
3477
+ if (method !== "POST") {
3478
+ return void 0;
3479
+ }
3480
+ let accepted2 = false;
3481
+ let buffered2 = 0;
3482
+ let body = "";
3483
+ return {
3484
+ onResponse: (status) => {
3485
+ accepted2 = isSuccessful(status);
3486
+ },
3487
+ onBodyChunk: (chunk) => {
3488
+ if (!accepted2 || buffered2 >= RC_CREATE_RESPONSE_CAP_BYTES) {
3489
+ return;
3490
+ }
3491
+ const text = Buffer.from(chunk).toString("utf8");
3492
+ body = body + text.slice(0, RC_CREATE_RESPONSE_CAP_BYTES - buffered2);
3493
+ buffered2 = body.length;
3494
+ },
3495
+ onEnd: () => {
3496
+ if (!accepted2) {
3497
+ return;
3498
+ }
3499
+ const id2 = sessionCreateId(body);
3500
+ if (id2 === void 0) {
3501
+ return;
3502
+ }
3503
+ birth(id2, facts);
3504
+ }
3505
+ };
3506
+ }
3507
+ const rest = tail.slice(1);
3508
+ const [id] = rest.split("/");
3509
+ if (id?.startsWith(RC_SESSION_ID_PREFIX) !== true) {
3510
+ return void 0;
3511
+ }
3512
+ const entry = entries.get(id) ?? birth(id, facts);
3513
+ entry.lastSeenAt = deps.now();
3514
+ entry.oauthAuthorization = facts.oauthAuthorization ?? entry.oauthAuthorization;
3515
+ entry.anthropicVersion = facts.anthropicVersion ?? entry.anthropicVersion;
3516
+ entry.anthropicClientPlatform = facts.anthropicClientPlatform ?? entry.anthropicClientPlatform;
3517
+ const bodyKind = method === "POST" && rest === `${id}/worker/events` ? "worker-events" : method === "POST" && rest === `${id}/events` ? "client-events" : method === "POST" && rest === `${id}/worker/heartbeat` ? "heartbeat" : method === "PUT" && rest === `${id}/worker` ? "worker-registration" : void 0;
3518
+ let chunks = [];
3519
+ let buffered = 0;
3520
+ let oversized = false;
3521
+ let requestEnded = false;
3522
+ let accepted;
3523
+ let filed = false;
3524
+ const file = () => {
3525
+ if (filed || accepted !== true || !requestEnded || bodyKind === void 0) {
3526
+ return;
3527
+ }
3528
+ filed = true;
3529
+ const factsOfBody = oversized ? void 0 : parseRcRequestBody(bodyKind, Buffer.concat(chunks).toString("utf8"));
3530
+ chunks = [];
3531
+ const entryNow = entries.get(id);
3532
+ if (entryNow === void 0 || factsOfBody === void 0) {
3533
+ return;
3534
+ }
3535
+ const now = deps.now();
3536
+ for (const controlRequest of factsOfBody.controlRequests) {
3537
+ entryNow.pending.set(controlRequest.requestId, { sessionId: id, ...controlRequest, observedAt: now });
3538
+ }
3539
+ for (const requestId of factsOfBody.answeredRequestIds) {
3540
+ entryNow.pending.delete(requestId);
3541
+ }
3542
+ if (factsOfBody.idleSeconds !== void 0) {
3543
+ entryNow.workerIdleSeconds = { value: factsOfBody.idleSeconds, observedAt: now };
3544
+ }
3545
+ if (factsOfBody.workerStatus !== void 0) {
3546
+ entryNow.workerState = { value: factsOfBody.workerStatus, observedAt: now };
3547
+ }
3548
+ };
3549
+ const archiving = method === "POST" && rest === `${id}/archive`;
3550
+ return {
3551
+ ...bodyKind === void 0 ? {} : {
3552
+ onRequestChunk: (chunk) => {
3553
+ if (oversized) {
3554
+ return;
3555
+ }
3556
+ chunks.push(Buffer.from(chunk));
3557
+ buffered += chunk.length;
3558
+ if (buffered > RC_REQUEST_PARSE_CAP_BYTES) {
3559
+ oversized = true;
3560
+ chunks = [];
3561
+ }
3562
+ },
3563
+ onRequestEnd: () => {
3564
+ requestEnded = true;
3565
+ file();
3566
+ }
3567
+ },
3568
+ onResponse: (status, headers) => {
3569
+ if (singleHeader(headers, CONFLICT_REASON_HEADER) !== void 0 || archiving && isSuccessful(status)) {
3570
+ expire(id);
3571
+ return;
3572
+ }
3573
+ accepted = isSuccessful(status);
3574
+ file();
3575
+ },
3576
+ onBodyChunk: () => {
3577
+ },
3578
+ onEnd: () => {
3579
+ }
3580
+ };
3581
+ };
3582
+ const summaryOf = ({ id, createdAt, lastSeenAt }) => ({ id, createdAt, lastSeenAt });
3583
+ const pendingSummaryOf = ({ sessionId, requestId, type, summary, observedAt }) => ({ sessionId, requestId, type, summary, observedAt });
3584
+ const sortedEntries = () => [...entries.values()].sort((left, right) => left.createdAt - right.createdAt || (left.id < right.id ? -1 : 1));
3585
+ const pendingSorted = (entry) => [...entry.pending.values()].sort((left, right) => left.observedAt - right.observedAt || (left.requestId < right.requestId ? -1 : 1)).map(pendingSummaryOf);
3586
+ return {
3587
+ observeExchange,
3588
+ list: () => {
3589
+ sweep();
3590
+ return sortedEntries().map(summaryOf);
3591
+ },
3592
+ statusOf: (sessionId) => {
3593
+ sweep();
3594
+ return sortedEntries().filter((entry) => sessionId === void 0 || entry.id === sessionId).map((entry) => ({ ...summaryOf(entry), workerState: entry.workerState, workerIdleSeconds: entry.workerIdleSeconds, pending: pendingSorted(entry) }));
3595
+ },
3596
+ pendingOf: (sessionId) => {
3597
+ sweep();
3598
+ return sortedEntries().filter((entry) => sessionId === void 0 || entry.id === sessionId).flatMap((entry) => pendingSorted(entry));
3599
+ },
3600
+ credentialOf: (sessionId) => {
3601
+ const entry = entries.get(sessionId);
3602
+ return entry === void 0 ? void 0 : { authorization: entry.oauthAuthorization, anthropicVersion: entry.anthropicVersion, anthropicClientPlatform: entry.anthropicClientPlatform };
3603
+ },
3604
+ noteSequenceNums: (sessionId, sequenceNums) => {
3605
+ const entry = entries.get(sessionId);
3606
+ if (entry === void 0) {
3607
+ return;
3608
+ }
3609
+ for (const sequenceNum of sequenceNums) {
3610
+ entry.sequenceNum = entry.sequenceNum === void 0 || sequenceNum > entry.sequenceNum ? sequenceNum : entry.sequenceNum;
3611
+ }
3612
+ },
3613
+ sequenceNumOf: (sessionId) => entries.get(sessionId)?.sequenceNum,
3614
+ fileStreamEvent: (sessionId, event) => {
3615
+ const entry = entries.get(sessionId);
3616
+ if (entry === void 0) {
3617
+ return;
3618
+ }
3619
+ entry.sequenceNum = entry.sequenceNum === void 0 || event.sequence_num > entry.sequenceNum ? event.sequence_num : entry.sequenceNum;
3620
+ if (!isRecord2(event.payload)) {
3621
+ return;
3622
+ }
3623
+ const pending = pendingOfControlRequestPayload(event.payload);
3624
+ if (pending !== void 0) {
3625
+ if (event.source === RC_STREAM_WORKER_SOURCE) {
3626
+ entry.pending.set(pending.requestId, { sessionId, ...pending, observedAt: deps.now() });
3627
+ }
3628
+ return;
3629
+ }
3630
+ for (const requestId of answeredRequestIdsOfControlResponsePayload(event.payload)) {
3631
+ entry.pending.delete(requestId);
3632
+ }
3633
+ },
3634
+ completePending: (sessionId, requestId) => {
3635
+ entries.get(sessionId)?.pending.delete(requestId);
3636
+ },
3637
+ close: () => {
3638
+ clearInterval(timer);
3639
+ }
3640
+ };
3641
+ }
3642
+ function observingRoutedRoute(route, tracker, hooks) {
3643
+ return {
3644
+ ...route,
3645
+ serve: async (request4, response) => {
3646
+ const observed = tracker.observeExchange({ method: request4.method, url: request4.url, headers: request4.headers });
3647
+ if (observed?.onRequestChunk !== void 0) {
3648
+ request4.body.on("data", (chunk) => {
3649
+ observed.onRequestChunk?.(chunk);
3398
3650
  });
3399
- response.on("end", () => {
3400
- resolve({ status: response.statusCode ?? HTTP_BAD_GATEWAY, body: Buffer.concat(chunks).toString("utf8") });
3651
+ request4.body.on("end", () => {
3652
+ observed.onRequestEnd?.();
3401
3653
  });
3402
- });
3403
- request4.once("error", reject);
3404
- request4.end(body);
3405
- })
3654
+ }
3655
+ await route.serve(request4, observed === void 0 ? response : teeRoutedResponse(response, observed, hooks?.onExchangeSettled));
3656
+ }
3406
3657
  };
3407
3658
  }
3408
- function realConnectEffects() {
3409
- const plainAgent = new ExemptHttpAgent();
3410
- const tlsAgent = new ExemptTlsAgent();
3411
- const listenOnce = async (port, onSocket) => await new Promise((resolve, reject) => {
3412
- const accepted = /* @__PURE__ */ new Set();
3413
- const server = net2.createServer((socket) => {
3414
- accepted.add(socket);
3415
- socket.on("close", () => {
3416
- accepted.delete(socket);
3417
- });
3418
- onSocket(socket);
3419
- });
3420
- server.once("error", reject);
3421
- server.listen(port, "127.0.0.1", () => {
3422
- const address = server.address();
3423
- const bound = typeof address === "object" && address !== null ? address.port : 0;
3424
- if (bound === 0) {
3425
- reject(new Error("could not bind a loopback port"));
3659
+ function teeRoutedResponse(response, observer, onSettled) {
3660
+ return {
3661
+ get headersSent() {
3662
+ return response.headersSent;
3663
+ },
3664
+ start: (status, headers) => {
3665
+ observer.onResponse(status, headers);
3666
+ response.start(status, headers);
3667
+ },
3668
+ flush: () => {
3669
+ response.flush();
3670
+ },
3671
+ write: async (chunk) => {
3672
+ observer.onBodyChunk(typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk);
3673
+ await response.write(chunk);
3674
+ },
3675
+ end: () => {
3676
+ response.end();
3677
+ observer.onEnd();
3678
+ onSettled?.();
3679
+ },
3680
+ destroy: () => {
3681
+ response.destroy();
3682
+ observer.onEnd();
3683
+ onSettled?.();
3684
+ }
3685
+ };
3686
+ }
3687
+ function rcObserverAsPassthrough(observer) {
3688
+ return {
3689
+ onRequestChunk: (chunk) => {
3690
+ observer.onRequestChunk?.(chunk);
3691
+ },
3692
+ ...observer.onRequestEnd === void 0 ? {} : {
3693
+ onRequestEnd: () => {
3694
+ observer.onRequestEnd?.();
3695
+ }
3696
+ },
3697
+ onResponse: (status, headers) => {
3698
+ observer.onResponse(status, headers);
3699
+ },
3700
+ onResponseChunk: (chunk) => {
3701
+ observer.onBodyChunk(chunk);
3702
+ },
3703
+ onEnd: () => {
3704
+ observer.onEnd();
3705
+ }
3706
+ };
3707
+ }
3708
+ function buildRcUserMessagePayload(uuid, sessionId, text) {
3709
+ return {
3710
+ type: "user",
3711
+ uuid,
3712
+ session_id: sessionId,
3713
+ parent_tool_use_id: null,
3714
+ message: { role: "user", content: text }
3715
+ };
3716
+ }
3717
+ function buildRcEventWriteBody(payload) {
3718
+ return { events: [{ payload }] };
3719
+ }
3720
+ function sequenceNumsOf(body) {
3721
+ let parsed;
3722
+ try {
3723
+ parsed = JSON.parse(body);
3724
+ } catch {
3725
+ return void 0;
3726
+ }
3727
+ if (typeof parsed !== "object" || parsed === null || !("results" in parsed) || !Array.isArray(parsed.results)) {
3728
+ return void 0;
3729
+ }
3730
+ const sequenceNums = [];
3731
+ const results = parsed.results;
3732
+ for (const result of results) {
3733
+ if (typeof result !== "object" || result === null || !("sequence_num" in result)) {
3734
+ return void 0;
3735
+ }
3736
+ const sequenceNum = result.sequence_num;
3737
+ if (typeof sequenceNum === "number") {
3738
+ sequenceNums.push(sequenceNum);
3739
+ } else if (typeof sequenceNum === "string" && /^[0-9]+$/.test(sequenceNum)) {
3740
+ sequenceNums.push(Number(sequenceNum));
3741
+ } else {
3742
+ return void 0;
3743
+ }
3744
+ }
3745
+ return sequenceNums.length === 0 ? void 0 : sequenceNums;
3746
+ }
3747
+ function rcEventWriteResultFromAnswer(answer) {
3748
+ if (!isSuccessful(answer.status)) {
3749
+ if (answer.status === HTTP_STATUS.unauthorized) {
3750
+ return { ok: false, message: `the API refused the observed Authorization bearer for this session (HTTP 401): the bearer went stale after the door last saw the session's traffic. The session's own client refreshes it on its next call, which the door will observe, so retry once Remote Control has been active again. API answer: ${answer.body}` };
3751
+ }
3752
+ return { ok: false, message: `the API answered HTTP ${String(answer.status)} to the injected event: ${answer.body}` };
3753
+ }
3754
+ const sequenceNums = sequenceNumsOf(answer.body);
3755
+ if (sequenceNums === void 0) {
3756
+ return { ok: false, message: `the API accepted the injected event but its answer named no results[].sequence_num, so delivery cannot be confirmed: ${answer.body}` };
3757
+ }
3758
+ return { ok: true, sequenceNums };
3759
+ }
3760
+ function noOAuthCredentialResult(sessionId) {
3761
+ return { ok: false, message: `no claude.ai OAuth bearer has been observed for session ${sessionId}: only worker calls crossed this door, and the worker JWT they carry is answered 401 on the client half. Reconnect Remote Control through this door and the create's own bearer will be observed` };
3762
+ }
3763
+ function rcSessionNotObservedMessage(sessionId) {
3764
+ return `the front door has not observed Remote Control session ${sessionId}: it may never have passed through this door, or it ended or expired (an entry lives only a bounded idle period past its last observed traffic)`;
3765
+ }
3766
+ function rcWriteHeaders(credential) {
3767
+ const headers = { "content-type": "application/json" };
3768
+ if (credential.authorization !== void 0) {
3769
+ headers.authorization = credential.authorization;
3770
+ }
3771
+ if (credential.anthropicVersion !== void 0) {
3772
+ headers["anthropic-version"] = credential.anthropicVersion;
3773
+ }
3774
+ if (credential.anthropicClientPlatform !== void 0) {
3775
+ headers["anthropic-client-platform"] = credential.anthropicClientPlatform;
3776
+ }
3777
+ return headers;
3778
+ }
3779
+ async function injectRcUserMessage(deps, sessionId, text) {
3780
+ const credential = deps.credentialOf(sessionId);
3781
+ if (credential === void 0) {
3782
+ return { ok: false, message: rcSessionNotObservedMessage(sessionId) };
3783
+ }
3784
+ if (credential.authorization === void 0) {
3785
+ return noOAuthCredentialResult(sessionId);
3786
+ }
3787
+ const body = JSON.stringify(buildRcEventWriteBody(buildRcUserMessagePayload(deps.newUuid(), sessionId, text)));
3788
+ let answer;
3789
+ try {
3790
+ answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
3791
+ } catch (error) {
3792
+ return { ok: false, message: `the door could not reach the API host to inject into session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
3793
+ }
3794
+ const result = rcEventWriteResultFromAnswer(answer);
3795
+ if (result.ok) {
3796
+ deps.noteSequenceNums(sessionId, result.sequenceNums);
3797
+ }
3798
+ return result;
3799
+ }
3800
+ function buildRcControlResponsePayload(requestId, decision) {
3801
+ const result = decision.approve ? { behavior: "allow" } : { behavior: "deny", message: decision.message ?? "" };
3802
+ return { type: "control_response", response: { subtype: "success", request_id: requestId, response: result } };
3803
+ }
3804
+ var RC_PERMISSION_MODES = ["default", "acceptEdits", "bypassPermissions", "plan", "dontAsk", "auto"];
3805
+ function isRcPermissionMode(value) {
3806
+ return RC_PERMISSION_MODES.some((mode) => mode === value);
3807
+ }
3808
+ function buildRcInterruptPayload(requestId) {
3809
+ return { type: "control_request", request_id: requestId, request: { subtype: "interrupt" } };
3810
+ }
3811
+ function buildRcSetModelPayload(requestId, model) {
3812
+ return { type: "control_request", request_id: requestId, request: { subtype: "set_model", model } };
3813
+ }
3814
+ function buildRcSetPermissionModePayload(requestId, mode) {
3815
+ return { type: "control_request", request_id: requestId, request: { subtype: "set_permission_mode", mode } };
3816
+ }
3817
+ async function answerRcControlRequest(deps, sessionId, requestId, decision) {
3818
+ const credential = deps.credentialOf(sessionId);
3819
+ if (credential === void 0) {
3820
+ return { ok: false, message: rcSessionNotObservedMessage(sessionId) };
3821
+ }
3822
+ if (credential.authorization === void 0) {
3823
+ return noOAuthCredentialResult(sessionId);
3824
+ }
3825
+ if (!deps.pendingOf(sessionId).some((pending) => pending.requestId === requestId)) {
3826
+ return { ok: false, message: `the front door has not observed control request ${requestId} pending on session ${sessionId}: it was answered already (by this door or by an attached client), it passed its answer deadline (the protocol's permission round-trip bound), or it never passed through this door` };
3827
+ }
3828
+ const body = JSON.stringify(buildRcEventWriteBody(buildRcControlResponsePayload(requestId, decision)));
3829
+ let answer;
3830
+ try {
3831
+ answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
3832
+ } catch (error) {
3833
+ return { ok: false, message: `the door could not reach the API host to answer on session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
3834
+ }
3835
+ const result = rcEventWriteResultFromAnswer(answer);
3836
+ if (result.ok) {
3837
+ deps.completePending(sessionId, requestId);
3838
+ deps.noteSequenceNums(sessionId, result.sequenceNums);
3839
+ }
3840
+ return result;
3841
+ }
3842
+ async function interruptRcSession(deps, sessionId) {
3843
+ const credential = deps.credentialOf(sessionId);
3844
+ if (credential === void 0) {
3845
+ return { ok: false, message: rcSessionNotObservedMessage(sessionId) };
3846
+ }
3847
+ if (credential.authorization === void 0) {
3848
+ return noOAuthCredentialResult(sessionId);
3849
+ }
3850
+ const body = JSON.stringify(buildRcEventWriteBody(buildRcInterruptPayload(deps.newUuid())));
3851
+ let answer;
3852
+ try {
3853
+ answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
3854
+ } catch (error) {
3855
+ return { ok: false, message: `the door could not reach the API host to interrupt session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
3856
+ }
3857
+ const result = rcEventWriteResultFromAnswer(answer);
3858
+ if (result.ok) {
3859
+ deps.noteSequenceNums(sessionId, result.sequenceNums);
3860
+ }
3861
+ return result;
3862
+ }
3863
+ async function setRcSessionModel(deps, sessionId, model) {
3864
+ if (model === "") {
3865
+ return { ok: false, message: "a set-model write needs a non-empty model id: the SDK's own field treats an omitted or null value as a reset to the session default, which this operation never sends, and an empty string is neither" };
3866
+ }
3867
+ const credential = deps.credentialOf(sessionId);
3868
+ if (credential === void 0) {
3869
+ return { ok: false, message: rcSessionNotObservedMessage(sessionId) };
3870
+ }
3871
+ if (credential.authorization === void 0) {
3872
+ return noOAuthCredentialResult(sessionId);
3873
+ }
3874
+ const body = JSON.stringify(buildRcEventWriteBody(buildRcSetModelPayload(deps.newUuid(), model)));
3875
+ let answer;
3876
+ try {
3877
+ answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
3878
+ } catch (error) {
3879
+ return { ok: false, message: `the door could not reach the API host to set the model on session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
3880
+ }
3881
+ const result = rcEventWriteResultFromAnswer(answer);
3882
+ if (result.ok) {
3883
+ deps.noteSequenceNums(sessionId, result.sequenceNums);
3884
+ }
3885
+ return result;
3886
+ }
3887
+ async function setRcSessionPermissionMode(deps, sessionId, mode) {
3888
+ const credential = deps.credentialOf(sessionId);
3889
+ if (credential === void 0) {
3890
+ return { ok: false, message: rcSessionNotObservedMessage(sessionId) };
3891
+ }
3892
+ if (credential.authorization === void 0) {
3893
+ return noOAuthCredentialResult(sessionId);
3894
+ }
3895
+ const body = JSON.stringify(buildRcEventWriteBody(buildRcSetPermissionModePayload(deps.newUuid(), mode)));
3896
+ let answer;
3897
+ try {
3898
+ answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
3899
+ } catch (error) {
3900
+ return { ok: false, message: `the door could not reach the API host to set the permission mode on session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
3901
+ }
3902
+ const result = rcEventWriteResultFromAnswer(answer);
3903
+ if (result.ok) {
3904
+ deps.noteSequenceNums(sessionId, result.sequenceNums);
3905
+ }
3906
+ return result;
3907
+ }
3908
+
3909
+ // src/frontdoor/rcControl.ts
3910
+ var RC_PERMISSION_MODE_LIST = RC_PERMISSION_MODES.join(", ");
3911
+ var CONTROL_PATH_PREFIX = "/__agent-shim/rc";
3912
+ var CONTROL_BODY_CAP_BYTES = 10485760;
3913
+ function answerJson(response, status, body) {
3914
+ const text = JSON.stringify(body);
3915
+ response.writeHead(status, { "content-type": "application/json", "content-length": String(Buffer.byteLength(text, "utf8")) });
3916
+ response.end(text);
3917
+ }
3918
+ async function readBody(request4) {
3919
+ return await new Promise((resolve, reject) => {
3920
+ const chunks = [];
3921
+ let total = 0;
3922
+ request4.on("data", (chunk) => {
3923
+ total += chunk.length;
3924
+ if (total > CONTROL_BODY_CAP_BYTES) {
3925
+ request4.destroy();
3926
+ reject(new Error("too large"));
3426
3927
  return;
3427
3928
  }
3428
- resolve({
3429
- port: bound,
3430
- close: async () => {
3431
- await new Promise((closeResolve) => {
3432
- server.close(() => {
3433
- closeResolve(void 0);
3434
- });
3435
- for (const socket of accepted) {
3436
- socket.destroy();
3437
- }
3438
- });
3439
- }
3440
- });
3929
+ chunks.push(chunk);
3930
+ });
3931
+ request4.on("end", () => {
3932
+ resolve(Buffer.concat(chunks).toString("utf8"));
3933
+ });
3934
+ request4.on("error", () => {
3935
+ reject(new Error("the request body ended early"));
3441
3936
  });
3442
3937
  });
3443
- return {
3444
- listenLoopback: async (preferredPort, onSocket) => {
3445
- if (preferredPort !== void 0) {
3938
+ }
3939
+ function createRcControlHandler(deps) {
3940
+ const sessionsPath = `${CONTROL_PATH_PREFIX}/sessions`;
3941
+ const statusPath = `${CONTROL_PATH_PREFIX}/status`;
3942
+ const pendingPath = `${CONTROL_PATH_PREFIX}/pending`;
3943
+ const injectPath = `${CONTROL_PATH_PREFIX}/inject`;
3944
+ const answerPath = `${CONTROL_PATH_PREFIX}/answer`;
3945
+ const interruptPath = `${CONTROL_PATH_PREFIX}/interrupt`;
3946
+ const setModelPath = `${CONTROL_PATH_PREFIX}/set-model`;
3947
+ const setPermissionModePath = `${CONTROL_PATH_PREFIX}/set-permission-mode`;
3948
+ return (request4, response) => {
3949
+ const presented = request4.headers.authorization;
3950
+ const bearerPrefix = "bearer ".length;
3951
+ const token = typeof presented === "string" && presented.slice(0, bearerPrefix).toLowerCase() === "bearer " ? presented.slice(bearerPrefix) : void 0;
3952
+ if (token === void 0 || !isLiveCapability(token, [deps.expectedToken])) {
3953
+ answerJson(response, HTTP_STATUS.unauthorized, { error: "the front door's control routes demand this generation's control token as a Bearer credential" });
3954
+ return;
3955
+ }
3956
+ const url = new URL(request4.url ?? "/", "http://127.0.0.1");
3957
+ const handle = async () => {
3958
+ if (url.pathname === sessionsPath) {
3959
+ if (request4.method !== "GET") {
3960
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the session list is a GET" });
3961
+ return;
3962
+ }
3963
+ answerJson(response, HTTP_STATUS.ok, { sessions: deps.list() });
3964
+ return;
3965
+ }
3966
+ if (url.pathname === statusPath || url.pathname === pendingPath) {
3967
+ if (request4.method !== "GET") {
3968
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the status and pending reads are GETs" });
3969
+ return;
3970
+ }
3971
+ const session = url.searchParams.get("session") ?? void 0;
3972
+ if (session !== void 0 && !deps.statusOf(session).some((entry) => entry.id === session)) {
3973
+ answerJson(response, HTTP_STATUS.notFound, { error: rcSessionNotObservedMessage(session) });
3974
+ return;
3975
+ }
3976
+ answerJson(response, HTTP_STATUS.ok, url.pathname === statusPath ? { statuses: deps.statusOf(session) } : { pending: deps.pendingOf(session) });
3977
+ return;
3978
+ }
3979
+ if (url.pathname === injectPath) {
3980
+ if (request4.method !== "POST") {
3981
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the inject operation is a POST" });
3982
+ return;
3983
+ }
3984
+ let parsed;
3446
3985
  try {
3447
- return await listenOnce(preferredPort, onSocket);
3986
+ parsed = JSON.parse(await readBody(request4));
3448
3987
  } catch {
3988
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the inject body is not readable JSON within the control body cap" });
3989
+ return;
3990
+ }
3991
+ if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("text" in parsed) || typeof parsed.session !== "string" || typeof parsed.text !== "string" || parsed.session === "" || parsed.text === "") {
3992
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the inject body must be JSON naming a non-empty session id and text" });
3993
+ return;
3994
+ }
3995
+ const result = await deps.inject(parsed.session, parsed.text);
3996
+ if (result.ok) {
3997
+ answerJson(response, HTTP_STATUS.ok, { session: parsed.session, sequenceNums: result.sequenceNums });
3998
+ return;
3449
3999
  }
4000
+ answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4001
+ return;
3450
4002
  }
3451
- return await listenOnce(0, onSocket);
3452
- },
3453
- createTlsAcceptor: (leaf, onSecure, alpnProtocols) => {
3454
- let pendingContext = "";
3455
- const server = tls.createServer(
3456
- { key: leaf.keyPem, cert: leaf.certPem, ...alpnProtocols === void 0 ? {} : { ALPNProtocols: [...alpnProtocols] } },
3457
- (secure) => {
3458
- onSecure(secure, pendingContext);
4003
+ if (url.pathname === answerPath) {
4004
+ if (request4.method !== "POST") {
4005
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the answer operation is a POST" });
4006
+ return;
3459
4007
  }
3460
- );
3461
- server.on("clientError", (_error, socket) => {
3462
- socket.destroy();
3463
- });
3464
- return {
3465
- // tls.Server is a net.Server whose connection listener wraps the raw socket in the TLS handshake, and emitting the event by hand is what runs that listener on a socket this process already owns (the CONNECT half of the connection) rather than one the server accepted itself.
3466
- accept: (socket, context) => {
3467
- pendingContext = context;
3468
- server.emit("connection", socket);
3469
- },
3470
- close: () => {
3471
- server.close();
4008
+ let parsed;
4009
+ try {
4010
+ parsed = JSON.parse(await readBody(request4));
4011
+ } catch {
4012
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the answer body is not readable JSON within the control body cap" });
4013
+ return;
3472
4014
  }
3473
- };
3474
- },
3475
- createSniTlsAcceptor: (hosts, leafFor, onSecure) => {
3476
- const contexts = new Map(
3477
- hosts.map((host) => {
3478
- const leaf = leafFor(host);
3479
- return [host, tls.createSecureContext({ key: leaf.keyPem, cert: leaf.certPem })];
3480
- })
3481
- );
3482
- const server = tls.createServer(
3483
- {
3484
- // No default key or cert exists, so the SNI selection is the only source of credentials: an unserved name fails its handshake here, and a client that sent no SNI at all never reaches the selection and fails for want of any certificate, which is exactly the fail-closed shape this surface wants.
3485
- SNICallback: (servername, callback) => {
3486
- const context = contexts.get(servername);
3487
- callback(context === void 0 ? new Error(`the transparent surface serves no host named ${servername}`) : null, context);
3488
- }
3489
- },
3490
- (secure) => {
3491
- onSecure(secure, typeof secure.servername === "string" ? secure.servername : "");
4015
+ if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("request" in parsed) || !("approve" in parsed) || typeof parsed.session !== "string" || typeof parsed.request !== "string" || typeof parsed.approve !== "boolean" || parsed.session === "" || parsed.request === "") {
4016
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the answer body must be JSON naming a non-empty session id, request id, and an approve boolean" });
4017
+ return;
3492
4018
  }
3493
- );
3494
- server.on("clientError", (_error, socket) => {
3495
- socket.destroy();
3496
- });
3497
- return {
3498
- // The same hand-off the single-leaf acceptor uses: emitting the connection event runs the TLS server's own connection listener on a socket this process already owns (the redirect half of the connection) rather than one the server accepted itself.
3499
- accept: (socket) => {
3500
- server.emit("connection", socket);
3501
- },
3502
- close: () => {
3503
- server.close();
4019
+ const text = "text" in parsed && typeof parsed.text === "string" ? parsed.text : void 0;
4020
+ if (parsed.approve && text !== void 0 && text !== "") {
4021
+ answerJson(response, HTTP_STATUS.badRequest, { error: "an approval carries no text (the protocol's allow result has no message field); text is the denial message" });
4022
+ return;
3504
4023
  }
3505
- };
3506
- },
3507
- createHttpSession: (handler, onUpgrade) => {
3508
- const server = http.createServer(handler);
3509
- server.on("clientError", (_error, socket) => {
3510
- socket.destroy();
3511
- });
3512
- if (onUpgrade !== void 0) {
3513
- server.on("upgrade", (request4, socket, head) => {
3514
- onUpgrade(request4, socket, head);
3515
- });
4024
+ const result = await deps.answer(parsed.session, parsed.request, { approve: parsed.approve, message: parsed.approve ? void 0 : text });
4025
+ if (result.ok) {
4026
+ answerJson(response, HTTP_STATUS.ok, { session: parsed.session, request: parsed.request, sequenceNums: result.sequenceNums });
4027
+ return;
4028
+ }
4029
+ answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4030
+ return;
3516
4031
  }
3517
- return {
3518
- serve: (socket) => {
3519
- server.emit("connection", socket);
3520
- },
3521
- close: () => {
3522
- server.close();
3523
- server.closeAllConnections();
4032
+ if (url.pathname === interruptPath) {
4033
+ if (request4.method !== "POST") {
4034
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the interrupt operation is a POST" });
4035
+ return;
3524
4036
  }
3525
- };
3526
- },
3527
- connectTlsUpstream: async (host, port, clientAlpn) => {
3528
- const dialled = await reservedDial({ host, port });
3529
- if (dialled.error !== null) {
3530
- throw dialled.error;
4037
+ let parsed;
4038
+ try {
4039
+ parsed = JSON.parse(await readBody(request4));
4040
+ } catch {
4041
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the interrupt body is not readable JSON within the control body cap" });
4042
+ return;
4043
+ }
4044
+ if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || typeof parsed.session !== "string" || parsed.session === "") {
4045
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the interrupt body must be JSON naming a non-empty session id" });
4046
+ return;
4047
+ }
4048
+ const result = await deps.interrupt(parsed.session);
4049
+ if (result.ok) {
4050
+ answerJson(response, HTTP_STATUS.ok, { session: parsed.session, sequenceNums: result.sequenceNums });
4051
+ return;
4052
+ }
4053
+ answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4054
+ return;
3531
4055
  }
3532
- return await new Promise((resolve, reject) => {
3533
- const secure = tls.connect({ socket: dialled.socket, servername: host, ...clientAlpn === void 0 ? {} : { ALPNProtocols: [clientAlpn] } });
3534
- secure.once("secureConnect", () => {
3535
- resolve(secure);
3536
- });
3537
- secure.once("error", reject);
3538
- });
3539
- },
3540
- connectTcp: async (host, port) => await new Promise((resolve, reject) => {
3541
- const socket = net2.connect({ host, port });
3542
- socket.once("connect", () => {
3543
- resolve(socket);
3544
- });
3545
- socket.once("error", reject);
3546
- }),
3547
- forwardHttp: (target, request4, response, observer) => {
3548
- const headers = forwardableHeaders(request4.headers);
3549
- const options = {
3550
- host: target.host,
3551
- port: target.port,
3552
- lookup: realAddressLookup,
3553
- method: request4.method,
3554
- path: request4.url,
3555
- headers,
3556
- agent: target.tls ? tlsAgent : plainAgent
3557
- };
3558
- if (target.tls) {
3559
- options.servername = target.servername ?? target.host;
3560
- if (target.ca !== void 0) {
3561
- options.ca = [...target.ca];
4056
+ if (url.pathname === setModelPath) {
4057
+ if (request4.method !== "POST") {
4058
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the set-model operation is a POST" });
4059
+ return;
3562
4060
  }
3563
- if (target.rejectUnauthorized !== void 0) {
3564
- options.rejectUnauthorized = target.rejectUnauthorized;
4061
+ let parsed;
4062
+ try {
4063
+ parsed = JSON.parse(await readBody(request4));
4064
+ } catch {
4065
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the set-model body is not readable JSON within the control body cap" });
4066
+ return;
4067
+ }
4068
+ if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("model" in parsed) || typeof parsed.session !== "string" || typeof parsed.model !== "string" || parsed.session === "" || parsed.model === "") {
4069
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the set-model body must be JSON naming a non-empty session id and model id" });
4070
+ return;
4071
+ }
4072
+ const result = await deps.setModel(parsed.session, parsed.model);
4073
+ if (result.ok) {
4074
+ answerJson(response, HTTP_STATUS.ok, { session: parsed.session, model: parsed.model, sequenceNums: result.sequenceNums });
4075
+ return;
3565
4076
  }
4077
+ answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4078
+ return;
3566
4079
  }
3567
- const onUpstreamResponse = (upstreamResponse) => {
3568
- observer?.onResponse(upstreamResponse.statusCode ?? HTTP_BAD_GATEWAY, upstreamResponse.headers);
3569
- response.writeHead(upstreamResponse.statusCode ?? HTTP_BAD_GATEWAY, forwardableHeaders(upstreamResponse.headers));
3570
- response.flushHeaders();
3571
- if (observer !== void 0) {
3572
- upstreamResponse.on("data", (chunk) => {
3573
- observer.onResponseChunk(chunk);
3574
- });
4080
+ if (url.pathname === setPermissionModePath) {
4081
+ if (request4.method !== "POST") {
4082
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the set-permission-mode operation is a POST" });
4083
+ return;
3575
4084
  }
3576
- upstreamResponse.pipe(response);
3577
- };
3578
- const upstream = target.tls ? https.request(options, onUpstreamResponse) : http.request(options, onUpstreamResponse);
3579
- upstream.on("error", (error) => {
3580
- if (response.headersSent) {
3581
- response.destroy(error);
4085
+ let parsed;
4086
+ try {
4087
+ parsed = JSON.parse(await readBody(request4));
4088
+ } catch {
4089
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the set-permission-mode body is not readable JSON within the control body cap" });
3582
4090
  return;
3583
4091
  }
3584
- const body = `agent-shim headroom: upstream unreachable (${error.message})`;
3585
- response.writeHead(HTTP_BAD_GATEWAY, { "content-type": "text/plain", "content-length": String(body.length) });
3586
- response.end(body);
3587
- });
3588
- if (observer !== void 0) {
3589
- request4.on("data", (chunk) => {
3590
- observer.onRequestChunk(chunk);
3591
- });
3592
- if (observer.onRequestEnd !== void 0) {
3593
- request4.on("end", () => {
3594
- observer.onRequestEnd?.();
3595
- });
4092
+ if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("mode" in parsed) || typeof parsed.session !== "string" || parsed.session === "" || !isRcPermissionMode(parsed.mode)) {
4093
+ answerJson(response, HTTP_STATUS.badRequest, { error: `the set-permission-mode body must be JSON naming a non-empty session id and a mode the SDK's own type permits (${RC_PERMISSION_MODE_LIST})` });
4094
+ return;
3596
4095
  }
3597
- response.on("close", () => {
3598
- observer.onEnd();
3599
- });
4096
+ const result = await deps.setPermissionMode(parsed.session, parsed.mode);
4097
+ if (result.ok) {
4098
+ answerJson(response, HTTP_STATUS.ok, { session: parsed.session, mode: parsed.mode, sequenceNums: result.sequenceNums });
4099
+ return;
4100
+ }
4101
+ answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4102
+ return;
3600
4103
  }
3601
- request4.pipe(upstream);
3602
- request4.socket.setNoDelay(true);
3603
- upstream.on("socket", (socket) => {
3604
- socket.setNoDelay(true);
3605
- });
3606
- }
4104
+ answerJson(response, HTTP_STATUS.notFound, { error: `no such control route: ${url.pathname}` });
4105
+ };
4106
+ handle().catch((error) => {
4107
+ answerJson(response, HTTP_STATUS.internalServerError, { error: `the control route failed: ${error instanceof Error ? error.message : String(error)}` });
4108
+ });
3607
4109
  };
3608
4110
  }
3609
-
3610
- // src/codex/http.ts
3611
- var HTTP_STATUS = {
3612
- ok: 200,
3613
- badRequest: 400,
3614
- unauthorized: 401,
3615
- forbidden: 403,
3616
- notFound: 404,
3617
- methodNotAllowed: 405,
3618
- payloadTooLarge: 413,
3619
- tooManyRequests: 429,
3620
- /** Not sent to anyone: the client is gone. Recorded for a response abandoned because the client disconnected, following the convention nginx uses for the same case. */
3621
- clientClosedRequest: 499,
3622
- internalServerError: 500,
3623
- badGateway: 502
3624
- };
3625
-
3626
- // src/frontdoor/rcSessions.ts
3627
- var RC_SESSIONS_PATH_PREFIX = "/v1/code/sessions";
3628
- var RC_SESSION_ID_PREFIX = "cse_";
3629
- var RC_IDLE_EXPIRY_MS = 45e3;
3630
- var RC_CREATE_RESPONSE_CAP_BYTES = 8192;
3631
- var CONFLICT_REASON_HEADER = "x-ccr-conflict-reason";
3632
- var RC_PENDING_DEADLINE_MS = 14e3;
3633
- var RC_REQUEST_PARSE_CAP_BYTES = 262144;
3634
- var RC_PENDING_SUMMARY_EXCERPT_CHARS = 300;
3635
- var SUCCESS_STATUS_MAX_EXCLUSIVE = 300;
3636
- function isSuccessful(status) {
3637
- return status >= HTTP_STATUS.ok && status < SUCCESS_STATUS_MAX_EXCLUSIVE;
3638
- }
3639
- function singleHeader(headers, name) {
3640
- const value = headers[name];
3641
- return typeof value === "string" ? value : void 0;
3642
- }
3643
- var OAUTH_AUTHORIZATION_PREFIX = "Bearer sk-ant-oat";
3644
- function oauthAuthorizationOf(headers) {
3645
- const value = singleHeader(headers, "authorization");
3646
- return value?.startsWith(OAUTH_AUTHORIZATION_PREFIX) === true ? value : void 0;
4111
+ function realRcControlTransport(port, ca) {
4112
+ return {
4113
+ request: async (options) => await new Promise((resolve, reject) => {
4114
+ const request4 = https.request(
4115
+ {
4116
+ host: "127.0.0.1",
4117
+ port,
4118
+ method: options.method,
4119
+ path: options.path,
4120
+ headers: options.body === void 0 ? options.headers : { ...options.headers, "content-length": String(Buffer.byteLength(options.body, "utf8")) },
4121
+ agent: false,
4122
+ ca: [ca]
4123
+ },
4124
+ (response) => {
4125
+ const chunks = [];
4126
+ response.on("data", (chunk) => {
4127
+ chunks.push(chunk);
4128
+ });
4129
+ response.on("end", () => {
4130
+ resolve({ status: response.statusCode ?? 0, body: Buffer.concat(chunks).toString("utf8") });
4131
+ });
4132
+ }
4133
+ );
4134
+ request4.once("error", reject);
4135
+ if (options.body === void 0) {
4136
+ request4.end();
4137
+ } else {
4138
+ request4.end(options.body);
4139
+ }
4140
+ })
4141
+ };
3647
4142
  }
3648
- function sessionCreateId(body) {
3649
- let parsed;
4143
+ function controlErrorOf(body) {
3650
4144
  try {
3651
- parsed = JSON.parse(body);
4145
+ const parsed = JSON.parse(body);
4146
+ if (typeof parsed === "object" && parsed !== null && "error" in parsed && typeof parsed.error === "string") {
4147
+ return parsed.error;
4148
+ }
3652
4149
  } catch {
3653
- return void 0;
3654
- }
3655
- if (typeof parsed !== "object" || parsed === null || !("session" in parsed)) {
3656
- return void 0;
3657
- }
3658
- const session = parsed.session;
3659
- if (typeof session !== "object" || session === null || !("id" in session)) {
3660
- return void 0;
4150
+ return body;
3661
4151
  }
3662
- const id = session.id;
3663
- return typeof id === "string" && id.startsWith(RC_SESSION_ID_PREFIX) ? id : void 0;
3664
- }
3665
- function isRecord2(value) {
3666
- return typeof value === "object" && value !== null && !Array.isArray(value);
4152
+ return void 0;
3667
4153
  }
3668
- function parseJsonObject(body) {
3669
- let parsed;
3670
- try {
3671
- parsed = JSON.parse(body);
3672
- } catch {
3673
- return void 0;
4154
+ function isRcSessionSummary(value) {
4155
+ if (typeof value !== "object" || value === null) {
4156
+ return false;
3674
4157
  }
3675
- return isRecord2(parsed) ? parsed : void 0;
3676
- }
3677
- function nonEmptyString(record, field) {
3678
- const value = record === void 0 ? void 0 : record[field];
3679
- return typeof value === "string" && value !== "" ? value : void 0;
3680
- }
3681
- function finiteNumber(record, field) {
3682
- const value = record === void 0 ? void 0 : record[field];
3683
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
3684
- }
3685
- function excerpt(text) {
3686
- return text.length <= RC_PENDING_SUMMARY_EXCERPT_CHARS ? text : `${text.slice(0, RC_PENDING_SUMMARY_EXCERPT_CHARS)}...`;
4158
+ if (!("id" in value) || !("createdAt" in value) || !("lastSeenAt" in value)) {
4159
+ return false;
4160
+ }
4161
+ return typeof value.id === "string" && typeof value.createdAt === "number" && typeof value.lastSeenAt === "number";
3687
4162
  }
3688
- function payloadEventsOf(body) {
3689
- const parsed = parseJsonObject(body);
3690
- const events = parsed === void 0 ? void 0 : parsed.events;
3691
- if (!Array.isArray(events)) {
3692
- return [];
4163
+ function isRcWorkerFact(value, valueIs) {
4164
+ if (typeof value !== "object" || value === null) {
4165
+ return false;
3693
4166
  }
3694
- const payloads = [];
3695
- for (const event of events) {
3696
- if (!isRecord2(event)) {
3697
- continue;
3698
- }
3699
- const payload = event.payload;
3700
- if (!isRecord2(payload)) {
3701
- continue;
3702
- }
3703
- payloads.push(payload);
4167
+ if (!("value" in value) || !("observedAt" in value)) {
4168
+ return false;
3704
4169
  }
3705
- return payloads;
4170
+ return valueIs(value.value) && typeof value.observedAt === "number";
3706
4171
  }
3707
- function pendingOfControlRequestPayload(payload) {
3708
- if (payload.type !== "control_request") {
3709
- return void 0;
4172
+ function isRcSessionStatus(value) {
4173
+ if (!isRcSessionSummary(value)) {
4174
+ return false;
3710
4175
  }
3711
- const requestId = nonEmptyString(payload, "request_id") ?? nonEmptyString(payload, "uuid");
3712
- if (requestId === void 0) {
3713
- return void 0;
4176
+ if (!("pending" in value) || !Array.isArray(value.pending)) {
4177
+ return false;
3714
4178
  }
3715
- const request4 = isRecord2(payload.request) ? payload.request : void 0;
3716
- const subtype = nonEmptyString(request4, "subtype");
3717
- const type = subtype ?? "control_request";
3718
- let summary = "";
3719
- if (subtype === "can_use_tool") {
3720
- const toolName = nonEmptyString(request4, "tool_name") ?? "unknown tool";
3721
- const input = request4 === void 0 ? void 0 : request4.input;
3722
- summary = input === void 0 ? toolName : `${toolName} ${excerpt(JSON.stringify(input))}`;
3723
- } else if (request4 !== void 0) {
3724
- summary = excerpt(JSON.stringify(request4));
4179
+ if ("workerState" in value && value.workerState !== void 0 && !isRcWorkerFact(value.workerState, (candidate) => typeof candidate === "string")) {
4180
+ return false;
3725
4181
  }
3726
- return { requestId, type, summary };
4182
+ if ("workerIdleSeconds" in value && value.workerIdleSeconds !== void 0 && !isRcWorkerFact(value.workerIdleSeconds, (candidate) => typeof candidate === "number")) {
4183
+ return false;
4184
+ }
4185
+ return value.pending.every((candidate) => isRcPendingRequestSummary(candidate));
3727
4186
  }
3728
- function answeredRequestIdsOfControlResponsePayload(payload) {
3729
- if (payload.type !== "control_response") {
3730
- return [];
4187
+ function isRcPendingRequestSummary(value) {
4188
+ if (typeof value !== "object" || value === null) {
4189
+ return false;
3731
4190
  }
3732
- const response = isRecord2(payload.response) ? payload.response : void 0;
3733
- const id = nonEmptyString(response, "request_id") ?? nonEmptyString(payload, "request_id") ?? nonEmptyString(payload, "uuid");
3734
- return id === void 0 ? [] : [id];
4191
+ if (!("sessionId" in value) || !("requestId" in value) || !("type" in value) || !("summary" in value) || !("observedAt" in value)) {
4192
+ return false;
4193
+ }
4194
+ return typeof value.sessionId === "string" && typeof value.requestId === "string" && typeof value.type === "string" && typeof value.summary === "string" && typeof value.observedAt === "number";
3735
4195
  }
3736
- function parseRcRequestBody(kind, body) {
3737
- if (kind === "heartbeat") {
3738
- return { controlRequests: [], answeredRequestIds: [], idleSeconds: finiteNumber(parseJsonObject(body), "idle_seconds"), workerStatus: void 0 };
4196
+ function sequenceNumsOfBody(body) {
4197
+ let parsed;
4198
+ try {
4199
+ parsed = JSON.parse(body);
4200
+ } catch {
4201
+ return void 0;
3739
4202
  }
3740
- if (kind === "worker-registration") {
3741
- return { controlRequests: [], answeredRequestIds: [], idleSeconds: void 0, workerStatus: nonEmptyString(parseJsonObject(body), "status") };
4203
+ if (typeof parsed !== "object" || parsed === null || !("sequenceNums" in parsed) || !Array.isArray(parsed.sequenceNums)) {
4204
+ return void 0;
3742
4205
  }
3743
- const controlRequests = [];
3744
- const answeredRequestIds = [];
3745
- for (const payload of payloadEventsOf(body)) {
3746
- const pending = pendingOfControlRequestPayload(payload);
3747
- if (pending !== void 0) {
3748
- controlRequests.push({ requestId: pending.requestId, type: pending.type, summary: pending.summary });
3749
- continue;
4206
+ const sequenceNums = [];
4207
+ const values = parsed.sequenceNums;
4208
+ for (const value of values) {
4209
+ if (typeof value !== "number") {
4210
+ return void 0;
3750
4211
  }
3751
- answeredRequestIds.push(...answeredRequestIdsOfControlResponsePayload(payload));
4212
+ sequenceNums.push(value);
3752
4213
  }
3753
- return { controlRequests, answeredRequestIds, idleSeconds: void 0, workerStatus: void 0 };
4214
+ return sequenceNums;
3754
4215
  }
3755
- function createRcSessionTracker(deps) {
3756
- const entries = /* @__PURE__ */ new Map();
3757
- const expire = (id) => {
3758
- entries.delete(id);
3759
- };
3760
- const expirePendings = (entry, now) => {
3761
- for (const [requestId, pending] of entry.pending) {
3762
- if (now - pending.observedAt >= RC_PENDING_DEADLINE_MS) {
3763
- entry.pending.delete(requestId);
3764
- }
4216
+ function frontDoorRcControl(transport, token) {
4217
+ const headers = { authorization: `Bearer ${token}` };
4218
+ const listAnswerOf = async (path29, what) => {
4219
+ try {
4220
+ return await transport.request({ method: "GET", path: path29, headers });
4221
+ } catch (error) {
4222
+ throw new Error(`${what}: could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
3765
4223
  }
3766
4224
  };
3767
- const sweep = () => {
3768
- for (const [id, entry] of entries) {
3769
- if (deps.now() - entry.lastSeenAt >= deps.idleMs) {
3770
- expire(id);
3771
- continue;
4225
+ const sessionsOf = (answer, what) => {
4226
+ if (answer.status !== HTTP_STATUS.ok) {
4227
+ throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
4228
+ }
4229
+ let parsed;
4230
+ try {
4231
+ parsed = JSON.parse(answer.body);
4232
+ } catch {
4233
+ throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
4234
+ }
4235
+ if (typeof parsed !== "object" || parsed === null || !("sessions" in parsed) || !Array.isArray(parsed.sessions)) {
4236
+ throw new Error(`${what}: the door's answer named no sessions list: ${answer.body}`);
4237
+ }
4238
+ const candidates = parsed.sessions;
4239
+ const sessions = [];
4240
+ for (const value of candidates) {
4241
+ if (!isRcSessionSummary(value)) {
4242
+ throw new Error(`${what}: the door's answer named no sessions list: ${answer.body}`);
3772
4243
  }
3773
- expirePendings(entry, deps.now());
4244
+ sessions.push(value);
3774
4245
  }
4246
+ return sessions;
3775
4247
  };
3776
- const timer = setInterval(sweep, deps.idleMs);
3777
- timer.unref();
3778
- const birth = (id, facts) => {
3779
- const record = { id, createdAt: deps.now(), lastSeenAt: deps.now(), ...facts, pending: /* @__PURE__ */ new Map(), workerState: void 0, workerIdleSeconds: void 0 };
3780
- entries.set(id, record);
3781
- return record;
3782
- };
3783
- const observeExchange = (request4) => {
3784
- const method = (request4.method ?? "").toUpperCase();
3785
- const path29 = new URL(request4.url ?? "/", "http://127.0.0.1").pathname;
3786
- if (!path29.startsWith(RC_SESSIONS_PATH_PREFIX)) {
3787
- return void 0;
4248
+ const statusesOf = (answer, what) => {
4249
+ if (answer.status !== HTTP_STATUS.ok) {
4250
+ throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
3788
4251
  }
3789
- const tail = path29.slice(RC_SESSIONS_PATH_PREFIX.length);
3790
- const facts = {
3791
- oauthAuthorization: oauthAuthorizationOf(request4.headers),
3792
- anthropicVersion: singleHeader(request4.headers, "anthropic-version"),
3793
- anthropicClientPlatform: singleHeader(request4.headers, "anthropic-client-platform")
3794
- };
3795
- if (tail === "") {
3796
- if (method !== "POST") {
3797
- return void 0;
3798
- }
3799
- let accepted2 = false;
3800
- let buffered2 = 0;
3801
- let body = "";
3802
- return {
3803
- onResponse: (status) => {
3804
- accepted2 = isSuccessful(status);
3805
- },
3806
- onBodyChunk: (chunk) => {
3807
- if (!accepted2 || buffered2 >= RC_CREATE_RESPONSE_CAP_BYTES) {
3808
- return;
3809
- }
3810
- const text = Buffer.from(chunk).toString("utf8");
3811
- body = body + text.slice(0, RC_CREATE_RESPONSE_CAP_BYTES - buffered2);
3812
- buffered2 = body.length;
3813
- },
3814
- onEnd: () => {
3815
- if (!accepted2) {
3816
- return;
3817
- }
3818
- const id2 = sessionCreateId(body);
3819
- if (id2 === void 0) {
3820
- return;
3821
- }
3822
- birth(id2, facts);
3823
- }
3824
- };
4252
+ let parsed;
4253
+ try {
4254
+ parsed = JSON.parse(answer.body);
4255
+ } catch {
4256
+ throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
3825
4257
  }
3826
- const rest = tail.slice(1);
3827
- const [id] = rest.split("/");
3828
- if (id?.startsWith(RC_SESSION_ID_PREFIX) !== true) {
3829
- return void 0;
4258
+ if (typeof parsed !== "object" || parsed === null || !("statuses" in parsed) || !Array.isArray(parsed.statuses)) {
4259
+ throw new Error(`${what}: the door's answer named no status list: ${answer.body}`);
3830
4260
  }
3831
- const entry = entries.get(id) ?? birth(id, facts);
3832
- entry.lastSeenAt = deps.now();
3833
- entry.oauthAuthorization = facts.oauthAuthorization ?? entry.oauthAuthorization;
3834
- entry.anthropicVersion = facts.anthropicVersion ?? entry.anthropicVersion;
3835
- entry.anthropicClientPlatform = facts.anthropicClientPlatform ?? entry.anthropicClientPlatform;
3836
- const bodyKind = method === "POST" && rest === `${id}/worker/events` ? "worker-events" : method === "POST" && rest === `${id}/events` ? "client-events" : method === "POST" && rest === `${id}/worker/heartbeat` ? "heartbeat" : method === "PUT" && rest === `${id}/worker` ? "worker-registration" : void 0;
3837
- let chunks = [];
3838
- let buffered = 0;
3839
- let oversized = false;
3840
- let requestEnded = false;
3841
- let accepted;
3842
- let filed = false;
3843
- const file = () => {
3844
- if (filed || accepted !== true || !requestEnded || bodyKind === void 0) {
3845
- return;
3846
- }
3847
- filed = true;
3848
- const factsOfBody = oversized ? void 0 : parseRcRequestBody(bodyKind, Buffer.concat(chunks).toString("utf8"));
3849
- chunks = [];
3850
- const entryNow = entries.get(id);
3851
- if (entryNow === void 0 || factsOfBody === void 0) {
3852
- return;
3853
- }
3854
- const now = deps.now();
3855
- for (const controlRequest of factsOfBody.controlRequests) {
3856
- entryNow.pending.set(controlRequest.requestId, { sessionId: id, ...controlRequest, observedAt: now });
3857
- }
3858
- for (const requestId of factsOfBody.answeredRequestIds) {
3859
- entryNow.pending.delete(requestId);
3860
- }
3861
- if (factsOfBody.idleSeconds !== void 0) {
3862
- entryNow.workerIdleSeconds = { value: factsOfBody.idleSeconds, observedAt: now };
3863
- }
3864
- if (factsOfBody.workerStatus !== void 0) {
3865
- entryNow.workerState = { value: factsOfBody.workerStatus, observedAt: now };
3866
- }
3867
- };
3868
- const archiving = method === "POST" && rest === `${id}/archive`;
3869
- return {
3870
- ...bodyKind === void 0 ? {} : {
3871
- onRequestChunk: (chunk) => {
3872
- if (oversized) {
3873
- return;
3874
- }
3875
- chunks.push(Buffer.from(chunk));
3876
- buffered += chunk.length;
3877
- if (buffered > RC_REQUEST_PARSE_CAP_BYTES) {
3878
- oversized = true;
3879
- chunks = [];
3880
- }
3881
- },
3882
- onRequestEnd: () => {
3883
- requestEnded = true;
3884
- file();
3885
- }
3886
- },
3887
- onResponse: (status, headers) => {
3888
- if (singleHeader(headers, CONFLICT_REASON_HEADER) !== void 0 || archiving && isSuccessful(status)) {
3889
- expire(id);
3890
- return;
3891
- }
3892
- accepted = isSuccessful(status);
3893
- file();
3894
- },
3895
- onBodyChunk: () => {
3896
- },
3897
- onEnd: () => {
4261
+ const statuses = [];
4262
+ for (const value of parsed.statuses) {
4263
+ if (!isRcSessionStatus(value)) {
4264
+ throw new Error(`${what}: the door's answer named no status list: ${answer.body}`);
3898
4265
  }
3899
- };
3900
- };
3901
- const summaryOf = ({ id, createdAt, lastSeenAt }) => ({ id, createdAt, lastSeenAt });
3902
- const pendingSummaryOf = ({ sessionId, requestId, type, summary, observedAt }) => ({ sessionId, requestId, type, summary, observedAt });
3903
- const sortedEntries = () => [...entries.values()].sort((left, right) => left.createdAt - right.createdAt || (left.id < right.id ? -1 : 1));
3904
- const pendingSorted = (entry) => [...entry.pending.values()].sort((left, right) => left.observedAt - right.observedAt || (left.requestId < right.requestId ? -1 : 1)).map(pendingSummaryOf);
3905
- return {
3906
- observeExchange,
3907
- list: () => {
3908
- sweep();
3909
- return sortedEntries().map(summaryOf);
3910
- },
3911
- statusOf: (sessionId) => {
3912
- sweep();
3913
- return sortedEntries().filter((entry) => sessionId === void 0 || entry.id === sessionId).map((entry) => ({ ...summaryOf(entry), workerState: entry.workerState, workerIdleSeconds: entry.workerIdleSeconds, pending: pendingSorted(entry) }));
3914
- },
3915
- pendingOf: (sessionId) => {
3916
- sweep();
3917
- return sortedEntries().filter((entry) => sessionId === void 0 || entry.id === sessionId).flatMap((entry) => pendingSorted(entry));
3918
- },
3919
- credentialOf: (sessionId) => {
3920
- const entry = entries.get(sessionId);
3921
- return entry === void 0 ? void 0 : { authorization: entry.oauthAuthorization, anthropicVersion: entry.anthropicVersion, anthropicClientPlatform: entry.anthropicClientPlatform };
3922
- },
3923
- completePending: (sessionId, requestId) => {
3924
- entries.get(sessionId)?.pending.delete(requestId);
3925
- },
3926
- close: () => {
3927
- clearInterval(timer);
4266
+ statuses.push(value);
3928
4267
  }
4268
+ return statuses;
3929
4269
  };
3930
- }
3931
- function observingRoutedRoute(route, tracker) {
3932
- return {
3933
- ...route,
3934
- serve: async (request4, response) => {
3935
- const observed = tracker.observeExchange({ method: request4.method, url: request4.url, headers: request4.headers });
3936
- if (observed?.onRequestChunk !== void 0) {
3937
- request4.body.on("data", (chunk) => {
3938
- observed.onRequestChunk?.(chunk);
3939
- });
3940
- request4.body.on("end", () => {
3941
- observed.onRequestEnd?.();
3942
- });
4270
+ const pendingOfAnswer = (answer, what) => {
4271
+ if (answer.status !== HTTP_STATUS.ok) {
4272
+ throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
4273
+ }
4274
+ let parsed;
4275
+ try {
4276
+ parsed = JSON.parse(answer.body);
4277
+ } catch {
4278
+ throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
4279
+ }
4280
+ if (typeof parsed !== "object" || parsed === null || !("pending" in parsed) || !Array.isArray(parsed.pending)) {
4281
+ throw new Error(`${what}: the door's answer named no pending list: ${answer.body}`);
4282
+ }
4283
+ const pending = [];
4284
+ for (const value of parsed.pending) {
4285
+ if (!isRcPendingRequestSummary(value)) {
4286
+ throw new Error(`${what}: the door's answer named no pending list: ${answer.body}`);
3943
4287
  }
3944
- await route.serve(request4, observed === void 0 ? response : teeRoutedResponse(response, observed));
4288
+ pending.push(value);
3945
4289
  }
4290
+ return pending;
3946
4291
  };
3947
- }
3948
- function teeRoutedResponse(response, observer) {
3949
- return {
3950
- get headersSent() {
3951
- return response.headersSent;
3952
- },
3953
- start: (status, headers) => {
3954
- observer.onResponse(status, headers);
3955
- response.start(status, headers);
3956
- },
3957
- flush: () => {
3958
- response.flush();
3959
- },
3960
- write: async (chunk) => {
3961
- observer.onBodyChunk(typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk);
3962
- await response.write(chunk);
3963
- },
3964
- end: () => {
3965
- response.end();
3966
- observer.onEnd();
3967
- },
3968
- destroy: () => {
3969
- response.destroy();
3970
- observer.onEnd();
4292
+ const writeOf = async (path29, body, describeFailure) => {
4293
+ let answer;
4294
+ try {
4295
+ answer = await transport.request({ method: "POST", path: path29, headers: { ...headers, "content-type": "application/json" }, body });
4296
+ } catch (error) {
4297
+ return { ok: false, message: `could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}` };
3971
4298
  }
3972
- };
3973
- }
3974
- function rcObserverAsPassthrough(observer) {
3975
- return {
3976
- onRequestChunk: (chunk) => {
3977
- observer.onRequestChunk?.(chunk);
3978
- },
3979
- ...observer.onRequestEnd === void 0 ? {} : {
3980
- onRequestEnd: () => {
3981
- observer.onRequestEnd?.();
4299
+ if (answer.status === HTTP_STATUS.ok) {
4300
+ const sequenceNums = sequenceNumsOfBody(answer.body);
4301
+ if (sequenceNums === void 0) {
4302
+ return { ok: false, message: `the door accepted the event but its answer named no sequence numbers: ${answer.body}` };
3982
4303
  }
3983
- },
3984
- onResponse: (status, headers) => {
3985
- observer.onResponse(status, headers);
3986
- },
3987
- onResponseChunk: (chunk) => {
3988
- observer.onBodyChunk(chunk);
3989
- },
3990
- onEnd: () => {
3991
- observer.onEnd();
4304
+ return { ok: true, sequenceNums };
3992
4305
  }
4306
+ return { ok: false, message: describeFailure(answer.status, controlErrorOf(answer.body) ?? answer.body) };
3993
4307
  };
3994
- }
3995
- function buildRcUserMessagePayload(uuid, sessionId, text) {
4308
+ const sessionQuery = (sessionId) => sessionId === void 0 ? "" : `?session=${encodeURIComponent(sessionId)}`;
3996
4309
  return {
3997
- type: "user",
3998
- uuid,
3999
- session_id: sessionId,
4000
- parent_tool_use_id: null,
4001
- message: { role: "user", content: text }
4310
+ listSessions: async () => sessionsOf(await listAnswerOf(`${CONTROL_PATH_PREFIX}/sessions`, "listing the door's Remote Control sessions"), "listing the door's Remote Control sessions"),
4311
+ statusOf: async (sessionId) => statusesOf(await listAnswerOf(`${CONTROL_PATH_PREFIX}/status${sessionQuery(sessionId)}`, "reading the door's Remote Control session status"), "reading the door's Remote Control session status"),
4312
+ pendingOf: async (sessionId) => pendingOfAnswer(await listAnswerOf(`${CONTROL_PATH_PREFIX}/pending${sessionQuery(sessionId)}`, "listing the door's pending Remote Control control requests"), "listing the door's pending Remote Control control requests"),
4313
+ sendPrompt: async (sessionId, text) => await writeOf(`${CONTROL_PATH_PREFIX}/inject`, JSON.stringify({ session: sessionId, text }), (status, message) => `injecting into ${sessionId} failed (HTTP ${String(status)}): ${message}`),
4314
+ answerRequest: async (sessionId, requestId, decision) => await writeOf(
4315
+ `${CONTROL_PATH_PREFIX}/answer`,
4316
+ JSON.stringify({ session: sessionId, request: requestId, approve: decision.approve, ...decision.approve || decision.message === void 0 ? {} : { text: decision.message } }),
4317
+ (status, message) => `answering control request ${requestId} on ${sessionId} failed (HTTP ${String(status)}): ${message}`
4318
+ ),
4319
+ interruptSession: async (sessionId) => await writeOf(`${CONTROL_PATH_PREFIX}/interrupt`, JSON.stringify({ session: sessionId }), (status, message) => `interrupting ${sessionId} failed (HTTP ${String(status)}): ${message}`),
4320
+ setModel: async (sessionId, model) => await writeOf(`${CONTROL_PATH_PREFIX}/set-model`, JSON.stringify({ session: sessionId, model }), (status, message) => `setting the model on ${sessionId} failed (HTTP ${String(status)}): ${message}`),
4321
+ setPermissionMode: async (sessionId, mode) => await writeOf(`${CONTROL_PATH_PREFIX}/set-permission-mode`, JSON.stringify({ session: sessionId, mode }), (status, message) => `setting the permission mode on ${sessionId} failed (HTTP ${String(status)}): ${message}`)
4002
4322
  };
4003
4323
  }
4004
- function buildRcEventWriteBody(payload) {
4005
- return { events: [{ payload }] };
4006
- }
4007
- function sequenceNumsOf(body) {
4008
- let parsed;
4009
- try {
4010
- parsed = JSON.parse(body);
4011
- } catch {
4012
- return void 0;
4013
- }
4014
- if (typeof parsed !== "object" || parsed === null || !("results" in parsed) || !Array.isArray(parsed.results)) {
4015
- return void 0;
4016
- }
4017
- const sequenceNums = [];
4018
- const results = parsed.results;
4019
- for (const result of results) {
4020
- if (typeof result !== "object" || result === null || !("sequence_num" in result)) {
4021
- return void 0;
4022
- }
4023
- const sequenceNum = result.sequence_num;
4024
- if (typeof sequenceNum === "number") {
4025
- sequenceNums.push(sequenceNum);
4026
- } else if (typeof sequenceNum === "string" && /^[0-9]+$/.test(sequenceNum)) {
4027
- sequenceNums.push(Number(sequenceNum));
4028
- } else {
4029
- return void 0;
4324
+
4325
+ // src/frontdoor/server.ts
4326
+ async function* upstreamChunks(stream) {
4327
+ for await (const chunk of stream) {
4328
+ if (typeof chunk === "string") {
4329
+ yield Buffer.from(chunk, "utf8");
4330
+ continue;
4030
4331
  }
4031
- }
4032
- return sequenceNums.length === 0 ? void 0 : sequenceNums;
4033
- }
4034
- function rcEventWriteResultFromAnswer(answer) {
4035
- if (!isSuccessful(answer.status)) {
4036
- if (answer.status === HTTP_STATUS.unauthorized) {
4037
- return { ok: false, message: `the API refused the observed Authorization bearer for this session (HTTP 401): the bearer went stale after the door last saw the session's traffic. The session's own client refreshes it on its next call, which the door will observe, so retry once Remote Control has been active again. API answer: ${answer.body}` };
4332
+ if (chunk instanceof Uint8Array) {
4333
+ yield chunk;
4038
4334
  }
4039
- return { ok: false, message: `the API answered HTTP ${String(answer.status)} to the injected event: ${answer.body}` };
4040
- }
4041
- const sequenceNums = sequenceNumsOf(answer.body);
4042
- if (sequenceNums === void 0) {
4043
- return { ok: false, message: `the API accepted the injected event but its answer named no results[].sequence_num, so delivery cannot be confirmed: ${answer.body}` };
4044
4335
  }
4045
- return { ok: true, sequenceNums };
4046
4336
  }
4047
- function noOAuthCredentialResult(sessionId) {
4048
- return { ok: false, message: `no claude.ai OAuth bearer has been observed for session ${sessionId}: only worker calls crossed this door, and the worker JWT they carry is answered 401 on the client half. Reconnect Remote Control through this door and the create's own bearer will be observed` };
4337
+
4338
+ // src/frontdoor/connectEffects.ts
4339
+ var SUCCESS_STATUS_MAX_EXCLUSIVE2 = 300;
4340
+ function isSuccessful2(status) {
4341
+ return status >= HTTP_STATUS.ok && status < SUCCESS_STATUS_MAX_EXCLUSIVE2;
4049
4342
  }
4050
- function rcWriteHeaders(credential) {
4051
- const headers = { "content-type": "application/json" };
4052
- if (credential.authorization !== void 0) {
4053
- headers.authorization = credential.authorization;
4054
- }
4055
- if (credential.anthropicVersion !== void 0) {
4056
- headers["anthropic-version"] = credential.anthropicVersion;
4057
- }
4058
- if (credential.anthropicClientPlatform !== void 0) {
4059
- headers["anthropic-client-platform"] = credential.anthropicClientPlatform;
4060
- }
4061
- return headers;
4343
+ var UPSTREAM_LOCAL_PORT_START = 47900;
4344
+ var UPSTREAM_LOCAL_PORT_END = 47919;
4345
+ var UPSTREAM_LOCAL_PORT_COUNT = UPSTREAM_LOCAL_PORT_END - UPSTREAM_LOCAL_PORT_START + 1;
4346
+ var nextUpstreamLocalPort = UPSTREAM_LOCAL_PORT_START;
4347
+ function upstreamLocalPort() {
4348
+ const port = nextUpstreamLocalPort;
4349
+ nextUpstreamLocalPort = nextUpstreamLocalPort === UPSTREAM_LOCAL_PORT_END ? UPSTREAM_LOCAL_PORT_START : nextUpstreamLocalPort + 1;
4350
+ return port;
4062
4351
  }
4063
- async function injectRcUserMessage(deps, sessionId, text) {
4064
- const credential = deps.credentialOf(sessionId);
4065
- if (credential === void 0) {
4066
- return { ok: false, message: `the front door has not observed Remote Control session ${sessionId}: it may never have passed through this door, or it ended or expired (an entry lives only a bounded idle period past its last observed traffic)` };
4067
- }
4068
- if (credential.authorization === void 0) {
4069
- return noOAuthCredentialResult(sessionId);
4070
- }
4071
- const body = JSON.stringify(buildRcEventWriteBody(buildRcUserMessagePayload(deps.newUuid(), sessionId, text)));
4072
- let answer;
4073
- try {
4074
- answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
4075
- } catch (error) {
4076
- return { ok: false, message: `the door could not reach the API host to inject into session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
4352
+ var realAddressLookup = (host, _options, callback) => {
4353
+ if (net2.isIP(host) !== 0) {
4354
+ callback(null, [{ address: host, family: net2.isIP(host) }]);
4355
+ return;
4077
4356
  }
4078
- return rcEventWriteResultFromAnswer(answer);
4079
- }
4080
- function buildRcControlResponsePayload(requestId, decision) {
4081
- const result = decision.approve ? { behavior: "allow" } : { behavior: "deny", message: decision.message ?? "" };
4082
- return { type: "control_response", response: { subtype: "success", request_id: requestId, response: result } };
4083
- }
4084
- var RC_PERMISSION_MODES = ["default", "acceptEdits", "bypassPermissions", "plan", "dontAsk", "auto"];
4085
- function isRcPermissionMode(value) {
4086
- return RC_PERMISSION_MODES.some((mode) => mode === value);
4087
- }
4088
- function buildRcInterruptPayload(requestId) {
4089
- return { type: "control_request", request_id: requestId, request: { subtype: "interrupt" } };
4090
- }
4091
- function buildRcSetModelPayload(requestId, model) {
4092
- return { type: "control_request", request_id: requestId, request: { subtype: "set_model", model } };
4357
+ import_node_dns.default.resolve4(host, (error, addresses) => {
4358
+ if (error !== null) {
4359
+ callback(error, [{ address: "", family: 4 }]);
4360
+ return;
4361
+ }
4362
+ const first = addresses[0];
4363
+ if (first === void 0) {
4364
+ callback(new Error(`no A record for ${host}`), [{ address: "", family: 4 }]);
4365
+ return;
4366
+ }
4367
+ callback(null, [{ address: first, family: 4 }]);
4368
+ });
4369
+ };
4370
+ var HTTP_PORT = 80;
4371
+ var HELD_PORT_ERRNOS = /* @__PURE__ */ new Set(["EADDRINUSE", "EADDRNOTAVAIL"]);
4372
+ async function dialOnce(connectOptions) {
4373
+ return await new Promise((resolve) => {
4374
+ const socket = net2.connect(connectOptions);
4375
+ socket.once("connect", () => {
4376
+ resolve({ error: null, socket });
4377
+ });
4378
+ socket.once("error", (error) => {
4379
+ resolve({ error, socket });
4380
+ });
4381
+ });
4093
4382
  }
4094
- function buildRcSetPermissionModePayload(requestId, mode) {
4095
- return { type: "control_request", request_id: requestId, request: { subtype: "set_permission_mode", mode } };
4383
+ function dialTarget(options, defaultPort) {
4384
+ return { host: typeof options.host === "string" ? options.host : "", port: typeof options.port === "number" ? options.port : defaultPort };
4096
4385
  }
4097
- async function answerRcControlRequest(deps, sessionId, requestId, decision) {
4098
- const credential = deps.credentialOf(sessionId);
4099
- if (credential === void 0) {
4100
- return { ok: false, message: `the front door has not observed Remote Control session ${sessionId}: it may never have passed through this door, or it ended or expired (an entry lives only a bounded idle period past its last observed traffic)` };
4101
- }
4102
- if (credential.authorization === void 0) {
4103
- return noOAuthCredentialResult(sessionId);
4104
- }
4105
- if (!deps.pendingOf(sessionId).some((pending) => pending.requestId === requestId)) {
4106
- return { ok: false, message: `the front door has not observed control request ${requestId} pending on session ${sessionId}: it was answered already (by this door or by an attached client), it passed its answer deadline (the protocol's permission round-trip bound), or it never passed through this door` };
4107
- }
4108
- const body = JSON.stringify(buildRcEventWriteBody(buildRcControlResponsePayload(requestId, decision)));
4109
- let answer;
4110
- try {
4111
- answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
4112
- } catch (error) {
4113
- return { ok: false, message: `the door could not reach the API host to answer on session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
4114
- }
4115
- const result = rcEventWriteResultFromAnswer(answer);
4116
- if (result.ok) {
4117
- deps.completePending(sessionId, requestId);
4118
- }
4119
- return result;
4386
+ function literalDial(target) {
4387
+ return net2.connect({ host: target.host, port: target.port });
4120
4388
  }
4121
- async function interruptRcSession(deps, sessionId) {
4122
- const credential = deps.credentialOf(sessionId);
4123
- if (credential === void 0) {
4124
- return { ok: false, message: `the front door has not observed Remote Control session ${sessionId}: it may never have passed through this door, or it ended or expired (an entry lives only a bounded idle period past its last observed traffic)` };
4125
- }
4126
- if (credential.authorization === void 0) {
4127
- return noOAuthCredentialResult(sessionId);
4128
- }
4129
- const body = JSON.stringify(buildRcEventWriteBody(buildRcInterruptPayload(deps.newUuid())));
4130
- let answer;
4131
- try {
4132
- answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
4133
- } catch (error) {
4134
- return { ok: false, message: `the door could not reach the API host to interrupt session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
4389
+ async function reservedDial(target) {
4390
+ for (let attempt = 0; ; attempt += 1) {
4391
+ const outcome = await dialOnce({ host: target.host, port: target.port, localPort: upstreamLocalPort(), lookup: realAddressLookup });
4392
+ if (outcome.error === null) {
4393
+ return outcome;
4394
+ }
4395
+ const held = outcome.error.code !== void 0 && HELD_PORT_ERRNOS.has(outcome.error.code);
4396
+ if (!held || attempt === UPSTREAM_LOCAL_PORT_COUNT - 1) {
4397
+ return outcome;
4398
+ }
4135
4399
  }
4136
- return rcEventWriteResultFromAnswer(answer);
4137
4400
  }
4138
- async function setRcSessionModel(deps, sessionId, model) {
4139
- if (model === "") {
4140
- return { ok: false, message: "a set-model write needs a non-empty model id: the SDK's own field treats an omitted or null value as a reset to the session default, which this operation never sends, and an empty string is neither" };
4141
- }
4142
- const credential = deps.credentialOf(sessionId);
4143
- if (credential === void 0) {
4144
- return { ok: false, message: `the front door has not observed Remote Control session ${sessionId}: it may never have passed through this door, or it ended or expired (an entry lives only a bounded idle period past its last observed traffic)` };
4145
- }
4146
- if (credential.authorization === void 0) {
4147
- return noOAuthCredentialResult(sessionId);
4148
- }
4149
- const body = JSON.stringify(buildRcEventWriteBody(buildRcSetModelPayload(deps.newUuid(), model)));
4150
- let answer;
4151
- try {
4152
- answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
4153
- } catch (error) {
4154
- return { ok: false, message: `the door could not reach the API host to set the model on session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
4155
- }
4156
- return rcEventWriteResultFromAnswer(answer);
4401
+ function requestServername(options, fallback) {
4402
+ return "servername" in options && typeof options.servername === "string" && options.servername !== "" ? options.servername : fallback;
4157
4403
  }
4158
- async function setRcSessionPermissionMode(deps, sessionId, mode) {
4159
- const credential = deps.credentialOf(sessionId);
4160
- if (credential === void 0) {
4161
- return { ok: false, message: `the front door has not observed Remote Control session ${sessionId}: it may never have passed through this door, or it ended or expired (an entry lives only a bounded idle period past its last observed traffic)` };
4404
+ var ExemptHttpAgent = class extends http.Agent {
4405
+ // A reserved-port dial that has to retry cannot produce its socket synchronously, so it settles first and arrives through the callback (node's documented asynchronous createConnection form); a literal dial has nothing to retry and keeps node's own synchronous shape.
4406
+ createConnection(options, oncreate) {
4407
+ const target = dialTarget(options, HTTP_PORT);
4408
+ if (net2.isIP(target.host) !== 0) {
4409
+ return literalDial(target);
4410
+ }
4411
+ void reservedDial(target).then((outcome) => {
4412
+ oncreate?.(outcome.error, outcome.socket);
4413
+ });
4414
+ return void 0;
4162
4415
  }
4163
- if (credential.authorization === void 0) {
4164
- return noOAuthCredentialResult(sessionId);
4416
+ };
4417
+ var ExemptTlsAgent = class extends https2.Agent {
4418
+ // The same split as the plain sibling: a literal dial wraps TLS around the socket node's own agent would have returned, a reserved dial settles (retries included) first and arrives through the callback, which is exactly where node's own agent wraps its own dials.
4419
+ createConnection(options, oncreate) {
4420
+ const target = dialTarget(options, HTTPS_PORT);
4421
+ if (net2.isIP(target.host) !== 0) {
4422
+ return tls.connect({ socket: literalDial(target), servername: requestServername(options, target.host), ...tlsFacts(options) });
4423
+ }
4424
+ void reservedDial(target).then((outcome) => {
4425
+ if (outcome.error !== null) {
4426
+ oncreate?.(outcome.error, outcome.socket);
4427
+ return;
4428
+ }
4429
+ oncreate?.(null, tls.connect({ socket: outcome.socket, servername: requestServername(options, target.host), ...tlsFacts(options) }));
4430
+ });
4431
+ return void 0;
4165
4432
  }
4166
- const body = JSON.stringify(buildRcEventWriteBody(buildRcSetPermissionModePayload(deps.newUuid(), mode)));
4167
- let answer;
4168
- try {
4169
- answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
4170
- } catch (error) {
4171
- return { ok: false, message: `the door could not reach the API host to set the permission mode on session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
4433
+ };
4434
+ function tlsFacts(options) {
4435
+ const facts = {};
4436
+ if ("ca" in options && Array.isArray(options.ca)) {
4437
+ facts.ca = options.ca;
4172
4438
  }
4173
- return rcEventWriteResultFromAnswer(answer);
4174
- }
4175
-
4176
- // src/frontdoor/rcControl.ts
4177
- var https2 = __toESM(require("node:https"), 1);
4178
- var RC_PERMISSION_MODE_LIST = RC_PERMISSION_MODES.join(", ");
4179
- var CONTROL_PATH_PREFIX = "/__agent-shim/rc";
4180
- var CONTROL_BODY_CAP_BYTES = 10485760;
4181
- function answerJson(response, status, body) {
4182
- const text = JSON.stringify(body);
4183
- response.writeHead(status, { "content-type": "application/json", "content-length": String(Buffer.byteLength(text, "utf8")) });
4184
- response.end(text);
4439
+ if ("rejectUnauthorized" in options && typeof options.rejectUnauthorized === "boolean") {
4440
+ facts.rejectUnauthorized = options.rejectUnauthorized;
4441
+ }
4442
+ return facts;
4185
4443
  }
4186
- async function readBody(request4) {
4187
- return await new Promise((resolve, reject) => {
4188
- const chunks = [];
4189
- let total = 0;
4190
- request4.on("data", (chunk) => {
4191
- total += chunk.length;
4192
- if (total > CONTROL_BODY_CAP_BYTES) {
4193
- request4.destroy();
4194
- reject(new Error("too large"));
4195
- return;
4444
+ function realRcEventDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
4445
+ const agent = new ExemptTlsAgent();
4446
+ return {
4447
+ writeEvents: async (sessionId, headers, body) => await new Promise((resolve, reject) => {
4448
+ const options = {
4449
+ host: target.host,
4450
+ port: target.port,
4451
+ method: "POST",
4452
+ path: `/v1/code/sessions/${encodeURIComponent(sessionId)}/events`,
4453
+ // 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.
4454
+ headers: { ...headers, host: target.servername ?? target.host, "content-length": String(Buffer.byteLength(body, "utf8")) },
4455
+ agent
4456
+ };
4457
+ options.servername = target.servername ?? target.host;
4458
+ if (target.ca !== void 0) {
4459
+ options.ca = [...target.ca];
4196
4460
  }
4197
- chunks.push(chunk);
4198
- });
4199
- request4.on("end", () => {
4200
- resolve(Buffer.concat(chunks).toString("utf8"));
4201
- });
4202
- request4.on("error", () => {
4203
- reject(new Error("the request body ended early"));
4461
+ if (target.rejectUnauthorized !== void 0) {
4462
+ options.rejectUnauthorized = target.rejectUnauthorized;
4463
+ }
4464
+ const request4 = https2.request(options, (response) => {
4465
+ const chunks = [];
4466
+ response.on("data", (chunk) => {
4467
+ chunks.push(chunk);
4468
+ });
4469
+ response.on("end", () => {
4470
+ resolve({ status: response.statusCode ?? HTTP_BAD_GATEWAY, body: Buffer.concat(chunks).toString("utf8") });
4471
+ });
4472
+ });
4473
+ request4.once("error", reject);
4474
+ request4.end(body);
4475
+ })
4476
+ };
4477
+ }
4478
+ var NO_CHUNKS = {
4479
+ [Symbol.asyncIterator]: () => ({
4480
+ next: async () => await Promise.resolve({ done: true, value: void 0 })
4481
+ })
4482
+ };
4483
+ function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
4484
+ const agent = new ExemptTlsAgent();
4485
+ const request4 = async (method, path29, headers, body, signal) => await new Promise((resolve, reject) => {
4486
+ const options = {
4487
+ host: target.host,
4488
+ port: target.port,
4489
+ method,
4490
+ path: path29,
4491
+ // 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.
4492
+ headers: { ...headers, host: target.servername ?? target.host, ...body === void 0 ? {} : { "content-length": String(Buffer.byteLength(body, "utf8")) } },
4493
+ agent,
4494
+ signal
4495
+ };
4496
+ options.servername = target.servername ?? target.host;
4497
+ if (target.ca !== void 0) {
4498
+ options.ca = [...target.ca];
4499
+ }
4500
+ if (target.rejectUnauthorized !== void 0) {
4501
+ options.rejectUnauthorized = target.rejectUnauthorized;
4502
+ }
4503
+ const sent = https2.request(options, (response) => {
4504
+ resolve({ status: response.statusCode ?? HTTP_BAD_GATEWAY, response });
4204
4505
  });
4506
+ sent.once("error", reject);
4507
+ if (body === void 0) {
4508
+ sent.end();
4509
+ } else {
4510
+ sent.end(body);
4511
+ }
4205
4512
  });
4206
- }
4207
- function createRcControlHandler(deps) {
4208
- const sessionsPath = `${CONTROL_PATH_PREFIX}/sessions`;
4209
- const statusPath = `${CONTROL_PATH_PREFIX}/status`;
4210
- const pendingPath = `${CONTROL_PATH_PREFIX}/pending`;
4211
- const injectPath = `${CONTROL_PATH_PREFIX}/inject`;
4212
- const answerPath = `${CONTROL_PATH_PREFIX}/answer`;
4213
- const interruptPath = `${CONTROL_PATH_PREFIX}/interrupt`;
4214
- const setModelPath = `${CONTROL_PATH_PREFIX}/set-model`;
4215
- const setPermissionModePath = `${CONTROL_PATH_PREFIX}/set-permission-mode`;
4216
- return (request4, response) => {
4217
- const presented = request4.headers.authorization;
4218
- const bearerPrefix = "bearer ".length;
4219
- const token = typeof presented === "string" && presented.slice(0, bearerPrefix).toLowerCase() === "bearer " ? presented.slice(bearerPrefix) : void 0;
4220
- if (token === void 0 || !isLiveCapability(token, [deps.expectedToken])) {
4221
- answerJson(response, HTTP_STATUS.unauthorized, { error: "the front door's control routes demand this generation's control token as a Bearer credential" });
4222
- return;
4513
+ const readAll = async (response) => {
4514
+ const chunks = [];
4515
+ for await (const chunk of upstreamChunks(response)) {
4516
+ chunks.push(Buffer.from(chunk));
4223
4517
  }
4224
- const url = new URL(request4.url ?? "/", "http://127.0.0.1");
4225
- const handle = async () => {
4226
- if (url.pathname === sessionsPath) {
4227
- if (request4.method !== "GET") {
4228
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the session list is a GET" });
4229
- return;
4230
- }
4231
- answerJson(response, HTTP_STATUS.ok, { sessions: deps.list() });
4232
- return;
4233
- }
4234
- if (url.pathname === statusPath || url.pathname === pendingPath) {
4235
- if (request4.method !== "GET") {
4236
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the status and pending reads are GETs" });
4237
- return;
4238
- }
4239
- const session = url.searchParams.get("session") ?? void 0;
4240
- if (session !== void 0 && !deps.statusOf(session).some((entry) => entry.id === session)) {
4241
- answerJson(response, HTTP_STATUS.notFound, { error: `the front door has not observed Remote Control session ${session}: it may never have passed through this door, or it ended or expired (an entry lives only a bounded idle period past its last observed traffic)` });
4242
- return;
4243
- }
4244
- answerJson(response, HTTP_STATUS.ok, url.pathname === statusPath ? { statuses: deps.statusOf(session) } : { pending: deps.pendingOf(session) });
4245
- return;
4246
- }
4247
- if (url.pathname === injectPath) {
4248
- if (request4.method !== "POST") {
4249
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the inject operation is a POST" });
4250
- return;
4251
- }
4252
- let parsed;
4253
- try {
4254
- parsed = JSON.parse(await readBody(request4));
4255
- } catch {
4256
- answerJson(response, HTTP_STATUS.badRequest, { error: "the inject body is not readable JSON within the control body cap" });
4257
- return;
4258
- }
4259
- if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("text" in parsed) || typeof parsed.session !== "string" || typeof parsed.text !== "string" || parsed.session === "" || parsed.text === "") {
4260
- answerJson(response, HTTP_STATUS.badRequest, { error: "the inject body must be JSON naming a non-empty session id and text" });
4261
- return;
4262
- }
4263
- const result = await deps.inject(parsed.session, parsed.text);
4264
- if (result.ok) {
4265
- answerJson(response, HTTP_STATUS.ok, { session: parsed.session, sequenceNums: result.sequenceNums });
4266
- return;
4267
- }
4268
- answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4269
- return;
4518
+ return Buffer.concat(chunks).toString("utf8");
4519
+ };
4520
+ return {
4521
+ announcePresence: async (sessionId, headers, clientId) => {
4522
+ const body = JSON.stringify({ client_id: clientId, clear: false });
4523
+ const { status, response } = await request4("POST", `/v1/code/sessions/${encodeURIComponent(sessionId)}/client/presence`, { ...headers, "content-type": "application/json" }, body, new AbortController().signal);
4524
+ return { status, body: await readAll(response) };
4525
+ },
4526
+ openStream: async (sessionId, headers, resume, signal) => {
4527
+ const path29 = resume === void 0 ? `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream` : `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream?from_sequence_num=${String(resume.fromSequenceNum)}`;
4528
+ const streamHeaders = resume === void 0 ? headers : { ...headers, "last-event-id": String(resume.fromSequenceNum) };
4529
+ const { status, response } = await request4("GET", path29, streamHeaders, void 0, signal);
4530
+ if (!isSuccessful2(status)) {
4531
+ await readAll(response);
4532
+ return { status, chunks: NO_CHUNKS };
4270
4533
  }
4271
- if (url.pathname === answerPath) {
4272
- if (request4.method !== "POST") {
4273
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the answer operation is a POST" });
4274
- return;
4275
- }
4276
- let parsed;
4277
- try {
4278
- parsed = JSON.parse(await readBody(request4));
4279
- } catch {
4280
- answerJson(response, HTTP_STATUS.badRequest, { error: "the answer body is not readable JSON within the control body cap" });
4281
- return;
4282
- }
4283
- if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("request" in parsed) || !("approve" in parsed) || typeof parsed.session !== "string" || typeof parsed.request !== "string" || typeof parsed.approve !== "boolean" || parsed.session === "" || parsed.request === "") {
4284
- answerJson(response, HTTP_STATUS.badRequest, { error: "the answer body must be JSON naming a non-empty session id, request id, and an approve boolean" });
4285
- return;
4286
- }
4287
- const text = "text" in parsed && typeof parsed.text === "string" ? parsed.text : void 0;
4288
- if (parsed.approve && text !== void 0 && text !== "") {
4289
- answerJson(response, HTTP_STATUS.badRequest, { error: "an approval carries no text (the protocol's allow result has no message field); text is the denial message" });
4290
- return;
4291
- }
4292
- const result = await deps.answer(parsed.session, parsed.request, { approve: parsed.approve, message: parsed.approve ? void 0 : text });
4293
- if (result.ok) {
4294
- answerJson(response, HTTP_STATUS.ok, { session: parsed.session, request: parsed.request, sequenceNums: result.sequenceNums });
4295
- return;
4296
- }
4297
- answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4534
+ return { status, chunks: response };
4535
+ }
4536
+ };
4537
+ }
4538
+ function realConnectEffects() {
4539
+ const plainAgent = new ExemptHttpAgent();
4540
+ const tlsAgent = new ExemptTlsAgent();
4541
+ const listenOnce = async (port, onSocket) => await new Promise((resolve, reject) => {
4542
+ const accepted = /* @__PURE__ */ new Set();
4543
+ const server = net2.createServer((socket) => {
4544
+ accepted.add(socket);
4545
+ socket.on("close", () => {
4546
+ accepted.delete(socket);
4547
+ });
4548
+ onSocket(socket);
4549
+ });
4550
+ server.once("error", reject);
4551
+ server.listen(port, "127.0.0.1", () => {
4552
+ const address = server.address();
4553
+ const bound = typeof address === "object" && address !== null ? address.port : 0;
4554
+ if (bound === 0) {
4555
+ reject(new Error("could not bind a loopback port"));
4298
4556
  return;
4299
4557
  }
4300
- if (url.pathname === interruptPath) {
4301
- if (request4.method !== "POST") {
4302
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the interrupt operation is a POST" });
4303
- return;
4558
+ resolve({
4559
+ port: bound,
4560
+ close: async () => {
4561
+ await new Promise((closeResolve) => {
4562
+ server.close(() => {
4563
+ closeResolve(void 0);
4564
+ });
4565
+ for (const socket of accepted) {
4566
+ socket.destroy();
4567
+ }
4568
+ });
4304
4569
  }
4305
- let parsed;
4570
+ });
4571
+ });
4572
+ });
4573
+ return {
4574
+ listenLoopback: async (preferredPort, onSocket) => {
4575
+ if (preferredPort !== void 0) {
4306
4576
  try {
4307
- parsed = JSON.parse(await readBody(request4));
4577
+ return await listenOnce(preferredPort, onSocket);
4308
4578
  } catch {
4309
- answerJson(response, HTTP_STATUS.badRequest, { error: "the interrupt body is not readable JSON within the control body cap" });
4310
- return;
4311
- }
4312
- if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || typeof parsed.session !== "string" || parsed.session === "") {
4313
- answerJson(response, HTTP_STATUS.badRequest, { error: "the interrupt body must be JSON naming a non-empty session id" });
4314
- return;
4315
- }
4316
- const result = await deps.interrupt(parsed.session);
4317
- if (result.ok) {
4318
- answerJson(response, HTTP_STATUS.ok, { session: parsed.session, sequenceNums: result.sequenceNums });
4319
- return;
4320
4579
  }
4321
- answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4322
- return;
4323
4580
  }
4324
- if (url.pathname === setModelPath) {
4325
- if (request4.method !== "POST") {
4326
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the set-model operation is a POST" });
4327
- return;
4581
+ return await listenOnce(0, onSocket);
4582
+ },
4583
+ createTlsAcceptor: (leaf, onSecure, alpnProtocols) => {
4584
+ let pendingContext = "";
4585
+ const server = tls.createServer(
4586
+ { key: leaf.keyPem, cert: leaf.certPem, ...alpnProtocols === void 0 ? {} : { ALPNProtocols: [...alpnProtocols] } },
4587
+ (secure) => {
4588
+ onSecure(secure, pendingContext);
4328
4589
  }
4329
- let parsed;
4330
- try {
4331
- parsed = JSON.parse(await readBody(request4));
4332
- } catch {
4333
- answerJson(response, HTTP_STATUS.badRequest, { error: "the set-model body is not readable JSON within the control body cap" });
4334
- return;
4590
+ );
4591
+ server.on("clientError", (_error, socket) => {
4592
+ socket.destroy();
4593
+ });
4594
+ return {
4595
+ // tls.Server is a net.Server whose connection listener wraps the raw socket in the TLS handshake, and emitting the event by hand is what runs that listener on a socket this process already owns (the CONNECT half of the connection) rather than one the server accepted itself.
4596
+ accept: (socket, context) => {
4597
+ pendingContext = context;
4598
+ server.emit("connection", socket);
4599
+ },
4600
+ close: () => {
4601
+ server.close();
4335
4602
  }
4336
- if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("model" in parsed) || typeof parsed.session !== "string" || typeof parsed.model !== "string" || parsed.session === "" || parsed.model === "") {
4337
- answerJson(response, HTTP_STATUS.badRequest, { error: "the set-model body must be JSON naming a non-empty session id and model id" });
4338
- return;
4603
+ };
4604
+ },
4605
+ createSniTlsAcceptor: (hosts, leafFor, onSecure) => {
4606
+ const contexts = new Map(
4607
+ hosts.map((host) => {
4608
+ const leaf = leafFor(host);
4609
+ return [host, tls.createSecureContext({ key: leaf.keyPem, cert: leaf.certPem })];
4610
+ })
4611
+ );
4612
+ const server = tls.createServer(
4613
+ {
4614
+ // No default key or cert exists, so the SNI selection is the only source of credentials: an unserved name fails its handshake here, and a client that sent no SNI at all never reaches the selection and fails for want of any certificate, which is exactly the fail-closed shape this surface wants.
4615
+ SNICallback: (servername, callback) => {
4616
+ const context = contexts.get(servername);
4617
+ callback(context === void 0 ? new Error(`the transparent surface serves no host named ${servername}`) : null, context);
4618
+ }
4619
+ },
4620
+ (secure) => {
4621
+ onSecure(secure, typeof secure.servername === "string" ? secure.servername : "");
4339
4622
  }
4340
- const result = await deps.setModel(parsed.session, parsed.model);
4341
- if (result.ok) {
4342
- answerJson(response, HTTP_STATUS.ok, { session: parsed.session, model: parsed.model, sequenceNums: result.sequenceNums });
4343
- return;
4623
+ );
4624
+ server.on("clientError", (_error, socket) => {
4625
+ socket.destroy();
4626
+ });
4627
+ return {
4628
+ // The same hand-off the single-leaf acceptor uses: emitting the connection event runs the TLS server's own connection listener on a socket this process already owns (the redirect half of the connection) rather than one the server accepted itself.
4629
+ accept: (socket) => {
4630
+ server.emit("connection", socket);
4631
+ },
4632
+ close: () => {
4633
+ server.close();
4344
4634
  }
4345
- answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4346
- return;
4635
+ };
4636
+ },
4637
+ createHttpSession: (handler, onUpgrade) => {
4638
+ const server = http.createServer(handler);
4639
+ server.on("clientError", (_error, socket) => {
4640
+ socket.destroy();
4641
+ });
4642
+ if (onUpgrade !== void 0) {
4643
+ server.on("upgrade", (request4, socket, head) => {
4644
+ onUpgrade(request4, socket, head);
4645
+ });
4347
4646
  }
4348
- if (url.pathname === setPermissionModePath) {
4349
- if (request4.method !== "POST") {
4350
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the set-permission-mode operation is a POST" });
4351
- return;
4647
+ return {
4648
+ serve: (socket) => {
4649
+ server.emit("connection", socket);
4650
+ },
4651
+ close: () => {
4652
+ server.close();
4653
+ server.closeAllConnections();
4352
4654
  }
4353
- let parsed;
4354
- try {
4355
- parsed = JSON.parse(await readBody(request4));
4356
- } catch {
4357
- answerJson(response, HTTP_STATUS.badRequest, { error: "the set-permission-mode body is not readable JSON within the control body cap" });
4358
- return;
4655
+ };
4656
+ },
4657
+ connectTlsUpstream: async (host, port, clientAlpn) => {
4658
+ const dialled = await reservedDial({ host, port });
4659
+ if (dialled.error !== null) {
4660
+ throw dialled.error;
4661
+ }
4662
+ return await new Promise((resolve, reject) => {
4663
+ const secure = tls.connect({ socket: dialled.socket, servername: host, ...clientAlpn === void 0 ? {} : { ALPNProtocols: [clientAlpn] } });
4664
+ secure.once("secureConnect", () => {
4665
+ resolve(secure);
4666
+ });
4667
+ secure.once("error", reject);
4668
+ });
4669
+ },
4670
+ connectTcp: async (host, port) => await new Promise((resolve, reject) => {
4671
+ const socket = net2.connect({ host, port });
4672
+ socket.once("connect", () => {
4673
+ resolve(socket);
4674
+ });
4675
+ socket.once("error", reject);
4676
+ }),
4677
+ forwardHttp: (target, request4, response, observer) => {
4678
+ const headers = forwardableHeaders(request4.headers);
4679
+ const options = {
4680
+ host: target.host,
4681
+ port: target.port,
4682
+ lookup: realAddressLookup,
4683
+ method: request4.method,
4684
+ path: request4.url,
4685
+ headers,
4686
+ agent: target.tls ? tlsAgent : plainAgent
4687
+ };
4688
+ if (target.tls) {
4689
+ options.servername = target.servername ?? target.host;
4690
+ if (target.ca !== void 0) {
4691
+ options.ca = [...target.ca];
4359
4692
  }
4360
- if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("mode" in parsed) || typeof parsed.session !== "string" || parsed.session === "" || !isRcPermissionMode(parsed.mode)) {
4361
- answerJson(response, HTTP_STATUS.badRequest, { error: `the set-permission-mode body must be JSON naming a non-empty session id and a mode the SDK's own type permits (${RC_PERMISSION_MODE_LIST})` });
4362
- return;
4693
+ if (target.rejectUnauthorized !== void 0) {
4694
+ options.rejectUnauthorized = target.rejectUnauthorized;
4363
4695
  }
4364
- const result = await deps.setPermissionMode(parsed.session, parsed.mode);
4365
- if (result.ok) {
4366
- answerJson(response, HTTP_STATUS.ok, { session: parsed.session, mode: parsed.mode, sequenceNums: result.sequenceNums });
4696
+ }
4697
+ const onUpstreamResponse = (upstreamResponse) => {
4698
+ observer?.onResponse(upstreamResponse.statusCode ?? HTTP_BAD_GATEWAY, upstreamResponse.headers);
4699
+ response.writeHead(upstreamResponse.statusCode ?? HTTP_BAD_GATEWAY, forwardableHeaders(upstreamResponse.headers));
4700
+ response.flushHeaders();
4701
+ if (observer !== void 0) {
4702
+ upstreamResponse.on("data", (chunk) => {
4703
+ observer.onResponseChunk(chunk);
4704
+ });
4705
+ }
4706
+ upstreamResponse.pipe(response);
4707
+ };
4708
+ const upstream = target.tls ? https2.request(options, onUpstreamResponse) : http.request(options, onUpstreamResponse);
4709
+ upstream.on("error", (error) => {
4710
+ if (response.headersSent) {
4711
+ response.destroy(error);
4367
4712
  return;
4368
4713
  }
4369
- answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4370
- return;
4714
+ const body = `agent-shim headroom: upstream unreachable (${error.message})`;
4715
+ response.writeHead(HTTP_BAD_GATEWAY, { "content-type": "text/plain", "content-length": String(body.length) });
4716
+ response.end(body);
4717
+ });
4718
+ if (observer !== void 0) {
4719
+ request4.on("data", (chunk) => {
4720
+ observer.onRequestChunk(chunk);
4721
+ });
4722
+ if (observer.onRequestEnd !== void 0) {
4723
+ request4.on("end", () => {
4724
+ observer.onRequestEnd?.();
4725
+ });
4726
+ }
4727
+ response.on("close", () => {
4728
+ observer.onEnd();
4729
+ });
4371
4730
  }
4372
- answerJson(response, HTTP_STATUS.notFound, { error: `no such control route: ${url.pathname}` });
4373
- };
4374
- handle().catch((error) => {
4375
- answerJson(response, HTTP_STATUS.internalServerError, { error: `the control route failed: ${error instanceof Error ? error.message : String(error)}` });
4376
- });
4731
+ request4.pipe(upstream);
4732
+ request4.socket.setNoDelay(true);
4733
+ upstream.on("socket", (socket) => {
4734
+ socket.setNoDelay(true);
4735
+ });
4736
+ }
4377
4737
  };
4378
4738
  }
4379
- function realRcControlTransport(port, ca) {
4380
- return {
4381
- request: async (options) => await new Promise((resolve, reject) => {
4382
- const request4 = https2.request(
4383
- {
4384
- host: "127.0.0.1",
4385
- port,
4386
- method: options.method,
4387
- path: options.path,
4388
- headers: options.body === void 0 ? options.headers : { ...options.headers, "content-length": String(Buffer.byteLength(options.body, "utf8")) },
4389
- agent: false,
4390
- ca: [ca]
4391
- },
4392
- (response) => {
4393
- const chunks = [];
4394
- response.on("data", (chunk) => {
4395
- chunks.push(chunk);
4396
- });
4397
- response.on("end", () => {
4398
- resolve({ status: response.statusCode ?? 0, body: Buffer.concat(chunks).toString("utf8") });
4399
- });
4739
+
4740
+ // src/frontdoor/rcApi.ts
4741
+ var import_client = require("@orpc/client");
4742
+ var import_fetch = require("@orpc/client/fetch");
4743
+ var import_server2 = require("@orpc/server");
4744
+ var import_node = require("@orpc/server/node");
4745
+ var import_undici = require("undici");
4746
+
4747
+ // src/frontdoor/rcSchemas.ts
4748
+ var import_zod4 = require("zod");
4749
+ var RcPermissionModeSchema = import_zod4.z.enum(RC_PERMISSION_MODES);
4750
+ var RcSessionSummarySchema = import_zod4.z.strictObject({
4751
+ id: import_zod4.z.string(),
4752
+ createdAt: import_zod4.z.number(),
4753
+ lastSeenAt: import_zod4.z.number()
4754
+ });
4755
+ function workerFactSchema(value) {
4756
+ return import_zod4.z.strictObject({ value, observedAt: import_zod4.z.number() });
4757
+ }
4758
+ var RcPendingRequestSummarySchema = import_zod4.z.strictObject({
4759
+ sessionId: import_zod4.z.string(),
4760
+ requestId: import_zod4.z.string(),
4761
+ type: import_zod4.z.string(),
4762
+ summary: import_zod4.z.string(),
4763
+ observedAt: import_zod4.z.number()
4764
+ });
4765
+ var RcSessionStatusSchema = import_zod4.z.strictObject({
4766
+ ...RcSessionSummarySchema.shape,
4767
+ workerState: workerFactSchema(import_zod4.z.string()).optional(),
4768
+ workerIdleSeconds: workerFactSchema(import_zod4.z.number()).optional(),
4769
+ pending: import_zod4.z.readonly(import_zod4.z.array(RcPendingRequestSummarySchema))
4770
+ });
4771
+ var RcStreamEnvelopeSchema = import_zod4.z.looseObject({
4772
+ /** The envelope's own event id, when the host sent one. */
4773
+ event_id: import_zod4.z.string().optional(),
4774
+ /** The envelope's event type, the discriminator a consumer switches on (`control_request`, `user`, and kin). */
4775
+ event_type: import_zod4.z.string(),
4776
+ /** The sequence number the host assigned, the value a resume continues after. */
4777
+ sequence_num: import_zod4.z.int(),
4778
+ /** Who emitted the event (`worker` for the CLI's half, a client id for a client's). */
4779
+ source: import_zod4.z.string(),
4780
+ /** The event's payload, carried verbatim: its shape is the payload family's, narrowed by whichever consumer needs it. Optional in the schema's own type because the door forwards the host's envelope as it arrived, asserting only the fields it relies on itself. */
4781
+ payload: import_zod4.z.unknown().optional(),
4782
+ /** When the host created the event; the protocol's own type for this field is not established here, so it is forwarded rather than asserted. */
4783
+ created_at: import_zod4.z.unknown().optional()
4784
+ });
4785
+ var RcStreamEventSchema = import_zod4.z.strictObject({
4786
+ session: import_zod4.z.string(),
4787
+ envelope: RcStreamEnvelopeSchema
4788
+ });
4789
+ var RcSessionQuerySchema = import_zod4.z.strictObject({
4790
+ session: import_zod4.z.string().min(1).optional()
4791
+ });
4792
+ var RcSendInputSchema = import_zod4.z.strictObject({
4793
+ session: import_zod4.z.string().min(1),
4794
+ text: import_zod4.z.string().min(1)
4795
+ });
4796
+ var RcAnswerInputSchema = import_zod4.z.strictObject({
4797
+ session: import_zod4.z.string().min(1),
4798
+ request: import_zod4.z.string().min(1),
4799
+ approve: import_zod4.z.boolean(),
4800
+ text: import_zod4.z.string().optional()
4801
+ }).refine((input) => !input.approve || input.text === void 0 || input.text === "", { message: "an approval carries no text (the protocol's allow result has no message field); text is the denial message" });
4802
+ var RcInterruptInputSchema = import_zod4.z.strictObject({
4803
+ session: import_zod4.z.string().min(1)
4804
+ });
4805
+ var RcSetModelInputSchema = import_zod4.z.strictObject({
4806
+ session: import_zod4.z.string().min(1),
4807
+ model: import_zod4.z.string().min(1)
4808
+ });
4809
+ var RcSetPermissionModeInputSchema = import_zod4.z.strictObject({
4810
+ session: import_zod4.z.string().min(1),
4811
+ mode: RcPermissionModeSchema
4812
+ });
4813
+ var RcListOutputSchema = import_zod4.z.strictObject({ sessions: import_zod4.z.readonly(import_zod4.z.array(RcSessionSummarySchema)) });
4814
+ var RcStatusOutputSchema = import_zod4.z.strictObject({ statuses: import_zod4.z.readonly(import_zod4.z.array(RcSessionStatusSchema)) });
4815
+ var RcPendingOutputSchema = import_zod4.z.strictObject({ pending: import_zod4.z.readonly(import_zod4.z.array(RcPendingRequestSummarySchema)) });
4816
+ var RcWriteOutputSchema = import_zod4.z.strictObject({
4817
+ session: import_zod4.z.string(),
4818
+ sequenceNums: import_zod4.z.readonly(import_zod4.z.array(import_zod4.z.number()))
4819
+ });
4820
+ var RcAnswerOutputSchema = import_zod4.z.strictObject({
4821
+ session: import_zod4.z.string(),
4822
+ request: import_zod4.z.string(),
4823
+ sequenceNums: import_zod4.z.readonly(import_zod4.z.array(import_zod4.z.number()))
4824
+ });
4825
+
4826
+ // src/frontdoor/rcApi.ts
4827
+ var RC_ORPC_PATH_PREFIX = "/__agent-shim/orpc";
4828
+ var RC_SUBSCRIBER_BUFFER_EVENTS = 100;
4829
+ function createRcApiRouter(deps) {
4830
+ const authed = import_server2.os.$context().use(({ context, next }) => {
4831
+ const presented = context.headers.authorization;
4832
+ const bearerPrefix = "bearer ".length;
4833
+ const token = typeof presented === "string" && presented.slice(0, bearerPrefix).toLowerCase() === "bearer " ? presented.slice(bearerPrefix) : void 0;
4834
+ if (token === void 0 || !isLiveCapability(token, [deps.expectedToken])) {
4835
+ throw new import_client.ORPCError("UNAUTHORIZED", { message: "the front door's typed API demands this generation's control token as a Bearer credential" });
4836
+ }
4837
+ return next();
4838
+ });
4839
+ const delivered = (sessionId, result) => {
4840
+ if (!result.ok) {
4841
+ throw new import_client.ORPCError("BAD_GATEWAY", { message: result.message });
4842
+ }
4843
+ return result.sequenceNums;
4844
+ };
4845
+ return {
4846
+ rc: {
4847
+ list: authed.output(RcListOutputSchema).handler(() => ({ sessions: deps.list() })),
4848
+ status: authed.input(RcSessionQuerySchema).output(RcStatusOutputSchema).handler(({ input }) => {
4849
+ const statuses = deps.statusOf(input.session);
4850
+ if (input.session !== void 0 && !statuses.some((entry) => entry.id === input.session)) {
4851
+ throw new import_client.ORPCError("NOT_FOUND", { message: rcSessionNotObservedMessage(input.session) });
4400
4852
  }
4401
- );
4402
- request4.once("error", reject);
4403
- if (options.body === void 0) {
4404
- request4.end();
4405
- } else {
4406
- request4.end(options.body);
4407
- }
4408
- })
4853
+ return { statuses };
4854
+ }),
4855
+ pending: authed.input(RcSessionQuerySchema).output(RcPendingOutputSchema).handler(({ input }) => {
4856
+ const pending = deps.pendingOf(input.session);
4857
+ if (input.session !== void 0 && deps.statusOf(input.session).length === 0) {
4858
+ throw new import_client.ORPCError("NOT_FOUND", { message: rcSessionNotObservedMessage(input.session) });
4859
+ }
4860
+ return { pending };
4861
+ }),
4862
+ send: authed.input(RcSendInputSchema).output(RcWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, sequenceNums: delivered(input.session, await deps.inject(input.session, input.text)) })),
4863
+ answer: authed.input(RcAnswerInputSchema).output(RcAnswerOutputSchema).handler(async ({ input }) => {
4864
+ const decision = { approve: input.approve, message: input.approve || input.text === void 0 ? void 0 : input.text };
4865
+ return { session: input.session, request: input.request, sequenceNums: delivered(input.session, await deps.answer(input.session, input.request, decision)) };
4866
+ }),
4867
+ interrupt: authed.input(RcInterruptInputSchema).output(RcWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, sequenceNums: delivered(input.session, await deps.interrupt(input.session)) })),
4868
+ setModel: authed.input(RcSetModelInputSchema).output(RcWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, sequenceNums: delivered(input.session, await deps.setModel(input.session, input.model)) })),
4869
+ setPermissionMode: authed.input(RcSetPermissionModeInputSchema).output(RcWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, sequenceNums: delivered(input.session, await deps.setPermissionMode(input.session, input.mode)) })),
4870
+ subscribe: authed.input(RcSessionQuerySchema).output((0, import_server2.eventIterator)(RcStreamEventSchema)).handler(async function* ({ input, signal }) {
4871
+ const queue = [];
4872
+ let wake;
4873
+ const detach = deps.fanout.subscribe(input.session, (event) => {
4874
+ if (queue.length >= RC_SUBSCRIBER_BUFFER_EVENTS) {
4875
+ queue.shift();
4876
+ }
4877
+ queue.push(event);
4878
+ wake?.();
4879
+ });
4880
+ const ended = new Promise((resolve) => {
4881
+ signal?.addEventListener("abort", () => {
4882
+ resolve();
4883
+ }, { once: true });
4884
+ });
4885
+ try {
4886
+ for (; ; ) {
4887
+ signal?.throwIfAborted();
4888
+ const event = queue.shift();
4889
+ if (event !== void 0) {
4890
+ yield (0, import_server2.withEventMeta)(event, { id: String(event.envelope.sequence_num) });
4891
+ continue;
4892
+ }
4893
+ await Promise.race([
4894
+ new Promise((resolve) => {
4895
+ wake = resolve;
4896
+ }),
4897
+ ended
4898
+ ]);
4899
+ }
4900
+ } finally {
4901
+ detach();
4902
+ }
4903
+ })
4904
+ }
4409
4905
  };
4410
4906
  }
4411
- function controlErrorOf(body) {
4412
- try {
4413
- const parsed = JSON.parse(body);
4414
- if (typeof parsed === "object" && parsed !== null && "error" in parsed && typeof parsed.error === "string") {
4415
- return parsed.error;
4907
+ function createRcApiNodeHandler(deps) {
4908
+ const handler = new import_node.RPCHandler(createRcApiRouter(deps), { plugins: [new import_node.BodyLimitPlugin({ maxBodySize: CONTROL_BODY_CAP_BYTES })] });
4909
+ return {
4910
+ pathPrefix: RC_ORPC_PATH_PREFIX,
4911
+ handle: async (request4, response) => await handler.handle(request4, response, { context: { headers: request4.headers }, prefix: RC_ORPC_PATH_PREFIX })
4912
+ };
4913
+ }
4914
+ function frontDoorRcApiClient(port, ca, token) {
4915
+ const dispatcher = new import_undici.Agent({ connect: { ca } });
4916
+ const link = new import_fetch.RPCLink({
4917
+ url: `https://127.0.0.1:${String(port)}${RC_ORPC_PATH_PREFIX}`,
4918
+ headers: { authorization: `Bearer ${token}` },
4919
+ // undici's own Request and Response types and the global ones are distinct declarations of the same standard shapes (the package's bundled types sit beside @types/node's own), and its fetch refuses the global Request instance outright, so the call is rebuilt from the request's parts and the answer re-wrapped through the global constructors, never cast between the two. The request body is one bounded JSON object (the same protocol cap the handler enforces), so reading it whole costs nothing; it is the answer that streams.
4920
+ fetch: async (request4, _init, options) => {
4921
+ const body = request4.body === null ? void 0 : Buffer.from(await request4.arrayBuffer());
4922
+ const answered = await (0, import_undici.fetch)(request4.url, {
4923
+ method: request4.method,
4924
+ headers: [...request4.headers],
4925
+ ...body === void 0 ? {} : { body },
4926
+ dispatcher,
4927
+ ...options.signal === void 0 ? {} : { signal: options.signal }
4928
+ });
4929
+ return new Response(answered.body, { status: answered.status, statusText: answered.statusText, headers: [...answered.headers] });
4416
4930
  }
4417
- } catch {
4418
- return body;
4419
- }
4420
- return void 0;
4931
+ });
4932
+ return (0, import_client.createORPCClient)(link);
4421
4933
  }
4422
- function isRcSessionSummary(value) {
4423
- if (typeof value !== "object" || value === null) {
4424
- return false;
4425
- }
4426
- if (!("id" in value) || !("createdAt" in value) || !("lastSeenAt" in value)) {
4427
- return false;
4428
- }
4429
- return typeof value.id === "string" && typeof value.createdAt === "number" && typeof value.lastSeenAt === "number";
4934
+
4935
+ // src/frontdoor/rcStream.ts
4936
+ var RC_STREAM_EVENT_NAME = "client_event";
4937
+ var SSE_BYTE_ORDER_MARK = 65279;
4938
+ var RC_STREAM_BACKOFF_MS = 45e3;
4939
+ var SUCCESS_STATUS_MAX_EXCLUSIVE3 = 300;
4940
+ function isSuccessful3(status) {
4941
+ return status >= HTTP_STATUS.ok && status < SUCCESS_STATUS_MAX_EXCLUSIVE3;
4942
+ }
4943
+ function createSseParser() {
4944
+ let buffer = "";
4945
+ let eventName;
4946
+ let eventId;
4947
+ let dataLines = [];
4948
+ let seenAnyText = false;
4949
+ return {
4950
+ write: (text) => {
4951
+ let incoming = text;
4952
+ if (!seenAnyText) {
4953
+ seenAnyText = true;
4954
+ incoming = incoming.charCodeAt(0) === SSE_BYTE_ORDER_MARK ? incoming.slice(1) : incoming;
4955
+ }
4956
+ buffer += incoming;
4957
+ const completed = [];
4958
+ for (; ; ) {
4959
+ const carriage = buffer.indexOf("\r");
4960
+ const lineFeed = buffer.indexOf("\n");
4961
+ const end = carriage === -1 ? lineFeed : lineFeed === -1 ? carriage : carriage < lineFeed ? carriage : lineFeed;
4962
+ if (end === -1) {
4963
+ break;
4964
+ }
4965
+ if (buffer[end] === "\r" && end === buffer.length - 1) {
4966
+ break;
4967
+ }
4968
+ const after = buffer[end] === "\r" && buffer[end + 1] === "\n" ? end + 2 : end + 1;
4969
+ const line = buffer.slice(0, end);
4970
+ buffer = buffer.slice(after);
4971
+ if (line === "") {
4972
+ if (dataLines.length > 0) {
4973
+ completed.push({ event: eventName, id: eventId, data: dataLines.join("\n") });
4974
+ }
4975
+ eventName = void 0;
4976
+ dataLines = [];
4977
+ continue;
4978
+ }
4979
+ if (line.startsWith(":")) {
4980
+ continue;
4981
+ }
4982
+ const colon = line.indexOf(":");
4983
+ const field = colon === -1 ? line : line.slice(0, colon);
4984
+ const value = colon === -1 ? "" : line.slice(colon + 1).replace(/^ /, "");
4985
+ if (field === "event") {
4986
+ eventName = value;
4987
+ } else if (field === "data") {
4988
+ dataLines.push(value);
4989
+ } else if (field === "id") {
4990
+ eventId = value;
4991
+ }
4992
+ }
4993
+ return completed;
4994
+ }
4995
+ };
4430
4996
  }
4431
- function isRcWorkerFact(value, valueIs) {
4432
- if (typeof value !== "object" || value === null) {
4433
- return false;
4434
- }
4435
- if (!("value" in value) || !("observedAt" in value)) {
4436
- return false;
4437
- }
4438
- return valueIs(value.value) && typeof value.observedAt === "number";
4997
+ function isRecord3(value) {
4998
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4439
4999
  }
4440
- function isRcSessionStatus(value) {
4441
- if (!isRcSessionSummary(value)) {
4442
- return false;
4443
- }
4444
- if (!("pending" in value) || !Array.isArray(value.pending)) {
4445
- return false;
4446
- }
4447
- if ("workerState" in value && value.workerState !== void 0 && !isRcWorkerFact(value.workerState, (candidate) => typeof candidate === "string")) {
4448
- return false;
5000
+ function sequenceNumOf(value) {
5001
+ if (typeof value === "number" && Number.isFinite(value) && Number.isInteger(value)) {
5002
+ return value;
4449
5003
  }
4450
- if ("workerIdleSeconds" in value && value.workerIdleSeconds !== void 0 && !isRcWorkerFact(value.workerIdleSeconds, (candidate) => typeof candidate === "number")) {
4451
- return false;
5004
+ if (typeof value === "string" && /^[0-9]+$/.test(value)) {
5005
+ return Number(value);
4452
5006
  }
4453
- return value.pending.every((candidate) => isRcPendingRequestSummary(candidate));
5007
+ return void 0;
4454
5008
  }
4455
- function isRcPendingRequestSummary(value) {
4456
- if (typeof value !== "object" || value === null) {
4457
- return false;
4458
- }
4459
- if (!("sessionId" in value) || !("requestId" in value) || !("type" in value) || !("summary" in value) || !("observedAt" in value)) {
4460
- return false;
5009
+ function parseRcStreamEnvelope(parsed) {
5010
+ if (parsed.event !== RC_STREAM_EVENT_NAME) {
5011
+ return void 0;
4461
5012
  }
4462
- return typeof value.sessionId === "string" && typeof value.requestId === "string" && typeof value.type === "string" && typeof value.summary === "string" && typeof value.observedAt === "number";
4463
- }
4464
- function sequenceNumsOfBody(body) {
4465
- let parsed;
5013
+ let data;
4466
5014
  try {
4467
- parsed = JSON.parse(body);
5015
+ data = JSON.parse(parsed.data);
4468
5016
  } catch {
4469
5017
  return void 0;
4470
5018
  }
4471
- if (typeof parsed !== "object" || parsed === null || !("sequenceNums" in parsed) || !Array.isArray(parsed.sequenceNums)) {
5019
+ if (!isRecord3(data)) {
4472
5020
  return void 0;
4473
5021
  }
4474
- const sequenceNums = [];
4475
- const values = parsed.sequenceNums;
4476
- for (const value of values) {
4477
- if (typeof value !== "number") {
4478
- return void 0;
4479
- }
4480
- sequenceNums.push(value);
5022
+ const eventType = data.event_type;
5023
+ const sequenceNum = sequenceNumOf(data.sequence_num);
5024
+ const source = data.source;
5025
+ if (typeof eventType !== "string" || sequenceNum === void 0 || typeof source !== "string") {
5026
+ return void 0;
4481
5027
  }
4482
- return sequenceNums;
5028
+ return { ...data, event_type: eventType, sequence_num: sequenceNum, source };
4483
5029
  }
4484
- function frontDoorRcControl(transport, token) {
4485
- const headers = { authorization: `Bearer ${token}` };
4486
- const listAnswerOf = async (path29, what) => {
4487
- try {
4488
- return await transport.request({ method: "GET", path: path29, headers });
4489
- } catch (error) {
4490
- throw new Error(`${what}: could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
5030
+ function createRcEventFanout() {
5031
+ const perSession = /* @__PURE__ */ new Map();
5032
+ const every = /* @__PURE__ */ new Set();
5033
+ return {
5034
+ publish: (event) => {
5035
+ for (const listener of every) {
5036
+ listener(event);
5037
+ }
5038
+ for (const listener of perSession.get(event.session) ?? []) {
5039
+ listener(event);
5040
+ }
5041
+ },
5042
+ subscribe: (session, listener) => {
5043
+ if (session === void 0) {
5044
+ every.add(listener);
5045
+ return () => {
5046
+ every.delete(listener);
5047
+ };
5048
+ }
5049
+ const listeners = perSession.get(session) ?? /* @__PURE__ */ new Set();
5050
+ perSession.set(session, listeners);
5051
+ listeners.add(listener);
5052
+ return () => {
5053
+ listeners.delete(listener);
5054
+ if (listeners.size === 0) {
5055
+ perSession.delete(session);
5056
+ }
5057
+ };
4491
5058
  }
4492
5059
  };
4493
- const sessionsOf = (answer, what) => {
4494
- if (answer.status !== HTTP_STATUS.ok) {
4495
- throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
4496
- }
4497
- let parsed;
4498
- try {
4499
- parsed = JSON.parse(answer.body);
4500
- } catch {
4501
- throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
4502
- }
4503
- if (typeof parsed !== "object" || parsed === null || !("sessions" in parsed) || !Array.isArray(parsed.sessions)) {
4504
- throw new Error(`${what}: the door's answer named no sessions list: ${answer.body}`);
4505
- }
4506
- const candidates = parsed.sessions;
4507
- const sessions = [];
4508
- for (const value of candidates) {
4509
- if (!isRcSessionSummary(value)) {
4510
- throw new Error(`${what}: the door's answer named no sessions list: ${answer.body}`);
5060
+ }
5061
+ function createRcStreamHub(deps) {
5062
+ const attachments = /* @__PURE__ */ new Map();
5063
+ const birth = (sessionId) => {
5064
+ const controller = new AbortController();
5065
+ let stopped = false;
5066
+ return {
5067
+ sessionId,
5068
+ clientId: deps.newClientId(),
5069
+ controller,
5070
+ isStopped: () => stopped,
5071
+ stop: () => {
5072
+ stopped = true;
5073
+ controller.abort();
4511
5074
  }
4512
- sessions.push(value);
4513
- }
4514
- return sessions;
5075
+ };
4515
5076
  };
4516
- const statusesOf = (answer, what) => {
4517
- if (answer.status !== HTTP_STATUS.ok) {
4518
- throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
5077
+ const streamHeaders = (credential) => {
5078
+ const headers = { accept: "text/event-stream" };
5079
+ if (credential.authorization !== void 0) {
5080
+ headers.authorization = credential.authorization;
4519
5081
  }
4520
- let parsed;
4521
- try {
4522
- parsed = JSON.parse(answer.body);
4523
- } catch {
4524
- throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
4525
- }
4526
- if (typeof parsed !== "object" || parsed === null || !("statuses" in parsed) || !Array.isArray(parsed.statuses)) {
4527
- throw new Error(`${what}: the door's answer named no status list: ${answer.body}`);
5082
+ if (credential.anthropicVersion !== void 0) {
5083
+ headers["anthropic-version"] = credential.anthropicVersion;
4528
5084
  }
4529
- const statuses = [];
4530
- for (const value of parsed.statuses) {
4531
- if (!isRcSessionStatus(value)) {
4532
- throw new Error(`${what}: the door's answer named no status list: ${answer.body}`);
4533
- }
4534
- statuses.push(value);
5085
+ if (credential.anthropicClientPlatform !== void 0) {
5086
+ headers["anthropic-client-platform"] = credential.anthropicClientPlatform;
4535
5087
  }
4536
- return statuses;
5088
+ return headers;
4537
5089
  };
4538
- const pendingOfAnswer = (answer, what) => {
4539
- if (answer.status !== HTTP_STATUS.ok) {
4540
- throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
4541
- }
4542
- let parsed;
4543
- try {
4544
- parsed = JSON.parse(answer.body);
4545
- } catch {
4546
- throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
5090
+ const attempt = async (attachment, credential) => {
5091
+ const headers = streamHeaders(credential);
5092
+ const presence = await deps.dial.announcePresence(attachment.sessionId, headers, attachment.clientId);
5093
+ if (presence.status === HTTP_STATUS.unauthorized) {
5094
+ return "unauthorized";
5095
+ }
5096
+ if (!isSuccessful3(presence.status)) {
5097
+ throw new Error(`the presence call answered HTTP ${String(presence.status)}: ${presence.body}`);
5098
+ }
5099
+ const cursor = deps.sequenceNumOf(attachment.sessionId);
5100
+ const resume = cursor === void 0 ? void 0 : { fromSequenceNum: cursor };
5101
+ const answer = await deps.dial.openStream(attachment.sessionId, headers, resume, attachment.controller.signal);
5102
+ if (answer.status === HTTP_STATUS.unauthorized) {
5103
+ return "unauthorized";
4547
5104
  }
4548
- if (typeof parsed !== "object" || parsed === null || !("pending" in parsed) || !Array.isArray(parsed.pending)) {
4549
- throw new Error(`${what}: the door's answer named no pending list: ${answer.body}`);
5105
+ if (!isSuccessful3(answer.status)) {
5106
+ throw new Error(`the client read stream answered HTTP ${String(answer.status)}`);
4550
5107
  }
4551
- const pending = [];
4552
- for (const value of parsed.pending) {
4553
- if (!isRcPendingRequestSummary(value)) {
4554
- throw new Error(`${what}: the door's answer named no pending list: ${answer.body}`);
5108
+ const parser = createSseParser();
5109
+ for await (const chunk of answer.chunks) {
5110
+ attachment.controller.signal.throwIfAborted();
5111
+ for (const parsed of parser.write(Buffer.from(chunk).toString("utf8"))) {
5112
+ const envelope = parseRcStreamEnvelope(parsed);
5113
+ if (envelope === void 0) {
5114
+ continue;
5115
+ }
5116
+ deps.fileStreamEvent(attachment.sessionId, envelope);
5117
+ deps.fanout.publish({ session: attachment.sessionId, envelope });
4555
5118
  }
4556
- pending.push(value);
4557
5119
  }
4558
- return pending;
5120
+ return "dropped";
4559
5121
  };
4560
- const writeOf = async (path29, body, describeFailure) => {
4561
- let answer;
4562
- try {
4563
- answer = await transport.request({ method: "POST", path: path29, headers: { ...headers, "content-type": "application/json" }, body });
4564
- } catch (error) {
4565
- return { ok: false, message: `could not reach the front door's control listener: ${error instanceof Error ? error.message : String(error)}` };
4566
- }
4567
- if (answer.status === HTTP_STATUS.ok) {
4568
- const sequenceNums = sequenceNumsOfBody(answer.body);
4569
- if (sequenceNums === void 0) {
4570
- return { ok: false, message: `the door accepted the event but its answer named no sequence numbers: ${answer.body}` };
5122
+ const runLoop = async (attachment) => {
5123
+ let retriedUnauthorized = false;
5124
+ for (; ; ) {
5125
+ if (attachment.isStopped()) {
5126
+ return;
4571
5127
  }
4572
- return { ok: true, sequenceNums };
5128
+ const live = deps.trackedSessions().includes(attachment.sessionId);
5129
+ const credential = deps.credentialOf(attachment.sessionId);
5130
+ if (!live || credential?.authorization === void 0) {
5131
+ if (attachments.get(attachment.sessionId) === attachment) {
5132
+ attachments.delete(attachment.sessionId);
5133
+ }
5134
+ return;
5135
+ }
5136
+ let outcome;
5137
+ try {
5138
+ outcome = await attempt(attachment, credential);
5139
+ } catch (error) {
5140
+ if (attachment.isStopped()) {
5141
+ return;
5142
+ }
5143
+ deps.log?.(`rc stream ${attachment.sessionId}: attachment failed (${error instanceof Error ? error.message : String(error)}); backing off`);
5144
+ await deps.sleep(deps.backoffMs);
5145
+ retriedUnauthorized = false;
5146
+ continue;
5147
+ }
5148
+ if (attachment.isStopped()) {
5149
+ return;
5150
+ }
5151
+ if (outcome === "dropped") {
5152
+ retriedUnauthorized = false;
5153
+ continue;
5154
+ }
5155
+ if (!retriedUnauthorized) {
5156
+ retriedUnauthorized = true;
5157
+ continue;
5158
+ }
5159
+ deps.log?.(`rc stream ${attachment.sessionId}: the client read stream refused the observed Authorization bearer past one retry; backing off`);
5160
+ await deps.sleep(deps.backoffMs);
5161
+ retriedUnauthorized = false;
4573
5162
  }
4574
- return { ok: false, message: describeFailure(answer.status, controlErrorOf(answer.body) ?? answer.body) };
4575
5163
  };
4576
- const sessionQuery = (sessionId) => sessionId === void 0 ? "" : `?session=${encodeURIComponent(sessionId)}`;
4577
5164
  return {
4578
- listSessions: async () => sessionsOf(await listAnswerOf(`${CONTROL_PATH_PREFIX}/sessions`, "listing the door's Remote Control sessions"), "listing the door's Remote Control sessions"),
4579
- statusOf: async (sessionId) => statusesOf(await listAnswerOf(`${CONTROL_PATH_PREFIX}/status${sessionQuery(sessionId)}`, "reading the door's Remote Control session status"), "reading the door's Remote Control session status"),
4580
- pendingOf: async (sessionId) => pendingOfAnswer(await listAnswerOf(`${CONTROL_PATH_PREFIX}/pending${sessionQuery(sessionId)}`, "listing the door's pending Remote Control control requests"), "listing the door's pending Remote Control control requests"),
4581
- sendPrompt: async (sessionId, text) => await writeOf(`${CONTROL_PATH_PREFIX}/inject`, JSON.stringify({ session: sessionId, text }), (status, message) => `injecting into ${sessionId} failed (HTTP ${String(status)}): ${message}`),
4582
- answerRequest: async (sessionId, requestId, decision) => await writeOf(
4583
- `${CONTROL_PATH_PREFIX}/answer`,
4584
- JSON.stringify({ session: sessionId, request: requestId, approve: decision.approve, ...decision.approve || decision.message === void 0 ? {} : { text: decision.message } }),
4585
- (status, message) => `answering control request ${requestId} on ${sessionId} failed (HTTP ${String(status)}): ${message}`
4586
- ),
4587
- interruptSession: async (sessionId) => await writeOf(`${CONTROL_PATH_PREFIX}/interrupt`, JSON.stringify({ session: sessionId }), (status, message) => `interrupting ${sessionId} failed (HTTP ${String(status)}): ${message}`),
4588
- setModel: async (sessionId, model) => await writeOf(`${CONTROL_PATH_PREFIX}/set-model`, JSON.stringify({ session: sessionId, model }), (status, message) => `setting the model on ${sessionId} failed (HTTP ${String(status)}): ${message}`),
4589
- setPermissionMode: async (sessionId, mode) => await writeOf(`${CONTROL_PATH_PREFIX}/set-permission-mode`, JSON.stringify({ session: sessionId, mode }), (status, message) => `setting the permission mode on ${sessionId} failed (HTTP ${String(status)}): ${message}`)
5165
+ reconcile: () => {
5166
+ const live = new Set(deps.trackedSessions());
5167
+ for (const [sessionId, attachment] of attachments) {
5168
+ if (!live.has(sessionId)) {
5169
+ attachment.stop();
5170
+ attachments.delete(sessionId);
5171
+ }
5172
+ }
5173
+ for (const sessionId of live) {
5174
+ if (attachments.has(sessionId)) {
5175
+ continue;
5176
+ }
5177
+ if (deps.credentialOf(sessionId)?.authorization === void 0) {
5178
+ continue;
5179
+ }
5180
+ const attachment = birth(sessionId);
5181
+ attachments.set(sessionId, attachment);
5182
+ void runLoop(attachment).catch((error) => {
5183
+ deps.log?.(`rc stream ${sessionId}: the attachment loop ended unexpectedly (${error instanceof Error ? error.message : String(error)})`);
5184
+ });
5185
+ }
5186
+ },
5187
+ close: () => {
5188
+ for (const attachment of attachments.values()) {
5189
+ attachment.stop();
5190
+ }
5191
+ attachments.clear();
5192
+ }
4590
5193
  };
4591
5194
  }
4592
5195
 
@@ -4596,31 +5199,31 @@ var import_node_crypto7 = require("node:crypto");
4596
5199
  // src/headroom/state.ts
4597
5200
  var import_node_crypto6 = require("node:crypto");
4598
5201
  var import_node_path8 = __toESM(require("node:path"), 1);
4599
- var import_zod4 = require("zod");
5202
+ var import_zod5 = require("zod");
4600
5203
  var HEADROOM_ANTHROPIC_UPSTREAM = "https://api.anthropic.com";
4601
5204
  var HEADROOM_STATE_SCHEMA_VERSION = 2;
4602
- var HeadroomStateSchema = import_zod4.z.strictObject({
5205
+ var HeadroomStateSchema = import_zod5.z.strictObject({
4603
5206
  /** The supervisor process owning the daemon. Alive means someone is keeping headroom running. */
4604
- supervisorPid: import_zod4.z.number().int().positive().optional(),
5207
+ supervisorPid: import_zod5.z.number().int().positive().optional(),
4605
5208
  /** The headroom proxy process itself. Absent while the supervisor is between restarts. */
4606
- headroomPid: import_zod4.z.number().int().positive().optional(),
5209
+ headroomPid: import_zod5.z.number().int().positive().optional(),
4607
5210
  /**
4608
5211
  * 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.
4609
5212
  */
4610
- socketPath: import_zod4.z.string().min(1).optional(),
5213
+ socketPath: import_zod5.z.string().min(1).optional(),
4611
5214
  /** The `headroom --version` output of the running install. */
4612
- version: import_zod4.z.string().optional(),
5215
+ version: import_zod5.z.string().optional(),
4613
5216
  /** Hash of the allowlist the running proxy was started with, so a provider-file change is detected as drift. */
4614
- allowlistHash: import_zod4.z.string().optional(),
5217
+ allowlistHash: import_zod5.z.string().optional(),
4615
5218
  /** Hash of the token-saving settings the running proxy was started with, so a settings change is detected as drift. */
4616
- settingsHash: import_zod4.z.string().optional(),
5219
+ settingsHash: import_zod5.z.string().optional(),
4617
5220
  /** The install spec the running install was last installed from, so a `source` config change is detected as drift. */
4618
- installedSource: import_zod4.z.string().optional(),
5221
+ installedSource: import_zod5.z.string().optional(),
4619
5222
  /** The last fatal error, kept across shutdowns so `headroom status` can explain a daemon that is not running. */
4620
- lastError: import_zod4.z.string().optional()
5223
+ lastError: import_zod5.z.string().optional()
4621
5224
  });
4622
- var HeadroomSessionSchema = import_zod4.z.strictObject({ pid: import_zod4.z.number().int().positive(), startedAt: import_zod4.z.number(), supervisorPid: import_zod4.z.number().int().positive() });
4623
- var HeadroomLockSchema = import_zod4.z.strictObject({ pid: import_zod4.z.number().int().positive(), at: import_zod4.z.number() });
5225
+ 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() });
5226
+ var HeadroomLockSchema = import_zod5.z.strictObject({ pid: import_zod5.z.number().int().positive(), at: import_zod5.z.number() });
4624
5227
  function parseJson(raw, schema) {
4625
5228
  if (raw === void 0 || raw.trim() === "") {
4626
5229
  return void 0;
@@ -4800,118 +5403,118 @@ var import_node_path10 = __toESM(require("node:path"), 1);
4800
5403
  var import_node_path9 = __toESM(require("node:path"), 1);
4801
5404
 
4802
5405
  // src/usage/schema.ts
4803
- var import_zod5 = require("zod");
5406
+ var import_zod6 = require("zod");
4804
5407
  var USAGE_SCHEMA_VERSION = 1;
4805
- var VersionSchema = import_zod5.z.literal(USAGE_SCHEMA_VERSION);
4806
- var InstantSchema = import_zod5.z.iso.datetime();
4807
- var TokenCountSchema = import_zod5.z.number().int().nonnegative();
4808
- var TokenUsageSchema = import_zod5.z.strictObject({
5408
+ var VersionSchema = import_zod6.z.literal(USAGE_SCHEMA_VERSION);
5409
+ var InstantSchema = import_zod6.z.iso.datetime();
5410
+ var TokenCountSchema = import_zod6.z.number().int().nonnegative();
5411
+ var TokenUsageSchema = import_zod6.z.strictObject({
4809
5412
  inputTokens: TokenCountSchema.optional(),
4810
5413
  outputTokens: TokenCountSchema.optional(),
4811
5414
  cacheCreationInputTokens: TokenCountSchema.optional(),
4812
5415
  cacheReadInputTokens: TokenCountSchema.optional()
4813
5416
  });
4814
5417
  var LIMIT_KINDS = ["rate-limited", "quota-exhausted"];
4815
- var LimitClassificationSchema = import_zod5.z.strictObject({
4816
- kind: import_zod5.z.enum(LIMIT_KINDS),
5418
+ var LimitClassificationSchema = import_zod6.z.strictObject({
5419
+ kind: import_zod6.z.enum(LIMIT_KINDS),
4817
5420
  /** Seconds to wait before retrying, from the response's `retry-after`. */
4818
- retryAfterSeconds: import_zod5.z.number().nonnegative().optional(),
5421
+ retryAfterSeconds: import_zod6.z.number().nonnegative().optional(),
4819
5422
  /** When the limiting window resets, from the upstream's own reset header. */
4820
5423
  resetAt: InstantSchema.optional(),
4821
5424
  /** The window the upstream named as the binding one (`anthropic-ratelimit-unified-representative-claim`), such as `five_hour` or `seven_day`. */
4822
- window: import_zod5.z.string().optional(),
5425
+ window: import_zod6.z.string().optional(),
4823
5426
  /** 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. */
4824
- evidence: import_zod5.z.array(import_zod5.z.string())
5427
+ evidence: import_zod6.z.array(import_zod6.z.string())
4825
5428
  });
4826
- var UsageRecordSchema = import_zod5.z.strictObject({
5429
+ var UsageRecordSchema = import_zod6.z.strictObject({
4827
5430
  schemaVersion: VersionSchema,
4828
5431
  /** When the front door received the request. */
4829
5432
  at: InstantSchema,
4830
5433
  /** The launching identity, when the launch resolved one. */
4831
- identity: import_zod5.z.string().optional(),
5434
+ identity: import_zod6.z.string().optional(),
4832
5435
  /** `anthropic` for an OAuth session's request to Claude Code's own API, otherwise the provider's name. */
4833
- provider: import_zod5.z.string(),
5436
+ provider: import_zod6.z.string(),
4834
5437
  /** The launch's session id, generated per launch. */
4835
- sessionId: import_zod5.z.string().optional(),
5438
+ sessionId: import_zod6.z.string().optional(),
4836
5439
  /** The project the launch ran in (its git repository root), when the launch sent one: headroom launches do. */
4837
- project: import_zod5.z.string().optional(),
5440
+ project: import_zod6.z.string().optional(),
4838
5441
  /** The front-door route that served the request. */
4839
- route: import_zod5.z.string(),
4840
- method: import_zod5.z.string(),
5442
+ route: import_zod6.z.string(),
5443
+ method: import_zod6.z.string(),
4841
5444
  /** The API path as the upstream sees it (`/v1/messages`), without the provider prefix or a query string. */
4842
- endpoint: import_zod5.z.string(),
5445
+ endpoint: import_zod6.z.string(),
4843
5446
  /** The model the response named. */
4844
- model: import_zod5.z.string().optional(),
4845
- status: import_zod5.z.number().int(),
5447
+ model: import_zod6.z.string().optional(),
5448
+ status: import_zod6.z.number().int(),
4846
5449
  /** Milliseconds from the request's arrival to its response head. */
4847
- latencyMs: import_zod5.z.number().int().nonnegative(),
5450
+ latencyMs: import_zod6.z.number().int().nonnegative(),
4848
5451
  /** Milliseconds from the request's arrival to the end of its response body. */
4849
- durationMs: import_zod5.z.number().int().nonnegative(),
5452
+ durationMs: import_zod6.z.number().int().nonnegative(),
4850
5453
  /** Whether the client received the whole body. */
4851
- outcome: import_zod5.z.enum(["completed", "aborted"]),
5454
+ outcome: import_zod6.z.enum(["completed", "aborted"]),
4852
5455
  usage: TokenUsageSchema.optional(),
4853
5456
  /** The response's quota and rate-limit headers, by name (see `isRateLimitHeader`). */
4854
- rateLimitHeaders: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.string()).optional(),
5457
+ rateLimitHeaders: import_zod6.z.record(import_zod6.z.string(), import_zod6.z.string()).optional(),
4855
5458
  limit: LimitClassificationSchema.optional(),
4856
5459
  /** The upstream's request id (`request-id`), for matching a record to the provider's own logs. */
4857
- requestId: import_zod5.z.string().optional()
5460
+ requestId: import_zod6.z.string().optional()
4858
5461
  });
4859
- var QuotaWindowSchema = import_zod5.z.strictObject({
5462
+ var QuotaWindowSchema = import_zod6.z.strictObject({
4860
5463
  /** The fraction of the window used, as the upstream reports it (0 to 1). */
4861
- utilization: import_zod5.z.number().nonnegative().optional(),
5464
+ utilization: import_zod6.z.number().nonnegative().optional(),
4862
5465
  resetsAt: InstantSchema.optional(),
4863
5466
  /** The window's own status (`allowed`, `allowed_warning`, `rejected`). */
4864
- status: import_zod5.z.string().optional()
5467
+ status: import_zod6.z.string().optional()
4865
5468
  });
4866
- var UnifiedRateLimitSchema = import_zod5.z.strictObject({
5469
+ var UnifiedRateLimitSchema = import_zod6.z.strictObject({
4867
5470
  /** The overall status: `allowed`, `allowed_warning` or `rejected`. */
4868
- status: import_zod5.z.string().optional(),
5471
+ status: import_zod6.z.string().optional(),
4869
5472
  fiveHour: QuotaWindowSchema.optional(),
4870
5473
  sevenDay: QuotaWindowSchema.optional(),
4871
5474
  /** The window that currently binds. */
4872
- representativeClaim: import_zod5.z.string().optional(),
5475
+ representativeClaim: import_zod6.z.string().optional(),
4873
5476
  /** When the binding window resets. */
4874
5477
  resetAt: InstantSchema.optional(),
4875
5478
  /** Whether usage beyond the plan (extra usage) is available: `allowed` or `rejected`. */
4876
- overageStatus: import_zod5.z.string().optional()
5479
+ overageStatus: import_zod6.z.string().optional()
4877
5480
  });
4878
- var RateLimitStateSchema = import_zod5.z.strictObject({
5481
+ var RateLimitStateSchema = import_zod6.z.strictObject({
4879
5482
  observedAt: InstantSchema,
4880
5483
  /** Every quota and rate-limit header on that response, by name. */
4881
- headers: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.string()),
5484
+ headers: import_zod6.z.record(import_zod6.z.string(), import_zod6.z.string()),
4882
5485
  unified: UnifiedRateLimitSchema.optional()
4883
5486
  });
4884
5487
  var LimitEventSchema = LimitClassificationSchema.extend({
4885
5488
  observedAt: InstantSchema,
4886
- status: import_zod5.z.number().int()
5489
+ status: import_zod6.z.number().int()
4887
5490
  });
4888
- var ProviderQuotaWindowSchema = import_zod5.z.strictObject({
5491
+ var ProviderQuotaWindowSchema = import_zod6.z.strictObject({
4889
5492
  /** What the window measures, in the provider's terms (`tokens`, `tool-calls`). */
4890
- measures: import_zod5.z.string(),
5493
+ measures: import_zod6.z.string(),
4891
5494
  /** 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. */
4892
- periodMs: import_zod5.z.number().int().positive().optional(),
5495
+ periodMs: import_zod6.z.number().int().positive().optional(),
4893
5496
  /** The provider's own description of the period when `periodMs` could not be derived, such as `unit 4 x 1`. */
4894
- period: import_zod5.z.string().optional(),
5497
+ period: import_zod6.z.string().optional(),
4895
5498
  /** The fraction of the window used (0 to 1). */
4896
- utilization: import_zod5.z.number().nonnegative(),
5499
+ utilization: import_zod6.z.number().nonnegative(),
4897
5500
  resetsAt: InstantSchema.optional(),
4898
5501
  /** Absolute counts, when the provider reports them for this window. */
4899
- limit: import_zod5.z.number().nonnegative().optional(),
4900
- used: import_zod5.z.number().nonnegative().optional(),
4901
- remaining: import_zod5.z.number().nonnegative().optional()
5502
+ limit: import_zod6.z.number().nonnegative().optional(),
5503
+ used: import_zod6.z.number().nonnegative().optional(),
5504
+ remaining: import_zod6.z.number().nonnegative().optional()
4902
5505
  });
4903
- var ProviderQuotaSchema = import_zod5.z.strictObject({
5506
+ var ProviderQuotaSchema = import_zod6.z.strictObject({
4904
5507
  observedAt: InstantSchema,
4905
5508
  /** Which usage endpoint produced it (`z.ai`). */
4906
- source: import_zod5.z.string(),
5509
+ source: import_zod6.z.string(),
4907
5510
  /** The subscription level the endpoint reports, when it does. */
4908
- level: import_zod5.z.string().optional(),
4909
- windows: import_zod5.z.array(ProviderQuotaWindowSchema)
5511
+ level: import_zod6.z.string().optional(),
5512
+ windows: import_zod6.z.array(ProviderQuotaWindowSchema)
4910
5513
  });
4911
- var ProviderUsageStateSchema = import_zod5.z.strictObject({
5514
+ var ProviderUsageStateSchema = import_zod6.z.strictObject({
4912
5515
  lastRequestAt: InstantSchema,
4913
- lastStatus: import_zod5.z.number().int(),
4914
- lastModel: import_zod5.z.string().optional(),
5516
+ lastStatus: import_zod6.z.number().int(),
5517
+ lastModel: import_zod6.z.string().optional(),
4915
5518
  /** The latest rate-limit state, from the last response that carried any rate-limit header. */
4916
5519
  rateLimit: RateLimitStateSchema.optional(),
4917
5520
  /** The latest classified refusal. It stays after later successes, so a reader compares its `resetAt` (or `observedAt` plus `retryAfterSeconds`) with the current time. */
@@ -4919,31 +5522,31 @@ var ProviderUsageStateSchema = import_zod5.z.strictObject({
4919
5522
  /** The latest quota the provider's usage endpoint reported, for providers whose quota is not visible in response headers. */
4920
5523
  quota: ProviderQuotaSchema.optional()
4921
5524
  });
4922
- var AccountMetadataSchema = import_zod5.z.strictObject({
4923
- accountUuid: import_zod5.z.string().optional(),
4924
- emailAddress: import_zod5.z.string().optional(),
4925
- displayName: import_zod5.z.string().optional(),
4926
- organizationUuid: import_zod5.z.string().optional(),
4927
- organizationName: import_zod5.z.string().optional(),
4928
- organizationType: import_zod5.z.string().optional(),
4929
- organizationRole: import_zod5.z.string().optional(),
4930
- workspaceRole: import_zod5.z.string().optional(),
4931
- billingType: import_zod5.z.string().optional(),
4932
- seatTier: import_zod5.z.string().optional(),
4933
- organizationRateLimitTier: import_zod5.z.string().optional(),
4934
- userRateLimitTier: import_zod5.z.string().optional(),
4935
- hasExtraUsageEnabled: import_zod5.z.boolean().optional(),
4936
- subscriptionCreatedAt: import_zod5.z.string().optional(),
4937
- accountCreatedAt: import_zod5.z.string().optional()
5525
+ var AccountMetadataSchema = import_zod6.z.strictObject({
5526
+ accountUuid: import_zod6.z.string().optional(),
5527
+ emailAddress: import_zod6.z.string().optional(),
5528
+ displayName: import_zod6.z.string().optional(),
5529
+ organizationUuid: import_zod6.z.string().optional(),
5530
+ organizationName: import_zod6.z.string().optional(),
5531
+ organizationType: import_zod6.z.string().optional(),
5532
+ organizationRole: import_zod6.z.string().optional(),
5533
+ workspaceRole: import_zod6.z.string().optional(),
5534
+ billingType: import_zod6.z.string().optional(),
5535
+ seatTier: import_zod6.z.string().optional(),
5536
+ organizationRateLimitTier: import_zod6.z.string().optional(),
5537
+ userRateLimitTier: import_zod6.z.string().optional(),
5538
+ hasExtraUsageEnabled: import_zod6.z.boolean().optional(),
5539
+ subscriptionCreatedAt: import_zod6.z.string().optional(),
5540
+ accountCreatedAt: import_zod6.z.string().optional()
4938
5541
  });
4939
- var UsageSnapshotSchema = import_zod5.z.strictObject({
5542
+ var UsageSnapshotSchema = import_zod6.z.strictObject({
4940
5543
  schemaVersion: VersionSchema,
4941
- identity: import_zod5.z.string(),
5544
+ identity: import_zod6.z.string(),
4942
5545
  updatedAt: InstantSchema,
4943
5546
  /** The identity's account metadata as of `updatedAt`. */
4944
5547
  account: AccountMetadataSchema.optional(),
4945
5548
  /** Latest state per provider, keyed by provider name (`anthropic` for OAuth sessions). */
4946
- providers: import_zod5.z.record(import_zod5.z.string(), ProviderUsageStateSchema)
5549
+ providers: import_zod6.z.record(import_zod6.z.string(), ProviderUsageStateSchema)
4947
5550
  });
4948
5551
 
4949
5552
  // src/usage/account.ts
@@ -5147,20 +5750,20 @@ function quotaWarnings(snapshot, provider, nowMs) {
5147
5750
  }
5148
5751
 
5149
5752
  // src/usage/plan.ts
5150
- var import_zod6 = require("zod");
5151
- var PlanClassSchema = import_zod6.z.union([
5152
- import_zod6.z.strictObject({
5153
- kind: import_zod6.z.literal("subscription"),
5753
+ var import_zod7 = require("zod");
5754
+ var PlanClassSchema = import_zod7.z.union([
5755
+ import_zod7.z.strictObject({
5756
+ kind: import_zod7.z.literal("subscription"),
5154
5757
  /** The plan's size as a multiple of the smallest subscription tier (Max 5x is 5, Max 20x is 20). */
5155
- capacity: import_zod6.z.number().positive(),
5758
+ capacity: import_zod7.z.number().positive(),
5156
5759
  /** False when the tier string named no multiplier and no tier this project knows, so `capacity` is the neutral 1 rather than a reading. */
5157
- recognised: import_zod6.z.boolean(),
5760
+ recognised: import_zod7.z.boolean(),
5158
5761
  /** The tier string the classification rests on, when the account had one. */
5159
- tier: import_zod6.z.string().optional()
5762
+ tier: import_zod7.z.string().optional()
5160
5763
  }),
5161
- import_zod6.z.strictObject({
5162
- kind: import_zod6.z.literal("pay-per-use"),
5163
- tier: import_zod6.z.string().optional()
5764
+ import_zod7.z.strictObject({
5765
+ kind: import_zod7.z.literal("pay-per-use"),
5766
+ tier: import_zod7.z.string().optional()
5164
5767
  })
5165
5768
  ]);
5166
5769
  var TIER_MULTIPLIER = /(?:^|_)(\d+)x$/;
@@ -5229,17 +5832,17 @@ function parseUnifiedRateLimit(headers) {
5229
5832
  }
5230
5833
 
5231
5834
  // src/usage/scan.ts
5232
- var import_zod7 = require("zod");
5233
- var AnthropicUsageSchema = import_zod7.z.looseObject({
5234
- input_tokens: import_zod7.z.number().int().nonnegative().nullish(),
5235
- output_tokens: import_zod7.z.number().int().nonnegative().nullish(),
5236
- cache_creation_input_tokens: import_zod7.z.number().int().nonnegative().nullish(),
5237
- cache_read_input_tokens: import_zod7.z.number().int().nonnegative().nullish()
5835
+ var import_zod8 = require("zod");
5836
+ var AnthropicUsageSchema = import_zod8.z.looseObject({
5837
+ input_tokens: import_zod8.z.number().int().nonnegative().nullish(),
5838
+ output_tokens: import_zod8.z.number().int().nonnegative().nullish(),
5839
+ cache_creation_input_tokens: import_zod8.z.number().int().nonnegative().nullish(),
5840
+ cache_read_input_tokens: import_zod8.z.number().int().nonnegative().nullish()
5238
5841
  });
5239
- var ErrorObjectSchema = import_zod7.z.looseObject({
5240
- type: import_zod7.z.string().optional(),
5241
- code: import_zod7.z.union([import_zod7.z.string(), import_zod7.z.number()]).optional(),
5242
- message: import_zod7.z.string().optional()
5842
+ var ErrorObjectSchema = import_zod8.z.looseObject({
5843
+ type: import_zod8.z.string().optional(),
5844
+ code: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.number()]).optional(),
5845
+ message: import_zod8.z.string().optional()
5243
5846
  });
5244
5847
 
5245
5848
  // src/usage/middleware.ts
@@ -5399,7 +6002,7 @@ function rankPool(input) {
5399
6002
 
5400
6003
  // src/usage/poolPick.ts
5401
6004
  var import_node_path11 = __toESM(require("node:path"), 1);
5402
- var import_zod8 = require("zod");
6005
+ var import_zod9 = require("zod");
5403
6006
 
5404
6007
  // src/usage/store.ts
5405
6008
  var DAY_MS2 = 864e5;
@@ -5408,10 +6011,10 @@ var USAGE_RETENTION_MS = DAYS_IN_WEEK * DAY_MS2;
5408
6011
 
5409
6012
  // src/usage/poolPick.ts
5410
6013
  var SCHEMA_VERSION = 1;
5411
- var PickEntrySchema = import_zod8.z.strictObject({ identity: import_zod8.z.string().min(1), at: import_zod8.z.iso.datetime() });
5412
- var PicksFileSchema = import_zod8.z.strictObject({
5413
- schemaVersion: import_zod8.z.literal(SCHEMA_VERSION),
5414
- picks: import_zod8.z.record(import_zod8.z.string().min(1), PickEntrySchema)
6014
+ var PickEntrySchema = import_zod9.z.strictObject({ identity: import_zod9.z.string().min(1), at: import_zod9.z.iso.datetime() });
6015
+ var PicksFileSchema = import_zod9.z.strictObject({
6016
+ schemaVersion: import_zod9.z.literal(SCHEMA_VERSION),
6017
+ picks: import_zod9.z.record(import_zod9.z.string().min(1), PickEntrySchema)
5415
6018
  });
5416
6019
  function errorMessage(error) {
5417
6020
  return error instanceof Error ? error.message : String(error);
@@ -5611,33 +6214,33 @@ function collectPoolPick(params) {
5611
6214
  }
5612
6215
 
5613
6216
  // src/usage/pickReportSchema.ts
5614
- var import_zod9 = require("zod");
5615
- var PoolPickCandidateViewSchema = import_zod9.z.strictObject({
5616
- identity: import_zod9.z.string(),
6217
+ var import_zod10 = require("zod");
6218
+ var PoolPickCandidateViewSchema = import_zod10.z.strictObject({
6219
+ identity: import_zod10.z.string(),
5617
6220
  /** In pick order: `scored` has usable quota data, `unknown` has none, `pay-per-use` bills by use, `ineligible` is refused right now. */
5618
- class: import_zod9.z.enum(["scored", "unknown", "pay-per-use", "ineligible"]),
6221
+ class: import_zod10.z.enum(["scored", "unknown", "pay-per-use", "ineligible"]),
5619
6222
  /** Plan-size-weighted remaining quota per hour until its reset; present for `scored` only. */
5620
- score: import_zod9.z.number().optional(),
6223
+ score: import_zod10.z.number().optional(),
5621
6224
  /** False when the five-hour window would run dry, at the observed pace, before it resets. */
5622
- feasible: import_zod9.z.boolean(),
6225
+ feasible: import_zod10.z.boolean(),
5623
6226
  /** When an `ineligible` member can be used again, as an ISO instant. */
5624
- blockedUntil: import_zod9.z.iso.datetime().optional(),
6227
+ blockedUntil: import_zod10.z.iso.datetime().optional(),
5625
6228
  plan: PlanClassSchema,
5626
6229
  /** The facts behind the class and score, in the order they matter. */
5627
- reasons: import_zod9.z.array(import_zod9.z.string())
6230
+ reasons: import_zod10.z.array(import_zod10.z.string())
5628
6231
  });
5629
- var PoolPickReportSchema = import_zod9.z.strictObject({
5630
- pool: import_zod9.z.string(),
5631
- directory: import_zod9.z.string(),
6232
+ var PoolPickReportSchema = import_zod10.z.strictObject({
6233
+ pool: import_zod10.z.string(),
6234
+ directory: import_zod10.z.string(),
5632
6235
  /** The member a launch would run as, absent when every member is refused. */
5633
- pick: import_zod9.z.string().optional(),
5634
- candidates: import_zod9.z.array(PoolPickCandidateViewSchema),
6236
+ pick: import_zod10.z.string().optional(),
6237
+ candidates: import_zod10.z.array(PoolPickCandidateViewSchema),
5635
6238
  /** Members that name an identity that does not exist; a launch skips them. */
5636
- missing: import_zod9.z.array(import_zod9.z.string()),
6239
+ missing: import_zod10.z.array(import_zod10.z.string()),
5637
6240
  /** When nothing can be picked, the soonest any member returns. */
5638
- earliestReturn: import_zod9.z.strictObject({ identity: import_zod9.z.string(), at: import_zod9.z.iso.datetime() }).optional(),
6241
+ earliestReturn: import_zod10.z.strictObject({ identity: import_zod10.z.string(), at: import_zod10.z.iso.datetime() }).optional(),
5639
6242
  /** Why the last-pick record could not be read, when that is the case. */
5640
- stickyProblem: import_zod9.z.string().optional()
6243
+ stickyProblem: import_zod10.z.string().optional()
5641
6244
  });
5642
6245
 
5643
6246
  // src/headroom/ensure.ts
@@ -5800,10 +6403,10 @@ function pruneStaleHeadroomSockets(fs12, paths, isRunning) {
5800
6403
  }
5801
6404
 
5802
6405
  // src/headroom/source.ts
5803
- var import_zod10 = require("zod");
6406
+ var import_zod11 = require("zod");
5804
6407
  var GIT_SPEC_RE = /git\+[^@\s]+(?:@([^\s#]+))?/;
5805
6408
  var COMMIT_SHA_RE = /^[0-9a-f]{40}$/i;
5806
- var DirectUrlSchema = import_zod10.z.object({ vcs_info: import_zod10.z.object({ commit_id: import_zod10.z.string() }) });
6409
+ var DirectUrlSchema = import_zod11.z.object({ vcs_info: import_zod11.z.object({ commit_id: import_zod11.z.string() }) });
5807
6410
  function isMovingGitSource(spec) {
5808
6411
  const match = GIT_SPEC_RE.exec(spec);
5809
6412
  if (match === null) {
@@ -6517,11 +7120,11 @@ var import_node_fs5 = __toESM(require("node:fs"), 1);
6517
7120
  var import_node_path17 = __toESM(require("node:path"), 1);
6518
7121
 
6519
7122
  // src/credentialCache.ts
6520
- var import_zod11 = require("zod");
7123
+ var import_zod12 = require("zod");
6521
7124
  var MS_PER_UNIT = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
6522
- var CachedCredentialSchema = import_zod11.z.strictObject({
6523
- token: import_zod11.z.string().min(1),
6524
- fetchedAt: import_zod11.z.number().int().nonnegative(),
7125
+ var CachedCredentialSchema = import_zod12.z.strictObject({
7126
+ token: import_zod12.z.string().min(1),
7127
+ fetchedAt: import_zod12.z.number().int().nonnegative(),
6525
7128
  source: CredentialSourceSchema
6526
7129
  });
6527
7130
  function effectiveStore(cache, platform) {
@@ -6787,14 +7390,14 @@ function providerExists(paths, name) {
6787
7390
  var LEGACY_PROVIDER_FIELDS = ["tokenEnv", "tokenCommand", "authScheme"];
6788
7391
  var LEGACY_ENV_CREDENTIAL_KEYS = Object.values(CREDENTIAL_TARGET_VARS);
6789
7392
  var LEGACY_LITERAL_PLACEHOLDER = "<the value of env.ANTHROPIC_AUTH_TOKEN>";
6790
- function isRecord3(value) {
7393
+ function isRecord4(value) {
6791
7394
  return typeof value === "object" && value !== null && !Array.isArray(value);
6792
7395
  }
6793
7396
  function legacyProviderConversion(raw) {
6794
- if (!isRecord3(raw) || "credential" in raw) {
7397
+ if (!isRecord4(raw) || "credential" in raw) {
6795
7398
  return void 0;
6796
7399
  }
6797
- const env = isRecord3(raw.env) ? raw.env : void 0;
7400
+ const env = isRecord4(raw.env) ? raw.env : void 0;
6798
7401
  const legacyEnvKeys = env === void 0 ? [] : Object.keys(env).filter((key) => LEGACY_ENV_CREDENTIAL_KEYS.includes(key));
6799
7402
  const fields = [...LEGACY_PROVIDER_FIELDS.filter((field) => field in raw), ...legacyEnvKeys.map((key) => `env.${key}`)];
6800
7403
  if (fields.length === 0) {
@@ -7758,7 +8361,7 @@ function realResolveClaudeBinary(isOwnBinary) {
7758
8361
 
7759
8362
  // src/checkReport.ts
7760
8363
  var import_node_path23 = __toESM(require("node:path"), 1);
7761
- var import_zod12 = require("zod");
8364
+ var import_zod13 = require("zod");
7762
8365
 
7763
8366
  // src/cli/bool.ts
7764
8367
  function parseBoolWord(input) {
@@ -7873,9 +8476,9 @@ function lookupKeychainService(run, farmRoot) {
7873
8476
  note: serviceName === void 0 ? `A Keychain entry was found for account "${farmRoot}" but its service name could not be parsed from security's output.` : `Keychain service name for this identity: "${serviceName}".`
7874
8477
  };
7875
8478
  }
7876
- var SettingsSecretsShapeSchema = import_zod12.z.looseObject({
7877
- env: import_zod12.z.record(import_zod12.z.string(), import_zod12.z.unknown()).optional(),
7878
- hooks: import_zod12.z.record(import_zod12.z.string(), import_zod12.z.array(import_zod12.z.unknown())).optional()
8479
+ var SettingsSecretsShapeSchema = import_zod13.z.looseObject({
8480
+ env: import_zod13.z.record(import_zod13.z.string(), import_zod13.z.unknown()).optional(),
8481
+ hooks: import_zod13.z.record(import_zod13.z.string(), import_zod13.z.array(import_zod13.z.unknown())).optional()
7879
8482
  });
7880
8483
  function hookCommandCountOf(group) {
7881
8484
  if (typeof group !== "object" || group === null) {
@@ -8169,11 +8772,11 @@ function collectCheckReport(params) {
8169
8772
  // src/claudeShim.ts
8170
8773
  var import_node_fs8 = __toESM(require("node:fs"), 1);
8171
8774
  var import_node_path24 = __toESM(require("node:path"), 1);
8172
- var import_zod13 = require("zod");
8173
- var ClaudeShimStateSchema = import_zod13.z.strictObject({
8174
- targetPath: import_zod13.z.string().min(1),
8175
- method: import_zod13.z.enum(["hardlink", "copy"]),
8176
- installedAtMs: import_zod13.z.number()
8775
+ var import_zod14 = require("zod");
8776
+ var ClaudeShimStateSchema = import_zod14.z.strictObject({
8777
+ targetPath: import_zod14.z.string().min(1),
8778
+ method: import_zod14.z.enum(["hardlink", "copy"]),
8779
+ installedAtMs: import_zod14.z.number()
8177
8780
  });
8178
8781
  function commandFilename(ownExecutablePath, commandName) {
8179
8782
  return ownExecutablePath.toLowerCase().endsWith(".exe") ? `${commandName}.exe` : commandName;
@@ -8732,9 +9335,11 @@ var BOOLEAN_FLAGS = [
8732
9335
  ];
8733
9336
  var LAUNCHER_FLAG_NAMES = [
8734
9337
  ...VALUED_FLAGS,
9338
+ "--native",
8735
9339
  "--no-provider",
8736
9340
  ...BOOLEAN_FLAGS.flatMap(({ flag }) => [flag, `--no-${flag.slice(2)}`])
8737
9341
  ];
9342
+ var NATIVE_FLAG = "--native";
8738
9343
  var TERMINATOR2 = "--";
8739
9344
  function matchValuedFlag(token) {
8740
9345
  for (const flag of VALUED_FLAGS) {
@@ -8762,6 +9367,7 @@ function parseLauncherArgv(argv) {
8762
9367
  const first = argv[0];
8763
9368
  const positionalIdentity = first !== void 0 && first.startsWith("@") && first.length > 1 ? first.slice(1) : void 0;
8764
9369
  const remaining = positionalIdentity === void 0 ? argv : argv.slice(1);
9370
+ let native = false;
8765
9371
  let flagIdentity;
8766
9372
  let configProfile;
8767
9373
  let provider;
@@ -8783,6 +9389,10 @@ function parseLauncherArgv(argv) {
8783
9389
  provider = false;
8784
9390
  continue;
8785
9391
  }
9392
+ if (token === NATIVE_FLAG) {
9393
+ native = true;
9394
+ continue;
9395
+ }
8786
9396
  const booleanFlag = matchBooleanFlag(token);
8787
9397
  if (booleanFlag !== void 0) {
8788
9398
  booleans[booleanFlag.key] = booleanFlag.value;
@@ -8836,6 +9446,7 @@ function parseLauncherArgv(argv) {
8836
9446
  ...identity === void 0 ? {} : { identity },
8837
9447
  ...configProfile === void 0 ? {} : { configProfile },
8838
9448
  ...provider === void 0 ? {} : { provider },
9449
+ ...native ? { native: true } : {},
8839
9450
  ...booleans,
8840
9451
  categoryFlags,
8841
9452
  shareFlags,
@@ -9545,6 +10156,9 @@ function buildFarmRuntime(paths, cwd) {
9545
10156
  ...loaded.globalConfig?.pools === void 0 ? {} : { pools: loaded.globalConfig.pools }
9546
10157
  };
9547
10158
  }
10159
+ function realClaudeBinaryResolver(paths) {
10160
+ return realResolveClaudeBinary(resolveOwnBinaryCheck(paths, realContentSourcePath()));
10161
+ }
9548
10162
  function realPrepareLaunchParams(paths, options) {
9549
10163
  const { farm } = options;
9550
10164
  return {
@@ -9552,7 +10166,7 @@ function realPrepareLaunchParams(paths, options) {
9552
10166
  fs: realFsPort,
9553
10167
  proc: options.proc,
9554
10168
  log: options.log,
9555
- resolveClaudeBinary: realResolveClaudeBinary(resolveOwnBinaryCheck(paths, realContentSourcePath())),
10169
+ resolveClaudeBinary: realClaudeBinaryResolver(paths),
9556
10170
  farm: farm.runtime,
9557
10171
  headroom: realHeadroomPort(paths, { spawnDaemon: options.spawnDaemon, cwd: farm.runtime.cwd }),
9558
10172
  frontdoor: realFrontDoorPort(paths, options.spawnDaemon),
@@ -9643,11 +10257,16 @@ function prepareClaudeLaunch(options) {
9643
10257
  ProviderNotFoundError,
9644
10258
  ProviderSchema,
9645
10259
  RC_IDLE_EXPIRY_MS,
10260
+ RC_ORPC_PATH_PREFIX,
9646
10261
  RC_PENDING_DEADLINE_MS,
9647
10262
  RC_PERMISSION_MODES,
9648
10263
  RC_REQUEST_PARSE_CAP_BYTES,
9649
10264
  RC_SESSIONS_PATH_PREFIX,
10265
+ RC_STREAM_BACKOFF_MS,
9650
10266
  ROUTED_PATH_PREFIX,
10267
+ RcPermissionModeSchema,
10268
+ RcStreamEnvelopeSchema,
10269
+ RcStreamEventSchema,
9651
10270
  UsageError,
9652
10271
  UsageSnapshotError,
9653
10272
  UsageSnapshotSchema,
@@ -9673,8 +10292,13 @@ function prepareClaudeLaunch(options) {
9673
10292
  collectPoolPick,
9674
10293
  createLeafCache,
9675
10294
  createProfile,
10295
+ createRcApiNodeHandler,
10296
+ createRcApiRouter,
9676
10297
  createRcControlHandler,
10298
+ createRcEventFanout,
9677
10299
  createRcSessionTracker,
10300
+ createRcStreamHub,
10301
+ createSseParser,
9678
10302
  describeProviderEndpoint,
9679
10303
  detectAmbientCredential,
9680
10304
  effectiveWindow,
@@ -9687,6 +10311,7 @@ function prepareClaudeLaunch(options) {
9687
10311
  formatCheckReport,
9688
10312
  formatDoctorReport,
9689
10313
  forwardableHeaders,
10314
+ frontDoorRcApiClient,
9690
10315
  frontDoorRcControl,
9691
10316
  generateCa,
9692
10317
  identityExists,
@@ -9704,6 +10329,7 @@ function prepareClaudeLaunch(options) {
9704
10329
  mintLeaf,
9705
10330
  observingRoutedRoute,
9706
10331
  parseConnectTarget,
10332
+ parseRcStreamEnvelope,
9707
10333
  planOf,
9708
10334
  prepareClaudeLaunch,
9709
10335
  prepareLaunch,
@@ -9725,6 +10351,7 @@ function prepareClaudeLaunch(options) {
9725
10351
  realConnectEffects,
9726
10352
  realRcControlTransport,
9727
10353
  realRcEventDial,
10354
+ realRcStreamDial,
9728
10355
  recoverFarm,
9729
10356
  recoveryDiagnostics,
9730
10357
  removeDirectoryRule,