Skip to content

fix(tui): preserve form drafts across tabs - #48952

Merged
nexxeln merged 4 commits into
anomalyco:v2from
OpeOginni:preserve-tab-drafts
Sep 14, 2026
Merged

nexxeln merged 4 commits into
anomalyco:v2from
OpeOginni:preserve-tab-drafts

Conversation

@OpeOginni

@OpeOginni OpeOginni commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Issue for this PR

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

  • Keeps unfinished V2 TUI form answers when a session tab unmounts.
  • Restores the active field, selections, custom input, validation state, and cursor when the user returns.
  • Owns drafts in an app-lifetime provider that evicts them on local or remote form settlement.
  • Adds regression tests for uncommitted text, prior choices in a multi-question form, and settlement from another client.

How did you verify your code works?

  • bun test test/cli/tui/form.test.tsx from packages/tui: 30 passed.
  • bun typecheck from packages/tui: passed.
  • bun run check from the repository root: passed.
  • Prettier and diff checks: passed.

Screenshots / recordings

Screen.Recording.2026-09-14.at.10.49.34.mov

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@holny holny 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.

Ran the suite on top of e73442c locally — 29/29 in form.test.tsx including the new remount test, and the restore path reads clean. Two observations:

The one gap I see: drafts are only evicted on reply/cancel success or on the next mount. If the form gets settled somewhere else (another tab or client answers it), the form list drops it, FormPrompt unmounts through the keyed Show in session/index.tsx:1375, and the onCleanup at form.tsx:236 stores a draft for a form id that never comes back — it sits in the module-level map for the whole TUI process. Small per abandoned form, but it adds up. The test fixture works around exactly this by giving each test a unique form id (formSequence in form.test.tsx:18), which is a hint the map could use an owner for eviction — e.g. dropping drafts whose ids fall out of the session's form list, or clearing them on session switch.

Smaller thing: the settle dance between onCleanup and reply/cancel is correct but only because both halves cooperate — cleanup snapshots the draft while settled is still false, then the .then() at form.tsx:299 deletes it after the fact. If that delete ever gets dropped, a stale draft quietly comes back for an already-answered form. Might deserve a one-line comment, or a settle() helper both paths call, since the settled = true + drafts.delete pair is duplicated in reply and cancel anyway.

The cursor restore with the gotoLineEnd fallback kept for the no-draft case is a nice touch, and asserting that no replies were sent during the round-trip is the right test shape.

OpeOginni and others added 2 commits September 14, 2026 11:17
Replace the app-lifetime FormDraftProvider and its event-driven settlement
bookkeeping with a module-level Map, mirroring component/prompt/draft-stash.
A settled form is already gone from data when FormPrompt unmounts, so a
membership check in onCleanup is enough to skip stashing it.
@nexxeln
nexxeln merged commit f64ce6a into anomalyco:v2 Sep 14, 2026
7 of 8 checks passed
@OpeOginni
OpeOginni deleted the preserve-tab-drafts branch September 22, 2026 11:11
jinhuang712 pushed a commit to jinhuang712/opencode that referenced this pull request Sep 26, 2026
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants