refactor(tui): collapse simulation activation into renderer creation
app.tsx now has a single simulation touchpoint inside the renderer acquire: in simulation mode it delegates to Simulation.createSimulation, which picks the fake or visible renderer and starts the control server. The server is tied to renderer destroy, so no extra finalizer is needed in app code.
This commit is contained in:
parent
bab30226b9
commit
3dc36ec38b
2 changed files with 47 additions and 38 deletions
|
|
@ -180,25 +180,31 @@ function isVersionGreater(left: string, right: string) {
|
|||
export const run = Effect.fn("Tui.run")(function* (input: TuiInput) {
|
||||
const global = yield* Global.Service
|
||||
const exit = { epilogue: undefined as string | undefined, reason: undefined as unknown }
|
||||
const simulationEnabled = process.env.OPENCODE_SIMULATION === "1" || process.env.OPENCODE_SIMULATION === "true"
|
||||
const result = yield* Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
let renderer = yield* Effect.acquireRelease(
|
||||
const renderer = yield* Effect.acquireRelease(
|
||||
Effect.tryPromise({
|
||||
try: () =>
|
||||
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" }],
|
||||
},
|
||||
}),
|
||||
try: async () => {
|
||||
const createVisibleRenderer = () =>
|
||||
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" }],
|
||||
},
|
||||
})
|
||||
if (process.env.OPENCODE_SIMULATION === "1" || process.env.OPENCODE_SIMULATION === "true") {
|
||||
const { Simulation } = await import("./simulation/simulation")
|
||||
return Simulation.createSimulation(createVisibleRenderer)
|
||||
}
|
||||
return createVisibleRenderer()
|
||||
},
|
||||
catch: (error) => (error instanceof Error ? error : new Error(String(error))),
|
||||
}),
|
||||
(renderer) =>
|
||||
|
|
@ -206,28 +212,6 @@ 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(
|
||||
|
|
|
|||
25
packages/tui/src/simulation/simulation.ts
Normal file
25
packages/tui/src/simulation/simulation.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import type { CliRenderer } from "@opentui/core"
|
||||
import { SimulationActions } from "./actions"
|
||||
import { SimulationRenderer } from "./renderer"
|
||||
import { SimulationServer } from "./server"
|
||||
|
||||
/**
|
||||
* Simulation-mode renderer entry point.
|
||||
*
|
||||
* Creates the renderer (fake when OPENCODE_SIMULATION_RENDERER=fake, the
|
||||
* normal visible renderer otherwise) and starts the simulation control
|
||||
* server against it. The server stops when the renderer is destroyed, so the
|
||||
* caller only manages the renderer lifecycle.
|
||||
*/
|
||||
export async function createSimulation(createVisibleRenderer: () => Promise<CliRenderer>): Promise<CliRenderer> {
|
||||
const renderer =
|
||||
process.env.OPENCODE_SIMULATION_RENDERER === "fake" ? await SimulationRenderer.create() : await createVisibleRenderer()
|
||||
const server = SimulationServer.start(SimulationActions.createHarness(renderer))
|
||||
if (server) {
|
||||
process.stderr.write(`opencode simulation websocket: ${server.url}\n`)
|
||||
renderer.once("destroy", () => server.stop())
|
||||
}
|
||||
return renderer
|
||||
}
|
||||
|
||||
export * as Simulation from "./simulation"
|
||||
Loading…
Add table
Add a link
Reference in a new issue