refactor(simulation): scope Drive lifecycle with Effect (#36908)

This commit is contained in:
Kit Langton 2026-07-14 17:16:50 -04:00 committed by GitHub
commit 947566f611
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 1313 additions and 600 deletions

View file

@ -1,32 +1,27 @@
import { createCliRenderer, type CliRenderer, type CliRendererConfig } from "@opentui/core"
import { createCliRenderer, type CliRendererConfig } from "@opentui/core"
import { Config, Effect } from "effect"
import { DriveManifest } from "../manifest"
import { SimulationActions } from "./actions"
import { SimulationRenderer } from "./renderer"
import { SimulationServer } from "./server"
/**
* Drive-mode renderer entry point.
*
* Creates the renderer (headless when OPENCODE_DRIVE_RENDERER=headless, the normal
* visible renderer otherwise) and starts the UI control
* server against it. The server stops when the renderer is destroyed, so the
* caller only manages the renderer lifecycle.
*/
export async function create(options: CliRendererConfig): Promise<CliRenderer> {
const headless = process.env.OPENCODE_DRIVE_RENDERER === "headless"
const manifest = DriveManifest.resolve()
/** Drive-mode renderer and control-server acquisition. */
export const create = Effect.fn("Drive.create")(function* (options: CliRendererConfig) {
const headless = (yield* Config.string("OPENCODE_DRIVE_RENDERER").pipe(Config.withDefault("visible"))) === "headless"
const manifest = yield* DriveManifest.resolve()
const renderer = headless
? await SimulationRenderer.create(options, manifest.recording?.timeline, manifest.viewport)
: await createCliRenderer(options)
? yield* SimulationRenderer.create(options, manifest.recording?.timeline, manifest.viewport)
: yield* Effect.acquireRelease(
Effect.tryPromise(() => createCliRenderer(options)),
(renderer) =>
Effect.sync(() => {
if (!renderer.isDestroyed) renderer.destroy()
}),
)
if (!headless && manifest.viewport) renderer.resize(manifest.viewport.cols, manifest.viewport.rows)
const server = SimulationServer.start(
SimulationActions.createHarness(renderer),
manifest.endpoints.ui,
headless && manifest.recording ? () => SimulationRenderer.finish(renderer) : undefined,
)
process.stderr.write(`opencode drive ui websocket: ${server.url}\n`)
renderer.once("destroy", () => server.stop())
const server = yield* SimulationServer.start(SimulationActions.createHarness(renderer), manifest.endpoints.ui)
yield* Effect.sync(() => process.stderr.write(`opencode drive ui websocket: ${server.url}\n`))
return renderer
}
})
export * as Drive from "./simulation"