fix(tui): persist global details mode sections

Pin all detail sections when /details sets a global mode so config sync does not restore built-in section defaults.
This commit is contained in:
Brooklyn Nicholson 2026-04-29 16:46:42 -05:00
parent b52b63396c
commit c2cb6d1071
4 changed files with 48 additions and 2 deletions

View file

@ -879,6 +879,36 @@ def test_config_set_statusbar_survives_non_dict_display(tmp_path, monkeypatch):
assert saved["display"]["tui_statusbar"] == "bottom" assert saved["display"]["tui_statusbar"] == "bottom"
def test_config_set_details_mode_pins_all_sections(tmp_path, monkeypatch):
import yaml
cfg_path = tmp_path / "config.yaml"
cfg_path.write_text(
yaml.safe_dump(
{"display": {"sections": {"tools": "expanded", "activity": "hidden"}}}
)
)
monkeypatch.setattr(server, "_hermes_home", tmp_path)
resp = server.handle_request(
{
"id": "1",
"method": "config.set",
"params": {"key": "details_mode", "value": "collapsed"},
}
)
assert resp["result"] == {"key": "details_mode", "value": "collapsed"}
saved = yaml.safe_load(cfg_path.read_text())
assert saved["display"]["details_mode"] == "collapsed"
assert saved["display"]["sections"] == {
"thinking": "collapsed",
"tools": "collapsed",
"subagents": "collapsed",
"activity": "collapsed",
}
def test_config_set_section_writes_per_section_override(tmp_path, monkeypatch): def test_config_set_section_writes_per_section_override(tmp_path, monkeypatch):
import yaml import yaml

View file

@ -3130,7 +3130,15 @@ def _(rid, params: dict) -> dict:
allowed_dm = frozenset({"hidden", "collapsed", "expanded"}) allowed_dm = frozenset({"hidden", "collapsed", "expanded"})
if nv not in allowed_dm: if nv not in allowed_dm:
return _err(rid, 4002, f"unknown details_mode: {value}") return _err(rid, 4002, f"unknown details_mode: {value}")
_write_config_key("display.details_mode", nv) cfg = _load_cfg()
display = cfg.get("display") if isinstance(cfg.get("display"), dict) else {}
sections = display.get("sections") if isinstance(display.get("sections"), dict) else {}
display["details_mode"] = nv
for section in ("thinking", "tools", "subagents", "activity"):
sections[section] = nv
display["sections"] = sections
cfg["display"] = display
_save_cfg(cfg)
return _ok(rid, {"key": key, "value": nv}) return _ok(rid, {"key": key, "value": nv})
if key.startswith("details_mode."): if key.startswith("details_mode."):

View file

@ -141,6 +141,12 @@ describe('createSlashHandler', () => {
expect(createSlashHandler(ctx)('/details toggle')).toBe(true) expect(createSlashHandler(ctx)('/details toggle')).toBe(true)
expect(getUiState().detailsMode).toBe('expanded') expect(getUiState().detailsMode).toBe('expanded')
expect(getUiState().detailsModeCommandOverride).toBe(true) expect(getUiState().detailsModeCommandOverride).toBe(true)
expect(getUiState().sections).toEqual({
thinking: 'expanded',
tools: 'expanded',
subagents: 'expanded',
activity: 'expanded'
})
expect(ctx.gateway.rpc).toHaveBeenCalledWith('config.set', { expect(ctx.gateway.rpc).toHaveBeenCalledWith('config.set', {
key: 'details_mode', key: 'details_mode',
value: 'expanded' value: 'expanded'

View file

@ -266,7 +266,9 @@ export const coreCommands: SlashCommand[] = [
return transcript.sys(DETAILS_USAGE) return transcript.sys(DETAILS_USAGE)
} }
patchUiState({ detailsMode: next, detailsModeCommandOverride: true }) const sections = Object.fromEntries(SECTION_NAMES.map(section => [section, next]))
patchUiState({ detailsMode: next, detailsModeCommandOverride: true, sections })
gateway.rpc<ConfigSetResponse>('config.set', { key: 'details_mode', value: next }).catch(() => {}) gateway.rpc<ConfigSetResponse>('config.set', { key: 'details_mode', value: next }).catch(() => {})
transcript.sys(`details: ${next}`) transcript.sys(`details: ${next}`)
} }