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