Skip to content
Open
Show file tree
Hide file tree
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
8 changes: 8 additions & 0 deletions packages/opencode/src/cli/cmd/tui/context/sync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,14 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
if (match.found) return store.session[match.index]
return undefined
},
siblings(sessionID: string) {
const session = result.session.get(sessionID)
if (!session) return []
const parentID = session.parentID ?? session.id
return store.session
.filter((x) => x.parentID === parentID || x.id === parentID)
.toSorted((b, a) => a.id.localeCompare(b.id))
},
status(sessionID: string) {
const session = result.session.get(sessionID)
if (!session) return "idle"
Expand Down
37 changes: 35 additions & 2 deletions packages/opencode/src/cli/cmd/tui/routes/session/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,19 @@ import type { Session } from "@opencode-ai/sdk/v2"
import { useKeybind } from "../../context/keybind"
import { useTerminalDimensions } from "@opentui/solid"

const Title = (props: { session: Accessor<Session>; truncate?: boolean }) => {
const Title = (props: {
session: Accessor<Session>
truncate?: boolean
position: Accessor<{ current: number; total: number } | null>
}) => {
const { theme } = useTheme()
return (
<text fg={theme.text} wrapMode={props.truncate ? "none" : undefined} flexShrink={props.truncate ? 1 : 0}>
<Show when={props.position()}>
<span style={{ fg: theme.textMuted }}>
[{props.position()!.current}/{props.position()!.total}]{" "}
</span>
</Show>
<span style={{ bold: true }}>#</span> <span style={{ bold: true }}>{props.session().title}</span>
</text>
)
Expand All @@ -28,6 +37,25 @@ export function Header() {
const dimensions = useTerminalDimensions()
const tall = createMemo(() => dimensions().height > 40)

// Calculate session position among siblings (parent + children)
const sessionPosition = createMemo(() => {
const current = session()
if (!current) return null

const siblings = sync.session.siblings(current.id)

// Only show counter if there are multiple sessions (parent has children)
if (siblings.length <= 1) return null

const currentIndex = siblings.findIndex((x) => x.id === current.id)
if (currentIndex === -1) return null

return {
current: currentIndex + 1, // 1-indexed for users
total: siblings.length,
}
})

return (
<box flexShrink={0}>
<box
Expand Down Expand Up @@ -78,6 +106,11 @@ export function Header() {
<Match when={session()?.parentID}>
<box flexDirection="row" gap={2}>
<text fg={theme.text}>
<Show when={sessionPosition()}>
<span style={{ fg: theme.textMuted }}>
[{sessionPosition()!.current}/{sessionPosition()!.total}]{" "}
</span>
</Show>
<b>Subagent session</b>
</text>
<text fg={theme.text}>
Expand All @@ -99,7 +132,7 @@ export function Header() {
</Match>
<Match when={true}>
<box flexDirection="row" justifyContent="space-between" gap={1}>
<Title session={session} truncate={!tall()} />
<Title session={session} truncate={!tall()} position={sessionPosition} />
<Show when={showShare()}>
<text fg={theme.textMuted} wrapMode="none" flexShrink={0}>
/share{" "}
Expand Down
9 changes: 4 additions & 5 deletions packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,11 @@ export function Session() {
const local = useLocal()

function moveChild(direction: number) {
const parentID = session()?.parentID ?? session()?.id
let children = sync.data.session
.filter((x) => x.parentID === parentID || x.id === parentID)
.toSorted((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))
const currentSession = session()
if (!currentSession) return
const children = sync.session.siblings(currentSession.id)
if (children.length === 1) return
let next = children.findIndex((x) => x.id === session()?.id) + direction
let next = children.findIndex((x) => x.id === currentSession.id) + direction
if (next >= children.length) next = 0
if (next < 0) next = children.length - 1
if (children[next]) {
Expand Down