Skip to content

feat(inspector): generate an earlier commit's message with AI while rewording it - #83

Merged
cheat2001 merged 4 commits into
cheat2001:mainfrom
alcalaperez:feature/ai-reword-message
Nov 1, 2026
Merged

cheat2001 merged 4 commits into
cheat2001:mainfrom
alcalaperez:feature/ai-reword-message

Conversation

@alcalaperez

Copy link
Copy Markdown
Contributor

What & why

You can already edit an earlier commit's message from the inspector (pencil button or double-click on the title), but that editor had no AI help. This PR adds the commit box's sparkle button to the editor's summary row. It sends that commit's own diff to the configured AI provider with your commit style and branch prefix rules, then fills in the summary and description. You review the text and press Save message, and the existing reword flow takes over: an undoable tracked('reword'), plus the force-push warning when the commit is already pushed. A run can be stopped, and Cancel, Save or selecting another commit throws away a late answer so it never lands in the wrong editor. No engine changes.

The second commit fixes a race that made the tabs switch with mod+digit… e2e test flaky on main (about 1 run in 5 locally). useRepo.open() adds the tab through a deferred import().then(addRepoTab), so a Ctrl+W right after switching to a tab could close it before that add ran, and the late add put the closed tab back. The add now skips when a newer open() has started (the G26 pattern). With the guard the test passed 30 of 30 runs.

Screenshots

One icon button (the commit box's existing Sparkles button) in the commit message editor's summary row.

image

Checklist

  • pnpm typecheck && pnpm test pass (280 unit tests)
  • cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo test pass (if Rust changed) — no Rust changes
  • New engine functions have integration tests in tests/git_engine.rs — none added
  • Mutating operations go through the undo tracked() wrapper where undoable — Save still uses tracked('reword')
  • Colors use design tokens only (no hex in components)
  • CLAUDE.md updated if conventions/architecture changed
  • Commits carry no trailers from coding tools (Co-authored-by: <tool>, Generated with …)

New e2e test: the AI button fills the summary and description while editing an earlier commit's message (stubbed Ollama /api/chat, checks the prompt carries the commit's diff) and saves. The full e2e suite passes locally, 121/121.

…ewording it

The commit message editor in the inspector gets the commit box's sparkle
button. It sends the commit's own diff to the configured AI provider with the
commit style and branch prefix rules, and replaces the draft summary and
description. The run is stoppable, and cancel, save or selecting another
commit discard a late answer.
useRepo.open() adds the tab through a deferred import, so a Ctrl+W right
after switching to a tab could close it before that add ran, and the late
add put the closed tab back. The add now skips when a newer open started.
The tab shortcut e2e failed about one run in five on main because of it.
@cheat2001

Copy link
Copy Markdown
Owner

Thanks Joel, this is a nice one and the tab race fix is real, I got the mod+digit test to fail 1 in 15 on main and 20 of 20 with your guard.

One thing from running it in WebKit. Clicking a button there doesn't focus it, so after a click on the sparkle nothing in the editor has focus and Escape and ⌘⏎ stop working until you click back into a field. Chromium focuses the button, which is why the e2e didn't catch it. The disabled on the two textareas also dims them to 50% and drops the editor's ring while it runs.

What fixed it for me: readOnly={messageAiBusy} instead of disabled on both fields, and draftSummaryRef.current?.focus() as the first line of generateDraftMessage. I also tightened your e2e so it checks the summary is focused after the click and that Escape closes the editor while the stubbed provider is still waiting. I'll fold that in when I land this unless you'd rather push it yourself.

@cheat2001 cheat2001 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Details in my comment above: the sparkle needs to keep focus inside the editor and the fields should be readOnly rather than disabled while it runs. Happy to fold it in myself if you'd rather not push again.

… it runs

WebKit never focuses a clicked button, so clicking the sparkle left
nothing inside the editor focused and Esc and Cmd+Enter stopped working
until a field was clicked again. generateDraftMessage now focuses the
summary first, on both the start and the stop click. The summary and
description are locked with readOnly instead of disabled while a run is
in flight, so they hold focus-within (the editor's ring) and no longer
dim to 50%.

The e2e holds the stubbed provider's answer, asserts the summary is
focused after the click and that Escape closes the editor while the
answer is still pending, then fills and saves on a second run.
The PR's unreleased entries (AI reword, AI editor keyboard fix, tab-close
fix) stay under Unreleased; main's 0.25.0 section lands verbatim below
them. The testing map takes main's updated counts with the AI e2e
description reapplied (E2E now 122).
@alcalaperez
alcalaperez requested a review from cheat2001 October 29, 2026 08:20

@cheat2001 cheat2001 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the fix, thanks Joel. The new test fails in WebKit without the focus line and passes with it. Merging.

@cheat2001
cheat2001 merged commit d36f473 into cheat2001:main Nov 1, 2026
6 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.

2 participants