use anyhow::Result;
use std::path::PathBuf;
use std::process::Command;
use crate::cli::SetupArgs;
use crate::storage;
pub fn run(args: SetupArgs) -> Result<()> {
let cwd = std::env::current_dir()?;
let project_file = cwd.join("project.req");
println!("req setup — bootstrapping this project for managed requirements\n");
if project_file.exists() {
println!(
" [skip] project.req already exists at {}",
project_file.display()
);
} else {
let name = args
.name
.clone()
.or_else(|| {
cwd.file_name()
.and_then(|s| s.to_str())
.map(|s| s.to_string())
})
.unwrap_or_else(|| "unnamed project".into());
let init_args = crate::cli::InitArgs {
name: name.clone(),
output: project_file.clone(),
force: false,
layout: crate::cli::LayoutArg::Single,
};
crate::commands::init::run(init_args)?;
println!(" [done] req init -n \"{}\"", name);
}
let is_git = cwd.join(".git").exists();
if args.no_hooks {
println!(" [skip] hooks (--no-hooks)");
} else if !is_git {
println!(" [skip] hooks (.git directory not found — run `git init` first)");
} else {
let hooks_args = crate::cli::HooksArgs {
action: "install".into(),
repo: Some(cwd.clone()),
force: args.force,
claude_code: false,
strict: args.strict,
};
crate::commands::hooks::run(hooks_args)?;
println!(
" [done] req hooks install{}",
if args.strict { " --strict" } else { "" }
);
let registered_name = std::process::Command::new("git")
.args(["config", "merge.req-merge.name", "req merge driver"])
.current_dir(&cwd)
.status();
let registered_driver = std::process::Command::new("git")
.args([
"config",
"merge.req-merge.driver",
"req renumber --base %O || true",
])
.current_dir(&cwd)
.status();
match (registered_name, registered_driver) {
(Ok(s1), Ok(s2)) if s1.success() && s2.success() => {
println!(" [done] git merge driver registered");
}
_ => {
println!(
" [skip] git merge driver (could not run `git config` — register manually)"
);
}
}
}
if args.no_agents {
println!(" [skip] AGENTS.md (--no-agents)");
} else {
let installed = install_agents_block(&cwd)?;
if installed {
println!(" [done] AGENTS.md managed block installed");
} else {
println!(" [skip] AGENTS.md already contains the managed block");
}
}
println!();
println!("You're set up. Next steps:");
println!();
println!(" req add -t \"My first requirement\" \\");
println!(" -s \"The system shall expose a hello endpoint.\" \\");
println!(" -r \"Establishes the baseline contract.\" \\");
println!(" -k functional -p must \\");
println!(" -a \"GET /hello returns 200 with non-empty body\"");
println!(" # write your first requirement");
println!(" req brief # session-start summary");
println!(" req help agents # the agent workflow guide");
println!();
println!("Or, if you have an existing spec to ingest:");
println!(" req import -f markdown your-spec.md");
println!();
Ok(())
}
fn install_agents_block(cwd: &PathBuf) -> Result<bool> {
let bin = std::env::current_exe()?;
let out = Command::new(bin)
.current_dir(cwd)
.args(["help", "agents", "--install"])
.output()?;
let stdout = String::from_utf8_lossy(&out.stdout);
Ok(stdout.contains("Installed") || stdout.contains("Updated"))
}
#[allow(dead_code)]
fn _silence_unused() {
let _ = storage::FORMAT_TAG;
}