Metadata-Version: 2.4
Name: warpclean
Version: 0.2.1
Summary: WARPCLEAN - A CLI tool to organize your files at Warp Speed
Author-email: Srimoneyshankar Ajith <moneytosms@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/moneytosms/warpclean
Project-URL: Repository, https://github.com/moneytosms/warpclean
Project-URL: Issues, https://github.com/moneytosms/warpclean/issues
Project-URL: Changelog, https://github.com/moneytosms/warpclean/releases
Keywords: cli,files,organize,filesystem,downloads,cleanup
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Utilities
Classifier: Topic :: System :: Filesystems
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: rich>=10.0.0
Requires-Dist: python-magic>=0.4.27; sys_platform != "win32"
Requires-Dist: python-magic-bin>=0.4.14; sys_platform == "win32"
Dynamic: license-file

# WARPCLEAN

[![CI](https://github.com/moneytosms/warpclean/actions/workflows/ci.yml/badge.svg)](https://github.com/moneytosms/warpclean/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/warpclean.svg)](https://pypi.org/project/warpclean/)
[![Python](https://img.shields.io/pypi/pyversions/warpclean.svg)](https://pypi.org/project/warpclean/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)

## Organize Your Files at Warp Speed

```bash
pip install warpclean
```

WARPCLEAN is a deterministic, rule-based Python CLI for organizing files. It is built for speed, safety, and reversibility. No machine learning. No unpredictable heuristics. Just a fast, reliable pipeline that does exactly what you expect.

Point it at any directory. Preview what will happen. Execute when ready. Undo if needed.

---

## The Problem

Your Downloads folder is a disaster. Your Desktop is cluttered. Your photo library is a mess of `IMG_0001.jpg` duplicates scattered across five folders.

You need to organize, but:

- You don't want to lose files
- You don't want to spend hours doing it manually
- You don't trust tools that move things without showing you first
- You need a way to undo if something goes wrong

---

## The Solution

WARPCLEAN gives you complete control:

| Feature                   | What It Does                                            |
| ------------------------- | ------------------------------------------------------- |
| **Dry Run**               | See exactly what will happen before any file is touched |
| **Undo System**           | Every operation is logged and fully reversible          |
| **Copy Mode**             | Organize into a new folder without moving originals     |
| **Warp Drive Mode**       | Skip deep content analysis for maximum speed            |
| **Duplicate Detection**   | Identify and skip duplicate files automatically         |
| **Date Organization**     | Sort photos and videos by year, month, and day          |
| **Related File Grouping** | Keep sequences and versions together                    |
| **Progress Tracking**     | Visual progress bars for large operations               |
| **Depth Control**         | Limit recursion with `--depth N`                        |
| **Exclude Patterns**      | Skip files/dirs via `--exclude`, `--exclude-file`, or `.warpcleanignore` |
| **Confirmation Prompt**   | Real runs summarize the plan and ask before touching anything |
| **Config File**           | Per-user and per-directory `.toml` defaults and custom categories |
| **Run Statistics**        | `--stats` prints counts, bytes, per-category breakdown, elapsed time |
| **Idempotent**            | A second run on an organized directory does nothing at all      |

---

## Installation

**Requirements:** Python 3.11 or newer (the config loader uses the stdlib `tomllib` module)

```bash
pip install warpclean
```

Once installed, the `warpclean` command is available globally in your terminal. You can also check what you have:

```bash
warpclean --version
```

### Development Setup

See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, tests, lint, and the module layout.

### Bundled Dependencies

These are installed automatically. You do not need to add them yourself.

| Package        | Purpose                                                      |
| -------------- | ------------------------------------------------------------ |
| `rich`         | Colored terminal output, formatted tables, and progress bars |
| `python-magic` | Deep MIME-type detection using file content signatures       |

On Windows, `python-magic-bin` is installed instead of `python-magic`. If either import fails at runtime, WARPCLEAN degrades gracefully: output falls back to plain text, and classification falls back to file extensions.

---

## Quick Start

### Preview Before You Organize

Run a dry run to see what WARPCLEAN would do without touching any files:

```bash
warpclean ~/Downloads --dry-run
```

This executes the full classification and planning pipeline, then displays a complete report of all proposed moves. Nothing is changed on disk.

### Organize For Real

When you are ready:

```bash
warpclean ~/Downloads
```

WARPCLEAN builds the plan, prints how many files land in which folder, and asks:

```
About to move 42 file(s) into /home/you/Downloads:
  Pictures: 21 file(s)
  Documents: 14 file(s)
  Archives: 7 file(s)

Proceed? [y/N]
```

Anything other than `y`/`yes` aborts without touching a file. Pass `--yes` (or `-y`) to skip the prompt. See [Confirmation Prompt](#confirmation-prompt) for the scripting rules.

Once confirmed, files are moved into structured category folders. Every operation is logged for undo.

### Keep Your Originals

If you want to organize without moving the source files:

```bash
warpclean ~/Downloads --copy
```

This creates a `warpclean/` subdirectory containing the organized structure. Your original files remain exactly where they were.

---

## How It Works

WARPCLEAN runs a strict six-stage pipeline:

```
SCAN  >>>  CLASSIFY  >>>  PLAN  >>>  CONFIRM  >>>  EXECUTE  >>>  LOG
```

### Stage 1: Scan

Recursively discovers all files in the target directory. Hidden files and system files are respected. Symbolic links are handled safely. A top-level directory named `warpclean` is always skipped, which is what makes `--copy` idempotent.

### Stage 2: Classify

Each file is analyzed to determine its type. Classification uses:

1. **MIME type detection** (preferred, uses file content signatures)
2. **File extension** (fallback when MIME detection is unavailable)
3. **Explicit category rules** (for special file types like installers)

In Warp Drive Mode (`--fast`), content analysis is skipped and extensions are trusted directly.

### Stage 3: Plan

A complete operation plan is built before any changes occur. The plan includes:

- Source and destination paths for every file
- Skip decisions for files already in their correct locations
- Collision resolution (automatic renaming if a *different* file already holds the destination name)

The identity check runs before collision resolution, which is what makes WARPCLEAN idempotent. See [Idempotency](#idempotency).

### Stage 4: Confirm

On a real run, the operation count and a per-folder breakdown are printed and you are asked to confirm. Dry runs skip this stage entirely. `--yes` skips it, and it is skipped automatically when stdin is a genuine pipe or redirect. If the prompt is shown and the read hits end-of-input, the run aborts. See [Confirmation Prompt](#confirmation-prompt).

### Stage 5: Execute

Moves or copies are performed file by file. If an individual operation fails (e.g. a permission error), it is logged with an `error` status and the pipeline continues with the remaining files rather than aborting.

### Stage 6: Log

Every successful operation is recorded to `.warpclean_undo.jsonl` in the target directory. The log is written incrementally, one line per file, as each operation completes. Pressing Ctrl+C mid-run therefore still leaves a complete, reversible record of everything that actually moved.

---

## Organization Categories

Files are sorted into these default categories:

| Category      | File Types                                        |
| ------------- | ------------------------------------------------- |
| `Pictures/`   | JPEG, PNG, GIF, WebP, SVG, RAW formats, PSD, HEIC |
| `Videos/`     | MP4, MKV, AVI, MOV, WebM, FLV, WMV                |
| `Audio/`      | MP3, FLAC, WAV, AAC, OGG, M4A, AIFF               |
| `Documents/`  | PDF, DOCX, XLSX, PPTX, TXT, MD, ODT, EPUB         |
| `Archives/`   | ZIP, RAR, 7Z, TAR, GZ, BZ2, XZ                    |
| `Installers/` | EXE, MSI, DMG, DEB, RPM, AppImage                 |
| `Misc/`       | Everything else                                   |

Classification is deterministic. The same file will always be placed in the same category.

You can add your own categories, or steal extensions away from the built-ins, with a [config file](#config-file).

---

## Feature Reference

### Dry Run Mode

```bash
warpclean ~/Downloads --dry-run
```

Simulates the entire organization process without modifying any files. Displays a detailed table showing:

- Source file name
- Action (move/copy direction)
- Destination path

This is the recommended first step for any new directory.

### Tree View

```bash
warpclean ~/Downloads --dry-run --tree
```

Displays dry run results as a visual directory tree instead of a table. Useful for understanding the final folder structure before committing.

### Copy Mode

```bash
warpclean ~/Downloads --copy
```

Instead of moving files, creates organized copies in a `warpclean/` subdirectory:

```
~/Downloads/
├── original_file.pdf           # untouched
├── another_file.jpg            # untouched
└── warpclean/
    ├── Documents/
    │   └── original_file.pdf   # organized copy
    └── Pictures/
        └── another_file.jpg    # organized copy
```

Perfect for organizing without risk, or for creating a parallel organized structure.

**Copy mode is idempotent.** The scanner always skips a top-level directory named `warpclean`, so running `--copy` twice does not produce `warpclean/warpclean/`. The second run only sees files that are still loose in the target directory.

**Caveat:** that skip is unconditional and name-based. If you already have your own folder named `warpclean` at the top level of the target directory, its contents will never be scanned or organized, with or without `--copy`. Rename it, or point WARPCLEAN somewhere else.

### Warp Drive Mode

```bash
warpclean ~/Downloads --fast
```

Skips content-based MIME detection and trusts file extensions directly. This dramatically increases throughput for large directories.

**Use when:**

- Processing thousands of files
- Extensions are reliable
- Speed is more important than deep content inspection

**Avoid when:**

- Files have incorrect or missing extensions
- You need precise content-based classification

### Date-Based Organization

```bash
warpclean ~/Photos --date-based
```

Organizes images and videos into a date-based folder hierarchy:

```
Pictures/
└── 2024/
    └── 01/
        └── 15/
            ├── IMG_0001.jpg
            └── IMG_0002.jpg
```

Uses file modification time to determine dates. Ideal for camera dumps, screenshots, and media archives.

Date organization keys off the file's **media type**, not the folder name. A file classified as image or video gets `YYYY/MM/DD` subfolders whether it landed in a built-in folder or in a custom `[categories]` folder. Everything else stays flat. Files with no usable timestamp fall back to the flat folder. See [Config File](#config-file).

### Duplicate Detection

```bash
warpclean ~/Files --detect-duplicates
```

Detects duplicate files using a two-stage process:

1. **Size filtering:** Files with unique sizes are immediately cleared
2. **MD5 hashing:** Files with matching sizes are hashed and compared

Behavior:

- First occurrence is organized normally
- Subsequent duplicates are skipped
- No files are deleted automatically
- Duplicate count is reported at the end

### Related File Grouping

```bash
warpclean ~/Projects --group-related
```

Identifies and groups files that belong together:

| Pattern            | Example                                                 |
| ------------------ | ------------------------------------------------------- |
| Numbered sequences | `img_001.jpg`, `img_002.jpg`, `img_003.jpg`             |
| Versioned files    | `report_v1.docx`, `report_v2.docx`, `report_final.docx` |
| Sidecar files      | `photo.jpg`, `photo.xmp`, `photo.jpg.json`              |

Grouped files are placed together in a collection folder to prevent separation.

### Progress Bars

```bash
warpclean ~/Downloads --progress
```

Displays visual progress bars during scanning, classification, and execution.

Shows:

- Current operation
- Files processed / total files
- Elapsed time
- Estimated time remaining

Progress bars stay opt-in, and they additionally require a real terminal. When stdout is piped, redirected, or running under CI, `--progress` is silently ignored so log files do not fill with animation frames.

### Depth Control

```bash
warpclean ~/Downloads --depth 0
```

Limits how deep WARPCLEAN scans into subdirectories:

| Value       | Behavior                                      |
| ----------- | --------------------------------------------- |
| `--depth 0` | Only files in the root directory (no subdirs) |
| `--depth 1` | Root + immediate subdirectories               |
| `--depth 2` | Up to 2 levels deep                           |
| (default)   | Unlimited depth (scan everything)             |

**Use when:**

- You only want to organize files at the top level
- You want to avoid touching deeply nested project folders
- You need fine control over which directories are processed

Example: Organize only files directly in Downloads, ignoring subfolders:

```bash
warpclean ~/Downloads --depth 0 --dry-run
```

### Exclude Patterns

```bash
warpclean ~/Downloads --exclude node_modules --exclude "*.tmp"
```

Skips files and directories matching gitignore-lite patterns. Patterns come from three sources, merged together:

| Source                 | How                                                          |
| ----------------------- | ------------------------------------------------------------ |
| `--exclude PATTERN`     | Repeatable flag, one pattern per use                         |
| `--exclude-file PATH`   | A file with one pattern per line                             |
| `.warpcleanignore`      | Auto-discovered in the target directory, no flag needed      |

Pattern syntax (gitignore-lite, **no negation / `!` support**):

| Pattern       | Behavior                                      |
| ------------- | ---------------------------------------------- |
| `# comment`   | Ignored, as are blank lines                    |
| `node_modules`| No `/` — matches this basename anywhere        |
| `build/`      | Trailing `/` — matches directories only        |
| `src/tmp`     | Contains `/` — matches against the path relative to the scan root |

Example `.warpcleanignore`:

```
# build artifacts
node_modules
*.tmp
dist/
```

**Use when:**

- You want to skip version control or dependency folders
- You have temp/cache files that shouldn't be organized
- You want a reusable, per-directory ignore file instead of repeating flags

### Config File

WARPCLEAN reads TOML config files so you do not have to retype the same flags. Discovery order, **later wins**:

| Order | Location                             | Scope                        |
| ----- | ------------------------------------ | ---------------------------- |
| 1     | `~/.config/warpclean/config.toml`    | Per-user, applies everywhere |
| 2     | `.warpclean.toml` in the target directory | Per-directory           |
| 3     | Explicit CLI flags                   | Always win                   |

A flag you actually typed always beats both files. A flag you did not type falls back to the config, then to the built-in default.

```toml
[defaults]
progress = true
depth = 1
detect_duplicates = true

[categories]
Pictures = [".jpg", ".png", ".heic"]
Code = [".py", ".rs", ".go"]
```

**`[defaults]`** is an **allowlist** of run-shaping flags, spelled as long-form flag names with dashes turned into underscores. Exactly these 15 keys are accepted:

`group_related`, `fast`, `clean_empty_dirs`, `copy`, `detect_duplicates`, `date_based`, `progress`, `verbose`, `color`, `no_color`, `tree`, `depth`, `exclude`, `exclude_file`, `stats`

Booleans take `true`/`false`, `depth` takes an integer, `exclude` takes a string or a list of strings.

Six real flags are **refused** from a config file, each with a warning naming the key and the reason: `dry_run`, `undo`, `yes`, `no_config`, `help`, `version`. The reasoning is that a config file must not be able to change what a command *is*. `dry_run = true` would silently neuter every run in that directory so nothing would ever actually be organized; `yes = true` would disable the confirmation prompt for a tool that moves files; `undo` is a one-off recovery command, not a persistent default; `no_config` cannot ask for config files to be ignored; `help` and `version` are not settings. Pass those on the command line instead.

**`[categories]`** adds to or overrides the extension-to-folder mapping. Each key is a destination folder name, each value is a list of extensions (the leading dot is optional and case is ignored). An extension listed here beats whatever built-in rule would otherwise claim it. Extensions you do not list keep their built-in behavior completely.

Custom categories participate in `--date-based` on the same terms as the built-ins. Date organization is decided by the file's media type, not by the folder name:

| Config entry            | Without `--date-based` | With `--date-based`           |
| ----------------------- | ---------------------- | ----------------------------- |
| `Photos = [".png"]`     | `Photos/x.png`         | `Photos/2026/08/09/x.png`     |
| `Code = [".py"]`        | `Code/x.py`            | `Code/x.py` (not media, flat) |

This is the same rule the built-ins follow: `Pictures/` and `Videos/` gain date subfolders, `Documents/` stays flat.

Error handling:

| Situation                        | Behavior                                            |
| -------------------------------- | --------------------------------------------------- |
| Refused key in `[defaults]`      | Warning naming the key and why, key ignored, run continues |
| Unknown key in `[defaults]`      | Warning printed, key ignored, run continues         |
| Malformed TOML, or unreadable file | Error printed, exits with code 2                   |
| No config files present          | Silently uses built-in defaults                     |

To ignore every config file for a single run:

```bash
warpclean ~/Downloads --no-config
```

### Colored Output

Color is automatic. Rich output with formatted tables is **on by default when stdout is a terminal**, and **off when output is piped, redirected, or running in CI**. You do not need a flag for the common case.

Two flags override the detection:

| Flag         | Effect                                                                       |
| ------------ | ---------------------------------------------------------------------------- |
| `--no-color` | Force color off, even on a terminal                                          |
| `--color`    | Force color on, even when not a terminal (useful when piping into a pager)   |

```bash
warpclean ~/Downloads --no-color        # plain text on a terminal
warpclean ~/Downloads --color | less -R # keep color through a pipe
```

If both are passed, `--no-color` wins.

### Confirmation Prompt

A real (non-dry-run) run summarizes the plan and asks `Proceed? [y/N]` before moving anything. Only `y` or `yes` proceeds; anything else aborts with exit code 1 and no files touched.

```bash
warpclean ~/Downloads --yes    # skip the prompt
warpclean ~/Downloads -y       # same
```

The decision is made in this order:

| Order | Situation                                              | Result                                                     |
| ----- | ------------------------------------------------------ | ---------------------------------------------------------- |
| 1     | `--yes` / `-y` was passed                              | Proceeds. Nothing is read from stdin at all.               |
| 2     | stdin is a genuine pipe or redirect (not a terminal)   | Proceeds, and logs that it did.                            |
| 3     | The prompt was shown and the read hit end-of-input     | **Aborts.** Exit code 1, no files touched.                 |

Case 3 is a deliberate refusal, and it changed: an end-of-input read used to be treated as consent. This tool moves files, and an ambiguous read is not consent. It shows up on stdin that *looks* interactive but yields nothing, such as an inherited Windows `NUL` handle that reports `isatty()` as true. You get an explicit message rather than a silent mass move:

```
No answer could be read from stdin (end of input).
Refusing to proceed: this tool moves files, so an ambiguous read is not consent.
Pass --yes for an unattended run.
```

**If you automate warpclean, pass `--yes` explicitly.** Do not rely on stdin detection to infer it for you.

> **Upgrading from 0.1.x?** This is the one behavior change that will surprise you. The same command you ran last week now stops and asks. Add `--yes` to restore the old behavior.

### Version

```bash
warpclean --version
```

Prints the installed version and exits. It works without a path argument.

### Verbose Logging

```bash
warpclean ~/Downloads --verbose
```

Enables detailed debug output. Shows:

- Every file discovered during scan
- Classification decisions and reasoning
- Plan generation details
- Individual operation results

### Empty Directory Cleanup

```bash
warpclean ~/Downloads --clean-empty-dirs
```

After organization (or undo), recursively removes any empty directories left behind. Only removes directories that are completely empty.

### Run Statistics

```bash
warpclean ~/Downloads --stats
```

Prints a summary block after the run: files scanned, planned, moved (or copied), skipped, errors, duplicates skipped when `--detect-duplicates` is on, a per-category breakdown with file counts and byte totals, the total bytes in human units, and elapsed wall-clock time.

```
RUN SUMMARY
  Files scanned:      6
  Files planned:      6
  Files moved:        6
  Files skipped:      0
  Errors:             0
  Bytes moved:        308 B
  Elapsed:            0.04s

== Per-category breakdown =
   Folder  | Files |  Size
---------------------------
Documents  |3      |54 B
Pictures   |2      |240 B
Archives   |1      |14 B
===========================
```

It works on dry runs too, where every count is what **would** have happened and the block says so:

```
RUN SUMMARY (DRY RUN - nothing was written; counts are what WOULD happen)
  Files scanned:      6
  Files planned:      6
  Files that would be moved: 6
  Files skipped:      0
  Errors:             0
  Bytes that would be moved: 308 B
  Elapsed:            0.04s
```

The per-category table follows it unchanged in shape.

When nothing was organized, the breakdown states so explicitly rather than printing nothing:

```
  Per-category breakdown: none (no files were organized).
```

Settable from a config file as `stats = true`.

### Idempotency

Running WARPCLEAN twice on the same directory is a no-op the second time:

```
$ warpclean ~/Downloads --yes
Done. 6 file(s) moved successfully.

$ warpclean ~/Downloads --yes
Found 6 files.
Classifying...
Planning moves...
No moves necessary. Everything is clean!
```

A file already sitting in its correct category folder is recognized as already placed and dropped from the plan before collision resolution ever looks at it.

> **Fixed in 0.2.0.** Every 0.1.x release had this backwards: the source-equals-destination check ran *after* collision resolution, so an already-organized file collided with itself and was renamed. A second `warpclean ~/Downloads` renamed every organized file to `name_1.ext`, a third to `name_1_1.ext`, and so on. If you are on 0.1.x, upgrade; if a past run left `_1`-suffixed files behind, `--undo` will reverse them.

---

## Undo System

Every operation batch is logged to `.warpclean_undo.jsonl` in the target directory.

### List Batches

```bash
warpclean ~/Downloads --undo --list-batches
```

Lists what is in the undo log without reversing anything: the `N` you would pass to `--undo N`, the batch timestamp, its operation count, and whether the batch is complete or was interrupted.

```
2 batch(es) in C:\...\demo\.warpclean_undo.jsonl (newest first):

  N   TIMESTAMP                    OPS   STATE
  1   2026-08-09T07:30:40.646463   1     complete
  2   2026-08-09T07:30:34.235895   6     complete

Pass the N above to --undo N to reverse that many of the newest batches (--undo 0 reverses all).
```

A missing log, an empty log, and a log with no batch markers each get their own message rather than silence.

`--list-batches` is only a modifier of `--undo`. Passing it on its own is an error and exits with code 2:

```
[ERROR] --list-batches only works together with --undo. Try: warpclean ~/Downloads --undo --list-batches
```

### Undo Last Operation

```bash
warpclean ~/Downloads --undo
```

Reverses the most recent batch of operations. Files are moved back to their original locations.

### Undo Multiple Batches

```bash
warpclean ~/Downloads --undo 3
```

Reverses the last 3 batches of operations.

### Undo Everything

```bash
warpclean ~/Downloads --undo 0
```

Reverses all logged operations. Returns the directory to its original state.

### Preview an Undo

```bash
warpclean ~/Downloads --undo --dry-run
warpclean ~/Downloads --undo 0 --dry-run
```

Shows exactly what the undo would reverse without touching anything on disk. Works with any `--undo` count.

### How Undo Works

- Operations are replayed in reverse order
- Destination directories created during organization are cleaned up
- The undo itself is not logged (prevents infinite loops)
- If a file has been modified or deleted since organization, undo will skip it safely
- Because the log is written incrementally, an interrupted run is still fully undoable

---

## Command Reference

```bash
warpclean <path> [options]
```

### Positional Arguments

| Argument | Description                  |
| -------- | ---------------------------- |
| `path`   | Target directory to organize |

### Options

| Flag                  | Description                                                 |
| --------------------- | ----------------------------------------------------------- |
| `--dry-run`           | Simulate operations without moving files (also previews `--undo`) |
| `--group-related`     | Keep related files (sequences, versions, sidecars) together |
| `--undo [N]`          | Undo last N operation batches (default: 1, use 0 for all)   |
| `--fast`              | Warp drive mode: trust extensions, skip content detection   |
| `--clean-empty-dirs`  | Remove empty directories after organizing                   |
| `--copy`              | Copy files to `warpclean/` subdirectory instead of moving   |
| `--detect-duplicates` | Identify and skip duplicate files                           |
| `--date-based`        | Organize images and videos by date (YYYY/MM/DD structure)   |
| `--progress`          | Show progress bars (requires a terminal)                    |
| `--verbose`, `-v`     | Enable detailed debug logging                               |
| `--color`             | Force colored output on (default: on when stdout is a tty)  |
| `--no-color`          | Force colored output off                                    |
| `--tree`              | Display dry run results as a directory tree                 |
| `--depth N`           | Limit scan depth (0 = root only; default unlimited)         |
| `--exclude PATTERN`   | Gitignore-style exclude pattern (repeatable, no negation)   |
| `--exclude-file PATH` | File with one gitignore-style exclude pattern per line      |
| `--stats`             | Print a run summary (counts, bytes, per-category, elapsed)  |
| `--list-batches`      | With `--undo`: list undo batches instead of reversing       |
| `--yes`, `-y`         | Skip the confirmation prompt before a real run              |
| `--no-config`         | Ignore all config files                                     |
| `--version`           | Print version and exit                                      |
| `--help`, `-h`        | Show help message                                           |

### Exit Codes

| Code | Meaning                                                     |
| ---- | ----------------------------------------------------------- |
| `0`  | Success (including a dry run, or nothing to do)             |
| `1`  | Target directory not found, or the confirmation was declined (including an end-of-input read at the prompt) |
| `2`  | A config file was malformed or unreadable, or `--list-batches` was passed without `--undo` |
| `130`| Interrupted with Ctrl+C (completed operations remain undoable) |

---

## Safety Guarantees

WARPCLEAN is built with safety as a core design principle:

| Guarantee              | Description                                                                                                            |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **No overwrites**      | Destination files are never overwritten. Name collisions are resolved automatically (`file.txt` becomes `file_1.txt`). |
| **No deletions**       | Files are never deleted. Duplicates are skipped, not removed.                                                          |
| **No surprises**       | Dry run shows exactly what will happen, and a real run asks `Proceed? [y/N]` before the first file moves. An unreadable answer aborts rather than proceeding. |
| **Idempotent**         | Files already in their correct category folder are skipped, not re-collided. A second run reports `No moves necessary. Everything is clean!` |
| **Full reversibility** | Every operation is logged. Undo restores files to their exact original locations.                                      |
| **Clean failures**     | If an operation fails, it is logged as an error and the pipeline continues. Completed operations can be undone.        |
| **Interrupt-safe**     | The undo log is written incrementally as each file moves, so Ctrl+C mid-run still leaves a complete, reversible record. |

---

## Real-World Examples

### Clean Up a Downloads Folder

```bash
warpclean ~/Downloads --progress --clean-empty-dirs
```

Organizes all files into categories, shows progress, and removes empty folders afterward.

### Organize Years of Photos

```bash
warpclean ~/Photos --date-based --copy --detect-duplicates --progress
```

Creates a date-organized copy of your photo library, skipping duplicates and showing progress.

### Preview a Project Folder

```bash
warpclean ~/Projects --dry-run --tree --group-related
```

Shows what organization would look like, with related files grouped and displayed as a tree.

### Full-Featured Organization

```bash
warpclean ~/Messy --copy --date-based --detect-duplicates --group-related --progress
```

Uses every major feature: copies instead of moves, organizes by date, detects duplicates, groups related files, and shows progress. Color comes on automatically on a terminal.

### Unattended or CI Run

```bash
warpclean ~/Downloads --yes --no-color --no-config
```

No prompt, no ANSI escapes in the log, no config file surprises from the machine it happens to run on.

### Undo After Testing

```bash
warpclean ~/Downloads --undo 0
```

Reverses all operations and returns the directory to its original state.

---

## License

MIT License

---

## One Last Thing

Always run a dry run first.

```bash
warpclean ~/YourFolder --dry-run
```

Warp speed is powerful. Control keeps it safe.
