Skip to main content

sparrow/onboarding/
mod.rs

1use crate::config::Config;
2
3pub mod claude_compat;
4pub mod enterprise;
5pub mod migration;
6pub mod setup_agent;
7pub mod wizard;
8pub mod zero_question;
9
10// ─── User mode ─────────────────────────────────────────────────────────────────
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
13pub enum UserMode {
14    Beginner,
15    Expert,
16}
17
18impl Default for UserMode {
19    fn default() -> Self {
20        UserMode::Beginner
21    }
22}
23
24// ─── Onboarding engine ─────────────────────────────────────────────────────────
25
26pub struct Onboarding {
27    pub mode: UserMode,
28    pub lessons: Vec<Lesson>,
29}
30
31#[derive(Debug, Clone)]
32pub struct Lesson {
33    pub id: String,
34    pub title: String,
35    pub description: String,
36    pub command: String,
37    pub expected_output: String,
38}
39
40impl Default for Onboarding {
41    fn default() -> Self {
42        Self {
43            mode: UserMode::Beginner,
44            lessons: default_lessons(),
45        }
46    }
47}
48
49fn default_lessons() -> Vec<Lesson> {
50    vec![
51        Lesson {
52            id: "run".into(),
53            title: "Your First Run".into(),
54            description: "Execute a simple task and see Sparrow in action.".into(),
55            command: r#"run "Create a file called hello.txt with 'Hello Sparrow' inside""#.into(),
56            expected_output: "file created".into(),
57        },
58        Lesson {
59            id: "swarm".into(),
60            title: "The Swarm".into(),
61            description: "See Planner → Coder → Verifier work together.".into(),
62            command: r#"swarm "Add a comment to hello.txt explaining what it contains""#.into(),
63            expected_output: "Planner → Coder → Verifier".into(),
64        },
65        Lesson {
66            id: "autonomy".into(),
67            title: "Autonomy Dial".into(),
68            description: "Understand how Sparrow keeps you safe with graduated trust.".into(),
69            command: r#"run "Read hello.txt" --autonomy supervised"#.into(),
70            expected_output: "autonomy gate".into(),
71        },
72        Lesson {
73            id: "skills".into(),
74            title: "Self-Improving Skills".into(),
75            description: "Sparrow learns from experience and gets better over time.".into(),
76            command: "skills list".into(),
77            expected_output: "skill library".into(),
78        },
79        Lesson {
80            id: "gateway".into(),
81            title: "Everywhere You Are".into(),
82            description: "Continue your session from Telegram, Discord, or Slack.".into(),
83            command: "gateway status".into(),
84            expected_output: "messaging surfaces".into(),
85        },
86    ]
87}
88
89impl Onboarding {
90    /// Run interactive tutorial
91    pub fn run_interactive(&self) -> anyhow::Result<()> {
92        use std::io::{self, BufRead};
93
94        println!("═══ SPARROW LEARN ═══");
95        println!("5 interactive lessons to master Sparrow.\n");
96
97        for (i, lesson) in self.lessons.iter().enumerate() {
98            println!(
99                "── Lesson {}/{} : {} ──",
100                i + 1,
101                self.lessons.len(),
102                lesson.title
103            );
104            println!("{}", lesson.description);
105            println!("\n  sparrow {}", lesson.command);
106            println!("\nPress Enter to continue...");
107            io::stdin().lock().lines().next();
108            println!();
109        }
110
111        println!("═══ All lessons complete! ═══");
112        println!("Try: sparrow run 'your own task'");
113        println!("Help: sparrow --help\n");
114        Ok(())
115    }
116
117    /// Detect user mode from config or interactive choice
118    pub fn detect_mode(config: &Config) -> UserMode {
119        if config.defaults.autonomy == crate::event::AutonomyLevel::Supervised {
120            UserMode::Beginner
121        } else {
122            UserMode::Expert
123        }
124    }
125
126    /// Generate friendly error messages
127    pub fn friendly_error(error_type: &str, context: &str) -> String {
128        match error_type {
129            "no_provider" => format!(
130                "No API key configured.\n→ Run: sparrow auth add <provider>\n→ Or: sparrow setup\n→ Or set env: {}_API_KEY",
131                context.to_uppercase()
132            ),
133            "no_model" => format!(
134                "Model '{}' not available.\n→ List models: sparrow model --list\n→ Add one: edit ~/.config/sparrow/config.toml",
135                context
136            ),
137            "budget" => format!(
138                "Budget limit reached (${}).\n→ Increase: sparrow run --budget <amount>\n→ Or edit: config.toml [budget]",
139                context
140            ),
141            "sandbox" => format!(
142                "Operation blocked by sandbox: {}\n→ Check: sparrow doctor\n→ Change: config.toml [defaults] sandbox",
143                context
144            ),
145            "permission" => format!(
146                "Permission denied: {}\n→ In Supervised mode, mutating actions require approval.\n→ Use: --autonomy trusted\n→ Or: sparrow config --edit",
147                context
148            ),
149            _ => format!(
150                "Error: {}\n→ Run diagnostics: sparrow doctor\n→ Get help: sparrow --help\n→ Docs: https://github.com/ucav/Sparrow",
151                context
152            ),
153        }
154    }
155
156    /// Examples gallery
157    pub fn examples_gallery() -> Vec<(&'static str, &'static str)> {
158        vec![
159            ("run \"fix the failing auth test\"", "Fix a bug"),
160            ("run \"add a /health endpoint to the API\"", "Add a feature"),
161            ("run \"explain this codebase\" --local", "Analyze offline"),
162            ("swarm \"refactor the rate limiter\"", "Swarm review"),
163            (
164                "schedule \"run tests\" --cron \"0 */6 * * *\"",
165                "Schedule checks",
166            ),
167            ("skills list", "See learned skills"),
168            ("checkpoint list", "View safety net"),
169            ("replay <id>", "Replay any run"),
170        ]
171    }
172}