magi-code 0.77.1

Repository-aware CLI coding agent for terminal work
Documentation
mod engine;
mod matcher;
mod reader;
use super::{
    ToolResult, ToolResultDisplay, ToolRuntime,
    args::{GrepArgs, GrepMode},
    contract::tool_name,
};
use crate::cancellation::AgentCancellation;
use serde_json::json;
impl ToolRuntime {
    pub(super) fn grep(
        &self,
        args: GrepArgs,
        cancellation: &AgentCancellation,
    ) -> anyhow::Result<ToolResult> {
        let path_arg = args.path.clone().unwrap_or_else(|| ".".into());
        let path = self.resolve_existing_path(
            &path_arg,
            super::fs::ExistingPathPolicy::grep(self.grep_absolute_paths),
        )?;
        cancellation.check()?;
        let mode = args.mode.unwrap_or(GrepMode::Ranked);
        let raw = mode == GrepMode::Raw || args.pattern.is_some();
        let limit = args.limit.unwrap_or(crate::tools::args::GREP_DEFAULT_LIMIT);
        let offset = args.offset.unwrap_or(0);
        let context = args.context.unwrap_or(0);
        let scan = engine::run(engine::GrepRequest {
            cwd: &self.cwd_canonical,
            walker: &self.workspace_walker,
            patterns: args
                .patterns
                .as_ref()
                .ok_or_else(|| anyhow::anyhow!("patterns required"))?,
            root: &path,
            limit,
            offset,
            context,
            raw,
            cancellation,
        })?;
        let pattern_count = args.patterns.as_ref().map_or(0, Vec::len);
        let mut metadata = json!({
            "engine": "native",
            "patterns_count": pattern_count,
            "mode": if raw { "raw" } else { "ranked" },
            "offset": offset,
            "limit": limit,
            "output_format": if raw { "raw_v1" } else { "grouped_v1" },
            "order": if raw { "path_line_v1" } else { "ranked_v1" },
            "matches_returned": scan.matches_returned,
            "output_lines_returned": scan.output_lines_returned,
            "truncated": scan.truncated,
            "timed_out": scan.timed_out,
            "files_scanned": scan.files_scanned,
            "bytes_scanned": scan.bytes_scanned,
            "byte_limit_reached": scan.byte_limit_reached,
            "scan_byte_limit_reached": scan.scan_byte_limit_reached,
            "file_limit_reached": scan.file_limit_reached,
            "match_limit_reached": scan.match_limit_reached,
            "per_file_limit_reached": scan.per_file_limit_reached,
            "files_with_matches": scan.files_with_matches,
            "files_returned": scan.files_returned,
            "invalid_utf8_files": scan.invalid_utf8_files,
            "invalid_utf8_lines": scan.invalid_utf8_lines,
            "read_errors_skipped": scan.read_errors_skipped,
            "walk_errors": scan.walk_errors,
            "walk_entries_omitted": scan.walk_entries_omitted,
            "binary_files_skipped": scan.binary_files_skipped,
            "scan_complete": scan.scan_complete,
            "matches_seen": scan.matches_seen,
            "matches_seen_exact": scan.matches_seen_exact,
            "output_bytes": scan.output_bytes,
            "output_byte_limit_reached": scan.output_byte_limit_reached,
            "context_lines_omitted": scan.context_lines_omitted,
            "patterns_adjusted": scan.patterns_adjusted,
            "literal_fallbacks": scan.literal_fallbacks,
            "raw_lookahead_reached": scan.raw_lookahead_reached,
            "truncation_reasons": scan.truncation_reasons,
            "limit_reason": scan.truncation_reasons.first().copied(),
        });
        metadata["next_offset"] = scan
            .next_offset
            .map_or(serde_json::Value::Null, |v| json!(v));
        metadata["has_more"] = scan.has_more.map_or(serde_json::Value::Null, |v| json!(v));

        Ok(ToolResult {
            tool_name: tool_name::GREP.into(),
            success: true,
            content: scan.lines.join("\n"),
            metadata,
            display: ToolResultDisplay::default(),
        })
    }
}