agent-shim 8.23.0 → 8.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -93,10 +93,12 @@ __export(index_exports, {
93
93
  ProviderKindMismatchError: () => ProviderKindMismatchError,
94
94
  ProviderNotFoundError: () => ProviderNotFoundError,
95
95
  ProviderSchema: () => ProviderSchema,
96
+ RC_CONTEXT_USAGE_DETAILS: () => RC_CONTEXT_USAGE_DETAILS,
96
97
  RC_IDLE_EXPIRY_MS: () => RC_IDLE_EXPIRY_MS,
97
98
  RC_ORPC_PATH_PREFIX: () => RC_ORPC_PATH_PREFIX,
98
99
  RC_PENDING_DEADLINE_MS: () => RC_PENDING_DEADLINE_MS,
99
100
  RC_PERMISSION_MODES: () => RC_PERMISSION_MODES,
101
+ RC_READ_FILE_ENCODINGS: () => RC_READ_FILE_ENCODINGS,
100
102
  RC_REQUEST_PARSE_CAP_BYTES: () => RC_REQUEST_PARSE_CAP_BYTES,
101
103
  RC_SELF_HOST_ENV: () => RC_SELF_HOST_ENV,
102
104
  RC_SELF_HOST_KEEPALIVE_MS: () => RC_SELF_HOST_KEEPALIVE_MS,
@@ -127,11 +129,23 @@ __export(index_exports, {
127
129
  addPool: () => addPool,
128
130
  addProvider: () => addProvider,
129
131
  answerRcControlRequest: () => answerRcControlRequest,
132
+ authenticateRcSessionMcpServer: () => authenticateRcSessionMcpServer,
130
133
  buildEntryFacts: () => buildEntryFacts,
131
134
  buildLayoutPaths: () => buildLayoutPaths,
135
+ buildRcControlRequestPayload: () => buildRcControlRequestPayload,
132
136
  buildRcControlResponsePayload: () => buildRcControlResponsePayload,
137
+ buildRcEndSessionPayload: () => buildRcEndSessionPayload,
133
138
  buildRcEventWriteBody: () => buildRcEventWriteBody,
139
+ buildRcFileSuggestionsPayload: () => buildRcFileSuggestionsPayload,
140
+ buildRcGetContextUsagePayload: () => buildRcGetContextUsagePayload,
141
+ buildRcGetUsagePayload: () => buildRcGetUsagePayload,
134
142
  buildRcInterruptPayload: () => buildRcInterruptPayload,
143
+ buildRcKeepAlivePayload: () => buildRcKeepAlivePayload,
144
+ buildRcMcpAuthenticatePayload: () => buildRcMcpAuthenticatePayload,
145
+ buildRcMcpOAuthCallbackUrlPayload: () => buildRcMcpOAuthCallbackUrlPayload,
146
+ buildRcMcpReconnectPayload: () => buildRcMcpReconnectPayload,
147
+ buildRcMcpStatusPayload: () => buildRcMcpStatusPayload,
148
+ buildRcReadFilePayload: () => buildRcReadFilePayload,
135
149
  buildRcSetModelPayload: () => buildRcSetModelPayload,
136
150
  buildRcSetPermissionModePayload: () => buildRcSetPermissionModePayload,
137
151
  buildRcUserMessagePayload: () => buildRcUserMessagePayload,
@@ -164,6 +178,7 @@ __export(index_exports, {
164
178
  doorApiAuth: () => doorApiAuth,
165
179
  doorApiNodeHandlerOf: () => doorApiNodeHandlerOf,
166
180
  effectiveWindow: () => effectiveWindow,
181
+ endRcSession: () => endRcSession,
167
182
  ensureCa: () => ensureCa,
168
183
  ensureFrontDoor: () => ensureFrontDoor,
169
184
  ensureHeadroom: () => ensureHeadroom,
@@ -180,6 +195,9 @@ __export(index_exports, {
180
195
  frontDoorRcApiClient: () => frontDoorRcApiClient,
181
196
  frontDoorRcControl: () => frontDoorRcControl,
182
197
  generateCa: () => generateCa,
198
+ getRcSessionContextUsage: () => getRcSessionContextUsage,
199
+ getRcSessionMcpStatus: () => getRcSessionMcpStatus,
200
+ getRcSessionUsage: () => getRcSessionUsage,
183
201
  headroomSocketTarget: () => headroomSocketTarget,
184
202
  identityExists: () => identityExists,
185
203
  injectRcUserMessage: () => injectRcUserMessage,
@@ -187,7 +205,9 @@ __export(index_exports, {
187
205
  isIdentityDirectoryName: () => isIdentityDirectoryName,
188
206
  isInterceptedHost: () => isInterceptedHost,
189
207
  isPrivateAddress: () => isPrivateAddress,
208
+ isRcContextUsageDetail: () => isRcContextUsageDetail,
190
209
  isRcPermissionMode: () => isRcPermissionMode,
210
+ isRcReadFileEncoding: () => isRcReadFileEncoding,
191
211
  lateRcEventDial: () => lateRcEventDial,
192
212
  lateRcStreamDial: () => lateRcStreamDial,
193
213
  listDirectoryRules: () => listDirectoryRules,
@@ -221,6 +241,7 @@ __export(index_exports, {
221
241
  readProfile: () => readProfile,
222
242
  readProvider: () => readProvider,
223
243
  readRcSelfHostRecord: () => readRcSelfHostRecord,
244
+ readRcSessionFile: () => readRcSessionFile,
224
245
  readUsageSnapshot: () => readUsageSnapshot,
225
246
  realConnectCertStore: () => realConnectCertStore,
226
247
  realConnectEffects: () => realConnectEffects,
@@ -228,6 +249,7 @@ __export(index_exports, {
228
249
  realRcEventDial: () => realRcEventDial,
229
250
  realRcStreamDial: () => realRcStreamDial,
230
251
  realRcWebFetch: () => realRcWebFetch,
252
+ reconnectRcSessionMcpServer: () => reconnectRcSessionMcpServer,
231
253
  recoverFarm: () => recoverFarm,
232
254
  recoveryDiagnostics: () => recoveryDiagnostics,
233
255
  removeDirectoryRule: () => removeDirectoryRule,
@@ -247,6 +269,7 @@ __export(index_exports, {
247
269
  runFrontDoorSupervisor: () => runFrontDoorSupervisor,
248
270
  runLauncher: () => runLauncher,
249
271
  runSupervisor: () => runSupervisor,
272
+ sendRcKeepAlive: () => sendRcKeepAlive,
250
273
  servedByPipeline: () => servedByPipeline,
251
274
  setAllowAmbientCredential: () => setAllowAmbientCredential,
252
275
  setDefaultConfigProfile: () => setDefaultConfigProfile,
@@ -262,6 +285,8 @@ __export(index_exports, {
262
285
  snapshotPath: () => snapshotPath,
263
286
  spawnClaude: () => spawnClaude,
264
287
  startConnectServer: () => startConnectServer,
288
+ submitRcSessionMcpOAuthCallbackUrl: () => submitRcSessionMcpOAuthCallbackUrl,
289
+ suggestRcSessionFiles: () => suggestRcSessionFiles,
265
290
  topLevelNames: () => topLevelNames,
266
291
  updateDirectoryRule: () => updateDirectoryRule,
267
292
  updateProvider: () => updateProvider,
@@ -3902,6 +3927,8 @@ function rcObserverAsPassthrough(observer) {
3902
3927
  }
3903
3928
  };
3904
3929
  }
3930
+
3931
+ // src/frontdoor/rcWrites.ts
3905
3932
  function buildRcUserMessagePayload(uuid, sessionId, text) {
3906
3933
  return {
3907
3934
  type: "user",
@@ -4002,14 +4029,55 @@ var RC_PERMISSION_MODES = ["default", "acceptEdits", "bypassPermissions", "plan"
4002
4029
  function isRcPermissionMode(value) {
4003
4030
  return RC_PERMISSION_MODES.some((mode) => mode === value);
4004
4031
  }
4032
+ function buildRcControlRequestPayload(requestId, request4) {
4033
+ return { type: "control_request", request_id: requestId, request: request4 };
4034
+ }
4005
4035
  function buildRcInterruptPayload(requestId) {
4006
- return { type: "control_request", request_id: requestId, request: { subtype: "interrupt" } };
4036
+ return buildRcControlRequestPayload(requestId, { subtype: "interrupt" });
4007
4037
  }
4008
4038
  function buildRcSetModelPayload(requestId, model) {
4009
- return { type: "control_request", request_id: requestId, request: { subtype: "set_model", model } };
4039
+ return buildRcControlRequestPayload(requestId, { subtype: "set_model", model });
4010
4040
  }
4011
4041
  function buildRcSetPermissionModePayload(requestId, mode) {
4012
- return { type: "control_request", request_id: requestId, request: { subtype: "set_permission_mode", mode } };
4042
+ return buildRcControlRequestPayload(requestId, { subtype: "set_permission_mode", mode });
4043
+ }
4044
+ function buildRcEndSessionPayload(requestId, reason) {
4045
+ return buildRcControlRequestPayload(requestId, { subtype: "end_session", ...reason === void 0 ? {} : { reason } });
4046
+ }
4047
+ function buildRcGetUsagePayload(requestId, skipBehaviors) {
4048
+ return buildRcControlRequestPayload(requestId, { subtype: "get_usage", ...skipBehaviors === true ? { skip_behaviors: true } : {} });
4049
+ }
4050
+ var RC_CONTEXT_USAGE_DETAILS = ["summary", "full"];
4051
+ function isRcContextUsageDetail(value) {
4052
+ return RC_CONTEXT_USAGE_DETAILS.some((detail) => detail === value);
4053
+ }
4054
+ function buildRcGetContextUsagePayload(requestId, detail) {
4055
+ return buildRcControlRequestPayload(requestId, { subtype: "get_context_usage", ...detail === void 0 ? {} : { detail } });
4056
+ }
4057
+ var RC_READ_FILE_ENCODINGS = ["utf-8", "base64"];
4058
+ function isRcReadFileEncoding(value) {
4059
+ return RC_READ_FILE_ENCODINGS.some((encoding) => encoding === value);
4060
+ }
4061
+ function buildRcReadFilePayload(requestId, path32, options) {
4062
+ return buildRcControlRequestPayload(requestId, { subtype: "read_file", path: path32, ...options?.maxBytes === void 0 ? {} : { max_bytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } });
4063
+ }
4064
+ function buildRcFileSuggestionsPayload(requestId, query) {
4065
+ return buildRcControlRequestPayload(requestId, { subtype: "file_suggestions", query });
4066
+ }
4067
+ function buildRcMcpStatusPayload(requestId) {
4068
+ return buildRcControlRequestPayload(requestId, { subtype: "mcp_status" });
4069
+ }
4070
+ function buildRcMcpReconnectPayload(requestId, serverName) {
4071
+ return buildRcControlRequestPayload(requestId, { subtype: "mcp_reconnect", serverName });
4072
+ }
4073
+ function buildRcMcpAuthenticatePayload(requestId, serverName, redirectUri) {
4074
+ return buildRcControlRequestPayload(requestId, { subtype: "mcp_authenticate", serverName, redirectUri });
4075
+ }
4076
+ function buildRcMcpOAuthCallbackUrlPayload(requestId, serverName, callbackUrl) {
4077
+ return buildRcControlRequestPayload(requestId, { subtype: "mcp_oauth_callback_url", serverName, callbackUrl });
4078
+ }
4079
+ function buildRcKeepAlivePayload() {
4080
+ return { type: "keep_alive" };
4013
4081
  }
4014
4082
  async function answerRcControlRequest(deps, sessionId, requestId, decision) {
4015
4083
  const credential = deps.credentialOf(sessionId);
@@ -4036,7 +4104,7 @@ async function answerRcControlRequest(deps, sessionId, requestId, decision) {
4036
4104
  }
4037
4105
  return result;
4038
4106
  }
4039
- async function interruptRcSession(deps, sessionId) {
4107
+ async function deliverRcClientPayload(deps, sessionId, payload, action) {
4040
4108
  const credential = deps.credentialOf(sessionId);
4041
4109
  if (credential === void 0) {
4042
4110
  return { ok: false, message: rcSessionNotObservedMessage(sessionId) };
@@ -4044,12 +4112,12 @@ async function interruptRcSession(deps, sessionId) {
4044
4112
  if (credential.authorization === void 0) {
4045
4113
  return noOAuthCredentialResult(sessionId);
4046
4114
  }
4047
- const body = JSON.stringify(buildRcEventWriteBody(buildRcInterruptPayload(deps.newUuid())));
4115
+ const body = JSON.stringify(buildRcEventWriteBody(payload));
4048
4116
  let answer;
4049
4117
  try {
4050
4118
  answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
4051
4119
  } catch (error) {
4052
- return { ok: false, message: `the door could not reach the API host to interrupt session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
4120
+ return { ok: false, message: `the door could not reach the API host to ${action}: ${error instanceof Error ? error.message : String(error)}` };
4053
4121
  }
4054
4122
  const result = rcEventWriteResultFromAnswer(answer);
4055
4123
  if (result.ok) {
@@ -4057,50 +4125,89 @@ async function interruptRcSession(deps, sessionId) {
4057
4125
  }
4058
4126
  return result;
4059
4127
  }
4128
+ async function interruptRcSession(deps, sessionId) {
4129
+ const requestId = deps.newUuid();
4130
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcInterruptPayload(requestId), `interrupt session ${sessionId}`);
4131
+ return result.ok ? { ...result, requestId } : result;
4132
+ }
4060
4133
  async function setRcSessionModel(deps, sessionId, model) {
4061
4134
  if (model === "") {
4062
4135
  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" };
4063
4136
  }
4064
- const credential = deps.credentialOf(sessionId);
4065
- if (credential === void 0) {
4066
- return { ok: false, message: rcSessionNotObservedMessage(sessionId) };
4067
- }
4068
- if (credential.authorization === void 0) {
4069
- return noOAuthCredentialResult(sessionId);
4137
+ const requestId = deps.newUuid();
4138
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcSetModelPayload(requestId, model), `set the model on session ${sessionId}`);
4139
+ return result.ok ? { ...result, requestId } : result;
4140
+ }
4141
+ async function setRcSessionPermissionMode(deps, sessionId, mode) {
4142
+ const requestId = deps.newUuid();
4143
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcSetPermissionModePayload(requestId, mode), `set the permission mode on session ${sessionId}`);
4144
+ return result.ok ? { ...result, requestId } : result;
4145
+ }
4146
+ async function endRcSession(deps, sessionId, reason) {
4147
+ if (reason === "") {
4148
+ return { ok: false, message: "an end-session write needs either no reason or a non-empty one: the worker reads an absent reason as its own unspecified form, and an empty string is neither" };
4070
4149
  }
4071
- const body = JSON.stringify(buildRcEventWriteBody(buildRcSetModelPayload(deps.newUuid(), model)));
4072
- let answer;
4073
- try {
4074
- answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
4075
- } catch (error) {
4076
- return { ok: false, message: `the door could not reach the API host to set the model on session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
4150
+ const requestId = deps.newUuid();
4151
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcEndSessionPayload(requestId, reason), `end session ${sessionId}`);
4152
+ return result.ok ? { ...result, requestId } : result;
4153
+ }
4154
+ async function getRcSessionUsage(deps, sessionId, skipBehaviors) {
4155
+ const requestId = deps.newUuid();
4156
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcGetUsagePayload(requestId, skipBehaviors), `request the usage of session ${sessionId}`);
4157
+ return result.ok ? { ...result, requestId } : result;
4158
+ }
4159
+ async function getRcSessionContextUsage(deps, sessionId, detail) {
4160
+ const requestId = deps.newUuid();
4161
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcGetContextUsagePayload(requestId, detail), `request the context usage of session ${sessionId}`);
4162
+ return result.ok ? { ...result, requestId } : result;
4163
+ }
4164
+ async function readRcSessionFile(deps, sessionId, path32, options) {
4165
+ if (path32 === "") {
4166
+ return { ok: false, message: "a read-file write needs a non-empty path: the SDK's own field names the file the worker resolves against the session's cwd, and an empty string names none" };
4077
4167
  }
4078
- const result = rcEventWriteResultFromAnswer(answer);
4079
- if (result.ok) {
4080
- deps.noteSequenceNums(sessionId, result.sequenceNums);
4168
+ if (options?.maxBytes !== void 0 && (!Number.isInteger(options.maxBytes) || options.maxBytes <= 0)) {
4169
+ return { ok: false, message: "a read-file write's max-bytes is a positive whole number of bytes: the SDK's own field caps the read, and a zero or negative cap reads nothing" };
4081
4170
  }
4082
- return result;
4171
+ const requestId = deps.newUuid();
4172
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcReadFilePayload(requestId, path32, options), `read ${path32} from session ${sessionId}`);
4173
+ return result.ok ? { ...result, requestId } : result;
4083
4174
  }
4084
- async function setRcSessionPermissionMode(deps, sessionId, mode) {
4085
- const credential = deps.credentialOf(sessionId);
4086
- if (credential === void 0) {
4087
- return { ok: false, message: rcSessionNotObservedMessage(sessionId) };
4088
- }
4089
- if (credential.authorization === void 0) {
4090
- return noOAuthCredentialResult(sessionId);
4175
+ async function suggestRcSessionFiles(deps, sessionId, query) {
4176
+ const requestId = deps.newUuid();
4177
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcFileSuggestionsPayload(requestId, query), `request file suggestions from session ${sessionId}`);
4178
+ return result.ok ? { ...result, requestId } : result;
4179
+ }
4180
+ async function getRcSessionMcpStatus(deps, sessionId) {
4181
+ const requestId = deps.newUuid();
4182
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcMcpStatusPayload(requestId), `request the MCP status of session ${sessionId}`);
4183
+ return result.ok ? { ...result, requestId } : result;
4184
+ }
4185
+ async function reconnectRcSessionMcpServer(deps, sessionId, serverName) {
4186
+ if (serverName === "") {
4187
+ return { ok: false, message: "an mcp-reconnect write needs a non-empty server name: the SDK's own field names the server as mcp_status reports it, and an empty string names none" };
4091
4188
  }
4092
- const body = JSON.stringify(buildRcEventWriteBody(buildRcSetPermissionModePayload(deps.newUuid(), mode)));
4093
- let answer;
4094
- try {
4095
- answer = await deps.dial.writeEvents(sessionId, rcWriteHeaders(credential), body);
4096
- } catch (error) {
4097
- return { ok: false, message: `the door could not reach the API host to set the permission mode on session ${sessionId}: ${error instanceof Error ? error.message : String(error)}` };
4189
+ const requestId = deps.newUuid();
4190
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcMcpReconnectPayload(requestId, serverName), `reconnect MCP server ${serverName} on session ${sessionId}`);
4191
+ return result.ok ? { ...result, requestId } : result;
4192
+ }
4193
+ async function authenticateRcSessionMcpServer(deps, sessionId, serverName, redirectUri) {
4194
+ if (serverName === "" || redirectUri === "") {
4195
+ return { ok: false, message: "an mcp-authenticate write needs a non-empty server name and redirect URI: the CLI's own request names the server and where its OAuth flow redirects back to, and an empty string names neither" };
4098
4196
  }
4099
- const result = rcEventWriteResultFromAnswer(answer);
4100
- if (result.ok) {
4101
- deps.noteSequenceNums(sessionId, result.sequenceNums);
4197
+ const requestId = deps.newUuid();
4198
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcMcpAuthenticatePayload(requestId, serverName, redirectUri), `authenticate MCP server ${serverName} on session ${sessionId}`);
4199
+ return result.ok ? { ...result, requestId } : result;
4200
+ }
4201
+ async function submitRcSessionMcpOAuthCallbackUrl(deps, sessionId, serverName, callbackUrl) {
4202
+ if (serverName === "" || callbackUrl === "") {
4203
+ return { ok: false, message: "an mcp-oauth-callback-url write needs a non-empty server name and callback URL: the CLI's own request names the server and the URL its OAuth flow landed on, and an empty string names neither" };
4102
4204
  }
4103
- return result;
4205
+ const requestId = deps.newUuid();
4206
+ const result = await deliverRcClientPayload(deps, sessionId, buildRcMcpOAuthCallbackUrlPayload(requestId, serverName, callbackUrl), `hand MCP server ${serverName}'s OAuth callback to session ${sessionId}`);
4207
+ return result.ok ? { ...result, requestId } : result;
4208
+ }
4209
+ async function sendRcKeepAlive(deps, sessionId) {
4210
+ return await deliverRcClientPayload(deps, sessionId, buildRcKeepAlivePayload(), `keep session ${sessionId} alive`);
4104
4211
  }
4105
4212
 
4106
4213
  // src/frontdoor/rcControl.ts
@@ -4112,6 +4219,25 @@ function answerJson(response, status, body) {
4112
4219
  response.writeHead(status, { "content-type": "application/json", "content-length": String(Buffer.byteLength(text, "utf8")) });
4113
4220
  response.end(text);
4114
4221
  }
4222
+ function isJsonObject(value) {
4223
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4224
+ }
4225
+ function bodyString(body, field) {
4226
+ const value = body[field];
4227
+ return typeof value === "string" && value !== "" ? value : void 0;
4228
+ }
4229
+ function bodyStringAllowingEmpty(body, field) {
4230
+ const value = body[field];
4231
+ return typeof value === "string" ? value : void 0;
4232
+ }
4233
+ function bodyBoolean(body, field) {
4234
+ const value = body[field];
4235
+ return typeof value === "boolean" ? value : void 0;
4236
+ }
4237
+ function bodyPositiveInteger(body, field) {
4238
+ const value = body[field];
4239
+ return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : void 0;
4240
+ }
4115
4241
  async function readBody(request4) {
4116
4242
  return await new Promise((resolve, reject) => {
4117
4243
  const chunks = [];
@@ -4139,9 +4265,127 @@ function createRcControlHandler(deps) {
4139
4265
  const pendingPath = `${CONTROL_PATH_PREFIX}/pending`;
4140
4266
  const injectPath = `${CONTROL_PATH_PREFIX}/inject`;
4141
4267
  const answerPath = `${CONTROL_PATH_PREFIX}/answer`;
4142
- const interruptPath = `${CONTROL_PATH_PREFIX}/interrupt`;
4143
- const setModelPath = `${CONTROL_PATH_PREFIX}/set-model`;
4144
- const setPermissionModePath = `${CONTROL_PATH_PREFIX}/set-permission-mode`;
4268
+ const controlWrites = [
4269
+ {
4270
+ name: "interrupt",
4271
+ path: "interrupt",
4272
+ read: (body) => {
4273
+ const session = bodyString(body, "session");
4274
+ return session === void 0 ? { error: "the interrupt body must be JSON naming a non-empty session id" } : { session, run: async () => await deps.interrupt(session) };
4275
+ }
4276
+ },
4277
+ {
4278
+ name: "set-model",
4279
+ path: "set-model",
4280
+ read: (body) => {
4281
+ const session = bodyString(body, "session");
4282
+ const model = bodyString(body, "model");
4283
+ return session === void 0 || model === void 0 ? { error: "the set-model body must be JSON naming a non-empty session id and model id" } : { session, run: async () => await deps.setModel(session, model) };
4284
+ }
4285
+ },
4286
+ {
4287
+ name: "set-permission-mode",
4288
+ path: "set-permission-mode",
4289
+ read: (body) => {
4290
+ const session = bodyString(body, "session");
4291
+ const mode = body.mode;
4292
+ return session === void 0 || !isRcPermissionMode(mode) ? { 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})` } : { session, run: async () => await deps.setPermissionMode(session, mode) };
4293
+ }
4294
+ },
4295
+ {
4296
+ name: "end-session",
4297
+ path: "end-session",
4298
+ read: (body) => {
4299
+ const session = bodyString(body, "session");
4300
+ const reason = "reason" in body ? bodyString(body, "reason") : void 0;
4301
+ return session === void 0 || "reason" in body && reason === void 0 ? { error: "the end-session body must be JSON naming a non-empty session id, and a reason only as a non-empty string or absent" } : { session, run: async () => await deps.endSession(session, reason) };
4302
+ }
4303
+ },
4304
+ {
4305
+ name: "get-usage",
4306
+ path: "get-usage",
4307
+ read: (body) => {
4308
+ const session = bodyString(body, "session");
4309
+ const skipBehaviors = "skipBehaviors" in body ? bodyBoolean(body, "skipBehaviors") : void 0;
4310
+ return session === void 0 || "skipBehaviors" in body && skipBehaviors === void 0 ? { error: "the get-usage body must be JSON naming a non-empty session id, and skipBehaviors only as a boolean or absent" } : { session, run: async () => await deps.getUsage(session, skipBehaviors) };
4311
+ }
4312
+ },
4313
+ {
4314
+ name: "get-context-usage",
4315
+ path: "get-context-usage",
4316
+ read: (body) => {
4317
+ const session = bodyString(body, "session");
4318
+ const detail = "detail" in body && isRcContextUsageDetail(body.detail) ? body.detail : void 0;
4319
+ return session === void 0 || "detail" in body && detail === void 0 ? { error: `the get-context-usage body must be JSON naming a non-empty session id, and a detail level the SDK's own type permits (${RC_CONTEXT_USAGE_DETAILS.join(", ")}) or none` } : { session, run: async () => await deps.getContextUsage(session, detail) };
4320
+ }
4321
+ },
4322
+ {
4323
+ name: "read-file",
4324
+ path: "read-file",
4325
+ read: (body) => {
4326
+ const session = bodyString(body, "session");
4327
+ const path32 = bodyString(body, "path");
4328
+ const maxBytes = "maxBytes" in body ? bodyPositiveInteger(body, "maxBytes") : void 0;
4329
+ const encoding = "encoding" in body && isRcReadFileEncoding(body.encoding) ? body.encoding : void 0;
4330
+ const refused2 = session === void 0 || path32 === void 0 || "maxBytes" in body && maxBytes === void 0 || "encoding" in body && encoding === void 0;
4331
+ return refused2 ? { error: `the read-file body must be JSON naming a non-empty session id and path, maxBytes only as a positive whole number or absent, and an encoding the SDK's own type permits (${RC_READ_FILE_ENCODINGS.join(", ")}) or none` } : { session, run: async () => await deps.readFile(session, path32, { ...maxBytes === void 0 ? {} : { maxBytes }, ...encoding === void 0 ? {} : { encoding } }) };
4332
+ }
4333
+ },
4334
+ {
4335
+ name: "file-suggestions",
4336
+ path: "file-suggestions",
4337
+ read: (body) => {
4338
+ const session = bodyString(body, "session");
4339
+ const query = bodyStringAllowingEmpty(body, "query");
4340
+ return session === void 0 || query === void 0 ? { error: "the file-suggestions body must be JSON naming a non-empty session id and a query string, which may be empty" } : { session, run: async () => await deps.fileSuggestions(session, query) };
4341
+ }
4342
+ },
4343
+ {
4344
+ name: "keep-alive",
4345
+ path: "keep-alive",
4346
+ read: (body) => {
4347
+ const session = bodyString(body, "session");
4348
+ return session === void 0 ? { error: "the keep-alive body must be JSON naming a non-empty session id" } : { session, run: async () => await deps.keepAlive(session) };
4349
+ }
4350
+ },
4351
+ {
4352
+ name: "mcp-status",
4353
+ path: "mcp-status",
4354
+ read: (body) => {
4355
+ const session = bodyString(body, "session");
4356
+ return session === void 0 ? { error: "the mcp-status body must be JSON naming a non-empty session id" } : { session, run: async () => await deps.mcpStatus(session) };
4357
+ }
4358
+ },
4359
+ {
4360
+ name: "mcp-reconnect",
4361
+ path: "mcp-reconnect",
4362
+ read: (body) => {
4363
+ const session = bodyString(body, "session");
4364
+ const serverName = bodyString(body, "serverName");
4365
+ return session === void 0 || serverName === void 0 ? { error: "the mcp-reconnect body must be JSON naming a non-empty session id and server name" } : { session, run: async () => await deps.mcpReconnect(session, serverName) };
4366
+ }
4367
+ },
4368
+ {
4369
+ name: "mcp-authenticate",
4370
+ path: "mcp-authenticate",
4371
+ read: (body) => {
4372
+ const session = bodyString(body, "session");
4373
+ const serverName = bodyString(body, "serverName");
4374
+ const redirectUri = bodyString(body, "redirectUri");
4375
+ return session === void 0 || serverName === void 0 || redirectUri === void 0 ? { error: "the mcp-authenticate body must be JSON naming a non-empty session id, server name, and redirect URI" } : { session, run: async () => await deps.mcpAuthenticate(session, serverName, redirectUri) };
4376
+ }
4377
+ },
4378
+ {
4379
+ name: "mcp-oauth-callback-url",
4380
+ path: "mcp-oauth-callback-url",
4381
+ read: (body) => {
4382
+ const session = bodyString(body, "session");
4383
+ const serverName = bodyString(body, "serverName");
4384
+ const callbackUrl = bodyString(body, "callbackUrl");
4385
+ 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) };
4386
+ }
4387
+ }
4388
+ ];
4145
4389
  return (request4, response) => {
4146
4390
  const presented = request4.headers.authorization;
4147
4391
  const bearerPrefix = "bearer ".length;
@@ -4226,73 +4470,33 @@ function createRcControlHandler(deps) {
4226
4470
  answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4227
4471
  return;
4228
4472
  }
4229
- if (url.pathname === interruptPath) {
4230
- if (request4.method !== "POST") {
4231
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the interrupt operation is a POST" });
4232
- return;
4233
- }
4234
- let parsed;
4235
- try {
4236
- parsed = JSON.parse(await readBody(request4));
4237
- } catch {
4238
- answerJson(response, HTTP_STATUS.badRequest, { error: "the interrupt body is not readable JSON within the control body cap" });
4239
- return;
4240
- }
4241
- if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || typeof parsed.session !== "string" || parsed.session === "") {
4242
- answerJson(response, HTTP_STATUS.badRequest, { error: "the interrupt body must be JSON naming a non-empty session id" });
4243
- return;
4244
- }
4245
- const result = await deps.interrupt(parsed.session);
4246
- if (result.ok) {
4247
- answerJson(response, HTTP_STATUS.ok, { session: parsed.session, sequenceNums: result.sequenceNums });
4248
- return;
4473
+ for (const route of controlWrites) {
4474
+ if (url.pathname !== `${CONTROL_PATH_PREFIX}/${route.path}`) {
4475
+ continue;
4249
4476
  }
4250
- answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4251
- return;
4252
- }
4253
- if (url.pathname === setModelPath) {
4254
4477
  if (request4.method !== "POST") {
4255
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the set-model operation is a POST" });
4478
+ answerJson(response, HTTP_STATUS.methodNotAllowed, { error: `the ${route.name} operation is a POST` });
4256
4479
  return;
4257
4480
  }
4258
4481
  let parsed;
4259
4482
  try {
4260
4483
  parsed = JSON.parse(await readBody(request4));
4261
4484
  } catch {
4262
- answerJson(response, HTTP_STATUS.badRequest, { error: "the set-model body is not readable JSON within the control body cap" });
4485
+ answerJson(response, HTTP_STATUS.badRequest, { error: `the ${route.name} body is not readable JSON within the control body cap` });
4263
4486
  return;
4264
4487
  }
4265
- if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("model" in parsed) || typeof parsed.session !== "string" || typeof parsed.model !== "string" || parsed.session === "" || parsed.model === "") {
4266
- answerJson(response, HTTP_STATUS.badRequest, { error: "the set-model body must be JSON naming a non-empty session id and model id" });
4488
+ if (!isJsonObject(parsed)) {
4489
+ answerJson(response, HTTP_STATUS.badRequest, { error: `the ${route.name} body must be a JSON object` });
4267
4490
  return;
4268
4491
  }
4269
- const result = await deps.setModel(parsed.session, parsed.model);
4270
- if (result.ok) {
4271
- answerJson(response, HTTP_STATUS.ok, { session: parsed.session, model: parsed.model, sequenceNums: result.sequenceNums });
4492
+ const read = route.read(parsed);
4493
+ if ("error" in read) {
4494
+ answerJson(response, HTTP_STATUS.badRequest, { error: read.error });
4272
4495
  return;
4273
4496
  }
4274
- answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
4275
- return;
4276
- }
4277
- if (url.pathname === setPermissionModePath) {
4278
- if (request4.method !== "POST") {
4279
- answerJson(response, HTTP_STATUS.methodNotAllowed, { error: "the set-permission-mode operation is a POST" });
4280
- return;
4281
- }
4282
- let parsed;
4283
- try {
4284
- parsed = JSON.parse(await readBody(request4));
4285
- } catch {
4286
- answerJson(response, HTTP_STATUS.badRequest, { error: "the set-permission-mode body is not readable JSON within the control body cap" });
4287
- return;
4288
- }
4289
- if (typeof parsed !== "object" || parsed === null || !("session" in parsed) || !("mode" in parsed) || typeof parsed.session !== "string" || parsed.session === "" || !isRcPermissionMode(parsed.mode)) {
4290
- 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})` });
4291
- return;
4292
- }
4293
- const result = await deps.setPermissionMode(parsed.session, parsed.mode);
4497
+ const result = await read.run();
4294
4498
  if (result.ok) {
4295
- answerJson(response, HTTP_STATUS.ok, { session: parsed.session, mode: parsed.mode, sequenceNums: result.sequenceNums });
4499
+ answerJson(response, HTTP_STATUS.ok, { session: read.session, ...result.requestId === void 0 ? {} : { request: result.requestId }, sequenceNums: result.sequenceNums });
4296
4500
  return;
4297
4501
  }
4298
4502
  answerJson(response, HTTP_STATUS.badGateway, { error: result.message });
@@ -4410,6 +4614,19 @@ function sequenceNumsOfBody(body) {
4410
4614
  }
4411
4615
  return sequenceNums;
4412
4616
  }
4617
+ function requestIdOfBody(body) {
4618
+ let parsed;
4619
+ try {
4620
+ parsed = JSON.parse(body);
4621
+ } catch {
4622
+ return void 0;
4623
+ }
4624
+ if (typeof parsed !== "object" || parsed === null || !("request" in parsed)) {
4625
+ return void 0;
4626
+ }
4627
+ const value = parsed.request;
4628
+ return typeof value === "string" && value !== "" ? value : void 0;
4629
+ }
4413
4630
  function frontDoorRcControl(transport, token) {
4414
4631
  const headers = { authorization: `Bearer ${token}` };
4415
4632
  const listAnswerOf = async (path32, what) => {
@@ -4498,7 +4715,8 @@ function frontDoorRcControl(transport, token) {
4498
4715
  if (sequenceNums === void 0) {
4499
4716
  return { ok: false, message: `the door accepted the event but its answer named no sequence numbers: ${answer.body}` };
4500
4717
  }
4501
- return { ok: true, sequenceNums };
4718
+ const requestId = requestIdOfBody(answer.body);
4719
+ return requestId === void 0 ? { ok: true, sequenceNums } : { ok: true, sequenceNums, requestId };
4502
4720
  }
4503
4721
  return { ok: false, message: describeFailure(answer.status, controlErrorOf(answer.body) ?? answer.body) };
4504
4722
  };
@@ -4515,7 +4733,21 @@ function frontDoorRcControl(transport, token) {
4515
4733
  ),
4516
4734
  interruptSession: async (sessionId) => await writeOf(`${CONTROL_PATH_PREFIX}/interrupt`, JSON.stringify({ session: sessionId }), (status, message) => `interrupting ${sessionId} failed (HTTP ${String(status)}): ${message}`),
4517
4735
  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}`),
4518
- 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}`)
4736
+ 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}`),
4737
+ endSession: async (sessionId, reason) => await writeOf(`${CONTROL_PATH_PREFIX}/end-session`, JSON.stringify({ session: sessionId, ...reason === void 0 ? {} : { reason } }), (status, message) => `ending ${sessionId} failed (HTTP ${String(status)}): ${message}`),
4738
+ getUsage: async (sessionId, skipBehaviors) => await writeOf(`${CONTROL_PATH_PREFIX}/get-usage`, JSON.stringify({ session: sessionId, ...skipBehaviors === void 0 ? {} : { skipBehaviors } }), (status, message) => `requesting the usage of ${sessionId} failed (HTTP ${String(status)}): ${message}`),
4739
+ getContextUsage: async (sessionId, detail) => await writeOf(`${CONTROL_PATH_PREFIX}/get-context-usage`, JSON.stringify({ session: sessionId, ...detail === void 0 ? {} : { detail } }), (status, message) => `requesting the context usage of ${sessionId} failed (HTTP ${String(status)}): ${message}`),
4740
+ readFile: async (sessionId, path32, options) => await writeOf(
4741
+ `${CONTROL_PATH_PREFIX}/read-file`,
4742
+ JSON.stringify({ session: sessionId, path: path32, ...options?.maxBytes === void 0 ? {} : { maxBytes: options.maxBytes }, ...options?.encoding === void 0 ? {} : { encoding: options.encoding } }),
4743
+ (status, message) => `reading ${path32} from ${sessionId} failed (HTTP ${String(status)}): ${message}`
4744
+ ),
4745
+ fileSuggestions: async (sessionId, query) => await writeOf(`${CONTROL_PATH_PREFIX}/file-suggestions`, JSON.stringify({ session: sessionId, query }), (status, message) => `requesting file suggestions from ${sessionId} failed (HTTP ${String(status)}): ${message}`),
4746
+ keepAlive: async (sessionId) => await writeOf(`${CONTROL_PATH_PREFIX}/keep-alive`, JSON.stringify({ session: sessionId }), (status, message) => `keeping ${sessionId} alive failed (HTTP ${String(status)}): ${message}`),
4747
+ 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}`),
4748
+ 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}`),
4749
+ 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}`),
4750
+ 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}`)
4519
4751
  };
4520
4752
  }
4521
4753
 
@@ -5137,6 +5369,48 @@ var RcSetPermissionModeInputSchema = import_zod4.z.strictObject({
5137
5369
  session: import_zod4.z.string().min(1),
5138
5370
  mode: RcPermissionModeSchema
5139
5371
  });
5372
+ var RcEndSessionInputSchema = import_zod4.z.strictObject({
5373
+ session: import_zod4.z.string().min(1),
5374
+ reason: import_zod4.z.string().min(1).optional()
5375
+ });
5376
+ var RcGetUsageInputSchema = import_zod4.z.strictObject({
5377
+ session: import_zod4.z.string().min(1),
5378
+ skipBehaviors: import_zod4.z.boolean().optional()
5379
+ });
5380
+ var RcGetContextUsageInputSchema = import_zod4.z.strictObject({
5381
+ session: import_zod4.z.string().min(1),
5382
+ detail: import_zod4.z.enum(RC_CONTEXT_USAGE_DETAILS).optional()
5383
+ });
5384
+ var RcReadFileInputSchema = import_zod4.z.strictObject({
5385
+ session: import_zod4.z.string().min(1),
5386
+ path: import_zod4.z.string().min(1),
5387
+ maxBytes: import_zod4.z.number().int().positive().optional(),
5388
+ encoding: import_zod4.z.enum(RC_READ_FILE_ENCODINGS).optional()
5389
+ });
5390
+ var RcFileSuggestionsInputSchema = import_zod4.z.strictObject({
5391
+ session: import_zod4.z.string().min(1),
5392
+ query: import_zod4.z.string()
5393
+ });
5394
+ var RcKeepAliveInputSchema = import_zod4.z.strictObject({
5395
+ session: import_zod4.z.string().min(1)
5396
+ });
5397
+ var RcMcpStatusInputSchema = import_zod4.z.strictObject({
5398
+ session: import_zod4.z.string().min(1)
5399
+ });
5400
+ var RcMcpReconnectInputSchema = import_zod4.z.strictObject({
5401
+ session: import_zod4.z.string().min(1),
5402
+ serverName: import_zod4.z.string().min(1)
5403
+ });
5404
+ var RcMcpAuthenticateInputSchema = import_zod4.z.strictObject({
5405
+ session: import_zod4.z.string().min(1),
5406
+ serverName: import_zod4.z.string().min(1),
5407
+ redirectUri: import_zod4.z.string().min(1)
5408
+ });
5409
+ var RcMcpOAuthCallbackUrlInputSchema = import_zod4.z.strictObject({
5410
+ session: import_zod4.z.string().min(1),
5411
+ serverName: import_zod4.z.string().min(1),
5412
+ callbackUrl: import_zod4.z.string().min(1)
5413
+ });
5140
5414
  var RcListOutputSchema = import_zod4.z.strictObject({ sessions: import_zod4.z.readonly(import_zod4.z.array(RcSessionSummarySchema)) });
5141
5415
  var RcStatusOutputSchema = import_zod4.z.strictObject({ statuses: import_zod4.z.readonly(import_zod4.z.array(RcSessionStatusSchema)) });
5142
5416
  var RcPendingOutputSchema = import_zod4.z.strictObject({ pending: import_zod4.z.readonly(import_zod4.z.array(RcPendingRequestSummarySchema)) });
@@ -5144,6 +5418,11 @@ var RcWriteOutputSchema = import_zod4.z.strictObject({
5144
5418
  session: import_zod4.z.string(),
5145
5419
  sequenceNums: import_zod4.z.readonly(import_zod4.z.array(import_zod4.z.number()))
5146
5420
  });
5421
+ var RcControlWriteOutputSchema = import_zod4.z.strictObject({
5422
+ session: import_zod4.z.string(),
5423
+ request: import_zod4.z.string(),
5424
+ sequenceNums: import_zod4.z.readonly(import_zod4.z.array(import_zod4.z.number()))
5425
+ });
5147
5426
  var RcAnswerOutputSchema = import_zod4.z.strictObject({
5148
5427
  session: import_zod4.z.string(),
5149
5428
  request: import_zod4.z.string(),
@@ -5172,6 +5451,15 @@ function createRcApiRouter(deps) {
5172
5451
  }
5173
5452
  return result.sequenceNums;
5174
5453
  };
5454
+ const deliveredControl = (sessionId, result) => {
5455
+ if (!result.ok) {
5456
+ throw new import_client.ORPCError("BAD_GATEWAY", { message: result.message });
5457
+ }
5458
+ if (result.requestId === void 0) {
5459
+ throw new import_client.ORPCError("INTERNAL_SERVER_ERROR", { message: "the control request was delivered but the door cannot name the request id it minted, so the worker's answer cannot be matched" });
5460
+ }
5461
+ return { request: result.requestId, sequenceNums: result.sequenceNums };
5462
+ };
5175
5463
  return {
5176
5464
  rc: {
5177
5465
  list: authed.output(RcListOutputSchema).handler(() => ({ sessions: deps.list() })),
@@ -5194,9 +5482,19 @@ function createRcApiRouter(deps) {
5194
5482
  const decision = { approve: input.approve, message: input.approve || input.text === void 0 ? void 0 : input.text };
5195
5483
  return { session: input.session, request: input.request, sequenceNums: delivered(input.session, await deps.answer(input.session, input.request, decision)) };
5196
5484
  }),
5197
- interrupt: authed.input(RcInterruptInputSchema).output(RcWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, sequenceNums: delivered(input.session, await deps.interrupt(input.session)) })),
5198
- setModel: authed.input(RcSetModelInputSchema).output(RcWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, sequenceNums: delivered(input.session, await deps.setModel(input.session, input.model)) })),
5199
- setPermissionMode: authed.input(RcSetPermissionModeInputSchema).output(RcWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, sequenceNums: delivered(input.session, await deps.setPermissionMode(input.session, input.mode)) })),
5485
+ interrupt: authed.input(RcInterruptInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.interrupt(input.session)) })),
5486
+ setModel: authed.input(RcSetModelInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.setModel(input.session, input.model)) })),
5487
+ setPermissionMode: authed.input(RcSetPermissionModeInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.setPermissionMode(input.session, input.mode)) })),
5488
+ endSession: authed.input(RcEndSessionInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.endSession(input.session, input.reason)) })),
5489
+ getUsage: authed.input(RcGetUsageInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.getUsage(input.session, input.skipBehaviors)) })),
5490
+ getContextUsage: authed.input(RcGetContextUsageInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.getContextUsage(input.session, input.detail)) })),
5491
+ readFile: authed.input(RcReadFileInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.readFile(input.session, input.path, { ...input.maxBytes === void 0 ? {} : { maxBytes: input.maxBytes }, ...input.encoding === void 0 ? {} : { encoding: input.encoding } })) })),
5492
+ fileSuggestions: authed.input(RcFileSuggestionsInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.fileSuggestions(input.session, input.query)) })),
5493
+ keepAlive: authed.input(RcKeepAliveInputSchema).output(RcWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, sequenceNums: delivered(input.session, await deps.keepAlive(input.session)) })),
5494
+ mcpStatus: authed.input(RcMcpStatusInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.mcpStatus(input.session)) })),
5495
+ mcpReconnect: authed.input(RcMcpReconnectInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.mcpReconnect(input.session, input.serverName)) })),
5496
+ mcpAuthenticate: authed.input(RcMcpAuthenticateInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.mcpAuthenticate(input.session, input.serverName, input.redirectUri)) })),
5497
+ mcpOAuthCallbackUrl: authed.input(RcMcpOAuthCallbackUrlInputSchema).output(RcControlWriteOutputSchema).handler(async ({ input }) => ({ session: input.session, ...deliveredControl(input.session, await deps.mcpOAuthCallbackUrl(input.session, input.serverName, input.callbackUrl)) })),
5200
5498
  subscribe: authed.input(RcSessionQuerySchema).output((0, import_server2.eventIterator)(RcStreamEventSchema)).handler(async function* ({ input, signal }) {
5201
5499
  const queue = [];
5202
5500
  let wake;
@@ -11466,7 +11764,7 @@ var import_node_path30 = __toESM(require("node:path"), 1);
11466
11764
  // package.json
11467
11765
  var package_default = {
11468
11766
  name: "agent-shim",
11469
- version: "8.23.0",
11767
+ version: "8.24.0",
11470
11768
  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.",
11471
11769
  license: "MIT",
11472
11770
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -12709,10 +13007,12 @@ function prepareClaudeLaunch(options) {
12709
13007
  ProviderKindMismatchError,
12710
13008
  ProviderNotFoundError,
12711
13009
  ProviderSchema,
13010
+ RC_CONTEXT_USAGE_DETAILS,
12712
13011
  RC_IDLE_EXPIRY_MS,
12713
13012
  RC_ORPC_PATH_PREFIX,
12714
13013
  RC_PENDING_DEADLINE_MS,
12715
13014
  RC_PERMISSION_MODES,
13015
+ RC_READ_FILE_ENCODINGS,
12716
13016
  RC_REQUEST_PARSE_CAP_BYTES,
12717
13017
  RC_SELF_HOST_ENV,
12718
13018
  RC_SELF_HOST_KEEPALIVE_MS,
@@ -12743,11 +13043,23 @@ function prepareClaudeLaunch(options) {
12743
13043
  addPool,
12744
13044
  addProvider,
12745
13045
  answerRcControlRequest,
13046
+ authenticateRcSessionMcpServer,
12746
13047
  buildEntryFacts,
12747
13048
  buildLayoutPaths,
13049
+ buildRcControlRequestPayload,
12748
13050
  buildRcControlResponsePayload,
13051
+ buildRcEndSessionPayload,
12749
13052
  buildRcEventWriteBody,
13053
+ buildRcFileSuggestionsPayload,
13054
+ buildRcGetContextUsagePayload,
13055
+ buildRcGetUsagePayload,
12750
13056
  buildRcInterruptPayload,
13057
+ buildRcKeepAlivePayload,
13058
+ buildRcMcpAuthenticatePayload,
13059
+ buildRcMcpOAuthCallbackUrlPayload,
13060
+ buildRcMcpReconnectPayload,
13061
+ buildRcMcpStatusPayload,
13062
+ buildRcReadFilePayload,
12751
13063
  buildRcSetModelPayload,
12752
13064
  buildRcSetPermissionModePayload,
12753
13065
  buildRcUserMessagePayload,
@@ -12780,6 +13092,7 @@ function prepareClaudeLaunch(options) {
12780
13092
  doorApiAuth,
12781
13093
  doorApiNodeHandlerOf,
12782
13094
  effectiveWindow,
13095
+ endRcSession,
12783
13096
  ensureCa,
12784
13097
  ensureFrontDoor,
12785
13098
  ensureHeadroom,
@@ -12796,6 +13109,9 @@ function prepareClaudeLaunch(options) {
12796
13109
  frontDoorRcApiClient,
12797
13110
  frontDoorRcControl,
12798
13111
  generateCa,
13112
+ getRcSessionContextUsage,
13113
+ getRcSessionMcpStatus,
13114
+ getRcSessionUsage,
12799
13115
  headroomSocketTarget,
12800
13116
  identityExists,
12801
13117
  injectRcUserMessage,
@@ -12803,7 +13119,9 @@ function prepareClaudeLaunch(options) {
12803
13119
  isIdentityDirectoryName,
12804
13120
  isInterceptedHost,
12805
13121
  isPrivateAddress,
13122
+ isRcContextUsageDetail,
12806
13123
  isRcPermissionMode,
13124
+ isRcReadFileEncoding,
12807
13125
  lateRcEventDial,
12808
13126
  lateRcStreamDial,
12809
13127
  listDirectoryRules,
@@ -12837,6 +13155,7 @@ function prepareClaudeLaunch(options) {
12837
13155
  readProfile,
12838
13156
  readProvider,
12839
13157
  readRcSelfHostRecord,
13158
+ readRcSessionFile,
12840
13159
  readUsageSnapshot,
12841
13160
  realConnectCertStore,
12842
13161
  realConnectEffects,
@@ -12844,6 +13163,7 @@ function prepareClaudeLaunch(options) {
12844
13163
  realRcEventDial,
12845
13164
  realRcStreamDial,
12846
13165
  realRcWebFetch,
13166
+ reconnectRcSessionMcpServer,
12847
13167
  recoverFarm,
12848
13168
  recoveryDiagnostics,
12849
13169
  removeDirectoryRule,
@@ -12863,6 +13183,7 @@ function prepareClaudeLaunch(options) {
12863
13183
  runFrontDoorSupervisor,
12864
13184
  runLauncher,
12865
13185
  runSupervisor,
13186
+ sendRcKeepAlive,
12866
13187
  servedByPipeline,
12867
13188
  setAllowAmbientCredential,
12868
13189
  setDefaultConfigProfile,
@@ -12878,6 +13199,8 @@ function prepareClaudeLaunch(options) {
12878
13199
  snapshotPath,
12879
13200
  spawnClaude,
12880
13201
  startConnectServer,
13202
+ submitRcSessionMcpOAuthCallbackUrl,
13203
+ suggestRcSessionFiles,
12881
13204
  topLevelNames,
12882
13205
  updateDirectoryRule,
12883
13206
  updateProvider,