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<PathBuf>,
/// 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<String>,
/// 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
}