# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed
- **Removed internal command-execution timeout caps (ADR-008)** — `CommandRunner` no longer
  imposes a wall-clock cap on wrapped commands. Previous versions killed `cargo test`,
  `npm build`, and other long-but-finite commands after 300 s (default) or 600 s (builds).
  Skim is a transparent command wrapper; a transparent wrapper must not change whether or
  when a command completes. Bind child-process lifetime externally when needed: CI step
  timeout, the shell `timeout(1)` utility, the agent tool timeout, or `Ctrl-C`. The 64 MiB
  output memory cap (`MAX_OUTPUT_BYTES`) is unchanged — only the TIME bound is removed.
  **Accepted side-effect**: long finite commands now produce no output until they exit
  (skim buffers to compress); `SKIM_PASSTHROUGH=1` is the human escape hatch.
- **`skim vitest` now runs in watch mode by default (ADR-008 Part C)** — bare `skim vitest`
  and `cat output | skim vitest` are detected as indefinite and passed through live (no
  compression). To compress a one-shot run, use `skim vitest run` (or set
  `SKIM_PASSTHROUGH=1` to forward piped content).

### Fixed
- **Kill-on-drop guard for spawned children (ADR-008)** — `CommandRunner` now wraps every
  spawned process in a `ChildGuard` RAII struct. On any early-return path (size-cap error,
  pipe-capture failure, reader-thread panic) the guard calls `kill()` + `wait()` on the
  still-running child, preventing orphan processes. On the normal path the child has already
  exited before drop fires, so `kill()` is a harmless no-op. This also fixes the pre-existing
  orphan on the 64 MiB size-cap path.

### Added
- **Daemon / streaming command passthrough (ADR-008 Part C)** — Indefinitely-running
  commands (`vite dev`, `npm run dev`, `jest --watch`, `tail -f`, `kubectl logs -f`, etc.)
  are now detected before skim tries to capture their output. They are passed through with
  fully inherited stdio: live output streams to the terminal, stdin is forwarded (interactive
  dev servers work), and `Ctrl-C` terminates the child normally. Detection is heuristic and
  conservative — a missed daemon degrades to the old buffered path (64 MiB cap still applies);
  `SKIM_PASSTHROUGH=1` is an explicit escape hatch.
  **Accepted limitation**: stdin-reading interactive commands on the buffered (non-daemon)
  path could block on stdin; this is pre-existing and out of scope.

### Added
- **Wave 3e: AST Pattern Library & Structural Index v2** — `rskim-search` AST index format bumped to v2 (breaking; re-index required). Adds per-file structural metrics (max depth, max block statements, max params, branch count) and synthetic n-gram markers (EMPTY_BODY, DEEP_NODE, LARGE_BODY, MANY_PARAMS) emitted via a single-pass extraction. Pattern library catalog with 29 named patterns (ErrorHandling, Performance, Concurrency, Quality, Structure) GOLD-verified against real parse output; each pattern is either exact (reliable subset of every occurrence) or approximate (description says "approximation" or "structural"). (#196)

### Migration Note
- **AST index format v2 (breaking change)** — Files written by Wave 3d (`format_version=1`) are rejected with "please rebuild". Run `skim search index --rebuild` (or `--force`) to regenerate. The v2 format adds 10 bytes per file entry for structural metrics and stores `avg_max_depth:f32` in the header. No data loss: v2 is a strict superset of v1.

### Added
- **Universal shell interception via PATH wrappers** — `skim init --wrappers` creates symlinks in `~/.skim/bin/` for all supported tools. The skim binary detects `argv[0]` and dispatches through the existing handlers. Recursion is prevented by stripping `~/.skim/bin` from PATH as the very first action in `main()`. `--no-wrappers` skips wrapper installation unconditionally; in TTY environments without either flag, the user is prompted interactively. Non-TTY environments default to skipping. (#258)
- **Hook scripts include PATH prepend for wrapper activation** — Generated hook scripts now prepend `~/.skim/bin` to PATH so that sub-agents in restricted PATH environments still resolve wrapper symlinks. The prepend is guarded by a `[ -d "$HOME/.skim/bin" ]` check, so hooks installed before `skim init --wrappers` was run are unaffected. The skim binary's startup PATH strip prevents infinite recursion. (#258)

### Changed
- **`skim init` prompts interactively for wrapper installation on TTY** — When neither `--wrappers` nor `--no-wrappers` is supplied and stdin is a TTY, `skim init` now asks whether to install PATH wrappers. Non-TTY environments (CI, scripted installs) are unaffected and default to skipping wrappers. Use `--no-wrappers` as an escape hatch in scripted TTY contexts. (#258)

### Added
- **Temporal search flags** — Composable sort and filter flags for `skim search`: `--hot` (sort by hotspot score), `--cold` (invert hotspot sort), `--risky` (sort by fix-commit risk score), and `--blast-radius FILE` (pre-filter results to co-change peers of FILE before ranking). Flags compose freely; `--blast-radius` narrows the candidate set, then sort flags rank within it. 4 new CLI flags, 6 new public methods on `SearchQuery`/`SearchResults`, schema v2 migration (performance indexes for top-N and per-file lookup queries). (#189)
- **`skim search index` subcommand** — Build or update the n-gram search index for the current project. Walk/classify/build pipeline with parallel tree-sitter classification (rayon), JSONL manifest sidecar for incremental builds (SHA-256 cache hits skip re-classification), atomic write ordering, minified file detection, and 50K file cap. `--force` flag for full rebuild, `--root` for explicit project root, `--max-files` override. (#182)
- **`skim dig` / `skim nslookup` subcommands** — DNS query output compression via two independent parsers: `dig` uses section-based parsing (QUESTION/ANSWER sections), `nslookup` uses key-value line parsing. Both support three-tier degradation, `--json` structured output, error state compression, and macOS + Linux format variants. `nslookup` includes no-args guard. 2 new rewrite rules (total: 148) (#168)
- **`skim make` / `skim gmake` subcommands** — GNU Make build output compression via three-tier parser: Tier 1 (GCC/Clang diagnostics regex + make failure lines), Tier 2 (noise-stripped invocation/directory-change lines), Tier 3 (passthrough). Includes `gmake` rewrite rule for hook integration. 17 unit tests, 2 E2E tests (#167)

## [2.10.0] - 2026-05-13

Container, cloud, database compression; search crate foundation; heatmap insights. 3,558 tests passing (up from 3,310 in v2.9.0).

### Added
- **`rskim-search` crate (Wave 0)** — New workspace crate providing the search foundation: `SearchLayer`, `LayerBuilder`, and `FieldClassifier` traits, `SearchQuery`/`SearchResult`/`IndexStats` types, AST-aware `SearchField` classification (8 field variants), and typed `SearchError` hierarchy. Pure library with no I/O — CLI integration in future waves (#213)
- **`skim heatmap --insights` flag** — threshold-filtered one-liner findings for focused risk analysis. Reports only CRITICAL/WARNING severity metrics (fix-risk, bus-factor, churn, coupling) in text and JSON formats, skipping healthy files (#215)
- **`skim psql` subcommand** — PostgreSQL query output compression via three-tier degradation: Tier 1 (tabular `----+----` format), Tier 2 (regex row-count extraction), Tier 3 (passthrough). Supports `--json` for structured `DbResult` output (#117)
- **`skim mysql` subcommand** — MySQL query output compression: Tier 1 (TSV batch output), Tier 2 (bordered `+---+` table format), Tier 3 (passthrough). Handles empty-set detection and multi-result sets. Supports `--json` (#117)
- **`skim sqlite3` subcommand** — SQLite query output compression: Tier 1 (pipe-separated with `-header -separator |` injection), Tier 3 (passthrough for schema dumps and meta-commands). Supports `--json` (#117)
- **`DbResult` canonical type** — Structured database query result with column/row data, row count, truncation flag, and pre-rendered aligned table output. Part of the canonical output type system (#117)
- **`skim docker` subcommand** — Docker output compression for `ps`, `images`, `inspect`, `build`, `logs`, `compose` via three-tier degradation (#117)
- **`skim kubectl` subcommand** — Kubernetes output compression for `get`, `describe`, `logs`. Injects `-o json` for `get` (skipped for watch/existing format flags) (#117)
- **`skim terraform` subcommand** — Terraform output compression for `plan` and `apply`: Tier 1 (NDJSON from `-json`), Tier 2 (regex on human-readable text). Safety invariant: never injects `-json` for plan/apply to preserve interactive approval prompts (#117)
- **15 new rewrite rules** — Docker (ps, images, build, inspect, logs, compose ps, compose logs), kubectl (get, describe, logs), terraform (plan, apply), psql (-c), mysql (-e), sqlite3. Total: 122 rules across 8 categories (#117)

### Fixed
- **DB family ANSI strip bypass** — `strip_ansi_escapes` was stripping ASCII tab characters (0x09) from stdin content, causing MySQL TSV parsers to receive tab-free data and fall through to passthrough. DB family commands now bypass ANSI stripping to preserve tab separators (#117)
- **Heatmap `set_var`/`remove_var` unsafe blocks** — Rust 2024 edition requires explicit `unsafe {}` blocks for `std::env::set_var` and `std::env::remove_var` in test code
- **Test isolation for `SKIM_PASSTHROUGH`** — Hook and parser E2E tests now clear `SKIM_PASSTHROUGH` from inherited environment, preventing false failures when tests run inside a skim hook session

### Testing
- 3,558 tests passing (up from 3,310 in v2.9.0)
- 14 new E2E parser tests: psql (tier 1, empty, tier 2, tier 3, JSON), mysql (tier 1 TSV, tier 2 bordered, tier 3, empty set, JSON), sqlite3 (tier 1, empty, tier 3 schema, JSON)
- 19 new E2E rewrite tests: docker (5 positive, 1 skip), kubectl (3 positive, 2 skip), terraform (2 positive, 1 skip), DB tools (3 positive, 1 skip)
- 22 new `rskim-search` unit tests: type roundtrips, trait contracts, field classifier, serde agreement (#213)

## [2.9.0] - 2026-05-08

Heatmap analysis, system utility parsers, curl hardening. 3,310 tests passing (up from 3,103 in v2.8.0).

### Added
- **`skim heatmap` subcommand** — Git history risk and coupling analysis. Mines git log to produce 6 metrics: file churn, co-change coupling (blast radius), stability scores, author concentration (bus factor), fix-after-touch risk, and module encapsulation health. Supports adaptive dual windowing (max of 90 days / 200 commits), auto-exclusion of lock files and build artifacts, JSON and text output, and path scoping. 87 new tests (#163)
- **Heatmap file targeting** — positional file args, `--diff` flag for changed-files-only analysis, display filter for focusing output on specific paths (#171)
- **System utility parsers** — `df`, `du`, `env`, `printenv`, `ps`, `wc`, `diff`, `rg`, `tree` output compression via flat dispatch subcommands (#166)

### Changed
- **Curl parser hardened** — error status detection, redirect chain compression, HTML body truncation, verbose header filtering, write-out format support (#169)

### Fixed
- **CI release workflow** — fail hard on real publish errors, skip gracefully on already-published versions (#165)

### Testing
- 3,310 tests passing (up from 3,103 in v2.8.0)

## [2.8.0] - 2026-05-07

Flat dispatch, Crush agent, multi-file args. 3,103 tests passing (up from 3,002 in v2.7.0).

### Breaking Changes

- **Flat dispatch CLI syntax** — Tool names are now top-level subcommands instead of being grouped under family prefixes (#158). The old `skim <family> <tool>` syntax is removed. Hooks auto-adapt — no user action needed for rewrite rules.

  **Migration Guide:**

  | v2.7.x | v2.8.0 |
  |---|---|
  | `skim test cargo` | `skim cargo test` |
  | `skim test vitest` | `skim vitest` |
  | `skim test pytest` | `skim pytest` |
  | `skim test jest` | `skim jest` |
  | `skim test go` | `skim go test` |
  | `skim build cargo` | `skim cargo build` |
  | `skim build clippy` | `skim cargo clippy` |
  | `skim build tsc` | `skim tsc` |
  | `skim lint eslint` | `skim eslint` |
  | `skim lint ruff` | `skim ruff` |
  | `skim lint biome` | `skim biome` |
  | `skim pkg npm audit` | `skim npm audit` |
  | `skim pkg pip install` | `skim pip install` |
  | `skim file find .` | `skim find .` |
  | `skim file ls` | `skim ls` |
  | `skim file grep pattern` | `skim grep pattern` |
  | `skim infra gh pr view` | `skim gh pr view` |
  | `skim infra curl` | `skim curl` |
  | `skim infra aws` | `skim aws` |

- **OpenCode agent removed** — `skim init --agent opencode` is no longer supported. Use `skim init --agent crush` instead (#160).

### Added
- **Multiple file args** — CLI now accepts multiple file arguments and absolute glob paths (`skim src/main.rs src/lib.rs`, `skim /absolute/**/*.ts`) (#161)
- **Session ID sidecar** — fallback attribution for analytics when session ID is not available from the agent hook (#159)
- **Crush agent support** — `skim init --agent crush` installs hooks for the Crush AI agent; `HookProtocol` extended with config lifecycle methods (#160)

### Changed
- **Init guidance refactored** — prescriptive decision table replaced with principle-based agent guidance for clearer, more maintainable hook installation output (b79f6e3)
- **Dispatch architecture rewritten** — family-grouped subcommands (`test`, `build`, `lint`, `pkg`, `file`, `infra`) replaced with flat dispatch where tool names (`cargo`, `vitest`, `eslint`, `npm`, `find`, `gh`) are top-level subcommands (#158)

### Fixed
- **Clippy lint scoping** — `allow(unwrap/expect/panic)` attributes scoped to inline `#[cfg(test)]` modules in rskim-core, not the entire crate (#162)

### Removed
- **OpenCode agent** — removed from `HookProtocol` implementations; `skim init --agent opencode` no longer supported (#160)

### Testing
- 3,103 tests passing (up from 3,002 in v2.7.0)

## [2.7.0] - 2026-05-01

Line numbers, session tracking, output sanitization. 3,002 tests passing (up from 2,883 in v2.6.0).

### Added
- `-n`/`--line-numbers` flag — prefix output lines with source line numbers across all transformation modes (#155)
- Session tracking pipeline — `session_id` extraction from agent hooks (Claude, Cursor, Copilot, Gemini), injection into rewritten commands, per-session stats on analytics dashboard (#150)
- Schema v3 migration — nullable `session_id` column with index in analytics database
- Advanced $5/MTok pricing tier between Standard ($3) and Premium ($15)
- `RecordingContext<'a>` struct — eliminates parameter threading in analytics pipeline
- `is_safe_session_id()` — centralized session ID validation (128-char max, rejects metacharacters)

### Changed
- Output sanitization across all parsers: dropped command-type prefixes (BUILD/LINT/PKG/TEST/INFRA/LOG/FILE), lowercase status labels (pass/fail/skip), reduced indentation, collapsed body stubs (`{...}` from `{ /* ... */ }`), simplified multi-file separators and diff headers
- Git operation prefixes simplified: `[status]`/`[log]`/`[fetch]` → `status`/`log`/`fetch`
- `serde(skip_serializing)` added to all rendered fields in canonical types
- Init guidance uses `--line-numbers` instead of `-n` for clarity

### Testing
- 3,002 tests passing (up from 2,883 in v2.6.0)

## [2.6.0] - 2026-04-27

Terminal UX overhaul, non-interactive init, plugin ecosystem removal. 2,883 tests passing (up from 2,800 in v2.5.1).

### Added
- `--no-truncate` flag for `discover` and `learn` subcommands — disables terminal-width-aware table truncation (#154)
- Terminal UX primitives (`cmd/ux.rs`): `with_spinner` closure helper, `print_indented_table`, comfy-table formatting, colored output across `discover`, `learn`, `agents`, `init` (#153)
- Responsive table truncation — auto-detect terminal width, truncate wide columns to fit viewport, graceful fallback for non-TTY (#154)

### Changed
- `skim init` install is always non-interactive — removed scope/marketplace prompts and confirmation; `--yes` still accepted for backward compatibility (#151)
- Hook scripts use bare `exec skim rewrite --hook` (PATH-resolved) instead of hardcoded absolute binary paths — eliminates "unknown git subcommand" failures after npm upgrades (#151)
- Format-aware idempotency — old-format hooks with absolute paths are detected and force-regenerated even when version matches (#151)
- Stats dashboard shows savings percentage only once (on bar line), not redundantly next to token count (#153)

### Fixed
- Hook script absolute path failures after upgrading skim via npm (#151)

### Removed
- Plugin ecosystem — `.claude-plugin/` directory, `plugins/skimmer/` directory, `.github/workflows/sync-skimmer-plugin.yml` CI workflow, marketplace registration from init state (#153)
- `validate_shell_safe_path()`, `SHELL_UNSAFE_CHARS`, and 12 associated tests — attack surface no longer exists with bare command approach (#151)
- `prompt_choice()` helper (dead code after non-interactive install change) (#151)

### Testing
- 2,883 tests passing (up from 2,800 in v2.5.1)

## [2.5.1] - 2026-04-20

Hook safety and command coverage gaps — SKIM_PASSTHROUGH bypass, npx fallback, tiered test compression, 5 new parsers, streaming primitive. 2,800 tests passing (up from 2,629 in v2.5.0).

### Added
- **`skim git commit`** — new parser compressing `git commit` output: extracts commit hash, subject, and changed-files summary; terminates at verbose diff scissors line (`---...>8---`, AD-GC-1); skips hook noise (pre-commit, black, ruff, eslint output)
- **`skim git push`** — new parser compressing `git push` output: full porcelain mode (auto-injected `--porcelain`, AD-GP-2); per-ref status (`* new`, `= up to date`, `+ forced`, `! rejected`); credential URL scrubbing via `scrub_credential_url` (AD-GP-1)
- **`skim infra gh api`** — new parser compressing `gh api` / `gh api graphql` output: GraphQL `.data` unwrap + `.errors` prepend, base64 `content` field replacement, binary passthrough, depth-limited JSON compaction (AD-API-1)
- **`skim infra gh run watch`** — new streaming parser for `gh run watch`: emits job status transitions (queued → in-progress → completed/failed), suppresses progress noise, emits `Run complete: N/M succeeded` summary (AD-GRW-1)
- **`skim infra gh release view`** — new parser compressing `gh release view --json` output: extracts tag, name, dates, assets list (capped at 20), body truncation outside code fences (AD-RV-1)
- **Rewrite rules for new commands** — 7 new rules (93→100): 5 specific (`git commit`, `git push`, `gh run watch`, `gh release view`, `gh api`) + 2 catch-all (`ls`, `grep`) (AD-RW-2)
- **Catch-all ls/grep rewrite rules** (B.1/B.2) — any `ls` or `grep` invocation without a more-specific match is now rewritten; `--help`/`--version` pass through; pipe sources excluded from rewriting
- **Redirect stripping** (`strip_segment_redirects`) — per-segment redirect stripping in compound commands; redirects are restored at emission time (appended to end), preserving shell semantics
- **Streaming primitive** (`streaming.rs`) — `StreamingParser` trait, `run_streamed_spawned`, `DropGuard` for fire-and-forget analytics on streaming commands
- **Shared git helper** (`git/shared.rs`) — `scrub_credential_url` strips credential-embedded URLs (`https://<token>@github.com/...`) using lazy regex (AD-GP-1)
- **`SKIM_PASSTHROUGH` env var** — universal bypass for all compression (hook, vitest, go, pytest, generic); set to `1`/`true`/`yes` to disable skim rewriting for a single invocation
- **Cascading spawn fallback** — vitest/jest spawn attempts PATH → `./node_modules/.bin` → `npx --no-install`; prevents hook failures on projects where the binary is not globally installed
- **Tiered test compression** — on test failure, the last 50 lines of raw output are appended so agents see the full failure context without disabling compression
- **stderr hint on compressed test failures** — failed compressed test output includes a `SKIM_PASSTHROUGH=1` guidance hint on stderr for debugging
- **Troubleshooting section in `skim init` guidance output** — init instructions now include a troubleshooting block with `SKIM_PASSTHROUGH=1` usage
- **`emit_failure_context` shared helper** — DRY helper for appending raw failure context across vitest, go, pytest, and generic test handlers

### Fixed
- **`find` and `rg` pipe-source exclusion** — `find . | head` and `rg pattern | head` are no longer rewritten; `exclude_pipe_source: true` was missing from their rules despite having specific rule entries (regression vs. intended AD-RW-2 semantics). `is_catch_all` renamed to `exclude_pipe_source` to accurately describe the field's purpose.
- **`try_parse_porcelain` false-trigger** — porcelain parser now ignores informational lines starting with flag characters (`!`, `-`, `=`) that don't contain a ref path (`refs/` prefix) or src:dst notation (`:`). Prevents lines like `! [remote rejected] branch (pre-receive hook declined)` from being misparsed as ref-status entries. Root cause: `strip_ansi_escapes` strips tab bytes, so tab-based guard heuristics are unreliable.
- **Credential scrubbing on success and failure analytics paths** — `raw` (success) and `output.stdout` (failure) are now scrubbed line-by-line via `scrub_credential_url` before being passed to `finalize_git_output_owned` / `finalize_git_output_passthrough`. Previously, `analytics.db` could persist credential-bearing URLs from push/fetch output (PF-024).
- **`ssh://` credential scrubbing** — `CREDENTIAL_URL_RE` now matches `ssh://user@host/...` in addition to `https://` and `git://` (AD-GP-1). SSH-cloned repos with embedded credentials in push/fetch output are now scrubbed on the same code path.
- **`build_streaming_label` analytics label alignment** — `gh run watch` now produces analytics labels via the shared `build_streaming_label` helper, matching the `"skim {family} {program} {subcommand} {args}"` format used by non-streaming infra commands (PF-022). `gh api` uses the standard `ParsedCommandConfig` analytics path via `run_infra_tool` and does not need the streaming helper.
- **Node.js spawn fallback scoped to spawn failures only** — cascading PATH → `node_modules/.bin` → `npx` fallback only triggers on spawn errors (ENOENT/permission denied), not on non-zero test exit codes; stderr is routed correctly in passthrough mode

### Changed
- **`is_catch_all` renamed to `exclude_pipe_source`** — field semantics now describe the actual behavior (pipe-source suppression) rather than the matching strategy (AD-RW-2)
- **Rewrite engine deduplication** — `should_skip_by_flag` extracted as a named function (replacing two duplicated inline closures); `has_pipe_operator` and `reconstruct_pipe_parts` extracted to `compound.rs`; `splice_redirects_back` promoted to `pub(super)`. Dead index (`PIPE_EXCLUDED_SOURCES` slice) removed.

### Testing
- 2,800 tests passing (up from 2,629 in v2.5.0; +33 from hook safety (#149))
- Pipe-source exclusion tests for `find` and `rg` (standalone rewritten, piped suppressed, `||` chain not suppressed)
- Negative tests for compress-or-skip (`ls --help`, `grep --version` passthrough)
- Redirect stripping coverage for all 7 single-token forms + two-token `2> /dev/null`
- `scan_operator` regression test for `>&1&&` edge case
- Credential scrubbing error-path tests (stderr with `https://` and `ssh://` URLs)
- Porcelain parser false-trigger regression tests (informational `!`/`-` lines without tabs)
- Pipe/stdin E2E parsed-vs-raw compression comparison for `gh run watch` and `gh api`
- Hook safety E2E tests: `SKIM_PASSTHROUGH` bypass, spawn fallback (PATH/node_modules/.bin/npx), tiered failure context

## [2.5.0] - 2026-04-17

Formatter output compression — 8 new parsers for code formatter tools. 2,629 tests passing (up from 2,482 in v2.4.1).

### Added
- **`skim lint` formatter support** — 8 new parsers: ruff format, prettier --write, rustfmt, black, gofmt, biome, dprint, oxlint
- `LintResult.files_formatted` field to track formatted files separately from lint errors
- Path-aware regex patterns for files with spaces
- Rewrite rules for formatter commands (`ruff format`, `prettier --write`, `black`, `gofmt`, `biome check --write`, `dprint fmt`, `oxlint --fix`)

### Changed
- `skim lint` dispatcher unified — formatter and linter parsers use single dispatch path
- Tech debt consolidation: dispatch logic, canonical output helpers, file handler signatures unified across lint/file/infra/git modules

## [2.4.1] - 2026-04-15

### Changed
- **`skim stats` dashboard redesign** — weighted savings %, category grouping, column headers, by-command breakdown (top 15 commands by tokens saved), DRY render helpers, O(n) truncation
- **`skim stats --cost` deprecated** — cost estimates are now always shown; `--cost` flag prints a deprecation warning
- **`skim stats --verbose`** — new flag to show parse quality section
- **`skim stats --format json` schema updated** — `cost_estimate` is now always present (previously only included when `--cost` flag was passed). The `cost_estimate` object uses a `tier` key (e.g. `"Standard"`) instead of the former `model` key. Two new top-level fields are always present: `by_original_cmd` (array of top-15 commands by tokens saved, each with `original_cmd`, `invocations`, `tokens_saved`, `avg_savings_pct`, `avg_duration_ms`) and `summary.weighted_savings_pct` (tokens-weighted savings percentage, more accurate than `avg_savings_pct` for uneven workloads). Downstream consumers of `skim stats --format json` must update to use `tier` instead of `model` in `cost_estimate`.

### Fixed
- `skim git show` test now handles guardrail passthrough correctly when compressed output exceeds raw size
- Stats verbose test uses canonicalized fixture paths to work with `Language::from_path()` security check

## [2.4.0] - 2026-04-14

GitHub CLI compression, git subcommand completion, multi-agent handler fixes, quality improvements. 2,482 tests passing (up from 2,223 in v2.3.1).

### Added
- `skim infra gh pr view` now always renders `draft`, `mergeable`, and `ci` items so agents observe the full merge-readiness signal set even on clean PRs. A `[DRAFT]` prefix is added to the summary when the PR is a draft. CI aggregation: `FAILURE`/`CANCELLED`/`TIMED_OUT` → `failing`; `PENDING`/`QUEUED`/`IN_PROGRESS` → `pending`; else `passing`; null/empty → `none`. (AD-INFRA-9, commit 689e397, see `crates/rskim/src/cmd/infra/gh/pr_view.rs`)
- `prettier --check`, `rustfmt --check`, `cargo fmt --check`, and `cargo fmt -- --check` are now acknowledged as already-compact (AD-RW-11, compress-or-skip rule). `skim rewrite` echoes the original command instead of rewriting to `skim lint prettier/rustfmt`. This prevents the skim header from inflating output on clean or near-clean codebases.
- `parse_tier` field added to `GitResult` and propagated through all git handlers to the analytics DB (AD-GIT-12). Git invocations now appear with `"full"`, `"degraded"`, or `"passthrough"` tier labels, consistent with the file/lint/infra handler families.

### Fixed
- `skim git show <commit>` now preserves the full commit message body (multi-paragraph) and merge-parent hashes (`Merge: p1 p2` prefix in rendered output). Previously both were silently dropped. GPG/SSH signature blocks (`gpgsig`/`mergetag`) remain elided. (AD-GIT-8, commit 0f9c82b, see `ShowCommitResult::body` and `parents` fields in `crates/rskim/src/cmd/git/show.rs`)
- `skim git diff` now records a zero-compression analytics row when the diff is empty (previously uncounted). This unifies analytics recording across empty and non-empty invocations. ([#132](https://github.com/dean0x/skim/issues/132), [#135](https://github.com/dean0x/skim/pull/135))
- `skim git show <annotated-tag|blob|tree>` (non-commit passthrough) now records analytics (previously uncounted). This unifies analytics recording across all `git show` modes. ([#132](https://github.com/dean0x/skim/issues/132), [#135](https://github.com/dean0x/skim/pull/135))
- `skim git log`, `skim git status`, `skim git fetch`, `skim git diff` now record analytics on non-zero exit codes (previously, failed git invocations were silently dropped from the analytics DB). (AD-GIT-14, commit ea4e52f)
- `skim infra gh pr checks` and `skim infra gh run view` now include URLs for failing checks and run items so agents can navigate directly to the failure without a second command. (AD-INFRA-15, see `crates/rskim/src/cmd/infra/gh/pr_checks.rs` and `run_view.rs`)
- `skim pkg npm audit` and `skim pkg pnpm audit` now include advisory identifiers (`GHSA-xxxx-yyyy-zzzz` extracted from `via[i].url`, or `NPM-{source}` fallback for legacy numeric IDs) in rendered advisory details. Mirrors `skim pkg cargo audit` existing behaviour. (AD-PKG-18, commit 9041511)
- `skim test cargo` and `skim test vitest` now surface failing test names in their Tier-2 regex fallback paths (previously returned empty entries). Names are capped at 100 to match Tier-1 semantics. ANSI codes are stripped before regex matching. (commit cc662e6, see `crates/rskim/src/cmd/test/shared.rs::scrape_failures`)
- `skim test vitest` Tier-2 regex now tolerates leading whitespace on failing-test lines (e.g. `   × divides by zero`), matching real vitest output rather than only bare-`✕` hand-crafted fixtures. (AD-TEST-19, commit ea4e52f)
- `skim rewrite '<full command>'` with a single quoted-string argument now tokenizes the same way as stdin input (via `split_whitespace` inside `collect_input_tokens`). Previously the single-arg form produced a one-element vector that matched no rule and no ACK prefix, silently returning exit 1. (AD-RW-13, commit 48dded7)
- `skim log` pending_stack is now capped at 4 frames (sliding window); excess frames are elided incrementally rather than accumulating unboundedly. Output behavior is unchanged (last 3 frames shown + elision count in `LogResult.stack_frames_elided`), but memory is now bounded at O(1) regardless of input length. (DoS hardening, commit ec32165)
- `skim log` JSON log fields are now capped before processing: `level` at 32 chars, `message` at 16 KiB. Values that exceed the cap are truncated and suffixed with `[truncated]` so consumers can detect elision. Prevents resource exhaustion from adversarially large JSON log lines. (DoS hardening, commit ec32165)
- `skim log` deduplication allocations reduced: key construction no longer heap-allocates on the common (non-duplicate) path. (commit ec32165)
- `skim log` now tracks stack frames attached to the preceding log entry (up to 3 frames shown; elision count in `LogResult.stack_frames_elided`). Deduplication is level-aware (`level|message` key). (AD-LOG-10)
- `skim file ls` degradation marker now uses `"tree:"` prefix, matching the format contract for all `skim file` parsers. (commit e8fbf50)
- `skim infra curl` now surfaces up to 20 object keys (was 5) before truncating. The truncation notice displays the actual cap.
- `skim file tree` depth-capped output now reports the count of hidden deeper entries (`"(N deeper entries hidden)"`) instead of a generic cap notice.
- `skim lint golangci` severity now inferred from linter name and message text (was always `Warning`). (AD-LINT-16, see `crates/rskim/src/cmd/lint/golangci.rs::infer_severity_from_text`)
- `skim lint rustfmt` location messages now include the diff line number (`"formatting difference at line N"` vs. `"formatting difference detected"`). (AD-LINT-17, see `crates/rskim/src/cmd/lint/rustfmt.rs`)
- `skim git diff` warns on non-empty stderr at exit 0 (`[skim] git diff notice: ...`) so LF/CRLF replacement warnings are not silently discarded.
- PF-018 fully resolved: `finalize_git_output_passthrough` eliminates double-clone on passthrough paths across all git handlers. (commit 6f06e9d)
- PF-021 fully resolved: `run_passthrough` now uses `build_analytics_label` so format strings are not allocated when analytics are disabled. (commit 6f06e9d)

### Changed
- `git show` diff rendering (`render_show_diff`) now uses rayon parallel iteration for large multi-file diffs, consistent with other multi-file diff paths. (commit 6f06e9d)
- `parse_commit_header` refactored to borrow body slices from the input rather than cloning them, reducing allocations on the hot path. (commit 6f06e9d)
- `gh pr checks` parser extracted `ParsedCheck` struct and `non_empty_capture` helper, replacing positional tuple usage and eliminating silent field-swap risk. (commit d6ff12c)

### Testing
- **2,470 tests passing** (up from 2,223 in v2.3.1; +16 alignment E2E, +parse_tier unit tests, +stack-trace/dedup/npm-audit/gh-pr-view/scrape_failures/scrutinizer-regression unit tests, +Wave 1 regression tests for git show failure analytics and rewrite tokenization)
- New `cli_e2e_rewrite_alignment.rs` — 16 tests closing the rewrite→execute loop for all major command families
- Double ANSI strip eliminated in vitest Tier-2 test path (commit fd3ce4f)
- New regression tests: `git show` failure-path analytics, `skim rewrite` single-arg tokenization (commit fd3ce4f)

## [2.3.1] - 2026-04-09

Patch release: discover/rewrite alignment, rewritable gap closures, stats bar fix.

### Fixed
- `render_bar` zero-width ANSI color leak in stats dashboard
- Removed unjustified skip flags from rewrite rules (git status, git log, gh list)

### Added
- Jest / npx jest rewrite rules for test output compression
- `pub(crate) would_rewrite()` API for discover/rewrite alignment
- `--debug` flag for `skim discover` command

### Testing
- **2,223 tests passing** (consolidated from 2,306 in v2.3.0 via PR #130 alignment work)

## [2.3.0] - 2026-04-08

Minor release: Stats dashboard v3, debug-gated warnings, git fetch compression.

### Added
- `skim git fetch` subcommand — parses git fetch output (ref updates, new branches/tags, pruned refs, forced updates, submodule fetches)
- `--debug` flag and `SKIM_DEBUG` env var — gates `[skim:warning]`/`[skim:notice]` stderr markers (silent by default)
- `transform_with_quality()` public API in rskim-core — returns parse quality flag alongside content
- Enriched degradation markers across all 23 parsers (e.g., `"eslint: JSON parse failed, using regex"`)
- Stats dashboard v3 — green-only efficiency colors, daily trend subtitle, parse tier tracking

### Fixed
- Parse tier tracking through ProcessResult/cache/analytics chain
- Git diff rewrite rules: added `--shortstat`/`--numstat` to skip-flags
- `parse_fetch` submodule context bug (refs after submodule block incorrectly attributed)
- Debug module: atomic ordering upgraded to Release/Acquire, env var cached at startup
- Test pollution: `force_enable_debug()` now has `reset_debug_for_tests()` cleanup

### Testing
- **2,306 tests passing** (up from 2,226 in v2.2.0)

## [2.2.0] - 2026-04-06

Minor release: File, log, and infrastructure output compression (12 new tool parsers), learn command fix, rewrite/discover integration.

### Added — File Output Compression (`skim file`)
- New subcommand: `skim file <tool> [args...]`
- Supported tools: find, ls, tree, grep, rg
- grep/rg deduplication and match grouping
- Item limits and byte caps for large outputs

### Added — Log Output Compression (`skim log`)
- New subcommand: `skim log [args...]`
- JSON structured log deduplication with counts
- Regex-based plaintext log deduplication
- Debug/trace level filtering with `--debug-only` and `--keep-debug`
- Stack trace collapsing

### Added — Infrastructure Output Compression (`skim infra`)
- New subcommand: `skim infra <tool> [args...]`
- Supported tools: gh, aws, curl, wget
- Metadata stripping, pagination removal, response body extraction

### Added — Lint Extensions
- prettier check-mode output compression
- rustfmt check-mode output compression

### Added — Integration
- Rewrite rules updated for file, log, and infra subcommands
- Discover integration for new subcommands
- Shell completions for new subcommands

### Fixed
- Router: subcommands always take priority over filesystem paths (no more collisions with files/dirs named `test`, `log`, etc.)
- Learn command: fixed guidance injection and improved error handling (#115)

### Testing
- **2,226 tests passing** (up from 1,993 in v2.1.0 — 12% increase)

## [2.1.0] - 2026-04-01

Minor release: Kotlin + Swift language support (17 total), AST-aware git diff, lint and package manager output compression, canonical output types, and expanded rewrite rules.

### Added — Language Support
- **Kotlin** — data classes, sealed classes, coroutines, interfaces (tree-sitter-kotlin-ng)
- **Swift** — protocols, generics, SwiftUI structs (tree-sitter-swift)
- Now 17 languages total (was 15 at v2.0.0)

### Added — AST-Aware Git Diff (`skim git diff`)
- Function-boundary-aware diff rendering with `+`/`-` markers
- `--mode structure` — adds unchanged functions as signatures for architectural context
- `--mode full` — shows entire files with change markers
- `--json` output for machine-readable diff results
- Supports `--staged`, commit ranges (`HEAD~3`, `main..feature`), and all git diff flags

### Added — Lint Output Compression (`skim lint`)
- New subcommand: `skim lint <linter> [args...]`
- Supported linters: ESLint (JSON + text), Ruff (JSON + text), mypy (JSON + text), golangci-lint (JSON + text)
- Canonical `LintResult` output with severity grouping
- Three-tier degradation: Structured → Regex → Passthrough

### Added — Package Manager Output Compression (`skim pkg`)
- New subcommand: `skim pkg <tool> [subcmd] [args...]`
- npm: audit, install, ls, outdated
- pnpm: audit, install, outdated
- pip: install, check, outdated
- cargo: audit
- Input sanitization for terminal escape injection prevention

### Added — Infrastructure
- **Canonical output module** — strongly-typed `TestResult`, `LintResult`, `GitResult` types with `Display` that is compact on success, verbose on failure
- **Expanded rewrite rules** — `skim rewrite` now covers lint and pkg commands

### Changed — Architecture
- Git module refactored into `diff/`, `log.rs`, `status.rs` submodules
- AST diff pipeline: `parse.rs` → `ast.rs` → `source.rs` → `render.rs` → `types.rs`
- Tech debt from PRs #106 and #107 resolved

### Testing
- **1,993 tests passing** (up from 1,594 in v2.0.0 — 25% increase)
- New test suites: `cli_diff.rs`, `cli_e2e_lint_parsers.rs`, `cli_e2e_pkg_parsers.rs`, `cli_e2e_rewrite.rs`
- New fixtures: diff, lint, pkg, C#, Ruby, SQL, Kotlin, Swift

## [2.0.0] - 2026-03-28

Major release: skim evolves from a streaming code reader into a full context optimization engine for AI coding agents. Adds command output compression, agent hook integration, persistent analytics, and MCP server mode.

### Added — Command Output Compression
- **Test Output Parsers** — cargo test (`--message-format=json`), pytest (`--tb=short`), vitest/jest (`--reporter=json`), go test (`-json`) with three-tier degradation: Structured → Regex → Passthrough
- **Git Output Compression** — `skim git` compresses `git status`, `git diff`, `git log` output
- **Build Output Compression** — `skim build` compresses `cargo build`, `cargo clippy`, `tsc` output
- **Three-Tier Parse Degradation** — all parsers gracefully degrade: Structured JSON → Regex fallback → Passthrough (never corrupts output)
- **Output Guardrail** — compressed output is guaranteed never larger than raw input
- **Raw Output Recovery** — on parse failure, original output preserved via tee/recovery system

### Added — Agent Integration
- **`skim init`** — one-command hook installation for 6 AI agents: Claude Code, Cursor, Codex, Gemini, Copilot, OpenCode
- **`skim rewrite`** — declarative command rewriting engine with `--hook` mode for agent integration
- **Compound Shell Support** — rewrite engine handles piped commands and `&&`/`||` chains
- **`skim init --uninstall`** — clean hook removal with SHA-256 integrity verification
- **Multi-Agent Session Support** — discover and learn commands work across all 6 agent session formats

### Added — Token Analytics & Intelligence
- **`skim stats`** — persistent SQLite-based analytics dashboard with per-command savings, daily/weekly trends
- **`skim stats --cost`** — cost estimation with configurable $/MTok rate (`SKIM_INPUT_COST_PER_MTOK`)
- **`skim stats --format json`** — machine-readable analytics export
- **`skim discover`** — scan agent session history to identify missed optimization opportunities
- **`skim learn`** — detect CLI error-retry patterns and generate correction rules
- **Fire-and-forget recording** — analytics never blocks main output path (background threads)

### Added — Infrastructure
- **MCP Server Mode** — native Model Context Protocol integration for agent-native workflows
- **Shell Completions** — `skim completions bash|zsh|fish` for all subcommands
- **Homebrew Distribution** — `brew install dean0x/tap/skim`
- **`skim agents`** — display detected AI agents and their hook/session status (`--json`)
- **Pre-parse Router** — CLI subcommand dispatch without full argument parsing

### Added — Code Reading Enhancements
- **Pseudo Mode** — code-aware output with simplified bodies (human-readable, not just structural)
- **Gitignore Support** — `--no-ignore` override for directory traversal
- **`--last-lines N`** — show last N lines of output (tail mode)

### Changed
- Analytics database at `~/.cache/skim/analytics.db` (SQLite with WAL mode)
- `--clear-cache` clears parser cache only; `skim stats --clear` resets analytics
- Versioned database migrations (v1: token_savings, v2: analytics_meta)

### Architecture
- Extracted `cascade`, `process`, and `multi` modules from monolithic main.rs
- Agent detection centralized via `AgentKind` with SRP extraction
- `AnalyticsStore` trait enables mock-based testing without real database
- `OutputParser` trait standardizes command output compression interface

### Testing
- **1,594 tests passing** (up from 145 in v1.0.0 — 11x increase)
- End-to-end tests for all command compression paths
- Multi-agent session provider tests
- Analytics pipeline integration tests
- Three-tier degradation coverage for all parsers

## [1.0.0] - 2026-03-18

This is the first stable release. All publicly exported types and functions in `rskim-core` are
considered stable from this version forward. Users on `rskim-core = "0.9"` should update their
dependency to `rskim-core = "1.0"`.

### Added
- **Minimal Mode** (`--mode=minimal`) — aggressive transformation for maximum token reduction
- **Token Budget** (`--tokens N`) — cascade through modes to fit a target token count
- **Max Lines** (`--max-lines N`) — AST-aware smart truncation
- **C Language Support** — full C11 with tree-sitter
- **C++ Language Support** — C++20 including templates, namespaces, classes
- **TOML Language Support** — serde-based structure extraction
- **`--lang` alias** for `--language` flag
- **`--filename` flag** for stdin language detection from path
- **Skimmer plugin** for Claude Code — codebase orientation agent

### Changed
- Public API marked stable (`rskim-core` exports considered stable from this release)
- Unified node-kind tables and marker budget handling
- Encapsulated `truncate_to_token_budget` behind stable public API

### Fixed
- Eliminated redundant tokenization and binary search allocation churn
- Wave 1 tech debt cleanup (from issue #28)

### Performance
- Token budget cascade avoids re-parsing and redundant token counting

### Testing
- 145 tests passing (134 unit + 11 doc-tests)
- 12 languages supported: TypeScript, JavaScript, Python, Rust, Go, Java, C, C++, Markdown, JSON, YAML, TOML

## [0.9.0] - 2026-03-16

### Added
- **C Language Support** - Extract structure from C source files using tree-sitter
  - Full C11 support with excellent grammar coverage
  - Automatic language detection for `.c` and `.h` files
  - CLI support: `--language=c` for stdin processing
  - Supports all transformation modes (structure/signatures/types/full)
  - Function body stripping, struct/union/enum preservation
  - Test fixtures: functions, structs, enums, pointers, preprocessor directives

- **C++ Language Support** - Extract structure from C++ source files using tree-sitter
  - C++20 support including templates, classes, namespaces
  - Automatic language detection for `.cpp`, `.hpp`, `.cc`, `.hh`, `.cxx`, `.hxx` files
  - CLI support: `--language=cpp` for stdin processing
  - Supports all transformation modes (structure/signatures/types/full)
  - Class/template/namespace preservation with body stripping
  - Test fixtures: classes, templates, namespaces, inheritance, modern C++ features

- **TOML Language Support** - Extract structure from TOML configuration files
  - Strips all values, keeps only keys and nesting structure
  - Automatic language detection for `.toml` files
  - CLI support: `--language=toml` for stdin processing
  - Security limits: MAX_TOML_DEPTH=500, MAX_TOML_KEYS=10,000
  - Uses toml crate (Strategy Pattern for non-tree-sitter languages)
  - All modes (structure/signatures/types) produce identical output (TOML is data, not code)
  - Test fixtures: Cargo.toml-style configs, nested tables, arrays of tables

### Testing
- **400 total tests** - All passing (up from 186 in v0.8.0)
  - New C language tests (CLI and integration)
  - New C++ language tests (CLI and integration)
  - New TOML language tests (CLI and integration)

## [0.8.0] - 2025-12-06

### Added
- **YAML Language Support** - Extract structure from YAML files for LLM context optimization
  - Strips all values, keeps only keys and nesting structure
  - Multi-document support (preserves `---` separators between documents)
  - Automatic language detection for `.yaml` and `.yml` files
  - CLI support: `--language=yaml` or `--language=yml` for stdin processing
  - 60-80% token reduction for typical YAML files
  - Security limits: MAX_YAML_DEPTH=500, MAX_YAML_KEYS=10,000
  - Uses serde_yaml_ng (maintained fork, Strategy Pattern for non-tree-sitter languages)
  - All modes (structure/signatures/types) produce identical output (YAML is data, not code)
  - Real-world fixtures: Kubernetes manifests, GitHub Actions workflows
  - Note: Anchors/aliases are resolved by serde_yaml_ng parser (not preserved in output)

## [0.7.0] - 2025-11-16

### Added
- **JSON Language Support** - Extract structure from JSON files for LLM context optimization
  - Strips all values, keeps only keys and nesting structure
  - Automatic language detection for `.json` files
  - CLI support: `--language=json` for stdin processing
  - 60-80% token reduction for typical JSON files
  - Security limits: MAX_JSON_DEPTH=500, MAX_JSON_KEYS=10,000
  - Uses serde_json (Strategy Pattern for non-tree-sitter languages)
  - All modes (structure/signatures/types) produce identical output (JSON is data, not code)

### Changed
- **Architecture Improvement** - Strategy Pattern for language-specific parsing
  - `Language::transform_source()` routes each language to appropriate parser
  - Non-tree-sitter languages (JSON, future YAML/TOML) handled cleanly
  - Type-safe Option returns instead of unreachable!() panics
  - Eliminates special-case conditionals in transform function

### Fixed
- Type safety violations in transform modules (replaced unreachable!() with Option types)
- Missing JSON in CLI language argument options

## [0.6.1] - 2025-11-12

### Added
- **ARM64 Linux Support** - Added `aarch64-unknown-linux-gnu` target for Linux ARM64 systems
  - Fixes npm installation on ARM64 Linux (Raspberry Pi, AWS Graviton, etc.)
  - Uses cross-compilation via `cross-rs` for reliable builds
  - npm package now includes `bin/linux/arm64/skim` binary
  - Updated platform support documentation

### Security
- **HIGH**: Semantic version validation to prevent command injection in release workflow
- **CRITICAL**: Pin cross-rs to stable v0.2.5 from crates.io (supply chain hardening)
- **HIGH**: Pin Ubuntu runner to 22.04 for deterministic QEMU version
- **MEDIUM**: Quote glob patterns in artifact extraction (shell injection prevention)
- **MEDIUM**: Use quoted HERE-doc for package.json generation (JSON injection prevention)

### Fixed
- npm installation failure on ARM64 Linux platforms
- Version consistency checks now prevent Cargo.toml/tag mismatches
- Code formatting (rustfmt) across all source files

### Changed
- **Smoke Tests in CI** - All release binaries now verified before publishing
  - Native platform tests execute `--version` and basic transformation
  - ARM64 Linux tested via QEMU emulation
  - Prevents shipping broken cross-compiled binaries
- **Comprehensive Test Suites** - 38 new security regression tests
  - npm wrapper test suite (21 tests) validates platform detection and error handling
  - Version check validation tests (17 tests) ensure regex extraction correctness
  - Tests run automatically in CI before builds
  - Prevents security regressions (command injection, shell injection, JSON injection)
- **Improved npm Error Messages** - Better diagnostics for installation failures
  - Lists all supported platforms explicitly
  - Distinguishes "unsupported platform" from "packaging bug" from "libc mismatch"
  - Suggests `cargo install rskim` workaround when appropriate
  - Detects Alpine Linux (musl) incompatibility and provides guidance
- CI/CD now builds 5 platform targets (was 4)
- Release workflow uses `cross` for ARM64 Linux cross-compilation

## [0.6.0] - 2025-10-23

### Added
- **Directory Support** - Process entire directories recursively
  - Process directories: `skim src/`, `skim .`
  - Recursive traversal of all subdirectories
  - Mixed-language support (process `.ts`, `.py`, `.rs` files in same directory)
  - Works with all existing flags (`--mode`, `--jobs`, `--show-stats`, etc.)
  - Compatible with caching and parallel processing

### Security & Hardening
- **Critical security fix** - Symlink detection bug in directory traversal
  - Changed from `entry.metadata()` to `path.symlink_metadata()`
  - Previous bug: `metadata()` follows symlinks, so `is_symlink()` check never triggered
  - Impact: Directory processing could follow symlinks to sensitive files
  - Now correctly detects and rejects symlinks for security

### Improvements
- **Language Detection** - Auto-detection is now primary, `--language` is fallback
  - Language detection always tries auto-detect from file extension first
  - `--language` flag now acts as fallback/override when auto-detection fails
  - Better experience: Most files "just work" without manual flag
  - Breaking change: None (backward compatible behavior)

### Code Quality
- Added `MAX_JOBS` constant (was magic number 128)
- Extracted `MultiFileOptions` struct to reduce function parameters (8 → 3)
- Added explanatory comments for symlink security checks
- Refactored `process_files()` for reuse by glob and directory inputs

### Documentation
- Updated README with directory examples and real-world use cases
- Added real-world benchmarks: 60-91% token reduction on 80-file codebase
- Clarified auto-detection is default, `--language` is fallback
- Updated CLI help text with directory processing examples
- Refactored documentation structure: moved detailed content to `docs/` folder
- Modernized README messaging and improved storytelling
- Added professional badges (crates.io, npm, downloads, Rust version)

### Testing
- **128 total tests** - All passing (+13 tests from v0.5.0's 115)
  - Added 13 new directory processing tests (`cli_directory.rs`)
  - Tests cover single/mixed languages, recursive directories, edge cases
  - Comprehensive testing of symlink rejection security fix

### Performance
- Maintains <50ms target for individual file processing
- Caching works seamlessly with directory processing
- Parallel processing with `--jobs` flag applies to directories
- Real-world verified: 80-file Next.js codebase processed efficiently

### Breaking Changes
None. All changes are backward compatible.

## [0.5.0] - 2025-10-21

### Added
- **Markdown Support** - Extract document structure from markdown files
  - Support for `.md` and `.markdown` file extensions
  - **Structure mode** - Extracts H1-H3 headers only (document outline)
  - **Signatures/Types modes** - Extracts all headers H1-H6 (complete structure)
  - **Full mode** - Returns original markdown unchanged
  - Supports both ATX headers (`# Title`) and Setext headers (underlined)
  - Auto-detection from file extension

### Internal
- New test fixture: `tests/fixtures/markdown/simple.md`
- Added 10 CLI integration tests for markdown (`cli_markdown.rs`)
- Added 4 core library unit tests for markdown (`integration.rs`)
- Updated `supported_languages()` API to include Markdown
- Added `Language::Markdown` to CLI `LanguageArg` enum

### Security & Hardening
- Added `MAX_MARKDOWN_DEPTH` (500) limit to prevent stack overflow
- Added `MAX_MARKDOWN_HEADERS` (10,000) limit to prevent memory exhaustion
- Improved setext header detection using AST instead of text matching
- Depth tracking in markdown AST traversal

### Dependencies
- **Updated** tree-sitter from 0.23 to 0.25 (ABI 15 support)
- **Updated** tree-sitter-javascript from 0.23 to 0.25
- **Updated** tree-sitter-python from 0.23 to 0.25
- **Updated** tree-sitter-go from 0.23 to 0.25
- **Added** tree-sitter-md 0.5 (markdown grammar)

### Testing
- **115 total tests** - All passing (+14% increase from v0.4.0's 101 tests)
  - 10 new markdown CLI tests
  - 4 new markdown integration tests
  - All existing tests continue to pass

### Breaking Changes
None. Markdown support is additive and auto-detected by file extension.

## [0.4.0] - 2025-10-17

### Added
- **Multi-file Glob Support** - Process multiple files with wildcard patterns
  - Glob pattern matching: `skim 'src/**/*.ts'`, `skim '*.{js,ts}'`
  - File header separators for multi-file output
  - `--no-header` flag to disable headers in multi-file mode
  - Recursive directory traversal with glob patterns

- **Parallel Processing** - Rayon-powered multi-core processing
  - `--jobs` flag for configurable parallelism (default: number of CPUs)
  - 2.4x speedup demonstrated with `--jobs 4`
  - Efficient thread pool management
  - Scales linearly with CPU cores

- **File-based Caching** - Massive speedup on repeated processing
  - **Enabled by default** for 40-50x speedup on cached reads
  - SHA256 cache keys with mtime-based invalidation
  - Platform-specific cache directory (`~/.cache/skim/`)
  - `--no-cache` flag to disable caching
  - `--clear-cache` command to clear cache directory
  - Smart invalidation on file modification

- **Token Counting** - Measure LLM context window savings
  - `--show-stats` flag shows token reduction statistics
  - Uses tiktoken with cl100k_base encoding (GPT-3.5/GPT-4 compatible)
  - Works with single files, globs, and stdin
  - Aggregates stats across multiple files
  - Output to stderr for clean piping

### Performance
- **Verified benchmarks**: 14.6ms for 3000-line files (3x faster than 50ms target)
- **Cached reads**: 5ms average (40-50x speedup)
- **Parallel processing**: 2.4x speedup with 4 cores
- **Token reduction**: 60-95% depending on mode

### Internal
- New module: `crates/rskim/src/cache.rs` - Caching implementation
- New module: `crates/rskim/src/tokens.rs` - Token counting with tiktoken
- Major refactor: `crates/rskim/src/main.rs` - Integrated all Phase 3 features
- Architecture cleanup: Removed unused exports, clarified core/CLI boundaries
- Dependencies added: glob, rayon, dirs, serde, serde_json, sha2, tiktoken-rs

### Documentation
- Updated all READMEs with Phase 3 features
- Updated CLAUDE.md to reflect 100% completion (70 tests passing)
- Updated CONTRIBUTING.md with accurate crate names and performance targets
- Fixed benchmark imports for consistency

### Security & Hardening
- **Path traversal prevention** - Glob patterns reject absolute paths and `..` components
- **Symlink filtering** - Glob processing skips symlinks to prevent sensitive file access
- **Secure cache permissions** - Cache directory set to 0700, files to 0600 (Unix)
- **Integer overflow protection** - Fixed overflow in token reduction calculation for edge cases

### Performance Optimizations
- **Lazy tokenizer initialization** - Using `OnceLock` to avoid recreating tokenizer on every call
- **Token count caching** - Extended `CacheEntry` struct to store token counts, eliminating double file reads
- **Improved glob validation** - Added `--jobs` upper bound validation (max 128) to prevent resource exhaustion

### Code Quality Improvements
- **Named return types** - Replaced tuple returns with `ProcessResult` struct for clarity
- **Reduced function parameters** - Created `ProcessOptions` struct (5 params → 1 struct)
- **Helper functions** - Extracted `report_token_stats()` to eliminate code duplication
- **Clippy fixes** - Renamed `Mode::from_str()` to `Mode::parse()` to avoid standard library conflicts
- **Lifetime cleanup** - Removed unnecessary lifetime annotations

### Dependencies
- **Updated** tiktoken-rs from 0.5 to 0.7 (latest stable)
- **Updated** dirs from 5.0 to 6.0 (latest stable)

### Testing
- **101 total tests** - All passing (+44% increase from v0.3.3's 70 tests)
  - 8 unit tests
  - 19 CLI tests
  - 10 glob pattern tests (NEW)
  - 9 caching tests (NEW)
  - 12 token stats tests (NEW)
  - 11 rskim-core tests
  - 24 integration tests
  - 8 doc tests
- Verified parallel processing with CPU usage tests
- Verified caching with repeated file processing
- Verified token counting accuracy
- Comprehensive glob security testing (path traversal, symlink rejection)

### Breaking Changes
None. All new features are opt-in via CLI flags.

## [0.3.3] - 2025-10-16

### Fixed
- **CLI README (crates.io)** - Critical branding and command errors
  - Title changed from "# rskim" to "# Skim" (official brand name)
  - Overview text changed from "rskim transforms..." to "**Skim** transforms..."
  - Fixed broken npx commands: `npx skim file.ts` → `npx rskim file.ts` (2 occurrences)

**Context**: The CLI README is displayed on crates.io and was showing incorrect branding and broken commands that would not work.

**Important distinction:**
- **Brand name**: Skim (official name)
- **Package name**: rskim (for `npm install -g rskim`, `npx rskim`, `cargo install rskim`)
- **Binary name**: skim (after installation: `skim file.ts`)

## [0.3.2] - 2025-10-16

### Fixed
- **Main README** - Project status showed outdated version (v0.2.3 → v0.3.1)
- **Main README** - Planned features example still used old binary name (`rskim` → `skim`)
- **Core library README** - Dependency version example showed `"0.2"` instead of `"0.3"`
- **Core library** - Doc tests and integration tests used wrong crate name (`skim_core` → `rskim_core`)
  - Affected files: `lib.rs`, `types.rs`, `integration.rs`, `transform/mod.rs`
  - All doc examples now use correct `rskim_core` import
  - Fixed unused import warning in transform module

**Context**: Documentation and naming issues discovered after v0.3.1 release. The `skim_core` references were remnants from original project naming before the v0.2.1 rename to `rskim`.

## [0.3.1] - 2025-10-16

### Fixed
- CLI README documentation still referenced old language names (`type-script`, `java-script`)
- Test files using incorrect language flag format (should be `typescript`, not `type-script`)
- Test version assertion updated to match current version (0.3.0 → 0.3.1)

**Context**: These issues were overlooked in v0.3.0 release. Language names were changed to lowercase in v0.2.4, but some documentation and test references weren't updated.

## [0.3.0] - 2025-10-16

### Changed
- **BREAKING:** Binary name changed from `rskim` to `skim`
  - Installation still uses `rskim`: `npm install -g rskim` or `cargo install rskim`
  - Command usage now uses `skim`: `skim file.ts` (shorter, cleaner)
  - Official branded name: **Skim**
  - Package name remains `rskim` to avoid conflicts

### Migration
```bash
# Installation (unchanged)
npm install -g rskim
cargo install rskim

# Old command (v0.2.x)
rskim file.ts

# New command (v0.3.0+)
skim file.ts
```

**Rationale**: Shorter command for daily use. Package name `rskim` avoids npm/crates.io namespace conflicts.

## [0.2.4] - 2025-10-16

### Fixed
- **BREAKING:** Language flag names now use lowercase instead of kebab-case
  - `--language=type-script` → `--language=typescript`
  - `--language=java-script` → `--language=javascript`
  - Short aliases still work: `--lang=ts`, `--lang=js`
- All README files updated to reflect current state (npm live, correct package names)
- CHANGELOG now includes all historical versions (0.2.1, 0.2.2, 0.2.3)
- Error message fixed: `skim` → `rskim`

### Changed
- Installation documentation now recommends `npx` for trial usage
- Clarified npx performance trade-offs (~100-500ms overhead per invocation)

## [0.2.3] - 2025-10-15

### Fixed
- npm wrapper script syntax error (template literal escaping)
- Binary now works correctly when installed via npm

## [0.2.2] - 2025-10-15

### Added
- npm distribution via GitHub Actions
- Automated cross-platform binary building (Linux, macOS x64/ARM, Windows)
- npm package published as `rskim`

### Fixed
- GitHub Actions workflow for npm publishing

## [0.2.1] - 2025-10-15

### Changed
- **BREAKING:** Renamed all packages to `rskim` for consistency
  - `skim-core` → `rskim-core`
  - `skim-cli` → `rskim` (binary also renamed)
  - Updated repository URLs to https://github.com/dean0x/skim
- Simplified distribution strategy: native CLI only (removed WASM)
- Configured cargo-dist for npm distribution as `rskim`

### Migration Guide
```bash
# Old (v0.1.0)
cargo install skim-cli

# New (v0.2.0+)
cargo install rskim

# Or via npm
npm install -g rskim
npx rskim file.ts  # no install required
```

## [0.1.0] - 2025-10-15

### Added
- 🎉 **Initial release** - Production-ready CLI tool

**Core Features:**
- Multi-language support: TypeScript, JavaScript, Python, Rust, Go, Java
- Four transformation modes: structure (70-80%), signatures (85-92%), types (90-95%), full (0%)
- CLI with stdin support and language auto-detection
- UTF-8/Unicode support (emoji, Chinese, multi-byte characters)
- Streaming output to stdout for pipe workflows

**Testing:**
- 62 total tests (11 unit, 24 integration, 19 CLI, 8 doc tests)
- 100% test pass rate
- Performance benchmarking suite with criterion
- Real-world testing on complex codebases

**Security:**
- Stack overflow protection (max recursion depth: 500)
- Memory exhaustion protection (max input: 50MB, max nodes: 100k)
- UTF-8 boundary validation (prevents panics)
- Path traversal protection (rejects `..` components)
- DoS-resistant with comprehensive input validation

**Developer Experience:**
- Comprehensive error messages
- Help and version flags
- Language detection with file extensions
- Explicit language override with `--language` flag

### Fixed
- Overlapping replacements bug in structure mode (nested functions)
- Path traversal validation (now allows absolute paths correctly)
- tree-sitter version compatibility (pinned to 0.23.x)
- Removed duplicate parser implementation
- Cleaned up unused code warnings

### Technical
- Zero-copy string operations where possible
- Streaming stdout output with buffering
- Error-tolerant parsing (handles incomplete/broken code gracefully)
- No panics in library code (enforced by clippy lints)
- Clean builds with comprehensive test coverage

---

## Version History

- **2.10.0** (2026-05-13): Container/cloud/database compression, search crate foundation, heatmap insights (3,558 tests)
- **2.9.0** (2026-05-08): Heatmap analysis, system utility parsers, curl hardening (3,310 tests)
- **2.8.0** (2026-05-07): Flat dispatch, Crush agent, multi-file args (3,103 tests)
- **2.7.0** (2026-05-01): Line numbers, session tracking, output sanitization (3,002 tests)
- **2.6.0** (2026-04-27): Terminal UX overhaul, non-interactive init, plugin ecosystem removal (2,883 tests)
- **2.5.1** (2026-04-20): Hook safety, SKIM_PASSTHROUGH bypass, npx fallback, 5 new parsers (2,800 tests)
- **2.5.0** (2026-04-17): Formatter output compression, 8 new lint parsers (2,629 tests)
- **2.4.1** (2026-04-15): Stats dashboard redesign, weighted %, by-command breakdown, --cost deprecation (2,482 tests)
- **2.4.0** (2026-04-14): GitHub CLI compression, git subcommand completion, quality improvements (2,482 tests)
- **2.3.1** (2026-04-09): Discover/rewrite alignment, rewritable gap closures, stats bar fix
- **2.3.0** (2026-04-08): Stats dashboard v3, debug-gated warnings, git fetch compression, parse tier tracking
- **2.2.0** (2026-04-06): File, log, infra output compression (12 new parsers), learn fix, rewrite/discover integration
- **2.1.0** (2026-04-01): Kotlin + Swift, AST-aware git diff, lint/pkg compression, canonical output
- **2.0.0** (2026-03-28): Context optimization engine — command compression, agent hooks, analytics, MCP server
- **1.0.0** (2026-03-18): First stable release — minimal mode, token budgets, max-lines, C/C++/TOML, skimmer plugin
- **0.9.0** (2026-03-16): C, C++, and TOML language support (12 languages total, 400 tests)
- **0.8.0** (2025-12-06): YAML language support
- **0.4.0** (2025-10-17): Multi-file glob support, caching, parallel processing, token counting (Phase 3 complete)
- **0.3.3** (2025-10-16): CLI README branding and broken npx command fixes
- **0.3.2** (2025-10-16): README documentation alignment fixes
- **0.3.1** (2025-10-16): Hotfix for remaining language name references in docs/tests
- **0.3.0** (2025-10-16): Binary renamed to `skim`, package remains `rskim`
- **0.2.4** (2025-10-16): Fixed language flag names, updated all documentation
- **0.2.3** (2025-10-15): Fixed npm wrapper script syntax
- **0.2.2** (2025-10-15): npm distribution via GitHub Actions
- **0.2.1** (2025-10-15): Renamed package to rskim with comprehensive documentation
- **0.1.0** (2025-10-15): Initial release as skim-cli

---

## Links

- [Repository](https://github.com/dean0x/skim)
- [Issues](https://github.com/dean0x/skim/issues)
- [Security Policy](SECURITY.md)
- [Contributing Guide](CONTRIBUTING.md)
