magi-code 0.77.1

Repository-aware CLI coding agent for terminal work
Documentation
use super::*;

#[test]
fn generic_tool_card_keeps_existing_preview_behavior() {
    let state = linked_tool_state(
        "call_dynamic",
        "dynamic_tool",
        "dynamic_tool inspect",
        ActivityStatus::Success,
        vec![("path".to_string(), "src/lib.rs".to_string())],
        "STATUS: success\nPATH: src/lib.rs\nOUTPUT:\ncontents",
    );

    let cards = project_cards(&state);
    assert_eq!(cards[0].role, TranscriptCardRole::Tool);
    assert_eq!(cards[0].title, "dynamic_tool");
    assert!(cards[0].body.contains("STATUS: success"));
    assert!(cards[0].body.contains("PATH: src/lib.rs"));

    let visual = state.transcript_visual_text();
    assert!(
        visual.contains("✓ Tool • dynamic_tool\n  STATUS: success"),
        "{visual}"
    );
    assert!(visual.contains("PATH: src/lib.rs"), "{visual}");
}

#[test]
fn typed_tool_summary_controls_card_even_when_body_looks_like_another_tool() {
    use crate::tui::transcript::{TranscriptEntry, TranscriptToolData, TranscriptToolIdentity};
    let mut state = MissionControlState::default();
    state.transcript.push_back(TranscriptEntry::tool(
        "✗ subagents • misleading display text".to_string(),
        TranscriptToolData {
            identity: TranscriptToolIdentity::Summary(crate::output::ToolDisplaySummary {
                tool_name: "dynamic_tool".to_string(),
                status: crate::output::ToolStatus::Success,
                unicode_mark: "",
                ascii_mark: "+",
                label: "inspect".to_string(),
                metadata: Vec::new(),
            }),
            children: Vec::new(),
        },
    ));
    let cards = project_cards(&state);
    assert_eq!(cards[0].role, TranscriptCardRole::Tool);
    assert_eq!(cards[0].title, "dynamic_tool");
    assert_eq!(cards[0].status, TranscriptCardStatus::Success);
    assert!(cards[0].body.contains("misleading display text"));
}

#[test]
fn bash_tool_card_header_and_body_use_dedicated_projection() {
    let state = bash_card_state(
        "call_bash_header",
        "bash",
        ActivityStatus::Success,
        serde_json::json!({"command":"cargo check"}),
        serde_json::json!({"exit_code":0,"timed_out":false,"stdout":"ok","stderr":""}),
        "stdout:\nok\nstderr:\n",
    );

    let wide_lines = visual_lines(&state, CARD_LAYOUT_MIN_WIDTH);
    let wide_header = line_text(&wide_lines[1].line);
    assert!(wide_header.starts_with(" ✓ Bash • exit 0"), "{wide_header}");
    assert!(!wide_header.contains("cargo check"), "{wide_header}");

    let visual = state.transcript_visual_text();
    assert_eq!(visual, "✓ Bash • exit 0\n  cargo check\n  1 line");
}

#[test]
fn subagents_card_header_uses_dispatch_name_without_task_metadata() {
    let state = linked_tool_state(
        "call_parallel",
        "subagents",
        "subagents • 2 tasks",
        ActivityStatus::Running,
        vec![("tasks".to_string(), "2".to_string())],
        "STATUS: running\nTASK_COUNT: 2\nTASK_IDS: g1, g2\nsummary: total=2 completed=0 failed=0",
    );

    let cards = project_cards(&state);
    assert_eq!(cards[0].role, TranscriptCardRole::SubagentBatch);
    // Subagent card panel carries aggregate progress, not raw tool-output metadata.
    assert!(cards[0].metadata.is_empty());
    let subagent_card = cards[0]
        .subagent_card
        .as_ref()
        .expect("subagent batch carries subagent card summary");
    assert_eq!(subagent_card.total, 2);
    assert_eq!(subagent_card.done, 0);
    assert_eq!(subagent_card.failed, 0);

    let wide_lines = visual_lines(&state, CARD_LAYOUT_MIN_WIDTH);
    let wide_header = line_text(&wide_lines[1].line);
    assert!(wide_header.contains("Subagents"), "{wide_header}");
    assert!(wide_header.contains("0/2 settled"), "{wide_header}");
    // Raw tool-output noise stays out of the card.
    assert!(!wide_header.contains("TASK_COUNT"), "{wide_header}");
    assert!(!wide_header.contains("Tool:"), "{wide_header}");

    let rendered = wide_lines
        .iter()
        .map(|line| line_text(&line.line))
        .collect::<Vec<_>>()
        .join("\n");
    assert!(!rendered.contains("[view-activity]"), "{rendered}");
    assert!(!rendered.contains("TASK_COUNT"), "{rendered}");
    assert!(!rendered.contains("TASK_IDS"), "{rendered}");
}

#[test]
fn tool_and_subagent_cards_have_no_activity_affordance() {
    let mut state = MissionControlState::default();
    state
        .transcript
        .push_back("tool: ✓ read • done".to_string());
    state
        .transcript
        .push_back("tool: ⟳ subagents • running".to_string());
    state.transcript.link_activity(
        0,
        TranscriptActivityLink {
            activity_id: ActivityId::new("call_read"),
            tool_name: "read".to_string(),
        },
    );
    state.transcript.link_activity(
        1,
        TranscriptActivityLink {
            activity_id: ActivityId::new("call_parallel"),
            tool_name: "subagents".to_string(),
        },
    );
    state.invalidate_transcript_cache();

    for width in [20, CARD_LAYOUT_MIN_WIDTH, 80] {
        let rendered = visual_lines(&state, width)
            .iter()
            .map(|line| line_text(&line.line))
            .collect::<Vec<_>>()
            .join("\n");
        assert!(
            !rendered.contains("[view-activity]"),
            "width {width}: {rendered}"
        );
        assert!(
            !rendered.contains("[activity]"),
            "width {width}: {rendered}"
        );
    }
}

#[test]
fn visual_text_excludes_card_decoration_and_keeps_labels() {
    let mut state = MissionControlState::default();
    state.apply_output_event(&OutputEvent::UserPrompt {
        text: "hello".into(),
    });
    state.apply_output_event(&OutputEvent::AssistantComplete {
        text: "**world**".into(),
    });

    let text = visual_text(&state);
    assert!(text.contains("User: hello"));
    assert!(text.contains("Agent\n  world"));
    assert!(!text.contains(''));
    assert!(!text.contains(''));
}

#[test]
fn tui_perf_projected_card_counter_only_updates_when_enabled() {
    let mut disabled = MissionControlState::default();
    disabled.transcript.push_back("assistant: off".to_string());
    let _ = project_cards(&disabled);
    assert_eq!(disabled.perf.latest_snapshot(), None);

    let mut enabled = MissionControlState {
        perf: crate::tui::perf::TuiPerfCounters::with_enabled(true),
        ..Default::default()
    };
    enabled.transcript.push_back("assistant: on".to_string());
    enabled.perf.reset_projected_cards();
    let _ = project_cards(&enabled);
    enabled.perf.record_draw_us(1);

    let snapshot = enabled.perf.latest_snapshot().unwrap();
    assert_eq!(snapshot.projected_cards, 1);
}