fix(cli): audit-driven improvements to flags, help, exit codes, and deprecation
Addresses findings from a comprehensive CLI readiness audit:
Flag design (I2):
- Add hidden --no-verbose flag with overrides_with semantics, matching
the --no-quiet pattern already established for all other boolean flags.
Help text (I3):
- Add after_help examples to issues, mrs, search, sync, and timeline
subcommands. Each shows 3-4 concrete, runnable commands with comments.
Help headings (I4/P5):
- Move --mode and --fts-mode from "Output" heading to "Mode" heading
in the search subcommand. These control search strategy, not output
format — "Output" is reserved for --limit, --explain, --fields.
Exit codes (I5):
- Health check failure now exits 19 (was 1). Exit code 1 is reserved
for internal errors only. robot-docs updated to document code 19.
Deprecation visibility (P4):
- Deprecated commands (list, show, auth-test, sync-status) now emit
structured JSON warnings to stderr in robot mode:
{"warning":{"type":"DEPRECATED","message":"...","successor":"..."}}
Previously these were silently swallowed in robot mode.
Version string (P1):
- Cli struct uses env!("LORE_VERSION") from build.rs so --version shows
git hash (see previous commit).
Fields flag (P3):
- --fields help text updated to document the "minimal" preset.
Robot-docs (parallel work):
- response_schema added for every command, documenting the JSON shape
agents will receive. Agents can now introspect expected fields before
calling a command.
- error_format documents the new "actions" array.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
pub mod commands;
|
||||
pub mod progress;
|
||||
pub mod robot;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::io::IsTerminal;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "lore")]
|
||||
#[command(version, about = "Local GitLab data management with semantic search", long_about = None)]
|
||||
#[command(version = env!("LORE_VERSION"), about = "Local GitLab data management with semantic search", long_about = None)]
|
||||
#[command(subcommand_required = false)]
|
||||
pub struct Cli {
|
||||
/// Path to config file
|
||||
@@ -54,9 +55,17 @@ pub struct Cli {
|
||||
pub no_quiet: bool,
|
||||
|
||||
/// Increase log verbosity (-v, -vv, -vvv)
|
||||
#[arg(short = 'v', long = "verbose", action = clap::ArgAction::Count, global = true, help = "Increase log verbosity (-v, -vv, -vvv)")]
|
||||
#[arg(short = 'v', long = "verbose", action = clap::ArgAction::Count, global = true, help = "Increase log verbosity (-v, -vv, -vvv)", overrides_with = "no_verbose")]
|
||||
pub verbose: u8,
|
||||
|
||||
#[arg(
|
||||
long = "no-verbose",
|
||||
global = true,
|
||||
hide = true,
|
||||
overrides_with = "verbose"
|
||||
)]
|
||||
pub no_verbose: bool,
|
||||
|
||||
/// Log format for stderr output: text (default) or json
|
||||
#[arg(long = "log-format", global = true, value_parser = ["text", "json"], default_value = "text", help = "Log format for stderr output: text (default) or json")]
|
||||
pub log_format: String,
|
||||
@@ -246,6 +255,11 @@ pub enum Commands {
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(after_help = "\x1b[1mExamples:\x1b[0m
|
||||
lore issues -n 10 # List 10 most recently updated issues
|
||||
lore issues -s opened -l bug # Open issues labeled 'bug'
|
||||
lore issues 42 -p group/repo # Show issue #42 in a specific project
|
||||
lore issues --since 7d -a jsmith # Issues updated in last 7 days by jsmith")]
|
||||
pub struct IssuesArgs {
|
||||
/// Issue IID (omit to list, provide to show details)
|
||||
pub iid: Option<i64>,
|
||||
@@ -259,7 +273,7 @@ pub struct IssuesArgs {
|
||||
)]
|
||||
pub limit: usize,
|
||||
|
||||
/// Select output fields (comma-separated: iid,title,state,author,labels,updated)
|
||||
/// Select output fields (comma-separated, or 'minimal' preset: iid,title,state,updated_at_iso)
|
||||
#[arg(long, help_heading = "Output", value_delimiter = ',')]
|
||||
pub fields: Option<Vec<String>>,
|
||||
|
||||
@@ -331,6 +345,11 @@ pub struct IssuesArgs {
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(after_help = "\x1b[1mExamples:\x1b[0m
|
||||
lore mrs -s opened # List open merge requests
|
||||
lore mrs -s merged --since 2w # MRs merged in the last 2 weeks
|
||||
lore mrs 99 -p group/repo # Show MR !99 in a specific project
|
||||
lore mrs -D --reviewer jsmith # Non-draft MRs reviewed by jsmith")]
|
||||
pub struct MrsArgs {
|
||||
/// MR IID (omit to list, provide to show details)
|
||||
pub iid: Option<i64>,
|
||||
@@ -344,7 +363,7 @@ pub struct MrsArgs {
|
||||
)]
|
||||
pub limit: usize,
|
||||
|
||||
/// Select output fields (comma-separated: iid,title,state,author,labels,updated)
|
||||
/// Select output fields (comma-separated, or 'minimal' preset: iid,title,state,updated_at_iso)
|
||||
#[arg(long, help_heading = "Output", value_delimiter = ',')]
|
||||
pub fields: Option<Vec<String>>,
|
||||
|
||||
@@ -480,12 +499,17 @@ pub struct StatsArgs {
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(after_help = "\x1b[1mExamples:\x1b[0m
|
||||
lore search 'authentication bug' # Hybrid search (default)
|
||||
lore search 'deploy' --mode lexical --type mr # Lexical search, MRs only
|
||||
lore search 'API rate limit' --since 30d # Recent results only
|
||||
lore search 'config' -p group/repo --explain # With ranking explanation")]
|
||||
pub struct SearchArgs {
|
||||
/// Search query string
|
||||
pub query: String,
|
||||
|
||||
/// Search mode (lexical, hybrid, semantic)
|
||||
#[arg(long, default_value = "hybrid", value_parser = ["lexical", "hybrid", "semantic"], help_heading = "Output")]
|
||||
#[arg(long, default_value = "hybrid", value_parser = ["lexical", "hybrid", "semantic"], help_heading = "Mode")]
|
||||
pub mode: String,
|
||||
|
||||
/// Filter by source type (issue, mr, discussion)
|
||||
@@ -533,7 +557,7 @@ pub struct SearchArgs {
|
||||
pub no_explain: bool,
|
||||
|
||||
/// FTS query mode: safe (default) or raw
|
||||
#[arg(long = "fts-mode", default_value = "safe", value_parser = ["safe", "raw"], help_heading = "Output")]
|
||||
#[arg(long = "fts-mode", default_value = "safe", value_parser = ["safe", "raw"], help_heading = "Mode")]
|
||||
pub fts_mode: String,
|
||||
}
|
||||
|
||||
@@ -549,6 +573,11 @@ pub struct GenerateDocsArgs {
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(after_help = "\x1b[1mExamples:\x1b[0m
|
||||
lore sync # Full pipeline: ingest + docs + embed
|
||||
lore sync --no-embed # Skip embedding step
|
||||
lore sync --full --force # Full re-sync, override stale lock
|
||||
lore sync --dry-run # Preview what would change")]
|
||||
pub struct SyncArgs {
|
||||
/// Reset cursors, fetch everything
|
||||
#[arg(long, overrides_with = "no_full")]
|
||||
@@ -602,6 +631,10 @@ pub struct EmbedArgs {
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(after_help = "\x1b[1mExamples:\x1b[0m
|
||||
lore timeline 'deployment' # Events related to deployments
|
||||
lore timeline 'auth' --since 30d -p group/repo # Scoped to project and time
|
||||
lore timeline 'migration' --depth 2 --expand-mentions # Deep cross-reference expansion")]
|
||||
pub struct TimelineArgs {
|
||||
/// Search query (keywords to find in issues, MRs, and discussions)
|
||||
pub query: String,
|
||||
|
||||
Reference in New Issue
Block a user