History

[codex] Enforce canonical Node namespace imports (#3238)

Julius Marminge committed 4 months ago

Commit 2fa37ec1 parent db2750271 files · +1205 −952Browse files

Unified · Split

71 files
  1. .macroscope/check-run-agents/effect-service-conventions.md +1 −1
  2. apps/desktop/scripts/build-preview-annotation-css.mjs +16 −16
  3. apps/desktop/scripts/dev-electron.mjs +13 −9
  4. apps/desktop/scripts/electron-launcher.mjs +89 −73
  5. apps/desktop/scripts/ensure-electron-runtime.mjs +34 −32
  6. apps/desktop/scripts/smoke-test.mjs +7 −7
  7. apps/desktop/scripts/start-electron.mjs +2 −2
  8. apps/desktop/scripts/wait-for-resources.mjs +8 −8
  9. apps/desktop/src/backend/DesktopNetworkInterfaces.ts +2 −2
  10. apps/desktop/src/ipc/methods/preview.ts +2 −2
  11. apps/desktop/src/preview/PlaywrightInjectedRuntime.ts +11 −7
  12. apps/mobile/modules/t3-markdown-text/scripts/sync-pierre-file-icons.mjs +21 −18
  13. apps/server/integration/OrchestrationEngineHarness.integration.ts +2 −2
  14. apps/server/integration/orchestrationEngine.integration.test.ts +12 −9
  15. apps/server/scripts/acp-mock-agent.ts +3 −3
  16. apps/server/scripts/cursor-acp-model-mismatch-probe.ts +24 −24
  17. apps/server/src/attachmentPaths.ts +1 −1
  18. apps/server/src/attachmentStore.test.ts +13 −9
  19. apps/server/src/attachmentStore.ts +4 −4
  20. apps/server/src/auth/utils.ts +3 −3
  21. apps/server/src/bin.test.ts +47 −25
  22. apps/server/src/bootstrap.test.ts +13 −13
  23. apps/server/src/bootstrap.ts +13 −13
  24. apps/server/src/checkpointing/CheckpointStore.test.ts +4 −4
  25. apps/server/src/cloud/CliTokenManager.ts +2 −2
  26. apps/server/src/cloud/http.ts +2 −2
  27. apps/server/src/environment/ServerEnvironment.test.ts +2 −2
  28. apps/server/src/git/GitManager.test.ts +64 −56
  29. apps/server/src/git/Utils.ts +3 −3
  30. apps/server/src/orchestration/Layers/CheckpointReactor.test.ts +17 −17
  31. apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts +7 −6
  32. apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts +6 −6
  33. apps/server/src/pathExpansion.test.ts +5 −5
  34. apps/server/src/pathExpansion.ts +4 −4
  35. apps/server/src/persistence/NodeSqliteClient.ts +11 −7
  36. apps/server/src/preview/PortScanner.test.ts +4 −4
  37. apps/server/src/provider/Layers/ClaudeAdapter.test.ts +9 −9
  38. apps/server/src/provider/Layers/CodexAdapter.test.ts +98 −96
  39. apps/server/src/provider/Layers/CodexSessionRuntime.test.ts +18 −18
  40. apps/server/src/provider/Layers/CursorAdapter.test.ts +63 −49
  41. apps/server/src/provider/Layers/CursorProvider.ts +2 −2
  42. apps/server/src/provider/Layers/EventNdjsonLogger.test.ts +28 −31
  43. apps/server/src/provider/Layers/EventNdjsonLogger.ts +4 −4
  44. apps/server/src/provider/Layers/GrokAdapter.test.ts +18 −16
  45. apps/server/src/provider/Layers/OpenCodeAdapter.test.ts +48 −48
  46. apps/server/src/provider/Layers/OpenCodeProvider.test.ts +22 −19
  47. apps/server/src/provider/Layers/ProviderService.test.ts +21 −15
  48. apps/server/src/provider/Layers/ProviderSessionDirectory.test.ts +6 −6
  49. apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts +10 −10
  50. apps/server/src/provider/opencodeRuntime.ts +2 −2
  51. apps/server/src/provider/providerMaintenance.test.ts +44 −44
  52. apps/server/src/relay/AgentAwarenessRelay.test.ts +2 −2
  53. apps/server/src/server.test.ts +22 −22
  54. apps/server/src/terminal/NodePtyAdapter.ts +2 −2
  55. apps/server/src/textGeneration/CursorTextGeneration.test.ts +25 −21
  56. apps/server/src/textGeneration/GrokTextGeneration.test.ts +18 −16
  57. apps/server/src/vcs/GitVcsDriver.ts +5 −2
  58. apps/server/src/workspace/WorkspaceEntries.test.ts +9 −3
  59. apps/server/src/workspace/WorkspaceEntries.ts +5 −5
  60. apps/server/src/workspace/WorkspaceFileSystem.ts +4 −4
  61. apps/server/src/workspace/WorkspacePaths.ts +3 −3
  62. oxlint-plugin-t3code/index.ts +2 −0
  63. oxlint-plugin-t3code/rules/namespace-node-imports.test.ts +63 −0
  64. oxlint-plugin-t3code/rules/namespace-node-imports.ts +76 −0
  65. packages/shared/src/logging.ts +15 −15
  66. packages/shared/src/shell.ts +8 −8
  67. packages/ssh/src/command.ts +5 −2
  68. scripts/build-desktop-artifact.ts +2 −2
  69. scripts/lib/public-config.test.ts +9 −9
  70. scripts/release-smoke.ts +62 −64
  71. vite.config.ts +3 −2
.macroscope/check-run-agents/effect-service-conventions.md+1−1
@@ -27,7 +27,7 @@ Review changed TypeScript and directly affected call sites for the conventions b · 26 unmodified lines
2727
2828 - Import Effect library modules from their subpaths as namespaces, for example `import * as Effect from "effect/Effect"` and `import * as Layer from "effect/Layer"`. Flag consolidated named imports from `"effect"` in touched Effect service code.
2929 - At a service boundary, import the local service module as a namespace and use its public module shape: `WorkspacePaths.WorkspacePaths`, `WorkspacePaths.make`, and `WorkspacePaths.layer`. Flag aliases such as `import { layer as workspacePathsLayer }` that erase the module namespace.
30−- Namespace imports are not a blanket rule. Keep named imports for whole packages such as `@t3tools/contracts` and `electron`, and for modules used only for a pure helper, error, schema, config value, or standalone type. Do not request `import type * as Contracts`.
30+- Namespace imports are not a blanket rule. Keep named imports for whole packages such as `@t3tools/contracts`, and for modules used only for a pure helper, error, schema, config value, or standalone type. Do not request `import type * as Contracts`.
3131 - A package subpath that is itself a service module may use a namespace import when callers access its service/tag, `make`, or `layer` members.
3232 - When a barrel exposes an entire service module, prefer `export * as TokenStore from "./tokenStore.ts"` so consumers can use `TokenStore.TokenStore` and `TokenStore.layer`. Do not individually rename `make` and `layer` exports to simulate a namespace.
3333
apps/desktop/scripts/build-preview-annotation-css.mjs+16−16
@@ -1,23 +1,23 @@
1−import { readFile, writeFile } from "node:fs/promises";
2−import { createRequire } from "node:module";
3−import { dirname, join } from "node:path";
4−import { fileURLToPath } from "node:url";
1+import * as NodeFSP from "node:fs/promises";
2+import * as NodeModule from "node:module";
3+import * as NodePath from "node:path";
4+import * as NodeURL from "node:url";
55
66 import { compile } from "tailwindcss";
77
8−const directory = dirname(fileURLToPath(import.meta.url));
9−const appRoot = join(directory, "..");
10−const sourcePath = join(appRoot, "src", "preview", "Annotation.css");
11−const preloadPath = join(appRoot, "src", "preview", "PickPreload.ts");
12−const outputPath = join(appRoot, "src", "preview", "AnnotationStyles.generated.ts");
13−const require = createRequire(import.meta.url);
14−const tailwindRoot = dirname(require.resolve("tailwindcss/package.json"));
8+const directory = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
9+const appRoot = NodePath.join(directory, "..");
10+const sourcePath = NodePath.join(appRoot, "src", "preview", "Annotation.css");
11+const preloadPath = NodePath.join(appRoot, "src", "preview", "PickPreload.ts");
12+const outputPath = NodePath.join(appRoot, "src", "preview", "AnnotationStyles.generated.ts");
13+const require = NodeModule.createRequire(import.meta.url);
14+const tailwindRoot = NodePath.dirname(require.resolve("tailwindcss/package.json"));
1515
1616 const [annotationSource, preloadSource, themeSource, preflightSource] = await Promise.all([
17− readFile(sourcePath, "utf8"),
18− readFile(preloadPath, "utf8"),
19− readFile(join(tailwindRoot, "theme.css"), "utf8"),
20− readFile(join(tailwindRoot, "preflight.css"), "utf8"),
17+ NodeFSP.readFile(sourcePath, "utf8"),
18+ NodeFSP.readFile(preloadPath, "utf8"),
19+ NodeFSP.readFile(NodePath.join(tailwindRoot, "theme.css"), "utf8"),
20+ NodeFSP.readFile(NodePath.join(tailwindRoot, "preflight.css"), "utf8"),
2121 ]);
2222
2323 const candidates = new Set(
@@ -37,4 +37,4 @@ const encodedCss = `'${css · 13 unmodified lines
3737 .replaceAll("\n", "\\n")}'`;
3838 const moduleSource = `// Generated by scripts/build-preview-annotation-css.mjs. Do not edit.\nexport const previewAnnotationStyles =\n ${encodedCss};\n`;
3939
40−await writeFile(outputPath, moduleSource);
40+await NodeFSP.writeFile(outputPath, moduleSource);
apps/desktop/scripts/dev-electron.mjs+13−9
@@ -1,7 +1,7 @@
1−import { spawn, spawnSync } from "node:child_process";
2−import { watch } from "node:fs";
1+import * as NodeChildProcess from "node:child_process";
2+import * as NodeFS from "node:fs";
33 import * as NodeOS from "node:os";
4−import { join } from "node:path";
4+import * as NodePath from "node:path";
55
66 import {
77 desktopDir,
@@ -64,7 +64,7 @@ function killChildTreeByPid(pid, signal) { · 56 unmodified lines
6464 return;
6565 }
6666
67− spawnSync("pkill", [`-${signal}`, "-P", String(pid)], { stdio: "ignore" });
67+ NodeChildProcess.spawnSync("pkill", [`-${signal}`, "-P", String(pid)], { stdio: "ignore" });
6868 }
6969
7070 function cleanupStaleDevApps() {
@@ -72,7 +72,9 @@ function cleanupStaleDevApps() { · 1 unmodified line
7272 return;
7373 }
7474
75− spawnSync("pkill", ["-f", "--", `--t3code-dev-root=${desktopDir}`], { stdio: "ignore" });
75+ NodeChildProcess.spawnSync("pkill", ["-f", "--", `--t3code-dev-root=${desktopDir}`], {
76+ stdio: "ignore",
77+ });
7678 }
7779
7880 function startApp() {
@@ -87,7 +89,7 @@ function startApp() { · 8 unmodified lines
8789 ? electronArgs
8890 : [...electronArgs, `--t3code-dev-root=${desktopDir}`, "dist-electron/main.cjs"];
8991 const electronCommand = resolveElectronLaunchCommand(launchArgs);
90− const app = spawn(electronCommand.electronPath, electronCommand.args, {
92+ const app = NodeChildProcess.spawn(electronCommand.electronPath, electronCommand.args, {
9193 cwd: desktopDir,
9294 env: childEnv,
9395 stdio: "inherit",
@@ -180,8 +182,8 @@ function scheduleRestart() { · 86 unmodified lines
180182
181183 function startWatchers() {
182184 for (const { directory, files } of watchedDirectories) {
183− const watcher = watch(
184− join(desktopDir, directory),
185+ const watcher = NodeFS.watch(
186+ NodePath.join(desktopDir, directory),
185187 { persistent: true },
186188 (_eventType, filename) => {
187189 if (typeof filename !== "string" || !files.has(filename)) {
@@ -202,7 +204,9 @@ function killChildTree(signal) { · 14 unmodified lines
202204 }
203205
204206 // Kill direct children as a final fallback in case normal shutdown leaves stragglers.
205− spawnSync("pkill", [`-${signal}`, "-P", String(process.pid)], { stdio: "ignore" });
207+ NodeChildProcess.spawnSync("pkill", [`-${signal}`, "-P", String(process.pid)], {
208+ stdio: "ignore",
209+ });
206210 }
207211
208212 async function shutdown(exitCode) {
apps/desktop/scripts/electron-launcher.mjs+89−73
@@ -1,29 +1,18 @@
11 // This file mostly exists because we want dev mode to say "T3 Code (Dev)" instead of "electron"
22
3−import { spawnSync } from "node:child_process";
4−import {
5− copyFileSync,
6− chmodSync,
7− cpSync,
8− existsSync,
9− mkdirSync,
10− mkdtempSync,
11− readFileSync,
12− rmSync,
13− statSync,
14− writeFileSync,
15−} from "node:fs";
16−import { createRequire } from "node:module";
3+import * as NodeChildProcess from "node:child_process";
4+import * as NodeFS from "node:fs";
5+import * as NodeModule from "node:module";
176 import * as NodeOS from "node:os";
18−import { basename, dirname, join, resolve } from "node:path";
19−import { fileURLToPath } from "node:url";
7+import * as NodePath from "node:path";
8+import * as NodeURL from "node:url";
209 import { ensureElectronRuntime } from "./ensure-electron-runtime.mjs";
2110
2211 const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL);
23−const __dirname = dirname(fileURLToPath(import.meta.url));
24−export const desktopDir = resolve(__dirname, "..");
25−const repoRoot = resolve(desktopDir, "..", "..");
26−const devBundleIdSuffix = basename(repoRoot)
12+const __dirname = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
13+export const desktopDir = NodePath.resolve(__dirname, "..");
14+const repoRoot = NodePath.resolve(desktopDir, "..", "..");
15+const devBundleIdSuffix = NodePath.basename(repoRoot)
2716 .toLowerCase()
2817 .replaceAll(/[^a-z0-9]+/g, "");
2918 export const APP_DISPLAY_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)";
@@ -32,22 +21,35 @@ export const APP_BUNDLE_ID = isDevelopment · 2 unmodified lines
3221 : "com.t3tools.t3code";
3322 const APP_PROTOCOL_SCHEMES = isDevelopment ? ["t3code-dev"] : ["t3code"];
3423 const LAUNCHER_VERSION = 12;
35−const defaultIconPath = join(desktopDir, "resources", "icon.icns");
36−const developmentMacIconPngPath = join(repoRoot, "assets", "dev", "blueprint-macos-1024.png");
24+const defaultIconPath = NodePath.join(desktopDir, "resources", "icon.icns");
25+const developmentMacIconPngPath = NodePath.join(
26+ repoRoot,
27+ "assets",
28+ "dev",
29+ "blueprint-macos-1024.png",
30+);
3731 // oxlint-disable-next-line t3code/no-global-process-runtime -- Standalone launcher script has no Effect runtime.
3832 const hostPlatform = NodeOS.platform();
3933
4034 function setPlistString(plistPath, key, value) {
41− const replaceResult = spawnSync("plutil", ["-replace", key, "-string", value, plistPath], {
42− encoding: "utf8",
43− });
35+ const replaceResult = NodeChildProcess.spawnSync(
36+ "plutil",
37+ ["-replace", key, "-string", value, plistPath],
38+ {
39+ encoding: "utf8",
40+ },
41+ );
4442 if (replaceResult.status === 0) {
4543 return;
4644 }
4745
48− const insertResult = spawnSync("plutil", ["-insert", key, "-string", value, plistPath], {
49− encoding: "utf8",
50− });
46+ const insertResult = NodeChildProcess.spawnSync(
47+ "plutil",
48+ ["-insert", key, "-string", value, plistPath],
49+ {
50+ encoding: "utf8",
51+ },
52+ );
5153 if (insertResult.status === 0) {
5254 return;
5355 }
@@ -58,16 +60,24 @@ function setPlistString(plistPath, key, value) { · 4 unmodified lines
5860
5961 function setPlistJson(plistPath, key, value) {
6062 const serialized = JSON.stringify(value);
61− const replaceResult = spawnSync("plutil", ["-replace", key, "-json", serialized, plistPath], {
62− encoding: "utf8",
63− });
63+ const replaceResult = NodeChildProcess.spawnSync(
64+ "plutil",
65+ ["-replace", key, "-json", serialized, plistPath],
66+ {
67+ encoding: "utf8",
68+ },
69+ );
6470 if (replaceResult.status === 0) {
6571 return;
6672 }
6773
68− const insertResult = spawnSync("plutil", ["-insert", key, "-json", serialized, plistPath], {
69− encoding: "utf8",
70− });
74+ const insertResult = NodeChildProcess.spawnSync(
75+ "plutil",
76+ ["-insert", key, "-json", serialized, plistPath],
77+ {
78+ encoding: "utf8",
79+ },
80+ );
7181 if (insertResult.status === 0) {
7282 return;
7383 }
@@ -77,7 +87,7 @@ function setPlistJson(plistPath, key, value) { · 3 unmodified lines
7787 }
7888
7989 function runChecked(command, args) {
80− const result = spawnSync(command, args, { encoding: "utf8" });
90+ const result = NodeChildProcess.spawnSync(command, args, { encoding: "utf8" });
8191 if (result.status === 0) {
8292 return;
8393 }
@@ -91,7 +101,7 @@ function shellSingleQuote(value) { · 7 unmodified lines
91101 }
92102
93103 function writeDevelopmentLauncherScript(targetBinaryPath, electronBinaryPath) {
94− const mainEntryPath = join(desktopDir, "dist-electron", "main.cjs");
104+ const mainEntryPath = NodePath.join(desktopDir, "dist-electron", "main.cjs");
95105 const envEntries = [
96106 ["VITE_DEV_SERVER_URL", process.env.VITE_DEV_SERVER_URL],
97107 ["T3CODE_PORT", process.env.T3CODE_PORT],
@@ -101,7 +111,7 @@ function writeDevelopmentLauncherScript(targetBinaryPath, electronBinaryPath) { · 3 unmodified lines
101111 ["T3CODE_OTLP_EXPORT_INTERVAL_MS", process.env.T3CODE_OTLP_EXPORT_INTERVAL_MS],
102112 ["T3CODE_DESKTOP_APP_USER_MODEL_ID", APP_BUNDLE_ID],
103113 ].filter((entry) => typeof entry[1] === "string" && entry[1].trim().length > 0);
104− writeFileSync(
114+ NodeFS.writeFileSync(
105115 targetBinaryPath,
106116 [
107117 "#!/bin/sh",
@@ -110,7 +120,7 @@ function writeDevelopmentLauncherScript(targetBinaryPath, electronBinaryPath) { · 2 unmodified lines
110120 "",
111121 ].join("\n"),
112122 );
113− chmodSync(targetBinaryPath, 0o755);
123+ NodeFS.chmodSync(targetBinaryPath, 0o755);
114124 }
115125
116126 function registerMacLauncherBundle(appBundlePath) {
@@ -140,21 +150,24 @@ function registerMacLauncherBundle(appBundlePath) { · 23 unmodified lines
140150 }
141151
142152 function ensureDevelopmentIconIcns(runtimeDir) {
143− const generatedIconPath = join(runtimeDir, "icon-dev.icns");
144− mkdirSync(runtimeDir, { recursive: true });
153+ const generatedIconPath = NodePath.join(runtimeDir, "icon-dev.icns");
154+ NodeFS.mkdirSync(runtimeDir, { recursive: true });
145155
146− if (!existsSync(developmentMacIconPngPath)) {
156+ if (!NodeFS.existsSync(developmentMacIconPngPath)) {
147157 return defaultIconPath;
148158 }
149159
150− const sourceMtimeMs = statSync(developmentMacIconPngPath).mtimeMs;
151− if (existsSync(generatedIconPath) && statSync(generatedIconPath).mtimeMs >= sourceMtimeMs) {
160+ const sourceMtimeMs = NodeFS.statSync(developmentMacIconPngPath).mtimeMs;
161+ if (
162+ NodeFS.existsSync(generatedIconPath) &&
163+ NodeFS.statSync(generatedIconPath).mtimeMs >= sourceMtimeMs
164+ ) {
152165 return generatedIconPath;
153166 }
154167
155− const iconsetRoot = mkdtempSync(join(runtimeDir, "dev-iconset-"));
156− const iconsetDir = join(iconsetRoot, "icon.iconset");
157− mkdirSync(iconsetDir, { recursive: true });
168+ const iconsetRoot = NodeFS.mkdtempSync(NodePath.join(runtimeDir, "dev-iconset-"));
169+ const iconsetDir = NodePath.join(iconsetRoot, "icon.iconset");
170+ NodeFS.mkdirSync(iconsetDir, { recursive: true });
158171
159172 try {
160173 for (const size of [16, 32, 128, 256, 512]) {
@@ -164,7 +177,7 @@ function ensureDevelopmentIconIcns(runtimeDir) { · 3 unmodified lines
164177 String(size),
165178 developmentMacIconPngPath,
166179 "--out",
167− join(iconsetDir, `icon_${size}x${size}.png`),
180+ NodePath.join(iconsetDir, `icon_${size}x${size}.png`),
168181 ]);
169182
170183 const retinaSize = size * 2;
@@ -174,7 +187,7 @@ function ensureDevelopmentIconIcns(runtimeDir) { · 3 unmodified lines
174187 String(retinaSize),
175188 developmentMacIconPngPath,
176189 "--out",
177− join(iconsetDir, `icon_${size}x${size}@2x.png`),
190+ NodePath.join(iconsetDir, `icon_${size}x${size}@2x.png`),
178191 ]);
179192 }
180193
@@ -187,12 +200,12 @@ function ensureDevelopmentIconIcns(runtimeDir) { · 6 unmodified lines
187200 );
188201 return defaultIconPath;
189202 } finally {
190− rmSync(iconsetRoot, { recursive: true, force: true });
203+ NodeFS.rmSync(iconsetRoot, { recursive: true, force: true });
191204 }
192205 }
193206
194207 function patchMainBundleInfoPlist(appBundlePath, iconPath) {
195− const infoPlistPath = join(appBundlePath, "Contents", "Info.plist");
208+ const infoPlistPath = NodePath.join(appBundlePath, "Contents", "Info.plist");
196209 setPlistString(infoPlistPath, "CFBundleDisplayName", APP_DISPLAY_NAME);
197210 setPlistString(infoPlistPath, "CFBundleName", APP_DISPLAY_NAME);
198211 setPlistString(infoPlistPath, "CFBundleIdentifier", APP_BUNDLE_ID);
@@ -204,9 +217,9 @@ function patchMainBundleInfoPlist(appBundlePath, iconPath) { · 5 unmodified lines
204217 },
205218 ]);
206219
207− const resourcesDir = join(appBundlePath, "Contents", "Resources");
208− copyFileSync(iconPath, join(resourcesDir, "icon.icns"));
209− copyFileSync(iconPath, join(resourcesDir, "electron.icns"));
220+ const resourcesDir = NodePath.join(appBundlePath, "Contents", "Resources");
221+ NodeFS.copyFileSync(iconPath, NodePath.join(resourcesDir, "icon.icns"));
222+ NodeFS.copyFileSync(iconPath, NodePath.join(resourcesDir, "electron.icns"));
210223 }
211224
212225 function patchHelperBundleInfoPlists(appBundlePath) {
@@ -218,7 +231,7 @@ function patchHelperBundleInfoPlists(appBundlePath) { · 5 unmodified lines
218231 ];
219232
220233 for (const [bundleName, bundleIdentifierSuffix, bundleDisplayName] of helperBundleNames) {
221− const infoPlistPath = join(
234+ const infoPlistPath = NodePath.join(
222235 appBundlePath,
223236 "Contents",
224237 "Frameworks",
@@ -226,7 +239,7 @@ function patchHelperBundleInfoPlists(appBundlePath) { · 1 unmodified line
226239 "Contents",
227240 "Info.plist",
228241 );
229− if (!existsSync(infoPlistPath)) {
242+ if (!NodeFS.existsSync(infoPlistPath)) {
230243 continue;
231244 }
232245
@@ -242,34 +255,34 @@ function patchHelperBundleInfoPlists(appBundlePath) { · 9 unmodified lines
242255
243256 function readJson(path) {
244257 try {
245− return JSON.parse(readFileSync(path, "utf8"));
258+ return JSON.parse(NodeFS.readFileSync(path, "utf8"));
246259 } catch {
247260 return null;
248261 }
249262 }
250263
251264 function buildMacLauncher(electronBinaryPath) {
252− const sourceAppBundlePath = resolve(dirname(electronBinaryPath), "../..");
253− const runtimeDir = join(desktopDir, ".electron-runtime");
254− const targetAppBundlePath = join(runtimeDir, `${APP_DISPLAY_NAME}.app`);
255− const targetBinaryPath = join(targetAppBundlePath, "Contents", "MacOS", "Electron");
265+ const sourceAppBundlePath = NodePath.resolve(NodePath.dirname(electronBinaryPath), "../..");
266+ const runtimeDir = NodePath.join(desktopDir, ".electron-runtime");
267+ const targetAppBundlePath = NodePath.join(runtimeDir, `${APP_DISPLAY_NAME}.app`);
268+ const targetBinaryPath = NodePath.join(targetAppBundlePath, "Contents", "MacOS", "Electron");
256269 const iconPath = isDevelopment ? ensureDevelopmentIconIcns(runtimeDir) : defaultIconPath;
257− const metadataPath = join(runtimeDir, "metadata.json");
270+ const metadataPath = NodePath.join(runtimeDir, "metadata.json");
258271
259− mkdirSync(runtimeDir, { recursive: true });
272+ NodeFS.mkdirSync(runtimeDir, { recursive: true });
260273
261274 const expectedMetadata = {
262275 launcherVersion: LAUNCHER_VERSION,
263276 sourceAppBundlePath,
264− sourceAppMtimeMs: statSync(sourceAppBundlePath).mtimeMs,
265− iconMtimeMs: statSync(iconPath).mtimeMs,
277+ sourceAppMtimeMs: NodeFS.statSync(sourceAppBundlePath).mtimeMs,
278+ iconMtimeMs: NodeFS.statSync(iconPath).mtimeMs,
266279 appBundleId: APP_BUNDLE_ID,
267280 appProtocolSchemes: APP_PROTOCOL_SCHEMES,
268281 };
269282
270283 const currentMetadata = readJson(metadataPath);
271284 if (
272− existsSync(targetBinaryPath) &&
285+ NodeFS.existsSync(targetBinaryPath) &&
273286 currentMetadata &&
274287 JSON.stringify(currentMetadata) === JSON.stringify(expectedMetadata)
275288 ) {
@@ -277,18 +290,21 @@ function buildMacLauncher(electronBinaryPath) { · 1 unmodified line
277290 return targetBinaryPath;
278291 }
279292
280− rmSync(targetAppBundlePath, { recursive: true, force: true });
293+ NodeFS.rmSync(targetAppBundlePath, { recursive: true, force: true });
281294 // verbatimSymlinks keeps the framework's relative symlinks intact
282295 // (e.g. Resources -> Versions/Current/Resources). Without it cpSync
283296 // rewrites them to absolute paths into node_modules, which escape the
284297 // bundle and crash sandboxed helper processes (icudtl.dat not found).
285− cpSync(sourceAppBundlePath, targetAppBundlePath, { recursive: true, verbatimSymlinks: true });
298+ NodeFS.cpSync(sourceAppBundlePath, targetAppBundlePath, {
299+ recursive: true,
300+ verbatimSymlinks: true,
301+ });
286302 patchMainBundleInfoPlist(targetAppBundlePath, iconPath);
287303 patchHelperBundleInfoPlists(targetAppBundlePath);
288304 if (isDevelopment) {
289305 writeDevelopmentLauncherScript(targetBinaryPath, electronBinaryPath);
290306 }
291− writeFileSync(metadataPath, `${JSON.stringify(expectedMetadata, null, 2)}\n`);
307+ NodeFS.writeFileSync(metadataPath, `${JSON.stringify(expectedMetadata, null, 2)}\n`);
292308 registerMacLauncherBundle(targetAppBundlePath);
293309
294310 return targetBinaryPath;
@@ -299,9 +315,9 @@ function isLinuxSetuidSandboxConfigured(electronBinaryPath) { · 4 unmodified lines
299315 return true;
300316 }
301317
302− const sandboxPath = join(dirname(electronBinaryPath), "chrome-sandbox");
318+ const sandboxPath = NodePath.join(NodePath.dirname(electronBinaryPath), "chrome-sandbox");
303319 try {
304− const sandboxStat = statSync(sandboxPath);
320+ const sandboxStat = NodeFS.statSync(sandboxPath);
305321 return sandboxStat.uid === 0 && (sandboxStat.mode & 0o4777) === 0o4755;
306322 } catch {
307323 return false;
@@ -322,7 +338,7 @@ function resolveLinuxSandboxArgs(electronBinaryPath) { · 14 unmodified lines
322338 export function resolveElectronPath() {
323339 ensureElectronRuntime();
324340
325− const require = createRequire(import.meta.url);
341+ const require = NodeModule.createRequire(import.meta.url);
326342 const electronBinaryPath = require("electron");
327343
328344 if (hostPlatform !== "darwin") {
@@ -345,11 +361,11 @@ export function resolveDevProtocolClient() { · 16 unmodified lines
345361 return null;
346362 }
347363
348− const require = createRequire(import.meta.url);
364+ const require = NodeModule.createRequire(import.meta.url);
349365 const electronBinaryPath = require("electron");
350366 const launcherBinaryPath = buildMacLauncher(electronBinaryPath);
351367 return {
352− appBundlePath: resolve(launcherBinaryPath, "..", "..", ".."),
368+ appBundlePath: NodePath.resolve(launcherBinaryPath, "..", "..", ".."),
353369 appBundleId: APP_BUNDLE_ID,
354370 };
355371 }
apps/desktop/scripts/ensure-electron-runtime.mjs+34−32
@@ -1,14 +1,14 @@
1−import { chmodSync, existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2−import { createRequire } from "node:module";
3−import { arch, platform, tmpdir } from "node:os";
4−import { dirname, join } from "node:path";
5−import { spawnSync } from "node:child_process";
1+import * as NodeFS from "node:fs";
2+import * as NodeModule from "node:module";
3+import * as NodeOS from "node:os";
4+import * as NodePath from "node:path";
5+import * as NodeChildProcess from "node:child_process";
66
7−const require = createRequire(import.meta.url);
7+const require = NodeModule.createRequire(import.meta.url);
88 // oxlint-disable-next-line t3code/no-global-process-runtime -- Standalone repair script has no Effect runtime.
9−const hostPlatform = platform();
9+const hostPlatform = NodeOS.platform();
1010 // oxlint-disable-next-line t3code/no-global-process-runtime -- Standalone repair script has no Effect runtime.
11−const hostArch = arch();
11+const hostArch = NodeOS.arch();
1212
1313 function getPlatformPath() {
1414 switch (hostPlatform) {
@@ -27,26 +27,28 @@ function getPlatformPath() { · 12 unmodified lines
2727
2828 function ensureExecutable(filePath) {
2929 if (hostPlatform !== "win32") {
30− chmodSync(filePath, 0o755);
30+ NodeFS.chmodSync(filePath, 0o755);
3131 }
3232 }
3333
3434 function repairPathFile(electronDir, platformPath) {
35− const pathFile = join(electronDir, "path.txt");
36− const currentPath = existsSync(pathFile) ? readFileSync(pathFile, "utf8") : undefined;
35+ const pathFile = NodePath.join(electronDir, "path.txt");
36+ const currentPath = NodeFS.existsSync(pathFile)
37+ ? NodeFS.readFileSync(pathFile, "utf8")
38+ : undefined;
3739
3840 if (currentPath !== platformPath) {
39− writeFileSync(pathFile, platformPath);
41+ NodeFS.writeFileSync(pathFile, platformPath);
4042 }
4143 }
4244
4345 function getRequiredRuntimePaths(electronDir, platformPath) {
44− const paths = [join(electronDir, "dist", platformPath)];
46+ const paths = [NodePath.join(electronDir, "dist", platformPath)];
4547
4648 if (hostPlatform === "darwin") {
4749 paths.push(
48− join(electronDir, "dist", "Electron.app", "Contents", "Info.plist"),
49− join(
50+ NodePath.join(electronDir, "dist", "Electron.app", "Contents", "Info.plist"),
51+ NodePath.join(
5052 electronDir,
5153 "dist",
5254 "Electron.app",
@@ -66,7 +68,7 @@ function isMachO(filePath) { · 13 unmodified lines
6668 return true;
6769 }
6870
69− const result = spawnSync("file", ["-b", filePath], {
71+ const result = NodeChildProcess.spawnSync("file", ["-b", filePath], {
7072 encoding: "utf8",
7173 });
7274
@@ -75,7 +77,7 @@ function isMachO(filePath) { · 2 unmodified lines
7577
7678 function missingRuntimePaths(electronDir, platformPath) {
7779 return getRequiredRuntimePaths(electronDir, platformPath).filter((runtimePath) => {
78− return !existsSync(runtimePath);
80+ return !NodeFS.existsSync(runtimePath);
7981 });
8082 }
8183
@@ -85,8 +87,8 @@ function invalidRuntimePaths(electronDir, platformPath) { · 3 unmodified lines
8587 }
8688
8789 return [
88− join(electronDir, "dist", platformPath),
89− join(
90+ NodePath.join(electronDir, "dist", platformPath),
91+ NodePath.join(
9092 electronDir,
9193 "dist",
9294 "Electron.app",
@@ -95,11 +97,11 @@ function invalidRuntimePaths(electronDir, platformPath) { · 2 unmodified lines
9597 "Electron Framework.framework",
9698 "Electron Framework",
9799 ),
98− ].filter((runtimePath) => existsSync(runtimePath) && !isMachO(runtimePath));
100+ ].filter((runtimePath) => NodeFS.existsSync(runtimePath) && !isMachO(runtimePath));
99101 }
100102
101103 function runChecked(command, args) {
102− const result = spawnSync(command, args, {
104+ const result = NodeChildProcess.spawnSync(command, args, {
103105 encoding: "utf8",
104106 stdio: "inherit",
105107 });
@@ -114,8 +116,8 @@ function runChecked(command, args) { · 8 unmodified lines
114116 }
115117
116118 function installElectronRuntime(electronDir, version) {
117− const tempDir = mkdtempSync(join(tmpdir(), "t3-electron-"));
118− const zipPath = join(tempDir, `electron-v${version}-${hostPlatform}-${hostArch}.zip`);
119+ const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-electron-"));
120+ const zipPath = NodePath.join(tempDir, `electron-v${version}-${hostPlatform}-${hostArch}.zip`);
119121
120122 try {
121123 runChecked("curl", [
@@ -125,34 +127,34 @@ function installElectronRuntime(electronDir, version) { · 3 unmodified lines
125127 zipPath,
126128 ]);
127129 if (hostPlatform === "darwin") {
128− runChecked("ditto", ["-x", "-k", zipPath, join(electronDir, "dist")]);
130+ runChecked("ditto", ["-x", "-k", zipPath, NodePath.join(electronDir, "dist")]);
129131 } else {
130132 runChecked("python3", [
131133 "-c",
132134 "import os, sys, zipfile; os.makedirs(sys.argv[2], exist_ok=True); zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])",
133135 zipPath,
134− join(electronDir, "dist"),
136+ NodePath.join(electronDir, "dist"),
135137 ]);
136138 }
137139 } finally {
138− rmSync(tempDir, { recursive: true, force: true });
140+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
139141 }
140142 }
141143
142144 export function ensureElectronRuntime() {
143145 const electronPackageJsonPath = require.resolve("electron/package.json");
144− const electronPackageJson = JSON.parse(readFileSync(electronPackageJsonPath, "utf8"));
145− const electronDir = dirname(electronPackageJsonPath);
146+ const electronPackageJson = JSON.parse(NodeFS.readFileSync(electronPackageJsonPath, "utf8"));
147+ const electronDir = NodePath.dirname(electronPackageJsonPath);
146148 const platformPath = getPlatformPath();
147− const electronPath = join(electronDir, "dist", platformPath);
149+ const electronPath = NodePath.join(electronDir, "dist", platformPath);
148150 const missingBeforeInstall = missingRuntimePaths(electronDir, platformPath);
149151 const invalidBeforeInstall = invalidRuntimePaths(electronDir, platformPath);
150152
151153 if (missingBeforeInstall.length > 0 || invalidBeforeInstall.length > 0) {
152− if (existsSync(join(electronDir, "dist"))) {
153− rmSync(join(electronDir, "dist"), { recursive: true, force: true });
154+ if (NodeFS.existsSync(NodePath.join(electronDir, "dist"))) {
155+ NodeFS.rmSync(NodePath.join(electronDir, "dist"), { recursive: true, force: true });
154156 }
155− rmSync(join(electronDir, "path.txt"), { force: true });
157+ NodeFS.rmSync(NodePath.join(electronDir, "path.txt"), { force: true });
156158 installElectronRuntime(electronDir, electronPackageJson.version);
157159 }
158160
apps/desktop/scripts/smoke-test.mjs+7−7
@@ -1,16 +1,16 @@
1−import { spawn } from "node:child_process";
2−import { dirname, resolve } from "node:path";
3−import { fileURLToPath } from "node:url";
1+import * as NodeChildProcess from "node:child_process";
2+import * as NodePath from "node:path";
3+import * as NodeURL from "node:url";
44 import { resolveElectronLaunchCommand } from "./electron-launcher.mjs";
55
6−const __dirname = dirname(fileURLToPath(import.meta.url));
7−const desktopDir = resolve(__dirname, "..");
8−const mainJs = resolve(desktopDir, "dist-electron/main.cjs");
6+const __dirname = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
7+const desktopDir = NodePath.resolve(__dirname, "..");
8+const mainJs = NodePath.resolve(desktopDir, "dist-electron/main.cjs");
99
1010 console.log("\nLaunching Electron smoke test...");
1111
1212 const electronCommand = resolveElectronLaunchCommand([mainJs]);
13−const child = spawn(electronCommand.electronPath, electronCommand.args, {
13+const child = NodeChildProcess.spawn(electronCommand.electronPath, electronCommand.args, {
1414 stdio: ["pipe", "pipe", "pipe"],
1515 env: {
1616 ...process.env,
apps/desktop/scripts/start-electron.mjs+2−2
@@ -1,4 +1,4 @@
1−import { spawn } from "node:child_process";
1+import * as NodeChildProcess from "node:child_process";
22
33 import { desktopDir, resolveElectronLaunchCommand } from "./electron-launcher.mjs";
44
@@ -6,7 +6,7 @@ const childEnv = { ...process.env }; · 1 unmodified line
66 delete childEnv.ELECTRON_RUN_AS_NODE;
77
88 const electronCommand = resolveElectronLaunchCommand(["dist-electron/main.cjs"]);
9−const child = spawn(electronCommand.electronPath, electronCommand.args, {
9+const child = NodeChildProcess.spawn(electronCommand.electronPath, electronCommand.args, {
1010 stdio: "inherit",
1111 cwd: desktopDir,
1212 env: childEnv,
apps/desktop/scripts/wait-for-resources.mjs+8−8
@@ -1,13 +1,13 @@
1−import * as FileSystem from "node:fs/promises";
2−import * as Net from "node:net";
3−import * as Path from "node:path";
4−import * as Timers from "node:timers/promises";
1+import * as NodeFSP from "node:fs/promises";
2+import * as NodeNet from "node:net";
3+import * as NodePath from "node:path";
4+import * as NodeTimersPromises from "node:timers/promises";
55
66 const defaultTcpHosts = ["127.0.0.1", "localhost", "::1"];
77
88 async function fileExists(filePath) {
99 try {
10− await FileSystem.access(filePath);
10+ await NodeFSP.access(filePath);
1111 return true;
1212 } catch {
1313 return false;
@@ -16,7 +16,7 @@ async function fileExists(filePath) { · 2 unmodified lines
1616
1717 function tcpPortIsReady({ host, port, connectTimeoutMs = 500 }) {
1818 return new Promise((resolveReady) => {
19− const socket = Net.createConnection({ host, port });
19+ const socket = NodeNet.createConnection({ host, port });
2020 let settled = false;
2121
2222 const finish = (ready) => {
@@ -47,7 +47,7 @@ async function resolvePendingResources({ baseDir, files, tcpPort, tcpHosts, conn · 24 unmodified lines
4747 const pendingFiles = [];
4848
4949 for (const relativeFilePath of files) {
50− const ready = await fileExists(Path.resolve(baseDir, relativeFilePath));
50+ const ready = await fileExists(NodePath.resolve(baseDir, relativeFilePath));
5151 if (!ready) {
5252 pendingFiles.push(relativeFilePath);
5353 }
@@ -114,6 +114,6 @@ export async function waitForResources({ · 60 unmodified lines
114114 );
115115 }
116116
117− await Timers.setTimeout(intervalMs);
117+ await NodeTimersPromises.setTimeout(intervalMs);
118118 }
119119 }
apps/desktop/src/backend/DesktopNetworkInterfaces.ts+2−2
@@ -1,4 +1,4 @@
1−import { networkInterfaces } from "node:os";
1+import * as NodeOS from "node:os";
22
33 import * as Context from "effect/Context";
44 import * as Effect from "effect/Effect";
@@ -27,7 +27,7 @@ export class DesktopNetworkInterfaces extends Context.Service< · 22 unmodified lines
2727
2828 export const make = (): DesktopNetworkInterfaces["Service"] =>
2929 DesktopNetworkInterfaces.of({
30− read: Effect.sync(() => networkInterfaces()),
30+ read: Effect.sync(() => NodeOS.networkInterfaces()),
3131 });
3232
3333 export const layer = Layer.succeed(DesktopNetworkInterfaces, make());
apps/desktop/src/ipc/methods/preview.ts+2−2
@@ -22,7 +22,7 @@ import { · 21 unmodified lines
2222 import { BrowserWindow } from "electron";
2323 import * as Effect from "effect/Effect";
2424 import * as Schema from "effect/Schema";
25−import { pathToFileURL } from "node:url";
25+import * as NodeURL from "node:url";
2626
2727 import * as PreviewManager from "../../preview/Manager.ts";
2828 import { PREVIEW_WEBVIEW_PREFERENCES } from "../../preview/WebviewPreferences.ts";
@@ -196,7 +196,7 @@ export const getPreviewConfig = DesktopIpc.makeIpcMethod({ · 167 unmodified lines
196196 return {
197197 partition: yield* manager.getBrowserPartition(environmentId),
198198 webPreferences: PREVIEW_WEBVIEW_PREFERENCES,
199− preloadUrl: pathToFileURL(`${__dirname}/preview-pick-preload.cjs`).href,
199+ preloadUrl: NodeURL.pathToFileURL(`${__dirname}/preview-pick-preload.cjs`).href,
200200 };
201201 }),
202202 });
apps/desktop/src/preview/PlaywrightInjectedRuntime.ts+11−7
@@ -1,14 +1,14 @@
11 // @effect-diagnostics nodeBuiltinImport:off - Extracts Playwright's installed Node bundle for browser injection.
2−import { readFile } from "node:fs/promises";
3−import { createRequire } from "node:module";
4−import { dirname, join } from "node:path";
5−import { runInNewContext } from "node:vm";
2+import * as NodeFSP from "node:fs/promises";
3+import * as NodeModule from "node:module";
4+import * as NodePath from "node:path";
5+import * as NodeVM from "node:vm";
66
77 import * as Data from "effect/Data";
88 import * as Effect from "effect/Effect";
99 import * as Schema from "effect/Schema";
1010
11−const require = createRequire(import.meta.url);
11+const require = NodeModule.createRequire(import.meta.url);
1212 const encodeUnknownJson = Schema.encodeUnknownEffect(Schema.UnknownFromJsonString);
1313
1414 export class PlaywrightInjectedRuntimeError extends Data.TaggedError(
@@ -32,7 +32,11 @@ export const playwrightInjectedRuntimeSource = Effect.fn("PlaywrightInjectedRunt · 17 unmodified lines
3232 catch: (cause) => fail("resolvePackage", cause),
3333 });
3434 const coreBundle = yield* Effect.tryPromise({
35− try: () => readFile(join(dirname(packageJsonPath), "lib/coreBundle.js"), "utf8"),
35+ try: () =>
36+ NodeFSP.readFile(
37+ NodePath.join(NodePath.dirname(packageJsonPath), "lib/coreBundle.js"),
38+ "utf8",
39+ ),
3640 catch: (cause) => fail("readCoreBundle", cause),
3741 });
3842 const marker = "source3 = ";
@@ -53,7 +57,7 @@ export const playwrightInjectedRuntimeSource = Effect.fn("PlaywrightInjectedRunt · 14 unmodified lines
5357 }
5458 const literal = coreBundle.slice(literalStart, literalEnd);
5559 const source = yield* Effect.try({
56− try: () => runInNewContext(literal, Object.create(null), { timeout: 1_000 }),
60+ try: () => NodeVM.runInNewContext(literal, Object.create(null), { timeout: 1_000 }),
5761 catch: (cause) => fail("evaluateSourceLiteral", cause),
5862 });
5963 if (typeof source !== "string" || source.length < 100_000) {
apps/mobile/modules/t3-markdown-text/scripts/sync-pierre-file-icons.mjs+21−18
@@ -1,16 +1,19 @@
1−import { execFileSync } from "node:child_process";
2−import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3−import { dirname, join, resolve } from "node:path";
4−import { fileURLToPath } from "node:url";
1+import * as NodeChildProcess from "node:child_process";
2+import * as NodeFS from "node:fs";
3+import * as NodePath from "node:path";
4+import * as NodeURL from "node:url";
55
66 import { getBuiltInSpriteSheet } from "@pierre/trees";
77
8−const scriptDirectory = dirname(fileURLToPath(import.meta.url));
9−const moduleDirectory = resolve(scriptDirectory, "..");
10−const repositoryRoot = resolve(moduleDirectory, "../../../..");
11−const outputDirectory = join(moduleDirectory, "assets/file-icons");
12−const generatedModulePath = join(moduleDirectory, "src/markdownFileIcons.generated.ts");
13−const webIconSource = readFileSync(join(repositoryRoot, "apps/web/src/pierre-icons.ts"), "utf8");
8+const scriptDirectory = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
9+const moduleDirectory = NodePath.resolve(scriptDirectory, "..");
10+const repositoryRoot = NodePath.resolve(moduleDirectory, "../../../..");
11+const outputDirectory = NodePath.join(moduleDirectory, "assets/file-icons");
12+const generatedModulePath = NodePath.join(moduleDirectory, "src/markdownFileIcons.generated.ts");
13+const webIconSource = NodeFS.readFileSync(
14+ NodePath.join(repositoryRoot, "apps/web/src/pierre-icons.ts"),
15+ "utf8",
16+);
1417 const customSprite = webIconSource.match(/const T3_FILE_ICON_SPRITE = `([\s\S]*?)`;/)?.[1];
1518
1619 if (!customSprite) {
@@ -95,20 +98,20 @@ function symbolFromSprite(sprite, id) { · 78 unmodified lines
9598 }
9699
97100 function renderIcon(token, symbol, color) {
98− const svgPath = join(outputDirectory, `.pierre-${token}.svg`);
99− const pngPath = join(outputDirectory, `pierre_${token}.png`);
100− writeFileSync(
101+ const svgPath = NodePath.join(outputDirectory, `.pierre-${token}.svg`);
102+ const pngPath = NodePath.join(outputDirectory, `pierre_${token}.png`);
103+ NodeFS.writeFileSync(
101104 svgPath,
102105 `<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="${symbol.viewBox}" style="color:${color}">${symbol.body}</svg>`,
103106 );
104− execFileSync("sips", ["-s", "format", "png", svgPath, "--out", pngPath], {
107+ NodeChildProcess.execFileSync("sips", ["-s", "format", "png", svgPath, "--out", pngPath], {
105108 stdio: "ignore",
106109 });
107− rmSync(svgPath);
110+ NodeFS.rmSync(svgPath);
108111 }
109112
110−rmSync(outputDirectory, { recursive: true, force: true });
111−mkdirSync(outputDirectory, { recursive: true });
113+NodeFS.rmSync(outputDirectory, { recursive: true, force: true });
114+NodeFS.mkdirSync(outputDirectory, { recursive: true });
112115
113116 const builtInSprite = getBuiltInSpriteSheet("complete");
114117 const builtInTokens = [...builtInSprite.matchAll(/<symbol id="file-tree-builtin-([^"]+)"/g)]
@@ -130,4 +133,4 @@ const tokens = [...new Set([...builtInTokens, ...Object.keys(customIcons)])].sor · 15 unmodified lines
130133 const generatedSource = `import type { ImageSourcePropType } from "react-native";\n\nexport const MARKDOWN_FILE_ICON_SOURCES = {\n${tokens
131134 .map((token) => ` ${token}: require("../assets/file-icons/pierre_${token}.png"),`)
132135 .join("\n")}\n} as const satisfies Readonly<Record<string, ImageSourcePropType>>;\n`;
133−writeFileSync(generatedModulePath, generatedSource);
136+NodeFS.writeFileSync(generatedModulePath, generatedSource);
apps/server/integration/OrchestrationEngineHarness.integration.ts+2−2
@@ -1,5 +1,5 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import { execFileSync } from "node:child_process";
2+import * as NodeChildProcess from "node:child_process";
33
44 import * as NodeServices from "@effect/platform-node/NodeServices";
55 import {
@@ -82,7 +82,7 @@ import * as AgentAwarenessRelay from "../src/relay/AgentAwarenessRelay.ts"; · 76 unmodified lines
8282 const decodeCodexSettings = Schema.decodeEffect(CodexSettings);
8383
8484 function runGit(cwd: string, args: ReadonlyArray<string>) {
85− return execFileSync("git", args, {
85+ return NodeChildProcess.execFileSync("git", args, {
8686 cwd,
8787 stdio: ["ignore", "pipe", "pipe"],
8888 encoding: "utf8",
apps/server/integration/orchestrationEngine.integration.test.ts+12−9
@@ -1,6 +1,6 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import fs from "node:fs";
3−import path from "node:path";
2+import * as NodeFS from "node:fs";
3+import * as NodePath from "node:path";
44
55 import {
66 ApprovalRequestId,
@@ -409,7 +409,7 @@ it.live("runs multi-turn file edits and persists checkpoint diffs", () => · 402 unmodified lines
409409 ],
410410 mutateWorkspace: ({ cwd }) =>
411411 Effect.sync(() => {
412− fs.writeFileSync(path.join(cwd, "README.md"), "v2\n", "utf8");
412+ NodeFS.writeFileSync(NodePath.join(cwd, "README.md"), "v2\n", "utf8");
413413 }),
414414 });
415415
@@ -456,7 +456,7 @@ it.live("runs multi-turn file edits and persists checkpoint diffs", () => · 40 unmodified lines
456456 ],
457457 mutateWorkspace: ({ cwd }) =>
458458 Effect.sync(() => {
459− fs.writeFileSync(path.join(cwd, "README.md"), "v3\n", "utf8");
459+ NodeFS.writeFileSync(NodePath.join(cwd, "README.md"), "v3\n", "utf8");
460460 }),
461461 });
462462
@@ -752,7 +752,7 @@ it.live("reverts to an earlier checkpoint and trims checkpoint projections + git · 289 unmodified lines
752752 ],
753753 mutateWorkspace: ({ cwd }) =>
754754 Effect.sync(() => {
755− fs.writeFileSync(path.join(cwd, "README.md"), "v2\n", "utf8");
755+ NodeFS.writeFileSync(NodePath.join(cwd, "README.md"), "v2\n", "utf8");
756756 }),
757757 });
758758 yield* startTurn({
@@ -811,7 +811,7 @@ it.live("reverts to an earlier checkpoint and trims checkpoint projections + git · 52 unmodified lines
811811 ],
812812 mutateWorkspace: ({ cwd }) =>
813813 Effect.sync(() => {
814− fs.writeFileSync(path.join(cwd, "README.md"), "v3\n", "utf8");
814+ NodeFS.writeFileSync(NodePath.join(cwd, "README.md"), "v3\n", "utf8");
815815 }),
816816 });
817817 yield* startTurn({
@@ -869,7 +869,10 @@ it.live("reverts to an earlier checkpoint and trims checkpoint projections + git · 51 unmodified lines
869869 ),
870870 true,
871871 );
872− assert.equal(fs.readFileSync(path.join(harness.workspaceDir, "README.md"), "utf8"), "v2\n");
872+ assert.equal(
873+ NodeFS.readFileSync(NodePath.join(harness.workspaceDir, "README.md"), "utf8"),
874+ "v2\n",
875+ );
873876 assert.equal(
874877 gitRefExists(harness.workspaceDir, checkpointRefForThreadTurn(THREAD_ID, 2)),
875878 false,
@@ -1332,7 +1335,7 @@ it.live("reverts claudeAgent turns and rolls back provider conversation state", · 456 unmodified lines
13321335 ],
13331336 mutateWorkspace: ({ cwd }) =>
13341337 Effect.sync(() => {
1335− fs.writeFileSync(path.join(cwd, "README.md"), "v2\n", "utf8");
1338+ NodeFS.writeFileSync(NodePath.join(cwd, "README.md"), "v2\n", "utf8");
13361339 }),
13371340 });
13381341
@@ -1390,7 +1393,7 @@ it.live("reverts claudeAgent turns and rolls back provider conversation state", · 51 unmodified lines
13901393 ],
13911394 mutateWorkspace: ({ cwd }) =>
13921395 Effect.sync(() => {
1393− fs.writeFileSync(path.join(cwd, "README.md"), "v3\n", "utf8");
1396+ NodeFS.writeFileSync(NodePath.join(cwd, "README.md"), "v3\n", "utf8");
13941397 }),
13951398 });
13961399
apps/server/scripts/acp-mock-agent.ts+3−3
@@ -1,6 +1,6 @@
11 #!/usr/bin/env node
22 // @effect-diagnostics nodeBuiltinImport:off
3−import { appendFileSync } from "node:fs";
3+import * as NodeFS from "node:fs";
44
55 import * as Effect from "effect/Effect";
66
@@ -42,7 +42,7 @@ function logExit(reason: string): void { · 35 unmodified lines
4242 if (!exitLogPath) {
4343 return;
4444 }
45− appendFileSync(exitLogPath, `${reason}\n`, "utf8");
45+ NodeFS.appendFileSync(exitLogPath, `${reason}\n`, "utf8");
4646 }
4747
4848 process.once("SIGTERM", () => {
@@ -693,7 +693,7 @@ const program = Effect.gen(function* () { · 644 unmodified lines
693693 }
694694 const payload = event.payload;
695695 return Effect.sync(() => {
696− appendFileSync(
696+ NodeFS.appendFileSync(
697697 requestLogPath,
698698 payload.endsWith("\n") ? payload : `${payload}\n`,
699699 "utf8",
apps/server/scripts/cursor-acp-model-mismatch-probe.ts+24−24
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import { spawn, type ChildProcessWithoutNullStreams } from "node:child_process";
3−import process from "node:process";
4−import readline from "node:readline";
2+import * as NodeChildProcess from "node:child_process";
3+import * as NodeProcess from "node:process";
4+import * as NodeReadline from "node:readline";
55 import * as NodeTimers from "node:timers";
66 import { resolveSpawnCommand } from "@t3tools/shared/shell";
77 import * as Effect from "effect/Effect";
@@ -56,19 +56,19 @@ type PendingRequest = { · 48 unmodified lines
5656 reject: (error: Error) => void;
5757 };
5858
59−const targetCwd = process.argv[2] ?? process.cwd();
60−const targetModel = process.argv[3] ?? "gpt-5.4";
61−const promptText = process.argv[4] ?? "helo";
62−const targetReasoning = process.env.CURSOR_REASONING ?? "";
63−const targetContext = process.env.CURSOR_CONTEXT ?? "";
64−const targetFast = process.env.CURSOR_FAST ?? "";
65−const agentBin = process.env.CURSOR_AGENT_BIN ?? "agent";
66−const promptWaitMs = Number(process.env.CURSOR_PROMPT_WAIT_MS ?? "4000");
67−const requestTimeoutMs = Number(process.env.CURSOR_REQUEST_TIMEOUT_MS ?? "20000");
59+const targetCwd = NodeProcess.argv[2] ?? NodeProcess.cwd();
60+const targetModel = NodeProcess.argv[3] ?? "gpt-5.4";
61+const promptText = NodeProcess.argv[4] ?? "helo";
62+const targetReasoning = NodeProcess.env.CURSOR_REASONING ?? "";
63+const targetContext = NodeProcess.env.CURSOR_CONTEXT ?? "";
64+const targetFast = NodeProcess.env.CURSOR_FAST ?? "";
65+const agentBin = NodeProcess.env.CURSOR_AGENT_BIN ?? "agent";
66+const promptWaitMs = Number(NodeProcess.env.CURSOR_PROMPT_WAIT_MS ?? "4000");
67+const requestTimeoutMs = Number(NodeProcess.env.CURSOR_REQUEST_TIMEOUT_MS ?? "20000");
6868
6969 function logSection(title: string, value: unknown) {
70− process.stdout.write(`\n=== ${title} ===\n`);
71− process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
70+ NodeProcess.stdout.write(`\n=== ${title} ===\n`);
71+ NodeProcess.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
7272 }
7373
7474 function fail(message: string): never {
@@ -124,18 +124,18 @@ function sleep(ms: number) { · 49 unmodified lines
124124 }
125125
126126 class JsonRpcChild {
127− readonly child: ChildProcessWithoutNullStreams;
127+ readonly child: NodeChildProcess.ChildProcessWithoutNullStreams;
128128 readonly pending = new Map<JsonRpcId, PendingRequest>();
129129 nextId = 1;
130130 closed = false;
131131
132132 constructor(bin: string, args: string[], cwd: string) {
133133 const spawnCommand = Effect.runSync(resolveSpawnCommand(bin, args));
134− this.child = spawn(spawnCommand.command, spawnCommand.args, {
134+ this.child = NodeChildProcess.spawn(spawnCommand.command, spawnCommand.args, {
135135 cwd,
136136 shell: spawnCommand.shell,
137137 stdio: ["pipe", "pipe", "pipe"],
138− env: process.env,
138+ env: NodeProcess.env,
139139 });
140140
141141 this.child.on("exit", (code, signal) => {
@@ -155,14 +155,14 @@ class JsonRpcChild { · 13 unmodified lines
155155 this.pending.clear();
156156 });
157157
158− const stdout = readline.createInterface({ input: this.child.stdout });
158+ const stdout = NodeReadline.createInterface({ input: this.child.stdout });
159159 stdout.on("line", (line) => {
160160 void this.handleStdoutLine(line);
161161 });
162162
163− const stderr = readline.createInterface({ input: this.child.stderr });
163+ const stderr = NodeReadline.createInterface({ input: this.child.stderr });
164164 stderr.on("line", (line) => {
165− process.stdout.write(`[stderr] ${line}\n`);
165+ NodeProcess.stdout.write(`[stderr] ${line}\n`);
166166 });
167167 }
168168
@@ -175,7 +175,7 @@ class JsonRpcChild { · 6 unmodified lines
175175 headers: [],
176176 ...message,
177177 });
178− process.stdout.write(`>>> ${payload}\n`);
178+ NodeProcess.stdout.write(`>>> ${payload}\n`);
179179 this.child.stdin.write(`${payload}\n`);
180180 }
181181
@@ -240,13 +240,13 @@ class JsonRpcChild { · 58 unmodified lines
240240 return;
241241 }
242242
243− process.stdout.write(`<<< ${line}\n`);
243+ NodeProcess.stdout.write(`<<< ${line}\n`);
244244
245245 let message: JsonRpcMessage;
246246 try {
247247 message = JSON.parse(line) as JsonRpcMessage;
248248 } catch (error) {
249− process.stdout.write(`[parse-error] ${(error as Error).message}\n`);
249+ NodeProcess.stdout.write(`[parse-error] ${(error as Error).message}\n`);
250250 return;
251251 }
252252
@@ -435,7 +435,7 @@ async function main() { · 182 unmodified lines
435435 }
436436
437437 void main().catch((error: unknown) => {
438− process.stderr.write(
438+ NodeProcess.stderr.write(
439439 `${error instanceof Error ? (error.stack ?? error.message) : String(error)}\n`,
440440 );
441441 process.exitCode = 1;
apps/server/src/attachmentPaths.ts+1−1
@@ -1,5 +1,5 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import NodePath from "node:path";
2+import * as NodePath from "node:path";
33
44 export function normalizeAttachmentRelativePath(rawRelativePath: string): string | null {
55 const normalized = NodePath.normalize(rawRelativePath).replace(/^[/\\]+/, "");
apps/server/src/attachmentStore.test.ts+13−9
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import fs from "node:fs";
3−import os from "node:os";
4−import path from "node:path";
2+import * as NodeFS from "node:fs";
3+import * as NodeOS from "node:os";
4+import * as NodePath from "node:path";
55
66 import { describe, expect, it } from "vite-plus/test";
77
@@ -45,11 +45,13 @@ describe("attachmentStore", () => { · 37 unmodified lines
4545 });
4646
4747 it("resolves attachment path by id using the extension that exists on disk", () => {
48− const attachmentsDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3code-attachment-store-"));
48+ const attachmentsDir = NodeFS.mkdtempSync(
49+ NodePath.join(NodeOS.tmpdir(), "t3code-attachment-store-"),
50+ );
4951 try {
5052 const attachmentId = "thread-1-attachment";
51− const pngPath = path.join(attachmentsDir, `${attachmentId}.png`);
52− fs.writeFileSync(pngPath, Buffer.from("hello"));
53+ const pngPath = NodePath.join(attachmentsDir, `${attachmentId}.png`);
54+ NodeFS.writeFileSync(pngPath, Buffer.from("hello"));
5355
5456 const resolved = resolveAttachmentPathById({
5557 attachmentsDir,
@@ -57,12 +59,14 @@ describe("attachmentStore", () => { · 1 unmodified line
5759 });
5860 expect(resolved).toBe(pngPath);
5961 } finally {
60− fs.rmSync(attachmentsDir, { recursive: true, force: true });
62+ NodeFS.rmSync(attachmentsDir, { recursive: true, force: true });
6163 }
6264 });
6365
6466 it("returns null when no attachment file exists for the id", () => {
65− const attachmentsDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3code-attachment-store-"));
67+ const attachmentsDir = NodeFS.mkdtempSync(
68+ NodePath.join(NodeOS.tmpdir(), "t3code-attachment-store-"),
69+ );
6670 try {
6771 const resolved = resolveAttachmentPathById({
6872 attachmentsDir,
@@ -70,7 +74,7 @@ describe("attachmentStore", () => { · 1 unmodified line
7074 });
7175 expect(resolved).toBeNull();
7276 } finally {
73− fs.rmSync(attachmentsDir, { recursive: true, force: true });
77+ NodeFS.rmSync(attachmentsDir, { recursive: true, force: true });
7478 }
7579 });
7680 });
apps/server/src/attachmentStore.ts+4−4
@@ -1,6 +1,6 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import { randomUUID } from "node:crypto";
3−import { existsSync } from "node:fs";
2+import * as NodeCrypto from "node:crypto";
3+import * as NodeFS from "node:fs";
44
55 import type { ChatAttachment } from "@t3tools/contracts";
66
@@ -39,7 +39,7 @@ export function createAttachmentId(threadId: string): string | null { · 32 unmodified lines
3939 if (!threadSegment) {
4040 return null;
4141 }
42− return `${threadSegment}-${randomUUID()}`;
42+ return `${threadSegment}-${NodeCrypto.randomUUID()}`;
4343 }
4444
4545 export function parseThreadSegmentFromAttachmentId(attachmentId: string): string | null {
@@ -89,7 +89,7 @@ export function resolveAttachmentPathById(input: { · 43 unmodified lines
8989 attachmentsDir: input.attachmentsDir,
9090 relativePath: `${normalizedId}${extension}`,
9191 });
92− if (maybePath && existsSync(maybePath)) {
92+ if (maybePath && NodeFS.existsSync(maybePath)) {
9393 return maybePath;
9494 }
9595 }
apps/server/src/auth/utils.ts+3−3
@@ -4,7 +4,7 @@ import type { · 3 unmodified lines
44 AuthClientPresentationMetadata,
55 } from "@t3tools/contracts";
66 import type * as HttpServerRequest from "effect/unstable/http/HttpServerRequest";
7−import * as Crypto from "node:crypto";
7+import * as NodeCrypto from "node:crypto";
88 import * as Encoding from "effect/Encoding";
99 import * as Result from "effect/Result";
1010
@@ -32,7 +32,7 @@ export function base64UrlDecodeUtf8(input: string): string { · 21 unmodified lines
3232 }
3333
3434 export function signPayload(payload: string, secret: Uint8Array): string {
35− return Crypto.createHmac("sha256", Buffer.from(secret)).update(payload).digest("base64url");
35+ return NodeCrypto.createHmac("sha256", Buffer.from(secret)).update(payload).digest("base64url");
3636 }
3737
3838 export function timingSafeEqualBase64Url(left: string, right: string): boolean {
@@ -41,7 +41,7 @@ export function timingSafeEqualBase64Url(left: string, right: string): boolean { · 2 unmodified lines
4141 if (leftBuffer.length !== rightBuffer.length) {
4242 return false;
4343 }
44− return Crypto.timingSafeEqual(leftBuffer, rightBuffer);
44+ return NodeCrypto.timingSafeEqual(leftBuffer, rightBuffer);
4545 }
4646
4747 function normalizeNonEmptyString(value: string | null | undefined): string | undefined {
apps/server/src/bin.test.ts+47−25
@@ -1,8 +1,8 @@
11 // @effect-diagnostics nodeBuiltinImport:off - CLI integration exercises Node HTTP and filesystem boundaries.
2−import { createServer } from "node:http";
3−import { existsSync, mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
4−import { tmpdir } from "node:os";
5−import { join } from "node:path";
2+import * as NodeHttp from "node:http";
3+import * as NodeFS from "node:fs";
4+import * as NodeOS from "node:os";
5+import * as NodePath from "node:path";
66
77 import * as NodeHttpServer from "@effect/platform-node/NodeHttpServer";
88 import * as NodeServices from "@effect/platform-node/NodeServices";
@@ -124,7 +124,7 @@ const withLiveProjectCliServer = <A, E, R>(baseDir: string, run: () => Effect.Ef · 115 unmodified lines
124124 ),
125125 Layer.provideMerge(makeProjectPersistenceLayer(config)),
126126 Layer.provideMerge(
127− NodeHttpServer.layer(createServer, {
127+ NodeHttpServer.layer(NodeHttp.createServer, {
128128 host: "127.0.0.1",
129129 port: 0,
130130 }),
@@ -197,7 +197,9 @@ it.layer(NodeServices.layer)("bin cli parsing", (it) => { · 66 unmodified lines
197197
198198 it.effect("reports fresh headless connect state without requiring local configuration", () =>
199199 Effect.gen(function* () {
200− const baseDir = mkdtempSync(join(tmpdir(), "t3-cli-cloud-status-test-"));
200+ const baseDir = NodeFS.mkdtempSync(
201+ NodePath.join(NodeOS.tmpdir(), "t3-cli-cloud-status-test-"),
202+ );
201203 const { output } = yield* captureStdout(
202204 runConnectCli(["connect", "status", "--base-dir", baseDir, "--json"]),
203205 );
@@ -220,7 +222,9 @@ it.layer(NodeServices.layer)("bin cli parsing", (it) => { · 16 unmodified lines
220222
221223 it.effect("reports actionable human-readable headless connect state", () =>
222224 Effect.gen(function* () {
223− const baseDir = mkdtempSync(join(tmpdir(), "t3-cli-cloud-status-human-test-"));
225+ const baseDir = NodeFS.mkdtempSync(
226+ NodePath.join(NodeOS.tmpdir(), "t3-cli-cloud-status-human-test-"),
227+ );
224228 const { output } = yield* captureStdout(
225229 runConnectCli(["connect", "status", "--base-dir", baseDir]),
226230 );
@@ -234,11 +238,13 @@ it.layer(NodeServices.layer)("bin cli parsing", (it) => { · 7 unmodified lines
234238
235239 it.effect("logs in to headless connect without enabling access", () =>
236240 Effect.gen(function* () {
237− const baseDir = mkdtempSync(join(tmpdir(), "t3-cli-cloud-login-test-"));
241+ const baseDir = NodeFS.mkdtempSync(
242+ NodePath.join(NodeOS.tmpdir(), "t3-cli-cloud-login-test-"),
243+ );
238244 const { secretsDir } = yield* ServerConfig.deriveServerPaths(baseDir, undefined);
239− mkdirSync(secretsDir, { recursive: true });
240− writeFileSync(
241− join(secretsDir, "cloud-cli-oauth-token.bin"),
245+ NodeFS.mkdirSync(secretsDir, { recursive: true });
246+ NodeFS.writeFileSync(
247+ NodePath.join(secretsDir, "cloud-cli-oauth-token.bin"),
242248 // @effect-diagnostics-next-line preferSchemaOverJson:off - Test fixture matches the persisted CLI token representation.
243249 JSON.stringify({
244250 accessToken: "access-token",
@@ -267,7 +273,9 @@ it.layer(NodeServices.layer)("bin cli parsing", (it) => { · 22 unmodified lines
267273
268274 it.effect("disables headless connect without a running server", () =>
269275 Effect.gen(function* () {
270− const baseDir = mkdtempSync(join(tmpdir(), "t3-cli-cloud-unlink-test-"));
276+ const baseDir = NodeFS.mkdtempSync(
277+ NodePath.join(NodeOS.tmpdir(), "t3-cli-cloud-unlink-test-"),
278+ );
271279 const { output } = yield* captureStdout(
272280 runConnectCli(["connect", "unlink", "--base-dir", baseDir]),
273281 );
@@ -278,24 +286,28 @@ it.layer(NodeServices.layer)("bin cli parsing", (it) => { · 4 unmodified lines
278286
279287 it.effect("logs out of headless connect and removes the stored CLI authorization", () =>
280288 Effect.gen(function* () {
281− const baseDir = mkdtempSync(join(tmpdir(), "t3-cli-cloud-logout-test-"));
289+ const baseDir = NodeFS.mkdtempSync(
290+ NodePath.join(NodeOS.tmpdir(), "t3-cli-cloud-logout-test-"),
291+ );
282292 const { secretsDir } = yield* ServerConfig.deriveServerPaths(baseDir, undefined);
283− const tokenPath = join(secretsDir, "cloud-cli-oauth-token.bin");
284− mkdirSync(secretsDir, { recursive: true });
285− writeFileSync(tokenPath, "invalid persisted token");
293+ const tokenPath = NodePath.join(secretsDir, "cloud-cli-oauth-token.bin");
294+ NodeFS.mkdirSync(secretsDir, { recursive: true });
295+ NodeFS.writeFileSync(tokenPath, "invalid persisted token");
286296
287297 const { output } = yield* captureStdout(
288298 runConnectCli(["connect", "logout", "--base-dir", baseDir]),
289299 );
290300
291301 assert.equal(output, "Signed out of T3 Connect locally.");
292− assert.isFalse(existsSync(tokenPath));
302+ assert.isFalse(NodeFS.existsSync(tokenPath));
293303 }),
294304 );
295305
296306 it.effect("executes auth pairing subcommands and redacts secrets from list output", () =>
297307 Effect.gen(function* () {
298− const baseDir = mkdtempSync(join(tmpdir(), "t3-cli-auth-pairing-test-"));
308+ const baseDir = NodeFS.mkdtempSync(
309+ NodePath.join(NodeOS.tmpdir(), "t3-cli-auth-pairing-test-"),
310+ );
299311
300312 const createdOutput = yield* captureStdout(
301313 runCli(["auth", "pairing", "create", "--base-dir", baseDir, "--json"]),
@@ -325,7 +337,9 @@ it.layer(NodeServices.layer)("bin cli parsing", (it) => { · 23 unmodified lines
325337
326338 it.effect("executes auth session subcommands and redacts secrets from list output", () =>
327339 Effect.gen(function* () {
328− const baseDir = mkdtempSync(join(tmpdir(), "t3-cli-auth-session-test-"));
340+ const baseDir = NodeFS.mkdtempSync(
341+ NodePath.join(NodeOS.tmpdir(), "t3-cli-auth-session-test-"),
342+ );
329343
330344 const issuedOutput = yield* captureStdout(
331345 runCli(["auth", "session", "issue", "--base-dir", baseDir, "--json"]),
@@ -400,8 +414,12 @@ it.layer(NodeServices.layer)("bin cli parsing", (it) => { · 68 unmodified lines
400414
401415 it.effect("adds, renames, and removes projects offline through the orchestration engine", () =>
402416 Effect.gen(function* () {
403− const baseDir = mkdtempSync(join(tmpdir(), "t3-cli-projects-offline-test-"));
404− const workspaceRoot = mkdtempSync(join(tmpdir(), "t3-cli-projects-workspace-"));
417+ const baseDir = NodeFS.mkdtempSync(
418+ NodePath.join(NodeOS.tmpdir(), "t3-cli-projects-offline-test-"),
419+ );
420+ const workspaceRoot = NodeFS.mkdtempSync(
421+ NodePath.join(NodeOS.tmpdir(), "t3-cli-projects-workspace-"),
422+ );
405423
406424 yield* runCliWithRuntime([
407425 "project",
@@ -444,8 +462,12 @@ it.layer(NodeServices.layer)("bin cli parsing", (it) => { · 36 unmodified lines
444462
445463 it.effect("routes project commands through a running server when runtime state is present", () =>
446464 Effect.gen(function* () {
447− const baseDir = mkdtempSync(join(tmpdir(), "t3-cli-projects-live-test-"));
448− const workspaceRoot = mkdtempSync(join(tmpdir(), "t3-cli-projects-live-workspace-"));
465+ const baseDir = NodeFS.mkdtempSync(
466+ NodePath.join(NodeOS.tmpdir(), "t3-cli-projects-live-test-"),
467+ );
468+ const workspaceRoot = NodeFS.mkdtempSync(
469+ NodePath.join(NodeOS.tmpdir(), "t3-cli-projects-live-workspace-"),
470+ );
449471
450472 yield* withLiveProjectCliServer(baseDir, () =>
451473 Effect.gen(function* () {
@@ -472,8 +494,8 @@ it.layer(NodeServices.layer)("bin cli parsing", (it) => { · 20 unmodified lines
472494
473495 it.effect("rejects dev-url on project commands", () =>
474496 Effect.gen(function* () {
475− const workspaceRoot = mkdtempSync(
476− join(tmpdir(), "t3-cli-projects-unknown-option-workspace-"),
497+ const workspaceRoot = NodeFS.mkdtempSync(
498+ NodePath.join(NodeOS.tmpdir(), "t3-cli-projects-unknown-option-workspace-"),
477499 );
478500 const error = yield* runCliWithRuntime([
479501 "project",
apps/server/src/bootstrap.test.ts+13−13
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import * as NFS from "node:fs";
3−import * as path from "node:path";
4−import { execFileSync, spawn } from "node:child_process";
2+import * as NodeFS from "node:fs";
3+import * as NodePath from "node:path";
4+import * as NodeChildProcess from "node:child_process";
55 import * as NodeServices from "@effect/platform-node/NodeServices";
66 import { it } from "@effect/vitest";
77 import * as FileSystem from "effect/FileSystem";
@@ -53,8 +53,8 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => { · 45 unmodified lines
5353 );
5454
5555 const fd = yield* Effect.acquireRelease(
56− Effect.sync(() => NFS.openSync(filePath, "r")),
57− (fd) => Effect.sync(() => NFS.closeSync(fd)),
56+ Effect.sync(() => NodeFS.openSync(filePath, "r")),
57+ (fd) => Effect.sync(() => NodeFS.closeSync(fd)),
5858 );
5959
6060 const payload = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, { timeoutMs: 100 });
@@ -78,7 +78,7 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => { · 17 unmodified lines
7878 // so the stream owns the fd lifecycle and closes it asynchronously on end.
7979 // Attempting to also close it synchronously in a finalizer races with the
8080 // stream's async close and produces an uncaught EBADF.
81− const fd = NFS.openSync(filePath, "r");
81+ const fd = NodeFS.openSync(filePath, "r");
8282
8383 openSyncInterceptor.failPath = `/proc/self/fd/${fd}`;
8484 try {
@@ -96,8 +96,8 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => { · 11 unmodified lines
9696
9797 it.effect("returns none when the fd is unavailable", () =>
9898 Effect.gen(function* () {
99− const fd = NFS.openSync("/dev/null", "r");
100− NFS.closeSync(fd);
99+ const fd = NodeFS.openSync("/dev/null", "r");
100+ NodeFS.closeSync(fd);
101101
102102 const payload = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, { timeoutMs: 100 });
103103 assertNone(payload);
@@ -108,13 +108,13 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => { · 4 unmodified lines
108108 Effect.gen(function* () {
109109 const fs = yield* FileSystem.FileSystem;
110110 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-bootstrap-" });
111− const fifoPath = path.join(tempDir, "bootstrap.pipe");
111+ const fifoPath = NodePath.join(tempDir, "bootstrap.pipe");
112112
113− yield* Effect.sync(() => execFileSync("mkfifo", [fifoPath]));
113+ yield* Effect.sync(() => NodeChildProcess.execFileSync("mkfifo", [fifoPath]));
114114
115115 const _writer = yield* Effect.acquireRelease(
116116 Effect.sync(() =>
117− spawn("sh", ["-c", 'exec 3>"$1"; sleep 60', "sh", fifoPath], {
117+ NodeChildProcess.spawn("sh", ["-c", 'exec 3>"$1"; sleep 60', "sh", fifoPath], {
118118 stdio: ["ignore", "ignore", "ignore"],
119119 }),
120120 ),
@@ -125,8 +125,8 @@ it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => { · 4 unmodified lines
125125 );
126126
127127 const fd = yield* Effect.acquireRelease(
128− Effect.sync(() => NFS.openSync(fifoPath, "r")),
129− (fd) => Effect.sync(() => NFS.closeSync(fd)),
128+ Effect.sync(() => NodeFS.openSync(fifoPath, "r")),
129+ (fd) => Effect.sync(() => NodeFS.closeSync(fd)),
130130 );
131131
132132 const fiber = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, {
apps/server/src/bootstrap.ts+13−13
@@ -1,8 +1,8 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import * as NFS from "node:fs";
3−import * as Net from "node:net";
4−import * as readline from "node:readline";
5−import type { Readable } from "node:stream";
2+import * as NodeFS from "node:fs";
3+import * as NodeNet from "node:net";
4+import * as NodeReadline from "node:readline";
5+import type * as NodeStream from "node:stream";
66
77 import * as Data from "effect/Data";
88 import * as Effect from "effect/Effect";
@@ -33,7 +33,7 @@ export const readBootstrapEnvelope = Effect.fn("readBootstrapEnvelope")(function · 24 unmodified lines
3333 const timeoutMs = options?.timeoutMs ?? 1000;
3434
3535 return yield* Effect.callback<Option.Option<A>, BootstrapError>((resume) => {
36− const input = readline.createInterface({
36+ const input = NodeReadline.createInterface({
3737 input: stream,
3838 crlfDelay: Infinity,
3939 });
@@ -96,7 +96,7 @@ const isUnavailableBootstrapFdError = Predicate.compose( · 56 unmodified lines
9696
9797 const isFdReady = (fd: number) =>
9898 Effect.try({
99− try: () => NFS.fstatSync(fd),
99+ try: () => NodeFS.fstatSync(fd),
100100 catch: (error) =>
101101 new BootstrapError({
102102 message: "Failed to stat bootstrap fd.",
@@ -113,7 +113,7 @@ const isFdReady = (fd: number) => · 10 unmodified lines
113113 const makeBootstrapInputStream = (fd: number) =>
114114 Effect.gen(function* () {
115115 const platform = yield* HostProcessPlatform;
116− return yield* Effect.try<Readable, BootstrapError>({
116+ return yield* Effect.try<NodeStream.Readable, BootstrapError>({
117117 try: () => {
118118 const fdPath = resolveFdPath(fd, platform);
119119 if (fdPath === undefined) {
@@ -122,8 +122,8 @@ const makeBootstrapInputStream = (fd: number) => · 2 unmodified lines
122122
123123 let streamFd: number | undefined;
124124 try {
125− streamFd = NFS.openSync(fdPath, "r");
126− return NFS.createReadStream("", {
125+ streamFd = NodeFS.openSync(fdPath, "r");
126+ return NodeFS.createReadStream("", {
127127 fd: streamFd,
128128 encoding: "utf8",
129129 autoClose: true,
@@ -131,7 +131,7 @@ const makeBootstrapInputStream = (fd: number) => · 1 unmodified line
131131 } catch (error) {
132132 if (isBootstrapFdPathDuplicationError(error)) {
133133 if (streamFd !== undefined) {
134− NFS.closeSync(streamFd);
134+ NodeFS.closeSync(streamFd);
135135 }
136136 return makeDirectBootstrapStream(fd);
137137 }
@@ -146,15 +146,15 @@ const makeBootstrapInputStream = (fd: number) => · 8 unmodified lines
146146 });
147147 });
148148
149−const makeDirectBootstrapStream = (fd: number): Readable => {
149+const makeDirectBootstrapStream = (fd: number): NodeStream.Readable => {
150150 try {
151− return NFS.createReadStream("", {
151+ return NodeFS.createReadStream("", {
152152 fd,
153153 encoding: "utf8",
154154 autoClose: true,
155155 });
156156 } catch {
157− const stream = new Net.Socket({
157+ const stream = new NodeNet.Socket({
158158 fd,
159159 readable: true,
160160 writable: false,
apps/server/src/checkpointing/CheckpointStore.test.ts+4−4
@@ -1,5 +1,5 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import path from "node:path";
2+import * as NodePath from "node:path";
33
44 import * as NodeServices from "@effect/platform-node/NodeServices";
55 import { it } from "@effect/vitest";
@@ -80,7 +80,7 @@ function initRepoWithCommit( · 74 unmodified lines
8080 yield* git(cwd, ["init"]);
8181 yield* git(cwd, ["config", "user.email", "test@test.com"]);
8282 yield* git(cwd, ["config", "user.name", "Test"]);
83− yield* writeTextFile(path.join(cwd, "README.md"), "# test\n");
83+ yield* writeTextFile(NodePath.join(cwd, "README.md"), "# test\n");
8484 yield* git(cwd, ["add", "."]);
8585 yield* git(cwd, ["commit", "-m", "initial commit"]);
8686 });
@@ -107,7 +107,7 @@ it.layer(TestLayer)("CheckpointStore.layer", (it) => { · 20 unmodified lines
107107 cwd: tmp,
108108 checkpointRef: fromCheckpointRef,
109109 });
110− yield* writeTextFile(path.join(tmp, "README.md"), buildLargeText());
110+ yield* writeTextFile(NodePath.join(tmp, "README.md"), buildLargeText());
111111 yield* checkpointStore.captureCheckpoint({
112112 cwd: tmp,
113113 checkpointRef: toCheckpointRef,
@@ -135,7 +135,7 @@ it.layer(TestLayer)("CheckpointStore.layer", (it) => { · 21 unmodified lines
135135 const fromCheckpointRef = checkpointRefForThreadTurn(threadId, 0);
136136 const toCheckpointRef = checkpointRefForThreadTurn(threadId, 1);
137137
138− const componentPath = path.join(tmp, "Component.tsx");
138+ const componentPath = NodePath.join(tmp, "Component.tsx");
139139 yield* writeTextFile(
140140 componentPath,
141141 [
apps/server/src/cloud/CliTokenManager.ts+2−2
@@ -1,5 +1,5 @@
11 // @effect-diagnostics nodeBuiltinImport:off - The CLI loopback OAuth callback is a Node HTTP boundary.
2−import { createServer } from "node:http";
2+import * as NodeHttp from "node:http";
33
44 import * as NodeHttpServer from "@effect/platform-node/NodeHttpServer";
55 import * as Clock from "effect/Clock";
@@ -206,7 +206,7 @@ export const make = Effect.gen(function* () { · 200 unmodified lines
206206 disableLogger: true,
207207 }).pipe(
208208 Layer.provide(
209− NodeHttpServer.layer(createServer, {
209+ NodeHttpServer.layer(NodeHttp.createServer, {
210210 host: "127.0.0.1",
211211 port: 34338,
212212 disablePreemptiveShutdown: true,
apps/server/src/cloud/http.ts+2−2
@@ -1,4 +1,4 @@
1−import { createPublicKey } from "node:crypto";
1+import * as NodeCrypto from "node:crypto";
22 import {
33 AuthRelayReadScope,
44 AuthRelayWriteScope,
@@ -152,7 +152,7 @@ function validateCloudMintPublicKey( · 147 unmodified lines
152152 publicKey: string,
153153 ): Effect.Effect<void, EnvironmentHttpBadRequestError> {
154154 return Effect.try({
155− try: () => createPublicKey(publicKey.replace(/\\n/g, "\n")),
155+ try: () => NodeCrypto.createPublicKey(publicKey.replace(/\\n/g, "\n")),
156156 catch: () =>
157157 new EnvironmentHttpBadRequestError({
158158 message: "Cloud mint public key must be a valid Ed25519 public key.",
apps/server/src/environment/ServerEnvironment.test.ts+2−2
@@ -1,5 +1,5 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import { dirname } from "node:path";
2+import * as NodePath from "node:path";
33 import * as NodeServices from "@effect/platform-node/NodeServices";
44 import { expect, it } from "@effect/vitest";
55 import * as Effect from "effect/Effect";
@@ -76,7 +76,7 @@ it.layer(NodeServices.layer)("ServerEnvironmentLive", (it) => { · 70 unmodified lines
7676 });
7777 const serverConfig = yield* makeServerConfig(baseDir);
7878 const environmentIdPath = serverConfig.environmentIdPath;
79− yield* fileSystem.makeDirectory(dirname(environmentIdPath), { recursive: true });
79+ yield* fileSystem.makeDirectory(NodePath.dirname(environmentIdPath), { recursive: true });
8080 yield* fileSystem.writeFileString(environmentIdPath, "persisted-environment-id\n");
8181 const writeAttempts: string[] = [];
8282 const failingFileSystemLayer = FileSystem.layerNoop({
apps/server/src/git/GitManager.test.ts+64−56
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import fs from "node:fs";
3−import path from "node:path";
4−import { spawnSync } from "node:child_process";
2+import * as NodeFS from "node:fs";
3+import * as NodePath from "node:path";
4+import * as NodeChildProcess from "node:child_process";
55
66 import * as NodeServices from "@effect/platform-node/NodeServices";
77 import { it } from "@effect/vitest";
@@ -164,7 +164,7 @@ function normalizeFakePullRequestSummary(raw: unknown): GitHubCli.GitHubPullRequ · 156 unmodified lines
164164 }
165165
166166 function runGitSyncForFakeGh(cwd: string, args: readonly string[]): void {
167− const result = spawnSync("git", args, {
167+ const result = NodeChildProcess.spawnSync("git", args, {
168168 cwd,
169169 encoding: "utf8",
170170 });
@@ -254,7 +254,7 @@ function initRepo( · 83 unmodified lines
254254 yield* runGit(cwd, ["init", "--initial-branch=main"]);
255255 yield* runGit(cwd, ["config", "user.email", "test@example.com"]);
256256 yield* runGit(cwd, ["config", "user.name", "Test User"]);
257− yield* fs.writeFileString(path.join(cwd, "README.md"), "hello\n");
257+ yield* fs.writeFileString(NodePath.join(cwd, "README.md"), "hello\n");
258258 yield* runGit(cwd, ["add", "README.md"]);
259259 yield* runGit(cwd, ["commit", "-m", "Initial commit"]);
260260 });
@@ -459,7 +459,7 @@ function createGitHubCliWithFakeGh(scenario: FakeGhScenario = {}): { · 198 unmodified lines
459459 try: () => {
460460 const headBranch = scenario.pullRequest?.headRefName;
461461 if (headBranch) {
462− const existingBranch = spawnSync(
462+ const existingBranch = NodeChildProcess.spawnSync(
463463 "git",
464464 ["show-ref", "--verify", "--quiet", `refs/heads/${headBranch}`],
465465 {
@@ -916,7 +916,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 450 unmodified lines
916916 it.effect("status returns an explicit non-repo result for deleted directories", () =>
917917 Effect.gen(function* () {
918918 const rootDir = yield* makeTempDir("t3code-git-manager-missing-dir-");
919− const cwd = path.join(rootDir, "deleted-repo");
919+ const cwd = NodePath.join(rootDir, "deleted-repo");
920920 yield* makeDirectory(cwd);
921921 yield* removePath(cwd);
922922 const { manager } = yield* makeManager();
@@ -1026,7 +1026,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 103 unmodified lines
10261026 const forkDir = yield* createBareRemote();
10271027 yield* runGit(repoDir, ["remote", "add", "fork-seed", forkDir]);
10281028 yield* runGit(repoDir, ["checkout", "-b", "statemachine"]);
1029− fs.writeFileSync(path.join(repoDir, "fork-pr.txt"), "fork pr\n");
1029+ NodeFS.writeFileSync(NodePath.join(repoDir, "fork-pr.txt"), "fork pr\n");
10301030 yield* runGit(repoDir, ["add", "fork-pr.txt"]);
10311031 yield* runGit(repoDir, ["commit", "-m", "Fork PR branch"]);
10321032 yield* runGit(repoDir, ["push", "-u", "fork-seed", "statemachine"]);
@@ -1348,7 +1348,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 315 unmodified lines
13481348 Effect.gen(function* () {
13491349 const repoDir = yield* makeTempDir("t3code-git-manager-");
13501350 yield* initRepo(repoDir);
1351− fs.writeFileSync(path.join(repoDir, "README.md"), "hello\nworld\n");
1351+ NodeFS.writeFileSync(NodePath.join(repoDir, "README.md"), "hello\nworld\n");
13521352
13531353 const { manager } = yield* makeManager();
13541354 const result = yield* runStackedAction(manager, {
@@ -1383,7 +1383,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 28 unmodified lines
13831383 Effect.gen(function* () {
13841384 const repoDir = yield* makeTempDir("t3code-git-manager-");
13851385 yield* initRepo(repoDir);
1386− fs.writeFileSync(path.join(repoDir, "README.md"), "hello\ncustom\n");
1386+ NodeFS.writeFileSync(NodePath.join(repoDir, "README.md"), "hello\ncustom\n");
13871387 let generatedCount = 0;
13881388
13891389 const { manager } = yield* makeManager({
@@ -1426,8 +1426,8 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 36 unmodified lines
14261426 Effect.gen(function* () {
14271427 const repoDir = yield* makeTempDir("t3code-git-manager-");
14281428 yield* initRepo(repoDir);
1429− fs.writeFileSync(path.join(repoDir, "a.txt"), "file a\n");
1430− fs.writeFileSync(path.join(repoDir, "b.txt"), "file b\n");
1429+ NodeFS.writeFileSync(NodePath.join(repoDir, "a.txt"), "file a\n");
1430+ NodeFS.writeFileSync(NodePath.join(repoDir, "b.txt"), "file b\n");
14311431
14321432 const { manager } = yield* makeManager();
14331433 const result = yield* runStackedAction(manager, {
@@ -1454,7 +1454,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 20 unmodified lines
14541454 const remoteDir = yield* createBareRemote();
14551455 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
14561456 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
1457− fs.writeFileSync(path.join(repoDir, "README.md"), "hello\nfeature-branch\n");
1457+ NodeFS.writeFileSync(NodePath.join(repoDir, "README.md"), "hello\nfeature-branch\n");
14581458 let generatedCount = 0;
14591459
14601460 const { manager } = yield* makeManager({
@@ -1514,7 +1514,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 53 unmodified lines
15141514 Effect.gen(function* () {
15151515 const repoDir = yield* makeTempDir("t3code-git-manager-");
15161516 yield* initRepo(repoDir);
1517− fs.writeFileSync(path.join(repoDir, "README.md"), "hello\ncustom-feature\n");
1517+ NodeFS.writeFileSync(NodePath.join(repoDir, "README.md"), "hello\ncustom-feature\n");
15181518 let generatedCount = 0;
15191519
15201520 const { manager } = yield* makeManager({
@@ -1597,7 +1597,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 76 unmodified lines
15971597 yield* runGit(repoDir, ["checkout", "-b", "feature/stacked-flow"]);
15981598 const remoteDir = yield* createBareRemote();
15991599 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
1600− fs.writeFileSync(path.join(repoDir, "feature.txt"), "feature\n");
1600+ NodeFS.writeFileSync(NodePath.join(repoDir, "feature.txt"), "feature\n");
16011601
16021602 const { manager } = yield* makeManager();
16031603 const result = yield* runStackedAction(manager, {
@@ -1626,7 +1626,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 22 unmodified lines
16261626 yield* runGit(repoDir, ["checkout", "-b", "feature/no-upstream-pr"]);
16271627 const remoteDir = yield* createBareRemote();
16281628 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
1629− fs.writeFileSync(path.join(repoDir, "feature.txt"), "feature\n");
1629+ NodeFS.writeFileSync(NodePath.join(repoDir, "feature.txt"), "feature\n");
16301630
16311631 const { manager, ghCalls } = yield* makeManager({
16321632 ghScenario: {
@@ -1697,7 +1697,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 64 unmodified lines
16971697 yield* runGit(repoDir, ["checkout", "-b", "feature/push-only"]);
16981698 const remoteDir = yield* createBareRemote();
16991699 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
1700− fs.writeFileSync(path.join(repoDir, "push-only.txt"), "push only\n");
1700+ NodeFS.writeFileSync(NodePath.join(repoDir, "push-only.txt"), "push only\n");
17011701 yield* runGit(repoDir, ["add", "push-only.txt"]);
17021702 yield* runGit(repoDir, ["commit", "-m", "Push only branch"]);
17031703
@@ -1725,11 +1725,11 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 21 unmodified lines
17251725 yield* runGit(repoDir, ["checkout", "-b", "feature/push-dirty"]);
17261726 const remoteDir = yield* createBareRemote();
17271727 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
1728− fs.writeFileSync(path.join(repoDir, "push-dirty.txt"), "push dirty\n");
1728+ NodeFS.writeFileSync(NodePath.join(repoDir, "push-dirty.txt"), "push dirty\n");
17291729 yield* runGit(repoDir, ["add", "push-dirty.txt"]);
17301730 yield* runGit(repoDir, ["commit", "-m", "Push dirty branch"]);
1731− fs.mkdirSync(path.join(repoDir, ".vercel"));
1732− fs.writeFileSync(path.join(repoDir, ".vercel", "project.json"), "{}\n");
1731+ NodeFS.mkdirSync(NodePath.join(repoDir, ".vercel"));
1732+ NodeFS.writeFileSync(NodePath.join(repoDir, ".vercel", "project.json"), "{}\n");
17331733
17341734 const { manager } = yield* makeManager();
17351735 const result = yield* runStackedAction(manager, {
@@ -1760,7 +1760,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 24 unmodified lines
17601760 yield* runGit(repoDir, ["checkout", "-b", "feature/create-pr-only"]);
17611761 const remoteDir = yield* createBareRemote();
17621762 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
1763− fs.writeFileSync(path.join(repoDir, "create-pr-only.txt"), "create pr\n");
1763+ NodeFS.writeFileSync(NodePath.join(repoDir, "create-pr-only.txt"), "create pr\n");
17641764 yield* runGit(repoDir, ["add", "create-pr-only.txt"]);
17651765 yield* runGit(repoDir, ["commit", "-m", "Create PR only branch"]);
17661766
@@ -1805,7 +1805,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 38 unmodified lines
18051805 const repoDir = yield* makeTempDir("t3code-git-manager-");
18061806 yield* initRepo(repoDir);
18071807 yield* runGit(repoDir, ["checkout", "-b", "feature/provider-fallback"]);
1808− fs.writeFileSync(path.join(repoDir, "provider-fallback.txt"), "fallback\n");
1808+ NodeFS.writeFileSync(NodePath.join(repoDir, "provider-fallback.txt"), "fallback\n");
18091809 yield* runGit(repoDir, ["add", "provider-fallback.txt"]);
18101810 yield* runGit(repoDir, ["commit", "-m", "Provider fallback"]);
18111811 const remoteDir = yield* createBareRemote();
@@ -1982,7 +1982,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 170 unmodified lines
19821982 yield* runGit(repoDir, ["checkout", "main"]);
19831983 yield* runGit(repoDir, ["branch", "-D", "effect-atom"]);
19841984 yield* runGit(repoDir, ["checkout", "--track", "my-org/upstream/effect-atom"]);
1985− fs.writeFileSync(path.join(repoDir, "changes.txt"), "change\n");
1985+ NodeFS.writeFileSync(NodePath.join(repoDir, "changes.txt"), "change\n");
19861986 yield* runGit(repoDir, ["add", "changes.txt"]);
19871987 yield* runGit(repoDir, ["commit", "-m", "Feature commit"]);
19881988
@@ -2200,7 +2200,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 211 unmodified lines
22002200 yield* runGit(repoDir, ["checkout", "-b", "feature-create-pr"]);
22012201 const remoteDir = yield* createBareRemote();
22022202 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
2203− fs.writeFileSync(path.join(repoDir, "changes.txt"), "change\n");
2203+ NodeFS.writeFileSync(NodePath.join(repoDir, "changes.txt"), "change\n");
22042204 yield* runGit(repoDir, ["add", "changes.txt"]);
22052205 yield* runGit(repoDir, ["commit", "-m", "Feature commit"]);
22062206 yield* runGit(repoDir, ["push", "-u", "origin", "feature-create-pr"]);
@@ -2252,7 +2252,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 45 unmodified lines
22522252 yield* runGit(peerDir, ["clone", remoteDir, "."]);
22532253 yield* runGit(peerDir, ["config", "user.email", "peer@example.com"]);
22542254 yield* runGit(peerDir, ["config", "user.name", "Peer User"]);
2255− fs.writeFileSync(path.join(peerDir, "remote.txt"), "remote\n");
2255+ NodeFS.writeFileSync(NodePath.join(peerDir, "remote.txt"), "remote\n");
22562256 yield* runGit(peerDir, ["add", "remote.txt"]);
22572257 yield* runGit(peerDir, ["commit", "-m", "Remote base commit"]);
22582258 yield* runGit(peerDir, ["push", "origin", "main"]);
@@ -2265,7 +2265,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 6 unmodified lines
22652265 "feature/remote-base",
22662266 "origin/main",
22672267 ]);
2268− fs.writeFileSync(path.join(repoDir, "feature.txt"), "feature\n");
2268+ NodeFS.writeFileSync(NodePath.join(repoDir, "feature.txt"), "feature\n");
22692269 yield* runGit(repoDir, ["add", "feature.txt"]);
22702270 yield* runGit(repoDir, ["commit", "-m", "Feature commit"]);
22712271 yield* runGit(repoDir, ["push", "-u", "origin", "feature/remote-base"]);
@@ -2304,7 +2304,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 32 unmodified lines
23042304 yield* runGit(repoDir, ["checkout", "-b", "feature/no-fork-match"]);
23052305 const remoteDir = yield* createBareRemote();
23062306 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
2307− fs.writeFileSync(path.join(repoDir, "changes.txt"), "change\n");
2307+ NodeFS.writeFileSync(NodePath.join(repoDir, "changes.txt"), "change\n");
23082308 yield* runGit(repoDir, ["add", "changes.txt"]);
23092309 yield* runGit(repoDir, ["commit", "-m", "Feature commit"]);
23102310 yield* runGit(repoDir, ["push", "-u", "origin", "feature/no-fork-match"]);
@@ -2376,7 +2376,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 65 unmodified lines
23762376 const forkDir = yield* createBareRemote();
23772377 yield* runGit(repoDir, ["remote", "add", "fork-seed", forkDir]);
23782378 yield* runGit(repoDir, ["checkout", "-b", "statemachine"]);
2379− fs.writeFileSync(path.join(repoDir, "changes.txt"), "change\n");
2379+ NodeFS.writeFileSync(NodePath.join(repoDir, "changes.txt"), "change\n");
23802380 yield* runGit(repoDir, ["add", "changes.txt"]);
23812381 yield* runGit(repoDir, ["commit", "-m", "Feature commit"]);
23822382 yield* runGit(repoDir, ["push", "-u", "fork-seed", "statemachine"]);
@@ -2556,7 +2556,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 173 unmodified lines
25562556 const repoDir = yield* makeTempDir("t3code-git-manager-");
25572557 yield* initRepo(repoDir);
25582558 yield* runGit(repoDir, ["checkout", "-b", "feature/pr-local"]);
2559− fs.writeFileSync(path.join(repoDir, "local.txt"), "local\n");
2559+ NodeFS.writeFileSync(NodePath.join(repoDir, "local.txt"), "local\n");
25602560 yield* runGit(repoDir, ["add", "local.txt"]);
25612561 yield* runGit(repoDir, ["commit", "-m", "Local PR branch"]);
25622562
@@ -2597,7 +2597,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 34 unmodified lines
25972597 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
25982598 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
25992599 yield* runGit(repoDir, ["checkout", "-b", "feature/pr-local-upstream"]);
2600− fs.writeFileSync(path.join(repoDir, "upstream.txt"), "upstream\n");
2600+ NodeFS.writeFileSync(NodePath.join(repoDir, "upstream.txt"), "upstream\n");
26012601 yield* runGit(repoDir, ["add", "upstream.txt"]);
26022602 yield* runGit(repoDir, ["commit", "-m", "Local upstream PR branch"]);
26032603 yield* runGit(repoDir, ["push", "-u", "origin", "feature/pr-local-upstream"]);
@@ -2655,7 +2655,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 51 unmodified lines
26552655 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
26562656 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
26572657 yield* runGit(repoDir, ["checkout", "-b", "feature/pr-local-no-head-repo"]);
2658− fs.writeFileSync(path.join(repoDir, "no-head-repo.txt"), "upstream\n");
2658+ NodeFS.writeFileSync(NodePath.join(repoDir, "no-head-repo.txt"), "upstream\n");
26592659 yield* runGit(repoDir, ["add", "no-head-repo.txt"]);
26602660 yield* runGit(repoDir, ["commit", "-m", "Local PR branch without repo metadata"]);
26612661 yield* runGit(repoDir, ["push", "-u", "origin", "feature/pr-local-no-head-repo"]);
@@ -2702,7 +2702,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 40 unmodified lines
27022702 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
27032703 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
27042704 yield* runGit(repoDir, ["checkout", "-b", "feature/pr-worktree"]);
2705− fs.writeFileSync(path.join(repoDir, "worktree.txt"), "worktree\n");
2705+ NodeFS.writeFileSync(NodePath.join(repoDir, "worktree.txt"), "worktree\n");
27062706 yield* runGit(repoDir, ["add", "worktree.txt"]);
27072707 yield* runGit(repoDir, ["commit", "-m", "PR worktree branch"]);
27082708 yield* runGit(repoDir, ["push", "-u", "origin", "feature/pr-worktree"]);
@@ -2730,7 +2730,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 21 unmodified lines
27302730
27312731 expect(result.branch).toBe("feature/pr-worktree");
27322732 expect(result.worktreePath).not.toBeNull();
2733− expect(fs.existsSync(result.worktreePath as string)).toBe(true);
2733+ expect(NodeFS.existsSync(result.worktreePath as string)).toBe(true);
27342734 const worktreeBranch = (yield* runGit(result.worktreePath as string, [
27352735 "branch",
27362736 "--show-current",
@@ -2747,7 +2747,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 10 unmodified lines
27472747 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
27482748 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
27492749 yield* runGit(repoDir, ["checkout", "-b", "feature/pr-worktree-setup"]);
2750− fs.writeFileSync(path.join(repoDir, "setup.txt"), "setup\n");
2750+ NodeFS.writeFileSync(NodePath.join(repoDir, "setup.txt"), "setup\n");
27512751 yield* runGit(repoDir, ["add", "setup.txt"]);
27522752 yield* runGit(repoDir, ["commit", "-m", "PR worktree setup branch"]);
27532753 yield* runGit(repoDir, ["push", "-u", "origin", "feature/pr-worktree-setup"]);
@@ -2802,7 +2802,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 48 unmodified lines
28022802 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
28032803 yield* runGit(repoDir, ["remote", "add", "fork-seed", forkDir]);
28042804 yield* runGit(repoDir, ["checkout", "-b", "feature/pr-fork"]);
2805− fs.writeFileSync(path.join(repoDir, "fork.txt"), "fork\n");
2805+ NodeFS.writeFileSync(NodePath.join(repoDir, "fork.txt"), "fork\n");
28062806 yield* runGit(repoDir, ["add", "fork.txt"]);
28072807 yield* runGit(repoDir, ["commit", "-m", "Fork PR branch"]);
28082808 yield* runGit(repoDir, ["push", "-u", "fork-seed", "feature/pr-fork"]);
@@ -2864,7 +2864,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 55 unmodified lines
28642864 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
28652865 yield* runGit(repoDir, ["remote", "add", "fork-seed", forkDir]);
28662866 yield* runGit(repoDir, ["checkout", "-b", "feature/pr-local-fork"]);
2867− fs.writeFileSync(path.join(repoDir, "local-fork.txt"), "local fork\n");
2867+ NodeFS.writeFileSync(NodePath.join(repoDir, "local-fork.txt"), "local fork\n");
28682868 yield* runGit(repoDir, ["add", "local-fork.txt"]);
28692869 yield* runGit(repoDir, ["commit", "-m", "Local fork PR branch"]);
28702870 yield* runGit(repoDir, ["push", "-u", "fork-seed", "feature/pr-local-fork"]);
@@ -2917,7 +2917,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 46 unmodified lines
29172917 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
29182918 yield* runGit(repoDir, ["remote", "add", "binbandit-seed", forkDir]);
29192919 yield* runGit(repoDir, ["checkout", "-b", "fix/git-action-default-without-origin"]);
2920− fs.writeFileSync(path.join(repoDir, "derived-fork.txt"), "derived fork\n");
2920+ NodeFS.writeFileSync(NodePath.join(repoDir, "derived-fork.txt"), "derived fork\n");
29212921 yield* runGit(repoDir, ["add", "derived-fork.txt"]);
29222922 yield* runGit(repoDir, ["commit", "-m", "Derived fork PR branch"]);
29232923 yield* runGit(repoDir, [
@@ -2969,11 +2969,15 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 45 unmodified lines
29692969 const repoDir = yield* makeTempDir("t3code-git-manager-");
29702970 yield* initRepo(repoDir);
29712971 yield* runGit(repoDir, ["checkout", "-b", "feature/pr-existing-worktree"]);
2972− fs.writeFileSync(path.join(repoDir, "existing.txt"), "existing\n");
2972+ NodeFS.writeFileSync(NodePath.join(repoDir, "existing.txt"), "existing\n");
29732973 yield* runGit(repoDir, ["add", "existing.txt"]);
29742974 yield* runGit(repoDir, ["commit", "-m", "Existing worktree branch"]);
29752975 yield* runGit(repoDir, ["checkout", "main"]);
2976− const worktreePath = path.join(repoDir, "..", `pr-existing-${path.basename(repoDir)}`);
2976+ const worktreePath = NodePath.join(
2977+ repoDir,
2978+ "..",
2979+ `pr-existing-${NodePath.basename(repoDir)}`,
2980+ );
29772981 yield* runGit(repoDir, ["worktree", "add", worktreePath, "feature/pr-existing-worktree"]);
29782982
29792983 const setupCalls: ProjectSetupScriptRunner.ProjectSetupScriptRunnerInput[] = [];
@@ -3004,8 +3008,8 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 24 unmodified lines
30043008 threadId: asThreadId("thread-pr-existing-worktree"),
30053009 });
30063010
3007− expect(result.worktreePath && fs.realpathSync.native(result.worktreePath)).toBe(
3008− fs.realpathSync.native(worktreePath),
3011+ expect(result.worktreePath && NodeFS.realpathSync.native(result.worktreePath)).toBe(
3012+ NodeFS.realpathSync.native(worktreePath),
30093013 );
30103014 expect(result.branch).toBe("feature/pr-existing-worktree");
30113015 expect(setupCalls).toHaveLength(0);
@@ -3024,7 +3028,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 12 unmodified lines
30243028 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
30253029 yield* runGit(repoDir, ["remote", "add", "fork-seed", forkDir]);
30263030 yield* runGit(repoDir, ["checkout", "-b", "fork-main-source"]);
3027− fs.writeFileSync(path.join(repoDir, "fork-main.txt"), "fork main\n");
3031+ NodeFS.writeFileSync(NodePath.join(repoDir, "fork-main.txt"), "fork main\n");
30283032 yield* runGit(repoDir, ["add", "fork-main.txt"]);
30293033 yield* runGit(repoDir, ["commit", "-m", "Fork main branch"]);
30303034 yield* runGit(repoDir, ["push", "-u", "fork-seed", "fork-main-source:main"]);
@@ -3084,7 +3088,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 53 unmodified lines
30843088 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
30853089 yield* runGit(repoDir, ["remote", "add", "fork-seed", forkDir]);
30863090 yield* runGit(repoDir, ["checkout", "-b", "fork-main-source"]);
3087− fs.writeFileSync(path.join(repoDir, "fork-main-second.txt"), "fork main second\n");
3091+ NodeFS.writeFileSync(NodePath.join(repoDir, "fork-main-second.txt"), "fork main second\n");
30883092 yield* runGit(repoDir, ["add", "fork-main-second.txt"]);
30893093 yield* runGit(repoDir, ["commit", "-m", "Fork main second branch"]);
30903094 yield* runGit(repoDir, ["push", "-u", "fork-seed", "fork-main-source:main"]);
@@ -3142,12 +3146,16 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 51 unmodified lines
31423146 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
31433147 yield* runGit(repoDir, ["remote", "add", "fork-seed", forkDir]);
31443148 yield* runGit(repoDir, ["checkout", "-b", "feature/pr-reused-fork"]);
3145− fs.writeFileSync(path.join(repoDir, "reused-fork.txt"), "reused fork\n");
3149+ NodeFS.writeFileSync(NodePath.join(repoDir, "reused-fork.txt"), "reused fork\n");
31463150 yield* runGit(repoDir, ["add", "reused-fork.txt"]);
31473151 yield* runGit(repoDir, ["commit", "-m", "Reused fork PR branch"]);
31483152 yield* runGit(repoDir, ["push", "-u", "fork-seed", "feature/pr-reused-fork"]);
31493153 yield* runGit(repoDir, ["checkout", "main"]);
3150− const worktreePath = path.join(repoDir, "..", `pr-reused-fork-${path.basename(repoDir)}`);
3154+ const worktreePath = NodePath.join(
3155+ repoDir,
3156+ "..",
3157+ `pr-reused-fork-${NodePath.basename(repoDir)}`,
3158+ );
31513159 yield* runGit(repoDir, ["worktree", "add", worktreePath, "feature/pr-reused-fork"]);
31523160 yield* runGit(worktreePath, ["branch", "--unset-upstream"], true);
31533161
@@ -3179,8 +3187,8 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 25 unmodified lines
31793187 mode: "worktree",
31803188 });
31813189
3182− expect(result.worktreePath && fs.realpathSync.native(result.worktreePath)).toBe(
3183− fs.realpathSync.native(worktreePath),
3190+ expect(result.worktreePath && NodeFS.realpathSync.native(result.worktreePath)).toBe(
3191+ NodeFS.realpathSync.native(worktreePath),
31843192 );
31853193 expect(
31863194 (yield* runGit(worktreePath, ["rev-parse", "--abbrev-ref", "@{upstream}"])).stdout.trim(),
@@ -3196,7 +3204,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 9 unmodified lines
31963204 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
31973205 yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
31983206 yield* runGit(repoDir, ["checkout", "-b", "feature/pr-setup-failure"]);
3199− fs.writeFileSync(path.join(repoDir, "setup-failure.txt"), "setup failure\n");
3207+ NodeFS.writeFileSync(NodePath.join(repoDir, "setup-failure.txt"), "setup failure\n");
32003208 yield* runGit(repoDir, ["add", "setup-failure.txt"]);
32013209 yield* runGit(repoDir, ["commit", "-m", "PR setup failure branch"]);
32023210 yield* runGit(repoDir, ["push", "-u", "origin", "feature/pr-setup-failure"]);
@@ -3236,7 +3244,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 33 unmodified lines
32363244
32373245 expect(result.branch).toBe("feature/pr-setup-failure");
32383246 expect(result.worktreePath).not.toBeNull();
3239− expect(fs.existsSync(result.worktreePath as string)).toBe(true);
3247+ expect(NodeFS.existsSync(result.worktreePath as string)).toBe(true);
32403248 }),
32413249 );
32423250
@@ -3276,9 +3284,9 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 33 unmodified lines
32763284 Effect.gen(function* () {
32773285 const repoDir = yield* makeTempDir("t3code-git-manager-");
32783286 yield* initRepo(repoDir);
3279− fs.writeFileSync(path.join(repoDir, "hooked.txt"), "hooked\n");
3280− fs.writeFileSync(
3281− path.join(repoDir, ".git", "hooks", "pre-commit"),
3287+ NodeFS.writeFileSync(NodePath.join(repoDir, "hooked.txt"), "hooked\n");
3288+ NodeFS.writeFileSync(
3289+ NodePath.join(repoDir, ".git", "hooks", "pre-commit"),
32823290 '#!/bin/sh\necho "hook: start" >&2\nsleep 0.05\necho "hook: end" >&2\n',
32833291 { mode: 0o755 },
32843292 );
@@ -3339,9 +3347,9 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 54 unmodified lines
33393347 Effect.gen(function* () {
33403348 const repoDir = yield* makeTempDir("t3code-git-manager-");
33413349 yield* initRepo(repoDir);
3342− fs.writeFileSync(path.join(repoDir, "hook-failure.txt"), "broken\n");
3343− fs.writeFileSync(
3344− path.join(repoDir, ".git", "hooks", "pre-commit"),
3350+ NodeFS.writeFileSync(NodePath.join(repoDir, "hook-failure.txt"), "broken\n");
3351+ NodeFS.writeFileSync(
3352+ NodePath.join(repoDir, ".git", "hooks", "pre-commit"),
33453353 '#!/bin/sh\necho "hook: fail" >&2\nexit 1\n',
33463354 { mode: 0o755 },
33473355 );
@@ -3392,7 +3400,7 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 44 unmodified lines
33923400 yield* runGit(repoDir, ["checkout", "-b", "feature/pr-only-follow-up"]);
33933401 const remoteDir = yield* createBareRemote();
33943402 yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
3395− fs.writeFileSync(path.join(repoDir, "pr-only.txt"), "pr only\n");
3403+ NodeFS.writeFileSync(NodePath.join(repoDir, "pr-only.txt"), "pr only\n");
33963404 yield* runGit(repoDir, ["add", "pr-only.txt"]);
33973405 yield* runGit(repoDir, ["commit", "-m", "PR only branch"]);
33983406 yield* runGit(repoDir, ["push", "-u", "origin", "feature/pr-only-follow-up"]);
apps/server/src/git/Utils.ts+3−3
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import { existsSync } from "node:fs";
3−import { join } from "node:path";
2+import * as NodeFS from "node:fs";
3+import * as NodePath from "node:path";
44
55 export function isGitRepository(cwd: string): boolean {
6− return existsSync(join(cwd, ".git"));
6+ return NodeFS.existsSync(NodePath.join(cwd, ".git"));
77 }
apps/server/src/orchestration/Layers/CheckpointReactor.test.ts+17−17
@@ -1,8 +1,8 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import fs from "node:fs";
3−import os from "node:os";
4−import path from "node:path";
5−import { execFileSync } from "node:child_process";
2+import * as NodeFS from "node:fs";
3+import * as NodeOS from "node:os";
4+import * as NodePath from "node:path";
5+import * as NodeChildProcess from "node:child_process";
66
77 import {
88 ProviderDriverKind,
@@ -198,7 +198,7 @@ async function waitForEvent( · 189 unmodified lines
198198 }
199199
200200 function runGit(cwd: string, args: ReadonlyArray<string>) {
201− return execFileSync("git", args, {
201+ return NodeChildProcess.execFileSync("git", args, {
202202 cwd,
203203 stdio: ["ignore", "pipe", "pipe"],
204204 encoding: "utf8",
@@ -206,11 +206,11 @@ function runGit(cwd: string, args: ReadonlyArray<string>) { · 1 unmodified line
206206 }
207207
208208 function createGitRepository() {
209− const cwd = fs.mkdtempSync(path.join(os.tmpdir(), "t3-checkpoint-handler-"));
209+ const cwd = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-checkpoint-handler-"));
210210 runGit(cwd, ["init", "--initial-branch=main"]);
211211 runGit(cwd, ["config", "user.email", "test@example.com"]);
212212 runGit(cwd, ["config", "user.name", "Test User"]);
213− fs.writeFileSync(path.join(cwd, "README.md"), "v1\n", "utf8");
213+ NodeFS.writeFileSync(NodePath.join(cwd, "README.md"), "v1\n", "utf8");
214214 runGit(cwd, ["add", "."]);
215215 runGit(cwd, ["commit", "-m", "Initial"]);
216216 return cwd;
@@ -267,7 +267,7 @@ describe("CheckpointReactor", () => { · 50 unmodified lines
267267 while (tempDirs.length > 0) {
268268 const dir = tempDirs.pop();
269269 if (dir) {
270− fs.rmSync(dir, { recursive: true, force: true });
270+ NodeFS.rmSync(dir, { recursive: true, force: true });
271271 }
272272 }
273273 });
@@ -395,14 +395,14 @@ describe("CheckpointReactor", () => { · 121 unmodified lines
395395 checkpointRef: checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0),
396396 }),
397397 );
398− fs.writeFileSync(path.join(cwd, "README.md"), "v2\n", "utf8");
398+ NodeFS.writeFileSync(NodePath.join(cwd, "README.md"), "v2\n", "utf8");
399399 await runtime.runPromise(
400400 checkpointStore.captureCheckpoint({
401401 cwd,
402402 checkpointRef: checkpointRefForThreadTurn(ThreadId.make("thread-1"), 1),
403403 }),
404404 );
405− fs.writeFileSync(path.join(cwd, "README.md"), "v3\n", "utf8");
405+ NodeFS.writeFileSync(NodePath.join(cwd, "README.md"), "v3\n", "utf8");
406406 await runtime.runPromise(
407407 checkpointStore.captureCheckpoint({
408408 cwd,
@@ -456,7 +456,7 @@ describe("CheckpointReactor", () => { · 47 unmodified lines
456456 checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0),
457457 );
458458
459− fs.writeFileSync(path.join(harness.cwd, "README.md"), "v2\n", "utf8");
459+ NodeFS.writeFileSync(NodePath.join(harness.cwd, "README.md"), "v2\n", "utf8");
460460 harness.provider.emit({
461461 type: "turn.completed",
462462 eventId: EventId.make("evt-turn-completed-1"),
@@ -554,7 +554,7 @@ describe("CheckpointReactor", () => { · 91 unmodified lines
554554 checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0),
555555 );
556556
557− fs.writeFileSync(path.join(harness.cwd, "README.md"), "v2\n", "utf8");
557+ NodeFS.writeFileSync(NodePath.join(harness.cwd, "README.md"), "v2\n", "utf8");
558558
559559 harness.provider.emit({
560560 type: "turn.completed",
@@ -628,7 +628,7 @@ describe("CheckpointReactor", () => { · 67 unmodified lines
628628 checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0),
629629 );
630630
631− fs.writeFileSync(path.join(harness.cwd, "README.md"), "v2\n", "utf8");
631+ NodeFS.writeFileSync(NodePath.join(harness.cwd, "README.md"), "v2\n", "utf8");
632632 harness.provider.emit({
633633 type: "turn.completed",
634634 eventId: EventId.make("evt-turn-completed-claude-1"),
@@ -761,7 +761,7 @@ describe("CheckpointReactor", () => { · 126 unmodified lines
761761 }),
762762 );
763763
764− fs.writeFileSync(path.join(harness.cwd, "README.md"), "v2\n", "utf8");
764+ NodeFS.writeFileSync(NodePath.join(harness.cwd, "README.md"), "v2\n", "utf8");
765765 harness.provider.emit({
766766 type: "turn.completed",
767767 eventId: EventId.make("evt-turn-completed-missing-provider-cwd"),
@@ -829,8 +829,8 @@ describe("CheckpointReactor", () => { · 61 unmodified lines
829829 });
830830
831831 it("continues processing runtime events after a single checkpoint runtime failure", async () => {
832− const nonRepositorySessionCwd = fs.mkdtempSync(
833− path.join(os.tmpdir(), "t3-checkpoint-runtime-non-repo-"),
832+ const nonRepositorySessionCwd = NodeFS.mkdtempSync(
833+ NodePath.join(NodeOS.tmpdir(), "t3-checkpoint-runtime-non-repo-"),
834834 );
835835 tempDirs.push(nonRepositorySessionCwd);
836836
@@ -963,7 +963,7 @@ describe("CheckpointReactor", () => { · 126 unmodified lines
963963 threadId: ThreadId.make("thread-1"),
964964 numTurns: 1,
965965 });
966− expect(fs.readFileSync(path.join(harness.cwd, "README.md"), "utf8")).toBe("v2\n");
966+ expect(NodeFS.readFileSync(NodePath.join(harness.cwd, "README.md"), "utf8")).toBe("v2\n");
967967 expect(
968968 gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.make("thread-1"), 2)),
969969 ).toBe(false);
apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts+7−6
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import fs from "node:fs";
3−import os from "node:os";
4−import path from "node:path";
2+import * as NodeFS from "node:fs";
3+import * as NodeOS from "node:os";
4+import * as NodePath from "node:path";
55
66 import {
77 ModelSelection,
@@ -107,11 +107,11 @@ describe("ProviderCommandReactor", () => { · 99 unmodified lines
107107 }
108108 runtime = null;
109109 for (const stateDir of createdStateDirs) {
110− fs.rmSync(stateDir, { recursive: true, force: true });
110+ NodeFS.rmSync(stateDir, { recursive: true, force: true });
111111 }
112112 createdStateDirs.clear();
113113 for (const baseDir of createdBaseDirs) {
114− fs.rmSync(baseDir, { recursive: true, force: true });
114+ NodeFS.rmSync(baseDir, { recursive: true, force: true });
115115 }
116116 createdBaseDirs.clear();
117117 });
@@ -147,7 +147,8 @@ describe("ProviderCommandReactor", () => { · 29 unmodified lines
147147 readonly requiresNewThreadForModelChange?: boolean;
148148 }) {
149149 const now = "2026-01-01T00:00:00.000Z";
150− const baseDir = input?.baseDir ?? fs.mkdtempSync(path.join(os.tmpdir(), "t3code-reactor-"));
150+ const baseDir =
151+ input?.baseDir ?? NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3code-reactor-"));
151152 createdBaseDirs.add(baseDir);
152153 const { stateDir } = deriveServerPathsSync(baseDir, undefined);
153154 createdStateDirs.add(stateDir);
apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts+6−6
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import fs from "node:fs";
3−import os from "node:os";
4−import path from "node:path";
2+import * as NodeFS from "node:fs";
3+import * as NodeOS from "node:os";
4+import * as NodePath from "node:path";
55
66 import {
77 OrchestrationReadModel,
@@ -198,7 +198,7 @@ describe("ProviderRuntimeIngestion", () => { · 190 unmodified lines
198198 const tempDirs: string[] = [];
199199
200200 function makeTempDir(prefix: string): string {
201− const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
201+ const dir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), prefix));
202202 tempDirs.push(dir);
203203 return dir;
204204 }
@@ -213,13 +213,13 @@ describe("ProviderRuntimeIngestion", () => { · 8 unmodified lines
213213 }
214214 runtime = null;
215215 for (const dir of tempDirs.splice(0)) {
216− fs.rmSync(dir, { recursive: true, force: true });
216+ NodeFS.rmSync(dir, { recursive: true, force: true });
217217 }
218218 });
219219
220220 async function createHarness(options?: { serverSettings?: Partial<ServerSettings> }) {
221221 const workspaceRoot = makeTempDir("t3-provider-project-");
222− fs.mkdirSync(path.join(workspaceRoot, ".git"));
222+ NodeFS.mkdirSync(NodePath.join(workspaceRoot, ".git"));
223223 const provider = createProviderServiceHarness();
224224 const orchestrationLayer = OrchestrationEngineLive.pipe(
225225 Layer.provide(OrchestrationProjectionSnapshotQueryLive),
apps/server/src/pathExpansion.test.ts+5−5
@@ -1,6 +1,6 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import { homedir } from "node:os";
3−import { join } from "node:path";
2+import * as NodeOS from "node:os";
3+import * as NodePath from "node:path";
44 import { describe, expect, it } from "vite-plus/test";
55
66 import { expandHomePath } from "./pathExpansion.ts";
@@ -17,15 +17,15 @@ describe("expandHomePath", () => { · 10 unmodified lines
1717 });
1818
1919 it("expands a lone tilde to the home directory", () => {
20− expect(expandHomePath("~")).toBe(homedir());
20+ expect(expandHomePath("~")).toBe(NodeOS.homedir());
2121 });
2222
2323 it("expands ~/ to a subpath of the home directory", () => {
24− expect(expandHomePath("~/.codex-work")).toBe(join(homedir(), ".codex-work"));
24+ expect(expandHomePath("~/.codex-work")).toBe(NodePath.join(NodeOS.homedir(), ".codex-work"));
2525 });
2626
2727 it("expands a Windows-style ~\\ prefix", () => {
28− expect(expandHomePath("~\\.codex")).toBe(join(homedir(), ".codex"));
28+ expect(expandHomePath("~\\.codex")).toBe(NodePath.join(NodeOS.homedir(), ".codex"));
2929 });
3030
3131 it("does not expand ~user paths", () => {
apps/server/src/pathExpansion.ts+4−4
@@ -1,6 +1,6 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import { homedir } from "node:os";
3−import { join } from "node:path";
2+import * as NodeOS from "node:os";
3+import * as NodePath from "node:path";
44
55 /**
66 * Expand a leading `~` (or `~/…`, `~\…`) in a user-supplied path to the
@@ -16,9 +16,9 @@ import { join } from "node:path"; · 9 unmodified lines
1616 */
1717 export function expandHomePath(value: string): string {
1818 if (!value) return value;
19− if (value === "~") return homedir();
19+ if (value === "~") return NodeOS.homedir();
2020 if (value.startsWith("~/") || value.startsWith("~\\")) {
21− return join(homedir(), value.slice(2));
21+ return NodePath.join(NodeOS.homedir(), value.slice(2));
2222 }
2323 return value;
2424 }
apps/server/src/persistence/NodeSqliteClient.ts+11−7
@@ -4,7 +4,7 @@ · 3 unmodified lines
44 *
55 * @module SqliteClient
66 */
7−import { DatabaseSync, type StatementSync } from "node:sqlite";
7+import * as NodeSqlite from "node:sqlite";
88
99 import * as Cache from "effect/Cache";
1010 import * as Config from "effect/Config";
@@ -69,7 +69,7 @@ const checkNodeSqliteCompat = () => { · 58 unmodified lines
6969
7070 const makeWithDatabase = Effect.fn("makeWithDatabase")(function* (
7171 options: SqliteClientConfig,
72− openDatabase: () => DatabaseSync,
72+ openDatabase: () => NodeSqlite.DatabaseSync,
7373 ): Effect.fn.Return<Client.SqlClient, never, Scope.Scope | Reactivity.Reactivity> {
7474 yield* checkNodeSqliteCompat();
7575
@@ -86,8 +86,8 @@ const makeWithDatabase = Effect.fn("makeWithDatabase")(function* ( · 10 unmodified lines
8686 Effect.sync(() => db.close()),
8787 );
8888
89− const statementReaderCache = new WeakMap<StatementSync, boolean>();
90− const hasRows = (statement: StatementSync): boolean => {
89+ const statementReaderCache = new WeakMap<NodeSqlite.StatementSync, boolean>();
90+ const hasRows = (statement: NodeSqlite.StatementSync): boolean => {
9191 const cached = statementReaderCache.get(statement);
9292 if (cached !== undefined) {
9393 return cached;
@@ -113,7 +113,11 @@ const makeWithDatabase = Effect.fn("makeWithDatabase")(function* ( · 19 unmodified lines
113113 }),
114114 });
115115
116− const runStatement = (statement: StatementSync, params: ReadonlyArray<unknown>, raw: boolean) =>
116+ const runStatement = (
117+ statement: NodeSqlite.StatementSync,
118+ params: ReadonlyArray<unknown>,
119+ raw: boolean,
120+ ) =>
117121 Effect.withFiber<ReadonlyArray<any>, SqlError>((fiber) => {
118122 statement.setReadBigInts(Boolean(Context.get(fiber.context, Client.SafeIntegers)));
119123 try {
@@ -220,7 +224,7 @@ const make = ( · 100 unmodified lines
220224 makeWithDatabase(
221225 options,
222226 () =>
223− new DatabaseSync(options.filename, {
227+ new NodeSqlite.DatabaseSync(options.filename, {
224228 readOnly: options.readonly ?? false,
225229 allowExtension: options.allowExtension ?? false,
226230 }),
@@ -236,7 +240,7 @@ const makeMemory = ( · 9 unmodified lines
236240 readonly: false,
237241 },
238242 () => {
239− const database = new DatabaseSync(":memory:", {
243+ const database = new NodeSqlite.DatabaseSync(":memory:", {
240244 allowExtension: config.allowExtension ?? false,
241245 });
242246 return database;
apps/server/src/preview/PortScanner.test.ts+4−4
@@ -1,4 +1,4 @@
1−import * as net from "node:net";
1+import * as NodeNet from "node:net";
22
33 import { it as effectIt } from "@effect/vitest";
44 import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
@@ -17,9 +17,9 @@ const TestPortDiscoveryLive = PortScanner.layer.pipe( · 12 unmodified lines
1717 ),
1818 );
1919
20−const openServer = (port: number): Effect.Effect<net.Server | null> =>
20+const openServer = (port: number): Effect.Effect<NodeNet.Server | null> =>
2121 Effect.callback((resume) => {
22− const server = net.createServer();
22+ const server = NodeNet.createServer();
2323 server.once("error", () => {
2424 resume(Effect.succeed(null));
2525 });
@@ -31,7 +31,7 @@ const openServer = (port: number): Effect.Effect<net.Server | null> => · 5 unmodified lines
3131 });
3232 });
3333
34−const closeServer = (server: net.Server): Effect.Effect<void> =>
34+const closeServer = (server: NodeNet.Server): Effect.Effect<void> =>
3535 Effect.callback((resume) => {
3636 server.close(() => resume(Effect.void));
3737 });
apps/server/src/provider/Layers/ClaudeAdapter.test.ts+9−9
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3−import os from "node:os";
4−import path from "node:path";
2+import * as NodeFS from "node:fs";
3+import * as NodeOS from "node:os";
4+import * as NodePath from "node:path";
55
66 import * as NodeServices from "@effect/platform-node/NodeServices";
77 import type {
@@ -395,7 +395,7 @@ describe("ClaudeAdapterLive", () => { · 387 unmodified lines
395395 });
396396
397397 const createInput = harness.getLastCreateQueryInput();
398− assert.equal(createInput?.options.env?.HOME, path.join(os.homedir(), ".claude-work"));
398+ assert.equal(createInput?.options.env?.HOME, NodePath.join(NodeOS.homedir(), ".claude-work"));
399399 }).pipe(
400400 Effect.provideService(Random.Random, makeDeterministicRandomService()),
401401 Effect.provide(harness.layer),
@@ -649,7 +649,7 @@ describe("ClaudeAdapterLive", () => { · 247 unmodified lines
649649 });
650650
651651 it.effect("embeds image attachments in Claude user messages", () => {
652− const baseDir = mkdtempSync(path.join(os.tmpdir(), "claude-attachments-"));
652+ const baseDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "claude-attachments-"));
653653 const harness = makeHarness({
654654 cwd: "/tmp/project-claude-attachments",
655655 baseDir,
@@ -657,7 +657,7 @@ describe("ClaudeAdapterLive", () => { · 1 unmodified line
657657 return Effect.gen(function* () {
658658 yield* Effect.addFinalizer(() =>
659659 Effect.sync(() =>
660− rmSync(baseDir, {
660+ NodeFS.rmSync(baseDir, {
661661 recursive: true,
662662 force: true,
663663 }),
@@ -674,9 +674,9 @@ describe("ClaudeAdapterLive", () => { · 10 unmodified lines
674674 mimeType: "image/png",
675675 sizeBytes: 4,
676676 };
677− const attachmentPath = path.join(attachmentsDir, attachmentRelativePath(attachment));
678− mkdirSync(path.dirname(attachmentPath), { recursive: true });
679− writeFileSync(attachmentPath, Uint8Array.from([1, 2, 3, 4]));
677+ const attachmentPath = NodePath.join(attachmentsDir, attachmentRelativePath(attachment));
678+ NodeFS.mkdirSync(NodePath.dirname(attachmentPath), { recursive: true });
679+ NodeFS.writeFileSync(attachmentPath, Uint8Array.from([1, 2, 3, 4]));
680680
681681 const session = yield* adapter.startSession({
682682 threadId: THREAD_ID,
apps/server/src/provider/Layers/CodexAdapter.test.ts+98−96
@@ -1,8 +1,8 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import assert from "node:assert/strict";
3−import fs from "node:fs";
4−import os from "node:os";
5−import path from "node:path";
2+import * as NodeAssert from "node:assert/strict";
3+import * as NodeFS from "node:fs";
4+import * as NodeOS from "node:os";
5+import * as NodePath from "node:path";
66 import {
77 ApprovalRequestId,
88 CodexSettings,
@@ -250,8 +250,8 @@ validationLayer("CodexAdapterLive validation", (it) => { · 241 unmodified lines
250250 })
251251 .pipe(Effect.result);
252252
253− assert.equal(result._tag, "Failure");
254− assert.deepStrictEqual(
253+ NodeAssert.equal(result._tag, "Failure");
254+ NodeAssert.deepStrictEqual(
255255 result.failure,
256256 new ProviderAdapterValidationError({
257257 provider: ProviderDriverKind.make("codex"),
@@ -259,7 +259,7 @@ validationLayer("CodexAdapterLive validation", (it) => { · 1 unmodified line
259259 issue: "Expected provider 'codex' but received 'claudeAgent'.",
260260 }),
261261 );
262− assert.equal(validationRuntimeFactory.factory.mock.calls.length, 0);
262+ NodeAssert.equal(validationRuntimeFactory.factory.mock.calls.length, 0);
263263 }),
264264 );
265265 it.effect("maps codex model options before starting a session", () =>
@@ -276,7 +276,7 @@ validationLayer("CodexAdapterLive validation", (it) => { · 10 unmodified lines
276276 runtimeMode: "full-access",
277277 });
278278
279− assert.deepStrictEqual(validationRuntimeFactory.factory.mock.calls[0]?.[0], {
279+ NodeAssert.deepStrictEqual(validationRuntimeFactory.factory.mock.calls[0]?.[0], {
280280 binaryPath: "codex",
281281 cwd: process.cwd(),
282282 model: "gpt-5.3-codex",
@@ -319,10 +319,10 @@ sessionErrorLayer("CodexAdapterLive session errors", (it) => { · 36 unmodified lines
319319 })
320320 .pipe(Effect.result);
321321
322− assert.equal(result._tag, "Failure");
323− assert.equal(result.failure._tag, "ProviderAdapterSessionNotFoundError");
324− assert.equal(result.failure.provider, "codex");
325− assert.equal(result.failure.threadId, "sess-missing");
322+ NodeAssert.equal(result._tag, "Failure");
323+ NodeAssert.equal(result.failure._tag, "ProviderAdapterSessionNotFoundError");
324+ NodeAssert.equal(result.failure.provider, "codex");
325+ NodeAssert.equal(result.failure.threadId, "sess-missing");
326326 }),
327327 );
328328
@@ -335,7 +335,7 @@ sessionErrorLayer("CodexAdapterLive session errors", (it) => { · 6 unmodified lines
335335 runtimeMode: "full-access",
336336 });
337337 const runtime = sessionRuntimeFactory.lastRuntime;
338− assert.ok(runtime);
338+ NodeAssert.ok(runtime);
339339 runtime.sendTurnImpl.mockClear();
340340
341341 yield* Effect.ignore(
@@ -350,7 +350,7 @@ sessionErrorLayer("CodexAdapterLive session errors", (it) => { · 8 unmodified lines
350350 }),
351351 );
352352
353− assert.deepStrictEqual(runtime.sendTurnImpl.mock.calls[0]?.[0], {
353+ NodeAssert.deepStrictEqual(runtime.sendTurnImpl.mock.calls[0]?.[0], {
354354 input: "hello",
355355 model: "gpt-5.3-codex",
356356 effort: "high",
@@ -386,7 +386,7 @@ sessionErrorLayer("CodexAdapterLive session errors", (it) => { · 29 unmodified lines
386386 runtimeMode: "full-access",
387387 });
388388 const runtime = customRuntimeFactory.lastRuntime;
389− assert.ok(runtime);
389+ NodeAssert.ok(runtime);
390390 runtime.sendTurnImpl.mockClear();
391391
392392 yield* Effect.ignore(
@@ -405,7 +405,7 @@ sessionErrorLayer("CodexAdapterLive session errors", (it) => { · 12 unmodified lines
405405 }),
406406 );
407407
408− assert.deepStrictEqual(runtime.sendTurnImpl.mock.calls[0]?.[0], {
408+ NodeAssert.deepStrictEqual(runtime.sendTurnImpl.mock.calls[0]?.[0], {
409409 input: "hello",
410410 model: "gpt-5.3-codex",
411411 effort: "high",
@@ -442,7 +442,7 @@ function startLifecycleRuntime() { · 30 unmodified lines
442442 runtimeMode: "full-access",
443443 });
444444 const runtime = lifecycleRuntimeFactory.lastRuntime;
445− assert.ok(runtime);
445+ NodeAssert.ok(runtime);
446446 return { adapter, runtime };
447447 });
448448 }
@@ -477,17 +477,17 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 28 unmodified lines
477477 yield* runtime.emit(event);
478478 const firstEvent = yield* Fiber.join(firstEventFiber);
479479
480− assert.equal(firstEvent._tag, "Some");
480+ NodeAssert.equal(firstEvent._tag, "Some");
481481 if (firstEvent._tag !== "Some") {
482482 return;
483483 }
484− assert.equal(firstEvent.value.type, "item.completed");
484+ NodeAssert.equal(firstEvent.value.type, "item.completed");
485485 if (firstEvent.value.type !== "item.completed") {
486486 return;
487487 }
488− assert.equal(firstEvent.value.itemId, "msg_1");
489− assert.equal(firstEvent.value.turnId, "turn-1");
490− assert.equal(firstEvent.value.payload.itemType, "assistant_message");
488+ NodeAssert.equal(firstEvent.value.itemId, "msg_1");
489+ NodeAssert.equal(firstEvent.value.turnId, "turn-1");
490+ NodeAssert.equal(firstEvent.value.payload.itemType, "assistant_message");
491491 }),
492492 );
493493
@@ -524,13 +524,13 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 30 unmodified lines
524524 });
525525 const firstEvent = yield* Fiber.join(firstEventFiber);
526526
527− assert.equal(firstEvent._tag, "Some");
527+ NodeAssert.equal(firstEvent._tag, "Some");
528528 if (firstEvent._tag !== "Some" || firstEvent.value.type !== "item.completed") {
529529 return;
530530 }
531− assert.equal(firstEvent.value.payload.itemType, "mcp_tool_call");
532− assert.equal(firstEvent.value.payload.title, "t3-code · preview_status");
533− assert.deepStrictEqual(firstEvent.value.payload.data, {
531+ NodeAssert.equal(firstEvent.value.payload.itemType, "mcp_tool_call");
532+ NodeAssert.equal(firstEvent.value.payload.title, "t3-code · preview_status");
533+ NodeAssert.deepStrictEqual(firstEvent.value.payload.data, {
534534 completedAtMs: 1_778_000_000_000,
535535 threadId: "thread-1",
536536 turnId: "turn-1",
@@ -578,16 +578,16 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 41 unmodified lines
578578 yield* runtime.emit(event);
579579 const firstEvent = yield* Fiber.join(firstEventFiber);
580580
581− assert.equal(firstEvent._tag, "Some");
581+ NodeAssert.equal(firstEvent._tag, "Some");
582582 if (firstEvent._tag !== "Some") {
583583 return;
584584 }
585− assert.equal(firstEvent.value.type, "turn.proposed.completed");
585+ NodeAssert.equal(firstEvent.value.type, "turn.proposed.completed");
586586 if (firstEvent.value.type !== "turn.proposed.completed") {
587587 return;
588588 }
589− assert.equal(firstEvent.value.turnId, "turn-1");
590− assert.equal(firstEvent.value.payload.planMarkdown, "## Final plan\n\n- one\n- two");
589+ NodeAssert.equal(firstEvent.value.turnId, "turn-1");
590+ NodeAssert.equal(firstEvent.value.payload.planMarkdown, "## Final plan\n\n- one\n- two");
591591 }),
592592 );
593593
@@ -615,16 +615,16 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 21 unmodified lines
615615
616616 const firstEvent = yield* Fiber.join(firstEventFiber);
617617
618− assert.equal(firstEvent._tag, "Some");
618+ NodeAssert.equal(firstEvent._tag, "Some");
619619 if (firstEvent._tag !== "Some") {
620620 return;
621621 }
622− assert.equal(firstEvent.value.type, "turn.proposed.delta");
622+ NodeAssert.equal(firstEvent.value.type, "turn.proposed.delta");
623623 if (firstEvent.value.type !== "turn.proposed.delta") {
624624 return;
625625 }
626− assert.equal(firstEvent.value.turnId, "turn-1");
627− assert.equal(firstEvent.value.payload.delta, "## Final plan");
626+ NodeAssert.equal(firstEvent.value.turnId, "turn-1");
627+ NodeAssert.equal(firstEvent.value.payload.delta, "## Final plan");
628628 }),
629629 );
630630
@@ -646,16 +646,16 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 15 unmodified lines
646646 yield* runtime.emit(event);
647647 const firstEvent = yield* Fiber.join(firstEventFiber);
648648
649− assert.equal(firstEvent._tag, "Some");
649+ NodeAssert.equal(firstEvent._tag, "Some");
650650 if (firstEvent._tag !== "Some") {
651651 return;
652652 }
653− assert.equal(firstEvent.value.type, "session.exited");
653+ NodeAssert.equal(firstEvent.value.type, "session.exited");
654654 if (firstEvent.value.type !== "session.exited") {
655655 return;
656656 }
657− assert.equal(firstEvent.value.threadId, "thread-1");
658− assert.equal(firstEvent.value.payload.reason, "Session stopped");
657+ NodeAssert.equal(firstEvent.value.threadId, "thread-1");
658+ NodeAssert.equal(firstEvent.value.payload.reason, "Session stopped");
659659 }),
660660 );
661661
@@ -684,16 +684,16 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 22 unmodified lines
684684
685685 const firstEvent = yield* Fiber.join(firstEventFiber);
686686
687− assert.equal(firstEvent._tag, "Some");
687+ NodeAssert.equal(firstEvent._tag, "Some");
688688 if (firstEvent._tag !== "Some") {
689689 return;
690690 }
691− assert.equal(firstEvent.value.type, "runtime.warning");
691+ NodeAssert.equal(firstEvent.value.type, "runtime.warning");
692692 if (firstEvent.value.type !== "runtime.warning") {
693693 return;
694694 }
695− assert.equal(firstEvent.value.turnId, "turn-1");
696− assert.equal(firstEvent.value.payload.message, "Reconnecting... 2/5");
695+ NodeAssert.equal(firstEvent.value.turnId, "turn-1");
696+ NodeAssert.equal(firstEvent.value.payload.message, "Reconnecting... 2/5");
697697 }),
698698 );
699699
@@ -715,16 +715,16 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 15 unmodified lines
715715
716716 const firstEvent = yield* Fiber.join(firstEventFiber);
717717
718− assert.equal(firstEvent._tag, "Some");
718+ NodeAssert.equal(firstEvent._tag, "Some");
719719 if (firstEvent._tag !== "Some") {
720720 return;
721721 }
722− assert.equal(firstEvent.value.type, "runtime.warning");
722+ NodeAssert.equal(firstEvent.value.type, "runtime.warning");
723723 if (firstEvent.value.type !== "runtime.warning") {
724724 return;
725725 }
726− assert.equal(firstEvent.value.turnId, "turn-1");
727− assert.equal(
726+ NodeAssert.equal(firstEvent.value.turnId, "turn-1");
727+ NodeAssert.equal(
728728 firstEvent.value.payload.message,
729729 "The filename or extension is too long. (os error 206)",
730730 );
@@ -752,16 +752,16 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 21 unmodified lines
752752
753753 const firstEvent = yield* Fiber.join(firstEventFiber);
754754
755− assert.equal(firstEvent._tag, "Some");
755+ NodeAssert.equal(firstEvent._tag, "Some");
756756 if (firstEvent._tag !== "Some") {
757757 return;
758758 }
759− assert.equal(firstEvent.value.type, "thread.realtime.started");
759+ NodeAssert.equal(firstEvent.value.type, "thread.realtime.started");
760760 if (firstEvent.value.type !== "thread.realtime.started") {
761761 return;
762762 }
763− assert.equal(firstEvent.value.threadId, "thread-1");
764− assert.equal(firstEvent.value.payload.realtimeSessionId, "realtime-session-1");
763+ NodeAssert.equal(firstEvent.value.threadId, "thread-1");
764+ NodeAssert.equal(firstEvent.value.payload.realtimeSessionId, "realtime-session-1");
765765 }),
766766 );
767767
@@ -784,17 +784,17 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 16 unmodified lines
784784
785785 const firstEvent = yield* Fiber.join(firstEventFiber);
786786
787− assert.equal(firstEvent._tag, "Some");
787+ NodeAssert.equal(firstEvent._tag, "Some");
788788 if (firstEvent._tag !== "Some") {
789789 return;
790790 }
791− assert.equal(firstEvent.value.type, "runtime.error");
791+ NodeAssert.equal(firstEvent.value.type, "runtime.error");
792792 if (firstEvent.value.type !== "runtime.error") {
793793 return;
794794 }
795− assert.equal(firstEvent.value.turnId, "turn-1");
796− assert.equal(firstEvent.value.payload.class, "provider_error");
797− assert.equal(
795+ NodeAssert.equal(firstEvent.value.turnId, "turn-1");
796+ NodeAssert.equal(firstEvent.value.payload.class, "provider_error");
797+ NodeAssert.equal(
798798 firstEvent.value.payload.message,
799799 "2026-03-31T18:14:06.833399Z ERROR codex_api::endpoint::responses_websocket: failed to connect to websocket: HTTP error: 503 Service Unavailable, url: wss://chatgpt.com/backend-api/codex/responses",
800800 );
@@ -824,15 +824,15 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 23 unmodified lines
824824 yield* runtime.emit(event);
825825 const firstEvent = yield* Fiber.join(firstEventFiber);
826826
827− assert.equal(firstEvent._tag, "Some");
827+ NodeAssert.equal(firstEvent._tag, "Some");
828828 if (firstEvent._tag !== "Some") {
829829 return;
830830 }
831− assert.equal(firstEvent.value.type, "request.resolved");
831+ NodeAssert.equal(firstEvent.value.type, "request.resolved");
832832 if (firstEvent.value.type !== "request.resolved") {
833833 return;
834834 }
835− assert.equal(firstEvent.value.payload.requestType, "command_execution_approval");
835+ NodeAssert.equal(firstEvent.value.payload.requestType, "command_execution_approval");
836836 }),
837837 );
838838
@@ -859,15 +859,15 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 20 unmodified lines
859859 yield* runtime.emit(event);
860860 const firstEvent = yield* Fiber.join(firstEventFiber);
861861
862− assert.equal(firstEvent._tag, "Some");
862+ NodeAssert.equal(firstEvent._tag, "Some");
863863 if (firstEvent._tag !== "Some") {
864864 return;
865865 }
866− assert.equal(firstEvent.value.type, "request.resolved");
866+ NodeAssert.equal(firstEvent.value.type, "request.resolved");
867867 if (firstEvent.value.type !== "request.resolved") {
868868 return;
869869 }
870− assert.equal(firstEvent.value.payload.requestType, "file_read_approval");
870+ NodeAssert.equal(firstEvent.value.payload.requestType, "file_read_approval");
871871 }),
872872 );
873873
@@ -895,15 +895,15 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 21 unmodified lines
895895 yield* runtime.emit(event);
896896 const firstEvent = yield* Fiber.join(firstEventFiber);
897897
898− assert.equal(firstEvent._tag, "Some");
898+ NodeAssert.equal(firstEvent._tag, "Some");
899899 if (firstEvent._tag !== "Some") {
900900 return;
901901 }
902− assert.equal(firstEvent.value.type, "user-input.resolved");
902+ NodeAssert.equal(firstEvent.value.type, "user-input.resolved");
903903 if (firstEvent.value.type !== "user-input.resolved") {
904904 return;
905905 }
906− assert.deepEqual(firstEvent.value.payload.answers, {
906+ NodeAssert.deepEqual(firstEvent.value.payload.answers, {
907907 scope: [],
908908 });
909909 }),
@@ -934,20 +934,20 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 24 unmodified lines
934934 yield* runtime.emit(event);
935935 const events = Array.from(yield* Fiber.join(eventsFiber));
936936
937− assert.equal(events.length, 2);
937+ NodeAssert.equal(events.length, 2);
938938
939939 const firstEvent = events[0];
940940 const secondEvent = events[1];
941941
942− assert.equal(firstEvent?.type, "session.state.changed");
942+ NodeAssert.equal(firstEvent?.type, "session.state.changed");
943943 if (firstEvent?.type === "session.state.changed") {
944− assert.equal(firstEvent.payload.state, "error");
945− assert.equal(firstEvent.payload.reason, "Sandbox setup failed");
944+ NodeAssert.equal(firstEvent.payload.state, "error");
945+ NodeAssert.equal(firstEvent.payload.reason, "Sandbox setup failed");
946946 }
947947
948− assert.equal(secondEvent?.type, "runtime.warning");
948+ NodeAssert.equal(secondEvent?.type, "runtime.warning");
949949 if (secondEvent?.type === "runtime.warning") {
950− assert.equal(secondEvent.payload.message, "Sandbox setup failed");
950+ NodeAssert.equal(secondEvent.payload.message, "Sandbox setup failed");
951951 }
952952 }),
953953 );
@@ -1006,17 +1006,17 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 52 unmodified lines
10061006 } satisfies ProviderEvent);
10071007
10081008 const events = Array.from(yield* Fiber.join(eventsFiber));
1009− assert.equal(events[0]?.type, "user-input.requested");
1009+ NodeAssert.equal(events[0]?.type, "user-input.requested");
10101010 if (events[0]?.type === "user-input.requested") {
1011− assert.equal(events[0].requestId, "req-user-input-1");
1012− assert.equal(events[0].payload.questions[0]?.id, "sandbox_mode");
1013− assert.equal(events[0].payload.questions[0]?.multiSelect, false);
1011+ NodeAssert.equal(events[0].requestId, "req-user-input-1");
1012+ NodeAssert.equal(events[0].payload.questions[0]?.id, "sandbox_mode");
1013+ NodeAssert.equal(events[0].payload.questions[0]?.multiSelect, false);
10141014 }
10151015
1016− assert.equal(events[1]?.type, "user-input.resolved");
1016+ NodeAssert.equal(events[1]?.type, "user-input.resolved");
10171017 if (events[1]?.type === "user-input.resolved") {
1018− assert.equal(events[1].requestId, "req-user-input-1");
1019− assert.deepEqual(events[1].payload.answers, {
1018+ NodeAssert.equal(events[1].requestId, "req-user-input-1");
1019+ NodeAssert.deepEqual(events[1].payload.answers, {
10201020 sandbox_mode: "workspace-write",
10211021 });
10221022 }
@@ -1060,16 +1060,16 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { · 37 unmodified lines
10601060 } satisfies ProviderEvent);
10611061
10621062 const firstEvent = yield* Fiber.join(firstEventFiber);
1063− assert.equal(firstEvent._tag, "Some");
1063+ NodeAssert.equal(firstEvent._tag, "Some");
10641064 if (firstEvent._tag !== "Some") {
10651065 return;
10661066 }
1067− assert.equal(firstEvent.value.type, "thread.token-usage.updated");
1067+ NodeAssert.equal(firstEvent.value.type, "thread.token-usage.updated");
10681068 if (firstEvent.value.type !== "thread.token-usage.updated") {
10691069 return;
10701070 }
10711071
1072− assert.deepEqual(firstEvent.value.payload.usage, {
1072+ NodeAssert.deepEqual(firstEvent.value.payload.usage, {
10731073 usedTokens: 126,
10741074 totalProcessedTokens: 11_839,
10751075 maxTokens: 258_400,
@@ -1119,15 +1119,15 @@ scopedLifecycleLayer("CodexAdapterLive scoped lifecycle", (it) => { · 43 unmodified lines
11191119 });
11201120
11211121 const runtime = scopedLifecycleRuntimeFactory.lastRuntime;
1122− assert.ok(runtime);
1122+ NodeAssert.ok(runtime);
11231123
11241124 yield* adapter.stopSession(asThreadId("thread-stop"));
11251125
1126− assert.equal(runtime.closeImpl.mock.calls.length, 1);
1127− assert.deepStrictEqual(scopedLifecycleRuntimeFactory.releasedThreadIds, [
1126+ NodeAssert.equal(runtime.closeImpl.mock.calls.length, 1);
1127+ NodeAssert.deepStrictEqual(scopedLifecycleRuntimeFactory.releasedThreadIds, [
11281128 asThreadId("thread-stop"),
11291129 ]);
1130− assert.equal(yield* adapter.hasSession(asThreadId("thread-stop")), false);
1130+ NodeAssert.equal(yield* adapter.hasSession(asThreadId("thread-stop")), false);
11311131 }),
11321132 );
11331133 });
@@ -1164,20 +1164,22 @@ scopedFailureLayer("CodexAdapterLive scoped startup failure", (it) => { · 30 unmodified lines
11641164 })
11651165 .pipe(Effect.result);
11661166
1167− assert.equal(result._tag, "Failure");
1168− assert.equal(result.failure._tag, "ProviderAdapterProcessError");
1169− assert.deepStrictEqual(scopedFailureRuntimeFactory.releasedThreadIds, [
1167+ NodeAssert.equal(result._tag, "Failure");
1168+ NodeAssert.equal(result.failure._tag, "ProviderAdapterProcessError");
1169+ NodeAssert.deepStrictEqual(scopedFailureRuntimeFactory.releasedThreadIds, [
11701170 asThreadId("thread-fail"),
11711171 ]);
1172− assert.equal(yield* adapter.hasSession(asThreadId("thread-fail")), false);
1172+ NodeAssert.equal(yield* adapter.hasSession(asThreadId("thread-fail")), false);
11731173 }),
11741174 );
11751175 });
11761176
11771177 it.effect("flushes managed native logs when the adapter layer shuts down", () =>
11781178 Effect.gen(function* () {
1179− const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-codex-adapter-native-log-"));
1180− const basePath = path.join(tempDir, "provider-native.ndjson");
1179+ const tempDir = NodeFS.mkdtempSync(
1180+ NodePath.join(NodeOS.tmpdir(), "t3-codex-adapter-native-log-"),
1181+ );
1182+ const basePath = NodePath.join(tempDir, "provider-native.ndjson");
11811183 const runtimeFactory = makeRuntimeFactory();
11821184 const scope = yield* Scope.make("sequential");
11831185 let scopeClosed = false;
@@ -1208,7 +1210,7 @@ it.effect("flushes managed native logs when the adapter layer shuts down", () => · 24 unmodified lines
12081210 });
12091211
12101212 const runtime = runtimeFactory.lastRuntime;
1211− assert.ok(runtime);
1213+ NodeAssert.ok(runtime);
12121214
12131215 const firstEventFiber = yield* Stream.runHead(adapter.streamEvents).pipe(Effect.forkChild);
12141216 yield* runtime.emit({
@@ -1225,15 +1227,15 @@ it.effect("flushes managed native logs when the adapter layer shuts down", () => · 10 unmodified lines
12251227 yield* Scope.close(scope, Exit.void);
12261228 scopeClosed = true;
12271229
1228− const threadLogPath = path.join(tempDir, "thread-logger.log");
1229− assert.equal(fs.existsSync(threadLogPath), true);
1230− const contents = fs.readFileSync(threadLogPath, "utf8");
1231− assert.match(contents, /NTIVE: .*"message":"native flush test"/);
1230+ const threadLogPath = NodePath.join(tempDir, "thread-logger.log");
1231+ NodeAssert.equal(NodeFS.existsSync(threadLogPath), true);
1232+ const contents = NodeFS.readFileSync(threadLogPath, "utf8");
1233+ NodeAssert.match(contents, /NTIVE: .*"message":"native flush test"/);
12321234 } finally {
12331235 if (!scopeClosed) {
12341236 yield* Scope.close(scope, Exit.void);
12351237 }
1236− fs.rmSync(tempDir, { recursive: true, force: true });
1238+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
12371239 }
12381240 }),
12391241 );
apps/server/src/provider/Layers/CodexSessionRuntime.test.ts+18−18
@@ -1,4 +1,4 @@
1−import assert from "node:assert/strict";
1+import * as NodeAssert from "node:assert/strict";
22
33 import * as Effect from "effect/Effect";
44 import * as Schema from "effect/Schema";
@@ -55,7 +55,7 @@ describe("buildTurnStartParams", () => { · 50 unmodified lines
5555 }),
5656 );
5757
58− assert.deepStrictEqual(params, {
58+ NodeAssert.deepStrictEqual(params, {
5959 threadId: "provider-thread-1",
6060 approvalPolicy: "never",
6161 sandboxPolicy: {
@@ -97,7 +97,7 @@ describe("buildTurnStartParams", () => { · 35 unmodified lines
9797 }),
9898 );
9999
100− assert.deepStrictEqual(params, {
100+ NodeAssert.deepStrictEqual(params, {
101101 threadId: "provider-thread-1",
102102 approvalPolicy: "on-request",
103103 sandboxPolicy: {
@@ -134,7 +134,7 @@ describe("buildTurnStartParams", () => { · 30 unmodified lines
134134 }),
135135 );
136136
137− assert.deepStrictEqual(params, {
137+ NodeAssert.deepStrictEqual(params, {
138138 threadId: "provider-thread-1",
139139 approvalPolicy: "untrusted",
140140 sandboxPolicy: {
@@ -156,19 +156,19 @@ describe("T3 browser developer instructions", () => { · 15 unmodified lines
156156 CODEX_DEFAULT_MODE_DEVELOPER_INSTRUCTIONS,
157157 CODEX_PLAN_MODE_DEVELOPER_INSTRUCTIONS,
158158 ]) {
159− assert.match(instructions, /t3-code/);
160− assert.match(instructions, /preview_status/);
161− assert.match(instructions, /preview_open/);
162− assert.match(instructions, /Do not switch to global browser skills/);
159+ NodeAssert.match(instructions, /t3-code/);
160+ NodeAssert.match(instructions, /preview_status/);
161+ NodeAssert.match(instructions, /preview_open/);
162+ NodeAssert.match(instructions, /Do not switch to global browser skills/);
163163 }
164164 });
165165 });
166166
167167 describe("hasConfiguredMcpServer", () => {
168168 it("detects inline Codex MCP configuration arguments", () => {
169− assert.equal(hasConfiguredMcpServer(undefined), false);
170− assert.equal(hasConfiguredMcpServer(["--model", "gpt-5.4"]), false);
171− assert.equal(
169+ NodeAssert.equal(hasConfiguredMcpServer(undefined), false);
170+ NodeAssert.equal(hasConfiguredMcpServer(["--model", "gpt-5.4"]), false);
171+ NodeAssert.equal(
172172 hasConfiguredMcpServer(["-c", 'mcp_servers.t3-code.url="http://127.0.0.1/mcp"']),
173173 true,
174174 );
@@ -177,7 +177,7 @@ describe("hasConfiguredMcpServer", () => { · 2 unmodified lines
177177
178178 describe("isRecoverableThreadResumeError", () => {
179179 it("matches missing thread errors", () => {
180− assert.equal(
180+ NodeAssert.equal(
181181 isRecoverableThreadResumeError(
182182 new CodexErrors.CodexAppServerRequestError({
183183 code: -32603,
@@ -189,7 +189,7 @@ describe("isRecoverableThreadResumeError", () => { · 5 unmodified lines
189189 });
190190
191191 it("ignores non-recoverable resume errors", () => {
192− assert.equal(
192+ NodeAssert.equal(
193193 isRecoverableThreadResumeError(
194194 new CodexErrors.CodexAppServerRequestError({
195195 code: -32603,
@@ -201,7 +201,7 @@ describe("isRecoverableThreadResumeError", () => { · 5 unmodified lines
201201 });
202202
203203 it("ignores unrelated missing-resource errors that do not mention threads", () => {
204− assert.equal(
204+ NodeAssert.equal(
205205 isRecoverableThreadResumeError(
206206 new CodexErrors.CodexAppServerRequestError({
207207 code: -32603,
@@ -210,7 +210,7 @@ describe("isRecoverableThreadResumeError", () => { · 2 unmodified lines
210210 ),
211211 false,
212212 );
213− assert.equal(
213+ NodeAssert.equal(
214214 isRecoverableThreadResumeError(
215215 new CodexErrors.CodexAppServerRequestError({
216216 code: -32603,
@@ -256,8 +256,8 @@ describe("openCodexThread", () => { · 39 unmodified lines
256256 }),
257257 );
258258
259− assert.equal(opened.thread.id, "fresh-thread");
260− assert.deepStrictEqual(
259+ NodeAssert.equal(opened.thread.id, "fresh-thread");
260+ NodeAssert.deepStrictEqual(
261261 calls.map((call) => call.method),
262262 ["thread/resume", "thread/start"],
263263 );
@@ -283,7 +283,7 @@ describe("openCodexThread", () => { · 19 unmodified lines
283283 },
284284 };
285285
286− await assert.rejects(
286+ await NodeAssert.rejects(
287287 Effect.runPromise(
288288 openCodexThread({
289289 client,
apps/server/src/provider/Layers/CursorAdapter.test.ts+63−49
@@ -1,8 +1,8 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import * as path from "node:path";
3−import * as os from "node:os";
4−import { chmod, mkdtemp, readFile, writeFile } from "node:fs/promises";
5−import { fileURLToPath } from "node:url";
2+import * as NodePath from "node:path";
3+import * as NodeOS from "node:os";
4+import * as NodeFSP from "node:fs/promises";
5+import * as NodeURL from "node:url";
66
77 import * as NodeServices from "@effect/platform-node/NodeServices";
88 import { assert, it } from "@effect/vitest";
@@ -36,8 +36,8 @@ class CursorAdapter extends Context.Service<CursorAdapter, CursorAdapterShape>() · 27 unmodified lines
3636 "t3/provider/Layers/CursorAdapter.test/CursorAdapter",
3737 ) {}
3838
39−const __dirname = path.dirname(fileURLToPath(import.meta.url));
40−const mockAgentPath = path.join(__dirname, "../../../scripts/acp-mock-agent.ts");
39+const __dirname = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
40+const mockAgentPath = NodePath.join(__dirname, "../../../scripts/acp-mock-agent.ts");
4141 const mockAgentCommand = "node";
4242 const mockAgentArgs = [mockAgentPath] as const;
4343
@@ -45,8 +45,8 @@ async function makeMockAgentWrapper( · 1 unmodified line
4545 extraEnv?: Record<string, string>,
4646 options?: { initialDelaySeconds?: number },
4747 ) {
48− const dir = await mkdtemp(path.join(os.tmpdir(), "cursor-acp-mock-"));
49− const wrapperPath = path.join(dir, "fake-agent.sh");
48+ const dir = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "cursor-acp-mock-"));
49+ const wrapperPath = NodePath.join(dir, "fake-agent.sh");
5050 const envExports = Object.entries(extraEnv ?? {})
5151 .map(([key, value]) => `export ${key}=${JSON.stringify(value)}`)
5252 .join("\n");
@@ -55,8 +55,8 @@ ${envExports} · 2 unmodified lines
5555 ${options?.initialDelaySeconds ? `sleep ${JSON.stringify(String(options.initialDelaySeconds))}` : ""}
5656 exec ${JSON.stringify(mockAgentCommand)} ${mockAgentArgs.map((arg) => JSON.stringify(arg)).join(" ")} "$@"
5757 `;
58− await writeFile(wrapperPath, script, "utf8");
59− await chmod(wrapperPath, 0o755);
58+ await NodeFSP.writeFile(wrapperPath, script, "utf8");
59+ await NodeFSP.chmod(wrapperPath, 0o755);
6060 return wrapperPath;
6161 }
6262
@@ -65,8 +65,8 @@ async function makeProbeWrapper( · 2 unmodified lines
6565 argvLogPath: string,
6666 extraEnv?: Record<string, string>,
6767 ) {
68− const dir = await mkdtemp(path.join(os.tmpdir(), "cursor-acp-probe-"));
69− const wrapperPath = path.join(dir, "fake-agent.sh");
68+ const dir = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "cursor-acp-probe-"));
69+ const wrapperPath = NodePath.join(dir, "fake-agent.sh");
7070 const envExports = Object.entries(extraEnv ?? {})
7171 .map(([key, value]) => `export ${key}=${JSON.stringify(value)}`)
7272 .join("\n");
@@ -77,13 +77,13 @@ export T3_ACP_REQUEST_LOG_PATH=${JSON.stringify(requestLogPath)} · 4 unmodified lines
7777 ${envExports}
7878 exec ${JSON.stringify(mockAgentCommand)} ${mockAgentArgs.map((arg) => JSON.stringify(arg)).join(" ")} "$@"
7979 `;
80− await writeFile(wrapperPath, script, "utf8");
81− await chmod(wrapperPath, 0o755);
80+ await NodeFSP.writeFile(wrapperPath, script, "utf8");
81+ await NodeFSP.chmod(wrapperPath, 0o755);
8282 return wrapperPath;
8383 }
8484
8585 async function readArgvLog(filePath: string) {
86− const raw = await readFile(filePath, "utf8");
86+ const raw = await NodeFSP.readFile(filePath, "utf8");
8787 return raw
8888 .split("\n")
8989 .map((line) => line.trim())
@@ -92,7 +92,7 @@ async function readArgvLog(filePath: string) { · 2 unmodified lines
9292 }
9393
9494 async function readJsonLines(filePath: string) {
95− const raw = await readFile(filePath, "utf8");
95+ const raw = await NodeFSP.readFile(filePath, "utf8");
9696 return raw
9797 .split("\n")
9898 .map((line) => line.trim())
@@ -103,7 +103,7 @@ async function readJsonLines(filePath: string) { · 4 unmodified lines
103103 async function waitForFileContent(filePath: string, attempts = 40) {
104104 for (let attempt = 0; attempt < attempts; attempt += 1) {
105105 try {
106− const raw = await readFile(filePath, "utf8");
106+ const raw = await NodeFSP.readFile(filePath, "utf8");
107107 if (raw.trim().length > 0) {
108108 return raw;
109109 }
@@ -315,9 +315,9 @@ cursorAdapterTestLayer("CursorAdapterLive", (it) => { · 205 unmodified lines
315315 const settings = yield* ServerSettingsService;
316316 const threadId = ThreadId.make("cursor-stop-session-close");
317317 const tempDir = yield* Effect.promise(() =>
318− mkdtemp(path.join(os.tmpdir(), "cursor-adapter-exit-log-")),
318+ NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "cursor-adapter-exit-log-")),
319319 );
320− const exitLogPath = path.join(tempDir, "exit.log");
320+ const exitLogPath = NodePath.join(tempDir, "exit.log");
321321
322322 const wrapperPath = yield* Effect.promise(() =>
323323 makeMockAgentWrapper({
@@ -349,9 +349,9 @@ cursorAdapterTestLayer("CursorAdapterLive", (it) => { · 25 unmodified lines
349349 const settings = yield* ServerSettingsService;
350350 const threadId = ThreadId.make("cursor-concurrent-start-session");
351351 const tempDir = yield* Effect.promise(() =>
352− mkdtemp(path.join(os.tmpdir(), "cursor-adapter-concurrent-exit-log-")),
352+ NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "cursor-adapter-concurrent-exit-log-")),
353353 );
354− const exitLogPath = path.join(tempDir, "exit.log");
354+ const exitLogPath = NodePath.join(tempDir, "exit.log");
355355
356356 const wrapperPath = yield* Effect.promise(() =>
357357 makeMockAgentWrapper(
@@ -414,10 +414,12 @@ cursorAdapterTestLayer("CursorAdapterLive", (it) => { · 56 unmodified lines
414414 const adapter = yield* CursorAdapter;
415415 const serverSettings = yield* ServerSettingsService;
416416 const threadId = ThreadId.make("cursor-plan-mode-probe");
417− const tempDir = yield* Effect.promise(() => mkdtemp(path.join(os.tmpdir(), "cursor-acp-")));
418− const requestLogPath = path.join(tempDir, "requests.ndjson");
419− const argvLogPath = path.join(tempDir, "argv.txt");
420− yield* Effect.promise(() => writeFile(requestLogPath, "", "utf8"));
417+ const tempDir = yield* Effect.promise(() =>
418+ NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "cursor-acp-")),
419+ );
420+ const requestLogPath = NodePath.join(tempDir, "requests.ndjson");
421+ const argvLogPath = NodePath.join(tempDir, "argv.txt");
422+ yield* Effect.promise(() => NodeFSP.writeFile(requestLogPath, "", "utf8"));
421423 const wrapperPath = yield* Effect.promise(() =>
422424 makeProbeWrapper(requestLogPath, argvLogPath),
423425 );
@@ -470,10 +472,12 @@ cursorAdapterTestLayer("CursorAdapterLive", (it) => { · 46 unmodified lines
470472 const adapter = yield* CursorAdapter;
471473 const serverSettings = yield* ServerSettingsService;
472474 const threadId = ThreadId.make("cursor-initial-config-probe");
473− const tempDir = yield* Effect.promise(() => mkdtemp(path.join(os.tmpdir(), "cursor-acp-")));
474− const requestLogPath = path.join(tempDir, "requests.ndjson");
475− const argvLogPath = path.join(tempDir, "argv.txt");
476− yield* Effect.promise(() => writeFile(requestLogPath, "", "utf8"));
475+ const tempDir = yield* Effect.promise(() =>
476+ NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "cursor-acp-")),
477+ );
478+ const requestLogPath = NodePath.join(tempDir, "requests.ndjson");
479+ const argvLogPath = NodePath.join(tempDir, "argv.txt");
480+ yield* Effect.promise(() => NodeFSP.writeFile(requestLogPath, "", "utf8"));
477481 const wrapperPath = yield* Effect.promise(() =>
478482 makeProbeWrapper(requestLogPath, argvLogPath),
479483 );
@@ -713,10 +717,12 @@ cursorAdapterTestLayer("CursorAdapterLive", (it) => { · 233 unmodified lines
713717 const runtimeEvents: Array<ProviderRuntimeEvent> = [];
714718 const settledEventTypes = new Set<string>();
715719 const settledEventsReady = yield* Deferred.make<void>();
716− const tempDir = yield* Effect.promise(() => mkdtemp(path.join(os.tmpdir(), "cursor-acp-")));
717− const requestLogPath = path.join(tempDir, "requests.ndjson");
718− const argvLogPath = path.join(tempDir, "argv.txt");
719− yield* Effect.promise(() => writeFile(requestLogPath, "", "utf8"));
720+ const tempDir = yield* Effect.promise(() =>
721+ NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "cursor-acp-")),
722+ );
723+ const requestLogPath = NodePath.join(tempDir, "requests.ndjson");
724+ const argvLogPath = NodePath.join(tempDir, "argv.txt");
725+ yield* Effect.promise(() => NodeFSP.writeFile(requestLogPath, "", "utf8"));
720726 const wrapperPath = yield* Effect.promise(() =>
721727 makeProbeWrapper(requestLogPath, argvLogPath, { T3_ACP_EMIT_TOOL_CALLS: "1" }),
722728 );
@@ -931,10 +937,12 @@ cursorAdapterTestLayer("CursorAdapterLive", (it) => { · 208 unmodified lines
931937 const adapter = yield* CursorAdapter;
932938 const serverSettings = yield* ServerSettingsService;
933939 const threadId = ThreadId.make("cursor-cancel-probe");
934− const tempDir = yield* Effect.promise(() => mkdtemp(path.join(os.tmpdir(), "cursor-acp-")));
935− const requestLogPath = path.join(tempDir, "requests.ndjson");
936− const argvLogPath = path.join(tempDir, "argv.txt");
937− yield* Effect.promise(() => writeFile(requestLogPath, "", "utf8"));
940+ const tempDir = yield* Effect.promise(() =>
941+ NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "cursor-acp-")),
942+ );
943+ const requestLogPath = NodePath.join(tempDir, "requests.ndjson");
944+ const argvLogPath = NodePath.join(tempDir, "argv.txt");
945+ yield* Effect.promise(() => NodeFSP.writeFile(requestLogPath, "", "utf8"));
938946 const wrapperPath = yield* Effect.promise(() =>
939947 makeProbeWrapper(requestLogPath, argvLogPath, { T3_ACP_EMIT_TOOL_CALLS: "1" }),
940948 );
@@ -1192,10 +1200,12 @@ cursorAdapterTestLayer("CursorAdapterLive", (it) => { · 251 unmodified lines
11921200 const adapter = yield* CursorAdapter;
11931201 const serverSettings = yield* ServerSettingsService;
11941202 const threadId = ThreadId.make("cursor-model-switch");
1195− const tempDir = yield* Effect.promise(() => mkdtemp(path.join(os.tmpdir(), "cursor-acp-")));
1196− const requestLogPath = path.join(tempDir, "requests.ndjson");
1197− const argvLogPath = path.join(tempDir, "argv.txt");
1198− yield* Effect.promise(() => writeFile(requestLogPath, "", "utf8"));
1203+ const tempDir = yield* Effect.promise(() =>
1204+ NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "cursor-acp-")),
1205+ );
1206+ const requestLogPath = NodePath.join(tempDir, "requests.ndjson");
1207+ const argvLogPath = NodePath.join(tempDir, "argv.txt");
1208+ yield* Effect.promise(() => NodeFSP.writeFile(requestLogPath, "", "utf8"));
11991209 const wrapperPath = yield* Effect.promise(() =>
12001210 makeProbeWrapper(requestLogPath, argvLogPath),
12011211 );
@@ -1255,10 +1265,12 @@ cursorAdapterTestLayer("CursorAdapterLive", (it) => { · 53 unmodified lines
12551265 const adapter = yield* CursorAdapter;
12561266 const serverSettings = yield* ServerSettingsService;
12571267 const threadId = ThreadId.make("cursor-fast-mode-reset");
1258− const tempDir = yield* Effect.promise(() => mkdtemp(path.join(os.tmpdir(), "cursor-acp-")));
1259− const requestLogPath = path.join(tempDir, "requests.ndjson");
1260− const argvLogPath = path.join(tempDir, "argv.txt");
1261− yield* Effect.promise(() => writeFile(requestLogPath, "", "utf8"));
1268+ const tempDir = yield* Effect.promise(() =>
1269+ NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "cursor-acp-")),
1270+ );
1271+ const requestLogPath = NodePath.join(tempDir, "requests.ndjson");
1272+ const argvLogPath = NodePath.join(tempDir, "argv.txt");
1273+ yield* Effect.promise(() => NodeFSP.writeFile(requestLogPath, "", "utf8"));
12621274 const wrapperPath = yield* Effect.promise(() =>
12631275 makeProbeWrapper(requestLogPath, argvLogPath),
12641276 );
@@ -1339,10 +1351,12 @@ cursorAdapterTestLayer("CursorAdapterLive", (it) => { · 74 unmodified lines
13391351 const adapter = yield* CursorAdapter;
13401352 const serverSettings = yield* ServerSettingsService;
13411353 const threadId = ThreadId.make("cursor-fast-mode-custom-instance");
1342− const tempDir = yield* Effect.promise(() => mkdtemp(path.join(os.tmpdir(), "cursor-acp-")));
1343− const requestLogPath = path.join(tempDir, "requests.ndjson");
1344− const argvLogPath = path.join(tempDir, "argv.txt");
1345− yield* Effect.promise(() => writeFile(requestLogPath, "", "utf8"));
1354+ const tempDir = yield* Effect.promise(() =>
1355+ NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "cursor-acp-")),
1356+ );
1357+ const requestLogPath = NodePath.join(tempDir, "requests.ndjson");
1358+ const argvLogPath = NodePath.join(tempDir, "argv.txt");
1359+ yield* Effect.promise(() => NodeFSP.writeFile(requestLogPath, "", "utf8"));
13461360 const wrapperPath = yield* Effect.promise(() =>
13471361 makeProbeWrapper(requestLogPath, argvLogPath),
13481362 );
apps/server/src/provider/Layers/CursorProvider.ts+2−2
@@ -1,4 +1,4 @@
1−import * as NodeOs from "node:os";
1+import * as NodeOS from "node:os";
22 import type {
33 CursorSettings,
44 ModelCapabilities,
@@ -746,7 +746,7 @@ function isCursorAboutJsonFormatUnsupported(result: CommandResult): boolean { · 741 unmodified lines
746746 const readCursorCliConfigChannel = Effect.fn("readCursorCliConfigChannel")(function* () {
747747 const fileSystem = yield* FileSystem.FileSystem;
748748 const path = yield* Path.Path;
749− const configPath = path.join(NodeOs.homedir(), ".cursor", "cli-config.json");
749+ const configPath = path.join(NodeOS.homedir(), ".cursor", "cli-config.json");
750750 const raw = yield* fileSystem.readFileString(configPath).pipe(Effect.orElseSucceed(() => ""));
751751 return parseCursorCliConfigChannel(raw);
752752 });
apps/server/src/provider/Layers/EventNdjsonLogger.test.ts+28−31
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import fs from "node:fs";
3−import os from "node:os";
4−import path from "node:path";
2+import * as NodeFS from "node:fs";
3+import * as NodeOS from "node:os";
4+import * as NodePath from "node:path";
55
66 import { ThreadId } from "@t3tools/contracts";
77 import { assert, describe, it } from "@effect/vitest";
@@ -31,8 +31,8 @@ function parseLogLine(line: string) { · 23 unmodified lines
3131 describe("EventNdjsonLogger", () => {
3232 it.effect("writes effect-style lines to thread-scoped files", () =>
3333 Effect.gen(function* () {
34− const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-provider-log-"));
35− const basePath = path.join(tempDir, "provider-native.ndjson");
34+ const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-provider-log-"));
35+ const basePath = NodePath.join(tempDir, "provider-native.ndjson");
3636
3737 try {
3838 const logger = yield* makeEventNdjsonLogger(basePath, { stream: "native" });
@@ -51,13 +51,13 @@ describe("EventNdjsonLogger", () => { · 12 unmodified lines
5151 );
5252 yield* logger.close();
5353
54− const threadOnePath = path.join(tempDir, "thread-1.log");
55− const threadTwoPath = path.join(tempDir, "thread-2.log");
56− assert.equal(fs.existsSync(threadOnePath), true);
57− assert.equal(fs.existsSync(threadTwoPath), true);
54+ const threadOnePath = NodePath.join(tempDir, "thread-1.log");
55+ const threadTwoPath = NodePath.join(tempDir, "thread-2.log");
56+ assert.equal(NodeFS.existsSync(threadOnePath), true);
57+ assert.equal(NodeFS.existsSync(threadTwoPath), true);
5858
59− const first = parseLogLine(fs.readFileSync(threadOnePath, "utf8").trim());
60− const second = parseLogLine(fs.readFileSync(threadTwoPath, "utf8").trim());
59+ const first = parseLogLine(NodeFS.readFileSync(threadOnePath, "utf8").trim());
60+ const second = parseLogLine(NodeFS.readFileSync(threadTwoPath, "utf8").trim());
6161
6262 assert.equal(Number.isNaN(Date.parse(first.observedAt)), false);
6363 assert.equal(first.stream, "NTIVE");
@@ -70,7 +70,7 @@ describe("EventNdjsonLogger", () => { · 6 unmodified lines
7070 '{"type":"turn.completed","threadId":"provider-thread-2","id":"evt-2"}',
7171 );
7272 } finally {
73− fs.rmSync(tempDir, { recursive: true, force: true });
73+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
7474 }
7575 }),
7676 );
@@ -79,8 +79,8 @@ describe("EventNdjsonLogger", () => { · 2 unmodified lines
7979 "falls back to a global segment when orchestration thread id is missing or invalid",
8080 () =>
8181 Effect.gen(function* () {
82− const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-provider-log-"));
83− const basePath = path.join(tempDir, "provider-canonical.ndjson");
82+ const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-provider-log-"));
83+ const basePath = NodePath.join(tempDir, "provider-canonical.ndjson");
8484
8585 try {
8686 const logger = yield* makeEventNdjsonLogger(basePath, { stream: "orchestration" });
@@ -93,10 +93,9 @@ describe("EventNdjsonLogger", () => { · 6 unmodified lines
9393 yield* logger.write({ id: "evt-invalid-thread" }, "!!!" as unknown as ThreadId);
9494 yield* logger.close();
9595
96− const globalPath = path.join(tempDir, "_global.log");
97− assert.equal(fs.existsSync(globalPath), true);
98− const lines = fs
99− .readFileSync(globalPath, "utf8")
96+ const globalPath = NodePath.join(tempDir, "_global.log");
97+ assert.equal(NodeFS.existsSync(globalPath), true);
98+ const lines = NodeFS.readFileSync(globalPath, "utf8")
10099 .trim()
101100 .split("\n")
102101 .map((line) => parseLogLine(line));
@@ -108,15 +107,15 @@ describe("EventNdjsonLogger", () => { · 5 unmodified lines
108107 assert.equal(lines[1]?.stream, "CANON");
109108 assert.equal(lines[1]?.payload, '{"id":"evt-invalid-thread"}');
110109 } finally {
111− fs.rmSync(tempDir, { recursive: true, force: true });
110+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
112111 }
113112 }),
114113 );
115114
116115 it.effect("serializes concurrent first writes for the same segment", () =>
117116 Effect.gen(function* () {
118− const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-provider-log-"));
119− const basePath = path.join(tempDir, "provider-canonical.ndjson");
117+ const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-provider-log-"));
118+ const basePath = NodePath.join(tempDir, "provider-canonical.ndjson");
120119
121120 try {
122121 const logger = yield* makeEventNdjsonLogger(basePath, {
@@ -137,10 +136,9 @@ describe("EventNdjsonLogger", () => { · 14 unmodified lines
137136 );
138137 yield* logger.close();
139138
140− const globalPath = path.join(tempDir, "_global.log");
141− assert.equal(fs.existsSync(globalPath), true);
142− const lines = fs
143− .readFileSync(globalPath, "utf8")
139+ const globalPath = NodePath.join(tempDir, "_global.log");
140+ assert.equal(NodeFS.existsSync(globalPath), true);
141+ const lines = NodeFS.readFileSync(globalPath, "utf8")
144142 .trim()
145143 .split("\n")
146144 .map((line) => parseLogLine(line));
@@ -151,15 +149,15 @@ describe("EventNdjsonLogger", () => { · 4 unmodified lines
151149 '{"id":"evt-concurrent-2"}',
152150 ]);
153151 } finally {
154− fs.rmSync(tempDir, { recursive: true, force: true });
152+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
155153 }
156154 }),
157155 );
158156
159157 it.effect("rotates per-thread files when max size is exceeded", () =>
160158 Effect.gen(function* () {
161− const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-provider-log-"));
162− const basePath = path.join(tempDir, "provider-native.ndjson");
159+ const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-provider-log-"));
160+ const basePath = NodePath.join(tempDir, "provider-native.ndjson");
163161
164162 try {
165163 const logger = yield* makeEventNdjsonLogger(basePath, {
@@ -185,8 +183,7 @@ describe("EventNdjsonLogger", () => { · 19 unmodified lines
185183 yield* logger.close();
186184
187185 const fileStem = "thread-rotate.log";
188− const matchingFiles = fs
189− .readdirSync(tempDir)
186+ const matchingFiles = NodeFS.readdirSync(tempDir)
190187 .filter((entry) => entry === fileStem || entry.startsWith(`${fileStem}.`))
191188 .toSorted();
192189
@@ -203,7 +200,7 @@ describe("EventNdjsonLogger", () => { · 10 unmodified lines
203200 false,
204201 );
205202 } finally {
206− fs.rmSync(tempDir, { recursive: true, force: true });
203+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
207204 }
208205 }),
209206 );
apps/server/src/provider/Layers/EventNdjsonLogger.ts+4−4
@@ -6,8 +6,8 @@ · 5 unmodified lines
66 * single effect-style text line in a thread-scoped file. Failures are
77 * downgraded to warnings so provider runtime behavior is unaffected.
88 */
9−import fs from "node:fs";
10−import path from "node:path";
9+import * as NodeFS from "node:fs";
10+import * as NodePath from "node:path";
1111
1212 import type { ThreadId } from "@t3tools/contracts";
1313 import { RotatingFileSink } from "@t3tools/shared/logging";
@@ -178,7 +178,7 @@ export const makeEventNdjsonLogger = Effect.fn("makeEventNdjsonLogger")(function · 164 unmodified lines
178178
179179 const directoryReady = yield* Effect.sync(() => {
180180 try {
181− fs.mkdirSync(path.dirname(filePath), { recursive: true });
181+ NodeFS.mkdirSync(NodePath.dirname(filePath), { recursive: true });
182182 return true;
183183 } catch (error) {
184184 return { ok: false as const, error };
@@ -211,7 +211,7 @@ export const makeEventNdjsonLogger = Effect.fn("makeEventNdjsonLogger")(function · 26 unmodified lines
211211 }
212212
213213 return makeThreadWriter({
214− filePath: path.join(path.dirname(filePath), `${threadSegment}.log`),
214+ filePath: NodePath.join(NodePath.dirname(filePath), `${threadSegment}.log`),
215215 maxBytes,
216216 maxFiles,
217217 batchWindowMs,
apps/server/src/provider/Layers/GrokAdapter.test.ts+18−16
@@ -1,8 +1,8 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import * as path from "node:path";
3−import * as os from "node:os";
4−import { chmod, mkdtemp, readFile, writeFile } from "node:fs/promises";
5−import { fileURLToPath } from "node:url";
2+import * as NodePath from "node:path";
3+import * as NodeOS from "node:os";
4+import * as NodeFSP from "node:fs/promises";
5+import * as NodeURL from "node:url";
66
77 import * as NodeServices from "@effect/platform-node/NodeServices";
88 import { assert, it } from "@effect/vitest";
@@ -26,13 +26,13 @@ import { ServerConfig } from "../../config.ts"; · 17 unmodified lines
2626 import { makeGrokAdapter } from "./GrokAdapter.ts";
2727 const decodeGrokSettings = Schema.decodeSync(GrokSettings);
2828
29−const __dirname = path.dirname(fileURLToPath(import.meta.url));
30−const mockAgentPath = path.join(__dirname, "../../../scripts/acp-mock-agent.ts");
29+const __dirname = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
30+const mockAgentPath = NodePath.join(__dirname, "../../../scripts/acp-mock-agent.ts");
3131 const mockAgentCommand = process.execPath;
3232
3333 async function makeMockGrokWrapper(extraEnv?: Record<string, string>) {
34− const dir = await mkdtemp(path.join(os.tmpdir(), "grok-acp-mock-"));
35− const wrapperPath = path.join(dir, "fake-grok.sh");
34+ const dir = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "grok-acp-mock-"));
35+ const wrapperPath = NodePath.join(dir, "fake-grok.sh");
3636 const envExports = Object.entries(extraEnv ?? {})
3737 .map(([key, value]) => `export ${key}=${JSON.stringify(value)}`)
3838 .join("\n");
@@ -40,8 +40,8 @@ async function makeMockGrokWrapper(extraEnv?: Record<string, string>) { · 1 unmodified line
4040 ${envExports}
4141 exec ${JSON.stringify(mockAgentCommand)} ${JSON.stringify(mockAgentPath)} "$@"
4242 `;
43− await writeFile(wrapperPath, script, "utf8");
44− await chmod(wrapperPath, 0o755);
43+ await NodeFSP.writeFile(wrapperPath, script, "utf8");
44+ await NodeFSP.chmod(wrapperPath, 0o755);
4545 return wrapperPath;
4646 }
4747
@@ -51,7 +51,7 @@ function waitForFileContent(filePath: string, attempts = 40): Effect.Effect<stri · 3 unmodified lines
5151 if (remainingAttempts <= 0) {
5252 return yield* Effect.die(new Error(`Timed out waiting for file content at ${filePath}`));
5353 }
54− const raw = yield* Effect.tryPromise(() => readFile(filePath, "utf8")).pipe(
54+ const raw = yield* Effect.tryPromise(() => NodeFSP.readFile(filePath, "utf8")).pipe(
5555 Effect.orElseSucceed(() => ""),
5656 );
5757 if (raw.trim().length > 0) {
@@ -64,7 +64,7 @@ function waitForFileContent(filePath: string, attempts = 40): Effect.Effect<stri · 6 unmodified lines
6464 }
6565
6666 async function readJsonLines(filePath: string) {
67− const raw = await readFile(filePath, "utf8");
67+ const raw = await NodeFSP.readFile(filePath, "utf8");
6868 return raw
6969 .split("\n")
7070 .map((line) => line.trim())
@@ -149,9 +149,9 @@ it.layer(grokAdapterTestLayer)("GrokAdapterLive", (it) => { · 78 unmodified lines
149149 Effect.gen(function* () {
150150 const threadId = ThreadId.make("grok-stop-session-close");
151151 const tempDir = yield* Effect.promise(() =>
152− mkdtemp(path.join(os.tmpdir(), "grok-adapter-exit-log-")),
152+ NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "grok-adapter-exit-log-")),
153153 );
154− const exitLogPath = path.join(tempDir, "exit.log");
154+ const exitLogPath = NodePath.join(tempDir, "exit.log");
155155
156156 const wrapperPath = yield* Effect.promise(() =>
157157 makeMockGrokWrapper({
@@ -227,8 +227,10 @@ it.layer(grokAdapterTestLayer)("GrokAdapterLive", (it) => { · 69 unmodified lines
227227 it.effect("responds to ACP approvals using provider-supplied option ids", () =>
228228 Effect.gen(function* () {
229229 const threadId = ThreadId.make("grok-custom-approval-option-id");
230− const tempDir = yield* Effect.promise(() => mkdtemp(path.join(os.tmpdir(), "grok-acp-")));
231− const requestLogPath = path.join(tempDir, "requests.ndjson");
230+ const tempDir = yield* Effect.promise(() =>
231+ NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "grok-acp-")),
232+ );
233+ const requestLogPath = NodePath.join(tempDir, "requests.ndjson");
232234 const wrapperPath = yield* Effect.promise(() =>
233235 makeMockGrokWrapper({
234236 T3_ACP_REQUEST_LOG_PATH: requestLogPath,
apps/server/src/provider/Layers/OpenCodeAdapter.test.ts+48−48
@@ -1,4 +1,4 @@
1−import assert from "node:assert/strict";
1+import * as NodeAssert from "node:assert/strict";
22 import * as NodeServices from "@effect/platform-node/NodeServices";
33 import { it } from "@effect/vitest";
44 import * as Context from "effect/Context";
@@ -238,11 +238,11 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 233 unmodified lines
238238 runtimeMode: "full-access",
239239 });
240240
241− assert.equal(session.provider, "opencode");
242− assert.equal(session.threadId, "thread-opencode");
243− assert.deepEqual(runtimeMock.state.startCalls, []);
244− assert.deepEqual(runtimeMock.state.sessionCreateUrls, ["http://127.0.0.1:9999"]);
245− assert.deepEqual(runtimeMock.state.authHeaders, [
241+ NodeAssert.equal(session.provider, "opencode");
242+ NodeAssert.equal(session.threadId, "thread-opencode");
243+ NodeAssert.deepEqual(runtimeMock.state.startCalls, []);
244+ NodeAssert.deepEqual(runtimeMock.state.sessionCreateUrls, ["http://127.0.0.1:9999"]);
245+ NodeAssert.deepEqual(runtimeMock.state.authHeaders, [
246246 `Basic ${btoa("opencode:secret-password")}`,
247247 ]);
248248 }),
@@ -259,8 +259,8 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 10 unmodified lines
259259
260260 yield* adapter.stopSession(asThreadId("thread-opencode"));
261261
262− assert.deepEqual(runtimeMock.state.startCalls, []);
263− assert.deepEqual(
262+ NodeAssert.deepEqual(runtimeMock.state.startCalls, []);
263+ NodeAssert.deepEqual(
264264 runtimeMock.state.abortCalls.includes("http://127.0.0.1:9999/session"),
265265 true,
266266 );
@@ -286,7 +286,7 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 19 unmodified lines
286286 yield* adapter.stopSession(threadId);
287287
288288 const events = Array.from(yield* Fiber.join(eventsFiber).pipe(Effect.timeout("1 second")));
289− assert.deepEqual(
289+ NodeAssert.deepEqual(
290290 events.map((event) => event.type),
291291 ["session.started", "thread.started", "session.exited"],
292292 );
@@ -316,11 +316,11 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 23 unmodified lines
316316 yield* Effect.exit(adapter.stopAll());
317317 const sessions = yield* adapter.listSessions();
318318
319− assert.deepEqual(runtimeMock.state.closeCalls, [
319+ NodeAssert.deepEqual(runtimeMock.state.closeCalls, [
320320 "http://127.0.0.1:9999",
321321 "http://127.0.0.1:9999",
322322 ]);
323− assert.deepEqual(sessions, []);
323+ NodeAssert.deepEqual(sessions, []);
324324 }),
325325 );
326326
@@ -348,7 +348,7 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 21 unmodified lines
348348 scopeClosed = true;
349349
350350 const exit = yield* Fiber.await(eventsFiber).pipe(Effect.timeout("1 second"));
351− assert.equal(Exit.hasInterrupts(exit), true);
351+ NodeAssert.equal(Exit.hasInterrupts(exit), true);
352352 } finally {
353353 if (!scopeClosed) {
354354 yield* Scope.close(scope, Exit.void).pipe(Effect.ignore);
@@ -379,19 +379,19 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 24 unmodified lines
379379 .pipe(Effect.flip);
380380 const sessions = yield* adapter.listSessions();
381381
382− assert.equal(error._tag, "ProviderAdapterRequestError");
382+ NodeAssert.equal(error._tag, "ProviderAdapterRequestError");
383383 if (error._tag !== "ProviderAdapterRequestError") {
384384 throw new Error("Unexpected error type");
385385 }
386− assert.equal(error.detail, "prompt failed");
387− assert.equal(
386+ NodeAssert.equal(error.detail, "prompt failed");
387+ NodeAssert.equal(
388388 error.message,
389389 "Provider adapter request failed (opencode) for session.promptAsync: prompt failed",
390390 );
391− assert.equal(sessions.length, 1);
392− assert.equal(sessions[0]?.status, "ready");
393− assert.equal(sessions[0]?.activeTurnId, undefined);
394− assert.equal(sessions[0]?.lastError, "prompt failed");
391+ NodeAssert.equal(sessions.length, 1);
392+ NodeAssert.equal(sessions[0]?.status, "ready");
393+ NodeAssert.equal(sessions[0]?.activeTurnId, undefined);
394+ NodeAssert.equal(sessions[0]?.lastError, "prompt failed");
395395 }),
396396 );
397397
@@ -424,13 +424,13 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 26 unmodified lines
424424 model: "openai/gpt-5",
425425 },
426426 });
427− assert.equal(String(steeredTurn.turnId), String(turn.turnId));
427+ NodeAssert.equal(String(steeredTurn.turnId), String(turn.turnId));
428428
429429 const sessions = yield* adapter.listSessions();
430430 const session = sessions.find((entry) => entry.threadId === threadId);
431− assert.equal(session?.status, "running");
432− assert.equal(String(session?.activeTurnId), String(turn.turnId));
433− assert.equal(runtimeMock.state.promptCalls.length, 2);
431+ NodeAssert.equal(session?.status, "running");
432+ NodeAssert.equal(String(session?.activeTurnId), String(turn.turnId));
433+ NodeAssert.equal(runtimeMock.state.promptCalls.length, 2);
434434 }),
435435 );
436436
@@ -466,11 +466,11 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 29 unmodified lines
466466 .pipe(Effect.flip);
467467
468468 // The original turn keeps running — only the steer prompt failed.
469− assert.equal(error._tag, "ProviderAdapterRequestError");
469+ NodeAssert.equal(error._tag, "ProviderAdapterRequestError");
470470 const sessions = yield* adapter.listSessions();
471471 const session = sessions.find((entry) => entry.threadId === threadId);
472− assert.equal(session?.status, "running");
473− assert.equal(String(session?.activeTurnId), String(turn.turnId));
472+ NodeAssert.equal(session?.status, "running");
473+ NodeAssert.equal(String(session?.activeTurnId), String(turn.turnId));
474474 }),
475475 );
476476
@@ -508,7 +508,7 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 31 unmodified lines
508508 ),
509509 });
510510
511− assert.deepEqual(runtimeMock.state.promptCalls.at(-1), {
511+ NodeAssert.deepEqual(runtimeMock.state.promptCalls.at(-1), {
512512 sessionID: "http://127.0.0.1:9999/session",
513513 model: {
514514 providerID: "anthropic",
@@ -552,7 +552,7 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 37 unmodified lines
552552 input: "Fix it",
553553 });
554554
555− assert.deepEqual(runtimeMock.state.promptCalls.at(-1), {
555+ NodeAssert.deepEqual(runtimeMock.state.promptCalls.at(-1), {
556556 sessionID: "http://127.0.0.1:9999/session",
557557 model: {
558558 providerID: "anthropic",
@@ -596,15 +596,15 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 37 unmodified lines
596596 })
597597 .pipe(Effect.flip);
598598
599− assert.equal(error._tag, "ProviderAdapterValidationError");
599+ NodeAssert.equal(error._tag, "ProviderAdapterValidationError");
600600 if (error._tag !== "ProviderAdapterValidationError") {
601601 throw new Error("Unexpected error type");
602602 }
603− assert.equal(
603+ NodeAssert.equal(
604604 error.issue,
605605 "OpenCode model selection is bound to instance 'opencode', expected 'opencode_zen'.",
606606 );
607− assert.deepEqual(runtimeMock.state.promptCalls, []);
607+ NodeAssert.deepEqual(runtimeMock.state.promptCalls, []);
608608 }).pipe(Effect.provide(adapterLayer));
609609 });
610610
@@ -631,10 +631,10 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 20 unmodified lines
631631
632632 const snapshot = yield* adapter.rollbackThread(threadId, 2);
633633
634− assert.deepEqual(runtimeMock.state.revertCalls, [
634+ NodeAssert.deepEqual(runtimeMock.state.revertCalls, [
635635 { sessionID: "http://127.0.0.1:9999/session" },
636636 ]);
637− assert.deepEqual(snapshot.turns, []);
637+ NodeAssert.deepEqual(snapshot.turns, []);
638638 }),
639639 );
640640
@@ -644,11 +644,11 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 3 unmodified lines
644644 const overlapDelta = appendOpenCodeAssistantTextDelta(firstUpdate.latestText, "lo world");
645645 const secondUpdate = mergeOpenCodeAssistantText(overlapDelta.nextText, "Hellolo world");
646646
647− assert.deepEqual(
647+ NodeAssert.deepEqual(
648648 [firstUpdate.deltaToEmit, overlapDelta.deltaToEmit, secondUpdate.deltaToEmit],
649649 ["Hello", "lo world", ""],
650650 );
651− assert.equal(secondUpdate.latestText, "Hellolo world");
651+ NodeAssert.equal(secondUpdate.latestText, "Hellolo world");
652652 }),
653653 );
654654
@@ -721,14 +721,14 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 66 unmodified lines
721721
722722 const events = Array.from(yield* Fiber.join(eventsFiber).pipe(Effect.timeout("1 second")));
723723 const deltas = events.filter((event) => event.type === "content.delta");
724− assert.deepEqual(
724+ NodeAssert.deepEqual(
725725 deltas.map((event) => (event.type === "content.delta" ? event.payload.delta : "")),
726726 ["A B", "Bonus"],
727727 );
728− assert.equal(events.at(-1)?.type, "item.completed");
728+ NodeAssert.equal(events.at(-1)?.type, "item.completed");
729729 const completed = events.at(-1);
730730 if (completed?.type === "item.completed") {
731− assert.equal(completed.payload.detail, "A BBonus");
731+ NodeAssert.equal(completed.payload.detail, "A BBonus");
732732 }
733733 }),
734734 );
@@ -820,27 +820,27 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 85 unmodified lines
820820 return started;
821821 }).pipe(Effect.provide(adapterLayer));
822822
823− assert.equal(session.threadId, "thread-native-log");
824− assert.equal(nativeEvents.length, 1);
825− assert.equal(
823+ NodeAssert.equal(session.threadId, "thread-native-log");
824+ NodeAssert.equal(nativeEvents.length, 1);
825+ NodeAssert.equal(
826826 nativeEvents.some((record) => record.event?.provider === "opencode"),
827827 true,
828828 );
829− assert.equal(
829+ NodeAssert.equal(
830830 nativeEvents.some(
831831 (record) => record.event?.providerThreadId === "http://127.0.0.1:9999/session",
832832 ),
833833 true,
834834 );
835− assert.equal(
835+ NodeAssert.equal(
836836 nativeEvents.some((record) => record.event?.threadId === "thread-native-log"),
837837 true,
838838 );
839− assert.equal(
839+ NodeAssert.equal(
840840 nativeEvents.some((record) => record.event?.type === "message.updated"),
841841 true,
842842 );
843− assert.equal(
843+ NodeAssert.equal(
844844 nativeThreadIds.every((threadId) => threadId === "thread-native-log"),
845845 true,
846846 );
@@ -911,9 +911,9 @@ it.layer(OpenCodeAdapterTestLayer)("OpenCodeAdapterLive", (it) => { · 64 unmodified lines
911911 };
912912 }).pipe(Effect.provide(adapterLayer));
913913
914− assert.equal(sessions.length, 1);
915− assert.equal(sessions[0]?.threadId, "thread-native-log-failure");
916− assert.deepEqual(closeCallsDuringRun, []);
914+ NodeAssert.equal(sessions.length, 1);
915+ NodeAssert.equal(sessions[0]?.threadId, "thread-native-log-failure");
916+ NodeAssert.deepEqual(closeCallsDuringRun, []);
917917 }),
918918 );
919919 });
apps/server/src/provider/Layers/OpenCodeProvider.test.ts+22−19
@@ -1,4 +1,4 @@
1−import assert from "node:assert/strict";
1+import * as NodeAssert from "node:assert/strict";
22
33 import * as NodeServices from "@effect/platform-node/NodeServices";
44 import { it } from "@effect/vitest";
@@ -122,9 +122,12 @@ it.layer(testLayer)("checkOpenCodeProviderStatus", (it) => { · 117 unmodified lines
122122 runtimeMock.state.runVersionError = new Error("spawn opencode ENOENT");
123123 const snapshot = yield* checkOpenCodeProviderStatus(makeOpenCodeSettings(), process.cwd());
124124
125− assert.equal(snapshot.status, "error");
126− assert.equal(snapshot.installed, false);
127− assert.equal(snapshot.message, "OpenCode CLI (`opencode`) is not installed or not on PATH.");
125+ NodeAssert.equal(snapshot.status, "error");
126+ NodeAssert.equal(snapshot.installed, false);
127+ NodeAssert.equal(
128+ snapshot.message,
129+ "OpenCode CLI (`opencode`) is not installed or not on PATH.",
130+ );
128131 }),
129132 );
130133
@@ -133,9 +136,9 @@ it.layer(testLayer)("checkOpenCodeProviderStatus", (it) => { · 2 unmodified lines
133136 runtimeMock.state.runVersionError = new Error("An error occurred in Effect.tryPromise");
134137 const snapshot = yield* checkOpenCodeProviderStatus(makeOpenCodeSettings(), process.cwd());
135138
136− assert.equal(snapshot.status, "error");
137− assert.equal(snapshot.installed, true);
138− assert.equal(snapshot.message, "Failed to execute OpenCode CLI health check.");
139+ NodeAssert.equal(snapshot.status, "error");
140+ NodeAssert.equal(snapshot.installed, true);
141+ NodeAssert.equal(snapshot.message, "Failed to execute OpenCode CLI health check.");
139142 }),
140143 );
141144
@@ -174,20 +177,20 @@ it.layer(testLayer)("checkOpenCodeProviderStatus", (it) => { · 32 unmodified lines
174177 const snapshot = yield* checkOpenCodeProviderStatus(makeOpenCodeSettings(), process.cwd());
175178 const model = snapshot.models.find((entry) => entry.slug === "openai/gpt-5.4");
176179
177− assert.ok(model);
180+ NodeAssert.ok(model);
178181 const variantDescriptor = model.capabilities?.optionDescriptors?.find(
179182 (descriptor) => descriptor.id === "variant" && descriptor.type === "select",
180183 );
181− assert.ok(variantDescriptor && variantDescriptor.type === "select");
182− assert.equal(
184+ NodeAssert.ok(variantDescriptor && variantDescriptor.type === "select");
185+ NodeAssert.equal(
183186 variantDescriptor.options.find((option) => option.isDefault === true)?.id,
184187 "medium",
185188 );
186189 const agentDescriptor = model.capabilities?.optionDescriptors?.find(
187190 (descriptor) => descriptor.id === "agent" && descriptor.type === "select",
188191 );
189− assert.ok(agentDescriptor && agentDescriptor.type === "select");
190− assert.equal(
192+ NodeAssert.ok(agentDescriptor && agentDescriptor.type === "select");
193+ NodeAssert.equal(
191194 agentDescriptor.options.find((option) => option.isDefault === true)?.id,
192195 "build",
193196 );
@@ -198,7 +201,7 @@ it.layer(testLayer)("checkOpenCodeProviderStatus", (it) => { · 4 unmodified lines
198201 Effect.gen(function* () {
199202 yield* checkOpenCodeProviderStatus(makeOpenCodeSettings(), process.cwd());
200203
201− assert.equal(runtimeMock.state.closeCalls, 1);
204+ NodeAssert.equal(runtimeMock.state.closeCalls, 1);
202205 }),
203206 );
204207 });
@@ -215,9 +218,9 @@ it.layer(testLayer)("checkOpenCodeProviderStatus with configured server URL", (i · 10 unmodified lines
215218 process.cwd(),
216219 );
217220
218− assert.equal(snapshot.status, "error");
219− assert.equal(snapshot.installed, true);
220− assert.equal(
221+ NodeAssert.equal(snapshot.status, "error");
222+ NodeAssert.equal(snapshot.installed, true);
223+ NodeAssert.equal(
221224 snapshot.message,
222225 "OpenCode server rejected authentication. Check the server URL and password.",
223226 );
@@ -237,9 +240,9 @@ it.layer(testLayer)("checkOpenCodeProviderStatus with configured server URL", (i · 13 unmodified lines
237240 process.cwd(),
238241 );
239242
240− assert.equal(snapshot.status, "error");
241− assert.equal(snapshot.installed, true);
242− assert.equal(
243+ NodeAssert.equal(snapshot.status, "error");
244+ NodeAssert.equal(snapshot.installed, true);
245+ NodeAssert.equal(
243246 snapshot.message,
244247 "Couldn't reach the configured OpenCode server at http://127.0.0.1:9999. Check that the server is running and the URL is correct.",
245248 );
apps/server/src/provider/Layers/ProviderService.test.ts+21−15
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import fs from "node:fs";
3−import os from "node:os";
4−import path from "node:path";
2+import * as NodeFS from "node:fs";
3+import * as NodeOS from "node:os";
4+import * as NodePath from "node:path";
55
66 import type {
77 ProviderApprovalDecision,
@@ -644,8 +644,8 @@ it.effect("ProviderServiceLive writes canonical events to the emitting thread se · 636 unmodified lines
644644
645645 it.effect("ProviderServiceLive keeps persisted resumable sessions on startup", () =>
646646 Effect.gen(function* () {
647− const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-provider-service-"));
648− const dbPath = path.join(tempDir, "orchestration.sqlite");
647+ const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-provider-service-"));
648+ const dbPath = NodePath.join(tempDir, "orchestration.sqlite");
649649
650650 const codex = makeFakeCodexAdapter();
651651 const registry = makeAdapterRegistryMock({
@@ -706,7 +706,7 @@ it.effect("ProviderServiceLive keeps persisted resumable sessions on startup", ( · 54 unmodified lines
706706 }).pipe(Effect.provide(persistenceLayer));
707707 assert.equal(legacyTableRows.length, 0);
708708
709− fs.rmSync(tempDir, { recursive: true, force: true });
709+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
710710 }).pipe(Effect.provide(NodeServices.layer)),
711711 );
712712
@@ -714,8 +714,10 @@ it.effect( · 1 unmodified line
714714 "ProviderServiceLive restores rollback routing after restart using persisted thread mapping",
715715 () =>
716716 Effect.gen(function* () {
717− const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-provider-service-restart-"));
718− const dbPath = path.join(tempDir, "orchestration.sqlite");
717+ const tempDir = NodeFS.mkdtempSync(
718+ NodePath.join(NodeOS.tmpdir(), "t3-provider-service-restart-"),
719+ );
720+ const dbPath = NodePath.join(tempDir, "orchestration.sqlite");
719721 const persistenceLayer = makeSqlitePersistenceLive(dbPath);
720722 const runtimeRepositoryLayer = ProviderSessionRuntime.layer.pipe(
721723 Layer.provide(persistenceLayer),
@@ -834,7 +836,7 @@ it.effect( · 112 unmodified lines
834836 assert.equal(typeof rollbackCall?.[0], "string");
835837 assert.equal(rollbackCall?.[1], 1);
836838
837− fs.rmSync(tempDir, { recursive: true, force: true });
839+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
838840 }).pipe(Effect.provide(NodeServices.layer)),
839841 );
840842
@@ -1283,8 +1285,10 @@ routing.layer("ProviderServiceLive routing", (it) => { · 442 unmodified lines
12831285
12841286 it.effect("reuses persisted resume cursor when startSession is called after a restart", () =>
12851287 Effect.gen(function* () {
1286− const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-provider-service-start-"));
1287− const dbPath = path.join(tempDir, "orchestration.sqlite");
1288+ const tempDir = NodeFS.mkdtempSync(
1289+ NodePath.join(NodeOS.tmpdir(), "t3-provider-service-start-"),
1290+ );
1291+ const dbPath = NodePath.join(tempDir, "orchestration.sqlite");
12881292 const persistenceLayer = makeSqlitePersistenceLive(dbPath);
12891293 const runtimeRepositoryLayer = ProviderSessionRuntime.layer.pipe(
12901294 Layer.provide(persistenceLayer),
@@ -1379,7 +1383,7 @@ routing.layer("ProviderServiceLive routing", (it) => { · 88 unmodified lines
13791383 assert.equal(startPayload.threadId, initial.threadId);
13801384 }
13811385
1382− fs.rmSync(tempDir, { recursive: true, force: true });
1386+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
13831387 }).pipe(Effect.provide(NodeServices.layer)),
13841388 );
13851389
@@ -1387,8 +1391,10 @@ routing.layer("ProviderServiceLive routing", (it) => { · 1 unmodified line
13871391 "reuses persisted cwd when startSession resumes a claude session without cwd input",
13881392 () =>
13891393 Effect.gen(function* () {
1390− const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-provider-service-cwd-"));
1391− const dbPath = path.join(tempDir, "orchestration.sqlite");
1394+ const tempDir = NodeFS.mkdtempSync(
1395+ NodePath.join(NodeOS.tmpdir(), "t3-provider-service-cwd-"),
1396+ );
1397+ const dbPath = NodePath.join(tempDir, "orchestration.sqlite");
13921398 const persistenceLayer = makeSqlitePersistenceLive(dbPath);
13931399 const runtimeRepositoryLayer = ProviderSessionRuntime.layer.pipe(
13941400 Layer.provide(persistenceLayer),
@@ -1477,7 +1483,7 @@ routing.layer("ProviderServiceLive routing", (it) => { · 82 unmodified lines
14771483 assert.equal(startPayload.threadId, initial.threadId);
14781484 }
14791485
1480− fs.rmSync(tempDir, { recursive: true, force: true });
1486+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
14811487 }).pipe(Effect.provide(NodeServices.layer)),
14821488 );
14831489 });
apps/server/src/provider/Layers/ProviderSessionDirectory.test.ts+6−6
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import fs from "node:fs";
3−import os from "node:os";
4−import path from "node:path";
2+import * as NodeFS from "node:fs";
3+import * as NodeOS from "node:os";
4+import * as NodePath from "node:path";
55
66 import * as NodeServices from "@effect/platform-node/NodeServices";
77 import { ProviderDriverKind, ThreadId } from "@t3tools/contracts";
@@ -229,8 +229,8 @@ it.layer(makeDirectoryLayer(SqlitePersistenceMemory))("ProviderSessionDirectoryL · 221 unmodified lines
229229
230230 it("rehydrates persisted mappings across layer restart", () =>
231231 Effect.gen(function* () {
232− const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-provider-directory-"));
233− const dbPath = path.join(tempDir, "orchestration.sqlite");
232+ const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-provider-directory-"));
233+ const dbPath = NodePath.join(tempDir, "orchestration.sqlite");
234234 const directoryLayer = makeDirectoryLayer(makeSqlitePersistenceLive(dbPath));
235235
236236 const threadId = ThreadId.make("thread-restart");
@@ -266,6 +266,6 @@ it.layer(makeDirectoryLayer(SqlitePersistenceMemory))("ProviderSessionDirectoryL · 29 unmodified lines
266266 assert.equal(legacyTableRows.length, 0);
267267 }).pipe(Effect.provide(directoryLayer));
268268
269− fs.rmSync(tempDir, { recursive: true, force: true });
269+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
270270 }));
271271 });
apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts+10−10
@@ -1,8 +1,8 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import * as path from "node:path";
3−import * as os from "node:os";
4−import { fileURLToPath } from "node:url";
5−import { mkdtempSync, readFileSync, rmSync } from "node:fs";
2+import * as NodePath from "node:path";
3+import * as NodeOS from "node:os";
4+import * as NodeURL from "node:url";
5+import * as NodeFS from "node:fs";
66
77 import * as NodeServices from "@effect/platform-node/NodeServices";
88 import { it } from "@effect/vitest";
@@ -13,8 +13,8 @@ import { describe, expect } from "vite-plus/test"; · 4 unmodified lines
1313 import * as AcpSessionRuntime from "./AcpSessionRuntime.ts";
1414 import type * as EffectAcpProtocol from "effect-acp/protocol";
1515
16−const __dirname = path.dirname(fileURLToPath(import.meta.url));
17−const mockAgentPath = path.join(__dirname, "../../../scripts/acp-mock-agent.ts");
16+const __dirname = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
17+const mockAgentPath = NodePath.join(__dirname, "../../../scripts/acp-mock-agent.ts");
1818 const mockAgentCommand = "node";
1919 const mockAgentArgs = [mockAgentPath];
2020
@@ -347,8 +347,8 @@ describe("AcpSessionRuntime", () => { · 326 unmodified lines
347347 });
348348
349349 it.effect("rejects invalid config option values before sending session/set_config_option", () => {
350− const tempDir = mkdtempSync(path.join(os.tmpdir(), "acp-runtime-"));
351− const requestLogPath = path.join(tempDir, "requests.ndjson");
350+ const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "acp-runtime-"));
351+ const requestLogPath = NodePath.join(tempDir, "requests.ndjson");
352352 return Effect.gen(function* () {
353353 const runtime = yield* AcpSessionRuntime.AcpSessionRuntime;
354354 yield* runtime.start();
@@ -363,7 +363,7 @@ describe("AcpSessionRuntime", () => { · 8 unmodified lines
363363 expect(error.message).toContain("composer-2[fast=true]");
364364 }
365365
366− const recordedRequests = readFileSync(requestLogPath, "utf8")
366+ const recordedRequests = NodeFS.readFileSync(requestLogPath, "utf8")
367367 .trim()
368368 .split("\n")
369369 .filter((line) => line.length > 0)
@@ -392,7 +392,7 @@ describe("AcpSessionRuntime", () => { · 22 unmodified lines
392392 ),
393393 Effect.scoped,
394394 Effect.provide(NodeServices.layer),
395− Effect.ensuring(Effect.sync(() => rmSync(tempDir, { recursive: true, force: true }))),
395+ Effect.ensuring(Effect.sync(() => NodeFS.rmSync(tempDir, { recursive: true, force: true }))),
396396 );
397397 });
398398 });
apps/server/src/provider/opencodeRuntime.ts+2−2
@@ -1,4 +1,4 @@
1−import { pathToFileURL } from "node:url";
1+import * as NodeURL from "node:url";
22
33 import type { ChatAttachment, ProviderApprovalDecision, RuntimeMode } from "@t3tools/contracts";
44 import {
@@ -206,7 +206,7 @@ export function toOpenCodeFileParts(input: { · 201 unmodified lines
206206 type: "file",
207207 mime: attachment.mimeType,
208208 filename: attachment.name,
209− url: pathToFileURL(attachmentPath).href,
209+ url: NodeURL.pathToFileURL(attachmentPath).href,
210210 });
211211 }
212212
apps/server/src/provider/providerMaintenance.test.ts+44−44
@@ -1,9 +1,9 @@
11 // @effect-diagnostics nodeBuiltinImport:off
22 import { expect, it } from "@effect/vitest";
3−import { chmodSync, mkdirSync, symlinkSync, writeFileSync } from "node:fs";
3+import * as NodeFS from "node:fs";
44 import * as NodeServices from "@effect/platform-node/NodeServices";
55 import * as NodeOS from "node:os";
6−import path from "node:path";
6+import * as NodePath from "node:path";
77 import { ProviderDriverKind, ProviderInstanceId, type ServerProvider } from "@t3tools/contracts";
88 import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
99 import * as Crypto from "effect/Crypto";
@@ -25,7 +25,7 @@ const driver = (value: string) => ProviderDriverKind.make(value); · 15 unmodified lines
2525 const makeTempDir = (name: string) =>
2626 Crypto.Crypto.pipe(
2727 Effect.flatMap((crypto) => crypto.randomUUIDv4),
28− Effect.map((id) => path.join(NodeOS.tmpdir(), `${name}-${id}`)),
28+ Effect.map((id) => NodePath.join(NodeOS.tmpdir(), `${name}-${id}`)),
2929 );
3030 const isNativeTestCommandPath =
3131 (expectedPathSegment: string) =>
@@ -203,11 +203,11 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { · 171 unmodified lines
203203 () =>
204204 Effect.gen(function* () {
205205 const tempDir = yield* makeTempDir("t3-vite-plus-capabilities");
206− const vitePlusBinDir = path.join(tempDir, ".vite-plus", "bin");
207− mkdirSync(vitePlusBinDir, { recursive: true });
208− const packageToolPath = path.join(vitePlusBinDir, "package-tool");
209− writeFileSync(packageToolPath, "#!/bin/sh\n");
210− chmodSync(packageToolPath, 0o755);
206+ const vitePlusBinDir = NodePath.join(tempDir, ".vite-plus", "bin");
207+ NodeFS.mkdirSync(vitePlusBinDir, { recursive: true });
208+ const packageToolPath = NodePath.join(vitePlusBinDir, "package-tool");
209+ NodeFS.writeFileSync(packageToolPath, "#!/bin/sh\n");
210+ NodeFS.chmodSync(packageToolPath, 0o755);
211211
212212 const capabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(
213213 packageToolUpdate,
@@ -240,9 +240,9 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { · 26 unmodified lines
240240 () =>
241241 Effect.gen(function* () {
242242 const tempDir = yield* makeTempDir("t3-bun-capabilities");
243− const bunBinDir = path.join(tempDir, ".bun", "bin");
244− mkdirSync(bunBinDir, { recursive: true });
245− writeFileSync(path.join(bunBinDir, "native-package-tool.exe"), "MZ");
243+ const bunBinDir = NodePath.join(tempDir, ".bun", "bin");
244+ NodeFS.mkdirSync(bunBinDir, { recursive: true });
245+ NodeFS.writeFileSync(NodePath.join(bunBinDir, "native-package-tool.exe"), "MZ");
246246
247247 const capabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(
248248 nativePackageToolUpdate,
@@ -276,11 +276,11 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { · 27 unmodified lines
276276 () =>
277277 Effect.gen(function* () {
278278 const tempDir = yield* makeTempDir("t3-pnpm-capabilities");
279− const pnpmHomeDir = path.join(tempDir, ".local", "share", "pnpm");
280− mkdirSync(pnpmHomeDir, { recursive: true });
281− const scopedPackageToolPath = path.join(pnpmHomeDir, "scoped-package-tool");
282− writeFileSync(scopedPackageToolPath, "#!/bin/sh\n");
283− chmodSync(scopedPackageToolPath, 0o755);
279+ const pnpmHomeDir = NodePath.join(tempDir, ".local", "share", "pnpm");
280+ NodeFS.mkdirSync(pnpmHomeDir, { recursive: true });
281+ const scopedPackageToolPath = NodePath.join(pnpmHomeDir, "scoped-package-tool");
282+ NodeFS.writeFileSync(scopedPackageToolPath, "#!/bin/sh\n");
283+ NodeFS.chmodSync(scopedPackageToolPath, 0o755);
284284
285285 const capabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(
286286 scopedPackageToolUpdate,
@@ -336,11 +336,11 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { · 49 unmodified lines
336336 () =>
337337 Effect.gen(function* () {
338338 const tempDir = yield* makeTempDir("t3-native-package-tool-native-capabilities");
339− const nativeBinDir = path.join(tempDir, ".local", "bin");
340− mkdirSync(nativeBinDir, { recursive: true });
341− const nativePackageToolPath = path.join(nativeBinDir, "native-package-tool");
342− writeFileSync(nativePackageToolPath, "#!/bin/sh\n");
343− chmodSync(nativePackageToolPath, 0o755);
339+ const nativeBinDir = NodePath.join(tempDir, ".local", "bin");
340+ NodeFS.mkdirSync(nativeBinDir, { recursive: true });
341+ const nativePackageToolPath = NodePath.join(nativeBinDir, "native-package-tool");
342+ NodeFS.writeFileSync(nativePackageToolPath, "#!/bin/sh\n");
343+ NodeFS.chmodSync(nativePackageToolPath, 0o755);
344344
345345 const capabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(
346346 nativePackageToolUpdate,
@@ -373,11 +373,11 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { · 26 unmodified lines
373373 () =>
374374 Effect.gen(function* () {
375375 const tempDir = yield* makeTempDir("t3-scoped-package-tool-native-capabilities");
376− const nativeBinDir = path.join(tempDir, ".scoped-package-tool", "bin");
377− mkdirSync(nativeBinDir, { recursive: true });
378− const scopedPackageToolPath = path.join(nativeBinDir, "scoped-package-tool");
379− writeFileSync(scopedPackageToolPath, "#!/bin/sh\n");
380− chmodSync(scopedPackageToolPath, 0o755);
376+ const nativeBinDir = NodePath.join(tempDir, ".scoped-package-tool", "bin");
377+ NodeFS.mkdirSync(nativeBinDir, { recursive: true });
378+ const scopedPackageToolPath = NodePath.join(nativeBinDir, "scoped-package-tool");
379+ NodeFS.writeFileSync(scopedPackageToolPath, "#!/bin/sh\n");
380+ NodeFS.chmodSync(scopedPackageToolPath, 0o755);
381381
382382 const capabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(
383383 scopedPackageToolUpdate,
@@ -454,8 +454,8 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { · 70 unmodified lines
454454 it.effect("keeps npm updates for binaries symlinked into npm's global node_modules tree", () =>
455455 Effect.gen(function* () {
456456 const tempDir = yield* makeTempDir("t3-npm-capabilities");
457− const binDir = path.join(tempDir, "bin");
458− const packageBinDir = path.join(
457+ const binDir = NodePath.join(tempDir, "bin");
458+ const packageBinDir = NodePath.join(
459459 tempDir,
460460 "lib",
461461 "node_modules",
@@ -463,13 +463,13 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { · 1 unmodified line
463463 "package-tool",
464464 "bin",
465465 );
466− mkdirSync(binDir, { recursive: true });
467− mkdirSync(packageBinDir, { recursive: true });
468− const packageBinPath = path.join(packageBinDir, "package-tool.js");
469− const symlinkPath = path.join(binDir, "package-tool");
470− writeFileSync(packageBinPath, "#!/usr/bin/env node\n");
471− chmodSync(packageBinPath, 0o755);
472− symlinkSync(packageBinPath, symlinkPath);
466+ NodeFS.mkdirSync(binDir, { recursive: true });
467+ NodeFS.mkdirSync(packageBinDir, { recursive: true });
468+ const packageBinPath = NodePath.join(packageBinDir, "package-tool.js");
469+ const symlinkPath = NodePath.join(binDir, "package-tool");
470+ NodeFS.writeFileSync(packageBinPath, "#!/usr/bin/env node\n");
471+ NodeFS.chmodSync(packageBinPath, 0o755);
472+ NodeFS.symlinkSync(packageBinPath, symlinkPath);
473473
474474 const capabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(packageToolUpdate, {
475475 binaryPath: symlinkPath,
@@ -497,8 +497,8 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { · 21 unmodified lines
497497 it.effect("uses Effect FileSystem realPath when detecting pnpm global symlinks", () =>
498498 Effect.gen(function* () {
499499 const tempDir = yield* makeTempDir("t3-pnpm-realpath-capabilities");
500− const binDir = path.join(tempDir, "bin");
501− const packageBinDir = path.join(
500+ const binDir = NodePath.join(tempDir, "bin");
501+ const packageBinDir = NodePath.join(
502502 tempDir,
503503 ".local",
504504 "share",
@@ -510,13 +510,13 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => { · 5 unmodified lines
510510 "package-tool",
511511 "bin",
512512 );
513− mkdirSync(binDir, { recursive: true });
514− mkdirSync(packageBinDir, { recursive: true });
515− const packageBinPath = path.join(packageBinDir, "package-tool.js");
516− const symlinkPath = path.join(binDir, "package-tool");
517− writeFileSync(packageBinPath, "#!/usr/bin/env node\n");
518− chmodSync(packageBinPath, 0o755);
519− symlinkSync(packageBinPath, symlinkPath);
513+ NodeFS.mkdirSync(binDir, { recursive: true });
514+ NodeFS.mkdirSync(packageBinDir, { recursive: true });
515+ const packageBinPath = NodePath.join(packageBinDir, "package-tool.js");
516+ const symlinkPath = NodePath.join(binDir, "package-tool");
517+ NodeFS.writeFileSync(packageBinPath, "#!/usr/bin/env node\n");
518+ NodeFS.chmodSync(packageBinPath, 0o755);
519+ NodeFS.symlinkSync(packageBinPath, symlinkPath);
520520
521521 const capabilities = yield* resolveProviderMaintenanceCapabilitiesEffect(packageToolUpdate, {
522522 binaryPath: symlinkPath,
apps/server/src/relay/AgentAwarenessRelay.test.ts+2−2
@@ -1,4 +1,4 @@
1−import { generateKeyPairSync } from "node:crypto";
1+import * as NodeCrypto from "node:crypto";
22 import * as NodeServices from "@effect/platform-node/NodeServices";
33
44 import type {
@@ -348,7 +348,7 @@ describe.sequential("signRelayAgentActivityPublishProof", () => { · 343 unmodified lines
348348 });
349349
350350 it("signs the activity publish JWT and rejects tampering", async () => {
351− const keyPair = generateKeyPairSync("ed25519", {
351+ const keyPair = NodeCrypto.generateKeyPairSync("ed25519", {
352352 privateKeyEncoding: { format: "pem", type: "pkcs8" },
353353 publicKeyEncoding: { format: "pem", type: "spki" },
354354 });
apps/server/src/server.test.ts+22−22
@@ -1,7 +1,7 @@
11 import * as NodeHttpServer from "@effect/platform-node/NodeHttpServer";
22 import * as NodeSocket from "@effect/platform-node/NodeSocket";
33 import * as NodeServices from "@effect/platform-node/NodeServices";
4−import { generateKeyPairSync, type KeyObject, sign } from "node:crypto";
4+import * as NodeCrypto from "node:crypto";
55
66 import {
77 AuthAccessTokenType,
@@ -950,14 +950,14 @@ const makeDpopProof = (input: { · 942 unmodified lines
950950 readonly iat: number;
951951 readonly accessToken?: string;
952952 readonly jti?: string;
953− readonly privateKey?: KeyObject;
953+ readonly privateKey?: NodeCrypto.KeyObject;
954954 readonly publicJwk?: DpopPublicJwk;
955955 }) => {
956956 const keyPair =
957957 input.privateKey && input.publicJwk
958958 ? { privateKey: input.privateKey, publicJwk: input.publicJwk }
959959 : (() => {
960− const { privateKey, publicKey } = generateKeyPairSync("ec", {
960+ const { privateKey, publicKey } = NodeCrypto.generateKeyPairSync("ec", {
961961 namedCurve: "P-256",
962962 });
963963 return { privateKey, publicJwk: publicKey.export({ format: "jwk" }) as DpopPublicJwk };
@@ -978,7 +978,7 @@ const makeDpopProof = (input: { · 14 unmodified lines
978978 ...(input.accessToken ? { ath: computeDpopAccessTokenHash(input.accessToken) } : {}),
979979 }),
980980 ).toString("base64url");
981− const signature = sign("sha256", Buffer.from(`${header}.${payload}`), {
981+ const signature = NodeCrypto.sign("sha256", Buffer.from(`${header}.${payload}`), {
982982 key: keyPair.privateKey,
983983 dsaEncoding: "ieee-p1363",
984984 }).toString("base64url");
@@ -1024,7 +1024,7 @@ const makeCloudMintCredentialRequest = (input: { · 39 unmodified lines
10241024 const encodedPayload = Buffer.from(JSON.stringify(payload)).toString("base64url");
10251025 const signingInput = `${header}.${encodedPayload}`;
10261026 return {
1027− proof: `${signingInput}.${sign(null, Buffer.from(signingInput), input.privateKey).toString("base64url")}`,
1027+ proof: `${signingInput}.${NodeCrypto.sign(null, Buffer.from(signingInput), input.privateKey).toString("base64url")}`,
10281028 };
10291029 };
10301030
@@ -1057,7 +1057,7 @@ const makeCloudEnvironmentHealthRequest = (input: { · 26 unmodified lines
10571057 const encodedPayload = Buffer.from(JSON.stringify(payload)).toString("base64url");
10581058 const signingInput = `${header}.${encodedPayload}`;
10591059 return {
1060− proof: `${signingInput}.${sign(null, Buffer.from(signingInput), input.privateKey).toString("base64url")}`,
1060+ proof: `${signingInput}.${NodeCrypto.sign(null, Buffer.from(signingInput), input.privateKey).toString("base64url")}`,
10611061 };
10621062 };
10631063
@@ -2054,7 +2054,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 990 unmodified lines
20542054 Effect.gen(function* () {
20552055 yield* buildAppUnderTest();
20562056
2057− const cloudKeyPair = generateKeyPairSync("ed25519", {
2057+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
20582058 privateKeyEncoding: { format: "pem", type: "pkcs8" },
20592059 publicKeyEncoding: { format: "pem", type: "spki" },
20602060 });
@@ -2131,7 +2131,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 70 unmodified lines
21312131 Effect.gen(function* () {
21322132 yield* buildAppUnderTest();
21332133
2134− const cloudKeyPair = generateKeyPairSync("ed25519", {
2134+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
21352135 privateKeyEncoding: { format: "pem", type: "pkcs8" },
21362136 publicKeyEncoding: { format: "pem", type: "spki" },
21372137 });
@@ -2174,7 +2174,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 36 unmodified lines
21742174 Effect.gen(function* () {
21752175 yield* buildAppUnderTest();
21762176
2177− const cloudKeyPair = generateKeyPairSync("ed25519", {
2177+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
21782178 privateKeyEncoding: { format: "pem", type: "pkcs8" },
21792179 publicKeyEncoding: { format: "pem", type: "spki" },
21802180 });
@@ -2268,7 +2268,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 87 unmodified lines
22682268 },
22692269 });
22702270
2271− const cloudKeyPair = generateKeyPairSync("ed25519", {
2271+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
22722272 privateKeyEncoding: { format: "pem", type: "pkcs8" },
22732273 publicKeyEncoding: { format: "pem", type: "spki" },
22742274 });
@@ -2345,7 +2345,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 70 unmodified lines
23452345 Effect.gen(function* () {
23462346 yield* buildAppUnderTest();
23472347
2348− const cloudKeyPair = generateKeyPairSync("ed25519", {
2348+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
23492349 privateKeyEncoding: { format: "pem", type: "pkcs8" },
23502350 publicKeyEncoding: { format: "pem", type: "spki" },
23512351 });
@@ -2404,7 +2404,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 52 unmodified lines
24042404 Effect.gen(function* () {
24052405 yield* buildAppUnderTest();
24062406
2407− const cloudKeyPair = generateKeyPairSync("ed25519", {
2407+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
24082408 privateKeyEncoding: { format: "pem", type: "pkcs8" },
24092409 publicKeyEncoding: { format: "pem", type: "spki" },
24102410 });
@@ -2463,7 +2463,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 52 unmodified lines
24632463 Effect.gen(function* () {
24642464 yield* buildAppUnderTest();
24652465
2466− const cloudKeyPair = generateKeyPairSync("ed25519", {
2466+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
24672467 privateKeyEncoding: { format: "pem", type: "pkcs8" },
24682468 publicKeyEncoding: { format: "pem", type: "spki" },
24692469 });
@@ -2523,7 +2523,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 53 unmodified lines
25232523 Effect.gen(function* () {
25242524 yield* buildAppUnderTest();
25252525
2526− const cloudKeyPair = generateKeyPairSync("ed25519", {
2526+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
25272527 privateKeyEncoding: { format: "pem", type: "pkcs8" },
25282528 publicKeyEncoding: { format: "pem", type: "spki" },
25292529 });
@@ -2584,7 +2584,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 54 unmodified lines
25842584 Effect.gen(function* () {
25852585 yield* buildAppUnderTest();
25862586
2587− const cloudKeyPair = generateKeyPairSync("ed25519", {
2587+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
25882588 privateKeyEncoding: { format: "pem", type: "pkcs8" },
25892589 publicKeyEncoding: { format: "pem", type: "spki" },
25902590 });
@@ -2664,7 +2664,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 73 unmodified lines
26642664 },
26652665 });
26662666
2667− const cloudKeyPair = generateKeyPairSync("ed25519", {
2667+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
26682668 privateKeyEncoding: { format: "pem", type: "pkcs8" },
26692669 publicKeyEncoding: { format: "pem", type: "spki" },
26702670 });
@@ -2733,7 +2733,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 62 unmodified lines
27332733 Effect.gen(function* () {
27342734 yield* buildAppUnderTest();
27352735
2736− const cloudKeyPair = generateKeyPairSync("ed25519", {
2736+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
27372737 privateKeyEncoding: { format: "pem", type: "pkcs8" },
27382738 publicKeyEncoding: { format: "pem", type: "spki" },
27392739 });
@@ -2800,7 +2800,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 60 unmodified lines
28002800 Effect.gen(function* () {
28012801 yield* buildAppUnderTest();
28022802
2803− const cloudKeyPair = generateKeyPairSync("ed25519", {
2803+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
28042804 privateKeyEncoding: { format: "pem", type: "pkcs8" },
28052805 publicKeyEncoding: { format: "pem", type: "spki" },
28062806 });
@@ -2851,7 +2851,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 44 unmodified lines
28512851 Effect.gen(function* () {
28522852 yield* buildAppUnderTest();
28532853
2854− const cloudKeyPair = generateKeyPairSync("ed25519", {
2854+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
28552855 privateKeyEncoding: { format: "pem", type: "pkcs8" },
28562856 publicKeyEncoding: { format: "pem", type: "spki" },
28572857 });
@@ -2902,7 +2902,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 44 unmodified lines
29022902 Effect.gen(function* () {
29032903 yield* buildAppUnderTest();
29042904
2905− const cloudKeyPair = generateKeyPairSync("ed25519", {
2905+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
29062906 privateKeyEncoding: { format: "pem", type: "pkcs8" },
29072907 publicKeyEncoding: { format: "pem", type: "spki" },
29082908 });
@@ -2967,7 +2967,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 58 unmodified lines
29672967 Effect.gen(function* () {
29682968 yield* buildAppUnderTest();
29692969
2970− const cloudKeyPair = generateKeyPairSync("ed25519", {
2970+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
29712971 privateKeyEncoding: { format: "pem", type: "pkcs8" },
29722972 publicKeyEncoding: { format: "pem", type: "spki" },
29732973 });
@@ -3017,7 +3017,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 43 unmodified lines
30173017 Effect.gen(function* () {
30183018 yield* buildAppUnderTest();
30193019
3020− const cloudKeyPair = generateKeyPairSync("ed25519", {
3020+ const cloudKeyPair = NodeCrypto.generateKeyPairSync("ed25519", {
30213021 privateKeyEncoding: { format: "pem", type: "pkcs8" },
30223022 publicKeyEncoding: { format: "pem", type: "spki" },
30233023 });
apps/server/src/terminal/NodePtyAdapter.ts+2−2
@@ -1,4 +1,4 @@
1−import { createRequire } from "node:module";
1+import * as NodeModule from "node:module";
22
33 import * as Effect from "effect/Effect";
44 import * as FileSystem from "effect/FileSystem";
@@ -11,7 +11,7 @@ import * as PtyAdapter from "./PtyAdapter.ts"; · 6 unmodified lines
1111 let didEnsureSpawnHelperExecutable = false;
1212
1313 const resolveNodePtySpawnHelperPath = Effect.gen(function* () {
14− const requireForNodePty = createRequire(import.meta.url);
14+ const requireForNodePty = NodeModule.createRequire(import.meta.url);
1515 const path = yield* Path.Path;
1616 const fs = yield* FileSystem.FileSystem;
1717 const platform = yield* HostProcessPlatform;
apps/server/src/textGeneration/CursorTextGeneration.test.ts+25−21
@@ -1,8 +1,8 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import * as path from "node:path";
3−import * as os from "node:os";
4−import { fileURLToPath } from "node:url";
5−import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2+import * as NodePath from "node:path";
3+import * as NodeOS from "node:os";
4+import * as NodeURL from "node:url";
5+import * as NodeFS from "node:fs";
66
77 import * as NodeServices from "@effect/platform-node/NodeServices";
88 import { it } from "@effect/vitest";
@@ -21,8 +21,8 @@ import * as TextGeneration from "./TextGeneration.ts"; · 12 unmodified lines
2121 import { makeCursorTextGeneration } from "./CursorTextGeneration.ts";
2222 const decodeCursorSettings = Schema.decodeSync(CursorSettings);
2323
24−const __dirname = path.dirname(fileURLToPath(import.meta.url));
25−const mockAgentPath = path.join(__dirname, "../../scripts/acp-mock-agent.ts");
24+const __dirname = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
25+const mockAgentPath = NodePath.join(__dirname, "../../scripts/acp-mock-agent.ts");
2626
2727 function shellSingleQuote(value: string): string {
2828 return `'${value.replaceAll("'", `'"'"'`)}'`;
@@ -33,10 +33,10 @@ const CursorTextGenerationTestLayer = ServerConfig.ServerConfig.layerTest(proces · 4 unmodified lines
3333 }).pipe(Layer.provideMerge(NodeServices.layer));
3434
3535 function makeAcpAgentWrapper(dir: string, env: Record<string, string>): string {
36− const binDir = path.join(dir, "bin");
37− const agentPath = path.join(binDir, "agent");
38− mkdirSync(binDir, { recursive: true });
39− writeFileSync(
36+ const binDir = NodePath.join(dir, "bin");
37+ const agentPath = NodePath.join(binDir, "agent");
38+ NodeFS.mkdirSync(binDir, { recursive: true });
39+ NodeFS.writeFileSync(
4040 agentPath,
4141 [
4242 "#!/bin/sh",
@@ -50,7 +50,7 @@ function makeAcpAgentWrapper(dir: string, env: Record<string, string>): string { · 7 unmodified lines
5050 ].join("\n"),
5151 "utf8",
5252 );
53− chmodSync(agentPath, 0o755);
53+ NodeFS.chmodSync(agentPath, 0o755);
5454 return agentPath;
5555 }
5656
@@ -59,10 +59,10 @@ function withFakeAcpAgent<A, E, R>( · 2 unmodified lines
5959 effectFn: (textGeneration: TextGeneration.TextGeneration["Service"]) => Effect.Effect<A, E, R>,
6060 ) {
6161 return Effect.gen(function* () {
62− const tempDir = mkdtempSync(path.join(os.tmpdir(), "t3code-cursor-text-acp-"));
62+ const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3code-cursor-text-acp-"));
6363 yield* Effect.addFinalizer(() =>
6464 Effect.sync(() => {
65− rmSync(tempDir, { recursive: true, force: true });
65+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
6666 }),
6767 );
6868 const agentPath = makeAcpAgentWrapper(tempDir, env);
@@ -76,7 +76,7 @@ function waitForFileContent(path: string): Effect.Effect<string> { · 7 unmodified lines
7676 return Effect.gen(function* () {
7777 const deadline = (yield* Clock.currentTimeMillis) + 5_000;
7878 for (;;) {
79− const result = yield* Effect.exit(Effect.sync(() => readFileSync(path, "utf8")));
79+ const result = yield* Effect.exit(Effect.sync(() => NodeFS.readFileSync(path, "utf8")));
8080 if (Exit.isSuccess(result)) {
8181 return result.value;
8282 }
@@ -92,8 +92,10 @@ function waitForFileContent(path: string): Effect.Effect<string> { · 9 unmodified lines
9292
9393 it.layer(CursorTextGenerationTestLayer)("CursorTextGeneration", (it) => {
9494 it.effect("uses ACP model config options instead of raw CLI model ids", () => {
95− const requestLogDir = mkdtempSync(path.join(os.tmpdir(), "t3code-cursor-text-log-"));
96− const requestLogPath = path.join(requestLogDir, "requests.ndjson");
95+ const requestLogDir = NodeFS.mkdtempSync(
96+ NodePath.join(NodeOS.tmpdir(), "t3code-cursor-text-log-"),
97+ );
98+ const requestLogPath = NodePath.join(requestLogDir, "requests.ndjson");
9799
98100 return withFakeAcpAgent(
99101 {
@@ -123,7 +125,7 @@ it.layer(CursorTextGenerationTestLayer)("CursorTextGeneration", (it) => { · 23 unmodified lines
123125 expect(generated.subject).toBe("Add generated commit message");
124126 expect(generated.body).toBe("- verify cursor acp model config path");
125127
126− const requests = readFileSync(requestLogPath, "utf8")
128+ const requests = NodeFS.readFileSync(requestLogPath, "utf8")
127129 .trim()
128130 .split("\n")
129131 .filter((line) => line.length > 0)
@@ -181,7 +183,7 @@ it.layer(CursorTextGenerationTestLayer)("CursorTextGeneration", (it) => { · 51 unmodified lines
181183 ]),
182184 );
183185
184− rmSync(requestLogDir, { recursive: true, force: true });
186+ NodeFS.rmSync(requestLogDir, { recursive: true, force: true });
185187 }),
186188 );
187189 });
@@ -235,8 +237,10 @@ it.layer(CursorTextGenerationTestLayer)("CursorTextGeneration", (it) => { · 47 unmodified lines
235237 );
236238
237239 it.effect("closes the ACP child process after text generation completes", () => {
238− const exitLogDir = mkdtempSync(path.join(os.tmpdir(), "t3code-cursor-text-exit-log-"));
239− const exitLogPath = path.join(exitLogDir, "exit.log");
240+ const exitLogDir = NodeFS.mkdtempSync(
241+ NodePath.join(NodeOS.tmpdir(), "t3code-cursor-text-exit-log-"),
242+ );
243+ const exitLogPath = NodePath.join(exitLogDir, "exit.log");
240244
241245 return withFakeAcpAgent(
242246 {
@@ -265,7 +269,7 @@ it.layer(CursorTextGenerationTestLayer)("CursorTextGeneration", (it) => { · 22 unmodified lines
265269 const exitLog = yield* waitForFileContent(exitLogPath);
266270 expect(exitLog).toContain("exit:0");
267271
268− rmSync(exitLogDir, { recursive: true, force: true });
272+ NodeFS.rmSync(exitLogDir, { recursive: true, force: true });
269273 }),
270274 );
271275 });
apps/server/src/textGeneration/GrokTextGeneration.test.ts+18−16
@@ -1,8 +1,8 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import * as path from "node:path";
3−import * as os from "node:os";
4−import { fileURLToPath } from "node:url";
5−import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2+import * as NodePath from "node:path";
3+import * as NodeOS from "node:os";
4+import * as NodeURL from "node:url";
5+import * as NodeFS from "node:fs";
66
77 import * as NodeServices from "@effect/platform-node/NodeServices";
88 import { it } from "@effect/vitest";
@@ -18,8 +18,8 @@ import * as TextGeneration from "./TextGeneration.ts"; · 9 unmodified lines
1818 import { makeGrokTextGeneration } from "./GrokTextGeneration.ts";
1919 const decodeGrokSettings = Schema.decodeSync(GrokSettings);
2020
21−const __dirname = path.dirname(fileURLToPath(import.meta.url));
22−const mockAgentPath = path.join(__dirname, "../../scripts/acp-mock-agent.ts");
21+const __dirname = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
22+const mockAgentPath = NodePath.join(__dirname, "../../scripts/acp-mock-agent.ts");
2323
2424 function shellSingleQuote(value: string): string {
2525 return `'${value.replaceAll("'", `'"'"'`)}'`;
@@ -30,10 +30,10 @@ const GrokTextGenerationTestLayer = ServerConfig.ServerConfig.layerTest(process. · 4 unmodified lines
3030 }).pipe(Layer.provideMerge(NodeServices.layer));
3131
3232 function makeAcpGrokWrapper(dir: string, env: Record<string, string>): string {
33− const binDir = path.join(dir, "bin");
34− const grokPath = path.join(binDir, "grok");
35− mkdirSync(binDir, { recursive: true });
36− writeFileSync(
33+ const binDir = NodePath.join(dir, "bin");
34+ const grokPath = NodePath.join(binDir, "grok");
35+ NodeFS.mkdirSync(binDir, { recursive: true });
36+ NodeFS.writeFileSync(
3737 grokPath,
3838 [
3939 "#!/bin/sh",
@@ -47,7 +47,7 @@ function makeAcpGrokWrapper(dir: string, env: Record<string, string>): string { · 7 unmodified lines
4747 ].join("\n"),
4848 "utf8",
4949 );
50− chmodSync(grokPath, 0o755);
50+ NodeFS.chmodSync(grokPath, 0o755);
5151 return grokPath;
5252 }
5353
@@ -56,10 +56,10 @@ function withFakeAcpGrok<A, E, R>( · 2 unmodified lines
5656 effectFn: (textGeneration: TextGeneration.TextGeneration["Service"]) => Effect.Effect<A, E, R>,
5757 ) {
5858 return Effect.gen(function* () {
59− const tempDir = mkdtempSync(path.join(os.tmpdir(), "t3code-grok-text-acp-"));
59+ const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3code-grok-text-acp-"));
6060 yield* Effect.addFinalizer(() =>
6161 Effect.sync(() => {
62− rmSync(tempDir, { recursive: true, force: true });
62+ NodeFS.rmSync(tempDir, { recursive: true, force: true });
6363 }),
6464 );
6565 const binaryPath = makeAcpGrokWrapper(tempDir, env);
@@ -72,7 +72,7 @@ function withFakeAcpGrok<A, E, R>( · 6 unmodified lines
7272 function readJsonRpcRequests(
7373 filePath: string,
7474 ): ReadonlyArray<{ readonly method?: string; readonly params?: Record<string, unknown> }> {
75− return readFileSync(filePath, "utf8")
75+ return NodeFS.readFileSync(filePath, "utf8")
7676 .trim()
7777 .split("\n")
7878 .filter((line) => line.length > 0)
@@ -81,8 +81,10 @@ function readJsonRpcRequests( · 2 unmodified lines
8181
8282 it.layer(GrokTextGenerationTestLayer)("GrokTextGeneration", (it) => {
8383 it.effect("uses ACP with disabled tool capabilities and forwards the requested model id", () => {
84− const requestLogDir = mkdtempSync(path.join(os.tmpdir(), "t3code-grok-text-log-"));
85− const requestLogPath = path.join(requestLogDir, "requests.ndjson");
84+ const requestLogDir = NodeFS.mkdtempSync(
85+ NodePath.join(NodeOS.tmpdir(), "t3code-grok-text-log-"),
86+ );
87+ const requestLogPath = NodePath.join(requestLogDir, "requests.ndjson");
8688
8789 return withFakeAcpGrok(
8890 {
apps/server/src/vcs/GitVcsDriver.ts+5−2
@@ -1,4 +1,4 @@
1−import { randomUUID } from "node:crypto";
1+import * as NodeCrypto from "node:crypto";
22
33 import * as Context from "effect/Context";
44 import * as DateTime from "effect/DateTime";
@@ -651,7 +651,10 @@ export const makeVcsDriverShape = Effect.fn("makeGitVcsDriverShape")(function* ( · 646 unmodified lines
651651 captureCheckpoint: Effect.fn("GitVcsDriver.checkpoints.captureCheckpoint")(function* (input) {
652652 const operation = "GitVcsDriver.checkpoints.captureCheckpoint";
653653 const gitCommonDir = yield* resolveGitCommonDir(input.cwd);
654− const tempIndexPath = path.join(gitCommonDir, `t3-checkpoint-index-${randomUUID()}`);
654+ const tempIndexPath = path.join(
655+ gitCommonDir,
656+ `t3-checkpoint-index-${NodeCrypto.randomUUID()}`,
657+ );
655658 const commitEnv: NodeJS.ProcessEnv = {
656659 ...process.env,
657660 GIT_INDEX_FILE: tempIndexPath,
apps/server/src/workspace/WorkspaceEntries.test.ts+9−3
@@ -1,13 +1,14 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import fsPromises from "node:fs/promises";
2+import * as NodeFSP from "node:fs/promises";
33 import * as NodeServices from "@effect/platform-node/NodeServices";
44 import { FileFinder } from "@ff-labs/fff-node";
5−import { it, afterEach, describe, expect, vi } from "@effect/vitest";
5+import { it, afterEach, describe, expect } from "@effect/vitest";
66 import * as Effect from "effect/Effect";
77 import * as FileSystem from "effect/FileSystem";
88 import * as Layer from "effect/Layer";
99 import * as Path from "effect/Path";
1010 import * as PlatformError from "effect/PlatformError";
11+import { vi } from "vite-plus/test";
1112
1213 import * as ServerConfig from "../config.ts";
1314 import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
@@ -15,6 +16,11 @@ import * as VcsProcess from "../vcs/VcsProcess.ts"; · 1 unmodified line
1516 import * as WorkspaceEntries from "./WorkspaceEntries.ts";
1617 import * as WorkspacePaths from "./WorkspacePaths.ts";
1718
19+vi.mock("node:fs/promises", async (importOriginal) => {
20+ const actual = await importOriginal<typeof import("node:fs/promises")>();
21+ return { ...actual, readdir: vi.fn(actual.readdir) };
22+});
23+
1824 const TestLayer = Layer.empty.pipe(
1925 Layer.provideMerge(WorkspaceEntries.layer.pipe(Layer.provide(WorkspacePaths.layer))),
2026 Layer.provideMerge(WorkspacePaths.layer),
@@ -376,7 +382,7 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceEntries", (it) => { · 355 unmodified lines
376382 const cwd = yield* makeTempDir({ prefix: "t3code-workspace-browse-eacces-" });
377383
378384 const denied = Object.assign(new Error("EACCES: permission denied"), { code: "EACCES" });
379− vi.spyOn(fsPromises, "readdir").mockRejectedValueOnce(denied);
385+ vi.mocked(NodeFSP.readdir).mockRejectedValueOnce(denied);
380386
381387 const result = yield* workspaceEntries.browse({
382388 partialPath: yield* appendSeparator(cwd),
apps/server/src/workspace/WorkspaceEntries.ts+5−5
@@ -1,6 +1,6 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import { readdir } from "node:fs/promises";
3−import { homedir } from "node:os";
2+import * as NodeFSP from "node:fs/promises";
3+import * as NodeOS from "node:os";
44
55 import * as Context from "effect/Context";
66 import * as Effect from "effect/Effect";
@@ -98,10 +98,10 @@ export class WorkspaceEntries extends Context.Service< · 91 unmodified lines
9898
9999 function expandHomePath(input: string, path: Path.Path): string {
100100 if (input === "~") {
101− return homedir();
101+ return NodeOS.homedir();
102102 }
103103 if (input.startsWith("~/") || input.startsWith("~\\")) {
104− return path.join(homedir(), input.slice(2));
104+ return path.join(NodeOS.homedir(), input.slice(2));
105105 }
106106 return input;
107107 }
@@ -176,7 +176,7 @@ export const make = Effect.gen(function* () { · 68 unmodified lines
176176 const prefix = endsWithSeparator ? "" : path.basename(resolvedInputPath);
177177
178178 const dirents = yield* Effect.tryPromise({
179− try: () => readdir(parentPath, { withFileTypes: true }),
179+ try: () => NodeFSP.readdir(parentPath, { withFileTypes: true }),
180180 catch: (cause) =>
181181 new WorkspaceEntriesReadDirectoryError({
182182 cwd: input.cwd,
apps/server/src/workspace/WorkspaceFileSystem.ts+4−4
@@ -7,7 +7,7 @@ · 6 unmodified lines
77 *
88 * @module WorkspaceFileSystem
99 */
10−import { open, realpath } from "node:fs/promises";
10+import * as NodeFSP from "node:fs/promises";
1111
1212 import type {
1313 ProjectReadFileInput,
@@ -89,8 +89,8 @@ export const make = Effect.gen(function* () { · 75 unmodified lines
8989 return yield* Effect.tryPromise({
9090 try: async () => {
9191 const [realWorkspaceRoot, realTargetPath] = await Promise.all([
92− realpath(input.cwd),
93− realpath(target.absolutePath),
92+ NodeFSP.realpath(input.cwd),
93+ NodeFSP.realpath(target.absolutePath),
9494 ]);
9595 const relativeRealPath = path.relative(realWorkspaceRoot, realTargetPath);
9696 if (
@@ -101,7 +101,7 @@ export const make = Effect.gen(function* () { · 4 unmodified lines
101101 throw new Error("Workspace file path resolves outside the project root.");
102102 }
103103
104− const handle = await open(realTargetPath, "r");
104+ const handle = await NodeFSP.open(realTargetPath, "r");
105105 try {
106106 const stat = await handle.stat();
107107 if (!stat.isFile()) {
apps/server/src/workspace/WorkspacePaths.ts+3−3
@@ -6,7 +6,7 @@ · 5 unmodified lines
66 *
77 * @module WorkspacePaths
88 */
9−import { homedir } from "node:os";
9+import * as NodeOS from "node:os";
1010
1111 import * as Context from "effect/Context";
1212 import * as Effect from "effect/Effect";
@@ -105,10 +105,10 @@ function toPosixRelativePath(input: string): string { · 92 unmodified lines
105105
106106 function expandHomePath(input: string, path: Path.Path): string {
107107 if (input === "~") {
108− return homedir();
108+ return NodeOS.homedir();
109109 }
110110 if (input.startsWith("~/") || input.startsWith("~\\")) {
111− return path.join(homedir(), input.slice(2));
111+ return path.join(NodeOS.homedir(), input.slice(2));
112112 }
113113 return input;
114114 }
oxlint-plugin-t3code/index.ts+2−0
@@ -1,5 +1,6 @@
11 import { definePlugin } from "@oxlint/plugins";
22
3+import namespaceNodeImports from "./rules/namespace-node-imports.ts";
34 import noGlobalProcessRuntime from "./rules/no-global-process-runtime.ts";
45 import noInlineSchemaCompile from "./rules/no-inline-schema-compile.ts";
56 import noManualEffectRuntimeInTests from "./rules/no-manual-effect-runtime-in-tests.ts";
@@ -9,6 +10,7 @@ export default definePlugin({ · 3 unmodified lines
910 name: "t3code",
1011 },
1112 rules: {
13+ "namespace-node-imports": namespaceNodeImports,
1214 "no-global-process-runtime": noGlobalProcessRuntime,
1315 "no-inline-schema-compile": noInlineSchemaCompile,
1416 "no-manual-effect-runtime-in-tests": noManualEffectRuntimeInTests,
oxlint-plugin-t3code/rules/namespace-node-imports.test.ts+63−0
@@ -0,0 +1,63 @@
1+import { assert, describe } from "@effect/vitest";
2+
3+import { createOxlintRuleHarness } from "../test/utils.ts";
4+
5+const rule = createOxlintRuleHarness("t3code/namespace-node-imports");
6+
7+describe("t3code/namespace-node-imports", () => {
8+ rule.valid(
9+ "allows canonical Node namespaces",
10+ `
11+ import * as NodeFS from "node:fs";
12+ import * as NodeFSP from "node:fs/promises";
13+ import * as NodeAssert from "node:assert/strict";
14+ import * as NodeChildProcess from "node:child_process";
15+ import * as NodeTimersPromises from "node:timers/promises";
16+ import type * as NodeStream from "node:stream";
17+
18+ NodeAssert.ok(NodeChildProcess.spawn && NodeTimersPromises.setTimeout);
19+ export const read = NodeFS.readFileSync;
20+ export const readAsync = NodeFSP.readFile;
21+ export type Input = NodeStream.Readable;
22+ `,
23+ );
24+
25+ rule.valid(
26+ "does not apply to non-Node packages",
27+ `
28+ import { BrowserWindow } from "electron";
29+ `,
30+ );
31+
32+ rule.invalid(
33+ "reports named imports",
34+ `
35+ import { readFile } from "node:fs/promises";
36+ `,
37+ (output) => {
38+ assert.match(output, /namespace named NodeFSP/);
39+ },
40+ );
41+
42+ rule.invalid(
43+ "reports default imports",
44+ `
45+ import path from "node:path";
46+ `,
47+ (output) => {
48+ assert.match(output, /namespace named NodePath/);
49+ },
50+ );
51+
52+ rule.invalid(
53+ "reports non-canonical namespace aliases",
54+ `
55+ import * as Crypto from "node:crypto";
56+ import * as NodeOs from "node:os";
57+ `,
58+ (output) => {
59+ assert.match(output, /namespace named NodeCrypto/);
60+ assert.match(output, /namespace named NodeOS/);
61+ },
62+ );
63+});
oxlint-plugin-t3code/rules/namespace-node-imports.ts+76−0
@@ -0,0 +1,76 @@
1+import { defineRule } from "@oxlint/plugins";
2+
3+const NODE_MODULE_ALIASES = new Map([
4+ ["assert/strict", "Assert"],
5+ ["fs/promises", "FSP"],
6+]);
7+
8+const NODE_SEGMENT_ALIASES = new Map([
9+ ["fs", "FS"],
10+ ["os", "OS"],
11+ ["url", "URL"],
12+ ["vm", "VM"],
13+]);
14+
15+const toPascalCase = (value: string) =>
16+ value
17+ .split(/[_-]/u)
18+ .filter((segment) => segment.length > 0)
19+ .map((segment) => segment[0]?.toUpperCase() + segment.slice(1))
20+ .join("");
21+
22+const expectedNamespaceAlias = (source: string) => {
23+ const moduleName = source.slice("node:".length);
24+ const knownAlias = NODE_MODULE_ALIASES.get(moduleName);
25+ if (knownAlias !== undefined) return `Node${knownAlias}`;
26+
27+ return `Node${moduleName
28+ .split("/")
29+ .map((segment) => NODE_SEGMENT_ALIASES.get(segment) ?? toPascalCase(segment))
30+ .join("")}`;
31+};
32+
33+const literalStringValue = (node: unknown): string | undefined => {
34+ if (typeof node !== "object" || node === null) return undefined;
35+ if (!("type" in node) || node.type !== "Literal") return undefined;
36+ if (!("value" in node) || typeof node.value !== "string") return undefined;
37+ return node.value;
38+};
39+
40+const identifierName = (node: unknown): string | undefined => {
41+ if (typeof node !== "object" || node === null) return undefined;
42+ if (!("type" in node) || node.type !== "Identifier") return undefined;
43+ if (!("name" in node) || typeof node.name !== "string") return undefined;
44+ return node.name;
45+};
46+
47+export default defineRule({
48+ meta: {
49+ type: "problem",
50+ docs: {
51+ description: "Require canonical namespace imports for Node.js built-in modules.",
52+ },
53+ },
54+ create(context) {
55+ return {
56+ ImportDeclaration(node) {
57+ const source = literalStringValue(node.source);
58+ if (source === undefined || !source.startsWith("node:")) return;
59+
60+ const expectedAlias = expectedNamespaceAlias(source);
61+ const namespaceImport =
62+ node.specifiers.length === 1 && node.specifiers[0]?.type === "ImportNamespaceSpecifier"
63+ ? node.specifiers[0]
64+ : undefined;
65+ const actualAlias = identifierName(namespaceImport?.local);
66+
67+ if (actualAlias === expectedAlias) return;
68+
69+ context.report({
70+ node,
71+ message: `Import ${source} as a namespace named ${expectedAlias}.`,
72+ });
73+ },
74+ };
75+ },
76+});
packages/shared/src/logging.ts+15−15
@@ -1,6 +1,6 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import fs from "node:fs";
3−import path from "node:path";
2+import * as NodeFS from "node:fs";
3+import * as NodePath from "node:path";
44
55 export interface RotatingFileSinkOptions {
66 readonly filePath: string;
@@ -29,7 +29,7 @@ export class RotatingFileSink { · 22 unmodified lines
2929 this.maxFiles = options.maxFiles;
3030 this.throwOnError = options.throwOnError ?? false;
3131
32− fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
32+ NodeFS.mkdirSync(NodePath.dirname(this.filePath), { recursive: true });
3333 this.pruneOverflowBackups();
3434 this.currentSize = this.readCurrentSize();
3535 }
@@ -43,7 +43,7 @@ export class RotatingFileSink { · 7 unmodified lines
4343 this.rotate();
4444 }
4545
46− fs.appendFileSync(this.filePath, buffer);
46+ NodeFS.appendFileSync(this.filePath, buffer);
4747 this.currentSize += buffer.length;
4848
4949 if (this.currentSize > this.maxBytes) {
@@ -60,20 +60,20 @@ export class RotatingFileSink { · 10 unmodified lines
6060 private rotate(): void {
6161 try {
6262 const oldest = this.withSuffix(this.maxFiles);
63− if (fs.existsSync(oldest)) {
64− fs.rmSync(oldest, { force: true });
63+ if (NodeFS.existsSync(oldest)) {
64+ NodeFS.rmSync(oldest, { force: true });
6565 }
6666
6767 for (let index = this.maxFiles - 1; index >= 1; index -= 1) {
6868 const source = this.withSuffix(index);
6969 const target = this.withSuffix(index + 1);
70− if (fs.existsSync(source)) {
71− fs.renameSync(source, target);
70+ if (NodeFS.existsSync(source)) {
71+ NodeFS.renameSync(source, target);
7272 }
7373 }
7474
75− if (fs.existsSync(this.filePath)) {
76− fs.renameSync(this.filePath, this.withSuffix(1));
75+ if (NodeFS.existsSync(this.filePath)) {
76+ NodeFS.renameSync(this.filePath, this.withSuffix(1));
7777 }
7878
7979 this.currentSize = 0;
@@ -87,13 +87,13 @@ export class RotatingFileSink { · 7 unmodified lines
8787
8888 private pruneOverflowBackups(): void {
8989 try {
90− const dir = path.dirname(this.filePath);
91− const baseName = path.basename(this.filePath);
92− for (const entry of fs.readdirSync(dir)) {
90+ const dir = NodePath.dirname(this.filePath);
91+ const baseName = NodePath.basename(this.filePath);
92+ for (const entry of NodeFS.readdirSync(dir)) {
9393 if (!entry.startsWith(`${baseName}.`)) continue;
9494 const suffix = Number(entry.slice(baseName.length + 1));
9595 if (!Number.isInteger(suffix) || suffix <= this.maxFiles) continue;
96− fs.rmSync(path.join(dir, entry), { force: true });
96+ NodeFS.rmSync(NodePath.join(dir, entry), { force: true });
9797 }
9898 } catch {
9999 if (this.throwOnError) {
@@ -104,7 +104,7 @@ export class RotatingFileSink { · 4 unmodified lines
104104
105105 private readCurrentSize(): number {
106106 try {
107− return fs.statSync(this.filePath).size;
107+ return NodeFS.statSync(this.filePath).size;
108108 } catch {
109109 return 0;
110110 }
packages/shared/src/shell.ts+8−8
@@ -1,8 +1,8 @@
11 // @effect-diagnostics nodeBuiltinImport:off
22 import * as NodeOS from "node:os";
33 import * as NodePath from "node:path";
4−import { execFileSync } from "node:child_process";
5−import { accessSync, constants as fileSystemConstants, statSync } from "node:fs";
4+import * as NodeChildProcess from "node:child_process";
5+import * as NodeFS from "node:fs";
66 import * as Data from "effect/Data";
77 import * as Effect from "effect/Effect";
88 import * as FileSystem from "effect/FileSystem";
@@ -26,7 +26,7 @@ type ExecFileSyncLike = ( · 17 unmodified lines
2626
2727 function canExecuteFile(filePath: string): boolean {
2828 try {
29− accessSync(filePath, fileSystemConstants.X_OK);
29+ NodeFS.accessSync(filePath, NodeFS.constants.X_OK);
3030 return true;
3131 } catch {
3232 return false;
@@ -108,7 +108,7 @@ function resolveSpawnExecutableWithNode( · 75 unmodified lines
108108 );
109109 const isExecutable = (candidate: string) => {
110110 try {
111− if (!statSync(candidate).isFile()) return false;
111+ if (!NodeFS.statSync(candidate).isFile()) return false;
112112 if (platform === "win32") {
113113 return windowsPathExtensions.includes(path.extname(candidate).toUpperCase());
114114 }
@@ -192,13 +192,13 @@ export function extractPathFromShellOutput(output: string): string | null { · 77 unmodified lines
192192
193193 export function readPathFromLoginShell(
194194 shell: string,
195− execFile: ExecFileSyncLike = execFileSync,
195+ execFile: ExecFileSyncLike = NodeChildProcess.execFileSync,
196196 ): string | undefined {
197197 return readEnvironmentFromLoginShell(shell, ["PATH"], execFile).PATH;
198198 }
199199
200200 export function readPathFromLaunchctl(
201− execFile: ExecFileSyncLike = execFileSync,
201+ execFile: ExecFileSyncLike = NodeChildProcess.execFileSync,
202202 ): string | undefined {
203203 try {
204204 return trimNonEmpty(
@@ -305,7 +305,7 @@ export type ShellEnvironmentReader = ( · 100 unmodified lines
305305 export const readEnvironmentFromLoginShell: ShellEnvironmentReader = (
306306 shell,
307307 names,
308− execFile = execFileSync,
308+ execFile = NodeChildProcess.execFileSync,
309309 ) => {
310310 if (names.length === 0) {
311311 return {};
@@ -371,7 +371,7 @@ export function readEnvironmentFromWindowsShell( · 59 unmodified lines
371371 const execFile: ExecFileSyncLike =
372372 typeof optionsOrExecFile === "function"
373373 ? optionsOrExecFile
374− : (maybeExecFile ?? (execFileSync as ExecFileSyncLike));
374+ : (maybeExecFile ?? (NodeChildProcess.execFileSync as ExecFileSyncLike));
375375 const command = buildWindowsEnvironmentCaptureCommand(names);
376376 const args = [
377377 "-NoLogo",
packages/ssh/src/command.ts+5−2
@@ -1,4 +1,4 @@
1−import * as Crypto from "node:crypto";
1+import * as NodeCrypto from "node:crypto";
22
33 import type { DesktopSshEnvironmentTarget, DesktopUpdateChannel } from "@t3tools/contracts";
44 import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
@@ -74,7 +74,10 @@ export function targetConnectionKey(target: DesktopSshEnvironmentTarget): string · 69 unmodified lines
7474 }
7575
7676 export function remoteStateKey(target: DesktopSshEnvironmentTarget): string {
77− return Crypto.createHash("sha256").update(targetConnectionKey(target)).digest("hex").slice(0, 16);
77+ return NodeCrypto.createHash("sha256")
78+ .update(targetConnectionKey(target))
79+ .digest("hex")
80+ .slice(0, 16);
7881 }
7982
8083 export function buildSshHostSpec(target: DesktopSshEnvironmentTarget): string {
scripts/build-desktop-artifact.ts+2−2
@@ -1,6 +1,6 @@
11 #!/usr/bin/env node
22
3−import { createRequire } from "node:module";
3+import * as NodeModule from "node:module";
44
55 import { fromYaml } from "@t3tools/shared/schemaYaml";
66 import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
@@ -482,7 +482,7 @@ const stageClerkPasskeyNativeBinaries = Effect.fn("stageClerkPasskeyNativeBinari · 475 unmodified lines
482482 path.join(stageAppDir, "node_modules", "@clerk", "electron-passkeys", "index.js"),
483483 );
484484 const packageDir = path.dirname(packageEntryPath);
485− const packageRequire = createRequire(packageEntryPath);
485+ const packageRequire = NodeModule.createRequire(packageEntryPath);
486486
487487 for (const artifact of resolveClerkPasskeyNativeArtifacts(platform, arch)) {
488488 const sourcePath = yield* Effect.try({
scripts/lib/public-config.test.ts+9−9
@@ -1,7 +1,7 @@
11 // @effect-diagnostics nodeBuiltinImport:off - Tests exercise root env file precedence directly.
2−import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3−import { tmpdir } from "node:os";
4−import { join } from "node:path";
2+import * as NodeFS from "node:fs";
3+import * as NodeOS from "node:os";
4+import * as NodePath from "node:path";
55 import { afterEach, describe, expect, it } from "vite-plus/test";
66
77 import { loadRepoEnv, resolvePublicConfig } from "./public-config.ts";
@@ -10,7 +10,7 @@ const temporaryDirectories: string[] = []; · 2 unmodified lines
1010
1111 afterEach(() => {
1212 for (const directory of temporaryDirectories.splice(0)) {
13− rmSync(directory, { recursive: true, force: true });
13+ NodeFS.rmSync(directory, { recursive: true, force: true });
1414 }
1515 });
1616
@@ -43,12 +43,12 @@ describe("loadRepoEnv", () => { · 26 unmodified lines
4343
4444 it("applies process, root local, and root precedence in that order", () => {
4545 const repoRoot = makeTemporaryDirectory();
46− writeFileSync(
47− join(repoRoot, ".env"),
46+ NodeFS.writeFileSync(
47+ NodePath.join(repoRoot, ".env"),
4848 "T3CODE_CLERK_PUBLISHABLE_KEY=pk_root\nT3CODE_CLERK_JWT_TEMPLATE=template_root\nT3CODE_CLERK_CLI_OAUTH_CLIENT_ID=oauth_root\nT3CODE_RELAY_URL=https://root.example.test\n",
4949 );
50− writeFileSync(
51− join(repoRoot, ".env.local"),
50+ NodeFS.writeFileSync(
51+ NodePath.join(repoRoot, ".env.local"),
5252 "T3CODE_CLERK_PUBLISHABLE_KEY=pk_local\nT3CODE_CLERK_JWT_TEMPLATE=template_local\nT3CODE_CLERK_CLI_OAUTH_CLIENT_ID=oauth_local\nT3CODE_RELAY_URL=https://local.example.test\n",
5353 );
5454
@@ -148,7 +148,7 @@ describe("loadRepoEnv", () => { · 93 unmodified lines
148148 });
149149
150150 function makeTemporaryDirectory() {
151− const directory = mkdtempSync(join(tmpdir(), "t3code-public-config-"));
151+ const directory = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3code-public-config-"));
152152 temporaryDirectories.push(directory);
153153 return directory;
154154 }
scripts/release-smoke.ts+62−64
@@ -1,21 +1,13 @@
11 // @effect-diagnostics nodeBuiltinImport:off
2−import { execFileSync } from "node:child_process";
3−import {
4− cpSync,
5− existsSync,
6− mkdirSync,
7− mkdtempSync,
8− readFileSync,
9− rmSync,
10− writeFileSync,
11−} from "node:fs";
12−import { tmpdir } from "node:os";
13−import { dirname, join, resolve } from "node:path";
14−import { fileURLToPath } from "node:url";
2+import * as NodeChildProcess from "node:child_process";
3+import * as NodeFS from "node:fs";
4+import * as NodeOS from "node:os";
5+import * as NodePath from "node:path";
6+import * as NodeURL from "node:url";
157 import * as Console from "effect/Console";
168 import * as Effect from "effect/Effect";
179
18−const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
10+const repoRoot = NodePath.resolve(NodePath.dirname(NodeURL.fileURLToPath(import.meta.url)), "..");
1911
2012 const workspaceFiles = [
2113 "package.json",
@@ -44,26 +36,26 @@ const workspaceFiles = [ · 22 unmodified lines
4436
4537 function copyWorkspaceManifestFixture(targetRoot: string): void {
4638 for (const relativePath of workspaceFiles) {
47− const sourcePath = resolve(repoRoot, relativePath);
48− const destinationPath = resolve(targetRoot, relativePath);
49− mkdirSync(dirname(destinationPath), { recursive: true });
50− cpSync(sourcePath, destinationPath);
39+ const sourcePath = NodePath.resolve(repoRoot, relativePath);
40+ const destinationPath = NodePath.resolve(targetRoot, relativePath);
41+ NodeFS.mkdirSync(NodePath.dirname(destinationPath), { recursive: true });
42+ NodeFS.cpSync(sourcePath, destinationPath);
5143 }
5244
53− const patchesDirectory = resolve(repoRoot, "patches");
54− if (existsSync(patchesDirectory)) {
55− cpSync(patchesDirectory, resolve(targetRoot, "patches"), { recursive: true });
45+ const patchesDirectory = NodePath.resolve(repoRoot, "patches");
46+ if (NodeFS.existsSync(patchesDirectory)) {
47+ NodeFS.cpSync(patchesDirectory, NodePath.resolve(targetRoot, "patches"), { recursive: true });
5648 }
5749 }
5850
5951 function writeMacManifestFixtures(targetRoot: string): { arm64Path: string; x64Path: string } {
60− const assetDirectory = resolve(targetRoot, "release-assets");
61− mkdirSync(assetDirectory, { recursive: true });
52+ const assetDirectory = NodePath.resolve(targetRoot, "release-assets");
53+ NodeFS.mkdirSync(assetDirectory, { recursive: true });
6254
63− const arm64Path = resolve(assetDirectory, "latest-mac.yml");
64− const x64Path = resolve(assetDirectory, "latest-mac-x64.yml");
55+ const arm64Path = NodePath.resolve(assetDirectory, "latest-mac.yml");
56+ const x64Path = NodePath.resolve(assetDirectory, "latest-mac-x64.yml");
6557
66− writeFileSync(
58+ NodeFS.writeFileSync(
6759 arm64Path,
6860 `version: 9.9.9-smoke.0
6961 files:
@@ -79,7 +71,7 @@ releaseDate: '2026-03-08T10:32:14.587Z' · 9 unmodified lines
7971 `,
8072 );
8173
82− writeFileSync(
74+ NodeFS.writeFileSync(
8375 x64Path,
8476 `version: 9.9.9-smoke.0
8577 files:
@@ -102,13 +94,13 @@ function writeWindowsManifestFixtures( · 16 unmodified lines
10294 targetRoot: string,
10395 channel: string,
10496 ): { arm64Path: string; x64Path: string } {
105− const assetDirectory = resolve(targetRoot, "release-assets");
106− mkdirSync(assetDirectory, { recursive: true });
97+ const assetDirectory = NodePath.resolve(targetRoot, "release-assets");
98+ NodeFS.mkdirSync(assetDirectory, { recursive: true });
10799
108− const arm64Path = resolve(assetDirectory, `${channel}-win-arm64.yml`);
109− const x64Path = resolve(assetDirectory, `${channel}-win-x64.yml`);
100+ const arm64Path = NodePath.resolve(assetDirectory, `${channel}-win-arm64.yml`);
101+ const x64Path = NodePath.resolve(assetDirectory, `${channel}-win-x64.yml`);
110102
111− writeFileSync(
103+ NodeFS.writeFileSync(
112104 arm64Path,
113105 `version: 9.9.9-smoke.0
114106 files:
@@ -124,7 +116,7 @@ releaseDate: '2026-03-08T10:32:14.587Z' · 9 unmodified lines
124116 `,
125117 );
126118
127− writeFileSync(
119+ NodeFS.writeFileSync(
128120 x64Path,
129121 `version: 9.9.9-smoke.0
130122 files:
@@ -147,11 +139,11 @@ function writeWindowsBuilderDebugFixtures(targetRoot: string): { · 16 unmodified lines
147139 arm64Path: string;
148140 x64Path: string;
149141 } {
150− const assetDirectory = resolve(targetRoot, "release-assets");
151− mkdirSync(assetDirectory, { recursive: true });
142+ const assetDirectory = NodePath.resolve(targetRoot, "release-assets");
143+ NodeFS.mkdirSync(assetDirectory, { recursive: true });
152144
153− const arm64Path = resolve(assetDirectory, "builder-debug-win-arm64.yml");
154− const x64Path = resolve(assetDirectory, "builder-debug-win-x64.yml");
145+ const arm64Path = NodePath.resolve(assetDirectory, "builder-debug-win-arm64.yml");
146+ const x64Path = NodePath.resolve(assetDirectory, "builder-debug-win-x64.yml");
155147 const debugFixture = `arm64:
156148 firstOrDefaultFilePatterns:
157149 - '**/*'
@@ -160,8 +152,8 @@ nsis: · 2 unmodified lines
160152 !include "example.nsh"
161153 `;
162154
163− writeFileSync(arm64Path, debugFixture);
164− writeFileSync(x64Path, debugFixture);
155+ NodeFS.writeFileSync(arm64Path, debugFixture);
156+ NodeFS.writeFileSync(x64Path, debugFixture);
165157
166158 return { arm64Path, x64Path };
167159 }
@@ -172,13 +164,13 @@ function assertContains(haystack: string, needle: string, message: string): void · 4 unmodified lines
172164 }
173165
174166 function assertExists(path: string, message: string): void {
175− if (!existsSync(path)) {
167+ if (!NodeFS.existsSync(path)) {
176168 throw new Error(message);
177169 }
178170 }
179171
180172 function assertPackageVersion(path: string, version: string): void {
181− const packageJson = JSON.parse(readFileSync(path, "utf8")) as {
173+ const packageJson = JSON.parse(NodeFS.readFileSync(path, "utf8")) as {
182174 readonly version?: unknown;
183175 };
184176
@@ -188,20 +180,20 @@ function assertPackageVersion(path: string, version: string): void { · 3 unmodified lines
188180 }
189181
190182 function assertMissing(path: string, message: string): void {
191− if (existsSync(path)) {
183+ if (NodeFS.existsSync(path)) {
192184 throw new Error(message);
193185 }
194186 }
195187
196−const tempRoot = mkdtempSync(join(tmpdir(), "t3-release-smoke-"));
188+const tempRoot = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-release-smoke-"));
197189
198190 try {
199191 copyWorkspaceManifestFixture(tempRoot);
200192
201− execFileSync(
193+ NodeChildProcess.execFileSync(
202194 process.execPath,
203195 [
204− resolve(repoRoot, "scripts/update-release-package-versions.ts"),
196+ NodePath.resolve(repoRoot, "scripts/update-release-package-versions.ts"),
205197 "9.9.9-smoke.0",
206198 "--root",
207199 tempRoot,
@@ -212,14 +204,14 @@ try { · 4 unmodified lines
212204 },
213205 );
214206
215− rmSync(resolve(tempRoot, "pnpm-lock.yaml"), { force: true });
207+ NodeFS.rmSync(NodePath.resolve(tempRoot, "pnpm-lock.yaml"), { force: true });
216208
217− execFileSync("vp", ["install", "--lockfile-only", "--ignore-scripts"], {
209+ NodeChildProcess.execFileSync("vp", ["install", "--lockfile-only", "--ignore-scripts"], {
218210 cwd: tempRoot,
219211 stdio: "inherit",
220212 });
221213
222− const lockfile = readFileSync(resolve(tempRoot, "pnpm-lock.yaml"), "utf8");
214+ const lockfile = NodeFS.readFileSync(NodePath.resolve(tempRoot, "pnpm-lock.yaml"), "utf8");
223215 assertContains(lockfile, "lockfileVersion:", "Expected pnpm-lock.yaml to be regenerated.");
224216
225217 for (const relativePath of [
@@ -228,13 +220,13 @@ try { · 2 unmodified lines
228220 "apps/web/package.json",
229221 "packages/contracts/package.json",
230222 ]) {
231− assertPackageVersion(resolve(tempRoot, relativePath), "9.9.9-smoke.0");
223+ assertPackageVersion(NodePath.resolve(tempRoot, relativePath), "9.9.9-smoke.0");
232224 }
233225
234− const nightlyReleaseMetadata = execFileSync(
226+ const nightlyReleaseMetadata = NodeChildProcess.execFileSync(
235227 process.execPath,
236228 [
237− resolve(repoRoot, "scripts/resolve-nightly-release.ts"),
229+ NodePath.resolve(repoRoot, "scripts/resolve-nightly-release.ts"),
238230 "--date",
239231 "20260413",
240232 "--run-number",
@@ -266,10 +258,10 @@ try { · 25 unmodified lines
266258 );
267259
268260 const { arm64Path, x64Path } = writeMacManifestFixtures(tempRoot);
269− execFileSync(
261+ NodeChildProcess.execFileSync(
270262 process.execPath,
271263 [
272− resolve(repoRoot, "scripts/merge-update-manifests.ts"),
264+ NodePath.resolve(repoRoot, "scripts/merge-update-manifests.ts"),
273265 "--platform",
274266 "mac",
275267 arm64Path,
@@ -281,7 +273,7 @@ try { · 5 unmodified lines
281273 },
282274 );
283275
284− const mergedManifest = readFileSync(arm64Path, "utf8");
276+ const mergedManifest = NodeFS.readFileSync(arm64Path, "utf8");
285277 assertContains(
286278 mergedManifest,
287279 "T3-Code-9.9.9-smoke.0-arm64.zip",
@@ -297,21 +289,21 @@ try { · 9 unmodified lines
297289 tempRoot,
298290 "latest",
299291 );
300− const mergedWindowsManifestPath = resolve(tempRoot, "release-assets/latest.yml");
292+ const mergedWindowsManifestPath = NodePath.resolve(tempRoot, "release-assets/latest.yml");
301293 const { arm64Path: nightlyWinArm64Path, x64Path: nightlyWinX64Path } =
302294 writeWindowsManifestFixtures(tempRoot, "nightly");
303− const mergedNightlyWindowsManifestPath = resolve(tempRoot, "release-assets/nightly.yml");
295+ const mergedNightlyWindowsManifestPath = NodePath.resolve(tempRoot, "release-assets/nightly.yml");
304296 const { arm64Path: previewWinArm64Path, x64Path: previewWinX64Path } =
305297 writeWindowsManifestFixtures(tempRoot, "preview");
306− const mergedPreviewWindowsManifestPath = resolve(tempRoot, "release-assets/preview.yml");
298+ const mergedPreviewWindowsManifestPath = NodePath.resolve(tempRoot, "release-assets/preview.yml");
307299 const { arm64Path: winDebugArm64Path, x64Path: winDebugX64Path } =
308300 writeWindowsBuilderDebugFixtures(tempRoot);
309− execFileSync(
301+ NodeChildProcess.execFileSync(
310302 "bash",
311303 [
312304 "-lc",
313305 `
314− release_assets_dir=${JSON.stringify(resolve(tempRoot, "release-assets"))}
306+ release_assets_dir=${JSON.stringify(NodePath.resolve(tempRoot, "release-assets"))}
315307 shopt -s nullglob
316308 found_windows_manifest=false
317309 for x64_manifest in "$release_assets_dir"/*-win-x64.yml; do
@@ -327,7 +319,7 @@ try { · 9 unmodified lines
327319 fi
328320
329321 found_windows_manifest=true
330− ${JSON.stringify(process.execPath)} ${JSON.stringify(resolve(repoRoot, "scripts/merge-update-manifests.ts"))} --platform win \
322+ ${JSON.stringify(process.execPath)} ${JSON.stringify(NodePath.resolve(repoRoot, "scripts/merge-update-manifests.ts"))} --platform win \
331323 "$arm64_manifest" \
332324 "$x64_manifest" \
333325 "$output_manifest"
@@ -346,7 +338,7 @@ try { · 12 unmodified lines
346338 },
347339 );
348340
349− const mergedWindowsManifest = readFileSync(mergedWindowsManifestPath, "utf8");
341+ const mergedWindowsManifest = NodeFS.readFileSync(mergedWindowsManifestPath, "utf8");
350342 assertContains(
351343 mergedWindowsManifest,
352344 "T3-Code-9.9.9-smoke.0-arm64.exe",
@@ -357,7 +349,10 @@ try { · 4 unmodified lines
357349 "T3-Code-9.9.9-smoke.0-x64.exe",
358350 "Merged Windows manifest is missing the x64 asset.",
359351 );
360− const mergedNightlyWindowsManifest = readFileSync(mergedNightlyWindowsManifestPath, "utf8");
352+ const mergedNightlyWindowsManifest = NodeFS.readFileSync(
353+ mergedNightlyWindowsManifestPath,
354+ "utf8",
355+ );
361356 assertContains(
362357 mergedNightlyWindowsManifest,
363358 "T3-Code-9.9.9-smoke.0-arm64.exe",
@@ -368,7 +363,10 @@ try { · 4 unmodified lines
368363 "T3-Code-9.9.9-smoke.0-x64.exe",
369364 "Merged nightly Windows manifest is missing the x64 asset.",
370365 );
371− const mergedPreviewWindowsManifest = readFileSync(mergedPreviewWindowsManifestPath, "utf8");
366+ const mergedPreviewWindowsManifest = NodeFS.readFileSync(
367+ mergedPreviewWindowsManifestPath,
368+ "utf8",
369+ );
372370 assertContains(
373371 mergedPreviewWindowsManifest,
374372 "T3-Code-9.9.9-smoke.0-arm64.exe",
@@ -411,5 +409,5 @@ try { · 36 unmodified lines
411409
412410 Effect.runSync(Console.log("Release smoke checks passed."));
413411 } finally {
414− rmSync(tempRoot, { recursive: true, force: true });
412+ NodeFS.rmSync(tempRoot, { recursive: true, force: true });
415413 }
vite.config.ts+3−2
@@ -1,11 +1,11 @@
11 import "vite-plus/test/config";
22 import { defineConfig } from "vite-plus";
3−import { fileURLToPath } from "node:url";
3+import * as NodeURL from "node:url";
44
55 export default defineConfig({
66 resolve: {
77 alias: {
8− "~": fileURLToPath(new URL("./apps/web/src", import.meta.url)),
8+ "~": NodeURL.fileURLToPath(new URL("./apps/web/src", import.meta.url)),
99 },
1010 },
1111 test: {
@@ -111,6 +111,7 @@ export default defineConfig({ · 99 unmodified lines
111111 "t3code/no-global-process-runtime": "error",
112112 "t3code/no-inline-schema-compile": "warn",
113113 "t3code/no-manual-effect-runtime-in-tests": "error",
114+ "t3code/namespace-node-imports": "error",
114115 },
115116 options: {
116117 // Revisit once Oxlint's tsgolint path can integrate with @effect/tsgo diagnostics.