feat: [ENG-744] Add vc diff command#543
Conversation
|
Claude finished @bao-byterover's task in 4m 7s —— View job PR Review: feat: [ENG-744] Add vc diff command
SummaryOverall score: 4 / 5 Solid feature addition. The discriminated-union transport design is clean, test coverage is thorough (7 new test files covering all four modes), and the implementation follows established codebase patterns throughout (fired-ref mutation pattern, Outside-In structure, transport event style). The one issue worth fixing before merge is the missing error translation in Issuessuggestion (should fix): Missing
The mode-based path has no Every other ref-accepting handler wraps this with // current (bare throw propagates)
const changed = await this.gitService.listChangedFiles({directory, from, to})// suggested fix
let changed: ChangedFile[]
try {
changed = await this.gitService.listChangedFiles({directory, from, to})
} catch (error) {
const classified = classifyIsomorphicGitError(error, VcErrorCode.INVALID_REF)
if (classified) throw classified
throw error
}The test suite at nitpick:
Input if (rangeMatch && (!rangeMatch[1] || !rangeMatch[2])) {
throw new Error("invalid range: both <ref1> and <ref2> are required")
}nitpick: Block comment in
CLAUDE.md says "Never write multi-paragraph docstrings or multi-line comment blocks — one short line max" and "Default to writing no comments". The component opens with a four-line block comment. The other Praisepraise: Discriminated union design for
The praise:
Falling back to praise:
The praise:
The |
|
Claude finished @bao-byterover's task in 5m 30s —— View job PR Review: feat: [ENG-744] Add vc diff command
SummaryOverall score: 4.5 / 5 (up from 4/5) The one "should fix" from the previous review was addressed: One unresolved nitpick from the previous review remains. No new blocking issues found. Previous Review: Issues Resolved✅
The ✅ Block comment in The four-line file-level block comment is gone; the file now starts directly with imports, consistent with all other Remaining Issuenitpick (unresolved from previous review):
Inputs like // before the rangeMatch return, add:
if (!rangeMatch?.[1] || !rangeMatch?.[2]) {
// only reachable if the arg contained ".." but the regex didn't capture two non-empty parts
throw new Error("invalid range: both <ref1> and <ref2> are required (e.g. 'main..feature')")
}A cleaner alternative is to widen the regex to Praisepraise:
Wrapping the whole praise:
The condition praise: Error classification covers both throw sites in the mode path
Three tests — |
Summary
brv vchad no way to view diffs from the CLI or REPL. Users could only see per-file status, not the actual line changes, and had to drop back to systemgitto inspect edits.brv vcreaches parity with the coregit diffverbs users already expect. Makes isomorphic-git based workflows self-sufficient without shelling out.brv vc diff(oclif) and/vc diff(REPL) supporting four modes: unstaged (no args),--staged,<ref>(ref vs working tree), and<ref1>..<ref2>(range).vc:diffstransport event with a discriminatedmodevariant:{kind: 'unstaged' | 'staged'} | {kind: 'ref-vs-worktree', ref} | {kind: 'range', from, to}. Server auto-discovers changed files and returnsIVcDiffFile[]with status + short oids; binary files are filtered out.isomorphic-git-service.ts(HEAD / index / worktree / arbitrary refs), and a newdiffs(mode)handler branch invc-handler.ts.src/tui/features/vc/diff/utils/format-diff.tsthat emitsgit diffcompatible unified output using thediffpackage'sstructuredPatch, with chalk coloring (green adds, red deletes, cyan hunk headers, bold file headers).getVcDiffsQueryOptionsnow accepts only the{paths, side}variant (WebUI never called themodeshape).getVcDiffsQueryOptions; the request it sends on the wire is identical.IVcDiffRequest/IVcDiffResponsesurface andvc:diffevent.a...b) is explicitly rejected with a user-facing error (two-dot only, matching the ticket's AC).--binaryflag.--word-diff, no--stat, no pathspec filtering.Type of change
Scope (select all touched areas)
Also touched: WebUI (type-only narrowing in
src/webui/features/vc/api/get-vc-diffs.ts, no runtime change).Root cause (bug fixes only, otherwise write
N/A)N/A (new feature)
Test plan
test/unit/tui/features/vc/diff/parse-mode.test.ts--staged,<ref>,<a>..<b>,...rejection,--staged+ ref conflicttest/unit/tui/features/vc/diff/format-diff.test.tstest/unit/tui/features/commands/definitions/vc-diff.test.ts/vc diff)test/unit/infra/transport/handlers/vc-handler.diffs-mode.test.tsVcDiffModevariant + error pathstest/unit/infra/transport/handlers/vc-handler.test.tstest/integration/infra/git/isomorphic-git-service.test.tstest/unit/webui/features/vc/api/diff-contract.test.ts{paths, side}request shapebrv vc diffshows unstaged changes (working tree vs index).brv vc diff --stagedshows staged changes (index vs HEAD).brv vc diff <commit>andbrv vc diff <branch>show ref vs working tree.brv vc diff <a>..<b>shows diff between two refs.index,new file mode,deleted file mode,--- /dev/null,+++ /dev/nullmarkers.Binary files a/... and b/... differwith no hunks.--staged+ positional ref errors out.{paths, side}shape is wired up from the browser.User-visible changes
New commands:
brv vc diff(oclif):brv vc diff [ref] [--staged]/vc diff(REPL slash command): same args and flagOutput: unified diff matching
git diffformat, colored with chalk (green+, red-, cyan hunk headers, bold file headers). No output when there are no changes (CLI) /No changes.(REPL).No other defaults, config keys, or existing CLI output changed.
Evidence
main).scripts/e2e-vc-diff.sh(untracked, kept local) exercising the four modes against a temp repo.Checklist
npm test)npm run lint)npm run typecheck)npm run build)feat: [ENG-744] Add vc diff command)--helpoutputmain(one commit ahead ofmaintip)Risks and mitigations
diff@^9(plus@types/diff@^7devDep) adds a small bundle cost on the daemon/CLI side.diffis widely used, stable, and isolated toformat-diff.ts. The formatter is the only import site, so it is easy to swap or remove later.IVcDiffsRequestdiscriminated union now has two shapes ({mode}for CLI/TUI,{paths, side}for WebUI). A future caller could pick the wrong one.getVcDiffsQueryOptionsis narrowed to only the{paths, side}variant, anddiff-contract.test.tsasserts that shape.git diff(hunk-context heuristic, short-oid length, no rename detection).findHunkContext).brv vc diff <ref>on the CLI which streams to stdout. No pager in this PR, flagged as follow-up if feedback requires it.