Skip to content

feat: grouped diff summary — explain --grouped and an AI review guide in diff view - #174

Open
athal7 wants to merge 3 commits into
jnsahaj:mainfrom
athal7:feat/grouped-diff-summary
Open

feat: grouped diff summary — explain --grouped and an AI review guide in diff view#174
athal7 wants to merge 3 commits into
jnsahaj:mainfrom
athal7:feat/grouped-diff-summary

Conversation

@athal7

@athal7 athal7 commented Jul 10, 2026

Copy link
Copy Markdown

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 per
    group plus an optional overall summary. Conflicts with --query.
  • lumen diff --guide: generates the same grouping for the diff
    being 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 between
    files within a group (driving the normal diff pane), space marks
    the current file viewed, V marks every file in the group viewed.
    Off by default (--guide or guide = true in config, mirroring
    wrap), since enabling it fires a background AI call on load.

Implementation notes:

  • New grouped_summary module 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 explain path.
  • The diff TUI previously had no AI wiring at all. A persistent
    background worker thread now owns the LumenProvider for the
    session and generates on request over an mpsc channel, so the
    render loop never blocks on the network call. The worker captures
    a tokio::runtime::Handle once, on a thread already inside the
    async runtime context, and reuses it for every request — calling
    Handle::current() from inside a freshly spawned std::thread
    panics, since a bare thread has no ambient tokio context even with
    a live multi-thread runtime.
  • Generation is eager (fires on diff load, stacked-commit navigation,
    and watch-reload) but cached per diff identity — commit SHA in
    --stacked mode, a sha256 of the reconstructed diff otherwise —
    so revisiting the same diff never re-triggers a call.
  • explain --grouped and the diff-view path share one prompt builder
    (AIPrompt::build_grouped_explain_prompt / explain_grouped); the
    diff view feeds it a diff reconstructed from the displayed file
    content via similar, since it doesn't retain a raw diff string.
  • Group-level "mark all viewed" reuses the existing viewed-file
    state, so it composes with --pr's GitHub sync and --stacked's
    per-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).

athal7 and others added 2 commits July 9, 2026 13:46
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>
@athal7

athal7 commented Jul 10, 2026

Copy link
Copy Markdown
Author

This PR builds on #176 (explain --grouped) — once that merges, I'll rebase this branch so the diff here only shows the diff --guide TUI work.

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

1 participant