<h1 align="center">
    <img width="90px" height="auto" src="https://raw.githubusercontent.com/jamesgober/jamesgober/main/media/icons/hexagon-3.svg" alt="Triple Hexagon">
    <br><b>CHANGELOG</b>
</h1>
<p>
  All notable changes to <code>cli-forge</code> will be documented in this file. The format is based on <a href="https://keepachangelog.com/en/1.1.0/">Keep a Changelog</a>,
  and this project adheres to <a href="https://semver.org/spec/v2.0.0.html/">Semantic Versioning</a>.
</p>

---

## [Unreleased]

### Added

### Changed

### Fixed

### Security

---

## [1.0.0] - 2026-07-01

The stable API freeze. No new public API — the surface built across the 0.x series
is now guaranteed under Semantic Versioning: no breaking change before 2.0.

### Added

- Command-parse benchmarks (`parse_simple`, `parse_rich`) rounding out the
  benchmark suite alongside the output-layer benches (internal; not public API).

### Changed

- Public surface **declared stable**. `docs/API.md` records the SemVer promise
  (breaking changes require a MAJOR bump; additions are minor; fixes/optimization
  are patch; the 1.85 MSRV rises only in minors).
- README and API.md status updated from "pre-1.0 / frozen" to "1.0 — stable".
- Doc comments that referenced upcoming milestones (`reserved for v0.5.0`, "surface
  once the auth seam lands") corrected to describe the shipped behavior.

---

## [0.6.0] - 2026-07-01

Two small, common argument conveniences — counting flags and multiple values —
added within the frozen surface (strictly additive; nothing existing changed).

### Added

- `Arg::count(name)`: a repeatable flag whose occurrences are tallied
  (`-v`/`-vv`/`-vvv`, `-v -v -v`, `--verbose --verbose`). Read with
  `Matches::count(name) -> usize`.
- `Arg::multiple(bool)`: collect every occurrence of an option into a list, or
  make a positional variadic (absorbing the remaining bare values). Read with
  `Matches::values(name) -> impl Iterator<Item = &str>`.
- `Matches::count` and `Matches::values` accessors. `Matches::flag` now also
  reports `true` for a counting flag once its count reaches one.
- `examples/arguments.rs`: every argument kind in one command.

### Changed

- Counts saturate rather than overflowing on pathological repeated input.
- `docs/API.md` documents the two new argument kinds with parameter tables and
  examples; the Stability section notes the additive step.

---

## [0.5.0] - 2026-07-01

The auth seam, and the public surface declared frozen ahead of 1.0.

### Added

- `App::auth(hook)` (feature `auth`): the authorization seam. The hook —
  `Fn(&AuthRequest) -> bool`, supplied by the consumer — decides whether an
  auth-gated command may run. cli-forge holds the seam; the login/logout logic
  lives in the consumer or a sibling crate.
- `AuthRequest` (feature `auth`): the `#[non_exhaustive]` context passed to the
  hook, naming the command being authorized (`command()`, `path()`).
- `ParseError::Unauthorized { command }`: returned when an auth-gated command is
  invoked without authorization. The handler does not run.
- `examples/auth.rs`: an auth-gated command that runs only when authorized.

### Changed

- `Command::requires_auth` is now enforced with the `auth` feature: an auth-gated
  command runs — and appears in help — only when the hook authorizes it, and
  fails closed when no hook is set. Without the `auth` feature the flag is inert
  (the command runs and shows normally).
- The `auth` feature now enables the seam (was a reserved no-op) and implies `std`.
- `docs/API.md` documents the auth seam and **declares the public surface frozen**:
  the remaining 0.x releases add tests, docs, and optimization only, and 0.5.0's
  surface becomes the 1.0 contract.

### Security

- Auth-gated commands fail closed: with the `auth` feature and no hook set, they
  are never authorized (neither run nor listed in help).

---

## [0.4.0] - 2026-06-30

The help engine, plus the small conveniences a base CLI is expected to have:
command aliases, `--help`/`-h`, and `--version`/`-V`.

### Added

- Auto-generated help rendered through the output layer: styled section headers,
  aligned columns, a usage line, and command/argument/option listings. The
  injectable `App::help_header` / `App::help_footer` wrap every page.
- `App::help() -> String` renders the top-level help on demand (for a no-command
  fallback, a `help` command, etc.).
- `App::version(...)` and the `-V` / `--version` flags, printed to standard output
  with exit `0`.
- `-h` / `--help` at any command level renders that level's help (top-level or a
  specific command), to standard output with exit `0`. A command may override the
  built-in by declaring its own `help` / `h` argument.
- `Command::alias(...)` / `Command::aliases(...)`: alternative invocation names.
  Aliases resolve to the canonical command (the parsed subcommand name stays
  canonical) and are shown alongside the name in help.
- `ParseError::HelpRequested(String)` and `ParseError::VersionRequested(String)`
  control signals (carrying the rendered text) so the exiting `parse` and the
  non-exiting `try_parse_from` share one path.

### Changed

- Hidden and auth-gated commands are omitted from generated help listings
  (auth-gated commands surface once the auth seam lands in v0.5.0).
- `docs/API.md` documents the help engine, aliases, version, and the new
  `ParseError` signals.

---

## [0.3.0] - 2026-06-30

The command layer: a recursive command tree, runtime registration from anywhere,
and arg/flag parsing with structured, non-panicking errors.

### Added

- `App`: the command registry and entry point — `new`, `register` (callable from
  any module), `help_header` / `help_footer` (stored for the v0.4.0 help engine),
  `parse` (env args; prints a structured error and exits `2` on malformed input),
  and `try_parse_from` (non-exiting, testable/embeddable).
- `Command`: the recursive tree node — `new`, `about`, `arg`, `subcommand`,
  `hidden`, `requires_auth` (flag stored; enforced with the auth seam in v0.5.0),
  and `run` for the handler.
- `Arg`: `flag` / `option` / `positional` constructors with `short`, `long`,
  `help`, `required`, and `default`.
- `Matches`: `flag`, `value`, and `subcommand` accessors, passed to handlers.
- `ParseError`: a `#[non_exhaustive]` structured error
  (`UnknownFlag`, `MissingValue`, `MissingRequired`, `UnknownCommand`,
  `UnexpectedArgument`) implementing `Display` and `std::error::Error`.
- Parser handling the standard forms: `--long`, `--long=value`, `--long value`,
  `-s`, `-s value`, `-svalue`, bundled short flags `-abc`, positionals, and the
  `--` end-of-options marker. Selected command's handler dispatched on parse.
- `tests/registration.rs`: a command registered from a non-`main` module is
  reachable and behaves identically (the predecessor's limitation, now tested).
- `examples/commands.rs`: a subcommand CLI with flags, options, positionals, and
  the structured-error exit path.
- `proptest` fuzzing of the parser (arbitrary argument vectors never panic).

### Changed

- `docs/API.md` now documents the implemented command surface (`App`, `Command`,
  `Arg`, `Matches`, `ParseError`) with parameter tables and examples.

---

## [0.2.5] - 2026-06-30

The output layer — the load-bearing piece every sibling crate depends on. Three
styling paths over one cross-platform terminal backend, with the plain path proven
allocation-free by test rather than by claim. This is the first substantive release
under the `cli-forge` name, following the 0.2.0 name claim.

### Added

- `out` / `err`: the plain output path. Line-oriented, no tag parsing, and
  allocation-free for a string literal &mdash; proven by a counting-allocator test
  (`tests/allocation.rs`).
- `style` builder: chainable styling (`Style`) with the eight standard named
  colors, 24-bit `hex` / `rgb`, `bold`, `underline`, `render`, and `Display`.
- `parse`: inline tag styling &mdash; `<b>`, `<u>`, `<c=VALUE>` (named / `#rrggbb`
  / `r,g,b`), and `</>`. Nesting, graceful pass-through of unrecognized markup.
- `define_tag` / `tag` / `Tag`: a named-style registry &mdash; define a style once,
  recall it anywhere by name.
- A single terminal backend resolving color depth once (true-color / 256 / 16 /
  none) from `NO_COLOR`, `CLICOLOR_FORCE`, `TERM`, `COLORTERM`, and TTY detection,
  with automatic Windows virtual-terminal enablement and a plain-text fall-back.
- 24-bit colors degrade to the nearest 256- or 16-color value on terminals that
  cannot render them.
- Cross-path byte-identical rendering: the builder, tags, and registry produce the
  same bytes for the same intent (verified across all color levels).
- Runnable examples: `quick_start`, `three_paths`, `colors`, `status_report`.
- Criterion benchmarks for the plain and styled render paths; property tests
  (`proptest`) over the parser and color downgrades.
- `docs/API.md` rewritten to document the implemented surface with parameters and
  multiple examples per item.

### Changed

- `Cargo.toml` features now match the documented surface: `std`, `color` (default,
  implies `std`), and a reserved `auth`. The undocumented `serde` feature/dependency
  was removed (YAGNI).
- Added `rust-toolchain.toml` pinning the development channel; the CI matrix
  overrides it per-job via `RUSTUP_TOOLCHAIN` so the 1.85 MSRV is still exercised.

### Fixed

- `clippy.toml` MSRV corrected from `1.87` to the crate's `1.85`.
- `deny.toml` header comment corrected (`rate-net` &rarr; `cli-forge`).
- `Cargo.lock` is now committed (removed from `.gitignore`) for reproducible
  builds, as REPS requires.

---

## [0.2.0] - 2026-06-30

Name claim. The crate's original name was unavailable on crates.io, so the project
was renamed to `cli-forge` and this version was published to secure the name. It
carries the 0.1.0 structure forward under the new name; the output layer ships in
0.2.5.

### Changed

- Crate renamed to `cli-forge` (crate name, library path `cli_forge`, repository
  and documentation links).

---

## [0.1.0] - 2026-06-30

Initial scaffold and repository bootstrap. No domain logic yet &mdash; this release establishes the structure, tooling, and quality gates the implementation will be built on.

### Added

- `Cargo.toml` with crate metadata, Rust 2024 edition, MSRV 1.85.
- Dual `Apache-2.0 OR MIT` license files.
- `README.md`, `CHANGELOG.md`, and a documentation skeleton.
- `REPS.md` compliance baseline.
- `.github/workflows/ci.yml` CI matrix; `deny.toml`, `clippy.toml`, `rustfmt.toml`.
- `dev/DIRECTIVES.md` and `dev/ROADMAP.md` (committed engineering standards + plan).

[Unreleased]: https://github.com/jamesgober/cli-forge/compare/v1.0.0...HEAD
[1.0.0]: https://github.com/jamesgober/cli-forge/compare/v0.6.0...v1.0.0
[0.6.0]: https://github.com/jamesgober/cli-forge/compare/v0.5.0...v0.6.0
[0.5.0]: https://github.com/jamesgober/cli-forge/compare/v0.4.0...v0.5.0
[0.4.0]: https://github.com/jamesgober/cli-forge/compare/v0.3.0...v0.4.0
[0.3.0]: https://github.com/jamesgober/cli-forge/compare/v0.2.5...v0.3.0
[0.2.5]: https://github.com/jamesgober/cli-forge/compare/v0.2.0...v0.2.5
[0.2.0]: https://github.com/jamesgober/cli-forge/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/jamesgober/cli-forge/releases/tag/v0.1.0
