feat: grouped diff summary — explain --grouped and an AI review guide in diff view - #174
Open
athal7 wants to merge 3 commits into
Open
feat: grouped diff summary — explain --grouped and an AI review guide in diff view#174athal7 wants to merge 3 commits into
athal7 wants to merge 3 commits into
Conversation
Adds `lumen explain --grouped`, which clusters a diff into logical groups with a per-group AI summary plus an optional overall summary. - New grouped_summary module: JSON parsing (tolerant of markdown fences and stray prose), ground-truth file extraction from unified diff headers, reconciliation against hallucinated/missing files, and markdown rendering. - New AIPrompt::build_grouped_explain_prompt that instructs the model to return a single grouped JSON object. - Threads a new grouped: bool through the CLI, CommandType::Explain, and ExplainCommand, selecting the grouped prompt/renderer in provider::explain and ExplainCommand::execute. - --grouped conflicts with --query. Co-Authored-By: anthropic/claude-sonnet-5 <noreply@opencode.ai>
…marking
Adds an 'a' keybinding in the diff TUI that asks the AI to cluster the
current diff into logical groups with a per-group summary, shown in a
new scrollable modal, and lets the group's files be marked viewed
together (reusing the existing viewed_files/GitHub-sync machinery).
- Thread the provider through as Arc<LumenProvider> (main.rs,
command/mod.rs, command/diff/app.rs) so the diff TUI can share it
with a background grouping request.
- Add combined_unified_diff() to concatenate non-binary FileDiffs into
one unified diff string for the grouping prompt.
- Add generate_groups_async() to request a grouped summary via
ExplainCommand{grouped: true} on a background OS thread and report
the reconciled result back over an mpsc channel. Takes a
pre-captured tokio::runtime::Handle rather than calling
Handle::current() inside the spawned thread, since a bare
std::thread::spawn closure has no ambient runtime context and that
call would panic.
- New DiffGroups modal (title, files, and prose summary per group,
scrollable), cached on AppState.diff_groups and invalidated on
reload.
- Space inside the modal marks all files in the selected group as
viewed (set-only, syncs to GitHub in PR mode) without dismissing the
modal, so multiple groups can be marked in one sitting.
- Add AppState::file_index_for_path and the standalone
mark_paths_viewed helper backing the group-viewed action.
- Document the new 'a' keybinding in the help modal.
Co-Authored-By: anthropic/claude-sonnet-5 <noreply@opencode.ai>
Author
|
This PR builds on #176 ( |
Pressing `a` without --guide was a silent no-op, with no indication the flag was required. Also add a footer indicator while the AI grouping is generating, visible without toggling into the Guide sidebar first. Co-Authored-By: anthropic/claude-sonnet-5 <noreply@opencode.ai>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds AI-generated grouping of a diff into logical clusters with a
per-group summary, in two places:
lumen explain --grouped: clusters the diff, prints a summary pergroup plus an optional overall summary. Conflicts with
--query.lumen diff --guide: generates the same grouping for the diffbeing viewed and shows it as a "Guide" sidebar (toggle with
a)— a pager over AI-derived groups, each with its title, summary,
and file list.
,/.move between groups, arrows/jk move betweenfiles within a group (driving the normal diff pane), space marks
the current file viewed,
Vmarks every file in the group viewed.Off by default (
--guideorguide = truein config, mirroringwrap), since enabling it fires a background AI call on load.Implementation notes:
grouped_summarymodule parses the model's JSON response(tolerant of markdown-fenced output), reconciles the model's file
list against the diff's actual files (drops hallucinated files,
buckets anything missed into an "Ungrouped" group), and renders
markdown for the
explainpath.background worker thread now owns the
LumenProviderfor thesession and generates on request over an mpsc channel, so the
render loop never blocks on the network call. The worker captures
a
tokio::runtime::Handleonce, on a thread already inside theasync runtime context, and reuses it for every request — calling
Handle::current()from inside a freshly spawnedstd::threadpanics, since a bare thread has no ambient tokio context even with
a live multi-thread runtime.
and watch-reload) but cached per diff identity — commit SHA in
--stackedmode, a sha256 of the reconstructed diff otherwise —so revisiting the same diff never re-triggers a call.
explain --groupedand the diff-view path share one prompt builder(
AIPrompt::build_grouped_explain_prompt/explain_grouped); thediff view feeds it a diff reconstructed from the displayed file
content via
similar, since it doesn't retain a raw diff string.state, so it composes with
--pr's GitHub sync and--stacked'sper-commit tracking for free.
163 tests pass. No new clippy warnings versus main (pre-existing
clippy/fmt debt on a handful of files, untouched by this change).