Skip to content

Commit b0d2ee7

Browse files
refactor(server): load the Cua SDK as an Effect
Drop the promise wrapper and node:fs/node:path usage from the SDK loader. The loader is now a lazy Effect.fn over FileSystem and Path, fails with CuaDriverSdkLoadError directly, and the standalone factory takes it as a plain Effect so tests inject Effect.succeed / Effect.fail instead of async thunks. createRequire stays because it is the only way a single-executable reaches a file-backed package. Claude Fable 5 via Claude Code. Co-Authored-By: Claude Fable 5 <[email protected]>
1 parent b8781e4 commit b0d2ee7

2 files changed

Lines changed: 84 additions & 64 deletions

File tree

‎apps/server/src/cua/CuaDriver.test.ts‎

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -50,31 +50,34 @@ const standaloneFixture = Effect.fn(function* (failFirstDestroy = false) {
5050
let creates = 0;
5151
let stops = 0;
5252
let destroys = 0;
53-
const factory = yield* makeStandaloneHostFactory("/driver", async () => ({
54-
EmbeddedCuaDriverHost: class {
55-
constructor() {
56-
creates++;
57-
}
58-
start() {
59-
started.resolve();
60-
return start.promise;
61-
}
62-
stop() {
63-
stops++;
64-
stopped.resolve();
65-
return stop.promise;
66-
}
67-
waitForExit(_generation: string, options?: { signal: AbortSignal }) {
68-
watching.resolve(options!.signal);
69-
return monitor.promise;
70-
}
71-
uniffiDestroy() {
72-
destroys++;
73-
destroyed.resolve();
74-
if (failFirstDestroy && destroys === 1) throw destroyFailure;
75-
}
76-
},
77-
}));
53+
const factory = yield* makeStandaloneHostFactory(
54+
"/driver",
55+
Effect.succeed({
56+
EmbeddedCuaDriverHost: class {
57+
constructor() {
58+
creates++;
59+
}
60+
start() {
61+
started.resolve();
62+
return start.promise;
63+
}
64+
stop() {
65+
stops++;
66+
stopped.resolve();
67+
return stop.promise;
68+
}
69+
waitForExit(_generation: string, options?: { signal: AbortSignal }) {
70+
watching.resolve(options!.signal);
71+
return monitor.promise;
72+
}
73+
uniffiDestroy() {
74+
destroys++;
75+
destroyed.resolve();
76+
if (failFirstDestroy && destroys === 1) throw destroyFailure;
77+
}
78+
},
79+
}),
80+
);
7881
const connection: EmbeddedDriverConnection = {
7982
socketPath: "/socket",
8083
pid: 1,
@@ -103,9 +106,10 @@ describe("Cua Driver failure boundaries", () => {
103106
it.effect("preserves SDK import failures without exposing their message", () =>
104107
Effect.gen(function* () {
105108
const cause = new Error("private SDK loader details");
106-
const factory = yield* CuaDriver.makeStandaloneHostFactory("/driver", async () => {
107-
throw cause;
108-
});
109+
const factory = yield* CuaDriver.makeStandaloneHostFactory(
110+
"/driver",
111+
Effect.fail(new CuaDriver.CuaDriverSdkLoadError({ cause })),
112+
);
109113
const failure = yield* Effect.flip(factory);
110114
expect(failure._tag).toBe("CuaDriverSdkLoadError");
111115
expect(failure.message).toBe("Could not load the Cua Driver SDK.");
@@ -117,23 +121,26 @@ describe("Cua Driver failure boundaries", () => {
117121
it.effect("preserves native constructor failures and identifies the binary", () =>
118122
Effect.gen(function* () {
119123
const cause = new Error("private constructor details");
120-
const factory = yield* CuaDriver.makeStandaloneHostFactory("/driver", async () => ({
121-
EmbeddedCuaDriverHost: class {
122-
constructor() {
123-
throw cause;
124-
}
125-
start() {
126-
return Promise.reject(cause);
127-
}
128-
stop() {
129-
return Promise.resolve();
130-
}
131-
waitForExit() {
132-
return Promise.reject(cause);
133-
}
134-
uniffiDestroy() {}
135-
},
136-
}));
124+
const factory = yield* CuaDriver.makeStandaloneHostFactory(
125+
"/driver",
126+
Effect.succeed({
127+
EmbeddedCuaDriverHost: class {
128+
constructor() {
129+
throw cause;
130+
}
131+
start() {
132+
return Promise.reject(cause);
133+
}
134+
stop() {
135+
return Promise.resolve();
136+
}
137+
waitForExit() {
138+
return Promise.reject(cause);
139+
}
140+
uniffiDestroy() {}
141+
},
142+
}),
143+
);
137144
const failure = yield* Effect.flip(factory);
138145
expect(failure._tag).toBe("CuaDriverHostCreateError");
139146
expect(failure.message).toBe("Could not create the Cua Driver host.");

‎apps/server/src/cua/CuaDriver.ts‎

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
// @effect-diagnostics nodeBuiltinImport:off - createRequire is the only way the single-executable reaches a file-backed package.
21
import * as NodeCrypto from "node:crypto";
3-
import * as NodeFS from "node:fs";
42
import * as NodeModule from "node:module";
5-
import * as NodePath from "node:path";
63

74
import type { CuaDriverMcpConfiguration, DesktopCuaDriverReport } from "@t3tools/contracts";
85
import type { EmbeddedCuaDriverHost, EmbeddedDriverConnection } from "@trycua/cua-driver/embedded";
96
import * as Context from "effect/Context";
107
import * as Deferred from "effect/Deferred";
118
import * as Effect from "effect/Effect";
9+
import * as FileSystem from "effect/FileSystem";
1210
import * as Layer from "effect/Layer";
1311
import * as Option from "effect/Option";
12+
import * as Path from "effect/Path";
1413
import * as Schema from "effect/Schema";
1514
import * as Scope from "effect/Scope";
1615
import * as Semaphore from "effect/Semaphore";
@@ -297,23 +296,32 @@ type StandaloneHostModule = {
297296
// package through the same lookup paths and require its entry file directly.
298297
const requireForCuaDriver = NodeModule.createRequire(import.meta.url);
299298

300-
const loadEmbeddedCuaDriver = (): Promise<StandaloneHostModule> =>
301-
Promise.resolve().then(() => {
302-
for (const lookupPath of requireForCuaDriver.resolve.paths("@trycua/cua-driver") ?? []) {
303-
const packageDir = NodePath.join(lookupPath, "@trycua", "cua-driver");
304-
if (NodeFS.existsSync(NodePath.join(packageDir, "package.json"))) {
305-
return requireForCuaDriver(
306-
NodePath.join(packageDir, "dist", "embedded.js"),
307-
) as StandaloneHostModule;
308-
}
299+
const loadEmbeddedCuaDriver = Effect.fn("CuaDriver.loadEmbeddedSdk")(function* () {
300+
const fs = yield* FileSystem.FileSystem;
301+
const path = yield* Path.Path;
302+
for (const lookupPath of requireForCuaDriver.resolve.paths("@trycua/cua-driver") ?? []) {
303+
const packageDir = path.join(lookupPath, "@trycua", "cua-driver");
304+
if (
305+
yield* fs
306+
.exists(path.join(packageDir, "package.json"))
307+
.pipe(Effect.orElseSucceed(() => false))
308+
) {
309+
return yield* Effect.try({
310+
try: () =>
311+
requireForCuaDriver(path.join(packageDir, "dist", "embedded.js")) as StandaloneHostModule,
312+
catch: (cause) => new CuaDriverSdkLoadError({ cause }),
313+
});
309314
}
310-
throw new Error("@trycua/cua-driver is not installed beside this server.");
315+
}
316+
return yield* new CuaDriverSdkLoadError({
317+
cause: "@trycua/cua-driver is not installed beside this server.",
311318
});
319+
});
312320

313321
/** A timed-out native cleanup still owns the factory until every call settles. */
314322
export const makeStandaloneHostFactory = Effect.fn("CuaDriver.standaloneHostFactory")(function* (
315323
binaryPath: string,
316-
loadEmbedded: () => Promise<StandaloneHostModule> = loadEmbeddedCuaDriver,
324+
loadEmbedded: Effect.Effect<StandaloneHostModule, CuaDriverSdkLoadError>,
317325
) {
318326
const mutex = yield* Semaphore.make(1);
319327
let occupied = false;
@@ -324,10 +332,7 @@ export const makeStandaloneHostFactory = Effect.fn("CuaDriver.standaloneHostFact
324332
if (occupied) {
325333
return yield* new CuaDriverBusyError({});
326334
}
327-
const { EmbeddedCuaDriverHost } = yield* Effect.tryPromise({
328-
try: loadEmbedded,
329-
catch: (cause) => new CuaDriverSdkLoadError({ cause }),
330-
});
335+
const { EmbeddedCuaDriverHost } = yield* loadEmbedded;
331336
const host = yield* Effect.try({
332337
try: () => new EmbeddedCuaDriverHost(binaryPath, "com.t3tools.t3code.server"),
333338
catch: (cause) => new CuaDriverHostCreateError({ binaryPath, cause }),
@@ -469,12 +474,20 @@ export const layer = Layer.effect(
469474
CuaDriver,
470475
Effect.gen(function* () {
471476
const config = yield* ServerConfig.ServerConfig;
477+
const fs = yield* FileSystem.FileSystem;
478+
const path = yield* Path.Path;
472479
const binaryPath = process.env.T3CODE_CUA_DRIVER_PATH?.trim();
473480
const createHost =
474481
config.mode === "desktop" && config.desktopTelemetryControlFd !== undefined
475482
? yield* makeDesktopHostFactory()
476483
: binaryPath
477-
? yield* makeStandaloneHostFactory(binaryPath)
484+
? yield* makeStandaloneHostFactory(
485+
binaryPath,
486+
loadEmbeddedCuaDriver().pipe(
487+
Effect.provideService(FileSystem.FileSystem, fs),
488+
Effect.provideService(Path.Path, path),
489+
),
490+
)
478491
: Effect.logWarning(
479492
"Cua Driver requires the T3 desktop host or an explicit T3CODE_CUA_DRIVER_PATH on this server.",
480493
).pipe(Effect.andThen(Effect.fail(new CuaDriverNotConfiguredError({}))));

0 commit comments

Comments
 (0)