MCPcopy Create free account
hub / github.com/cloudflare/computer / ShellWorker

Class ShellWorker

packages/computer/src/backends/worker-shell/entrypoint.ts:88–262  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

86 | { id: string; seq: number; name: "exit"; value: number };
87
88export class ShellWorker<
89 Env extends ShellWorkerEnv = ShellWorkerEnv,
90> extends WorkerEntrypoint<Env> {
91 // Subclasses override to change the default cwd.
92 // ECMAScript module execution uses workspace.runtime; just-bash's Python and JavaScript
93 // commands require node:worker_threads and cannot run in workerd.
94 protected readonly shellOptions: ShellWorkerOptions = {};
95 readonly #executions = new Map<string, AbortController>();
96
97 // Test seam: when set, exec uses this to spawn the command
98 // instead of `new Bash({...}).exec(...)`. Real production
99 // paths never touch it.
100 //
101 // The override receives the customCommands list that would
102 // have gone into the Bash constructor so tests can assert on
103 // it directly — the git command is registered here, and a
104 // subclass extraCommands hook would layer onto the same list.
105 protected bashFactoryOverride:
106 | ((
107 command: string,
108 options: {
109 cwd?: string;
110 env?: Record<string, string>;
111 stdin?: Uint8Array;
112 signal?: AbortSignal;
113 customCommands: CustomCommand[];
114 },
115 ) => Promise<{ stdout: string; stderr: string; exitCode: number }>)
116 | undefined;
117
118 /**
119 * Subclass hook for registering additional custom commands
120 * alongside the built-in `git` command. Symmetric with
121 * `shellOptions`: the base class returns an empty list and
122 * subclasses override to layer their own commands on top.
123 *
124 * Called once per `exec` with the live host stub the shell
125 * already reached, so subclass commands share that stub's
126 * lifetime without needing to refetch.
127 */
128 protected extraCommands(_ws: HostWorkspaceStub): CustomCommand[] {
129 return [];
130 }
131
132 override async fetch(_request: Request): Promise<Response> {
133 return new Response(
134 "ShellWorker is invoked over Workers RPC — dispatch through the Workspace's WorkerShellBackend.",
135 { status: 426, headers: { "content-type": "text/plain; charset=utf-8" } },
136 );
137 }
138
139 async exec(input: ExecInput): Promise<{ id: string; events: ReadableStream<Uint8Array> }> {
140 const id = input.id ?? crypto.randomUUID();
141 const cwd = input.cwd ?? this.shellOptions.cwd ?? DEFAULT_CWD;
142 if (this.#executions.has(id))
143 throw createShellError("EEXEC_BUSY", `execution ${id} is running`);
144 const controller = new AbortController();
145 this.#executions.set(id, controller);

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected