sid-isnt-done 0.3.0

sid is a UNIX-inspired coding agent for Anthropic-compatible APIs
Documentation
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use std::process::ExitCode;

struct InitFile {
    path: &'static str,
    contents: &'static str,
    executable: bool,
}

const INIT_FILES: &[InitFile] = &[
    InitFile {
        path: "agents.conf",
        contents: include_str!("../../init/agents.conf"),
        executable: false,
    },
    InitFile {
        path: "tools.conf",
        contents: include_str!("../../init/tools.conf"),
        executable: false,
    },
    InitFile {
        path: "agents/build.md",
        contents: include_str!("../../init/agents/build.md"),
        executable: false,
    },
    InitFile {
        path: "agents/compact.md",
        contents: include_str!("../../init/agents/compact.md"),
        executable: false,
    },
    InitFile {
        path: "agents/skill-inject",
        contents: include_str!("../../init/agents/skill-inject"),
        executable: true,
    },
    InitFile {
        path: "tools/edit",
        contents: include_str!("../../init/tools/edit"),
        executable: true,
    },
    InitFile {
        path: "tools/git-diff",
        contents: include_str!("../../init/tools/git-diff"),
        executable: true,
    },
    InitFile {
        path: "tools/git-diff.json",
        contents: include_str!("../../init/tools/git-diff.json"),
        executable: false,
    },
    InitFile {
        path: "tools/git-status",
        contents: include_str!("../../init/tools/git-status"),
        executable: true,
    },
    InitFile {
        path: "tools/git-status.json",
        contents: include_str!("../../init/tools/git-status.json"),
        executable: false,
    },
    InitFile {
        path: "tools/glob",
        contents: include_str!("../../init/tools/glob"),
        executable: true,
    },
    InitFile {
        path: "tools/glob.json",
        contents: include_str!("../../init/tools/glob.json"),
        executable: false,
    },
    InitFile {
        path: "tools/read",
        contents: include_str!("../../init/tools/read"),
        executable: true,
    },
    InitFile {
        path: "tools/read.json",
        contents: include_str!("../../init/tools/read.json"),
        executable: false,
    },
    InitFile {
        path: "tools/search",
        contents: include_str!("../../init/tools/search"),
        executable: true,
    },
    InitFile {
        path: "tools/search.json",
        contents: include_str!("../../init/tools/search.json"),
        executable: false,
    },
];

fn main() -> ExitCode {
    let sid_home = match std::env::var("SID_HOME") {
        Ok(val) if !val.is_empty() => val,
        _ => {
            eprintln!("sid-init: SID_HOME must be set and non-empty");
            return ExitCode::from(1);
        }
    };

    let root = Path::new(&sid_home);

    for file in INIT_FILES {
        let dest = root.join(file.path);

        if dest.exists() {
            eprintln!("skip: {} (already exists)", dest.display());
            continue;
        }

        if let Some(parent) = dest.parent()
            && let Err(e) = fs::create_dir_all(parent)
        {
            eprintln!(
                "sid-init: cannot create directory {}: {e}",
                parent.display()
            );
            return ExitCode::from(1);
        }

        if let Err(e) = fs::write(&dest, file.contents) {
            eprintln!("sid-init: cannot write {}: {e}", dest.display());
            return ExitCode::from(1);
        }

        if file.executable
            && let Err(e) = fs::set_permissions(&dest, fs::Permissions::from_mode(0o755))
        {
            eprintln!(
                "sid-init: cannot set permissions on {}: {e}",
                dest.display()
            );
            return ExitCode::from(1);
        }

        eprintln!("create: {}", dest.display());
    }

    eprintln!("sid-init: initialized {sid_home}");
    ExitCode::SUCCESS
}