From bab30226b98c212816e40fbc3eceef02006befb6 Mon Sep 17 00:00:00 2001 From: James Long Date: Thu, 2 Jul 2026 18:37:20 +0000 Subject: [PATCH] refactor(tui): move fake renderer swap into single simulation block --- packages/tui/src/app.tsx | 64 ++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/packages/tui/src/app.tsx b/packages/tui/src/app.tsx index 4e45f69672b..2cf079b898c 100644 --- a/packages/tui/src/app.tsx +++ b/packages/tui/src/app.tsx @@ -183,24 +183,22 @@ export const run = Effect.fn("Tui.run")(function* (input: TuiInput) { const simulationEnabled = process.env.OPENCODE_SIMULATION === "1" || process.env.OPENCODE_SIMULATION === "true" const result = yield* Effect.scoped( Effect.gen(function* () { - const renderer = yield* Effect.acquireRelease( + let renderer = yield* Effect.acquireRelease( Effect.tryPromise({ try: () => - simulationEnabled && process.env.OPENCODE_SIMULATION_RENDERER === "fake" - ? import("./simulation/renderer").then(({ SimulationRenderer }) => SimulationRenderer.create()) - : createCliRenderer({ - externalOutputMode: "passthrough", - targetFps: 60, - gatherStats: false, - exitOnCtrlC: false, - useKittyKeyboard: {}, - autoFocus: false, - openConsoleOnError: false, - useMouse: !Flag.OPENCODE_DISABLE_MOUSE && input.config.mouse, - consoleOptions: { - keyBindings: [{ name: "y", ctrl: true, action: "copy-selection" }], - }, - }), + createCliRenderer({ + externalOutputMode: "passthrough", + targetFps: 60, + gatherStats: false, + exitOnCtrlC: false, + useKittyKeyboard: {}, + autoFocus: false, + openConsoleOnError: false, + useMouse: !Flag.OPENCODE_DISABLE_MOUSE && input.config.mouse, + consoleOptions: { + keyBindings: [{ name: "y", ctrl: true, action: "copy-selection" }], + }, + }), catch: (error) => (error instanceof Error ? error : new Error(String(error))), }), (renderer) => @@ -208,6 +206,28 @@ export const run = Effect.fn("Tui.run")(function* (input: TuiInput) { destroyRenderer(renderer) }), ) + + if (simulationEnabled) { + if (process.env.OPENCODE_SIMULATION_RENDERER === "fake") { + const { SimulationRenderer } = yield* Effect.promise(() => import("./simulation/renderer")) + destroyRenderer(renderer) + renderer = yield* Effect.acquireRelease( + Effect.promise(() => SimulationRenderer.create()), + (fake) => Effect.sync(() => destroyRenderer(fake)), + ) + } + const target = renderer + const simulation = yield* Effect.promise(async () => { + const { SimulationActions } = await import("./simulation/actions") + const { SimulationServer } = await import("./simulation/server") + return SimulationServer.start(SimulationActions.createHarness(target)) + }) + if (simulation) { + process.stderr.write(`opencode simulation websocket: ${simulation.url}\n`) + yield* Effect.addFinalizer(() => Effect.sync(() => simulation.stop())) + } + } + win32DisableProcessedInput() const keymap = createDefaultOpenTuiKeymap(renderer) yield* Effect.acquireRelease( @@ -233,18 +253,6 @@ export const run = Effect.fn("Tui.run")(function* (input: TuiInput) { renderer.once("destroy", () => Deferred.doneUnsafe(shutdown, Effect.void)) const pluginRuntime = createPluginRuntime() - if (simulationEnabled) { - const simulation = yield* Effect.promise(async () => { - const { SimulationActions } = await import("./simulation/actions") - const { SimulationServer } = await import("./simulation/server") - return SimulationServer.start(SimulationActions.createHarness(renderer)) - }) - if (simulation) { - process.stderr.write(`opencode simulation websocket: ${simulation.url}\n`) - yield* Effect.addFinalizer(() => Effect.sync(() => simulation.stop())) - } - } - yield* Effect.tryPromise(async () => { // Prewarm palette before ThemeProvider mounts so `system` theme avoids a first-paint fallback flash. void renderer.getPalette({ size: 16 }).catch(() => undefined)