vtcode_core/commands/
validate.rs

1//! Validate command implementation - environment and configuration validation
2
3use crate::config::constants::tools;
4use crate::config::types::AgentConfig;
5use crate::prompts::read_system_prompt_from_md;
6use crate::tools::ToolRegistry;
7use anyhow::Result;
8use console::style;
9use serde_json::json;
10
11/// Handle the validate command - check environment and configuration
12pub async fn handle_validate_command(
13    config: AgentConfig,
14    check_api: bool,
15    check_filesystem: bool,
16    _check_tools: bool,
17    _check_config: bool,
18    all: bool,
19) -> Result<()> {
20    println!(
21        "{}",
22        style(" Validating environment and configuration...")
23            .cyan()
24            .bold()
25    );
26
27    let mut all_checks = true;
28
29    // Check API connectivity if requested
30    if check_api || all {
31        println!("{}", style("Checking API connectivity...").dim());
32        match check_api_connectivity(&config).await {
33            Ok(_) => println!("  {} API connectivity OK", style("✓").green()),
34            Err(e) => {
35                println!("  {} API connectivity failed: {}", style("✗").red(), e);
36                all_checks = false;
37            }
38        }
39    }
40
41    // Check filesystem permissions if requested
42    if check_filesystem || all {
43        println!("{}", style("Checking filesystem permissions...").dim());
44        match check_filesystem_permissions(&config).await {
45            Ok(_) => println!("  {} Filesystem permissions OK", style("✓").green()),
46            Err(e) => {
47                println!("  {} Filesystem permissions issue: {}", style("✗").red(), e);
48                all_checks = false;
49            }
50        }
51    }
52
53    // Summary
54    if all_checks {
55        println!("{}", style("All validation checks passed!").green().bold());
56    } else {
57        println!(
58            "{}",
59            style(" Some validation checks failed.").yellow().bold()
60        );
61        println!("{}", style("Please address the issues above.").dim());
62    }
63
64    Ok(())
65}
66
67/// Check API connectivity
68async fn check_api_connectivity(config: &AgentConfig) -> Result<()> {
69    use crate::gemini::models::SystemInstruction;
70    use crate::gemini::{Client, Content, GenerateContentRequest};
71    use crate::prompts::generate_lightweight_instruction;
72
73    let mut client = Client::new(config.api_key.clone(), config.model.clone());
74    let contents = vec![Content::user_text("Hello")];
75    let lightweight_instruction = generate_lightweight_instruction();
76
77    // Convert Content to SystemInstruction
78    let system_instruction = if let Some(part) = lightweight_instruction.parts.first() {
79        if let Some(text) = part.as_text() {
80            SystemInstruction::new(text)
81        } else {
82            SystemInstruction::new(
83                read_system_prompt_from_md()
84                    .unwrap_or_else(|_| "You are a helpful coding assistant.".to_string()),
85            )
86        }
87    } else {
88        SystemInstruction::new(
89            read_system_prompt_from_md()
90                .unwrap_or_else(|_| "You are a helpful coding assistant.".to_string()),
91        )
92    };
93
94    let request = GenerateContentRequest {
95        contents,
96        tools: None,
97        tool_config: None,
98        generation_config: Some(json!({
99            "maxOutputTokens": 10,
100            "temperature": 0.1
101        })),
102        system_instruction: Some(system_instruction),
103        reasoning_config: None,
104    };
105
106    client.generate(&request).await?;
107    Ok(())
108}
109
110/// Check filesystem permissions
111async fn check_filesystem_permissions(config: &AgentConfig) -> Result<()> {
112    let mut registry = ToolRegistry::new(config.workspace.clone());
113
114    // Try to list files in the workspace
115    registry
116        .execute_tool(tools::LIST_FILES, json!({"path": ".", "max_items": 5}))
117        .await?;
118
119    // Try to create a test file
120    registry
121        .execute_tool(
122            tools::WRITE_FILE,
123            json!({
124                "path": ".vtcode_test",
125                "content": "test",
126                "overwrite": true
127            }),
128        )
129        .await?;
130
131    // Clean up test file
132    // Delete is supported via delete_file tool in ToolRegistry; we still validate permissions here
133
134    Ok(())
135}