internal/diff/(git.go + parser.go + hunk.go + resolver.go + relocation.go)internal/diff 是 OCR「讀取變更」的層。兩個重點:git.go 的 Provider 用 shell 呼叫 git 產生三種模式的 diff;parser.go 的 ParseDiffText 把 unified diff 文字解析成結構化的 []model.Diff(含 hunk、插入/刪除計數、重新命名偵測)。
Mode 是 int 列舉(Workspace/Commit/Range)。NewProvider(repoDir, from, to, runner) 建 range 模式;NewCommitProvider(repoDir, commit, runner) 建 commit 模式;NewWorkspaceProvider 建工作區模式。三個都共用 gitcmd.Runner——它把 git 子程序執行透過 concurrency limiter 共享,避免同時開太多 git process。
ResolveInput 判定模式並解析 ref(merge-base、commit 的 parents)。GetDiff 依模式跑:workspace 用 git diff HEAD + git ls-files --others(untracked 從磁碟讀當整檔新增);commit 用 git show;range 用 merge-base(a,b)..b。雜訊目錄(vendor/node_modules…)在 filterDiffs 剔除。
核心是狀態機:用正則 diffHeaderRe 偵測 diff --git a/.. b/.. 開新檔區段,用 inHunk 旗標區分「hunk 內容」(有 +/-/空格前綴)與「extended header」。有趣的細節:+++i 這種「內容本身以 + 開頭」的 added line,靠 inHunk 狀態正確計數。index 行被略過(物件 ID 對評審無用)。每個檔區段結束呼叫 finalizeDiff。
inHunk 旗標是正確解析 unified diff 的關鍵——沒有它,「--- a/x」「+++ b/y」這類 header 會被誤算成插入/刪除。range/commit 模式用 git show ref:path 讀新檔內容;workspace 從磁碟讀。內容存進 Diff.NewFileContent——供 file_read 工具與行解析使用。刪除檔設 /dev/null。
hunk.go 的 ParseHunks 把 @@ -x,y +m,n @@ 區段拆成 HunkLine。動態滑動視窗行解析(ResolveLineNumbers)把 existing_code 文字比對到新/舊側行號;失敗時 relocation.go 跑 RE_LOCATION_TASK prompt 請模型重新錨定。
ParseDiffText 的狀態機與 inHunk 旗標為何關鍵、finalizeDiff 如何補新檔內容、以及行解析的「滑動視窗 → 重新定位」兩階段。下一步:internal/config/rules 或回程式碼對照。