magi-code 0.77.1

Repository-aware CLI coding agent for terminal work
Documentation
use super::super::*;
use super::support::*;
use std::collections::HashSet;

#[test]
fn keybindings_have_no_duplicate_keys_in_same_context() {
    let mut seen = HashSet::new();
    for binding in default_keybindings() {
        assert!(
            seen.insert((binding.context, binding.key)),
            "duplicate keybinding in {:?}: {}",
            binding.context,
            binding.label
        );
    }
}

#[test]
fn alt_up_down_keybindings_are_context_specific() {
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Up, KeyModifiers::ALT),
            KeyContext::Prompt
        ),
        Some(KeyCommand::ScrollTranscriptUp)
    );
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Down, KeyModifiers::ALT),
            KeyContext::Prompt
        ),
        Some(KeyCommand::ScrollTranscriptDown)
    );
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Up, KeyModifiers::ALT),
            KeyContext::ActivityDetail
        ),
        Some(KeyCommand::ScrollDetailUp)
    );
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Down, KeyModifiers::ALT),
            KeyContext::ActivityDetail
        ),
        Some(KeyCommand::ScrollDetailDown)
    );
}

#[test]
fn ctrl_shift_left_right_keybindings_are_global_layout_shortcuts() {
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Right, KeyModifiers::CONTROL | KeyModifiers::SHIFT),
            KeyContext::Prompt
        ),
        Some(KeyCommand::FocusActivityLayout)
    );
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Left, KeyModifiers::CONTROL | KeyModifiers::SHIFT),
            KeyContext::Prompt
        ),
        Some(KeyCommand::FocusTranscriptLayout)
    );
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Right, KeyModifiers::CONTROL | KeyModifiers::SHIFT),
            KeyContext::ActivityTree
        ),
        Some(KeyCommand::FocusActivityLayout)
    );
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Left, KeyModifiers::CONTROL | KeyModifiers::SHIFT),
            KeyContext::ActivityTree
        ),
        Some(KeyCommand::FocusTranscriptLayout)
    );
}

#[test]
fn alt_left_right_keybindings_remain_global_layout_aliases() {
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Right, KeyModifiers::ALT),
            KeyContext::Prompt
        ),
        Some(KeyCommand::FocusActivityLayout)
    );
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Left, KeyModifiers::ALT),
            KeyContext::Prompt
        ),
        Some(KeyCommand::FocusTranscriptLayout)
    );
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Right, KeyModifiers::ALT),
            KeyContext::ActivityTree
        ),
        Some(KeyCommand::FocusActivityLayout)
    );
    assert_eq!(
        action_for_key(
            modified_key(KeyCode::Left, KeyModifiers::ALT),
            KeyContext::ActivityTree
        ),
        Some(KeyCommand::FocusTranscriptLayout)
    );
}

#[test]
fn ctrl_shift_left_right_switch_layout_without_changing_prompt_or_scroll_state() {
    let candidates = autocomplete_candidates();
    let mut state = state_with_activity();
    state.focus_prompt();
    state.set_prompt_text("/q", 2);
    state.set_scroll_offset(&state.scroll_views.transcript, 4);
    state.set_scroll_offset(&state.scroll_views.activity_tree, 5);
    state.set_scroll_offset(&state.scroll_views.detail, 6);
    state.recompute_autocomplete(&candidates);
    let autocomplete_before = state.autocomplete.clone();

    assert_eq!(
        handle_key(
            modified_key(KeyCode::Right, KeyModifiers::CONTROL | KeyModifiers::SHIFT),
            &mut state
        ),
        InputAction::None
    );
    assert_eq!(
        state.layout_mode,
        crate::tui::state::TuiLayoutMode::ActivityFocused
    );
    assert_eq!(
        handle_key(
            modified_key(KeyCode::Left, KeyModifiers::CONTROL | KeyModifiers::SHIFT),
            &mut state
        ),
        InputAction::None
    );
    assert_eq!(
        state.layout_mode,
        crate::tui::state::TuiLayoutMode::TranscriptFocused
    );
    assert_eq!(state.prompt_plain_text(), "/q");
    assert_eq!(state.prompt_cursor(), 2);
    assert_eq!(state.transcript_scroll_offset(), 4);
    assert_eq!(state.activity_scroll_offset(), 5);
    assert_eq!(state.detail_offset(), 6);
    assert_eq!(state.selected, 0);
    assert!(state.is_prompt_focused());
    assert_eq!(state.autocomplete, autocomplete_before);
}

#[test]
fn alt_t_cycles_reasoning_without_editing_prompt_or_conflicting_with_plain_t_or_shift_tab() {
    let mut state = MissionControlState {
        provider: crate::providers::OPENAI_CODEX_PROVIDER.to_string(),
        model: "gpt-5".to_string(),
        focus_pane: crate::tui::state::TuiFocusPane::Prompt,
        prompt_editor: crate::tui::state::PromptEditor::new("draft", 5),
        ..Default::default()
    };
    state.refresh_thinking_levels(
        crate::thinking::ThinkingLevel::Default,
        crate::thinking::ThinkingLevel::EFFORT_GENERIC.to_vec(),
    );
    state.set_primary_agents(vec![crate::tui::state::PrimaryAgentEntry {
        id: "tars".to_string(),
        name: "TARS".to_string(),
        description: "tactical unit".to_string(),
        prompt: "stay alive".to_string(),
    }]);

    assert_eq!(
        handle_key(key(KeyCode::Char('t')), &mut state),
        InputAction::None
    );
    assert_eq!(state.prompt_plain_text(), "draftt");
    assert_eq!(
        handle_key(
            modified_key(KeyCode::Char('t'), KeyModifiers::ALT),
            &mut state
        ),
        InputAction::ThinkingLevelSelectionChanged(crate::thinking::ThinkingLevel::Low)
    );
    assert_eq!(state.prompt_plain_text(), "draftt");
    assert_eq!(state.thinking_level, crate::thinking::ThinkingLevel::Low);
    assert_eq!(
        state.effective_thinking_level,
        crate::thinking::ThinkingLevel::Low
    );
    assert_eq!(
        handle_key(
            modified_key(KeyCode::BackTab, KeyModifiers::SHIFT),
            &mut state
        ),
        InputAction::PrimaryAgentSelectionChanged(Some("tars".to_string()))
    );
    assert_eq!(state.prompt_plain_text(), "draftt");
}

#[test]
fn alt_t_on_unsupported_model_reports_diagnostic_without_changing_prompt() {
    let mut state = MissionControlState {
        provider: "local-ai".to_string(),
        model: "model".to_string(),
        focus_pane: crate::tui::state::TuiFocusPane::Prompt,
        prompt_editor: crate::tui::state::PromptEditor::new("draft", 0),
        ..Default::default()
    };
    state.refresh_thinking_levels(
        crate::thinking::ThinkingLevel::High,
        state.thinking_levels.clone(),
    );

    assert_eq!(
        handle_key(
            modified_key(KeyCode::Char('t'), KeyModifiers::ALT),
            &mut state
        ),
        InputAction::None
    );
    assert_eq!(state.prompt_plain_text(), "draft");
    assert_eq!(
        state.effective_thinking_level,
        crate::thinking::ThinkingLevel::Default
    );
    assert!(state.status.contains("not configurable"));
}

#[test]
fn help_text_is_generated_from_keymap_and_mentions_auth_commands() {
    let help = help_text();
    for binding in default_keybindings() {
        assert!(help.contains(binding.label), "missing {}", binding.label);
        assert!(
            help.contains(binding.description),
            "missing {}",
            binding.description
        );
    }
    assert!(help.contains("type normally"));
    assert!(help.contains("arrows move the cursor"));
    assert!(help.contains("[Alt-Up]/[Alt-Down] scroll transcript while Prompt is focused"));
    assert!(help.contains("mouse wheel over Transcript also scrolls transcript"));
    assert!(!help.contains("with Transcript focused"));
    assert!(help.contains("[Ctrl-Shift-Right] uses activity-focused columns"));
    assert!(help.contains("[Alt-Right]/[Alt-Left] remain secondary aliases"));
    assert!(help.contains(
        "Long prompt: use cursor keys to navigate; the prompt does not scroll with the mouse wheel."
    ));
    assert!(!help.contains("Alt-Up/Alt-Down or mouse wheel over Prompt"));
    assert!(!help.contains("scroll prompt up"));
    assert!(!help.contains("scroll prompt down"));
    assert!(help.contains("mouse wheel over Help scrolls this text"));
    assert!(help.contains("Mouse: wheel follows the hovered scrollable pane; the Prompt editor is not mouse-scrollable"));
    assert!(help.contains("System prompt modal: [Esc]/[q] close; [Up]/[Down]/[Alt-Up]/[Alt-Down]/[PageUp]/[PageDown]/[Home]/[End] and mouse wheel scroll."));
    assert!(help.contains("@ anywhere tags cwd files with fuzzy matching"));
    assert!(help.contains("$ anywhere tags enabled skills with fuzzy matching"));
    assert!(help.contains("/login openai-codex authenticates"));
    assert!(help.contains("/logout openai-codex removes local auth"));
    assert!(help.contains("/new starts a fresh session"));
    assert!(help.contains("/quit exits"));
    assert!(help.contains("[Ctrl-T] focuses activity tree"));
    assert!(help.contains("[Tab] cycles Prompt, Transcript"));
    assert!(help.contains("[Alt-1] Activity, [Alt-2] Summary"));
    assert!(help.contains("[Alt-T]"));
    assert!(!help.contains("Ctrl-Shift-T"));
    assert!(!help.contains("future work in TUI mode"));
}