Skip to main content

vtcode_core/commands/
analyze.rs

1//! Analyze command implementation - workspace analysis
2
3use crate::config::constants::tools;
4use crate::config::types::{AgentConfig, AnalysisDepth, OutputFormat};
5use crate::tools::ToolRegistry;
6use crate::utils::colors::style;
7use anyhow::Result;
8use serde_json::json;
9
10/// Handle the analyze command - comprehensive workspace analysis
11pub async fn handle_analyze_command(
12    config: AgentConfig,
13    depth: String,
14    format: String,
15) -> Result<()> {
16    println!("{}", style("Analyzing workspace...").cyan().bold());
17
18    let depth = match depth.to_lowercase().as_str() {
19        "basic" => AnalysisDepth::Basic,
20        "standard" => AnalysisDepth::Standard,
21        "deep" => AnalysisDepth::Deep,
22        _ => {
23            println!("{}", style("Invalid depth. Using 'standard'.").red());
24            AnalysisDepth::Standard
25        }
26    };
27
28    let _output_format = match format.to_lowercase().as_str() {
29        "text" => OutputFormat::Text,
30        "json" => OutputFormat::Json,
31        "html" => OutputFormat::Html,
32        _ => {
33            println!("{}", style("Invalid format. Using 'text'.").red());
34            OutputFormat::Text
35        }
36    };
37
38    let registry = ToolRegistry::new(config.workspace.clone()).await;
39
40    // Step 1: Get high-level directory structure
41    println!("{}", style("1. Getting workspace structure...").dim());
42    let root_files = registry
43        .execute_tool(
44            tools::UNIFIED_SEARCH,
45            json!({"action": "list", "path": ".", "max_items": 50}),
46        )
47        .await;
48
49    match root_files {
50        Ok(result) => {
51            println!("{}", style("Root directory structure obtained").green());
52            if let Some(files_array) = result.get("files") {
53                println!(
54                    "   Found {} files/directories in root",
55                    files_array.as_array().unwrap_or(&vec![]).len()
56                );
57            }
58        }
59        Err(e) => println!("{} {}", style("Failed to list root directory:").red(), e),
60    }
61
62    // Step 2: Look for important project files
63    println!("{}", style("2. Identifying project type...").dim());
64    let important_files = vec![
65        "README.md",
66        "Cargo.toml",
67        "package.json",
68        "go.mod",
69        "requirements.txt",
70        "Makefile",
71    ];
72
73    for file in important_files {
74        let check_file = registry
75            .execute_tool(
76                tools::UNIFIED_SEARCH,
77                json!({"action": "list", "path": ".", "include_hidden": false}),
78            )
79            .await;
80        if let Ok(result) = check_file
81            && let Some(files) = result.get("files")
82            && let Some(files_array) = files.as_array()
83        {
84            for file_obj in files_array {
85                if let Some(path) = file_obj.get("path")
86                    && path.as_str().unwrap_or("") == file
87                {
88                    println!("   {} Detected: {}", style("Detected").green(), file);
89                    break;
90                }
91            }
92        }
93    }
94
95    // Step 3: Read key configuration files
96    println!("{}", style("3. Reading project configuration...").dim());
97    let config_files = vec!["AGENTS.md", "README.md", "Cargo.toml", "package.json"];
98
99    for config_file in config_files {
100        let read_result = registry
101            .execute_tool(
102                tools::READ_FILE,
103                json!({"path": config_file, "max_bytes": 2000}),
104            )
105            .await;
106        if let Ok(result) = read_result {
107            println!(
108                "   {} Read {} ({} bytes)",
109                style("Read").green(),
110                config_file,
111                result
112                    .get("metadata")
113                    .and_then(|m| m.get("size"))
114                    .unwrap_or(&serde_json::json!(null))
115            );
116        }
117    }
118
119    // Step 4: Analyze source code structure
120    println!("{}", style("4. Analyzing source code structure...").dim());
121
122    // Check for common source directories
123    let src_dirs = vec!["src", "lib", "pkg", "internal", "cmd"];
124    for dir in src_dirs {
125        let check_dir = registry
126            .execute_tool(
127                tools::UNIFIED_SEARCH,
128                json!({"action": "list", "path": ".", "include_hidden": false}),
129            )
130            .await;
131        if let Ok(result) = check_dir
132            && let Some(files) = result.get("files")
133            && let Some(files_array) = files.as_array()
134        {
135            for file_obj in files_array {
136                if let Some(path) = file_obj.get("path")
137                    && path.as_str().unwrap_or("") == dir
138                {
139                    println!(
140                        "   {} Found source directory: {}",
141                        style("Found").green(),
142                        dir
143                    );
144                    break;
145                }
146            }
147        }
148    }
149
150    if matches!(depth, AnalysisDepth::Deep) {
151        println!(
152            "{}",
153            style("Deep analysis: use grep/search tools for detailed code inspection.").dim()
154        );
155    }
156
157    println!("{}", style("Workspace analysis complete!").green().bold());
158    println!(
159        "{}",
160        style("You can now ask me specific questions about the codebase.").dim()
161    );
162
163    Ok(())
164}