syncable_cli/cli.rs
1use clap::{Parser, Subcommand, ValueEnum};
2use std::path::PathBuf;
3
4#[derive(Parser)]
5#[command(name = "sync-ctl")]
6#[command(version = env!("CARGO_PKG_VERSION"))]
7#[command(about = "Generate Infrastructure as Code from your codebase")]
8#[command(
9 long_about = "A powerful CLI tool that analyzes your codebase and automatically generates optimized Infrastructure as Code configurations including Dockerfiles, Docker Compose files, and Terraform configurations"
10)]
11pub struct Cli {
12 #[command(subcommand)]
13 pub command: Commands,
14
15 /// Path to configuration file
16 #[arg(short, long, global = true, value_name = "FILE")]
17 pub config: Option<PathBuf>,
18
19 /// Enable verbose logging (-v for info, -vv for debug, -vvv for trace)
20 #[arg(short, long, global = true, action = clap::ArgAction::Count)]
21 pub verbose: u8,
22
23 /// Suppress all output except errors
24 #[arg(short, long, global = true)]
25 pub quiet: bool,
26
27 /// Output in JSON format where applicable
28 #[arg(long, global = true)]
29 pub json: bool,
30
31 /// Clear the update check cache and force a new check
32 #[arg(long, global = true)]
33 pub clear_update_cache: bool,
34
35 /// Disable telemetry data collection
36 #[arg(long, global = true)]
37 pub disable_telemetry: bool,
38}
39
40#[derive(Subcommand)]
41pub enum Commands {
42 /// Analyze a project and display detected components
43 Analyze {
44 /// Path to the project directory to analyze
45 #[arg(value_name = "PROJECT_PATH")]
46 path: PathBuf,
47
48 /// Output analysis results in JSON format
49 #[arg(short, long)]
50 json: bool,
51
52 /// Show detailed analysis information (legacy format)
53 #[arg(short, long, conflicts_with = "display")]
54 detailed: bool,
55
56 /// Display format for analysis results
57 #[arg(long, value_enum, default_value = "matrix")]
58 display: Option<DisplayFormat>,
59
60 /// Only analyze specific aspects (languages, frameworks, dependencies)
61 #[arg(long, value_delimiter = ',')]
62 only: Option<Vec<String>>,
63
64 /// Color scheme for terminal output (auto-detect, dark, light)
65 #[arg(long, value_enum, default_value = "auto")]
66 color_scheme: Option<ColorScheme>,
67
68 /// Output compressed JSON for AI agent consumption (implies --json)
69 #[arg(long)]
70 agent: bool,
71 },
72
73 /// Generate IaC files for a project
74 Generate {
75 /// Path to the project directory to analyze
76 #[arg(value_name = "PROJECT_PATH")]
77 path: PathBuf,
78
79 /// Output directory for generated files
80 #[arg(short, long, value_name = "OUTPUT_DIR")]
81 output: Option<PathBuf>,
82
83 /// Generate Dockerfile
84 #[arg(long)]
85 dockerfile: bool,
86
87 /// Generate Docker Compose file
88 #[arg(long)]
89 compose: bool,
90
91 /// Generate Terraform configuration
92 #[arg(long)]
93 terraform: bool,
94
95 /// Generate all supported IaC files
96 #[arg(long, conflicts_with_all = ["dockerfile", "compose", "terraform"])]
97 all: bool,
98
99 /// Perform a dry run without creating files
100 #[arg(long)]
101 dry_run: bool,
102
103 /// Overwrite existing files
104 #[arg(long)]
105 force: bool,
106 },
107
108 /// Validate existing IaC files against best practices
109 Validate {
110 /// Path to the directory containing IaC files
111 #[arg(value_name = "PATH")]
112 path: PathBuf,
113
114 /// Types of files to validate
115 #[arg(long, value_delimiter = ',')]
116 types: Option<Vec<String>>,
117
118 /// Fix issues automatically where possible
119 #[arg(long)]
120 fix: bool,
121
122 /// Output compressed JSON for AI agent consumption (implies --json)
123 #[arg(long)]
124 agent: bool,
125 },
126
127 /// Show supported languages and frameworks
128 Support {
129 /// Show only languages
130 #[arg(long)]
131 languages: bool,
132
133 /// Show only frameworks
134 #[arg(long)]
135 frameworks: bool,
136
137 /// Show detailed information
138 #[arg(short, long)]
139 detailed: bool,
140 },
141
142 /// Analyze project dependencies in detail
143 Dependencies {
144 /// Path to the project directory to analyze
145 #[arg(value_name = "PROJECT_PATH")]
146 path: PathBuf,
147
148 /// Show license information for dependencies
149 #[arg(long)]
150 licenses: bool,
151
152 /// Check for known vulnerabilities
153 #[arg(long)]
154 vulnerabilities: bool,
155
156 /// Show only production dependencies
157 #[arg(long, conflicts_with = "dev_only")]
158 prod_only: bool,
159
160 /// Show only development dependencies
161 #[arg(long, conflicts_with = "prod_only")]
162 dev_only: bool,
163
164 /// Output format
165 #[arg(long, value_enum, default_value = "table")]
166 format: OutputFormat,
167
168 /// Output compressed JSON for AI agent consumption (implies --json)
169 #[arg(long)]
170 agent: bool,
171 },
172
173 /// Check dependencies for known vulnerabilities
174 Vulnerabilities {
175 /// Check vulnerabilities in a specific path
176 #[arg(default_value = ".")]
177 path: PathBuf,
178
179 /// Show only vulnerabilities with severity >= threshold
180 #[arg(long, value_enum)]
181 severity: Option<SeverityThreshold>,
182
183 /// Output format
184 #[arg(long, value_enum, default_value = "table")]
185 format: OutputFormat,
186
187 /// Export report to file
188 #[arg(long)]
189 output: Option<PathBuf>,
190
191 /// Output compressed JSON for AI agent consumption (implies --json)
192 #[arg(long)]
193 agent: bool,
194 },
195
196 /// Perform comprehensive security analysis
197 Security {
198 /// Path to the project directory to analyze
199 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
200 path: PathBuf,
201
202 /// Security scan mode (lightning, fast, balanced, thorough, paranoid)
203 #[arg(long, value_enum, default_value = "thorough")]
204 mode: SecurityScanMode,
205
206 /// Include low severity findings
207 #[arg(long)]
208 include_low: bool,
209
210 /// Skip secrets detection
211 #[arg(long)]
212 no_secrets: bool,
213
214 /// Skip code pattern analysis
215 #[arg(long)]
216 no_code_patterns: bool,
217
218 /// Skip infrastructure analysis (not implemented yet)
219 #[arg(long, hide = true)]
220 no_infrastructure: bool,
221
222 /// Skip compliance checks (not implemented yet)
223 #[arg(long, hide = true)]
224 no_compliance: bool,
225
226 /// Compliance frameworks to check (not implemented yet)
227 #[arg(long, value_delimiter = ',', hide = true)]
228 frameworks: Vec<String>,
229
230 /// Output format
231 #[arg(long, value_enum, default_value = "table")]
232 format: OutputFormat,
233
234 /// Export report to file
235 #[arg(long)]
236 output: Option<PathBuf>,
237
238 /// Exit with error code on security findings
239 #[arg(long)]
240 fail_on_findings: bool,
241
242 /// Output compressed JSON for AI agent consumption (implies --json)
243 #[arg(long)]
244 agent: bool,
245 },
246
247 /// Manage vulnerability scanning tools
248 Tools {
249 #[command(subcommand)]
250 command: ToolsCommand,
251 },
252
253 /// Analyze Kubernetes manifests for resource optimization opportunities
254 Optimize {
255 /// Path to Kubernetes manifests (file or directory)
256 #[arg(value_name = "PATH", default_value = ".")]
257 path: PathBuf,
258
259 /// Connect to a live Kubernetes cluster for metrics-based recommendations
260 /// Uses current kubeconfig context, or specify a context name
261 #[arg(long, short = 'k', value_name = "CONTEXT", default_missing_value = "current", num_args = 0..=1)]
262 cluster: Option<String>,
263
264 /// Prometheus URL for historical metrics (e.g., http://localhost:9090)
265 #[arg(long, value_name = "URL")]
266 prometheus: Option<String>,
267
268 /// Target namespace(s) for cluster analysis (comma-separated, or * for all)
269 #[arg(long, short = 'n', value_name = "NAMESPACE")]
270 namespace: Option<String>,
271
272 /// Analysis period for historical metrics (e.g., 7d, 30d)
273 #[arg(long, short = 'p', default_value = "7d")]
274 period: String,
275
276 /// Minimum severity to report (critical, warning, info)
277 #[arg(long, short = 's')]
278 severity: Option<String>,
279
280 /// Minimum waste percentage threshold (0-100)
281 #[arg(long, short = 't')]
282 threshold: Option<u8>,
283
284 /// Safety margin percentage for recommendations (default: 20)
285 #[arg(long)]
286 safety_margin: Option<u8>,
287
288 /// Include info-level suggestions
289 #[arg(long)]
290 include_info: bool,
291
292 /// Include system namespaces (kube-system, etc.)
293 #[arg(long)]
294 include_system: bool,
295
296 /// Output format (table, json, yaml)
297 #[arg(long, value_enum, default_value = "table")]
298 format: OutputFormat,
299
300 /// Write report to file
301 #[arg(long, short = 'o')]
302 output: Option<PathBuf>,
303
304 /// Generate fix suggestions
305 #[arg(long)]
306 fix: bool,
307
308 /// Apply fixes to manifest files (requires --fix or --full with live cluster)
309 #[arg(long, requires = "fix")]
310 apply: bool,
311
312 /// Preview changes without applying (dry-run mode)
313 #[arg(long)]
314 dry_run: bool,
315
316 /// Backup directory for original files before applying fixes
317 #[arg(long, value_name = "DIR")]
318 backup_dir: Option<PathBuf>,
319
320 /// Minimum confidence threshold for auto-apply (0-100, default: 70)
321 #[arg(long, default_value = "70")]
322 min_confidence: u8,
323
324 /// Cloud provider for cost estimation (aws, gcp, azure, onprem)
325 #[arg(long, value_name = "PROVIDER")]
326 cloud_provider: Option<String>,
327
328 /// Region for cloud pricing (e.g., us-east-1, us-central1)
329 #[arg(long, value_name = "REGION", default_value = "us-east-1")]
330 region: String,
331
332 /// Run comprehensive analysis (includes kubelint security checks and helmlint validation)
333 #[arg(long, short = 'f')]
334 full: bool,
335
336 /// Output compressed JSON for AI agent consumption (implies --json)
337 #[arg(long)]
338 agent: bool,
339 },
340
341 /// Retrieve stored output from a previous --agent command
342 Retrieve {
343 /// Reference ID (e.g., "security_a1b2c3d4") or "latest" for most recent
344 #[arg(value_name = "REF_ID")]
345 ref_id: Option<String>,
346
347 /// Filter query (e.g., "severity:critical", "file:path", "section:frameworks")
348 #[arg(long, short = 'q')]
349 query: Option<String>,
350
351 /// List all stored outputs
352 #[arg(long)]
353 list: bool,
354
355 /// Maximum number of results to return (default: 20)
356 #[arg(long, short = 'l', default_value = "20")]
357 limit: usize,
358
359 /// Number of results to skip (for pagination)
360 #[arg(long, default_value = "0")]
361 offset: usize,
362 },
363
364 /// Start an interactive AI chat session to analyze and understand your project
365 Chat {
366 /// Path to the project directory (default: current directory)
367 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
368 path: PathBuf,
369
370 /// LLM provider to use (uses saved preference by default)
371 #[arg(long, value_enum, default_value = "auto")]
372 provider: ChatProvider,
373
374 /// Model to use (e.g., gpt-4o, claude-3-5-sonnet-latest, llama3.2)
375 #[arg(long)]
376 model: Option<String>,
377
378 /// Run a single query instead of interactive mode
379 #[arg(long)]
380 query: Option<String>,
381
382 /// Resume a previous session (accepts: "latest", session number, or UUID)
383 #[arg(long, short = 'r')]
384 resume: Option<String>,
385
386 /// List available sessions for this project and exit
387 #[arg(long)]
388 list_sessions: bool,
389
390 /// Start AG-UI server for frontend connectivity (SSE/WebSocket)
391 #[arg(long)]
392 ag_ui: bool,
393
394 /// AG-UI server port (default: 9090)
395 #[arg(long, default_value = "9090", requires = "ag_ui")]
396 ag_ui_port: u16,
397 },
398
399 /// Authenticate with the Syncable platform
400 Auth {
401 #[command(subcommand)]
402 command: AuthCommand,
403 },
404
405 /// Manage Syncable projects
406 Project {
407 #[command(subcommand)]
408 command: ProjectCommand,
409 },
410
411 /// Manage Syncable organizations
412 Org {
413 #[command(subcommand)]
414 command: OrgCommand,
415 },
416
417 /// Manage environments within a project
418 Env {
419 #[command(subcommand)]
420 command: EnvCommand,
421 },
422
423 /// Deploy services to the Syncable platform (launches wizard by default)
424 Deploy {
425 /// Path to the project directory (default: current directory)
426 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
427 path: PathBuf,
428
429 #[command(subcommand)]
430 command: Option<DeployCommand>,
431 },
432
433 /// Run as dedicated AG-UI agent server (headless mode for containers)
434 Agent {
435 /// Path to the project directory
436 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
437 path: PathBuf,
438
439 /// Port for AG-UI server
440 #[arg(long, short, default_value = "9090")]
441 port: u16,
442
443 /// Host address to bind to
444 #[arg(long, default_value = "127.0.0.1")]
445 host: String,
446
447 /// LLM provider to use
448 #[arg(long, value_enum, default_value = "auto")]
449 provider: ChatProvider,
450
451 /// Model to use
452 #[arg(long)]
453 model: Option<String>,
454 },
455}
456
457#[derive(Subcommand)]
458pub enum ToolsCommand {
459 /// Check which vulnerability scanning tools are installed
460 Status {
461 /// Output format
462 #[arg(long, value_enum, default_value = "table")]
463 format: OutputFormat,
464
465 /// Check tools for specific languages only
466 #[arg(long, value_delimiter = ',')]
467 languages: Option<Vec<String>>,
468 },
469
470 /// Install missing vulnerability scanning tools
471 Install {
472 /// Install tools for specific languages only
473 #[arg(long, value_delimiter = ',')]
474 languages: Option<Vec<String>>,
475
476 /// Also install OWASP Dependency Check (large download)
477 #[arg(long)]
478 include_owasp: bool,
479
480 /// Perform a dry run to show what would be installed
481 #[arg(long)]
482 dry_run: bool,
483
484 /// Skip confirmation prompts
485 #[arg(short, long)]
486 yes: bool,
487 },
488
489 /// Verify that installed tools are working correctly
490 Verify {
491 /// Test tools for specific languages only
492 #[arg(long, value_delimiter = ',')]
493 languages: Option<Vec<String>>,
494
495 /// Show detailed verification output
496 #[arg(short, long)]
497 detailed: bool,
498 },
499
500 /// Show tool installation guides for manual setup
501 Guide {
502 /// Show guide for specific languages only
503 #[arg(long, value_delimiter = ',')]
504 languages: Option<Vec<String>>,
505
506 /// Show platform-specific instructions
507 #[arg(long)]
508 platform: Option<String>,
509 },
510}
511
512/// Authentication subcommands for the Syncable platform
513#[derive(Subcommand)]
514pub enum AuthCommand {
515 /// Log in to Syncable (opens browser for authentication)
516 Login {
517 /// Don't open browser automatically
518 #[arg(long)]
519 no_browser: bool,
520 },
521
522 /// Log out and clear stored credentials
523 Logout,
524
525 /// Show current authentication status
526 Status,
527
528 /// Print current access token (for scripting)
529 Token {
530 /// Print raw token without formatting
531 #[arg(long)]
532 raw: bool,
533 },
534}
535
536/// Project management subcommands
537#[derive(Subcommand)]
538pub enum ProjectCommand {
539 /// List projects in the current organization
540 List {
541 /// Organization ID to list projects from (uses current org if not specified)
542 #[arg(long)]
543 org_id: Option<String>,
544
545 /// Output format
546 #[arg(long, value_enum, default_value = "table")]
547 format: OutputFormat,
548 },
549
550 /// Select a project to work with
551 Select {
552 /// Project ID to select
553 id: String,
554 },
555
556 /// Show current organization and project context
557 Current,
558
559 /// Show details of a project
560 Info {
561 /// Project ID (uses current project if not specified)
562 id: Option<String>,
563 },
564}
565
566/// Organization management subcommands
567#[derive(Subcommand)]
568pub enum OrgCommand {
569 /// List organizations you belong to
570 List {
571 /// Output format
572 #[arg(long, value_enum, default_value = "table")]
573 format: OutputFormat,
574 },
575
576 /// Select an organization to work with
577 Select {
578 /// Organization ID to select
579 id: String,
580 },
581}
582
583/// Environment management subcommands
584#[derive(Subcommand)]
585pub enum EnvCommand {
586 /// List environments in the current project
587 List {
588 /// Output format
589 #[arg(long, value_enum, default_value = "table")]
590 format: OutputFormat,
591 },
592
593 /// Select an environment to work with
594 Select {
595 /// Environment ID to select
596 id: String,
597 },
598}
599
600/// Deployment subcommands
601#[derive(Subcommand)]
602pub enum DeployCommand {
603 /// Launch interactive deployment wizard
604 Wizard {
605 /// Path to the project directory (default: current directory)
606 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
607 path: PathBuf,
608 },
609
610 /// Create a new environment for the current project
611 NewEnv,
612
613 /// Check deployment status
614 Status {
615 /// The deployment task ID (from deploy command output)
616 task_id: String,
617
618 /// Watch for status updates (poll until complete)
619 #[arg(short, long)]
620 watch: bool,
621 },
622
623 /// Preview deployment recommendation (non-interactive, JSON output for agents)
624 Preview {
625 /// Path to project or service subdirectory
626 #[arg(value_name = "PATH", default_value = ".")]
627 path: PathBuf,
628
629 /// Override service name (default: derived from directory name)
630 #[arg(long)]
631 service_name: Option<String>,
632
633 /// Override cloud provider (gcp, hetzner, azure)
634 #[arg(long)]
635 provider: Option<String>,
636
637 /// Override region
638 #[arg(long)]
639 region: Option<String>,
640
641 /// Override machine type
642 #[arg(long)]
643 machine_type: Option<String>,
644
645 /// Override detected port
646 #[arg(long)]
647 port: Option<u16>,
648
649 /// Make service publicly accessible
650 #[arg(long)]
651 public: bool,
652 },
653
654 /// Deploy a service non-interactively (for agents and CI/CD)
655 Run {
656 /// Path to project or service subdirectory
657 #[arg(value_name = "PATH", default_value = ".")]
658 path: PathBuf,
659
660 /// Override service name (default: derived from directory name)
661 #[arg(long)]
662 service_name: Option<String>,
663
664 /// Cloud provider (gcp, hetzner, azure)
665 #[arg(long)]
666 provider: Option<String>,
667
668 /// Region
669 #[arg(long)]
670 region: Option<String>,
671
672 /// Machine type
673 #[arg(long)]
674 machine_type: Option<String>,
675
676 /// Port to expose
677 #[arg(long)]
678 port: Option<u16>,
679
680 /// Make service publicly accessible
681 #[arg(long)]
682 public: bool,
683
684 /// CPU allocation (for GCP/Azure, e.g. "1000m", "2")
685 #[arg(long)]
686 cpu: Option<String>,
687
688 /// Memory allocation (for GCP/Azure, e.g. "512Mi", "2Gi")
689 #[arg(long)]
690 memory: Option<String>,
691
692 /// Min instances/replicas
693 #[arg(long)]
694 min_instances: Option<i32>,
695
696 /// Max instances/replicas
697 #[arg(long)]
698 max_instances: Option<i32>,
699
700 /// Environment variable as KEY=VALUE (non-secret, repeatable)
701 #[arg(long = "env", value_name = "KEY=VALUE")]
702 env_vars: Vec<String>,
703
704 /// Secret key name (user prompted in terminal for value, repeatable)
705 #[arg(long = "secret")]
706 secrets: Vec<String>,
707
708 /// Load environment variables from a .env file
709 #[arg(long)]
710 env_file: Option<PathBuf>,
711 },
712}
713
714#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
715pub enum OutputFormat {
716 Table,
717 Json,
718}
719
720#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
721pub enum DisplayFormat {
722 /// Compact matrix/dashboard view (modern, easy to scan)
723 Matrix,
724 /// Detailed vertical view (legacy format with all details)
725 Detailed,
726 /// Brief summary only
727 Summary,
728}
729
730#[derive(Clone, Copy, Debug, ValueEnum)]
731pub enum ColorScheme {
732 /// Auto-detect terminal background (default)
733 Auto,
734 /// Dark background terminal colors
735 Dark,
736 /// Light background terminal colors
737 Light,
738}
739
740#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
741pub enum SeverityThreshold {
742 Low,
743 Medium,
744 High,
745 Critical,
746}
747
748#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
749pub enum SecurityScanMode {
750 /// Lightning fast scan - critical files only (.env, configs)
751 Lightning,
752 /// Fast scan - smart sampling with priority patterns
753 Fast,
754 /// Balanced scan - good coverage with performance optimizations (recommended)
755 Balanced,
756 /// Thorough scan - comprehensive analysis of all files
757 Thorough,
758 /// Paranoid scan - most comprehensive including low-severity findings
759 Paranoid,
760}
761
762#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum, Default)]
763pub enum ChatProvider {
764 /// OpenAI (GPT-4o, GPT-4, etc.)
765 Openai,
766 /// Anthropic (Claude 3)
767 Anthropic,
768 /// AWS Bedrock (Claude via AWS)
769 Bedrock,
770 /// Ollama (local LLM, no API key needed)
771 Ollama,
772 /// Use saved default from config file
773 #[default]
774 Auto,
775}
776
777impl Cli {
778 /// Initialize logging based on verbosity level
779 pub fn init_logging(&self) {
780 if self.quiet {
781 return;
782 }
783
784 let level = match self.verbose {
785 0 => log::LevelFilter::Warn,
786 1 => log::LevelFilter::Info,
787 2 => log::LevelFilter::Debug,
788 _ => log::LevelFilter::Trace,
789 };
790
791 env_logger::Builder::from_default_env()
792 .filter_level(level)
793 .init();
794 }
795}