use crate::error::DevbrainError;
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(
name = "devbrain",
version,
about = "Track developer notes, commands, and errors",
long_about = "A small CLI for capturing and exploring developer activity across projects.",
after_help = "Capture Commands:\n log Log a developer note\n log-cmd Log a command you ran\n log-error Log an error entry\n\nBrowse Commands:\n search Search past entries\n timeline View recent activity\n errors View recent error entries\n commands View recent command entries\n session Show commands from the current shell session\n last Show the most recent entry\n stats Show summary statistics\n\nMaintenance Commands:\n doctor Diagnose common database issues\n export Export all entries to JSON\n import Import entries from JSON\n clear Delete all stored entries\n\nExamples:\n devbrain log \"Investigated flaky test\" --tag testing\n devbrain log-cmd \"cargo test\" --tag ci\n devbrain log-error \"panic in parser\" --tag bug\n devbrain search panic --limit 5\n devbrain timeline --all\n devbrain commands --session\n devbrain last\n devbrain doctor\n devbrain export backup.json\n devbrain import backup.json --merge"
)]
pub struct Cli {
#[arg(long, global = true, help = "Disable ANSI color output")]
pub no_color: bool,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
#[command(
alias = "l",
about = "Log a developer note",
display_order = 1,
after_help = "Example:\n devbrain log \"Investigated flaky test\" --tag testing"
)]
Log {
#[arg(help = "Note content to log")]
message: String,
#[arg(long, help = "Add a tag to the entry")]
tag: Vec<String>,
},
#[command(
alias = "lc",
about = "Log a command you ran",
display_order = 2,
after_help = "Example:\n devbrain log-cmd \"cargo test\" --tag ci"
)]
LogCmd {
#[arg(help = "Command text to log")]
command: String,
#[arg(long, help = "Add a tag to the entry")]
tag: Vec<String>,
},
#[command(name = "shell-log", hide = true)]
ShellLog {
#[arg(help = "Command text to log")]
command: String,
#[arg(long, help = "Exit status code from the shell command")]
status: Option<i32>,
#[arg(long, help = "Session identifier from the shell")]
session: Option<String>,
},
#[command(
alias = "le",
about = "Log an error entry",
display_order = 3,
after_help = "Example:\n devbrain log-error \"panic in parser\" --tag bug"
)]
LogError {
#[arg(help = "Error text to log")]
error: String,
#[arg(long, help = "Add a tag to the entry")]
tag: Vec<String>,
},
#[command(
alias = "s",
about = "Search past entries",
display_order = 10,
after_help = "Examples:\n devbrain search panic\n devbrain search cargo --type command --limit 10\n devbrain search auth --recent\n devbrain search auth --since 1h"
)]
Search {
#[arg(help = "Keyword to search for")]
query: String,
#[arg(long, help = "Include entries from all projects")]
all: bool,
#[arg(long, help = "Output results as JSON")]
json: bool,
#[arg(long, help = "Limit number of results")]
limit: Option<usize>,
#[arg(long, help = "Show 5 recent results")]
recent: bool,
#[arg(long, help = "Skip this many results before showing entries")]
offset: Option<usize>,
#[arg(long = "type", help = "Filter by type: log, command, error")]
entry_type: Option<String>,
#[arg(long, help = "Show entries since a duration like 1h, 1d, 7d")]
since: Option<String>,
#[arg(long, help = "Show only successful commands")]
success: bool,
#[arg(long, help = "Show only failed commands")]
failed: bool,
#[arg(long, help = "Show only entries from the current shell session")]
session: bool,
},
#[command(
alias = "t",
about = "View recent activity",
display_order = 11,
after_help = "Examples:\n devbrain timeline\n devbrain timeline --all --limit 20\n devbrain timeline --since 7d"
)]
Timeline {
#[arg(long, help = "Include entries from all projects")]
all: bool,
#[arg(long, help = "Output results as JSON")]
json: bool,
#[arg(long, help = "Limit number of results")]
limit: Option<usize>,
#[arg(long, help = "Skip this many results before showing entries")]
offset: Option<usize>,
#[arg(long, help = "Filter by type: log, command, error")]
entry_type: Option<String>,
#[arg(long, help = "Show entries since a duration like 1h, 1d, 7d")]
since: Option<String>,
#[arg(long, help = "Show only entries from the current shell session")]
session: bool,
},
#[command(
about = "Interactively search past entries",
display_order = 11,
after_help = "Example:\n devbrain explore"
)]
Explore,
#[command(
about = "View recent error entries",
display_order = 12,
after_help = "Examples:\n devbrain errors --limit 10\n devbrain errors --recent\n devbrain errors --since 1h"
)]
Errors {
#[arg(long, help = "Include entries from all projects")]
all: bool,
#[arg(long, help = "Output results as JSON")]
json: bool,
#[arg(long, help = "Limit number of results")]
limit: Option<usize>,
#[arg(long, help = "Show 5 recent results")]
recent: bool,
#[arg(long, help = "Show entries since a duration like 1h, 1d, 7d")]
since: Option<String>,
},
#[command(
name = "commands",
about = "View recent command entries",
display_order = 13,
after_help = "Examples:\n devbrain commands --limit 10\n devbrain commands --session\n devbrain commands --recent\n devbrain commands --since 1d"
)]
CmdHistory {
#[arg(long, help = "Include entries from all projects")]
all: bool,
#[arg(long, help = "Output results as JSON")]
json: bool,
#[arg(long, help = "Limit number of results")]
limit: Option<usize>,
#[arg(long, help = "Show 5 recent results")]
recent: bool,
#[arg(long, help = "Show entries since a duration like 1h, 1d, 7d")]
since: Option<String>,
#[arg(long, help = "Show only entries from the current shell session")]
session: bool,
},
#[command(
about = "Show command entries from the current shell session",
display_order = 14,
after_help = "Example:\n devbrain session --limit 15"
)]
Session {
#[arg(long, help = "Output results as JSON")]
json: bool,
#[arg(long, help = "Limit number of results")]
limit: Option<usize>,
},
#[command(
about = "Show the most recent entry",
display_order = 15,
after_help = "Examples:\n devbrain last\n devbrain last --all"
)]
Last {
#[arg(long, help = "Include entries from all projects")]
all: bool,
#[arg(long, help = "Output results as JSON")]
json: bool,
},
#[command(
about = "Delete all stored entries",
display_order = 22,
after_help = "Example:\n devbrain clear --force"
)]
Clear {
#[arg(long, help = "Delete immediately without confirmation")]
force: bool,
},
#[command(
about = "Remove duplicate, empty, and optionally old entries",
display_order = 23,
after_help = "Examples:\n devbrain cleanup\n devbrain cleanup --older-than 30"
)]
Cleanup {
#[arg(long, help = "Remove entries older than this many days")]
older_than: Option<i64>,
},
#[command(
about = "Export all entries to a JSON file",
display_order = 20,
after_help = "Example:\n devbrain export backup.json"
)]
Export {
#[arg(help = "Output file path")]
output: String,
},
#[command(
about = "Import entries from a JSON file",
display_order = 21,
after_help = "Examples:\n devbrain import backup.json\n devbrain import backup.json --merge"
)]
Import {
#[arg(help = "Input file path")]
input: String,
#[arg(long, help = "Merge imported entries with existing data")]
merge: bool,
},
#[command(
about = "Diagnose common database issues",
display_order = 19,
after_help = "Example:\n devbrain doctor"
)]
Doctor,
#[command(
about = "Show summary statistics for stored entries",
display_order = 16,
after_help = "Example:\n devbrain stats"
)]
Stats,
#[command(
about = "Show summary statistics for the current project",
display_order = 17,
after_help = "Example:\n devbrain project"
)]
Project,
#[command(
about = "Show recent failed commands, errors, and logs for the current project",
display_order = 18,
after_help = "Example:\n devbrain debug"
)]
Debug,
#[command(
about = "Run or save a query preset",
display_order = 19,
after_help = "Examples:\n devbrain preset recent-errors\n devbrain preset recent-commands\n devbrain preset debug\n devbrain preset save auth-errors \"search auth --type error\""
)]
Preset {
#[arg(help = "Preset action or preset name", num_args = 1..)]
args: Vec<String>,
},
#[command(
about = "Suggest useful commands from history",
display_order = 20,
after_help = "Example:\n devbrain suggest build"
)]
Suggest {
#[arg(help = "Keyword to match against past commands")]
query: String,
},
}
pub fn parse() -> Result<Cli, DevbrainError> {
Cli::try_parse().map_err(|error| DevbrainError::CliError(error.to_string()))
}