agent-shim 8.24.0 → 8.25.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 +387 -121
- package/dist/index.cjs +373 -111
- package/dist/index.mjs +371 -111
- package/dist/types/index.d.ts +40 -3
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -61796,7 +61796,7 @@ function registerIdentityCommand(program2, deps) {
|
|
|
61796
61796
|
// package.json
|
|
61797
61797
|
var package_default = {
|
|
61798
61798
|
name: "agent-shim",
|
|
61799
|
-
version: "8.
|
|
61799
|
+
version: "8.25.0",
|
|
61800
61800
|
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.",
|
|
61801
61801
|
license: "MIT",
|
|
61802
61802
|
author: "Joseph Mearman <joseph@mearman.co.uk>",
|
|
@@ -66142,13 +66142,6 @@ var https3 = __toESM(require("node:https"), 1);
|
|
|
66142
66142
|
var net2 = __toESM(require("node:net"), 1);
|
|
66143
66143
|
var tls = __toESM(require("node:tls"), 1);
|
|
66144
66144
|
|
|
66145
|
-
// src/frontdoor/server.ts
|
|
66146
|
-
var import_node_http2 = __toESM(require("node:http"), 1);
|
|
66147
|
-
var import_node_https = __toESM(require("node:https"), 1);
|
|
66148
|
-
|
|
66149
|
-
// src/frontdoor/rcControl.ts
|
|
66150
|
-
var https = __toESM(require("node:https"), 1);
|
|
66151
|
-
|
|
66152
66145
|
// src/frontdoor/rcSessions.ts
|
|
66153
66146
|
var RC_SESSIONS_PATH_PREFIX = "/v1/code/sessions";
|
|
66154
66147
|
var RC_SESSION_ID_PREFIX = "cse_";
|
|
@@ -66725,7 +66718,7 @@ async function answerRcControlRequest(deps, sessionId, requestId, decision) {
|
|
|
66725
66718
|
}
|
|
66726
66719
|
return result;
|
|
66727
66720
|
}
|
|
66728
|
-
async function deliverRcClientPayload(deps, sessionId, payload, action) {
|
|
66721
|
+
async function deliverRcClientPayload(deps, sessionId, payload, action, to = "events") {
|
|
66729
66722
|
const credential = deps.credentialOf(sessionId);
|
|
66730
66723
|
if (credential === void 0) {
|
|
66731
66724
|
return { ok: false, message: rcSessionNotObservedMessage(sessionId) };
|
|
@@ -66736,7 +66729,7 @@ async function deliverRcClientPayload(deps, sessionId, payload, action) {
|
|
|
66736
66729
|
const body = JSON.stringify(buildRcEventWriteBody(payload));
|
|
66737
66730
|
let answer;
|
|
66738
66731
|
try {
|
|
66739
|
-
answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
|
|
66732
|
+
answer = await (to === "teleport-events" ? deps.dial.writeTeleportEvents(sessionId, rcWriteHeaders(credential), body) : deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body));
|
|
66740
66733
|
} catch (error62) {
|
|
66741
66734
|
return { ok: false, message: `the door could not reach the API host to ${action}: ${error62 instanceof Error ? error62.message : String(error62)}` };
|
|
66742
66735
|
}
|
|
@@ -66830,8 +66823,22 @@ async function submitRcSessionMcpOAuthCallbackUrl(deps, sessionId, serverName, c
|
|
|
66830
66823
|
async function sendRcKeepAlive(deps, sessionId) {
|
|
66831
66824
|
return await deliverRcClientPayload(deps, sessionId, buildRcKeepAlivePayload(), `keep session ${sessionId} alive`);
|
|
66832
66825
|
}
|
|
66826
|
+
async function teleportRcSession(deps, sessionId, marker) {
|
|
66827
|
+
if (marker === "") {
|
|
66828
|
+
return { ok: false, message: "a teleport write needs a non-empty marker: the teleport relay anchors on a marker line's uuid and string content, and an empty string carries neither" };
|
|
66829
|
+
}
|
|
66830
|
+
return await deliverRcClientPayload(deps, sessionId, buildRcUserMessagePayload(deps.newUuid(), sessionId, marker), `teleport a marker into session ${sessionId}`, "teleport-events");
|
|
66831
|
+
}
|
|
66832
|
+
function buildRcMarkReadBody(eventId) {
|
|
66833
|
+
return eventId === void 0 ? {} : { event_id: eventId };
|
|
66834
|
+
}
|
|
66835
|
+
|
|
66836
|
+
// src/frontdoor/server.ts
|
|
66837
|
+
var import_node_http2 = __toESM(require("node:http"), 1);
|
|
66838
|
+
var import_node_https = __toESM(require("node:https"), 1);
|
|
66833
66839
|
|
|
66834
66840
|
// src/frontdoor/rcControl.ts
|
|
66841
|
+
var https = __toESM(require("node:https"), 1);
|
|
66835
66842
|
var RC_PERMISSION_MODE_LIST = RC_PERMISSION_MODES.join(", ");
|
|
66836
66843
|
var CONTROL_PATH_PREFIX = "/__agent-shim/rc";
|
|
66837
66844
|
var CONTROL_BODY_CAP_BYTES = 10485760;
|
|
@@ -67005,6 +67012,15 @@ function createRcControlHandler(deps) {
|
|
|
67005
67012
|
const callbackUrl = bodyString(body, "callbackUrl");
|
|
67006
67013
|
return session === void 0 || serverName === void 0 || callbackUrl === void 0 ? { error: "the mcp-oauth-callback-url body must be JSON naming a non-empty session id, server name, and callback URL" } : { session, run: async () => await deps.mcpOAuthCallbackUrl(session, serverName, callbackUrl) };
|
|
67007
67014
|
}
|
|
67015
|
+
},
|
|
67016
|
+
{
|
|
67017
|
+
name: "teleport",
|
|
67018
|
+
path: "teleport",
|
|
67019
|
+
read: (body) => {
|
|
67020
|
+
const session = bodyString(body, "session");
|
|
67021
|
+
const marker = bodyString(body, "marker");
|
|
67022
|
+
return session === void 0 || marker === void 0 ? { error: "the teleport body must be JSON naming a non-empty session id and marker" } : { session, run: async () => await deps.teleport(session, marker) };
|
|
67023
|
+
}
|
|
67008
67024
|
}
|
|
67009
67025
|
];
|
|
67010
67026
|
return (request7, response) => {
|
|
@@ -67368,7 +67384,8 @@ function frontDoorRcControl(transport, token) {
|
|
|
67368
67384
|
mcpStatus: async (sessionId) => await writeOf(`${CONTROL_PATH_PREFIX}/mcp-status`, JSON.stringify({ session: sessionId }), (status, message) => `requesting the MCP status of ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
67369
67385
|
mcpReconnect: async (sessionId, serverName) => await writeOf(`${CONTROL_PATH_PREFIX}/mcp-reconnect`, JSON.stringify({ session: sessionId, serverName }), (status, message) => `reconnecting MCP server ${serverName} on ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
67370
67386
|
mcpAuthenticate: async (sessionId, serverName, redirectUri) => await writeOf(`${CONTROL_PATH_PREFIX}/mcp-authenticate`, JSON.stringify({ session: sessionId, serverName, redirectUri }), (status, message) => `authenticating MCP server ${serverName} on ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
67371
|
-
mcpOAuthCallbackUrl: async (sessionId, serverName, callbackUrl) => await writeOf(`${CONTROL_PATH_PREFIX}/mcp-oauth-callback-url`, JSON.stringify({ session: sessionId, serverName, callbackUrl }), (status, message) => `handing MCP server ${serverName}'s OAuth callback to ${sessionId} failed (HTTP ${String(status)}): ${message}`)
|
|
67387
|
+
mcpOAuthCallbackUrl: async (sessionId, serverName, callbackUrl) => await writeOf(`${CONTROL_PATH_PREFIX}/mcp-oauth-callback-url`, JSON.stringify({ session: sessionId, serverName, callbackUrl }), (status, message) => `handing MCP server ${serverName}'s OAuth callback to ${sessionId} failed (HTTP ${String(status)}): ${message}`),
|
|
67388
|
+
teleport: async (sessionId, marker) => await writeOf(`${CONTROL_PATH_PREFIX}/teleport`, JSON.stringify({ session: sessionId, marker }), (status, message) => `teleporting a marker into ${sessionId} failed (HTTP ${String(status)}): ${message}`)
|
|
67372
67389
|
};
|
|
67373
67390
|
}
|
|
67374
67391
|
|
|
@@ -67650,36 +67667,38 @@ function tlsFacts(options) {
|
|
|
67650
67667
|
}
|
|
67651
67668
|
function realRcEventDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_PORT }) {
|
|
67652
67669
|
const agent = new ExemptTlsAgent();
|
|
67653
|
-
|
|
67654
|
-
|
|
67655
|
-
|
|
67656
|
-
|
|
67657
|
-
|
|
67658
|
-
|
|
67659
|
-
|
|
67660
|
-
|
|
67661
|
-
|
|
67662
|
-
|
|
67663
|
-
|
|
67664
|
-
|
|
67665
|
-
|
|
67666
|
-
|
|
67667
|
-
|
|
67668
|
-
|
|
67669
|
-
|
|
67670
|
-
|
|
67671
|
-
const
|
|
67672
|
-
|
|
67673
|
-
|
|
67674
|
-
chunks.push(chunk);
|
|
67675
|
-
});
|
|
67676
|
-
response.on("end", () => {
|
|
67677
|
-
resolve({ status: response.statusCode ?? HTTP_BAD_GATEWAY, body: Buffer.concat(chunks).toString("utf8") });
|
|
67678
|
-
});
|
|
67670
|
+
const post = async (path46, headers, body) => await new Promise((resolve, reject) => {
|
|
67671
|
+
const options = {
|
|
67672
|
+
host: target.host,
|
|
67673
|
+
port: target.port,
|
|
67674
|
+
method: "POST",
|
|
67675
|
+
path: path46,
|
|
67676
|
+
// The Host header names the host whose API this is, not the address dialled: a redirected test dials a loopback stand-in while still speaking to the API host by name, exactly as the forwarded paths present their SNI.
|
|
67677
|
+
headers: { ...headers, host: target.servername ?? target.host, "content-length": String(Buffer.byteLength(body, "utf8")) },
|
|
67678
|
+
agent
|
|
67679
|
+
};
|
|
67680
|
+
options.servername = target.servername ?? target.host;
|
|
67681
|
+
if (target.ca !== void 0) {
|
|
67682
|
+
options.ca = [...target.ca];
|
|
67683
|
+
}
|
|
67684
|
+
if (target.rejectUnauthorized !== void 0) {
|
|
67685
|
+
options.rejectUnauthorized = target.rejectUnauthorized;
|
|
67686
|
+
}
|
|
67687
|
+
const request7 = https3.request(options, (response) => {
|
|
67688
|
+
const chunks = [];
|
|
67689
|
+
response.on("data", (chunk) => {
|
|
67690
|
+
chunks.push(chunk);
|
|
67679
67691
|
});
|
|
67680
|
-
|
|
67681
|
-
|
|
67682
|
-
|
|
67692
|
+
response.on("end", () => {
|
|
67693
|
+
resolve({ status: response.statusCode ?? HTTP_BAD_GATEWAY, body: Buffer.concat(chunks).toString("utf8") });
|
|
67694
|
+
});
|
|
67695
|
+
});
|
|
67696
|
+
request7.once("error", reject);
|
|
67697
|
+
request7.end(body);
|
|
67698
|
+
});
|
|
67699
|
+
return {
|
|
67700
|
+
writeEvents: async (sessionId, headers, body) => await post(`/v1/code/sessions/${encodeURIComponent(sessionId)}/events`, headers, body),
|
|
67701
|
+
writeTeleportEvents: async (sessionId, headers, body) => await post(`/v1/code/sessions/${encodeURIComponent(sessionId)}/teleport-events`, headers, body)
|
|
67683
67702
|
};
|
|
67684
67703
|
}
|
|
67685
67704
|
var NO_CHUNKS = {
|
|
@@ -67697,7 +67716,8 @@ function lateRcEventDial(resolve) {
|
|
|
67697
67716
|
return built.dial;
|
|
67698
67717
|
};
|
|
67699
67718
|
return {
|
|
67700
|
-
writeEvents: async (sessionId, headers, body) => await dialFor().writeEvents(sessionId, headers, body)
|
|
67719
|
+
writeEvents: async (sessionId, headers, body) => await dialFor().writeEvents(sessionId, headers, body),
|
|
67720
|
+
writeTeleportEvents: async (sessionId, headers, body) => await dialFor().writeTeleportEvents(sessionId, headers, body)
|
|
67701
67721
|
};
|
|
67702
67722
|
}
|
|
67703
67723
|
function lateRcStreamDial(resolve) {
|
|
@@ -67710,7 +67730,8 @@ function lateRcStreamDial(resolve) {
|
|
|
67710
67730
|
return built.dial;
|
|
67711
67731
|
};
|
|
67712
67732
|
return {
|
|
67713
|
-
announcePresence: async (sessionId, headers, clientId) => await dialFor().announcePresence(sessionId, headers, clientId),
|
|
67733
|
+
announcePresence: async (sessionId, headers, clientId, clear) => await dialFor().announcePresence(sessionId, headers, clientId, clear),
|
|
67734
|
+
markRead: async (sessionId, headers, eventId) => await dialFor().markRead(sessionId, headers, eventId),
|
|
67714
67735
|
openStream: async (sessionId, headers, resume, signal) => await dialFor().openStream(sessionId, headers, resume, signal)
|
|
67715
67736
|
};
|
|
67716
67737
|
}
|
|
@@ -67752,11 +67773,16 @@ function realRcStreamDial(target = { host: CONNECT_INTERCEPT_HOST, port: HTTPS_P
|
|
|
67752
67773
|
return Buffer.concat(chunks).toString("utf8");
|
|
67753
67774
|
};
|
|
67754
67775
|
return {
|
|
67755
|
-
announcePresence: async (sessionId, headers, clientId) => {
|
|
67756
|
-
const body = JSON.stringify({ client_id: clientId, clear
|
|
67776
|
+
announcePresence: async (sessionId, headers, clientId, clear) => {
|
|
67777
|
+
const body = JSON.stringify({ client_id: clientId, clear });
|
|
67757
67778
|
const { status, response } = await request7("POST", `/v1/code/sessions/${encodeURIComponent(sessionId)}/client/presence`, { ...headers, "content-type": "application/json" }, body, new AbortController().signal);
|
|
67758
67779
|
return { status, body: await readAll(response) };
|
|
67759
67780
|
},
|
|
67781
|
+
markRead: async (sessionId, headers, eventId) => {
|
|
67782
|
+
const body = JSON.stringify(buildRcMarkReadBody(eventId));
|
|
67783
|
+
const { status, response } = await request7("POST", `/v1/code/sessions/${encodeURIComponent(sessionId)}/mark_read`, { ...headers, "content-type": "application/json" }, body, new AbortController().signal);
|
|
67784
|
+
return { status, body: await readAll(response) };
|
|
67785
|
+
},
|
|
67760
67786
|
openStream: async (sessionId, headers, resume, signal) => {
|
|
67761
67787
|
const path46 = resume === void 0 ? `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream` : `/v1/code/sessions/${encodeURIComponent(sessionId)}/events/stream?from_sequence_num=${String(resume.fromSequenceNum)}`;
|
|
67762
67788
|
const streamHeaders = resume === void 0 ? headers : { ...headers, "last-event-id": String(resume.fromSequenceNum) };
|
|
@@ -72074,6 +72100,10 @@ var RcMcpOAuthCallbackUrlInputSchema = external_exports.strictObject({
|
|
|
72074
72100
|
serverName: external_exports.string().min(1),
|
|
72075
72101
|
callbackUrl: external_exports.string().min(1)
|
|
72076
72102
|
});
|
|
72103
|
+
var RcTeleportInputSchema = external_exports.strictObject({
|
|
72104
|
+
session: external_exports.string().min(1),
|
|
72105
|
+
marker: external_exports.string().min(1)
|
|
72106
|
+
});
|
|
72077
72107
|
var RcListOutputSchema = external_exports.strictObject({ sessions: external_exports.readonly(external_exports.array(RcSessionSummarySchema)) });
|
|
72078
72108
|
var RcStatusOutputSchema = external_exports.strictObject({ statuses: external_exports.readonly(external_exports.array(RcSessionStatusSchema)) });
|
|
72079
72109
|
var RcPendingOutputSchema = external_exports.strictObject({ pending: external_exports.readonly(external_exports.array(RcPendingRequestSummarySchema)) });
|
|
@@ -72158,6 +72188,7 @@ function createRcApiRouter(deps) {
|
|
|
72158
72188
|
mcpReconnect: authed.input(RcMcpReconnectInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input: input2 }) => ({ session: input2.session, ...deliveredControl(input2.session, await deps.mcpReconnect(input2.session, input2.serverName)) })),
|
|
72159
72189
|
mcpAuthenticate: authed.input(RcMcpAuthenticateInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input: input2 }) => ({ session: input2.session, ...deliveredControl(input2.session, await deps.mcpAuthenticate(input2.session, input2.serverName, input2.redirectUri)) })),
|
|
72160
72190
|
mcpOAuthCallbackUrl: authed.input(RcMcpOAuthCallbackUrlInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input: input2 }) => ({ session: input2.session, ...deliveredControl(input2.session, await deps.mcpOAuthCallbackUrl(input2.session, input2.serverName, input2.callbackUrl)) })),
|
|
72191
|
+
teleport: authed.input(RcTeleportInputSchema).output(RcWriteOutputSchema).handler(async ({ input: input2 }) => ({ session: input2.session, sequenceNums: delivered(input2.session, await deps.teleport(input2.session, input2.marker)) })),
|
|
72161
72192
|
subscribe: authed.input(RcSessionQuerySchema).output(eventIterator(RcStreamEventSchema)).handler(async function* ({ input: input2, signal }) {
|
|
72162
72193
|
const queue = [];
|
|
72163
72194
|
let wake;
|
|
@@ -73738,6 +73769,193 @@ var import_node_crypto14 = require("node:crypto");
|
|
|
73738
73769
|
// src/frontdoor/rcSelfHostMint.ts
|
|
73739
73770
|
var import_node_path34 = __toESM(require("node:path"), 1);
|
|
73740
73771
|
|
|
73772
|
+
// src/frontdoor/rcSelfHostEndpoints.ts
|
|
73773
|
+
var RC_SOURCE_WORKER = "worker";
|
|
73774
|
+
var RC_SOURCE_CLIENT = "client";
|
|
73775
|
+
function isRecord4(value2) {
|
|
73776
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
73777
|
+
}
|
|
73778
|
+
function parseJsonObject2(body) {
|
|
73779
|
+
let parsed;
|
|
73780
|
+
try {
|
|
73781
|
+
parsed = JSON.parse(body);
|
|
73782
|
+
} catch {
|
|
73783
|
+
return void 0;
|
|
73784
|
+
}
|
|
73785
|
+
return isRecord4(parsed) ? parsed : void 0;
|
|
73786
|
+
}
|
|
73787
|
+
function nonEmptyString2(record2, field) {
|
|
73788
|
+
const value2 = record2 === void 0 ? void 0 : record2[field];
|
|
73789
|
+
return typeof value2 === "string" && value2 !== "" ? value2 : void 0;
|
|
73790
|
+
}
|
|
73791
|
+
function numberOf(record2, field) {
|
|
73792
|
+
const value2 = record2 === void 0 ? void 0 : record2[field];
|
|
73793
|
+
if (typeof value2 === "number" && Number.isFinite(value2)) {
|
|
73794
|
+
return value2;
|
|
73795
|
+
}
|
|
73796
|
+
if (typeof value2 === "string" && /^[0-9]+$/.test(value2)) {
|
|
73797
|
+
return Number(value2);
|
|
73798
|
+
}
|
|
73799
|
+
return void 0;
|
|
73800
|
+
}
|
|
73801
|
+
function pageOfRcChannel(url2, rows, idOf, rowOf) {
|
|
73802
|
+
const query = new URL(url2, "http://127.0.0.1").searchParams;
|
|
73803
|
+
const anchor2 = query.get("after_event_id") ?? query.get("cursor");
|
|
73804
|
+
const rawLimit = query.get("limit");
|
|
73805
|
+
const limit = rawLimit === null ? void 0 : numberOf({ value: rawLimit }, "value");
|
|
73806
|
+
if (limit !== void 0 && limit < 1) {
|
|
73807
|
+
return { error: "the limit names a whole number of rows of at least one" };
|
|
73808
|
+
}
|
|
73809
|
+
const from = anchor2 === null ? 0 : rows.findIndex((row) => idOf(row) === anchor2) + 1;
|
|
73810
|
+
if (anchor2 !== null && from === 0) {
|
|
73811
|
+
return { error: `the anchor names an event id this surface holds no row for: ${anchor2}` };
|
|
73812
|
+
}
|
|
73813
|
+
const page = limit === void 0 ? rows.slice(from) : rows.slice(from, from + limit);
|
|
73814
|
+
const last = page[page.length - 1];
|
|
73815
|
+
return { data: page.map(rowOf), ...last === void 0 ? {} : { next_cursor: idOf(last) } };
|
|
73816
|
+
}
|
|
73817
|
+
async function serveRcClientChannels(ctx, tail, method, maxBatchEvents) {
|
|
73818
|
+
const { request: request7, response, session } = ctx;
|
|
73819
|
+
if (tail === "client/presence" && method === "POST") {
|
|
73820
|
+
const body = parseJsonObject2(await ctx.readBody(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
73821
|
+
const clientId = nonEmptyString2(body, "client_id");
|
|
73822
|
+
const clear = body?.clear;
|
|
73823
|
+
if (clientId === void 0 || clear !== void 0 && typeof clear !== "boolean") {
|
|
73824
|
+
await ctx.answerJson(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "a presence announcement is JSON naming a non-empty client_id, with clear only as a boolean or absent" } });
|
|
73825
|
+
return true;
|
|
73826
|
+
}
|
|
73827
|
+
if (clear === true) {
|
|
73828
|
+
session.clients.delete(clientId);
|
|
73829
|
+
ctx.log?.(`rc selfhost ${session.id}: client ${clientId} cleared its presence`);
|
|
73830
|
+
} else {
|
|
73831
|
+
session.clients.set(clientId, ctx.now());
|
|
73832
|
+
ctx.log?.(`rc selfhost ${session.id}: client ${clientId} announced its presence${session.clients.size === 1 ? "" : ` (${String(session.clients.size)} clients now announced)`}`);
|
|
73833
|
+
}
|
|
73834
|
+
await ctx.answerJson(response, HTTP_STATUS.ok, { refresh_after_seconds: ctx.presenceRefreshSeconds });
|
|
73835
|
+
return true;
|
|
73836
|
+
}
|
|
73837
|
+
if (tail === "mark_read" && method === "POST") {
|
|
73838
|
+
const body = parseJsonObject2(await ctx.readBody(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
73839
|
+
const eventId = nonEmptyString2(body, "event_id");
|
|
73840
|
+
const clientId = nonEmptyString2(body, "client_id");
|
|
73841
|
+
if (body !== void 0 && "event_id" in body && eventId === void 0 || "client_id" in (body ?? {}) && clientId === void 0) {
|
|
73842
|
+
await ctx.answerJson(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "a read receipt is JSON naming the event_id it read or none for the whole session, and client_id only as a non-empty string or absent" } });
|
|
73843
|
+
return true;
|
|
73844
|
+
}
|
|
73845
|
+
const receipt = ctx.publish(session, clientId ?? RC_SOURCE_CLIENT, { type: "mark_read", ...eventId === void 0 ? {} : { event_id: eventId }, ...clientId === void 0 ? {} : { client_id: clientId } }, true);
|
|
73846
|
+
ctx.log?.(`rc selfhost ${session.id}: ${clientId === void 0 ? "an unnamed client" : `client ${clientId}`} marked ${eventId === void 0 ? "the session read" : `event ${eventId} read`} as sequence ${String(receipt.sequenceNum)}`);
|
|
73847
|
+
await ctx.answerJson(response, HTTP_STATUS.ok, {});
|
|
73848
|
+
return true;
|
|
73849
|
+
}
|
|
73850
|
+
if (tail === "teleport-events" && method === "POST") {
|
|
73851
|
+
const body = parseJsonObject2(await ctx.readBody(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
73852
|
+
const events = body?.events;
|
|
73853
|
+
if (!Array.isArray(events) || events.length === 0 || events.length > maxBatchEvents) {
|
|
73854
|
+
await ctx.answerJson(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: `a teleport write is a non-empty array of at most ${String(maxBatchEvents)} events` } });
|
|
73855
|
+
return true;
|
|
73856
|
+
}
|
|
73857
|
+
const results = [];
|
|
73858
|
+
for (const event of events) {
|
|
73859
|
+
if (!isRecord4(event) || !isRecord4(event.payload)) {
|
|
73860
|
+
await ctx.answerJson(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "every event in a teleport write is an object carrying one payload object" } });
|
|
73861
|
+
return true;
|
|
73862
|
+
}
|
|
73863
|
+
const published = ctx.publish(session, RC_SOURCE_CLIENT, event.payload);
|
|
73864
|
+
results.push({ sequence_num: String(published.sequenceNum), duplicate: published.duplicate });
|
|
73865
|
+
}
|
|
73866
|
+
ctx.sweep();
|
|
73867
|
+
ctx.log?.(`rc selfhost ${session.id}: teleport write published ${String(results.length)} marker event(s)`);
|
|
73868
|
+
await ctx.answerJson(response, HTTP_STATUS.ok, { results });
|
|
73869
|
+
return true;
|
|
73870
|
+
}
|
|
73871
|
+
if (tail === "teleport-events" && method === "GET") {
|
|
73872
|
+
const page = pageOfRcChannel(request7.url, session.events, (event) => event.eventId, (event) => ({ event_id: event.eventId, payload: event.payload }));
|
|
73873
|
+
if ("error" in page) {
|
|
73874
|
+
await ctx.answerJson(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: page.error } });
|
|
73875
|
+
return true;
|
|
73876
|
+
}
|
|
73877
|
+
await ctx.answerJson(response, HTTP_STATUS.ok, page);
|
|
73878
|
+
return true;
|
|
73879
|
+
}
|
|
73880
|
+
return false;
|
|
73881
|
+
}
|
|
73882
|
+
var compatSessionRow = (session, now) => ({ id: session.id, title: session.title, created_at: new Date(session.createdAt).toISOString(), updated_at: new Date(now()).toISOString(), session_status: "active" });
|
|
73883
|
+
async function serveRcCompatSessions(ctx, pathname, compatPath) {
|
|
73884
|
+
const { request: request7, response } = ctx;
|
|
73885
|
+
const method = request7.method.toUpperCase();
|
|
73886
|
+
if (pathname === compatPath) {
|
|
73887
|
+
if (method !== "GET") {
|
|
73888
|
+
await ctx.answerJson(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the compatibility session list is a GET" } });
|
|
73889
|
+
return;
|
|
73890
|
+
}
|
|
73891
|
+
const listRefusal = ctx.credentialRefusal(request7.headers);
|
|
73892
|
+
if (listRefusal !== void 0) {
|
|
73893
|
+
await ctx.unauthorized(response, listRefusal);
|
|
73894
|
+
return;
|
|
73895
|
+
}
|
|
73896
|
+
await ctx.answerJson(response, HTTP_STATUS.ok, { data: [...ctx.sessions.values()].map((session2) => compatSessionRow(session2, ctx.now)) });
|
|
73897
|
+
return;
|
|
73898
|
+
}
|
|
73899
|
+
const rest = pathname.slice(`${compatPath}/`.length);
|
|
73900
|
+
const slash = rest.indexOf("/");
|
|
73901
|
+
const address = slash === -1 ? rest : rest.slice(0, slash);
|
|
73902
|
+
const compatTail = slash === -1 ? "" : rest.slice(slash + 1);
|
|
73903
|
+
const refusal = ctx.credentialRefusal(request7.headers);
|
|
73904
|
+
if (refusal !== void 0) {
|
|
73905
|
+
await ctx.unauthorized(response, refusal);
|
|
73906
|
+
return;
|
|
73907
|
+
}
|
|
73908
|
+
const session = ctx.sessions.get(address) ?? ctx.sessions.get(`cse_${address}`);
|
|
73909
|
+
if (compatTail === "") {
|
|
73910
|
+
if (method === "GET") {
|
|
73911
|
+
if (session === void 0) {
|
|
73912
|
+
await ctx.answerJson(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `Session not found: ${address}` } });
|
|
73913
|
+
return;
|
|
73914
|
+
}
|
|
73915
|
+
await ctx.answerJson(response, HTTP_STATUS.ok, compatSessionRow(session, ctx.now));
|
|
73916
|
+
return;
|
|
73917
|
+
}
|
|
73918
|
+
if (method === "PATCH" || method === "PUT") {
|
|
73919
|
+
if (session === void 0) {
|
|
73920
|
+
await ctx.answerJson(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `Session not found: ${address}` } });
|
|
73921
|
+
return;
|
|
73922
|
+
}
|
|
73923
|
+
const body = parseJsonObject2(await ctx.readBody(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
73924
|
+
const title = nonEmptyString2(body, "title");
|
|
73925
|
+
if (title === void 0) {
|
|
73926
|
+
await ctx.answerJson(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "a compatibility session update is JSON naming a non-empty title" } });
|
|
73927
|
+
return;
|
|
73928
|
+
}
|
|
73929
|
+
session.title = title;
|
|
73930
|
+
session.lastTrafficAt = ctx.now();
|
|
73931
|
+
ctx.log?.(`rc selfhost ${session.id}: retitled through the compatibility family`);
|
|
73932
|
+
await ctx.answerJson(response, HTTP_STATUS.ok, compatSessionRow(session, ctx.now));
|
|
73933
|
+
return;
|
|
73934
|
+
}
|
|
73935
|
+
await ctx.answerJson(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the compatibility session read is a GET and its update a PATCH or PUT" } });
|
|
73936
|
+
return;
|
|
73937
|
+
}
|
|
73938
|
+
if ((compatTail === "archive" || compatTail === "unarchive") && method === "POST") {
|
|
73939
|
+
await ctx.readBody(request7.body, CONTROL_BODY_CAP_BYTES);
|
|
73940
|
+
if (session === void 0) {
|
|
73941
|
+
await ctx.answerJson(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `Session not found: ${address}` } });
|
|
73942
|
+
return;
|
|
73943
|
+
}
|
|
73944
|
+
if (compatTail === "unarchive") {
|
|
73945
|
+
await ctx.answerJson(response, HTTP_STATUS.ok, compatSessionRow(session, ctx.now));
|
|
73946
|
+
return;
|
|
73947
|
+
}
|
|
73948
|
+
for (const sink of [...session.workerStreams, ...session.clientStreams]) {
|
|
73949
|
+
sink.retire();
|
|
73950
|
+
}
|
|
73951
|
+
ctx.sessions.delete(session.id);
|
|
73952
|
+
ctx.log?.(`rc selfhost ${session.id}: archived through the compatibility family`);
|
|
73953
|
+
await ctx.answerJson(response, HTTP_STATUS.ok, {});
|
|
73954
|
+
return;
|
|
73955
|
+
}
|
|
73956
|
+
await ctx.answerJson(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `the compatibility session family serves no path "${compatTail}"` } });
|
|
73957
|
+
}
|
|
73958
|
+
|
|
73741
73959
|
// src/frontdoor/rcWebFetch.ts
|
|
73742
73960
|
var dns2 = __toESM(require("node:dns"), 1);
|
|
73743
73961
|
var http6 = __toESM(require("node:http"), 1);
|
|
@@ -74006,21 +74224,19 @@ var RC_PRESENCE_REFRESH_SECONDS = 60;
|
|
|
74006
74224
|
var RC_SELF_HOST_MAX_BATCH_EVENTS = 100;
|
|
74007
74225
|
var RC_SELF_HOST_WORKER_EPOCH = 1;
|
|
74008
74226
|
var RC_STREAM_EVENT_NAME = "client_event";
|
|
74009
|
-
var RC_SOURCE_WORKER = "worker";
|
|
74010
|
-
var RC_SOURCE_CLIENT = "client";
|
|
74011
74227
|
var CONFLICT_REASON_HEADER2 = "x-ccr-conflict-reason";
|
|
74012
74228
|
var CONFLICT_REASON_EPOCH_STALE = "epoch_stale";
|
|
74013
|
-
function
|
|
74229
|
+
function isRecord5(value2) {
|
|
74014
74230
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
74015
74231
|
}
|
|
74016
74232
|
function isWebSearchRefusal(value2) {
|
|
74017
74233
|
return !Array.isArray(value2);
|
|
74018
74234
|
}
|
|
74019
|
-
function
|
|
74235
|
+
function nonEmptyString3(record2, field) {
|
|
74020
74236
|
const value2 = record2 === void 0 ? void 0 : record2[field];
|
|
74021
74237
|
return typeof value2 === "string" && value2 !== "" ? value2 : void 0;
|
|
74022
74238
|
}
|
|
74023
|
-
function
|
|
74239
|
+
function numberOf2(record2, field) {
|
|
74024
74240
|
const value2 = record2 === void 0 ? void 0 : record2[field];
|
|
74025
74241
|
if (typeof value2 === "number" && Number.isFinite(value2)) {
|
|
74026
74242
|
return value2;
|
|
@@ -74087,14 +74303,14 @@ async function readBody3(request7, capBytes) {
|
|
|
74087
74303
|
});
|
|
74088
74304
|
});
|
|
74089
74305
|
}
|
|
74090
|
-
function
|
|
74306
|
+
function parseJsonObject3(body) {
|
|
74091
74307
|
let parsed;
|
|
74092
74308
|
try {
|
|
74093
74309
|
parsed = JSON.parse(body);
|
|
74094
74310
|
} catch {
|
|
74095
74311
|
return void 0;
|
|
74096
74312
|
}
|
|
74097
|
-
return
|
|
74313
|
+
return isRecord5(parsed) ? parsed : void 0;
|
|
74098
74314
|
}
|
|
74099
74315
|
function mintWorkerJwt(randomToken, issuedAt) {
|
|
74100
74316
|
const encode3 = (value2) => Buffer.from(JSON.stringify(value2), "utf8").toString("base64url");
|
|
@@ -74117,11 +74333,16 @@ function createRcSelfHostSurface(deps) {
|
|
|
74117
74333
|
for (const session of sessions.values()) {
|
|
74118
74334
|
while (session.events[0] !== void 0 && now - session.events[0].storedAt > RC_SELF_HOST_RETENTION_MS) {
|
|
74119
74335
|
const dropped = session.events.shift();
|
|
74120
|
-
const uuid3 = dropped === void 0 ? void 0 :
|
|
74336
|
+
const uuid3 = dropped === void 0 ? void 0 : nonEmptyString3(dropped.payload, "uuid");
|
|
74121
74337
|
if (uuid3 !== void 0) {
|
|
74122
74338
|
session.seenPayloadUuids.delete(uuid3);
|
|
74123
74339
|
}
|
|
74124
74340
|
}
|
|
74341
|
+
for (const [clientId, lastSeenAt] of session.clients) {
|
|
74342
|
+
if (now - lastSeenAt > RC_SELF_HOST_RETENTION_MS) {
|
|
74343
|
+
session.clients.delete(clientId);
|
|
74344
|
+
}
|
|
74345
|
+
}
|
|
74125
74346
|
if (session.workerStreams.size === 0 && session.clientStreams.size === 0 && now - session.lastTrafficAt > RC_SELF_HOST_RETENTION_MS) {
|
|
74126
74347
|
sessions.delete(session.id);
|
|
74127
74348
|
}
|
|
@@ -74160,7 +74381,7 @@ function createRcSelfHostSurface(deps) {
|
|
|
74160
74381
|
const frameOf = (event) => {
|
|
74161
74382
|
const envelope = {
|
|
74162
74383
|
event_id: event.eventId,
|
|
74163
|
-
event_type:
|
|
74384
|
+
event_type: nonEmptyString3(event.payload, "type") ?? "event",
|
|
74164
74385
|
sequence_num: event.sequenceNum,
|
|
74165
74386
|
source: event.source,
|
|
74166
74387
|
payload: event.payload,
|
|
@@ -74174,7 +74395,7 @@ data: ${JSON.stringify(envelope)}
|
|
|
74174
74395
|
};
|
|
74175
74396
|
const holdStream = async (session, which, wantsReplay, request7, response) => {
|
|
74176
74397
|
const url2 = new URL(request7.url, "http://127.0.0.1");
|
|
74177
|
-
const cursor3 =
|
|
74398
|
+
const cursor3 = numberOf2({ value: url2.searchParams.get("from_sequence_num") }, "value") ?? numberOf2({ value: singleHeader2(request7.headers, "last-event-id") }, "value");
|
|
74178
74399
|
const replay = cursor3 === void 0 ? [] : session.events.filter((event) => wantsReplay(event) && event.sequenceNum > cursor3);
|
|
74179
74400
|
response.start(HTTP_STATUS.ok, { "content-type": "text/event-stream", "cache-control": "no-cache" });
|
|
74180
74401
|
response.flush();
|
|
@@ -74203,8 +74424,8 @@ data: ${JSON.stringify(envelope)}
|
|
|
74203
74424
|
sink.retire();
|
|
74204
74425
|
response.end();
|
|
74205
74426
|
};
|
|
74206
|
-
const publish = (session, source, payload) => {
|
|
74207
|
-
const uuid3 =
|
|
74427
|
+
const publish = (session, source, payload, toWorker = source === RC_SOURCE_CLIENT) => {
|
|
74428
|
+
const uuid3 = nonEmptyString3(payload, "uuid");
|
|
74208
74429
|
const duplicate = uuid3 !== void 0 && session.seenPayloadUuids.has(uuid3);
|
|
74209
74430
|
session.sequenceNum += 1;
|
|
74210
74431
|
const event = {
|
|
@@ -74212,9 +74433,9 @@ data: ${JSON.stringify(envelope)}
|
|
|
74212
74433
|
eventId: uuid3 ?? deps.newUuid(),
|
|
74213
74434
|
source,
|
|
74214
74435
|
// The one enrichment the real service was observed making on the live rig's stream: the wall-clock instant it took the write. The worker's handler ignores it; the door's own parser forwards it verbatim.
|
|
74215
|
-
payload: source ===
|
|
74436
|
+
payload: source === RC_SOURCE_WORKER ? payload : { ...payload, server_received_wall_ms: deps.now() },
|
|
74216
74437
|
createdAt: new Date(deps.now()).toISOString(),
|
|
74217
|
-
toWorker
|
|
74438
|
+
toWorker,
|
|
74218
74439
|
storedAt: deps.now()
|
|
74219
74440
|
};
|
|
74220
74441
|
session.events.push(event);
|
|
@@ -74262,8 +74483,26 @@ data: ${JSON.stringify(envelope)}
|
|
|
74262
74483
|
}
|
|
74263
74484
|
session.lastTrafficAt = deps.now();
|
|
74264
74485
|
if (tail === "") {
|
|
74486
|
+
if (method === "PATCH" || method === "PUT") {
|
|
74487
|
+
const refusal = credentialRefusal(request7.headers);
|
|
74488
|
+
if (refusal !== void 0) {
|
|
74489
|
+
await unauthorized(response, refusal);
|
|
74490
|
+
return;
|
|
74491
|
+
}
|
|
74492
|
+
const body = parseJsonObject3(await readBody3(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
74493
|
+
const title = nonEmptyString3(body, "title");
|
|
74494
|
+
if (title === void 0) {
|
|
74495
|
+
await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "a session update is JSON naming a non-empty title" } });
|
|
74496
|
+
return;
|
|
74497
|
+
}
|
|
74498
|
+
session.title = title;
|
|
74499
|
+
session.lastTrafficAt = deps.now();
|
|
74500
|
+
deps.log?.(`rc selfhost ${session.id}: retitled at its client's request`);
|
|
74501
|
+
await answerJson2(response, HTTP_STATUS.ok, {});
|
|
74502
|
+
return;
|
|
74503
|
+
}
|
|
74265
74504
|
if (method !== "GET") {
|
|
74266
|
-
await answerJson2(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the session read is a GET" } });
|
|
74505
|
+
await answerJson2(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the session read is a GET, and its update a PATCH or PUT" } });
|
|
74267
74506
|
return;
|
|
74268
74507
|
}
|
|
74269
74508
|
await answerJson2(response, HTTP_STATUS.ok, { session: { id: session.id, title: session.title, created_at: new Date(session.createdAt).toISOString(), status: "active" } });
|
|
@@ -74308,17 +74547,17 @@ data: ${JSON.stringify(envelope)}
|
|
|
74308
74547
|
return;
|
|
74309
74548
|
}
|
|
74310
74549
|
if (workerTail === "" && method === "PUT") {
|
|
74311
|
-
const body =
|
|
74312
|
-
const claimedEpoch =
|
|
74550
|
+
const body = parseJsonObject3(await readBody3(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
74551
|
+
const claimedEpoch = numberOf2(body, "worker_epoch");
|
|
74313
74552
|
if (claimedEpoch !== void 0 && claimedEpoch !== RC_SELF_HOST_WORKER_EPOCH) {
|
|
74314
74553
|
await epochStale(response);
|
|
74315
74554
|
return;
|
|
74316
74555
|
}
|
|
74317
|
-
const status =
|
|
74556
|
+
const status = nonEmptyString3(body, "worker_status");
|
|
74318
74557
|
if (status !== void 0) {
|
|
74319
74558
|
session.workerStatus = status;
|
|
74320
74559
|
}
|
|
74321
|
-
if (
|
|
74560
|
+
if (isRecord5(body?.external_metadata)) {
|
|
74322
74561
|
session.externalMetadata = body.external_metadata;
|
|
74323
74562
|
}
|
|
74324
74563
|
await answerJson2(response, HTTP_STATUS.ok, {});
|
|
@@ -74335,8 +74574,8 @@ data: ${JSON.stringify(envelope)}
|
|
|
74335
74574
|
return;
|
|
74336
74575
|
}
|
|
74337
74576
|
if (workerTail === "events" && method === "POST") {
|
|
74338
|
-
const body =
|
|
74339
|
-
const claimedEpoch =
|
|
74577
|
+
const body = parseJsonObject3(await readBody3(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
74578
|
+
const claimedEpoch = numberOf2(body, "worker_epoch");
|
|
74340
74579
|
if (claimedEpoch !== void 0 && claimedEpoch !== RC_SELF_HOST_WORKER_EPOCH) {
|
|
74341
74580
|
await epochStale(response);
|
|
74342
74581
|
return;
|
|
@@ -74348,7 +74587,7 @@ data: ${JSON.stringify(envelope)}
|
|
|
74348
74587
|
}
|
|
74349
74588
|
const results = [];
|
|
74350
74589
|
for (const event of events) {
|
|
74351
|
-
if (!
|
|
74590
|
+
if (!isRecord5(event) || !isRecord5(event.payload)) {
|
|
74352
74591
|
await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "every event in a batch is an object carrying one payload object" } });
|
|
74353
74592
|
return;
|
|
74354
74593
|
}
|
|
@@ -74369,8 +74608,8 @@ data: ${JSON.stringify(envelope)}
|
|
|
74369
74608
|
return;
|
|
74370
74609
|
}
|
|
74371
74610
|
if (workerTail === "internal-events" && method === "POST") {
|
|
74372
|
-
const body =
|
|
74373
|
-
const claimedEpoch =
|
|
74611
|
+
const body = parseJsonObject3(await readBody3(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
74612
|
+
const claimedEpoch = numberOf2(body, "worker_epoch");
|
|
74374
74613
|
if (claimedEpoch !== void 0 && claimedEpoch !== RC_SELF_HOST_WORKER_EPOCH) {
|
|
74375
74614
|
await epochStale(response);
|
|
74376
74615
|
return;
|
|
@@ -74381,19 +74620,26 @@ data: ${JSON.stringify(envelope)}
|
|
|
74381
74620
|
return;
|
|
74382
74621
|
}
|
|
74383
74622
|
for (const event of events) {
|
|
74384
|
-
if (
|
|
74385
|
-
session.internalEvents.push({
|
|
74623
|
+
if (isRecord5(event)) {
|
|
74624
|
+
session.internalEvents.push({ eventId: deps.newUuid(), body: event });
|
|
74386
74625
|
}
|
|
74387
74626
|
}
|
|
74388
74627
|
await answerJson2(response, HTTP_STATUS.ok, {});
|
|
74389
74628
|
return;
|
|
74390
74629
|
}
|
|
74391
74630
|
if (workerTail === "internal-events" && method === "GET") {
|
|
74392
|
-
const
|
|
74393
|
-
|
|
74394
|
-
|
|
74395
|
-
|
|
74396
|
-
|
|
74631
|
+
const query = new URL(request7.url, "http://127.0.0.1").searchParams;
|
|
74632
|
+
if (query.get("session_agent_id") !== null || query.get("subagents") !== null) {
|
|
74633
|
+
await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "this surface keeps one internal-events channel per session, so an agent-scoped read has no subset to serve" } });
|
|
74634
|
+
return;
|
|
74635
|
+
}
|
|
74636
|
+
const page = pageOfRcChannel(request7.url, session.internalEvents, (event) => event.eventId, (event) => ({ event_id: event.eventId, payload: event.body }));
|
|
74637
|
+
if ("error" in page) {
|
|
74638
|
+
const anchorUnknown = query.get("after_event_id") !== null && page.error.startsWith("the anchor names an event id");
|
|
74639
|
+
await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: anchorUnknown ? "after_event_id_not_found" : "invalid_request_error", message: page.error } });
|
|
74640
|
+
return;
|
|
74641
|
+
}
|
|
74642
|
+
await answerJson2(response, HTTP_STATUS.ok, page);
|
|
74397
74643
|
return;
|
|
74398
74644
|
}
|
|
74399
74645
|
if (workerTail === "diagnostics" && method === "POST") {
|
|
@@ -74402,8 +74648,8 @@ data: ${JSON.stringify(envelope)}
|
|
|
74402
74648
|
return;
|
|
74403
74649
|
}
|
|
74404
74650
|
if (workerTail === "web-fetch" && method === "POST") {
|
|
74405
|
-
const body =
|
|
74406
|
-
const target =
|
|
74651
|
+
const body = parseJsonObject3(await readBody3(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
74652
|
+
const target = nonEmptyString3(body, "url");
|
|
74407
74653
|
if (target === void 0) {
|
|
74408
74654
|
await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "a worker web-fetch carries one url" } });
|
|
74409
74655
|
return;
|
|
@@ -74425,8 +74671,8 @@ data: ${JSON.stringify(envelope)}
|
|
|
74425
74671
|
return;
|
|
74426
74672
|
}
|
|
74427
74673
|
if (workerTail === "web-search" && method === "POST") {
|
|
74428
|
-
const body =
|
|
74429
|
-
const query =
|
|
74674
|
+
const body = parseJsonObject3(await readBody3(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
74675
|
+
const query = nonEmptyString3(body, "query");
|
|
74430
74676
|
if (query === void 0) {
|
|
74431
74677
|
await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "a worker web-search carries one query" } });
|
|
74432
74678
|
return;
|
|
@@ -74437,7 +74683,7 @@ data: ${JSON.stringify(envelope)}
|
|
|
74437
74683
|
await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "the domain filters of a worker web-search are string arrays" } });
|
|
74438
74684
|
return;
|
|
74439
74685
|
}
|
|
74440
|
-
const searchProfile =
|
|
74686
|
+
const searchProfile = nonEmptyString3(body, "search_profile");
|
|
74441
74687
|
const backend = deps.webSearch;
|
|
74442
74688
|
if (backend === void 0) {
|
|
74443
74689
|
deps.log?.(`rc selfhost ${session.id}: worker web-search of "${query}" refused: no search backend serves this door`);
|
|
@@ -74462,7 +74708,7 @@ data: ${JSON.stringify(envelope)}
|
|
|
74462
74708
|
return;
|
|
74463
74709
|
}
|
|
74464
74710
|
if (tail === "events" && method === "POST") {
|
|
74465
|
-
const body =
|
|
74711
|
+
const body = parseJsonObject3(await readBody3(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
74466
74712
|
const events = body?.events;
|
|
74467
74713
|
if (!Array.isArray(events) || events.length === 0 || events.length > RC_SELF_HOST_MAX_BATCH_EVENTS) {
|
|
74468
74714
|
await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: `a client event write is a non-empty array of at most ${String(RC_SELF_HOST_MAX_BATCH_EVENTS)} events` } });
|
|
@@ -74470,7 +74716,7 @@ data: ${JSON.stringify(envelope)}
|
|
|
74470
74716
|
}
|
|
74471
74717
|
const results = [];
|
|
74472
74718
|
for (const event of events) {
|
|
74473
|
-
if (!
|
|
74719
|
+
if (!isRecord5(event) || !isRecord5(event.payload)) {
|
|
74474
74720
|
await answerJson2(response, HTTP_STATUS.badRequest, { type: "error", error: { type: "invalid_request_error", message: "every event in a write is an object carrying one payload object" } });
|
|
74475
74721
|
return;
|
|
74476
74722
|
}
|
|
@@ -74482,26 +74728,14 @@ data: ${JSON.stringify(envelope)}
|
|
|
74482
74728
|
return;
|
|
74483
74729
|
}
|
|
74484
74730
|
if (tail === "events" && method === "GET") {
|
|
74485
|
-
await answerJson2(response, HTTP_STATUS.ok, { data: session.events.map((event) => ({ event_id: event.eventId, event_type:
|
|
74731
|
+
await answerJson2(response, HTTP_STATUS.ok, { data: session.events.map((event) => ({ event_id: event.eventId, event_type: nonEmptyString3(event.payload, "type") ?? "event", sequence_num: event.sequenceNum, source: event.source, payload: event.payload, created_at: event.createdAt })) });
|
|
74486
74732
|
return;
|
|
74487
74733
|
}
|
|
74488
74734
|
if (tail === "events/stream" && method === "GET") {
|
|
74489
74735
|
await holdStream(session, "clientStreams", () => true, request7, response);
|
|
74490
74736
|
return;
|
|
74491
74737
|
}
|
|
74492
|
-
if (
|
|
74493
|
-
await readBody3(request7.body, CONTROL_BODY_CAP_BYTES);
|
|
74494
|
-
await answerJson2(response, HTTP_STATUS.ok, { refresh_after_seconds: RC_PRESENCE_REFRESH_SECONDS });
|
|
74495
|
-
return;
|
|
74496
|
-
}
|
|
74497
|
-
if (tail === "mark_read" && method === "POST") {
|
|
74498
|
-
await readBody3(request7.body, CONTROL_BODY_CAP_BYTES);
|
|
74499
|
-
await answerJson2(response, HTTP_STATUS.ok, {});
|
|
74500
|
-
return;
|
|
74501
|
-
}
|
|
74502
|
-
if (tail === "teleport-events" && method === "POST") {
|
|
74503
|
-
await readBody3(request7.body, CONTROL_BODY_CAP_BYTES);
|
|
74504
|
-
await answerJson2(response, HTTP_STATUS.ok, {});
|
|
74738
|
+
if (await serveRcClientChannels({ request: request7, response, session, answerJson: answerJson2, readBody: readBody3, publish, sweep, now: deps.now, presenceRefreshSeconds: RC_PRESENCE_REFRESH_SECONDS, ...deps.log === void 0 ? {} : { log: deps.log } }, tail, method, RC_SELF_HOST_MAX_BATCH_EVENTS)) {
|
|
74505
74739
|
return;
|
|
74506
74740
|
}
|
|
74507
74741
|
await answerJson2(response, HTTP_STATUS.notFound, { type: "error", error: { type: "api_error", message: `the self-hosted Remote Control surface serves no path "${tail}"` } });
|
|
@@ -74518,17 +74752,8 @@ data: ${JSON.stringify(envelope)}
|
|
|
74518
74752
|
await noCredential(response);
|
|
74519
74753
|
return;
|
|
74520
74754
|
}
|
|
74521
|
-
if (pathname === RC_COMPAT_SESSIONS_PATH) {
|
|
74522
|
-
|
|
74523
|
-
await answerJson2(response, HTTP_STATUS.methodNotAllowed, { type: "error", error: { type: "api_error", message: "the compatibility session list is a GET" } });
|
|
74524
|
-
return;
|
|
74525
|
-
}
|
|
74526
|
-
const listRefusal = credentialRefusal(request7.headers);
|
|
74527
|
-
if (listRefusal !== void 0) {
|
|
74528
|
-
await unauthorized(response, listRefusal);
|
|
74529
|
-
return;
|
|
74530
|
-
}
|
|
74531
|
-
await answerJson2(response, HTTP_STATUS.ok, { data: [] });
|
|
74755
|
+
if (pathname === RC_COMPAT_SESSIONS_PATH || pathname.startsWith(`${RC_COMPAT_SESSIONS_PATH}/`)) {
|
|
74756
|
+
await serveRcCompatSessions({ request: request7, response, sessions, answerJson: answerJson2, readBody: readBody3, credentialRefusal, unauthorized, now: deps.now, ...deps.log === void 0 ? {} : { log: deps.log } }, pathname, RC_COMPAT_SESSIONS_PATH);
|
|
74532
74757
|
return;
|
|
74533
74758
|
}
|
|
74534
74759
|
if (pathname !== RC_SESSIONS_PATH_PREFIX2 && !pathname.startsWith(`${RC_SESSIONS_PATH_PREFIX2}/`)) {
|
|
@@ -74542,11 +74767,11 @@ data: ${JSON.stringify(envelope)}
|
|
|
74542
74767
|
await unauthorized(response, createRefusal);
|
|
74543
74768
|
return;
|
|
74544
74769
|
}
|
|
74545
|
-
const body =
|
|
74770
|
+
const body = parseJsonObject3(await readBody3(request7.body, CONTROL_BODY_CAP_BYTES));
|
|
74546
74771
|
const session = {
|
|
74547
74772
|
id: `${RC_SESSION_ID_PREFIX2}${deps.newUuid()}`,
|
|
74548
74773
|
createdAt: deps.now(),
|
|
74549
|
-
title:
|
|
74774
|
+
title: nonEmptyString3(body, "title"),
|
|
74550
74775
|
workerJwts: /* @__PURE__ */ new Set(),
|
|
74551
74776
|
sequenceNum: 0,
|
|
74552
74777
|
events: [],
|
|
@@ -74554,6 +74779,7 @@ data: ${JSON.stringify(envelope)}
|
|
|
74554
74779
|
workerStreams: /* @__PURE__ */ new Set(),
|
|
74555
74780
|
clientStreams: /* @__PURE__ */ new Set(),
|
|
74556
74781
|
internalEvents: [],
|
|
74782
|
+
clients: /* @__PURE__ */ new Map(),
|
|
74557
74783
|
workerStatus: void 0,
|
|
74558
74784
|
externalMetadata: void 0,
|
|
74559
74785
|
lastTrafficAt: deps.now()
|
|
@@ -74598,7 +74824,7 @@ data: ${JSON.stringify(envelope)}
|
|
|
74598
74824
|
const pathname = new URL(request7.url ?? "/", "http://127.0.0.1").pathname;
|
|
74599
74825
|
if (host === RC_SELF_HOST_OAUTH_HOST) {
|
|
74600
74826
|
if (method === "POST" && pathname === "/v1/oauth/token") {
|
|
74601
|
-
const body =
|
|
74827
|
+
const body = parseJsonObject3(await readBody3(request7, CONTROL_BODY_CAP_BYTES));
|
|
74602
74828
|
const record2 = deps.credentialRecord();
|
|
74603
74829
|
if (record2 === void 0) {
|
|
74604
74830
|
answerServerJson(response, HTTP_SERVICE_UNAVAILABLE, { error: "the front door's self-hosted Remote Control surface is on but no credential has been minted for it" });
|
|
@@ -74683,7 +74909,7 @@ var RC_SELF_HOST_RECORD_DIR = "rc-selfhost";
|
|
|
74683
74909
|
var RC_SELF_HOST_RECORD_FILE = "credential.json";
|
|
74684
74910
|
var SELF_HOST_EMAIL = "selfhost@agent-shim.invalid";
|
|
74685
74911
|
var SELF_HOST_SUBSCRIPTION_TYPE = "max";
|
|
74686
|
-
function
|
|
74912
|
+
function isRecord6(value2) {
|
|
74687
74913
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
74688
74914
|
}
|
|
74689
74915
|
function readJsonObject(fs20, file2) {
|
|
@@ -74697,7 +74923,7 @@ function readJsonObject(fs20, file2) {
|
|
|
74697
74923
|
} catch {
|
|
74698
74924
|
return void 0;
|
|
74699
74925
|
}
|
|
74700
|
-
return
|
|
74926
|
+
return isRecord6(parsed) ? parsed : void 0;
|
|
74701
74927
|
}
|
|
74702
74928
|
function readRcSelfHostRecord(fs20, frontdoorDir) {
|
|
74703
74929
|
const parsed = readJsonObject(fs20, import_node_path34.default.join(frontdoorDir, RC_SELF_HOST_RECORD_DIR, RC_SELF_HOST_RECORD_FILE));
|
|
@@ -74721,7 +74947,7 @@ function mintRcSelfHostCredential(deps) {
|
|
|
74721
74947
|
const recordFile = import_node_path34.default.join(recordDir, RC_SELF_HOST_RECORD_FILE);
|
|
74722
74948
|
const previousRecord = readRcSelfHostRecord(deps.fs, deps.frontdoorDir);
|
|
74723
74949
|
const existingCredentials = readJsonObject(deps.fs, credentialsFile);
|
|
74724
|
-
const existingOauth =
|
|
74950
|
+
const existingOauth = isRecord6(existingCredentials?.claudeAiOauth) ? existingCredentials.claudeAiOauth : void 0;
|
|
74725
74951
|
const existingToken = typeof existingOauth?.accessToken === "string" && existingOauth.accessToken !== "" ? existingOauth.accessToken : void 0;
|
|
74726
74952
|
const existingIsOwn = existingToken !== void 0 && previousRecord?.accessToken === existingToken;
|
|
74727
74953
|
if (existingToken !== void 0 && !existingIsOwn && !deps.force) {
|
|
@@ -74738,7 +74964,7 @@ function mintRcSelfHostCredential(deps) {
|
|
|
74738
74964
|
deps.fs.writeFilePrivate(credentialsFile, `${JSON.stringify({ ...existingCredentials, claudeAiOauth: { accessToken, refreshToken, expiresAt: null, scopes: [...RC_SELF_HOST_SCOPE_LIST], subscriptionType: SELF_HOST_SUBSCRIPTION_TYPE, rateLimitTier: null } }, null, 2)}
|
|
74739
74965
|
`);
|
|
74740
74966
|
const claudeJson = readJsonObject(deps.fs, claudeJsonFile) ?? {};
|
|
74741
|
-
const existingBlock = (value2) =>
|
|
74967
|
+
const existingBlock = (value2) => isRecord6(value2) ? value2 : {};
|
|
74742
74968
|
deps.fs.writeFilePrivate(claudeJsonFile, `${JSON.stringify({
|
|
74743
74969
|
...claudeJson,
|
|
74744
74970
|
oauthAccount: {
|
|
@@ -75037,6 +75263,12 @@ function registerRcCommand(frontdoor, paths) {
|
|
|
75037
75263
|
}),
|
|
75038
75264
|
["agent-shim frontdoor rc mcp-oauth-callback-url --session cse_00000000-0000-4000-8000-000000000000 --server github --callback-url https://example.com/oauth/callback?code=x"]
|
|
75039
75265
|
);
|
|
75266
|
+
withExamples(
|
|
75267
|
+
rc.command("teleport").description("Send one teleport marker into an observed session over the teleport-events channel, the write half the cloud UI's ultrapan path owns on the real service. The marker rides the SDK user-message shape, the line the teleport relay anchors on.").requiredOption("--session <id>", "The cse_ session id, as `frontdoor rc list` shows it.").requiredOption("--marker <text>", "The marker text, the string content the teleport relay anchors on.").option("--json", "Print the delivery result as JSON.").action(async (options) => {
|
|
75268
|
+
reportControlWrite(`teleported a marker into the session`, options.session, await frontDoorRcControlFromState(realFarmFs, paths).teleport(options.session, options.marker), options.json, { marker: options.marker });
|
|
75269
|
+
}),
|
|
75270
|
+
['agent-shim frontdoor rc teleport --session cse_00000000-0000-4000-8000-000000000000 --marker "__ULTRAPAN_TELEPORT_LOCAL__"']
|
|
75271
|
+
);
|
|
75040
75272
|
withExamples(
|
|
75041
75273
|
rc.command("watch").description("Print the observed sessions' client read stream events as they arrive, the approvals the door's held stream receives above all, until Ctrl-C leaves. Read-only.").argument("[session]", "One cse_ session id, as `frontdoor rc list` shows it; every observed session when omitted.").option("--json", "Print each event as one JSON line as it arrives.").action(async (session, options) => {
|
|
75042
75274
|
const client = frontDoorRcApiFromState(realFarmFs, paths);
|
|
@@ -75096,11 +75328,11 @@ var import_node_path35 = __toESM(require("node:path"), 1);
|
|
|
75096
75328
|
function isSafeSessionId(sessionId) {
|
|
75097
75329
|
return /^[A-Za-z0-9_-]+$/.test(sessionId);
|
|
75098
75330
|
}
|
|
75099
|
-
function
|
|
75331
|
+
function isRecord7(value2) {
|
|
75100
75332
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
75101
75333
|
}
|
|
75102
75334
|
function credentialOfJson(parsed) {
|
|
75103
|
-
if (!
|
|
75335
|
+
if (!isRecord7(parsed)) {
|
|
75104
75336
|
return void 0;
|
|
75105
75337
|
}
|
|
75106
75338
|
const { authorization, anthropicVersion, anthropicClientPlatform } = parsed;
|
|
@@ -75130,7 +75362,7 @@ function createRcCredentialStore(fs20, dir) {
|
|
|
75130
75362
|
} catch {
|
|
75131
75363
|
return void 0;
|
|
75132
75364
|
}
|
|
75133
|
-
return
|
|
75365
|
+
return isRecord7(parsed) ? parsed : void 0;
|
|
75134
75366
|
};
|
|
75135
75367
|
return {
|
|
75136
75368
|
read: (sessionId) => {
|
|
@@ -75694,7 +75926,7 @@ function createSseParser() {
|
|
|
75694
75926
|
}
|
|
75695
75927
|
};
|
|
75696
75928
|
}
|
|
75697
|
-
function
|
|
75929
|
+
function isRecord8(value2) {
|
|
75698
75930
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
75699
75931
|
}
|
|
75700
75932
|
function sequenceNumOf(value2) {
|
|
@@ -75716,7 +75948,7 @@ function parseRcStreamEnvelope(parsed) {
|
|
|
75716
75948
|
} catch {
|
|
75717
75949
|
return void 0;
|
|
75718
75950
|
}
|
|
75719
|
-
if (!
|
|
75951
|
+
if (!isRecord8(data)) {
|
|
75720
75952
|
return void 0;
|
|
75721
75953
|
}
|
|
75722
75954
|
const eventType = data.event_type;
|
|
@@ -75799,9 +76031,26 @@ function createRcStreamHub(deps) {
|
|
|
75799
76031
|
}
|
|
75800
76032
|
return headers;
|
|
75801
76033
|
};
|
|
76034
|
+
let receiptFailureLogged = false;
|
|
76035
|
+
const sendReceipt = (attachment, headers, eventId) => {
|
|
76036
|
+
if (eventId === void 0) {
|
|
76037
|
+
return;
|
|
76038
|
+
}
|
|
76039
|
+
deps.dial.markRead(attachment.sessionId, headers, eventId).then(
|
|
76040
|
+
() => {
|
|
76041
|
+
receiptFailureLogged = false;
|
|
76042
|
+
},
|
|
76043
|
+
(error62) => {
|
|
76044
|
+
if (!receiptFailureLogged) {
|
|
76045
|
+
receiptFailureLogged = true;
|
|
76046
|
+
deps.log?.(`rc stream ${attachment.sessionId}: the read receipt for event ${eventId} could not be sent (${error62 instanceof Error ? error62.message : String(error62)}); further receipt failures stay quiet until one lands`);
|
|
76047
|
+
}
|
|
76048
|
+
}
|
|
76049
|
+
);
|
|
76050
|
+
};
|
|
75802
76051
|
const attempt = async (attachment, credential) => {
|
|
75803
76052
|
const headers = streamHeaders(credential);
|
|
75804
|
-
const presence = await deps.dial.announcePresence(attachment.sessionId, headers, attachment.clientId);
|
|
76053
|
+
const presence = await deps.dial.announcePresence(attachment.sessionId, headers, attachment.clientId, false);
|
|
75805
76054
|
if (presence.status === HTTP_STATUS.unauthorized) {
|
|
75806
76055
|
return "unauthorized";
|
|
75807
76056
|
}
|
|
@@ -75821,6 +76070,7 @@ function createRcStreamHub(deps) {
|
|
|
75821
76070
|
const parser = createSseParser();
|
|
75822
76071
|
for await (const chunk of answer.chunks) {
|
|
75823
76072
|
attachment.controller.signal.throwIfAborted();
|
|
76073
|
+
let lastEventId;
|
|
75824
76074
|
for (const parsed of parser.write(Buffer.from(chunk).toString("utf8"))) {
|
|
75825
76075
|
const envelope = parseRcStreamEnvelope(parsed);
|
|
75826
76076
|
if (envelope === void 0) {
|
|
@@ -75828,10 +76078,21 @@ function createRcStreamHub(deps) {
|
|
|
75828
76078
|
}
|
|
75829
76079
|
deps.fileStreamEvent(attachment.sessionId, envelope);
|
|
75830
76080
|
deps.fanout.publish({ session: attachment.sessionId, envelope });
|
|
76081
|
+
if (typeof envelope.event_id === "string" && envelope.event_type !== "mark_read") {
|
|
76082
|
+
lastEventId = envelope.event_id;
|
|
76083
|
+
}
|
|
75831
76084
|
}
|
|
76085
|
+
sendReceipt(attachment, headers, lastEventId);
|
|
75832
76086
|
}
|
|
75833
76087
|
return "dropped";
|
|
75834
76088
|
};
|
|
76089
|
+
const clearPresence = (attachment, headers) => {
|
|
76090
|
+
if (headers === void 0) {
|
|
76091
|
+
return;
|
|
76092
|
+
}
|
|
76093
|
+
void deps.dial.announcePresence(attachment.sessionId, headers, attachment.clientId, true).catch(() => {
|
|
76094
|
+
});
|
|
76095
|
+
};
|
|
75835
76096
|
const runLoop = async (attachment) => {
|
|
75836
76097
|
let retriedUnauthorized = false;
|
|
75837
76098
|
for (; ; ) {
|
|
@@ -75843,6 +76104,7 @@ function createRcStreamHub(deps) {
|
|
|
75843
76104
|
if (!live || credential?.authorization === void 0) {
|
|
75844
76105
|
deps.log?.(`rc stream ${attachment.sessionId}: the attachment ended (${live ? "the session's client credential is no longer known" : "the tracker gave up on the session"})`);
|
|
75845
76106
|
persistCursor(attachment.sessionId);
|
|
76107
|
+
clearPresence(attachment, credential === void 0 ? void 0 : streamHeaders(credential));
|
|
75846
76108
|
if (attachments.get(attachment.sessionId) === attachment) {
|
|
75847
76109
|
attachments.delete(attachment.sessionId);
|
|
75848
76110
|
}
|
|
@@ -75905,6 +76167,8 @@ function createRcStreamHub(deps) {
|
|
|
75905
76167
|
close: () => {
|
|
75906
76168
|
for (const attachment of attachments.values()) {
|
|
75907
76169
|
persistCursor(attachment.sessionId);
|
|
76170
|
+
const credential = deps.credentialOf(attachment.sessionId);
|
|
76171
|
+
clearPresence(attachment, credential?.authorization === void 0 ? void 0 : streamHeaders(credential));
|
|
75908
76172
|
attachment.stop();
|
|
75909
76173
|
}
|
|
75910
76174
|
attachments.clear();
|
|
@@ -76392,6 +76656,7 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
76392
76656
|
const rcMcpReconnect = async (sessionId, serverName) => await reconnectRcSessionMcpServer(rcControlRequestDeps, sessionId, serverName);
|
|
76393
76657
|
const rcMcpAuthenticate = async (sessionId, serverName, redirectUri) => await authenticateRcSessionMcpServer(rcControlRequestDeps, sessionId, serverName, redirectUri);
|
|
76394
76658
|
const rcMcpOAuthCallbackUrl = async (sessionId, serverName, callbackUrl) => await submitRcSessionMcpOAuthCallbackUrl(rcControlRequestDeps, sessionId, serverName, callbackUrl);
|
|
76659
|
+
const rcTeleport = async (sessionId, marker) => await teleportRcSession(rcControlRequestDeps, sessionId, marker);
|
|
76395
76660
|
const controlDeps = {
|
|
76396
76661
|
usageSnapshots: () => listUsageSnapshots(realFarmFs, paths.usageSnapshotsDir),
|
|
76397
76662
|
usageSnapshotOf: (identity) => readUsageSnapshot(realFarmFs, paths.usageSnapshotsDir, identity),
|
|
@@ -76409,7 +76674,7 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
76409
76674
|
},
|
|
76410
76675
|
log,
|
|
76411
76676
|
mintLeaf(authority, LOOPBACK_LEAF_NAMES, /* @__PURE__ */ new Date()),
|
|
76412
|
-
createRcControlHandler({ expectedToken: rcControlToken, list: rcTracker.list, statusOf: rcTracker.statusOf, pendingOf: rcTracker.pendingOf, inject: rcInject, answer: rcAnswer, interrupt: rcInterrupt, setModel: rcSetModel, setPermissionMode: rcSetPermissionMode, endSession: rcEndSession, getUsage: rcGetUsage, getContextUsage: rcGetContextUsage, readFile: rcReadFile, fileSuggestions: rcFileSuggestions, keepAlive: rcKeepAlive, mcpStatus: rcMcpStatus, mcpReconnect: rcMcpReconnect, mcpAuthenticate: rcMcpAuthenticate, mcpOAuthCallbackUrl: rcMcpOAuthCallbackUrl }),
|
|
76677
|
+
createRcControlHandler({ expectedToken: rcControlToken, list: rcTracker.list, statusOf: rcTracker.statusOf, pendingOf: rcTracker.pendingOf, inject: rcInject, answer: rcAnswer, interrupt: rcInterrupt, setModel: rcSetModel, setPermissionMode: rcSetPermissionMode, endSession: rcEndSession, getUsage: rcGetUsage, getContextUsage: rcGetContextUsage, readFile: rcReadFile, fileSuggestions: rcFileSuggestions, keepAlive: rcKeepAlive, mcpStatus: rcMcpStatus, mcpReconnect: rcMcpReconnect, mcpAuthenticate: rcMcpAuthenticate, mcpOAuthCallbackUrl: rcMcpOAuthCallbackUrl, teleport: rcTeleport }),
|
|
76413
76678
|
[
|
|
76414
76679
|
createDoorApiNodeHandler({
|
|
76415
76680
|
expectedToken: rcControlToken,
|
|
@@ -76431,6 +76696,7 @@ function realFrontDoorSupervisorPorts(paths) {
|
|
|
76431
76696
|
mcpReconnect: rcMcpReconnect,
|
|
76432
76697
|
mcpAuthenticate: rcMcpAuthenticate,
|
|
76433
76698
|
mcpOAuthCallbackUrl: rcMcpOAuthCallbackUrl,
|
|
76699
|
+
teleport: rcTeleport,
|
|
76434
76700
|
fanout: rcFanout,
|
|
76435
76701
|
...controlDeps,
|
|
76436
76702
|
events: doorEvents
|