use crate::config::Config;
use super::marketplace::{add_marketplace, list_marketplaces, update_marketplace};
pub const DEFAULT_SKILLS_URL: &str =
"https://atomgit.com/atomgit_atomcode/atomcode-skills.git";
const BOOTSTRAP_MARKER_FILENAME: &str = ".plugin_bootstrap_v1";
const UPGRADED_FROM_ENV: &str = "ATOMCODE_UPGRADED_FROM";
pub fn run_startup_hooks(config: &Config) {
if config.plugin.auto_install_default_skills {
maybe_install_default_skills();
}
let upgraded = std::env::var(UPGRADED_FROM_ENV).is_ok();
if upgraded && config.plugin.auto_update_marketplaces {
refresh_installed_marketplaces();
}
}
fn bootstrap_marker_path() -> std::path::PathBuf {
Config::config_dir().join(BOOTSTRAP_MARKER_FILENAME)
}
fn marker_exists() -> bool {
bootstrap_marker_path().exists()
}
fn touch_marker() {
let path = bootstrap_marker_path();
if let Some(parent) = path.parent() {
let _ = std::fs::create_dir_all(parent);
}
let _ = std::fs::write(&path, b"");
}
fn maybe_install_default_skills() {
if marker_exists() {
return;
}
let already_installed = list_marketplaces()
.map(|list| {
list.iter()
.any(|m| m.source.eq_ignore_ascii_case(DEFAULT_SKILLS_URL))
})
.unwrap_or(false);
if already_installed {
touch_marker();
return;
}
match add_marketplace(DEFAULT_SKILLS_URL) {
Ok(info) => {
eprintln!(
"✓ Auto-installed default skills marketplace `{}` (commit {}).",
info.name,
short_commit(&info.git_commit)
);
}
Err(e) => {
eprintln!(
"⚠ Auto-install of default skills marketplace failed (non-fatal): {e}\n \
Run `/plugin install {DEFAULT_SKILLS_URL}` manually when ready."
);
}
}
touch_marker();
}
fn refresh_installed_marketplaces() {
let list = match list_marketplaces() {
Ok(l) => l,
Err(e) => {
eprintln!("⚠ Could not enumerate marketplaces for auto-update: {e}");
return;
}
};
if list.is_empty() {
return;
}
for entry in list {
match update_marketplace(&entry.name) {
Ok(info) => {
if info.git_commit != entry.git_commit {
eprintln!(
"✓ Updated marketplace `{}` ({} → {}).",
entry.name,
short_commit(&entry.git_commit),
short_commit(&info.git_commit)
);
}
}
Err(e) => {
eprintln!(
"⚠ Auto-update of marketplace `{}` failed (non-fatal): {e}",
entry.name
);
}
}
}
}
fn short_commit(sha: &str) -> &str {
if sha.len() >= 7 {
&sha[..7]
} else {
sha
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn short_commit_truncates_long_shas() {
assert_eq!(short_commit("0123456789abcdef"), "0123456");
}
#[test]
fn short_commit_passes_through_short_input() {
assert_eq!(short_commit("abc"), "abc");
assert_eq!(short_commit(""), "");
}
#[test]
fn marker_path_uses_versioned_filename() {
let p = bootstrap_marker_path();
assert!(
p.to_string_lossy().ends_with(BOOTSTRAP_MARKER_FILENAME),
"marker path must end with versioned filename, got {:?}",
p
);
}
}