Problem/Context
During upstream merges, the TUI spinner customizations became inconsistent across the application. While the configurable spinner system exists and works for some components (bash tool, sidebar, session loading), it's not being used in two key places:
- Prompt loading indicator (
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx:1268) - Uses a hardcoded Knight Rider style spinner from ui/spinner.ts instead of the user-configurable spinner
- Session list dialog (
packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx:28,52) - Uses hardcoded braille frames ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] instead of the user's selected spinner
This means users who customize their spinner style via the "Change spinner style" command (spinner.style) or interval (spinner.interval) won't see their preferences reflected consistently.
Current State
Configurable Spinner System (Working)
- Location:
packages/opencode/src/cli/cmd/tui/util/spinners.ts
- Used by:
- Bash tool output (
session/index.tsx:2245)
- Session loading indicator (
session/index.tsx:1422)
- Sidebar active session indicator (
sidebar.tsx:217)
- ToolTitle component (
session/index.tsx:2167)
- Features:
- 60+ spinner styles (braille, blocks, emoji, etc.)
- Configurable interval (20ms-500ms)
- Persisted via KV store
Not Using Configurable System
| Location |
Current Implementation |
Issue |
prompt/index.tsx:1268 |
<spinner ... frames={spinnerDef().frames}> |
Uses Knight Rider createFrames() from ui/spinner.ts |
dialog-session-list.tsx:28 |
Hardcoded ["⠋", "⠙", ...] array |
Never reads user preference |
Acceptance Criteria
Implementation Details
Option A: Integrate getSpinnerFrame() everywhere (Simpler)
Replace hardcoded spinners with the reactive getSpinnerFrame() function:
// In prompt/index.tsx - replace spinnerDef() usage with:
import { getSpinnerFrame } from "../../util/spinners"
// ...
<text fg={spinnerColor}>{getSpinnerFrame()}</text>
// In dialog-session-list.tsx - replace hardcoded frames:
import { getSpinnerFrame } from "../../util/spinners"
// Remove: const spinnerFrames = ["⠋", "⠙", ...]
// Use: {getSpinnerFrame()}
Option B: Add Knight Rider to configurable options (More Complete)
Add the Knight Rider style as an option in util/spinners.ts alongside the existing braille/block spinners. This would require:
- Converting the
createFrames() output to a static frame array
- Adding it to the
SPINNERS record
Files to Modify
-
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
- Lines 942-960:
spinnerDef memo
- Line 1268:
<spinner> usage
-
packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx
- Line 28: Remove hardcoded
spinnerFrames
- Line 52: Use
getSpinnerFrame() instead
Reference: Existing Pattern
The sidebar already demonstrates the correct pattern:
// packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx:12,217
import { getSpinnerFrame } from "../../util/spinners"
// ...
{isActive() ? getSpinnerFrame() : isError() ? "✗" : "✓"}
Tasks
External References
- cli-spinners - Standard CLI spinner library with similar frame-based approach
- ora - Popular Node.js spinner with configurable frames/interval
Problem/Context
During upstream merges, the TUI spinner customizations became inconsistent across the application. While the configurable spinner system exists and works for some components (bash tool, sidebar, session loading), it's not being used in two key places:
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx:1268) - Uses a hardcoded Knight Rider style spinner fromui/spinner.tsinstead of the user-configurable spinnerpackages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx:28,52) - Uses hardcoded braille frames["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]instead of the user's selected spinnerThis means users who customize their spinner style via the "Change spinner style" command (
spinner.style) or interval (spinner.interval) won't see their preferences reflected consistently.Current State
Configurable Spinner System (Working)
packages/opencode/src/cli/cmd/tui/util/spinners.tssession/index.tsx:2245)session/index.tsx:1422)sidebar.tsx:217)session/index.tsx:2167)Not Using Configurable System
prompt/index.tsx:1268<spinner ... frames={spinnerDef().frames}>createFrames()fromui/spinner.tsdialog-session-list.tsx:28["⠋", "⠙", ...]arrayAcceptance Criteria
Implementation Details
Option A: Integrate
getSpinnerFrame()everywhere (Simpler)Replace hardcoded spinners with the reactive
getSpinnerFrame()function:Option B: Add Knight Rider to configurable options (More Complete)
Add the Knight Rider style as an option in
util/spinners.tsalongside the existing braille/block spinners. This would require:createFrames()output to a static frame arraySPINNERSrecordFiles to Modify
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsxspinnerDefmemo<spinner>usagepackages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsxspinnerFramesgetSpinnerFrame()insteadReference: Existing Pattern
The sidebar already demonstrates the correct pattern:
Tasks
prompt/index.tsxto usegetSpinnerFrame()for the loading spinnerdialog-session-list.tsxto usegetSpinnerFrame()for session listExternal References