fix(tui): tighten subagent background shortcut

This commit is contained in:
Kit Langton 2026-06-30 13:44:55 -04:00
commit 3d0ff1c705
5 changed files with 66 additions and 20 deletions

View file

@ -7,6 +7,7 @@ import { useTheme, selectedForeground } from "../../../context/theme"
import { Locale } from "../../../util/locale"
import { useBindings, useCommandShortcut } from "../../../keymap"
import { useComposerTab } from "./index"
import { useTuiConfig } from "../../../config"
interface SubagentEntry {
sessionID: string
@ -23,6 +24,7 @@ export function SubagentsTab(props: { sessionID: string }) {
const { theme } = useTheme()
const fg = selectedForeground(theme)
const composer = useComposerTab()
const tuiConfig = useTuiConfig()
const interruptHint = useCommandShortcut("composer.subagent.interrupt")
const session = createMemo(() => data.session.get(props.sessionID))
@ -175,6 +177,7 @@ export function SubagentsTab(props: { sessionID: string }) {
{ key: "down", desc: "Next subagent", group: "Subagents", cmd: "composer.subagent.down" },
{ key: "return", desc: "Navigate to subagent", group: "Subagents", cmd: "composer.subagent.select" },
{ key: "ctrl+d", desc: "Interrupt subagent", group: "Subagents", cmd: "composer.subagent.interrupt" },
...tuiConfig.keybinds.gather("session.background", ["session.background"] as const),
],
}))

View file

@ -253,6 +253,13 @@ export function Session() {
}),
)
createEffect(
on(backgroundSessionID, (sessionID) => {
if (sessionID === route.sessionID) return
void data.session.message.refresh(sessionID)
}),
)
createEffect(
on(descendantSessionIDs, (sessionIDs) => {
void Promise.all(sessionIDs.map((sessionID) => data.session.permission.refresh(sessionID)))
@ -907,12 +914,6 @@ export function Session() {
bindings: tuiConfig.keybinds.gather("session.background", sessionBackgroundBindingCommands),
}))
useBindings(() => ({
mode: "composer",
enabled: () => foregroundSubagents() > 0 && composer.open,
bindings: tuiConfig.keybinds.gather("session.background", sessionBackgroundBindingCommands),
}))
// snap to bottom when session changes
createEffect(on(() => route.sessionID, toBottom))
createEffect(

View file

@ -65,11 +65,12 @@ export function foregroundSubagentCount(input: {
.map((session) => session.id),
)
const runningSessionTitles = new Set(
input.sessions
.filter((session) => runningSessionIDs.has(session.id) && session.title)
.map((session) => session.title),
)
const runningSessionTitleCounts = input.sessions
.filter((session) => runningSessionIDs.has(session.id) && session.title)
.reduce((counts, session) => {
if (!session.title) return counts
return counts.set(session.title, (counts.get(session.title) ?? 0) + 1)
}, new Map<string, number>())
const runningRows = input.messages.flatMap((message) =>
message.type === "assistant"
@ -91,16 +92,20 @@ export function foregroundSubagentCount(input: {
}),
)
const anonymousRunningRows = runningRows.filter((part) => {
if (subagentSessionID(part.state?.structured ?? {})) return false
const anonymousRunningRows = runningRows.filter((part) => !subagentSessionID(part.state?.structured ?? {}))
const matchedAnonymousRows = anonymousRunningRows.filter((part) => {
const input = part.state?.input
if (typeof input !== "object" || input === null || Array.isArray(input) || !("description" in input)) return true
return typeof input.description === "string" ? !runningSessionTitles.has(input.description) : true
if (typeof input !== "object" || input === null || Array.isArray(input) || !("description" in input)) return false
if (typeof input.description !== "string") return false
const remaining = runningSessionTitleCounts.get(input.description) ?? 0
if (remaining <= 0) return false
runningSessionTitleCounts.set(input.description, remaining - 1)
return true
}).length
const runningSessions = [...runningSessionIDs].filter((session) => !runningRowSessionIDs.has(session)).length
return runningSessions + runningRowSessionIDs.size + anonymousRunningRows
return runningSessions + runningRowSessionIDs.size + anonymousRunningRows.length - matchedAnonymousRows
}
export function subagentDisplayState(input: SubagentDisplayStateInput) {
@ -111,7 +116,7 @@ export function subagentDisplayState(input: SubagentDisplayStateInput) {
return {
background,
running,
icon: running ? "│" : "✓",
icon: running ? "│" : input.toolStatus === "completed" ? "✓" : "│",
}
}