llman 0.0.68

A tool for managing LLM application rules(prompts) ...
Documentation
use clap::{Parser, Subcommand, ValueEnum};
use std::path::PathBuf;

#[derive(Parser)]
pub struct ToolArgs {
    #[command(subcommand)]
    pub command: ToolCommands,
}

#[derive(Subcommand)]
pub enum ToolCommands {
    /// Clean useless comments from source code
    #[command(alias = "cuc")]
    CleanUselessComments(CleanUselessCommentsArgs),
    /// Remove useless directories recursively
    RmUselessDirs(RmUselessDirsArgs),
    /// Sync ignore rules across OpenCode/Cursor/Claude Code
    #[command(alias = "si")]
    SyncIgnore(SyncIgnoreArgs),
    /// Manage agent init files (AGENTS.md / CLAUDE.md / .cursor/ etc.)
    AgentsMd(AgentsMdArgs),
}

#[derive(Parser, Debug, Clone)]
pub struct AgentsMdArgs {
    #[command(subcommand)]
    pub command: AgentsMdCommands,
}

#[derive(Subcommand, Debug, Clone)]
pub enum AgentsMdCommands {
    /// Scan the project for agent init files and list their relative paths
    Scan(AgentsMdScanArgs),
    /// Delete agent init files recorded in project config
    Clean(AgentsMdCleanArgs),
    /// Restore agent init files from the default branch
    Revert(AgentsMdRevertArgs),
}

#[derive(Parser, Debug, Clone)]
pub struct AgentsMdScanArgs {
    /// Write discovered paths into the project `.llman/config.yaml` (create if missing)
    #[arg(long, action = clap::ArgAction::SetTrue)]
    pub upsert_project_configs: bool,

    /// Configuration file path (default: project `.llman/config.yaml`, then global)
    #[arg(long, short = 'c')]
    pub config: Option<PathBuf>,

    /// Verbose output
    #[arg(long, short = 'v', action = clap::ArgAction::SetTrue)]
    pub verbose: bool,
}

#[derive(Parser, Debug, Clone)]
pub struct AgentsMdCleanArgs {
    /// Apply changes (default: dry-run preview)
    #[arg(short = 'y', long, action = clap::ArgAction::SetTrue)]
    pub yes: bool,

    /// `git add` the removed files and commit on the current branch
    #[arg(long, action = clap::ArgAction::SetTrue)]
    pub commit: bool,

    /// Force `--commit` even on the default branch (main/master)
    #[arg(long, short = 'f', action = clap::ArgAction::SetTrue)]
    pub force: bool,

    /// Configuration file path (default: project `.llman/config.yaml`, then global)
    #[arg(long, short = 'c')]
    pub config: Option<PathBuf>,

    /// Verbose output
    #[arg(long, short = 'v', action = clap::ArgAction::SetTrue)]
    pub verbose: bool,
}

#[derive(Parser, Debug, Clone)]
pub struct AgentsMdRevertArgs {
    /// Apply changes (default: dry-run preview)
    #[arg(short = 'y', long, action = clap::ArgAction::SetTrue)]
    pub yes: bool,

    /// Create a branch and commit the restored files
    #[arg(long, action = clap::ArgAction::SetTrue)]
    pub commit: bool,

    /// Configuration file path (default: project `.llman/config.yaml`, then global)
    #[arg(long, short = 'c')]
    pub config: Option<PathBuf>,

    /// Verbose output
    #[arg(long, short = 'v', action = clap::ArgAction::SetTrue)]
    pub verbose: bool,
}

#[derive(Parser, Debug, Clone)]
pub struct CleanUselessCommentsArgs {
    /// Configuration file path (default: .llman/config.yaml)
    #[arg(long, short = 'c')]
    pub config: Option<PathBuf>,

    /// Dry run mode, show changes without applying them
    #[arg(long, short = 'd')]
    pub dry_run: bool,

    /// Apply changes (default: dry run)
    #[arg(long, short = 'y')]
    pub yes: bool,

    /// Interactive mode, confirm changes before applying
    #[arg(long, short = 'i')]
    pub interactive: bool,

    /// Force execution, skip confirmation prompts
    #[arg(long, short = 'f')]
    pub force: bool,

    /// Verbose output
    #[arg(long, short = 'v')]
    pub verbose: bool,

    /// Only process Git tracked files
    #[arg(long)]
    pub git_only: bool,

    /// Files to process (if not specified, use config scope)
    pub files: Vec<PathBuf>,
}

#[derive(Parser, Debug, Clone)]
pub struct RmUselessDirsArgs {
    /// Configuration file path (default: .llman/config.yaml)
    #[arg(long, short = 'c')]
    pub config: Option<PathBuf>,

    /// Directory to scan (default: current directory)
    pub path: Option<PathBuf>,

    /// Actually delete empty directories (default: dry run)
    #[arg(short = 'y', long)]
    pub yes: bool,

    /// Path to a .gitignore file to honor (default: repo root .gitignore, else `target`/.gitignore)
    #[arg(long)]
    pub gitignore: Option<PathBuf>,

    /// Treat directories containing only ignored entries as removable (deletes ignored files/dirs)
    #[arg(long)]
    pub prune_ignored: bool,

    /// Verbose output
    #[arg(long, short = 'v')]
    pub verbose: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum SyncIgnoreTarget {
    /// Project root `.ignore` (OpenCode / ripgrep)
    Opencode,
    /// Project root `.cursorignore`
    Cursor,
    /// `.claude/settings.json`
    ClaudeShared,
    /// `.claude/settings.local.json`
    ClaudeLocal,
    /// All supported targets
    All,
}

#[derive(Parser, Debug, Clone)]
#[command(
    after_help = "Examples:\n  llman tool sync-ignore\n  llman tool sync-ignore -y\n  llman tool sync-ignore --target cursor --target claude-shared -y\n  llman tool sync-ignore --interactive\n"
)]
pub struct SyncIgnoreArgs {
    /// Apply changes (default: dry-run preview)
    #[arg(short = 'y', long, action = clap::ArgAction::SetTrue)]
    pub yes: bool,

    /// Interactive mode (MultiSelect targets + preview + confirm)
    #[arg(long, action = clap::ArgAction::SetTrue)]
    pub interactive: bool,

    /// Force execution even when no git repository is found
    #[arg(long, action = clap::ArgAction::SetTrue)]
    pub force: bool,

    /// Verbose output
    #[arg(long, short = 'v', action = clap::ArgAction::SetTrue)]
    pub verbose: bool,

    /// Output target(s) to sync (repeatable, or comma-separated)
    #[arg(long, short = 't', value_enum, value_delimiter = ',')]
    pub target: Vec<SyncIgnoreTarget>,

    /// Additional input file path(s) to include as sources (repeatable)
    #[arg(long, short = 'i')]
    pub input: Vec<PathBuf>,
}