mirror of
https://github.com/anomalyco/opencode.git
synced 2026-09-12 02:35:22 +00:00
88 lines
4.7 KiB
TypeScript
88 lines
4.7 KiB
TypeScript
import { Effect, Stream } from "effect"
|
|
import { Llm, OpenCodeDriver } from "opencode-drive"
|
|
|
|
const label = process.env.DEMO_LABEL ?? "AFTER"
|
|
|
|
// Run from the repository root with `opencode-drive run script/drive/shell-output.ts`.
|
|
// Set OPENCODE_DEV to an immutable base worktree and DEMO_LABEL=BEFORE for comparison.
|
|
// Only the conversation is simulated; shell execution and output reads are real.
|
|
export default OpenCodeDriver.use(
|
|
{
|
|
opencode: { dev: process.env.OPENCODE_DEV ?? process.cwd() },
|
|
keepArtifacts: true,
|
|
tui: { recording: true, keypressOverlay: true, viewport: { cols: 90, rows: 30 } },
|
|
config: { autoupdate: false, username: "Demo" },
|
|
tuiConfig: { theme: { name: "opencode", mode: "dark" }, animations: false, tabs: { enabled: false } },
|
|
project: {
|
|
git: true,
|
|
files: {
|
|
"README.md": "# Shell output demo\nDeterministic real shell output.\n",
|
|
"render-scene.sh": [
|
|
"#!/bin/sh",
|
|
"i=1",
|
|
'while [ "$i" -le 40 ]; do printf "Frame %02d: rendered successfully\\n" "$i"; i=$((i+1)); done',
|
|
"while [ ! -f continue ]; do sleep 0.1; done",
|
|
'while [ "$i" -le 48 ]; do printf "Frame %02d: rendered successfully\\n" "$i"; i=$((i+1)); sleep 0.25; done',
|
|
"while [ ! -f finish ]; do sleep 0.1; done",
|
|
"printf 'Diagnostics: no errors\\n' >&2",
|
|
"printf 'Render complete: 48 frames saved.\\n'",
|
|
].join("\n"),
|
|
},
|
|
},
|
|
},
|
|
({ ui, llm, tui, opencode, artifacts }) =>
|
|
Effect.gen(function* () {
|
|
const recording = tui.recording
|
|
if (!recording) return yield* Effect.fail(new Error("Recording required"))
|
|
yield* llm.serve(() => Stream.make(Llm.text("Ready to inspect the render job.")))
|
|
yield* ui.submit("Inspect the render job.")
|
|
yield* ui.waitFor("Ready to inspect the render job.")
|
|
const sessions = yield* opencode.session.list({ limit: 1, order: "desc" })
|
|
const session = sessions.data[0]
|
|
if (!session) return yield* Effect.fail(new Error("Session missing"))
|
|
yield* opencode.session.rename({ sessionID: session.id, title: "Shell output demo" })
|
|
yield* opencode.shell.create({ command: "sh render-scene.sh", timeout: 0, metadata: { sessionID: session.id } })
|
|
yield* ui.arrow("down")
|
|
yield* ui.arrow("right")
|
|
yield* ui.waitFor("sh render-scene.sh")
|
|
yield* recording.mark(`${label}: select a running shell`)
|
|
yield* Effect.sleep(1000)
|
|
yield* ui.enter()
|
|
yield* ui.waitFor(label === "AFTER" ? "Frame 40: rendered successfully" : "sh render-scene.sh")
|
|
yield* Effect.sleep(1000)
|
|
yield* recording.mark(`${label}: Enter ${label === "AFTER" ? "opens live output" : "does nothing"}`)
|
|
console.log("opened:", yield* ui.screenshot(`${label.toLowerCase()}-opened`))
|
|
yield* Effect.promise(() => Bun.write(`${artifacts}/files/continue`, "go"))
|
|
if (label === "AFTER") yield* ui.waitFor("Frame 48: rendered successfully")
|
|
yield* Effect.sleep(2800)
|
|
yield* ui.press("home")
|
|
yield* ui.waitFor(label === "AFTER" ? "Frame 01: rendered successfully" : "sh render-scene.sh")
|
|
yield* recording.mark(`${label}: ${label === "AFTER" ? "Home scrolls to earlier output" : "no output to scroll"}`)
|
|
yield* Effect.sleep(1500)
|
|
console.log("scrolled:", yield* ui.screenshot(`${label.toLowerCase()}-scrolled`))
|
|
yield* ui.press("end")
|
|
yield* ui.waitFor(label === "AFTER" ? "Frame 48: rendered successfully" : "sh render-scene.sh")
|
|
yield* recording.mark(`${label}: ${label === "AFTER" ? "End follows the latest output" : "no output to follow"}`)
|
|
yield* Effect.sleep(1000)
|
|
yield* Effect.promise(() => Bun.write(`${artifacts}/files/finish`, "go"))
|
|
yield* ui.waitFor(label === "AFTER" ? "Render complete: 48 frames saved." : "No shell commands")
|
|
if (label === "AFTER") yield* ui.waitFor("Exited · code 0")
|
|
yield* Effect.sleep(1600)
|
|
yield* recording.mark(
|
|
`${label}: ${label === "AFTER" ? "result stays open after exit" : "finished shell disappears"}`,
|
|
)
|
|
console.log("exited:", yield* ui.screenshot(`${label.toLowerCase()}-exited`))
|
|
yield* Effect.sleep(2000)
|
|
yield* ui.resize({ cols: 40, rows: 24 })
|
|
yield* Effect.sleep(500)
|
|
console.log("narrow:", yield* ui.screenshot(`${label.toLowerCase()}-narrow`))
|
|
yield* ui.resize({ cols: 90, rows: 30 })
|
|
yield* Effect.sleep(500)
|
|
yield* ui.press("escape")
|
|
if (label === "AFTER") yield* ui.waitFor("No shell commands")
|
|
yield* recording.mark(`${label}: Esc back`)
|
|
yield* Effect.sleep(1000)
|
|
console.log("back:", yield* ui.screenshot(`${label.toLowerCase()}-back`))
|
|
return console.log("video:", yield* recording.finish())
|
|
}),
|
|
)
|