Skip to content

Commit 860ef69

Browse files
committed
computer: Remove Think compatibility
Delete the useThink option, root-level filesystem adapters, compatibility types, and Workers RPC flag. Think integrations now consume workspace.fs and the Computer tool set directly.
1 parent d6a67a7 commit 860ef69

7 files changed

Lines changed: 29 additions & 317 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cloudflare/computer": minor
3+
---
4+
5+
Remove the deprecated `useThink` compatibility layer. Think integrations must use `workspace.fs` and `@cloudflare/computer/tools` directly.

packages/computer/src/client.test.ts

Lines changed: 16 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
import { SQLiteTestStorage } from "@cloudflare/dofs/testing";
1111
import { describe, expect, it } from "vitest";
1212

13-
import { getWorkspace, type WorkspaceClient } from "./client.js";
13+
import { getWorkspace } from "./client.js";
1414
import { WORKSPACE, type WorkspaceStubHost } from "./with-workspace.js";
15-
import { type ThinkWorkspaceCompatibility, Workspace } from "./workspace.js";
15+
import { Workspace } from "./workspace.js";
1616

1717
interface ExecCall {
1818
command: string;
@@ -87,7 +87,6 @@ function fakeRemote(): {
8787
let disposed = false;
8888
const stub = {
8989
fs: { marker: "fs" },
90-
useThink: false,
9190
git: { marker: "git" },
9291
assets: undefined,
9392
artifacts: { marker: "artifacts" },
@@ -104,14 +103,20 @@ function fakeRemote(): {
104103
};
105104
}
106105

107-
function fakeBrokenRemote(): {
106+
function fakeLegacyFlagRemote(): {
108107
host: WorkspaceStubHost;
109108
disposed: () => boolean;
110109
} {
110+
const { runtime } = fakeRuntime(true);
111111
let disposed = false;
112112
const stub = {
113+
fs: { marker: "fs" },
114+
runtime,
115+
git: { marker: "git" },
116+
assets: undefined,
117+
artifacts: { marker: "artifacts" },
113118
get useThink(): boolean {
114-
throw new Error("compatibility lookup failed");
119+
throw new Error("legacy compatibility flag was read");
115120
},
116121
[Symbol.dispose]() {
117122
disposed = true;
@@ -177,29 +182,15 @@ describe("getWorkspace — remote dispatch", () => {
177182
expect(disposed()).toBe(true);
178183
});
179184

180-
it("disposes the remote stub when client initialization fails", async () => {
181-
const { host, disposed } = fakeBrokenRemote();
185+
it("does not inspect the removed remote useThink flag", async () => {
186+
const { host, disposed } = fakeLegacyFlagRemote();
182187

183-
await expect(getWorkspace(host)).rejects.toThrow("compatibility lookup failed");
188+
const ws = await getWorkspace(host);
189+
expect(ws.fs).toEqual({ marker: "fs" });
190+
expect(disposed()).toBe(false);
191+
ws[Symbol.dispose]();
184192
expect(disposed()).toBe(true);
185193
});
186-
187-
it("adds Think compatibility when the remote Workspace enables it", async () => {
188-
const workspace = new Workspace({
189-
storage: new SQLiteTestStorage(),
190-
useThink: true,
191-
});
192-
await workspace.fs.writeFile("/notes.txt", "hello");
193-
const host: WorkspaceStubHost = {
194-
__getWorkspaceStub: () => Promise.resolve(workspace.stub()),
195-
};
196-
197-
const client = (await getWorkspace(host)) as WorkspaceClient & ThinkWorkspaceCompatibility;
198-
199-
expect(client).toHaveProperty("readFile");
200-
await expect(client.readFile("/notes.txt")).resolves.toBe("hello");
201-
await expect(client.readFile("/missing.txt")).resolves.toBeNull();
202-
});
203194
});
204195

205196
describe("getWorkspace — local dispatch", () => {
@@ -216,20 +207,6 @@ describe("getWorkspace — local dispatch", () => {
216207
const ws = await getWorkspace(host);
217208
expect(() => ws[Symbol.dispose]()).not.toThrow();
218209
});
219-
220-
it("adds Think compatibility when the local Workspace enables it", async () => {
221-
const workspace = new Workspace({
222-
storage: new SQLiteTestStorage(),
223-
useThink: true,
224-
});
225-
const host = { [WORKSPACE]: workspace };
226-
const { runtime } = fakeRuntime();
227-
Object.defineProperty(workspace, "runtime", { get: () => runtime });
228-
229-
const client = (await getWorkspace(host)) as WorkspaceClient & ThinkWorkspaceCompatibility;
230-
231-
expect(client).toHaveProperty("readFile");
232-
});
233210
});
234211

235212
describe("client runtime.exec — tagged template form", () => {

packages/computer/src/client.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,7 @@ import { decodeRuntimeEvents } from "./runtime/wire.js";
4242
import { type ShellValue, sh } from "./sh.js";
4343
import type { ExecEncoding } from "./shell.js";
4444
import { WORKSPACE, type WorkspaceStubHost } from "./with-workspace.js";
45-
import {
46-
createThinkCompatibility,
47-
type ThinkWorkspaceCompatibility,
48-
Workspace,
49-
} from "./workspace.js";
45+
import { Workspace } from "./workspace.js";
5046

5147
// The remote runtime handle stub: a result / stream / kill surface
5248
// carried across Workers RPC.
@@ -315,7 +311,7 @@ function withExecutionId(
315311
// `fs`, `git`, `artifacts`, and `assets` are the underlying surface's
316312
// members, passed through. The filesystem stub mirrors the local
317313
// filesystem, so it also serves as the common client type.
318-
export interface WorkspaceClient extends Partial<ThinkWorkspaceCompatibility> {
314+
export interface WorkspaceClient {
319315
readonly fs: WorkspaceFilesystem;
320316
readonly runtime: WorkspaceRuntimeClient;
321317
// biome-ignore lint/suspicious/noExplicitAny: git type differs local vs remote
@@ -332,7 +328,6 @@ function makeClient(
332328
surface: any,
333329
rehydrate: (handle: unknown, metadata?: RuntimeHandleMetadata) => unknown,
334330
dispose: () => void,
335-
useThink: boolean,
336331
): WorkspaceClient {
337332
const runtime = makeRuntimeClient(
338333
surface.runtime as UnderlyingRuntime,
@@ -354,7 +349,6 @@ function makeClient(
354349
},
355350
[Symbol.dispose]: dispose,
356351
};
357-
if (useThink) Object.assign(client, createThinkCompatibility(client.fs));
358352
return client;
359353
}
360354

@@ -383,7 +377,6 @@ export async function getWorkspace(handle: WorkspaceHandle): Promise<WorkspaceCl
383377
// Local handle is already a host ExecHandle — pass it through.
384378
(h) => h,
385379
() => {},
386-
local.useThink,
387380
);
388381
}
389382
// Remote path: fetch the stub over RPC and delegate to it. Handle
@@ -397,7 +390,6 @@ export async function getWorkspace(handle: WorkspaceHandle): Promise<WorkspaceCl
397390
() => {
398391
(stub as { [Symbol.dispose]?: () => void })[Symbol.dispose]?.();
399392
},
400-
await stub.useThink,
401393
);
402394
} catch (error) {
403395
(stub as { [Symbol.dispose]?: () => void })[Symbol.dispose]?.();

packages/computer/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ export {
9999
type SyncRetryIntent,
100100
type SyncRetryOptions,
101101
type SyncRetryScheduler,
102-
type ThinkWorkspaceCompatibility,
103102
Workspace,
104103
type WorkspaceGitFactory,
105104
type WorkspaceOptions,

packages/computer/src/stub.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,6 @@ export class WorkspaceStub extends RpcTarget {
604604
readonly #git: WorkspaceGitStub;
605605
readonly #assets: WorkspaceAssetsStub | undefined;
606606
readonly #artifacts: WorkspaceArtifactsStub;
607-
readonly #useThink: boolean;
608607

609608
constructor(ws: Workspace) {
610609
super();
@@ -613,7 +612,6 @@ export class WorkspaceStub extends RpcTarget {
613612
this.#git = new WorkspaceGitStub(ws);
614613
this.#assets = ws.assets === undefined ? undefined : new WorkspaceAssetsStub(ws);
615614
this.#artifacts = new WorkspaceArtifactsStub(ws.artifacts);
616-
this.#useThink = ws.useThink;
617615
trackStub(this);
618616
}
619617

@@ -636,10 +634,6 @@ export class WorkspaceStub extends RpcTarget {
636634
return this.#fs;
637635
}
638636

639-
get useThink(): boolean {
640-
return this.#useThink;
641-
}
642-
643637
get runtime(): WorkspaceRuntimeStub {
644638
return this.#runtime;
645639
}

packages/computer/src/workspace.test.ts

Lines changed: 6 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,12 @@ import type { BackendHandle, WorkspaceBackend } from "./backend.js";
55
import { createGitClient } from "./git/index.js";
66
import type { WorkspaceModuleBackend } from "./runtime/types.js";
77
import { WorkspaceTransportError } from "./transport-failure.js";
8-
import { type ThinkWorkspaceCompatibility, Workspace } from "./workspace.js";
8+
import { Workspace } from "./workspace.js";
99

1010
function makeStorage(): SQLiteTestStorage {
1111
return new SQLiteTestStorage();
1212
}
1313

14-
function expectThinkWorkspace(
15-
ws: Workspace,
16-
): asserts ws is Workspace & ThinkWorkspaceCompatibility {
17-
expect(ws).toHaveProperty("readFile");
18-
expect(ws).toHaveProperty("readFileBytes");
19-
expect(ws).toHaveProperty("writeFile");
20-
expect(ws).toHaveProperty("readDir");
21-
expect(ws).toHaveProperty("glob");
22-
expect(ws).toHaveProperty("mkdir");
23-
expect(ws).toHaveProperty("rm");
24-
expect(ws).toHaveProperty("stat");
25-
}
26-
2714
// In-process fakes. We never spawn anything from the package
2815
// code; the backend's only contract is "produce a SyncRPC
2916
// stub that computerd would speak". A plain object is enough.
@@ -1463,49 +1450,15 @@ describe("Workspace transport-failure invalidation", () => {
14631450
]);
14641451
});
14651452
});
1466-
describe("Workspace Think compatibility", () => {
1467-
it("adds Think-compatible filesystem methods when useThink is true", async () => {
1453+
describe("Workspace compatibility surface", () => {
1454+
it("does not accept useThink or add root-level filesystem methods", () => {
14681455
const ws = new Workspace({
14691456
storage: makeStorage(),
1457+
// @ts-expect-error useThink was removed with the compatibility layer.
14701458
useThink: true,
1471-
now: () => 1_700_000_000_000,
1472-
});
1473-
1474-
expectThinkWorkspace(ws);
1475-
1476-
await ws.mkdir("/workspace/notes", { recursive: true });
1477-
await ws.writeFile("/workspace/notes/a.txt", "hello");
1478-
await ws.writeFile("/workspace/notes/b.md", "# title");
1479-
1480-
expect(await ws.readFile("/workspace/notes/a.txt")).toBe("hello");
1481-
expect(await ws.readFile("/workspace/missing.txt")).toBeNull();
1482-
expect(new TextDecoder().decode(await ws.readFileBytes("/workspace/notes/a.txt"))).toBe(
1483-
"hello",
1484-
);
1485-
expect(await ws.readFileBytes("/workspace/missing.txt")).toBeNull();
1486-
1487-
await expect(ws.stat("/workspace/notes/a.txt")).resolves.toMatchObject({
1488-
path: "/workspace/notes/a.txt",
1489-
name: "a.txt",
1490-
type: "file",
1491-
size: 5,
14921459
});
1493-
await expect(ws.stat("/workspace/missing.txt")).resolves.toBeNull();
1494-
1495-
await expect(ws.readDir("/workspace/notes", { limit: 1, offset: 1 })).resolves.toEqual([
1496-
expect.objectContaining({ path: "/workspace/notes/b.md", name: "b.md", type: "file" }),
1497-
]);
1498-
await expect(ws.glob("/workspace/notes/**/*.txt")).resolves.toEqual([
1499-
expect.objectContaining({ path: "/workspace/notes/a.txt", name: "a.txt", type: "file" }),
1500-
]);
1501-
1502-
await ws.rm("/workspace/notes/a.txt", { force: true });
1503-
expect(await ws.readFile("/workspace/notes/a.txt")).toBeNull();
1504-
});
1505-
1506-
it("does not add Think compatibility methods by default", () => {
1507-
const ws = new Workspace({ storage: makeStorage() });
15081460

1461+
expect(ws).not.toHaveProperty("useThink");
15091462
expect(ws).not.toHaveProperty("readFile");
15101463
expect(ws).not.toHaveProperty("readFileBytes");
15111464
expect(ws).not.toHaveProperty("writeFile");
@@ -1514,5 +1467,6 @@ describe("Workspace Think compatibility", () => {
15141467
expect(ws).not.toHaveProperty("mkdir");
15151468
expect(ws).not.toHaveProperty("rm");
15161469
expect(ws).not.toHaveProperty("stat");
1470+
expect(ws.stub()).not.toHaveProperty("useThink");
15171471
});
15181472
});

0 commit comments

Comments
 (0)