Skip to content

Commit 654e38d

Browse files
kitlangtonleohenon
authored andcommitted
tui: fix agent cycling and prompt metadata polish (anomalyco#23115)
1 parent a1ca922 commit 654e38d

4 files changed

Lines changed: 24 additions & 12 deletions

File tree

packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ function init() {
6363
useKeyboard((evt) => {
6464
if (suspended()) return
6565
if (dialog.stack.length > 0) return
66+
if (evt.defaultPrevented) return
6667
for (const option of entries()) {
6768
if (!isEnabled(option)) continue
6869
if (option.keybind && keybind.match(option.keybind, evt)) {

packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import path from "path"
2626
import { fileURLToPath } from "url"
2727
import { Filesystem } from "@/util"
2828
import { useLocal } from "@tui/context/local"
29-
import { useTheme } from "@tui/context/theme"
29+
import { tint, useTheme } from "@tui/context/theme"
3030
import { EmptyBorder, SplitBorder } from "@tui/component/border"
3131
import { useSDK } from "@tui/context/sdk"
3232
import { useRoute } from "@tui/context/route"
@@ -804,20 +804,26 @@ export function Prompt(props: PromptProps) {
804804
createEffect(() => {
805805
if (!input || input.isDestroyed) return
806806
if (props.visible === false || dialog.stack.length > 0) {
807-
input.blur()
807+
if (input.focused) input.blur()
808808
vimState.clearPending()
809809
return
810810
}
811811

812812
// Slot/plugin updates can remount the background prompt while a dialog is open.
813813
// Keep focus with the dialog and let the prompt reclaim it after the dialog closes.
814-
input.focus()
814+
if (!input.focused) input.focus()
815815
})
816816

817817
createEffect(() => {
818818
if (!input || input.isDestroyed) return
819+
const capture =
820+
store.mode === "normal"
821+
? auto()?.visible
822+
? (["escape", "navigate", "submit", "tab"] as const)
823+
: (["tab"] as const)
824+
: undefined
819825
input.traits = {
820-
capture: auto()?.visible ? ["escape", "navigate", "submit", "tab"] : undefined,
826+
capture,
821827
suspend: !!props.disabled || store.mode === "shell",
822828
status: store.mode === "shell" ? "SHELL" : undefined,
823829
}
@@ -1239,6 +1245,7 @@ export function Prompt(props: PromptProps) {
12391245
() => !!local.agent.current() && store.mode === "normal" && showVariant(),
12401246
animationsEnabled,
12411247
)
1248+
const borderHighlight = createMemo(() => tint(theme.border, highlight(), agentMetaAlpha()))
12421249

12431250
const placeholderText = createMemo(() => {
12441251
if (props.showPlaceholder === false) return undefined
@@ -1302,7 +1309,7 @@ export function Prompt(props: PromptProps) {
13021309
<box ref={(r) => (anchor = r)} visible={props.visible !== false}>
13031310
<box
13041311
border={["left"]}
1305-
borderColor={highlight()}
1312+
borderColor={borderHighlight()}
13061313
customBorderChars={{
13071314
...SplitBorder.customBorderChars,
13081315
bottomLeft: "╹",
@@ -1582,11 +1589,10 @@ export function Prompt(props: PromptProps) {
15821589
<Show when={local.agent.current()} fallback={<box height={1} />}>
15831590
{(agent) => (
15841591
<>
1585-
<text fg={fadeColor(highlight(), agentMetaAlpha())}>
1586-
{store.mode === "shell" ? "Shell" : Locale.titlecase(agent().name)}{" "}
1587-
</text>
1592+
<text fg={fadeColor(highlight(), agentMetaAlpha())}>{store.mode === "shell" ? "Shell" : Locale.titlecase(agent().name)}</text>
15881593
<Show when={store.mode === "normal"}>
15891594
<box flexDirection="row" gap={1}>
1595+
<text fg={fadeColor(theme.textMuted, modelMetaAlpha())}>·</text>
15901596
<text
15911597
flexShrink={0}
15921598
fg={fadeColor(dimmed() ? theme.textMuted : theme.text, modelMetaAlpha())}
@@ -1630,7 +1636,7 @@ export function Prompt(props: PromptProps) {
16301636
<box
16311637
height={1}
16321638
border={["left"]}
1633-
borderColor={highlight()}
1639+
borderColor={borderHighlight()}
16341640
customBorderChars={{
16351641
...EmptyBorder,
16361642
vertical: theme.backgroundElement.a !== 0 ? "╹" : " ",

packages/opencode/src/cli/cmd/tui/context/local.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
7575
},
7676
move(direction: 1 | -1) {
7777
batch(() => {
78-
let next = agents().findIndex((x) => x.name === agentStore.current) + direction
78+
const current = this.current()
79+
if (!current) return
80+
let next = agents().findIndex((x) => x.name === current.name) + direction
7981
if (next < 0) next = agents().length - 1
8082
if (next >= agents().length) next = 0
8183
const value = agents()[next]

packages/opencode/src/cli/cmd/tui/util/signal.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,23 @@ export function createDebouncedSignal<T>(value: T, ms: number): [Accessor<T>, Sc
88

99
export function createFadeIn(show: Accessor<boolean>, enabled: Accessor<boolean>) {
1010
const [alpha, setAlpha] = createSignal(show() ? 1 : 0)
11+
let revealed = show()
1112

1213
createEffect(
13-
on([show, enabled], ([visible, animate], previous) => {
14+
on([show, enabled], ([visible, animate]) => {
1415
if (!visible) {
1516
setAlpha(0)
1617
return
1718
}
1819

19-
if (!animate || !previous) {
20+
if (!animate || revealed) {
21+
revealed = true
2022
setAlpha(1)
2123
return
2224
}
2325

2426
const start = performance.now()
27+
revealed = true
2528
setAlpha(0)
2629

2730
const timer = setInterval(() => {

0 commit comments

Comments
 (0)