diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-status.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-status.tsx
index 3b6b5ef21827..6918400c1513 100644
--- a/packages/opencode/src/cli/cmd/tui/component/dialog-status.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/dialog-status.tsx
@@ -4,6 +4,7 @@ import { useTheme } from "../context/theme"
import { useDialog } from "@tui/ui/dialog"
import { useSync } from "@tui/context/sync"
import { For, Match, Switch, Show, createMemo } from "solid-js"
+import { useTerminalDimensions } from "@opentui/solid"
export type DialogStatusProps = {}
@@ -11,6 +12,7 @@ export function DialogStatus() {
const sync = useSync()
const { theme } = useTheme()
const dialog = useDialog()
+ const dimensions = useTerminalDimensions()
const enabledFormatters = createMemo(() => sync.data.formatter.filter((f) => f.enabled))
@@ -40,8 +42,8 @@ export function DialogStatus() {
})
return (
-
-
+
+
Status
@@ -49,119 +51,131 @@ export function DialogStatus() {
esc
- 0} fallback={No MCP Servers}>
-
- {Object.keys(sync.data.mcp).length} MCP Servers
-
- {([key, item]) => (
-
-
+ 0} fallback={No MCP Servers}>
+
+ {Object.keys(sync.data.mcp).length} MCP Servers
+
+ {([key, item]) => (
+
+
+ )[item.status],
+ }}
+ >
+ •
+
+
+ {key}{" "}
+
+
+ Connected
+ {(val) => val().error}
+ Disabled in configuration
+
+ Needs authentication (run: opencode mcp auth {key})
+
+
+ {(val) => (val() as { error: string }).error}
+
+
+
+
+
+ )}
+
+
+
+ {sync.data.lsp.length > 0 && (
+
+ {sync.data.lsp.length} LSP Servers
+
+ {(item) => (
+
+
- )[item.status],
- }}
- >
- •
-
-
- {key}{" "}
-
-
- Connected
- {(val) => val().error}
- Disabled in configuration
-
- Needs authentication (run: opencode mcp auth {key})
-
-
- {(val) => (val() as { error: string }).error}
-
-
-
-
-
- )}
-
-
-
- {sync.data.lsp.length > 0 && (
-
- {sync.data.lsp.length} LSP Servers
-
- {(item) => (
-
-
- •
-
-
- {item.id} {item.root}
-
-
- )}
-
-
- )}
- 0} fallback={No Formatters}>
-
- {enabledFormatters().length} Formatters
-
- {(item) => (
-
-
- •
-
-
- {item.name}
-
-
- )}
-
-
-
- 0} fallback={No Plugins}>
-
- {plugins().length} Plugins
-
- {(item) => (
-
-
- •
-
-
- {item.name}
- {item.version && @{item.version}}
-
-
- )}
-
-
-
+ error: theme.error,
+ }[item.status],
+ }}
+ >
+ •
+
+
+ {item.id} {item.root}
+
+
+ )}
+
+
+ )}
+ 0} fallback={No Formatters}>
+
+ {enabledFormatters().length} Formatters
+
+ {(item) => (
+
+
+ •
+
+
+ {item.name}
+
+
+ )}
+
+
+
+ 0} fallback={No Plugins}>
+
+ {plugins().length} Plugins
+
+ {(item) => (
+
+
+ •
+
+
+ {item.name}
+ {item.version && @{item.version}}
+
+
+ )}
+
+
+
+
)
}
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx
index 42ac5fbe080a..7b9249071641 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx
@@ -3,6 +3,7 @@ import { createMemo, For, Show, Switch, Match } from "solid-js"
import { createStore } from "solid-js/store"
import { useTheme } from "../../context/theme"
import { Locale } from "@/util/locale"
+import { fileURLToPath } from "bun"
import path from "path"
import type { AssistantMessage } from "@opencode-ai/sdk/v2"
import { Global } from "@/global"
@@ -25,6 +26,8 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
diff: true,
todo: true,
lsp: true,
+ formatters: true,
+ plugins: true,
})
// Sort MCP servers alphabetically for consistent display order
@@ -40,6 +43,34 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
).length,
)
+
+ const enabledFormatters = createMemo(() => sync.data.formatter.filter((f) => f.enabled))
+
+ const plugins = createMemo(() => {
+ const list = sync.data.config.plugin ?? []
+ const result = list.map((value) => {
+ if (value.startsWith("file://")) {
+ const fileURLPath = fileURLToPath(value)
+ const parts = fileURLPath.split("/")
+ const filename = parts.pop() || fileURLPath
+ if (!filename.includes(".")) return { name: filename }
+ const basename = filename.split(".")[0]
+ if (basename === "index") {
+ const dirname = parts.pop()
+ const name = dirname || basename
+ return { name }
+ }
+ return { name: basename }
+ }
+ const index = value.lastIndexOf("@")
+ if (index <= 0) return { name: value, version: "latest" }
+ const name = value.substring(0, index)
+ const version = value.substring(index + 1)
+ return { name, version }
+ })
+ return result.toSorted((a, b) => a.name.localeCompare(b.name))
+ })
+
const cost = createMemo(() => {
const total = messages().reduce((sum, x) => sum + (x.role === "assistant" ? x.cost : 0), 0)
return new Intl.NumberFormat("en-US", {
@@ -210,6 +241,78 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
+
+ 0}>
+
+ enabledFormatters().length > 2 && setExpanded("formatters", !expanded.formatters)}
+ >
+ 2}>
+ {expanded.formatters ? "▼" : "▶"}
+
+
+ Formatters
+
+
+
+
+ {(item) => (
+
+
+ •
+
+
+ {item.name}
+
+
+ )}
+
+
+
+
+ 0}>
+
+ plugins().length > 2 && setExpanded("plugins", !expanded.plugins)}
+ >
+ 2}>
+ {expanded.plugins ? "▼" : "▶"}
+
+
+ Plugins
+
+
+
+
+ {(item) => (
+
+
+ •
+
+
+ {item.name}
+ {item.version && @{item.version}}
+
+
+ )}
+
+
+
+
0 && todo().some((t) => t.status !== "completed")}>