Skip to content

feat(vcs): add status raw diff and guarded apply - #956

Merged
Astro-Han merged 23 commits into
devfrom
codex/i936-vcs-parity
May 29, 2026
Merged

feat(vcs): add status raw diff and guarded apply#956
Astro-Han merged 23 commits into
devfrom
codex/i936-vcs-parity

Conversation

@Astro-Han

@Astro-Han Astro-Han commented May 27, 2026

Copy link
Copy Markdown
Owner

Summary

Add VCS parity endpoints and SDK surface for the next #936 migration slice:

  • GET /vcs/status returns working-tree file summaries.
  • GET /vcs/diff/raw returns raw patch text for tracked, staged, unstaged, untracked, and binary changes, with a bounded output contract.
  • POST /vcs/apply applies a patch through git and returns structured failure reasons for git failures, oversized input, and invalid request bodies.
  • The existing /vcs/diff?mode=unstaged|staged|branch contract remains unchanged.

Why

#936 identified VCS parity as the next low-risk backend slice before any broader Hono-to-Effect HttpApi migration. This adds the useful upstream VCS API shape while keeping PawWork's current Hono server path and existing diff modes intact.

Related Issue

Closes part of #936.

Human Review Status

Pending

Review Focus

Please review:

  • POST /vcs/apply behavior and error mapping, especially invalid input, oversized input, non-git projects, non-clean patches, and subdirectory requests.
  • GET /vcs/diff/raw round-trip behavior for initial repositories, staged-then-modified files, binary files, subdirectory requests, and oversized patches.
  • The old /vcs/diff mode contract remains preserved.
  • The bounded JSON body helper used by /vcs/apply preserves the existing route behavior while moving stream/request reconstruction out of InstanceRoutes.

Risk Notes

  • POST /vcs/apply intentionally mutates the current git worktree by passing patch text to git apply -; tests cover success, non-git rejection, non-clean apply failure, subdirectory requests, invalid JSON/schema input, and oversized input.
  • Raw VCS diff and VCS apply now enforce a 10 MB patch budget; VCS apply also rejects oversized request bodies before JSON validation and allows escaped JSON bodies whose decoded patch is within the 10 MB patch limit.
  • Visible UI/copy check skipped: no UI or user-visible app copy changed in this PR branch.
  • Generated content included: v2 SDK generated types/client were regenerated; checked-in legacy packages/sdk/openapi.json was intentionally left unchanged because it is a route-inventory baseline, not the SDK build source.

How To Verify

Dependency setup: bun install --frozen-lockfile completed in the isolated worktree.
TDD RED checks: subdirectory /vcs/status summaries, subdirectory /vcs/diff/raw untracked round-trip, no-HEAD staged-then-modified raw round-trip, raw separator budget, subdirectory /vcs/apply root-relative patches, escaped JSON body within decoded patch limit, invalid apply input failure body, and app test module-mock leakage each failed before the fix.
Focused VCS tests: bun test test/server/vcs-routes.test.ts test/project/vcs.test.ts test/git/git.test.ts test/server/route-inventory-harness.test.ts in packages/opencode -> passed, 64 tests.
Apply body focused tests: bun test test/server/vcs-routes.test.ts -t 'returns typed apply failures|rejects oversized apply request bodies|accepts escaped JSON bodies|rejects oversized apply patches' in packages/opencode -> passed, 4 tests.
App CI regression tests: bun test --preload ./happydom.ts src/hooks/use-providers.test.ts src/pages/session/session-layout.test.ts src/context/prompt.test.ts src/pages/session/session-action-readiness.test.ts src/pages/session/use-session-followups.test.ts src/components/prompt-input/draft-isolation.integration.test.ts in packages/app -> passed, 46 tests; bun test --preload ./happydom.ts src/pages/session/use-session-followups.test.ts src/context/global-sync/child-store.test.ts src/components/prompt-input/history-navigation.test.ts src/pages/layout/layout-page-store.test.ts src/components/prompt-input/submit.test.ts in packages/app -> passed, 64 tests.
App CI suite: bun run test:ci in packages/app -> passed, 1619 tests.
App typecheck: bun run typecheck in packages/app -> passed.
Opencode typecheck: bun run typecheck in packages/opencode -> passed.
SDK typecheck: bun run typecheck in packages/sdk/js -> passed.
SDK generation: bun run build in packages/sdk/js -> regenerated v2 SDK successfully.
Opencode CI-equivalent package suite: bun run test:ci in packages/opencode -> passed, 3204 tests.
Whitespace: git diff --check -> clean.
GitHub Actions checks on latest head b2da258639 -> passed; CodeRabbit review completed.

Screenshots or Recordings

Not applicable; no visible UI changes.

Checklist

How to use this checklist:

  • Tick a box by replacing [ ] with [x]. Do not edit, add, or remove items.
  • The bot-applied label items can only be honestly ticked AFTER the PR is opened and the labeler / priority-triage bots have run — return to the PR description and tick them then.
  • Most items are required. The few that are conditional are explicitly marked (conditional); for those, leave unticked if they truly do not apply and explain why in Risk Notes. All other items must be ticked before requesting human review.
  • Type label — this PR carries exactly one of bug, enhancement, task, documentation. Type labels are author-added; the labeler bot does NOT assign them. Add the label in the GitHub UI, then tick this.
  • Routing labels — this PR carries at least one of app, ui, platform, harness, ci. The labeler bot assigns these on PR open based on changed paths. Confirm the bot's choice (or override if wrong), then tick this.
  • Priority label — this PR carries exactly one of P0, P1, P2, P3. The priority-triage bot suggests one on PR open. Confirm or override, then tick this.
  • Human Review Status above is set to Pending, Approved by @<reviewer>, or Not required: <reason> (default is Pending; "not required" is restricted to bot-authored low-risk PRs).
  • I linked the related issue, or stated in Summary why there is no issue.
  • I described the review focus and any meaningful risks.
  • I replaced the example block in How To Verify with the real verification steps and the key result for each.
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope.
  • (conditional) I manually checked visible UI or copy changes when needed, with screenshots or recordings. Leave unticked only if no visible UI or copy changed.
  • (conditional) I considered macOS and Windows impact for platform, packaging, updater, signing, paths, shell, or permissions changes. Leave unticked only if no platform/packaging surface was touched.
  • (conditional) I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant. Leave unticked only if none of those surfaces was touched.
  • I reviewed the final diff for unrelated changes and suspicious dependency changes.
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English.

@github-actions github-actions Bot added the harness Model harness, prompts, tool descriptions, and session mechanics label May 27, 2026
@Astro-Han Astro-Han added enhancement New feature or request app Application behavior and product flows P2 Medium priority upstream Tracked upstream or vendor behavior tech-debt Supplemental cleanup, maintainability, architecture, test, or quality debt context labels May 27, 2026
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds stdin-based git patch piping and binary patch support; exposes new git patch APIs; implements Vcs.status, Vcs.diffRaw (10MB budget, truncation errors), and Vcs.apply with Zod schemas and errors; wires HTTP routes for status/diff/raw/apply; and adds unit and integration tests covering success and failure cases.

Changes

VCS Patch Operations

Layer / File(s) Summary
Git stdin and patch operations
packages/opencode/src/git/index.ts
Git.Options adds optional stdin; PatchOptions gains binary; run() supports piping stdin; new patchAll, patchStagedAll, and applyPatch methods include --binary when requested and pipe patch text into git apply -; Service wiring exports new methods.
VCS service layer with status and patch operations
packages/opencode/src/project/vcs.ts
New Zod schemas/types and error classes (FileStatus, ApplyInput, ApplyResult, RawDiffError, PatchApplyError); Vcs.Interface extended with status, diffRaw, and apply; status computes per-file additions/deletions, diffRaw aggregates HEAD/staged/untracked patches with raw size budget enforcement, apply validates git project and calls git.applyPatch.
HTTP routes for VCS operations
packages/opencode/src/server/instance/index.ts
Adds GET /vcs/status (JSON array), GET /vcs/diff/raw (returns text/plain, maps RawDiffError -> 413), and POST /vcs/apply (validates ApplyInput, returns { applied: true } or maps PatchApplyError -> 400).
Project VCS unit tests
packages/opencode/test/project/vcs.test.ts
Adds tests verifying Vcs.status() file tracking/staging/untracked output; Vcs.diffRaw() contains tracked and untracked diffs; Vcs.apply() success between repos and failure modes (non-git, not-clean) preserving file contents on failure.
Server VCS routes integration tests
packages/opencode/test/server/vcs-routes.test.ts
Adds OpenAPI contract checks and behavior tests for /vcs/status, /vcs/diff/raw (including patch-budget 413 cases), and /vcs/apply success/not-clean failure; includes binary file round-trip tests and per-test Instance cleanup.

Sequence Diagram

sequenceDiagram
  participant Client
  participant VcsRoute as /vcs/apply Route
  participant VcsService as Vcs.apply
  participant GitService as Git.applyPatch
  participant ChildProcess
  Client->>VcsRoute: POST { patch: "..." }
  VcsRoute->>VcsService: apply({ patch })
  VcsService->>GitService: applyPatch(cwd, patch)
  GitService->>ChildProcess: run "git apply -" with stdin=patch
  ChildProcess-->>GitService: exit code
  alt exit code 0
    GitService-->>VcsService: { ok: true }
    VcsService-->>VcsRoute: { applied: true }
    VcsRoute-->>Client: 200 { applied: true }
  else exit code non-zero
    GitService-->>VcsService: error
    VcsService-->>VcsRoute: PatchApplyError
    VcsRoute-->>Client: 400 { error: "vcs_apply_failed", reason: "..." }
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Suggested labels

app

Poem

In burrows of code I softly tap,
A patch slips in through stdin's lap.
Files learn their changes, neat and bright,
Diffs fly forth, then land just right.
A rabbit cheers: "Applied!"—what a wrap. 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely summarizes the main changes: adding VCS status, raw diff, and guarded patch apply functionality.
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.
Description check ✅ Passed The PR description comprehensively covers all required template sections: Summary, Why, Related Issue, Human Review Status, Review Focus, Risk Notes, How To Verify, Screenshots/Recordings, and Checklist.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/i936-vcs-parity

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 and usage tips.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested priority: P2 (includes non-doc, non-test paths outside the low-risk bucket).

P1/P0 are reserved for maintainer confirmation. Please relabel manually if this is a release blocker, security issue, data-loss risk, or updater/runtime failure.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces new Version Control System (VCS) capabilities, including endpoints and SDK support for retrieving working tree status summaries (/vcs/status), fetching raw patch diffs (/vcs/diff/raw), and applying git patches (/vcs/apply). Corresponding unit and integration tests have been added. A critical issue was identified in the test suite where the assertion for untracked file diff headers is incorrect and will cause test failures.

Comment thread packages/opencode/test/project/vcs.test.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/opencode/test/server/vcs-routes.test.ts (1)

31-34: 💤 Low value

Consider order-insensitive assertion for status array.

The toEqual assertion is order-sensitive. If Vcs.status() returns files in a different order (e.g., due to filesystem iteration or parallel processing), this test could become flaky.

♻️ Suggested order-insensitive assertion
-    expect(await response.json()).toEqual([
-      { file: "tracked.txt", additions: 1, deletions: 1, status: "modified" },
-      { file: "untracked.txt", additions: 1, deletions: 0, status: "added" },
-    ])
+    expect(await response.json()).toEqual(
+      expect.arrayContaining([
+        { file: "tracked.txt", additions: 1, deletions: 1, status: "modified" },
+        { file: "untracked.txt", additions: 1, deletions: 0, status: "added" },
+      ]),
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/test/server/vcs-routes.test.ts` around lines 31 - 34, The
test currently uses an order-sensitive toEqual on the response JSON; change it
to an order-insensitive assertion by either sorting the returned array by the
`file` property before comparing or using Jest's arrayContaining/matchers to
assert the expected items exist regardless of order (locate the assertion in
packages/opencode/test/server/vcs-routes.test.ts where response.json() is
compared to the expected array for files "tracked.txt" and "untracked.txt");
ensure you still validate each object's additions, deletions, and status fields
exactly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/opencode/test/project/vcs.test.ts`:
- Around line 148-155: Tests using withVcsOnly currently call await
withVcsOnly(...) inside plain test blocks and use Instance.provide; refactor to
use the Effect test harness by creating const it = testEffect(describe) and
convert those tests to it.live(...) so they run in the Effect runtime, and
update withVcsOnly to accept and use provideTmpdirInstance(tmp.path) /
provideInstance(...) instead of Instance.provide; locate usages of withVcsOnly
in packages/opencode/test/project/vcs.test.ts and replace the await
withVcsOnly(...) pattern around calls like Vcs.status() with an it.live test
that provides the tmpdir and other fixtures via the Effect providers.

---

Nitpick comments:
In `@packages/opencode/test/server/vcs-routes.test.ts`:
- Around line 31-34: The test currently uses an order-sensitive toEqual on the
response JSON; change it to an order-insensitive assertion by either sorting the
returned array by the `file` property before comparing or using Jest's
arrayContaining/matchers to assert the expected items exist regardless of order
(locate the assertion in packages/opencode/test/server/vcs-routes.test.ts where
response.json() is compared to the expected array for files "tracked.txt" and
"untracked.txt"); ensure you still validate each object's additions, deletions,
and status fields exactly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3834a20d-190a-4c44-8c38-eb5fd445586c

📥 Commits

Reviewing files that changed from the base of the PR and between 8757642 and 9e816a2.

⛔ Files ignored due to path filters (2)
  • packages/sdk/js/src/v2/gen/sdk.gen.ts is excluded by !**/gen/**
  • packages/sdk/js/src/v2/gen/types.gen.ts is excluded by !**/gen/**
📒 Files selected for processing (5)
  • packages/opencode/src/git/index.ts
  • packages/opencode/src/project/vcs.ts
  • packages/opencode/src/server/instance/index.ts
  • packages/opencode/test/project/vcs.test.ts
  • packages/opencode/test/server/vcs-routes.test.ts

Comment thread packages/opencode/test/project/vcs.test.ts Outdated
@github-actions github-actions Bot removed the app Application behavior and product flows label May 27, 2026
@github-actions github-actions Bot added the platform Electron shell, OS integration, packaging, updater, signing, paths, and permissions label May 28, 2026
Astro-Han added 4 commits May 28, 2026 12:15
# Conflicts:
#	packages/desktop-electron/scripts/repair-electron-install.mjs
#	packages/desktop-electron/scripts/repair-electron-install.test.ts
@github-actions github-actions Bot removed the platform Electron shell, OS integration, packaging, updater, signing, paths, and permissions label May 28, 2026
@github-actions github-actions Bot added the app Application behavior and product flows label May 28, 2026
@github-actions

github-actions Bot commented May 28, 2026

Copy link
Copy Markdown

Perf delta summary

Comparator: pass

Profile / Scenario interaction median interaction worst long task max tbt frame gap p95 frame gap max jank count cls status
default / homepage-cold 32 -> 32 (0) 40 -> 40 (0) 67 -> 67 (0) 17 -> 17 (0) 16.8 -> 33.3 (+16.5) 166.6 -> 166.7 (+0.1) 4 -> 3 (-1) 0 -> 0 (0) pass
default / long-session-input-lag 48 -> 48 (0) 48 -> 48 (0) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 16.7 (0) 16.8 -> 16.8 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / session-streaming-long 40 -> 32 (-8) 56 -> 56 (0) 0 -> 0 (0) 0 -> 0 (0) 16.8 -> 16.8 (0) 33.2 -> 16.8 (-16.4) 0 -> 0 (0) 0 -> 0 (0) pass
default / tool-call-expand 24 -> 24 (0) 24 -> 40 (+16) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 16.8 (+0.1) 16.7 -> 16.8 (+0.1) 0 -> 0 (0) 0 -> 0 (0) pass
default / terminal-side-panel-open 48 -> 48 (0) 56 -> 56 (0) 0 -> 0 (0) 0 -> 0 (0) 33.4 -> 33.3 (-0.1) 33.4 -> 33.3 (-0.1) 0 -> 0 (0) 0 -> 0 (0) pass
default / session-scroll-reading 16 -> 16 (0) 16 -> 16 (0) 0 -> 0 (0) 0 -> 0 (0) 16.8 -> 16.7 (-0.1) 16.8 -> 16.7 (-0.1) 0 -> 0 (0) 0 -> 0 (0) pass
low-end / session-scroll-reading-long 0 -> 0 (0) 0 -> 0 (0) 60 -> 61 (+1) 10 -> 11 (+1) 33.3 -> 33.3 (0) 50 -> 50 (0) 0 -> 0 (0) 0 -> 0 (0) pass
low-end / session-timeline-recompute 32 -> 40 (+8) 40 -> 48 (+8) 0 -> 0 (0) 0 -> 0 (0) 33.3 -> 33.3 (0) 33.4 -> 33.3 (-0.1) 0 -> 0 (0) 1.075 -> 1.075 (0) pass
low-end / concurrent-shimmer-extreme 0 -> 0 (0) 0 -> 0 (0) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 16.7 (0) 16.8 -> 16.8 (0) 0 -> 0 (0) 0 -> 0 (0) pass

@Astro-Han
Astro-Han merged commit 6b813b2 into dev May 29, 2026
30 checks passed
@Astro-Han
Astro-Han deleted the codex/i936-vcs-parity branch May 29, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Application behavior and product flows enhancement New feature or request harness Model harness, prompts, tool descriptions, and session mechanics P2 Medium priority tech-debt Supplemental cleanup, maintainability, architecture, test, or quality debt context upstream Tracked upstream or vendor behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant