From 012e8ac274d4fe82b992a142d98d93c635c510f5 Mon Sep 17 00:00:00 2001 From: aron <263346377+aron-cf@users.noreply.github.com> Date: Fri, 31 Jul 2026 21:30:35 +0000 Subject: [PATCH 1/7] computer: rename Worker-hosted backends to worker-shell and worker-javascript Rename the two Dynamic-Worker-hosted backends so their names describe what they are. Both run inside a Worker; they differ only in whether the shell is just-bash or an ECMAScript module. The previous names obscured that: WorkerBackend carried type "worker" but default id "isolate-shell", and the JavaScript backend was IsolateJavaScriptBackend with type "isolate-javascript". WorkerBackend becomes WorkerShellBackend, and IsolateJavaScriptBackend becomes WorkerJavaScriptBackend. Both now hold matching type and default id values, "worker-shell" and "worker-javascript". The source directories and package export subpaths move in step, from backends/worker and backends/javascript to backends/worker-shell and backends/worker-javascript. Changing the JavaScript backend's default id re-keys its execution journal and watermark rows; existing rows written under the old id become invisible to the renamed backend. This is acceptable for the preview journal, which is ephemeral. --- .gitignore | 2 +- packages/computer/package.json | 14 ++-- packages/computer/rolldown.config.ts | 4 +- packages/computer/src/backend.ts | 4 +- .../computer/src/backends/javascript/index.ts | 4 -- .../src/backends/worker-javascript/index.ts | 4 ++ .../module-graph.ts | 2 +- .../worker-javascript.test.ts} | 68 +++++++++---------- .../worker-javascript.ts} | 36 +++++----- .../{worker => worker-shell}/adapter.test.ts | 0 .../{worker => worker-shell}/adapter.ts | 0 .../artifacts-command.test.ts | 0 .../artifacts-command.ts | 0 .../assets-command.test.ts | 0 .../assets-command.ts | 0 .../entrypoint.test.ts | 2 +- .../{worker => worker-shell}/entrypoint.ts | 4 +- .../generated-bundle.test.ts | 0 .../git-command.test.ts | 0 .../{worker => worker-shell}/git-command.ts | 0 .../{worker => worker-shell}/index.ts | 10 ++- .../runtime-modules.ts | 0 .../script/build-bundle.mjs | 4 +- .../worker-shell.test.ts} | 28 ++++---- .../worker-shell.ts} | 26 +++---- packages/computer/src/index.ts | 2 +- packages/computer/src/runtime/bridge.ts | 4 +- packages/computer/src/stub.test.ts | 4 +- .../computer/tests/script-runner-worker.ts | 14 ++-- .../computer/tests/worker-backend-worker.ts | 8 +-- .../computer/tests/worker-backend.test.ts | 6 +- .../tests/wrangler.worker-backend.jsonc | 4 +- .../computer/vitest.config.worker-backend.ts | 2 +- 33 files changed, 130 insertions(+), 126 deletions(-) delete mode 100644 packages/computer/src/backends/javascript/index.ts create mode 100644 packages/computer/src/backends/worker-javascript/index.ts rename packages/computer/src/backends/{javascript => worker-javascript}/module-graph.ts (99%) rename packages/computer/src/backends/{javascript/javascript-backend.test.ts => worker-javascript/worker-javascript.test.ts} (92%) rename packages/computer/src/backends/{javascript/javascript-backend.ts => worker-javascript/worker-javascript.ts} (96%) rename packages/computer/src/backends/{worker => worker-shell}/adapter.test.ts (100%) rename packages/computer/src/backends/{worker => worker-shell}/adapter.ts (100%) rename packages/computer/src/backends/{worker => worker-shell}/artifacts-command.test.ts (100%) rename packages/computer/src/backends/{worker => worker-shell}/artifacts-command.ts (100%) rename packages/computer/src/backends/{worker => worker-shell}/assets-command.test.ts (100%) rename packages/computer/src/backends/{worker => worker-shell}/assets-command.ts (100%) rename packages/computer/src/backends/{worker => worker-shell}/entrypoint.test.ts (99%) rename packages/computer/src/backends/{worker => worker-shell}/entrypoint.ts (99%) rename packages/computer/src/backends/{worker => worker-shell}/generated-bundle.test.ts (100%) rename packages/computer/src/backends/{worker => worker-shell}/git-command.test.ts (100%) rename packages/computer/src/backends/{worker => worker-shell}/git-command.ts (100%) rename packages/computer/src/backends/{worker => worker-shell}/index.ts (84%) rename packages/computer/src/backends/{worker => worker-shell}/runtime-modules.ts (100%) rename packages/computer/src/backends/{worker => worker-shell}/script/build-bundle.mjs (97%) rename packages/computer/src/backends/{worker/worker.test.ts => worker-shell/worker-shell.test.ts} (92%) rename packages/computer/src/backends/{worker/worker.ts => worker-shell/worker-shell.ts} (93%) diff --git a/.gitignore b/.gitignore index 8bf20f8a..6c6f75b3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,7 @@ PLAN.md # Generated bundle for the worker backend's ShellWorker. Built # by packages/computer/src/backends/worker/script/build-bundle.mjs # on prepare / pretest / pretypecheck. -packages/computer/src/backends/worker/generated-bundle.ts +packages/computer/src/backends/worker-shell/generated-bundle.ts # SEA binary destinations populated at publish time from # artifacts/computerd/ via the build-bin step. The @cloudflare/computer diff --git a/packages/computer/package.json b/packages/computer/package.json index 20f9a33d..ba4a860d 100644 --- a/packages/computer/package.json +++ b/packages/computer/package.json @@ -35,13 +35,13 @@ "types": "./dist/backends/container/index.d.ts", "import": "./dist/backends/container/index.js" }, - "./backends/javascript": { - "types": "./dist/backends/javascript/index.d.ts", - "import": "./dist/backends/javascript/index.js" + "./backends/worker-javascript": { + "types": "./dist/backends/worker-javascript/index.d.ts", + "import": "./dist/backends/worker-javascript/index.js" }, - "./backends/worker": { - "types": "./dist/backends/worker/index.d.ts", - "import": "./dist/backends/worker/index.js" + "./backends/worker-shell": { + "types": "./dist/backends/worker-shell/index.d.ts", + "import": "./dist/backends/worker-shell/index.js" }, "./observe/cloudflare": { "types": "./dist/observe/cloudflare.d.ts", @@ -56,7 +56,7 @@ ], "scripts": { "build:deps": "npm run build --workspace @cloudflare/computer-rpc", - "build:shell-bundle": "node ./src/backends/worker/script/build-bundle.mjs", + "build:shell-bundle": "node ./src/backends/worker-shell/script/build-bundle.mjs", "prebuild": "npm run build:deps && npm run build:shell-bundle", "pretest": "npm run build:shell-bundle", "pretypecheck": "npm run build:deps && npm run build:shell-bundle", diff --git a/packages/computer/rolldown.config.ts b/packages/computer/rolldown.config.ts index 044c57ec..8143bb8c 100644 --- a/packages/computer/rolldown.config.ts +++ b/packages/computer/rolldown.config.ts @@ -32,8 +32,8 @@ export default defineConfig({ "assets/index": "src/assets/index.ts", "tools/index": "src/tools/index.ts", "backends/container/index": "src/backends/container/index.ts", - "backends/javascript/index": "src/backends/javascript/index.ts", - "backends/worker/index": "src/backends/worker/index.ts", + "backends/worker-javascript/index": "src/backends/worker-javascript/index.ts", + "backends/worker-shell/index": "src/backends/worker-shell/index.ts", "observe/cloudflare": "src/observe/cloudflare.ts", }, external: [ diff --git a/packages/computer/src/backend.ts b/packages/computer/src/backend.ts index 721547c0..ac3237c0 100644 --- a/packages/computer/src/backend.ts +++ b/packages/computer/src/backend.ts @@ -28,12 +28,12 @@ export interface WorkspaceBackend { // Each concrete backend constructor accepts an `id` option // and defaults it to a sensible string when omitted: "test" // for TestBackend, "container-shell" for the container - // backend, and "isolate-shell" for the worker backend. Single-backend + // backend, and "worker-shell" for the worker shell backend. Single-backend // setups can ride the default and never touch the field. readonly id: string; // Diagnostic kind of backend, fixed by the implementation - // ("test", "cloudflare-container", "worker"). Used for + // ("test", "cloudflare-container", "worker-shell"). Used for // tracing spans and stub-leak counters; not consumed by // Workspace selection logic. readonly type: string; diff --git a/packages/computer/src/backends/javascript/index.ts b/packages/computer/src/backends/javascript/index.ts deleted file mode 100644 index 460bb376..00000000 --- a/packages/computer/src/backends/javascript/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { - IsolateJavaScriptBackend, - type IsolateJavaScriptBackendOptions, -} from "./javascript-backend.js"; diff --git a/packages/computer/src/backends/worker-javascript/index.ts b/packages/computer/src/backends/worker-javascript/index.ts new file mode 100644 index 00000000..a3729142 --- /dev/null +++ b/packages/computer/src/backends/worker-javascript/index.ts @@ -0,0 +1,4 @@ +export { + WorkerJavaScriptBackend, + type WorkerJavaScriptBackendOptions, +} from "./worker-javascript.js"; diff --git a/packages/computer/src/backends/javascript/module-graph.ts b/packages/computer/src/backends/worker-javascript/module-graph.ts similarity index 99% rename from packages/computer/src/backends/javascript/module-graph.ts rename to packages/computer/src/backends/worker-javascript/module-graph.ts index 7c7605f4..3f5a3fcb 100644 --- a/packages/computer/src/backends/javascript/module-graph.ts +++ b/packages/computer/src/backends/worker-javascript/module-graph.ts @@ -103,7 +103,7 @@ export async function buildModuleGraph(options: BuildModuleGraphOptions) { } if (!Object.hasOwn(options.configuredModules, specifier)) { throw new Error( - `Module ${JSON.stringify(specifier)} is not configured for the isolate-javascript backend.`, + `Module ${JSON.stringify(specifier)} is not configured for the worker-javascript backend.`, ); } } diff --git a/packages/computer/src/backends/javascript/javascript-backend.test.ts b/packages/computer/src/backends/worker-javascript/worker-javascript.test.ts similarity index 92% rename from packages/computer/src/backends/javascript/javascript-backend.test.ts rename to packages/computer/src/backends/worker-javascript/worker-javascript.test.ts index df234e0e..12b82d89 100644 --- a/packages/computer/src/backends/javascript/javascript-backend.test.ts +++ b/packages/computer/src/backends/worker-javascript/worker-javascript.test.ts @@ -3,12 +3,12 @@ import { SQLiteTestStorage } from "@cloudflare/dofs/testing"; import { describe, expect, it, vi } from "vitest"; import { Workspace } from "../../workspace.js"; -import { IsolateJavaScriptBackend as ProductionIsolateJavaScriptBackend } from "./javascript-backend.js"; +import { WorkerJavaScriptBackend as ProductionWorkerJavaScriptBackend } from "./worker-javascript.js"; -class IsolateJavaScriptBackend extends ProductionIsolateJavaScriptBackend { +class WorkerJavaScriptBackend extends ProductionWorkerJavaScriptBackend { override readonly requiresWaitUntil = false; - override connect(host: Parameters[0]) { + override connect(host: Parameters[0]) { return super.connect({ ...host, waitUntil: host.waitUntil ?? (() => {}) }); } } @@ -21,9 +21,9 @@ function throwingLoader(message: string) { }; } -describe("IsolateJavaScriptBackend", () => { +describe("WorkerJavaScriptBackend", () => { it("requires a host event-lifetime hook", async () => { - const backend = new ProductionIsolateJavaScriptBackend({ loader: throwingLoader("unused") }); + const backend = new ProductionWorkerJavaScriptBackend({ loader: throwingLoader("unused") }); await expect( backend.connect({ db: undefined as never, @@ -37,14 +37,14 @@ describe("IsolateJavaScriptBackend", () => { it("validates timeout configuration", () => { expect( () => - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: throwingLoader("unused"), maxTimeoutMs: Number.NaN, }), ).toThrow(/positive finite/); expect( () => - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: throwingLoader("unused"), defaultTimeoutMs: -1, }), @@ -60,7 +60,7 @@ describe("IsolateJavaScriptBackend", () => { throw new Error("waitUntil unavailable"); }, backends: [ - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: { load() { return { @@ -98,7 +98,7 @@ describe("IsolateJavaScriptBackend", () => { storage: new SQLiteTestStorage(), waitUntil() {}, backends: [ - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: { load() { return { @@ -145,7 +145,7 @@ describe("IsolateJavaScriptBackend", () => { VALUES ('isolate-javascript', 'legacy', 'completed')`, ); const fs = new WorkspaceFilesystem(db); - const backend = new IsolateJavaScriptBackend({ loader: throwingLoader("unused") }); + const backend = new WorkerJavaScriptBackend({ loader: throwingLoader("unused") }); await backend.connect({ db, fs, git: undefined as never, artifacts: undefined as never }); const columns = db.all<{ name: string }>("PRAGMA table_info(workspace_runtime_executions)"); expect(columns.map((column) => column.name)).toEqual( @@ -165,7 +165,7 @@ describe("IsolateJavaScriptBackend", () => { const workspace = new Workspace({ storage: new SQLiteTestStorage(), backends: [ - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: { load }, maxInputBytes: 8, maxResultBytes: 8, @@ -198,7 +198,7 @@ describe("IsolateJavaScriptBackend", () => { await blocked; return readFile(...args); }) as typeof fs.readFile; - const backend = new IsolateJavaScriptBackend({ loader: throwingLoader("must not load") }); + const backend = new WorkerJavaScriptBackend({ loader: throwingLoader("must not load") }); const handle = await backend.connect({ db, fs, @@ -225,7 +225,7 @@ describe("IsolateJavaScriptBackend", () => { const load = vi.fn(); const workspace = new Workspace({ storage: new SQLiteTestStorage(), - backends: [new IsolateJavaScriptBackend({ loader: { load }, maxSourceBytes: 128 })], + backends: [new WorkerJavaScriptBackend({ loader: { load }, maxSourceBytes: 128 })], }); await workspace.fs.mkdir("/workspace", { recursive: true }); const execution = await workspace.runtime.exec("export default 1", { encoding: "utf8" }); @@ -240,14 +240,14 @@ describe("IsolateJavaScriptBackend", () => { const workspace = new Workspace({ storage: new SQLiteTestStorage(), backends: [ - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: throwingLoader("loader failed"), }), ], }); await workspace.fs.mkdir("/workspace", { recursive: true }); const handle = await workspace.runtime.exec("export default () => 1", { - backend: "isolate-javascript", + backend: "worker-javascript", id: "startup-failure", encoding: "utf8", }); @@ -257,7 +257,7 @@ describe("IsolateJavaScriptBackend", () => { stderr: expect.stringContaining("loader failed"), }); const replay = await workspace.runtime.getExec("startup-failure", { - backend: "isolate-javascript", + backend: "worker-javascript", encoding: "utf8", }); await expect(replay.result()).resolves.toMatchObject({ status: "failed", exitCode: 1 }); @@ -278,20 +278,20 @@ describe("IsolateJavaScriptBackend", () => { }; const first = new Workspace({ storage, - backends: [new IsolateJavaScriptBackend({ loader })], + backends: [new WorkerJavaScriptBackend({ loader })], }); await first.fs.mkdir("/workspace", { recursive: true }); await first.runtime.exec("export default async () => new Promise(() => {})", { - backend: "isolate-javascript", + backend: "worker-javascript", id: "interrupted", }); const recreated = new Workspace({ storage, - backends: [new IsolateJavaScriptBackend({ loader })], + backends: [new WorkerJavaScriptBackend({ loader })], }); const replay = await recreated.runtime.getExec("interrupted", { - backend: "isolate-javascript", + backend: "worker-javascript", encoding: "utf8", }); await expect(replay.result()).resolves.toMatchObject({ @@ -306,7 +306,7 @@ describe("IsolateJavaScriptBackend", () => { const workspace = new Workspace({ storage: new SQLiteTestStorage(), backends: [ - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: { load() { return { @@ -342,7 +342,7 @@ describe("IsolateJavaScriptBackend", () => { storage: new SQLiteTestStorage(), waitUntil, backends: [ - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: { load() { return { @@ -383,7 +383,7 @@ describe("IsolateJavaScriptBackend", () => { await writeReleased; return originalWrite(...args); }) as typeof fs.writeFile; - const backend = new IsolateJavaScriptBackend({ + const backend = new WorkerJavaScriptBackend({ loader: { load() { return { @@ -430,7 +430,7 @@ describe("IsolateJavaScriptBackend", () => { const fs = new WorkspaceFilesystem(db); await fs.mkdir("/workspace", { recursive: true }); let aborted = false; - const backend = new IsolateJavaScriptBackend({ + const backend = new WorkerJavaScriptBackend({ maxHostCallMs: 5, trustedModules: { "ws:test": { @@ -494,7 +494,7 @@ describe("IsolateJavaScriptBackend", () => { await writeReleased; return originalWrite(...args); }) as typeof fs.writeFile; - const backend = new IsolateJavaScriptBackend({ + const backend = new WorkerJavaScriptBackend({ loader: { load() { return { @@ -554,7 +554,7 @@ describe("IsolateJavaScriptBackend", () => { const evaluation = new Promise<{ result: number }>((resolve) => { finish = resolve; }); - const backend = new IsolateJavaScriptBackend({ + const backend = new WorkerJavaScriptBackend({ loader: { load() { return { @@ -596,7 +596,7 @@ describe("IsolateJavaScriptBackend", () => { const workspace = new Workspace({ storage: new SQLiteTestStorage(), backends: [ - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: throwingLoader("finished"), maxRetainedExecutions: 1, }), @@ -618,7 +618,7 @@ describe("IsolateJavaScriptBackend", () => { const load = vi.fn(); const workspace = new Workspace({ storage: new SQLiteTestStorage(), - backends: [new IsolateJavaScriptBackend({ loader: { load } })], + backends: [new WorkerJavaScriptBackend({ loader: { load } })], }); await workspace.fs.mkdir("/workspace", { recursive: true }); await expect(workspace.runtime.exec("export default 1", { cwd: "/outside" })).rejects.toThrow( @@ -635,7 +635,7 @@ describe("IsolateJavaScriptBackend", () => { initializeSchema(db, () => 0); const fs = new WorkspaceFilesystem(db); await fs.mkdir("/workspace", { recursive: true }); - const backend = new IsolateJavaScriptBackend({ + const backend = new WorkerJavaScriptBackend({ maxExecutionSubscribers: 2, loader: { load() { @@ -664,7 +664,7 @@ describe("IsolateJavaScriptBackend", () => { const workspace = new Workspace({ storage: new SQLiteTestStorage(), backends: [ - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: throwingLoader("must not load"), trustedModules: { "ws:bad/path": { @@ -679,7 +679,7 @@ describe("IsolateJavaScriptBackend", () => { await workspace.fs.mkdir("/workspace", { recursive: true }); await expect( workspace.runtime.exec(`import { call } from "ws:bad/path"; export default call;`, { - backend: "isolate-javascript", + backend: "worker-javascript", }), ).rejects.toThrow(/simple reserved ws:\*/); }); @@ -688,7 +688,7 @@ describe("IsolateJavaScriptBackend", () => { const load = vi.fn(); const workspace = new Workspace({ storage: new SQLiteTestStorage(), - backends: [new IsolateJavaScriptBackend({ loader: { load }, root: "/" })], + backends: [new WorkerJavaScriptBackend({ loader: { load }, root: "/" })], }); await workspace.fs.writeFile("/workspace-capabilities.js", "export const stolen = true"); await expect( @@ -704,7 +704,7 @@ describe("IsolateJavaScriptBackend", () => { const workspace = new Workspace({ storage: new SQLiteTestStorage(), backends: [ - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: { load }, modules: { "__workspace_entry__.js": "export default 42", @@ -715,7 +715,7 @@ describe("IsolateJavaScriptBackend", () => { }); await workspace.fs.mkdir("/workspace", { recursive: true }); await expect( - workspace.runtime.exec("export default 1", { backend: "isolate-javascript" }), + workspace.runtime.exec("export default 1", { backend: "worker-javascript" }), ).rejects.toThrow(/reserved module name/); expect(load).not.toHaveBeenCalled(); }); diff --git a/packages/computer/src/backends/javascript/javascript-backend.ts b/packages/computer/src/backends/worker-javascript/worker-javascript.ts similarity index 96% rename from packages/computer/src/backends/javascript/javascript-backend.ts rename to packages/computer/src/backends/worker-javascript/worker-javascript.ts index b17b5aed..ce4c5f53 100644 --- a/packages/computer/src/backends/javascript/javascript-backend.ts +++ b/packages/computer/src/backends/worker-javascript/worker-javascript.ts @@ -14,7 +14,7 @@ import type { } from "../../runtime/types.js"; import { buildModuleGraph } from "./module-graph.js"; -export interface IsolateJavaScriptBackendOptions { +export interface WorkerJavaScriptBackendOptions { loader: WorkspaceRuntimeLoader; id?: string; root?: string; @@ -58,9 +58,9 @@ export interface IsolateJavaScriptBackendOptions { allowArtifactNetwork?: boolean; } -type ResolvedIsolateJavaScriptBackendOptions = Required< +type ResolvedWorkerJavaScriptBackendOptions = Required< Pick< - IsolateJavaScriptBackendOptions, + WorkerJavaScriptBackendOptions, | "root" | "access" | "defaultTimeoutMs" @@ -85,7 +85,7 @@ type ResolvedIsolateJavaScriptBackendOptions = Required< | "compatibilityFlags" > > & - IsolateJavaScriptBackendOptions; + WorkerJavaScriptBackendOptions; interface JavaScriptEntrypoint { evaluate( @@ -118,15 +118,15 @@ interface ExecutionRecord { persistenceFailed?: boolean; } -export class IsolateJavaScriptBackend implements WorkspaceModuleBackend { +export class WorkerJavaScriptBackend implements WorkspaceModuleBackend { readonly protocol = "module" as const; readonly requiresWaitUntil = true; - readonly type = "isolate-javascript"; + readonly type = "worker-javascript"; readonly id: string; - readonly #options: ResolvedIsolateJavaScriptBackendOptions; + readonly #options: ResolvedWorkerJavaScriptBackendOptions; - constructor(options: IsolateJavaScriptBackendOptions) { - this.id = options.id ?? "isolate-javascript"; + constructor(options: WorkerJavaScriptBackendOptions) { + this.id = options.id ?? "worker-javascript"; const maxTimeoutMs = options.maxTimeoutMs ?? 30_000; const defaultTimeoutMs = options.defaultTimeoutMs ?? Math.min(10_000, maxTimeoutMs); assertPositiveFinite(maxTimeoutMs, "maxTimeoutMs"); @@ -157,14 +157,14 @@ export class IsolateJavaScriptBackend implements WorkspaceModuleBackend { assertPositiveFinite(options.retentionMs ?? 5 * 60_000, "retentionMs"); assertPositiveInteger(options.maxRetainedExecutions ?? 100, "maxRetainedExecutions"); if ((options.maxCapabilityBytes ?? 1024 * 1024) < 256) { - throw new Error("IsolateJavaScriptBackend maxCapabilityBytes must be at least 256 bytes."); + throw new Error("WorkerJavaScriptBackend maxCapabilityBytes must be at least 256 bytes."); } const compatibilityDate = options.compatibilityDate ?? "2026-05-23"; if (!/^\d{4}-\d{2}-\d{2}$/.test(compatibilityDate)) { - throw new Error("IsolateJavaScriptBackend compatibilityDate must use YYYY-MM-DD."); + throw new Error("WorkerJavaScriptBackend compatibilityDate must use YYYY-MM-DD."); } if (defaultTimeoutMs > maxTimeoutMs) { - throw new Error("IsolateJavaScriptBackend defaultTimeoutMs cannot exceed maxTimeoutMs."); + throw new Error("WorkerJavaScriptBackend defaultTimeoutMs cannot exceed maxTimeoutMs."); } this.#options = { ...options, @@ -197,7 +197,7 @@ export class IsolateJavaScriptBackend implements WorkspaceModuleBackend { async connect(host: WorkspaceModuleBackendHost): Promise { if (!host.waitUntil) { throw new Error( - "IsolateJavaScriptBackend requires WorkspaceOptions.waitUntil; pass ctx.waitUntil.bind(ctx).", + "WorkerJavaScriptBackend requires WorkspaceOptions.waitUntil; pass ctx.waitUntil.bind(ctx).", ); } return new JavaScriptBackendHandle(this.#options, host); @@ -205,7 +205,7 @@ export class IsolateJavaScriptBackend implements WorkspaceModuleBackend { } class JavaScriptBackendHandle implements WorkspaceModuleBackendHandle { - readonly #options: ResolvedIsolateJavaScriptBackendOptions; + readonly #options: ResolvedWorkerJavaScriptBackendOptions; readonly #host: WorkspaceModuleBackendHost; readonly #records = new Map(); readonly #pendingIds = new Set(); @@ -215,7 +215,7 @@ class JavaScriptBackendHandle implements WorkspaceModuleBackendHandle { #pendingStarts = 0; readonly #pendingStartWaiters = new Set<() => void>(); - constructor(options: ResolvedIsolateJavaScriptBackendOptions, host: WorkspaceModuleBackendHost) { + constructor(options: ResolvedWorkerJavaScriptBackendOptions, host: WorkspaceModuleBackendHost) { this.#options = options; this.#host = host; host.db.run(` @@ -462,7 +462,7 @@ class JavaScriptBackendHandle implements WorkspaceModuleBackendHandle { } get #backendId(): string { - return this.#options.id ?? "isolate-javascript"; + return this.#options.id ?? "worker-javascript"; } async #cancel(record: ExecutionRecord, message: string): Promise { @@ -1069,13 +1069,13 @@ function assertEncodedSize(value: WorkspaceRuntimeValue, maxBytes: number, name: function assertPositiveFinite(value: number, name: string) { if (!Number.isFinite(value) || value <= 0) { - throw new Error(`IsolateJavaScriptBackend ${name} must be a positive finite number.`); + throw new Error(`WorkerJavaScriptBackend ${name} must be a positive finite number.`); } } function assertPositiveInteger(value: number, name: string) { if (!Number.isSafeInteger(value) || value <= 0) { - throw new Error(`IsolateJavaScriptBackend ${name} must be a positive integer.`); + throw new Error(`WorkerJavaScriptBackend ${name} must be a positive integer.`); } } diff --git a/packages/computer/src/backends/worker/adapter.test.ts b/packages/computer/src/backends/worker-shell/adapter.test.ts similarity index 100% rename from packages/computer/src/backends/worker/adapter.test.ts rename to packages/computer/src/backends/worker-shell/adapter.test.ts diff --git a/packages/computer/src/backends/worker/adapter.ts b/packages/computer/src/backends/worker-shell/adapter.ts similarity index 100% rename from packages/computer/src/backends/worker/adapter.ts rename to packages/computer/src/backends/worker-shell/adapter.ts diff --git a/packages/computer/src/backends/worker/artifacts-command.test.ts b/packages/computer/src/backends/worker-shell/artifacts-command.test.ts similarity index 100% rename from packages/computer/src/backends/worker/artifacts-command.test.ts rename to packages/computer/src/backends/worker-shell/artifacts-command.test.ts diff --git a/packages/computer/src/backends/worker/artifacts-command.ts b/packages/computer/src/backends/worker-shell/artifacts-command.ts similarity index 100% rename from packages/computer/src/backends/worker/artifacts-command.ts rename to packages/computer/src/backends/worker-shell/artifacts-command.ts diff --git a/packages/computer/src/backends/worker/assets-command.test.ts b/packages/computer/src/backends/worker-shell/assets-command.test.ts similarity index 100% rename from packages/computer/src/backends/worker/assets-command.test.ts rename to packages/computer/src/backends/worker-shell/assets-command.test.ts diff --git a/packages/computer/src/backends/worker/assets-command.ts b/packages/computer/src/backends/worker-shell/assets-command.ts similarity index 100% rename from packages/computer/src/backends/worker/assets-command.ts rename to packages/computer/src/backends/worker-shell/assets-command.ts diff --git a/packages/computer/src/backends/worker/entrypoint.test.ts b/packages/computer/src/backends/worker-shell/entrypoint.test.ts similarity index 99% rename from packages/computer/src/backends/worker/entrypoint.test.ts rename to packages/computer/src/backends/worker-shell/entrypoint.test.ts index 5dc55e13..cde7eac9 100644 --- a/packages/computer/src/backends/worker/entrypoint.test.ts +++ b/packages/computer/src/backends/worker-shell/entrypoint.test.ts @@ -7,7 +7,7 @@ // 2. Build a fresh Bash around a WorkspaceFsAdapter wrapping // the workspace's fs surface. // 3. Run the command and frame the result into the NDJSON -// event stream the WorkerBackend's decoder consumes. +// event stream the WorkerShellBackend's decoder consumes. // // No state survives across exec calls. The same workspace stub // is fetched per call so concurrent execs can't share an diff --git a/packages/computer/src/backends/worker/entrypoint.ts b/packages/computer/src/backends/worker-shell/entrypoint.ts similarity index 99% rename from packages/computer/src/backends/worker/entrypoint.ts rename to packages/computer/src/backends/worker-shell/entrypoint.ts index 9bfff82b..84e8a423 100644 --- a/packages/computer/src/backends/worker/entrypoint.ts +++ b/packages/computer/src/backends/worker-shell/entrypoint.ts @@ -1,5 +1,5 @@ // ShellWorker — the WorkerEntrypoint a user Worker exposes for -// the WorkerBackend in @cloudflare/computer to call. +// the WorkerShellBackend in @cloudflare/computer to call. // // Each exec call independently reaches the host Workspace // through a DurableObjectNamespace binding wired into env by @@ -127,7 +127,7 @@ export class ShellWorker< override async fetch(_request: Request): Promise { return new Response( - "ShellWorker is invoked over Workers RPC — dispatch through the Workspace's WorkerBackend.", + "ShellWorker is invoked over Workers RPC — dispatch through the Workspace's WorkerShellBackend.", { status: 426, headers: { "content-type": "text/plain; charset=utf-8" } }, ); } diff --git a/packages/computer/src/backends/worker/generated-bundle.test.ts b/packages/computer/src/backends/worker-shell/generated-bundle.test.ts similarity index 100% rename from packages/computer/src/backends/worker/generated-bundle.test.ts rename to packages/computer/src/backends/worker-shell/generated-bundle.test.ts diff --git a/packages/computer/src/backends/worker/git-command.test.ts b/packages/computer/src/backends/worker-shell/git-command.test.ts similarity index 100% rename from packages/computer/src/backends/worker/git-command.test.ts rename to packages/computer/src/backends/worker-shell/git-command.test.ts diff --git a/packages/computer/src/backends/worker/git-command.ts b/packages/computer/src/backends/worker-shell/git-command.ts similarity index 100% rename from packages/computer/src/backends/worker/git-command.ts rename to packages/computer/src/backends/worker-shell/git-command.ts diff --git a/packages/computer/src/backends/worker/index.ts b/packages/computer/src/backends/worker-shell/index.ts similarity index 84% rename from packages/computer/src/backends/worker/index.ts rename to packages/computer/src/backends/worker-shell/index.ts index 1dd9cf23..8605014b 100644 --- a/packages/computer/src/backends/worker/index.ts +++ b/packages/computer/src/backends/worker-shell/index.ts @@ -8,7 +8,7 @@ // // Imported via: // -// import { WorkerBackend } from "@cloudflare/computer/backends/worker"; +// import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell"; // // The package ships SHELL_MODULES — a record of module name → // source string covering the pre-built ShellWorker entry plus @@ -18,7 +18,7 @@ // spreads both into the Loader callback's `modules` table // internally; consumers only need to reach for them when they // construct the Loader callback by hand (in which case they -// pass a `fetcher` factory to WorkerBackend instead of +// pass a `fetcher` factory to WorkerShellBackend instead of // `loader` + `workspace` + `ctx`). export { type WorkspaceFs, WorkspaceFsAdapter } from "./adapter.js"; @@ -28,4 +28,8 @@ export { type ExecInput, ShellWorker, type ShellWorkerOptions } from "./entrypoi export { SHELL_MODULES } from "./generated-bundle.js"; export { defineGitCommand, type GitCommandHost } from "./git-command.js"; export { SHELL_RUNTIME_MODULES } from "./runtime-modules.js"; -export { WorkerBackend, type WorkerBackendOptions, type WorkerShellFetcher } from "./worker.js"; +export { + WorkerShellBackend, + type WorkerShellBackendOptions, + type WorkerShellFetcher, +} from "./worker-shell.js"; diff --git a/packages/computer/src/backends/worker/runtime-modules.ts b/packages/computer/src/backends/worker-shell/runtime-modules.ts similarity index 100% rename from packages/computer/src/backends/worker/runtime-modules.ts rename to packages/computer/src/backends/worker-shell/runtime-modules.ts diff --git a/packages/computer/src/backends/worker/script/build-bundle.mjs b/packages/computer/src/backends/worker-shell/script/build-bundle.mjs similarity index 97% rename from packages/computer/src/backends/worker/script/build-bundle.mjs rename to packages/computer/src/backends/worker-shell/script/build-bundle.mjs index c749c349..406cbba4 100644 --- a/packages/computer/src/backends/worker/script/build-bundle.mjs +++ b/packages/computer/src/backends/worker-shell/script/build-bundle.mjs @@ -27,8 +27,8 @@ import { fileURLToPath } from "node:url"; import { build } from "esbuild"; const here = dirname(fileURLToPath(import.meta.url)); -// Script lives at .../backends/worker/script/build-bundle.mjs; -// the bundle target is one level up at .../backends/worker/. +// Script lives at .../backends/worker-shell/script/build-bundle.mjs; +// the bundle target is one level up at .../backends/worker-shell/. const root = resolve(here, ".."); const out = resolve(root, "generated-bundle.ts"); diff --git a/packages/computer/src/backends/worker/worker.test.ts b/packages/computer/src/backends/worker-shell/worker-shell.test.ts similarity index 92% rename from packages/computer/src/backends/worker/worker.test.ts rename to packages/computer/src/backends/worker-shell/worker-shell.test.ts index d199be57..58ba2532 100644 --- a/packages/computer/src/backends/worker/worker.test.ts +++ b/packages/computer/src/backends/worker-shell/worker-shell.test.ts @@ -1,4 +1,4 @@ -// Tests for WorkerBackend. +// Tests for WorkerShellBackend. // // The backend's job is small: when Workspace.shell.exec lands, it // dispatches into a user-supplied "shell fetcher" (the Fetcher @@ -23,7 +23,7 @@ import { describe, expect, it } from "vitest"; import type { BackendHandle, WorkspaceBackend } from "../../backend.js"; import { Workspace } from "../../workspace.js"; -import { WorkerBackend } from "./worker.js"; +import { WorkerShellBackend } from "./worker-shell.js"; type WireEvent = | { id: string; seq: number; name: "stdout"; value: string } @@ -78,7 +78,7 @@ function fakeFetcher( function noopFsBackend(): WorkspaceBackend { // Stand-in backend so Workspace.ready() resolves without - // wiring a real sync peer. WorkerBackend itself declares + // wiring a real sync peer. WorkerShellBackend itself declares // sync: "none"; this fake just stops the test from depending // on a container. return { @@ -96,7 +96,7 @@ function noopFsBackend(): WorkspaceBackend { }; } -describe("WorkerBackend", () => { +describe("WorkerShellBackend", () => { it("returns a BackendHandle with sync: 'none'", async () => { const fetcher = fakeFetcher(() => { throw new Error("exec not called in this test"); @@ -106,7 +106,7 @@ describe("WorkerBackend", () => { backends: [noopFsBackend()], }); await ws.ready(); - const backend = new WorkerBackend({ fetcher: () => fetcher }); + const backend = new WorkerShellBackend({ fetcher: () => fetcher }); const handle = await backend.connect(); expect(handle.sync).toBe("none"); await handle.close(); @@ -127,7 +127,7 @@ describe("WorkerBackend", () => { backends: [noopFsBackend()], }); await ws.ready(); - const backend = new WorkerBackend({ fetcher: () => fetcher }); + const backend = new WorkerShellBackend({ fetcher: () => fetcher }); const handle = await backend.connect(); const envelope = await handle.rpc.shell.exec({ command: "echo hello" }); @@ -158,7 +158,7 @@ describe("WorkerBackend", () => { }, }), })); - const handle = await new WorkerBackend({ fetcher: () => fetcher }).connect(); + const handle = await new WorkerShellBackend({ fetcher: () => fetcher }).connect(); const envelope = await handle.rpc.shell.exec({ command: "bad" }); await expect(envelope.events.getReader().read()).rejects.toMatchObject({ code: "EPROTOCOL" }); }); @@ -177,7 +177,7 @@ describe("WorkerBackend", () => { backends: [noopFsBackend()], }); await ws.ready(); - const backend = new WorkerBackend({ fetcher: () => fetcher }); + const backend = new WorkerShellBackend({ fetcher: () => fetcher }); const handle = await backend.connect(); await handle.rpc.shell.exec({ command: "x", cwd: "/workspace/src", id: "fixed" }); expect(observed?.cwd).toBe("/workspace/src"); @@ -185,7 +185,7 @@ describe("WorkerBackend", () => { }); it("plumbs through Workspace.shell.exec end-to-end", async () => { - // Construct WorkerBackend as the sole backend of a Workspace + // Construct WorkerShellBackend as the sole backend of a Workspace // and exercise the public shell.exec entry point. Pushes and // pulls are no-ops because of sync: "none". const fetcher = fakeFetcher((input) => ({ @@ -197,7 +197,7 @@ describe("WorkerBackend", () => { })); const ws = new Workspace({ storage: new SQLiteTestStorage() as never, - backends: [new WorkerBackend({ fetcher: () => fetcher })], + backends: [new WorkerShellBackend({ fetcher: () => fetcher })], }); await ws.ready(); const handle = await ws.runtime.exec("echo world", { encoding: "utf8" }); @@ -234,7 +234,7 @@ describe("WorkerBackend", () => { }, }; - const backend = new WorkerBackend({ + const backend = new WorkerShellBackend({ loader, workspace: { binding: "WorkspaceHost", id: "abc" }, ctx, @@ -267,7 +267,7 @@ describe("WorkerBackend", () => { }; }, }; - const backend = new WorkerBackend({ + const backend = new WorkerShellBackend({ loader, workspace: { binding: "WorkspaceHost", id: "abc" }, ctx: { exports: { WorkspaceServiceProxy: () => ({}) } }, @@ -281,7 +281,7 @@ describe("WorkerBackend", () => { it("disposes the Loader worker when entrypoint creation fails", async () => { let workerDisposals = 0; - const backend = new WorkerBackend({ + const backend = new WorkerShellBackend({ loader: { get() { return { @@ -316,7 +316,7 @@ describe("WorkerBackend", () => { backends: [noopFsBackend()], }); await ws.ready(); - const backend = new WorkerBackend({ + const backend = new WorkerShellBackend({ fetcher: async () => { factoryCalls += 1; return fetcher; diff --git a/packages/computer/src/backends/worker/worker.ts b/packages/computer/src/backends/worker-shell/worker-shell.ts similarity index 93% rename from packages/computer/src/backends/worker/worker.ts rename to packages/computer/src/backends/worker-shell/worker-shell.ts index 154c17fb..c3a1c554 100644 --- a/packages/computer/src/backends/worker/worker.ts +++ b/packages/computer/src/backends/worker-shell/worker-shell.ts @@ -1,4 +1,4 @@ -// WorkerBackend — backs Workspace with a just-bash shell that +// WorkerShellBackend — backs Workspace with a just-bash shell that // runs in a Dynamic Worker minted through env.LOADER. // // The common shape is the one ContainerBackend mirrors: the @@ -79,7 +79,7 @@ interface DurableObjectCtxWithExports { }; } -export interface WorkerBackendOptions { +export interface WorkerShellBackendOptions { // The Worker Loader binding from env. Required when `fetcher` // is omitted; the backend mints the Dynamic Worker through it. loader?: WorkerLoaderLike; @@ -124,7 +124,7 @@ export interface WorkerBackendOptions { fetcher?: () => unknown | Promise; // Selector this backend is registered under in Workspace. - // Defaults to "isolate-shell"; override when the workspace hosts + // Defaults to "worker-shell"; override when the workspace hosts // more than one instance of the same backend kind (e.g. two // workers on different loaders or with different shell // configurations). @@ -134,13 +134,13 @@ export interface WorkerBackendOptions { const DEFAULT_COMPAT_DATE = "2026-06-17"; const DEFAULT_COMPAT_FLAGS = ["nodejs_compat"]; -export class WorkerBackend implements WorkspaceBackend { - readonly type = "worker"; +export class WorkerShellBackend implements WorkspaceBackend { + readonly type = "worker-shell"; readonly id: string; - readonly #options: WorkerBackendOptions; + readonly #options: WorkerShellBackendOptions; - constructor(options: WorkerBackendOptions) { - this.id = options.id ?? "isolate-shell"; + constructor(options: WorkerShellBackendOptions) { + this.id = options.id ?? "worker-shell"; if (options.fetcher === undefined) { if ( options.loader === undefined || @@ -148,7 +148,7 @@ export class WorkerBackend implements WorkspaceBackend { options.ctx === undefined ) { throw new Error( - "WorkerBackend: pass either `fetcher` directly or all of " + + "WorkerShellBackend: pass either `fetcher` directly or all of " + "`loader`, `workspace`, and `ctx` so the backend can " + "mint the Dynamic Worker itself.", ); @@ -293,7 +293,7 @@ function parseFrame(line: string): ExecEvent { try { event = JSON.parse(line) as Record; } catch { - throw protocolError("WorkerBackend received invalid execution JSON"); + throw protocolError("WorkerShellBackend received invalid execution JSON"); } if ( typeof event.id !== "string" || @@ -302,7 +302,7 @@ function parseFrame(line: string): ExecEvent { ((event.name === "stdout" || event.name === "stderr") && typeof event.value !== "string") || (event.name === "exit" && !Number.isSafeInteger(event.value)) ) { - throw protocolError("WorkerBackend received a malformed execution frame"); + throw protocolError("WorkerShellBackend received a malformed execution frame"); } return reshape( event as { @@ -350,7 +350,7 @@ function disposeQuietly(value: { [Symbol.dispose]?: () => void }) { function noopSync(): SyncRPC { const refuse = (name: string): never => { throw new Error( - `WorkerBackend: sync.${name} must not be called — the handle declares sync: "none"`, + `WorkerShellBackend: sync.${name} must not be called — the handle declares sync: "none"`, ); }; return { @@ -361,7 +361,7 @@ function noopSync(): SyncRPC { fetchObjects: () => new ReadableStream({ start(c) { - c.error(new Error(`WorkerBackend: sync.fetchObjects must not be called`)); + c.error(new Error(`WorkerShellBackend: sync.fetchObjects must not be called`)); }, }), pushObjects: () => refuse("pushObjects") as never, diff --git a/packages/computer/src/index.ts b/packages/computer/src/index.ts index 3ed3a2f6..2d521050 100644 --- a/packages/computer/src/index.ts +++ b/packages/computer/src/index.ts @@ -10,7 +10,7 @@ // one of them: // // import { CloudflareContainerBackend } from "@cloudflare/computer/backends/container"; -// import { WorkerBackend } from "@cloudflare/computer/backends/worker"; +// import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell"; // // TestBackend stays on the main entry because it's a thin // test-only fake with no payload. diff --git a/packages/computer/src/runtime/bridge.ts b/packages/computer/src/runtime/bridge.ts index 3ca127dc..60cfee49 100644 --- a/packages/computer/src/runtime/bridge.ts +++ b/packages/computer/src/runtime/bridge.ts @@ -266,7 +266,7 @@ export class WorkspaceRuntimeBridge extends RpcTarget { this.#requireWrite("Artifacts import"); if (!this.#allowArtifactNetwork) { throw new Error( - "Artifacts import requires IsolateJavaScriptBackend allowArtifactNetwork: true.", + "Artifacts import requires WorkerJavaScriptBackend allowArtifactNetwork: true.", ); } return this.#artifacts.import( @@ -295,7 +295,7 @@ export class WorkspaceRuntimeBridge extends RpcTarget { #requireGitNetwork(operation: string) { if (!this.#allowGitNetwork) { - throw new Error(`${operation} requires IsolateJavaScriptBackend allowGitNetwork: true.`); + throw new Error(`${operation} requires WorkerJavaScriptBackend allowGitNetwork: true.`); } } diff --git a/packages/computer/src/stub.test.ts b/packages/computer/src/stub.test.ts index e11d0d43..507acb28 100644 --- a/packages/computer/src/stub.test.ts +++ b/packages/computer/src/stub.test.ts @@ -384,7 +384,7 @@ describe("WorkspaceStub", () => { // bound — without the cascade, every getWorkspace() leaks two // sub-stubs on the peer side. // - // The WorkerBackend reaches the fs half via `stub().fs` and + // The WorkerShellBackend reaches the fs half via `stub().fs` and // depends on this cascade for its own disposal contract; pin // it here so a future refactor that drops the cascade fails // loudly. @@ -421,7 +421,7 @@ describe("WorkspaceStub", () => { }); it("stub().fs survives long enough for the backend to hand it off", async () => { - // The WorkerBackend pattern is: + // The WorkerShellBackend pattern is: // using stub = workspace.stub(); // await fetcher.exec(input, stub.fs); // The fs reference must remain a live RpcTarget for the diff --git a/packages/computer/tests/script-runner-worker.ts b/packages/computer/tests/script-runner-worker.ts index df705952..0d1fab2b 100644 --- a/packages/computer/tests/script-runner-worker.ts +++ b/packages/computer/tests/script-runner-worker.ts @@ -1,5 +1,5 @@ import { DurableObject, RpcTarget, WorkerEntrypoint } from "cloudflare:workers"; -import { IsolateJavaScriptBackend } from "../src/backends/javascript/index.js"; +import { WorkerJavaScriptBackend } from "../src/backends/worker-javascript/index.js"; import { createGitClient } from "../src/git/index.js"; import type { DurableObjectStorageLike, @@ -23,7 +23,7 @@ export class HostDO extends DurableObject { waitUntil: ctx.waitUntil.bind(ctx), git: createGitClient(), backends: [ - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: env.LOADER, maxLogBytes: 64, maxLogEvents: 4, @@ -86,7 +86,7 @@ export class HostDO extends DurableObject { }) { await this.#workspace.fs.mkdir("/workspace", { recursive: true }); const handle = await this.#workspace.runtime.exec(input.source, { - backend: "isolate-javascript", + backend: "worker-javascript", cwd: input.cwd, input: input.value, id: input.id, @@ -98,7 +98,7 @@ export class HostDO extends DurableObject { async startRuntime(input: { source: string; id: string }) { await this.#workspace.fs.mkdir("/workspace", { recursive: true }); const handle = await this.#workspace.runtime.exec(input.source, { - backend: "isolate-javascript", + backend: "worker-javascript", id: input.id, }); void handle.result().catch(() => undefined); @@ -108,7 +108,7 @@ export class HostDO extends DurableObject { async getRuntime(id: string, resume?: "tail") { try { const handle = await this.#workspace.runtime.getExec(id, { - backend: "isolate-javascript", + backend: "worker-javascript", encoding: "utf8", resume, }); @@ -122,11 +122,11 @@ export class HostDO extends DurableObject { } killRuntime(id: string) { - return this.#workspace.runtime.killExec(id, { backend: "isolate-javascript" }); + return this.#workspace.runtime.killExec(id, { backend: "worker-javascript" }); } disposeRuntime(id: string) { - return this.#workspace.runtime.disposeExec(id, { backend: "isolate-javascript" }); + return this.#workspace.runtime.disposeExec(id, { backend: "worker-javascript" }); } } diff --git a/packages/computer/tests/worker-backend-worker.ts b/packages/computer/tests/worker-backend-worker.ts index c2032462..1e210136 100644 --- a/packages/computer/tests/worker-backend-worker.ts +++ b/packages/computer/tests/worker-backend-worker.ts @@ -1,4 +1,4 @@ -// Workerd test harness for the WorkerBackend integration tests. +// Workerd test harness for the WorkerShellBackend integration tests. // // Three exports: // @@ -8,7 +8,7 @@ // Dynamic Worker; the loaded ShellWorker reaches it through // env.HOST.getWorkspace(). // - HostDO — the host Durable Object. Owns one Workspace whose -// only backend is a WorkerBackend dialing through env.LOADER. +// only backend is a WorkerShellBackend dialing through env.LOADER. // Exposes writeFile / readFile / exec methods the test calls // directly through the DO stub; the exec method goes through // workspace.runtime.exec which actually drives just-bash in a @@ -18,7 +18,7 @@ // SELF.fetch instead of holding a DO reference itself. import { DurableObject, WorkerEntrypoint } from "cloudflare:workers"; -import { WorkerBackend } from "../src/backends/worker/index.js"; +import { WorkerShellBackend } from "../src/backends/worker-shell/index.js"; import type { DurableObjectStorageLike, WorkspaceStub } from "../src/index.js"; import { Workspace } from "../src/index.js"; @@ -38,7 +38,7 @@ export class HostDO extends DurableObject { this.#workspace = new Workspace({ storage: ctx.storage as unknown as DurableObjectStorageLike, backends: [ - new WorkerBackend({ + new WorkerShellBackend({ loader: env.LOADER, workspace: { binding: "HOST", id: ctx.id.toString() }, ctx, diff --git a/packages/computer/tests/worker-backend.test.ts b/packages/computer/tests/worker-backend.test.ts index 24ae54b0..6030d352 100644 --- a/packages/computer/tests/worker-backend.test.ts +++ b/packages/computer/tests/worker-backend.test.ts @@ -1,4 +1,4 @@ -// End-to-end integration test for the WorkerBackend. +// End-to-end integration test for the WorkerShellBackend. // // Unlike worker.test.ts and entrypoint.test.ts (vitest/node, both // of which mock the runtime with fakes), this suite runs inside @@ -11,7 +11,7 @@ // │ │ HOST.get(id) │ // │ ├─────────────────────────►│ // │ │ │ Workspace.shell.exec -// │ │ ├──► WorkerBackend +// │ │ ├──► WorkerShellBackend // │ │ │ │ // │ │ │ │ env.LOADER.get(...) // │ │ │ │ .getEntrypoint("ShellWorker") @@ -78,7 +78,7 @@ async function exec( return res.json(); } -describe("WorkerBackend end-to-end", () => { +describe("WorkerShellBackend end-to-end", () => { // Per-test timeouts come from vitest.config.worker-backend.ts's // testTimeout: 60_000 — the Worker Loader cold start + the // shell.js parse + just-bash boot dominates the runtime. diff --git a/packages/computer/tests/wrangler.worker-backend.jsonc b/packages/computer/tests/wrangler.worker-backend.jsonc index 9db69a1e..0a751598 100644 --- a/packages/computer/tests/wrangler.worker-backend.jsonc +++ b/packages/computer/tests/wrangler.worker-backend.jsonc @@ -1,9 +1,9 @@ { - // Test-only worker for the WorkerBackend integration tests. Not + // Test-only worker for the WorkerShellBackend integration tests. Not // deployed. Wires: // // - HOST — a host Durable Object that owns a Workspace whose - // only backend is a WorkerBackend dialing through env.LOADER. + // only backend is a WorkerShellBackend dialing through env.LOADER. // - LOADER — the Worker Loader binding the backend hands to // env.LOADER.get(...). Miniflare implements the loader; the // loaded Worker is the bundled ShellWorker the workspace diff --git a/packages/computer/vitest.config.worker-backend.ts b/packages/computer/vitest.config.worker-backend.ts index 935cb625..ce1a53ab 100644 --- a/packages/computer/vitest.config.worker-backend.ts +++ b/packages/computer/vitest.config.worker-backend.ts @@ -1,4 +1,4 @@ -// Workerd-backed runner for the WorkerBackend integration tests. +// Workerd-backed runner for the WorkerShellBackend integration tests. // The default vitest config aliases ./proxy.js and cloudflare:workers // to throwing stubs so the node runner doesn't have to resolve them; // the worker backend's real wiring (Worker Loader binding, the From b662d71d250ad48bee3adfe8a50da22e01934b29 Mon Sep 17 00:00:00 2001 From: aron <263346377+aron-cf@users.noreply.github.com> Date: Fri, 31 Jul 2026 21:33:43 +0000 Subject: [PATCH 2/7] examples: rename worker example to worker-shell and update backend imports The worker example now imports WorkerShellBackend from the backends/worker-shell subpath, and the example itself moves from examples/worker to examples/worker-shell so its name matches the backend it demonstrates. Its package name, wrangler name, and R2 bucket gain the -shell suffix in step. The artifacts and think examples, which also construct the shell backend, follow the same import and class rename. The think-compare-runtimes mock target moves to the new subpath. --- examples/artifacts/src/index.ts | 11 +++++++---- .../think-compare-runtimes/worker/index.ts | 4 ++-- .../worker/think/agents.test.ts | 4 ++-- .../worker/think/agents.ts | 9 ++++++--- examples/think/src/agent.ts | 8 ++++---- examples/{worker => worker-shell}/.gitignore | 0 examples/{worker => worker-shell}/README.md | 18 +++++++++--------- examples/{worker => worker-shell}/package.json | 8 ++++---- .../seed/data/hello.txt | 0 examples/{worker => worker-shell}/src/index.ts | 10 +++++----- .../{worker => worker-shell}/tsconfig.json | 0 .../worker-configuration.d.ts | 0 .../{worker => worker-shell}/wrangler.jsonc | 8 ++++---- 13 files changed, 43 insertions(+), 37 deletions(-) rename examples/{worker => worker-shell}/.gitignore (100%) rename examples/{worker => worker-shell}/README.md (91%) rename examples/{worker => worker-shell}/package.json (54%) rename examples/{worker => worker-shell}/seed/data/hello.txt (100%) rename examples/{worker => worker-shell}/src/index.ts (97%) rename examples/{worker => worker-shell}/tsconfig.json (100%) rename examples/{worker => worker-shell}/worker-configuration.d.ts (100%) rename examples/{worker => worker-shell}/wrangler.jsonc (83%) diff --git a/examples/artifacts/src/index.ts b/examples/artifacts/src/index.ts index 95b5f549..f7f1bff7 100644 --- a/examples/artifacts/src/index.ts +++ b/examples/artifacts/src/index.ts @@ -18,7 +18,10 @@ import { WorkspaceServiceProxy, withWorkspace, } from "@cloudflare/computer"; -import { WorkerBackend, type WorkerBackendOptions } from "@cloudflare/computer/backends/worker"; +import { + WorkerShellBackend, + type WorkerShellBackendOptions, +} from "@cloudflare/computer/backends/worker-shell"; export { WorkspaceServiceProxy }; @@ -55,8 +58,8 @@ const SHARE_TOKEN_TTL = "24h"; // `self.env`. export class ArtifactCreator extends withWorkspace(class extends DurableObject {}, (self) => { const { ctx, env } = self as unknown as { ctx: DurableObjectState; env: Env }; - const workerBackendOptions: WorkerBackendOptions = { - loader: env.LOADER as unknown as WorkerBackendOptions["loader"], + const workerShellBackendOptions: WorkerShellBackendOptions = { + loader: env.LOADER as unknown as WorkerShellBackendOptions["loader"], workspace: { binding: "ArtifactCreator", id: ctx.id.toString() }, ctx, }; @@ -64,7 +67,7 @@ export class ArtifactCreator extends withWorkspace(class extends DurableObject; - LOADER: WorkerBackendOptions["loader"]; + LOADER: WorkerShellBackendOptions["loader"]; SANDBOX_TRANSPORT: "rpc"; CONTAINER_SLEEP_AFTER?: string; WARM_POOL_REFRESH_INTERVAL?: string; diff --git a/examples/think-compare-runtimes/worker/think/agents.test.ts b/examples/think-compare-runtimes/worker/think/agents.test.ts index 031f429f..0c5a57d5 100644 --- a/examples/think-compare-runtimes/worker/think/agents.test.ts +++ b/examples/think-compare-runtimes/worker/think/agents.test.ts @@ -74,8 +74,8 @@ vi.mock("@cloudflare/computer/backends/container", () => ({ }, })); -vi.mock("@cloudflare/computer/backends/worker", () => ({ - WorkerBackend: class { +vi.mock("@cloudflare/computer/backends/worker-shell", () => ({ + WorkerShellBackend: class { readonly id: string; constructor(options: Record) { diff --git a/examples/think-compare-runtimes/worker/think/agents.ts b/examples/think-compare-runtimes/worker/think/agents.ts index 73e01e3a..ef980d89 100644 --- a/examples/think-compare-runtimes/worker/think/agents.ts +++ b/examples/think-compare-runtimes/worker/think/agents.ts @@ -6,7 +6,10 @@ import { type WorkspaceStub, } from "@cloudflare/computer"; import { CloudflareContainerBackend } from "@cloudflare/computer/backends/container"; -import { WorkerBackend, type WorkerBackendOptions } from "@cloudflare/computer/backends/worker"; +import { + WorkerShellBackend, + type WorkerShellBackendOptions, +} from "@cloudflare/computer/backends/worker-shell"; import { getSandbox, type Sandbox as SandboxDO } from "@cloudflare/sandbox"; import { type ChunkContext, type StepContext, Think } from "@cloudflare/think"; import type { ToolSet } from "ai"; @@ -54,7 +57,7 @@ export interface RuntimeThinkAgentEnv { WorkspaceWarmPool: ContainerWarmPoolNamespace; CONTAINER_SLEEP_AFTER?: string; FUSE_MOUNT?: string; - LOADER: WorkerBackendOptions["loader"]; + LOADER: WorkerShellBackendOptions["loader"]; WARM_POOL_RESET_KEY?: string; } @@ -332,7 +335,7 @@ export class WorkspaceThinkAgent extends RuntimeThinkAgent { const workspace = new Workspace({ storage: this.#ctx.storage as unknown as DurableObjectStorageLike, backends: [ - new WorkerBackend({ + new WorkerShellBackend({ id: "shell", loader: this.env.LOADER, workspace: workspaceRef, diff --git a/examples/think/src/agent.ts b/examples/think/src/agent.ts index d0fa05f7..e9ae6122 100644 --- a/examples/think/src/agent.ts +++ b/examples/think/src/agent.ts @@ -14,7 +14,7 @@ * - `Think` (via the Durable Object base) hands us the message * store, agentic loop, and chat protocol. * - We own a `@cloudflare/computer.Workspace` with two backends: - * a WorkerBackend (`"shell"`) for fast just-bash text tooling and + * a WorkerShellBackend (`"shell"`) for fast just-bash text tooling and * a CloudflareContainerBackend (`"container"`) for full Linux * userland through computerd. This mirrors examples/container while * keeping the chat surface unchanged. @@ -36,14 +36,14 @@ import { CloudflareContainerBackend, withWorkspaceContainer, } from "@cloudflare/computer/backends/container"; -import { WorkerBackend } from "@cloudflare/computer/backends/worker"; +import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell"; import { createAITools } from "@cloudflare/computer/tools"; import { Think } from "@cloudflare/think"; import type { ToolSet } from "ai"; import { createWorkersAI } from "workers-ai-provider"; // Re-export so the runtime can build loopback bindings. The -// WorkerBackend reaches WorkspaceServiceProxy through +// WorkerShellBackend reaches WorkspaceServiceProxy through // `ctx.exports.WorkspaceServiceProxy(...)` so the in-isolate shell // can call back into the host workspace. WorkspaceProxy carries the // container's outbound /ws egress back to this DO. @@ -91,7 +91,7 @@ export class Assistant extends withWorkspaceContainer(AssistantBase) { override workspace = new Workspace({ storage: this.ctx.storage as unknown as DurableObjectStorageLike, backends: [ - new WorkerBackend({ + new WorkerShellBackend({ id: "shell", loader: this.env.LOADER, workspace: workspaceRef(this.ctx), diff --git a/examples/worker/.gitignore b/examples/worker-shell/.gitignore similarity index 100% rename from examples/worker/.gitignore rename to examples/worker-shell/.gitignore diff --git a/examples/worker/README.md b/examples/worker-shell/README.md similarity index 91% rename from examples/worker/README.md rename to examples/worker-shell/README.md index 5d8dee73..324e629c 100644 --- a/examples/worker/README.md +++ b/examples/worker-shell/README.md @@ -17,7 +17,7 @@ recipes work, just without the container. client ─► Worker /c//{file,exec} │ (DO RPC calls) ▼ - DO (ContainerExample) ──► Workspace ──► WorkerBackend + DO (ContainerExample) ──► Workspace ──► WorkerShellBackend │ │ env.LOADER.get(...) ▼ @@ -30,8 +30,8 @@ client ─► Worker /c//{file,exec} back to ContainerExample DO ``` -1. The DO constructs a `WorkerBackend` from - `@cloudflare/computer/backends/worker`, passing the Loader +1. The DO constructs a `WorkerShellBackend` from + `@cloudflare/computer/backends/worker-shell`, passing the Loader binding, a `{binding, id}` reference to itself, and `ctx`. The backend handles the rest internally: it builds the Loader callback (with the code-split shell modules + the seek-bzip @@ -47,7 +47,7 @@ client ─► Worker /c//{file,exec} survive structured clone into the loader's env; the binding-shape Fetcher the proxy produces does. 3. `ShellWorker` (shipped in - `@cloudflare/computer/backends/worker`) lives inside that + `@cloudflare/computer/backends/worker-shell`) lives inside that Dynamic Worker. Each `exec(input)` calls `env.HOST.getWorkspace()`, builds a fresh `Bash` around a `WorkspaceFsAdapter` wrapping the stub's `.fs`, runs the @@ -82,10 +82,10 @@ so the shell can't reach the public internet on its own. Identical to the container example. Seed once with: ```sh -npm run seed:r2:local --workspace @example/computer-worker +npm run seed:r2:local --workspace @example/computer-worker-shell # or after deploy -npm run seed:r2 --workspace @example/computer-worker +npm run seed:r2 --workspace @example/computer-worker-shell ``` ## HTTP surface @@ -103,7 +103,7 @@ POST /c//exec { command | argv, cwd?, encoding? } No Docker, no extra build step. The shell ships as a record of pre-bundled modules (`SHELL_MODULES`) inside -`@cloudflare/computer/backends/worker`; `WorkerBackend` spreads +`@cloudflare/computer/backends/worker-shell`; `WorkerShellBackend` spreads the whole record into the Loader callback internally so the DO constructor stays a three-line backend invocation. The entry module parses on cold start; the dynamic chunks (python, js-exec, @@ -111,7 +111,7 @@ sqlite, curl, html-to-markdown) stay cold until a script reaches for them. ```sh -npm run dev --workspace @example/computer-worker +npm run dev --workspace @example/computer-worker-shell ``` Smoke test (same recipes as the container example): @@ -138,7 +138,7 @@ examples/worker/ ``` Nothing else. The Dynamic Worker source ships from -`@cloudflare/computer/backends/worker` as a pre-built module +`@cloudflare/computer/backends/worker-shell` as a pre-built module string. ## Known limitations diff --git a/examples/worker/package.json b/examples/worker-shell/package.json similarity index 54% rename from examples/worker/package.json rename to examples/worker-shell/package.json index 0df4c423..196a803b 100644 --- a/examples/worker/package.json +++ b/examples/worker-shell/package.json @@ -1,15 +1,15 @@ { - "name": "@example/computer-worker", + "name": "@example/computer-worker-shell", "version": "0.0.0", "private": true, "type": "module", - "description": "Example Worker + Durable Object that runs just-bash inside a Dynamic Worker via @cloudflare/computer's WorkerBackend.", + "description": "Example Worker + Durable Object that runs just-bash inside a Dynamic Worker via @cloudflare/computer's WorkerShellBackend.", "scripts": { "dev": "wrangler dev", "deploy": "wrangler deploy", "typecheck": "tsc --noEmit", - "seed:r2": "wrangler r2 object put computer-worker-hello/hello.txt --file ./seed/data/hello.txt --remote", - "seed:r2:local": "wrangler r2 object put computer-worker-hello/hello.txt --file ./seed/data/hello.txt --local" + "seed:r2": "wrangler r2 object put computer-worker-shell-hello/hello.txt --file ./seed/data/hello.txt --remote", + "seed:r2:local": "wrangler r2 object put computer-worker-shell-hello/hello.txt --file ./seed/data/hello.txt --local" }, "dependencies": { "@cloudflare/computer": "*" diff --git a/examples/worker/seed/data/hello.txt b/examples/worker-shell/seed/data/hello.txt similarity index 100% rename from examples/worker/seed/data/hello.txt rename to examples/worker-shell/seed/data/hello.txt diff --git a/examples/worker/src/index.ts b/examples/worker-shell/src/index.ts similarity index 97% rename from examples/worker/src/index.ts rename to examples/worker-shell/src/index.ts index 7d6b0e65..6099511f 100644 --- a/examples/worker/src/index.ts +++ b/examples/worker-shell/src/index.ts @@ -1,7 +1,7 @@ // Example Worker + Durable Object that runs a Workspace whose // shell is a Dynamic Worker. // -// The DO holds a Workspace whose WorkerBackend dispatches every +// The DO holds a Workspace whose WorkerShellBackend dispatches every // shell.exec into a Dynamic Worker loaded through env.LOADER. // The Dynamic Worker reaches the host workspace through a // DurableObjectNamespace binding wired into its env, the same @@ -14,7 +14,7 @@ // client ──► Worker /c//{file,exec} // │ (DO RPC calls) // ▼ -// ContainerExample DO ──► Workspace ──► WorkerBackend +// ContainerExample DO ──► Workspace ──► WorkerShellBackend // │ // │ env.LOADER.get(...) // ▼ @@ -35,12 +35,12 @@ import { WorkspaceServiceProxy, withWorkspace, } from "@cloudflare/computer"; -import { WorkerBackend } from "@cloudflare/computer/backends/worker"; +import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell"; // Re-export so the runtime can wrap WorkspaceServiceProxy into a // loopback Fetcher binding. The DO reaches the wrapped class // through ctx.exports.WorkspaceServiceProxy(...) inside the -// WorkerBackend below. +// WorkerShellBackend below. export { WorkspaceServiceProxy }; // The mixin owns the Workspace and installs the prototype accessor @@ -56,7 +56,7 @@ export class ContainerExample extends withWorkspace(class extends DurableObject< // matches. Cast through unknown to bypass invariance. storage: ctx.storage as unknown as DurableObjectStorageLike, backends: [ - new WorkerBackend({ + new WorkerShellBackend({ loader: env.LOADER, workspace: { binding: "ContainerExample", id: ctx.id.toString() }, ctx, diff --git a/examples/worker/tsconfig.json b/examples/worker-shell/tsconfig.json similarity index 100% rename from examples/worker/tsconfig.json rename to examples/worker-shell/tsconfig.json diff --git a/examples/worker/worker-configuration.d.ts b/examples/worker-shell/worker-configuration.d.ts similarity index 100% rename from examples/worker/worker-configuration.d.ts rename to examples/worker-shell/worker-configuration.d.ts diff --git a/examples/worker/wrangler.jsonc b/examples/worker-shell/wrangler.jsonc similarity index 83% rename from examples/worker/wrangler.jsonc rename to examples/worker-shell/wrangler.jsonc index 6f2b0274..6413b91e 100644 --- a/examples/worker/wrangler.jsonc +++ b/examples/worker-shell/wrangler.jsonc @@ -6,13 +6,13 @@ // name, same routes, same R2 mount. The only difference is the // shell: a Dynamic Worker instead of a container running computerd. "$schema": "node_modules/wrangler/config-schema.json", - "name": "computer-worker-example", + "name": "computer-worker-shell-example", "main": "src/index.ts", "compatibility_date": "2026-05-26", "compatibility_flags": ["nodejs_compat", "experimental"], // Worker Loader binding. The DO calls env.LOADER.get(id, ...) - // to mint a Dynamic Worker that the WorkerBackend then + // to mint a Dynamic Worker that the WorkerShellBackend then // dispatches shell.exec into. "worker_loaders": [ { @@ -31,12 +31,12 @@ // R2 bucket mounted into every Workspace at /workspace/r2 via // R2Bucket(...). Seed it once with: - // npm run seed:r2 --workspace @example/computer-worker + // npm run seed:r2 --workspace @example/computer-worker-shell // which uploads ./seed/data/hello.txt to the bucket. "r2_buckets": [ { "binding": "Bucket", - "bucket_name": "computer-worker-hello" + "bucket_name": "computer-worker-shell-hello" } ], From 0b5d9a3a54f80d0cda6b6d4b8216fa6272311205 Mon Sep 17 00:00:00 2001 From: aron <263346377+aron-cf@users.noreply.github.com> Date: Fri, 31 Jul 2026 21:35:34 +0000 Subject: [PATCH 3/7] computer: update README for the renamed backends Reflect the worker-shell and worker-javascript names in the README's package listing, import examples, and the default backend id sentence. --- packages/computer/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/computer/README.md b/packages/computer/README.md index 907c239c..6851c090 100644 --- a/packages/computer/README.md +++ b/packages/computer/README.md @@ -21,20 +21,20 @@ Three backends ship today on tree-shakeable subpaths: daemon. Full Linux userland, real binaries, real network. The container owns its own SQLite-backed VFS and the package syncs the two stores across a capnweb WebSocket. -- [`@cloudflare/computer/backends/worker`](./src/backends/worker/) — +- [`@cloudflare/computer/backends/worker-shell`](./src/backends/worker-shell/) — runs the shell as [just-bash](https://github.com/vercel-labs/just-bash) inside a Dynamic Worker minted through `env.LOADER`. Every filesystem operation forwards back to the same Durable Object; no second store, no sync round trip. See [`docs/12_worker_backend.md`](../../docs/12_worker_backend.md) and `examples/worker/`. -- [`@cloudflare/computer/backends/javascript`](./src/backends/javascript/) — +- [`@cloudflare/computer/backends/worker-javascript`](./src/backends/worker-javascript/) — executes ECMAScript modules in fresh Dynamic Workers with structured input/results, durable relative imports, configured libraries, durable `node:fs/promises`, and trusted `ws:git` / `ws:artifacts` modules. See [`docs/17_isolate_javascript.md`](../../docs/17_isolate_javascript.md). -The isolate-JavaScript backend runs after `runtime.exec()` returns. Pass +The worker-JavaScript backend runs after `runtime.exec()` returns. Pass `waitUntil: ctx.waitUntil.bind(ctx)` to `Workspace` so completion remains attached to the Durable Object event. The backend refuses to connect without this lifecycle hook. It admits one execution at a time by default and bounds @@ -121,7 +121,7 @@ Worker backend: ```ts import { Workspace, WorkspaceServiceProxy } from "@cloudflare/computer"; -import { WorkerBackend } from "@cloudflare/computer/backends/worker"; +import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell"; import { DurableObject } from "cloudflare:workers"; export { WorkspaceServiceProxy }; @@ -130,7 +130,7 @@ export class WorkerExample extends DurableObject { #workspace = new Workspace({ storage: this.ctx.storage, backends: [ - new WorkerBackend({ + new WorkerShellBackend({ loader: this.env.LOADER, workspace: { binding: "WorkerExample", id: this.ctx.id.toString() }, ctx: this.ctx, @@ -218,7 +218,7 @@ an in-shell `artifacts` command. See A Workspace can carry more than one backend. Each backend registers under a stable selector `id` (defaulting to -`"isolate-shell"`, `"container-shell"`, or `"isolate-javascript"`; this is intentionally separate from the diagnostic `type`). +`"worker-shell"`, `"container-shell"`, or `"worker-javascript"`; this is intentionally separate from the diagnostic `type`). `runtime.exec` picks the default (the first backend in the list) unless the caller names one through `WorkspaceRuntimeExecOptions.backend`. Per-backend sync cursors live in dofs's `_vfs_watermark` table keyed by @@ -229,7 +229,7 @@ the other's cursors. const workspace = new Workspace({ storage: ctx.storage, backends: [ - new WorkerBackend({ + new WorkerShellBackend({ id: "shell", loader: env.LOADER, workspace: { binding: "AgentDO", id: ctx.id.toString() }, From 549380c83546856768cfd6a9943eddb719ee5e95 Mon Sep 17 00:00:00 2001 From: aron <263346377+aron-cf@users.noreply.github.com> Date: Fri, 31 Jul 2026 21:35:34 +0000 Subject: [PATCH 4/7] docs: update backend references to worker-shell and worker-javascript Rename WorkerBackend to WorkerShellBackend and IsolateJavaScriptBackend to WorkerJavaScriptBackend throughout the design docs, along with the backends/worker-shell and backends/worker-javascript import subpaths and the worker-shell and worker-javascript selector ids. --- docs/05_runtime_interface.md | 12 ++++++------ docs/09_tool_interface.md | 2 +- docs/10_project_layout.md | 4 ++-- docs/12_worker_backend.md | 16 ++++++++-------- docs/13_git_interface.md | 4 ++-- docs/14_assets_interface.md | 2 +- docs/15_artifacts_interface.md | 4 ++-- docs/16_code_execution.md | 22 +++++++++++----------- docs/17_isolate_javascript.md | 14 +++++++------- docs/18_runtime_migration.md | 10 +++++----- docs/README.md | 4 ++-- 11 files changed, 47 insertions(+), 47 deletions(-) diff --git a/docs/05_runtime_interface.md b/docs/05_runtime_interface.md index 510e6640..0d642c3c 100644 --- a/docs/05_runtime_interface.md +++ b/docs/05_runtime_interface.md @@ -62,13 +62,13 @@ interface WorkspaceRuntimeResult { } ``` -Command backends leave `value` unset. `isolate-javascript` uses `value` for the module's structured return value and reports a zero-entry completed sync. A command can complete while its post-command pull fails; in that case `sync.status` is `"pending"`, and a configured `SyncRetryScheduler` can durably retry the pull without rerunning the command. +Command backends leave `value` unset. `worker-javascript` uses `value` for the module's structured return value and reports a zero-entry completed sync. A command can complete while its post-command pull fails; in that case `sync.status` is `"pending"`, and a configured `SyncRetryScheduler` can durably retry the pull without rerunning the command. ## Backend routing ```ts await workspace.runtime.exec("grep -R TODO .", { - backend: "isolate-shell", + backend: "worker-shell", }); await workspace.runtime.exec("npm test", { @@ -80,7 +80,7 @@ await workspace.runtime.exec( import fs from "node:fs/promises"; export default async () => fs.readFile("/workspace/package.json", "utf8"); `, - { backend: "isolate-javascript" }, + { backend: "worker-javascript" }, ); ``` @@ -94,7 +94,7 @@ Command backends continue to use the existing synchronization bracket: push → spawn → events/result → pull ``` -A backend with `sync: "none"`, such as `isolate-shell`, shares the host store and reports zero push/pull counts. A Container has its own VFS and synchronizes changes before and after command execution. Fully draining either `result()` or the event stream completes the post-command pull before the stream closes. +A backend with `sync: "none"`, such as `worker-shell`, shares the host store and reports zero push/pull counts. A Container has its own VFS and synchronizes changes before and after command execution. Fully draining either `result()` or the event stream completes the post-command pull before the stream closes. Module backends use host capability calls against the authoritative Workspace and therefore require no push/pull round trip. @@ -102,8 +102,8 @@ Module backends use host capability calls against the authoritative Workspace an `container-shell` provides computerd's retained process log, replay, signals, and disposal. -`isolate-javascript` provides a Workspace-owned execution journal, retained result/events, host cancellation, and explicit disposal. Active Workers cannot be serialized across host restart; orphaned running records are reconciled to failed. +`worker-javascript` provides a Workspace-owned execution journal, retained result/events, host cancellation, and explicit disposal. Active Workers cannot be serialized across host restart; orphaned running records are reconciled to failed. -`isolate-shell` intentionally preserves one-call, buffered-result behavior in this release. It does not retain executions for later reattachment or disposal. `timeoutMs` and a concurrent `killExec()` for a caller-supplied execution ID cooperatively abort just-bash at statement boundaries; by the time an ordinary `exec()` promise returns, the command has already settled. Use the Container or JavaScript isolate when detached execution and retained lifecycle are required. +`worker-shell` intentionally preserves one-call, buffered-result behavior in this release. It does not retain executions for later reattachment or disposal. `timeoutMs` and a concurrent `killExec()` for a caller-supplied execution ID cooperatively abort just-bash at statement boundaries; by the time an ordinary `exec()` promise returns, the command has already settled. Use the Container or JavaScript isolate when detached execution and retained lifecycle are required. See [16. Execution runtime architecture](./16_code_execution.md) and [17. Isolate JavaScript](./17_isolate_javascript.md). diff --git a/docs/09_tool_interface.md b/docs/09_tool_interface.md index 125d2b45..eeec7ca2 100644 --- a/docs/09_tool_interface.md +++ b/docs/09_tool_interface.md @@ -55,7 +55,7 @@ When assigning the same instance to `Think.workspace`, construct it with `useThi const workspace = new Workspace({ storage: ctx.storage, backends: [ - new WorkerBackend({ id: "shell", /* ... */ }), + new WorkerShellBackend({ id: "shell", /* ... */ }), new CloudflareContainerBackend({ id: "container", /* ... */ }), ], }); diff --git a/docs/10_project_layout.md b/docs/10_project_layout.md index 13bd1204..0ca1546a 100644 --- a/docs/10_project_layout.md +++ b/docs/10_project_layout.md @@ -199,7 +199,7 @@ Runnable examples live at the repo root, not inside any package: ``` examples/ ├── container/ # Reference container image for computerd -├── worker/ # WorkerBackend example +├── worker-shell/ # WorkerShellBackend example ├── code/ # workspace.runtime with Worker and Container shells └── think/ # @cloudflare/think integration ``` @@ -210,7 +210,7 @@ so each example can declare its own dependencies and scripts. ## Testing - **Unit tests live next to source.** Packages follow the `foo.ts` + `foo.test.ts` convention. -- **Workerd integration tests** for WorkerBackend, Workspace RPC, and `workspace.runtime` live in `packages/computer/tests/` with dedicated Vitest and Wrangler configuration. +- **Workerd integration tests** for WorkerShellBackend, Workspace RPC, and `workspace.runtime` live in `packages/computer/tests/` with dedicated Vitest and Wrangler configuration. - **Container and load harness tests** live in `packages/computer/test-harness/`: - `end-to-end.test.ts` — DO ↔ container round-trip - `shell.test.ts` — shell surface against a real backend diff --git a/docs/12_worker_backend.md b/docs/12_worker_backend.md index 9ee30ed8..b70e896e 100644 --- a/docs/12_worker_backend.md +++ b/docs/12_worker_backend.md @@ -2,7 +2,7 @@ > [!NOTE] > This doc reflects shipped code in -> `packages/computer/src/backends/worker/`. The example deployment +> `packages/computer/src/backends/worker-shell/`. The example deployment > lives at `examples/worker/`. The worker backend is the second `WorkspaceBackend` shape the @@ -17,7 +17,7 @@ Import via the sub-path so the bundled just-bash payload tree-shakes out of consumers that don't use it: ```ts -import { WorkerBackend } from "@cloudflare/computer/backends/worker"; +import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell"; ``` ## When to reach for it @@ -32,7 +32,7 @@ isolate that boots instantly, scales out cheaply, and has no container lifecycle. The shell is the just-bash interpreter; the supported command set is broad (`cat`, `grep`, `awk`, `sed`, `jq`, `sort`) but not the full Linux userland. JavaScript modules run through the -[`isolate-javascript` backend](./17_isolate_javascript.md), not through just-bash's +[`worker-javascript` backend](./17_isolate_javascript.md), not through just-bash's Node-only language commands. Filesystem operations forward into the same SQLite store as the container backend, so the storage shape, mount rules, and read-only enforcement are unchanged. @@ -55,7 +55,7 @@ Reach for the container backend when the agent runs `npm`, a real language runti agent code │ Workers RPC ▼ -host DO ─── Workspace ─── WorkerBackend +host DO ─── Workspace ─── WorkerShellBackend │ │ env.LOADER.get(loaderId, codeCallback) │ .getEntrypoint("ShellWorker") @@ -158,7 +158,7 @@ they already handle. ## Fetcher factory escape hatch -`WorkerBackend` is source-agnostic. The common case takes +`WorkerShellBackend` is source-agnostic. The common case takes `{ loader, workspace, ctx }` and builds the loader callback itself. For deployments that need a different Fetcher source — a Workers service binding, a Workers-for-Platforms dispatch @@ -219,7 +219,7 @@ export class MyAgent extends DurableObject { storage: ctx.storage, sessionId: ctx.id.toString(), artifacts: { binding: env.ARTIFACTS }, - backends: [new WorkerBackend(/* ... */)], + backends: [new WorkerShellBackend(/* ... */)], }); } } @@ -250,7 +250,7 @@ network-bound `git` subcommands do. See `/c//file/...` and `/c//exec` routes the container example also exposes). - No Dockerfile, no build script. The shell bundle ships with - `@cloudflare/computer/backends/worker` as `SHELL_MODULES` + `@cloudflare/computer/backends/worker-shell` as `SHELL_MODULES` (a record of module name → source covering the entry plus every code-split chunk); the backend hands the whole record to the Loader callback itself. @@ -258,7 +258,7 @@ network-bound `git` subcommands do. See The DO's backend wiring fits in three lines: ```ts -new WorkerBackend({ +new WorkerShellBackend({ loader: env.LOADER, workspace: { binding: "ContainerExample", id: ctx.id.toString() }, ctx, diff --git a/docs/13_git_interface.md b/docs/13_git_interface.md index 45bf2b28..9996168b 100644 --- a/docs/13_git_interface.md +++ b/docs/13_git_interface.md @@ -3,7 +3,7 @@ > [!NOTE] > This doc describes shipped code in `packages/computer/src/git/` > and the `git` custom command in -> `packages/computer/src/backends/worker/`. Everything below +> `packages/computer/src/backends/worker-shell/`. Everything below > works today. `workspace.git` is a major typed surface on `Workspace`, alongside `fs`, `runtime`, Assets, and Artifacts. It is opt-in: pass `createGitClient()` from `@cloudflare/computer/git` as `WorkspaceOptions.git` to enable it. Git runs every operation against the local SQLite-backed VFS through `isomorphic-git`, so a @@ -1068,7 +1068,7 @@ commands receive the live host stub the shell already reached, so they share its lifetime without refetching. ```ts -import { ShellWorker, defineGitCommand } from "@cloudflare/computer/backends/worker"; +import { ShellWorker, defineGitCommand } from "@cloudflare/computer/backends/worker-shell"; import { type CustomCommand } from "just-bash"; class MyShell extends ShellWorker { diff --git a/docs/14_assets_interface.md b/docs/14_assets_interface.md index ae7a773e..3ab9d1d9 100644 --- a/docs/14_assets_interface.md +++ b/docs/14_assets_interface.md @@ -34,7 +34,7 @@ client when constructing the `Workspace`: ```ts const ws = new Workspace({ storage: ctx.storage, - backends: [new WorkerBackend(/* ... */)], + backends: [new WorkerShellBackend(/* ... */)], assets: (ws) => createAssets({ ws, bucket: env.ASSETS, s3: { bucket: "agent-assets" }, env }), }); ``` diff --git a/docs/15_artifacts_interface.md b/docs/15_artifacts_interface.md index 541eaf5e..a75f5697 100644 --- a/docs/15_artifacts_interface.md +++ b/docs/15_artifacts_interface.md @@ -3,7 +3,7 @@ > [!NOTE] > This doc describes shipped code in > `packages/computer/src/artifacts/` and the `artifacts` custom -> command in `packages/computer/src/backends/worker/`. +> command in `packages/computer/src/backends/worker-shell/`. [Cloudflare Artifacts](https://developers.cloudflare.com/artifacts/) is versioned, Git-speaking repository storage. A Worker reaches it @@ -250,7 +250,7 @@ export class MyAgent extends DurableObject { storage: ctx.storage, sessionId: ctx.id.toString(), artifacts: { binding: env.ARTIFACTS }, - backends: [new WorkerBackend(/* ... */)], + backends: [new WorkerShellBackend(/* ... */)], }); } } diff --git a/docs/16_code_execution.md b/docs/16_code_execution.md index a10c42e8..26371512 100644 --- a/docs/16_code_execution.md +++ b/docs/16_code_execution.md @@ -16,8 +16,8 @@ The selected backend defines how it interprets `source`. | Backend | Source language | Intended use | | --- | --- | --- | | `container-shell` | shell command | Full Linux, native binaries, installed packages, processes | -| `isolate-shell` | just-bash command | Fast text tools and Workspace Git without a Container | -| `isolate-javascript` | ECMAScript module | Isolated structured JavaScript with trusted Workspace modules | +| `worker-shell` | just-bash command | Fast text tools and Workspace Git without a Container | +| `worker-javascript` | ECMAScript module | Isolated structured JavaScript with trusted Workspace modules | Applications may register additional command or module backends under their own IDs. Backend IDs are part of the execution contract: changing the backend may change the source language. @@ -26,19 +26,19 @@ Applications may register additional command or module backends under their own ```ts const handle = await workspace.runtime.exec(source, { id: "build-1", - backend: "isolate-javascript", + backend: "worker-javascript", }); handle.id; await handle.kill(); const resumed = await workspace.runtime.getExec("build-1", { - backend: "isolate-javascript", + backend: "worker-javascript", resume: "full", }); await workspace.runtime.disposeExec("build-1", { - backend: "isolate-javascript", + backend: "worker-javascript", }); ``` @@ -59,9 +59,9 @@ interface WorkspaceRuntimeResult { Command backends leave `value` unset. Module backends use it for their structured return value. -`container-shell` retains the existing computerd process lifecycle. `isolate-javascript` keeps an execution journal in the Workspace database and retains events/results until `disposeExec`. Active isolate cancellation is host-driven by disposing the child Worker. An execution left running across a Workspace host restart is reconciled to failed because a live Worker capability cannot be serialized into SQLite. +`container-shell` retains the existing computerd process lifecycle. `worker-javascript` keeps an execution journal in the Workspace database and retains events/results until `disposeExec`. Active isolate cancellation is host-driven by disposing the child Worker. An execution left running across a Workspace host restart is reconciled to failed because a live Worker capability cannot be serialized into SQLite. -`isolate-shell` intentionally retains its existing behavior in this release: it buffers a just-bash call to completion, does not retain cross-request events, and cannot reattach by ID. Callers that require supervised process behavior should use `container-shell`; callers that require a managed isolate should use `isolate-javascript`. +`worker-shell` intentionally retains its existing behavior in this release: it buffers a just-bash call to completion, does not retain cross-request events, and cannot reattach by ID. Callers that require supervised process behavior should use `container-shell`; callers that require a managed isolate should use `worker-javascript`. ## Backend authority @@ -70,14 +70,14 @@ There is no general `workspace.scope()` abstraction. Backend construction fixes For different authority levels, configure distinct backend instances: ```ts -new IsolateJavaScriptBackend({ - id: "isolate-javascript-readonly", +new WorkerJavaScriptBackend({ + id: "worker-javascript-readonly", loader: env.LOADER, access: "read", }); -new IsolateJavaScriptBackend({ - id: "isolate-javascript", +new WorkerJavaScriptBackend({ + id: "worker-javascript", loader: env.LOADER, access: "read-write", }); diff --git a/docs/17_isolate_javascript.md b/docs/17_isolate_javascript.md index dec08478..618445ef 100644 --- a/docs/17_isolate_javascript.md +++ b/docs/17_isolate_javascript.md @@ -1,16 +1,16 @@ # Isolate JavaScript runtime -`IsolateJavaScriptBackend` runs an ECMAScript module in a fresh Cloudflare Dynamic Worker: +`WorkerJavaScriptBackend` runs an ECMAScript module in a fresh Cloudflare Dynamic Worker: ```ts import { Workspace } from "@cloudflare/computer"; -import { IsolateJavaScriptBackend } from "@cloudflare/computer/backends/javascript"; +import { WorkerJavaScriptBackend } from "@cloudflare/computer/backends/worker-javascript"; const workspace = new Workspace({ storage: ctx.storage, waitUntil: ctx.waitUntil.bind(ctx), backends: [ - new IsolateJavaScriptBackend({ + new WorkerJavaScriptBackend({ loader: env.LOADER, root: "/workspace", access: "read-write", @@ -40,7 +40,7 @@ const handle = await workspace.runtime.exec( } `, { - backend: "isolate-javascript", + backend: "worker-javascript", input: { value: 21 }, encoding: "utf8", }, @@ -70,7 +70,7 @@ await workspace.fs.writeFile( await workspace.runtime.exec( `import task from "./task.js"; export default task;`, { - backend: "isolate-javascript", + backend: "worker-javascript", cwd: "/workspace", input: { value: 42 }, }, @@ -96,7 +96,7 @@ Host calls have a caller-visible deadline, controlled by `maxHostCallMs` and def Bare imports are installed at backend construction, not passed on individual executions: ```ts -new IsolateJavaScriptBackend({ +new WorkerJavaScriptBackend({ loader: env.LOADER, modules: { "tar-stream": TAR_STREAM_BUNDLE, @@ -165,4 +165,4 @@ Console output is bounded but currently buffered in the Dynamic Worker and publi ## Trusted integrations -A host can configure additional reserved capability modules through `IsolateJavaScriptBackend.trustedModules`; these modules are fixed when the backend is constructed and cannot be supplied or replaced by caller source. +A host can configure additional reserved capability modules through `WorkerJavaScriptBackend.trustedModules`; these modules are fixed when the backend is constructed and cannot be supplied or replaced by caller source. diff --git a/docs/18_runtime_migration.md b/docs/18_runtime_migration.md index 75aec455..541a051a 100644 --- a/docs/18_runtime_migration.md +++ b/docs/18_runtime_migration.md @@ -10,22 +10,22 @@ This change is a breaking preview-API migration. Public execution now uses one r | `workspace.shell.get(id, options)` | `workspace.runtime.getExec(id, options)` | | `workspace.shell.kill(id, options)` | `workspace.runtime.killExec(id, options)` | | `workspace.shell.dispose(id, options)` | `workspace.runtime.disposeExec(id, options)` | -| `workspace.code` / script execution | `workspace.runtime.exec(source, { backend: "isolate-javascript", input })` | +| `workspace.code` / script execution | `workspace.runtime.exec(source, { backend: "worker-javascript", input })` | `WorkspaceShell` still exists internally to implement command backends. It is not a public Workspace property. ## Default backend IDs - Cloudflare Container: `container-shell` -- just-bash Dynamic Worker: `isolate-shell` -- ECMAScript Dynamic Worker: `isolate-javascript` +- just-bash Dynamic Worker: `worker-shell` +- ECMAScript Dynamic Worker: `worker-javascript` The first configured backend is the default for `runtime.exec()`. Pass `backend` explicitly at security boundaries. Routing is not authorization: trusted gateways must choose from a host-owned allowlist rather than accepting an arbitrary model-supplied backend ID. ## Source semantics -Command backends interpret the first argument as a shell command and reject structured `input`. `isolate-javascript` interprets it as an ECMAScript module and supports structured JSON-compatible input/results, durable relative modules, `node:fs/promises`, and host-owned trusted modules. +Command backends interpret the first argument as a shell command and reject structured `input`. `worker-javascript` interprets it as an ECMAScript module and supports structured JSON-compatible input/results, durable relative modules, `node:fs/promises`, and host-owned trusted modules. ## Lifecycle differences -Container command executions use the remote process journal and push/pull synchronization bracket. `isolate-shell` uses the documented limited one-call Worker lifecycle. `isolate-javascript` stores execution status and events in the Workspace database and supports replay, cancellation, disposal, and restart recovery. Completed filesystem and provider side effects are not rolled back when execution fails or is cancelled. +Container command executions use the remote process journal and push/pull synchronization bracket. `worker-shell` uses the documented limited one-call Worker lifecycle. `worker-javascript` stores execution status and events in the Workspace database and supports replay, cancellation, disposal, and restart recovery. Completed filesystem and provider side effects are not rolled back when execution fails or is cancelled. diff --git a/docs/README.md b/docs/README.md index d9cfccc2..e3aa030b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -44,8 +44,8 @@ The package ships several entrypoints: | --- | --- | | `@cloudflare/computer` | The Workspace facade, first-class `workspace.runtime`, stub types, the R2 mount, and proxy classes. | | `@cloudflare/computer/backends/container` | `CloudflareContainerBackend` and `withWorkspaceContainer`. Pulls in the computerd / capnweb sync plumbing. | -| `@cloudflare/computer/backends/worker` | `WorkerBackend` and the bundled just-bash command runtime. | -| `@cloudflare/computer/backends/javascript` | `IsolateJavaScriptBackend`, configured libraries, durable relative imports, `node:fs/promises`, and trusted `ws:git` / `ws:artifacts`. | +| `@cloudflare/computer/backends/worker-shell` | `WorkerShellBackend` and the bundled just-bash command runtime. | +| `@cloudflare/computer/backends/worker-javascript` | `WorkerJavaScriptBackend`, configured libraries, durable relative imports, `node:fs/promises`, and trusted `ws:git` / `ws:artifacts`. | | `@cloudflare/computer/git` | Opt-in isomorphic-git glue for working with checkouts inside the workspace. Bundled lazily, with `pako` replaced by Workers `node:zlib`, and kept out of the default `@cloudflare/computer` graph. | | `@cloudflare/computer/artifacts` | `createArtifact`, a session-scoped facade over the Cloudflare Artifacts Workers binding, plus its argv CLI. | | `@cloudflare/computer/tools` | AI SDK tools for agents: read, write, edit, ls, optional exec, and optional publish. | From 7ec3962c378507c07ce16c9ab531a87688da7656 Mon Sep 17 00:00:00 2001 From: aron <263346377+aron-cf@users.noreply.github.com> Date: Sat, 1 Aug 2026 16:53:51 +0000 Subject: [PATCH 5/7] docs: correct stale worker example paths after the backend rename Several documents still pointed at the pre-rename example directory and source tree. Update the project layout tree to worker-shell and worker-javascript, and repoint the worker backend doc and the package README at examples/worker-shell. --- docs/10_project_layout.md | 4 ++-- docs/12_worker_backend.md | 4 ++-- examples/worker-shell/README.md | 4 ++-- packages/computer/README.md | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/10_project_layout.md b/docs/10_project_layout.md index 0ca1546a..27e5b33f 100644 --- a/docs/10_project_layout.md +++ b/docs/10_project_layout.md @@ -58,8 +58,8 @@ packages/computer/ │ ├── backend.ts # Command backend interface │ ├── backends/ │ │ ├── container/ # Cloudflare Container + computerd backend -│ │ ├── worker/ # Dynamic Worker + just-bash backend -│ │ ├── javascript/ # Dynamic Worker ECMAScript backend +│ │ ├── worker-shell/ # Dynamic Worker + just-bash shell backend +│ │ ├── worker-javascript/ # Dynamic Worker ECMAScript module backend │ │ └── test.ts # In-process test backend │ ├── proxy.ts # WorkspaceProxy │ ├── proxy-stub.ts # Client-side stub plumbing diff --git a/docs/12_worker_backend.md b/docs/12_worker_backend.md index b70e896e..d258349c 100644 --- a/docs/12_worker_backend.md +++ b/docs/12_worker_backend.md @@ -3,7 +3,7 @@ > [!NOTE] > This doc reflects shipped code in > `packages/computer/src/backends/worker-shell/`. The example deployment -> lives at `examples/worker/`. +> lives at `examples/worker-shell/`. The worker backend is the second `WorkspaceBackend` shape the package ships. It pairs a Workspace with a @@ -241,7 +241,7 @@ network-bound `git` subcommands do. See ## Example -`examples/worker/` is a single wrangler project that mirrors +`examples/worker-shell/` is a single wrangler project that mirrors `examples/container/` beat for beat: - One `wrangler.jsonc` with the Durable Object, an R2 mount at diff --git a/examples/worker-shell/README.md b/examples/worker-shell/README.md index 324e629c..ee1e0fb9 100644 --- a/examples/worker-shell/README.md +++ b/examples/worker-shell/README.md @@ -1,4 +1,4 @@ -# worker example +# worker-shell example > [!IMPORTANT] > **PREVIEW ONLY** This package is provided as a preview for feedback only. @@ -132,7 +132,7 @@ curl -X POST http://127.0.0.1:8787/c/demo/exec \ ## Layout ``` -examples/worker/ +examples/worker-shell/ wrangler.jsonc Worker + DO + worker_loaders binding src/index.ts Worker handler + DO (ContainerExample) ``` diff --git a/packages/computer/README.md b/packages/computer/README.md index 6851c090..e3dc4e5e 100644 --- a/packages/computer/README.md +++ b/packages/computer/README.md @@ -27,7 +27,7 @@ Three backends ship today on tree-shakeable subpaths: filesystem operation forwards back to the same Durable Object; no second store, no sync round trip. See [`docs/12_worker_backend.md`](../../docs/12_worker_backend.md) and - `examples/worker/`. + `examples/worker-shell/`. - [`@cloudflare/computer/backends/worker-javascript`](./src/backends/worker-javascript/) — executes ECMAScript modules in fresh Dynamic Workers with structured input/results, durable relative imports, configured libraries, durable From 16365d60a247e13c058a04c28742265db4798f5e Mon Sep 17 00:00:00 2001 From: aron <263346377+aron-cf@users.noreply.github.com> Date: Mon, 3 Aug 2026 09:49:52 +0000 Subject: [PATCH 6/7] examples, docs: repoint artifacts and prose at the renamed worker example The artifacts example clones this repo and copies EXAMPLE_PATH into the workspace at runtime; it still pointed at examples/worker, which the rename moved to examples/worker-shell, so the copy would fail once the rename landed. Update EXAMPLE_PATH and the surrounding prose, the root README link, AGENTS.md, and the artifacts example's own README, package.json, and wrangler.jsonc. --- AGENTS.md | 2 +- README.md | 2 +- examples/artifacts/README.md | 2 +- examples/artifacts/package.json | 2 +- examples/artifacts/src/index.ts | 6 +++--- examples/artifacts/wrangler.jsonc | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index bfb688bd..8ad024b6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -173,6 +173,6 @@ file and add it to the list above. backed tests only run on Linux and are skipped elsewhere automatically. - **Examples are real consumers.** `examples/think`, - `examples/container`, and `examples/worker` exercise the public + `examples/container`, and `examples/worker-shell` exercise the public surface. If you change a public API, update them in the same change. diff --git a/README.md b/README.md index 8455fc12..72a8d80b 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ To see the pieces working together, start with the examples: - [`examples/container`](examples/container) — runs `computerd` inside a container, mounts a workspace, and talks to a Durable Object over capnweb. -- [`examples/worker`](examples/worker) — same HTTP surface as the +- [`examples/worker-shell`](examples/worker-shell) — same HTTP surface as the container example, but the shell runs in a Dynamic Worker loaded through `env.LOADER`. No container. - [`examples/think`](examples/think) — an agent that uses the diff --git a/examples/artifacts/README.md b/examples/artifacts/README.md index 6adfbf55..9bdc9396 100644 --- a/examples/artifacts/README.md +++ b/examples/artifacts/README.md @@ -35,7 +35,7 @@ The Worker endpoint owns the orchestration. The durable object stays minimal: it `POST /create` does the following through `ws.runtime.exec(...)`: 1. clones `https://github.com/cloudflare/computer` into `/workspace/-source`; -2. copies `/workspace/-source/examples/worker` to `/workspace/`; +2. copies `/workspace/-source/examples/worker-shell` to `/workspace/`; 3. rewrites the copied Worker name with `sed`; 4. initializes and commits the generated project with the shell `git` command; 5. runs `artifacts create --remote origin --force` — one command that creates the session-scoped Artifact repo, mints a write token, and registers the credentialed remote as `origin`; diff --git a/examples/artifacts/package.json b/examples/artifacts/package.json index 82966a7a..a6044740 100644 --- a/examples/artifacts/package.json +++ b/examples/artifacts/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "type": "module", - "description": "Example Worker that turns examples/worker into a cloneable Cloudflare Artifacts repo through @cloudflare/computer.", + "description": "Example Worker that turns examples/worker-shell into a cloneable Cloudflare Artifacts repo through @cloudflare/computer.", "scripts": { "dev": "wrangler dev", "deploy": "wrangler deploy", diff --git a/examples/artifacts/src/index.ts b/examples/artifacts/src/index.ts index f7f1bff7..3e576fe5 100644 --- a/examples/artifacts/src/index.ts +++ b/examples/artifacts/src/index.ts @@ -1,7 +1,7 @@ // Minimal Artifacts example. // // POST /create { "name": "my-worker" } builds a fresh copy of -// examples/worker, rewrites its Worker name, publishes it to a new +// examples/worker-shell, rewrites its Worker name, publishes it to a new // Cloudflare Artifacts repo, and returns a read-only clone URL. // The Worker owns the endpoint logic. The durable object stays // minimal: it constructs the Workspace with `this` so the Worker can @@ -48,7 +48,7 @@ interface ArtifactCreateOutput { const WORKSPACE_ROOT = "/workspace"; const SOURCE_REPO = "https://github.com/cloudflare/computer"; -const EXAMPLE_PATH = "examples/worker"; +const EXAMPLE_PATH = "examples/worker-shell"; const GIT_REMOTE = "origin"; const SHARE_TOKEN_TTL = "24h"; @@ -87,7 +87,7 @@ export default { " -H 'content-type: application/json' \\", ' -d \'{"name":"my-worker"}\'', "", - "Builds examples/worker in a Workspace and pushes it to a", + "Builds examples/worker-shell in a Workspace and pushes it to a", "new Cloudflare Artifacts repo.", ].join("\n"), { headers: { "content-type": "text/plain; charset=utf-8" } }, diff --git a/examples/artifacts/wrangler.jsonc b/examples/artifacts/wrangler.jsonc index 545963df..9c41456d 100644 --- a/examples/artifacts/wrangler.jsonc +++ b/examples/artifacts/wrangler.jsonc @@ -1,6 +1,6 @@ { // Artifacts example. POST /create { "name": "my-worker" } - // generates examples/worker in a Workspace and publishes it to a + // generates examples/worker-shell in a Workspace and publishes it to a // Cloudflare Artifacts repo. "$schema": "node_modules/wrangler/config-schema.json", "name": "computer-artifacts-example", From ce6754b481f50d2f974d3de5dba8e265ac67467f Mon Sep 17 00:00:00 2001 From: aron <263346377+aron-cf@users.noreply.github.com> Date: Mon, 3 Aug 2026 10:30:09 +0000 Subject: [PATCH 7/7] computer: sync the lockfile with the renamed worker example package Renaming the example package from @example/computer-worker to @example/computer-worker-shell left package-lock.json referencing the old name, so npm ci failed with an out-of-sync lockfile. Regenerate the lockfile so a clean install resolves the renamed package. --- package-lock.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4137a7cc..86df3865 100644 --- a/package-lock.json +++ b/package-lock.json @@ -220,8 +220,8 @@ "dev": true, "license": "MIT OR Apache-2.0" }, - "examples/worker": { - "name": "@example/computer-worker", + "examples/worker-shell": { + "name": "@example/computer-worker-shell", "version": "0.0.0", "dependencies": { "@cloudflare/computer": "*" @@ -232,7 +232,7 @@ "wrangler": "^4.107.1" } }, - "examples/worker/node_modules/@cloudflare/workers-types": { + "examples/worker-shell/node_modules/@cloudflare/workers-types": { "version": "4.20260702.1", "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260702.1.tgz", "integrity": "sha512-mOhf5TUEB1m2vPrxtqoIGfz0fUC9xyxRDx5gWHy5s+OCo6dcV+g7wI1R7gYCMFohhqF/2y2xeKVwMwCJjfn/WA==", @@ -2822,8 +2822,8 @@ "resolved": "examples/tutorial", "link": true }, - "node_modules/@example/computer-worker": { - "resolved": "examples/worker", + "node_modules/@example/computer-worker-shell": { + "resolved": "examples/worker-shell", "link": true }, "node_modules/@exodus/bytes": {