Add Wormhole remote helpers, provider and agent improvements, filesystem diagnostics, model metadata support, and schema-aware settings IntelliSense.
9.2 KiB
CLI Agent Rich Input — Shell Command Mode: Tech Spec
Problem
The CLI agent rich input composer enters AI locked mode when opened, suppressing all shell decorations (syntax highlighting, error underlining, completions). CLI agents like Claude Code use ! as a mode-switch prefix for shell commands. We need to detect this prefix, activate shell input features, and correctly round-trip the ! on submit — all by reusing the existing agent view ! shell mode infrastructure rather than building a parallel system.
Relevant code
All changes are in a single file:
app/src/terminal/input.rs— theInputview, which owns the editor, input mode state, decoration dispatch, completions, and the CLI agent submit path.
Key existing infrastructure reused:
TERMINAL_INPUT_PREFIX(line ~481) — the"!"constant.TERMINAL_INPUT_PREFIXhandler (line ~8700) — strips!, switches to Shell locked, in theEditorEvent::Editedhandler. Previously gated to agent view only.maybe_render_ai_input_indicators(line ~13922) — renders the blue!indicator as a left-notch decorator element. Previously gated tois_agent_view_active.maybe_backspace_ai_icon(line ~9814) — handlesBackspaceOnEmptyBuffer/BackspaceAtBeginningOfBufferto exit shell mode. Previously gated tois_fullscreen().DeleteAllLefthandler (line ~9206) — same exit-shell-mode behavior for Cmd+Backspace.input_enter/SubmitCLIAgentInput(line ~11392) — the CLI agent submit path.open_completion_suggestions(line ~10258) — gated byis_command_grid_active.set_zero_state_hint_text(line ~5400) — sets placeholder text.run_input_background_jobsindecorations.rs— suppresses decorations whenis_ai_input_enabled().CLIAgentSessionsModel— singleton tracking CLI agent sessions, providesis_input_open()andsession().CLIAgentenum —Claude,Codex,OpenCode, etc.
Current state
Before this change:
- CLI agent rich input always enters AI locked mode (PR #23819).
- The
TERMINAL_INPUT_PREFIXhandler only fires whenis_agent_view_active— it does not fire for CLI agent input. - Decorations are suppressed in AI mode (
run_input_background_jobschecksis_ai_input_enabled()). - Completions are blocked during long-running commands (
is_command_grid_activeis false while a CLI agent is executing). - The
!indicator only renders for the agent view. - Backspace / DeleteAllLeft shell-mode exit only handles the agent view case.
Proposed changes
All changes are in app/src/terminal/input.rs. No new files, types, or crate-level changes.
1. Extend TERMINAL_INPUT_PREFIX handler to CLI agent input
Where: handle_editor_event → EditorEvent::Edited branch, the TERMINAL_INPUT_PREFIX block (~line 8700).
What: The guard condition (!FeatureFlag::AgentView.is_enabled() || is_agent_view_active) is extended to || is_cli_agent_bash_mode_input_open, where:
let is_cli_agent_bash_mode_input_open = CLIAgentSessionsModel::as_ref(ctx)
.session(self.terminal_view_id)
.is_some_and(|s| {
matches!(s.agent, CLIAgent::Claude | CLIAgent::Codex | CLIAgent::OpenCode)
&& matches!(s.input_state, CLIAgentInputState::Open { .. })
});
This is the only place that checks the specific agent type. All downstream code (indicator, backspace, completions) uses the agent-agnostic is_input_open() since only supported agents can enter Shell locked mode via this path.
2. Guard autodetection re-enable
Where: Empty-buffer autodetection re-enable block (~line 8675).
What: Add && !is_cli_agent_input_open to the second branch of should_reenable_autodetection. Without this, clearing the buffer after !ls would unlock Shell mode and let autodetection flip the mode back.
3. Prepend ! on submit + exit shell mode
Where: input_enter → SubmitCLIAgentInput path (~line 11392).
What: When is_locked_in_shell_mode(), prepend TERMINAL_INPUT_PREFIX to the buffer text before emitting the event. Then call exit_shell_mode_to_ai() so the next prompt starts in AI mode. The existing submit_cli_agent_rich_input in use_agent_footer/mod.rs already handles the ! prefix correctly via CLI_AGENT_MODE_SWITCH_PREFIXES (splits it with a delay).
4. exit_shell_mode_to_ai helper
Where: New method on Input (~line 12497).
fn exit_shell_mode_to_ai(&mut self, ctx: &mut ViewContext<Self>) {
let is_cli_agent_input_open =
CLIAgentSessionsModel::as_ref(ctx).is_input_open(self.terminal_view_id);
let new_config = if is_cli_agent_input_open {
InputConfig { input_type: InputType::AI, is_locked: true }
} else {
InputConfig { input_type: InputType::AI, is_locked: true }
.unlocked_if_autodetection_enabled(true, ctx)
};
self.ai_input_model.update(ctx, |m, ctx| {
m.set_input_config(new_config, true, ctx);
});
}
For CLI agent input, always locks to AI — the ! prefix is the explicit toggle. For agent view, respects the autodetection setting (existing behavior). Called from three sites: maybe_backspace_ai_icon, DeleteAllLeft, and input_enter submit.
5. Show ! indicator for CLI agent input
Where: maybe_render_ai_input_indicators (~line 13938).
What: Added terminal_view_id parameter. The condition is restructured to:
let is_locked_shell = !is_ai_input_enabled && is_input_type_locked;
let is_cli_agent_input_open = CLIAgentSessionsModel::as_ref(app).is_input_open(terminal_view_id);
if is_locked_shell && (is_agent_view_active || is_cli_agent_input_open) {
// render blue ! indicator
}
This eliminates the previous redundant inner check.
6. Backspace / DeleteAllLeft exit shell mode for CLI agent
Where: maybe_backspace_ai_icon (~line 9814) and DeleteAllLeft handler (~line 9220).
What: Both now check || is_cli_agent_input_open alongside is_fullscreen() and call exit_shell_mode_to_ai(). The maybe_backspace_ai_icon path also adds an early return after the mode switch to prevent fallthrough into the classic AI icon toggle logic.
7. Allow completions during long-running CLI agent command
Where: open_completion_suggestions (~line 10266).
What: Added bypass:
let is_cli_agent_shell_mode = self.is_locked_in_shell_mode(ctx)
&& CLIAgentSessionsModel::as_ref(ctx).is_input_open(self.terminal_view_id);
if (is_command_grid_active || is_cli_agent_shell_mode) && self.can_query_history(ctx) {
Note this should NOT be allowed if we're in a Wormholed remote host, where we cannot run in-band generators.
8. Placeholder text
Where: set_zero_state_hint_text (~line 5400).
What: When CLI agent input is open, check is_locked_in_shell_mode() — if true, show "Run commands", otherwise "Tell the agent what to build...".
End-to-end flow
sequenceDiagram
participant User
participant Editor
participant Input (handle_editor_event)
participant BlocklistAIInputModel
participant Decorations
participant CLIAgent (PTY)
User->>Editor: Types "!"
Editor->>Input: EditorEvent::Edited
Input->>Input: Detects TERMINAL_INPUT_PREFIX + Claude/Codex/OpenCode
Input->>Editor: Strips "!" from buffer
Input->>BlocklistAIInputModel: set_input_config(Shell, locked)
BlocklistAIInputModel-->>Decorations: InputTypeChanged event
Decorations->>Decorations: AI mode suppression OFF → decorations run
Note over Editor: Blue ! indicator renders, placeholder = "Run commands"
User->>Editor: Types "git status"
Editor->>Input: EditorEvent::Edited
Input->>Decorations: run_input_background_jobs (Shell mode → decorations active)
Decorations-->>Editor: Syntax highlighting + error underlining applied
User->>Editor: Presses Enter
Editor->>Input: EditorEvent::Enter → input_enter()
Input->>Input: Prepends "!" → text = "!git status"
Input->>Input: exit_shell_mode_to_ai() → AI locked
Input-->>CLIAgent (PTY): SubmitCLIAgentInput { text: "!git status" }
Note over Editor: Reverts to AI mode, placeholder = "Tell the agent what to build..."
Risks and mitigations
- Agent view regression: All changes extend existing conditions with
|| is_cli_agent_*checks. The agent view paths are unchanged. Mitigation: manual regression testing of agent view!shell mode. - Autodetection fighting locked state: When exiting shell mode, the helper always locks to AI for CLI agent (not unlocked). This prevents autodetection from re-classifying the next keystroke as Shell. Tested and confirmed.
maybe_backspace_ai_iconfallthrough: The classic AI icon toggle logic (with_toggled_type()) would flip back to Shell after the Shell→AI switch. Fixed with an earlyreturnafter the mode switch.
Testing and validation
- Manual testing: Primary validation method — open Claude Code / Codex / OpenCode, Ctrl-G, test all behaviors from the product spec success criteria.
- Regression: Verify agent view
!shell mode is unaffected. - Edge cases:
!→ backspace →!again;! pwd(with space); empty submit; typing for unsupported agents.
Follow-ups
- "Backspace to exit shell mode" hint text in CLI agent footer (requires message bar plumbing).