From 0cb7fcc49a22656eb9bf34a54b7567f2f6142873 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 14 Aug 2026 14:14:03 -0400 Subject: [PATCH] chore(tui): remove turn flash scaffolding --- packages/tui/AGENTS.md | 2 +- .../system/storybook/index.tsx | 3 +- .../system/storybook/turn-summary.tsx | 145 ------------------ .../test/component/assistant-summary.test.tsx | 68 -------- 4 files changed, 2 insertions(+), 216 deletions(-) delete mode 100644 packages/tui/src/feature-plugins/system/storybook/turn-summary.tsx delete mode 100644 packages/tui/test/component/assistant-summary.test.tsx diff --git a/packages/tui/AGENTS.md b/packages/tui/AGENTS.md index 4e8fe056230..d3887bde3f0 100644 --- a/packages/tui/AGENTS.md +++ b/packages/tui/AGENTS.md @@ -4,6 +4,6 @@ - Put the current treatment and meaningfully different variants in the story. Expose replay and tuning controls in `StoryFooter`, including reset when values are adjustable. - Let the user choose or tune a variant in the story before selecting production defaults. - After selection, register the behavior in `src/component/dialog-experiments.tsx` and gate it with `config.data.experimental?. === true`; experiments must not change default behavior. -- Keep the story as the safe tuning and regression fixture for the experiment. +- Treat tuning-only stories as local scaffolding and remove them and their registration before committing. Commit a story only when the user explicitly wants it retained as a reusable regression fixture. - Use OpenCode Drive with a simulated LLM for deterministic turn/session behavior. Do not invoke a real model only to verify TUI behavior. - Run the story with `OPENCODE_STORY= bun run dev:live` and exercise relevant wide and narrow terminal sizes. diff --git a/packages/tui/src/feature-plugins/system/storybook/index.tsx b/packages/tui/src/feature-plugins/system/storybook/index.tsx index d04a3c819b5..f6c38ecfc48 100644 --- a/packages/tui/src/feature-plugins/system/storybook/index.tsx +++ b/packages/tui/src/feature-plugins/system/storybook/index.tsx @@ -4,7 +4,6 @@ import { createSignal, For, type JSX } from "solid-js" import { StoryFooter } from "./footer" import { sessionTabsStory } from "./session-tabs" import { sessionLocationMissingStory } from "./session-location-missing" -import { turnSummaryStory } from "./turn-summary" /** * A story is a full-screen, fixture-driven simulation of a real production component. Stories own @@ -16,7 +15,7 @@ export type Story = { render: (context: Plugin.Context) => JSX.Element } -const stories: Story[] = [sessionTabsStory, turnSummaryStory, sessionLocationMissingStory] +const stories: Story[] = [sessionTabsStory, sessionLocationMissingStory] function Commands(props: { context: Plugin.Context }) { props.context.keymap.layer(() => ({ diff --git a/packages/tui/src/feature-plugins/system/storybook/turn-summary.tsx b/packages/tui/src/feature-plugins/system/storybook/turn-summary.tsx deleted file mode 100644 index 52170d02aff..00000000000 --- a/packages/tui/src/feature-plugins/system/storybook/turn-summary.tsx +++ /dev/null @@ -1,145 +0,0 @@ -import { Plugin } from "@opencode-ai/plugin/tui" -import { useTerminalDimensions } from "@opentui/solid" -import { createSignal, For } from "solid-js" -import { createStore } from "solid-js/store" -import { AssistantSummary } from "../../../component/assistant-summary" -import { useLocal } from "../../../context/local" -import { StoryFooter } from "./footer" -import type { Story } from "./index" - -const PRESETS = [ - { name: "Snap", duration: 0.18, intensity: 0.9 }, - { name: "Current", duration: 0.32, intensity: 0.75 }, - { name: "Gentle", duration: 0.5, intensity: 0.6 }, - { name: "Lingering", duration: 0.8, intensity: 0.7 }, -] - -function TurnSummaryStory(props: { context: Plugin.Context }) { - const dimensions = useTerminalDimensions() - const theme = props.context.theme - const local = useLocal() - const [presets, setPresets] = createStore(PRESETS.map((preset) => ({ ...preset, trigger: 0 }))) - const [selected, setSelected] = createSignal(1) - const [lastEvent, setLastEvent] = createSignal("press space to compare all four") - - const replay = (index?: number) => { - if (index === undefined) { - presets.forEach((_, presetIndex) => setPresets(presetIndex, "trigger", (trigger) => trigger + 1)) - setLastEvent("replayed all variants") - return - } - setPresets(index, "trigger", (trigger) => trigger + 1) - setLastEvent(`replayed ${presets[index]!.name.toLowerCase()}`) - } - const adjustDuration = (delta: number) => { - const index = selected() - setPresets(index, "duration", (duration) => Math.max(0.05, Math.round((duration + delta) * 100) / 100)) - replay(index) - } - const adjustIntensity = (delta: number) => { - const index = selected() - setPresets(index, "intensity", (intensity) => Math.max(0.1, Math.min(1, intensity + delta))) - replay(index) - } - const reset = () => { - PRESETS.forEach((preset, index) => setPresets(index, { ...preset, trigger: presets[index]!.trigger + 1 })) - setSelected(1) - setLastEvent("reset presets and replayed all variants") - } - - props.context.keymap.layer(() => ({ - commands: [ - { - bind: "escape", - title: "Back to storybook", - group: "Storybook", - run: () => props.context.ui.router.navigate({ type: "plugin", name: "storybook" }), - }, - { bind: "space", title: "Replay all variants", group: "Storybook", run: () => replay() }, - ...PRESETS.map((preset, index) => ({ - bind: String(index + 1), - title: `Replay ${preset.name}`, - group: "Storybook", - run: () => { - setSelected(index) - replay(index) - }, - })), - { - bind: "up,k", - title: "Select previous variant", - group: "Storybook", - run: () => setSelected((index) => (index + presets.length - 1) % presets.length), - }, - { - bind: "down,j", - title: "Select next variant", - group: "Storybook", - run: () => setSelected((index) => (index + 1) % presets.length), - }, - { bind: "left,h", title: "Shorten fade", group: "Storybook", run: () => adjustDuration(-0.05) }, - { bind: "right,l", title: "Lengthen fade", group: "Storybook", run: () => adjustDuration(0.05) }, - { bind: "-", title: "Dim flash", group: "Storybook", run: () => adjustIntensity(-0.05) }, - { bind: "+,=", title: "Brighten flash", group: "Storybook", run: () => adjustIntensity(0.05) }, - { bind: "r", title: "Reset variants", group: "Storybook", run: reset }, - ], - })) - - return ( - - - turn summary flash - compare the production completion treatment across timing presets - - - {(preset, index) => ( - - - {index() === selected() ? "›" : " "} {index() + 1} {preset.name.padEnd(10)} {preset.duration.toFixed(2)}s - {" "}{Math.round(preset.intensity * 100)}% - - - - - - )} - - - - - ) -} - -export const turnSummaryStory: Story = { - id: "turn-summary", - title: "Turn summary flash", - render: (context) => , -} diff --git a/packages/tui/test/component/assistant-summary.test.tsx b/packages/tui/test/component/assistant-summary.test.tsx deleted file mode 100644 index 98e75c88ad2..00000000000 --- a/packages/tui/test/component/assistant-summary.test.tsx +++ /dev/null @@ -1,68 +0,0 @@ -/** @jsxImportSource @opentui/solid */ -import { RGBA } from "@opentui/core" -import { testRender } from "@opentui/solid" -import { expect, test } from "bun:test" -import { AssistantSummary } from "../../src/component/assistant-summary" - -const agent = RGBA.fromHex("#6699ff") -const subdued = RGBA.fromHex("#667085") -const text = RGBA.fromHex("#f0f2ff") - -test("flashes a completed summary and settles to its semantic colors", async () => { - const app = await testRender( - () => ( - - ), - { width: 60, height: 1 }, - ) - - try { - await app.renderOnce() - const flashed = app.renderer.currentRenderBuffer.getSpanLines()[0]!.spans.filter((span) => span.text.trim()) - expect(flashed[0]!.fg.equals(agent)).toBeFalse() - expect(flashed[1]!.fg.equals(subdued)).toBeFalse() - - await Bun.sleep(900) - await app.renderOnce() - const settled = app.renderer.currentRenderBuffer.getSpanLines()[0]!.spans.filter((span) => span.text.trim()) - expect(settled[0]!.fg.equals(agent)).toBeTrue() - expect(settled[1]!.fg.equals(subdued)).toBeTrue() - } finally { - app.renderer.destroy() - } -}) - -test("stays at rest when animations are disabled", async () => { - const app = await testRender( - () => ( - - ), - { width: 60, height: 1 }, - ) - - try { - await app.renderOnce() - const spans = app.renderer.currentRenderBuffer.getSpanLines()[0]!.spans.filter((span) => span.text.trim()) - expect(spans[0]!.fg.equals(agent)).toBeTrue() - expect(spans[1]!.fg.equals(subdued)).toBeTrue() - } finally { - app.renderer.destroy() - } -})