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