intent_engine/
cli.rs

1use clap::{Parser, Subcommand};
2
3#[derive(Parser)]
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    #[command(subcommand)]
9    pub command: Commands,
10}
11
12#[derive(Subcommand)]
13pub enum Commands {
14    /// Task management commands
15    #[command(subcommand)]
16    Task(TaskCommands),
17
18    /// Workspace state management
19    Current {
20        /// Set the current task ID (for backward compatibility)
21        #[arg(long)]
22        set: Option<i64>,
23
24        #[command(subcommand)]
25        command: Option<CurrentAction>,
26    },
27
28    /// Generate analysis and reports
29    Report {
30        /// Time duration (e.g., "7d", "2h", "30m")
31        #[arg(long)]
32        since: Option<String>,
33
34        /// Filter by status
35        #[arg(long)]
36        status: Option<String>,
37
38        /// Filter by name pattern (FTS5)
39        #[arg(long)]
40        filter_name: Option<String>,
41
42        /// Filter by spec pattern (FTS5)
43        #[arg(long)]
44        filter_spec: Option<String>,
45
46        /// Output format
47        #[arg(long, default_value = "json")]
48        format: String,
49
50        /// Return summary only
51        #[arg(long)]
52        summary_only: bool,
53    },
54
55    /// Event logging commands
56    #[command(subcommand)]
57    Event(EventCommands),
58
59    /// Unified search across tasks and events
60    Search {
61        /// Search query (supports FTS5 syntax like "JWT AND authentication")
62        query: String,
63
64        /// Search in tasks (default: true)
65        #[arg(long, default_value = "true")]
66        tasks: bool,
67
68        /// Search in events (default: true)
69        #[arg(long, default_value = "true")]
70        events: bool,
71
72        /// Maximum number of results (default: 20)
73        #[arg(long)]
74        limit: Option<i64>,
75    },
76
77    /// Check system health and dependencies
78    Doctor,
79
80    /// Start MCP server for AI assistants (JSON-RPC stdio)
81    #[command(name = "mcp-server")]
82    McpServer,
83
84    /// Restore session context for AI agents (Focus Restoration - Phase 1)
85    ///
86    /// This command returns all context needed to restore work continuity:
87    /// - Current focused task
88    /// - Parent task and siblings progress
89    /// - Child tasks status
90    /// - Recent events (decisions, blockers, notes)
91    /// - Suggested next commands
92    ///
93    /// Designed for SessionStart hooks to inject context at the beginning of new sessions.
94    #[command(name = "session-restore")]
95    SessionRestore {
96        /// Number of recent events to include (default: 3)
97        #[arg(long, default_value = "3")]
98        include_events: usize,
99
100        /// Workspace path (default: current directory)
101        #[arg(long)]
102        workspace: Option<String>,
103    },
104
105    /// Unified setup command for AI tool integrations
106    ///
107    /// This command provides a unified interface for setting up intent-engine integration
108    /// with various AI assistant tools. It handles both hook installation and MCP server
109    /// configuration in one step.
110    ///
111    /// Features:
112    /// - User-level or project-level installation
113    /// - Atomic setup with rollback on failure
114    /// - Built-in connectivity testing
115    /// - Diagnosis mode for troubleshooting
116    Setup {
117        /// Target tool to configure (claude-code, gemini-cli, codex)
118        #[arg(long)]
119        target: Option<String>,
120
121        /// Installation scope: user (default, recommended), project, or both
122        #[arg(long, default_value = "user")]
123        scope: String,
124
125        /// Show what would be done without actually doing it
126        #[arg(long)]
127        dry_run: bool,
128
129        /// Overwrite existing configuration
130        #[arg(long)]
131        force: bool,
132
133        /// Run diagnosis on existing setup instead of installing
134        #[arg(long)]
135        diagnose: bool,
136
137        /// Custom config file path (advanced)
138        #[arg(long)]
139        config_path: Option<String>,
140
141        /// Project directory for INTENT_ENGINE_PROJECT_DIR env var
142        #[arg(long)]
143        project_dir: Option<String>,
144    },
145}
146
147#[derive(Subcommand)]
148pub enum CurrentAction {
149    /// Set the current task (low-level atomic command, prefer 'ie task start')
150    #[command(hide = true)]
151    Set {
152        /// Task ID to set as current
153        task_id: i64,
154    },
155
156    /// Clear the current task (low-level atomic command, prefer 'ie task done')
157    #[command(hide = true)]
158    Clear,
159}
160
161#[derive(Subcommand)]
162pub enum TaskCommands {
163    /// Add a new task
164    Add {
165        /// Task name
166        #[arg(long)]
167        name: String,
168
169        /// Parent task ID
170        #[arg(long)]
171        parent: Option<i64>,
172
173        /// Read spec from stdin
174        #[arg(long)]
175        spec_stdin: bool,
176    },
177
178    /// Get a task by ID
179    Get {
180        /// Task ID
181        id: i64,
182
183        /// Include events summary
184        #[arg(long)]
185        with_events: bool,
186    },
187
188    /// Update a task
189    Update {
190        /// Task ID
191        id: i64,
192
193        /// New task name
194        #[arg(long)]
195        name: Option<String>,
196
197        /// New parent task ID
198        #[arg(long)]
199        parent: Option<i64>,
200
201        /// New status
202        #[arg(long)]
203        status: Option<String>,
204
205        /// Task complexity (1-10)
206        #[arg(long)]
207        complexity: Option<i32>,
208
209        /// Task priority (critical, high, medium, low)
210        #[arg(long)]
211        priority: Option<String>,
212
213        /// Read spec from stdin
214        #[arg(long)]
215        spec_stdin: bool,
216    },
217
218    /// Delete a task
219    Del {
220        /// Task ID
221        id: i64,
222    },
223
224    /// List tasks with filters
225    List {
226        /// Filter by status
227        #[arg(long)]
228        status: Option<String>,
229
230        /// Filter by parent ID (use "null" for no parent)
231        #[arg(long)]
232        parent: Option<String>,
233    },
234
235    /// Start a task (atomic: update status + set current)
236    Start {
237        /// Task ID
238        id: i64,
239
240        /// Include events summary
241        #[arg(long)]
242        with_events: bool,
243    },
244
245    /// Complete the current focused task (atomic: check children + update status + clear current)
246    /// This command only operates on the current_task_id. It will:
247    /// - Check all subtasks are done
248    /// - Update the task status to done
249    /// - Clear the current_task_id
250    ///
251    ///   Prerequisites: A task must be set as current (via `current --set <ID>`)
252    Done,
253
254    /// Intelligently recommend the next task to work on
255    ///
256    /// This command uses a context-aware priority model to recommend a single task:
257    /// 1. First priority: Subtasks of the current focused task (depth-first)
258    /// 2. Second priority: Top-level tasks (breadth-first)
259    ///
260    /// The command is non-interactive and does not modify task status.
261    PickNext {
262        /// Output format (text or json)
263        #[arg(long, default_value = "text")]
264        format: String,
265    },
266
267    /// Create a subtask under current task and switch to it
268    SpawnSubtask {
269        /// Subtask name
270        #[arg(long)]
271        name: String,
272
273        /// Read spec from stdin
274        #[arg(long)]
275        spec_stdin: bool,
276    },
277
278    /// Switch to a specific task (atomic: update to doing + set current)
279    Switch {
280        /// Task ID
281        id: i64,
282    },
283
284    /// Add a dependency between tasks
285    ///
286    /// Creates a dependency where BLOCKED_TASK depends on BLOCKING_TASK.
287    /// The BLOCKING_TASK must be completed before BLOCKED_TASK can be started.
288    ///
289    /// Example: `task depends-on 42 41` means Task 42 depends on Task 41
290    /// (Task 41 must be done before Task 42 can start)
291    #[command(name = "depends-on")]
292    DependsOn {
293        /// Task ID that has the dependency (blocked task)
294        blocked_task_id: i64,
295
296        /// Task ID that must be completed first (blocking task)
297        blocking_task_id: i64,
298    },
299
300    /// Get task context (ancestors, siblings, children)
301    ///
302    /// Shows the full family tree of a task to understand its strategic context.
303    /// If no task ID is provided, uses the current focused task.
304    Context {
305        /// Task ID (optional, uses current task if omitted)
306        task_id: Option<i64>,
307    },
308}
309
310#[derive(Subcommand)]
311pub enum EventCommands {
312    /// Add a new event
313    Add {
314        /// Task ID (optional, uses current task if not specified)
315        #[arg(long)]
316        task_id: Option<i64>,
317
318        /// Log type
319        #[arg(long = "type")]
320        log_type: String,
321
322        /// Read discussion data from stdin
323        #[arg(long)]
324        data_stdin: bool,
325    },
326
327    /// List events for a task (or globally if task_id not specified)
328    List {
329        /// Task ID (optional, lists all events if not specified)
330        #[arg(long)]
331        task_id: Option<i64>,
332
333        /// Maximum number of events to return (default: 50)
334        #[arg(long)]
335        limit: Option<i64>,
336
337        /// Filter by log type (e.g., "decision", "blocker", "milestone", "note")
338        #[arg(long = "type")]
339        log_type: Option<String>,
340
341        /// Filter events created within duration (e.g., "7d", "24h", "30m")
342        #[arg(long)]
343        since: Option<String>,
344    },
345}