repo-flatten 0.2.1

A utility to flatten all files in the repository into a single file, consumed by LLMs. Will ignore .gitignore and hidden files.
//! A utility to flatten all files from a repo into a single text file.
//! This tool is useful for creating a single-file to feed into language models.

mod cli;
mod path_filter;
mod repository;
mod writer;

use anyhow::Result;
use tracing::{error, info, info_span};

fn main() -> Result<()> {
    // Initialize tracing subscriber for console output
    tracing_subscriber::fmt::init();

    let main_span = info_span!("flatten.main");
    let _guard = main_span.enter();

    info!("starting repository flattening");

    match run() {
        Ok(_) => {
            info!("repository flattening completed successfully");
            Ok(())
        }
        Err(e) => {
            error!(error=%e, "repository flattening failed");
            Err(e)
        }
    }
}

fn run() -> Result<()> {
    let span = info_span!("flatten.run");
    let _guard = span.enter();

    // Parse command line arguments
    let args = cli::parse_args();
    info!(repo_path=%args.repo.display(), output_path=%args.output.display(), "parsed cli arguments");

    // Discover and open the repository
    let repo_context = repository::discover_repository(&args.repo)?;
    info!(repo_root=%repo_context.root.display(), "repository discovered");

    // Get the current working directory info
    let wd_info = repository::get_working_dir_info(&repo_context.repo)?;
    info!(branch=%wd_info.branch_name, status=%wd_info.status_summary, "working directory analyzed");

    // Resolve and normalize filter paths
    let filter_paths = path_filter::resolve_filter_paths(&args.path, &repo_context.root)?;
    if !filter_paths.is_empty() {
        info!(paths=?filter_paths.iter().map(|p| p.display().to_string()).collect::<Vec<_>>(), "path filters applied");
    }

    // Create the output writer
    let mut output_writer = writer::create_output_writer(&args.output)?;
    info!(output_file=%args.output.display(), "output writer created");

    // Walk the working directory and write files
    let file_count = repository::walk_and_write_working_dir(
        &repo_context.repo,
        &filter_paths,
        &mut output_writer,
    )?;

    info!(
        files_processed = file_count,
        "working directory walking completed"
    );

    // Finalize the output
    writer::finalize_output(output_writer)?;
    info!("output finalized");

    println!(
        "\n✅ Success! Working directory content flattened to: {} (branch: {}, {})",
        args.output.display(),
        wd_info.branch_name,
        wd_info.status_summary
    );

    Ok(())
}