Skip to content

fix(work): make AI Work application undoable as a single editor edit - #394

Merged
petertzy merged 2 commits into
petertzy:mainfrom
harsh-thakkar7:fix/ai-work-undo-boundary
Oct 8, 2026
Merged

petertzy merged 2 commits into
petertzy:mainfrom
harsh-thakkar7:fix/ai-work-undo-boundary

Conversation

@harsh-thakkar7

Copy link
Copy Markdown
Contributor

Problem

Applying an AI Work result went straight through onDocumentChange, which updates React state but never performs an editor operation — so the AI replacement had no undo boundary of its own in Monaco. As issue #300 describes, a single Undo could not restore the exact pre-Work document.

Change

  • New importable module frontend/src/lib/apply-work-edit.mjs exporting applyWorkEdit(). When the mounted editor/model is available it replaces the full document with editor.executeEdits("ai-work", …) wrapped in editor.pushUndoStop() on both sides, so one Undo restores the pre-Work document and Redo reapplies the AI result without merging into the user’s previous typing.
  • useAIActions.executeWork() routes the (still freshness-guarded) result through applyWorkEdit, passing editorRef.current. The edit flows through the editor change callback, so the existing state/preview synchronization path is preserved.
  • Focus mode / editor-not-mounted falls back to onDocumentChange exactly as before.

Acceptance criteria (from #300)

  1. Applying to the unchanged active document is functionally equivalent — covered.
  2. One Undo restores the exact pre-Work content — covered.
  3. Redo restores the AI-applied content — covered.
  4. The replacement does not merge into the previous typing undo step — covered.
  5. Per-tab model isolation untouched — no model lifecycle changes.
  6. Focused regression coverage added; frontend test/lint/build green.

Tests

frontend/tests/ai-work-undo.test.mjs drives a real Monaco model: editor-vs-fallback routing, single-Undo/Redo, no merge with prior typing, consecutive AI applies each individually undoable, an unsealed prior edit not swallowed, and the no-editor fallback. Mutation-tested (dropping the opening/trailing undo stops, and forcing the fallback) — each mutation is caught.

Local: npm test 101 passed, npm run lint clean, npm run build green.

Fixes #300.

harsh-thakkar7 and others added 2 commits October 8, 2026 17:44
The AI Work result was pushed through onDocumentChange, which updates React
state but leaves the editor's undo stack untouched: the replacement was not
an editor operation, so one Undo could not restore the pre-Work document.

Extract applyWorkEdit() into src/lib/apply-work-edit.mjs and route executeWork
through it. When the mounted Monaco editor is available the full document is
replaced with editor.executeEdits("ai-work", ...) wrapped in pushUndoStop()
calls, so the whole AI result is one undo step (Undo restores the pre-Work
document, Redo reapplies it) and does not merge into the user's previous
typing. The change still flows through the editor change callback, preserving
the existing state/preview synchronization; when no editor/model is mounted
(focus mode, not yet ready) it falls back to onDocumentChange unchanged.

Fixes petertzy#300.
@petertzy

petertzy commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Approved. This is a necessary and well-scoped fix for the AI Work undo behavior. The implementation routes the full-document replacement through Monaco with explicit undo stops, preserving the existing change callback for state and preview synchronization while retaining the no-editor fallback. The focused regression coverage verifies undo/redo, separation from prior typing, consecutive Work applications, and fallback behavior. Frontend tests and lint pass.

@petertzy
petertzy merged commit 4d26d77 into petertzy:main Oct 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(work): make AI Work application undoable as a single editor edit

2 participants