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