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}