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