summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDax <[email protected]>2026-03-28 01:46:29 -0400
committerGitHub <[email protected]>2026-03-28 01:46:29 -0400
commitc3a9ec4a99f2636ec032091dd4b18b13ff3e25f3 (patch)
treeb7ff0143866e93012ead2e36baa496119b71afed
parent41b0d03f6afabc30696e9ccbbdbb7c3df34fd404 (diff)
downloadopencode-c3a9ec4a99f2636ec032091dd4b18b13ff3e25f3.tar.gz
opencode-c3a9ec4a99f2636ec032091dd4b18b13ff3e25f3.zip
fix: restore subagent footer and fix style guide violations (#19491)
-rw-r--r--packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx4
-rw-r--r--packages/opencode/src/cli/cmd/tui/component/dialog-variant.tsx1
-rw-r--r--packages/opencode/src/cli/cmd/tui/routes/session/index.tsx5
-rw-r--r--packages/opencode/src/cli/cmd/tui/routes/session/subagent-footer.tsx109
4 files changed, 115 insertions, 4 deletions
diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx
index a06e7e070..ee9fa225e 100644
--- a/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx
@@ -138,9 +138,9 @@ export function DialogModel(props: { providerID?: string }) {
local.model.set({ providerID, modelID }, { recent: true })
if (local.model.variant.list().length > 0) {
dialog.replace(() => <DialogVariant />)
- } else {
- dialog.clear()
+ return
}
+ dialog.clear()
}
return (
diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-variant.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-variant.tsx
index 8d06ab641..fd895e0cf 100644
--- a/packages/opencode/src/cli/cmd/tui/component/dialog-variant.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/dialog-variant.tsx
@@ -1,6 +1,5 @@
import { createMemo } from "solid-js"
import { useLocal } from "@tui/context/local"
-import { useSync } from "@tui/context/sync"
import { DialogSelect } from "@tui/ui/dialog-select"
import { useDialog } from "@tui/ui/dialog"
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 1baa2e997..2f84f9d7b 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
@@ -61,6 +61,7 @@ import { DialogTimeline } from "./dialog-timeline"
import { DialogForkFromTimeline } from "./dialog-fork-from-timeline"
import { DialogSessionRename } from "../../component/dialog-session-rename"
import { Sidebar } from "./sidebar"
+import { SubagentFooter } from "./subagent-footer.tsx"
import { Flag } from "@/flag/flag"
import { LANGUAGE_EXTENSIONS } from "@/lsp/language"
import parsers from "../../../../../../parsers-config.ts"
@@ -1054,7 +1055,6 @@ export function Session() {
flexGrow={1}
scrollAcceleration={scrollAcceleration()}
>
- <box height={1} />
<For each={messages()}>
{(message, index) => (
<Switch>
@@ -1158,6 +1158,9 @@ export function Session() {
<Show when={permissions().length === 0 && questions().length > 0}>
<QuestionPrompt request={questions()[0]} />
</Show>
+ <Show when={session()?.parentID}>
+ <SubagentFooter />
+ </Show>
<Prompt
visible={!session()?.parentID && permissions().length === 0 && questions().length === 0}
ref={(r) => {
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/subagent-footer.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/subagent-footer.tsx
new file mode 100644
index 000000000..315cd1e88
--- /dev/null
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/subagent-footer.tsx
@@ -0,0 +1,109 @@
+import { createMemo, createSignal, Show } from "solid-js"
+import { useRouteData } from "@tui/context/route"
+import { useSync } from "@tui/context/sync"
+import { useTheme } from "@tui/context/theme"
+import { SplitBorder } from "@tui/component/border"
+import type { AssistantMessage } from "@opencode-ai/sdk/v2"
+import { useCommandDialog } from "@tui/component/dialog-command"
+import { useKeybind } from "../../context/keybind"
+import { Locale } from "@/util/locale"
+import { useTerminalDimensions } from "@opentui/solid"
+
+export function SubagentFooter() {
+ const route = useRouteData("session")
+ const sync = useSync()
+ const messages = createMemo(() => sync.data.message[route.sessionID] ?? [])
+
+ const usage = createMemo(() => {
+ const msg = messages()
+ const last = msg.findLast((item): item is AssistantMessage => item.role === "assistant" && item.tokens.output > 0)
+ if (!last) return
+
+ const tokens =
+ last.tokens.input + last.tokens.output + last.tokens.reasoning + last.tokens.cache.read + last.tokens.cache.write
+ if (tokens <= 0) return
+
+ const model = sync.data.provider.find((item) => item.id === last.providerID)?.models[last.modelID]
+ const pct = model?.limit.context ? `${Math.round((tokens / model.limit.context) * 100)}%` : undefined
+ const cost = msg.reduce((sum, item) => sum + (item.role === "assistant" ? item.cost : 0), 0)
+
+ const money = new Intl.NumberFormat("en-US", {
+ style: "currency",
+ currency: "USD",
+ })
+
+ return {
+ context: pct ? `${Locale.number(tokens)} (${pct})` : Locale.number(tokens),
+ cost: cost > 0 ? money.format(cost) : undefined,
+ }
+ })
+
+ const { theme } = useTheme()
+ const keybind = useKeybind()
+ const command = useCommandDialog()
+ const [hover, setHover] = createSignal<"parent" | "prev" | "next" | null>(null)
+ const dimensions = useTerminalDimensions()
+
+ return (
+ <box flexShrink={0}>
+ <box
+ paddingTop={1}
+ paddingBottom={1}
+ paddingLeft={2}
+ paddingRight={1}
+ {...SplitBorder}
+ border={["left"]}
+ borderColor={theme.border}
+ flexShrink={0}
+ backgroundColor={theme.backgroundPanel}
+ >
+ <box flexDirection="row" justifyContent="space-between" gap={1}>
+ <box flexDirection="row" gap={2}>
+ <text fg={theme.text}>
+ <b>Subagent session</b>
+ </text>
+ <Show when={usage()}>
+ {(item) => (
+ <text fg={theme.textMuted} wrapMode="none">
+ {[item().context, item().cost].filter(Boolean).join(" ยท ")}
+ </text>
+ )}
+ </Show>
+ </box>
+ <box flexDirection="row" gap={2}>
+ <box
+ onMouseOver={() => setHover("parent")}
+ onMouseOut={() => setHover(null)}
+ onMouseUp={() => command.trigger("session.parent")}
+ backgroundColor={hover() === "parent" ? theme.backgroundElement : theme.backgroundPanel}
+ >
+ <text fg={theme.text}>
+ Parent <span style={{ fg: theme.textMuted }}>{keybind.print("session_parent")}</span>
+ </text>
+ </box>
+ <box
+ onMouseOver={() => setHover("prev")}
+ onMouseOut={() => setHover(null)}
+ onMouseUp={() => command.trigger("session.child.previous")}
+ backgroundColor={hover() === "prev" ? theme.backgroundElement : theme.backgroundPanel}
+ >
+ <text fg={theme.text}>
+ Prev <span style={{ fg: theme.textMuted }}>{keybind.print("session_child_cycle_reverse")}</span>
+ </text>
+ </box>
+ <box
+ onMouseOver={() => setHover("next")}
+ onMouseOut={() => setHover(null)}
+ onMouseUp={() => command.trigger("session.child.next")}
+ backgroundColor={hover() === "next" ? theme.backgroundElement : theme.backgroundPanel}
+ >
+ <text fg={theme.text}>
+ Next <span style={{ fg: theme.textMuted }}>{keybind.print("session_child_cycle")}</span>
+ </text>
+ </box>
+ </box>
+ </box>
+ </box>
+ </box>
+ )
+}