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        /// Filter by start time (e.g., "7d", "1w", "2025-01-01")
129        #[arg(long)]
130        since: Option<String>,
131
132        /// Filter by end time (e.g., "1d", "2025-12-31")
133        #[arg(long)]
134        until: Option<String>,
135
136        /// Output format (text or json)
137        #[arg(long, default_value = "text")]
138        format: String,
139    },
140
141    /// Initialize a new Intent-Engine project
142    ///
143    /// Creates a .intent-engine directory with database in the current working directory.
144    ///
145    /// Examples:
146    ///   ie init                    # Initialize in current directory
147    ///   ie init --at /my/project   # Initialize at specific directory
148    Init {
149        /// Custom directory to initialize (default: current directory)
150        #[arg(long)]
151        at: Option<String>,
152
153        /// Re-initialize even if .intent-engine already exists
154        #[arg(long)]
155        force: bool,
156    },
157
158    /// Dashboard management commands
159    #[command(subcommand)]
160    Dashboard(DashboardCommands),
161
162    /// Check system health and dependencies
163    Doctor,
164
165    /// Show current task context (focus spotlight)
166    ///
167    /// Displays the focused task with its complete context:
168    /// - Current task details (full info)
169    /// - Ancestors chain (full info)
170    /// - Siblings (id + name + status)
171    /// - Descendants (id + name + status + parent_id)
172    ///
173    /// Examples:
174    ///   ie status              # Show current focused task context
175    ///   ie status 42           # Show task 42's context (without changing focus)
176    ///   ie status -e           # Include event history
177    Status {
178        /// Task ID to inspect (optional, defaults to current focused task)
179        task_id: Option<i64>,
180
181        /// Include event history
182        #[arg(short = 'e', long)]
183        with_events: bool,
184
185        /// Output format (text or json)
186        #[arg(long, default_value = "text")]
187        format: String,
188    },
189}
190
191#[derive(clap::ValueEnum, Clone, Debug)]
192pub enum LogEventType {
193    Decision,
194    Blocker,
195    Milestone,
196    Note,
197}
198
199impl LogEventType {
200    pub fn as_str(&self) -> &str {
201        match self {
202            LogEventType::Decision => "decision",
203            LogEventType::Blocker => "blocker",
204            LogEventType::Milestone => "milestone",
205            LogEventType::Note => "note",
206        }
207    }
208}
209
210#[derive(Subcommand, Clone)]
211pub enum DashboardCommands {
212    /// Start the Dashboard server
213    Start {
214        /// Port to bind (default: 11391)
215        #[arg(long)]
216        port: Option<u16>,
217
218        /// Auto-open browser
219        #[arg(long)]
220        browser: bool,
221
222        /// Start in daemon mode (background)
223        #[arg(long)]
224        daemon: bool,
225    },
226
227    /// Stop the Dashboard server
228    Stop {
229        /// Stop all running dashboards
230        #[arg(long)]
231        all: bool,
232    },
233
234    /// Show Dashboard status
235    Status {
236        /// Show all instances
237        #[arg(long)]
238        all: bool,
239    },
240
241    /// List registered projects
242    List,
243
244    /// Open Dashboard in browser
245    Open,
246}