1import * as Context from "effect/Context";
2import * as Effect from "effect/Effect";
3import * as ErrorReporter from "effect/ErrorReporter";
4import * as Layer from "effect/Layer";
5import * as Schema from "effect/Schema";
6import * as Scope from "effect/Scope";
7import * as Stream from "effect/Stream";
8import * as Stdio from "effect/Stdio";
9import * as RpcClient from "effect/rpc/RpcClient";
10import * as RpcMessage from "effect/rpc/RpcMessage";
11import * as RpcServer from "effect/rpc/RpcServer";
12
13import * as AcpSchema from "./schema.ts";
14import { AGENT_METHODS, CLIENT_METHODS } from "./_generated/meta.gen.ts";
15import * as AcpError from "./errors.ts";
16import * as AcpProtocol from "./protocol.ts";
17import * as AcpRpcs from "./rpc.ts";
18import {
19 callRpc,
20 decodeExtNotificationRegistration,
21 decodeExtRequestRegistration,
22 isolateNotificationHandler,
23 runHandler,
24} from "./_internal/shared.ts";
25
26export interface AcpAgentOptions {
27 readonly logIncoming?: boolean;
28 readonly logOutgoing?: boolean;
29 readonly logger?: (event: AcpProtocol.AcpProtocolLogEvent) => Effect.Effect<void, never>;
30}
31
32export type AcpRequestHandler<Request, Response> = AcpProtocol.AcpRequestHandler<Request, Response>;
33
34export class AcpAgent extends Context.Service<
35 AcpAgent,
36 {
37 readonly raw: {
38 /**
39 * Stream of inbound ACP notifications observed on the connection. Unread
40 * ones are kept best-effort: the newest 32 whose JSON lines fit in 16Mi
41 * characters, always including the latest. Ends when the connection does.
42 */
43 readonly notifications: Stream.Stream<AcpProtocol.AcpIncomingNotification>;
44 readonly request: (
45 method: string,
46 payload: unknown,
47 ) => Effect.Effect<unknown, AcpError.AcpError>;
48 readonly notify: (method: string, payload: unknown) => Effect.Effect<void, AcpError.AcpError>;
49 };
50 readonly client: {
51 readonly requestPermission: (
52 payload: AcpSchema.RequestPermissionRequest,
53 ) => Effect.Effect<AcpSchema.RequestPermissionResponse, AcpError.AcpError>;
54 readonly elicit: (
55 payload: AcpSchema.CreateElicitationRequest,
56 ) => Effect.Effect<AcpSchema.CreateElicitationResponse, AcpError.AcpError>;
57 readonly sessionUpdate: (
58 payload: AcpSchema.SessionNotification,
59 ) => Effect.Effect<void, AcpError.AcpError>;
60 readonly elicitationComplete: (
61 payload: AcpSchema.CompleteElicitationNotification,
62 ) => Effect.Effect<void, AcpError.AcpError>;
63 readonly connectMcp: (
64 payload: AcpSchema.ConnectMcpRequest,
65 ) => Effect.Effect<AcpSchema.ConnectMcpResponse, AcpError.AcpError>;
66 readonly messageMcp: (
67 payload: AcpSchema.MessageMcpRequest,
68 ) => Effect.Effect<AcpSchema.MessageMcpResponse, AcpError.AcpError>;
69 readonly disconnectMcp: (
70 payload: AcpSchema.DisconnectMcpRequest,
71 ) => Effect.Effect<AcpSchema.DisconnectMcpResponse, AcpError.AcpError>;
72 readonly notifyMcp: (
73 payload: AcpSchema.MessageMcpNotification,
74 ) => Effect.Effect<void, AcpError.AcpError>;
75 readonly extRequest: (
76 method: string,
77 payload: unknown,
78 ) => Effect.Effect<unknown, AcpError.AcpError>;
79 readonly extNotification: (
80 method: string,
81 payload: unknown,
82 ) => Effect.Effect<void, AcpError.AcpError>;
83 };
84 readonly handleInitialize: (
85 handler: AcpRequestHandler<AcpSchema.InitializeRequest, AcpSchema.InitializeResponse>,
86 ) => Effect.Effect<void>;
87 readonly handleAuthenticate: (
88 handler: AcpRequestHandler<AcpSchema.AuthenticateRequest, AcpSchema.AuthenticateResponse>,
89 ) => Effect.Effect<void>;
90 readonly handleLogout: (
91 handler: AcpRequestHandler<AcpSchema.LogoutRequest, AcpSchema.LogoutResponse>,
92 ) => Effect.Effect<void>;
93 readonly handleCreateSession: (
94 handler: AcpRequestHandler<AcpSchema.NewSessionRequest, AcpSchema.NewSessionResponse>,
95 ) => Effect.Effect<void>;
96 readonly handleLoadSession: (
97 handler: AcpRequestHandler<AcpSchema.LoadSessionRequest, AcpSchema.LoadSessionResponse>,
98 ) => Effect.Effect<void>;
99 readonly handleListSessions: (
100 handler: AcpRequestHandler<AcpSchema.ListSessionsRequest, AcpSchema.ListSessionsResponse>,
101 ) => Effect.Effect<void>;
102 readonly handleForkSession: (
103 handler: AcpRequestHandler<AcpSchema.ForkSessionRequest, AcpSchema.ForkSessionResponse>,
104 ) => Effect.Effect<void>;
105 readonly handleResumeSession: (
106 handler: AcpRequestHandler<AcpSchema.ResumeSessionRequest, AcpSchema.ResumeSessionResponse>,
107 ) => Effect.Effect<void>;
108 readonly handleCloseSession: (
109 handler: AcpRequestHandler<AcpSchema.CloseSessionRequest, AcpSchema.CloseSessionResponse>,
110 ) => Effect.Effect<void>;
111 readonly handleDeleteSession: (
112 handler: AcpRequestHandler<AcpSchema.DeleteSessionRequest, AcpSchema.DeleteSessionResponse>,
113 ) => Effect.Effect<void>;
114 readonly handleListProviders: (
115 handler: AcpRequestHandler<AcpSchema.ListProvidersRequest, AcpSchema.ListProvidersResponse>,
116 ) => Effect.Effect<void>;
117 readonly handleSetProvider: (
118 handler: AcpRequestHandler<AcpSchema.SetProviderRequest, AcpSchema.SetProviderResponse>,
119 ) => Effect.Effect<void>;
120 readonly handleDisableProvider: (
121 handler: AcpRequestHandler<
122 AcpSchema.DisableProviderRequest,
123 AcpSchema.DisableProviderResponse
124 >,
125 ) => Effect.Effect<void>;
126 readonly handleSetSessionConfigOption: (
127 handler: AcpRequestHandler<
128 AcpSchema.SetSessionConfigOptionRequest,
129 AcpSchema.SetSessionConfigOptionResponse
130 >,
131 ) => Effect.Effect<void>;
132 readonly handlePrompt: (
133 handler: AcpRequestHandler<AcpSchema.PromptRequest, AcpSchema.PromptResponse>,
134 ) => Effect.Effect<void>;
135 readonly handleCancel: (
136 handler: (
137 notification: AcpSchema.CancelNotification,
138 ) => Effect.Effect<void, AcpError.AcpError>,
139 ) => Effect.Effect<void>;
140 readonly handleUnknownExtRequest: (
141 handler: (
142 method: string,
143 params: unknown,
144 context: AcpProtocol.AcpRequestContext,
145 ) => Effect.Effect<unknown, AcpError.AcpError>,
146 ) => Effect.Effect<void>;
147 readonly handleUnknownExtNotification: (
148 handler: (method: string, params: unknown) => Effect.Effect<void, AcpError.AcpError>,
149 ) => Effect.Effect<void>;
150 readonly handleExtRequest: <A, I>(
151 method: string,
152 payload: Schema.Codec<A, I>,
153 handler: AcpRequestHandler<A, unknown>,
154 ) => Effect.Effect<void>;
155 readonly handleExtNotification: <A, I>(
156 method: string,
157 payload: Schema.Codec<A, I>,
158 handler: (payload: A) => Effect.Effect<void, AcpError.AcpError>,
159 ) => Effect.Effect<void>;
160 }
161>()("effect-acp/agent/AcpAgent") {}
162
163interface AcpCoreAgentRequestHandlers {
164 initialize?: AcpRequestHandler<AcpSchema.InitializeRequest, AcpSchema.InitializeResponse>;
165 authenticate?: AcpRequestHandler<AcpSchema.AuthenticateRequest, AcpSchema.AuthenticateResponse>;
166 logout?: AcpRequestHandler<AcpSchema.LogoutRequest, AcpSchema.LogoutResponse>;
167 createSession?: AcpRequestHandler<AcpSchema.NewSessionRequest, AcpSchema.NewSessionResponse>;
168 loadSession?: AcpRequestHandler<AcpSchema.LoadSessionRequest, AcpSchema.LoadSessionResponse>;
169 listSessions?: AcpRequestHandler<AcpSchema.ListSessionsRequest, AcpSchema.ListSessionsResponse>;
170 forkSession?: AcpRequestHandler<AcpSchema.ForkSessionRequest, AcpSchema.ForkSessionResponse>;
171 resumeSession?: AcpRequestHandler<
172 AcpSchema.ResumeSessionRequest,
173 AcpSchema.ResumeSessionResponse
174 >;
175 closeSession?: AcpRequestHandler<AcpSchema.CloseSessionRequest, AcpSchema.CloseSessionResponse>;
176 deleteSession?: AcpRequestHandler<
177 AcpSchema.DeleteSessionRequest,
178 AcpSchema.DeleteSessionResponse
179 >;
180 listProviders?: AcpRequestHandler<
181 AcpSchema.ListProvidersRequest,
182 AcpSchema.ListProvidersResponse
183 >;
184 setProvider?: AcpRequestHandler<AcpSchema.SetProviderRequest, AcpSchema.SetProviderResponse>;
185 disableProvider?: AcpRequestHandler<
186 AcpSchema.DisableProviderRequest,
187 AcpSchema.DisableProviderResponse
188 >;
189 setSessionConfigOption?: AcpRequestHandler<
190 AcpSchema.SetSessionConfigOptionRequest,
191 AcpSchema.SetSessionConfigOptionResponse
192 >;
193 prompt?: AcpRequestHandler<AcpSchema.PromptRequest, AcpSchema.PromptResponse>;
194}
195
196const decodeCancelNotification = Schema.decodeUnknownEffect(AcpSchema.CancelNotification);
197
198/** @public */
199export const make = Effect.fn("effect-acp/AcpAgent.make")(function* (
200 stdio: Stdio.Stdio,
201 options: AcpAgentOptions = {},
202): Effect.fn.Return<AcpAgent["Service"], never, Scope.Scope> {
203 const coreHandlers: AcpCoreAgentRequestHandlers = {};
204 const cancelHandlers: Array<
205 (notification: AcpSchema.CancelNotification) => Effect.Effect<void, AcpError.AcpError>
206 > = [];
207 const extRequestHandlers = new Map<string, AcpRequestHandler<unknown, unknown>>();
208 const extNotificationHandlers = new Map<
209 string,
210 (params: unknown) => Effect.Effect<void, AcpError.AcpError>
211 >();
212 let unknownExtRequestHandler:
213 | ((
214 method: string,
215 params: unknown,
216 context: AcpProtocol.AcpRequestContext,
217 ) => Effect.Effect<unknown, AcpError.AcpError>)
218 | undefined;
219 let unknownExtNotificationHandler:
220 | ((method: string, params: unknown) => Effect.Effect<void, AcpError.AcpError>)
221 | undefined;
222
223 const transport = yield* AcpProtocol.makeAcpPatchedProtocol({
224 stdio,
225 serverRequestMethods: new Set(AcpRpcs.AgentRpcs.requests.keys()),
226 ...(options.logIncoming !== undefined ? { logIncoming: options.logIncoming } : {}),
227 ...(options.logOutgoing !== undefined ? { logOutgoing: options.logOutgoing } : {}),
228 ...(options.logger ? { logger: options.logger } : {}),
229 onNotification: (notification) => {
230 if (
231 notification._tag === "ExtNotification" &&
232 notification.method === AGENT_METHODS.session_cancel
233 ) {
234 return decodeCancelNotification(notification.params).pipe(
235 Effect.mapError((error) =>
236 AcpError.AcpProtocolParseError.fromSchemaError(
237 "decode-notification-payload",
238 AGENT_METHODS.session_cancel,
239 error,
240 ),
241 ),
242 Effect.flatMap((decoded) =>
243 Effect.forEach(
244 cancelHandlers,
245 (handler) => isolateNotificationHandler(handler(decoded)),
246 { discard: true },
247 ),
248 ),
249 );
250 }
251
252 if (notification._tag !== "ExtNotification") {
253 return Effect.void;
254 }
255
256 const handler = extNotificationHandlers.get(notification.method);
257 if (handler) {
258 return handler(notification.params);
259 }
260 return unknownExtNotificationHandler
261 ? unknownExtNotificationHandler(notification.method, notification.params)
262 : Effect.void;
263 },
264 onExtRequest: (method, params, context) => {
265 const handler = extRequestHandlers.get(method);
266 if (handler) {
267 return handler(params, context);
268 }
269 return unknownExtRequestHandler
270 ? unknownExtRequestHandler(method, params, context)
271 : Effect.fail(AcpError.AcpRequestError.methodNotFound(method));
272 },
273 });
274
275 const requestContext = (
276 requestId: RpcMessage.RequestId,
277 method: string,
278 ): AcpProtocol.AcpRequestContext => ({
279 requestId: AcpProtocol.acpRequestIdentity(requestId),
280 method,
281 });
282
283 const layerAgentHandler = AcpRpcs.AgentRpcs.toLayer(
284 AcpRpcs.AgentRpcs.of({
285 [AGENT_METHODS.initialize]: (payload, { requestId }) =>
286 runHandler(
287 coreHandlers.initialize,
288 payload,
289 AGENT_METHODS.initialize,
290 requestContext(requestId, AGENT_METHODS.initialize),
291 ),
292 [AGENT_METHODS.auth_login]: (payload, { requestId }) =>
293 runHandler(
294 coreHandlers.authenticate,
295 payload,
296 AGENT_METHODS.auth_login,
297 requestContext(requestId, AGENT_METHODS.auth_login),
298 ),
299 [AGENT_METHODS.auth_logout]: (payload, { requestId }) =>
300 runHandler(
301 coreHandlers.logout,
302 payload,
303 AGENT_METHODS.auth_logout,
304 requestContext(requestId, AGENT_METHODS.auth_logout),
305 ),
306 [AGENT_METHODS.session_new]: (payload, { requestId }) =>
307 runHandler(
308 coreHandlers.createSession,
309 payload,
310 AGENT_METHODS.session_new,
311 requestContext(requestId, AGENT_METHODS.session_new),
312 ),
313 [AGENT_METHODS.session_list]: (payload, { requestId }) =>
314 runHandler(
315 coreHandlers.listSessions,
316 payload,
317 AGENT_METHODS.session_list,
318 requestContext(requestId, AGENT_METHODS.session_list),
319 ),
320 [AGENT_METHODS.session_fork]: (payload, { requestId }) =>
321 runHandler(
322 coreHandlers.forkSession,
323 payload,
324 AGENT_METHODS.session_fork,
325 requestContext(requestId, AGENT_METHODS.session_fork),
326 ),
327 [AGENT_METHODS.session_resume]: (payload, { requestId }) =>
328 runHandler(
329 payload.replayFrom?.type === "start"
330 ? (coreHandlers.loadSession ?? coreHandlers.resumeSession)
331 : (coreHandlers.resumeSession ?? coreHandlers.loadSession),
332 payload,
333 AGENT_METHODS.session_resume,
334 requestContext(requestId, AGENT_METHODS.session_resume),
335 ),
336 [AGENT_METHODS.session_close]: (payload, { requestId }) =>
337 runHandler(
338 coreHandlers.closeSession,
339 payload,
340 AGENT_METHODS.session_close,
341 requestContext(requestId, AGENT_METHODS.session_close),
342 ),
343 [AGENT_METHODS.session_delete]: (payload, { requestId }) =>
344 runHandler(
345 coreHandlers.deleteSession,
346 payload,
347 AGENT_METHODS.session_delete,
348 requestContext(requestId, AGENT_METHODS.session_delete),
349 ),
350 [AGENT_METHODS.providers_list]: (payload, { requestId }) =>
351 runHandler(
352 coreHandlers.listProviders,
353 payload,
354 AGENT_METHODS.providers_list,
355 requestContext(requestId, AGENT_METHODS.providers_list),
356 ),
357 [AGENT_METHODS.providers_set]: (payload, { requestId }) =>
358 runHandler(
359 coreHandlers.setProvider,
360 payload,
361 AGENT_METHODS.providers_set,
362 requestContext(requestId, AGENT_METHODS.providers_set),
363 ),
364 [AGENT_METHODS.providers_disable]: (payload, { requestId }) =>
365 runHandler(
366 coreHandlers.disableProvider,
367 payload,
368 AGENT_METHODS.providers_disable,
369 requestContext(requestId, AGENT_METHODS.providers_disable),
370 ),
371 [AGENT_METHODS.session_set_config_option]: (payload, { requestId }) =>
372 runHandler(
373 coreHandlers.setSessionConfigOption,
374 payload,
375 AGENT_METHODS.session_set_config_option,
376 requestContext(requestId, AGENT_METHODS.session_set_config_option),
377 ),
378 [AGENT_METHODS.session_prompt]: (payload, { requestId }) =>
379 runHandler(
380 coreHandlers.prompt,
381 payload,
382 AGENT_METHODS.session_prompt,
383 requestContext(requestId, AGENT_METHODS.session_prompt),
384 ),
385 }),
386 );
387
388 yield* RpcServer.make(AcpRpcs.AgentRpcs, { disableFatalDefects: true }).pipe(
389 Effect.provideService(ErrorReporter.CurrentErrorReporters, new Set()),
390 Effect.provideService(RpcServer.Protocol, transport.serverProtocol),
391 Effect.provide(layerAgentHandler),
392 Effect.forkScoped,
393 );
394
395 let nextRpcRequestId = AcpProtocol.RPC_REQUEST_ID_START;
396 const rpc = yield* RpcClient.make(AcpRpcs.ClientRpcs, {
397 generateRequestId: () => RpcMessage.RequestId(nextRpcRequestId++),
398 }).pipe(Effect.provideService(RpcClient.Protocol, transport.clientProtocol));
399
400 return AcpAgent.of({
401 raw: {
402 notifications: transport.incoming,
403 request: transport.request,
404 notify: transport.notify,
405 },
406 client: {
407 requestPermission: (payload) =>
408 callRpc(
409 CLIENT_METHODS.session_request_permission,
410 rpc[CLIENT_METHODS.session_request_permission](payload),
411 ),
412 elicit: (payload) =>
413 callRpc(CLIENT_METHODS.elicitation_create, rpc[CLIENT_METHODS.elicitation_create](payload)),
414 sessionUpdate: (payload) => transport.notify(CLIENT_METHODS.session_update, payload),
415 elicitationComplete: (payload) =>
416 transport.notify(CLIENT_METHODS.elicitation_complete, payload),
417 connectMcp: (payload) =>
418 callRpc(CLIENT_METHODS.mcp_connect, rpc[CLIENT_METHODS.mcp_connect](payload)),
419 messageMcp: (payload) =>
420 callRpc(CLIENT_METHODS.mcp_message, rpc[CLIENT_METHODS.mcp_message](payload)),
421 disconnectMcp: (payload) =>
422 callRpc(CLIENT_METHODS.mcp_disconnect, rpc[CLIENT_METHODS.mcp_disconnect](payload)),
423 notifyMcp: (payload) => transport.notify(CLIENT_METHODS.mcp_message, payload),
424 extRequest: transport.request,
425 extNotification: transport.notify,
426 },
427 handleInitialize: Effect.fn("AcpAgent.handleInitialize")(function (handler) {
428 return Effect.suspend(() => {
429 coreHandlers.initialize = handler;
430 return Effect.void;
431 });
432 }),
433 handleAuthenticate: Effect.fn("AcpAgent.handleAuthenticate")(function (handler) {
434 return Effect.suspend(() => {
435 coreHandlers.authenticate = handler;
436 return Effect.void;
437 });
438 }),
439 handleLogout: Effect.fn("AcpAgent.handleLogout")(function (handler) {
440 return Effect.suspend(() => {
441 coreHandlers.logout = handler;
442 return Effect.void;
443 });
444 }),
445 handleCreateSession: Effect.fn("AcpAgent.handleCreateSession")(function (handler) {
446 return Effect.suspend(() => {
447 coreHandlers.createSession = handler;
448 return Effect.void;
449 });
450 }),
451 handleLoadSession: Effect.fn("AcpAgent.handleLoadSession")(function (handler) {
452 return Effect.suspend(() => {
453 coreHandlers.loadSession = handler;
454 return Effect.void;
455 });
456 }),
457 handleListSessions: Effect.fn("AcpAgent.handleListSessions")(function (handler) {
458 return Effect.suspend(() => {
459 coreHandlers.listSessions = handler;
460 return Effect.void;
461 });
462 }),
463 handleForkSession: Effect.fn("AcpAgent.handleForkSession")(function (handler) {
464 return Effect.suspend(() => {
465 coreHandlers.forkSession = handler;
466 return Effect.void;
467 });
468 }),
469 handleResumeSession: Effect.fn("AcpAgent.handleResumeSession")(function (handler) {
470 return Effect.suspend(() => {
471 coreHandlers.resumeSession = handler;
472 return Effect.void;
473 });
474 }),
475 handleCloseSession: Effect.fn("AcpAgent.handleCloseSession")(function (handler) {
476 return Effect.suspend(() => {
477 coreHandlers.closeSession = handler;
478 return Effect.void;
479 });
480 }),
481 handleDeleteSession: Effect.fn("AcpAgent.handleDeleteSession")(function (handler) {
482 return Effect.suspend(() => {
483 coreHandlers.deleteSession = handler;
484 return Effect.void;
485 });
486 }),
487 handleListProviders: Effect.fn("AcpAgent.handleListProviders")(function (handler) {
488 return Effect.suspend(() => {
489 coreHandlers.listProviders = handler;
490 return Effect.void;
491 });
492 }),
493 handleSetProvider: Effect.fn("AcpAgent.handleSetProvider")(function (handler) {
494 return Effect.suspend(() => {
495 coreHandlers.setProvider = handler;
496 return Effect.void;
497 });
498 }),
499 handleDisableProvider: Effect.fn("AcpAgent.handleDisableProvider")(function (handler) {
500 return Effect.suspend(() => {
501 coreHandlers.disableProvider = handler;
502 return Effect.void;
503 });
504 }),
505 handleSetSessionConfigOption: Effect.fn("AcpAgent.handleSetSessionConfigOption")(
506 function (handler) {
507 return Effect.suspend(() => {
508 coreHandlers.setSessionConfigOption = handler;
509 return Effect.void;
510 });
511 },
512 ),
513 handlePrompt: Effect.fn("AcpAgent.handlePrompt")(function (handler) {
514 return Effect.suspend(() => {
515 coreHandlers.prompt = handler;
516 return Effect.void;
517 });
518 }),
519 handleCancel: Effect.fn("AcpAgent.handleCancel")(function (handler) {
520 return Effect.suspend(() => {
521 cancelHandlers.push(handler);
522 return Effect.void;
523 });
524 }),
525 handleUnknownExtRequest: Effect.fn("AcpAgent.handleUnknownExtRequest")(function (handler) {
526 return Effect.suspend(() => {
527 unknownExtRequestHandler = handler;
528 return Effect.void;
529 });
530 }),
531 handleUnknownExtNotification: Effect.fn("AcpAgent.handleUnknownExtNotification")(
532 function (handler) {
533 return Effect.suspend(() => {
534 unknownExtNotificationHandler = handler;
535 return Effect.void;
536 });
537 },
538 ),
539 handleExtRequest: Effect.fn("AcpAgent.handleExtRequest")(function (method, payload, handler) {
540 return Effect.suspend(() => {
541 extRequestHandlers.set(method, decodeExtRequestRegistration(method, payload, handler));
542 return Effect.void;
543 });
544 }),
545 handleExtNotification: Effect.fn("AcpAgent.handleExtNotification")(
546 function (method, payload, handler) {
547 return Effect.suspend(() => {
548 extNotificationHandlers.set(
549 method,
550 decodeExtNotificationRegistration(method, payload, handler),
551 );
552 return Effect.void;
553 });
554 },
555 ),
556 });
557});
558
559export const layer = (stdio: Stdio.Stdio, options: AcpAgentOptions = {}): Layer.Layer<AcpAgent> =>
560 Layer.effect(AcpAgent, make(stdio, options));
561
562export const layerStdio = (
563 options: AcpAgentOptions = {},
564): Layer.Layer<AcpAgent, never, Stdio.Stdio> =>
565 Layer.effect(
566 AcpAgent,
567 Effect.flatMap(Effect.service(Stdio.Stdio), (stdio) => make(stdio, options)),
568 );