opencode/packages/tui/test/theme/gallery/scenario.ts
2026-07-16 18:54:39 +00:00

123 lines
4.3 KiB
TypeScript

import path from "node:path"
import { mkdir } from "node:fs/promises"
import { defineScript, wait } from "opencode-drive"
const file = required("OPENCODE_THEME_GALLERY_FILE")
const mode = required("OPENCODE_THEME_GALLERY_MODE")
const output = required("OPENCODE_THEME_GALLERY_OUTPUT")
const slug = required("OPENCODE_THEME_GALLERY_SLUG")
const themeName = `gallery-${slug}`
export default defineScript({
async setup({ fs, config }) {
await fs.writeFile("README.md", "# Theme gallery fixture\n\nA stable project for OpenCode TUI screenshots.\n")
await fs.writeFile("src/example.ts", "export const palette = ['neutral', 'accent', 'interactive']\n")
await fs.writeFile(`.opencode/themes/${themeName}.json`, await Bun.file(file).text())
await fs.writeFile(
".opencode/cli.json",
`${JSON.stringify({
theme: { name: themeName, mode },
}, undefined, 2)}\n`,
)
config.permissions = [
{ action: "*", resource: "*", effect: "allow" },
{ action: "shell", resource: "*", effect: "ask" },
]
},
async run({ llm, ui }) {
await mkdir(output, { recursive: true })
llm.title((_request, index) => (index === 0 ? "Theme gallery" : `Theme gallery ${index + 1}`))
await ui.waitFor((state) => state.focused.editor)
await ui.waitFor("local")
await wait(750)
await capture(ui, "01-home")
await ui.submit("Show me a compact markdown theme specimen")
await llm.send(
llm.reasoning("I will provide a stable markdown sample for the theme gallery."),
llm.text(
[
"# Theme Review",
"",
"A compact response with **strong text**, *emphasis*, and an `inline token`.",
"",
"> Good themes preserve hierarchy without losing contrast.",
"",
"- Neutral surfaces",
"- Interactive accents",
"- Success, warning, and error feedback",
"",
"```ts",
"const mode = 'gallery'",
"```",
].join("\n"),
),
)
await ui.waitFor("Theme Review")
await capture(ui, "02-markdown")
const permission = llm.send(
llm.toolCall({
id: "theme-gallery-permission",
index: 0,
name: "shell",
input: { command: "printf 'theme gallery permission'" },
}),
)
await ui.submit("Run a protected command so I can inspect the permission prompt")
await ui.waitFor("Permission required")
await capture(ui, "03-permission")
await ui.enter()
await permission
await llm.send(llm.text("The protected command completed successfully."))
await ui.waitFor("completed successfully")
const form = llm.send(
llm.toolCall({
id: "theme-gallery-question",
index: 0,
name: "question",
input: {
questions: [
{
header: "Theme direction",
question: "Which direction should this theme emphasize?",
options: [
{ label: "Balanced", description: "Keep surfaces and accents evenly weighted" },
{ label: "Expressive", description: "Give accent colors more visual presence" },
{ label: "Quiet", description: "Favor neutral surfaces and restrained contrast" },
],
},
],
},
}),
)
await ui.submit("Ask me for a theme direction")
await ui.waitFor("Which direction should this theme emphasize?")
await capture(ui, "04-form")
await ui.enter()
await form
await llm.send(llm.text("The theme review form was submitted."))
await ui.waitFor("form was submitted")
await ui.submit("/new")
await ui.waitFor((state) => state.focused.editor)
await ui.submit("Create a second session for the session switcher gallery")
await llm.send(llm.text("This second session makes the switcher state visible."))
await ui.submit("/sessions")
await ui.waitFor("Sessions")
await capture(ui, "05-session-switcher")
},
})
async function capture(ui: { screenshot(name?: string): Promise<string> }, state: string) {
const source = await ui.screenshot(`${slug}-${mode}-${state}`)
await Bun.write(path.join(output, `${slug}-${mode}-${state}.png`), Bun.file(source))
}
function required(name: string) {
const value = process.env[name]
if (!value) throw new Error(`${name} is required`)
return value
}