feat(tui): hide the activity panel by default

The activity panel (gateway hints, terminal-parity nudges, background
notifications) is noise for the typical day-to-day user, who only cares
about thinking + tools + streamed content.  Make `hidden` the built-in
default for that section so users land on the quiet mode out of the box.

Tool failures still render inline on the failing tool row, so this
default suppresses the noise feed without losing the signal.

Opt back in with `display.sections.activity: collapsed` (chevron) or
`expanded` (always open) in `~/.hermes/config.yaml`, or live with
`/details activity collapsed`.

Implementation: SECTION_DEFAULTS in domain/details.ts, applied as the
fallback in `sectionMode()` between the explicit override and the
global details_mode.  Existing `display.sections.activity` overrides
take precedence — no migration needed for users who already set it.
This commit is contained in:
Brooklyn Nicholson 2026-04-24 02:37:42 -05:00
parent 78481ac124
commit 728767e910
3 changed files with 49 additions and 11 deletions

View file

@ -72,13 +72,22 @@ describe('resolveSections', () => {
})
describe('sectionMode', () => {
it('falls back to the global mode when no override is set', () => {
it('falls back to the global mode for sections without a built-in default', () => {
expect(sectionMode('tools', 'collapsed', {})).toBe('collapsed')
expect(sectionMode('tools', 'expanded', undefined)).toBe('expanded')
expect(sectionMode('thinking', 'collapsed', {})).toBe('collapsed')
expect(sectionMode('subagents', 'expanded', {})).toBe('expanded')
})
it('honours per-section overrides over the global mode', () => {
expect(sectionMode('activity', 'expanded', { activity: 'hidden' })).toBe('hidden')
it('hides the activity panel by default regardless of global mode', () => {
expect(sectionMode('activity', 'collapsed', {})).toBe('hidden')
expect(sectionMode('activity', 'expanded', undefined)).toBe('hidden')
expect(sectionMode('activity', 'hidden', {})).toBe('hidden')
})
it('honours per-section overrides over both the section default and global mode', () => {
expect(sectionMode('activity', 'collapsed', { activity: 'expanded' })).toBe('expanded')
expect(sectionMode('activity', 'expanded', { activity: 'collapsed' })).toBe('collapsed')
expect(sectionMode('tools', 'collapsed', { tools: 'expanded' })).toBe('expanded')
})
})

View file

@ -49,13 +49,26 @@ export const resolveSections = (raw: unknown): SectionVisibility => {
return out
}
// Built-in per-section defaults applied when the user has no explicit
// override. The activity panel (gateway hints, terminal-parity nudges,
// background-process notifications) is hidden out of the box — it's noise
// for the typical day-to-day user, who only cares about thinking + tools +
// streamed content. Tool failures still surface inline on the failing tool
// row; this default only suppresses the ambient meta feed.
//
// Opt back in with `display.sections.activity: collapsed` (under chevron)
// or `expanded` (always open) in `~/.hermes/config.yaml`, or live with
// `/details activity collapsed`.
const SECTION_DEFAULTS: SectionVisibility = { activity: 'hidden' }
// Resolve the effective mode for one section: explicit override wins,
// otherwise the global details_mode. Single source of truth — every render
// site that needs to know "is this section open by default" calls this.
// then the SECTION_DEFAULTS fallback, then the global details_mode.
// Single source of truth — every render site that needs to know "is this
// section open by default" calls this.
export const sectionMode = (
name: SectionName,
global: DetailsMode,
sections?: SectionVisibility
): DetailsMode => sections?.[name] ?? global
): DetailsMode => sections?.[name] ?? SECTION_DEFAULTS[name] ?? global
export const nextDetailsMode = (m: DetailsMode): DetailsMode => MODES[(MODES.indexOf(m) + 1) % MODES.length]!