Skip to content

v2.7.1

Choose a tag to compare

@ppgranger ppgranger released this 04 Aug 19:14
· 36 commits to production since this release
fb8f1df

Token-Saver 2.7.1

Security and correctness release. Five audit-flagged bugs fixed (one of them
a genuine secret-leak path), plus a full pass to bring the shipped docs back
in line with the actual code.

Security fixes

  • Redacted secrets could leak back to the model. The compression-ratio
    gate exists to discard a processor's output and fall back to the raw input
    when the result isn't smaller by min_compression_ratio. For .env
    secret redaction, "the result" is API_KEY=*** and "the raw input" is the
    secret in the clear — so a short secret that didn't shrink the output
    enough was silently returned unredacted. A second, independent leak
    existed in the mismatch-fallback path, which re-ran the generic processor
    on the original unredacted output instead of the already-redacted one.
    Both paths are now short-circuited whenever a processor reports it
    redacted something for that call. Two regression tests cover both leak
    paths, plus a control test confirming ordinary compression is unaffected.

  • A cloned repo could achieve code execution or disable secret redaction.
    .token-saver.json is auto-discovered by walking up from the current
    directory — including a repo you just cloned and haven't reviewed yet.
    user_processors_dir is imported as Python on the next Bash command, so a
    project-level config could previously get arbitrary code to run.
    disabled_processors and redaction_allowlist could silently turn off
    the redaction safety net. All three keys are now only honored from the
    global ~/.token-saver/config.json or environment variables, never from
    a project file.

Correctness fixes

  • BuildOutputProcessor no longer reports "Build succeeded." on a failed
    run
    when the failure text doesn't contain a literal "error" — e.g.
    jest's bare FAIL, make's Failure N, ninja/rollup wording. Processors
    can now opt into seeing the real exit code as a last-resort signal.
  • Fixed false-positive "critical" lines pushing real errors out of
    capped output. The critical-line matcher was one case-insensitive pattern
    that also matched ordinary words like "Extracting" or "Entry"; it's now
    split into a case-insensitive vocabulary pattern and a case-sensitive
    symbol pattern (errno/signal names, bare E prefix).
  • Fixed silently dropped output in chained commands. A chain segment
    with no trailing newline (e.g. printf without \n) could glue the next
    segment's boundary marker onto the same line, breaking the split and
    losing that segment's output with no warning.
  • Hardened command-eligibility detection: 2>&1-style file-descriptor
    duplication is no longer mistaken for a real redirection (more commands
    are now eligible for compression); an unquoted background &, an
    unquoted non-continuation newline, and open shell constructs
    (for/while/if/case/select) are now correctly excluded. The
    rewritten command is also syntax-checked with a real shell -n check
    before it runs, falling back to the original, uncompressed command if the
    rewrite wouldn't parse.

Documentation

The shipped docs had drifted from the actual code in several places users
would hit directly:

  • skills/token-saver-config/SKILL.md documented a token-saver config set
    subcommand that doesn't exist, and four config keys/defaults that were
    wrong or invented. Rewritten to match the real config precedence and
    defaults.
  • commands/token-saver-stats.md's documented fallback command crashed
    with ModuleNotFoundError. Fixed to use the bundled CLI wrapper.
  • README's "Complete Parameter List" had drifted on most of its rows
    (e.g. min_input_length documented as 200, actually 1). Every row is
    now regenerated from src/config.py's real defaults, and a new test
    (tests/test_readme_config_sync.py) fails CI on the next drift instead
    of waiting for another audit.
  • "Zero added latency" replaced with a measured ~60ms/command overhead.
  • The .env redaction claim is now precise: .env.production, .env.local,
    etc. are redacted; bare .env, .env.example, .env.template are
    intentionally left untouched.
  • The Before/After compression table now uses the same figures the CI
    ratchet (tests/compression_baselines.json) actually locks in, instead of
    numbers that had quietly drifted from what the engine measures today.
  • README substantially expanded: table of contents, quick start,
    who-it's-for, worked real-output examples per tool, a full CLI reference,
    tuning recipes, an expanded security section, measured performance
    numbers, an FAQ, and a troubleshooting section.

Verification

Full suite: 1,319 passed, 12 skipped. ruff check, ruff format --check,
and mypy all clean. Compression ratchet unchanged — no baseline
regeneration needed.

Upgrading

token-saver update

or, for a manual install:

cd token-saver && git pull && python3 install.py --target claude

No config or data migration is required.