npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

coverage-cat

v1.0.0

Published

LLM-native coverage-annotated file viewer. Renders LNCAF format for AI-readable code coverage.

Readme

covcat

LLM-native coverage-annotated file viewer.

covcat reads a source file and overlays code coverage data from your test suite, producing output in LNCAF (LLM-Native Coverage Annotation Format) --- a text format designed for AI consumption, not human IDE gutters. Every executable line gets a coverage gutter marker. An LLM reading covcat output goes from coverage-blind to coverage-aware in a single tool call.

/* COV: src/orders.ts | | covered  . uncovered  ? partial  [B:x/y]=branches  [FN+/-]=function
   Collected: 2026-04-01 | lines: 5/12 (42%) | branches: 1/4 (25%)
*/
[FN+]     1->function processOrder(order: Order): Result {
|         2->  const validated = validateOrder(order);
?         3->  if (!validated) {                            [branch: else never taken]
.         4->    throw new ValidationError('Invalid order');
.         5->  }
|         6->  const pricing = calculatePrice(order.items);
?         7->  if (pricing.discount > 0) {                  [branch: both paths uncovered]
.         8->    applyDiscount(pricing);
.         9->  } else {
.        10->    pricing.discount = 0;
.        11->  }
|        12->  return fulfillOrder(order, pricing);
         13->}

An LLM reading this immediately knows: line 4 is untested (.), line 3 has a partial branch (?) where the else path is never taken, and lines 8--11 have zero coverage. Instead of guessing what needs testing, it can write "a test where validateOrder returns false" --- a concrete, actionable instruction derived from the annotation.


Table of Contents


Installation

# Clone and install
git clone <repo-url> covcat && cd covcat
yarn install

# Build
yarn build

# Link globally (optional)
npm link

Requires Node.js 18+ and Yarn 4.


Quick Start

# 1. Run your tests with coverage first
yarn test:coverage        # or: npx vitest --coverage

# 2. View coverage-annotated source
npx covcat src/utils.ts

# 3. That's it. covcat auto-discovers coverage data.

If you have coverage/coverage-final.json (Jest/Vitest) or coverage/lcov.info anywhere in your project tree, covcat finds it automatically.


LNCAF Format

LNCAF defines a single-character left-margin gutter on every executable line, with optional directional branch suffixes. Three tiers trade detail for token efficiency.

Gutter Vocabulary

| Marker | Meaning | |--------|---------| | \| | Line covered (executed at least once) | | . | Line uncovered (0 executions) | | ? | Branch statement, at least one path untaken | | | Non-executable line (blank, comment, closing brace) | | [FN+] | Function entry, called | | [FN-] | Function entry, never called |

Compact Tier (~1.2 tokens/line)

Minimal. Single-char gutter only. Best for large files (800+ lines) or batch scans.

// cov: | covered  . uncovered  ? partial branch
|  1->export function add(a, b) {
|  2->  return a + b;
   3->}

Standard Tier (~1.6 tokens/line) --- default

Gutter + function markers + directional branch suffixes. Best for interactive agentic workflows and test generation.

/* COV: src/math.ts | | covered  . uncovered  ? partial  [B:x/y]=branches  [FN+/-]=function
   Collected: 2026-04-01 | lines: 6/8 (75%) | branches: 1/2 (50%)
*/
[FN+]     1->export function divide(a: number, b: number): number {
?         2->  if (b === 0) {                               [branch: else never taken]
.         3->    return 0;
.         4->  }
|         5->  return a / b;
          6->}

Verbose Tier (~5-7 tokens/line)

Hit counts + function-level gap summary. Best for single-function deep analysis or hot-path review.

/* COV: src/orders.ts | ...
   Top gaps: L4-5, L10-11
*/
[FN+:42]  1->function processOrder(order: Order): Result {
|:42      2->  const validated = validateOrder(order);
?         3->  if (!validated) {                            [branch: if-true never taken]
.         4->    throw new ValidationError('Invalid order');

Directional Branch Encoding

The single highest-value feature. Instead of a bare ratio [B:1/2], covcat tells the LLM which branch to test:

| Pattern | Annotation | |---------|-----------| | if/else --- only if-true taken | [branch: else never taken] | | if/else --- only else taken | [branch: if-true never taken] | | switch --- 2 of 4 cases hit | [branch: case 2 never taken, case 3 never taken] | | x ?? default --- non-null only | [branch: alternate never taken] | | All branches missed | [branch: both paths uncovered] |

When directional data is unavailable (e.g., LCOV), falls back to ratio: [branch: 1/2 taken].


CLI Reference

Usage: covcat [options] [command] [file]

LLM-native coverage-annotated file viewer. Renders LNCAF format.

Arguments:
  file                   Source file to annotate with coverage

Options:
  -V, --version          Output the version number
  -f, --format <tier>    Annotation tier: compact, standard, verbose
  -c, --coverage <path>  Explicit coverage file path
  --no-branches          Hide branch detail annotations
  --hit-counts           Show hit counts (verbose tier)
  --no-daemon            Skip daemon, always parse directly
  -h, --help             Display help

Commands:
  daemon                 Manage the covcat daemon

Examples

# Auto-discover coverage, standard tier
covcat src/utils.ts

# Compact tier for a large file
covcat --format compact src/large-module.ts

# Verbose with hit counts
covcat --format verbose --hit-counts src/hot-path.ts

# Explicit coverage file
covcat --coverage coverage/lcov.info src/utils.ts

# Skip daemon, parse directly
covcat --no-daemon src/utils.ts

Daemon Mode

For fast repeated evaluation, covcat includes a background daemon that caches parsed coverage data and watches for changes.

# Start the daemon
covcat daemon start

# All subsequent covcat calls go through the daemon (<5ms cache hits)
covcat src/utils.ts          # First call: parse + cache
covcat src/utils.ts          # Second call: cache hit

# Check status
covcat daemon status
# covcat daemon: running
#   PID:          12345
#   Cache size:   3 entries
#   Memory:       1.2 MB
#   Watched:      1 files

# Stop when done
covcat daemon stop

How It Works

  1. The daemon listens on a Unix domain socket (.covcat/daemon.sock)
  2. When covcat <file> runs, it checks if the daemon is available
  3. If running: sends an annotate request over the socket, gets cached results
  4. If not running: falls back to direct pipeline (parse inline)
  5. The daemon watches coverage files with fs.watch and invalidates cache on change

Daemon Architecture

CLI ──> Unix Socket ──> DaemonServer
                            │
                      ┌─────┴──────┐
                      │ LRU Cache  │  (500 entries, 128MB)
                      │            │
                      │ fs.watch   │  (auto-invalidation)
                      └────────────┘

Run in foreground for debugging:

covcat daemon start --foreground

Configuration

Create covcat.yml (or .covcat.yml, covcat.yaml) in your project root:

coverage:
  # Annotation tier: compact | standard | verbose
  defaultFormat: standard

  # Show covered lines with | marker
  showCoveredLines: true

  # Show execution hit counts (verbose tier)
  showHitCounts: false

  # Show directional branch details
  showBranchDetails: true

  # Max token budget for annotations (0 = unlimited)
  maxAnnotationTokensBudget: 0

  # Staleness handling: warn-and-show | warn-and-hide | silent-hide | error
  stalenessMode: warn-and-show

  # Staleness check: mtime | linecount | hash
  stalenessCheckLevel: mtime

  # Coverage file discovery
  discovery:
    maxWalkDepth: 10
    additionalCandidates: []
    # Explicit path (overrides auto-discovery):
    # coveragePath: coverage/lcov.info

  # Daemon settings
  daemon:
    enabled: true
    watchFiles: true
    cache:
      maxEntries: 500
      maxMemoryMB: 128

Resolution Order

Settings resolve in order of precedence:

  1. CLI flags (--format verbose) --- highest priority
  2. covcat.yml (defaultFormat: compact)
  3. Built-in defaults (standard)

Config Discovery

covcat walks up from the source file's directory looking for config files, checking each of:

  • covcat.yml
  • covcat.yaml
  • .covcat.yml
  • .covcat.yaml

First match wins.


Coverage Formats

covcat auto-discovers and parses coverage data. Format detection uses file extension + content sniffing (first 512 bytes).

Supported Formats

| Format | Files | Ecosystem | Branch Quality | |--------|-------|-----------|---------------| | Istanbul JSON | coverage-final.json | Jest, Vitest, NYC, c8 | Directional (if/switch/cond-expr) | | LCOV | lcov.info, *.lcov | Universal interchange | Ratio-only (opaque block IDs) |

Auto-Discovery Probe Order

covcat walks up to the project root (detected via package.json, go.mod, Cargo.toml, etc.) and probes:

coverage/coverage-final.json    # Jest/Vitest default
coverage/coverage-summary.json  # NYC default
.nyc_output/coverage-final.json
coverage/lcov.info
lcov.info

16 paths are checked across Istanbul, LCOV, Cobertura, JaCoCo, Go, llvm-cov, SimpleCov, and coverage.py ecosystems.

Adapter Interface

Adding a new format is one file implementing CoverageAdapter:

interface CoverageAdapter {
  readonly format: CoverageFormat;
  canParse(filePath: string, contentPreview: string): boolean;
  parse(coverageFilePath: string, content: string): Promise<FileCoverageMap>;
}

Register it in src/adapters/detect.ts and coverage for that format works automatically.


Architecture

┌──────────────────────────────────────────────────────┐
│                     CLI (commander)                  │
│  covcat <file> ─── daemon subcommands                │
└──────────┬──────────────────────────────┬────────────┘
           │ direct                       │ via socket
           v                              v
┌──────────────────┐             ┌─────────────────────┐
│   Pipeline       │             │   DaemonServer      │
│                  │             │                     │
│  discovery       │             │  LRU Cache (500)    │
│  detect format   │             │  fs.watch           │
│  parse adapter   │             │  Unix socket IPC    │
│  render LNCAF    │             │                     │
└──────────────────┘             └─────────────────────┘
           │                              │
           v                              v
┌──────────────────────────────────────────────────────┐
│                    Adapters                          │
│  IstanbulAdapter   LcovAdapter   (pluggable)         │
│        │                │                            │
│        v                v                            │
│  ┌─────────────────────────────┐                     │
│  │  Unified Data Model         │                     │
│  │  LineCoverage, BranchData,  │                     │
│  │  FunctionEntry, FileSummary │                     │
│  └─────────────────────────────┘                     │
└──────────────────────────────────────────────────────┘
           │
           v
┌──────────────────────────────────────────────────────┐
│                 LNCAF Renderer                       │
│  Compact ──── Standard ──────── Verbose              │
│  (|.? )       (+[FN+] +branch)  (+hits +gaps)        │
└──────────────────────────────────────────────────────┘

Key Design Decisions

| Decision | Choice | Why | |----------|--------|-----| | Annotation placement | Left-margin prefix | LLM attention primacy: prefix primes interpretation | | Branch encoding | Directional text | "else never taken" > "1/2" for test generation | | Covered line annotation | Single \| char | Asymmetric density: 1 token for covered, 5-8 for uncovered | | Daemon IPC | Unix domain socket | Lowest latency, no port conflicts, automatic cleanup | | Cache strategy | LRU with mtime staleness | Parse-once serve-many; sub-ms cache hits | | Config validation | Zod schema | Type-safe, descriptive errors on invalid values |

Source Layout

src/
  index.ts              CLI entry point (commander)
  cli/
    pipeline.ts         Annotation pipeline orchestrator
  core/
    types.ts            LNCAF type system (32 types)
    config.ts           YAML config loader (zod)
    discovery.ts        Coverage file auto-discovery
  adapters/
    istanbul.ts         Istanbul JSON parser
    lcov.ts             LCOV tracefile parser
    detect.ts           Format detection + adapter registry
  renderer/
    renderer.ts         3-tier LNCAF renderer
  daemon/
    cache.ts            LRU coverage cache
    server.ts           Unix socket daemon + client

Claude SKILL Integration

covcat ships with a Claude SKILL definition at .claude/skills/covcat/SKILL.md. When installed in a Claude Code project, it enables natural-language triggers:

  • "show coverage for src/utils.ts"
  • "what's untested in this file?"
  • "coverage gaps in the auth module"
  • "run covcat on the changed files"

The SKILL definition includes the full LNCAF gutter reference, usage examples, and configuration guidance so Claude can use covcat effectively without additional prompting.


Development

# Install dependencies
yarn install

# Build TypeScript
yarn build

# Run tests
yarn test

# Run tests with coverage
yarn test:coverage

# Coverage fitness score (composite metric)
./scripts/score.sh

# Run in dev mode (no build needed)
npx tsx src/index.ts --help
npx tsx src/index.ts --coverage test/fixtures/coverage-final.json test/fixtures/utils.ts

Testing

Tests use Vitest with real fixture data (no mocking of coverage adapters):

test/
  adapters/
    istanbul.test.ts    Istanbul JSON parsing + branch descriptions
    lcov.test.ts        LCOV parsing + summary computation
  renderer/
    renderer.test.ts    All 3 tiers + gutter markers + branch suffixes
  fixtures/
    coverage-final.json Istanbul JSON fixture (processOrder function)
    sample.lcov         LCOV fixture (add + divide functions)
    utils.ts            Source file matching Istanbul fixture
    math.ts             Source file matching LCOV fixture

Coverage Fitness Function

The project uses a weighted composite score to track test coverage:

score = stmts_pct * 0.60 + branches_pct * 0.25 + fns_pct * 0.15
./scripts/score.sh          # Human-readable
./scripts/score.sh --json   # Machine-readable

Research Background

covcat is built on the LNCAF research corpus, a systematic analysis of LLM-native coverage representation:

  • 13 source coverage formats analyzed (LCOV, Istanbul, Cobertura, JaCoCo, Go, llvm-cov, SimpleCov, coverage.py, Codecov, V8, OpenCover, Clover, dotCover)
  • 17 AI-coverage tools surveyed (CoverUp, Qodo Cover, Codecov AI, SonarQube, GitHub Copilot, etc.)
  • 7 annotation strategies evaluated on an 8-criterion weighted matrix
  • 0 existing tools produce coverage-annotated output in the line-numbered text format LLMs read

The key finding: no existing tool fills the gap between IDE gutter markers (visual, invisible to LLMs) and raw coverage data files (separate from source, require mental mapping). LNCAF bridges this gap with inline annotation that adds ~800 tokens of overhead to a 500-line file --- a 5-7% increase that transforms an LLM from coverage-blind to coverage-aware.

CoverUp (arXiv:2403.16218) provides the empirical proof: inline line-tagging achieves 82% median coverage vs. 47% baseline. Preamble-only references fail. covcat extends this insight from excerpt-level to file-level operation.

See FINAL-SYNTHESIS.md for the complete specification.


License

MIT