feat(tui): add /undo and /revert commands - #43
Conversation
The dashboard's "edit message" flow already lets an operator drop a turn
and revert every file the agent touched in it. The TUI had no way to
reach that machinery — operators had to leave the terminal, open the
dashboard, find the message, and click a button, or hand-edit
~/.antares/checkpoints/ and prune the message log by hand.
/undo stages a rollback of the most recent user turn:
Revert to the last turn?
3 file(s) to restore (1 created files will be removed).
1 file(s) edited outside this session will be skipped.
[revert] internal/agent/agent.go
[delete] internal/agent/foo_new.go
[skip ] README.md
Press y to confirm, any other key to cancel.
'y' on an empty composer runs the same three-step commit the dashboard
uses: agent.RollbackSince (files), store.DeleteMessagesFrom (message
log), and drop the persisted context_compact summary whose through_seq
now points past deleted rows. Esc or any other key discards the stage
and falls through so the keystroke lands normally — no modal to
dismiss, no separate confirm widget.
/revert opens the existing modal picker over the session's user
messages, newest first, with a preview label and "N turns ago" hint.
Selecting an entry runs through the same stage/commit path. Also
accepts /revert <message-id> for scripts and copy/paste from the
dashboard.
The dashboard, /undo, and /revert share every primitive
(agent.PreviewChangesSince / RollbackSince, store.DeleteMessagesFrom)
so their behaviour stays in sync — a fix to the checkpoint layer lands
in both surfaces at once. TUI-side additions total ~330 lines behind
the existing Model + block/picker infrastructure.
/redo is intentionally out of scope: OpenCode and omp implement it by
recording reverse-ops per tool call into a session journal, which
Antares does not have. Adding it would need a schema change; left as
future work.
Tests cover the picker-label renderer (previewText), the confirm
message shape (counts, tags, always-present cancel hint), the cancel
path (state cleared, idempotent), and that both commands stay in the
palette registry.
|
Merged into 1. 2. The "N skipped" count was always zero. Three regression tests added in The design itself is good — reusing Verified: |
What
Two new TUI slash commands that reuse the dashboard's edit-message primitives:
/undo— rollback the most recent user turn (files + messages)./revert— picker over the session's user messages; rollback to any earlier point. Also accepts/revert <message-id>for scripts and copy/paste from the dashboard.Why
The dashboard's "edit message" flow already lets an operator drop a turn and revert every file the agent touched in it. The TUI had no way to reach that machinery — operators had to leave the terminal, open the dashboard, find the message, and click a button, or hand-edit
~/.antares/checkpoints/and prune the message log by hand.UX
Inline confirm block, no modal.
yon an empty composer commits, Esc discards, everything else discards and falls through so the keystroke lands normally./revertuses the same modal picker/modeland/themealready use — one keyboard idiom for every selection. Preview label carries the message text (single-line elided at 60 chars); right column showslatest/N turns ago.Commit path
Files first, then messages, then drop the persisted context summary:
agent.RollbackSince(sessionID, marker, skipExternal=true)— restore snapshots, remove agent-created files, honour "externally changed" (leave user-edited files alone).store.DeleteMessagesFrom(sessionID, marker)— drop the message and everything after it.meta.context_compact— itsthrough_seqnow points past deleted rows; leaving it would either replay a stale summary or hide live messages.If file restore fails, the message log stays intact — a half-done state where messages are gone but files are still at their post-turn contents is worse than "nothing happened, try again".
Every primitive is the same one
server/handlers_chat.go'shandleEditMessageuses, so the dashboard and TUI stay in sync — a fix in the checkpoint layer lands in both surfaces at once./redo— intentionally not includedOpenCode and omp implement
/redoby recording reverse-ops per tool call into a session journal. Antares has append-only messages plus per-turn checkpoint tarballs; no branch semantics. Adding/redowould need a schema change (session_undo_log table + reverse-op recording per tool call). Left as future work — same conclusion as the "known bugs" gap OpenCode issue #15391 documents.Files
internal/tui/undo.gointernal/tui/undo_test.gointernal/tui/tui.gopending *pendingRevertfieldinternal/tui/tui.goy/Esc after a stageinternal/tui/commands.go/undo+/revertin paletteNot touched
Verify
GOTOOLCHAIN=go1.26.3 go build ./...cleanGOTOOLCHAIN=go1.26.3 go vet ./...cleango test ./internal/tui/... ./internal/agent/... ./internal/server/... ./internal/checkpoint/... ./internal/store/... -count=1— 5 packages greengo run ./cmd/antares tui→/undo,/revert,/revert <id>all work; empty-session guards fire the expected notice; cancel path leaves state untouched.