Skip to content
Open
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
55 changes: 55 additions & 0 deletions packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
diff: true,
todo: true,
lsp: true,
subagents: true,
})

// Sort MCP servers alphabetically for consistent display order
Expand Down Expand Up @@ -63,6 +64,13 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
const directory = useDirectory()
const kv = useKV()

const subagents = createMemo(() =>
sync.data.session
.filter((x) => x.parentID === props.sessionID)
.map((x) => x.id)
.toSorted((a, b) => (a < b ? -1 : a > b ? 1 : 0)),
)

const hasProviders = createMemo(() =>
sync.data.provider.some((x) => x.id !== "opencode" || Object.values(x.models).some((y) => y.cost?.input !== 0)),
)
Expand Down Expand Up @@ -229,6 +237,53 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
</Show>
</box>
</Show>
<Show when={subagents().length > 0}>
<box>
<box
flexDirection="row"
gap={1}
onMouseDown={() => subagents().length > 2 && setExpanded("subagents", !expanded.subagents)}
>
<Show when={subagents().length > 2}>
<text fg={theme.text}>{expanded.subagents ? "▼" : "▶"}</text>
</Show>
<text fg={theme.text}>
<b>Subagents</b>
<Show when={!expanded.subagents}>
<span style={{ fg: theme.textMuted }}> ({subagents().length})</span>
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the Subagents section is collapsed (more than 2 subagents), the header shows only the total count, e.g., (4). The MCP section (an established pattern in this file) shows a more informative summary in its collapsed header, e.g., (3 active, 1 error). Since the primary reason for this feature is to track working vs. idle subagent status, the collapsed header would be more useful if it showed a count breakdown, such as (3 working, 1 idle), consistent with the MCP section pattern.

Suggested change
<span style={{ fg: theme.textMuted }}> ({subagents().length})</span>
{(() => {
const counts = subagents().reduce(
(acc, id) => {
const status = sync.session.status(id)
if (status === "idle") {
acc.idle += 1
} else {
acc.working += 1
}
return acc
},
{ working: 0, idle: 0 },
)
return (
<span style={{ fg: theme.textMuted }}>
{" "}
({counts.working} working, {counts.idle} idle)
</span>
)
})()}

Copilot uses AI. Check for mistakes.
</Show>
</text>
</box>
<Show when={subagents().length <= 2 || expanded.subagents}>
<For each={subagents()}>
{(id) => {
const status = createMemo(() => sync.session.status(id))
const title = createMemo(() => sync.session.get(id)?.title ?? id)
return (
<box flexDirection="row" gap={1}>
<text
flexShrink={0}
style={{
fg: status() === "idle" ? theme.success : theme.warning,
}}
>
</text>
<box flexGrow={1}>
<text fg={theme.text} wrapMode="word">
{title()}
</text>
<text fg={theme.textMuted}>
{status() === "idle" ? "idle" : "working"}
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The status() check only handles "idle" vs. everything else, but sync.session.status() can return three distinct values: "idle", "working", and "compacting" (when session.time.compacting is set). When a subagent's session is compacting, it will display "working" with a warning color, which is misleading because compacting is a distinct background housekeeping operation. The displayed label should reflect the compacting state, and the indicator color could differentiate it (e.g., use a different color or a different label like "compacting").

Suggested change
{status() === "idle" ? "idle" : "working"}
{status() === "idle" ? "idle" : status() === "compacting" ? "compacting" : "working"}

Copilot uses AI. Check for mistakes.
</text>
</box>
</box>
)
}}
</For>
</Show>
</box>
</Show>
<Show when={diff().length > 0}>
<box>
<box
Expand Down
Loading