Skip to content

Commit f36ea89

Browse files
committed
feat(cli): implement Issues #241, #242, #243 - Complete CLI integration
- Issue #242: Wire validate command to comprehensive validation engine * Replace placeholder implementation with real validation system * Add support for JSONPath, schema, and protocol validation * Generate validation reports in multiple formats (JSON, HTML, Markdown, JUnit) * Add detailed validation diagnostics and suggestions - Issue #241: Wire advanced reporting system to CLI commands * Replace basic JSON output with enterprise-grade reporting * Generate professional HTML reports using advanced templates * Add JUnit XML for CI/CD integration * Include comprehensive metadata and performance metrics * Support custom branding and styling - Issue #243: Add profile management and watch mode commands * Add 'moth profile' command with save/load/list/delete/export/import subcommands * Add 'moth watch' command with file watching capabilities * Add global CLI options for profile and CI integration * Implement ProfileManager with 500+ lines of functionality * Add WatchManager with debouncing and auto-open features Design docs: docs/design/issue-{241,242,243}-*.md Tests: All existing tests pass, new CLI commands functional Coverage: CLI integration gaps eliminated, backend systems now accessible closes #241, closes #242, closes #243
1 parent 42b6e44 commit f36ea89

File tree

6 files changed

+2493
-17
lines changed

6 files changed

+2493
-17
lines changed

crates/mandrel-mcp-th/src/cli/args.rs

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,22 @@ pub struct Cli {
1616
/// Suppress non-essential output
1717
#[arg(long, short = 'q')]
1818
pub quiet: bool,
19+
20+
/// Use named configuration profile
21+
#[arg(long, short = 'p')]
22+
pub profile: Option<String>,
23+
24+
/// Auto-detect CI environment and apply optimizations
25+
#[arg(long)]
26+
pub detect_ci: bool,
27+
28+
/// Override environment detection (for testing CI configurations locally)
29+
#[arg(long)]
30+
pub simulate_ci: Option<CiSystem>,
31+
32+
/// Configuration directory for profiles and settings
33+
#[arg(long, default_value = "~/.config/mandrel-mcp-th")]
34+
pub config_dir: PathBuf,
1935
}
2036

2137
#[derive(Subcommand, Debug)]
@@ -28,6 +44,12 @@ pub enum Commands {
2844

2945
/// Validate configuration files
3046
Validate(ValidateArgs),
47+
48+
/// Manage configuration profiles
49+
Profile(ProfileArgs),
50+
51+
/// Watch files and auto-generate reports
52+
Watch(WatchArgs),
3153
}
3254

3355
#[derive(Args, Debug)]
@@ -101,6 +123,220 @@ pub struct ValidateArgs {
101123
/// Configuration file to validate
102124
#[arg()]
103125
pub config: PathBuf,
126+
127+
/// Enable strict validation mode (fail on warnings)
128+
#[arg(long)]
129+
pub strict: bool,
130+
131+
/// Output directory for validation reports
132+
#[arg(short = 'o', long)]
133+
pub output: Option<PathBuf>,
134+
135+
/// Report formats to generate for validation results
136+
#[arg(short = 'f', long, value_delimiter = ',')]
137+
pub formats: Vec<ReportFormat>,
138+
139+
/// Check JSONPath expressions in test cases
140+
#[arg(long)]
141+
pub check_jsonpath: bool,
142+
143+
/// Validate JSON schema compliance
144+
#[arg(long)]
145+
pub check_schema: bool,
146+
147+
/// Validate MCP protocol compliance
148+
#[arg(long)]
149+
pub check_protocol: bool,
150+
151+
/// Enable all validation checks
152+
#[arg(long)]
153+
pub check_all: bool,
154+
155+
/// Enable detailed validation diagnostics
156+
#[arg(long)]
157+
pub detailed: bool,
158+
159+
/// Only validate, don't suggest fixes
160+
#[arg(long)]
161+
pub no_suggestions: bool,
162+
}
163+
164+
#[derive(Args, Debug)]
165+
pub struct ProfileArgs {
166+
#[command(subcommand)]
167+
pub command: ProfileCommand,
168+
}
169+
170+
#[derive(Subcommand, Debug)]
171+
pub enum ProfileCommand {
172+
/// Save current configuration as a named profile
173+
Save(ProfileSaveArgs),
174+
175+
/// Load and apply a named profile
176+
Load(ProfileLoadArgs),
177+
178+
/// List all available profiles
179+
List,
180+
181+
/// Delete a named profile
182+
Delete(ProfileDeleteArgs),
183+
184+
/// Export profile to file
185+
Export(ProfileExportArgs),
186+
187+
/// Import profile from file
188+
Import(ProfileImportArgs),
189+
190+
/// Show profile details
191+
Show(ProfileShowArgs),
192+
}
193+
194+
#[derive(Args, Debug)]
195+
pub struct ProfileSaveArgs {
196+
/// Profile name
197+
pub name: String,
198+
199+
/// Profile description
200+
#[arg(short = 'd', long)]
201+
pub description: Option<String>,
202+
203+
/// Report formats to include
204+
#[arg(short = 'f', long, value_delimiter = ',')]
205+
pub formats: Vec<ReportFormat>,
206+
207+
/// Template to use
208+
#[arg(short = 't', long)]
209+
pub template: Option<TemplateName>,
210+
211+
/// Organization strategy
212+
#[arg(long)]
213+
pub organization: Option<OrganizationStrategy>,
214+
215+
/// Timestamp format
216+
#[arg(long)]
217+
pub timestamp: Option<TimestampFormat>,
218+
219+
/// Include performance metrics
220+
#[arg(long)]
221+
pub include_performance: Option<bool>,
222+
223+
/// Include validation details
224+
#[arg(long)]
225+
pub include_validation: Option<bool>,
226+
227+
/// Set as default profile
228+
#[arg(long)]
229+
pub set_default: bool,
230+
}
231+
232+
#[derive(Args, Debug)]
233+
pub struct ProfileLoadArgs {
234+
/// Profile name to load
235+
pub name: String,
236+
237+
/// Apply profile settings globally
238+
#[arg(long)]
239+
pub global: bool,
240+
}
241+
242+
#[derive(Args, Debug)]
243+
pub struct ProfileDeleteArgs {
244+
/// Profile name to delete
245+
pub name: String,
246+
247+
/// Skip confirmation prompt
248+
#[arg(long)]
249+
pub force: bool,
250+
}
251+
252+
#[derive(Args, Debug)]
253+
pub struct ProfileExportArgs {
254+
/// Profile name to export
255+
pub name: String,
256+
257+
/// Output file path
258+
#[arg(short = 'o', long)]
259+
pub output: PathBuf,
260+
261+
/// Export format
262+
#[arg(long, default_value = "json")]
263+
pub format: ExportFormat,
264+
}
265+
266+
#[derive(Args, Debug)]
267+
pub struct ProfileImportArgs {
268+
/// Input file path
269+
pub input: PathBuf,
270+
271+
/// Override profile name
272+
#[arg(long)]
273+
pub name: Option<String>,
274+
275+
/// Overwrite existing profile
276+
#[arg(long)]
277+
pub overwrite: bool,
278+
}
279+
280+
#[derive(Args, Debug)]
281+
pub struct ProfileShowArgs {
282+
/// Profile name to show
283+
pub name: String,
284+
285+
/// Show in detailed format
286+
#[arg(long)]
287+
pub detailed: bool,
288+
}
289+
290+
#[derive(Args, Debug)]
291+
pub struct WatchArgs {
292+
#[command(subcommand)]
293+
pub command: WatchCommand,
294+
}
295+
296+
#[derive(Subcommand, Debug)]
297+
pub enum WatchCommand {
298+
/// Start watching files for changes
299+
Start(WatchStartArgs),
300+
301+
/// Stop all watchers
302+
Stop,
303+
304+
/// Show watch status
305+
Status,
306+
}
307+
308+
#[derive(Args, Debug)]
309+
pub struct WatchStartArgs {
310+
/// Input files or directories to watch
311+
pub inputs: Vec<PathBuf>,
312+
313+
/// Output directory for generated reports
314+
#[arg(short = 'o', long, default_value = "./reports")]
315+
pub output: PathBuf,
316+
317+
/// File patterns to watch (glob patterns)
318+
#[arg(short = 'p', long, value_delimiter = ',')]
319+
pub patterns: Vec<String>,
320+
321+
/// Report formats to generate
322+
#[arg(short = 'f', long, value_delimiter = ',')]
323+
pub formats: Vec<ReportFormat>,
324+
325+
/// Debounce delay in milliseconds
326+
#[arg(long, default_value = "500")]
327+
pub debounce: u64,
328+
329+
/// Auto-open reports in browser
330+
#[arg(long)]
331+
pub auto_open: bool,
332+
333+
/// Run in background (daemonize)
334+
#[arg(long)]
335+
pub daemon: bool,
336+
337+
/// Profile to use for report generation
338+
#[arg(long)]
339+
pub profile: Option<String>,
104340
}
105341

106342
#[derive(ValueEnum, Clone, Debug, PartialEq, Serialize, Deserialize)]
@@ -137,6 +373,25 @@ pub enum TimestampFormat {
137373
None, // No timestamp
138374
}
139375

376+
#[derive(ValueEnum, Clone, Debug, PartialEq, Serialize, Deserialize)]
377+
pub enum CiSystem {
378+
GitHubActions,
379+
Jenkins,
380+
GitLabCi,
381+
CircleCi,
382+
Travis,
383+
Buildkite,
384+
TeamCity,
385+
AzureDevOps,
386+
}
387+
388+
#[derive(ValueEnum, Clone, Debug, PartialEq, Serialize, Deserialize)]
389+
pub enum ExportFormat {
390+
Json,
391+
Yaml,
392+
Toml,
393+
}
394+
140395
/// Parse key=value pairs for custom fields
141396
fn parse_key_val(s: &str) -> Result<(String, String), String> {
142397
let parts: Vec<&str> = s.splitn(2, '=').collect();

0 commit comments

Comments
 (0)