mati_core/scaffold/
mod.rs1use std::path::Path;
5
6use anyhow::Result;
7
8pub mod claude_md;
9pub mod codex;
10pub mod settings;
11
12pub use claude_md::write_claude_md_stub;
13pub use codex::install_codex;
14pub use settings::install_hooks;
15
16pub fn mati_binary_path() -> String {
21 std::env::current_exe()
22 .ok()
23 .and_then(|p| p.canonicalize().ok())
24 .map(|p| p.to_string_lossy().into_owned())
25 .unwrap_or_else(|| "mati".to_owned())
26}
27
28pub fn write_mati_wrapper(hooks_dir: &Path) -> Result<()> {
34 let bin = mati_binary_path();
35 let content = format!(
36 "#!/usr/bin/env bash\n\
37 # mati binary wrapper — written by mati init.\n\
38 # Ensures hooks use the same binary as the MCP server.\n\
39 # DO NOT EDIT — regenerated on each mati init.\n\
40 [ -x \"{bin}\" ] || exit 0\n\
41 exec \"{bin}\" \"$@\"\n"
42 );
43 let path = hooks_dir.join("mati");
44 write_if_changed(&path, &content)?;
45 make_executable(&path)?;
46 Ok(())
47}
48
49pub(crate) fn write_if_changed(path: &Path, content: &str) -> Result<()> {
50 if path.exists() {
51 if let Ok(existing) = std::fs::read_to_string(path) {
52 if existing == content {
53 return Ok(());
54 }
55 }
56 }
57 std::fs::write(path, content)?;
58 Ok(())
59}
60
61#[cfg(unix)]
62pub(crate) fn make_executable(path: &Path) -> Result<()> {
63 use std::os::unix::fs::PermissionsExt;
64 let mut perms = std::fs::metadata(path)?.permissions();
65 perms.set_mode(0o755);
66 std::fs::set_permissions(path, perms)?;
67 Ok(())
68}
69
70#[cfg(not(unix))]
71pub(crate) fn make_executable(_path: &Path) -> Result<()> {
72 Ok(())
73}