feat(tui): add width-budgeted "resumes when subagent finishes" status segment

When idle with a background subagent still in flight, append a tail status
segment spelling out that the agent resumes on its own. Width-budgeted like
every tail segment, so it drops first on a tight terminal where the ⛓ count
already carries the signal.
This commit is contained in:
Brooklyn Nicholson 2026-06-25 19:57:58 -05:00
parent 563d347e4d
commit 7f02f30b76
2 changed files with 50 additions and 0 deletions

View file

@ -129,6 +129,41 @@ describe('StatusRule background-subagent indicator', () => {
expect(textContent(element)).not.toContain('⛓')
})
it('spells out the auto-resume hint when idle with subagents in flight', () => {
const element = StatusRule({
...baseProps,
usage: { ...baseProps.usage, active_subagents: 1 }
})
expect(textContent(element)).toContain('resumes when subagent finishes')
})
it('pluralizes the resume hint for multiple in-flight subagents', () => {
const element = StatusRule({
...baseProps,
usage: { ...baseProps.usage, active_subagents: 3 }
})
expect(textContent(element)).toContain('resumes when 3 subagents finish')
})
it('hides the resume hint mid-turn (a busy turn owns the indicator)', () => {
const element = StatusRule({
...baseProps,
busy: true,
turnStartedAt: Date.now(),
usage: { ...baseProps.usage, active_subagents: 2 }
})
expect(textContent(element)).not.toContain('resumes when')
})
it('omits the resume hint when no subagents are running', () => {
const element = StatusRule({ ...baseProps })
expect(textContent(element)).not.toContain('resumes when')
})
it('drops the subagent segment before the bg segment on a narrow terminal', () => {
// cols=44 is below the subagents breakpoint (92) but the bg breakpoint
// (88) too — both gone. Assert the lower-priority subagent indicator is

View file

@ -512,6 +512,15 @@ export function StatusRule({
const showBg = segs.bg && bgCount > 0 && fits(SEP + stringWidth(`${bgCount} bg`))
const subagentCount = typeof usage.active_subagents === 'number' ? usage.active_subagents : 0
const showSubagents = segs.subagents && subagentCount > 0 && fits(SEP + stringWidth(`${subagentCount}`))
// Parked-background reassurance: a top-level delegate_task runs in the
// background, so the turn ends (idle) while the subagent keeps working and its
// result re-enters as a fresh turn later. When idle with work still in flight,
// spell out that the agent resumes on its own — no spinner, nothing to poll.
// Width-budgeted like every tail segment, so it drops first on a tight
// terminal where ⛓ already carries the signal.
const resumeHintText =
subagentCount === 1 ? '↩ resumes when subagent finishes' : `↩ resumes when ${subagentCount} subagents finish`
const showResumeHint = !busy && subagentCount > 0 && fits(SEP + stringWidth(resumeHintText))
// Dev-gated readout (HERMES_DEV_CREDITS), lowest priority,
// so it consumes tail budget LAST and drops first on a narrow terminal.
const showDevCredits = !!devCreditsText && fits(SEP + stringWidth(devCreditsText))
@ -624,6 +633,12 @@ export function StatusRule({
{subagentCount}
</Text>
) : null}
{showResumeHint ? (
<Text color={t.color.muted} dim wrap="truncate-end">
{' │ '}
{resumeHintText}
</Text>
) : null}
{showDevCredits ? (
<Text color={t.color.accent} wrap="truncate-end">
{' │ '}