Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ file is the human-readable summary of what changed and why.

## Unreleased

### TUI

- **Bouncing-bar footer spinner** — the busy indicator in the prompt footer
(and the `codev run` footer) changed from the dotted scanner bar to
[cli-spinners](https://github.com/sindresorhus/cli-spinners)' `bouncingBar`
animation (`[== ]`). It keeps the agent's accent color in the TUI and
the theme highlight in `codev run`; the reduced-motion `[⋯]` fallback is
unchanged.

## 1.18.3-1

### Sessions
Expand Down
1 change: 1 addition & 0 deletions DIVERGENCES.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ from the squash message first, or use a plain merge.
| `packages/app/src/context/language.tsx`, `packages/app/src/entry.tsx`, `packages/desktop/src/renderer/i18n/index.ts`, `packages/console/app/src/i18n/index.ts`, `packages/console/app/src/lib/language.ts`, `packages/console/app/src/component/footer.tsx`, `packages/stats/app/src/i18n.ts`, `packages/enterprise/src/app.tsx`, `packages/app/e2e/regression/session-timeline-locale-projection.spec.ts` | Locale registries trimmed to `en` + `es`: `Locale` types, LOCALES/LABEL/TAG/DOCS maps, dict loaders, accept-language matchers; enterprise/entry `zh` special cases now use `es`; console footer always links Discord (Feishu was zh-only); e2e locale-projection spec tests `es` ("Explorado") instead of de/ar | Fork ships English + Spanish only. | Keep our trimmed lists; take upstream's structural changes and re-trim any new locale entries. |
| `packages/tui/src/component/prompt/autocomplete.tsx`, `packages/app/src/components/prompt-input.tsx`, `packages/opencode/src/cli/cmd/run/footer.prompt.tsx`, `packages/core/src/filesystem/search.ts`, `packages/tui/test/fixture/tui-sdk.ts`, `packages/opencode/test/cli/run/footer.view.test.tsx`, `packages/core/test/filesystem/search.test.ts` | `@` mention autocomplete lists file/directory results before references/agents/MCP resources; TUI and run-CLI menus cap the leading files so up to 3 non-file matches stay in the first visible page; web app group rank reordered to recent → file → reference → agent → resource (extracted into fork-only `prompt-input/at-options.ts`). TUI and run-CLI file resources track menu visibility so opening on an empty query fetches (previously nothing refetched until the query changed); core's ripgrep-fallback `find` returns its first entries for an empty query to mirror fff. Tests: tui-sdk fixture's `FetchHandler` gains an optional `method` arg, `renderFooter` accepts `findFiles`/`agents` overrides + a mention-menu ordering test, core search tests cover the fallback's empty query (fork-only test files: `packages/tui/test/prompt-autocomplete.test.tsx`, `packages/app/test-browser/prompt-at-options.test.ts`, `packages/app/src/components/prompt-input/at-options{,.test}.ts`) | Files are the dominant `@` use case; they should rank first and appear on a bare `@`. | Keep our ordering/reserve logic, resource source tracking, empty-query branch, fixture/test additions; take upstream's surrounding changes. |
| `packages/slack/.gitignore`, `sdks/vscode/.gitignore` | Added the missing trailing newline (content unchanged) | Upstream's copies end without a newline; POSIX text files should end with one, and tools that concatenate or append to these files misbehave without it. | Whitespace-only: keep the trailing newline; take upstream's entries. |
| `packages/tui/src/component/prompt/index.tsx`, `packages/opencode/src/cli/cmd/run/footer.view.tsx` | Busy footer spinner: the procedural Knight-Rider scanner bar (`createFrames`/`createColors` from `ui/spinner.ts`, `style: "blocks"`, `interval={40}`) is replaced by cli-spinners' `bouncingBar` preset via opentui-spinner's `name` prop (`<spinner name="bouncingBar">`; the preset supplies frames + 80ms interval). prompt/index.tsx keeps the agent-color logic in a `spinnerColor` memo (was inside `spinnerDef`); footer.view.tsx passes `theme().highlight` directly. Both `createFrames`/`createColors` imports are dropped; `ui/spinner.ts` itself is untouched (now unconsumed in the TUI/run CLI). | The footer busy indicator is the bouncingBar animation (`[== ]`) instead of the dotted scanner. | Keep the `name="bouncingBar"` renders, the `spinnerColor` memo, and the dropped imports; take upstream's surrounding changes. If upstream reworks the footer spinner, re-apply bouncingBar at the new render site. |

## Known rebrand gaps

Expand Down
19 changes: 1 addition & 18 deletions packages/opencode/src/cli/cmd/run/footer.view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import { useTerminalDimensions } from "@opentui/solid"
import { For, Match, Show, Switch, createEffect, createMemo, createSignal, onCleanup } from "solid-js"
import { registerOpencodeSpinner } from "@opencode-ai/tui/component/register-spinner"
import { createColors, createFrames } from "@opencode-ai/tui/ui/spinner"
import {
RUN_SUBAGENT_PANEL_ROWS,
RunCommandMenuBody,
Expand Down Expand Up @@ -254,22 +253,6 @@ export function RunFooterView(props: RunFooterViewProps) {
const runTheme = createMemo(() => props.theme())
const theme = createMemo(() => runTheme().footer)
const block = createMemo(() => runTheme().block)
const spin = createMemo(() => {
return {
frames: createFrames({
color: theme().highlight,
style: "blocks",
inactiveFactor: 0.6,
minAlpha: 0.3,
}),
color: createColors({
color: theme().highlight,
style: "blocks",
inactiveFactor: 0.6,
minAlpha: 0.3,
}),
}
})
const permission = createMemo<Extract<FooterView, { type: "permission" }> | undefined>(() => {
const view = active()
return view.type === "permission" ? view : undefined
Expand Down Expand Up @@ -841,7 +824,7 @@ export function RunFooterView(props: RunFooterViewProps) {
>
<Show when={busy() && !exiting()}>
<box flexShrink={0}>
<spinner color={spin().color} frames={spin().frames} interval={40} />
<spinner name="bouncingBar" color={theme().highlight} />
</box>
</Show>

Expand Down
23 changes: 3 additions & 20 deletions packages/tui/src/component/prompt/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import type { AssistantMessage, FilePart, UserMessage } from "@opencode-ai/sdk/v
import { Locale } from "../../util/locale"
import { errorMessage } from "../../util/error"
import { formatDuration } from "../../util/format"
import { createColors, createFrames } from "../../ui/spinner"
import { useDialog } from "../../ui/dialog"
import { DialogProvider as DialogProviderConnect } from "../dialog-provider"
import { useConnected } from "../use-connected"
Expand Down Expand Up @@ -1313,28 +1312,12 @@ export function Prompt(props: PromptProps) {
return `Ask anything... "${list()[store.placeholder % list().length]}"`
})

const spinnerDef = createMemo(() => {
const spinnerColor = createMemo(() => {
const agent =
status().type !== "idle"
? (local.agent.list().find((a) => a.name === lastUserMessage()?.agent) ?? local.agent.current())
: local.agent.current()
const color = agent ? local.agent.color(agent.name) : theme.border
return {
frames: createFrames({
color,
style: "blocks",
inactiveFactor: 0.6,
// enableFading: false,
minAlpha: 0.3,
}),
color: createColors({
color,
style: "blocks",
inactiveFactor: 0.6,
// enableFading: false,
minAlpha: 0.3,
}),
}
return agent ? local.agent.color(agent.name) : theme.border
})
const maxHeight = createMemo(() => tuiConfig.prompt?.max_height ?? Math.max(6, Math.floor(dimensions().height / 3)))
const moveLabelWidth = createMemo(() => Math.max(12, Math.min(44, dimensions().width - 48)))
Expand Down Expand Up @@ -1498,7 +1481,7 @@ export function Prompt(props: PromptProps) {
<box flexShrink={0} flexDirection="row" gap={1}>
<box marginLeft={1}>
<Show when={kv.get("animations_enabled", true)} fallback={<text fg={theme.textMuted}>[⋯]</text>}>
<spinner color={spinnerDef().color} frames={spinnerDef().frames} interval={40} />
<spinner name="bouncingBar" color={spinnerColor()} />
</Show>
</box>
<box flexDirection="row" gap={1} flexShrink={0}>
Expand Down
Loading