pub mod add;
pub mod apply;
pub mod doctor;
pub mod init;
pub mod list;
pub mod register;
pub mod remove;
pub mod status;
pub mod unregister;
pub mod update;
use std::collections::BTreeMap;
use std::env;
use camino::{Utf8Path, Utf8PathBuf};
use crate::error::{Error, Result};
use crate::render::parse_cli_var;
pub(crate) fn resolve_pj_root(at: Option<Utf8PathBuf>) -> Result<Utf8PathBuf> {
let raw = match at {
Some(p) => p,
None => Utf8PathBuf::from_path_buf(
env::current_dir()
.map_err(|e| Error::io_at(env::current_dir().ok().unwrap_or_default(), e))?,
)
.map_err(|p| Error::Config(format!("cwd is not valid UTF-8: {}", p.display())))?,
};
if raw.is_absolute() {
return Ok(raw);
}
let cwd = env::current_dir().map_err(|e| Error::io_at(Utf8PathBuf::new().as_std_path(), e))?;
let abs = Utf8PathBuf::from_path_buf(cwd.join(raw.as_std_path()))
.map_err(|p| Error::Config(format!("path is not valid UTF-8: {}", p.display())))?;
Ok(abs)
}
pub(crate) fn parse_cli_vars(items: Vec<String>) -> Result<BTreeMap<String, toml::Value>> {
let mut out = BTreeMap::new();
for it in items {
let (k, v) = parse_cli_var(&it)?;
out.insert(k, v);
}
Ok(out)
}
pub(crate) fn ensure_state_dir(root: &Utf8Path) -> Result<()> {
let dir = root.join(crate::paths::PJ_STATE_DIR);
std::fs::create_dir_all(&dir).map_err(|e| Error::io_at(dir.as_std_path(), e))?;
Ok(())
}
const DEFAULT_AI_CONCURRENCY: usize = 4;
pub(crate) fn resolve_ai_concurrency(cli_override: Option<usize>) -> usize {
cli_override.unwrap_or_else(|| {
crate::config::GlobalConfig::load()
.map(|c| c.defaults.ai_concurrency)
.unwrap_or(DEFAULT_AI_CONCURRENCY)
})
}
pub(crate) async fn resolve_project_name(pj_root: &Utf8Path) -> String {
if let Some(name) = crate::git::repo_name_from_remote(pj_root).await {
return name;
}
pj_root.file_name().unwrap_or("kata-project").to_string()
}
const DEFAULT_PJ_CONCURRENCY: usize = 4;
pub(crate) fn resolve_pj_concurrency(cli_override: Option<usize>) -> usize {
cli_override.unwrap_or_else(|| {
crate::config::GlobalConfig::load()
.ok()
.and_then(|c| c.defaults.pj_concurrency)
.unwrap_or(DEFAULT_PJ_CONCURRENCY)
})
}
pub(crate) fn select_registered_projects(
config: &crate::config::GlobalConfig,
tag_filter: &[String],
) -> Vec<crate::config::ProjectEntry> {
config
.projects
.iter()
.filter(|p| {
tag_filter
.iter()
.all(|wanted| p.tags.iter().any(|t| t == wanted))
})
.cloned()
.collect()
}
pub mod doctor_helpers {
use std::process::Command;
pub fn detect(cmd: &str, args: &[&str]) -> bool {
Command::new(cmd)
.args(args)
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
}
}