Skip to content

fix(diff): don't overcount new-file additions by the trailing newline - #1873

Merged
kevincodex1 merged 1 commit into
Gitlawb:mainfrom
0xfandom:fix/newfile-added-lines-trailing-newline
Jul 7, 2026
Merged

fix(diff): don't overcount new-file additions by the trailing newline#1873
kevincodex1 merged 1 commit into
Gitlawb:mainfrom
0xfandom:fix/newfile-added-lines-trailing-newline

Conversation

@0xfandom

@0xfandom 0xfandom commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

countLinesChanged has a dedicated branch for new files (used by FileWriteTool when writing a file that did not exist), which counts every content line as an addition:

if (patch.length === 0 && newFileContent) {
  // For new files, count all lines as additions
  numAdditions = newFileContent.split(/\r?\n/).length
}

Splitting on newlines produces a trailing empty element when the content ends in a newline — which is the normal case for a text file. So a 2-line file "a\nb\n" is counted as 3 additions instead of 2, "line1\nline2\nline3\n" as 4 instead of 3, and so on. Git reports 2 + lines for a 2-line new file, and the diff-based update path in the same function counts +-prefixed hunk lines git-accurately — so the create path is off by one against both.

The inflated count feeds the tengu_file_changed analytics event (lines_added) and the process-wide total-lines-changed counter (addToTotalLinesChanged → session stats), so nearly every new file overstates added lines by one.

Fix

Drop the phantom trailing element when the content is newline-terminated, matching git and the update path. Content without a trailing newline (and CRLF endings) are unaffected.

Testing

New src/utils/diff.test.ts measures the delta countLinesChanged contributes to the running total:

  • "a\nb\n" → 2, "line1\nline2\nline3\n" → 3, "only\n" → 1 (newline-terminated).
  • "a\nb" → 2, "single" → 1 (no trailing newline, already correct).
  • CRLF ("a\r\nb\r\n") counts the same as LF.

Reverting to the plain .split(...).length re-fails the newline-terminated and CRLF assertions.

bun test src/utils/diff.test.ts   # pass
bun run typecheck                 # clean

Summary by CodeRabbit

  • Bug Fixes
    • Corrected line-change counting for newly added files so trailing newlines no longer add an extra phantom line.
    • Ensured files with LF and CRLF line endings are counted consistently.
    • Added test coverage for newline-terminated content, files without a trailing newline, and Windows-style line endings.

countLinesChanged's new-file branch counted added lines as
newFileContent.split(/\r?\n/).length. Content that ends in a newline (the
normal case) yields a trailing empty element, so a 2-line file "a\nb\n"
counted as 3 additions instead of 2. That inflated the tengu_file_changed
telemetry and the running total-lines-changed counter for essentially every new
file, and disagreed with the diff-based update path (which counts `+` hunk
lines git-accurately).

Drop the phantom trailing line when the content is newline-terminated so the
count matches git and the update path.
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 68d0c51c-4d5f-4428-aba2-65750f4cc090

📥 Commits

Reviewing files that changed from the base of the PR and between 214ee3d and 732de7a.

📒 Files selected for processing (2)
  • src/utils/diff.test.ts
  • src/utils/diff.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: smoke-and-tests
🧰 Additional context used
📓 Path-based instructions (4)
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Use TypeScript with strict mode
Use ESM imports in TypeScript source files

Files:

  • src/utils/diff.test.ts
  • src/utils/diff.ts
**

⚙️ CodeRabbit configuration file

**: # AGENTS.md - AI Agent Coding Guide

This guide is for AI coding agents working in the OpenClaude repository. Read it before changing code, and also follow CONTRIBUTING.md for contributor policy, PR expectations, review follow-up, and project scope.

Project Snapshot

OpenClaude is a coding-agent CLI for cloud and local model providers. It supports OpenAI-compatible APIs, Anthropic, Gemini, DeepSeek, Ollama, MCP, local backends, slash commands, tools, agents, and a React/Ink terminal UI.

The installed CLI runs on Node.js >=22.0.0. Bun is used for source builds, scripts, dependency management, and tests.

Work Style

  • Keep changes focused on one problem.
  • Prefer existing patterns in the file or nearby module.
  • Avoid unrelated formatting, renames, dependency changes, or broad rewrites.
  • Add or update tests when behavior changes.
  • Update docs when setup, commands, provider behavior, or user-facing behavior changes.
  • For new features, larger refactors, dependencies, or runtime changes, follow the issue-first guidance in CONTRIBUTING.md.

Stack And Conventions

  • TypeScript with strict mode and ESM imports.
  • React + Ink for terminal UI.
  • Bun lockfile and Bun scripts for development workflows.
  • Node runtime for the built CLI.

Common libraries and patterns:

  • chalk for terminal color.
  • commander for CLI argument parsing.
  • execa for child processes.
  • Existing service, provider, settings, permission, and UI patterns over new abstractions.

Repository Map

  • src/commands/ - slash and CLI command implementations.
  • src/components/ - React/Ink UI components.
  • src/services/ - API, MCP, OAuth, wiki, voice, and other service integrations.
  • src/tools/ - tool implementations.
  • src/utils/ - shared utilities.
  • src/integrations/ - provider and model integration metadata.
  • src/entrypoints/ - CLI, MCP, SDK, and generated public types.
  • src/tasks/ - local, remote, workflow, and monitor tas...

Files:

  • src/utils/diff.test.ts
  • src/utils/diff.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/diff.test.ts
  • src/utils/diff.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/diff.test.ts
🔇 Additional comments (2)
src/utils/diff.ts (1)

55-62: LGTM!

src/utils/diff.test.ts (1)

1-38: LGTM!


📝 Walkthrough

Walkthrough

This PR fixes an off-by-one error in countLinesChanged where new-file addition counts were overcounted by one for newline-terminated content. A new test suite validates correct behavior for newline-terminated, non-terminated, and CRLF content.

Changes

Diff line counting fix

Layer / File(s) Summary
Fix numAdditions calculation
src/utils/diff.ts
New-file branch now trims the trailing empty line from split content when newFileContent ends with a newline, correcting the addition count.
Line-counting test suite
src/utils/diff.test.ts
Adds Bun tests with an addedLinesFor helper (mocking analytics) that verify correct added-line counts for newline-terminated, non-terminated, and CRLF content.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Suggested reviewers: jatmn, kevincodex1

🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, scoped, and accurately reflects the newline-counting fix in countLinesChanged.
Description check ✅ Passed The description covers Summary and Testing well, but it omits the Impact and Notes sections from the template.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Risk Surface Disclosed ✅ Passed Only src/utils/diff.ts and its test changed; no auth, routing, permissions, network, or similar risk surfaces were touched.
No Hidden Policy Change ✅ Passed Only diff-counting logic and tests changed; no policy, routing, permission, trust-model, or network behavior was introduced or hidden.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution. I do not see any actionable issues from my review.

@kevincodex1 LGTM

@kevincodex1
kevincodex1 merged commit 8d90849 into Gitlawb:main Jul 7, 2026
4 checks passed
hotmanxp pushed a commit to hotmanxp/openclaude that referenced this pull request Jul 7, 2026
…Gitlawb#1873)

countLinesChanged's new-file branch counted added lines as
newFileContent.split(/\r?\n/).length. Content that ends in a newline (the
normal case) yields a trailing empty element, so a 2-line file "a\nb\n"
counted as 3 additions instead of 2. That inflated the tengu_file_changed
telemetry and the running total-lines-changed counter for essentially every new
file, and disagreed with the diff-based update path (which counts `+` hunk
lines git-accurately).

Drop the phantom trailing line when the content is newline-terminated so the
count matches git and the update path.

(cherry picked from commit 8d90849)
(cherry picked from commit 63e057b13ca994335ba0c2d934144767a9b9aba3)
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.

3 participants