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}