Skip to main content

gobby_code/commands/
init.rs

1use std::path::Path;
2
3use crate::config;
4use crate::db;
5use crate::index::api;
6use crate::output::{self, Format};
7use crate::project;
8use crate::skill;
9
10pub fn run(project_root: &Path, format: Format, quiet: bool) -> anyhow::Result<()> {
11    let identity =
12        config::resolve_project_identity(project_root, config::MissingIdentity::Generate)?;
13    config::warn_project_identity(&identity, quiet);
14    let (project_id, was_created) = if identity.should_write_gcode_json {
15        project::ensure_gcode_json(project_root)?
16    } else {
17        (identity.project_id.clone(), false)
18    };
19
20    let status = match identity.source {
21        config::ProjectIdentitySource::IsolatedRoot => "isolated",
22        config::ProjectIdentitySource::LinkedWorktree => "linked-worktree",
23        config::ProjectIdentitySource::ProjectJson => "gobby",
24        config::ProjectIdentitySource::Generated if was_created => "initialized",
25        _ => "existing",
26    };
27
28    // Install AI CLI skills (skip if Gobby manages this project)
29    let mut installed_skills: Vec<String> = Vec::new();
30    if status != "gobby" {
31        for target in skill::supported_targets() {
32            match skill::install_skill(project_root, target) {
33                Ok(path) if !path.is_empty() => {
34                    if !quiet {
35                        eprintln!(
36                            "Installed gcode skill for {} → {}",
37                            target.display_name, path
38                        );
39                    }
40                    installed_skills.push(target.display_name.to_string());
41                }
42                Err(e) if !quiet => {
43                    eprintln!(
44                        "Warning: failed to install skill for {}: {}",
45                        target.display_name, e
46                    );
47                }
48                _ => {}
49            }
50        }
51    }
52
53    // Auto-index the project. The daemon process is not required, but a migrated
54    // PostgreSQL hub must already be configured in Gobby bootstrap.
55    let database_url = db::resolve_database_url()?;
56    let index_ctx = config::Context {
57        database_url,
58        project_root: project_root.to_path_buf(),
59        project_id: project_id.clone(),
60        quiet,
61        falkordb: None,
62        qdrant: None,
63        embedding: None,
64        code_vectors: config::CodeVectorSettings::default(),
65        daemon_url: None,
66    };
67    let index_result = api::index_files(
68        api::IndexRequest {
69            project_root: project_root.to_path_buf(),
70            path_filter: None,
71            explicit_files: Vec::new(),
72            full: false,
73            require_cpp_semantics: false,
74            sync_projections: false,
75        },
76        &index_ctx,
77    )?;
78    if !quiet {
79        eprintln!(
80            "Indexed {} files, {} symbols in {}ms",
81            index_result.indexed_files,
82            index_result.symbols_indexed,
83            index_result.durations.total_ms
84        );
85    }
86
87    match format {
88        Format::Json => {
89            let mut result = serde_json::json!({
90                "project_id": project_id,
91                "project_root": project_root.to_string_lossy(),
92                "status": status,
93                "files_indexed": index_result.indexed_files,
94                "symbols_found": index_result.symbols_indexed,
95                "duration_ms": index_result.durations.total_ms,
96            });
97            if !installed_skills.is_empty() {
98                result["skills_installed"] = serde_json::json!(installed_skills);
99            }
100            output::print_json(&result)
101        }
102        Format::Text => {
103            if !quiet {
104                match status {
105                    "initialized" => {
106                        eprintln!(
107                            "Initialized project at {}\nProject ID: {}",
108                            project_root.display(),
109                            project_id
110                        );
111                    }
112                    "gobby" => {
113                        eprintln!(
114                            "Using gobby project: {} ({})",
115                            project_id,
116                            project_root.display()
117                        );
118                    }
119                    "isolated" | "linked-worktree" => {
120                        eprintln!(
121                            "Using {} code index: {} ({})",
122                            status,
123                            project_id,
124                            project_root.display()
125                        );
126                    }
127                    _ => {
128                        eprintln!(
129                            "Already initialized: {} ({})",
130                            project_id,
131                            project_root.display()
132                        );
133                    }
134                }
135            }
136            Ok(())
137        }
138    }
139}