intent_engine/cli.rs
1use clap::{Parser, Subcommand};
2
3#[derive(Parser)]
4#[command(name = "intent-engine")]
5#[command(about = "A command-line database service for tracking strategic intent", long_about = None)]
6#[command(version)]
7pub struct Cli {
8 #[command(subcommand)]
9 pub command: Commands,
10}
11
12#[derive(Subcommand)]
13pub enum Commands {
14 /// Task management commands
15 #[command(subcommand)]
16 Task(TaskCommands),
17
18 /// Workspace state management
19 Current {
20 /// Set the current task ID (for backward compatibility)
21 #[arg(long)]
22 set: Option<i64>,
23
24 #[command(subcommand)]
25 command: Option<CurrentAction>,
26 },
27
28 /// Generate analysis and reports
29 Report {
30 /// Time duration (e.g., "7d", "2h", "30m")
31 #[arg(long)]
32 since: Option<String>,
33
34 /// Filter by status
35 #[arg(long)]
36 status: Option<String>,
37
38 /// Filter by name pattern (FTS5)
39 #[arg(long)]
40 filter_name: Option<String>,
41
42 /// Filter by spec pattern (FTS5)
43 #[arg(long)]
44 filter_spec: Option<String>,
45
46 /// Output format
47 #[arg(long, default_value = "json")]
48 format: String,
49
50 /// Return summary only
51 #[arg(long)]
52 summary_only: bool,
53 },
54
55 /// Event logging commands
56 #[command(subcommand)]
57 Event(EventCommands),
58
59 /// Unified search across tasks and events
60 Search {
61 /// Search query (supports FTS5 syntax like "JWT AND authentication")
62 query: String,
63
64 /// Search in tasks (default: true)
65 #[arg(long, default_value = "true")]
66 tasks: bool,
67
68 /// Search in events (default: true)
69 #[arg(long, default_value = "true")]
70 events: bool,
71
72 /// Maximum number of results (default: 20)
73 #[arg(long)]
74 limit: Option<i64>,
75 },
76
77 /// Check system health and dependencies
78 Doctor,
79
80 /// Start MCP server for AI assistants (JSON-RPC stdio)
81 #[command(name = "mcp-server")]
82 McpServer,
83
84 /// Restore session context for AI agents (Focus Restoration - Phase 1)
85 ///
86 /// This command returns all context needed to restore work continuity:
87 /// - Current focused task
88 /// - Parent task and siblings progress
89 /// - Child tasks status
90 /// - Recent events (decisions, blockers, notes)
91 /// - Suggested next commands
92 ///
93 /// Designed for SessionStart hooks to inject context at the beginning of new sessions.
94 #[command(name = "session-restore")]
95 SessionRestore {
96 /// Number of recent events to include (default: 3)
97 #[arg(long, default_value = "3")]
98 include_events: usize,
99
100 /// Workspace path (default: current directory)
101 #[arg(long)]
102 workspace: Option<String>,
103 },
104
105 /// Dashboard management commands
106 #[command(subcommand)]
107 Dashboard(DashboardCommands),
108
109 /// Unified setup command for AI tool integrations
110 ///
111 /// This command provides a unified interface for setting up intent-engine integration
112 /// with various AI assistant tools. It handles both hook installation and MCP server
113 /// configuration in one step.
114 ///
115 /// Features:
116 /// - User-level or project-level installation
117 /// - Atomic setup with rollback on failure
118 /// - Built-in connectivity testing
119 /// - Diagnosis mode for troubleshooting
120 Setup {
121 /// Target tool to configure (claude-code, gemini-cli, codex)
122 #[arg(long)]
123 target: Option<String>,
124
125 /// Installation scope: user (default, recommended), project, or both
126 #[arg(long, default_value = "user")]
127 scope: String,
128
129 /// Show what would be done without actually doing it
130 #[arg(long)]
131 dry_run: bool,
132
133 /// Overwrite existing configuration
134 #[arg(long)]
135 force: bool,
136
137 /// Run diagnosis on existing setup instead of installing
138 #[arg(long)]
139 diagnose: bool,
140
141 /// Custom config file path (advanced)
142 #[arg(long)]
143 config_path: Option<String>,
144
145 /// Project directory for INTENT_ENGINE_PROJECT_DIR env var
146 #[arg(long)]
147 project_dir: Option<String>,
148 },
149
150 // ========================================
151 // Hybrid Commands - High-Frequency Aliases
152 // ========================================
153 // These are convenience aliases for the most common operations.
154 // They provide a verb-centric, streamlined UX for frequent actions.
155 // See: docs/architecture-03-cli-hybrid-command.md
156 /// Add a new task (alias for 'task add')
157 #[command(alias = "a")]
158 Add {
159 /// Task name
160 name: String,
161
162 /// Detailed specification (markdown)
163 #[arg(long)]
164 spec: Option<String>,
165
166 /// Parent task ID
167 #[arg(long)]
168 parent: Option<i64>,
169
170 /// Priority (critical, high, medium, low)
171 #[arg(long)]
172 priority: Option<String>,
173 },
174
175 /// Start a task and set focus (alias for 'task start')
176 #[command(alias = "s")]
177 Start {
178 /// Task ID
179 id: i64,
180
181 /// Include events summary
182 #[arg(long, default_value = "true")]
183 with_events: bool,
184 },
185
186 /// Complete the current focused task (alias for 'task done')
187 #[command(alias = "d")]
188 Done,
189
190 /// Switch to a different task (alias for 'task switch')
191 #[command(alias = "sw")]
192 Switch {
193 /// Task ID
194 id: i64,
195
196 /// Include events summary
197 #[arg(long)]
198 with_events: bool,
199 },
200
201 /// Record an event for current task (alias for 'event add')
202 Log {
203 /// Event type (decision, blocker, milestone, note)
204 #[arg(value_parser = ["decision", "blocker", "milestone", "note"])]
205 event_type: String,
206
207 /// Event data/description
208 data: String,
209
210 /// Task ID (optional, uses current task if not specified)
211 #[arg(long)]
212 task_id: Option<i64>,
213 },
214
215 /// Get the next recommended task (alias for 'task pick-next')
216 #[command(alias = "n")]
217 Next {
218 /// Output format (text or json)
219 #[arg(long, default_value = "text")]
220 format: String,
221 },
222
223 /// List tasks with filters (alias for 'task list')
224 ///
225 /// Examples:
226 /// ie ls # List all tasks
227 /// ie ls todo # List todo tasks
228 /// ie ls doing # List doing tasks
229 /// ie ls done # List done tasks
230 #[command(alias = "ls")]
231 List {
232 /// Filter by status (todo, doing, done)
233 status: Option<String>,
234
235 /// Filter by parent ID (use "null" for no parent)
236 #[arg(long)]
237 parent: Option<String>,
238 },
239
240 /// Get task context (alias for 'task context')
241 #[command(alias = "ctx")]
242 Context {
243 /// Task ID (optional, uses current task if omitted)
244 task_id: Option<i64>,
245 },
246
247 /// Get task details (alias for 'task get')
248 Get {
249 /// Task ID
250 id: i64,
251
252 /// Include events summary
253 #[arg(long)]
254 with_events: bool,
255 },
256}
257
258#[derive(Subcommand)]
259pub enum CurrentAction {
260 /// Set the current task (low-level atomic command, prefer 'ie task start')
261 #[command(hide = true)]
262 Set {
263 /// Task ID to set as current
264 task_id: i64,
265 },
266
267 /// Clear the current task (low-level atomic command, prefer 'ie task done')
268 #[command(hide = true)]
269 Clear,
270}
271
272#[derive(Subcommand)]
273pub enum TaskCommands {
274 /// Add a new task
275 Add {
276 /// Task name
277 #[arg(long)]
278 name: String,
279
280 /// Parent task ID
281 #[arg(long)]
282 parent: Option<i64>,
283
284 /// Read spec from stdin
285 #[arg(long)]
286 spec_stdin: bool,
287 },
288
289 /// Get a task by ID
290 Get {
291 /// Task ID
292 id: i64,
293
294 /// Include events summary
295 #[arg(long)]
296 with_events: bool,
297 },
298
299 /// Update a task
300 Update {
301 /// Task ID
302 id: i64,
303
304 /// New task name
305 #[arg(long)]
306 name: Option<String>,
307
308 /// New parent task ID
309 #[arg(long)]
310 parent: Option<i64>,
311
312 /// New status
313 #[arg(long)]
314 status: Option<String>,
315
316 /// Task complexity (1-10)
317 #[arg(long)]
318 complexity: Option<i32>,
319
320 /// Task priority (critical, high, medium, low)
321 #[arg(long)]
322 priority: Option<String>,
323
324 /// Read spec from stdin
325 #[arg(long)]
326 spec_stdin: bool,
327 },
328
329 /// Delete a task
330 Del {
331 /// Task ID
332 id: i64,
333 },
334
335 /// List tasks with filters
336 ///
337 /// Examples:
338 /// ie task list # List all tasks
339 /// ie task list todo # List todo tasks
340 /// ie task list doing # List doing tasks
341 /// ie task list done # List done tasks
342 List {
343 /// Filter by status (todo, doing, done)
344 status: Option<String>,
345
346 /// Filter by parent ID (use "null" for no parent)
347 #[arg(long)]
348 parent: Option<String>,
349 },
350
351 /// Start a task (atomic: update status + set current)
352 Start {
353 /// Task ID
354 id: i64,
355
356 /// Include events summary
357 #[arg(long)]
358 with_events: bool,
359 },
360
361 /// Complete the current focused task (atomic: check children + update status + clear current)
362 /// This command only operates on the current_task_id. It will:
363 /// - Check all subtasks are done
364 /// - Update the task status to done
365 /// - Clear the current_task_id
366 ///
367 /// Prerequisites: A task must be set as current (via `current --set <ID>`)
368 Done,
369
370 /// Intelligently recommend the next task to work on
371 ///
372 /// This command uses a context-aware priority model to recommend a single task:
373 /// 1. First priority: Subtasks of the current focused task (depth-first)
374 /// 2. Second priority: Top-level tasks (breadth-first)
375 ///
376 /// The command is non-interactive and does not modify task status.
377 PickNext {
378 /// Output format (text or json)
379 #[arg(long, default_value = "text")]
380 format: String,
381 },
382
383 /// Create a subtask under current task and switch to it
384 SpawnSubtask {
385 /// Subtask name
386 #[arg(long)]
387 name: String,
388
389 /// Read spec from stdin
390 #[arg(long)]
391 spec_stdin: bool,
392 },
393
394 /// Switch to a specific task (atomic: update to doing + set current)
395 Switch {
396 /// Task ID
397 id: i64,
398 },
399
400 /// Add a dependency between tasks
401 ///
402 /// Creates a dependency where BLOCKED_TASK depends on BLOCKING_TASK.
403 /// The BLOCKING_TASK must be completed before BLOCKED_TASK can be started.
404 ///
405 /// Example: `task depends-on 42 41` means Task 42 depends on Task 41
406 /// (Task 41 must be done before Task 42 can start)
407 #[command(name = "depends-on")]
408 DependsOn {
409 /// Task ID that has the dependency (blocked task)
410 blocked_task_id: i64,
411
412 /// Task ID that must be completed first (blocking task)
413 blocking_task_id: i64,
414 },
415
416 /// Get task context (ancestors, siblings, children)
417 ///
418 /// Shows the full family tree of a task to understand its strategic context.
419 /// If no task ID is provided, uses the current focused task.
420 Context {
421 /// Task ID (optional, uses current task if omitted)
422 task_id: Option<i64>,
423 },
424}
425
426#[derive(Subcommand)]
427pub enum EventCommands {
428 /// Add a new event
429 Add {
430 /// Task ID (optional, uses current task if not specified)
431 #[arg(long)]
432 task_id: Option<i64>,
433
434 /// Log type
435 #[arg(long = "type")]
436 log_type: String,
437
438 /// Read discussion data from stdin
439 #[arg(long)]
440 data_stdin: bool,
441 },
442
443 /// List events for a task (or globally if task_id not specified)
444 List {
445 /// Task ID (optional, lists all events if not specified)
446 #[arg(long)]
447 task_id: Option<i64>,
448
449 /// Maximum number of events to return (default: 50)
450 #[arg(long)]
451 limit: Option<i64>,
452
453 /// Filter by log type (e.g., "decision", "blocker", "milestone", "note")
454 #[arg(long = "type")]
455 log_type: Option<String>,
456
457 /// Filter events created within duration (e.g., "7d", "24h", "30m")
458 #[arg(long)]
459 since: Option<String>,
460 },
461}
462
463#[derive(Subcommand)]
464pub enum DashboardCommands {
465 /// Start the Dashboard web server for current project
466 Start {
467 /// Custom port (default: auto-allocated 3030-3099)
468 #[arg(long)]
469 port: Option<u16>,
470
471 /// Run in foreground (default: daemon mode)
472 #[arg(long)]
473 foreground: bool,
474 },
475
476 /// Stop the Dashboard server
477 Stop {
478 /// Stop all Dashboard instances
479 #[arg(long)]
480 all: bool,
481 },
482
483 /// Show Dashboard status
484 Status {
485 /// Show status for all projects
486 #[arg(long)]
487 all: bool,
488 },
489
490 /// List all registered Dashboard instances
491 List,
492
493 /// Open Dashboard in browser
494 Open,
495}