Metadata-Version: 2.4
Name: filemerger-cli
Version: 0.4.0
Summary: Developer CLI tool to consolidate project files into a single, AI-ready output
Author: BinaryFleet
License: MIT
Project-URL: Homepage, https://github.com/binaryfleet/filemerger
Project-URL: Repository, https://github.com/binaryfleet/filemerger
Project-URL: Issues, https://github.com/binaryfleet/filemerger/issues
Keywords: cli,developer-tools,file-merger,llm,ai-context,code-review
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pathspec>=0.11
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.1; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Dynamic: license-file

# FileMerger

[![Python](https://img.shields.io/pypi/pyversions/filemerger-cli)](https://pypi.org/project/filemerger-cli/)
[![PyPI](https://img.shields.io/pypi/v/filemerger-cli)](https://pypi.org/project/filemerger-cli/)
[![Downloads](https://static.pepy.tech/badge/filemerger-cli)](https://pepy.tech/project/filemerger-cli)
[![Build](https://github.com/codefleetx/filemerger/actions/workflows/tests.yml/badge.svg)](https://github.com/codefleetx/filemerger/actions/workflows/tests.yml)
[![Coverage](https://img.shields.io/codecov/c/github/codefleetx/filemerger)](https://codecov.io/gh/codefleetx/filemerger)
[![License](https://img.shields.io/github/license/codefleetx/filemerger)](LICENSE)
[![GitHub Release](https://img.shields.io/github/v/release/codefleetx/filemerger)](https://github.com/codefleetx/filemerger/releases)
[![GitHub Stars](https://img.shields.io/github/stars/codefleetx/filemerger?style=social)](https://github.com/codefleetx/filemerger/stargazers)

A developer-focused CLI that consolidates project files into a single AI-ready context document for LLMs.

Maintained by [DjangoPlay](https://djangoplay.org).

---
**FileMerger** is a developer-focused CLI tool that consolidates project
files into a single, **AI-ready** text output. It's built to be read by a
model, not a human — the goal is to give an AI an accurate, low-noise,
structurally-aware picture of "the underlying implementation" of a codebase
or a slice of one.

It helps you:

- Feed complete, structured code context to AI tools (ChatGPT, Gemini, Grok, Claude, etc.)
- Target files/directories by **name** across multiple source roots, without hand-writing paths
- Keep secrets out of what you paste into a chat window
- Produce deterministic, git-ignore-aware snapshots for review or audit

---

# Installation

```bash
pip install filemerger-cli
```

---

# Basic Usage

Merge a directory:

```bash
filemerger src/
```

Merge from multiple named sources, targeting by directory/file name, skipping others:

```bash
filemerger --source app api --target views/ models.py --skip migrations/ __pycache__/
```

Stream Markdown straight to stdout (e.g. to pipe into a clipboard tool):

```bash
filemerger src/ --format markdown --stdout | pbcopy
```

Dry run (no file written):

```bash
filemerger . --dry-run
```

# Advanced Usage
## Default Output

Merge the current directory using the default output format with common filtering, limits, and statistics.

```bash
filemerger . --source . --skip __pycache__/ node_modules/ .git/ --output merged --no-tree --separator 80 --include Dockerfile "*.env.example" --exclude "*.min.js" "*.map" --allow-dir migrations,tests --allow-file .DS_Store --allow-ext .yaml,.yml,.toml --max-size 25 --follow-symlinks --sort path --max-lines-per-file 1000 --max-tokens 200000 --stats --verbose
```

## Markdown Output

Merge the current directory and generate Markdown output.

```bash
filemerger . --source . --skip __pycache__/ node_modules/ .git/ --output merged --format markdown --no-tree --include Dockerfile "*.env.example" --exclude "*.min.js" "*.map" --allow-dir migrations,tests --allow-file .DS_Store --allow-ext .yaml,.yml,.toml --max-size 25 --follow-symlinks --sort path --max-lines-per-file 1000 --max-tokens 200000 --stats --verbose
```

## LLM Output

Merge the current directory using the LLM-optimized output format.

```bash
filemerger . --source . --skip __pycache__/ node_modules/ .git/ --output merged --llm --no-tree --include Dockerfile "*.env.example" --exclude "*.min.js" "*.map" --allow-dir migrations,tests --allow-file .DS_Store --allow-ext .yaml,.yml,.toml --max-size 25 --follow-symlinks --sort path --max-lines-per-file 1000 --max-tokens 200000 --stats --verbose
```

## Compact LLM Output

Merge the current directory using the compact LLM output format.

```bash
filemerger . --source . --skip __pycache__/ node_modules/ .git/ --output merged --llm-compact --no-tree --include Dockerfile "*.env.example" --exclude "*.min.js" "*.map" --allow-dir migrations,tests --allow-file .DS_Store --allow-ext .yaml,.yml,.toml --max-size 25 --follow-symlinks --sort path --max-lines-per-file 1000 --max-tokens 200000 --stats --verbose
```

## AI Markers Output

Merge the current directory using AI-friendly file boundary markers.

```bash
filemerger . --source . --skip __pycache__/ node_modules/ .git/ --output merged --ai-markers --no-tree --include Dockerfile "*.env.example" --exclude "*.min.js" "*.map" --allow-dir migrations,tests --allow-file .DS_Store --allow-ext .yaml,.yml,.toml --max-size 25 --follow-symlinks --sort path --max-lines-per-file 1000 --max-tokens 200000 --stats --verbose
```

## JSON Output

Merge the current directory and generate JSON output.

```bash
filemerger . --source . --skip __pycache__/ node_modules/ .git/ --output merged --format json --no-tree --include Dockerfile "*.env.example" --exclude "*.min.js" "*.map" --allow-dir migrations,tests --allow-file .DS_Store --allow-ext .yaml,.yml,.toml --max-size 25 --follow-symlinks --sort path --max-lines-per-file 1000 --max-tokens 200000 --stats --verbose
```

## Print to Standard Output

Merge the current directory and print Markdown output directly to the terminal.

```bash
filemerger . --source . --skip __pycache__/ node_modules/ .git/ --stdout --format markdown --no-tree --include Dockerfile "*.env.example" --exclude "*.min.js" "*.map" --allow-dir migrations,tests --allow-file .DS_Store --allow-ext .yaml,.yml,.toml --max-size 25 --follow-symlinks --sort path --max-lines-per-file 1000 --max-tokens 200000 --stats --verbose
```

## Dry Run

Preview which files would be merged without generating any output.

```bash
filemerger . --source . --skip __pycache__/ node_modules/ .git/ --format markdown --no-tree --include Dockerfile "*.env.example" --exclude "*.min.js" "*.map" --allow-dir migrations,tests --allow-file .DS_Store --allow-ext .yaml,.yml,.toml --max-size 25 --follow-symlinks --sort path --max-lines-per-file 1000 --max-tokens 200000 --dry-run --stats --verbose
```

## Without Secret Redaction

Merge the current directory while disabling automatic secret redaction.

```bash
filemerger . --source . --skip __pycache__/ node_modules/ .git/ --output merged --format markdown --no-tree --include Dockerfile "*.env.example" --exclude "*.min.js" "*.map" --allow-dir migrations,tests --allow-file .DS_Store --allow-ext .yaml,.yml,.toml --max-size 25 --follow-symlinks --sort path --no-redact-secrets --max-lines-per-file 1000 --max-tokens 200000 --stats --verbose
```

---

# Selecting Files

There are two ways to choose input, and they can be combined in one run.

## 1. Explicit paths (original behavior)

```bash
filemerger src/ utils/helpers.py
```

Any mix of files and directories.

## 2. Name/path targeting — `--source` / `--target` / `--skip`

For codebases where you want "every `views/` folder and every `models.py`
file under these roots, except migrations":

```bash
filemerger --source users apidocs/views help/forms \
           --target views/ models.py \
           --skip migrations/ __pycache__/
```

Matching rules (identical for `--target` and `--skip`):

| Entry form | Meaning |
|---|---|
| `views/` (trailing slash) | Directory **name**, matched anywhere under a `--source` root |
| `views/login.py` (contains `/`, no trailing slash) | An **exact relative path** from a `--source` root |
| `models.py` (no slash) | A bare **filename**, matched anywhere under a `--source` root |

If `--target` is omitted, every file under `--source` is a candidate
(subject to the usual filtering below).

This replaces the standalone `get_filemerger_paths.py` helper script —
its intent is now built directly into the main tool, with the directory
matching bug fixed (it previously never actually included directory
targets) and dependable pruning during the directory walk instead of
fragile path-prefix comparisons.

---

# Filtering

Applied to every candidate file, from either selection method:

- **Extensions** — allow-listed (`.py`, `.js`, `.ts`, `.json`, `.md`, …). Extend with `--allow-ext`, or force-include a specific file regardless of extension with `--include` (glob, e.g. `--include Dockerfile`).
- **`.gitignore`** — honored **per-directory**, the same way `git` does (a nested `.gitignore` only applies to its own subtree), plus an optional `.filemergerignore` with identical syntax.
- **Excluded directories/files** — `node_modules`, `__pycache__`, `.git`, `migrations`, `tests`, etc. by default. Restore one with `--allow-dir`/`--allow-file`; drop more with `--exclude` (glob).
- **Symlinks** — not followed by default. Opt in with `--follow-symlinks`.
- **Binary files** — detected via a null-byte heuristic (not just a failed extension check) and skipped, reported as such.
- **Max file size** — 2 MB default, override with `--max-size`.

---

# Safety

## Secret redaction (on by default)

Before anything is written, file content is scanned for common secret
shapes (AWS keys, generic `api_key=...`, bearer tokens, private key
blocks, Slack/GitHub tokens) and matches are replaced with
`[REDACTED:SECRET]`. Disable with `--no-redact-secrets` if you specifically
need raw content. The number of redactions appears in `--stats`.

## Context budgeting

```bash
filemerger . --stats --max-tokens 100000
```

`--stats` reports an approximate token count (character-based heuristic,
no extra dependency). `--max-tokens` warns and exits non-zero if the
merged output would exceed that budget — useful in scripts/CI before
piping into a model with a fixed context window.

## Per-file truncation

```bash
filemerger . --max-lines-per-file 400
```

Caps any single file's contributed lines, appending a `[truncated after N
lines]` marker, so one huge generated file can't dominate the output.

---

# Output Formats

Select with `--format`, or the older shorthand flags (kept for backward compatibility).

| `--format` | Shorthand flag | Best for |
|---|---|---|
| `default` | *(none)* | Human review, audits |
| `llm` | `--llm` / `--llm-compact` | Legacy structured plain-text for AI ingestion |
| `ai-markers` | `--ai-markers` | Explicit `<<<FILE>>>` boundary markers |
| `markdown` | — | **Recommended default for AI chat tools** — fenced code blocks, per-language syntax highlighting, renders cleanly |
| `json` | — | Programmatic consumption — a list of `{path, language, content, skipped, redactions, ...}` |

All formats (except `json`) are preceded by a directory-tree summary so the
model sees project shape before content. Disable with `--no-tree`.

```bash
filemerger src/ --format markdown
```

---

# Output Destination

By default, output is written to `filemerger-output.txt` (or `-o <name>`)
in the current directory. Use `--stdout` to stream to stdout instead
(status/stat lines go to stderr so stdout stays clean for piping):

```bash
filemerger src/ --format json --stdout > context.json
```

---

# Statistics

```bash
filemerger src/ --stats
```

Reports: files, lines, bytes, estimated tokens, skipped files (binary /
non-UTF8 / unreadable), and redacted-secret count.

---

# Ordering

```bash
filemerger src/ --sort {path,name,size,mtime}
```

Default is `path` (deterministic, matches prior versions).

---

# Configuration

Optional `.filemerger.toml`, discovered by searching **upward** from the
current directory to the filesystem root (git-style), so it works the same
whether you run `filemerger` from the project root or a subdirectory:

```toml
[filters]
max_file_size_mb = 1
exclude_dirs = ["tests"]

[output]
separator_length = 60
```

## Runtime Overrides

CLI flags always win over `.filemerger.toml`, which always wins over
built-in defaults:

```
CLI arguments → .filemerger.toml → config.py defaults
```

```bash
filemerger . \
  --allow-dir migrations,tests \
  --allow-ext .yaml \
  --allow-file .DS_Store \
  --max-size 5 \
  --separator 40
```

---

# Design Goals

- Deterministic output
- Minimal configuration
- AI-first formatting (Markdown/JSON as first-class formats, not afterthoughts)
- Safe by default (secrets redacted, binaries skipped, symlinks not followed)
- Predictable file ordering
- Zero project mutation

---

# License

This project is licensed under the **MIT License**. See [LICENSE](LICENSE).
