Skip to main content

sift_queue/
lib.rs

1pub mod cli;
2pub mod queue;
3pub mod queue_path;
4
5use clap::{Parser, Subcommand};
6use std::path::PathBuf;
7
8#[derive(Parser)]
9#[command(name = "sq", about = "Manage Sift's review queue")]
10pub struct Cli {
11    /// Path to queue file
12    #[arg(short = 'q', long = "queue", value_name = "PATH", global = true)]
13    pub queue: Option<PathBuf>,
14
15    #[command(subcommand)]
16    pub command: Commands,
17}
18
19#[derive(Subcommand)]
20pub enum Commands {
21    /// Add a new item to the review queue
22    Add(AddArgs),
23    /// List queue items
24    List(ListArgs),
25    /// Show details of a queue item
26    Show(ShowArgs),
27    /// Edit an existing queue item
28    Edit(EditArgs),
29    /// Mark an item as closed
30    Close(StatusArgs),
31    /// Remove an item from the queue
32    Rm(RmArgs),
33    /// Output sift workflow context for AI agents
34    Prime(PrimeArgs),
35}
36
37#[derive(Parser)]
38pub struct AddArgs {
39    /// Add diff source (repeatable)
40    #[arg(long = "diff", value_name = "PATH")]
41    pub diff: Vec<String>,
42
43    /// Add file source (repeatable)
44    #[arg(long = "file", value_name = "PATH")]
45    pub file: Vec<String>,
46
47    /// Add text source (repeatable)
48    #[arg(long = "text", value_name = "STRING")]
49    pub text: Vec<String>,
50
51    /// Add directory source (repeatable)
52    #[arg(long = "directory", value_name = "PATH")]
53    pub directory: Vec<String>,
54
55    /// Read source content from stdin (diff|file|text|directory)
56    #[arg(long = "stdin", value_name = "TYPE")]
57    pub stdin: Option<String>,
58
59    /// Title for the item
60    #[arg(long = "title", value_name = "TITLE")]
61    pub title: Option<String>,
62
63    /// Description for the item
64    #[arg(long = "description", value_name = "TEXT")]
65    pub description: Option<String>,
66
67    /// Attach metadata as JSON
68    #[arg(long = "metadata", value_name = "JSON")]
69    pub metadata: Option<String>,
70
71    /// Comma-separated blocker IDs
72    #[arg(long = "blocked-by", value_name = "IDS")]
73    pub blocked_by: Option<String>,
74
75    /// Output as JSON
76    #[arg(long = "json")]
77    pub json: bool,
78}
79
80#[derive(Parser)]
81pub struct ListArgs {
82    /// Filter by status (pending|in_progress|closed)
83    #[arg(long = "status", value_name = "STATUS")]
84    pub status: Option<String>,
85
86    /// Include closed items when status is not explicitly filtered
87    #[arg(long = "all")]
88    pub all: bool,
89
90    /// Output as JSON
91    #[arg(long = "json")]
92    pub json: bool,
93
94    /// jq select expression
95    #[arg(long = "filter", value_name = "EXPR")]
96    pub filter: Option<String>,
97
98    /// jq path expression to sort by
99    #[arg(long = "sort", value_name = "PATH")]
100    pub sort: Option<String>,
101
102    /// Reverse sort order
103    #[arg(long = "reverse")]
104    pub reverse: bool,
105
106    /// Show only ready items (pending and unblocked)
107    #[arg(long = "ready")]
108    pub ready: bool,
109}
110
111#[derive(Parser)]
112pub struct ShowArgs {
113    /// Item ID
114    pub id: Option<String>,
115
116    /// Output as JSON
117    #[arg(long = "json")]
118    pub json: bool,
119}
120
121#[derive(Parser)]
122pub struct EditArgs {
123    /// Item ID
124    pub id: Option<String>,
125
126    /// Add diff source
127    #[arg(long = "add-diff", value_name = "PATH")]
128    pub add_diff: Vec<String>,
129
130    /// Add file source
131    #[arg(long = "add-file", value_name = "PATH")]
132    pub add_file: Vec<String>,
133
134    /// Add text source
135    #[arg(long = "add-text", value_name = "STRING")]
136    pub add_text: Vec<String>,
137
138    /// Add directory source
139    #[arg(long = "add-directory", value_name = "PATH")]
140    pub add_directory: Vec<String>,
141
142    /// Add transcript source
143    #[arg(long = "add-transcript", value_name = "PATH")]
144    pub add_transcript: Vec<String>,
145
146    /// Remove source by index (0-based, repeatable)
147    #[arg(long = "rm-source", value_name = "INDEX")]
148    pub rm_source: Vec<usize>,
149
150    /// Change status (pending|in_progress|closed)
151    #[arg(long = "set-status", value_name = "STATUS")]
152    pub set_status: Option<String>,
153
154    /// Set title for the item
155    #[arg(long = "set-title", value_name = "TITLE")]
156    pub set_title: Option<String>,
157
158    /// Set description for the item
159    #[arg(long = "set-description", value_name = "TEXT")]
160    pub set_description: Option<String>,
161
162    /// Set metadata as JSON (replaces full metadata object)
163    #[arg(long = "set-metadata", value_name = "JSON")]
164    pub set_metadata: Option<String>,
165
166    /// Merge metadata object as JSON (deep object merge)
167    #[arg(long = "merge-metadata", value_name = "JSON")]
168    pub merge_metadata: Option<String>,
169
170    /// Set blocker IDs (comma-separated, empty to clear)
171    #[arg(long = "set-blocked-by", value_name = "IDS")]
172    pub set_blocked_by: Option<String>,
173
174    /// Output as JSON
175    #[arg(long = "json")]
176    pub json: bool,
177}
178
179#[derive(Parser)]
180pub struct StatusArgs {
181    /// Item ID
182    pub id: Option<String>,
183
184    /// Output as JSON
185    #[arg(long = "json")]
186    pub json: bool,
187}
188
189#[derive(Parser)]
190pub struct RmArgs {
191    /// Item ID
192    pub id: Option<String>,
193
194    /// Output as JSON
195    #[arg(long = "json")]
196    pub json: bool,
197}
198
199#[derive(Parser)]
200pub struct PrimeArgs {
201    /// Force full CLI output
202    #[arg(long = "full")]
203    pub full: bool,
204}