personal activity index (bluesky, leaflet, substack) pai.desertthunder.dev
rss bluesky
at main 139 lines 4.0 kB view raw
1use clap::{Parser, Subcommand}; 2use pai_core::SourceKind; 3use std::path::PathBuf; 4 5/// Personal Activity Index - POSIX-style CLI for content aggregation 6#[derive(Parser, Debug)] 7#[command(name = "pai")] 8#[command(version, about, long_about = None)] 9pub struct Cli { 10 /// Set configuration directory 11 #[arg(short = 'C', value_name = "DIR", global = true)] 12 pub config_dir: Option<PathBuf>, 13 14 /// Path to SQLite database file 15 #[arg(short = 'd', value_name = "PATH", global = true)] 16 pub db_path: Option<PathBuf>, 17 18 #[command(subcommand)] 19 pub command: Commands, 20} 21 22#[derive(Parser, Debug)] 23pub struct ExportOpts { 24 /// Filter by source kind 25 #[arg(short = 'k', value_name = "KIND")] 26 pub kind: Option<SourceKind>, 27 28 /// Filter by specific source ID 29 #[arg(short = 'S', value_name = "ID")] 30 pub source_id: Option<String>, 31 32 /// Maximum number of items 33 #[arg(short = 'n', value_name = "NUMBER")] 34 pub limit: Option<usize>, 35 36 /// Only items published at or after this time 37 #[arg(short = 's', value_name = "TIME")] 38 pub since: Option<String>, 39 40 /// Filter items by substring 41 #[arg(short = 'q', value_name = "PATTERN")] 42 pub query: Option<String>, 43 44 /// Output format 45 #[arg(short = 'f', value_name = "FORMAT", default_value = "json")] 46 pub format: String, 47 48 /// Output file (default: stdout) 49 #[arg(short = 'o', value_name = "FILE")] 50 pub output: Option<PathBuf>, 51} 52 53#[derive(Subcommand, Debug)] 54pub enum Commands { 55 /// Fetch and store content from configured sources 56 Sync { 57 /// Sync all configured sources (default) 58 #[arg(short = 'a')] 59 all: bool, 60 61 /// Sync only a particular source kind 62 #[arg(short = 'k', value_name = "KIND")] 63 kind: Option<SourceKind>, 64 65 /// Sync only a specific source instance 66 #[arg(short = 'S', value_name = "ID")] 67 source_id: Option<String>, 68 }, 69 70 /// Inspect stored items 71 List { 72 /// Filter by source kind 73 #[arg(short = 'k', value_name = "KIND")] 74 kind: Option<SourceKind>, 75 76 /// Filter by specific source ID 77 #[arg(short = 'S', value_name = "ID")] 78 source_id: Option<String>, 79 80 /// Maximum number of items to display 81 #[arg(short = 'n', value_name = "NUMBER", default_value = "20")] 82 limit: usize, 83 84 /// Only show items published at or after this time 85 #[arg(short = 's', value_name = "TIME")] 86 since: Option<String>, 87 88 /// Filter items by substring in title/summary 89 #[arg(short = 'q', value_name = "PATTERN")] 90 query: Option<String>, 91 }, 92 93 /// Produce feeds or export files 94 Export(ExportOpts), 95 96 /// Self-host HTTP API 97 Serve { 98 /// Address to bind HTTP server to 99 #[arg(short = 'a', value_name = "ADDRESS", default_value = "127.0.0.1:8080")] 100 address: String, 101 }, 102 103 /// Verify database schema and print statistics 104 DbCheck, 105 106 /// Initialize configuration file 107 Init { 108 /// Force overwrite existing config 109 #[arg(short = 'f')] 110 force: bool, 111 }, 112 113 /// Generate or install the pai(1) manpage 114 Man { 115 /// Output file (default: stdout) 116 #[arg(short = 'o', value_name = "FILE")] 117 output: Option<PathBuf>, 118 119 /// Install into a manpath directory (defaults to ~/.local/share/man if unset) 120 #[arg(long)] 121 install: bool, 122 123 /// Custom directory for --install (e.g., /usr/local/share/man) 124 #[arg(long, value_name = "DIR")] 125 install_dir: Option<PathBuf>, 126 }, 127 128 /// Initialize Cloudflare Worker deployment scaffolding 129 #[command(name = "cf-init")] 130 CfInit { 131 /// Output directory for scaffolding (default: current directory) 132 #[arg(short = 'o', value_name = "DIR")] 133 output_dir: Option<PathBuf>, 134 135 /// Dry run - show what would be created without writing files 136 #[arg(long)] 137 dry_run: bool, 138 }, 139}