1use std::path::Path;
2
3use anyhow::bail;
4
5use crate::agent::{self, SourceKind};
6use crate::engine::{compute_plan, managed_gitignore_entries};
7use crate::error::RtangoError;
8use crate::spec::io::{gitignore_update, lock_path, rtango_dir, spec_path, write_gitignore};
9use crate::spec::{AgentName, Defaults, Lock, Rule, RuleKind, Source, Spec};
10
11pub fn exec(
12 root: &Path,
13 force: bool,
14 no_detect: bool,
15 gitignore_targets: bool,
16) -> anyhow::Result<()> {
17 let spec_path = spec_path(root);
18 let lock_path = lock_path(root);
19
20 if spec_path.exists() && !force {
21 bail!(RtangoError::SpecExists);
22 }
23
24 let detected = if no_detect {
25 Vec::new()
26 } else {
27 let detected = agent::detect_agents(root);
28 if detected.is_empty() {
29 bail!(RtangoError::NoAgentsDetected);
30 }
31 detected
32 };
33
34 let agent_names: Vec<AgentName> = detected.iter().map(|d| d.name.clone()).collect();
35
36 let mut rules = Vec::new();
37 for agent in &detected {
38 for source in &agent.sources {
39 rules.push(Rule {
40 id: source.id.clone(),
41 source: Source::Local(source.path.clone()),
42 schema_agent: agent.name.clone(),
43 on_target_modified: None,
44 kind: match source.kind {
45 SourceKind::SkillSet => RuleKind::skill_set(),
46 SourceKind::AgentSet => RuleKind::agent_set(),
47 },
48 });
49 }
50 }
51
52 let spec = Spec {
53 version: 1,
54 agents: agent_names.clone(),
55 defaults: Defaults {
56 gitignore_targets,
57 ..Defaults::default()
58 },
59 rules,
60 };
61
62 let lock = Lock {
63 version: 1,
64 tracked_agents: agent_names,
65 owners: vec![],
66 deployments: vec![],
67 };
68
69 let spec_yaml = serde_yml::to_string(&spec)?;
70 let lock_yaml = serde_yml::to_string(&lock)?;
71
72 std::fs::create_dir_all(rtango_dir(root))?;
73 std::fs::write(&spec_path, &spec_yaml)?;
74 std::fs::write(&lock_path, &lock_yaml)?;
75
76 if gitignore_targets {
77 let plan = compute_plan(root, &spec, &lock, true, true)?;
78 let update = gitignore_update(root, &managed_gitignore_entries(&plan, None))?;
79 if update.changed {
80 write_gitignore(root, &update.content)?;
81 }
82 }
83
84 Ok(())
85}