Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
# Conflicts: # crates/ui/src/composer.rs # crates/ui/src/motion.rs # crates/ui/src/pickers.rs # crates/ui/src/settings.rs # crates/ui/src/settings/shortcuts.rs # crates/ui/src/shell.rs
Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The reset button's job is better served by jumping to the Model Loadout settings page, and the traits tray painted a second hairline under the tab row's own bottom border. Also switches the loadouts tab glyph to a star and lands the remaining upstream-merge adaptations (draft options now live in defaults, test call sites updated). Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
Also this was not listed above but the Pi provider in the model selector respects the model filter that is set in the Pi config. It should accurately represent what /models looks like in the pi cli. |
wingleeio
left a comment
There was a problem hiding this comment.
Security audit
Went through the full diff (39 files, +7910/−500) looking for malicious code, unintended side effects, and accidental exploit surface. Nothing concerning found.
- Dependencies: the only new dep is
glob = "0.3"(workspace +zeron-harness). It resolves to theglob0.3.4 package that was already inCargo.locktransitively — same crates.io source and checksum, no new package block. Used only forenabledModelspattern matching inacp/mod.rs. - Process / network / filesystem: no new
Commandspawns, no new HTTP calls, no new sockets. All UI ↔ engine traffic goes through the existingengine.client().call(methods::LIST_HARNESSES | LIST_MODELS)path. The only new fs reads areread_pi_settingson$PI_CODING_AGENT_DIR|~/.pi/agent/settings.jsonand<cwd>/.pi/settings.json— read-only, JSON-parsed, failures logged viatracing::warn!and treated as "no patterns". Test code writes only intotempfile::tempdir(). fake-cursor-shim.sh: test fixture only; the change adds aneffortparameter to the fake catalog and ascenario:reasoningbranch that echoes canned frames. No commands executed from input.ListModelsParams.cwd(new RPC input): client-controlled path forwarded tomodels_for_cwd. For Pi it becomes the agent'scurrent_dirfor the discovery probe and the location of the project.pi/settings.json. This is the same trust level as existingSetChatCwd/ history RPCs that already take an unjailedcwd, and the chat itself already runs Pi in that cwd, so no new capability is exposed. Non-Pi harnesses ignore it (default trait impl).- Shortcut recording:
bindings.rs::on_key_downonly captures a keystroke whilerecording_slot.is_some(), stores the normalized combo string in settings, emitsRecordingChanged, and stops. No key logging or persistence beyond the slot field. - Unicode: no bidi/zero-width/homoglyph characters in added lines (only
⌘ ⇧ → – — …in display strings/comments). - Formatting churn in unrelated files (
schema.rs,uploads.rs,e2e.rs,normalize.rs,subagent.rs,browser/*.rs, examples):maincurrently failscargo fmt --checkon exactly those spans; this PR just brings them in line. Pure whitespace/line-wrapping, verified.
Verification (Linux, PR head 37ef3a45)
| Check | Result |
|---|---|
cargo fmt --check |
clean |
cargo check --workspace --all-targets |
pass |
cargo test -p zeron-ui loadout |
67 passed |
cargo test -p zeron-ui pickers / shortcut / settings:: |
28 / 42 / 140 passed |
cargo test -p zeron-harness |
209 passed (incl. new Pi scope, model_argument, cursor effort tests) |
cargo test -p zeron-engine --test e2e |
20 passed, 1 ignored |
| clippy | 2 pre-existing deny errors in opencode/tests.rs (untouched by this PR), nothing new |
Manual test under Xvfb (X11, real claude/codex/cursor-agent/devin CLIs on PATH, mock engine)
| Composer model picker: pinned loadout rows with shortcut badges, harness rail, context-window + reasoning bar | Picker config popover |
|---|---|
![]() |
![]() |
| Settings › Model Loadout after drag-and-dropping three models into slots (catalogs populated from live CLIs) | Slot root menu |
|---|---|
![]() |
![]() |
| Shortcut submenu, recording | Conflict detection (recorded Ctrl+Shift+2 on slot 1) | Slot activated from picker row → composer chip updates |
|---|---|---|
![]() |
![]() |
![]() |
Worked as described: drag-and-drop into slots, checkmarks on catalog rows, slot menus (agent / model / effort / context window / fast / shortcut / remove), shortcut recording + conflict notice, clicking a loadout row in the picker, and Ctrl+N auto-applying slot 1 to a new session. No loadout/picker/toast warnings or panics in the app log.
Findings
1. Default loadout chords Ctrl+Shift+1–5 don't dispatch on Linux/X11 (bug)
Pressing Ctrl+Shift+1…5 in the chat view never fired ActivateLoadout — no model switch on a filled slot and no "slot is empty" toast on an empty one (control: Ctrl+N, Ctrl+, work fine).
Root cause: gpui_linux::keystroke_from_xkb reports Ctrl+Shift+1 as {control, key: "!", shift: false} (shift is intentionally dropped for symbols), and Linux uses DummyKeyboardMapper, so a ctrl-shift-1 binding never matches. The PR already has the fix — loadout_symbol_alias (mod-shift-1 → mod-!) — but it is only bound under #[cfg(target_os = "macos")] in apply_keymap (shell.rs:409). The gpui tests pass because simulate_keystrokes bypasses XKB translation. Suggest dropping the cfg gate (bind the alias on every platform; harmless where the shifted form is what arrives).
The conflict screenshot shows the same mechanism from the recorder side: the notice reads "Ctrl+@ is already assigned to loadout slot 2" — the physical-key comparison correctly resolved it, but the display should fold mod-@ back to Ctrl+Shift+2 (invert SHIFTED_DIGITS in normalize_loadout_shortcut or in display_combo).
2. heal_reserved_shortcuts can silently rewrite a user's custom app shortcut (behavior note)
Because the five default loadout combos are now "owned", any persisted keymap entry on mod-shift-1..5 is reset to its default on load, and if the default is taken it becomes "" (disabled) with no notice. fixed_loadout_shortcuts_heal_persisted_conflicts asserts exactly this. Probably acceptable, but worth a changelog/toast since it changes existing users' bindings on upgrade.
3. Pi discovery error path hides the cause (minor)
In models_for_cwd, Err(_) if patterns.is_some() => Ok(Vec::new()) returns an empty catalog when the probe fails and the user has enabledModels, so the column shows nothing rather than an error. Consider propagating the error (or at least tracing::warn!).
4. Per-cwd Pi probe is uncached
Pi now spawns a fresh discovery process on every LIST_MODELS (the models_cache short-circuit is skipped so project-local enabledModels can apply). The UI caches per scope so it's only on scope change, but worth keeping in mind.
Overall: safe to merge from a security standpoint; #1 is a functional regression on Linux I'd fix before merging.







Summary
Some("")disables a slot shortcut whileNonekeeps the positionalmod-shift-Ndefaultprovider_ordermodel[1m]idempotently via a sharedmodel_argumenthelper; picker rows show each row's resolved loadout shortcut badgeloadout/{bindings,cards,catalog,indicator,options}.rsand add extensive unit + gpui tests (shortcut normalization, reorder semantics, menu navigation, macOS shifted-digit aliases)Screenshots
Test plan
cargo check --workspace --all-targetscargo test -p zeron-ui loadout(67 tests)cargo fmt --checkCmd+Shift+1-5defaults still workGenerated with Devin