greppy/cli/
mod.rs

1//! CLI command definitions and handlers
2
3pub mod daemon;
4pub mod index;
5pub mod login;
6pub mod search;
7
8use clap::{Parser, Subcommand};
9use std::path::PathBuf;
10
11const LONG_ABOUT: &str = r#"
12 ██████╗ ██████╗ ███████╗██████╗ ██████╗ ██╗   ██╗
13██╔════╝ ██╔══██╗██╔════╝██╔══██╗██╔══██╗╚██╗ ██╔╝
14██║  ███╗██████╔╝█████╗  ██████╔╝██████╔╝ ╚████╔╝ 
15██║   ██║██╔══██╗██╔══╝  ██╔═══╝ ██╔═══╝   ╚██╔╝  
16╚██████╔╝██║  ██║███████╗██║     ██║        ██║   
17 ╚═════╝ ╚═╝  ╚═╝╚══════╝╚═╝     ╚═╝        ╚═╝   
18
19Sub-millisecond semantic code search powered by BM25 + AI reranking.
20
21QUICK START:
22    1. greppy index           Index your codebase (one-time setup)
23    2. greppy login           Authenticate with Claude or Gemini (optional)
24    3. greppy search <query>  Search your code!
25
26SEARCH MODES:
27    greppy search "query"     Semantic search - AI reranks BM25 results
28    greppy search -d "query"  Direct search - BM25 only (no AI, faster)
29
30DAEMON (optional, for faster searches):
31    greppy start              Start background daemon with file watcher
32    greppy stop               Stop the daemon
33    greppy status             Check if daemon is running
34
35AUTHENTICATION:
36    greppy login              Authenticate with Claude or Gemini via OAuth
37    greppy logout             Remove stored credentials
38
39    Semantic search uses AI to rerank results by relevance. Without login,
40    searches fall back to direct BM25 mode automatically.
41
42EXAMPLES:
43    greppy index                      Index current directory
44    greppy search "error handling"    Find error handling code
45    greppy search -d "TODO" -n 50     Find all TODOs (direct mode)
46    greppy search "auth" --json       JSON output for scripting
47"#;
48
49/// Sub-millisecond semantic code search
50#[derive(Parser, Debug)]
51#[command(name = "greppy")]
52#[command(author, version)]
53#[command(about = "Sub-millisecond semantic code search")]
54#[command(long_about = LONG_ABOUT)]
55#[command(propagate_version = true)]
56pub struct Cli {
57    #[command(subcommand)]
58    pub command: Commands,
59}
60
61#[derive(Subcommand, Debug)]
62pub enum Commands {
63    /// Search for code (semantic by default, -d for direct BM25)
64    #[command(visible_alias = "s")]
65    Search(SearchArgs),
66
67    /// Index a project for searching
68    #[command(visible_alias = "i")]
69    Index(IndexArgs),
70
71    /// Start the background daemon
72    Start,
73
74    /// Stop the background daemon
75    Stop,
76
77    /// Check if the daemon is running
78    Status,
79
80    /// Authenticate with Claude or Gemini for AI-powered semantic search
81    #[command(after_help = "AUTHENTICATION:
82    Greppy uses OAuth to authenticate with AI providers. No API keys needed!
83    
84    1. Run 'greppy login'
85    2. Select your provider (Claude or Gemini) using arrow keys
86    3. Complete the OAuth flow in your browser
87    4. You're ready to use semantic search!
88
89PROVIDERS:
90    Claude (Anthropic) - Uses your Claude.ai account
91    Gemini (Google)    - Uses your Google account
92
93NOTES:
94    - Tokens are stored securely in your system keychain
95    - Free tier usage through OAuth (no API billing)
96    - Run 'greppy logout' to remove stored credentials")]
97    Login,
98
99    /// Remove stored credentials and log out from all providers
100    #[command(
101        after_help = "This removes all stored OAuth tokens from your system keychain.
102After logging out, semantic search will fall back to direct BM25 search.
103Run 'greppy login' to authenticate again."
104    )]
105    Logout,
106}
107
108/// Arguments for the search command
109#[derive(Parser, Debug)]
110#[command(after_help = "EXAMPLES:
111    greppy search \"authentication\"       Semantic search (AI)
112    greppy search -d \"authentication\"    Direct BM25 search
113    greppy search \"error\" -n 10          Limit results
114    greppy search \"query\" --json         JSON output")]
115pub struct SearchArgs {
116    /// Search query
117    pub query: String,
118
119    /// Direct mode (BM25 only, no AI)
120    #[arg(short = 'd', long)]
121    pub direct: bool,
122
123    /// Max results
124    #[arg(short = 'n', long, default_value = "20")]
125    pub limit: usize,
126
127    /// JSON output
128    #[arg(long)]
129    pub json: bool,
130
131    /// Project path (default: current directory)
132    #[arg(short, long)]
133    pub project: Option<PathBuf>,
134}
135
136/// Arguments for the index command
137#[derive(Parser, Debug)]
138#[command(after_help = "EXAMPLES:
139    greppy index              Index current directory
140    greppy index -p ~/code    Index specific directory
141    greppy index --force      Force full re-index")]
142pub struct IndexArgs {
143    /// Project path (default: current directory)
144    #[arg(short, long)]
145    pub project: Option<PathBuf>,
146
147    /// Force full re-index
148    #[arg(short, long)]
149    pub force: bool,
150}
151
152/// Output format options
153#[derive(Debug, Clone, Copy, PartialEq, Eq)]
154pub enum OutputFormat {
155    Human,
156    Json,
157}