daat-locus 0.1.0

A long-running local agent runtime with memory, workflows, apps, and sleep-time self-improvement.
use crate::{
    apply_patch::{
        PatchOperationKind, PatchPreviewLineKind, apply_patch_in_root, build_patch_preview_in_root,
    },
    context::Context,
    runtime_tools::ToolExecutionResult,
    tool_ui::ToolUiEvent,
};
use serde_json::json;

pub(crate) async fn execute_apply_patch_tool(
    context: &Context,
    patch_text: &str,
) -> miette::Result<ToolExecutionResult> {
    let preview_files = build_patch_preview_in_root(&context.execution_cwd, patch_text).await?;
    let summary =
        apply_patch_in_root(&context.execution_cwd, &context.sandbox_policy, patch_text).await?;
    Ok(ToolExecutionResult::new(
        format!("patched {} file(s)", summary.changed_files),
        json!({
            "changed_files": summary.changed_files,
            "added_files": summary.added_files,
            "deleted_files": summary.deleted_files,
            "updated_files": summary.updated_files,
            "added_lines": summary.added_lines,
            "removed_lines": summary.removed_lines,
            "files": summary.files.iter().map(|file| {
                json!({
                    "path": file.path,
                    "operation": match file.operation {
                        PatchOperationKind::Add => "add",
                        PatchOperationKind::Delete => "delete",
                        PatchOperationKind::Update => "update",
                    },
                    "added_lines": file.added_lines,
                    "removed_lines": file.removed_lines,
                })
            }).collect::<Vec<_>>(),
        }),
        ToolUiEvent::patch(
            format!(
                "{} file(s) changed (+{} -{})",
                summary.changed_files, summary.added_lines, summary.removed_lines
            ),
            preview_files
                .into_iter()
                .map(|file| crate::tool_ui::PatchFileUiData {
                    path: file.path,
                    operation: match file.operation {
                        PatchOperationKind::Add => crate::tool_ui::PatchFileOperation::Add,
                        PatchOperationKind::Delete => crate::tool_ui::PatchFileOperation::Delete,
                        PatchOperationKind::Update => crate::tool_ui::PatchFileOperation::Update,
                    },
                    added_lines: file.added_lines,
                    removed_lines: file.removed_lines,
                    diff_lines: file
                        .diff_lines
                        .into_iter()
                        .map(|line| crate::tool_ui::PatchDiffLineUiData {
                            kind: match line.kind {
                                PatchPreviewLineKind::Context => {
                                    crate::tool_ui::PatchDiffLineKind::Context
                                }
                                PatchPreviewLineKind::Delete => {
                                    crate::tool_ui::PatchDiffLineKind::Delete
                                }
                                PatchPreviewLineKind::Add => crate::tool_ui::PatchDiffLineKind::Add,
                                PatchPreviewLineKind::HunkBreak => {
                                    crate::tool_ui::PatchDiffLineKind::HunkBreak
                                }
                            },
                            old_lineno: line.old_lineno,
                            new_lineno: line.new_lineno,
                            text: line.text,
                        })
                        .collect(),
                })
                .collect(),
        ),
    ))
}