use anyhow::Result;
use clap::Args;
use crate::commands::tutorial as tutorial_cmd;
fn is_tty() -> bool {
atty::is(atty::Stream::Stdin) && atty::is(atty::Stream::Stdout)
}
fn resolve_interactive_mode(explicit_non_interactive: bool) -> bool {
if explicit_non_interactive {
false
} else {
is_tty()
}
}
pub fn handle_tutorial(args: TutorialArgs) -> Result<()> {
let interactive = resolve_interactive_mode(args.non_interactive);
tutorial_cmd::run_tutorial(tutorial_cmd::TutorialOptions {
interactive,
keep_sandbox: args.keep_sandbox,
})
}
#[derive(Args)]
#[command(
about = "Run interactive tutorial for Ralph onboarding",
after_long_help = "Examples:\n ralph tutorial\n ralph tutorial --keep-sandbox\n ralph tutorial --non-interactive\n\nThe tutorial creates a temporary sandbox project and walks you through:\n 1. Initializing Ralph in a project\n 2. Creating your first task\n 3. Running a task (dry-run preview)\n 4. Reviewing the results\n\nUse --keep-sandbox to preserve the sandbox directory after the tutorial.\nUse --non-interactive for automated testing or CI environments."
)]
pub struct TutorialArgs {
#[arg(long)]
pub keep_sandbox: bool,
#[arg(long)]
pub non_interactive: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolve_interactive_mode_explicit_non_interactive() {
let result = resolve_interactive_mode(true);
assert!(!result);
}
#[test]
fn resolve_interactive_mode_auto_detect() {
let result = resolve_interactive_mode(false);
assert_eq!(result, is_tty());
}
}