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
198 // ========================================
199 // Hybrid Commands - High-Frequency Aliases
200 // ========================================
201 // These are convenience aliases for the most common operations.
202 // They provide a verb-centric, streamlined UX for frequent actions.
203 // See: docs/architecture-03-cli-hybrid-command.md
204 /// Add a new task (alias for 'task add')
205 #[command(alias = "a")]
206 Add {
207 /// Task name
208 name: String,
209
210 /// Detailed specification (markdown)
211 #[arg(long)]
212 spec: Option<String>,
213
214 /// Parent task ID
215 #[arg(long)]
216 parent: Option<i64>,
217
218 /// Priority (critical, high, medium, low)
219 #[arg(long)]
220 priority: Option<String>,
221 },
222
223 /// Start a task and set focus (alias for 'task start')
224 #[command(alias = "s")]
225 Start {
226 /// Task ID
227 id: i64,
228
229 /// Include events summary
230 #[arg(long, default_value = "true")]
231 with_events: bool,
232 },
233
234 /// Complete the current focused task (alias for 'task done')
235 #[command(alias = "d")]
236 Done,
237
238 /// Record an event for current task (alias for 'event add')
239 Log {
240 /// Event type (decision, blocker, milestone, note)
241 #[arg(value_parser = ["decision", "blocker", "milestone", "note"])]
242 event_type: String,
243
244 /// Event data/description
245 data: String,
246
247 /// Task ID (optional, uses current task if not specified)
248 #[arg(long)]
249 task_id: Option<i64>,
250 },
251
252 /// Get the next recommended task (alias for 'task pick-next')
253 #[command(alias = "n")]
254 Next {
255 /// Output format (text or json)
256 #[arg(long, default_value = "text")]
257 format: String,
258 },
259
260 /// List tasks with filters (alias for 'task list')
261 ///
262 /// Examples:
263 /// ie ls # List all tasks
264 /// ie ls todo # List todo tasks
265 /// ie ls doing # List doing tasks
266 /// ie ls done # List done tasks
267 #[command(alias = "ls")]
268 List {
269 /// Filter by status (todo, doing, done)
270 status: Option<String>,
271
272 /// Filter by parent ID (use "null" for no parent)
273 #[arg(long)]
274 parent: Option<String>,
275 },
276
277 /// Get task context (alias for 'task context')
278 #[command(alias = "ctx")]
279 Context {
280 /// Task ID (optional, uses current task if omitted)
281 task_id: Option<i64>,
282 },
283
284 /// Get task details (alias for 'task get')
285 Get {
286 /// Task ID
287 id: i64,
288
289 /// Include events summary
290 #[arg(long)]
291 with_events: bool,
292 },
293
294 /// Query and view application logs
295 ///
296 /// Examples:
297 /// ie logs # Show recent logs from all modes
298 /// ie logs --mode dashboard # Show dashboard logs only
299 /// ie logs --level error --since 1h # Show errors from last hour
300 /// ie logs --follow # Real-time log monitoring
301 Logs {
302 /// Filter by application mode (dashboard, mcp-server, cli)
303 #[arg(long)]
304 mode: Option<String>,
305
306 /// Filter by log level (error, warn, info, debug, trace)
307 #[arg(long)]
308 level: Option<String>,
309
310 /// Show logs since duration (e.g., "1h", "24h", "7d")
311 #[arg(long)]
312 since: Option<String>,
313
314 /// Show logs until timestamp (ISO8601 format)
315 #[arg(long)]
316 until: Option<String>,
317
318 /// Maximum number of log entries to show
319 #[arg(long)]
320 limit: Option<usize>,
321
322 /// Follow logs in real-time (like tail -f)
323 #[arg(short, long)]
324 follow: bool,
325
326 /// Export format (text or json)
327 #[arg(long, default_value = "text")]
328 export: String,
329 },
330}
331
332#[derive(Subcommand, Clone)]
333pub enum CurrentAction {
334 /// Set the current task (low-level atomic command, prefer 'ie task start')
335 #[command(hide = true)]
336 Set {
337 /// Task ID to set as current
338 task_id: i64,
339 },
340
341 /// Clear the current task (low-level atomic command, prefer 'ie task done')
342 #[command(hide = true)]
343 Clear,
344}
345
346#[derive(Subcommand, Clone)]
347pub enum TaskCommands {
348 /// Add a new task
349 Add {
350 /// Task name
351 #[arg(long)]
352 name: String,
353
354 /// Parent task ID
355 #[arg(long)]
356 parent: Option<i64>,
357
358 /// Read spec from stdin
359 #[arg(long)]
360 spec_stdin: bool,
361 },
362
363 /// Get a task by ID
364 Get {
365 /// Task ID
366 id: i64,
367
368 /// Include events summary
369 #[arg(long)]
370 with_events: bool,
371 },
372
373 /// Update a task
374 Update {
375 /// Task ID
376 id: i64,
377
378 /// New task name
379 #[arg(long)]
380 name: Option<String>,
381
382 /// New parent task ID
383 #[arg(long)]
384 parent: Option<i64>,
385
386 /// New status
387 #[arg(long)]
388 status: Option<String>,
389
390 /// Task complexity (1-10)
391 #[arg(long)]
392 complexity: Option<i32>,
393
394 /// Task priority (critical, high, medium, low)
395 #[arg(long)]
396 priority: Option<String>,
397
398 /// Read spec from stdin
399 #[arg(long)]
400 spec_stdin: bool,
401 },
402
403 /// Delete a task
404 Del {
405 /// Task ID
406 id: i64,
407 },
408
409 /// List tasks with filters
410 ///
411 /// Examples:
412 /// ie task list # List all tasks
413 /// ie task list todo # List todo tasks
414 /// ie task list doing # List doing tasks
415 /// ie task list done # List done tasks
416 List {
417 /// Filter by status (todo, doing, done)
418 status: Option<String>,
419
420 /// Filter by parent ID (use "null" for no parent)
421 #[arg(long)]
422 parent: Option<String>,
423 },
424
425 /// Start a task (atomic: update status + set current)
426 Start {
427 /// Task ID
428 id: i64,
429
430 /// Include events summary
431 #[arg(long)]
432 with_events: bool,
433 },
434
435 /// Complete the current focused task (atomic: check children + update status + clear current)
436 /// This command only operates on the current_task_id. It will:
437 /// - Check all subtasks are done
438 /// - Update the task status to done
439 /// - Clear the current_task_id
440 ///
441 /// Prerequisites: A task must be set as current (via `current --set <ID>`)
442 Done,
443
444 /// Intelligently recommend the next task to work on
445 ///
446 /// This command uses a context-aware priority model to recommend a single task:
447 /// 1. First priority: 'doing' subtasks of current focused task
448 /// 2. Second priority: 'todo' subtasks of current focused task
449 /// 3. Third priority: Top-level 'doing' tasks
450 /// 4. Fourth priority: Top-level 'todo' tasks
451 ///
452 /// Within the same priority level, 'doing' tasks are prioritized over 'todo' tasks.
453 /// The command is non-interactive and does not modify task status.
454 PickNext {
455 /// Output format (text or json)
456 #[arg(long, default_value = "text")]
457 format: String,
458 },
459
460 /// Create a subtask under current task and switch to it
461 SpawnSubtask {
462 /// Subtask name
463 #[arg(long)]
464 name: String,
465
466 /// Read spec from stdin
467 #[arg(long)]
468 spec_stdin: bool,
469 },
470
471 /// Switch to a specific task (atomic: update to doing + set current)
472 /// Add a dependency between tasks
473 ///
474 /// Creates a dependency where BLOCKED_TASK depends on BLOCKING_TASK.
475 /// The BLOCKING_TASK must be completed before BLOCKED_TASK can be started.
476 ///
477 /// Example: `task depends-on 42 41` means Task 42 depends on Task 41
478 /// (Task 41 must be done before Task 42 can start)
479 #[command(name = "depends-on")]
480 DependsOn {
481 /// Task ID that has the dependency (blocked task)
482 blocked_task_id: i64,
483
484 /// Task ID that must be completed first (blocking task)
485 blocking_task_id: i64,
486 },
487
488 /// Get task context (ancestors, siblings, children)
489 ///
490 /// Shows the full family tree of a task to understand its strategic context.
491 /// If no task ID is provided, uses the current focused task.
492 Context {
493 /// Task ID (optional, uses current task if omitted)
494 task_id: Option<i64>,
495 },
496}
497
498#[derive(Subcommand, Clone)]
499pub enum EventCommands {
500 /// Add a new event
501 Add {
502 /// Task ID (optional, uses current task if not specified)
503 #[arg(long)]
504 task_id: Option<i64>,
505
506 /// Log type
507 #[arg(long = "type")]
508 log_type: String,
509
510 /// Read discussion data from stdin
511 #[arg(long)]
512 data_stdin: bool,
513 },
514
515 /// List events for a task (or globally if task_id not specified)
516 List {
517 /// Task ID (optional, lists all events if not specified)
518 #[arg(long)]
519 task_id: Option<i64>,
520
521 /// Maximum number of events to return (default: 50)
522 #[arg(long)]
523 limit: Option<i64>,
524
525 /// Filter by log type (e.g., "decision", "blocker", "milestone", "note")
526 #[arg(long = "type")]
527 log_type: Option<String>,
528
529 /// Filter events created within duration (e.g., "7d", "24h", "30m")
530 #[arg(long)]
531 since: Option<String>,
532 },
533}
534
535#[derive(Subcommand, Clone)]
536pub enum DashboardCommands {
537 /// Start the Dashboard web server for current project
538 Start {
539 /// Custom port (default: 11391)
540 #[arg(long)]
541 port: Option<u16>,
542
543 /// Run in foreground (default: daemon mode)
544 #[arg(long)]
545 foreground: bool,
546
547 /// Automatically open browser (default: false, use --browser to enable)
548 #[arg(long)]
549 browser: bool,
550 },
551
552 /// Stop the Dashboard server
553 Stop {
554 /// Stop all Dashboard instances
555 #[arg(long)]
556 all: bool,
557 },
558
559 /// Show Dashboard status
560 Status {
561 /// Show status for all projects
562 #[arg(long)]
563 all: bool,
564 },
565
566 /// List all registered Dashboard instances
567 List,
568
569 /// Open Dashboard in browser
570 Open,
571}