magi-code 0.77.1

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

#[test]
fn resolve_child_cwd_allows_absolute_by_default_and_false_rejects_outside() {
    let parent = tempfile::TempDir::new().unwrap();
    let outside = tempfile::TempDir::new().unwrap();

    let allowed = resolve_child_cwd(parent.path(), Some(outside.path()), true).unwrap();
    assert_eq!(allowed, outside.path().canonicalize().unwrap());

    let absolute_err = resolve_child_cwd(parent.path(), Some(outside.path()), false)
        .unwrap_err()
        .to_string();
    assert!(absolute_err.contains("tools.subagents.absolute_paths"));

    let relative_err = resolve_child_cwd(parent.path(), Some(Path::new("..")), true)
        .unwrap_err()
        .to_string();
    assert!(relative_err.contains("escapes parent cwd"));
}

#[test]
fn child_cwd_write_stays_inside_requested_child_directory() {
    let temp = tempfile::TempDir::new().unwrap();
    std::fs::create_dir(temp.path().join("child-dir")).unwrap();
    let provider = Arc::new(WritingProvider::new());
    let output = run_subagents(
        SubagentsArgs {
            concurrency: Some(1),
            tasks: vec![SubagentTask {
                intent: "write child file".into(),
                agent: None,
                identity: None,
                context: None,
                cwd: Some(PathBuf::from("child-dir")),
            }],
        },
        config(provider, temp.path()),
    )
    .unwrap();
    let changed_file = temp
        .path()
        .join("child-dir/child.txt")
        .canonicalize()
        .unwrap();
    assert_eq!(
        std::fs::read_to_string(&changed_file).unwrap(),
        "made by child"
    );
    assert_eq!(
        output.results[0].cwd,
        temp.path().join("child-dir").canonicalize().unwrap()
    );
    assert_eq!(output.results[0].changed_files, vec![changed_file]);
}

#[test]
fn resolve_child_cwd_rejects_missing_non_directory_and_symlink_escape() {
    let parent = tempfile::TempDir::new().unwrap();
    let missing = resolve_child_cwd(parent.path(), Some(Path::new("missing")), true)
        .unwrap_err()
        .to_string();
    assert!(
        missing.contains("No such file") || missing.contains("not found"),
        "{missing}"
    );

    std::fs::write(parent.path().join("file-cwd"), "file").unwrap();
    let file_err = resolve_child_cwd(parent.path(), Some(Path::new("file-cwd")), true)
        .unwrap_err()
        .to_string();
    assert!(file_err.contains("not a directory"), "{file_err}");

    #[cfg(unix)]
    {
        use std::os::unix::fs::symlink;
        let outside = tempfile::TempDir::new().unwrap();
        symlink(outside.path(), parent.path().join("escape-link")).unwrap();
        let link_err = resolve_child_cwd(parent.path(), Some(Path::new("escape-link")), true)
            .unwrap_err()
            .to_string();
        assert!(link_err.contains("escapes parent cwd"), "{link_err}");
    }
}

#[test]
fn multiple_child_sessions_are_unique() {
    let temp = tempfile::TempDir::new().unwrap();
    let provider = Arc::new(CountingProvider::new("never"));
    let mut cfg = config(provider, temp.path());
    cfg.sessions_root = Some(temp.path().join("sessions"));
    let output = run_subagents(
        SubagentsArgs {
            concurrency: Some(2),
            tasks: vec![
                SubagentTask {
                    intent: "one".into(),
                    agent: None,
                    identity: None,
                    context: None,
                    cwd: None,
                },
                SubagentTask {
                    intent: "two".into(),
                    agent: None,
                    identity: None,
                    context: None,
                    cwd: None,
                },
            ],
        },
        cfg,
    )
    .unwrap();
    let first = &output.results[0];
    let second = &output.results[1];
    assert!(first.session_id.is_some() && second.session_id.is_some());
    assert_ne!(first.session_id, second.session_id);
    assert_ne!(first.session_path, second.session_path);
    for path in [
        first.session_path.as_ref().unwrap(),
        second.session_path.as_ref().unwrap(),
    ] {
        assert!(path.starts_with(temp.path().join("sessions/subagents")));
        assert!(path.exists());
    }
}