1use std::collections::HashMap;
2use clap::{ArgMatches, Command};
3use colored::*;
4use thiserror::Error;
5use quote::ToTokens;
6pub mod bench_diff;
7pub mod dep_audit;
8pub mod test_gen;
9pub mod workspace_sync;
10pub mod panic_analyzer;
11pub mod cross_test;
12pub mod refactor_engine;
13pub mod rust_mentor;
14pub mod release_automation;
15pub mod bloat_check;
16pub mod cache_analyzer;
17pub mod async_lint;
18pub mod crud_gen;
19pub mod proto_bind;
20pub mod error_derive;
21pub mod builder_gen;
22pub mod example_gen;
23pub mod api_changelog;
24pub mod trait_explorer;
25pub mod env_check;
26pub mod feature_map;
27pub mod vendorize;
28pub mod macro_expand;
29pub mod lifetime_visualizer;
30pub mod compile_time_tracker;
31pub mod mock_derive;
32pub mod coverage_guard;
33#[cfg(test)]
34pub mod snapshot_test;
35pub mod wasm_optimize;
36pub mod installer_gen;
37pub mod migration_gen;
38pub mod serde_validator;
39pub mod sql_macro_check;
40pub mod secret_scanner;
41pub mod unsafe_analyzer;
42pub mod license_bundler;
43pub mod code_analyzer;
44#[derive(Error, Debug)]
45pub enum ToolError {
46 #[error("Tool '{0}' not found")]
47 ToolNotFound(String),
48 #[error("Tool execution failed: {0}")]
49 ExecutionFailed(String),
50 #[error("Configuration error: {0}")]
51 ConfigError(String),
52 #[error("Invalid arguments: {0}")]
53 InvalidArguments(String),
54 #[error("IO error: {0}")]
55 IoError(#[from] std::io::Error),
56 #[error("TOML parsing error: {0}")]
57 TomlError(#[from] toml::de::Error),
58 #[error("JSON parsing error: {0}")]
59 JsonError(#[from] serde_json::Error),
60 #[error("Syn parsing error: {0}")]
61 SynError(String),
62}
63impl From<syn::Error> for ToolError {
64 fn from(err: syn::Error) -> Self {
65 ToolError::SynError(
66 format!(
67 "Rust syntax parsing failed: {}. This usually indicates invalid Rust code or an unsupported language feature.",
68 err
69 ),
70 )
71 }
72}
73pub type Result<T> = std::result::Result<T, ToolError>;
74pub trait Tool {
75 fn name(&self) -> &'static str;
76 fn description(&self) -> &'static str;
78 fn command(&self) -> Command;
79 fn execute(&self, matches: &ArgMatches) -> Result<()>;
80}
81pub struct ToolRegistry {
82 tools: HashMap<String, Box<dyn Tool>>,
83}
84impl ToolRegistry {
85 pub fn new() -> Self {
86 Self { tools: HashMap::new() }
87 }
88 pub fn register<T: Tool + 'static>(mut self, tool: T) -> Self {
89 self.tools.insert(tool.name().to_string(), Box::new(tool));
90 self
91 }
92 pub fn get(&self, name: &str) -> Option<&Box<dyn Tool>> {
93 self.tools.get(name)
94 }
95 pub fn list_tools(&self) -> Vec<(&str, &str)> {
96 let mut tools: Vec<_> = self
97 .tools
98 .values()
99 .map(|tool| (tool.name(), tool.description()))
100 .collect();
101 tools.sort_by(|a, b| a.0.cmp(b.0));
102 tools
103 }
104 pub fn has_tool(&self, name: &str) -> bool {
105 self.tools.contains_key(name)
106 }
107}
108#[derive(Debug, Clone)]
110pub struct ToolConfig {
111 pub verbose: bool,
112 pub dry_run: bool,
113 pub output_format: OutputFormat,
114}
115#[derive(Debug, Clone)]
116pub enum OutputFormat {
117 Human,
118 Json,
119 Table,
120}
121impl Default for ToolConfig {
122 fn default() -> Self {
123 Self {
124 verbose: false,
125 dry_run: false,
126 output_format: OutputFormat::Human,
127 }
128 }
129}
130pub fn create_registry() -> ToolRegistry {
132 let registry = ToolRegistry::new();
133 registry
134 .register(bench_diff::BenchDiffTool::new())
135 .register(dep_audit::DepAuditTool::new())
136 .register(test_gen::TestGenTool::new())
137 .register(workspace_sync::WorkspaceSyncTool::new())
138 .register(panic_analyzer::PanicAnalyzerTool::new())
139 .register(cross_test::CrossTestTool::new())
140 .register(release_automation::ReleaseAutomationTool::new())
141 .register(crud_gen::CrudGenTool::new())
142 .register(proto_bind::ProtoBindTool::new())
143 .register(error_derive::ErrorDeriveTool::new())
144 .register(builder_gen::BuilderGenTool::new())
145 .register(example_gen::ExampleGenTool::new())
146 .register(api_changelog::ApiChangelogTool::new())
147 .register(trait_explorer::TraitExplorerTool::new())
148 .register(rust_mentor::RustMentorTool::new())
149 .register(refactor_engine::RefactorEngineTool::new())
150 .register(env_check::EnvCheckTool::new())
151 .register(bloat_check::BloatCheckTool::new())
152 .register(cache_analyzer::CacheAnalyzerTool::new())
153 .register(async_lint::AsyncLintTool::new())
154 .register(feature_map::FeatureMapTool::new())
155 .register(vendorize::VendorizeTool::new())
156 .register(macro_expand::MacroExpandTool::new())
157 .register(lifetime_visualizer::LifetimeVisualizerTool::new())
158 .register(compile_time_tracker::CompileTimeTrackerTool::new())
159 .register(mock_derive::MockDeriveTool::new())
160 .register(coverage_guard::CoverageGuardTool::new())
161 .register(wasm_optimize::WasmOptimizeTool::new())
162 .register(installer_gen::InstallerGenTool::new())
163 .register(migration_gen::MigrationGenTool::new())
164 .register(serde_validator::SerdeValidatorTool::new())
165 .register(sql_macro_check::SqlMacroCheckTool::new())
166 .register(secret_scanner::SecretScannerTool::new())
167 .register(unsafe_analyzer::UnsafeAnalyzerTool::new())
168 .register(license_bundler::LicenseBundlerTool::new())
169 .register(code_analyzer::CodeAnalyzer::new())
170}
171static mut REGISTRY: Option<ToolRegistry> = None;
172pub fn get_registry() -> &'static ToolRegistry {
174 unsafe {
175 if REGISTRY.is_none() {
176 REGISTRY = Some(create_registry());
177 }
178 REGISTRY.as_ref().unwrap()
179 }
180}
181pub fn list_tools() {
182 let registry = get_registry();
183 let tools = registry.list_tools();
184 if tools.is_empty() {
185 println!("{}", "No tools available yet.".yellow());
186 println!("Tools are being developed and will be added soon!");
187 return;
188 }
189 println!("{}", "🔧 Available Tools".bold().blue());
190 println!("{}", "═".repeat(50).blue());
191 for (name, description) in tools {
192 println!(" {} - {}", name.green().bold(), description);
193 }
194 println!();
195 println!("{}", "Usage:".bold());
196 println!(" cm tool list # List all tools");
197 println!(" cm tool help <name> # Show help for a tool");
198 println!(" cm tool <name> [options] # Run a tool");
199 println!(" cm tool run <name> [options] # Run a tool (explicit)");
200}
201pub fn show_tool_help(name: &str) {
202 let registry = get_registry();
203 if let Some(tool) = registry.get(name) {
204 let mut command = tool.command();
205 println!("{}", format!("Help for tool: {}", name) .bold().blue());
206 println!("{}", "═".repeat(50).blue());
207 println!("{}", tool.description());
208 println!();
209 let _ = command.print_help();
210 } else {
211 println!("{}", format!("❌ Tool '{}' not found", name) .red());
212 println!();
213 println!("{}", "Available tools:".bold());
214 list_tools();
215 }
216}
217pub fn run_tool(name: &str, args: &[String]) -> Result<()> {
218 let registry = get_registry();
219 let tool = registry
220 .get(name)
221 .ok_or_else(|| ToolError::ToolNotFound(name.to_string()))?;
222 let command = tool.command();
223 let clap_args = std::iter::once(name.to_string())
224 .chain(args.iter().cloned())
225 .collect::<Vec<_>>();
226 let arg_refs: Vec<&str> = clap_args.iter().map(|s| s.as_str()).collect();
227 let matches = command
228 .try_get_matches_from(&arg_refs)
229 .map_err(|e| ToolError::InvalidArguments(e.to_string()))?;
230 tool.execute(&matches)
231}
232pub fn common_options() -> Vec<clap::Arg> {
233 vec![
234 clap::Arg::new("verbose").long("verbose").short('v')
235 .help("Enable verbose output").action(clap::ArgAction::SetTrue),
236 clap::Arg::new("dry-run").long("dry-run")
237 .help("Show what would be done without executing")
238 .action(clap::ArgAction::SetTrue), clap::Arg::new("output").long("output")
239 .short('o').help("Output format").value_parser(["human", "json", "table"])
240 .default_value("human"),
241 ]
242}
243pub fn parse_output_format(matches: &ArgMatches) -> OutputFormat {
244 match matches.get_one::<String>("output").map(|s| s.as_str()) {
245 Some("json") => OutputFormat::Json,
246 Some("table") => OutputFormat::Table,
247 _ => OutputFormat::Human,
248 }
249}
250#[cfg(test)]
251mod tests {
252 use super::*;
253 #[test]
254 fn test_registry_creation() {
255 let registry = create_registry();
256 assert!(! registry.has_tool("nonexistent"));
257 }
258 #[test]
259 fn test_list_tools_empty() {
260 let registry = create_registry();
261 let tools = registry.list_tools();
262 assert!(tools.is_empty() || ! tools.is_empty());
263 }
264}