intent_engine/
cli.rs

1use clap::{Parser, Subcommand};
2
3const LONG_ABOUT: &str = r#"
4Intent-Engine - AI Long-Term Task Memory System
5
6What does it offer beyond Claude Code's built-in TodoWrite?
7  ✅ Cross-session persistence (never lost)
8  ✅ Hierarchical task trees (parent-child, dependencies)
9  ✅ Decision logs (why you made choices)
10  ✅ Web Dashboard (visual management)
11
12When to use ie instead of TodoWrite?
13  • Would be a shame to lose it → use ie
14  • Use once and discard → use TodoWrite
15
16AI Workflow:
17  ie status   ← Run at session start to restore context
18  ie plan     ← Declarative task management (create/update/complete)
19  ie log      ← Record decisions, blockers, milestones
20  ie search   ← Search tasks and event history
21"#;
22
23#[derive(Parser, Clone)]
24#[command(name = "intent-engine")]
25#[command(
26    about = "AI Long-Term Task Memory - Cross-session persistence, hierarchical tasks, decision logs"
27)]
28#[command(long_about = LONG_ABOUT)]
29#[command(version)]
30pub struct Cli {
31    /// Enable verbose output (-v)
32    #[arg(short, long, action = clap::ArgAction::Count)]
33    pub verbose: u8,
34
35    /// Suppress non-error output (-q)
36    #[arg(short, long)]
37    pub quiet: bool,
38
39    /// Output logs in JSON format
40    #[arg(long)]
41    pub json: bool,
42
43    #[command(subcommand)]
44    pub command: Commands,
45}
46
47#[derive(Subcommand, Clone)]
48pub enum Commands {
49    /// Create or update task structures declaratively
50    #[command(long_about = include_str!("../docs/help/plan.md"))]
51    Plan {
52        /// Output format (text or json)
53        #[arg(long, default_value = "text")]
54        format: String,
55    },
56
57    /// Record events (decisions, blockers, milestones, notes)
58    ///
59    /// Quick event logging for the current focused task or a specific task.
60    ///
61    /// Examples:
62    ///   ie log decision "Chose JWT authentication"
63    ///   ie log blocker "API rate limit hit" --task 42
64    ///   ie log milestone "MVP complete"
65    ///   ie log note "Consider caching optimization"
66    Log {
67        /// Event type: decision, blocker, milestone, note
68        #[arg(value_enum)]
69        event_type: LogEventType,
70
71        /// Event message (markdown supported)
72        message: String,
73
74        /// Target task ID (optional, uses current focused task if not specified)
75        #[arg(long)]
76        task: Option<i64>,
77
78        /// Output format (text or json)
79        #[arg(long, default_value = "text")]
80        format: String,
81    },
82
83    /// Unified search across tasks and events
84    ///
85    /// Smart keyword detection:
86    ///   - Query with ONLY status keywords (todo, doing, done) → filters by status
87    ///   - Query with other words → uses FTS5 full-text search
88    ///
89    /// Status filter examples (returns tasks with matching status):
90    ///   ie search "todo doing"     # All unfinished tasks (AI session start)
91    ///   ie search "todo"           # Only todo tasks
92    ///   ie search "done"           # Only completed tasks
93    ///
94    /// FTS5 search examples (full-text search):
95    ///   ie search "JWT authentication"
96    ///   ie search "API AND client"
97    ///   ie search "blocker" --events --no-tasks
98    Search {
99        /// Search query: status keywords (todo/doing/done) or FTS5 syntax
100        query: String,
101
102        /// Search in tasks (default: true)
103        #[arg(long, default_value = "true")]
104        tasks: bool,
105
106        /// Search in events (default: true)
107        #[arg(long, default_value = "true")]
108        events: bool,
109
110        /// Maximum number of results (default: 20)
111        #[arg(long)]
112        limit: Option<i64>,
113
114        /// Result offset for pagination (default: 0)
115        #[arg(long)]
116        offset: Option<i64>,
117
118        /// Output format (text or json)
119        #[arg(long, default_value = "text")]
120        format: String,
121    },
122
123    /// Initialize a new Intent-Engine project
124    ///
125    /// Creates a .intent-engine directory with database in the current working directory.
126    ///
127    /// Examples:
128    ///   ie init                    # Initialize in current directory
129    ///   ie init --at /my/project   # Initialize at specific directory
130    Init {
131        /// Custom directory to initialize (default: current directory)
132        #[arg(long)]
133        at: Option<String>,
134
135        /// Re-initialize even if .intent-engine already exists
136        #[arg(long)]
137        force: bool,
138    },
139
140    /// Dashboard management commands
141    #[command(subcommand)]
142    Dashboard(DashboardCommands),
143
144    /// Check system health and dependencies
145    Doctor,
146
147    /// Show current task context (focus spotlight)
148    ///
149    /// Displays the focused task with its complete context:
150    /// - Current task details (full info)
151    /// - Ancestors chain (full info)
152    /// - Siblings (id + name + status)
153    /// - Descendants (id + name + status + parent_id)
154    ///
155    /// Examples:
156    ///   ie status              # Show current focused task context
157    ///   ie status 42           # Show task 42's context (without changing focus)
158    ///   ie status -e           # Include event history
159    Status {
160        /// Task ID to inspect (optional, defaults to current focused task)
161        task_id: Option<i64>,
162
163        /// Include event history
164        #[arg(short = 'e', long)]
165        with_events: bool,
166
167        /// Output format (text or json)
168        #[arg(long, default_value = "text")]
169        format: String,
170    },
171}
172
173#[derive(clap::ValueEnum, Clone, Debug)]
174pub enum LogEventType {
175    Decision,
176    Blocker,
177    Milestone,
178    Note,
179}
180
181impl LogEventType {
182    pub fn as_str(&self) -> &str {
183        match self {
184            LogEventType::Decision => "decision",
185            LogEventType::Blocker => "blocker",
186            LogEventType::Milestone => "milestone",
187            LogEventType::Note => "note",
188        }
189    }
190}
191
192#[derive(Subcommand, Clone)]
193pub enum DashboardCommands {
194    /// Start the Dashboard server
195    Start {
196        /// Port to bind (default: 11391)
197        #[arg(long)]
198        port: Option<u16>,
199
200        /// Auto-open browser
201        #[arg(long)]
202        browser: bool,
203
204        /// Start in daemon mode (background)
205        #[arg(long)]
206        daemon: bool,
207    },
208
209    /// Stop the Dashboard server
210    Stop {
211        /// Stop all running dashboards
212        #[arg(long)]
213        all: bool,
214    },
215
216    /// Show Dashboard status
217    Status {
218        /// Show all instances
219        #[arg(long)]
220        all: bool,
221    },
222
223    /// List registered projects
224    List,
225
226    /// Open Dashboard in browser
227    Open,
228}