## Coverage Report

#### Created: 2025-09-08 21:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /home/noah/src/ruchy/src/bin/handlers/mod.rs

    Line
    Count
    Source
    1
    use anyhow::{Context, Result};
    2
    3
    mod commands;
    4
    mod handlers_modules;
    5
    use ruchy::{Parser as RuchyParser, Transpiler};
    6
    use ruchy::frontend::ast::Expr;
    7
    use ruchy::runtime::Repl;
    8
    use ruchy::runtime::replay_converter::ConversionConfig;
    9
    // Replay functionality imports removed - not needed in handler, used directly in REPL
    10
    use std::fs;
    11
    use std::io::{self, Read};
    12
    use std::path::{Path, PathBuf};
    13
    14
    /// Handle eval command - evaluate a one-liner expression with -e flag
    15
    ///
    16
    /// # Arguments
    17
    /// * `expr` - The expression to evaluate
    18
    /// * `verbose` - Enable verbose output
    19
    /// * `format` - Output format ("json" or default text)
    20
    ///
    21
    /// # Examples
    22
    /// ```
    23
    /// // This function is typically called by the CLI with parsed arguments
    24
    /// // handle_eval_command("2 + 2", false, "text");
    25
    /// ```
    26
    ///
    27
    /// # Errors
    28
    /// Returns error if expression cannot be parsed or evaluated
    29
    0
    pub fn handle_eval_command(expr: &str, verbose: bool, format: &str) -> Result<()> {
    30
    0
        if verbose {
    31
    0
            eprintln!("Parsing expression: {expr}");
    32
    0
        }
    33
    34
    0
        let mut repl = Repl::new()?;
    35
    0
        match repl.eval(expr) {
    36
    0
            Ok(result) => {
    37
    0
                if verbose {
    38
    0
                    eprintln!("Evaluation successful");
    39
    0
                }
    40
    41
    0
                if format == "json" {
    42
    0
                    // Manually construct JSON to ensure field order matches test expectations
    43
    0
                    let result_str = result.replace('"', "\\\"");
    44
    0
                    println!("{{\"success\":true,\"result\":\"{result_str}\"}}");
    45
    0
                } else {
    46
    0
                    // Default text output - always show result for one-liner evaluation
    47
    0
                    println!("{result}");
    48
    0
                }
    49
    0
                Ok(())
    50
            }
    51
    0
            Err(e) => {
    52
    0
                if verbose {
    53
    0
                    eprintln!("Evaluation failed: {e}");
    54
    0
                }
    55
    56
    0
                match format {
    57
    0
                    "json" => {
    58
    0
                        println!(
    59
    0
                            "{}",
    60
    0
                            serde_json::json!({
    61
    0
                                "success": false,
    62
    0
                                "error": e.to_string()
    63
    0
                            })
    64
    0
                        );
    65
    0
                    }
    66
    0
                    _ => {
    67
    0
                        eprintln!("Error: {e}");
    68
    0
                    }
    69
                }
    70
    0
                std::process::exit(1);
    71
            }
    72
        }
    73
    0
    }
    74
    75
    /// Handle file execution - run a Ruchy script file directly (not via subcommand)
    76
    ///
    77
    /// # Arguments
    78
    /// * `file` - Path to the Ruchy file to execute
    79
    ///
    80
    /// # Examples
    81
    /// ```
    82
    /// // This function is typically called by the CLI
    83
    /// // handle_file_execution(&Path::new("script.ruchy"));
    84
    /// ```
    85
    ///
    86
    /// # Errors
    87
    /// Returns error if file cannot be read, parsed, or executed
    88
    0
    pub fn handle_file_execution(file: &Path) -> Result<()> {
    89
    0
        let source = fs::read_to_string(file)
    90
    0
            .with_context(|| format!("Failed to read file: {}", file.display()))?;
    91
    92
        // Use REPL to evaluate the file
    93
    0
        let mut repl = Repl::new()?;
    94
    0
        match repl.eval(&source) {
    95
    0
            Ok(result) => {
    96
                // Only print non-unit results
    97
    0
                if result != "Unit" && result != "()" {
    98
    0
                    println!("{result}");
    99
    0
                }
    100
    0
                Ok(())
    101
            }
    102
    0
            Err(e) => {
    103
    0
                eprintln!("Error: {e}");
    104
    0
                std::process::exit(1);
    105
            }
    106
        }
    107
    0
    }
    108
    109
    /// Handle stdin/piped input - evaluate input from standard input
    110
    ///
    111
    /// # Arguments
    112
    /// * `input` - The input string to evaluate
    113
    ///
    114
    /// # Examples
    115
    /// ```
    116
    /// // This function is typically called when input is piped to the CLI
    117
    /// // handle_stdin_input("2 + 2");
    118
    /// ```
    119
    ///
    120
    /// # Errors
    121
    /// Returns error if input cannot be parsed or evaluated
    122
    0
    pub fn handle_stdin_input(input: &str) -> Result<()> {
    123
    0
        let mut repl = Repl::new()?;
    124
    0
        match repl.eval(input) {
    125
    0
            Ok(result) => {
    126
    0
                println!("{result}");
    127
    0
                Ok(())
    128
            }
    129
    0
            Err(e) => {
    130
    0
                eprintln!("Error: {e}");
    131
    0
                std::process::exit(1);
    132
            }
    133
        }
    134
    0
    }
    135
    136
    /// Handle parse command - show AST for a Ruchy file
    137
    0
    pub fn handle_parse_command(file: &Path, verbose: bool) -> Result<()> {
    138
    0
        if verbose {
    139
    0
            eprintln!("Parsing file: {}", file.display());
    140
    0
        }
    141
    142
    0
        let source = fs::read_to_string(file)
    143
    0
            .with_context(|| format!("Failed to read file: {}", file.display()))?;
    144
    145
    0
        let mut parser = RuchyParser::new(&source);
    146
    0
        match parser.parse() {
    147
    0
            Ok(ast) => {
    148
    0
                println!("{ast:#?}");
    149
    0
                Ok(())
    150
            }
    151
    0
            Err(e) => {
    152
    0
                eprintln!("Parse error: {e}");
    153
    0
                std::process::exit(1);
    154
            }
    155
        }
    156
    0
    }
    157
    158
    /// Handle transpile command - convert Ruchy to Rust
    159
    0
    pub fn handle_transpile_command(
    160
    0
        file: &Path,
    161
    0
        output: Option<&Path>,
    162
    0
        minimal: bool,
    163
    0
        verbose: bool
    164
    0
    ) -> Result<()> {
    165
    0
        log_transpile_start(file, minimal, verbose);
    166
    167
    0
        let source = read_source_file(file, verbose)?;
    168
    0
        let ast = parse_source(&source)?;
    169
    0
        let rust_code = transpile_ast(&ast, minimal)?;
    170
    171
    0
        write_output(&rust_code, output, verbose)?;
    172
    0
        Ok(())
    173
    0
    }
    174
    175
    /// Log transpilation start (complexity: 3)
    176
    0
    fn log_transpile_start(file: &Path, minimal: bool, verbose: bool) {
    177
    0
        if !verbose {
    178
    0
            return;
    179
    0
        }
    180
    0
        eprintln!("Transpiling file: {}", file.display());
    181
    0
        if minimal {
    182
    0
            eprintln!("Using minimal codegen for self-hosting");
    183
    0
        }
    184
    0
    }
    185
    186
    /// Read source from file or stdin (complexity: 5)
    187
    0
    fn read_source_file(file: &Path, verbose: bool) -> Result<String> {
    188
    0
        if file.as_os_str() == "-" {
    189
    0
            if verbose {
    190
    0
                eprintln!("Reading from stdin...");
    191
    0
            }
    192
    0
            let mut input = String::new();
    193
    0
            io::stdin().read_to_string(&mut input)?;
    194
    0
            Ok(input)
    195
        } else {
    196
    0
            fs::read_to_string(file)
    197
    0
                .with_context(|| format!("Failed to read file: {}", file.display()))
    198
        }
    199
    0
    }
    200
    201
    /// Parse source code to AST (complexity: 2)
    202
    0
    fn parse_source(source: &str) -> Result<Expr> {
    203
    0
        let mut parser = RuchyParser::new(source);
    204
    0
        parser.parse()
    205
    0
            .with_context(|| "Failed to parse input")
    206
    0
    }
    207
    208
    /// Transpile AST to Rust code (complexity: 4)
    209
    0
    fn transpile_ast(ast: &Expr, minimal: bool) -> Result<String> {
    210
    0
        let mut transpiler = Transpiler::new();
    211
    0
        if minimal {
    212
    0
            transpiler.transpile_minimal(ast)
    213
    0
                .with_context(|| "Failed to transpile to Rust (minimal)")
    214
        } else {
    215
    0
            transpiler.transpile_to_program(ast)
    216
    0
                .map(|tokens| tokens.to_string())
    217
    0
                .with_context(|| "Failed to transpile to Rust")
    218
        }
    219
    0
    }
    220
    221
    /// Write output to file or stdout (complexity: 5)
    222
    0
    fn write_output(rust_code: &str, output: Option<&Path>, verbose: bool) -> Result<()> {
    223
    0
        if let Some(output_path) = output {
    224
    0
            fs::write(output_path, rust_code)
    225
    0
                .with_context(|| format!("Failed to write output file: {}", output_path.display()))?;
    226
    0
            if verbose {
    227
    0
                eprintln!("Output written to: {}", output_path.display());
    228
    0
            }
    229
    0
        } else {
    230
    0
            print!("{rust_code}");
    231
    0
        }
    232
    0
        Ok(())
    233
    0
    }
    234
    235
    /// Handle run command - compile and execute a Ruchy file
    236
    0
    pub fn handle_run_command(file: &Path, verbose: bool) -> Result<()> {
    237
    0
        log_run_start(file, verbose);
    238
    239
        // Parse and transpile
    240
    0
        let source = fs::read_to_string(file)
    241
    0
            .with_context(|| format!("Failed to read file: {}", file.display()))?;
    242
    0
        let ast = parse_source(&source)?;
    243
    0
        let rust_code = transpile_for_execution(&ast, file)?;
    244
    245
        // Compile and execute
    246
    0
        let (temp_source, binary_path) = prepare_compilation(&rust_code, verbose)?;
    247
    0
        compile_rust_code(temp_source.path(), &binary_path)?;
    248
    0
        execute_binary(&binary_path)?;
    249
    250
    0
        Ok(())
    251
    0
    }
    252
    253
    /// Log run command start (complexity: 2)
    254
    0
    fn log_run_start(file: &Path, verbose: bool) {
    255
    0
        if verbose {
    256
    0
            eprintln!("Running file: {}", file.display());
    257
    0
        }
    258
    0
    }
    259
    260
    /// Transpile AST for execution with context (complexity: 3)
    261
    0
    fn transpile_for_execution(ast: &Expr, file: &Path) -> Result<String> {
    262
    0
        let transpiler = Transpiler::new();
    263
    0
        transpiler.transpile_to_program_with_context(ast, Some(file))
    264
    0
            .map(|tokens| tokens.to_string())
    265
    0
            .with_context(|| "Failed to transpile to Rust")
    266
    0
    }
    267
    268
    /// Prepare compilation artifacts (complexity: 4)
    269
    0
    fn prepare_compilation(rust_code: &str, verbose: bool) -> Result<(tempfile::NamedTempFile, PathBuf)> {
    270
    0
        let temp_source = tempfile::NamedTempFile::new()
    271
    0
            .with_context(|| "Failed to create temporary file")?;
    272
    0
        fs::write(temp_source.path(), rust_code)
    273
    0
            .with_context(|| "Failed to write temporary file")?;
    274
    275
    0
        if verbose {
    276
    0
            eprintln!("Temporary Rust file: {}", temp_source.path().display());
    277
    0
            eprintln!("Compiling and running...");
    278
    0
        }
    279
    280
        // Create unique binary path using process ID for temporary compilation output
    281
    0
        let binary_path = std::env::temp_dir().join(format!("ruchy_temp_bin_{}", std::process::id()));
    282
    283
    0
        Ok((temp_source, binary_path))
    284
    0
    }
    285
    286
    /// Compile Rust code using rustc (complexity: 5)
    287
    0
    fn compile_rust_code(source_path: &Path, binary_path: &Path) -> Result<()> {
    288
    0
        let output = std::process::Command::new("rustc")
    289
    0
            .arg("--edition=2021")
    290
    0
            .arg("--crate-name=ruchy_temp")
    291
    0
            .arg("-o")
    292
    0
            .arg(binary_path)
    293
    0
            .arg(source_path)
    294
    0
            .output()
    295
    0
            .with_context(|| "Failed to run rustc")?;
    296
    297
    0
        if !output.status.success() {
    298
    0
            eprintln!("Compilation failed:");
    299
    0
            eprintln!("{}", String::from_utf8_lossy(&output.stderr));
    300
    0
            std::process::exit(1);
    301
    0
        }
    302
    303
    0
        Ok(())
    304
    0
    }
    305
    306
    /// Execute compiled binary and handle output (complexity: 5)
    307
    0
    fn execute_binary(binary_path: &Path) -> Result<()> {
    308
    0
        let run_output = std::process::Command::new(binary_path)
    309
    0
            .output()
    310
    0
            .with_context(|| "Failed to run compiled binary")?;
    311
    312
    0
        print!("{}", String::from_utf8_lossy(&run_output.stdout));
    313
    0
        if !run_output.stderr.is_empty() {
    314
    0
            eprint!("{}", String::from_utf8_lossy(&run_output.stderr));
    315
    0
        }
    316
    317
    0
        if !run_output.status.success() {
    318
    0
            std::process::exit(run_output.status.code().unwrap_or(1));
    319
    0
        }
    320
    321
    0
        Ok(())
    322
    0
    }
    323
    324
    /// Handle interactive theorem prover (RUCHY-0820) - delegated to refactored module
    325
    0
    pub fn handle_prove_command(
    326
    0
        file: Option<&std::path::Path>,
    327
    0
        backend: &str,
    328
    0
        ml_suggestions: bool,
    329
    0
        timeout: u64,
    330
    0
        script: Option<&std::path::Path>,
    331
    0
        export: Option<&std::path::Path>,
    332
    0
        check: bool,
    333
    0
        counterexample: bool,
    334
    0
        verbose: bool,
    335
    0
        format: &str,
    336
    0
    ) -> anyhow::Result<()> {
    337
        // Delegate to refactored module with ≤10 complexity
    338
    0
        handlers_modules::prove::handle_prove_command(
    339
    0
            file,
    340
    0
            backend,
    341
    0
            ml_suggestions,
    342
    0
            timeout,
    343
    0
            script,
    344
    0
            export,
    345
    0
            check,
    346
    0
            counterexample,
    347
    0
            verbose,
    348
    0
            format,
    349
        )
    350
    0
    }
    351
    352
    /// Print prover help - moved to separate function for clarity
    353
    0
    fn print_prover_help() {
    354
    0
        println!("\nInteractive Prover Commands:");
    355
    0
        println!("  help          - Show this help message");
    356
    0
        println!("  quit/exit     - Exit the prover");
    357
    0
        println!("  goals         - Show current proof goals");
    358
    0
        println!("  tactics       - List available tactics");
    359
    0
        println!("  goal <stmt>   - Add a new proof goal");
    360
    0
        println!("  apply <tactic> - Apply a tactic to current goal");
    361
    0
        println!("\nTactics:");
    362
    0
        println!("  intro         - Introduce hypothesis from implication");
    363
    0
        println!("  split         - Split conjunction into subgoals");
    364
    0
        println!("  induction     - Proof by induction");
    365
    0
        println!("  contradiction - Proof by contradiction");
    366
    0
        println!("  reflexivity   - Prove equality by reflexivity");
    367
    0
        println!("  simplify      - Simplify expression");
    368
    0
        println!("  assumption    - Prove using an assumption");
    369
    0
        println!("\nExamples:");
    370
    0
        println!("  goal x > 0 -> x + 1 > 1");
    371
    0
        println!("  apply intro");
    372
    0
        println!("  apply simplify\n");
    373
    0
    }
    374
    375
    /// Handle REPL command - start the interactive Read-Eval-Print Loop
    376
    ///
    377
    /// # Examples
    378
    /// ```
    379
    /// // This function is typically called when no command or when repl command is specified
    380
    /// // handle_repl_command();
    381
    /// ```
    382
    ///
    383
    /// # Errors
    384
    /// Returns error if REPL fails to initialize or run
    385
    0
    pub fn handle_repl_command(record_file: Option<PathBuf>) -> Result<()> {
    386
        use colored::Colorize;
    387
    388
    0
        let version_msg = format!("Welcome to Ruchy REPL v{}", env!("CARGO_PKG_VERSION"));
    389
    0
        println!("{}", version_msg.bright_cyan().bold());
    390
    0
        println!(
    391
    0
            "Type {} for commands, {} to exit\n",
    392
    0
            ":help".green(),
    393
    0
            ":quit".yellow()
    394
        );
    395
    396
    0
        let mut repl = Repl::new()?;
    397
    398
    0
        if let Some(record_path) = record_file {
    399
    0
            repl.run_with_recording(&record_path)
    400
        } else {
    401
    0
            repl.run()
    402
        }
    403
    0
    }
    404
    405
    /// Handle compile command - compile Ruchy file to native binary
    406
    ///
    407
    /// # Arguments
    408
    /// * `file` - Path to the Ruchy file to compile
    409
    /// * `output` - Output binary path
    410
    /// * `opt_level` - Optimization level (0, 1, 2, 3, s, z)
    411
    /// * `strip` - Strip debug symbols
    412
    /// * `static_link` - Use static linking
    413
    /// * `target` - Target triple for cross-compilation
    414
    ///
    415
    /// # Examples
    416
    /// ```
    417
    /// // This function is typically called by the CLI compile command
    418
    /// // handle_compile_command(&Path::new("app.ruchy"), PathBuf::from("app"), "2".to_string(), true, false, None);
    419
    /// ```
    420
    ///
    421
    /// # Errors
    422
    /// Returns error if compilation fails or rustc is not available
    423
    0
    pub fn handle_compile_command(
    424
    0
        file: &Path,
    425
    0
        output: PathBuf,
    426
    0
        opt_level: String,
    427
    0
        strip: bool,
    428
    0
        static_link: bool,
    429
    0
        target: Option<String>,
    430
    0
    ) -> Result<()> {
    431
        use ruchy::backend::{CompileOptions, compile_to_binary as backend_compile};
    432
        use colored::Colorize;
    433
        use std::fs;
    434
    435
        // Check if rustc is available
    436
    0
        if let Err(e) = ruchy::backend::compiler::check_rustc_available() {
    437
    0
            eprintln!("{} {}", "Error:".bright_red(), e);
    438
    0
            eprintln!("Please install Rust toolchain from https://rustup.rs/");
    439
    0
            std::process::exit(1);
    440
    0
        }
    441
    442
    0
        println!("{} Compiling {}...", "→".bright_blue(), file.display());
    443
    444
    0
        let options = CompileOptions {
    445
    0
            output,
    446
    0
            opt_level,
    447
    0
            strip,
    448
    0
            static_link,
    449
    0
            target,
    450
    0
            rustc_flags: Vec::new(),
    451
    0
        };
    452
    453
    0
        match backend_compile(file, &options) {
    454
    0
            Ok(binary_path) => {
    455
    0
                println!(
    456
    0
                    "{} Successfully compiled to: {}",
    457
    0
                    "✓".bright_green(),
    458
    0
                    binary_path.display()
    459
                );
    460
    461
                // Make the binary executable on Unix
    462
                #[cfg(unix)]
    463
                {
    464
                    use std::os::unix::fs::PermissionsExt;
    465
    0
                    let mut perms = fs::metadata(&binary_path)?.permissions();
    466
    0
                    perms.set_mode(0o755);
    467
    0
                    fs::set_permissions(&binary_path, perms)?;
    468
                }
    469
    470
    0
                println!(
    471
    0
                    "{} Binary size: {} bytes",
    472
    0
                    "ℹ".bright_blue(),
    473
    0
                    fs::metadata(&binary_path)?.len()
    474
                );
    475
            }
    476
    0
            Err(e) => {
    477
    0
                eprintln!("{} Compilation failed: {}", "✗".bright_red(), e);
    478
    0
                std::process::exit(1);
    479
            }
    480
        }
    481
    482
    0
        Ok(())
    483
    0
    }
    484
    485
    /// Handle check command - check syntax of a Ruchy file
    486
    ///
    487
    /// # Arguments
    488
    /// * `file` - Path to the Ruchy file to check
    489
    /// * `watch` - Enable file watching mode
    490
    ///
    491
    /// # Examples
    492
    /// ```
    493
    /// // This function is typically called by the CLI check command
    494
    /// // handle_check_command(&Path::new("script.ruchy"), false);
    495
    /// ```
    496
    ///
    497
    /// # Errors
    498
    /// Returns error if file cannot be read or has syntax errors
    499
    0
    pub fn handle_check_command(file: &Path, watch: bool) -> Result<()> {
    500
    0
        if watch {
    501
    0
            handle_watch_and_check(file)
    502
        } else {
    503
    0
            handle_check_syntax(file)
    504
        }
    505
    0
    }
    506
    507
    /// Check syntax of a single file
    508
    0
    fn handle_check_syntax(file: &Path) -> Result<()> {
    509
        use colored::Colorize;
    510
    511
    0
        let source = fs::read_to_string(file)?;
    512
    0
        let mut parser = RuchyParser::new(&source);
    513
    0
        match parser.parse() {
    514
            Ok(_) => {
    515
    0
                println!("{}", "✓ Syntax is valid".green());
    516
    0
                Ok(())
    517
            }
    518
    0
            Err(e) => {
    519
    0
                eprintln!("{}", format!("✗ Syntax error: {e}").red());
    520
    0
                std::process::exit(1);
    521
            }
    522
        }
    523
    0
    }
    524
    525
    /// Watch a file and check syntax on changes
    526
    0
    fn handle_watch_and_check(file: &Path) -> Result<()> {
    527
        use colored::Colorize;
    528
        use std::thread;
    529
        use std::time::Duration;
    530
    531
    0
        println!(
    532
    0
            "{} Watching {} for changes...",
    533
    0
            "👁".bright_cyan(),
    534
    0
            file.display()
    535
        );
    536
    0
        println!("Press Ctrl+C to stop watching\n");
    537
    538
        // Initial check
    539
    0
        handle_check_syntax(file)?;
    540
    541
        // Simple file watching using polling
    542
    0
        let mut last_modified = fs::metadata(file)?.modified()?;
    543
    544
        loop {
    545
    0
            thread::sleep(Duration::from_millis(500));
    546
    547
    0
            let Ok(metadata) = fs::metadata(file) else {
    548
    0
                continue; // File might be temporarily unavailable
    549
            };
    550
    551
    0
            let Ok(modified) = metadata.modified() else {
    552
    0
                continue;
    553
            };
    554
    555
    0
            if modified != last_modified {
    556
    0
                last_modified = modified;
    557
    0
                println!("\n{} File changed, checking...", "→".bright_cyan());
    558
    0
                let _ = handle_check_syntax(file); // Don't exit on error, keep watching
    559
    0
            }
    560
        }
    561
    0
    }
    562
    563
    /// Handle test command - run tests with various options (delegated to refactored module)
    564
    ///
    565
    /// # Arguments
    566
    /// * `path` - Optional path to test directory
    567
    /// * `watch` - Enable watch mode
    568
    /// * `verbose` - Enable verbose output
    569
    /// * `filter` - Optional test filter
    570
    /// * `coverage` - Enable coverage reporting
    571
    /// * `coverage_format` - Coverage report format
    572
    /// * `parallel` - Number of parallel test threads
    573
    /// * `threshold` - Coverage threshold
    574
    /// * `format` - Output format
    575
    ///
    576
    /// # Examples
    577
    /// ```
    578
    /// // This function is typically called by the CLI test command
    579
    /// // handle_test_command(None, false, false, None, false, &"text".to_string(), 1, 80.0, &"text".to_string());
    580
    /// ```
    581
    ///
    582
    /// # Errors
    583
    /// Returns error if tests fail to run or coverage threshold is not met
    584
    0
    pub fn handle_test_command(
    585
    0
        path: Option<PathBuf>,
    586
    0
        watch: bool,
    587
    0
        verbose: bool,
    588
    0
        filter: Option<&str>,
    589
    0
        coverage: bool,
    590
    0
        coverage_format: &str,
    591
    0
        parallel: usize,
    592
    0
        threshold: f64,
    593
    0
        format: &str,
    594
    0
    ) -> Result<()> {
    595
        // Delegate to refactored module with ≤10 complexity
    596
    0
        handlers_modules::test::handle_test_command(
    597
    0
            path,
    598
    0
            watch,
    599
    0
            verbose,
    600
    0
            filter,
    601
    0
            coverage,
    602
    0
            coverage_format,
    603
    0
            parallel,
    604
    0
            threshold,
    605
    0
            format,
    606
        )
    607
    0
    }
    608
    609
    /// Handle the coverage command - generate coverage report for Ruchy code
    610
    ///
    611
    /// # Arguments
    612
    /// * `path` - File or directory path to analyze
    613
    /// * `threshold` - Coverage threshold to check against
    614
    /// * `format` - Output format (text, html, json)
    615
    /// * `verbose` - Enable verbose output
    616
    ///
    617
    /// # Errors
    618
    /// Returns error if coverage analysis fails or threshold is not met
    619
    0
    pub fn handle_coverage_command(
    620
    0
        path: &Path,
    621
    0
        threshold: f64,
    622
    0
        format: &str,
    623
    0
        verbose: bool,
    624
    0
    ) -> Result<()> {
    625
        use ruchy::quality::ruchy_coverage::RuchyCoverageCollector;
    626
    627
    0
        if verbose {
    628
    0
            println!("🔍 Analyzing coverage for: {}", path.display());
    629
    0
            println!("📊 Threshold: {:.1}%", threshold);
    630
    0
            println!("📋 Format: {}", format);
    631
    0
        }
    632
    633
        // Create coverage collector
    634
    0
        let mut collector = RuchyCoverageCollector::new();
    635
    636
        // Execute the file with coverage collection
    637
    0
        collector.execute_with_coverage(path)?;
    638
    639
        // Generate the coverage report based on format
    640
    0
        let report = match format {
    641
    0
            "html" => collector.generate_html_report(),
    642
    0
            "json" => collector.generate_json_report(),
    643
    0
            _ => collector.generate_text_report(), // Default to text
    644
        };
    645
    0
        println!("{}", report);
    646
    647
        // Check threshold if specified
    648
    0
        if threshold > 0.0 {
    649
    0
            if collector.meets_threshold(threshold) {
    650
    0
                println!("\n✅ Coverage meets threshold of {:.1}%", threshold);
    651
    0
            } else {
    652
    0
                eprintln!("\n❌ Coverage below threshold of {:.1}%", threshold);
    653
    0
                std::process::exit(1);
    654
            }
    655
    0
        }
    656
    657
    0
        Ok(())
    658
    0
    }
    659
    660
    /// Watch and run tests on changes - delegated to refactored module
    661
    0
    fn handle_watch_and_test(path: &Path, verbose: bool, filter: Option<&str>) -> Result<()> {
    662
    0
        handlers_modules::test::handle_test_command(
    663
    0
            Some(path.to_path_buf()),
    664
            true, // watch mode
    665
    0
            verbose,
    666
    0
            filter,
    667
            false, // coverage
    668
    0
            "text",
    669
            1,
    670
            0.0,
    671
    0
            "text",
    672
        )
    673
    0
    }
    674
    675
    /// Run enhanced tests - delegated to refactored module
    676
    #[allow(clippy::unnecessary_wraps)]
    677
    0
    fn handle_run_enhanced_tests(
    678
    0
        path: &Path,
    679
    0
        verbose: bool,
    680
    0
        filter: Option<&str>,
    681
    0
        coverage: bool,
    682
    0
        coverage_format: &str,
    683
    0
        parallel: usize,
    684
    0
        threshold: f64,
    685
    0
        format: &str,
    686
    0
    ) -> Result<()> {
    687
    0
        handlers_modules::test::handle_test_command(
    688
    0
            Some(path.to_path_buf()),
    689
            false, // not watch mode
    690
    0
            verbose,
    691
    0
            filter,
    692
    0
            coverage,
    693
    0
            coverage_format,
    694
    0
            parallel,
    695
    0
            threshold,
    696
    0
            format,
    697
        )
    698
    0
    }
    699
    700
    /// Run a single .ruchy test file - delegated to `test_helpers` module
    701
    0
    fn run_ruchy_test_file(test_file: &Path, verbose: bool) -> Result<()> {
    702
    0
        handlers_modules::test_helpers::run_test_file(test_file, verbose)
    703
    0
    }
    704
    705
    /// Verify proofs extracted from AST - delegated to `prove_helpers` module
    706
    0
    fn verify_proofs_from_ast(
    707
    0
        ast: &ruchy::frontend::ast::Expr,
    708
    0
        file_path: &std::path::Path,
    709
    0
        format: &str,
    710
    0
        counterexample: bool,
    711
    0
        verbose: bool
    712
    0
    ) -> Result<()> {
    713
    0
        handlers_modules::prove_helpers::verify_proofs_from_ast(
    714
    0
            ast,
    715
    0
            file_path,
    716
    0
            format,
    717
    0
            counterexample,
    718
    0
            verbose,
    719
        )
    720
    0
    }
    721
    ///
    722
    /// # Arguments
    723
    /// * `command` - The command to execute
    724
    ///
    725
    /// # Examples
    726
    /// ```
    727
    /// // This function is typically called by the main dispatcher for complex commands
    728
    /// ```
    729
    ///
    730
    /// # Errors
    731
    /// Returns error if command execution fails
    732
    #[allow(clippy::unnecessary_wraps)]
    733
    0
    pub fn handle_complex_command(command: crate::Commands) -> Result<()> {
    734
    0
        match command {
    735
            crate::Commands::Ast {
    736
    0
                file,
    737
    0
                json,
    738
    0
                graph,
    739
    0
                metrics,
    740
    0
                symbols,
    741
    0
                deps,
    742
    0
                verbose,
    743
    0
                output
    744
            } => {
    745
    0
                commands::handle_ast_command(
    746
    0
                    &file,
    747
    0
                    json,
    748
    0
                    graph,
    749
    0
                    metrics,
    750
    0
                    symbols,
    751
    0
                    deps,
    752
    0
                    verbose,
    753
    0
                    output.as_deref(),
    754
                )
    755
            }
    756
            crate::Commands::Provability {
    757
    0
                file,
    758
    0
                verify,
    759
    0
                contracts,
    760
    0
                invariants,
    761
    0
                termination,
    762
    0
                bounds,
    763
    0
                verbose,
    764
    0
                output
    765
            } => {
    766
    0
                commands::handle_provability_command(
    767
    0
                    &file,
    768
    0
                    verify,
    769
    0
                    contracts,
    770
    0
                    invariants,
    771
    0
                    termination,
    772
    0
                    bounds,
    773
    0
                    verbose,
    774
    0
                    output.as_deref(),
    775
                )
    776
            }
    777
            crate::Commands::Runtime {
    778
    0
                file,
    779
    0
                profile,
    780
    0
                bigo,
    781
    0
                bench,
    782
    0
                compare,
    783
    0
                memory,
    784
    0
                verbose,
    785
    0
                output
    786
            } => {
    787
    0
                commands::handle_runtime_command(
    788
    0
                    &file,
    789
    0
                    profile,
    790
    0
                    bigo,
    791
    0
                    bench,
    792
    0
                    compare.as_deref(),
    793
    0
                    memory,
    794
    0
                    verbose,
    795
    0
                    output.as_deref(),
    796
                )
    797
            }
    798
            crate::Commands::Score {
    799
    0
                path,
    800
    0
                depth,
    801
    0
                fast,
    802
    0
                deep,
    803
    0
                watch,
    804
    0
                explain,
    805
    0
                baseline,
    806
    0
                min,
    807
    0
                config,
    808
    0
                format,
    809
    0
                verbose,
    810
    0
                output,
    811
            } => {
    812
    0
                commands::handle_score_command(
    813
    0
                    &path,
    814
    0
                    &depth,
    815
    0
                    fast,
    816
    0
                    deep,
    817
    0
                    watch,
    818
    0
                    explain,
    819
    0
                    baseline.as_deref(),
    820
    0
                    min,
    821
    0
                    config.as_deref(),
    822
    0
                    &format,
    823
    0
                    verbose,
    824
    0
                    output.as_deref(),
    825
                )
    826
            }
    827
            crate::Commands::QualityGate {
    828
    0
                path,
    829
    0
                config,
    830
                depth: _,
    831
    0
                fail_fast,
    832
    0
                format,
    833
    0
                export,
    834
                ci: _,
    835
    0
                verbose,
    836
            } => {
    837
                // Simplified quality gate handling
    838
    0
                commands::handle_quality_gate_command(
    839
    0
                    &path,
    840
    0
                    config.as_deref(),
    841
    0
                    fail_fast,    // Use as strict
    842
    0
                    !verbose,     // Use as quiet
    843
    0
                    format == "json",
    844
    0
                    verbose,
    845
    0
                    None,         // No output field
    846
    0
                    export.as_deref(),
    847
                )
    848
            }
    849
            crate::Commands::Fmt {
    850
    0
                file,
    851
    0
                all,
    852
    0
                check,
    853
    0
                stdout,
    854
    0
                diff,
    855
    0
                config,
    856
                line_width: _,
    857
                indent: _,
    858
                use_tabs: _,
    859
            } => {
    860
                // Simplified fmt handling
    861
    0
                commands::handle_fmt_command(
    862
    0
                    &file,
    863
    0
                    check,
    864
    0
                    !check && !stdout,  // write if not check or stdout
    865
    0
                    config.as_deref(),
    866
    0
                    all,
    867
    0
                    diff,
    868
    0
                    stdout,
    869
                    false,  // verbose not available
    870
                )
    871
            }
    872
            crate::Commands::Lint {
    873
    0
                file,
    874
                all: _,
    875
    0
                fix,
    876
    0
                strict,
    877
    0
                verbose,
    878
    0
                format,
    879
    0
                rules,
    880
                deny_warnings: _,
    881
                max_complexity: _,
    882
    0
                config,
    883
    0
                init_config,
    884
            } => {
    885
    0
                if init_config {
    886
                    // Create default lint config
    887
    0
                    println!("Creating default lint configuration...");
    888
    0
                    Ok(())
    889
    0
                } else if let Some(file_path) = file {
    890
    0
                    commands::handle_lint_command(
    891
    0
                        &file_path,
    892
    0
                        fix,
    893
    0
                        strict,
    894
    0
                        rules.as_deref(),
    895
    0
                        format == "json",
    896
    0
                        verbose,
    897
    0
                        None,  // ignore not available
    898
    0
                        config.as_deref(),
    899
                    )
    900
                } else {
    901
    0
                    eprintln!("Error: Either provide a file or use --all flag");
    902
    0
                    std::process::exit(1);
    903
                }
    904
            }
    905
            crate::Commands::Prove {
    906
    0
                file,
    907
    0
                backend,
    908
    0
                ml_suggestions,
    909
    0
                timeout,
    910
    0
                script,
    911
    0
                export,
    912
    0
                check,
    913
    0
                counterexample,
    914
    0
                verbose,
    915
    0
                format,
    916
            } => {
    917
    0
                handle_prove_command(
    918
    0
                    file.as_deref(),
    919
    0
                    &backend,
    920
    0
                    ml_suggestions,
    921
    0
                    timeout,
    922
    0
                    script.as_deref(),
    923
    0
                    export.as_deref(),
    924
    0
                    check,
    925
    0
                    counterexample,
    926
    0
                    verbose,
    927
    0
                    &format,
    928
                )
    929
            }
    930
    0
            crate::Commands::Coverage { path, threshold, format, verbose } => {
    931
    0
                handle_coverage_command(&path, threshold.unwrap_or(80.0), &format, verbose)
    932
            }
    933
    0
            crate::Commands::ReplayToTests { input, output, property_tests, benchmarks, timeout } => {
    934
    0
                handle_replay_to_tests_command(&input, output.as_deref(), property_tests, benchmarks, timeout)
    935
            }
    936
            _ => {
    937
                // Other commands not yet implemented
    938
    0
                eprintln!("Command not yet implemented");
    939
    0
                Ok(())
    940
            }
    941
        }
    942
    943
        /*
    944
        // Original complex command handling - commented out until handlers implemented
    945
        match command {
    946
            crate::Commands::Ast {
    947
                file,
    948
                json,
    949
                graph,
    950
                metrics,
    951
                symbols,
    952
                deps,
    953
                verbose,
    954
                output
    955
            } => {
    956
                // AST analysis implementation planned
    957
                eprintln!("AST analysis not yet implemented");
    958
                Ok(())
    959
            }
    960
            crate::Commands::Provability {
    961
                file,
    962
                verify,
    963
                contracts,
    964
                invariants,
    965
                termination,
    966
                bounds,
    967
                verbose,
    968
                output
    969
            } => {
    970
                // Provability analysis implementation planned
    971
                eprintln!("Provability analysis not yet implemented");
    972
                Ok(())
    973
            }
    974
            crate::Commands::Runtime {
    975
                file,
    976
                profile,
    977
                bigo,
    978
                bench,
    979
                compare,
    980
                memory,
    981
                verbose,
    982
                output
    983
            } => {
    984
                // Runtime analysis implementation planned
    985
                eprintln!("Runtime analysis not yet implemented");
    986
                Ok(())
    987
            }
    988
            crate::Commands::Score {
    989
                path,
    990
                depth,
    991
                fast,
    992
                deep,
    993
                watch,
    994
                explain,
    995
                baseline,
    996
                min,
    997
                config,
    998
                format,
    999
                verbose,
    1000
                output,
    1001
            } => {
    1002
                let baseline_str = baseline.as_deref();
    1003
                let config_str = config.as_ref().and_then(|p| p.to_str());
    1004
                let output_str = output.as_ref().and_then(|p| p.to_str());
    1005
                // Quality score calculation implementation planned
    1006
                eprintln!("Quality score calculation not yet implemented");
    1007
                Ok(())
    1008
            }
    1009
            crate::Commands::QualityGate {
    1010
                path,
    1011
                config,
    1012
                depth,
    1013
                fail_fast,
    1014
                format,
    1015
                export,
    1016
                ci,
    1017
                verbose,
    1018
            } => {
    1019
                // Quality gates implementation planned
    1020
                eprintln!("Quality gates enforcement not yet implemented");
    1021
                Ok(())
    1022
            }
    1023
            crate::Commands::Fmt {
    1024
                file: _,
    1025
                all: _,
    1026
                check: _,
    1027
                stdout: _,
    1028
                diff: _,
    1029
                config: _,
    1030
                line_width: _,
    1031
                indent: _,
    1032
                use_tabs: _,
    1033
            } => {
    1034
                // Code formatting implementation planned
    1035
                eprintln!("Code formatting not yet implemented");
    1036
                Ok(())
    1037
            }
    1038
            crate::Commands::Doc {
    1039
                path,
    1040
                output,
    1041
                format,
    1042
                private,
    1043
                open,
    1044
                all,
    1045
                verbose,
    1046
            } => {
    1047
                // Documentation generation implementation planned
    1048
                eprintln!("Documentation generation not yet implemented");
    1049
                Ok(())
    1050
            }
    1051
            crate::Commands::Bench {
    1052
                file,
    1053
                iterations,
    1054
                warmup,
    1055
                format,
    1056
                output,
    1057
                verbose,
    1058
            } => {
    1059
                crate::benchmark_ruchy_code(
    1060
                    &file,
    1061
                    iterations,
    1062
                    warmup,
    1063
                    &format,
    1064
                    output.as_deref(),
    1065
                    verbose,
    1066
                )
    1067
            }
    1068
            crate::Commands::Lint {
    1069
                file,
    1070
                all: _,
    1071
                fix,
    1072
                strict,
    1073
                verbose,
    1074
                format,
    1075
                rules,
    1076
                deny_warnings: _,
    1077
                max_complexity: _,
    1078
                config,
    1079
                init_config,
    1080
            } => {
    1081
                if init_config {
    1082
                    crate::generate_default_lint_config()
    1083
                } else {
    1084
                    // Load custom rules if config provided
    1085
                    let custom_rules = if let Some(config_path) = config {
    1086
                        crate::load_custom_lint_rules(&config_path)?
    1087
                    } else {
    1088
                        // Custom lint rules implementation planned
    1089
                        Default::default()
    1090
                    };
    1091
    1092
                    if all {
    1093
                        crate::lint_ruchy_code(
    1094
                            &PathBuf::from("."),
    1095
                            all,
    1096
                            fix,
    1097
                            strict,
    1098
                            verbose,
    1099
                            &format,
    1100
                            rules.as_deref(),
    1101
                            deny_warnings,
    1102
                            max_complexity,
    1103
                            &custom_rules,
    1104
                        )
    1105
                    } else if let Some(file) = file {
    1106
                        crate::lint_ruchy_code(
    1107
                            &file,
    1108
                            false,
    1109
                            fix,
    1110
                            strict,
    1111
                            verbose,
    1112
                            &format,
    1113
                            rules.as_deref(),
    1114
                            deny_warnings,
    1115
                            max_complexity,
    1116
                            &custom_rules,
    1117
                        )
    1118
                    } else {
    1119
                        eprintln!("Error: Either provide a file or use --all flag");
    1120
                        std::process::exit(1);
    1121
                    }
    1122
                }
    1123
            }
    1124
            crate::Commands::Add {
    1125
                package,
    1126
                version,
    1127
                dev,
    1128
                registry,
    1129
            } => {
    1130
                crate::add_package(&package, version.as_deref(), dev, &registry)
    1131
            }
    1132
            crate::Commands::Publish {
    1133
                registry,
    1134
                version,
    1135
                dry_run,
    1136
                allow_dirty,
    1137
            } => {
    1138
                crate::publish_package(&registry, version.as_deref(), dry_run, allow_dirty)
    1139
            }
    1140
            crate::Commands::Mcp {
    1141
                name,
    1142
                streaming,
    1143
                timeout,
    1144
                min_score,
    1145
                max_complexity,
    1146
                verbose,
    1147
                config,
    1148
            } => {
    1149
                let config_str = config.as_ref().and_then(|p| p.to_str());
    1150
                crate::start_mcp_server(&name, streaming, timeout, min_score, max_complexity, verbose, config_str)
    1151
            }
    1152
            crate::Commands::Optimize {
    1153
                file,
    1154
                hardware,
    1155
                depth,
    1156
                cache,
    1157
                branches,
    1158
                vectorization,
    1159
                abstractions,
    1160
                benchmark,
    1161
                format,
    1162
                output,
    1163
                verbose,
    1164
                threshold,
    1165
            } => {
    1166
                crate::optimize_file(
    1167
                    &file,
    1168
                    &hardware,
    1169
                    &depth,
    1170
                    cache,
    1171
                    branches,
    1172
                    vectorization,
    1173
                    abstractions,
    1174
                    benchmark,
    1175
                    &format,
    1176
                    output.as_deref(),
    1177
                    verbose,
    1178
                    threshold,
    1179
                )
    1180
            }
    1181
            crate::Commands::ActorObserve {
    1182
                config,
    1183
                refresh_interval,
    1184
                max_traces,
    1185
                max_actors,
    1186
                enable_deadlock_detection,
    1187
                deadlock_interval,
    1188
                start_mode,
    1189
                no_color,
    1190
                format,
    1191
                export,
    1192
                duration,
    1193
                verbose,
    1194
                filter_actor,
    1195
                filter_failed,
    1196
                filter_slow,
    1197
            } => {
    1198
                crate::start_actor_observatory(
    1199
                    config.as_ref(),
    1200
                    refresh_interval,
    1201
                    max_traces,
    1202
                    max_actors,
    1203
                    enable_deadlock_detection,
    1204
                    deadlock_interval,
    1205
                    &start_mode,
    1206
                    !no_color,
    1207
                    &format,
    1208
                    export.as_ref(),
    1209
                    duration,
    1210
                    verbose,
    1211
                    filter_actor.as_ref(),
    1212
                    filter_failed,
    1213
                    filter_slow,
    1214
                )
    1215
            }
    1216
            crate::Commands::DataflowDebug {
    1217
                config,
    1218
                max_rows,
    1219
                auto_materialize,
    1220
                enable_profiling,
    1221
                timeout,
    1222
                track_memory,
    1223
                compute_diffs,
    1224
                sample_rate,
    1225
                refresh_interval,
    1226
                no_color,
    1227
                format,
    1228
                export,
    1229
                verbose,
    1230
                breakpoint,
    1231
                start_mode,
    1232
            } => {
    1233
                crate::start_dataflow_debugger(
    1234
                    config.as_ref(),
    1235
                    max_rows,
    1236
                    auto_materialize,
    1237
                    enable_profiling,
    1238
                    timeout,
    1239
                    track_memory,
    1240
                    compute_diffs,
    1241
                    sample_rate,
    1242
                    refresh_interval,
    1243
                    !no_color,
    1244
                    &format,
    1245
                    export.as_ref(),
    1246
                    verbose,
    1247
                    &breakpoint,
    1248
                    &start_mode,
    1249
                )
    1250
            }
    1251
            crate::Commands::Wasm {
    1252
                file,
    1253
                output,
    1254
                target,
    1255
                wit,
    1256
                deploy,
    1257
                deploy_target,
    1258
                portability,
    1259
                opt_level,
    1260
                debug,
    1261
                simd,
    1262
                threads,
    1263
                component_model,
    1264
                name,
    1265
                version,
    1266
                verbose,
    1267
            } => {
    1268
                crate::handle_wasm_command(
    1269
                    &file,
    1270
                    output.as_deref(),
    1271
                    &target,
    1272
                    wit,
    1273
                    deploy,
    1274
                    deploy_target.as_deref(),
    1275
                    portability,
    1276
                    &opt_level,
    1277
                    debug,
    1278
                    simd,
    1279
                    threads,
    1280
                    component_model,
    1281
                    name.as_deref(),
    1282
                    &version,
    1283
                    verbose,
    1284
                )
    1285
            }
    1286
            _ => {
    1287
                // This should not be reached since handled commands are processed elsewhere
    1288
                eprintln!("Error: Command not implemented in complex handler");
    1289
                std::process::exit(1);
    1290
            }
    1291
        }
    1292
        */
    1293
    0
    }
    1294
    1295
    /// Handle replay-to-tests command - convert .replay files to regression tests
    1296
    ///
    1297
    /// # Arguments
    1298
    /// * `input` - Input replay file or directory containing .replay files
    1299
    /// * `output` - Optional output test file path
    1300
    /// * `property_tests` - Whether to include property tests
    1301
    /// * `benchmarks` - Whether to include benchmarks
    1302
    /// * `timeout` - Test timeout in milliseconds
    1303
    ///
    1304
    /// # Examples
    1305
    /// ```
    1306
    /// // Convert single replay file
    1307
    /// handle_replay_to_tests_command(Path::new("demo.replay"), None, true, false, 5000);
    1308
    ///
    1309
    /// // Convert directory of replay files
    1310
    /// handle_replay_to_tests_command(Path::new("demos/"), Some(Path::new("tests/replays.rs")), true, true, 10000);
    1311
    /// ```
    1312
    ///
    1313
    /// # Errors
    1314
    /// Returns error if replay files can't be read or test files can't be written
    1315
    1316
    /// Setup conversion configuration for replay-to-test conversion (complexity: 4)
    1317
    0
    fn setup_conversion_config(property_tests: bool, benchmarks: bool, timeout: u64) -> ConversionConfig {
    1318
    0
        ConversionConfig {
    1319
    0
            test_module_prefix: "replay_generated".to_string(),
    1320
    0
            include_property_tests: property_tests,
    1321
    0
            include_benchmarks: benchmarks,
    1322
    0
            timeout_ms: timeout,
    1323
    0
        }
    1324
    0
    }
    1325
    1326
    /// Determine output path, using default if none provided (complexity: 3)
    1327
    0
    fn determine_output_path(output: Option<&Path>) -> &Path {
    1328
    0
        let default_output = Path::new("tests/generated_from_replays.rs");
    1329
    0
        output.unwrap_or(default_output)
    1330
    0
    }
    1331
    1332
    /// Validate that file has .replay extension (complexity: 3)
    1333
    0
    fn validate_replay_file(path: &Path) -> Result<()> {
    1334
    0
        if path.extension().and_then(|s| s.to_str()) == Some("replay") {
    1335
    0
            Ok(())
    1336
        } else {
    1337
    0
            eprintln!("❌ Input file must have .replay extension");
    1338
    0
            Err(anyhow::anyhow!("Invalid file extension"))
    1339
        }
    1340
    0
    }
    1341
    1342
    /// Process a single .replay file (complexity: 8)
    1343
    0
    fn process_single_file(
    1344
    0
        input: &Path,
    1345
    0
        converter: &ruchy::runtime::replay_converter::ReplayConverter,
    1346
    0
        all_tests: &mut Vec<ruchy::runtime::replay_converter::GeneratedTest>,
    1347
    0
        processed_files: &mut usize
    1348
    0
    ) -> Result<()> {
    1349
    1350
    1351
    0
        validate_replay_file(input)?;
    1352
    1353
    0
        println!("📄 Processing replay file: {}", input.display());
    1354
    1355
    0
        match converter.convert_file(input) {
    1356
    0
            Ok(tests) => {
    1357
    0
                println!("  ✅ Generated {} tests", tests.len());
    1358
    0
                all_tests.extend(tests);
    1359
    0
                *processed_files += 1;
    1360
    0
                Ok(())
    1361
            }
    1362
    0
            Err(e) => {
    1363
    0
                eprintln!("  ❌ Failed to process {}: {}", input.display(), e);
    1364
    0
                Err(e)
    1365
            }
    1366
        }
    1367
    0
    }
    1368
    1369
    /// Process directory containing .replay files (complexity: 10)
    1370
    0
    fn process_directory(
    1371
    0
        input: &Path,
    1372
    0
        converter: &ruchy::runtime::replay_converter::ReplayConverter,
    1373
    0
        all_tests: &mut Vec<ruchy::runtime::replay_converter::GeneratedTest>,
    1374
    0
        processed_files: &mut usize
    1375
    0
    ) -> Result<()> {
    1376
    1377
        use std::fs;
    1378
    1379
    0
        println!("📁 Processing replay directory: {}", input.display());
    1380
    1381
        // Find all .replay files in directory
    1382
    0
        let replay_files: Vec<_> = fs::read_dir(input)?
    1383
    0
            .filter_map(|entry| {
    1384
    0
                let entry = entry.ok()?;
    1385
    0
                let path = entry.path();
    1386
    0
                if path.is_file() && path.extension()? == "replay" {
    1387
    0
                    Some(path)
    1388
                } else {
    1389
    0
                    None
    1390
                }
    1391
    0
            })
    1392
    0
            .collect();
    1393
    1394
    0
        if replay_files.is_empty() {
    1395
    0
            println!("⚠️  No .replay files found in directory");
    1396
    0
            return Ok(());
    1397
    0
        }
    1398
    1399
    0
        println!("🔍 Found {} replay files", replay_files.len());
    1400
    1401
    0
        for replay_file in replay_files {
    1402
    0
            println!("📄 Processing: {}", replay_file.display());
    1403
    1404
    0
            match converter.convert_file(&replay_file) {
    1405
    0
                Ok(tests) => {
    1406
    0
                    println!("  ✅ Generated {} tests", tests.len());
    1407
    0
                    all_tests.extend(tests);
    1408
    0
                    *processed_files += 1;
    1409
    0
                }
    1410
    0
                Err(e) => {
    1411
    0
                    eprintln!("  ⚠️  Failed to process {}: {}", replay_file.display(), e);
    1412
    0
                    // Continue with other files instead of failing completely
    1413
    0
                }
    1414
            }
    1415
        }
    1416
    1417
    0
        Ok(())
    1418
    0
    }
    1419
    1420
    /// Write test output to file, creating directories if needed (complexity: 4)
    1421
    0
    fn write_test_output(
    1422
    0
        converter: &ruchy::runtime::replay_converter::ReplayConverter,
    1423
    0
        all_tests: &[ruchy::runtime::replay_converter::GeneratedTest],
    1424
    0
        output_path: &Path
    1425
    0
    ) -> Result<()> {
    1426
        use std::fs;
    1427
        use anyhow::Context;
    1428
    1429
        // Create output directory if needed
    1430
    0
        if let Some(parent) = output_path.parent() {
    1431
    0
            fs::create_dir_all(parent)?;
    1432
    0
        }
    1433
    1434
    0
        println!("📝 Writing tests to: {}", output_path.display());
    1435
    1436
    0
        converter.write_tests(all_tests, output_path)
    1437
    0
            .context("Failed to write test file")?;
    1438
    1439
    0
        Ok(())
    1440
    0
    }
    1441
    1442
    /// Generate comprehensive summary report of conversion results (complexity: 8)
    1443
    0
    fn generate_summary_report(
    1444
    0
        all_tests: &[ruchy::runtime::replay_converter::GeneratedTest],
    1445
    0
        processed_files: usize
    1446
    0
    ) {
    1447
        use colored::Colorize;
    1448
        use std::collections::{HashMap, HashSet};
    1449
    1450
    0
        println!("\n{}", "🎉 Conversion Summary".bright_green().bold());
    1451
    0
        println!("=====================================");
    1452
    0
        println!("📊 Files processed: {}", processed_files);
    1453
    0
        println!("✅ Tests generated: {}", all_tests.len());
    1454
    1455
        // Breakdown by test category
    1456
    0
        let mut category_counts = HashMap::new();
    1457
    0
        let mut coverage_areas = HashSet::new();
    1458
    1459
    0
        for test in all_tests {
    1460
    0
            *category_counts.entry(&test.category).or_insert(0) += 1;
    1461
    0
            coverage_areas.extend(test.coverage_areas.iter().cloned());
    1462
    0
        }
    1463
    1464
    0
        println!("\n📋 Test Breakdown:");
    1465
    0
        for (category, count) in category_counts {
    1466
    0
            println!("   {:?}: {}", category, count);
    1467
    0
        }
    1468
    1469
    0
        println!("\n🎯 Coverage Areas: {} unique areas", coverage_areas.len());
    1470
    0
        if !coverage_areas.is_empty() {
    1471
    0
            let mut areas: Vec<_> = coverage_areas.into_iter().collect();
    1472
    0
            areas.sort();
    1473
    0
            for area in areas.iter().take(10) {  // Show first 10
    1474
    0
                println!("   • {}", area);
    1475
    0
            }
    1476
    0
            if areas.len() > 10 {
    1477
    0
                println!("   ... and {} more", areas.len() - 10);
    1478
    0
            }
    1479
    0
        }
    1480
    1481
    0
        println!("\n💡 Next Steps:");
    1482
    0
        println!("   1. Run tests: cargo test");
    1483
    0
        println!("   2. Measure coverage: cargo test -- --test-threads=1");
    1484
    0
        println!("   3. Validate replay determinism");
    1485
    1486
    0
        println!("\n🚀 {}", "Replay-to-test conversion complete!".bright_green());
    1487
    0
    }
    1488
    1489
    /// Process input path (file or directory) with replay files (complexity: 5)
    1490
    0
    fn process_input_path(
    1491
    0
        input: &Path,
    1492
    0
        converter: &ruchy::runtime::replay_converter::ReplayConverter,
    1493
    0
        all_tests: &mut Vec<ruchy::runtime::replay_converter::GeneratedTest>,
    1494
    0
        processed_files: &mut usize
    1495
    0
    ) -> Result<()> {
    1496
    0
        if input.is_file() {
    1497
    0
            process_single_file(input, converter, all_tests, processed_files)
    1498
    0
        } else if input.is_dir() {
    1499
    0
            process_directory(input, converter, all_tests, processed_files)
    1500
        } else {
    1501
    0
            eprintln!("❌ Input path must be a file or directory");
    1502
    0
            Err(anyhow::anyhow!("Invalid input path"))
    1503
        }
    1504
    0
    }
    1505
    1506
    /// Convert REPL replay files to regression tests (complexity: 7)
    1507
    0
    pub fn handle_replay_to_tests_command(
    1508
    0
        input: &Path,
    1509
    0
        output: Option<&Path>,
    1510
    0
        property_tests: bool,
    1511
    0
        benchmarks: bool,
    1512
    0
        timeout: u64,
    1513
    0
    ) -> Result<()> {
    1514
        use colored::Colorize;
    1515
        use ruchy::runtime::replay_converter::ReplayConverter;
    1516
    1517
    0
        println!("{}", "🔄 Converting REPL replay files to regression tests".bright_cyan().bold());
    1518
    0
        println!("Input: {}", input.display());
    1519
    1520
    0
        let config = setup_conversion_config(property_tests, benchmarks, timeout);
    1521
    0
        let converter = ReplayConverter::with_config(config);
    1522
    0
        let mut all_tests = Vec::new();
    1523
    0
        let mut processed_files = 0;
    1524
    1525
    0
        let output_path = determine_output_path(output);
    1526
    1527
    0
        process_input_path(input, &converter, &mut all_tests, &mut processed_files)?;
    1528
    1529
    0
        if all_tests.is_empty() {
    1530
    0
            println!("⚠️  No tests generated");
    1531
    0
            return Ok(());
    1532
    0
        }
    1533
    1534
    0
        write_test_output(&converter, &all_tests, output_path)?;
    1535
    0
        generate_summary_report(&all_tests, processed_files);
    1536
    1537
    0
        Ok(())
    1538
    0
    }