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}