feat(surgical-sync): add per-IID surgical sync pipeline

Wire --issue/--mr surgical dispatch, fix effective_project resolution bug,
remove dead struct fields and stale allow annotations, fix collapsible-if
clippy lints from concurrent changes.

Pipeline: PREFLIGHT -> TOCTOU -> INGEST -> DEPENDENTS -> DOCS -> EMBED -> FINALIZE
Token management: add lore token set/show commands with config file storage
This commit is contained in:
teernisse
2026-02-18 13:29:20 -05:00
parent 53ce20595b
commit d95392e079
41 changed files with 4391 additions and 76 deletions

View File

@@ -4,7 +4,7 @@ pub mod progress;
pub mod render;
pub mod robot;
use clap::{Parser, Subcommand};
use clap::{Args, Parser, Subcommand};
use std::io::IsTerminal;
#[derive(Parser)]
@@ -298,6 +298,15 @@ pub enum Commands {
lore cron uninstall # Remove cron job")]
Cron(CronArgs),
/// Manage stored GitLab token
#[command(after_help = "\x1b[1mExamples:\x1b[0m
lore token set # Interactive token entry + validation
lore token set --token glpat-xxx # Non-interactive token storage
echo glpat-xxx | lore token set # Pipe token from stdin
lore token show # Show token (masked)
lore token show --unmask # Show full token")]
Token(TokenArgs),
#[command(hide = true)]
List {
#[arg(value_parser = ["issues", "mrs"])]
@@ -798,7 +807,9 @@ pub struct GenerateDocsArgs {
lore sync --no-embed # Skip embedding step
lore sync --no-status # Skip work-item status enrichment
lore sync --full --force # Full re-sync, override stale lock
lore sync --dry-run # Preview what would change")]
lore sync --dry-run # Preview what would change
lore sync --issue 42 -p group/repo # Surgically sync one issue
lore sync --mr 10 --mr 20 -p g/r # Surgically sync two MRs")]
pub struct SyncArgs {
/// Reset cursors, fetch everything
#[arg(long, overrides_with = "no_full")]
@@ -848,6 +859,22 @@ pub struct SyncArgs {
/// Acquire file lock before syncing (skip if another sync is running)
#[arg(long)]
pub lock: bool,
/// Surgically sync specific issues by IID (repeatable, must be positive)
#[arg(long, value_parser = clap::value_parser!(u64).range(1..), action = clap::ArgAction::Append)]
pub issue: Vec<u64>,
/// Surgically sync specific merge requests by IID (repeatable, must be positive)
#[arg(long, value_parser = clap::value_parser!(u64).range(1..), action = clap::ArgAction::Append)]
pub mr: Vec<u64>,
/// Scope to a single project (required when --issue or --mr is used)
#[arg(short = 'p', long)]
pub project: Option<String>,
/// Validate remote entities exist without DB writes (preflight only)
#[arg(long)]
pub preflight_only: bool,
}
#[derive(Parser)]
@@ -973,15 +1000,14 @@ pub struct WhoArgs {
#[arg(short = 'p', long, help_heading = "Filters")]
pub project: Option<String>,
/// Maximum results per section (1..=500, bounded for output safety)
/// Maximum results per section (1..=500); omit for unlimited
#[arg(
short = 'n',
long = "limit",
default_value = "20",
value_parser = clap::value_parser!(u16).range(1..=500),
help_heading = "Output"
)]
pub limit: u16,
pub limit: Option<u16>,
/// Select output fields (comma-separated, or 'minimal' preset; varies by mode)
#[arg(long, help_heading = "Output", value_delimiter = ',')]
@@ -1128,3 +1154,26 @@ pub enum CronAction {
/// Show current cron configuration
Status,
}
#[derive(Args)]
pub struct TokenArgs {
#[command(subcommand)]
pub action: TokenAction,
}
#[derive(Subcommand)]
pub enum TokenAction {
/// Store a GitLab token in the config file
Set {
/// Token value (reads from stdin if omitted in non-interactive mode)
#[arg(long)]
token: Option<String>,
},
/// Show the current token (masked by default)
Show {
/// Show the full unmasked token
#[arg(long)]
unmask: bool,
},
}