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}