codetether-agent 4.5.7

A2A-native AI coding agent for the CodeTether ecosystem
Documentation
use anyhow::{Context, Result};
use std::fs;
use std::path::Path;
use std::process::Command;

#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;

pub fn install_commit_msg_hook(path: &Path) -> Result<()> {
    let output = Command::new("git")
        .args(["rev-parse", "--show-toplevel"])
        .current_dir(path)
        .output()
        .context("Failed to resolve git repo root")?;
    if !output.status.success() {
        return Ok(());
    }
    let root = String::from_utf8_lossy(&output.stdout).trim().to_string();
    if root.is_empty() {
        return Ok(());
    }
    let hook_path = Path::new(&root).join(".git/hooks/commit-msg");
    let script = "#!/bin/sh\nmsg_file=\"$1\"\n[ -n \"$msg_file\" ] || exit 0\nadd_trailer() {\n  key=\"$1\"\n  value=\"$2\"\n  [ -n \"$value\" ] || return 0\n  git interpret-trailers --in-place --if-exists doNothing --trailer \"$key: $value\" \"$msg_file\"\n}\ngit_cfg() {\n  git config --local --get \"$1\" 2>/dev/null || true\n}\nadd_trailer \"CodeTether-Provenance-ID\" \"$CODETETHER_PROVENANCE_ID\"\nadd_trailer \"CodeTether-Origin\" \"$CODETETHER_ORIGIN\"\nadd_trailer \"CodeTether-Agent-Name\" \"$CODETETHER_AGENT_NAME\"\nadd_trailer \"CodeTether-Agent-Identity\" \"$CODETETHER_AGENT_IDENTITY_ID\"\nadd_trailer \"CodeTether-Tenant-ID\" \"$CODETETHER_TENANT_ID\"\nadd_trailer \"CodeTether-Worker-ID\" \"$CODETETHER_WORKER_ID\"\nadd_trailer \"CodeTether-Session-ID\" \"$CODETETHER_SESSION_ID\"\nadd_trailer \"CodeTether-Task-ID\" \"$CODETETHER_TASK_ID\"\nadd_trailer \"CodeTether-Run-ID\" \"$CODETETHER_RUN_ID\"\nadd_trailer \"CodeTether-Attempt-ID\" \"$CODETETHER_ATTEMPT_ID\"\nadd_trailer \"CodeTether-Key-ID\" \"$CODETETHER_KEY_ID\"\nadd_trailer \"CodeTether-GitHub-Installation-ID\" \"$(git_cfg codetether.githubInstallationId)\"\nadd_trailer \"CodeTether-GitHub-App-ID\" \"$(git_cfg codetether.githubAppId)\"\nadd_trailer \"CodeTether-Signature\" \"$CODETETHER_SIGNATURE\"\n";
    fs::write(&hook_path, script).context("Failed to write commit-msg hook")?;
    #[cfg(unix)]
    {
        let mut permissions = fs::metadata(&hook_path)?.permissions();
        permissions.set_mode(0o755);
        fs::set_permissions(&hook_path, permissions).context("Failed to chmod commit-msg hook")?;
    }
    Ok(())
}