agent-shim 8.5.5 → 8.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -55519,14 +55519,14 @@ function ensureHeadroom(params) {
55519
55519
  const holders = sessionsForSupervisor(ports.fs, paths.headroomSessionsDir, state.supervisorPid).filter((session) => ports.isRunning(session.pid));
55520
55520
  if (holders.length > 0) {
55521
55521
  throw new HeadroomStartError(
55522
- `agent-shim: the running headroom daemon was started before this launch's front door address and would refuse every request this launch sends through it. It restarts once the launches using it end (pid ${holders.map((session) => String(session.pid)).join(", ")}); end them and launch again, or launch with --no-headroom.`
55522
+ `the running headroom daemon was started before this launch's front door address and would refuse every request this launch sends through it. It restarts once the launches using it end (pid ${holders.map((session) => String(session.pid)).join(", ")}); end them and launch again, or launch with --no-headroom.`
55523
55523
  );
55524
55524
  }
55525
55525
  awaitingAllowlist = true;
55526
55526
  }
55527
55527
  if (state.lastError !== void 0) {
55528
55528
  throw new HeadroomStartError(
55529
- `agent-shim: the headroom daemon reported a fatal error and is not serving: ${state.lastError} (daemon log: ${paths.headroomLogPath})`
55529
+ `the headroom daemon reported a fatal error and is not serving: ${state.lastError} (daemon log: ${paths.headroomLogPath})`
55530
55530
  );
55531
55531
  }
55532
55532
  } else if (!spawnedSupervisor) {
@@ -55550,7 +55550,7 @@ function ensureHeadroom(params) {
55550
55550
  if (ports.now() >= deadline) {
55551
55551
  const lastError = state?.lastError;
55552
55552
  throw new HeadroomStartError(
55553
- `agent-shim: the headroom daemon did not become ready within ${String(HEADROOM_START_TIMEOUT_MS)}ms` + (lastError === void 0 ? "" : ` (last error: ${lastError})`) + (awaitingAllowlist ? " (the running daemon's allowlist does not admit this launch's front door, and it did not restart)" : "") + `. Daemon log: ${paths.headroomLogPath}`
55553
+ `the headroom daemon did not become ready within ${String(HEADROOM_START_TIMEOUT_MS)}ms` + (lastError === void 0 ? "" : ` (last error: ${lastError})`) + (awaitingAllowlist ? " (the running daemon's allowlist does not admit this launch's front door, and it did not restart)" : "") + `. Daemon log: ${paths.headroomLogPath}`
55554
55554
  );
55555
55555
  }
55556
55556
  ports.sleep(HEADROOM_LAUNCHER_POLL_MS);
@@ -61586,7 +61586,7 @@ function registerIdentityCommand(program2, deps) {
61586
61586
  // package.json
61587
61587
  var package_default = {
61588
61588
  name: "agent-shim",
61589
- version: "8.5.5",
61589
+ version: "8.6.0",
61590
61590
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
61591
61591
  license: "MIT",
61592
61592
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -65639,2156 +65639,2304 @@ var import_node_https = __toESM(require("node:https"), 1);
65639
65639
 
65640
65640
  // src/frontdoor/rcControl.ts
65641
65641
  var https2 = __toESM(require("node:https"), 1);
65642
- var CONTROL_PATH_PREFIX = "/__agent-shim/rc";
65643
- var CONTROL_BODY_CAP_BYTES = 10485760;
65644
- function answerJson(response, status, body) {
65645
- const text2 = JSON.stringify(body);
65646
- response.writeHead(status, { "content-type": "application/json", "content-length": String(Buffer.byteLength(text2, "utf8")) });
65647
- response.end(text2);
65648
- }
65649
- async function readBody(request7) {
65650
- return await new Promise((resolve, reject) => {
65651
- const chunks = [];
65652
- let total = 0;
65653
- request7.on("data", (chunk) => {
65654
- total += chunk.length;
65655
- if (total > CONTROL_BODY_CAP_BYTES) {
65656
- request7.destroy();
65657
- reject(new Error("too large"));
65658
- return;
65659
- }
65660
- chunks.push(chunk);
65661
- });
65662
- request7.on("end", () => {
65663
- resolve(Buffer.concat(chunks).toString("utf8"));
65664
- });
65665
- request7.on("error", () => {
65666
- reject(new Error("the request body ended early"));
65667
- });
65668
- });
65642
+
65643
+ // src/frontdoor/rcSessions.ts
65644
+ var RC_SESSIONS_PATH_PREFIX = "/v1/code/sessions";
65645
+ var RC_SESSION_ID_PREFIX = "cse_";
65646
+ var RC_IDLE_EXPIRY_MS = 45e3;
65647
+ var RC_CREATE_RESPONSE_CAP_BYTES = 8192;
65648
+ var CONFLICT_REASON_HEADER = "x-ccr-conflict-reason";
65649
+ var RC_PENDING_DEADLINE_MS = 14e3;
65650
+ var RC_REQUEST_PARSE_CAP_BYTES = 262144;
65651
+ var RC_PENDING_SUMMARY_EXCERPT_CHARS = 300;
65652
+ var SUCCESS_STATUS_MAX_EXCLUSIVE = 300;
65653
+ function isSuccessful(status) {
65654
+ return status >= HTTP_STATUS.ok && status < SUCCESS_STATUS_MAX_EXCLUSIVE;
65669
65655
  }
65670
- function createRcControlHandler(deps) {
65671
- const sessionsPath = `${CONTROL_PATH_PREFIX}/sessions`;
65672
- const statusPath = `${CONTROL_PATH_PREFIX}/status`;
65673
- const pendingPath = `${CONTROL_PATH_PREFIX}/pending`;
65674
- const injectPath = `${CONTROL_PATH_PREFIX}/inject`;
65675
- const answerPath = `${CONTROL_PATH_PREFIX}/answer`;
65676
- return (request7, response) => {
65677
- const presented = request7.headers.authorization;
65678
- const bearerPrefix = "bearer ".length;
65679
- const token = typeof presented === "string" && presented.slice(0, bearerPrefix).toLowerCase() === "bearer " ? presented.slice(bearerPrefix) : void 0;
65680
- if (token === void 0 || !isLiveCapability(token, [deps.expectedToken])) {
65681
- answerJson(response, HTTP_STATUS.unauthorized, { error: "the front door's control routes demand this generation's control token as a Bearer credential" });
65682
- return;
65683
- }
65684
- const url2 = new URL(request7.url ?? "/", "http://127.0.0.1");
65685
- const handle = async () => {
65686
- if (url2.pathname === sessionsPath) {
65687
- if (request7.method !== "GET") {
65688
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the session list is a GET" });
65689
- return;
65690
- }
65691
- answerJson(response, HTTP_STATUS.ok, { sessions: deps.list() });
65692
- return;
65693
- }
65694
- if (url2.pathname === statusPath || url2.pathname === pendingPath) {
65695
- if (request7.method !== "GET") {
65696
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the status and pending reads are GETs" });
65697
- return;
65698
- }
65699
- const session = url2.searchParams.get("session") ?? void 0;
65700
- if (session !== void 0 && !deps.statusOf(session).some((entry) => entry.id === session)) {
65701
- 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)` });
65702
- return;
65703
- }
65704
- answerJson(response, HTTP_STATUS.ok, url2.pathname === statusPath ? { statuses: deps.statusOf(session) } : { pending: deps.pendingOf(session) });
65705
- return;
65706
- }
65707
- if (url2.pathname === injectPath) {
65708
- if (request7.method !== "POST") {
65709
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the inject operation is a POST" });
65710
- return;
65711
- }
65712
- let parsed;
65713
- try {
65714
- parsed = JSON.parse(await readBody(request7));
65715
- } catch {
65716
- answerJson(response, HTTP_STATUS.badRequest, { error: "the inject body is not readable JSON within the control body cap" });
65717
- return;
65718
- }
65719
- if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("text" in parsed) || typeof parsed.session !== "string" || typeof parsed.text !== "string" || parsed.session === "" || parsed.text === "") {
65720
- answerJson(response, HTTP_STATUS.badRequest, { error: "the inject body must be JSON naming a non-empty session id and text" });
65721
- return;
65722
- }
65723
- const result = await deps.inject(parsed.session, parsed.text);
65724
- if (result.ok) {
65725
- answerJson(response, HTTP_STATUS.ok, { session: parsed.session, sequenceNums: result.sequenceNums });
65726
- return;
65727
- }
65728
- answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
65729
- return;
65730
- }
65731
- if (url2.pathname === answerPath) {
65732
- if (request7.method !== "POST") {
65733
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the answer operation is a POST" });
65734
- return;
65735
- }
65736
- let parsed;
65737
- try {
65738
- parsed = JSON.parse(await readBody(request7));
65739
- } catch {
65740
- answerJson(response, HTTP_STATUS.badRequest, { error: "the answer body is not readable JSON within the control body cap" });
65741
- return;
65742
- }
65743
- 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 === "") {
65744
- answerJson(response, HTTP_STATUS.badRequest, { error: "the answer body must be JSON naming a non-empty session id, request id, and an approve boolean" });
65745
- return;
65746
- }
65747
- const text2 = "text" in parsed && typeof parsed.text === "string" ? parsed.text : void 0;
65748
- if (parsed.approve && text2 !== void 0 && text2 !== "") {
65749
- 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" });
65750
- return;
65751
- }
65752
- const result = await deps.answer(parsed.session, parsed.request, { approve: parsed.approve, message: parsed.approve ? void 0 : text2 });
65753
- if (result.ok) {
65754
- answerJson(response, HTTP_STATUS.ok, { session: parsed.session, request: parsed.request, sequenceNums: result.sequenceNums });
65755
- return;
65756
- }
65757
- answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
65758
- return;
65759
- }
65760
- answerJson(response, HTTP_STATUS.notFound, { error: `no such control route: ${url2.pathname}` });
65761
- };
65762
- handle().catch((error62) => {
65763
- answerJson(response, HTTP_STATUS.internalServerError, { error: `the control route failed: ${error62 instanceof Error ? error62.message : String(error62)}` });
65764
- });
65765
- };
65656
+ function singleHeader(headers, name) {
65657
+ const value = headers[name];
65658
+ return typeof value === "string" ? value : void 0;
65766
65659
  }
65767
- function realRcControlTransport(port, ca) {
65768
- return {
65769
- request: async (options) => await new Promise((resolve, reject) => {
65770
- const request7 = https2.request(
65771
- {
65772
- host: "127.0.0.1",
65773
- port,
65774
- method: options.method,
65775
- path: options.path,
65776
- headers: options.body === void 0 ? options.headers : { ...options.headers, "content-length": String(Buffer.byteLength(options.body, "utf8")) },
65777
- agent: false,
65778
- ca: [ca]
65779
- },
65780
- (response) => {
65781
- const chunks = [];
65782
- response.on("data", (chunk) => {
65783
- chunks.push(chunk);
65784
- });
65785
- response.on("end", () => {
65786
- resolve({ status: response.statusCode ?? 0, body: Buffer.concat(chunks).toString("utf8") });
65787
- });
65788
- }
65789
- );
65790
- request7.once("error", reject);
65791
- if (options.body === void 0) {
65792
- request7.end();
65793
- } else {
65794
- request7.end(options.body);
65795
- }
65796
- })
65797
- };
65660
+ var OAUTH_AUTHORIZATION_PREFIX = "Bearer sk-ant-oat";
65661
+ function oauthAuthorizationOf(headers) {
65662
+ const value = singleHeader(headers, "authorization");
65663
+ return value?.startsWith(OAUTH_AUTHORIZATION_PREFIX) === true ? value : void 0;
65798
65664
  }
65799
- function controlErrorOf(body) {
65665
+ function sessionCreateId(body) {
65666
+ let parsed;
65800
65667
  try {
65801
- const parsed = JSON.parse(body);
65802
- if (typeof parsed === "object" && parsed !== null && "error" in parsed && typeof parsed.error === "string") {
65803
- return parsed.error;
65804
- }
65668
+ parsed = JSON.parse(body);
65805
65669
  } catch {
65806
- return body;
65807
- }
65808
- return void 0;
65809
- }
65810
- function isRcSessionSummary(value) {
65811
- if (typeof value !== "object" || value === null) {
65812
- return false;
65813
- }
65814
- if (!("id" in value) || !("createdAt" in value) || !("lastSeenAt" in value)) {
65815
- return false;
65816
- }
65817
- return typeof value.id === "string" && typeof value.createdAt === "number" && typeof value.lastSeenAt === "number";
65818
- }
65819
- function isRcWorkerFact(value, valueIs) {
65820
- if (typeof value !== "object" || value === null) {
65821
- return false;
65822
- }
65823
- if (!("value" in value) || !("observedAt" in value)) {
65824
- return false;
65825
- }
65826
- return valueIs(value.value) && typeof value.observedAt === "number";
65827
- }
65828
- function isRcSessionStatus(value) {
65829
- if (!isRcSessionSummary(value)) {
65830
- return false;
65831
- }
65832
- if (!("pending" in value) || !Array.isArray(value.pending)) {
65833
- return false;
65670
+ return void 0;
65834
65671
  }
65835
- if ("workerState" in value && value.workerState !== void 0 && !isRcWorkerFact(value.workerState, (candidate) => typeof candidate === "string")) {
65836
- return false;
65672
+ if (typeof parsed !== "object" || parsed === null || !("session" in parsed)) {
65673
+ return void 0;
65837
65674
  }
65838
- if ("workerIdleSeconds" in value && value.workerIdleSeconds !== void 0 && !isRcWorkerFact(value.workerIdleSeconds, (candidate) => typeof candidate === "number")) {
65839
- return false;
65675
+ const session = parsed.session;
65676
+ if (typeof session !== "object" || session === null || !("id" in session)) {
65677
+ return void 0;
65840
65678
  }
65841
- return value.pending.every((candidate) => isRcPendingRequestSummary(candidate));
65679
+ const id = session.id;
65680
+ return typeof id === "string" && id.startsWith(RC_SESSION_ID_PREFIX) ? id : void 0;
65842
65681
  }
65843
- function isRcPendingRequestSummary(value) {
65844
- if (typeof value !== "object" || value === null) {
65845
- return false;
65846
- }
65847
- if (!("sessionId" in value) || !("requestId" in value) || !("type" in value) || !("summary" in value) || !("observedAt" in value)) {
65848
- return false;
65849
- }
65850
- return typeof value.sessionId === "string" && typeof value.requestId === "string" && typeof value.type === "string" && typeof value.summary === "string" && typeof value.observedAt === "number";
65682
+ function isRecord3(value) {
65683
+ return typeof value === "object" && value !== null && !Array.isArray(value);
65851
65684
  }
65852
- function sequenceNumsOfBody(body) {
65685
+ function parseJsonObject(body) {
65853
65686
  let parsed;
65854
65687
  try {
65855
65688
  parsed = JSON.parse(body);
65856
65689
  } catch {
65857
65690
  return void 0;
65858
65691
  }
65859
- if (typeof parsed !== "object" || parsed === null || !("sequenceNums" in parsed) || !Array.isArray(parsed.sequenceNums)) {
65860
- return void 0;
65861
- }
65862
- const sequenceNums = [];
65863
- const values = parsed.sequenceNums;
65864
- for (const value of values) {
65865
- if (typeof value !== "number") {
65866
- return void 0;
65867
- }
65868
- sequenceNums.push(value);
65869
- }
65870
- return sequenceNums;
65692
+ return isRecord3(parsed) ? parsed : void 0;
65871
65693
  }
65872
- function frontDoorRcControl(transport, token) {
65873
- const headers = { authorization: `Bearer ${token}` };
65874
- const listAnswerOf = async (path41, what) => {
65875
- try {
65876
- return await transport.request({ method: "GET", path: path41, headers });
65877
- } catch (error62) {
65878
- throw new Error(`${what}: could not reach the front door's control listener: ${error62 instanceof Error ? error62.message : String(error62)}`, { cause: error62 });
65879
- }
65880
- };
65881
- const sessionsOf = (answer, what) => {
65882
- if (answer.status !== HTTP_STATUS.ok) {
65883
- throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
65884
- }
65885
- let parsed;
65886
- try {
65887
- parsed = JSON.parse(answer.body);
65888
- } catch {
65889
- throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
65890
- }
65891
- if (typeof parsed !== "object" || parsed === null || !("sessions" in parsed) || !Array.isArray(parsed.sessions)) {
65892
- throw new Error(`${what}: the door's answer named no sessions list: ${answer.body}`);
65893
- }
65894
- const candidates = parsed.sessions;
65895
- const sessions = [];
65896
- for (const value of candidates) {
65897
- if (!isRcSessionSummary(value)) {
65898
- throw new Error(`${what}: the door's answer named no sessions list: ${answer.body}`);
65899
- }
65900
- sessions.push(value);
65901
- }
65902
- return sessions;
65903
- };
65904
- const statusesOf = (answer, what) => {
65905
- if (answer.status !== HTTP_STATUS.ok) {
65906
- throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
65907
- }
65908
- let parsed;
65909
- try {
65910
- parsed = JSON.parse(answer.body);
65911
- } catch {
65912
- throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
65694
+ function nonEmptyString(record2, field) {
65695
+ const value = record2 === void 0 ? void 0 : record2[field];
65696
+ return typeof value === "string" && value !== "" ? value : void 0;
65697
+ }
65698
+ function finiteNumber(record2, field) {
65699
+ const value = record2 === void 0 ? void 0 : record2[field];
65700
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
65701
+ }
65702
+ function excerpt(text2) {
65703
+ return text2.length <= RC_PENDING_SUMMARY_EXCERPT_CHARS ? text2 : `${text2.slice(0, RC_PENDING_SUMMARY_EXCERPT_CHARS)}...`;
65704
+ }
65705
+ function payloadEventsOf(body) {
65706
+ const parsed = parseJsonObject(body);
65707
+ const events = parsed === void 0 ? void 0 : parsed.events;
65708
+ if (!Array.isArray(events)) {
65709
+ return [];
65710
+ }
65711
+ const payloads = [];
65712
+ for (const event of events) {
65713
+ if (!isRecord3(event)) {
65714
+ continue;
65913
65715
  }
65914
- if (typeof parsed !== "object" || parsed === null || !("statuses" in parsed) || !Array.isArray(parsed.statuses)) {
65915
- throw new Error(`${what}: the door's answer named no status list: ${answer.body}`);
65716
+ const payload = event.payload;
65717
+ if (!isRecord3(payload)) {
65718
+ continue;
65916
65719
  }
65917
- const statuses = [];
65918
- for (const value of parsed.statuses) {
65919
- if (!isRcSessionStatus(value)) {
65920
- throw new Error(`${what}: the door's answer named no status list: ${answer.body}`);
65921
- }
65922
- statuses.push(value);
65720
+ payloads.push(payload);
65721
+ }
65722
+ return payloads;
65723
+ }
65724
+ function pendingOfControlRequestPayload(payload) {
65725
+ if (payload.type !== "control_request") {
65726
+ return void 0;
65727
+ }
65728
+ const requestId = nonEmptyString(payload, "request_id") ?? nonEmptyString(payload, "uuid");
65729
+ if (requestId === void 0) {
65730
+ return void 0;
65731
+ }
65732
+ const request7 = isRecord3(payload.request) ? payload.request : void 0;
65733
+ const subtype = nonEmptyString(request7, "subtype");
65734
+ const type = subtype ?? "control_request";
65735
+ let summary = "";
65736
+ if (subtype === "can_use_tool") {
65737
+ const toolName = nonEmptyString(request7, "tool_name") ?? "unknown tool";
65738
+ const input2 = request7 === void 0 ? void 0 : request7.input;
65739
+ summary = input2 === void 0 ? toolName : `${toolName} ${excerpt(JSON.stringify(input2))}`;
65740
+ } else if (request7 !== void 0) {
65741
+ summary = excerpt(JSON.stringify(request7));
65742
+ }
65743
+ return { requestId, type, summary };
65744
+ }
65745
+ function answeredRequestIdsOfControlResponsePayload(payload) {
65746
+ if (payload.type !== "control_response") {
65747
+ return [];
65748
+ }
65749
+ const response = isRecord3(payload.response) ? payload.response : void 0;
65750
+ const id = nonEmptyString(response, "request_id") ?? nonEmptyString(payload, "request_id") ?? nonEmptyString(payload, "uuid");
65751
+ return id === void 0 ? [] : [id];
65752
+ }
65753
+ function parseRcRequestBody(kind, body) {
65754
+ if (kind === "heartbeat") {
65755
+ return { controlRequests: [], answeredRequestIds: [], idleSeconds: finiteNumber(parseJsonObject(body), "idle_seconds"), workerStatus: void 0 };
65756
+ }
65757
+ if (kind === "worker-registration") {
65758
+ return { controlRequests: [], answeredRequestIds: [], idleSeconds: void 0, workerStatus: nonEmptyString(parseJsonObject(body), "status") };
65759
+ }
65760
+ const controlRequests = [];
65761
+ const answeredRequestIds = [];
65762
+ for (const payload of payloadEventsOf(body)) {
65763
+ const pending = pendingOfControlRequestPayload(payload);
65764
+ if (pending !== void 0) {
65765
+ controlRequests.push({ requestId: pending.requestId, type: pending.type, summary: pending.summary });
65766
+ continue;
65923
65767
  }
65924
- return statuses;
65768
+ answeredRequestIds.push(...answeredRequestIdsOfControlResponsePayload(payload));
65769
+ }
65770
+ return { controlRequests, answeredRequestIds, idleSeconds: void 0, workerStatus: void 0 };
65771
+ }
65772
+ function createRcSessionTracker(deps) {
65773
+ const entries = /* @__PURE__ */ new Map();
65774
+ const expire = (id) => {
65775
+ entries.delete(id);
65925
65776
  };
65926
- const pendingOfAnswer = (answer, what) => {
65927
- if (answer.status !== HTTP_STATUS.ok) {
65928
- throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
65929
- }
65930
- let parsed;
65931
- try {
65932
- parsed = JSON.parse(answer.body);
65933
- } catch {
65934
- throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
65935
- }
65936
- if (typeof parsed !== "object" || parsed === null || !("pending" in parsed) || !Array.isArray(parsed.pending)) {
65937
- throw new Error(`${what}: the door's answer named no pending list: ${answer.body}`);
65938
- }
65939
- const pending = [];
65940
- for (const value of parsed.pending) {
65941
- if (!isRcPendingRequestSummary(value)) {
65942
- throw new Error(`${what}: the door's answer named no pending list: ${answer.body}`);
65777
+ const expirePendings = (entry, now) => {
65778
+ for (const [requestId, pending] of entry.pending) {
65779
+ if (now - pending.observedAt >= RC_PENDING_DEADLINE_MS) {
65780
+ entry.pending.delete(requestId);
65943
65781
  }
65944
- pending.push(value);
65945
65782
  }
65946
- return pending;
65947
65783
  };
65948
- const writeOf = async (path41, body, describeFailure) => {
65949
- let answer;
65950
- try {
65951
- answer = await transport.request({ method: "POST", path: path41, headers: { ...headers, "content-type": "application/json" }, body });
65952
- } catch (error62) {
65953
- return { ok: false, message: `could not reach the front door's control listener: ${error62 instanceof Error ? error62.message : String(error62)}` };
65954
- }
65955
- if (answer.status === HTTP_STATUS.ok) {
65956
- const sequenceNums = sequenceNumsOfBody(answer.body);
65957
- if (sequenceNums === void 0) {
65958
- return { ok: false, message: `the door accepted the event but its answer named no sequence numbers: ${answer.body}` };
65784
+ const sweep = () => {
65785
+ for (const [id, entry] of entries) {
65786
+ if (deps.now() - entry.lastSeenAt >= deps.idleMs) {
65787
+ expire(id);
65788
+ continue;
65959
65789
  }
65960
- return { ok: true, sequenceNums };
65790
+ expirePendings(entry, deps.now());
65961
65791
  }
65962
- return { ok: false, message: describeFailure(answer.status, controlErrorOf(answer.body) ?? answer.body) };
65963
65792
  };
65964
- const sessionQuery = (sessionId) => sessionId === void 0 ? "" : `?session=${encodeURIComponent(sessionId)}`;
65965
- return {
65966
- listSessions: async () => sessionsOf(await listAnswerOf(`${CONTROL_PATH_PREFIX}/sessions`, "listing the door's Remote Control sessions"), "listing the door's Remote Control sessions"),
65967
- 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"),
65968
- 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"),
65969
- sendPrompt: async (sessionId, text2) => await writeOf(`${CONTROL_PATH_PREFIX}/inject`, JSON.stringify({ session: sessionId, text: text2 }), (status, message) => `injecting into ${sessionId} failed (HTTP ${String(status)}): ${message}`),
65970
- answerRequest: async (sessionId, requestId, decision) => await writeOf(
65971
- `${CONTROL_PATH_PREFIX}/answer`,
65972
- JSON.stringify({ session: sessionId, request: requestId, approve: decision.approve, ...decision.approve || decision.message === void 0 ? {} : { text: decision.message } }),
65973
- (status, message) => `answering control request ${requestId} on ${sessionId} failed (HTTP ${String(status)}): ${message}`
65974
- )
65793
+ const timer = setInterval(sweep, deps.idleMs);
65794
+ timer.unref();
65795
+ const birth = (id, facts) => {
65796
+ const record2 = { id, createdAt: deps.now(), lastSeenAt: deps.now(), ...facts, pending: /* @__PURE__ */ new Map(), workerState: void 0, workerIdleSeconds: void 0 };
65797
+ entries.set(id, record2);
65798
+ return record2;
65975
65799
  };
65976
- }
65977
-
65978
- // src/frontdoor/server.ts
65979
- var HEALTH_TIMEOUT_MS = 2e3;
65980
- var HEALTH_START_BUDGET_MS = 5e3;
65981
- var HEALTH_RETRY_MS = 50;
65982
- function createFrontDoorServer(pipeline, log, tls2, control) {
65983
- const handler = (request7, response) => {
65984
- if (request7.method === "GET" && request7.url === "/healthz") {
65985
- response.writeHead(HTTP_STATUS.ok, { "Content-Type": "text/plain" });
65986
- response.end("ok");
65987
- return;
65988
- }
65989
- if (control !== void 0 && (request7.url ?? "/").startsWith(CONTROL_PATH_PREFIX)) {
65990
- control(request7, response);
65991
- return;
65800
+ const observeExchange = (request7) => {
65801
+ const method = (request7.method ?? "").toUpperCase();
65802
+ const path41 = new URL(request7.url ?? "/", "http://127.0.0.1").pathname;
65803
+ if (!path41.startsWith(RC_SESSIONS_PATH_PREFIX)) {
65804
+ return void 0;
65992
65805
  }
65993
- const abort = new AbortController();
65994
- response.on("close", () => {
65995
- if (!response.writableFinished) {
65996
- abort.abort();
65997
- }
65998
- });
65999
- const handle = async () => {
66000
- await pipeline({ method: request7.method ?? "GET", url: request7.url ?? "/", headers: aliasLegacyWireHeaders(request7.headers), body: request7, signal: abort.signal, response });
66001
- if (!request7.readableEnded) {
66002
- request7.resume();
66003
- }
65806
+ const tail = path41.slice(RC_SESSIONS_PATH_PREFIX.length);
65807
+ const facts = {
65808
+ oauthAuthorization: oauthAuthorizationOf(request7.headers),
65809
+ anthropicVersion: singleHeader(request7.headers, "anthropic-version"),
65810
+ anthropicClientPlatform: singleHeader(request7.headers, "anthropic-client-platform")
66004
65811
  };
66005
- handle().catch((error62) => {
66006
- log(`request ${request7.method ?? "?"} ${request7.url ?? "?"} failed: ${error62 instanceof Error ? `${error62.name}: ${error62.message}` : String(error62)}`);
66007
- if (!response.headersSent) {
66008
- response.writeHead(HTTP_STATUS.internalServerError, { "Content-Type": "application/json" });
66009
- response.end(JSON.stringify({ type: "error", error: { type: "api_error", message: "internal error in the agent-shim front door" } }));
66010
- } else {
66011
- response.destroy();
65812
+ if (tail === "") {
65813
+ if (method !== "POST") {
65814
+ return void 0;
66012
65815
  }
66013
- });
66014
- };
66015
- if (tls2 === void 0) {
66016
- return import_node_http.default.createServer(handler);
66017
- }
66018
- const server = import_node_https.default.createServer({ key: tls2.keyPem, cert: tls2.certPem }, handler);
66019
- server.on("tlsClientError", (_error, socket) => {
66020
- socket.destroy();
66021
- });
66022
- return server;
66023
- }
66024
- async function frontDoorHealthy(port, ca) {
66025
- return await new Promise((resolve) => {
66026
- const onResponse = (response) => {
66027
- response.resume();
66028
- resolve(response.statusCode === HTTP_STATUS.ok);
66029
- };
66030
- const options = { host: "127.0.0.1", port, path: "/healthz", agent: false, timeout: HEALTH_TIMEOUT_MS };
66031
- const request7 = ca === void 0 ? import_node_http.default.get(options, onResponse) : import_node_https.default.get({ ...options, ca: [ca] }, onResponse);
66032
- request7.on("timeout", () => {
66033
- request7.destroy();
66034
- });
66035
- request7.on("error", () => {
66036
- resolve(false);
66037
- });
66038
- });
66039
- }
66040
- async function listenFrontDoor(server, options = {}) {
66041
- const { preferredPort, ca } = options;
66042
- const tryListen = async (port) => await new Promise((resolve, reject) => {
66043
- const onError = (error62) => {
66044
- server.off("error", onError);
66045
- reject(error62);
66046
- };
66047
- server.once("error", onError);
66048
- server.listen(port, "127.0.0.1", () => {
66049
- server.off("error", onError);
66050
- const address = server.address();
66051
- const bound2 = typeof address === "object" && address !== null ? address.port : 0;
66052
- if (bound2 === 0) {
66053
- reject(new Error("could not bind a loopback port"));
66054
- return;
66055
- }
66056
- resolve(bound2);
66057
- });
66058
- });
66059
- let bound;
66060
- if (preferredPort !== void 0) {
66061
- try {
66062
- bound = await tryListen(preferredPort);
66063
- } catch {
66064
- bound = await tryListen(0);
66065
- }
66066
- } else {
66067
- bound = await tryListen(0);
66068
- }
66069
- options.onBound?.(bound);
66070
- if (options.onError !== void 0) {
66071
- server.on("error", options.onError);
66072
- }
66073
- const deadline = Date.now() + HEALTH_START_BUDGET_MS;
66074
- for (; ; ) {
66075
- if (await frontDoorHealthy(bound, ca)) {
65816
+ let accepted2 = false;
65817
+ let buffered2 = 0;
65818
+ let body = "";
66076
65819
  return {
66077
- port: bound,
66078
- close: async () => {
66079
- await new Promise((resolve) => {
66080
- server.close(() => {
66081
- resolve(void 0);
66082
- });
66083
- server.closeAllConnections();
66084
- });
65820
+ onResponse: (status) => {
65821
+ accepted2 = isSuccessful(status);
65822
+ },
65823
+ onBodyChunk: (chunk) => {
65824
+ if (!accepted2 || buffered2 >= RC_CREATE_RESPONSE_CAP_BYTES) {
65825
+ return;
65826
+ }
65827
+ const text2 = Buffer.from(chunk).toString("utf8");
65828
+ body = body + text2.slice(0, RC_CREATE_RESPONSE_CAP_BYTES - buffered2);
65829
+ buffered2 = body.length;
65830
+ },
65831
+ onEnd: () => {
65832
+ if (!accepted2) {
65833
+ return;
65834
+ }
65835
+ const id2 = sessionCreateId(body);
65836
+ if (id2 === void 0) {
65837
+ return;
65838
+ }
65839
+ birth(id2, facts);
66085
65840
  }
66086
65841
  };
66087
65842
  }
66088
- if (Date.now() >= deadline) {
66089
- throw new Error(`the front door listener on 127.0.0.1:${String(bound)} did not answer its health probe`);
65843
+ const rest = tail.slice(1);
65844
+ const [id] = rest.split("/");
65845
+ if (id?.startsWith(RC_SESSION_ID_PREFIX) !== true) {
65846
+ return void 0;
66090
65847
  }
66091
- await new Promise((resolve) => {
66092
- setTimeout(resolve, HEALTH_RETRY_MS);
66093
- });
66094
- }
66095
- }
66096
- async function* upstreamChunks(stream) {
66097
- for await (const chunk of stream) {
66098
- if (typeof chunk === "string") {
66099
- yield Buffer.from(chunk, "utf8");
66100
- continue;
65848
+ const entry = entries.get(id) ?? birth(id, facts);
65849
+ entry.lastSeenAt = deps.now();
65850
+ entry.oauthAuthorization = facts.oauthAuthorization ?? entry.oauthAuthorization;
65851
+ entry.anthropicVersion = facts.anthropicVersion ?? entry.anthropicVersion;
65852
+ entry.anthropicClientPlatform = facts.anthropicClientPlatform ?? entry.anthropicClientPlatform;
65853
+ 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;
65854
+ let chunks = [];
65855
+ let buffered = 0;
65856
+ let oversized = false;
65857
+ let requestEnded = false;
65858
+ let accepted;
65859
+ let filed = false;
65860
+ const file2 = () => {
65861
+ if (filed || accepted !== true || !requestEnded || bodyKind === void 0) {
65862
+ return;
65863
+ }
65864
+ filed = true;
65865
+ const factsOfBody = oversized ? void 0 : parseRcRequestBody(bodyKind, Buffer.concat(chunks).toString("utf8"));
65866
+ chunks = [];
65867
+ const entryNow = entries.get(id);
65868
+ if (entryNow === void 0 || factsOfBody === void 0) {
65869
+ return;
65870
+ }
65871
+ const now = deps.now();
65872
+ for (const controlRequest of factsOfBody.controlRequests) {
65873
+ entryNow.pending.set(controlRequest.requestId, { sessionId: id, ...controlRequest, observedAt: now });
65874
+ }
65875
+ for (const requestId of factsOfBody.answeredRequestIds) {
65876
+ entryNow.pending.delete(requestId);
65877
+ }
65878
+ if (factsOfBody.idleSeconds !== void 0) {
65879
+ entryNow.workerIdleSeconds = { value: factsOfBody.idleSeconds, observedAt: now };
65880
+ }
65881
+ if (factsOfBody.workerStatus !== void 0) {
65882
+ entryNow.workerState = { value: factsOfBody.workerStatus, observedAt: now };
65883
+ }
65884
+ };
65885
+ const archiving = method === "POST" && rest === `${id}/archive`;
65886
+ return {
65887
+ ...bodyKind === void 0 ? {} : {
65888
+ onRequestChunk: (chunk) => {
65889
+ if (oversized) {
65890
+ return;
65891
+ }
65892
+ chunks.push(Buffer.from(chunk));
65893
+ buffered += chunk.length;
65894
+ if (buffered > RC_REQUEST_PARSE_CAP_BYTES) {
65895
+ oversized = true;
65896
+ chunks = [];
65897
+ }
65898
+ },
65899
+ onRequestEnd: () => {
65900
+ requestEnded = true;
65901
+ file2();
65902
+ }
65903
+ },
65904
+ onResponse: (status, headers) => {
65905
+ if (singleHeader(headers, CONFLICT_REASON_HEADER) !== void 0 || archiving && isSuccessful(status)) {
65906
+ expire(id);
65907
+ return;
65908
+ }
65909
+ accepted = isSuccessful(status);
65910
+ file2();
65911
+ },
65912
+ onBodyChunk: () => {
65913
+ },
65914
+ onEnd: () => {
65915
+ }
65916
+ };
65917
+ };
65918
+ const summaryOf = ({ id, createdAt, lastSeenAt }) => ({ id, createdAt, lastSeenAt });
65919
+ const pendingSummaryOf = ({ sessionId, requestId, type, summary, observedAt: observedAt2 }) => ({ sessionId, requestId, type, summary, observedAt: observedAt2 });
65920
+ const sortedEntries = () => [...entries.values()].sort((left, right) => left.createdAt - right.createdAt || (left.id < right.id ? -1 : 1));
65921
+ const pendingSorted = (entry) => [...entry.pending.values()].sort((left, right) => left.observedAt - right.observedAt || (left.requestId < right.requestId ? -1 : 1)).map(pendingSummaryOf);
65922
+ return {
65923
+ observeExchange,
65924
+ list: () => {
65925
+ sweep();
65926
+ return sortedEntries().map(summaryOf);
65927
+ },
65928
+ statusOf: (sessionId) => {
65929
+ sweep();
65930
+ return sortedEntries().filter((entry) => sessionId === void 0 || entry.id === sessionId).map((entry) => ({ ...summaryOf(entry), workerState: entry.workerState, workerIdleSeconds: entry.workerIdleSeconds, pending: pendingSorted(entry) }));
65931
+ },
65932
+ pendingOf: (sessionId) => {
65933
+ sweep();
65934
+ return sortedEntries().filter((entry) => sessionId === void 0 || entry.id === sessionId).flatMap((entry) => pendingSorted(entry));
65935
+ },
65936
+ credentialOf: (sessionId) => {
65937
+ const entry = entries.get(sessionId);
65938
+ return entry === void 0 ? void 0 : { authorization: entry.oauthAuthorization, anthropicVersion: entry.anthropicVersion, anthropicClientPlatform: entry.anthropicClientPlatform };
65939
+ },
65940
+ completePending: (sessionId, requestId) => {
65941
+ entries.get(sessionId)?.pending.delete(requestId);
65942
+ },
65943
+ close: () => {
65944
+ clearInterval(timer);
66101
65945
  }
66102
- if (chunk instanceof Uint8Array) {
66103
- yield chunk;
65946
+ };
65947
+ }
65948
+ function observingRoutedRoute(route, tracker) {
65949
+ return {
65950
+ ...route,
65951
+ serve: async (request7, response) => {
65952
+ const observed = tracker.observeExchange({ method: request7.method, url: request7.url, headers: request7.headers });
65953
+ if (observed?.onRequestChunk !== void 0) {
65954
+ request7.body.on("data", (chunk) => {
65955
+ observed.onRequestChunk?.(chunk);
65956
+ });
65957
+ request7.body.on("end", () => {
65958
+ observed.onRequestEnd?.();
65959
+ });
65960
+ }
65961
+ await route.serve(request7, observed === void 0 ? response : teeRoutedResponse(response, observed));
66104
65962
  }
66105
- }
65963
+ };
66106
65964
  }
66107
-
66108
- // src/frontdoor/headroomHop.ts
66109
- var HTTP_BAD_GATEWAY2 = HTTP_STATUS.badGateway;
66110
- function responseHeaders(headers) {
66111
- const result = {};
66112
- for (const [name, value] of Object.entries(forwardableHeaders(headers))) {
66113
- if (value === void 0) {
66114
- continue;
65965
+ function teeRoutedResponse(response, observer) {
65966
+ return {
65967
+ get headersSent() {
65968
+ return response.headersSent;
65969
+ },
65970
+ start: (status, headers) => {
65971
+ observer.onResponse(status, headers);
65972
+ response.start(status, headers);
65973
+ },
65974
+ flush: () => {
65975
+ response.flush();
65976
+ },
65977
+ write: async (chunk) => {
65978
+ observer.onBodyChunk(typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk);
65979
+ await response.write(chunk);
65980
+ },
65981
+ end: () => {
65982
+ response.end();
65983
+ observer.onEnd();
65984
+ },
65985
+ destroy: () => {
65986
+ response.destroy();
65987
+ observer.onEnd();
66115
65988
  }
66116
- result[name] = Array.isArray(value) ? value.join(", ") : value;
66117
- }
66118
- return result;
65989
+ };
66119
65990
  }
66120
- async function applyHeadroomHop(request7, response, upstream, deps) {
66121
- const target = deps.headroomSocket();
66122
- if (target === void 0) {
66123
- await answerBadGateway(response, "agent-shim front door: the headroom daemon is restarting");
66124
- return;
65991
+ function buildRcUserMessagePayload(uuid3, sessionId, text2) {
65992
+ return {
65993
+ type: "user",
65994
+ uuid: uuid3,
65995
+ session_id: sessionId,
65996
+ parent_tool_use_id: null,
65997
+ message: { role: "user", content: text2 }
65998
+ };
65999
+ }
66000
+ function buildRcEventWriteBody(payload) {
66001
+ return { events: [{ payload }] };
66002
+ }
66003
+ function sequenceNumsOf(body) {
66004
+ let parsed;
66005
+ try {
66006
+ parsed = JSON.parse(body);
66007
+ } catch {
66008
+ return void 0;
66125
66009
  }
66126
- if (target.refused !== void 0) {
66127
- deps.log(`front door: refusing the headroom hop (${request7.method} ${new URL(request7.url, "http://127.0.0.1").pathname}): ${target.refused}`);
66128
- await answerBadGateway(response, `agent-shim front door: refusing to send this request to headroom: ${target.refused}`);
66129
- return;
66010
+ if (typeof parsed !== "object" || parsed === null || !("results" in parsed) || !Array.isArray(parsed.results)) {
66011
+ return void 0;
66130
66012
  }
66131
- const { socketPath } = target;
66132
- let headers = forwardableHeaders(request7.headers);
66133
- let hopId;
66134
- if (upstream !== void 0) {
66135
- const provider = parseProviderPath(new URL(request7.url, "http://127.0.0.1").pathname)?.provider;
66136
- if (provider === void 0) {
66137
- throw new Error(`headroom hop for ${request7.url} names an upstream but no provider`);
66013
+ const sequenceNums = [];
66014
+ const results = parsed.results;
66015
+ for (const result of results) {
66016
+ if (typeof result !== "object" || result === null || !("sequence_num" in result)) {
66017
+ return void 0;
66018
+ }
66019
+ const sequenceNum = result.sequence_num;
66020
+ if (typeof sequenceNum === "number") {
66021
+ sequenceNums.push(sequenceNum);
66022
+ } else if (typeof sequenceNum === "string" && /^[0-9]+$/.test(sequenceNum)) {
66023
+ sequenceNums.push(Number(sequenceNum));
66024
+ } else {
66025
+ return void 0;
66138
66026
  }
66139
- const sequestered = deps.custody.sequester(headers, provider);
66140
- hopId = sequestered.hopId;
66141
- headers = sequestered.headers;
66142
- headers[HOP_ID_HEADER] = hopId;
66143
- headers[HEADROOM_BASE_URL_HEADER] = upstream;
66144
- }
66145
- if (request7.session.projectId !== void 0) {
66146
- headers[PROJECT_ID_HEADER] = request7.session.projectId;
66147
66027
  }
66148
- headers[HOP_SECRET_HEADER] = deps.hopSecret;
66149
- try {
66150
- await forwardThroughHeadroom(request7, response, { socketPath, headers, log: deps.log });
66151
- } finally {
66152
- if (hopId !== void 0) {
66153
- deps.custody.release(hopId);
66028
+ return sequenceNums.length === 0 ? void 0 : sequenceNums;
66029
+ }
66030
+ function rcEventWriteResultFromAnswer(answer) {
66031
+ if (!isSuccessful(answer.status)) {
66032
+ if (answer.status === HTTP_STATUS.unauthorized) {
66033
+ 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}` };
66154
66034
  }
66035
+ return { ok: false, message: `the API answered HTTP ${String(answer.status)} to the injected event: ${answer.body}` };
66036
+ }
66037
+ const sequenceNums = sequenceNumsOf(answer.body);
66038
+ if (sequenceNums === void 0) {
66039
+ 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}` };
66155
66040
  }
66041
+ return { ok: true, sequenceNums };
66156
66042
  }
66157
- async function answerBadGateway(response, message) {
66158
- response.start(HTTP_BAD_GATEWAY2, { "Content-Type": "application/json" });
66159
- await response.write(JSON.stringify({ type: "error", error: { type: "api_error", message } }));
66160
- response.end();
66043
+ function noOAuthCredentialResult(sessionId) {
66044
+ 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` };
66161
66045
  }
66162
- var HOP_AGENT = new http3.Agent({ keepAlive: false });
66163
- async function forwardThroughHeadroom(request7, response, target) {
66164
- const { socketPath, headers } = target;
66165
- await new Promise((resolve) => {
66166
- const onUpstreamResponse = (upstreamResponse) => {
66167
- response.start(upstreamResponse.statusCode ?? HTTP_BAD_GATEWAY2, responseHeaders(upstreamResponse.headers));
66168
- response.flush();
66169
- const stream = async () => {
66170
- try {
66171
- for await (const chunk of upstreamChunks(upstreamResponse)) {
66172
- if (request7.signal.aborted) {
66173
- break;
66174
- }
66175
- await response.write(chunk);
66176
- }
66177
- if (!request7.signal.aborted) {
66178
- response.end();
66179
- }
66180
- } catch (error62) {
66181
- if (!request7.signal.aborted) {
66182
- target.log(`front door: headroom hop to ${socketPath} ended mid-stream (${request7.method} ${new URL(request7.url, "http://127.0.0.1").pathname}): ${error62 instanceof Error ? error62.message : String(error62)}`);
66183
- }
66184
- response.destroy();
66185
- }
66186
- resolve(void 0);
66187
- };
66188
- void stream();
66189
- };
66190
- const hop = http3.request({ socketPath, method: request7.method, path: request7.url, headers, agent: HOP_AGENT }, onUpstreamResponse);
66191
- hop.on("error", (error62) => {
66192
- const phase = response.headersSent ? "mid-stream" : "before the response started";
66193
- const code = "code" in error62 && typeof error62.code === "string" ? ` ${error62.code}` : "";
66194
- target.log(`front door: headroom hop to ${socketPath} failed (${request7.method} ${new URL(request7.url, "http://127.0.0.1").pathname}, ${phase}): ${error62.message}${code}`);
66195
- if (!response.headersSent) {
66196
- response.start(HTTP_BAD_GATEWAY2, { "Content-Type": "application/json" });
66197
- void response.write(JSON.stringify({ type: "error", error: { type: "api_error", message: `agent-shim front door: the headroom daemon is unreachable (${error62.message})` } })).then(() => {
66198
- response.end();
66199
- });
66200
- } else {
66201
- response.destroy();
66202
- }
66203
- resolve(void 0);
66204
- });
66205
- request7.signal.addEventListener("abort", () => {
66206
- hop.destroy();
66207
- });
66208
- request7.body.pipe(hop);
66209
- request7.body.on("error", () => {
66210
- hop.destroy();
66211
- });
66212
- });
66046
+ function rcWriteHeaders(credential) {
66047
+ const headers = { "content-type": "application/json" };
66048
+ if (credential.authorization !== void 0) {
66049
+ headers.authorization = credential.authorization;
66050
+ }
66051
+ if (credential.anthropicVersion !== void 0) {
66052
+ headers["anthropic-version"] = credential.anthropicVersion;
66053
+ }
66054
+ if (credential.anthropicClientPlatform !== void 0) {
66055
+ headers["anthropic-client-platform"] = credential.anthropicClientPlatform;
66056
+ }
66057
+ return headers;
66213
66058
  }
66214
-
66215
- // src/frontdoor/pipeline.ts
66216
- function errorTypeFor(status) {
66217
- switch (status) {
66218
- case HTTP_STATUS.badRequest:
66219
- return "invalid_request_error";
66220
- case HTTP_STATUS.unauthorized:
66221
- return "authentication_error";
66222
- case HTTP_STATUS.forbidden:
66223
- return "permission_error";
66224
- case HTTP_STATUS.notFound:
66225
- return "not_found_error";
66226
- case HTTP_STATUS.tooManyRequests:
66227
- return "rate_limit_error";
66228
- default:
66229
- return "api_error";
66059
+ async function injectRcUserMessage(deps, sessionId, text2) {
66060
+ const credential = deps.credentialOf(sessionId);
66061
+ if (credential === void 0) {
66062
+ 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)` };
66063
+ }
66064
+ if (credential.authorization === void 0) {
66065
+ return noOAuthCredentialResult(sessionId);
66230
66066
  }
66067
+ const body = JSON.stringify(buildRcEventWriteBody(buildRcUserMessagePayload(deps.newUuid(), sessionId, text2)));
66068
+ let answer;
66069
+ try {
66070
+ answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
66071
+ } catch (error62) {
66072
+ return { ok: false, message: `the door could not reach the API host to inject into session ${sessionId}: ${error62 instanceof Error ? error62.message : String(error62)}` };
66073
+ }
66074
+ return rcEventWriteResultFromAnswer(answer);
66231
66075
  }
66232
- function errorBody(status, message) {
66233
- return JSON.stringify({ type: "error", error: { type: errorTypeFor(status), message } });
66076
+ function buildRcControlResponsePayload(requestId, decision) {
66077
+ const result = decision.approve ? { behavior: "allow" } : { behavior: "deny", message: decision.message ?? "" };
66078
+ return { type: "control_response", response: { subtype: "success", request_id: requestId, response: result } };
66234
66079
  }
66235
- function pathOf(url2) {
66236
- const query = url2.indexOf("?");
66237
- return query === -1 ? url2 : url2.slice(0, query);
66080
+ var RC_PERMISSION_MODES = ["default", "acceptEdits", "bypassPermissions", "plan", "dontAsk", "auto"];
66081
+ function isRcPermissionMode(value) {
66082
+ return RC_PERMISSION_MODES.some((mode) => mode === value);
66238
66083
  }
66239
- function describeThrown(error62) {
66240
- return error62 instanceof Error ? error62.message : String(error62);
66084
+ function buildRcInterruptPayload(requestId) {
66085
+ return { type: "control_request", request_id: requestId, request: { subtype: "interrupt" } };
66241
66086
  }
66242
- function createRoutedResponse(response, context) {
66243
- const { deps, session, route, request: request7 } = context;
66244
- let headersSent = false;
66245
- let bodyObservers = [];
66246
- let finished = false;
66247
- const observeBody = (call) => {
66248
- bodyObservers = bodyObservers.filter((observer) => {
66249
- try {
66250
- call(observer);
66251
- return true;
66252
- } catch (error62) {
66253
- deps.log(`front door: response body observer threw for ${route}: ${describeThrown(error62)}`);
66254
- return false;
66255
- }
66256
- });
66257
- };
66258
- const finish = (outcome) => {
66259
- if (finished) {
66260
- return;
66261
- }
66262
- finished = true;
66263
- observeBody((observer) => {
66264
- observer.end(outcome);
66265
- });
66266
- bodyObservers = [];
66267
- };
66268
- response.once("close", () => {
66269
- finish(response.writableFinished ? "completed" : "aborted");
66270
- });
66271
- const settle2 = async () => {
66272
- await new Promise((resolve) => {
66273
- const done = () => {
66274
- response.off("drain", done);
66275
- response.off("close", done);
66276
- resolve();
66277
- };
66278
- response.once("drain", done);
66279
- response.once("close", done);
66280
- });
66281
- };
66282
- return {
66283
- get headersSent() {
66284
- return headersSent;
66285
- },
66286
- start: (status, headers) => {
66287
- for (const observe of deps.responseObservers) {
66288
- try {
66289
- const body = observe({ session, route, method: request7.method, path: request7.path, receivedAt: request7.receivedAt, status, headers });
66290
- if (body !== void 0) {
66291
- bodyObservers.push(body);
66292
- }
66293
- } catch (error62) {
66294
- deps.log(`front door: response observer threw for ${route}: ${describeThrown(error62)}`);
66295
- }
66296
- }
66297
- response.writeHead(status, headers);
66298
- headersSent = true;
66299
- },
66300
- flush: () => {
66301
- response.flushHeaders();
66302
- },
66303
- write: async (chunk) => {
66304
- if (response.destroyed || response.writableEnded) {
66305
- return;
66306
- }
66307
- const accepted = response.write(chunk);
66308
- if (bodyObservers.length > 0) {
66309
- const bytes = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
66310
- observeBody((observer) => {
66311
- observer.chunk(bytes);
66312
- });
66313
- }
66314
- if (!accepted) {
66315
- await settle2();
66316
- }
66317
- },
66318
- end: () => {
66319
- const outcome = response.destroyed ? "aborted" : "completed";
66320
- response.end();
66321
- finish(outcome);
66322
- },
66323
- destroy: () => {
66324
- response.destroy();
66325
- finish("aborted");
66326
- }
66327
- };
66087
+ function buildRcSetModelPayload(requestId, model) {
66088
+ return { type: "control_request", request_id: requestId, request: { subtype: "set_model", model } };
66328
66089
  }
66329
- async function serveRouted(request7, deps) {
66330
- const observed = { method: request7.method, path: pathOf(request7.url), receivedAt: deps.now() };
66331
- const identified = identifyRequest(request7.headers);
66332
- const admission = deps.admit({ url: request7.url, headers: request7.headers, forwardable: identified.forwardableHeaders });
66333
- if (!admission.ok) {
66334
- const response2 = createRoutedResponse(request7.response, { deps, session: identified.session, route: "(unauthorized)", request: observed });
66335
- response2.start(HTTP_STATUS.unauthorized, { "Content-Type": "application/json" });
66336
- await response2.write(errorBody(HTTP_STATUS.unauthorized, admission.message));
66337
- response2.end();
66338
- return;
66090
+ function buildRcSetPermissionModePayload(requestId, mode) {
66091
+ return { type: "control_request", request_id: requestId, request: { subtype: "set_permission_mode", mode } };
66092
+ }
66093
+ async function answerRcControlRequest(deps, sessionId, requestId, decision) {
66094
+ const credential = deps.credentialOf(sessionId);
66095
+ if (credential === void 0) {
66096
+ 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)` };
66339
66097
  }
66340
- const routed = {
66341
- method: request7.method,
66342
- url: request7.url,
66343
- headers: admission.headers,
66344
- body: request7.body,
66345
- signal: request7.signal,
66346
- session: identified.session
66347
- };
66348
- const resolution = await deps.resolveRoute(routed);
66349
- if (!resolution.ok) {
66350
- const response2 = createRoutedResponse(request7.response, { deps, session: identified.session, route: "(unrouted)", request: observed });
66351
- response2.start(resolution.status, { "Content-Type": "application/json" });
66352
- await response2.write(errorBody(resolution.status, resolution.message));
66353
- response2.end();
66354
- return;
66098
+ if (credential.authorization === void 0) {
66099
+ return noOAuthCredentialResult(sessionId);
66355
66100
  }
66356
- const response = createRoutedResponse(request7.response, { deps, session: identified.session, route: resolution.route.name, request: observed });
66101
+ if (!deps.pendingOf(sessionId).some((pending) => pending.requestId === requestId)) {
66102
+ 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` };
66103
+ }
66104
+ const body = JSON.stringify(buildRcEventWriteBody(buildRcControlResponsePayload(requestId, decision)));
66105
+ let answer;
66357
66106
  try {
66358
- if (identified.session.headroom && resolution.route.headroomEligible && deps.headroom !== void 0) {
66359
- await applyHeadroomHop(routed, response, resolution.route.headroomUpstream, deps.headroom);
66360
- } else {
66361
- await resolution.route.serve(routed, response);
66362
- }
66107
+ answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
66363
66108
  } catch (error62) {
66364
- if (request7.signal.aborted) {
66365
- return;
66366
- }
66367
- deps.log(`front door: route ${resolution.route.name} failed: ${error62 instanceof Error ? `${error62.name}: ${error62.message}` : String(error62)}`);
66368
- if (!response.headersSent) {
66369
- response.start(HTTP_STATUS.internalServerError, { "Content-Type": "application/json" });
66370
- await response.write(errorBody(HTTP_STATUS.internalServerError, "internal error in the agent-shim front door"));
66371
- response.end();
66372
- return;
66373
- }
66374
- response.destroy();
66109
+ return { ok: false, message: `the door could not reach the API host to answer on session ${sessionId}: ${error62 instanceof Error ? error62.message : String(error62)}` };
66375
66110
  }
66376
- }
66377
-
66378
- // src/codex/translate.ts
66379
- var import_node_crypto11 = require("node:crypto");
66380
-
66381
- // src/codex/anthropic.ts
66382
- var TextBlockSchema = external_exports.looseObject({ type: external_exports.literal("text"), text: external_exports.string() });
66383
- var Base64ImageSourceSchema = external_exports.looseObject({ type: external_exports.literal("base64"), media_type: external_exports.string().min(1), data: external_exports.string() });
66384
- var UrlImageSourceSchema = external_exports.looseObject({ type: external_exports.literal("url"), url: external_exports.string().min(1) });
66385
- var ImageBlockSchema = external_exports.looseObject({
66386
- type: external_exports.literal("image"),
66387
- source: external_exports.union([Base64ImageSourceSchema, UrlImageSourceSchema])
66388
- });
66389
- var ToolUseBlockSchema = external_exports.looseObject({
66390
- type: external_exports.literal("tool_use"),
66391
- id: external_exports.string().min(1),
66392
- name: external_exports.string().min(1),
66393
- input: external_exports.unknown()
66394
- });
66395
- var ToolResultContentBlockSchema = external_exports.union([TextBlockSchema, external_exports.looseObject({ type: external_exports.string() })]);
66396
- var ToolResultBlockSchema = external_exports.looseObject({
66397
- type: external_exports.literal("tool_result"),
66398
- tool_use_id: external_exports.string().min(1),
66399
- content: external_exports.union([external_exports.string(), external_exports.array(ToolResultContentBlockSchema)]).optional()
66400
- });
66401
- var OtherBlockSchema = external_exports.looseObject({ type: external_exports.string() });
66402
- var ContentBlockSchema = external_exports.union([TextBlockSchema, ImageBlockSchema, ToolUseBlockSchema, ToolResultBlockSchema, OtherBlockSchema]);
66403
- var MessageSchema = external_exports.looseObject({
66404
- role: external_exports.enum(["user", "assistant", "system"]),
66405
- content: external_exports.union([external_exports.string(), external_exports.array(ContentBlockSchema)])
66406
- });
66407
- var ToolSchema = external_exports.looseObject({
66408
- name: external_exports.string().min(1),
66409
- description: external_exports.string().optional(),
66410
- input_schema: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
66411
- });
66412
- var ToolChoiceSchema = external_exports.union([
66413
- external_exports.looseObject({ type: external_exports.enum(["auto", "none", "any"]) }),
66414
- external_exports.looseObject({ type: external_exports.literal("tool"), name: external_exports.string().min(1) })
66415
- ]);
66416
- var SystemSchema = external_exports.union([external_exports.string(), external_exports.array(external_exports.union([TextBlockSchema, OtherBlockSchema]))]);
66417
- var MessagesRequestSchema = external_exports.looseObject({
66418
- model: external_exports.string().optional(),
66419
- system: SystemSchema.optional(),
66420
- messages: external_exports.array(MessageSchema),
66421
- tools: external_exports.array(ToolSchema).optional(),
66422
- tool_choice: ToolChoiceSchema.optional(),
66423
- stream: external_exports.boolean().optional(),
66424
- /** `user_id` is stable for one Claude Code session and differs between sessions, which is what makes it the right key for both the backend's prompt cache and its session header. */
66425
- metadata: external_exports.looseObject({ user_id: external_exports.string().optional() }).optional(),
66426
- /** Claude Code's effort setting. Any string is accepted; the translator honours only the levels the backend understands. */
66427
- output_config: external_exports.looseObject({ effort: external_exports.string().optional() }).optional()
66428
- });
66429
- var CountTokensRequestSchema = external_exports.looseObject({
66430
- system: external_exports.unknown().optional(),
66431
- messages: external_exports.unknown().optional(),
66432
- tools: external_exports.unknown().optional()
66433
- });
66434
- function isTextBlock(block2) {
66435
- return TextBlockSchema.safeParse(block2).success;
66436
- }
66437
- function isImageBlock(block2) {
66438
- return ImageBlockSchema.safeParse(block2).success;
66439
- }
66440
- function isToolUseBlock(block2) {
66441
- return ToolUseBlockSchema.safeParse(block2).success;
66442
- }
66443
- function isToolResultBlock(block2) {
66444
- return ToolResultBlockSchema.safeParse(block2).success;
66445
- }
66446
-
66447
- // src/codex/translate.ts
66448
- function resolveCodexConfig(config2) {
66449
- const overrides = config2?.models;
66450
- return {
66451
- defaultModel: config2?.defaultModel ?? CODEX_DEFAULT_MODEL,
66452
- models: {
66453
- fable: overrides?.fable ?? CODEX_DEFAULT_TIER_MODELS.fable,
66454
- opus: overrides?.opus ?? CODEX_DEFAULT_TIER_MODELS.opus,
66455
- sonnet: overrides?.sonnet ?? CODEX_DEFAULT_TIER_MODELS.sonnet,
66456
- haiku: overrides?.haiku ?? CODEX_DEFAULT_TIER_MODELS.haiku
66457
- },
66458
- effort: config2?.effort ?? CODEX_DEFAULT_EFFORT
66459
- };
66460
- }
66461
- function mapModel(requested, config2) {
66462
- if (requested.startsWith("gpt-")) {
66463
- return requested;
66111
+ const result = rcEventWriteResultFromAnswer(answer);
66112
+ if (result.ok) {
66113
+ deps.completePending(sessionId, requestId);
66464
66114
  }
66465
- const lower = requested.toLowerCase();
66466
- const tier = CODEX_TIERS.find((candidate) => lower.includes(candidate));
66467
- return tier === void 0 ? config2.defaultModel : config2.models[tier];
66468
- }
66469
- var REQUESTABLE_EFFORTS = ["low", "medium", "high"];
66470
- function isRequestableEffort(value) {
66471
- return REQUESTABLE_EFFORTS.includes(value);
66472
- }
66473
- function mapEffort(request7, config2) {
66474
- const requested = request7.output_config?.effort;
66475
- return requested !== void 0 && isRequestableEffort(requested) ? requested : config2.effort;
66115
+ return result;
66476
66116
  }
66477
- var BILLING_HEADER_LINE = /^x-anthropic-billing-header:[^\n]*\n/;
66478
- function systemToInstructions(system) {
66479
- if (system === void 0) {
66480
- return "";
66117
+ async function interruptRcSession(deps, sessionId) {
66118
+ const credential = deps.credentialOf(sessionId);
66119
+ if (credential === void 0) {
66120
+ 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)` };
66481
66121
  }
66482
- const texts = typeof system === "string" ? [system] : system.filter(isTextBlock).map((block2) => block2.text);
66483
- return texts.join("\n").replace(BILLING_HEADER_LINE, "");
66122
+ if (credential.authorization === void 0) {
66123
+ return noOAuthCredentialResult(sessionId);
66124
+ }
66125
+ const body = JSON.stringify(buildRcEventWriteBody(buildRcInterruptPayload(deps.newUuid())));
66126
+ let answer;
66127
+ try {
66128
+ answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
66129
+ } catch (error62) {
66130
+ return { ok: false, message: `the door could not reach the API host to interrupt session ${sessionId}: ${error62 instanceof Error ? error62.message : String(error62)}` };
66131
+ }
66132
+ return rcEventWriteResultFromAnswer(answer);
66484
66133
  }
66485
- var CODEX_TOOL_NAME_LIMIT = 64;
66486
- var TOOL_NAME_HASH_CHARS = 8;
66487
- function shortToolName(name, names) {
66488
- if (name.length <= CODEX_TOOL_NAME_LIMIT) {
66489
- return name;
66134
+ async function setRcSessionModel(deps, sessionId, model) {
66135
+ if (model === "") {
66136
+ 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" };
66490
66137
  }
66491
- const hash2 = (0, import_node_crypto11.createHash)("sha256").update(name).digest("hex").slice(0, TOOL_NAME_HASH_CHARS);
66492
- const shortened = `${name.slice(0, CODEX_TOOL_NAME_LIMIT - TOOL_NAME_HASH_CHARS - 1)}_${hash2}`;
66493
- names.set(shortened, name);
66494
- return shortened;
66138
+ const credential = deps.credentialOf(sessionId);
66139
+ if (credential === void 0) {
66140
+ 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)` };
66141
+ }
66142
+ if (credential.authorization === void 0) {
66143
+ return noOAuthCredentialResult(sessionId);
66144
+ }
66145
+ const body = JSON.stringify(buildRcEventWriteBody(buildRcSetModelPayload(deps.newUuid(), model)));
66146
+ let answer;
66147
+ try {
66148
+ answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
66149
+ } catch (error62) {
66150
+ return { ok: false, message: `the door could not reach the API host to set the model on session ${sessionId}: ${error62 instanceof Error ? error62.message : String(error62)}` };
66151
+ }
66152
+ return rcEventWriteResultFromAnswer(answer);
66495
66153
  }
66496
- var NON_TEXT_TOOL_RESULT = "[non-text tool result omitted]";
66497
- function flattenToolResult(content) {
66498
- if (content === void 0) {
66499
- return "";
66154
+ async function setRcSessionPermissionMode(deps, sessionId, mode) {
66155
+ const credential = deps.credentialOf(sessionId);
66156
+ if (credential === void 0) {
66157
+ 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)` };
66500
66158
  }
66501
- if (typeof content === "string") {
66502
- return content;
66159
+ if (credential.authorization === void 0) {
66160
+ return noOAuthCredentialResult(sessionId);
66503
66161
  }
66504
- return content.map((block2) => isTextBlock(block2) ? block2.text : NON_TEXT_TOOL_RESULT).join("\n");
66162
+ const body = JSON.stringify(buildRcEventWriteBody(buildRcSetPermissionModePayload(deps.newUuid(), mode)));
66163
+ let answer;
66164
+ try {
66165
+ answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
66166
+ } catch (error62) {
66167
+ return { ok: false, message: `the door could not reach the API host to set the permission mode on session ${sessionId}: ${error62 instanceof Error ? error62.message : String(error62)}` };
66168
+ }
66169
+ return rcEventWriteResultFromAnswer(answer);
66505
66170
  }
66506
- function systemReminder(text2) {
66507
- return `<system-reminder>
66508
- ${text2}
66509
- </system-reminder>`;
66171
+
66172
+ // src/frontdoor/rcControl.ts
66173
+ var RC_PERMISSION_MODE_LIST = RC_PERMISSION_MODES.join(", ");
66174
+ var CONTROL_PATH_PREFIX = "/__agent-shim/rc";
66175
+ var CONTROL_BODY_CAP_BYTES = 10485760;
66176
+ function answerJson(response, status, body) {
66177
+ const text2 = JSON.stringify(body);
66178
+ response.writeHead(status, { "content-type": "application/json", "content-length": String(Buffer.byteLength(text2, "utf8")) });
66179
+ response.end(text2);
66510
66180
  }
66511
- function turnBlocks(message) {
66512
- const blocks = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
66513
- if (message.role !== "system") {
66514
- return blocks;
66515
- }
66516
- return blocks.map((block2) => isTextBlock(block2) ? { ...block2, text: systemReminder(block2.text) } : block2);
66181
+ async function readBody(request7) {
66182
+ return await new Promise((resolve, reject) => {
66183
+ const chunks = [];
66184
+ let total = 0;
66185
+ request7.on("data", (chunk) => {
66186
+ total += chunk.length;
66187
+ if (total > CONTROL_BODY_CAP_BYTES) {
66188
+ request7.destroy();
66189
+ reject(new Error("too large"));
66190
+ return;
66191
+ }
66192
+ chunks.push(chunk);
66193
+ });
66194
+ request7.on("end", () => {
66195
+ resolve(Buffer.concat(chunks).toString("utf8"));
66196
+ });
66197
+ request7.on("error", () => {
66198
+ reject(new Error("the request body ended early"));
66199
+ });
66200
+ });
66517
66201
  }
66518
- function messagesToInput(messages, names) {
66519
- const input2 = [];
66520
- let pending;
66521
- const flush = () => {
66522
- if (pending !== void 0 && pending.parts.length > 0) {
66523
- input2.push({ type: "message", role: pending.role, content: pending.parts });
66524
- }
66525
- pending = void 0;
66526
- };
66527
- const partsFor = (role) => {
66528
- if (pending?.role !== role) {
66529
- flush();
66530
- pending = { role, parts: [] };
66202
+ function createRcControlHandler(deps) {
66203
+ const sessionsPath = `${CONTROL_PATH_PREFIX}/sessions`;
66204
+ const statusPath = `${CONTROL_PATH_PREFIX}/status`;
66205
+ const pendingPath = `${CONTROL_PATH_PREFIX}/pending`;
66206
+ const injectPath = `${CONTROL_PATH_PREFIX}/inject`;
66207
+ const answerPath = `${CONTROL_PATH_PREFIX}/answer`;
66208
+ const interruptPath = `${CONTROL_PATH_PREFIX}/interrupt`;
66209
+ const setModelPath = `${CONTROL_PATH_PREFIX}/set-model`;
66210
+ const setPermissionModePath = `${CONTROL_PATH_PREFIX}/set-permission-mode`;
66211
+ return (request7, response) => {
66212
+ const presented = request7.headers.authorization;
66213
+ const bearerPrefix = "bearer ".length;
66214
+ const token = typeof presented === "string" && presented.slice(0, bearerPrefix).toLowerCase() === "bearer " ? presented.slice(bearerPrefix) : void 0;
66215
+ if (token === void 0 || !isLiveCapability(token, [deps.expectedToken])) {
66216
+ answerJson(response, HTTP_STATUS.unauthorized, { error: "the front door's control routes demand this generation's control token as a Bearer credential" });
66217
+ return;
66531
66218
  }
66532
- return pending.parts;
66219
+ const url2 = new URL(request7.url ?? "/", "http://127.0.0.1");
66220
+ const handle = async () => {
66221
+ if (url2.pathname === sessionsPath) {
66222
+ if (request7.method !== "GET") {
66223
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the session list is a GET" });
66224
+ return;
66225
+ }
66226
+ answerJson(response, HTTP_STATUS.ok, { sessions: deps.list() });
66227
+ return;
66228
+ }
66229
+ if (url2.pathname === statusPath || url2.pathname === pendingPath) {
66230
+ if (request7.method !== "GET") {
66231
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the status and pending reads are GETs" });
66232
+ return;
66233
+ }
66234
+ const session = url2.searchParams.get("session") ?? void 0;
66235
+ if (session !== void 0 && !deps.statusOf(session).some((entry) => entry.id === session)) {
66236
+ 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)` });
66237
+ return;
66238
+ }
66239
+ answerJson(response, HTTP_STATUS.ok, url2.pathname === statusPath ? { statuses: deps.statusOf(session) } : { pending: deps.pendingOf(session) });
66240
+ return;
66241
+ }
66242
+ if (url2.pathname === injectPath) {
66243
+ if (request7.method !== "POST") {
66244
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the inject operation is a POST" });
66245
+ return;
66246
+ }
66247
+ let parsed;
66248
+ try {
66249
+ parsed = JSON.parse(await readBody(request7));
66250
+ } catch {
66251
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the inject body is not readable JSON within the control body cap" });
66252
+ return;
66253
+ }
66254
+ if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("text" in parsed) || typeof parsed.session !== "string" || typeof parsed.text !== "string" || parsed.session === "" || parsed.text === "") {
66255
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the inject body must be JSON naming a non-empty session id and text" });
66256
+ return;
66257
+ }
66258
+ const result = await deps.inject(parsed.session, parsed.text);
66259
+ if (result.ok) {
66260
+ answerJson(response, HTTP_STATUS.ok, { session: parsed.session, sequenceNums: result.sequenceNums });
66261
+ return;
66262
+ }
66263
+ answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
66264
+ return;
66265
+ }
66266
+ if (url2.pathname === answerPath) {
66267
+ if (request7.method !== "POST") {
66268
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the answer operation is a POST" });
66269
+ return;
66270
+ }
66271
+ let parsed;
66272
+ try {
66273
+ parsed = JSON.parse(await readBody(request7));
66274
+ } catch {
66275
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the answer body is not readable JSON within the control body cap" });
66276
+ return;
66277
+ }
66278
+ 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 === "") {
66279
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the answer body must be JSON naming a non-empty session id, request id, and an approve boolean" });
66280
+ return;
66281
+ }
66282
+ const text2 = "text" in parsed && typeof parsed.text === "string" ? parsed.text : void 0;
66283
+ if (parsed.approve && text2 !== void 0 && text2 !== "") {
66284
+ 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" });
66285
+ return;
66286
+ }
66287
+ const result = await deps.answer(parsed.session, parsed.request, { approve: parsed.approve, message: parsed.approve ? void 0 : text2 });
66288
+ if (result.ok) {
66289
+ answerJson(response, HTTP_STATUS.ok, { session: parsed.session, request: parsed.request, sequenceNums: result.sequenceNums });
66290
+ return;
66291
+ }
66292
+ answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
66293
+ return;
66294
+ }
66295
+ if (url2.pathname === interruptPath) {
66296
+ if (request7.method !== "POST") {
66297
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the interrupt operation is a POST" });
66298
+ return;
66299
+ }
66300
+ let parsed;
66301
+ try {
66302
+ parsed = JSON.parse(await readBody(request7));
66303
+ } catch {
66304
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the interrupt body is not readable JSON within the control body cap" });
66305
+ return;
66306
+ }
66307
+ if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || typeof parsed.session !== "string" || parsed.session === "") {
66308
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the interrupt body must be JSON naming a non-empty session id" });
66309
+ return;
66310
+ }
66311
+ const result = await deps.interrupt(parsed.session);
66312
+ if (result.ok) {
66313
+ answerJson(response, HTTP_STATUS.ok, { session: parsed.session, sequenceNums: result.sequenceNums });
66314
+ return;
66315
+ }
66316
+ answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
66317
+ return;
66318
+ }
66319
+ if (url2.pathname === setModelPath) {
66320
+ if (request7.method !== "POST") {
66321
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the set-model operation is a POST" });
66322
+ return;
66323
+ }
66324
+ let parsed;
66325
+ try {
66326
+ parsed = JSON.parse(await readBody(request7));
66327
+ } catch {
66328
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the set-model body is not readable JSON within the control body cap" });
66329
+ return;
66330
+ }
66331
+ if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("model" in parsed) || typeof parsed.session !== "string" || typeof parsed.model !== "string" || parsed.session === "" || parsed.model === "") {
66332
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the set-model body must be JSON naming a non-empty session id and model id" });
66333
+ return;
66334
+ }
66335
+ const result = await deps.setModel(parsed.session, parsed.model);
66336
+ if (result.ok) {
66337
+ answerJson(response, HTTP_STATUS.ok, { session: parsed.session, model: parsed.model, sequenceNums: result.sequenceNums });
66338
+ return;
66339
+ }
66340
+ answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
66341
+ return;
66342
+ }
66343
+ if (url2.pathname === setPermissionModePath) {
66344
+ if (request7.method !== "POST") {
66345
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the set-permission-mode operation is a POST" });
66346
+ return;
66347
+ }
66348
+ let parsed;
66349
+ try {
66350
+ parsed = JSON.parse(await readBody(request7));
66351
+ } catch {
66352
+ answerJson(response, HTTP_STATUS.badRequest, { error: "the set-permission-mode body is not readable JSON within the control body cap" });
66353
+ return;
66354
+ }
66355
+ if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("mode" in parsed) || typeof parsed.session !== "string" || parsed.session === "" || !isRcPermissionMode(parsed.mode)) {
66356
+ 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})` });
66357
+ return;
66358
+ }
66359
+ const result = await deps.setPermissionMode(parsed.session, parsed.mode);
66360
+ if (result.ok) {
66361
+ answerJson(response, HTTP_STATUS.ok, { session: parsed.session, mode: parsed.mode, sequenceNums: result.sequenceNums });
66362
+ return;
66363
+ }
66364
+ answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
66365
+ return;
66366
+ }
66367
+ answerJson(response, HTTP_STATUS.notFound, { error: `no such control route: ${url2.pathname}` });
66368
+ };
66369
+ handle().catch((error62) => {
66370
+ answerJson(response, HTTP_STATUS.internalServerError, { error: `the control route failed: ${error62 instanceof Error ? error62.message : String(error62)}` });
66371
+ });
66533
66372
  };
66534
- for (const message of messages) {
66535
- const role = message.role === "assistant" ? "assistant" : "user";
66536
- for (const block2 of turnBlocks(message)) {
66537
- if (isTextBlock(block2)) {
66538
- if (block2.text.trim() === "") {
66539
- continue;
66373
+ }
66374
+ function realRcControlTransport(port, ca) {
66375
+ return {
66376
+ request: async (options) => await new Promise((resolve, reject) => {
66377
+ const request7 = https2.request(
66378
+ {
66379
+ host: "127.0.0.1",
66380
+ port,
66381
+ method: options.method,
66382
+ path: options.path,
66383
+ headers: options.body === void 0 ? options.headers : { ...options.headers, "content-length": String(Buffer.byteLength(options.body, "utf8")) },
66384
+ agent: false,
66385
+ ca: [ca]
66386
+ },
66387
+ (response) => {
66388
+ const chunks = [];
66389
+ response.on("data", (chunk) => {
66390
+ chunks.push(chunk);
66391
+ });
66392
+ response.on("end", () => {
66393
+ resolve({ status: response.statusCode ?? 0, body: Buffer.concat(chunks).toString("utf8") });
66394
+ });
66540
66395
  }
66541
- partsFor(role).push(role === "assistant" ? { type: "output_text", text: block2.text } : { type: "input_text", text: block2.text });
66542
- } else if (isImageBlock(block2)) {
66543
- const { source } = block2;
66544
- partsFor(role).push({
66545
- type: "input_image",
66546
- image_url: source.type === "base64" ? `data:${source.media_type};base64,${source.data}` : source.url
66547
- });
66548
- } else if (isToolUseBlock(block2)) {
66549
- flush();
66550
- input2.push({
66551
- type: "function_call",
66552
- call_id: block2.id,
66553
- name: shortToolName(block2.name, names),
66554
- arguments: JSON.stringify(block2.input ?? {})
66555
- });
66556
- } else if (isToolResultBlock(block2)) {
66557
- flush();
66558
- input2.push({ type: "function_call_output", call_id: block2.tool_use_id, output: flattenToolResult(block2.content) });
66396
+ );
66397
+ request7.once("error", reject);
66398
+ if (options.body === void 0) {
66399
+ request7.end();
66400
+ } else {
66401
+ request7.end(options.body);
66559
66402
  }
66403
+ })
66404
+ };
66405
+ }
66406
+ function controlErrorOf(body) {
66407
+ try {
66408
+ const parsed = JSON.parse(body);
66409
+ if (typeof parsed === "object" && parsed !== null && "error" in parsed && typeof parsed.error === "string") {
66410
+ return parsed.error;
66560
66411
  }
66412
+ } catch {
66413
+ return body;
66561
66414
  }
66562
- flush();
66563
- return input2;
66415
+ return void 0;
66564
66416
  }
66565
- var EMPTY_PARAMETERS = { type: "object", properties: {} };
66566
- function mapTools(tools, names) {
66567
- if (tools === void 0 || tools.length === 0) {
66568
- return void 0;
66417
+ function isRcSessionSummary(value) {
66418
+ if (typeof value !== "object" || value === null) {
66419
+ return false;
66569
66420
  }
66570
- return tools.map((tool) => ({
66571
- type: "function",
66572
- name: shortToolName(tool.name, names),
66573
- description: tool.description ?? "",
66574
- parameters: tool.input_schema ?? EMPTY_PARAMETERS,
66575
- strict: false
66576
- }));
66421
+ if (!("id" in value) || !("createdAt" in value) || !("lastSeenAt" in value)) {
66422
+ return false;
66423
+ }
66424
+ return typeof value.id === "string" && typeof value.createdAt === "number" && typeof value.lastSeenAt === "number";
66577
66425
  }
66578
- function mapToolChoice(choice, names) {
66579
- if (choice === void 0) {
66580
- return void 0;
66426
+ function isRcWorkerFact(value, valueIs) {
66427
+ if (typeof value !== "object" || value === null) {
66428
+ return false;
66581
66429
  }
66582
- switch (choice.type) {
66583
- case "auto":
66584
- case "none":
66585
- return choice.type;
66586
- case "any":
66587
- return "required";
66588
- case "tool":
66589
- return { type: "function", name: shortToolName(choice.name, names) };
66590
- default:
66591
- return choice;
66430
+ if (!("value" in value) || !("observedAt" in value)) {
66431
+ return false;
66592
66432
  }
66433
+ return valueIs(value.value) && typeof value.observedAt === "number";
66593
66434
  }
66594
- function translateRequest(body, config2) {
66595
- const names = /* @__PURE__ */ new Map();
66596
- const effort = mapEffort(body, config2);
66597
- const tools = mapTools(body.tools, names);
66598
- const toolChoice = mapToolChoice(body.tool_choice, names);
66599
- const userId = body.metadata?.user_id;
66600
- const request7 = {
66601
- model: mapModel(body.model ?? "", config2),
66602
- instructions: systemToInstructions(body.system),
66603
- input: messagesToInput(body.messages, names),
66604
- stream: true,
66605
- store: false,
66606
- text: { verbosity: "medium" },
66607
- ...effort === "none" ? {} : { reasoning: { effort, summary: "auto" } },
66608
- ...userId === void 0 ? {} : { prompt_cache_key: userId },
66609
- ...tools === void 0 ? {} : { tools },
66610
- ...toolChoice === void 0 ? {} : { tool_choice: toolChoice }
66611
- };
66612
- return { request: request7, toolNames: names };
66613
- }
66614
-
66615
- // src/codex/events.ts
66616
- var ResponsesUsageSchema = external_exports.looseObject({
66617
- input_tokens: external_exports.number().optional(),
66618
- output_tokens: external_exports.number().optional(),
66619
- input_tokens_details: external_exports.looseObject({ cached_tokens: external_exports.number().optional(), cache_write_tokens: external_exports.number().optional() }).nullish()
66620
- });
66621
- var ResponseCreatedSchema = external_exports.looseObject({
66622
- type: external_exports.literal("response.created"),
66623
- response: external_exports.looseObject({ id: external_exports.string().optional() }).optional()
66624
- });
66625
- var OutputItemAddedSchema = external_exports.looseObject({
66626
- type: external_exports.literal("response.output_item.added"),
66627
- output_index: external_exports.number(),
66628
- item: external_exports.looseObject({
66629
- type: external_exports.string(),
66630
- id: external_exports.string().optional(),
66631
- call_id: external_exports.string().optional(),
66632
- name: external_exports.string().optional()
66633
- })
66634
- });
66635
- var OutputTextDeltaSchema = external_exports.looseObject({
66636
- type: external_exports.literal("response.output_text.delta"),
66637
- output_index: external_exports.number(),
66638
- delta: external_exports.string()
66639
- });
66640
- var FunctionArgumentsDeltaSchema = external_exports.looseObject({
66641
- type: external_exports.literal("response.function_call_arguments.delta"),
66642
- output_index: external_exports.number(),
66643
- delta: external_exports.string()
66644
- });
66645
- var OutputItemDoneSchema = external_exports.looseObject({
66646
- type: external_exports.literal("response.output_item.done"),
66647
- output_index: external_exports.number()
66648
- });
66649
- var ResponseCompletedSchema = external_exports.looseObject({
66650
- type: external_exports.literal("response.completed"),
66651
- response: external_exports.looseObject({ id: external_exports.string().optional(), status: external_exports.string().optional(), usage: ResponsesUsageSchema.nullish() }).optional()
66652
- });
66653
- var ResponseFailedSchema = external_exports.looseObject({
66654
- type: external_exports.literal("response.failed"),
66655
- response: external_exports.looseObject({ error: external_exports.looseObject({ message: external_exports.string().optional() }).nullish() }).optional()
66656
- });
66657
- var StreamErrorSchema = external_exports.looseObject({ type: external_exports.literal("error"), message: external_exports.string().optional() });
66658
- var CodexEventSchema = external_exports.union([
66659
- ResponseCreatedSchema,
66660
- OutputItemAddedSchema,
66661
- OutputTextDeltaSchema,
66662
- FunctionArgumentsDeltaSchema,
66663
- OutputItemDoneSchema,
66664
- ResponseCompletedSchema,
66665
- ResponseFailedSchema,
66666
- StreamErrorSchema
66667
- ]);
66668
- var CodexErrorEnvelopeSchema = external_exports.looseObject({
66669
- error: external_exports.looseObject({
66670
- message: external_exports.string().optional(),
66671
- resets_at: external_exports.number().optional(),
66672
- resets_in_seconds: external_exports.number().optional()
66673
- })
66674
- });
66675
- async function* parseSse(body) {
66676
- const decoder = new TextDecoder();
66677
- let buffer = "";
66678
- let data = "";
66679
- const parsed = function* (raw) {
66680
- try {
66681
- yield JSON.parse(raw);
66682
- } catch {
66683
- }
66684
- };
66685
- for await (const chunk of body) {
66686
- buffer += decoder.decode(chunk, { stream: true });
66687
- let newline = buffer.indexOf("\n");
66688
- while (newline !== -1) {
66689
- const line = buffer.slice(0, newline).replace(/\r$/, "");
66690
- buffer = buffer.slice(newline + 1);
66691
- if (line === "") {
66692
- if (data !== "") {
66693
- yield* parsed(data);
66694
- }
66695
- data = "";
66696
- } else if (line.startsWith("data:")) {
66697
- data += line.slice("data:".length).trimStart();
66698
- }
66699
- newline = buffer.indexOf("\n");
66700
- }
66435
+ function isRcSessionStatus(value) {
66436
+ if (!isRcSessionSummary(value)) {
66437
+ return false;
66701
66438
  }
66702
- const tail = (buffer + decoder.decode()).replace(/\r$/, "");
66703
- if (tail.startsWith("data:")) {
66704
- data += tail.slice("data:".length).trimStart();
66439
+ if (!("pending" in value) || !Array.isArray(value.pending)) {
66440
+ return false;
66705
66441
  }
66706
- if (data !== "") {
66707
- yield* parsed(data);
66442
+ if ("workerState" in value && value.workerState !== void 0 && !isRcWorkerFact(value.workerState, (candidate) => typeof candidate === "string")) {
66443
+ return false;
66708
66444
  }
66709
- }
66710
- async function* codexEvents(body) {
66711
- for await (const raw of parseSse(body)) {
66712
- const event = CodexEventSchema.safeParse(raw);
66713
- if (event.success) {
66714
- yield event.data;
66715
- }
66445
+ if ("workerIdleSeconds" in value && value.workerIdleSeconds !== void 0 && !isRcWorkerFact(value.workerIdleSeconds, (candidate) => typeof candidate === "number")) {
66446
+ return false;
66716
66447
  }
66448
+ return value.pending.every((candidate) => isRcPendingRequestSummary(candidate));
66717
66449
  }
66718
-
66719
- // src/codex/quota.ts
66720
- var QUOTA_FORWARD_HEADERS = [
66721
- "x-codex-active-limit",
66722
- "x-codex-plan-type",
66723
- "x-codex-primary-used-percent",
66724
- "x-codex-secondary-used-percent",
66725
- "x-codex-primary-window-minutes",
66726
- "x-codex-secondary-window-minutes",
66727
- "x-codex-primary-over-secondary-limit-percent",
66728
- "x-codex-primary-reset-after-seconds",
66729
- "x-codex-secondary-reset-after-seconds",
66730
- "x-codex-primary-reset-at",
66731
- "x-codex-secondary-reset-at"
66732
- ];
66733
- function quotaHeaders(upstream) {
66734
- const headers = {};
66735
- for (const name of QUOTA_FORWARD_HEADERS) {
66736
- const value = upstream.get(name);
66737
- if (value !== null && value !== "") {
66738
- headers[name] = value;
66739
- }
66450
+ function isRcPendingRequestSummary(value) {
66451
+ if (typeof value !== "object" || value === null) {
66452
+ return false;
66740
66453
  }
66741
- return headers;
66454
+ if (!("sessionId" in value) || !("requestId" in value) || !("type" in value) || !("summary" in value) || !("observedAt" in value)) {
66455
+ return false;
66456
+ }
66457
+ return typeof value.sessionId === "string" && typeof value.requestId === "string" && typeof value.type === "string" && typeof value.summary === "string" && typeof value.observedAt === "number";
66742
66458
  }
66743
- var EXHAUSTED_PERCENT = "100";
66744
- function unifiedQuotaHeaders(upstream, rejected, quotaError) {
66745
- const headers = { "anthropic-ratelimit-unified-status": rejected ? "rejected" : "allowed" };
66746
- const used7d = upstream.get("x-codex-primary-used-percent") ?? (rejected ? EXHAUSTED_PERCENT : null);
66747
- const reset7d = upstream.get("x-codex-primary-reset-at") ?? (quotaError?.resets_at === void 0 ? null : String(quotaError.resets_at));
66748
- if (used7d !== null && reset7d !== null) {
66749
- headers["anthropic-ratelimit-unified-7d-utilization"] = used7d;
66750
- headers["anthropic-ratelimit-unified-7d-reset"] = reset7d;
66751
- headers["anthropic-ratelimit-unified-reset"] = reset7d;
66459
+ function sequenceNumsOfBody(body) {
66460
+ let parsed;
66461
+ try {
66462
+ parsed = JSON.parse(body);
66463
+ } catch {
66464
+ return void 0;
66752
66465
  }
66753
- if (Number(upstream.get("x-codex-secondary-window-minutes")) > 0) {
66754
- const used5h = upstream.get("x-codex-secondary-used-percent");
66755
- const reset5h = upstream.get("x-codex-secondary-reset-at");
66756
- if (used5h !== null && used5h !== "" && reset5h !== null && reset5h !== "") {
66757
- headers["anthropic-ratelimit-unified-5h-utilization"] = used5h;
66758
- headers["anthropic-ratelimit-unified-5h-reset"] = reset5h;
66759
- const overall = headers["anthropic-ratelimit-unified-reset"];
66760
- if (overall !== void 0) {
66761
- headers["anthropic-ratelimit-unified-reset"] = String(Math.min(Number(overall), Number(reset5h)));
66762
- }
66466
+ if (typeof parsed !== "object" || parsed === null || !("sequenceNums" in parsed) || !Array.isArray(parsed.sequenceNums)) {
66467
+ return void 0;
66468
+ }
66469
+ const sequenceNums = [];
66470
+ const values = parsed.sequenceNums;
66471
+ for (const value of values) {
66472
+ if (typeof value !== "number") {
66473
+ return void 0;
66763
66474
  }
66475
+ sequenceNums.push(value);
66764
66476
  }
66765
- return headers;
66477
+ return sequenceNums;
66766
66478
  }
66767
- var MS_PER_SECOND5 = 1e3;
66768
- function buildUsageSnapshot(upstream, quotaError, nowMs) {
66769
- const used7 = upstream.get("x-codex-primary-used-percent") ?? (quotaError === void 0 ? null : EXHAUSTED_PERCENT);
66770
- const reset7 = upstream.get("x-codex-primary-reset-at") ?? (quotaError?.resets_at === void 0 ? null : String(quotaError.resets_at));
66771
- const sevenDay = used7 !== null && reset7 !== null ? { used_percentage: Number(used7), resets_at: new Date(Number(reset7) * MS_PER_SECOND5).toISOString() } : void 0;
66772
- let fiveHour;
66773
- if (Number(upstream.get("x-codex-secondary-window-minutes")) > 0) {
66774
- const used5 = upstream.get("x-codex-secondary-used-percent");
66775
- const reset5 = upstream.get("x-codex-secondary-reset-at");
66776
- if (used5 !== null && reset5 !== null) {
66777
- fiveHour = { used_percentage: Number(used5), resets_at: new Date(Number(reset5) * MS_PER_SECOND5).toISOString() };
66479
+ function frontDoorRcControl(transport, token) {
66480
+ const headers = { authorization: `Bearer ${token}` };
66481
+ const listAnswerOf = async (path41, what) => {
66482
+ try {
66483
+ return await transport.request({ method: "GET", path: path41, headers });
66484
+ } catch (error62) {
66485
+ throw new Error(`${what}: could not reach the front door's control listener: ${error62 instanceof Error ? error62.message : String(error62)}`, { cause: error62 });
66778
66486
  }
66779
- }
66780
- if (sevenDay === void 0 && fiveHour === void 0) {
66781
- return void 0;
66782
- }
66783
- return {
66784
- updated_at: new Date(nowMs).toISOString(),
66785
- ...sevenDay === void 0 ? {} : { seven_day: sevenDay },
66786
- ...fiveHour === void 0 ? {} : { five_hour: fiveHour }
66787
66487
  };
66788
- }
66789
- function retryAfterSeconds2(upstream, quotaError) {
66790
- const seconds = quotaError?.resets_in_seconds ?? Number(upstream.get("x-codex-primary-reset-after-seconds"));
66791
- return Number.isFinite(seconds) && seconds > 0 ? Math.ceil(seconds) : void 0;
66792
- }
66793
-
66794
- // src/codex/relay.ts
66795
- function anthropicUsage(usage) {
66796
- const cached2 = usage?.input_tokens_details?.cached_tokens ?? 0;
66797
- const written = usage?.input_tokens_details?.cache_write_tokens ?? 0;
66798
- return {
66799
- input_tokens: Math.max(0, (usage?.input_tokens ?? 0) - cached2 - written),
66800
- cache_creation_input_tokens: written,
66801
- cache_read_input_tokens: cached2,
66802
- output_tokens: usage?.output_tokens ?? 0
66488
+ const sessionsOf = (answer, what) => {
66489
+ if (answer.status !== HTTP_STATUS.ok) {
66490
+ throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
66491
+ }
66492
+ let parsed;
66493
+ try {
66494
+ parsed = JSON.parse(answer.body);
66495
+ } catch {
66496
+ throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
66497
+ }
66498
+ if (typeof parsed !== "object" || parsed === null || !("sessions" in parsed) || !Array.isArray(parsed.sessions)) {
66499
+ throw new Error(`${what}: the door's answer named no sessions list: ${answer.body}`);
66500
+ }
66501
+ const candidates = parsed.sessions;
66502
+ const sessions = [];
66503
+ for (const value of candidates) {
66504
+ if (!isRcSessionSummary(value)) {
66505
+ throw new Error(`${what}: the door's answer named no sessions list: ${answer.body}`);
66506
+ }
66507
+ sessions.push(value);
66508
+ }
66509
+ return sessions;
66803
66510
  };
66804
- }
66805
- function renderSseFrame(frame) {
66806
- return `event: ${frame.event}
66807
- data: ${JSON.stringify(frame.data)}
66511
+ const statusesOf = (answer, what) => {
66512
+ if (answer.status !== HTTP_STATUS.ok) {
66513
+ throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
66514
+ }
66515
+ let parsed;
66516
+ try {
66517
+ parsed = JSON.parse(answer.body);
66518
+ } catch {
66519
+ throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
66520
+ }
66521
+ if (typeof parsed !== "object" || parsed === null || !("statuses" in parsed) || !Array.isArray(parsed.statuses)) {
66522
+ throw new Error(`${what}: the door's answer named no status list: ${answer.body}`);
66523
+ }
66524
+ const statuses = [];
66525
+ for (const value of parsed.statuses) {
66526
+ if (!isRcSessionStatus(value)) {
66527
+ throw new Error(`${what}: the door's answer named no status list: ${answer.body}`);
66528
+ }
66529
+ statuses.push(value);
66530
+ }
66531
+ return statuses;
66532
+ };
66533
+ const pendingOfAnswer = (answer, what) => {
66534
+ if (answer.status !== HTTP_STATUS.ok) {
66535
+ throw new Error(`${what} failed (HTTP ${String(answer.status)}): ${controlErrorOf(answer.body) ?? answer.body}`);
66536
+ }
66537
+ let parsed;
66538
+ try {
66539
+ parsed = JSON.parse(answer.body);
66540
+ } catch {
66541
+ throw new Error(`${what}: the door's answer was not JSON: ${answer.body}`);
66542
+ }
66543
+ if (typeof parsed !== "object" || parsed === null || !("pending" in parsed) || !Array.isArray(parsed.pending)) {
66544
+ throw new Error(`${what}: the door's answer named no pending list: ${answer.body}`);
66545
+ }
66546
+ const pending = [];
66547
+ for (const value of parsed.pending) {
66548
+ if (!isRcPendingRequestSummary(value)) {
66549
+ throw new Error(`${what}: the door's answer named no pending list: ${answer.body}`);
66550
+ }
66551
+ pending.push(value);
66552
+ }
66553
+ return pending;
66554
+ };
66555
+ const writeOf = async (path41, body, describeFailure) => {
66556
+ let answer;
66557
+ try {
66558
+ answer = await transport.request({ method: "POST", path: path41, headers: { ...headers, "content-type": "application/json" }, body });
66559
+ } catch (error62) {
66560
+ return { ok: false, message: `could not reach the front door's control listener: ${error62 instanceof Error ? error62.message : String(error62)}` };
66561
+ }
66562
+ if (answer.status === HTTP_STATUS.ok) {
66563
+ const sequenceNums = sequenceNumsOfBody(answer.body);
66564
+ if (sequenceNums === void 0) {
66565
+ return { ok: false, message: `the door accepted the event but its answer named no sequence numbers: ${answer.body}` };
66566
+ }
66567
+ return { ok: true, sequenceNums };
66568
+ }
66569
+ return { ok: false, message: describeFailure(answer.status, controlErrorOf(answer.body) ?? answer.body) };
66570
+ };
66571
+ const sessionQuery = (sessionId) => sessionId === void 0 ? "" : `?session=${encodeURIComponent(sessionId)}`;
66572
+ return {
66573
+ listSessions: async () => sessionsOf(await listAnswerOf(`${CONTROL_PATH_PREFIX}/sessions`, "listing the door's Remote Control sessions"), "listing the door's Remote Control sessions"),
66574
+ 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"),
66575
+ 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"),
66576
+ sendPrompt: async (sessionId, text2) => await writeOf(`${CONTROL_PATH_PREFIX}/inject`, JSON.stringify({ session: sessionId, text: text2 }), (status, message) => `injecting into ${sessionId} failed (HTTP ${String(status)}): ${message}`),
66577
+ answerRequest: async (sessionId, requestId, decision) => await writeOf(
66578
+ `${CONTROL_PATH_PREFIX}/answer`,
66579
+ JSON.stringify({ session: sessionId, request: requestId, approve: decision.approve, ...decision.approve || decision.message === void 0 ? {} : { text: decision.message } }),
66580
+ (status, message) => `answering control request ${requestId} on ${sessionId} failed (HTTP ${String(status)}): ${message}`
66581
+ ),
66582
+ interruptSession: async (sessionId) => await writeOf(`${CONTROL_PATH_PREFIX}/interrupt`, JSON.stringify({ session: sessionId }), (status, message) => `interrupting ${sessionId} failed (HTTP ${String(status)}): ${message}`),
66583
+ 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}`),
66584
+ 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}`)
66585
+ };
66586
+ }
66587
+
66588
+ // src/frontdoor/server.ts
66589
+ var HEALTH_TIMEOUT_MS = 2e3;
66590
+ var HEALTH_START_BUDGET_MS = 5e3;
66591
+ var HEALTH_RETRY_MS = 50;
66592
+ function createFrontDoorServer(pipeline, log, tls2, control) {
66593
+ const handler = (request7, response) => {
66594
+ if (request7.method === "GET" && request7.url === "/healthz") {
66595
+ response.writeHead(HTTP_STATUS.ok, { "Content-Type": "text/plain" });
66596
+ response.end("ok");
66597
+ return;
66598
+ }
66599
+ if (control !== void 0 && (request7.url ?? "/").startsWith(CONTROL_PATH_PREFIX)) {
66600
+ control(request7, response);
66601
+ return;
66602
+ }
66603
+ const abort = new AbortController();
66604
+ response.on("close", () => {
66605
+ if (!response.writableFinished) {
66606
+ abort.abort();
66607
+ }
66608
+ });
66609
+ const handle = async () => {
66610
+ await pipeline({ method: request7.method ?? "GET", url: request7.url ?? "/", headers: aliasLegacyWireHeaders(request7.headers), body: request7, signal: abort.signal, response });
66611
+ if (!request7.readableEnded) {
66612
+ request7.resume();
66613
+ }
66614
+ };
66615
+ handle().catch((error62) => {
66616
+ log(`request ${request7.method ?? "?"} ${request7.url ?? "?"} failed: ${error62 instanceof Error ? `${error62.name}: ${error62.message}` : String(error62)}`);
66617
+ if (!response.headersSent) {
66618
+ response.writeHead(HTTP_STATUS.internalServerError, { "Content-Type": "application/json" });
66619
+ response.end(JSON.stringify({ type: "error", error: { type: "api_error", message: "internal error in the agent-shim front door" } }));
66620
+ } else {
66621
+ response.destroy();
66622
+ }
66623
+ });
66624
+ };
66625
+ if (tls2 === void 0) {
66626
+ return import_node_http.default.createServer(handler);
66627
+ }
66628
+ const server = import_node_https.default.createServer({ key: tls2.keyPem, cert: tls2.certPem }, handler);
66629
+ server.on("tlsClientError", (_error, socket) => {
66630
+ socket.destroy();
66631
+ });
66632
+ return server;
66633
+ }
66634
+ async function frontDoorHealthy(port, ca) {
66635
+ return await new Promise((resolve) => {
66636
+ const onResponse = (response) => {
66637
+ response.resume();
66638
+ resolve(response.statusCode === HTTP_STATUS.ok);
66639
+ };
66640
+ const options = { host: "127.0.0.1", port, path: "/healthz", agent: false, timeout: HEALTH_TIMEOUT_MS };
66641
+ const request7 = ca === void 0 ? import_node_http.default.get(options, onResponse) : import_node_https.default.get({ ...options, ca: [ca] }, onResponse);
66642
+ request7.on("timeout", () => {
66643
+ request7.destroy();
66644
+ });
66645
+ request7.on("error", () => {
66646
+ resolve(false);
66647
+ });
66648
+ });
66649
+ }
66650
+ async function listenFrontDoor(server, options = {}) {
66651
+ const { preferredPort, ca } = options;
66652
+ const tryListen = async (port) => await new Promise((resolve, reject) => {
66653
+ const onError = (error62) => {
66654
+ server.off("error", onError);
66655
+ reject(error62);
66656
+ };
66657
+ server.once("error", onError);
66658
+ server.listen(port, "127.0.0.1", () => {
66659
+ server.off("error", onError);
66660
+ const address = server.address();
66661
+ const bound2 = typeof address === "object" && address !== null ? address.port : 0;
66662
+ if (bound2 === 0) {
66663
+ reject(new Error("could not bind a loopback port"));
66664
+ return;
66665
+ }
66666
+ resolve(bound2);
66667
+ });
66668
+ });
66669
+ let bound;
66670
+ if (preferredPort !== void 0) {
66671
+ try {
66672
+ bound = await tryListen(preferredPort);
66673
+ } catch {
66674
+ bound = await tryListen(0);
66675
+ }
66676
+ } else {
66677
+ bound = await tryListen(0);
66678
+ }
66679
+ options.onBound?.(bound);
66680
+ if (options.onError !== void 0) {
66681
+ server.on("error", options.onError);
66682
+ }
66683
+ const deadline = Date.now() + HEALTH_START_BUDGET_MS;
66684
+ for (; ; ) {
66685
+ if (await frontDoorHealthy(bound, ca)) {
66686
+ return {
66687
+ port: bound,
66688
+ close: async () => {
66689
+ await new Promise((resolve) => {
66690
+ server.close(() => {
66691
+ resolve(void 0);
66692
+ });
66693
+ server.closeAllConnections();
66694
+ });
66695
+ }
66696
+ };
66697
+ }
66698
+ if (Date.now() >= deadline) {
66699
+ throw new Error(`the front door listener on 127.0.0.1:${String(bound)} did not answer its health probe`);
66700
+ }
66701
+ await new Promise((resolve) => {
66702
+ setTimeout(resolve, HEALTH_RETRY_MS);
66703
+ });
66704
+ }
66705
+ }
66706
+ async function* upstreamChunks(stream) {
66707
+ for await (const chunk of stream) {
66708
+ if (typeof chunk === "string") {
66709
+ yield Buffer.from(chunk, "utf8");
66710
+ continue;
66711
+ }
66712
+ if (chunk instanceof Uint8Array) {
66713
+ yield chunk;
66714
+ }
66715
+ }
66716
+ }
66717
+
66718
+ // src/frontdoor/headroomHop.ts
66719
+ var HTTP_BAD_GATEWAY2 = HTTP_STATUS.badGateway;
66720
+ function responseHeaders(headers) {
66721
+ const result = {};
66722
+ for (const [name, value] of Object.entries(forwardableHeaders(headers))) {
66723
+ if (value === void 0) {
66724
+ continue;
66725
+ }
66726
+ result[name] = Array.isArray(value) ? value.join(", ") : value;
66727
+ }
66728
+ return result;
66729
+ }
66730
+ async function applyHeadroomHop(request7, response, upstream, deps) {
66731
+ const target = deps.headroomSocket();
66732
+ if (target === void 0) {
66733
+ await answerBadGateway(response, "agent-shim front door: the headroom daemon is restarting");
66734
+ return;
66735
+ }
66736
+ if (target.refused !== void 0) {
66737
+ deps.log(`front door: refusing the headroom hop (${request7.method} ${new URL(request7.url, "http://127.0.0.1").pathname}): ${target.refused}`);
66738
+ await answerBadGateway(response, `agent-shim front door: refusing to send this request to headroom: ${target.refused}`);
66739
+ return;
66740
+ }
66741
+ const { socketPath } = target;
66742
+ let headers = forwardableHeaders(request7.headers);
66743
+ let hopId;
66744
+ if (upstream !== void 0) {
66745
+ const provider = parseProviderPath(new URL(request7.url, "http://127.0.0.1").pathname)?.provider;
66746
+ if (provider === void 0) {
66747
+ throw new Error(`headroom hop for ${request7.url} names an upstream but no provider`);
66748
+ }
66749
+ const sequestered = deps.custody.sequester(headers, provider);
66750
+ hopId = sequestered.hopId;
66751
+ headers = sequestered.headers;
66752
+ headers[HOP_ID_HEADER] = hopId;
66753
+ headers[HEADROOM_BASE_URL_HEADER] = upstream;
66754
+ }
66755
+ if (request7.session.projectId !== void 0) {
66756
+ headers[PROJECT_ID_HEADER] = request7.session.projectId;
66757
+ }
66758
+ headers[HOP_SECRET_HEADER] = deps.hopSecret;
66759
+ try {
66760
+ await forwardThroughHeadroom(request7, response, { socketPath, headers, log: deps.log });
66761
+ } finally {
66762
+ if (hopId !== void 0) {
66763
+ deps.custody.release(hopId);
66764
+ }
66765
+ }
66766
+ }
66767
+ async function answerBadGateway(response, message) {
66768
+ response.start(HTTP_BAD_GATEWAY2, { "Content-Type": "application/json" });
66769
+ await response.write(JSON.stringify({ type: "error", error: { type: "api_error", message } }));
66770
+ response.end();
66771
+ }
66772
+ var HOP_AGENT = new http3.Agent({ keepAlive: false });
66773
+ async function forwardThroughHeadroom(request7, response, target) {
66774
+ const { socketPath, headers } = target;
66775
+ await new Promise((resolve) => {
66776
+ const onUpstreamResponse = (upstreamResponse) => {
66777
+ response.start(upstreamResponse.statusCode ?? HTTP_BAD_GATEWAY2, responseHeaders(upstreamResponse.headers));
66778
+ response.flush();
66779
+ const stream = async () => {
66780
+ try {
66781
+ for await (const chunk of upstreamChunks(upstreamResponse)) {
66782
+ if (request7.signal.aborted) {
66783
+ break;
66784
+ }
66785
+ await response.write(chunk);
66786
+ }
66787
+ if (!request7.signal.aborted) {
66788
+ response.end();
66789
+ }
66790
+ } catch (error62) {
66791
+ if (!request7.signal.aborted) {
66792
+ target.log(`front door: headroom hop to ${socketPath} ended mid-stream (${request7.method} ${new URL(request7.url, "http://127.0.0.1").pathname}): ${error62 instanceof Error ? error62.message : String(error62)}`);
66793
+ }
66794
+ response.destroy();
66795
+ }
66796
+ resolve(void 0);
66797
+ };
66798
+ void stream();
66799
+ };
66800
+ const hop = http3.request({ socketPath, method: request7.method, path: request7.url, headers, agent: HOP_AGENT }, onUpstreamResponse);
66801
+ hop.on("error", (error62) => {
66802
+ const phase = response.headersSent ? "mid-stream" : "before the response started";
66803
+ const code = "code" in error62 && typeof error62.code === "string" ? ` ${error62.code}` : "";
66804
+ target.log(`front door: headroom hop to ${socketPath} failed (${request7.method} ${new URL(request7.url, "http://127.0.0.1").pathname}, ${phase}): ${error62.message}${code}`);
66805
+ if (!response.headersSent) {
66806
+ response.start(HTTP_BAD_GATEWAY2, { "Content-Type": "application/json" });
66807
+ void response.write(JSON.stringify({ type: "error", error: { type: "api_error", message: `agent-shim front door: the headroom daemon is unreachable (${error62.message})` } })).then(() => {
66808
+ response.end();
66809
+ });
66810
+ } else {
66811
+ response.destroy();
66812
+ }
66813
+ resolve(void 0);
66814
+ });
66815
+ request7.signal.addEventListener("abort", () => {
66816
+ hop.destroy();
66817
+ });
66818
+ request7.body.pipe(hop);
66819
+ request7.body.on("error", () => {
66820
+ hop.destroy();
66821
+ });
66822
+ });
66823
+ }
66824
+
66825
+ // src/frontdoor/pipeline.ts
66826
+ function errorTypeFor(status) {
66827
+ switch (status) {
66828
+ case HTTP_STATUS.badRequest:
66829
+ return "invalid_request_error";
66830
+ case HTTP_STATUS.unauthorized:
66831
+ return "authentication_error";
66832
+ case HTTP_STATUS.forbidden:
66833
+ return "permission_error";
66834
+ case HTTP_STATUS.notFound:
66835
+ return "not_found_error";
66836
+ case HTTP_STATUS.tooManyRequests:
66837
+ return "rate_limit_error";
66838
+ default:
66839
+ return "api_error";
66840
+ }
66841
+ }
66842
+ function errorBody(status, message) {
66843
+ return JSON.stringify({ type: "error", error: { type: errorTypeFor(status), message } });
66844
+ }
66845
+ function pathOf(url2) {
66846
+ const query = url2.indexOf("?");
66847
+ return query === -1 ? url2 : url2.slice(0, query);
66848
+ }
66849
+ function describeThrown(error62) {
66850
+ return error62 instanceof Error ? error62.message : String(error62);
66851
+ }
66852
+ function createRoutedResponse(response, context) {
66853
+ const { deps, session, route, request: request7 } = context;
66854
+ let headersSent = false;
66855
+ let bodyObservers = [];
66856
+ let finished = false;
66857
+ const observeBody = (call) => {
66858
+ bodyObservers = bodyObservers.filter((observer) => {
66859
+ try {
66860
+ call(observer);
66861
+ return true;
66862
+ } catch (error62) {
66863
+ deps.log(`front door: response body observer threw for ${route}: ${describeThrown(error62)}`);
66864
+ return false;
66865
+ }
66866
+ });
66867
+ };
66868
+ const finish = (outcome) => {
66869
+ if (finished) {
66870
+ return;
66871
+ }
66872
+ finished = true;
66873
+ observeBody((observer) => {
66874
+ observer.end(outcome);
66875
+ });
66876
+ bodyObservers = [];
66877
+ };
66878
+ response.once("close", () => {
66879
+ finish(response.writableFinished ? "completed" : "aborted");
66880
+ });
66881
+ const settle2 = async () => {
66882
+ await new Promise((resolve) => {
66883
+ const done = () => {
66884
+ response.off("drain", done);
66885
+ response.off("close", done);
66886
+ resolve();
66887
+ };
66888
+ response.once("drain", done);
66889
+ response.once("close", done);
66890
+ });
66891
+ };
66892
+ return {
66893
+ get headersSent() {
66894
+ return headersSent;
66895
+ },
66896
+ start: (status, headers) => {
66897
+ for (const observe of deps.responseObservers) {
66898
+ try {
66899
+ const body = observe({ session, route, method: request7.method, path: request7.path, receivedAt: request7.receivedAt, status, headers });
66900
+ if (body !== void 0) {
66901
+ bodyObservers.push(body);
66902
+ }
66903
+ } catch (error62) {
66904
+ deps.log(`front door: response observer threw for ${route}: ${describeThrown(error62)}`);
66905
+ }
66906
+ }
66907
+ response.writeHead(status, headers);
66908
+ headersSent = true;
66909
+ },
66910
+ flush: () => {
66911
+ response.flushHeaders();
66912
+ },
66913
+ write: async (chunk) => {
66914
+ if (response.destroyed || response.writableEnded) {
66915
+ return;
66916
+ }
66917
+ const accepted = response.write(chunk);
66918
+ if (bodyObservers.length > 0) {
66919
+ const bytes = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
66920
+ observeBody((observer) => {
66921
+ observer.chunk(bytes);
66922
+ });
66923
+ }
66924
+ if (!accepted) {
66925
+ await settle2();
66926
+ }
66927
+ },
66928
+ end: () => {
66929
+ const outcome = response.destroyed ? "aborted" : "completed";
66930
+ response.end();
66931
+ finish(outcome);
66932
+ },
66933
+ destroy: () => {
66934
+ response.destroy();
66935
+ finish("aborted");
66936
+ }
66937
+ };
66938
+ }
66939
+ async function serveRouted(request7, deps) {
66940
+ const observed = { method: request7.method, path: pathOf(request7.url), receivedAt: deps.now() };
66941
+ const identified = identifyRequest(request7.headers);
66942
+ const admission = deps.admit({ url: request7.url, headers: request7.headers, forwardable: identified.forwardableHeaders });
66943
+ if (!admission.ok) {
66944
+ const response2 = createRoutedResponse(request7.response, { deps, session: identified.session, route: "(unauthorized)", request: observed });
66945
+ response2.start(HTTP_STATUS.unauthorized, { "Content-Type": "application/json" });
66946
+ await response2.write(errorBody(HTTP_STATUS.unauthorized, admission.message));
66947
+ response2.end();
66948
+ return;
66949
+ }
66950
+ const routed = {
66951
+ method: request7.method,
66952
+ url: request7.url,
66953
+ headers: admission.headers,
66954
+ body: request7.body,
66955
+ signal: request7.signal,
66956
+ session: identified.session
66957
+ };
66958
+ const resolution = await deps.resolveRoute(routed);
66959
+ if (!resolution.ok) {
66960
+ const response2 = createRoutedResponse(request7.response, { deps, session: identified.session, route: "(unrouted)", request: observed });
66961
+ response2.start(resolution.status, { "Content-Type": "application/json" });
66962
+ await response2.write(errorBody(resolution.status, resolution.message));
66963
+ response2.end();
66964
+ return;
66965
+ }
66966
+ const response = createRoutedResponse(request7.response, { deps, session: identified.session, route: resolution.route.name, request: observed });
66967
+ try {
66968
+ if (identified.session.headroom && resolution.route.headroomEligible && deps.headroom !== void 0) {
66969
+ await applyHeadroomHop(routed, response, resolution.route.headroomUpstream, deps.headroom);
66970
+ } else {
66971
+ await resolution.route.serve(routed, response);
66972
+ }
66973
+ } catch (error62) {
66974
+ if (request7.signal.aborted) {
66975
+ return;
66976
+ }
66977
+ deps.log(`front door: route ${resolution.route.name} failed: ${error62 instanceof Error ? `${error62.name}: ${error62.message}` : String(error62)}`);
66978
+ if (!response.headersSent) {
66979
+ response.start(HTTP_STATUS.internalServerError, { "Content-Type": "application/json" });
66980
+ await response.write(errorBody(HTTP_STATUS.internalServerError, "internal error in the agent-shim front door"));
66981
+ response.end();
66982
+ return;
66983
+ }
66984
+ response.destroy();
66985
+ }
66986
+ }
66987
+
66988
+ // src/codex/translate.ts
66989
+ var import_node_crypto11 = require("node:crypto");
66990
+
66991
+ // src/codex/anthropic.ts
66992
+ var TextBlockSchema = external_exports.looseObject({ type: external_exports.literal("text"), text: external_exports.string() });
66993
+ var Base64ImageSourceSchema = external_exports.looseObject({ type: external_exports.literal("base64"), media_type: external_exports.string().min(1), data: external_exports.string() });
66994
+ var UrlImageSourceSchema = external_exports.looseObject({ type: external_exports.literal("url"), url: external_exports.string().min(1) });
66995
+ var ImageBlockSchema = external_exports.looseObject({
66996
+ type: external_exports.literal("image"),
66997
+ source: external_exports.union([Base64ImageSourceSchema, UrlImageSourceSchema])
66998
+ });
66999
+ var ToolUseBlockSchema = external_exports.looseObject({
67000
+ type: external_exports.literal("tool_use"),
67001
+ id: external_exports.string().min(1),
67002
+ name: external_exports.string().min(1),
67003
+ input: external_exports.unknown()
67004
+ });
67005
+ var ToolResultContentBlockSchema = external_exports.union([TextBlockSchema, external_exports.looseObject({ type: external_exports.string() })]);
67006
+ var ToolResultBlockSchema = external_exports.looseObject({
67007
+ type: external_exports.literal("tool_result"),
67008
+ tool_use_id: external_exports.string().min(1),
67009
+ content: external_exports.union([external_exports.string(), external_exports.array(ToolResultContentBlockSchema)]).optional()
67010
+ });
67011
+ var OtherBlockSchema = external_exports.looseObject({ type: external_exports.string() });
67012
+ var ContentBlockSchema = external_exports.union([TextBlockSchema, ImageBlockSchema, ToolUseBlockSchema, ToolResultBlockSchema, OtherBlockSchema]);
67013
+ var MessageSchema = external_exports.looseObject({
67014
+ role: external_exports.enum(["user", "assistant", "system"]),
67015
+ content: external_exports.union([external_exports.string(), external_exports.array(ContentBlockSchema)])
67016
+ });
67017
+ var ToolSchema = external_exports.looseObject({
67018
+ name: external_exports.string().min(1),
67019
+ description: external_exports.string().optional(),
67020
+ input_schema: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
67021
+ });
67022
+ var ToolChoiceSchema = external_exports.union([
67023
+ external_exports.looseObject({ type: external_exports.enum(["auto", "none", "any"]) }),
67024
+ external_exports.looseObject({ type: external_exports.literal("tool"), name: external_exports.string().min(1) })
67025
+ ]);
67026
+ var SystemSchema = external_exports.union([external_exports.string(), external_exports.array(external_exports.union([TextBlockSchema, OtherBlockSchema]))]);
67027
+ var MessagesRequestSchema = external_exports.looseObject({
67028
+ model: external_exports.string().optional(),
67029
+ system: SystemSchema.optional(),
67030
+ messages: external_exports.array(MessageSchema),
67031
+ tools: external_exports.array(ToolSchema).optional(),
67032
+ tool_choice: ToolChoiceSchema.optional(),
67033
+ stream: external_exports.boolean().optional(),
67034
+ /** `user_id` is stable for one Claude Code session and differs between sessions, which is what makes it the right key for both the backend's prompt cache and its session header. */
67035
+ metadata: external_exports.looseObject({ user_id: external_exports.string().optional() }).optional(),
67036
+ /** Claude Code's effort setting. Any string is accepted; the translator honours only the levels the backend understands. */
67037
+ output_config: external_exports.looseObject({ effort: external_exports.string().optional() }).optional()
67038
+ });
67039
+ var CountTokensRequestSchema = external_exports.looseObject({
67040
+ system: external_exports.unknown().optional(),
67041
+ messages: external_exports.unknown().optional(),
67042
+ tools: external_exports.unknown().optional()
67043
+ });
67044
+ function isTextBlock(block2) {
67045
+ return TextBlockSchema.safeParse(block2).success;
67046
+ }
67047
+ function isImageBlock(block2) {
67048
+ return ImageBlockSchema.safeParse(block2).success;
67049
+ }
67050
+ function isToolUseBlock(block2) {
67051
+ return ToolUseBlockSchema.safeParse(block2).success;
67052
+ }
67053
+ function isToolResultBlock(block2) {
67054
+ return ToolResultBlockSchema.safeParse(block2).success;
67055
+ }
66808
67056
 
66809
- `;
67057
+ // src/codex/translate.ts
67058
+ function resolveCodexConfig(config2) {
67059
+ const overrides = config2?.models;
67060
+ return {
67061
+ defaultModel: config2?.defaultModel ?? CODEX_DEFAULT_MODEL,
67062
+ models: {
67063
+ fable: overrides?.fable ?? CODEX_DEFAULT_TIER_MODELS.fable,
67064
+ opus: overrides?.opus ?? CODEX_DEFAULT_TIER_MODELS.opus,
67065
+ sonnet: overrides?.sonnet ?? CODEX_DEFAULT_TIER_MODELS.sonnet,
67066
+ haiku: overrides?.haiku ?? CODEX_DEFAULT_TIER_MODELS.haiku
67067
+ },
67068
+ effort: config2?.effort ?? CODEX_DEFAULT_EFFORT
67069
+ };
66810
67070
  }
66811
- function parseToolArguments(json2) {
66812
- if (json2 === "") {
66813
- return {};
67071
+ function mapModel(requested, config2) {
67072
+ if (requested.startsWith("gpt-")) {
67073
+ return requested;
66814
67074
  }
66815
- try {
66816
- const parsed = JSON.parse(json2);
66817
- return parsed;
66818
- } catch {
66819
- return {};
67075
+ const lower = requested.toLowerCase();
67076
+ const tier = CODEX_TIERS.find((candidate) => lower.includes(candidate));
67077
+ return tier === void 0 ? config2.defaultModel : config2.models[tier];
67078
+ }
67079
+ var REQUESTABLE_EFFORTS = ["low", "medium", "high"];
67080
+ function isRequestableEffort(value) {
67081
+ return REQUESTABLE_EFFORTS.includes(value);
67082
+ }
67083
+ function mapEffort(request7, config2) {
67084
+ const requested = request7.output_config?.effort;
67085
+ return requested !== void 0 && isRequestableEffort(requested) ? requested : config2.effort;
67086
+ }
67087
+ var BILLING_HEADER_LINE = /^x-anthropic-billing-header:[^\n]*\n/;
67088
+ function systemToInstructions(system) {
67089
+ if (system === void 0) {
67090
+ return "";
66820
67091
  }
67092
+ const texts = typeof system === "string" ? [system] : system.filter(isTextBlock).map((block2) => block2.text);
67093
+ return texts.join("\n").replace(BILLING_HEADER_LINE, "");
66821
67094
  }
66822
- function wireBlock(block2) {
66823
- return block2.type === "text" ? { type: "text", text: "" } : { type: "tool_use", id: block2.id, name: block2.name, input: {} };
67095
+ var CODEX_TOOL_NAME_LIMIT = 64;
67096
+ var TOOL_NAME_HASH_CHARS = 8;
67097
+ function shortToolName(name, names) {
67098
+ if (name.length <= CODEX_TOOL_NAME_LIMIT) {
67099
+ return name;
67100
+ }
67101
+ const hash2 = (0, import_node_crypto11.createHash)("sha256").update(name).digest("hex").slice(0, TOOL_NAME_HASH_CHARS);
67102
+ const shortened = `${name.slice(0, CODEX_TOOL_NAME_LIMIT - TOOL_NAME_HASH_CHARS - 1)}_${hash2}`;
67103
+ names.set(shortened, name);
67104
+ return shortened;
66824
67105
  }
66825
- function finalBlock(block2) {
66826
- return block2.type === "text" ? { type: "text", text: block2.text } : { type: "tool_use", id: block2.id, name: block2.name, input: parseToolArguments(block2.json) };
67106
+ var NON_TEXT_TOOL_RESULT = "[non-text tool result omitted]";
67107
+ function flattenToolResult(content) {
67108
+ if (content === void 0) {
67109
+ return "";
67110
+ }
67111
+ if (typeof content === "string") {
67112
+ return content;
67113
+ }
67114
+ return content.map((block2) => isTextBlock(block2) ? block2.text : NON_TEXT_TOOL_RESULT).join("\n");
66827
67115
  }
66828
- var STREAM_ERROR = "codex backend stream error";
66829
- function createRelay(params) {
66830
- const blockByOutput = /* @__PURE__ */ new Map();
66831
- const blocks = [];
66832
- let messageId;
66833
- let sawToolUse = false;
66834
- const block2 = (outputIndex) => {
66835
- const index = blockByOutput.get(outputIndex);
66836
- const found = index === void 0 ? void 0 : blocks[index];
66837
- return index === void 0 || found === void 0 ? void 0 : { index, block: found };
67116
+ function systemReminder(text2) {
67117
+ return `<system-reminder>
67118
+ ${text2}
67119
+ </system-reminder>`;
67120
+ }
67121
+ function turnBlocks(message) {
67122
+ const blocks = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
67123
+ if (message.role !== "system") {
67124
+ return blocks;
67125
+ }
67126
+ return blocks.map((block2) => isTextBlock(block2) ? { ...block2, text: systemReminder(block2.text) } : block2);
67127
+ }
67128
+ function messagesToInput(messages, names) {
67129
+ const input2 = [];
67130
+ let pending;
67131
+ const flush = () => {
67132
+ if (pending !== void 0 && pending.parts.length > 0) {
67133
+ input2.push({ type: "message", role: pending.role, content: pending.parts });
67134
+ }
67135
+ pending = void 0;
66838
67136
  };
66839
- const push = (event) => {
66840
- switch (event.type) {
66841
- case "response.created": {
66842
- messageId = event.response?.id ?? params.fallbackId();
66843
- return {
66844
- frames: [
66845
- {
66846
- event: "message_start",
66847
- data: {
66848
- type: "message_start",
66849
- message: {
66850
- id: messageId,
66851
- type: "message",
66852
- role: "assistant",
66853
- model: params.requestedModel,
66854
- content: [],
66855
- stop_reason: null,
66856
- stop_sequence: null,
66857
- usage: { input_tokens: 0, output_tokens: 0 }
66858
- }
66859
- }
66860
- }
66861
- ]
66862
- };
66863
- }
66864
- case "response.output_item.added": {
66865
- const { item } = event;
66866
- let opened;
66867
- if (item.type === "message") {
66868
- opened = { type: "text", text: "" };
66869
- } else if (item.type === "function_call") {
66870
- sawToolUse = true;
66871
- const name = item.name ?? "";
66872
- opened = { type: "tool_use", id: item.call_id ?? item.id ?? params.fallbackId(), name: params.toolNames.get(name) ?? name, json: "" };
66873
- } else {
66874
- return { frames: [] };
66875
- }
66876
- const index = blocks.length;
66877
- blocks.push(opened);
66878
- blockByOutput.set(event.output_index, index);
66879
- return { frames: [{ event: "content_block_start", data: { type: "content_block_start", index, content_block: wireBlock(opened) } }] };
66880
- }
66881
- case "response.output_text.delta": {
66882
- const target = block2(event.output_index);
66883
- if (target?.block.type !== "text") {
66884
- return { frames: [] };
66885
- }
66886
- target.block.text += event.delta;
66887
- return {
66888
- frames: [{ event: "content_block_delta", data: { type: "content_block_delta", index: target.index, delta: { type: "text_delta", text: event.delta } } }]
66889
- };
66890
- }
66891
- case "response.function_call_arguments.delta": {
66892
- const target = block2(event.output_index);
66893
- if (target?.block.type !== "tool_use") {
66894
- return { frames: [] };
67137
+ const partsFor = (role) => {
67138
+ if (pending?.role !== role) {
67139
+ flush();
67140
+ pending = { role, parts: [] };
67141
+ }
67142
+ return pending.parts;
67143
+ };
67144
+ for (const message of messages) {
67145
+ const role = message.role === "assistant" ? "assistant" : "user";
67146
+ for (const block2 of turnBlocks(message)) {
67147
+ if (isTextBlock(block2)) {
67148
+ if (block2.text.trim() === "") {
67149
+ continue;
66895
67150
  }
66896
- target.block.json += event.delta;
66897
- return {
66898
- frames: [
66899
- { event: "content_block_delta", data: { type: "content_block_delta", index: target.index, delta: { type: "input_json_delta", partial_json: event.delta } } }
66900
- ]
66901
- };
66902
- }
66903
- case "response.output_item.done": {
66904
- const target = block2(event.output_index);
66905
- return target === void 0 ? { frames: [] } : { frames: [{ event: "content_block_stop", data: { type: "content_block_stop", index: target.index } }] };
66906
- }
66907
- case "response.completed": {
66908
- const usage = event.response?.usage ?? void 0;
66909
- const stopReason = sawToolUse ? "tool_use" : event.response?.status === "incomplete" ? "max_tokens" : "end_turn";
66910
- const converted = anthropicUsage(usage);
66911
- const content = blocks.map(finalBlock);
66912
- return {
66913
- frames: [
66914
- { event: "message_delta", data: { type: "message_delta", delta: { stop_reason: stopReason, stop_sequence: null }, usage: converted } },
66915
- { event: "message_stop", data: { type: "message_stop" } }
66916
- ],
66917
- completed: {
66918
- message: {
66919
- id: event.response?.id ?? messageId ?? params.fallbackId(),
66920
- type: "message",
66921
- role: "assistant",
66922
- model: params.requestedModel,
66923
- content: content.length === 0 ? [{ type: "text", text: "" }] : content,
66924
- stop_reason: stopReason,
66925
- stop_sequence: null,
66926
- usage: converted
66927
- },
66928
- usage
66929
- }
66930
- };
67151
+ partsFor(role).push(role === "assistant" ? { type: "output_text", text: block2.text } : { type: "input_text", text: block2.text });
67152
+ } else if (isImageBlock(block2)) {
67153
+ const { source } = block2;
67154
+ partsFor(role).push({
67155
+ type: "input_image",
67156
+ image_url: source.type === "base64" ? `data:${source.media_type};base64,${source.data}` : source.url
67157
+ });
67158
+ } else if (isToolUseBlock(block2)) {
67159
+ flush();
67160
+ input2.push({
67161
+ type: "function_call",
67162
+ call_id: block2.id,
67163
+ name: shortToolName(block2.name, names),
67164
+ arguments: JSON.stringify(block2.input ?? {})
67165
+ });
67166
+ } else if (isToolResultBlock(block2)) {
67167
+ flush();
67168
+ input2.push({ type: "function_call_output", call_id: block2.tool_use_id, output: flattenToolResult(block2.content) });
66931
67169
  }
66932
- case "response.failed":
66933
- return { frames: [], failed: { message: event.response?.error?.message ?? STREAM_ERROR } };
66934
- case "error":
66935
- return { frames: [], failed: { message: event.message ?? STREAM_ERROR } };
66936
- default:
66937
- return event;
66938
67170
  }
66939
- };
66940
- return { push };
66941
- }
66942
-
66943
- // src/codex/route.ts
66944
- function errorTypeFor2(status) {
66945
- switch (status) {
66946
- case HTTP_STATUS.badRequest:
66947
- return "invalid_request_error";
66948
- case HTTP_STATUS.unauthorized:
66949
- return "authentication_error";
66950
- case HTTP_STATUS.forbidden:
66951
- return "permission_error";
66952
- case HTTP_STATUS.notFound:
66953
- return "not_found_error";
66954
- case HTTP_STATUS.tooManyRequests:
66955
- return "rate_limit_error";
66956
- default:
66957
- return "api_error";
66958
67171
  }
67172
+ flush();
67173
+ return input2;
66959
67174
  }
66960
- function errorBody2(status, message) {
66961
- return JSON.stringify({ type: "error", error: { type: errorTypeFor2(status), message } });
66962
- }
66963
- function errorResponse(status, message, headers = {}) {
66964
- return { status, headers: { "Content-Type": "application/json", ...headers }, body: errorBody2(status, message) };
66965
- }
66966
- function errorFrame(status, message) {
66967
- return `event: error
66968
- data: ${errorBody2(status, message)}
66969
-
66970
- `;
67175
+ var EMPTY_PARAMETERS = { type: "object", properties: {} };
67176
+ function mapTools(tools, names) {
67177
+ if (tools === void 0 || tools.length === 0) {
67178
+ return void 0;
67179
+ }
67180
+ return tools.map((tool) => ({
67181
+ type: "function",
67182
+ name: shortToolName(tool.name, names),
67183
+ description: tool.description ?? "",
67184
+ parameters: tool.input_schema ?? EMPTY_PARAMETERS,
67185
+ strict: false
67186
+ }));
66971
67187
  }
66972
- var UPSTREAM_DETAIL_CHARS = 2e3;
66973
- var UPSTREAM_LOG_DETAIL_CHARS = 300;
66974
- var CHARS_PER_TOKEN = 4;
66975
- function parseJson3(body) {
66976
- try {
66977
- const value = JSON.parse(body);
66978
- return { ok: true, value };
66979
- } catch (error62) {
66980
- return { ok: false, message: `request body is not JSON: ${error62 instanceof Error ? error62.message : String(error62)}` };
67188
+ function mapToolChoice(choice, names) {
67189
+ if (choice === void 0) {
67190
+ return void 0;
67191
+ }
67192
+ switch (choice.type) {
67193
+ case "auto":
67194
+ case "none":
67195
+ return choice.type;
67196
+ case "any":
67197
+ return "required";
67198
+ case "tool":
67199
+ return { type: "function", name: shortToolName(choice.name, names) };
67200
+ default:
67201
+ return choice;
66981
67202
  }
66982
67203
  }
66983
- function describeError(error62) {
66984
- return error62 instanceof Error ? `${error62.name}: ${error62.message}` : String(error62);
67204
+ function translateRequest(body, config2) {
67205
+ const names = /* @__PURE__ */ new Map();
67206
+ const effort = mapEffort(body, config2);
67207
+ const tools = mapTools(body.tools, names);
67208
+ const toolChoice = mapToolChoice(body.tool_choice, names);
67209
+ const userId = body.metadata?.user_id;
67210
+ const request7 = {
67211
+ model: mapModel(body.model ?? "", config2),
67212
+ instructions: systemToInstructions(body.system),
67213
+ input: messagesToInput(body.messages, names),
67214
+ stream: true,
67215
+ store: false,
67216
+ text: { verbosity: "medium" },
67217
+ ...effort === "none" ? {} : { reasoning: { effort, summary: "auto" } },
67218
+ ...userId === void 0 ? {} : { prompt_cache_key: userId },
67219
+ ...tools === void 0 ? {} : { tools },
67220
+ ...toolChoice === void 0 ? {} : { tool_choice: toolChoice }
67221
+ };
67222
+ return { request: request7, toolNames: names };
66985
67223
  }
66986
- function createCodexRoute(ports) {
66987
- const handleMessages = async (request7, config2, raw) => {
66988
- const parsed = MessagesRequestSchema.safeParse(raw);
66989
- if (!parsed.success) {
66990
- return errorResponse(HTTP_STATUS.badRequest, `not an Anthropic Messages request: ${parsed.error.issues.map((issue2) => `${issue2.path.join(".")}: ${issue2.message}`).join("; ")}`);
66991
- }
66992
- const body = parsed.data;
66993
- const requestedModel = body.model ?? "";
66994
- const { request: upstreamRequest, toolNames } = translateRequest(body, config2);
66995
- const started = ports.now();
66996
- const elapsed = () => `${String(ports.now() - started)}ms`;
66997
- let upstream;
66998
- try {
66999
- upstream = await callCodex(ports.upstream, upstreamRequest, sessionIdFor(body.metadata?.user_id, ports.upstream.randomId), request7.signal);
67000
- } catch (error62) {
67001
- if (request7.signal.aborted) {
67002
- return errorResponse(HTTP_STATUS.clientClosedRequest, "client disconnected");
67003
- }
67004
- ports.log(`${upstreamRequest.model} upstream fetch failed after ${elapsed()}: ${describeError(error62)}`);
67005
- return errorResponse(HTTP_STATUS.badGateway, `codex backend unreachable: ${describeError(error62)}`);
67006
- }
67007
- const snapshot = (quotaError) => {
67008
- const built = buildUsageSnapshot(upstream.headers, quotaError, ports.now());
67009
- if (built !== void 0) {
67010
- ports.writeUsageSnapshot(built);
67011
- }
67012
- };
67013
- if (!upstream.ok || upstream.body === null) {
67014
- const detail = (await upstream.text()).slice(0, UPSTREAM_DETAIL_CHARS);
67015
- let quotaError;
67016
- try {
67017
- const envelope = CodexErrorEnvelopeSchema.safeParse(JSON.parse(detail));
67018
- quotaError = envelope.success ? envelope.data.error : void 0;
67019
- } catch {
67020
- }
67021
- const rejected = upstream.status === HTTP_STATUS.tooManyRequests;
67022
- const retryAfter = rejected ? retryAfterSeconds2(upstream.headers, quotaError) : void 0;
67023
- ports.log(`${upstreamRequest.model} upstream ${String(upstream.status)} ${elapsed()}: ${detail.slice(0, UPSTREAM_LOG_DETAIL_CHARS)}`);
67024
- snapshot(quotaError);
67025
- return errorResponse(upstream.ok ? HTTP_STATUS.badGateway : upstream.status, `codex backend: ${detail}`, {
67026
- ...quotaHeaders(upstream.headers),
67027
- ...unifiedQuotaHeaders(upstream.headers, rejected, quotaError),
67028
- ...retryAfter === void 0 ? {} : { "retry-after": String(retryAfter) }
67029
- });
67030
- }
67031
- snapshot(void 0);
67032
- const relay = createRelay({ requestedModel, toolNames, fallbackId: () => `msg_${ports.upstream.randomId()}` });
67033
- const upstreamBody = upstream.body;
67034
- const quota = { ...quotaHeaders(upstream.headers), ...unifiedQuotaHeaders(upstream.headers, false, void 0) };
67035
- const logCompleted = (message, usage) => {
67036
- ports.log(
67037
- `${upstreamRequest.model} ok ${elapsed()} effort=${upstreamRequest.reasoning?.effort ?? "none"} stop=${message.stop_reason} in=${String(usage?.input_tokens ?? 0)} cached=${String(usage?.input_tokens_details?.cached_tokens ?? 0)} cache_write=${String(usage?.input_tokens_details?.cache_write_tokens ?? 0)} out=${String(usage?.output_tokens ?? 0)}`
67038
- );
67039
- };
67040
- if (body.stream === true) {
67041
- const frames = async function* () {
67042
- try {
67043
- for await (const event of codexEvents(upstreamBody)) {
67044
- const step = relay.push(event);
67045
- for (const frame of step.frames) {
67046
- yield renderSseFrame(frame);
67047
- }
67048
- if (step.completed !== void 0) {
67049
- logCompleted(step.completed.message, step.completed.usage);
67050
- return;
67051
- }
67052
- if (step.failed !== void 0) {
67053
- ports.log(`${upstreamRequest.model} stream error: ${step.failed.message}`);
67054
- yield errorFrame(HTTP_STATUS.internalServerError, step.failed.message);
67055
- return;
67056
- }
67057
- }
67058
- ports.log(`${upstreamRequest.model} stream ended without completing after ${elapsed()}`);
67059
- yield errorFrame(HTTP_STATUS.badGateway, "codex backend stream ended without completing");
67060
- } catch (error62) {
67061
- if (request7.signal.aborted) {
67062
- return;
67063
- }
67064
- ports.log(`${upstreamRequest.model} stream relay failed: ${describeError(error62)}`);
67065
- yield errorFrame(HTTP_STATUS.badGateway, `stream relay failed: ${describeError(error62)}`);
67066
- }
67067
- };
67068
- return {
67069
- status: HTTP_STATUS.ok,
67070
- headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive", ...quota },
67071
- body: frames()
67072
- };
67073
- }
67224
+
67225
+ // src/codex/events.ts
67226
+ var ResponsesUsageSchema = external_exports.looseObject({
67227
+ input_tokens: external_exports.number().optional(),
67228
+ output_tokens: external_exports.number().optional(),
67229
+ input_tokens_details: external_exports.looseObject({ cached_tokens: external_exports.number().optional(), cache_write_tokens: external_exports.number().optional() }).nullish()
67230
+ });
67231
+ var ResponseCreatedSchema = external_exports.looseObject({
67232
+ type: external_exports.literal("response.created"),
67233
+ response: external_exports.looseObject({ id: external_exports.string().optional() }).optional()
67234
+ });
67235
+ var OutputItemAddedSchema = external_exports.looseObject({
67236
+ type: external_exports.literal("response.output_item.added"),
67237
+ output_index: external_exports.number(),
67238
+ item: external_exports.looseObject({
67239
+ type: external_exports.string(),
67240
+ id: external_exports.string().optional(),
67241
+ call_id: external_exports.string().optional(),
67242
+ name: external_exports.string().optional()
67243
+ })
67244
+ });
67245
+ var OutputTextDeltaSchema = external_exports.looseObject({
67246
+ type: external_exports.literal("response.output_text.delta"),
67247
+ output_index: external_exports.number(),
67248
+ delta: external_exports.string()
67249
+ });
67250
+ var FunctionArgumentsDeltaSchema = external_exports.looseObject({
67251
+ type: external_exports.literal("response.function_call_arguments.delta"),
67252
+ output_index: external_exports.number(),
67253
+ delta: external_exports.string()
67254
+ });
67255
+ var OutputItemDoneSchema = external_exports.looseObject({
67256
+ type: external_exports.literal("response.output_item.done"),
67257
+ output_index: external_exports.number()
67258
+ });
67259
+ var ResponseCompletedSchema = external_exports.looseObject({
67260
+ type: external_exports.literal("response.completed"),
67261
+ response: external_exports.looseObject({ id: external_exports.string().optional(), status: external_exports.string().optional(), usage: ResponsesUsageSchema.nullish() }).optional()
67262
+ });
67263
+ var ResponseFailedSchema = external_exports.looseObject({
67264
+ type: external_exports.literal("response.failed"),
67265
+ response: external_exports.looseObject({ error: external_exports.looseObject({ message: external_exports.string().optional() }).nullish() }).optional()
67266
+ });
67267
+ var StreamErrorSchema = external_exports.looseObject({ type: external_exports.literal("error"), message: external_exports.string().optional() });
67268
+ var CodexEventSchema = external_exports.union([
67269
+ ResponseCreatedSchema,
67270
+ OutputItemAddedSchema,
67271
+ OutputTextDeltaSchema,
67272
+ FunctionArgumentsDeltaSchema,
67273
+ OutputItemDoneSchema,
67274
+ ResponseCompletedSchema,
67275
+ ResponseFailedSchema,
67276
+ StreamErrorSchema
67277
+ ]);
67278
+ var CodexErrorEnvelopeSchema = external_exports.looseObject({
67279
+ error: external_exports.looseObject({
67280
+ message: external_exports.string().optional(),
67281
+ resets_at: external_exports.number().optional(),
67282
+ resets_in_seconds: external_exports.number().optional()
67283
+ })
67284
+ });
67285
+ async function* parseSse(body) {
67286
+ const decoder = new TextDecoder();
67287
+ let buffer = "";
67288
+ let data = "";
67289
+ const parsed = function* (raw) {
67074
67290
  try {
67075
- for await (const event of codexEvents(upstreamBody)) {
67076
- const step = relay.push(event);
67077
- if (step.completed !== void 0) {
67078
- logCompleted(step.completed.message, step.completed.usage);
67079
- return { status: HTTP_STATUS.ok, headers: { "Content-Type": "application/json", ...quota }, body: JSON.stringify(step.completed.message) };
67080
- }
67081
- if (step.failed !== void 0) {
67082
- ports.log(`${upstreamRequest.model} stream error: ${step.failed.message}`);
67083
- return errorResponse(HTTP_STATUS.internalServerError, step.failed.message);
67084
- }
67085
- }
67086
- } catch (error62) {
67087
- if (request7.signal.aborted) {
67088
- return errorResponse(HTTP_STATUS.clientClosedRequest, "client disconnected");
67089
- }
67090
- ports.log(`${upstreamRequest.model} stream relay failed: ${describeError(error62)}`);
67091
- return errorResponse(HTTP_STATUS.badGateway, `stream relay failed: ${describeError(error62)}`);
67092
- }
67093
- ports.log(`${upstreamRequest.model} stream ended without completing after ${elapsed()}`);
67094
- return errorResponse(HTTP_STATUS.badGateway, "codex backend stream ended without completing");
67095
- };
67096
- const handleCountTokens = (raw) => {
67097
- const parsed = CountTokensRequestSchema.safeParse(raw);
67098
- if (!parsed.success) {
67099
- return errorResponse(HTTP_STATUS.badRequest, "not a count_tokens request");
67100
- }
67101
- const text2 = JSON.stringify({ system: parsed.data.system, messages: parsed.data.messages, tools: parsed.data.tools });
67102
- return { status: HTTP_STATUS.ok, headers: { "Content-Type": "application/json" }, body: JSON.stringify({ input_tokens: Math.ceil(text2.length / CHARS_PER_TOKEN) }) };
67103
- };
67104
- return async (request7) => {
67105
- if (request7.method === "GET" && request7.path === "/healthz") {
67106
- return { status: HTTP_STATUS.ok, headers: { "Content-Type": "text/plain" }, body: "ok" };
67107
- }
67108
- if (request7.method !== "POST") {
67109
- return errorResponse(HTTP_STATUS.methodNotAllowed, `unsupported ${request7.method} ${request7.path}`);
67110
- }
67111
- const scoped = parseProviderPath(request7.path);
67112
- if (scoped === void 0 || scoped.rest !== "/v1/messages" && scoped.rest !== "/v1/messages/count_tokens") {
67113
- return errorResponse(HTTP_STATUS.notFound, `no such endpoint: ${request7.path}`);
67114
- }
67115
- const provider = ports.loadProvider(scoped.provider);
67116
- if (!provider.ok) {
67117
- return errorResponse(provider.status, provider.message);
67118
- }
67119
- const json2 = parseJson3(request7.body);
67120
- if (!json2.ok) {
67121
- return errorResponse(HTTP_STATUS.badRequest, json2.message);
67291
+ yield JSON.parse(raw);
67292
+ } catch {
67122
67293
  }
67123
- return scoped.rest === "/v1/messages" ? await handleMessages(request7, provider.config, json2.value) : handleCountTokens(json2.value);
67124
67294
  };
67125
- }
67126
-
67127
- // src/frontdoor/codexMount.ts
67128
- var CODEX_MAX_BODY_BYTES = 67108864;
67129
- var BodyTooLargeError = class extends Error {
67130
- constructor() {
67131
- super("request body too large");
67132
- this.name = "BodyTooLargeError";
67133
- }
67134
- };
67135
- async function readBody2(request7) {
67136
- const chunks = [];
67137
- let size = 0;
67138
- for await (const chunk of request7.body) {
67139
- if (!Buffer.isBuffer(chunk)) {
67140
- throw new TypeError("request body chunk was not a Buffer");
67141
- }
67142
- size += chunk.length;
67143
- if (size > CODEX_MAX_BODY_BYTES) {
67144
- throw new BodyTooLargeError();
67295
+ for await (const chunk of body) {
67296
+ buffer += decoder.decode(chunk, { stream: true });
67297
+ let newline = buffer.indexOf("\n");
67298
+ while (newline !== -1) {
67299
+ const line = buffer.slice(0, newline).replace(/\r$/, "");
67300
+ buffer = buffer.slice(newline + 1);
67301
+ if (line === "") {
67302
+ if (data !== "") {
67303
+ yield* parsed(data);
67304
+ }
67305
+ data = "";
67306
+ } else if (line.startsWith("data:")) {
67307
+ data += line.slice("data:".length).trimStart();
67308
+ }
67309
+ newline = buffer.indexOf("\n");
67145
67310
  }
67146
- chunks.push(chunk);
67147
67311
  }
67148
- return Buffer.concat(chunks).toString("utf8");
67149
- }
67150
- async function writeRouteResponse(routed, response, signal) {
67151
- response.start(routed.status, routed.headers);
67152
- if (typeof routed.body === "string") {
67153
- await response.write(routed.body);
67154
- response.end();
67155
- return;
67312
+ const tail = (buffer + decoder.decode()).replace(/\r$/, "");
67313
+ if (tail.startsWith("data:")) {
67314
+ data += tail.slice("data:".length).trimStart();
67156
67315
  }
67157
- for await (const chunk of routed.body) {
67158
- if (signal.aborted) {
67159
- return;
67160
- }
67161
- await response.write(chunk);
67316
+ if (data !== "") {
67317
+ yield* parsed(data);
67162
67318
  }
67163
- response.end();
67164
- }
67165
- function createCodexRouteMount(ports, upstreamBase, provider) {
67166
- const route = createCodexRoute(ports);
67167
- return {
67168
- name: `codex:${provider}`,
67169
- headroomEligible: true,
67170
- headroomUpstream: upstreamBase,
67171
- serve: async (request7, response) => {
67172
- let body;
67173
- try {
67174
- body = await readBody2(request7);
67175
- } catch (error62) {
67176
- const tooLarge = error62 instanceof BodyTooLargeError;
67177
- response.start(tooLarge ? HTTP_STATUS.payloadTooLarge : HTTP_STATUS.badRequest, { "Content-Type": "application/json" });
67178
- await response.write(
67179
- JSON.stringify({ type: "error", error: { type: "invalid_request_error", message: error62 instanceof Error ? error62.message : String(error62) } })
67180
- );
67181
- response.end();
67182
- request7.body.resume();
67183
- return;
67184
- }
67185
- const path41 = new URL(request7.url, "http://127.0.0.1").pathname;
67186
- const translated = { method: request7.method, path: path41, body, signal: request7.signal };
67187
- const routed = await route(translated);
67188
- if (request7.signal.aborted) {
67189
- return;
67190
- }
67191
- await writeRouteResponse(routed, response, request7.signal);
67192
- }
67193
- };
67194
67319
  }
67195
-
67196
- // src/frontdoor/passthrough.ts
67197
- var http4 = __toESM(require("node:http"), 1);
67198
- var https4 = __toESM(require("node:https"), 1);
67199
- function responseHeaders2(headers) {
67200
- const result = {};
67201
- for (const [name, value] of Object.entries(forwardableHeaders(headers))) {
67202
- if (value === void 0) {
67203
- continue;
67320
+ async function* codexEvents(body) {
67321
+ for await (const raw of parseSse(body)) {
67322
+ const event = CodexEventSchema.safeParse(raw);
67323
+ if (event.success) {
67324
+ yield event.data;
67204
67325
  }
67205
- result[name] = Array.isArray(value) ? value.join(", ") : value;
67206
67326
  }
67207
- return result;
67208
- }
67209
- function createPassthroughRoute(name, target) {
67210
- const base = new URL(target.baseUrl);
67211
- const tls2 = base.protocol === "https:";
67212
- const basePath = base.pathname.replace(/\/+$/, "");
67213
- const agent = tls2 ? new ExemptTlsAgent() : new ExemptHttpAgent();
67214
- return {
67215
- name,
67216
- headroomEligible: true,
67217
- headroomUpstream: target.headroomUpstream,
67218
- serve: async (request7, response) => {
67219
- const incoming = new URL(request7.url, "http://127.0.0.1");
67220
- const path41 = target.stripPrefix !== void 0 && incoming.pathname.startsWith(target.stripPrefix) ? incoming.pathname.slice(target.stripPrefix.length) : incoming.pathname;
67221
- const headers = forwardableHeaders(request7.headers);
67222
- delete headers.host;
67223
- await new Promise((resolve) => {
67224
- const options = {
67225
- host: base.hostname,
67226
- port: base.port === "" ? void 0 : Number(base.port),
67227
- method: request7.method,
67228
- path: `${basePath}${path41}${incoming.search}`,
67229
- headers,
67230
- agent
67231
- };
67232
- const onUpstreamResponse = (upstreamResponse) => {
67233
- response.start(upstreamResponse.statusCode ?? HTTP_STATUS.badGateway, responseHeaders2(upstreamResponse.headers));
67234
- response.flush();
67235
- const stream = async () => {
67236
- try {
67237
- for await (const chunk of upstreamChunks(upstreamResponse)) {
67238
- if (request7.signal.aborted) {
67239
- return;
67240
- }
67241
- await response.write(chunk);
67242
- }
67243
- response.end();
67244
- } catch {
67245
- response.destroy();
67246
- }
67247
- resolve(void 0);
67248
- };
67249
- void stream();
67250
- };
67251
- const forward = tls2 ? https4.request(options, onUpstreamResponse) : http4.request(options, onUpstreamResponse);
67252
- forward.on("error", (error62) => {
67253
- if (!response.headersSent) {
67254
- response.start(HTTP_STATUS.badGateway, { "Content-Type": "application/json" });
67255
- void response.write(JSON.stringify({ type: "error", error: { type: "api_error", message: `upstream ${target.baseUrl} unreachable (${error62.message})` } })).then(() => {
67256
- response.end();
67257
- });
67258
- } else {
67259
- response.destroy();
67260
- }
67261
- resolve(void 0);
67262
- });
67263
- request7.signal.addEventListener("abort", () => {
67264
- forward.destroy();
67265
- });
67266
- request7.body.pipe(forward);
67267
- request7.body.on("error", () => {
67268
- forward.destroy();
67269
- });
67270
- });
67271
- }
67272
- };
67273
67327
  }
67274
67328
 
67275
- // src/frontdoor/providerRoute.ts
67276
- function createProviderRouteResolver(deps) {
67277
- const oauthRoute = createPassthroughRoute("anthropic", { baseUrl: `https://${CONNECT_INTERCEPT_HOST}:${String(HTTPS_PORT)}`, stripPrefix: void 0, headroomUpstream: void 0 });
67278
- const passthroughByTarget = /* @__PURE__ */ new Map();
67279
- const passthroughFor = (name, target) => {
67280
- const key = `${name}\0${target.baseUrl}\0${target.stripPrefix ?? ""}\0${target.headroomUpstream ?? ""}`;
67281
- const existing = passthroughByTarget.get(key);
67282
- if (existing !== void 0) {
67283
- return existing;
67284
- }
67285
- const route = createPassthroughRoute(name, target);
67286
- passthroughByTarget.set(key, route);
67287
- return route;
67288
- };
67289
- const resolve = (request7) => {
67290
- const path41 = new URL(request7.url, "http://127.0.0.1").pathname;
67291
- const scoped = parseProviderPath(path41);
67292
- if (scoped === void 0) {
67293
- return path41.startsWith("/v1/") ? { ok: true, route: oauthRoute } : { ok: false, status: HTTP_STATUS.notFound, message: `no such endpoint: ${path41}` };
67329
+ // src/codex/quota.ts
67330
+ var QUOTA_FORWARD_HEADERS = [
67331
+ "x-codex-active-limit",
67332
+ "x-codex-plan-type",
67333
+ "x-codex-primary-used-percent",
67334
+ "x-codex-secondary-used-percent",
67335
+ "x-codex-primary-window-minutes",
67336
+ "x-codex-secondary-window-minutes",
67337
+ "x-codex-primary-over-secondary-limit-percent",
67338
+ "x-codex-primary-reset-after-seconds",
67339
+ "x-codex-secondary-reset-after-seconds",
67340
+ "x-codex-primary-reset-at",
67341
+ "x-codex-secondary-reset-at"
67342
+ ];
67343
+ function quotaHeaders(upstream) {
67344
+ const headers = {};
67345
+ for (const name of QUOTA_FORWARD_HEADERS) {
67346
+ const value = upstream.get(name);
67347
+ if (value !== null && value !== "") {
67348
+ headers[name] = value;
67294
67349
  }
67295
- const { provider } = scoped;
67296
- let definition;
67297
- try {
67298
- definition = loadProvider(deps.providersDir, provider, deps.fs);
67299
- } catch (error62) {
67300
- if (error62 instanceof ConfigValidationError || error62 instanceof LegacyProviderFileError) {
67301
- return { ok: false, status: HTTP_STATUS.internalServerError, message: `provider ${provider} is invalid: ${error62 instanceof Error ? error62.message : String(error62)}` };
67350
+ }
67351
+ return headers;
67352
+ }
67353
+ var EXHAUSTED_PERCENT = "100";
67354
+ function unifiedQuotaHeaders(upstream, rejected, quotaError) {
67355
+ const headers = { "anthropic-ratelimit-unified-status": rejected ? "rejected" : "allowed" };
67356
+ const used7d = upstream.get("x-codex-primary-used-percent") ?? (rejected ? EXHAUSTED_PERCENT : null);
67357
+ const reset7d = upstream.get("x-codex-primary-reset-at") ?? (quotaError?.resets_at === void 0 ? null : String(quotaError.resets_at));
67358
+ if (used7d !== null && reset7d !== null) {
67359
+ headers["anthropic-ratelimit-unified-7d-utilization"] = used7d;
67360
+ headers["anthropic-ratelimit-unified-7d-reset"] = reset7d;
67361
+ headers["anthropic-ratelimit-unified-reset"] = reset7d;
67362
+ }
67363
+ if (Number(upstream.get("x-codex-secondary-window-minutes")) > 0) {
67364
+ const used5h = upstream.get("x-codex-secondary-used-percent");
67365
+ const reset5h = upstream.get("x-codex-secondary-reset-at");
67366
+ if (used5h !== null && used5h !== "" && reset5h !== null && reset5h !== "") {
67367
+ headers["anthropic-ratelimit-unified-5h-utilization"] = used5h;
67368
+ headers["anthropic-ratelimit-unified-5h-reset"] = reset5h;
67369
+ const overall = headers["anthropic-ratelimit-unified-reset"];
67370
+ if (overall !== void 0) {
67371
+ headers["anthropic-ratelimit-unified-reset"] = String(Math.min(Number(overall), Number(reset5h)));
67302
67372
  }
67303
- throw error62;
67304
- }
67305
- if (definition === void 0) {
67306
- return { ok: false, status: HTTP_STATUS.notFound, message: `no provider named "${provider}"` };
67307
67373
  }
67308
- if (isCodexProvider(definition)) {
67309
- const codexProvider = definition;
67310
- return {
67311
- ok: true,
67312
- route: createCodexRouteMount(
67313
- { ...deps.codexPorts, loadProvider: () => ({ ok: true, config: resolveCodexConfig(codexProvider.codex) }) },
67314
- directOrigin(deps.directPort()),
67315
- provider
67316
- )
67317
- };
67374
+ }
67375
+ return headers;
67376
+ }
67377
+ var MS_PER_SECOND5 = 1e3;
67378
+ function buildUsageSnapshot(upstream, quotaError, nowMs) {
67379
+ const used7 = upstream.get("x-codex-primary-used-percent") ?? (quotaError === void 0 ? null : EXHAUSTED_PERCENT);
67380
+ const reset7 = upstream.get("x-codex-primary-reset-at") ?? (quotaError?.resets_at === void 0 ? null : String(quotaError.resets_at));
67381
+ const sevenDay = used7 !== null && reset7 !== null ? { used_percentage: Number(used7), resets_at: new Date(Number(reset7) * MS_PER_SECOND5).toISOString() } : void 0;
67382
+ let fiveHour;
67383
+ if (Number(upstream.get("x-codex-secondary-window-minutes")) > 0) {
67384
+ const used5 = upstream.get("x-codex-secondary-used-percent");
67385
+ const reset5 = upstream.get("x-codex-secondary-reset-at");
67386
+ if (used5 !== null && reset5 !== null) {
67387
+ fiveHour = { used_percentage: Number(used5), resets_at: new Date(Number(reset5) * MS_PER_SECOND5).toISOString() };
67318
67388
  }
67319
- const httpProvider = definition;
67320
- return {
67321
- ok: true,
67322
- route: passthroughFor(`http:${provider}`, {
67323
- baseUrl: httpProvider.baseUrl,
67324
- stripPrefix: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(provider)}`,
67325
- headroomUpstream: directOrigin(deps.directPort())
67326
- })
67327
- };
67389
+ }
67390
+ if (sevenDay === void 0 && fiveHour === void 0) {
67391
+ return void 0;
67392
+ }
67393
+ return {
67394
+ updated_at: new Date(nowMs).toISOString(),
67395
+ ...sevenDay === void 0 ? {} : { seven_day: sevenDay },
67396
+ ...fiveHour === void 0 ? {} : { five_hour: fiveHour }
67328
67397
  };
67329
- return async (request7) => await Promise.resolve(resolve(request7));
67330
67398
  }
67331
-
67332
- // src/frontdoor/rcSessions.ts
67333
- var RC_SESSIONS_PATH_PREFIX = "/v1/code/sessions";
67334
- var RC_SESSION_ID_PREFIX = "cse_";
67335
- var RC_IDLE_EXPIRY_MS = 45e3;
67336
- var RC_CREATE_RESPONSE_CAP_BYTES = 8192;
67337
- var CONFLICT_REASON_HEADER = "x-ccr-conflict-reason";
67338
- var RC_PENDING_DEADLINE_MS = 14e3;
67339
- var RC_REQUEST_PARSE_CAP_BYTES = 262144;
67340
- var RC_PENDING_SUMMARY_EXCERPT_CHARS = 300;
67341
- var SUCCESS_STATUS_MAX_EXCLUSIVE = 300;
67342
- function isSuccessful(status) {
67343
- return status >= HTTP_STATUS.ok && status < SUCCESS_STATUS_MAX_EXCLUSIVE;
67399
+ function retryAfterSeconds2(upstream, quotaError) {
67400
+ const seconds = quotaError?.resets_in_seconds ?? Number(upstream.get("x-codex-primary-reset-after-seconds"));
67401
+ return Number.isFinite(seconds) && seconds > 0 ? Math.ceil(seconds) : void 0;
67344
67402
  }
67345
- function singleHeader(headers, name) {
67346
- const value = headers[name];
67347
- return typeof value === "string" ? value : void 0;
67403
+
67404
+ // src/codex/relay.ts
67405
+ function anthropicUsage(usage) {
67406
+ const cached2 = usage?.input_tokens_details?.cached_tokens ?? 0;
67407
+ const written = usage?.input_tokens_details?.cache_write_tokens ?? 0;
67408
+ return {
67409
+ input_tokens: Math.max(0, (usage?.input_tokens ?? 0) - cached2 - written),
67410
+ cache_creation_input_tokens: written,
67411
+ cache_read_input_tokens: cached2,
67412
+ output_tokens: usage?.output_tokens ?? 0
67413
+ };
67348
67414
  }
67349
- var OAUTH_AUTHORIZATION_PREFIX = "Bearer sk-ant-oat";
67350
- function oauthAuthorizationOf(headers) {
67351
- const value = singleHeader(headers, "authorization");
67352
- return value?.startsWith(OAUTH_AUTHORIZATION_PREFIX) === true ? value : void 0;
67415
+ function renderSseFrame(frame) {
67416
+ return `event: ${frame.event}
67417
+ data: ${JSON.stringify(frame.data)}
67418
+
67419
+ `;
67353
67420
  }
67354
- function sessionCreateId(body) {
67355
- let parsed;
67421
+ function parseToolArguments(json2) {
67422
+ if (json2 === "") {
67423
+ return {};
67424
+ }
67356
67425
  try {
67357
- parsed = JSON.parse(body);
67426
+ const parsed = JSON.parse(json2);
67427
+ return parsed;
67358
67428
  } catch {
67359
- return void 0;
67360
- }
67361
- if (typeof parsed !== "object" || parsed === null || !("session" in parsed)) {
67362
- return void 0;
67363
- }
67364
- const session = parsed.session;
67365
- if (typeof session !== "object" || session === null || !("id" in session)) {
67366
- return void 0;
67429
+ return {};
67367
67430
  }
67368
- const id = session.id;
67369
- return typeof id === "string" && id.startsWith(RC_SESSION_ID_PREFIX) ? id : void 0;
67370
67431
  }
67371
- function isRecord3(value) {
67372
- return typeof value === "object" && value !== null && !Array.isArray(value);
67432
+ function wireBlock(block2) {
67433
+ return block2.type === "text" ? { type: "text", text: "" } : { type: "tool_use", id: block2.id, name: block2.name, input: {} };
67434
+ }
67435
+ function finalBlock(block2) {
67436
+ return block2.type === "text" ? { type: "text", text: block2.text } : { type: "tool_use", id: block2.id, name: block2.name, input: parseToolArguments(block2.json) };
67437
+ }
67438
+ var STREAM_ERROR = "codex backend stream error";
67439
+ function createRelay(params) {
67440
+ const blockByOutput = /* @__PURE__ */ new Map();
67441
+ const blocks = [];
67442
+ let messageId;
67443
+ let sawToolUse = false;
67444
+ const block2 = (outputIndex) => {
67445
+ const index = blockByOutput.get(outputIndex);
67446
+ const found = index === void 0 ? void 0 : blocks[index];
67447
+ return index === void 0 || found === void 0 ? void 0 : { index, block: found };
67448
+ };
67449
+ const push = (event) => {
67450
+ switch (event.type) {
67451
+ case "response.created": {
67452
+ messageId = event.response?.id ?? params.fallbackId();
67453
+ return {
67454
+ frames: [
67455
+ {
67456
+ event: "message_start",
67457
+ data: {
67458
+ type: "message_start",
67459
+ message: {
67460
+ id: messageId,
67461
+ type: "message",
67462
+ role: "assistant",
67463
+ model: params.requestedModel,
67464
+ content: [],
67465
+ stop_reason: null,
67466
+ stop_sequence: null,
67467
+ usage: { input_tokens: 0, output_tokens: 0 }
67468
+ }
67469
+ }
67470
+ }
67471
+ ]
67472
+ };
67473
+ }
67474
+ case "response.output_item.added": {
67475
+ const { item } = event;
67476
+ let opened;
67477
+ if (item.type === "message") {
67478
+ opened = { type: "text", text: "" };
67479
+ } else if (item.type === "function_call") {
67480
+ sawToolUse = true;
67481
+ const name = item.name ?? "";
67482
+ opened = { type: "tool_use", id: item.call_id ?? item.id ?? params.fallbackId(), name: params.toolNames.get(name) ?? name, json: "" };
67483
+ } else {
67484
+ return { frames: [] };
67485
+ }
67486
+ const index = blocks.length;
67487
+ blocks.push(opened);
67488
+ blockByOutput.set(event.output_index, index);
67489
+ return { frames: [{ event: "content_block_start", data: { type: "content_block_start", index, content_block: wireBlock(opened) } }] };
67490
+ }
67491
+ case "response.output_text.delta": {
67492
+ const target = block2(event.output_index);
67493
+ if (target?.block.type !== "text") {
67494
+ return { frames: [] };
67495
+ }
67496
+ target.block.text += event.delta;
67497
+ return {
67498
+ frames: [{ event: "content_block_delta", data: { type: "content_block_delta", index: target.index, delta: { type: "text_delta", text: event.delta } } }]
67499
+ };
67500
+ }
67501
+ case "response.function_call_arguments.delta": {
67502
+ const target = block2(event.output_index);
67503
+ if (target?.block.type !== "tool_use") {
67504
+ return { frames: [] };
67505
+ }
67506
+ target.block.json += event.delta;
67507
+ return {
67508
+ frames: [
67509
+ { event: "content_block_delta", data: { type: "content_block_delta", index: target.index, delta: { type: "input_json_delta", partial_json: event.delta } } }
67510
+ ]
67511
+ };
67512
+ }
67513
+ case "response.output_item.done": {
67514
+ const target = block2(event.output_index);
67515
+ return target === void 0 ? { frames: [] } : { frames: [{ event: "content_block_stop", data: { type: "content_block_stop", index: target.index } }] };
67516
+ }
67517
+ case "response.completed": {
67518
+ const usage = event.response?.usage ?? void 0;
67519
+ const stopReason = sawToolUse ? "tool_use" : event.response?.status === "incomplete" ? "max_tokens" : "end_turn";
67520
+ const converted = anthropicUsage(usage);
67521
+ const content = blocks.map(finalBlock);
67522
+ return {
67523
+ frames: [
67524
+ { event: "message_delta", data: { type: "message_delta", delta: { stop_reason: stopReason, stop_sequence: null }, usage: converted } },
67525
+ { event: "message_stop", data: { type: "message_stop" } }
67526
+ ],
67527
+ completed: {
67528
+ message: {
67529
+ id: event.response?.id ?? messageId ?? params.fallbackId(),
67530
+ type: "message",
67531
+ role: "assistant",
67532
+ model: params.requestedModel,
67533
+ content: content.length === 0 ? [{ type: "text", text: "" }] : content,
67534
+ stop_reason: stopReason,
67535
+ stop_sequence: null,
67536
+ usage: converted
67537
+ },
67538
+ usage
67539
+ }
67540
+ };
67541
+ }
67542
+ case "response.failed":
67543
+ return { frames: [], failed: { message: event.response?.error?.message ?? STREAM_ERROR } };
67544
+ case "error":
67545
+ return { frames: [], failed: { message: event.message ?? STREAM_ERROR } };
67546
+ default:
67547
+ return event;
67548
+ }
67549
+ };
67550
+ return { push };
67373
67551
  }
67374
- function parseJsonObject(body) {
67375
- let parsed;
67376
- try {
67377
- parsed = JSON.parse(body);
67378
- } catch {
67379
- return void 0;
67552
+
67553
+ // src/codex/route.ts
67554
+ function errorTypeFor2(status) {
67555
+ switch (status) {
67556
+ case HTTP_STATUS.badRequest:
67557
+ return "invalid_request_error";
67558
+ case HTTP_STATUS.unauthorized:
67559
+ return "authentication_error";
67560
+ case HTTP_STATUS.forbidden:
67561
+ return "permission_error";
67562
+ case HTTP_STATUS.notFound:
67563
+ return "not_found_error";
67564
+ case HTTP_STATUS.tooManyRequests:
67565
+ return "rate_limit_error";
67566
+ default:
67567
+ return "api_error";
67380
67568
  }
67381
- return isRecord3(parsed) ? parsed : void 0;
67382
- }
67383
- function nonEmptyString(record2, field) {
67384
- const value = record2 === void 0 ? void 0 : record2[field];
67385
- return typeof value === "string" && value !== "" ? value : void 0;
67386
67569
  }
67387
- function finiteNumber(record2, field) {
67388
- const value = record2 === void 0 ? void 0 : record2[field];
67389
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
67570
+ function errorBody2(status, message) {
67571
+ return JSON.stringify({ type: "error", error: { type: errorTypeFor2(status), message } });
67390
67572
  }
67391
- function excerpt(text2) {
67392
- return text2.length <= RC_PENDING_SUMMARY_EXCERPT_CHARS ? text2 : `${text2.slice(0, RC_PENDING_SUMMARY_EXCERPT_CHARS)}...`;
67573
+ function errorResponse(status, message, headers = {}) {
67574
+ return { status, headers: { "Content-Type": "application/json", ...headers }, body: errorBody2(status, message) };
67393
67575
  }
67394
- function payloadEventsOf(body) {
67395
- const parsed = parseJsonObject(body);
67396
- const events = parsed === void 0 ? void 0 : parsed.events;
67397
- if (!Array.isArray(events)) {
67398
- return [];
67399
- }
67400
- const payloads = [];
67401
- for (const event of events) {
67402
- if (!isRecord3(event)) {
67403
- continue;
67404
- }
67405
- const payload = event.payload;
67406
- if (!isRecord3(payload)) {
67407
- continue;
67408
- }
67409
- payloads.push(payload);
67410
- }
67411
- return payloads;
67576
+ function errorFrame(status, message) {
67577
+ return `event: error
67578
+ data: ${errorBody2(status, message)}
67579
+
67580
+ `;
67412
67581
  }
67413
- function pendingOfControlRequestPayload(payload) {
67414
- if (payload.type !== "control_request") {
67415
- return void 0;
67416
- }
67417
- const requestId = nonEmptyString(payload, "request_id") ?? nonEmptyString(payload, "uuid");
67418
- if (requestId === void 0) {
67419
- return void 0;
67420
- }
67421
- const request7 = isRecord3(payload.request) ? payload.request : void 0;
67422
- const subtype = nonEmptyString(request7, "subtype");
67423
- const type = subtype ?? "control_request";
67424
- let summary = "";
67425
- if (subtype === "can_use_tool") {
67426
- const toolName = nonEmptyString(request7, "tool_name") ?? "unknown tool";
67427
- const input2 = request7 === void 0 ? void 0 : request7.input;
67428
- summary = input2 === void 0 ? toolName : `${toolName} ${excerpt(JSON.stringify(input2))}`;
67429
- } else if (request7 !== void 0) {
67430
- summary = excerpt(JSON.stringify(request7));
67582
+ var UPSTREAM_DETAIL_CHARS = 2e3;
67583
+ var UPSTREAM_LOG_DETAIL_CHARS = 300;
67584
+ var CHARS_PER_TOKEN = 4;
67585
+ function parseJson3(body) {
67586
+ try {
67587
+ const value = JSON.parse(body);
67588
+ return { ok: true, value };
67589
+ } catch (error62) {
67590
+ return { ok: false, message: `request body is not JSON: ${error62 instanceof Error ? error62.message : String(error62)}` };
67431
67591
  }
67432
- return { requestId, type, summary };
67433
67592
  }
67434
- function answeredRequestIdsOfControlResponsePayload(payload) {
67435
- if (payload.type !== "control_response") {
67436
- return [];
67437
- }
67438
- const response = isRecord3(payload.response) ? payload.response : void 0;
67439
- const id = nonEmptyString(response, "request_id") ?? nonEmptyString(payload, "request_id") ?? nonEmptyString(payload, "uuid");
67440
- return id === void 0 ? [] : [id];
67593
+ function describeError(error62) {
67594
+ return error62 instanceof Error ? `${error62.name}: ${error62.message}` : String(error62);
67441
67595
  }
67442
- function parseRcRequestBody(kind, body) {
67443
- if (kind === "heartbeat") {
67444
- return { controlRequests: [], answeredRequestIds: [], idleSeconds: finiteNumber(parseJsonObject(body), "idle_seconds"), workerStatus: void 0 };
67445
- }
67446
- if (kind === "worker-registration") {
67447
- return { controlRequests: [], answeredRequestIds: [], idleSeconds: void 0, workerStatus: nonEmptyString(parseJsonObject(body), "status") };
67448
- }
67449
- const controlRequests = [];
67450
- const answeredRequestIds = [];
67451
- for (const payload of payloadEventsOf(body)) {
67452
- const pending = pendingOfControlRequestPayload(payload);
67453
- if (pending !== void 0) {
67454
- controlRequests.push({ requestId: pending.requestId, type: pending.type, summary: pending.summary });
67455
- continue;
67596
+ function createCodexRoute(ports) {
67597
+ const handleMessages = async (request7, config2, raw) => {
67598
+ const parsed = MessagesRequestSchema.safeParse(raw);
67599
+ if (!parsed.success) {
67600
+ return errorResponse(HTTP_STATUS.badRequest, `not an Anthropic Messages request: ${parsed.error.issues.map((issue2) => `${issue2.path.join(".")}: ${issue2.message}`).join("; ")}`);
67456
67601
  }
67457
- answeredRequestIds.push(...answeredRequestIdsOfControlResponsePayload(payload));
67458
- }
67459
- return { controlRequests, answeredRequestIds, idleSeconds: void 0, workerStatus: void 0 };
67460
- }
67461
- function createRcSessionTracker(deps) {
67462
- const entries = /* @__PURE__ */ new Map();
67463
- const expire = (id) => {
67464
- entries.delete(id);
67465
- };
67466
- const expirePendings = (entry, now) => {
67467
- for (const [requestId, pending] of entry.pending) {
67468
- if (now - pending.observedAt >= RC_PENDING_DEADLINE_MS) {
67469
- entry.pending.delete(requestId);
67602
+ const body = parsed.data;
67603
+ const requestedModel = body.model ?? "";
67604
+ const { request: upstreamRequest, toolNames } = translateRequest(body, config2);
67605
+ const started = ports.now();
67606
+ const elapsed = () => `${String(ports.now() - started)}ms`;
67607
+ let upstream;
67608
+ try {
67609
+ upstream = await callCodex(ports.upstream, upstreamRequest, sessionIdFor(body.metadata?.user_id, ports.upstream.randomId), request7.signal);
67610
+ } catch (error62) {
67611
+ if (request7.signal.aborted) {
67612
+ return errorResponse(HTTP_STATUS.clientClosedRequest, "client disconnected");
67470
67613
  }
67614
+ ports.log(`${upstreamRequest.model} upstream fetch failed after ${elapsed()}: ${describeError(error62)}`);
67615
+ return errorResponse(HTTP_STATUS.badGateway, `codex backend unreachable: ${describeError(error62)}`);
67471
67616
  }
67472
- };
67473
- const sweep = () => {
67474
- for (const [id, entry] of entries) {
67475
- if (deps.now() - entry.lastSeenAt >= deps.idleMs) {
67476
- expire(id);
67477
- continue;
67617
+ const snapshot = (quotaError) => {
67618
+ const built = buildUsageSnapshot(upstream.headers, quotaError, ports.now());
67619
+ if (built !== void 0) {
67620
+ ports.writeUsageSnapshot(built);
67478
67621
  }
67479
- expirePendings(entry, deps.now());
67622
+ };
67623
+ if (!upstream.ok || upstream.body === null) {
67624
+ const detail = (await upstream.text()).slice(0, UPSTREAM_DETAIL_CHARS);
67625
+ let quotaError;
67626
+ try {
67627
+ const envelope = CodexErrorEnvelopeSchema.safeParse(JSON.parse(detail));
67628
+ quotaError = envelope.success ? envelope.data.error : void 0;
67629
+ } catch {
67630
+ }
67631
+ const rejected = upstream.status === HTTP_STATUS.tooManyRequests;
67632
+ const retryAfter = rejected ? retryAfterSeconds2(upstream.headers, quotaError) : void 0;
67633
+ ports.log(`${upstreamRequest.model} upstream ${String(upstream.status)} ${elapsed()}: ${detail.slice(0, UPSTREAM_LOG_DETAIL_CHARS)}`);
67634
+ snapshot(quotaError);
67635
+ return errorResponse(upstream.ok ? HTTP_STATUS.badGateway : upstream.status, `codex backend: ${detail}`, {
67636
+ ...quotaHeaders(upstream.headers),
67637
+ ...unifiedQuotaHeaders(upstream.headers, rejected, quotaError),
67638
+ ...retryAfter === void 0 ? {} : { "retry-after": String(retryAfter) }
67639
+ });
67640
+ }
67641
+ snapshot(void 0);
67642
+ const relay = createRelay({ requestedModel, toolNames, fallbackId: () => `msg_${ports.upstream.randomId()}` });
67643
+ const upstreamBody = upstream.body;
67644
+ const quota = { ...quotaHeaders(upstream.headers), ...unifiedQuotaHeaders(upstream.headers, false, void 0) };
67645
+ const logCompleted = (message, usage) => {
67646
+ ports.log(
67647
+ `${upstreamRequest.model} ok ${elapsed()} effort=${upstreamRequest.reasoning?.effort ?? "none"} stop=${message.stop_reason} in=${String(usage?.input_tokens ?? 0)} cached=${String(usage?.input_tokens_details?.cached_tokens ?? 0)} cache_write=${String(usage?.input_tokens_details?.cache_write_tokens ?? 0)} out=${String(usage?.output_tokens ?? 0)}`
67648
+ );
67649
+ };
67650
+ if (body.stream === true) {
67651
+ const frames = async function* () {
67652
+ try {
67653
+ for await (const event of codexEvents(upstreamBody)) {
67654
+ const step = relay.push(event);
67655
+ for (const frame of step.frames) {
67656
+ yield renderSseFrame(frame);
67657
+ }
67658
+ if (step.completed !== void 0) {
67659
+ logCompleted(step.completed.message, step.completed.usage);
67660
+ return;
67661
+ }
67662
+ if (step.failed !== void 0) {
67663
+ ports.log(`${upstreamRequest.model} stream error: ${step.failed.message}`);
67664
+ yield errorFrame(HTTP_STATUS.internalServerError, step.failed.message);
67665
+ return;
67666
+ }
67667
+ }
67668
+ ports.log(`${upstreamRequest.model} stream ended without completing after ${elapsed()}`);
67669
+ yield errorFrame(HTTP_STATUS.badGateway, "codex backend stream ended without completing");
67670
+ } catch (error62) {
67671
+ if (request7.signal.aborted) {
67672
+ return;
67673
+ }
67674
+ ports.log(`${upstreamRequest.model} stream relay failed: ${describeError(error62)}`);
67675
+ yield errorFrame(HTTP_STATUS.badGateway, `stream relay failed: ${describeError(error62)}`);
67676
+ }
67677
+ };
67678
+ return {
67679
+ status: HTTP_STATUS.ok,
67680
+ headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive", ...quota },
67681
+ body: frames()
67682
+ };
67683
+ }
67684
+ try {
67685
+ for await (const event of codexEvents(upstreamBody)) {
67686
+ const step = relay.push(event);
67687
+ if (step.completed !== void 0) {
67688
+ logCompleted(step.completed.message, step.completed.usage);
67689
+ return { status: HTTP_STATUS.ok, headers: { "Content-Type": "application/json", ...quota }, body: JSON.stringify(step.completed.message) };
67690
+ }
67691
+ if (step.failed !== void 0) {
67692
+ ports.log(`${upstreamRequest.model} stream error: ${step.failed.message}`);
67693
+ return errorResponse(HTTP_STATUS.internalServerError, step.failed.message);
67694
+ }
67695
+ }
67696
+ } catch (error62) {
67697
+ if (request7.signal.aborted) {
67698
+ return errorResponse(HTTP_STATUS.clientClosedRequest, "client disconnected");
67699
+ }
67700
+ ports.log(`${upstreamRequest.model} stream relay failed: ${describeError(error62)}`);
67701
+ return errorResponse(HTTP_STATUS.badGateway, `stream relay failed: ${describeError(error62)}`);
67702
+ }
67703
+ ports.log(`${upstreamRequest.model} stream ended without completing after ${elapsed()}`);
67704
+ return errorResponse(HTTP_STATUS.badGateway, "codex backend stream ended without completing");
67705
+ };
67706
+ const handleCountTokens = (raw) => {
67707
+ const parsed = CountTokensRequestSchema.safeParse(raw);
67708
+ if (!parsed.success) {
67709
+ return errorResponse(HTTP_STATUS.badRequest, "not a count_tokens request");
67710
+ }
67711
+ const text2 = JSON.stringify({ system: parsed.data.system, messages: parsed.data.messages, tools: parsed.data.tools });
67712
+ return { status: HTTP_STATUS.ok, headers: { "Content-Type": "application/json" }, body: JSON.stringify({ input_tokens: Math.ceil(text2.length / CHARS_PER_TOKEN) }) };
67713
+ };
67714
+ return async (request7) => {
67715
+ if (request7.method === "GET" && request7.path === "/healthz") {
67716
+ return { status: HTTP_STATUS.ok, headers: { "Content-Type": "text/plain" }, body: "ok" };
67717
+ }
67718
+ if (request7.method !== "POST") {
67719
+ return errorResponse(HTTP_STATUS.methodNotAllowed, `unsupported ${request7.method} ${request7.path}`);
67720
+ }
67721
+ const scoped = parseProviderPath(request7.path);
67722
+ if (scoped === void 0 || scoped.rest !== "/v1/messages" && scoped.rest !== "/v1/messages/count_tokens") {
67723
+ return errorResponse(HTTP_STATUS.notFound, `no such endpoint: ${request7.path}`);
67480
67724
  }
67725
+ const provider = ports.loadProvider(scoped.provider);
67726
+ if (!provider.ok) {
67727
+ return errorResponse(provider.status, provider.message);
67728
+ }
67729
+ const json2 = parseJson3(request7.body);
67730
+ if (!json2.ok) {
67731
+ return errorResponse(HTTP_STATUS.badRequest, json2.message);
67732
+ }
67733
+ return scoped.rest === "/v1/messages" ? await handleMessages(request7, provider.config, json2.value) : handleCountTokens(json2.value);
67481
67734
  };
67482
- const timer = setInterval(sweep, deps.idleMs);
67483
- timer.unref();
67484
- const birth = (id, facts) => {
67485
- const record2 = { id, createdAt: deps.now(), lastSeenAt: deps.now(), ...facts, pending: /* @__PURE__ */ new Map(), workerState: void 0, workerIdleSeconds: void 0 };
67486
- entries.set(id, record2);
67487
- return record2;
67488
- };
67489
- const observeExchange = (request7) => {
67490
- const method = (request7.method ?? "").toUpperCase();
67491
- const path41 = new URL(request7.url ?? "/", "http://127.0.0.1").pathname;
67492
- if (!path41.startsWith(RC_SESSIONS_PATH_PREFIX)) {
67493
- return void 0;
67735
+ }
67736
+
67737
+ // src/frontdoor/codexMount.ts
67738
+ var CODEX_MAX_BODY_BYTES = 67108864;
67739
+ var BodyTooLargeError = class extends Error {
67740
+ constructor() {
67741
+ super("request body too large");
67742
+ this.name = "BodyTooLargeError";
67743
+ }
67744
+ };
67745
+ async function readBody2(request7) {
67746
+ const chunks = [];
67747
+ let size = 0;
67748
+ for await (const chunk of request7.body) {
67749
+ if (!Buffer.isBuffer(chunk)) {
67750
+ throw new TypeError("request body chunk was not a Buffer");
67494
67751
  }
67495
- const tail = path41.slice(RC_SESSIONS_PATH_PREFIX.length);
67496
- const facts = {
67497
- oauthAuthorization: oauthAuthorizationOf(request7.headers),
67498
- anthropicVersion: singleHeader(request7.headers, "anthropic-version"),
67499
- anthropicClientPlatform: singleHeader(request7.headers, "anthropic-client-platform")
67500
- };
67501
- if (tail === "") {
67502
- if (method !== "POST") {
67503
- return void 0;
67504
- }
67505
- let accepted2 = false;
67506
- let buffered2 = 0;
67507
- let body = "";
67508
- return {
67509
- onResponse: (status) => {
67510
- accepted2 = isSuccessful(status);
67511
- },
67512
- onBodyChunk: (chunk) => {
67513
- if (!accepted2 || buffered2 >= RC_CREATE_RESPONSE_CAP_BYTES) {
67514
- return;
67515
- }
67516
- const text2 = Buffer.from(chunk).toString("utf8");
67517
- body = body + text2.slice(0, RC_CREATE_RESPONSE_CAP_BYTES - buffered2);
67518
- buffered2 = body.length;
67519
- },
67520
- onEnd: () => {
67521
- if (!accepted2) {
67522
- return;
67523
- }
67524
- const id2 = sessionCreateId(body);
67525
- if (id2 === void 0) {
67526
- return;
67527
- }
67528
- birth(id2, facts);
67529
- }
67530
- };
67752
+ size += chunk.length;
67753
+ if (size > CODEX_MAX_BODY_BYTES) {
67754
+ throw new BodyTooLargeError();
67531
67755
  }
67532
- const rest = tail.slice(1);
67533
- const [id] = rest.split("/");
67534
- if (id?.startsWith(RC_SESSION_ID_PREFIX) !== true) {
67535
- return void 0;
67756
+ chunks.push(chunk);
67757
+ }
67758
+ return Buffer.concat(chunks).toString("utf8");
67759
+ }
67760
+ async function writeRouteResponse(routed, response, signal) {
67761
+ response.start(routed.status, routed.headers);
67762
+ if (typeof routed.body === "string") {
67763
+ await response.write(routed.body);
67764
+ response.end();
67765
+ return;
67766
+ }
67767
+ for await (const chunk of routed.body) {
67768
+ if (signal.aborted) {
67769
+ return;
67536
67770
  }
67537
- const entry = entries.get(id) ?? birth(id, facts);
67538
- entry.lastSeenAt = deps.now();
67539
- entry.oauthAuthorization = facts.oauthAuthorization ?? entry.oauthAuthorization;
67540
- entry.anthropicVersion = facts.anthropicVersion ?? entry.anthropicVersion;
67541
- entry.anthropicClientPlatform = facts.anthropicClientPlatform ?? entry.anthropicClientPlatform;
67542
- 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;
67543
- let chunks = [];
67544
- let buffered = 0;
67545
- let oversized = false;
67546
- let requestEnded = false;
67547
- let accepted;
67548
- let filed = false;
67549
- const file2 = () => {
67550
- if (filed || accepted !== true || !requestEnded || bodyKind === void 0) {
67771
+ await response.write(chunk);
67772
+ }
67773
+ response.end();
67774
+ }
67775
+ function createCodexRouteMount(ports, upstreamBase, provider) {
67776
+ const route = createCodexRoute(ports);
67777
+ return {
67778
+ name: `codex:${provider}`,
67779
+ headroomEligible: true,
67780
+ headroomUpstream: upstreamBase,
67781
+ serve: async (request7, response) => {
67782
+ let body;
67783
+ try {
67784
+ body = await readBody2(request7);
67785
+ } catch (error62) {
67786
+ const tooLarge = error62 instanceof BodyTooLargeError;
67787
+ response.start(tooLarge ? HTTP_STATUS.payloadTooLarge : HTTP_STATUS.badRequest, { "Content-Type": "application/json" });
67788
+ await response.write(
67789
+ JSON.stringify({ type: "error", error: { type: "invalid_request_error", message: error62 instanceof Error ? error62.message : String(error62) } })
67790
+ );
67791
+ response.end();
67792
+ request7.body.resume();
67551
67793
  return;
67552
67794
  }
67553
- filed = true;
67554
- const factsOfBody = oversized ? void 0 : parseRcRequestBody(bodyKind, Buffer.concat(chunks).toString("utf8"));
67555
- chunks = [];
67556
- const entryNow = entries.get(id);
67557
- if (entryNow === void 0 || factsOfBody === void 0) {
67795
+ const path41 = new URL(request7.url, "http://127.0.0.1").pathname;
67796
+ const translated = { method: request7.method, path: path41, body, signal: request7.signal };
67797
+ const routed = await route(translated);
67798
+ if (request7.signal.aborted) {
67558
67799
  return;
67559
67800
  }
67560
- const now = deps.now();
67561
- for (const controlRequest of factsOfBody.controlRequests) {
67562
- entryNow.pending.set(controlRequest.requestId, { sessionId: id, ...controlRequest, observedAt: now });
67563
- }
67564
- for (const requestId of factsOfBody.answeredRequestIds) {
67565
- entryNow.pending.delete(requestId);
67566
- }
67567
- if (factsOfBody.idleSeconds !== void 0) {
67568
- entryNow.workerIdleSeconds = { value: factsOfBody.idleSeconds, observedAt: now };
67569
- }
67570
- if (factsOfBody.workerStatus !== void 0) {
67571
- entryNow.workerState = { value: factsOfBody.workerStatus, observedAt: now };
67572
- }
67573
- };
67574
- const archiving = method === "POST" && rest === `${id}/archive`;
67575
- return {
67576
- ...bodyKind === void 0 ? {} : {
67577
- onRequestChunk: (chunk) => {
67578
- if (oversized) {
67579
- return;
67580
- }
67581
- chunks.push(Buffer.from(chunk));
67582
- buffered += chunk.length;
67583
- if (buffered > RC_REQUEST_PARSE_CAP_BYTES) {
67584
- oversized = true;
67585
- chunks = [];
67586
- }
67587
- },
67588
- onRequestEnd: () => {
67589
- requestEnded = true;
67590
- file2();
67591
- }
67592
- },
67593
- onResponse: (status, headers) => {
67594
- if (singleHeader(headers, CONFLICT_REASON_HEADER) !== void 0 || archiving && isSuccessful(status)) {
67595
- expire(id);
67596
- return;
67597
- }
67598
- accepted = isSuccessful(status);
67599
- file2();
67600
- },
67601
- onBodyChunk: () => {
67602
- },
67603
- onEnd: () => {
67604
- }
67605
- };
67606
- };
67607
- const summaryOf = ({ id, createdAt, lastSeenAt }) => ({ id, createdAt, lastSeenAt });
67608
- const pendingSummaryOf = ({ sessionId, requestId, type, summary, observedAt: observedAt2 }) => ({ sessionId, requestId, type, summary, observedAt: observedAt2 });
67609
- const sortedEntries = () => [...entries.values()].sort((left, right) => left.createdAt - right.createdAt || (left.id < right.id ? -1 : 1));
67610
- const pendingSorted = (entry) => [...entry.pending.values()].sort((left, right) => left.observedAt - right.observedAt || (left.requestId < right.requestId ? -1 : 1)).map(pendingSummaryOf);
67611
- return {
67612
- observeExchange,
67613
- list: () => {
67614
- sweep();
67615
- return sortedEntries().map(summaryOf);
67616
- },
67617
- statusOf: (sessionId) => {
67618
- sweep();
67619
- return sortedEntries().filter((entry) => sessionId === void 0 || entry.id === sessionId).map((entry) => ({ ...summaryOf(entry), workerState: entry.workerState, workerIdleSeconds: entry.workerIdleSeconds, pending: pendingSorted(entry) }));
67620
- },
67621
- pendingOf: (sessionId) => {
67622
- sweep();
67623
- return sortedEntries().filter((entry) => sessionId === void 0 || entry.id === sessionId).flatMap((entry) => pendingSorted(entry));
67624
- },
67625
- credentialOf: (sessionId) => {
67626
- const entry = entries.get(sessionId);
67627
- return entry === void 0 ? void 0 : { authorization: entry.oauthAuthorization, anthropicVersion: entry.anthropicVersion, anthropicClientPlatform: entry.anthropicClientPlatform };
67628
- },
67629
- completePending: (sessionId, requestId) => {
67630
- entries.get(sessionId)?.pending.delete(requestId);
67631
- },
67632
- close: () => {
67633
- clearInterval(timer);
67801
+ await writeRouteResponse(routed, response, request7.signal);
67634
67802
  }
67635
67803
  };
67636
67804
  }
67637
- function observingRoutedRoute(route, tracker) {
67805
+
67806
+ // src/frontdoor/passthrough.ts
67807
+ var http4 = __toESM(require("node:http"), 1);
67808
+ var https4 = __toESM(require("node:https"), 1);
67809
+ function responseHeaders2(headers) {
67810
+ const result = {};
67811
+ for (const [name, value] of Object.entries(forwardableHeaders(headers))) {
67812
+ if (value === void 0) {
67813
+ continue;
67814
+ }
67815
+ result[name] = Array.isArray(value) ? value.join(", ") : value;
67816
+ }
67817
+ return result;
67818
+ }
67819
+ function createPassthroughRoute(name, target) {
67820
+ const base = new URL(target.baseUrl);
67821
+ const tls2 = base.protocol === "https:";
67822
+ const basePath = base.pathname.replace(/\/+$/, "");
67823
+ const agent = tls2 ? new ExemptTlsAgent() : new ExemptHttpAgent();
67638
67824
  return {
67639
- ...route,
67825
+ name,
67826
+ headroomEligible: true,
67827
+ headroomUpstream: target.headroomUpstream,
67640
67828
  serve: async (request7, response) => {
67641
- const observed = tracker.observeExchange({ method: request7.method, url: request7.url, headers: request7.headers });
67642
- if (observed?.onRequestChunk !== void 0) {
67643
- request7.body.on("data", (chunk) => {
67644
- observed.onRequestChunk?.(chunk);
67829
+ const incoming = new URL(request7.url, "http://127.0.0.1");
67830
+ const path41 = target.stripPrefix !== void 0 && incoming.pathname.startsWith(target.stripPrefix) ? incoming.pathname.slice(target.stripPrefix.length) : incoming.pathname;
67831
+ const headers = forwardableHeaders(request7.headers);
67832
+ delete headers.host;
67833
+ await new Promise((resolve) => {
67834
+ const options = {
67835
+ host: base.hostname,
67836
+ port: base.port === "" ? void 0 : Number(base.port),
67837
+ method: request7.method,
67838
+ path: `${basePath}${path41}${incoming.search}`,
67839
+ headers,
67840
+ agent
67841
+ };
67842
+ const onUpstreamResponse = (upstreamResponse) => {
67843
+ response.start(upstreamResponse.statusCode ?? HTTP_STATUS.badGateway, responseHeaders2(upstreamResponse.headers));
67844
+ response.flush();
67845
+ const stream = async () => {
67846
+ try {
67847
+ for await (const chunk of upstreamChunks(upstreamResponse)) {
67848
+ if (request7.signal.aborted) {
67849
+ return;
67850
+ }
67851
+ await response.write(chunk);
67852
+ }
67853
+ response.end();
67854
+ } catch {
67855
+ response.destroy();
67856
+ }
67857
+ resolve(void 0);
67858
+ };
67859
+ void stream();
67860
+ };
67861
+ const forward = tls2 ? https4.request(options, onUpstreamResponse) : http4.request(options, onUpstreamResponse);
67862
+ forward.on("error", (error62) => {
67863
+ if (!response.headersSent) {
67864
+ response.start(HTTP_STATUS.badGateway, { "Content-Type": "application/json" });
67865
+ void response.write(JSON.stringify({ type: "error", error: { type: "api_error", message: `upstream ${target.baseUrl} unreachable (${error62.message})` } })).then(() => {
67866
+ response.end();
67867
+ });
67868
+ } else {
67869
+ response.destroy();
67870
+ }
67871
+ resolve(void 0);
67645
67872
  });
67646
- request7.body.on("end", () => {
67647
- observed.onRequestEnd?.();
67873
+ request7.signal.addEventListener("abort", () => {
67874
+ forward.destroy();
67648
67875
  });
67649
- }
67650
- await route.serve(request7, observed === void 0 ? response : teeRoutedResponse(response, observed));
67876
+ request7.body.pipe(forward);
67877
+ request7.body.on("error", () => {
67878
+ forward.destroy();
67879
+ });
67880
+ });
67651
67881
  }
67652
67882
  };
67653
67883
  }
67654
- function teeRoutedResponse(response, observer) {
67655
- return {
67656
- get headersSent() {
67657
- return response.headersSent;
67658
- },
67659
- start: (status, headers) => {
67660
- observer.onResponse(status, headers);
67661
- response.start(status, headers);
67662
- },
67663
- flush: () => {
67664
- response.flush();
67665
- },
67666
- write: async (chunk) => {
67667
- observer.onBodyChunk(typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk);
67668
- await response.write(chunk);
67669
- },
67670
- end: () => {
67671
- response.end();
67672
- observer.onEnd();
67673
- },
67674
- destroy: () => {
67675
- response.destroy();
67676
- observer.onEnd();
67884
+
67885
+ // src/frontdoor/providerRoute.ts
67886
+ function createProviderRouteResolver(deps) {
67887
+ const oauthRoute = createPassthroughRoute("anthropic", { baseUrl: `https://${CONNECT_INTERCEPT_HOST}:${String(HTTPS_PORT)}`, stripPrefix: void 0, headroomUpstream: void 0 });
67888
+ const passthroughByTarget = /* @__PURE__ */ new Map();
67889
+ const passthroughFor = (name, target) => {
67890
+ const key = `${name}\0${target.baseUrl}\0${target.stripPrefix ?? ""}\0${target.headroomUpstream ?? ""}`;
67891
+ const existing = passthroughByTarget.get(key);
67892
+ if (existing !== void 0) {
67893
+ return existing;
67677
67894
  }
67895
+ const route = createPassthroughRoute(name, target);
67896
+ passthroughByTarget.set(key, route);
67897
+ return route;
67678
67898
  };
67679
- }
67680
- function buildRcUserMessagePayload(uuid3, sessionId, text2) {
67681
- return {
67682
- type: "user",
67683
- uuid: uuid3,
67684
- session_id: sessionId,
67685
- parent_tool_use_id: null,
67686
- message: { role: "user", content: text2 }
67687
- };
67688
- }
67689
- function buildRcEventWriteBody(payload) {
67690
- return { events: [{ payload }] };
67691
- }
67692
- function sequenceNumsOf(body) {
67693
- let parsed;
67694
- try {
67695
- parsed = JSON.parse(body);
67696
- } catch {
67697
- return void 0;
67698
- }
67699
- if (typeof parsed !== "object" || parsed === null || !("results" in parsed) || !Array.isArray(parsed.results)) {
67700
- return void 0;
67701
- }
67702
- const sequenceNums = [];
67703
- const results = parsed.results;
67704
- for (const result of results) {
67705
- if (typeof result !== "object" || result === null || !("sequence_num" in result)) {
67706
- return void 0;
67899
+ const resolve = (request7) => {
67900
+ const path41 = new URL(request7.url, "http://127.0.0.1").pathname;
67901
+ const scoped = parseProviderPath(path41);
67902
+ if (scoped === void 0) {
67903
+ return path41.startsWith("/v1/") ? { ok: true, route: oauthRoute } : { ok: false, status: HTTP_STATUS.notFound, message: `no such endpoint: ${path41}` };
67707
67904
  }
67708
- const sequenceNum = result.sequence_num;
67709
- if (typeof sequenceNum === "number") {
67710
- sequenceNums.push(sequenceNum);
67711
- } else if (typeof sequenceNum === "string" && /^[0-9]+$/.test(sequenceNum)) {
67712
- sequenceNums.push(Number(sequenceNum));
67713
- } else {
67714
- return void 0;
67905
+ const { provider } = scoped;
67906
+ let definition;
67907
+ try {
67908
+ definition = loadProvider(deps.providersDir, provider, deps.fs);
67909
+ } catch (error62) {
67910
+ if (error62 instanceof ConfigValidationError || error62 instanceof LegacyProviderFileError) {
67911
+ return { ok: false, status: HTTP_STATUS.internalServerError, message: `provider ${provider} is invalid: ${error62 instanceof Error ? error62.message : String(error62)}` };
67912
+ }
67913
+ throw error62;
67715
67914
  }
67716
- }
67717
- return sequenceNums.length === 0 ? void 0 : sequenceNums;
67718
- }
67719
- function rcEventWriteResultFromAnswer(answer) {
67720
- if (!isSuccessful(answer.status)) {
67721
- if (answer.status === HTTP_STATUS.unauthorized) {
67722
- 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}` };
67915
+ if (definition === void 0) {
67916
+ return { ok: false, status: HTTP_STATUS.notFound, message: `no provider named "${provider}"` };
67723
67917
  }
67724
- return { ok: false, message: `the API answered HTTP ${String(answer.status)} to the injected event: ${answer.body}` };
67725
- }
67726
- const sequenceNums = sequenceNumsOf(answer.body);
67727
- if (sequenceNums === void 0) {
67728
- 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}` };
67729
- }
67730
- return { ok: true, sequenceNums };
67731
- }
67732
- function noOAuthCredentialResult(sessionId) {
67733
- 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` };
67734
- }
67735
- function rcWriteHeaders(credential) {
67736
- const headers = { "content-type": "application/json" };
67737
- if (credential.authorization !== void 0) {
67738
- headers.authorization = credential.authorization;
67739
- }
67740
- if (credential.anthropicVersion !== void 0) {
67741
- headers["anthropic-version"] = credential.anthropicVersion;
67742
- }
67743
- if (credential.anthropicClientPlatform !== void 0) {
67744
- headers["anthropic-client-platform"] = credential.anthropicClientPlatform;
67745
- }
67746
- return headers;
67747
- }
67748
- async function injectRcUserMessage(deps, sessionId, text2) {
67749
- const credential = deps.credentialOf(sessionId);
67750
- if (credential === void 0) {
67751
- 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)` };
67752
- }
67753
- if (credential.authorization === void 0) {
67754
- return noOAuthCredentialResult(sessionId);
67755
- }
67756
- const body = JSON.stringify(buildRcEventWriteBody(buildRcUserMessagePayload(deps.newUuid(), sessionId, text2)));
67757
- let answer;
67758
- try {
67759
- answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
67760
- } catch (error62) {
67761
- return { ok: false, message: `the door could not reach the API host to inject into session ${sessionId}: ${error62 instanceof Error ? error62.message : String(error62)}` };
67762
- }
67763
- return rcEventWriteResultFromAnswer(answer);
67764
- }
67765
- function buildRcControlResponsePayload(requestId, decision) {
67766
- const result = decision.approve ? { behavior: "allow" } : { behavior: "deny", message: decision.message ?? "" };
67767
- return { type: "control_response", response: { subtype: "success", request_id: requestId, response: result } };
67768
- }
67769
- async function answerRcControlRequest(deps, sessionId, requestId, decision) {
67770
- const credential = deps.credentialOf(sessionId);
67771
- if (credential === void 0) {
67772
- 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)` };
67773
- }
67774
- if (credential.authorization === void 0) {
67775
- return noOAuthCredentialResult(sessionId);
67776
- }
67777
- if (!deps.pendingOf(sessionId).some((pending) => pending.requestId === requestId)) {
67778
- 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` };
67779
- }
67780
- const body = JSON.stringify(buildRcEventWriteBody(buildRcControlResponsePayload(requestId, decision)));
67781
- let answer;
67782
- try {
67783
- answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
67784
- } catch (error62) {
67785
- return { ok: false, message: `the door could not reach the API host to answer on session ${sessionId}: ${error62 instanceof Error ? error62.message : String(error62)}` };
67786
- }
67787
- const result = rcEventWriteResultFromAnswer(answer);
67788
- if (result.ok) {
67789
- deps.completePending(sessionId, requestId);
67790
- }
67791
- return result;
67918
+ if (isCodexProvider(definition)) {
67919
+ const codexProvider = definition;
67920
+ return {
67921
+ ok: true,
67922
+ route: createCodexRouteMount(
67923
+ { ...deps.codexPorts, loadProvider: () => ({ ok: true, config: resolveCodexConfig(codexProvider.codex) }) },
67924
+ directOrigin(deps.directPort()),
67925
+ provider
67926
+ )
67927
+ };
67928
+ }
67929
+ const httpProvider = definition;
67930
+ return {
67931
+ ok: true,
67932
+ route: passthroughFor(`http:${provider}`, {
67933
+ baseUrl: httpProvider.baseUrl,
67934
+ stripPrefix: `${PROVIDER_PATH_PREFIX}${encodeURIComponent(provider)}`,
67935
+ headroomUpstream: directOrigin(deps.directPort())
67936
+ })
67937
+ };
67938
+ };
67939
+ return async (request7) => await Promise.resolve(resolve(request7));
67792
67940
  }
67793
67941
 
67794
67942
  // src/usage/providerQuota.ts
@@ -68151,6 +68299,10 @@ function realFrontDoorSupervisorPorts(paths) {
68151
68299
  const rcDial = realRcEventDial();
68152
68300
  const rcInject = async (sessionId, text2) => await injectRcUserMessage({ credentialOf: rcTracker.credentialOf, dial: rcDial, newUuid: import_node_crypto12.randomUUID }, sessionId, text2);
68153
68301
  const rcAnswer = async (sessionId, requestId, decision) => await answerRcControlRequest({ credentialOf: rcTracker.credentialOf, pendingOf: (id) => rcTracker.pendingOf(id), completePending: rcTracker.completePending, dial: rcDial }, sessionId, requestId, decision);
68302
+ const rcControlRequestDeps = { credentialOf: rcTracker.credentialOf, dial: rcDial, newUuid: import_node_crypto12.randomUUID };
68303
+ const rcInterrupt = async (sessionId) => await interruptRcSession(rcControlRequestDeps, sessionId);
68304
+ const rcSetModel = async (sessionId, model) => await setRcSessionModel(rcControlRequestDeps, sessionId, model);
68305
+ const rcSetPermissionMode = async (sessionId, mode) => await setRcSessionPermissionMode(rcControlRequestDeps, sessionId, mode);
68154
68306
  realFarmFs.mkdirp(paths.frontdoorDir);
68155
68307
  realFarmFs.writeFilePrivate(paths.frontdoorControlTokenFile, `${rcControlToken}
68156
68308
  `);
@@ -68160,7 +68312,7 @@ function realFrontDoorSupervisorPorts(paths) {
68160
68312
  },
68161
68313
  log,
68162
68314
  mintLeaf(authority, LOOPBACK_LEAF_NAMES, /* @__PURE__ */ new Date()),
68163
- createRcControlHandler({ expectedToken: rcControlToken, list: rcTracker.list, statusOf: rcTracker.statusOf, pendingOf: rcTracker.pendingOf, inject: rcInject, answer: rcAnswer })
68315
+ createRcControlHandler({ expectedToken: rcControlToken, list: rcTracker.list, statusOf: rcTracker.statusOf, pendingOf: rcTracker.pendingOf, inject: rcInject, answer: rcAnswer, interrupt: rcInterrupt, setModel: rcSetModel, setPermissionMode: rcSetPermissionMode })
68164
68316
  );
68165
68317
  const handle = await listenFrontDoor(server, { ...preferredPort === void 0 ? {} : { preferredPort }, ca: authority.certPem, onError: onListenerError("provider") });
68166
68318
  return {
@@ -68352,7 +68504,7 @@ function registerFrontDoorCommand(program2, deps) {
68352
68504
  ["agent-shim frontdoor status", "agent-shim frontdoor status --json"]
68353
68505
  );
68354
68506
  const rc = withExamples(
68355
- frontdoor.command("rc").description("Observe the Remote Control sessions passing through the front door, send a prompt into one, and answer its pending control requests."),
68507
+ frontdoor.command("rc").description("Observe the Remote Control sessions passing through the front door, send a prompt into one, answer its pending control requests, and steer one with the client half's own control requests (interrupt, model, permission mode)."),
68356
68508
  ["agent-shim frontdoor rc list", "agent-shim frontdoor rc pending"]
68357
68509
  );
68358
68510
  withExamples(
@@ -68431,6 +68583,54 @@ function registerFrontDoorCommand(program2, deps) {
68431
68583
  'agent-shim frontdoor rc answer --session cse_00000000-0000-4000-8000-000000000000 --request req_00000000-0000-4000-8000-000000000000 --deny --text "not today"'
68432
68584
  ]
68433
68585
  );
68586
+ withExamples(
68587
+ rc.command("interrupt").description("Interrupt one observed Remote Control session's running turn, as an attached client's stop button would. Queued commands survive the interrupt.").requiredOption("--session <id>", "The cse_ session id, as `frontdoor rc list` shows it.").option("--json", "Print the delivery result as JSON.").action(async (options) => {
68588
+ const result = await frontDoorRcControlFromState(realFarmFs, paths).interruptSession(options.session);
68589
+ if (!result.ok) {
68590
+ throw new Error(result.message);
68591
+ }
68592
+ if (options.json === true) {
68593
+ printJson({ session: options.session, sequenceNums: result.sequenceNums });
68594
+ return;
68595
+ }
68596
+ console.log(`interrupted ${options.session}: sequence_num ${result.sequenceNums.join(", ")}`);
68597
+ }),
68598
+ ["agent-shim frontdoor rc interrupt --session cse_00000000-0000-4000-8000-000000000000"]
68599
+ );
68600
+ withExamples(
68601
+ rc.command("set-model").description("Set the model one observed Remote Control session's subsequent turns use, as an attached client's model picker would.").requiredOption("--session <id>", "The cse_ session id, as `frontdoor rc list` shows it.").requiredOption("--model <model>", "The model id to switch the session to.").option("--json", "Print the delivery result as JSON.").action(async (options) => {
68602
+ const result = await frontDoorRcControlFromState(realFarmFs, paths).setModel(options.session, options.model);
68603
+ if (!result.ok) {
68604
+ throw new Error(result.message);
68605
+ }
68606
+ if (options.json === true) {
68607
+ printJson({ session: options.session, model: options.model, sequenceNums: result.sequenceNums });
68608
+ return;
68609
+ }
68610
+ console.log(`set ${options.session} to model ${options.model}: sequence_num ${result.sequenceNums.join(", ")}`);
68611
+ }),
68612
+ ["agent-shim frontdoor rc set-model --session cse_00000000-0000-4000-8000-000000000000 --model claude-opus-5-5"]
68613
+ );
68614
+ withExamples(
68615
+ rc.command("set-permission-mode").description("Set one observed Remote Control session's permission mode, as an attached client's mode switcher would.").requiredOption("--session <id>", "The cse_ session id, as `frontdoor rc list` shows it.").requiredOption("--mode <mode>", `The permission mode to set; one of the SDK's own modes (${RC_PERMISSION_MODES.join(", ")}).`).option("--json", "Print the delivery result as JSON.").action(async (options) => {
68616
+ if (!isRcPermissionMode(options.mode)) {
68617
+ throw new UsageError(`--mode must be one of the SDK's own permission modes (${RC_PERMISSION_MODES.join(", ")}), not "${options.mode}"`);
68618
+ }
68619
+ const result = await frontDoorRcControlFromState(realFarmFs, paths).setPermissionMode(options.session, options.mode);
68620
+ if (!result.ok) {
68621
+ throw new Error(result.message);
68622
+ }
68623
+ if (options.json === true) {
68624
+ printJson({ session: options.session, mode: options.mode, sequenceNums: result.sequenceNums });
68625
+ return;
68626
+ }
68627
+ console.log(`set ${options.session} to permission mode ${options.mode}: sequence_num ${result.sequenceNums.join(", ")}`);
68628
+ }),
68629
+ [
68630
+ "agent-shim frontdoor rc set-permission-mode --session cse_00000000-0000-4000-8000-000000000000 --mode plan",
68631
+ "agent-shim frontdoor rc set-permission-mode --session cse_00000000-0000-4000-8000-000000000000 --mode acceptEdits"
68632
+ ]
68633
+ );
68434
68634
  program2.command("__frontdoor-supervisor", { hidden: true }).description("Internal: serve the front-door routing listeners. Started by the launcher; never run by hand.").allowUnknownOption().action(async () => {
68435
68635
  const idleShutdownMinutes = readGlobalConfig(paths)?.frontdoor?.idleShutdownMinutes ?? FRONTDOOR_DEFAULT_IDLE_SHUTDOWN_MINUTES;
68436
68636
  process.on("SIGTERM", () => {
@@ -69492,7 +69692,7 @@ function ensureFrontDoor(params) {
69492
69692
  ports.stopSupervisor(supervisorPid);
69493
69693
  while (ports.isRunning(supervisorPid)) {
69494
69694
  if (ports.now() >= deadline) {
69495
- throw new FrontDoorStartError(`agent-shim: the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}) is older than this launcher (protocol ${String(FRONT_DOOR_PROTOCOL)}) and did not exit when asked. Daemon log: ${paths.frontdoorLogPath}`);
69695
+ throw new FrontDoorStartError(`the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}) is older than this launcher (protocol ${String(FRONT_DOOR_PROTOCOL)}) and did not exit when asked. Daemon log: ${paths.frontdoorLogPath}`);
69496
69696
  }
69497
69697
  ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
69498
69698
  }
@@ -69506,13 +69706,13 @@ function ensureFrontDoor(params) {
69506
69706
  }
69507
69707
  lastRejection = `the listener on 127.0.0.1:${String(state.port)} (recorded for pid ${String(supervisorPid)}) failed authentication: ${verdict.reason}`;
69508
69708
  if (spawned) {
69509
- throw new FrontDoorStartError(`agent-shim: ${lastRejection}; refusing to send this session's credentials to it. Daemon log: ${paths.frontdoorLogPath}`);
69709
+ throw new FrontDoorStartError(`${lastRejection}; refusing to send this session's credentials to it. Daemon log: ${paths.frontdoorLogPath}`);
69510
69710
  }
69511
69711
  distrusted.add(supervisorPid);
69512
69712
  continue;
69513
69713
  }
69514
69714
  if (state?.lastError !== void 0) {
69515
- throw new FrontDoorStartError(`agent-shim: the front door reported a fatal error and is not serving: ${state.lastError} (daemon log: ${paths.frontdoorLogPath})`);
69715
+ throw new FrontDoorStartError(`the front door reported a fatal error and is not serving: ${state.lastError} (daemon log: ${paths.frontdoorLogPath})`);
69516
69716
  }
69517
69717
  } else if (!spawned) {
69518
69718
  ports.fs.mkdirp(paths.frontdoorDir);
@@ -69532,7 +69732,7 @@ function ensureFrontDoor(params) {
69532
69732
  if (ports.now() >= deadline) {
69533
69733
  const lastError = state?.lastError;
69534
69734
  throw new FrontDoorStartError(
69535
- `agent-shim: the front door did not become ready within ${String(FRONTDOOR_START_TIMEOUT_MS)}ms` + (lastError === void 0 ? "" : ` (last error: ${lastError})`) + (lastRejection === void 0 ? "" : ` (${lastRejection})`) + `. Daemon log: ${paths.frontdoorLogPath}`
69735
+ `the front door did not become ready within ${String(FRONTDOOR_START_TIMEOUT_MS)}ms` + (lastError === void 0 ? "" : ` (last error: ${lastError})`) + (lastRejection === void 0 ? "" : ` (${lastRejection})`) + `. Daemon log: ${paths.frontdoorLogPath}`
69536
69736
  );
69537
69737
  }
69538
69738
  ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);