vtcode_core/cli/args.rs
1//! CLI argument parsing and configuration
2
3use crate::config::models::ModelId;
4use clap::{ColorChoice, Parser, Subcommand, ValueHint};
5use std::path::PathBuf;
6
7/// Main CLI structure for vtcode with advanced features
8#[derive(Parser, Debug)]
9#[command(
10 name = "vtcode",
11 version,
12 about = "Advanced coding agent with Decision Ledger\n\nFeatures:\n• Single-agent architecture with Decision Ledger for reliable task execution\n• Tree-sitter powered code analysis (Rust, Python, JavaScript, TypeScript, Go, Java)\n• Multi-provider LLM support (Gemini, OpenAI, Anthropic, DeepSeek)\n• Real-time performance monitoring and benchmarking\n• Enhanced security with tool policies and sandboxing\n• Research-preview context management and conversation compression\n\nQuick Start:\n export GEMINI_API_KEY=\"your_key\"\n vtcode chat",
13 color = ColorChoice::Auto
14)]
15pub struct Cli {
16 /// Optional positional path to run vtcode against a different workspace
17 #[arg(
18 value_name = "WORKSPACE",
19 value_hint = ValueHint::DirPath,
20 global = true
21 )]
22 pub workspace_path: Option<PathBuf>,
23
24 /// LLM Model ID with latest model support
25 ///
26 /// Available providers & models:
27 /// • gemini-2.5-flash-lite-preview-06-17 - Fastest, most cost-effective (default)
28 /// • gemini-2.5-flash - Fast, cost-effective
29 /// • gemini-2.5-pro - Latest, most capable
30 /// • gpt-5 - OpenAI's latest
31 /// • claude-sonnet-4-20250514 - Anthropic's latest
32 /// • qwen/qwen3-4b-2507 - Qwen3 local model
33 /// • deepseek-reasoner - DeepSeek reasoning model
34 #[arg(long, global = true)]
35 pub model: Option<String>,
36
37 /// **LLM Provider** with expanded support
38 ///
39 /// Available providers:
40 /// • gemini - Google Gemini (default)
41 /// • openai - OpenAI GPT models
42 /// • anthropic - Anthropic Claude models
43 /// • deepseek - DeepSeek models
44 ///
45 /// Example: --provider deepseek
46 #[arg(long, global = true)]
47 pub provider: Option<String>,
48
49 /// **API key environment variable**\n\n**Auto-detects based on provider:**\n• Gemini: `GEMINI_API_KEY`\n• OpenAI: `OPENAI_API_KEY`\n• Anthropic: `ANTHROPIC_API_KEY`\n• DeepSeek: `DEEPSEEK_API_KEY`\n\n**Override:** --api-key-env CUSTOM_KEY
50 #[arg(long, global = true, default_value = crate::config::constants::defaults::DEFAULT_API_KEY_ENV)]
51 pub api_key_env: String,
52
53 /// **Workspace root directory for file operations**
54 ///
55 /// Security: All file operations restricted to this path
56 /// Default: Current directory
57 #[arg(
58 long,
59 global = true,
60 alias = "workspace-dir",
61 value_name = "PATH",
62 value_hint = ValueHint::DirPath
63 )]
64 pub workspace: Option<PathBuf>,
65
66 /// **Enable tree-sitter code analysis**
67 ///
68 /// Features:
69 /// • AST-based code parsing
70 /// • Symbol extraction and navigation
71 /// • Intelligent refactoring suggestions
72 /// • Multi-language support (Rust, Python, JS, TS, Go, Java)
73 #[arg(long, global = true)]
74 pub enable_tree_sitter: bool,
75
76 /// **Enable performance monitoring**
77 ///
78 /// Tracks:
79 /// • Token usage and API costs
80 /// • Response times and latency
81 /// • Tool execution metrics
82 /// • Memory usage patterns
83 #[arg(long, global = true)]
84 pub performance_monitoring: bool,
85
86 /// **Enable research-preview features**
87 ///
88 /// Includes:
89 /// • Advanced context compression
90 /// • Conversation summarization
91 /// • Enhanced error recovery
92 /// • Decision transparency tracking
93 #[arg(long, global = true)]
94 pub research_preview: bool,
95
96 /// **Security level** for tool execution
97 ///
98 /// Options:
99 /// • strict - Maximum security, prompt for all tools
100 /// • moderate - Balance security and usability
101 /// • permissive - Minimal restrictions (not recommended)
102 #[arg(long, global = true, default_value = "moderate")]
103 pub security_level: String,
104
105 /// **Show diffs for file changes in chat interface**
106 ///
107 /// Features:
108 /// • Real-time diff rendering
109 /// • Syntax highlighting
110 /// • Line-by-line changes
111 /// • Before/after comparison
112 #[arg(long, global = true)]
113 pub show_file_diffs: bool,
114
115 /// **Maximum concurrent async operations**
116 ///
117 /// Default: 5
118 /// Higher values: Better performance but more resource usage
119 #[arg(long, global = true, default_value_t = 5)]
120 pub max_concurrent_ops: usize,
121
122 /// **Maximum API requests per minute**
123 ///
124 /// Default: 30
125 /// Purpose: Prevents rate limiting
126 #[arg(long, global = true, default_value_t = 30)]
127 pub api_rate_limit: usize,
128
129 /// **Maximum tool calls per session**
130 ///
131 /// Default: 10
132 /// Purpose: Prevents runaway execution
133 #[arg(long, global = true, default_value_t = 10)]
134 pub max_tool_calls: usize,
135
136 /// **Enable debug output for troubleshooting**
137 ///
138 /// Shows:
139 /// • Tool call details
140 /// • API request/response
141 /// • Internal agent state
142 /// • Performance metrics
143 #[arg(long, global = true)]
144 pub debug: bool,
145
146 /// **Enable verbose logging**
147 ///
148 /// Includes:
149 /// • Detailed operation logs
150 /// • Context management info
151 /// • Agent coordination details
152 #[arg(long, global = true)]
153 pub verbose: bool,
154
155 /// **Configuration file path**
156 ///
157 /// Supported formats: TOML
158 /// Default locations: ./vtcode.toml, ~/.vtcode/vtcode.toml
159 #[arg(long, global = true)]
160 pub config: Option<PathBuf>,
161
162 /// Log level (error, warn, info, debug, trace)
163 ///
164 /// Default: info
165 #[arg(long, global = true, default_value = "info")]
166 pub log_level: String,
167
168 /// Disable color output
169 ///
170 /// Useful for: Log files, CI/CD pipelines
171 #[arg(long, global = true)]
172 pub no_color: bool,
173
174 /// Select UI theme for ANSI styling (e.g., ciapre-dark, ciapre-blue)
175 #[arg(long, global = true, value_name = "THEME")]
176 pub theme: Option<String>,
177
178 /// **Skip safety confirmations**
179 ///
180 /// Warning: Reduces security, use with caution
181 #[arg(long, global = true)]
182 pub skip_confirmations: bool,
183
184 /// **Enable full-auto mode (no interaction)**
185 ///
186 /// Runs the agent without pausing for approvals. Requires enabling in configuration.
187 #[arg(long, global = true)]
188 pub full_auto: bool,
189
190 #[command(subcommand)]
191 pub command: Option<Commands>,
192}
193
194/// Available commands with comprehensive features
195#[derive(Subcommand, Debug)]
196pub enum Commands {
197 /// **Interactive AI coding assistant** with advanced capabilities
198 ///
199 /// Features:
200 /// • Real-time code generation and editing
201 /// • Tree-sitter powered analysis
202 /// • Research-preview context management
203 ///
204 /// Usage: vtcode chat
205 Chat,
206
207 /// **Single prompt mode** - prints model reply without tools
208 ///
209 /// Perfect for:
210 /// • Quick questions
211 /// • Code explanations
212 /// • Simple queries
213 ///
214 /// Example: vtcode ask "Explain Rust ownership"
215 Ask { prompt: String },
216
217 /// **Verbose interactive chat** with enhanced transparency
218 ///
219 /// Shows:
220 /// • Tool execution details
221 /// • API request/response
222 /// • Performance metrics
223 ///
224 /// Usage: vtcode chat-verbose
225 ChatVerbose,
226
227 /// **Analyze workspace** with tree-sitter integration
228 ///
229 /// Provides:
230 /// • Project structure analysis
231 /// • Language detection
232 /// • Code complexity metrics
233 /// • Dependency insights
234 /// • Symbol extraction
235 ///
236 /// Usage: vtcode analyze
237 Analyze,
238
239 /// **Display performance metrics** and system status\n\n**Shows:**\n• Token usage and API costs\n• Response times and latency\n• Tool execution statistics\n• Memory usage patterns\n\n**Usage:** vtcode performance
240 Performance,
241
242 /// Pretty-print trajectory logs and show basic analytics
243 ///
244 /// Sources:
245 /// • logs/trajectory.jsonl (default)
246 /// Options:
247 /// • --file to specify an alternate path
248 /// • --top to limit report rows (default: 10)
249 ///
250 /// Shows:
251 /// • Class distribution with percentages
252 /// • Model usage statistics
253 /// • Tool success rates with status indicators
254 /// • Time range of logged activity
255 #[command(name = "trajectory")]
256 Trajectory {
257 /// Optional path to trajectory JSONL file
258 #[arg(long)]
259 file: Option<std::path::PathBuf>,
260 /// Number of top entries to show for each section
261 #[arg(long, default_value_t = 10)]
262 top: usize,
263 },
264
265 /// **Benchmark against SWE-bench evaluation framework**
266 ///
267 /// Features:
268 /// • Automated performance testing
269 /// • Comparative analysis across models
270 /// • Benchmark scoring and metrics
271 /// • Optimization insights
272 ///
273 /// Usage: vtcode benchmark
274 Benchmark,
275
276 /// **Create complete Rust project with advanced features**
277 ///
278 /// Features:
279 /// • Web frameworks (Axum, Rocket, Warp)
280 /// • Database integration
281 /// • Authentication systems
282 /// • Testing setup
283 /// • Tree-sitter integration
284 ///
285 /// Example: vtcode create-project myapp web,auth,db
286 CreateProject { name: String, features: Vec<String> },
287
288 /// **Compress conversation context** for long-running sessions
289 ///
290 /// Benefits:
291 /// • Reduced token usage
292 /// • Faster responses
293 /// • Memory optimization
294 /// • Context preservation
295 ///
296 /// Usage: vtcode compress-context
297 CompressContext,
298
299 /// **Revert agent to a previous snapshot
300 ///
301 /// Features:
302 /// • Revert to any previous turn
303 /// • Partial reverts (memory, context, full)
304 /// • Safe rollback with validation
305 ///
306 /// Examples:
307 /// vtcode revert --turn 5
308 /// vtcode revert --turn 3 --partial memory
309 Revert {
310 /// Turn number to revert to
311 ///
312 /// Required: Yes
313 /// Example: 5
314 #[arg(short, long)]
315 turn: usize,
316
317 /// Scope of revert operation
318 ///
319 /// Options: memory, context, full
320 /// Default: full
321 /// Examples:
322 /// --partial memory (revert conversation only)
323 /// --partial context (revert decisions/errors only)
324 #[arg(short, long)]
325 partial: Option<String>,
326 },
327
328 /// **List all available snapshots**
329 ///
330 /// Shows:
331 /// • Snapshot ID and turn number
332 /// • Creation timestamp
333 /// • Description
334 /// • File size and compression status
335 ///
336 /// Usage: vtcode snapshots
337 Snapshots,
338
339 /// **Clean up old snapshots**
340 ///
341 /// Features:
342 /// • Remove snapshots beyond limit
343 /// • Configurable retention policy
344 /// • Safe deletion with confirmation
345 ///
346 /// Examples:
347 /// vtcode cleanup-snapshots
348 /// vtcode cleanup-snapshots --max 20
349 #[command(name = "cleanup-snapshots")]
350 CleanupSnapshots {
351 /// Maximum number of snapshots to keep
352 ///
353 /// Default: 50
354 /// Example: --max 20
355 #[arg(short, long, default_value_t = 50)]
356 max: usize,
357 },
358
359 /// **Initialize project** with enhanced dot-folder structure
360 ///
361 /// Features:
362 /// • Creates project directory structure
363 /// • Sets up config, cache, embeddings directories
364 /// • Creates .project metadata file
365 /// • Tree-sitter parser setup
366 ///
367 /// Usage: vtcode init
368 Init,
369
370 /// **Initialize project with dot-folder structure** - sets up ~/.vtcode/projects/<project-name> structure
371 ///
372 /// Features:
373 /// • Creates project directory structure in ~/.vtcode/projects/
374 /// • Sets up config, cache, embeddings, and retrieval directories
375 /// • Creates .project metadata file
376 /// • Migrates existing config/cache files with user confirmation
377 ///
378 /// Examples:
379 /// vtcode init-project
380 /// vtcode init-project --name my-project
381 /// vtcode init-project --force
382 #[command(name = "init-project")]
383 InitProject {
384 /// Project name - defaults to current directory name
385 #[arg(long)]
386 name: Option<String>,
387
388 /// Force initialization - overwrite existing project structure
389 #[arg(long)]
390 force: bool,
391
392 /// Migrate existing files - move existing config/cache files to new structure
393 #[arg(long)]
394 migrate: bool,
395 },
396
397 /// **Generate configuration file - creates a vtcode.toml configuration file
398 ///
399 /// Features:
400 /// • Generate default configuration
401 /// • Support for global (home directory) and local configuration
402 /// • TOML format with comprehensive settings
403 /// • Tree-sitter and performance monitoring settings
404 ///
405 /// Examples:
406 /// vtcode config
407 /// vtcode config --output ./custom-config.toml
408 /// vtcode config --global
409 Config {
410 /// Output file path - where to save the configuration file
411 #[arg(long)]
412 output: Option<std::path::PathBuf>,
413
414 /// Create in user home directory - creates ~/.vtcode/vtcode.toml
415 #[arg(long)]
416 global: bool,
417 },
418
419 /// **Manage tool execution policies** - control which tools the agent can use
420 ///
421 /// Features:
422 /// • Granular tool permissions
423 /// • Security level presets
424 /// • Audit logging
425 /// • Safe tool execution
426 ///
427 /// Examples:
428 /// vtcode tool-policy status
429 /// vtcode tool-policy allow file-write
430 /// vtcode tool-policy deny shell-exec
431 #[command(name = "tool-policy")]
432 ToolPolicy {
433 #[command(subcommand)]
434 command: crate::cli::tool_policy_commands::ToolPolicyCommands,
435 },
436
437 /// **Manage models and providers** - configure and switch between LLM providers\n\n**Features:**\n• Support for latest models (DeepSeek, etc.)\n• Provider configuration and testing\n• Model performance comparison\n• API key management\n\n**Examples:**\n vtcode models list\n vtcode models set-provider deepseek\n vtcode models set-model deepseek-reasoner
438 Models {
439 #[command(subcommand)]
440 command: ModelCommands,
441 },
442
443 /// **Security and safety management**\n\n**Features:**\n• Security scanning and vulnerability detection\n• Audit logging and monitoring\n• Access control management\n• Privacy protection settings\n\n**Usage:** vtcode security
444 Security,
445
446 /// **Tree-sitter code analysis tools**\n\n**Features:**\n• AST-based code parsing\n• Symbol extraction and navigation\n• Code complexity analysis\n• Multi-language refactoring\n\n**Usage:** vtcode tree-sitter
447 #[command(name = "tree-sitter")]
448 TreeSitter,
449
450 /// **Generate or display man pages** for VTCode commands\n\n**Features:**\n• Generate Unix man pages for all commands\n• Display detailed command documentation\n• Save man pages to files\n• Comprehensive help for all VTCode features\n\n**Examples:**\n vtcode man\n vtcode man chat\n vtcode man chat --output chat.1
451 Man {
452 /// **Command name** to generate man page for (optional)\n\n**Available commands:**\n• chat, ask, analyze, performance, benchmark\n• create-project, init, man\n\n**If not specified, shows main VTCode man page**
453 command: Option<String>,
454
455 /// **Output file path** to save man page\n\n**Format:** Standard Unix man page format (.1, .8, etc.)\n**Default:** Display to stdout
456 #[arg(short, long)]
457 output: Option<std::path::PathBuf>,
458 },
459}
460
461/// Model management commands with concise, actionable help
462#[derive(Subcommand, Debug)]
463pub enum ModelCommands {
464 /// List all providers and models with status indicators
465 List,
466
467 /// Set default provider (gemini, openai, anthropic, deepseek)
468 #[command(name = "set-provider")]
469 SetProvider {
470 /// Provider name to set as default
471 provider: String,
472 },
473
474 /// Set default model (e.g., deepseek-reasoner, gpt-5, claude-sonnet-4-20250514)
475 #[command(name = "set-model")]
476 SetModel {
477 /// Model name to set as default
478 model: String,
479 },
480
481 /// Configure provider settings (API keys, base URLs, models)
482 Config {
483 /// Provider name to configure
484 provider: String,
485
486 /// API key for the provider
487 #[arg(long)]
488 api_key: Option<String>,
489
490 /// Base URL for local providers
491 #[arg(long)]
492 base_url: Option<String>,
493
494 /// Default model for this provider
495 #[arg(long)]
496 model: Option<String>,
497 },
498
499 /// Test provider connectivity and validate configuration
500 Test {
501 /// Provider name to test
502 provider: String,
503 },
504
505 /// Compare model performance across providers (coming soon)
506 Compare,
507
508 /// Show detailed model information and specifications
509 Info {
510 /// Model name to get information about
511 model: String,
512 },
513}
514
515/// Configuration file structure with latest features
516#[derive(Debug)]
517pub struct ConfigFile {
518 pub model: Option<String>,
519 pub provider: Option<String>,
520 pub api_key_env: Option<String>,
521 pub verbose: Option<bool>,
522 pub log_level: Option<String>,
523 pub workspace: Option<PathBuf>,
524 pub tools: Option<ToolConfig>,
525 pub context: Option<ContextConfig>,
526 pub logging: Option<LoggingConfig>,
527 pub tree_sitter: Option<TreeSitterConfig>,
528 pub performance: Option<PerformanceConfig>,
529 pub security: Option<SecurityConfig>,
530}
531
532/// Tool configuration from config file
533#[derive(Debug, serde::Deserialize)]
534pub struct ToolConfig {
535 pub enable_validation: Option<bool>,
536 pub max_execution_time_seconds: Option<u64>,
537 pub allow_file_creation: Option<bool>,
538 pub allow_file_deletion: Option<bool>,
539}
540
541/// Context management configuration
542#[derive(Debug, serde::Deserialize)]
543pub struct ContextConfig {
544 pub max_context_length: Option<usize>,
545 pub compression_threshold: Option<usize>,
546 pub summarization_interval: Option<usize>,
547}
548
549/// Logging configuration
550#[derive(Debug, serde::Deserialize)]
551pub struct LoggingConfig {
552 pub file_logging: Option<bool>,
553 pub log_directory: Option<String>,
554 pub max_log_files: Option<usize>,
555 pub max_log_size_mb: Option<usize>,
556}
557
558/// Tree-sitter configuration
559#[derive(Debug, serde::Deserialize)]
560pub struct TreeSitterConfig {
561 pub enabled: Option<bool>,
562 pub supported_languages: Option<Vec<String>>,
563 pub max_file_size_kb: Option<usize>,
564 pub enable_symbol_extraction: Option<bool>,
565 pub enable_complexity_analysis: Option<bool>,
566}
567
568/// Performance monitoring configuration
569#[derive(Debug, serde::Deserialize)]
570pub struct PerformanceConfig {
571 pub enabled: Option<bool>,
572 pub track_token_usage: Option<bool>,
573 pub track_api_costs: Option<bool>,
574 pub track_response_times: Option<bool>,
575 pub enable_benchmarking: Option<bool>,
576 pub metrics_retention_days: Option<usize>,
577}
578
579/// Security configuration
580#[derive(Debug, serde::Deserialize)]
581pub struct SecurityConfig {
582 pub level: Option<String>,
583 pub enable_audit_logging: Option<bool>,
584 pub enable_vulnerability_scanning: Option<bool>,
585 pub allow_external_urls: Option<bool>,
586 pub max_file_access_depth: Option<usize>,
587}
588
589impl Default for Cli {
590 fn default() -> Self {
591 Self {
592 workspace_path: None,
593 model: Some(ModelId::default().as_str().to_string()),
594 provider: Some("gemini".to_string()),
595 api_key_env: "GEMINI_API_KEY".to_string(),
596 workspace: None,
597 enable_tree_sitter: false,
598 performance_monitoring: false,
599 research_preview: false,
600 security_level: "moderate".to_string(),
601 show_file_diffs: false,
602 max_concurrent_ops: 5,
603 api_rate_limit: 30,
604 max_tool_calls: 10,
605 verbose: false,
606 config: None,
607 log_level: "info".to_string(),
608 no_color: false,
609 theme: None,
610 skip_confirmations: false,
611 full_auto: false,
612 debug: false,
613 command: Some(Commands::Chat),
614 }
615 }
616}
617
618impl Cli {
619 /// Get the model to use, with fallback to default
620 pub fn get_model(&self) -> String {
621 self.model
622 .clone()
623 .unwrap_or_else(|| ModelId::default().as_str().to_string())
624 }
625
626 /// Load configuration from a simple TOML-like file without external deps
627 ///
628 /// Supported keys (top-level): model, api_key_env, verbose, log_level, workspace
629 /// Example:
630 /// model = "gemini-2.5-flash-lite-preview-06-17"
631 /// api_key_env = "GEMINI_API_KEY"
632 /// verbose = true
633 /// log_level = "info"
634 /// workspace = "/path/to/workspace"
635 pub fn load_config(&self) -> Result<ConfigFile, Box<dyn std::error::Error>> {
636 use std::fs;
637 use std::path::Path;
638
639 // Resolve candidate path
640 let path = if let Some(p) = &self.config {
641 p.clone()
642 } else {
643 let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
644 let primary = cwd.join("vtcode.toml");
645 let secondary = cwd.join(".vtcode.toml");
646 if primary.exists() {
647 primary
648 } else if secondary.exists() {
649 secondary
650 } else {
651 // No config file; return empty config
652 return Ok(ConfigFile {
653 model: None,
654 provider: None,
655 api_key_env: None,
656 verbose: None,
657 log_level: None,
658 workspace: None,
659 tools: None,
660 context: None,
661 logging: None,
662 tree_sitter: None,
663 performance: None,
664 security: None,
665 });
666 }
667 };
668
669 let text = fs::read_to_string(&path)?;
670
671 // Very small parser: key = value, supports quoted strings, booleans, and plain paths
672 let mut cfg = ConfigFile {
673 model: None,
674 provider: None,
675 api_key_env: None,
676 verbose: None,
677 log_level: None,
678 workspace: None,
679 tools: None,
680 context: None,
681 logging: None,
682 tree_sitter: None,
683 performance: None,
684 security: None,
685 };
686
687 for raw_line in text.lines() {
688 let line = raw_line.trim();
689 if line.is_empty() || line.starts_with('#') || line.starts_with("//") {
690 continue;
691 }
692 // Strip inline comments after '#'
693 let line = match line.find('#') {
694 Some(idx) => &line[..idx],
695 None => line,
696 }
697 .trim();
698
699 // Expect key = value
700 let mut parts = line.splitn(2, '=');
701 let key = parts.next().map(|s| s.trim()).unwrap_or("");
702 let val = parts.next().map(|s| s.trim()).unwrap_or("");
703 if key.is_empty() || val.is_empty() {
704 continue;
705 }
706
707 // Remove surrounding quotes if present
708 let unquote = |s: &str| -> String {
709 let s = s.trim();
710 if (s.starts_with('"') && s.ends_with('"'))
711 || (s.starts_with('\'') && s.ends_with('\''))
712 {
713 s[1..s.len() - 1].to_string()
714 } else {
715 s.to_string()
716 }
717 };
718
719 match key {
720 "model" => cfg.model = Some(unquote(val)),
721 "api_key_env" => cfg.api_key_env = Some(unquote(val)),
722 "verbose" => {
723 let v = unquote(val).to_lowercase();
724 cfg.verbose = Some(matches!(v.as_str(), "true" | "1" | "yes"));
725 }
726 "log_level" => cfg.log_level = Some(unquote(val)),
727 "workspace" => {
728 let v = unquote(val);
729 let p = if Path::new(&v).is_absolute() {
730 PathBuf::from(v)
731 } else {
732 // Resolve relative to config file directory
733 let base = path.parent().unwrap_or(Path::new("."));
734 base.join(v)
735 };
736 cfg.workspace = Some(p);
737 }
738 _ => {
739 // Ignore unknown keys in this minimal parser
740 }
741 }
742 }
743
744 Ok(cfg)
745 }
746
747 /// Get the effective workspace path
748 pub fn get_workspace(&self) -> std::path::PathBuf {
749 self.workspace
750 .clone()
751 .unwrap_or_else(|| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
752 }
753
754 /// Get the effective API key environment variable
755 pub fn get_api_key_env(&self) -> String {
756 self.api_key_env.clone()
757 }
758
759 /// Check if verbose mode is enabled
760 pub fn is_verbose(&self) -> bool {
761 self.verbose
762 }
763
764 /// Check if tree-sitter analysis is enabled
765 pub fn is_tree_sitter_enabled(&self) -> bool {
766 self.enable_tree_sitter
767 }
768
769 /// Check if performance monitoring is enabled
770 pub fn is_performance_monitoring_enabled(&self) -> bool {
771 self.performance_monitoring
772 }
773
774 /// Check if research-preview features are enabled
775 pub fn is_research_preview_enabled(&self) -> bool {
776 self.research_preview
777 }
778
779 /// Get the security level
780 pub fn get_security_level(&self) -> &str {
781 &self.security_level
782 }
783
784 /// Check if debug mode is enabled (includes verbose)
785 pub fn is_debug_mode(&self) -> bool {
786 self.debug || self.verbose
787 }
788}