feat(chat): one-click "Revert changes" button for agent modifications (closes #85)#192
Open
haoyu-haoyu wants to merge 1 commit intoOpenLAIR:mainfrom
Open
feat(chat): one-click "Revert changes" button for agent modifications (closes #85)#192haoyu-haoyu wants to merge 1 commit intoOpenLAIR:mainfrom
haoyu-haoyu wants to merge 1 commit intoOpenLAIR:mainfrom
Conversation
…R#85) Adds a "Revert changes" button to each finished agent turn. Clicking it opens an inline confirmation, then sends the list of files that turn modified (via Edit / Write / ApplyPatch / MultiEdit / FileChanges tool calls, scraped from both toolInput and toolResult payload shapes) to a new POST /api/git/revert-agent-changes endpoint. The endpoint reverts each file independently: - untracked regular files the agent created are unlinked (directories and symlinks pointing outside the repo are refused) - tracked worktree+staged modifications are restored to HEAD with git restore --source=HEAD --staged --worktree - staged adds are unstaged and the working-tree copy is removed - rename / copy pairs are skipped so a revert cannot leave the repo with a half-applied rename - per-file error reporting, never all-or-nothing Porcelain is read once with --porcelain -z so filenames containing a literal " -> " do not confuse rename parsing. Path traversal is blocked via the existing safePath helper; untracked-symlink deletion is additionally re-validated with realpath() before unlink. Frontend uses authenticatedFetch (matching GitPanel patterns) and exposes aria-live status updates, focus-on-open, Escape to cancel. Copy is translatable via a new revertAgent block in en / zh-CN / ko. Tests: 8 new backend integration tests against a real temp git repo (including MM, AD, renamed, rename-with-modification, filenames containing " -> ", symlink safety, directory-deletion refusal) plus a route-level smoke test hitting POST /api/git/revert-agent-changes through an in-process Express app. 12 new frontend unit tests covering object / stringified-JSON / multi-file / Codex FileChanges / object-map changes / malformed input / subagent-child-tool extraction. All 130 tests pass; tsc --noEmit clean. Design notes: - Reverts restore to HEAD state. Any manual edits to one of the same files the agent modified will also be lost; the confirmation text warns about this explicitly. Edits to OTHER files are untouched. - Per-turn exact-snapshot revert with conflict detection would require capturing pre-agent content for each tool call; that's a larger change and can be a follow-up.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a "Revert changes" button to each finished Coding Agent turn so users can roll back that turn's file modifications from the chat UI instead of context-switching to the terminal for
git restore .. Closes #85.What it does
Edit/Write/ApplyPatch/MultiEdit/FileChangestool callstoolInput, multi-filefile_pathsarrays, Codex'skind: pathnewline format, and object-mapchangesfrom patch-apply results)POST /api/git/revert-agent-changesgit restore --source=HEAD --staged --worktree(handlesMM/AM/AD/MD/DM)git reset HEAD+ unlinkSafety
safePathhelper.realpath()against the project root beforeunlink.git status --porcelain -zprevents filenames containing" -> "from confusing rename parsing.git restoresemantics since we restore toHEAD, not a pre-agent snapshot. Per-turn exact-snapshot revert (with conflict detection for files the user also touched) would need pre-agent content capture and feels like a separate PR.Accessibility
role="group"on the inline confirmation witharia-label, focus moves to the destructive action on open, Escape cancels and restores focus to the triggerrole="status"+aria-liveon reverting / done / error statesaria-hiddenTest plan
All 130 Vitest tests pass (incl. 8 new backend integration tests against a real temp git repo, 1 in-process Express route test, and 12 new frontend unit tests).
tsc --noEmitclean.npm test -- --run(130 passed, 18 test files)npm run typecheck(clean)MMstate, rename skip, rename-with-modification skip, symlink safety (external file preserved), directory rejection, path traversal blocked, filename containing" -> "toolInput, stringified-JSONtoolInput, multi-filefile_paths, CodexFileChangesstring format, object-mapchanges, array-of-stringschanges, malformed JSON, subagent children, tool-error skipping, no-result skippingproject, 400 on non-arrayfiles, empty list, happy path, partial success reportingi18n
Added
revertAgentblock toen,zh-CN,kochat locales with i18next pluralization (_one/_other).Follow-ups (not in this PR)
providerInfo.nano,readyPrompt.nano) — left for a separate i18n-sync PR