use anyhow::Result; use clap::Parser; use std::path::PathBuf; mod chunk; mod config; mod crawler; mod extract; mod heuristic; mod llm; mod pipeline; mod redact; mod synth; #[derive(Parser, Debug)] #[command(name = "profileme", version, about = "Local-only filesystem profiler")] struct Cli { /// Roots to scan (default: home directory) #[arg(long, value_name = "PATH", action = clap::ArgAction::Append)] root: Vec, /// Output profile markdown #[arg(long, default_value = "profile.md")] out: PathBuf, /// Working / checkpoint directory #[arg(long, default_value = ".profileme")] workdir: PathBuf, /// Local LLM base URL (OpenAI-compatible) #[arg(long, default_value = "http://localhost:8085/v1")] model_url: String, /// Model id to request #[arg(long, default_value = "Qwen3.8-27B-AD-IQ3_S.gguf")] model: String, /// Skip files larger than this many bytes #[arg(long, default_value_t = 2_000_000)] max_file_bytes: u64, /// Cap number of files processed (0 = unlimited) #[arg(long, default_value_t = 0)] max_files: usize, /// Parallel LLM calls #[arg(long, default_value_t = 2)] concurrency: usize, /// List candidate files and exit #[arg(long)] dry_run: bool, /// Skip already-processed files #[arg(long)] resume: bool, /// OCR images with tesseract #[arg(long)] ocr: bool, /// Include hidden files/directories #[arg(long)] include_hidden: bool, /// Extra directory names to exclude #[arg(long, action = clap::ArgAction::Append)] exclude: Vec, /// Disable redaction (NOT recommended) #[arg(long)] no_redact: bool, /// Skip collecting installed applications #[arg(long)] no_apps: bool, /// Include source code files (default: skipped; code is poor for personality profiling) #[arg(long)] include_code: bool, /// Only extract text, skip LLM #[arg(long)] extract_only: bool, /// Run without an LLM: use heuristic extraction instead #[arg(long)] no_llm: bool, /// Verbose logging #[arg(short, long)] verbose: bool, } #[tokio::main] async fn main() -> Result<()> { let cli = Cli::parse(); let filter = tracing_subscriber::EnvFilter::try_from_default_env() .unwrap_or_else(|_| { if cli.verbose { tracing_subscriber::EnvFilter::new("debug") } else { tracing_subscriber::EnvFilter::new("info") } }); tracing_subscriber::fmt().with_env_filter(filter).init(); let cfg = config::Config::from_cli(&cli)?; pipeline::run(cfg).await }