|
5 | 5 | //! (decision 9) — stdout stays byte-identical (empty on errors). |
6 | 6 |
|
7 | 7 | use crate::commands::{ |
8 | | - cmd_coverage, cmd_decisions_for, cmd_diagnose, cmd_diff, cmd_doctor, cmd_eval, cmd_export, |
9 | | - cmd_find, cmd_gate, cmd_herald, cmd_hook, cmd_improve, cmd_index, cmd_init, cmd_inspect, |
10 | | - cmd_mcp_stats, cmd_migrate, cmd_new, cmd_portfolio, cmd_quickstart, cmd_relationships, |
11 | | - cmd_rename, cmd_resolve, cmd_retrieve, cmd_review, cmd_schema, cmd_sentry, cmd_skill, |
12 | | - cmd_stats, cmd_telemetry, cmd_templates, cmd_usage, cmd_validate, CoverageArgs, |
13 | | - DecisionsForArgs, DiagnoseArgs, DiffArgs, DoctorArgs, EvalArgs, ExportArgs, FindArgs, |
14 | | - GateArgs, HeraldArgs, HookArgs, ImproveArgs, IndexArgs, InitArgs, InspectArgs, McpStatsArgs, |
15 | | - MigrateArgs, NewArgs, PortfolioArgs, QuickstartArgs, RelationshipsArgs, RenameArgs, |
16 | | - ResolveArgs, RetrieveArgs, ReviewArgs, SchemaArgs, SentryArgs, SkillArgs, StatsArgs, |
17 | | - TelemetryArgs, TemplatesArgs, UsageArgs, ValidateArgs, WatchkeeperArgs, |
| 8 | + cmd_corpus_digest, cmd_coverage, cmd_decisions_for, cmd_diagnose, cmd_diff, cmd_doctor, |
| 9 | + cmd_eval, cmd_export, cmd_find, cmd_gate, cmd_herald, cmd_hook, cmd_improve, cmd_index, |
| 10 | + cmd_init, cmd_inspect, cmd_mcp_stats, cmd_migrate, cmd_new, cmd_portfolio, cmd_quickstart, |
| 11 | + cmd_relationships, cmd_rename, cmd_resolve, cmd_retrieve, cmd_review, cmd_schema, cmd_sentry, |
| 12 | + cmd_skill, cmd_stats, cmd_telemetry, cmd_templates, cmd_usage, cmd_validate, |
| 13 | + CorpusDigestArgs, CoverageArgs, DecisionsForArgs, DiagnoseArgs, DiffArgs, DoctorArgs, EvalArgs, |
| 14 | + ExportArgs, FindArgs, GateArgs, HeraldArgs, HookArgs, ImproveArgs, IndexArgs, InitArgs, |
| 15 | + InspectArgs, McpStatsArgs, MigrateArgs, NewArgs, PortfolioArgs, QuickstartArgs, |
| 16 | + RelationshipsArgs, RenameArgs, ResolveArgs, RetrieveArgs, ReviewArgs, SchemaArgs, SentryArgs, |
| 17 | + SkillArgs, StatsArgs, TelemetryArgs, TemplatesArgs, UsageArgs, ValidateArgs, WatchkeeperArgs, |
18 | 18 | }; |
19 | 19 | use crate::commands::cmd_watchkeeper; |
20 | 20 | use crate::output::rac_version; |
@@ -156,7 +156,10 @@ fn run_dispatch(args: &[String]) -> u8 { |
156 | 156 | // Native-only additions dispatch but are deliberately NOT in SUBCOMMANDS: |
157 | 157 | // the retired Python oracle's `invalid choice` bytes remain pinned by the |
158 | 158 | // bounded compatibility suite. |
159 | | - if !matches!(first.as_str(), "retrieve" | "sentry" | "herald" | "diagnose") |
| 159 | + if !matches!( |
| 160 | + first.as_str(), |
| 161 | + "retrieve" | "sentry" | "herald" | "diagnose" | "corpus" |
| 162 | + ) |
160 | 163 | && !SUBCOMMANDS.contains(&first.as_str()) |
161 | 164 | { |
162 | 165 | return argparse_error("decided", &invalid_choice_message(first)); |
@@ -232,6 +235,7 @@ fn run_dispatch(args: &[String]) -> u8 { |
232 | 235 | "quickstart" => run_quickstart(&rest), |
233 | 236 | "rename" => run_rename(&rest), |
234 | 237 | "migrate" => run_migrate(&rest), |
| 238 | + "corpus" => run_corpus(&rest), |
235 | 239 | other => { |
236 | 240 | eprintln!("decided-rs: subcommand '{other}' is not yet implemented"); |
237 | 241 | 2 |
@@ -278,6 +282,78 @@ fn take_opt_value( |
278 | 282 | } |
279 | 283 | } |
280 | 284 |
|
| 285 | +fn run_corpus(rest: &[&String]) -> u8 { |
| 286 | + let prog = "decided corpus"; |
| 287 | + let mut action: Option<String> = None; |
| 288 | + let mut root: Option<String> = None; |
| 289 | + let mut corpus: Option<String> = None; |
| 290 | + let mut extras: Vec<String> = Vec::new(); |
| 291 | + let mut positional_only = false; |
| 292 | + |
| 293 | + let mut i = 0; |
| 294 | + while i < rest.len() { |
| 295 | + let arg = rest[i].as_str(); |
| 296 | + if positional_only || arg == "-" || !arg.starts_with('-') { |
| 297 | + if action.is_none() { |
| 298 | + if arg != "digest" { |
| 299 | + return argparse_error( |
| 300 | + prog, |
| 301 | + &format!( |
| 302 | + "argument action: invalid choice: '{arg}' (choose from 'digest')" |
| 303 | + ), |
| 304 | + ); |
| 305 | + } |
| 306 | + action = Some(arg.to_string()); |
| 307 | + } else { |
| 308 | + extras.push(arg.to_string()); |
| 309 | + } |
| 310 | + i += 1; |
| 311 | + continue; |
| 312 | + } |
| 313 | + match arg { |
| 314 | + "--" => positional_only = true, |
| 315 | + other if other == "--root" || other.starts_with("--root=") => { |
| 316 | + match take_opt_value(prog, "--root", other, rest, &mut i) { |
| 317 | + Ok(value) => root = Some(value), |
| 318 | + Err(code) => return code, |
| 319 | + } |
| 320 | + } |
| 321 | + other if other == "--corpus" || other.starts_with("--corpus=") => { |
| 322 | + match take_opt_value(prog, "--corpus", other, rest, &mut i) { |
| 323 | + Ok(value) => corpus = Some(value), |
| 324 | + Err(code) => return code, |
| 325 | + } |
| 326 | + } |
| 327 | + other => extras.push(other.to_string()), |
| 328 | + } |
| 329 | + i += 1; |
| 330 | + } |
| 331 | + |
| 332 | + if action.is_none() { |
| 333 | + return argparse_error(prog, "the following arguments are required: action"); |
| 334 | + } |
| 335 | + if root.is_none() || corpus.is_none() { |
| 336 | + let missing = match (root.is_none(), corpus.is_none()) { |
| 337 | + (true, true) => "--root, --corpus", |
| 338 | + (true, false) => "--root", |
| 339 | + (false, true) => "--corpus", |
| 340 | + (false, false) => unreachable!(), |
| 341 | + }; |
| 342 | + return argparse_error( |
| 343 | + prog, |
| 344 | + &format!("the following arguments are required: {missing}"), |
| 345 | + ); |
| 346 | + } |
| 347 | + if !extras.is_empty() { |
| 348 | + return unrecognized(&extras); |
| 349 | + } |
| 350 | + |
| 351 | + cmd_corpus_digest(&CorpusDigestArgs { |
| 352 | + root: root.expect("checked above"), |
| 353 | + corpus: corpus.expect("checked above"), |
| 354 | + }) as u8 |
| 355 | +} |
| 356 | + |
281 | 357 | fn run_validate(rest: &[&String]) -> u8 { |
282 | 358 | let prog = "decided validate"; |
283 | 359 | let mut file: Option<String> = None; |
|
0 commit comments