From 97a7b9adc2ef30cca3f0173cb5a34239998f98fd Mon Sep 17 00:00:00 2001 From: Justin Levine <20596508+justinlevinedotme@users.noreply.github.com> Date: Sat, 24 Jan 2026 19:16:27 -0800 Subject: [PATCH 1/2] tui: add static busy indicator option for accessibility Allow neurodivergent users to replace distracting spinner animations with a static "[currently busy]" text indicator. This ensures the terminal interface remains accessible and focused for users who find motion distracting. --- .../cli/cmd/tui/component/prompt/index.tsx | 7 +- .../src/cli/cmd/tui/routes/session/index.tsx | 10 +++ plan-10244.md | 75 +++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 plan-10244.md diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index e19c8b70982..59991b23ba8 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -1001,7 +1001,12 @@ export function Prompt(props: PromptProps) { [⋯]}> - + } + > + [currently busy] + diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 1294ab849e9..246771080c0 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -147,6 +147,7 @@ export function Session() { const [showScrollbar, setShowScrollbar] = kv.signal("scrollbar_visible", false) const [diffWrapMode, setDiffWrapMode] = createSignal<"word" | "none">("word") const [animationsEnabled, setAnimationsEnabled] = kv.signal("animations_enabled", true) + const [busyIndicatorStyle, setBusyIndicatorStyle] = kv.signal<"dynamic" | "static">("busy_indicator_style", "dynamic") const wide = createMemo(() => dimensions().width > 120) const sidebarVisible = createMemo(() => { @@ -579,6 +580,15 @@ export function Session() { dialog.clear() }, }, + { + title: busyIndicatorStyle() === "dynamic" ? "Use static busy indicator" : "Use dynamic busy indicator", + value: "session.toggle.busy_style", + category: "Session", + onSelect: (dialog) => { + setBusyIndicatorStyle((prev) => (prev === "dynamic" ? "static" : "dynamic")) + dialog.clear() + }, + }, { title: "Page up", value: "session.page.up", diff --git a/plan-10244.md b/plan-10244.md new file mode 100644 index 00000000000..b76dbad54ff --- /dev/null +++ b/plan-10244.md @@ -0,0 +1,75 @@ +# Implementation Plan: On-the-Spectrum Friendly Busy Indicator + +## Issue + +GitHub Issue #10244: Request for a non-distracting "busy" indicator for neurodivergent accessibility. + +## Goal + +Implement a user-configurable "busy" indicator in the TUI that supports a static, non-distracting display mode (`[currently busy]`) as an alternative to the dynamic spinner animation. + +## Architecture + +- **Settings Store**: Use the existing `kv` (Key-Value) store in the TUI context to persist the user's preference for the busy indicator style. +- **UI Components**: + - Update `Prompt` component to toggle between the dynamic spinner and the static text based on the setting. + - Update the session settings menu to include a toggle for the busy indicator style. +- **Styling**: Use theme-consistent colors (blue/primary) for the static indicator to maintain high visibility without distracting movement. + +## Technology Choices + +| Choice | Rationale | Tradeoffs | +| ------------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- | +| `kv` store | Existing mechanism for TUI-specific persistent settings (like `animations_enabled`). | TUI-only; doesn't affect the core `opencode.json` unless explicitly synced. | +| Static `[currently busy]` | Specifically requested by the user for accessibility. | Takes up slightly more horizontal space than the 3-dot spinner. | +| Toggle in Session Menu | Consistent with how other UI features (animations, timestamps) are controlled. | Adds one more item to the command list/settings menu. | + +## Phases + +### Phase 1: Configuration & Settings + +1. **Define Setting**: Add `busy_indicator_style` to the `kv` store with values `"dynamic"` (default) or `"static"`. +2. **Settings UI**: Update `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx` to include a new command/toggle in the `command.register` block: + - Title: "Switch to static busy indicator" / "Switch to dynamic busy indicator" + - Value: `session.toggle.busy_style` + - Action: Toggle `busy_indicator_style` between `"static"` and `"dynamic"`. +3. **Verification**: Confirm the setting persists across TUI restarts. + +### Phase 2: UI Implementation + +1. **Update Prompt Component**: Modify `packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx`: + - Retrieve `busy_indicator_style` using `kv.get("busy_indicator_style", "dynamic")`. + - Update the busy indicator rendering logic (around line 1003): + - If `animations_enabled` is `false`, keep the existing fallback `[⋯]`. + - If `animations_enabled` is `true` AND `busy_indicator_style` is `"static"`, show `[currently busy]`. + - If `animations_enabled` is `true` AND `busy_indicator_style` is `"dynamic"`, show the existing ``. +2. **Verification**: Build the project and verify the different states of the busy indicator. + +### Phase 3: Final Polishing & SDK + +1. **SDK Check**: Determine if this setting should be promoted to the global `Config.Info`. + - _Current assessment: TUI-specific, so keeping it in `kv` is minimal and sufficient._ +2. **Re-generate SDK**: If any types were moved to shared packages, run `./packages/sdk/js/script/build.ts`. + - _Unlikely to be needed since this is TUI-specific._ +3. **Enterprise Tests**: Ignore as per instructions. + +## Risks & Mitigations + +| Risk | Mitigation | +| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| Horizontal space overflow | Use a concise label like `[busy]` if `[currently busy]` is too long for small terminals, but start with the requested label. | +| Interaction with `animations_enabled` | Ensure `animations_enabled: false` always takes precedence for a truly minimal UI, but allow `static` mode when animations are otherwise enabled. | + +## Files to Modify + +1. `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx` - Add settings toggle +2. `packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx` - Update busy indicator rendering logic + +## Testing Checklist + +- [ ] Setting persists across TUI restarts +- [ ] Dynamic mode shows spinner when `animations_enabled` is true +- [ ] Static mode shows `[currently busy]` text in blue when `animations_enabled` is true +- [ ] When `animations_enabled` is false, shows `[⋯]` regardless of `busy_indicator_style` +- [ ] Build succeeds +- [ ] All non-enterprise tests pass From 2870a6b5c5323d53a2198432ff30c74fea3ab9d4 Mon Sep 17 00:00:00 2001 From: Justin Levine <20596508+justinlevinedotme@users.noreply.github.com> Date: Sat, 24 Jan 2026 19:26:27 -0800 Subject: [PATCH 2/2] chore: remove plan file --- plan-10244.md | 75 --------------------------------------------------- 1 file changed, 75 deletions(-) delete mode 100644 plan-10244.md diff --git a/plan-10244.md b/plan-10244.md deleted file mode 100644 index b76dbad54ff..00000000000 --- a/plan-10244.md +++ /dev/null @@ -1,75 +0,0 @@ -# Implementation Plan: On-the-Spectrum Friendly Busy Indicator - -## Issue - -GitHub Issue #10244: Request for a non-distracting "busy" indicator for neurodivergent accessibility. - -## Goal - -Implement a user-configurable "busy" indicator in the TUI that supports a static, non-distracting display mode (`[currently busy]`) as an alternative to the dynamic spinner animation. - -## Architecture - -- **Settings Store**: Use the existing `kv` (Key-Value) store in the TUI context to persist the user's preference for the busy indicator style. -- **UI Components**: - - Update `Prompt` component to toggle between the dynamic spinner and the static text based on the setting. - - Update the session settings menu to include a toggle for the busy indicator style. -- **Styling**: Use theme-consistent colors (blue/primary) for the static indicator to maintain high visibility without distracting movement. - -## Technology Choices - -| Choice | Rationale | Tradeoffs | -| ------------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- | -| `kv` store | Existing mechanism for TUI-specific persistent settings (like `animations_enabled`). | TUI-only; doesn't affect the core `opencode.json` unless explicitly synced. | -| Static `[currently busy]` | Specifically requested by the user for accessibility. | Takes up slightly more horizontal space than the 3-dot spinner. | -| Toggle in Session Menu | Consistent with how other UI features (animations, timestamps) are controlled. | Adds one more item to the command list/settings menu. | - -## Phases - -### Phase 1: Configuration & Settings - -1. **Define Setting**: Add `busy_indicator_style` to the `kv` store with values `"dynamic"` (default) or `"static"`. -2. **Settings UI**: Update `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx` to include a new command/toggle in the `command.register` block: - - Title: "Switch to static busy indicator" / "Switch to dynamic busy indicator" - - Value: `session.toggle.busy_style` - - Action: Toggle `busy_indicator_style` between `"static"` and `"dynamic"`. -3. **Verification**: Confirm the setting persists across TUI restarts. - -### Phase 2: UI Implementation - -1. **Update Prompt Component**: Modify `packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx`: - - Retrieve `busy_indicator_style` using `kv.get("busy_indicator_style", "dynamic")`. - - Update the busy indicator rendering logic (around line 1003): - - If `animations_enabled` is `false`, keep the existing fallback `[⋯]`. - - If `animations_enabled` is `true` AND `busy_indicator_style` is `"static"`, show `[currently busy]`. - - If `animations_enabled` is `true` AND `busy_indicator_style` is `"dynamic"`, show the existing ``. -2. **Verification**: Build the project and verify the different states of the busy indicator. - -### Phase 3: Final Polishing & SDK - -1. **SDK Check**: Determine if this setting should be promoted to the global `Config.Info`. - - _Current assessment: TUI-specific, so keeping it in `kv` is minimal and sufficient._ -2. **Re-generate SDK**: If any types were moved to shared packages, run `./packages/sdk/js/script/build.ts`. - - _Unlikely to be needed since this is TUI-specific._ -3. **Enterprise Tests**: Ignore as per instructions. - -## Risks & Mitigations - -| Risk | Mitigation | -| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| Horizontal space overflow | Use a concise label like `[busy]` if `[currently busy]` is too long for small terminals, but start with the requested label. | -| Interaction with `animations_enabled` | Ensure `animations_enabled: false` always takes precedence for a truly minimal UI, but allow `static` mode when animations are otherwise enabled. | - -## Files to Modify - -1. `packages/opencode/src/cli/cmd/tui/routes/session/index.tsx` - Add settings toggle -2. `packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx` - Update busy indicator rendering logic - -## Testing Checklist - -- [ ] Setting persists across TUI restarts -- [ ] Dynamic mode shows spinner when `animations_enabled` is true -- [ ] Static mode shows `[currently busy]` text in blue when `animations_enabled` is true -- [ ] When `animations_enabled` is false, shows `[⋯]` regardless of `busy_indicator_style` -- [ ] Build succeeds -- [ ] All non-enterprise tests pass