From 0a8402832e4db8cd36698c8a580613996f4e2f23 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Tue, 18 Aug 2026 23:00:30 -0400 Subject: [PATCH] fix(tui): open subagent panel from footer --- .../tui/src/feature-plugins/prompt/footer.tsx | 48 +++++++++++++++---- .../feature-plugins/prompt-footer.test.tsx | 22 ++++++++- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/packages/tui/src/feature-plugins/prompt/footer.tsx b/packages/tui/src/feature-plugins/prompt/footer.tsx index 4b2d6020b2c..d34b50c07c5 100644 --- a/packages/tui/src/feature-plugins/prompt/footer.tsx +++ b/packages/tui/src/feature-plugins/prompt/footer.tsx @@ -1,5 +1,5 @@ import { Plugin } from "@opencode-ai/plugin/tui" -import { createMemo, Match, Show, Switch } from "solid-js" +import { createMemo, createSignal, Match, Show, Switch } from "solid-js" import { contextUsage, formatContextUsage } from "../../util/session" import { useTerminalDimensions } from "@opentui/solid" @@ -10,6 +10,7 @@ const money = new Intl.NumberFormat("en-US", { export function PromptFooter(props: { context: Plugin.Context; sessionID?: string; mode: "normal" | "shell" }) { const dimensions = useTerminalDimensions() + const [liveHovered, setLiveHovered] = createSignal(false) const subagents = createMemo(() => { if (!props.sessionID) return 0 const count = props.context.data.session @@ -47,16 +48,43 @@ export function PromptFooter(props: { context: Plugin.Context; sessionID?: strin 0}> - - - {(value) => {value()} } + + + setLiveHovered(true)} + onMouseOut={() => setLiveHovered(false)} + onMouseDown={() => setLiveHovered(true)} + onMouseUp={() => props.context.keymap.dispatch("session.child.first")} + > + + {(value) => <>{value()} } + {(value) => <>{value()}} + · + {(value) => <>{value()}} + + - {(value) => {value()}} - · - {(value) => {value()}} - 0}> · - 0}>{status().join(" · ")} - + 0}> + + · + {status().join(" · ")} + + + = 44}> diff --git a/packages/tui/test/feature-plugins/prompt-footer.test.tsx b/packages/tui/test/feature-plugins/prompt-footer.test.tsx index dbb7f9da7e2..f9215fdd03a 100644 --- a/packages/tui/test/feature-plugins/prompt-footer.test.tsx +++ b/packages/tui/test/feature-plugins/prompt-footer.test.tsx @@ -1,18 +1,28 @@ /** @jsxImportSource @opentui/solid */ import { expect, test } from "bun:test" -import { RGBA } from "@opentui/core" +import { BoxRenderable, RGBA } from "@opentui/core" import { testRender } from "@opentui/solid" import type { Context } from "@opencode-ai/plugin/tui/context" import { PromptFooter } from "../../src/feature-plugins/prompt/footer" test("prompt footer separates simultaneous subagent, shell, and usage status", async () => { const color = RGBA.fromInts(200, 200, 200) + const focused = RGBA.fromInts(40, 40, 40) + const dispatched: string[] = [] const context = { location: { directory: "/workspace" }, - theme: { text: { default: color, subdued: color } }, + theme: { + text: { + default: color, + subdued: color, + action: { primary: { default: color, focused: color } }, + }, + background: { action: { primary: { default: RGBA.fromInts(0, 0, 0, 0), focused } } }, + }, keymap: { shortcuts: (id: string) => id === "session.child.first" ? ["ctrl+j"] : id === "command.palette.show" ? ["ctrl+p"] : [], + dispatch: (id: string) => dispatched.push(id), }, data: { session: { @@ -39,6 +49,14 @@ test("prompt footer separates simultaneous subagent, shell, and usage status", a await app.renderOnce() expect(app.captureCharFrame()).toContain("ctrl+j 1 subagent · 1 shell · $1.00") expect(app.captureCharFrame()).toContain("ctrl+p commands") + + await app.mockMouse.moveTo(2, 0) + const live = app.renderer.root.getChildren()[0]?.getChildren()[0] + expect(live).toBeInstanceOf(BoxRenderable) + expect((live as BoxRenderable).backgroundColor.toInts()).toEqual(focused.toInts()) + + await app.mockMouse.click(2, 0) + expect(dispatched).toEqual(["session.child.first"]) } finally { app.renderer.destroy() }