# Changelog

All notable changes to this project are documented here.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.1] - 2026-08-22

First external review of this package — every sibling had between one and
four rounds; this one shipped with none, and the round found two real
defects.

### Fixed

- **A broken tool was reported as installed, with a version read out of its
  own error message.** Exit status was ignored whenever the default pattern
  found any dotted number in the output — documented as deliberate, and
  wrong: *failure* output routinely contains one. A Homebrew ffmpeg dying in
  the dynamic loader reported `{:ok, "265.215.0"}`, parsed from
  `libx265.215.dylib` in the dyld error, and satisfied `>= 4.0.0`. A
  non-zero exit is now an error, `{:check_failed, status, output}`. Tools
  that genuinely report their version with a non-zero exit — `ssh -V` exits
  255 — declare `allow_nonzero: true`.
- **A version command that waited on stdin hung the check forever.**
  `System.cmd/3` has no timeout, and the moduledoc itself places checks on a
  request path behind an expiring cache. The subprocess now runs under a
  Port with a ten-second default (`:timeout` per tool), is killed by OS pid
  on expiry rather than abandoned, and is unlinked so a trapping caller
  never receives its EXIT as a stray `handle_info`.
- **Output accumulation is capped at 64 KB, keeping the head.** A
  misconfigured executable that streams (`yes` measured 2.1 GB in one second
  through a port) filled the heap for the whole timeout budget. The head is
  kept — the opposite end from a converter's error tail — because a version
  banner sits at the start of output.
- `install: "one bare string"` crashed `install_hint/1` — but only on the
  failure path, so it survived every machine where the tool existed. Now
  accepted as `[default: hint]`.

### Documented

- An "Awkward tools" section: `ssh` (`allow_nonzero`), `elixir` (the OTP
  banner's erts version precedes "Elixir x.y.z", so the default pattern
  reads the wrong number — `:pattern` fixes it), and slow-first-run tools
  (`:timeout`).

## [0.1.0] - 2026-08-21

Initial release.

### Added

- `use CliDeps` with a `tool/2` macro for declaring external command-line
  dependencies.
- `check/1`, `check!/1`, `available?/1`, `explain/1`, `report/0`,
  `all_available?/0`, `invalidate/1`.
- Version requirements via `Version` requirement strings, with extraction from
  real-world `--version` output.
- Per-OS install hints (`:macos`, `:linux`, `:windows`, `:default`) surfaced in
  error messages.
- Result caching in `:persistent_term` with a one-hour default TTL, monotonic
  clock, and per-tool or global invalidation.
- `mix cli_deps.check` task that exits non-zero when anything is missing, for
  use as a CI or container-build gate.
- Compile-time validation of version requirements, regex patterns, and
  duplicate tool names.
