magi-code 0.96.1

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

pub(super) fn read_card(
    state: &MissionControlState,
    id: TranscriptCardId,
    link: Option<TranscriptActivityLink>,
) -> TranscriptCard {
    let node = link
        .as_ref()
        .and_then(|link| state.nodes.get(&link.activity_id));
    let detail = node.and_then(|node| node.tool_detail.as_ref());
    let status = node
        .map(|node| transcript_status_from_activity(node.status))
        .or_else(|| detail.map(|detail| transcript_status_from_activity(detail.status)))
        .unwrap_or_else(|| transcript_tool_status(state, id.entry_index));
    let targets = detail
        .and_then(|detail| read_targets(&detail.params))
        .unwrap_or_default();
    let results = detail
        .and_then(|detail| detail.metadata.get("results"))
        .and_then(serde_json::Value::as_array);
    let total = read_usize(detail, "files")
        .unwrap_or_else(|| results.map_or(targets.len(), Vec::len).max(targets.len()));
    let succeeded = read_usize(detail, "succeeded").unwrap_or_else(|| {
        results.map_or(0, |items| {
            items
                .iter()
                .filter(|item| {
                    item.get("success").and_then(serde_json::Value::as_bool) == Some(true)
                })
                .count()
        })
    });
    let failed = read_usize(detail, "failed").unwrap_or_else(|| total.saturating_sub(succeeded));
    let omitted = read_usize(detail, "omitted").unwrap_or(0);
    let incomplete = failed > 0 || omitted > 0 || succeeded < total;
    let multi = total > 1;
    let title = if multi {
        match status {
            TranscriptCardStatus::Success if incomplete => {
                format!("Read • {succeeded}/{total} resources")
            }
            _ => format!("Read • {total} resources"),
        }
    } else {
        "Read".to_string()
    };
    let card_body = if status == TranscriptCardStatus::Canceled {
        targets
            .iter()
            .cloned()
            .chain(std::iter::once("Canceled before completion".to_string()))
            .collect::<Vec<_>>()
            .join("\n")
    } else if status == TranscriptCardStatus::Running {
        targets.join("\n")
    } else if multi {
        read_multi_body(&targets, results)
    } else {
        let target = targets.first().cloned().unwrap_or_default();
        if status == TranscriptCardStatus::Failed {
            let error = detail
                .and_then(read_single_error)
                .unwrap_or_else(|| "read failed".to_string());
            format!("{target}\n{error}")
        } else if status == TranscriptCardStatus::Success {
            format_read_resource(&target, Some(read_line_count(detail)))
        } else {
            target
        }
    };
    let card_body = sanitize_display_controls(&card_body);
    let body_lines = read_body_lines(&card_body, &targets, status, multi);
    TranscriptCard {
        id,
        role: TranscriptCardRole::Read,
        status,
        title,
        metadata: Vec::new(),
        body: card_body,
        body_lines,
        children: Vec::new(),
        activity_rows: Vec::new(),
        subagent_card: None,
    }
}

fn read_targets(params: &serde_json::Value) -> Option<Vec<String>> {
    params
        .get("paths")
        .and_then(serde_json::Value::as_array)
        .map(|paths| {
            paths
                .iter()
                .filter_map(serde_json::Value::as_str)
                .map(sanitize_read_target)
                .collect()
        })
        .or_else(|| {
            params
                .get("path")
                .and_then(serde_json::Value::as_str)
                .map(|path| vec![sanitize_read_target(path)])
        })
}

fn sanitize_read_target(text: &str) -> String {
    sanitize_display_controls(text)
        .chars()
        .filter(|character| !character.is_control())
        .collect()
}

fn read_multi_body(targets: &[String], results: Option<&Vec<serde_json::Value>>) -> String {
    targets
        .iter()
        .enumerate()
        .map(|(index, target)| {
            let result = results.and_then(|items| items.get(index));
            if result
                .and_then(|item| item.get("success"))
                .and_then(serde_json::Value::as_bool)
                .unwrap_or(false)
            {
                format!(
                    "✓ {}",
                    format_read_resource(target, result.and_then(read_result_line_count))
                )
            } else {
                format!(
                    "✗ {target}\n  {}",
                    result
                        .and_then(|item| item.get("error"))
                        .and_then(serde_json::Value::as_str)
                        .and_then(read_first_non_empty_line)
                        .unwrap_or_else(|| "read failed".to_string())
                )
            }
        })
        .collect::<Vec<_>>()
        .join("\n")
}

fn format_read_resource(target: &str, line_count: Option<usize>) -> String {
    line_count.map_or_else(
        || target.to_string(),
        |count| {
            format!(
                "{target} • {count} {}",
                if count == 1 { "line" } else { "lines" }
            )
        },
    )
}

fn read_result_line_count(result: &serde_json::Value) -> Option<usize> {
    result
        .get("hashline_seen_lines")
        .and_then(serde_json::Value::as_array)
        .map(Vec::len)
}

fn read_usize(detail: Option<&crate::output::ToolActivityDetail>, key: &str) -> Option<usize> {
    detail?
        .metadata
        .get(key)?
        .as_u64()
        .and_then(|value| usize::try_from(value).ok())
}

fn read_single_error(detail: &crate::output::ToolActivityDetail) -> Option<String> {
    detail
        .metadata
        .get("error")
        .and_then(serde_json::Value::as_str)
        .and_then(read_first_non_empty_line)
        .or_else(|| read_first_non_empty_line(detail.output.as_ref()))
}

fn read_first_non_empty_line(text: &str) -> Option<String> {
    sanitize_display_controls(text)
        .lines()
        .map(str::trim)
        .find(|line| !line.is_empty())
        .map(str::to_string)
}

fn read_line_count(detail: Option<&crate::output::ToolActivityDetail>) -> usize {
    let seen_lines = detail
        .and_then(|detail| {
            detail.metadata.get("hashline_seen_lines").or_else(|| {
                detail
                    .metadata
                    .get("results")
                    .and_then(serde_json::Value::as_array)
                    .and_then(|results| results.first())
                    .and_then(|result| result.get("hashline_seen_lines"))
            })
        })
        .and_then(serde_json::Value::as_array)
        .map(Vec::len);
    seen_lines.unwrap_or_else(|| detail.map_or(0, |detail| detail.output.lines().count()))
}

fn read_body_lines(
    body: &str,
    targets: &[String],
    status: TranscriptCardStatus,
    multi: bool,
) -> Vec<DisplayLine> {
    body.lines()
        .enumerate()
        .map(|(index, line)| {
            let bare_target_row = index == 0
                || (matches!(
                    status,
                    TranscriptCardStatus::Running | TranscriptCardStatus::Canceled
                ) && index < targets.len());
            if bare_target_row
                && let Some(target) = targets
                    .iter()
                    .filter(|target| {
                        line == target.as_str() || line.starts_with(&format!("{target} • "))
                    })
                    .max_by_key(|target| target.len())
            {
                return read_resource_display_line(line, target, None);
            }
            if multi
                && let Some((marker, resource)) = line.split_once(' ')
                && matches!(marker, "✓" | "✗")
                && let Some(target) = targets
                    .iter()
                    .filter(|target| {
                        resource == target.as_str() || resource.starts_with(&format!("{target} • "))
                    })
                    .max_by_key(|target| target.len())
            {
                return read_resource_display_line(line, target, Some(marker));
            }
            DisplayLine::plain(line)
        })
        .collect()
}

fn read_resource_display_line(line: &str, target: &str, marker: Option<&str>) -> DisplayLine {
    let mut spans = Vec::new();
    let target_start = marker.map_or(0, |marker| {
        spans.push(DisplaySpan::new(
            format!("{marker} "),
            DisplayRole::ListMarker,
        ));
        marker.len() + 1
    });
    spans.push(DisplaySpan::new(target, DisplayRole::InlineCode));
    let suffix = &line[target_start + target.len()..];
    if let Some((prefix, count_and_unit)) = suffix.split_once('•') {
        spans.push(DisplaySpan::new(prefix, DisplayRole::Plain));
        spans.push(DisplaySpan::new("• ", DisplayRole::Punctuation));
        if let Some((count, unit)) = count_and_unit.trim_start().split_once(' ') {
            spans.push(DisplaySpan::new(count, DisplayRole::Number));
            spans.push(DisplaySpan::new(format!(" {unit}"), DisplayRole::Plain));
        }
    }
    tool_display_line(spans)
}