feat(tui): persist /model picker selection + fix release-event double-fire#162
Merged
Conversation
…l.json ControlCommand::ModelSwitch and ThinkingSwitch previously updated only the in-memory AgentConfig, so the user's picker selection was lost on restart. Persist both fields to <cwd>/.loopal/settings.local.json (gitignored Local layer), letting the next session load the choice via the existing config pipeline. Writer operates on serde_json::Value rather than Settings to preserve override-only semantics (Settings uses #[serde(default)] everywhere, which would inflate the file with every default value on round-trip).
Terminals that enable kitty keyboard protocol (kitty / WezTerm / ghostty / iTerm2 with DISAMBIGUATE_ESCAPE_CODES) emit both Press and Release for every keystroke. The model picker's Left/Right cycle handler would then advance thinking_selected twice per physical keypress, and the Char-based filter input would duplicate every typed character. Drop everything that isn't a real Press/Repeat at the input::handle_key entry so all downstream handlers stay correct without per-handler guards. Also surface current-model-first ordering and use indicator.width() for exact width budgeting in render_thinking_indicator.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/modelpicker 中切换 model / thinking 现在会持久化到<cwd>/.loopal/settings.local.json,下次启动自动恢复。之前只在内存生效,重启就丢。KeyEventKind::Release的健壮性缺陷:在启用 kitty keyboard protocol 的终端(kitty / WezTerm / ghostty / iTerm2 等)上,每次按键会同时收到 Press + Release,导致 picker 的 Left/Right cycle 双触发、Char 输入 filter 翻倍。Changes
持久化(commit 1)
crates/loopal-config/src/local_writer.rs(new) —update_local_settings_field(cwd, key, value),原子写入;用serde_json::Value而非Settings反序列化以保留 override-only 语义crates/loopal-runtime/src/agent_loop/input_control.rs—ModelSwitch/ThinkingSwitch在更新内存后 best-effort persist(失败仅 log,模式同已有的Clearmarker)TUI 健壮性 + picker UX(commit 2)
crates/loopal-tui/src/input/mod.rs—handle_key入口过滤!Press|Repeat,所有下游 handler 自动受益crates/loopal-tui/src/command/model_cmd.rs— 打开 picker 时把当前 model 置顶(避免大列表中找不到)crates/loopal-tui/src/views/picker.rs—render_thinking_indicator用Line::width()替代手算估算Test plan
/model切换 thinking → 退出 → 检查.loopal/settings.local.json含thinking字段 → 重启 picker 显示已记住选择