winx-code-agent 0.2.352

Remote-first Rust MCP runtime with Streamable HTTP, durable PTYs, and guarded agent tools
Documentation
use std::sync::OnceLock;

use regex::Regex;

use crate::errors::{Result, WinxError};

static SEARCH_MARKER: OnceLock<std::result::Result<Regex, regex::Error>> = OnceLock::new();
static DIVIDER_MARKER: OnceLock<std::result::Result<Regex, regex::Error>> = OnceLock::new();
static REPLACE_MARKER: OnceLock<std::result::Result<Regex, regex::Error>> = OnceLock::new();

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub(super) struct SearchReplaceBlock {
    pub(super) search: Vec<String>,
    pub(super) replace: Vec<String>,
    pub(super) anchor_start: Option<usize>,
    pub(super) anchor_end: Option<usize>,
}

fn regex_marker(
    marker: &'static OnceLock<std::result::Result<Regex, regex::Error>>,
    pattern: &'static str,
) -> Result<&'static Regex> {
    marker.get_or_init(|| Regex::new(pattern)).as_ref().map_err(|error| {
        WinxError::ArgumentParseError(format!("Invalid edit marker regex: {error}"))
    })
}

pub(super) fn search_marker() -> Result<&'static Regex> {
    regex_marker(&SEARCH_MARKER, r"(?m)^<<<<<<+\s*SEARCH>?(?:\s*@(\d+)(?:-(\d+))?)?\s*$")
}

fn divider_marker() -> Result<&'static Regex> {
    regex_marker(&DIVIDER_MARKER, r"(?m)^======*\s*$")
}

fn replace_marker() -> Result<&'static Regex> {
    regex_marker(&REPLACE_MARKER, r"(?m)^>>>>>>+\s*REPLACE\s*$")
}

pub(super) fn parse_blocks(content: &str) -> Result<Vec<SearchReplaceBlock>> {
    let mut blocks = Vec::new();
    let lines: Vec<&str> = content.lines().collect();
    let mut index = 0;

    while index < lines.len() {
        let anchors = search_marker()?.captures(lines[index]).map(|captures| {
            (
                captures.get(1).and_then(|value| value.as_str().parse::<usize>().ok()),
                captures.get(2).and_then(|value| value.as_str().parse::<usize>().ok()),
            )
        });
        if let Some((anchor_start, anchor_end)) = anchors {
            let marker_line = index + 1;
            index += 1;
            let mut search = Vec::new();
            while index < lines.len() && !divider_marker()?.is_match(lines[index]) {
                if search_marker()?.is_match(lines[index])
                    || replace_marker()?.is_match(lines[index])
                {
                    return Err(WinxError::SearchReplaceSyntaxError(format!(
                        "Line {}: stray marker in SEARCH block",
                        index + 1
                    )));
                }
                search.push(lines[index].to_string());
                index += 1;
            }

            if index >= lines.len() {
                return Err(WinxError::SearchReplaceSyntaxError(format!(
                    "Line {marker_line}: unclosed SEARCH block - missing ======= marker"
                )));
            }
            if search.is_empty() {
                return Err(WinxError::SearchReplaceSyntaxError(format!(
                    "Line {marker_line}: SEARCH block cannot be empty"
                )));
            }

            index += 1;
            let mut replace = Vec::new();
            while index < lines.len() && !replace_marker()?.is_match(lines[index]) {
                if search_marker()?.is_match(lines[index])
                    || divider_marker()?.is_match(lines[index])
                {
                    return Err(WinxError::SearchReplaceSyntaxError(format!(
                        "Line {}: stray marker in REPLACE block",
                        index + 1
                    )));
                }
                replace.push(lines[index].to_string());
                index += 1;
            }

            if index >= lines.len() {
                return Err(WinxError::SearchReplaceSyntaxError(format!(
                    "Line {marker_line}: unclosed block - missing REPLACE marker"
                )));
            }

            blocks.push(SearchReplaceBlock { search, replace, anchor_start, anchor_end });
        } else if divider_marker()?.is_match(lines[index])
            || replace_marker()?.is_match(lines[index])
        {
            return Err(WinxError::SearchReplaceSyntaxError(format!(
                "Line {}: stray marker outside block",
                index + 1
            )));
        }
        index += 1;
    }

    if blocks.is_empty() {
        return Err(WinxError::SearchReplaceSyntaxError("No valid blocks found".to_string()));
    }
    Ok(blocks)
}

pub(crate) fn uses_search_replace(percentage_to_change: u32, blocks: &str) -> bool {
    if percentage_to_change <= 50 {
        return true;
    }
    blocks
        .trim_start()
        .lines()
        .next()
        .is_some_and(|line| search_marker().is_ok_and(|marker| marker.is_match(line)))
}