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