mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
fix: make snapshot diffs resilient on Windows (#12583)
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
// kilocode_change - new file
|
||||
//
|
||||
// Patch generation. Runs `git diff --unified=INT_MAX` to produce
|
||||
// Patch generation. Runs `git diff --unified=3` to produce
|
||||
// unified-diff text for a set of files, instead of the npm `diff` package's
|
||||
// JS Myers implementation. Myers is O(N*M) with full context, so on
|
||||
// JS Myers implementation. Myers is O(N*M), so on
|
||||
// huge-file diffs it can block the event loop for minutes (the TUI freeze
|
||||
// where ESC stopped working after a turn).
|
||||
//
|
||||
@@ -18,8 +18,9 @@ import * as Log from "@opencode-ai/core/util/log"
|
||||
export namespace DiffFull {
|
||||
const log = Log.create({ service: "snapshot.diff-full" })
|
||||
|
||||
// INT_MAX — git clamps to this, effectively infinite context.
|
||||
const unified = "--unified=2147483647"
|
||||
// Keep context bounded. Git's effectively infinite context can emit
|
||||
// malformed repeated hunks on Windows and makes persisted snapshots huge.
|
||||
const unified = "--unified=3"
|
||||
|
||||
interface GitResult {
|
||||
readonly code: number
|
||||
@@ -28,7 +29,7 @@ export namespace DiffFull {
|
||||
}
|
||||
|
||||
/**
|
||||
* Run `git diff --unified=INT_MAX` for a set of files between two refs and
|
||||
* Run `git diff --unified=3` for a set of files between two refs and
|
||||
* return a `file → unified-diff text` map. Output format matches what the
|
||||
* `diff` package's `parsePatch` expects, so downstream clients continue to
|
||||
* work.
|
||||
@@ -85,7 +86,7 @@ export namespace DiffFull {
|
||||
|
||||
/**
|
||||
* Generate a structured + unified diff for a single file in the working
|
||||
* tree vs HEAD using `git diff --ignore-all-space --unified=INT_MAX`.
|
||||
* tree vs HEAD using `git diff --ignore-all-space --unified=3`.
|
||||
* Returns `null` if git produces no output (caller emits a content-only
|
||||
* response with no patch).
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import { $ } from "bun"
|
||||
import { describe, expect } from "bun:test"
|
||||
import { parsePatch } from "diff"
|
||||
import { Effect, Layer } from "effect"
|
||||
import path from "path"
|
||||
import * as CrossSpawnSpawner from "@opencode-ai/core/cross-spawn-spawner"
|
||||
@@ -106,6 +107,24 @@ describe("DiffFull.batch", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("keeps distant changes in bounded, parseable hunks", () =>
|
||||
Effect.gen(function* () {
|
||||
const dir = yield* tmpdirScoped({ git: true })
|
||||
const before = Array.from({ length: 30 }, (_, i) => `line ${i + 1}`)
|
||||
yield* Effect.promise(() => Filesystem.write(path.join(dir, "multi.txt"), before.join("\n") + "\n"))
|
||||
const from = yield* Effect.promise(() => commit(dir, "v1"))
|
||||
const after = before.with(1, "changed near start").with(27, "changed near end")
|
||||
yield* Effect.promise(() => Filesystem.write(path.join(dir, "multi.txt"), after.join("\n") + "\n"))
|
||||
const to = yield* Effect.promise(() => commit(dir, "v2"))
|
||||
|
||||
const result = yield* DiffFull.batch(gitResult(dir), from, to, ["multi.txt"])
|
||||
const parsed = parsePatch(result.get("multi.txt") ?? "")[0]
|
||||
|
||||
expect(parsed?.hunks).toHaveLength(2)
|
||||
expect(parsed?.hunks.every((hunk) => hunk.lines.length < before.length)).toBe(true)
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("returns an empty map without spawning for an empty file list", () =>
|
||||
Effect.gen(function* () {
|
||||
let calls = 0
|
||||
|
||||
Reference in New Issue
Block a user