pub mod cli;
pub mod collect;
pub mod queue;
pub mod queue_path;
use clap::{Arg, ArgAction, Args, Command, CommandFactory, Parser, Subcommand};
use std::path::PathBuf;
#[derive(Parser)]
#[command(
name = "sq",
version,
about = "Lightweight task-list CLI with structured sources",
long_about = "sq is a lightweight task-list CLI with structured sources.\n\nIt manages tasks in a JSONL file. You can use it directly from the shell or instruct agents to manage them for you."
)]
pub struct Cli {
#[arg(
short = 'q',
long = "queue",
value_name = "PATH",
global = true,
display_order = 900
)]
pub queue: Option<PathBuf>,
#[command(subcommand)]
pub command: Commands,
}
pub fn build_cli() -> Command {
let mut cmd = Cli::command()
.propagate_version(true)
.disable_version_flag(true)
.arg(
Arg::new("version")
.short('v')
.long("version")
.help("Print version")
.action(ArgAction::Version)
.global(true),
);
let root_help = crate::cli::help::root_after_help(cmd.get_styles());
cmd = cmd.after_help(root_help);
cmd = cmd.mut_subcommand("collect", |subcmd| {
let help = crate::cli::commands::collect::after_help(subcmd.get_styles());
subcmd.after_help(help)
});
cmd = cmd.mut_subcommand("add", |subcmd| {
let help = crate::cli::commands::add::after_help(subcmd.get_styles());
subcmd.after_help(help)
});
cmd = cmd.mut_subcommand("edit", |subcmd| {
let help = crate::cli::commands::edit::after_help(subcmd.get_styles());
subcmd.after_help(help)
});
cmd = cmd.mut_subcommand("list", |subcmd| {
let help = crate::cli::commands::list::after_help(subcmd.get_styles());
subcmd.after_help(help)
});
cmd = cmd.mut_subcommand("rm", |subcmd| {
let help = crate::cli::commands::rm::after_help(subcmd.get_styles());
subcmd.after_help(help)
});
cmd = cmd.mut_subcommand("close", |subcmd| {
let help = crate::cli::commands::status::close_after_help(subcmd.get_styles());
subcmd.long_about("").after_help(help)
});
cmd
}
#[derive(Subcommand)]
pub enum Commands {
Add(AddArgs),
Collect(CollectArgs),
List(ListArgs),
Show(ShowArgs),
Edit(EditArgs),
Close(StatusArgs),
Rm(RmArgs),
Prime(PrimeArgs),
}
#[derive(Args)]
#[command(about = "Output task workflow context for AI agents")]
pub struct PrimeArgs {
#[arg(long = "prelude", display_order = 1)]
pub prelude: bool,
}
#[derive(Parser)]
pub struct AddArgs {
#[arg(long = "title", value_name = "TITLE", display_order = 1)]
pub title: Option<String>,
#[arg(long = "description", value_name = "TEXT", display_order = 2)]
pub description: Option<String>,
#[arg(long = "priority", value_name = "PRIORITY", display_order = 3)]
pub priority: Option<String>,
#[arg(long = "diff", value_name = "PATH", display_order = 10)]
pub diff: Vec<String>,
#[arg(long = "file", value_name = "PATH", display_order = 11)]
pub file: Vec<String>,
#[arg(long = "text", value_name = "STRING", display_order = 12)]
pub text: Vec<String>,
#[arg(long = "directory", value_name = "PATH", display_order = 13)]
pub directory: Vec<String>,
#[arg(long = "stdin", value_name = "TYPE", display_order = 14)]
pub stdin: Option<String>,
#[arg(long = "metadata", value_name = "JSON", display_order = 15)]
pub metadata: Option<String>,
#[arg(long = "blocked-by", value_name = "IDS", display_order = 16)]
pub blocked_by: Option<String>,
#[arg(long = "json", display_order = 17)]
pub json: bool,
}
#[derive(Args)]
#[command(about = "Collect tasks from stdin")]
pub struct CollectArgs {
#[arg(long = "title", value_name = "TITLE", display_order = 1)]
pub title: Option<String>,
#[arg(long = "description", value_name = "TEXT", display_order = 2)]
pub description: Option<String>,
#[arg(long = "priority", value_name = "PRIORITY", display_order = 3)]
pub priority: Option<String>,
#[arg(long = "by-file", display_order = 10)]
pub by_file: bool,
#[arg(long = "stdin-format", value_name = "FORMAT", display_order = 11)]
pub stdin_format: Option<String>,
#[arg(long = "title-template", value_name = "TEMPLATE", display_order = 12)]
pub title_template: Option<String>,
#[arg(long = "metadata", value_name = "JSON", display_order = 13)]
pub metadata: Option<String>,
#[arg(long = "blocked-by", value_name = "IDS", display_order = 14)]
pub blocked_by: Option<String>,
#[arg(long = "json", display_order = 15)]
pub json: bool,
}
#[derive(Parser)]
pub struct ListArgs {
#[arg(long = "status", value_name = "STATUS", display_order = 1)]
pub status: Vec<String>,
#[arg(long = "all", display_order = 2)]
pub all: bool,
#[arg(long = "priority", value_name = "PRIORITY", display_order = 3)]
pub priority: Vec<String>,
#[arg(long = "ready", display_order = 4)]
pub ready: bool,
#[arg(long = "json", display_order = 10)]
pub json: bool,
#[arg(long = "filter", value_name = "EXPR", display_order = 11)]
pub filter: Option<String>,
#[arg(long = "sort", value_name = "PATH", display_order = 12)]
pub sort: Option<String>,
#[arg(long = "reverse", display_order = 13)]
pub reverse: bool,
}
#[derive(Parser)]
pub struct ShowArgs {
pub id: Option<String>,
#[arg(long = "json")]
pub json: bool,
}
#[derive(Parser)]
pub struct EditArgs {
pub id: Option<String>,
#[arg(long = "set-title", value_name = "TITLE", display_order = 1)]
pub set_title: Option<String>,
#[arg(long = "set-description", value_name = "TEXT", display_order = 2)]
pub set_description: Option<String>,
#[arg(long = "set-status", value_name = "STATUS", display_order = 3)]
pub set_status: Option<String>,
#[arg(long = "set-priority", value_name = "PRIORITY", display_order = 4)]
pub set_priority: Option<String>,
#[arg(long = "clear-priority", display_order = 5)]
pub clear_priority: bool,
#[arg(long = "add-diff", value_name = "PATH", display_order = 10)]
pub add_diff: Vec<String>,
#[arg(long = "add-file", value_name = "PATH", display_order = 11)]
pub add_file: Vec<String>,
#[arg(long = "add-text", value_name = "STRING", display_order = 12)]
pub add_text: Vec<String>,
#[arg(long = "add-directory", value_name = "PATH", display_order = 13)]
pub add_directory: Vec<String>,
#[arg(long = "rm-source", value_name = "INDEX", display_order = 14)]
pub rm_source: Vec<usize>,
#[arg(long = "set-metadata", value_name = "JSON", display_order = 15)]
pub set_metadata: Option<String>,
#[arg(long = "merge-metadata", value_name = "JSON", display_order = 16)]
pub merge_metadata: Option<String>,
#[arg(long = "set-blocked-by", value_name = "IDS", display_order = 17)]
pub set_blocked_by: Option<String>,
#[arg(long = "json", display_order = 18)]
pub json: bool,
}
#[derive(Parser)]
pub struct StatusArgs {
pub id: Option<String>,
#[arg(long = "json")]
pub json: bool,
}
#[derive(Parser)]
pub struct RmArgs {
pub id: Option<String>,
#[arg(long = "json")]
pub json: bool,
}