1use anyhow::Result;
2use std::path::{Path, PathBuf};
3
4pub fn get_data_dir() -> Result<PathBuf> {
5 let data_dir = dirs::data_dir()
6 .or_else(|| dirs::home_dir())
7 .ok_or_else(|| anyhow::anyhow!("Could not determine data directory"))?;
8
9 let vibe_dir = data_dir.join(".vibe");
10 std::fs::create_dir_all(&vibe_dir)?;
11
12 Ok(vibe_dir)
13}
14
15pub fn get_log_dir() -> Result<PathBuf> {
16 let log_dir = get_data_dir()?.join("logs");
17 std::fs::create_dir_all(&log_dir)?;
18 Ok(log_dir)
19}
20
21pub fn get_backup_dir() -> Result<PathBuf> {
22 let backup_dir = get_data_dir()?.join("backups");
23 std::fs::create_dir_all(&backup_dir)?;
24 Ok(backup_dir)
25}
26
27pub fn canonicalize_path(path: &Path) -> Result<PathBuf> {
28 Ok(path.canonicalize()?)
29}
30
31pub fn is_git_repository(path: &Path) -> bool {
32 path.join(".git").exists()
33}
34
35pub fn has_vibe_marker(path: &Path) -> bool {
36 path.join(".vibe").exists()
37}
38
39pub fn detect_project_name(path: &Path) -> String {
40 path.file_name()
41 .and_then(|name| name.to_str())
42 .unwrap_or("unknown")
43 .to_string()
44}
45
46pub fn get_git_hash(path: &Path) -> Option<String> {
47 if !is_git_repository(path) {
48 return None;
49 }
50
51 let git_dir = path.join(".git");
53
54 let head_content = std::fs::read_to_string(git_dir.join("HEAD")).ok()?;
55 let config_content = std::fs::read_to_string(git_dir.join("config")).ok()?;
56
57 use std::collections::hash_map::DefaultHasher;
59 use std::hash::{Hash, Hasher};
60
61 let mut hasher = DefaultHasher::new();
62 head_content.hash(&mut hasher);
63 config_content.hash(&mut hasher);
64
65 Some(format!("{:x}", hasher.finish()))
66}