From f711aec8dd7bb40edbae3f482aa2c41258f5e064 Mon Sep 17 00:00:00 2001 From: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com> Date: Mon, 23 Mar 2026 00:19:00 +0530 Subject: [PATCH 1/7] Load PTY adapter at runtime - Switch terminal PTY layer selection to dynamic imports - Avoid bundling the Bun adapter in Node-only runtimes --- apps/server/src/serverLayers.ts | 37 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/server/src/serverLayers.ts b/apps/server/src/serverLayers.ts index 7250f8566..197cabfb0 100644 --- a/apps/server/src/serverLayers.ts +++ b/apps/server/src/serverLayers.ts @@ -1,5 +1,5 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; -import { Effect, FileSystem, Layer } from "effect"; +import { Effect, FileSystem, Layer, Path } from "effect"; import * as SqlClient from "effect/unstable/sql/SqlClient"; import { CheckpointDiffQueryLive } from "./checkpointing/Layers/CheckpointDiffQuery"; @@ -32,10 +32,33 @@ import { GitCoreLive } from "./git/Layers/GitCore"; import { GitHubCliLive } from "./git/Layers/GitHubCli"; import { CodexTextGenerationLive } from "./git/Layers/CodexTextGeneration"; import { GitServiceLive } from "./git/Layers/GitService"; -import { BunPtyAdapterLive } from "./terminal/Layers/BunPTY"; -import { NodePtyAdapterLive } from "./terminal/Layers/NodePTY"; +import { PtyAdapter } from "./terminal/Services/PTY"; import { AnalyticsService } from "./telemetry/Services/AnalyticsService"; +type RuntimePtyAdapterLoader = { + layer: Layer.Layer; +}; + +const runtimePtyAdapterLoaders = { + bun: () => + import("./terminal/Layers/BunPTY").then(({ BunPtyAdapterLive }) => ({ + layer: BunPtyAdapterLive, + })), + node: () => + import("./terminal/Layers/NodePTY").then(({ NodePtyAdapterLive }) => ({ + layer: NodePtyAdapterLive, + })), +} satisfies Record Promise>; + +const makeRuntimePtyAdapterLayer = () => + Effect.gen(function* () { + const runtime = + process.versions.bun !== undefined && process.platform !== "win32" ? "bun" : "node"; + const loader = runtimePtyAdapterLoaders[runtime]; + const ptyAdapterModule = yield* Effect.promise(loader); + return ptyAdapterModule.layer; + }).pipe(Layer.unwrap); + export function makeServerProviderLayer(): Layer.Layer< ProviderService, ProviderUnsupportedError, @@ -108,13 +131,7 @@ export function makeServerRuntimeServicesLayer() { Layer.provideMerge(checkpointReactorLayer), ); - const terminalLayer = TerminalManagerLive.pipe( - Layer.provide( - typeof Bun !== "undefined" && process.platform !== "win32" - ? BunPtyAdapterLive - : NodePtyAdapterLive, - ), - ); + const terminalLayer = TerminalManagerLive.pipe(Layer.provide(makeRuntimePtyAdapterLayer())); const gitManagerLayer = GitManagerLive.pipe( Layer.provideMerge(gitCoreLayer), From aeb548153b79fc8423b9db2f1ae2d9a7d939e225 Mon Sep 17 00:00:00 2001 From: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com> Date: Mon, 23 Mar 2026 01:35:39 +0530 Subject: [PATCH 2/7] Use Bun runtime services when running under Bun - Detect Bun at startup and select the matching Effect runtime layer - Keep the server entrypoint working in both Bun and Node environments --- apps/server/src/index.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 363a07ee3..8ce49b1b6 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -1,3 +1,5 @@ +import * as BunRuntime from "@effect/platform-bun/BunRuntime"; +import * as BunServices from "@effect/platform-bun/BunServices"; import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; import * as NodeServices from "@effect/platform-node/NodeServices"; import * as Effect from "effect/Effect"; @@ -11,13 +13,17 @@ import { ServerLive } from "./wsServer"; import { NetService } from "@t3tools/shared/Net"; import { FetchHttpClient } from "effect/unstable/http"; +const isBun = process.versions.bun !== undefined; +const platformServicesLayer = isBun ? BunServices.layer : NodeServices.layer; +const runMain = isBun ? BunRuntime.runMain : NodeRuntime.runMain; + const RuntimeLayer = Layer.empty.pipe( Layer.provideMerge(CliConfig.layer), Layer.provideMerge(ServerLive), Layer.provideMerge(OpenLive), Layer.provideMerge(NetService.layer), - Layer.provideMerge(NodeServices.layer), + Layer.provideMerge(platformServicesLayer), Layer.provideMerge(FetchHttpClient.layer), ); -Command.run(t3Cli, { version }).pipe(Effect.provide(RuntimeLayer), NodeRuntime.runMain); +Command.run(t3Cli, { version }).pipe(Effect.provide(RuntimeLayer), runMain); From d3ebbe6575402148e62994c50a1ccf45792eb222 Mon Sep 17 00:00:00 2001 From: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com> Date: Mon, 23 Mar 2026 02:29:44 +0530 Subject: [PATCH 3/7] Use Node runtime services in server entrypoint - Remove Bun runtime branching from `apps/server/src/index.ts` - Run the server with the Node platform layer and runtime --- apps/server/src/index.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 8ce49b1b6..363a07ee3 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -1,5 +1,3 @@ -import * as BunRuntime from "@effect/platform-bun/BunRuntime"; -import * as BunServices from "@effect/platform-bun/BunServices"; import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; import * as NodeServices from "@effect/platform-node/NodeServices"; import * as Effect from "effect/Effect"; @@ -13,17 +11,13 @@ import { ServerLive } from "./wsServer"; import { NetService } from "@t3tools/shared/Net"; import { FetchHttpClient } from "effect/unstable/http"; -const isBun = process.versions.bun !== undefined; -const platformServicesLayer = isBun ? BunServices.layer : NodeServices.layer; -const runMain = isBun ? BunRuntime.runMain : NodeRuntime.runMain; - const RuntimeLayer = Layer.empty.pipe( Layer.provideMerge(CliConfig.layer), Layer.provideMerge(ServerLive), Layer.provideMerge(OpenLive), Layer.provideMerge(NetService.layer), - Layer.provideMerge(platformServicesLayer), + Layer.provideMerge(NodeServices.layer), Layer.provideMerge(FetchHttpClient.layer), ); -Command.run(t3Cli, { version }).pipe(Effect.provide(RuntimeLayer), runMain); +Command.run(t3Cli, { version }).pipe(Effect.provide(RuntimeLayer), NodeRuntime.runMain); From 6c63f05c170824d3a465c425ae57077343a4de9c Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Mon, 23 Mar 2026 10:30:47 -0700 Subject: [PATCH 4/7] die on bun windows combo --- apps/server/src/serverLayers.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/server/src/serverLayers.ts b/apps/server/src/serverLayers.ts index 197cabfb0..bcc8c6866 100644 --- a/apps/server/src/serverLayers.ts +++ b/apps/server/src/serverLayers.ts @@ -52,8 +52,12 @@ const runtimePtyAdapterLoaders = { const makeRuntimePtyAdapterLayer = () => Effect.gen(function* () { - const runtime = - process.versions.bun !== undefined && process.platform !== "win32" ? "bun" : "node"; + const runtime = process.versions.bun !== undefined ? "bun" : "node"; + if (runtime === "bun" && process.platform === "win32") { + return yield* Effect.die( + "Bun PTY terminal support is unavailable on Windows. Please use Node.js by running `npx t3` instead.", + ); + } const loader = runtimePtyAdapterLoaders[runtime]; const ptyAdapterModule = yield* Effect.promise(loader); return ptyAdapterModule.layer; From 73bd2badd8391a320a046950aff6ec2095b0cb94 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Mon, 23 Mar 2026 10:31:11 -0700 Subject: [PATCH 5/7] pty will auto-die for us --- apps/server/src/serverLayers.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/server/src/serverLayers.ts b/apps/server/src/serverLayers.ts index bcc8c6866..6edfafd32 100644 --- a/apps/server/src/serverLayers.ts +++ b/apps/server/src/serverLayers.ts @@ -53,11 +53,6 @@ const runtimePtyAdapterLoaders = { const makeRuntimePtyAdapterLayer = () => Effect.gen(function* () { const runtime = process.versions.bun !== undefined ? "bun" : "node"; - if (runtime === "bun" && process.platform === "win32") { - return yield* Effect.die( - "Bun PTY terminal support is unavailable on Windows. Please use Node.js by running `npx t3` instead.", - ); - } const loader = runtimePtyAdapterLoaders[runtime]; const ptyAdapterModule = yield* Effect.promise(loader); return ptyAdapterModule.layer; From 64659c7751fd4f0645267d516541686edd039393 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Mon, 23 Mar 2026 10:31:37 -0700 Subject: [PATCH 6/7] improve error message --- apps/server/src/terminal/Layers/BunPTY.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/server/src/terminal/Layers/BunPTY.ts b/apps/server/src/terminal/Layers/BunPTY.ts index 48b6492b1..761b89ae6 100644 --- a/apps/server/src/terminal/Layers/BunPTY.ts +++ b/apps/server/src/terminal/Layers/BunPTY.ts @@ -90,7 +90,9 @@ export const BunPtyAdapterLive = Layer.effect( PtyAdapter, Effect.gen(function* () { if (process.platform === "win32") { - return yield* Effect.die("Bun PTY terminal support is unavailable on Windows."); + return yield* Effect.die( + "Bun PTY terminal support is unavailable on Windows. Please use Node.js (e.g. by running `npx t3`) instead.", + ); } return { spawn: (input) => From 73623d21a5f22b8824212e78928e54d0f9eef4b8 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Mon, 23 Mar 2026 10:33:26 -0700 Subject: [PATCH 7/7] cool --- apps/server/src/serverLayers.ts | 12 +++--------- apps/server/src/terminal/Layers/BunPTY.ts | 2 +- apps/server/src/terminal/Layers/NodePTY.ts | 2 +- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/apps/server/src/serverLayers.ts b/apps/server/src/serverLayers.ts index 6edfafd32..b75444173 100644 --- a/apps/server/src/serverLayers.ts +++ b/apps/server/src/serverLayers.ts @@ -40,21 +40,15 @@ type RuntimePtyAdapterLoader = { }; const runtimePtyAdapterLoaders = { - bun: () => - import("./terminal/Layers/BunPTY").then(({ BunPtyAdapterLive }) => ({ - layer: BunPtyAdapterLive, - })), - node: () => - import("./terminal/Layers/NodePTY").then(({ NodePtyAdapterLive }) => ({ - layer: NodePtyAdapterLive, - })), + bun: () => import("./terminal/Layers/BunPTY"), + node: () => import("./terminal/Layers/NodePTY"), } satisfies Record Promise>; const makeRuntimePtyAdapterLayer = () => Effect.gen(function* () { const runtime = process.versions.bun !== undefined ? "bun" : "node"; const loader = runtimePtyAdapterLoaders[runtime]; - const ptyAdapterModule = yield* Effect.promise(loader); + const ptyAdapterModule = yield* Effect.promise(loader); return ptyAdapterModule.layer; }).pipe(Layer.unwrap); diff --git a/apps/server/src/terminal/Layers/BunPTY.ts b/apps/server/src/terminal/Layers/BunPTY.ts index 761b89ae6..1fb4bdd63 100644 --- a/apps/server/src/terminal/Layers/BunPTY.ts +++ b/apps/server/src/terminal/Layers/BunPTY.ts @@ -86,7 +86,7 @@ class BunPtyProcess implements PtyProcess { } } -export const BunPtyAdapterLive = Layer.effect( +export const layer = Layer.effect( PtyAdapter, Effect.gen(function* () { if (process.platform === "win32") { diff --git a/apps/server/src/terminal/Layers/NodePTY.ts b/apps/server/src/terminal/Layers/NodePTY.ts index 60a7ab622..cf1fdd219 100644 --- a/apps/server/src/terminal/Layers/NodePTY.ts +++ b/apps/server/src/terminal/Layers/NodePTY.ts @@ -84,7 +84,7 @@ class NodePtyProcess implements PtyProcess { } } -export const NodePtyAdapterLive = Layer.effect( +export const layer = Layer.effect( PtyAdapter, Effect.gen(function* () { const fs = yield* FileSystem.FileSystem;