Skip to content

Bug: generateUnifiedDiff() uses naive index-based comparison, produces incorrect diffs for JSON and other files #15584

@horizon105457

Description

@horizon105457

Summary

generateUnifiedDiff() in packages/opencode/src/patch/index.ts (line ~490) is a naive index-based comparison (old[i] vs new[i]), not a real diff algorithm. Any insertion or deletion causes all subsequent lines to misalign, producing incorrect and bloated diffs.

This is especially severe for JSON files, where many lines are structurally identical (}, },, repeated keys), but affects all file types.

Root Cause

The current implementation:

function generateUnifiedDiff(oldContent: string, newContent: string): string {
    const oldLines = oldContent.split("\n")
    const newLines = newContent.split("\n")

    let diff = "@@ -1 +1 @@\n"

    const maxLen = Math.max(oldLines.length, newLines.length)
    let hasChanges = false

    for (let i = 0; i < maxLen; i++) {
      const oldLine = oldLines[i] || ""
      const newLine = newLines[i] || ""

      if (oldLine !== newLine) {
        if (oldLine) diff += `-${oldLine}\n`
        if (newLine) diff += `+${newLine}\n`
        hasChanges = true
      } else if (oldLine) {
        diff += ` ${oldLine}\n`
      }
    }

    return hasChanges ? diff : ""
}

Problems:

  1. Not a diff algorithm — compares lines by index position, not by content similarity (no LCS/Myers/Patience)
  2. Single hunk — always emits @@ -1 +1 @@, never splits into multiple hunks with context windows
  3. Misaligns on any insert/delete — inserting 1 line at the top marks every subsequent line as changed
  4. Particularly bad for JSON — many identical lines (}, },) cannot be correctly matched

The source comment itself acknowledges: "Simple diff generation - in a real implementation you'd use a proper diff algorithm".

Suggested Fix

Replace with createTwoFilesPatch() from the diff npm package, which is already a dependency and used correctly in tool/edit.ts and tool/write.ts:

import { createTwoFilesPatch } from "diff"

// In deriveNewContentsFromChunks():
const unifiedDiff = createTwoFilesPatch(filePath, filePath, originalContent, newContent)

This is a minimal change — the diff package is already imported elsewhere in the codebase, and createTwoFilesPatch produces proper unified diffs with correct hunk splitting, context windows, and Myers-based line matching.

Reproduction

Any file edit that inserts or removes lines (rather than purely modifying in-place) will produce an incorrect diff. Most visible with JSON files containing repeated structural patterns.

Environment

  • opencode v1.2.15
  • Affected function: deriveNewContentsFromChunks()generateUnifiedDiff() in packages/opencode/src/patch/index.ts

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions