Skip to content

feat(stats): count what a branch changed by kind of file with --since - #42

Merged
flipvh merged 1 commit into
mainfrom
feat/stats-since
Oct 8, 2026
Merged

flipvh merged 1 commit into
mainfrom
feat/stats-since

Conversation

@flipvh

@flipvh flipvh commented Oct 7, 2026

Copy link
Copy Markdown
Member

cella stats counts the whole repository, so it cannot say where a pull request's lines went. This adds a branch
mode that can, as the tool behind a rule for cella's AGENTS.md: a PR that grows the codebase says which kind of
lines grew and why.

pnpm cella stats --since origin/main        # tables in the terminal, -V lists every file
pnpm cella stats --since origin/main --md   # a markdown table on stdout, for a PR description

Run on cella#1331, which shows as +722 −121 on GitHub:

  files    added  removed      net
      8     +438       -6     +432  tests
     14     +229     -109     +120  source
      1      +44        0      +44  docs
      2      +11       -6       +5  json
     25     +722     -121     +601  total

  source lines by content
            +152      -87      +65  code
             +49       -9      +40  comments
             +28      -13      +15  blank

  source lines by package
     11     +215      -95     +120  frontend
      3      +14      -14        0  backend

72% of that PR's growth is tests and 65 lines are new code, which the raw count hides.

How it counts

  • Committed work only, compared with the merge base of HEAD and the ref: the same diff a pull request into that
    ref shows. Uncommitted files are reported as not counted.
  • Every file in the diff counts. The snapshot only looks at code extensions; a diff also holds docs, workflows and
    lock files. So this adds docs (md, mdx) and other to the snapshot's categories and reads a lock file as
    generated. The snapshot's own classifier is reused unchanged for everything else.
  • Source lines by content come from a zero-context patch. A diff shows changed lines only, so a comment is
    recognized by how its line starts (//, /*, *, {/*). The parser follows each hunk header's line counts, so a
    changed line that itself starts with +++ is not taken for a file header. The three parts add up to the numstat
    totals of the source files; a test checks that on a real repo.
  • --md uses the existing machine-output mode: header, warnings and spinner go to stderr, the table to stdout.

Things to check

  1. The flag is --since <ref>, not --diff. --diff <path> already prints one file's patch in analyze and
    contributions. The ref is required: a default would have to guess between main and origin/main, and a stale
    local main counts other people's commits as the branch's.
  2. Overlap with refactor: code consistency pass against cella house style #41. That PR rewrites stats.ts, cli.ts, cella-cli.ts and types.ts. The mode lives in its
    own file, services/stats-since.ts, and touches those four by a few lines each (five export keywords, two option
    definitions, two config fields, one dispatch). Whichever merges second needs a small rebase.
  3. It needs a cella config like every service, so it does not run inside this repo. The table below comes from
    calling collectBranchStats and formatMarkdown directly.

Verification

pnpm check clean. pnpm test: 282 passed, 27 files. New tests/stats-since.test.ts covers the classifiers, both
parsers on literal git output (binary files, quoted paths, a hunk line that looks like a header), and the collector on
a real repo: kinds, content split, package split, merge base after the ref moved on, uncommitted work left out. The
built binary was run against cella#1331's branch for the output above, plus the two error paths (--md without
--since, an unknown ref) and the unchanged snapshot mode.

Size

Kind Files Added Removed Net
Source 5 +396 -8 +388
Tests 2 +276 0 +276
Docs 1 +41 -2 +39
Total 8 +713 -10 +703

Source lines by content: code +281, comments +52, blank +55.

  • Source is the mode itself, in one new 366-line file: two parsers (numstat, patch), the collector, and two
    formatters (terminal tables, markdown). The shared files grow by 30 lines of wiring.
  • Tests are one new file for the mode and one parse case in cli.test.ts.
  • Docs is the README section with the kinds table and the comment heuristic's limit.

🤖 Generated with Claude Code

`cella stats` counts the whole repository, so it could not say where a pull request's lines went.
`cella stats --since <ref>` counts what the current branch committed since it left the ref, which is
what a pull request into that ref shows:

- one row per kind of file: source, tests, stories, generated, json, docs, other
- the source lines split into code, comments and blank, read from a zero-context patch
- the source lines per workspace package
- `--md` prints the table as markdown on stdout for a PR description; `-V` lists every file

Every file in a diff counts, so beyond the snapshot's categories this knows docs (`md`, `mdx`) and a
rest group, and reads a lock file as generated. A diff shows changed lines only, so a comment is
recognized by how its line starts. Uncommitted files are reported as not counted.

The mode lives in its own file, `services/stats-since.ts`; `stats.ts` only exports the classifier
and the workspace lookup it shares.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@flipvh
flipvh merged commit 302bd9f into main Oct 8, 2026
7 checks passed
flipvh added a commit that referenced this pull request Oct 8, 2026
…review

Brings in stats --since (#42). Conflicts resolved by keeping this branch's
structure and wording and adding #42's feature on top:

- src/cli.ts: since/md read through the str()/flag() helpers; --md joins
  the machine-output modes next to the audit --list exception
- src/cella-cli.ts: braced stats case, runStats(config) for the snapshot
  mode, runBranchStats for --since
- src/services/stats.ts: this branch's comments, plus the exports
  stats-since.ts imports
- README.md: this branch's wording, plus the --since row and section

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant