Skip to content

Add /undo and /redo commands like OpenCode - #944

Open
KazenDev wants to merge 1 commit into
CodebuffAI:mainfrom
KazenDev:feat/undo-command
Open

Add /undo and /redo commands like OpenCode#944
KazenDev wants to merge 1 commit into
CodebuffAI:mainfrom
KazenDev:feat/undo-command

Conversation

@KazenDev

@KazenDev KazenDev commented Aug 5, 2026

Copy link
Copy Markdown

Closes #907

Adds snapshot-based /undo and /redo commands modeled after OpenCode's snapshot service, with a native full-screen picker.

What

  • cli/src/utils/undo-snapshot.ts — isolated per-project git snapshot repo (track / restore / revert / diff) that never touches the real .git
  • cli/src/state/undo-store.ts — per-chat undo journal with jump-back semantics: undoing a turn reverts that turn plus everything newer
  • /undo and /redo open a /history-style picker: searchable, keyboard and mouse, with a live files panel (modified / created / deleted)
  • Colored, detailed confirmations with the diff stat (git-style colors)

Why

Users currently have no way to revert the agent's changes without manual git surgery. This is the safety net that makes it safe to let the agent edit code freely.

Notes

  • Snapshots reuse the source repo's object database (alternates) for speed
  • Best-effort: failures disable undo for that turn rather than breaking the chat
  • The user's real git history is never touched

@KazenDev

KazenDev commented Aug 5, 2026

Copy link
Copy Markdown
Author

Thanks for taking a look! Since this mirror doesn't run public CI, here's how the change was validated and how to try it.

Automated tests (2 new files, ~264 lines):

bun test cli/src/state/__tests__/undo-store.test.ts cli/src/utils/__tests__/undo-snapshot.test.ts
# or the full CLI suite: cd cli && bun run test

Also validated locally with bun run typecheck (cli + sdk).

Manual walkthrough:

  1. Start the CLI on a scratch project (from cli/: bun run dev).
  2. Ask the agent to modify, create, and delete files in a single turn.
  3. Run /undo — a /history-style picker opens: arrow keys or mouse to select, type to search, Enter to undo, Esc to cancel. Each entry shows the user message and the files it touched.
  4. The selected turn and every newer one are reverted. The colored confirmation shows the git-style diff stat: files restored (↺) or removed (🗑).
  5. Run /redo — it offers the captured states; redo restores them. Jumping back past a redo entry invalidates the newer redo entries.
  6. Quit and reopen the CLI on the same project — /undo still lists the history (persisted per chat in undo.json, max 20 entries).

Notes:

  • Snapshots live in an isolated git repo (--git-dir / --work-tree); the user's real .git is never touched.
  • Snapshots reuse the source repo's object database via objects/info/alternates, so snapshots are fast.
  • Best-effort by design: if a snapshot fails for a turn, undo is disabled for that turn instead of breaking the chat.
  • Granularity is per turn (one agent message), matching the semantics requested in add /undo action #907.

@codebuff-team

Copy link
Copy Markdown
Contributor

This is clearly a serious effort — isolated snapshot git repo, per-chat undo/redo journal, a full-screen picker modeled on the existing /history UI, colored diff-stat rendering, and unit tests for both undo-store and undo-snapshot. That puts it well above the median PR here.

Concerns that keep this from being a clean port:

  1. Size/scope: +1935/-16 across 18 files touching core chat flow (use-send-message.ts), command registry, message rendering, and a new isolated git-snapshot subsystem. That's a lot of surface area for a maintainer to verify against a private codebase that may already have diverging internals in these exact files (chat.tsx, app.tsx, use-send-message.ts are hot paths).

  2. Snapshot lifecycle unclear: trackSnapshot/patchSnapshot run on every turn even when isUndoEnabled() is on, but there's no visible cleanup/GC of the snapshot object store over long sessions — worth confirming it doesn't grow unbounded.

  3. Race conditions: runChatId is captured to survive chat switches, but recordUndoEntry in the finally block runs regardless of whether the run was superseded by a newer one; interleaved concurrent turns (if ever possible) could record entries against the wrong snapshot state.

  4. UX assumption: jumping back via /undo reverts everything newer, which is a reasonable OpenCode-style semantic but a behavior change users need to be warned about clearly in the picker (right now it's only in a code comment, not obviously surfaced in the UI copy for multi-turn jumps).

Given the size and the coupling to use-send-message.ts, I'd want to see this split into a smaller first PR (snapshot utility + store, no UI) before the full picker lands, so a maintainer can review the risky bits in isolation.

@codebuff-team codebuff-team added bot:triaged Classified by the community triage bot pr:needs-work Right idea, not mergeable as written labels Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:triaged Classified by the community triage bot pr:needs-work Right idea, not mergeable as written

Projects

None yet

Development

Successfully merging this pull request may close these issues.

add /undo action

2 participants