profileme / src/main.rs

raw file 2690 bytes
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
}