Skip to content

feat(review): add working-tree staging, hunk actions, and focused files-pane UX - #1021

Open
yusing wants to merge 12 commits into
modem-dev:mainfrom
yusing:main
Open

feat(review): add working-tree staging, hunk actions, and focused files-pane UX#1021
yusing wants to merge 12 commits into
modem-dev:mainfrom
yusing:main

Conversation

@yusing

@yusing yusing commented Sep 7, 2026

Copy link
Copy Markdown

Problem

Working-tree review in Hunk could show a diff, but it could not act like a Git working-tree tool. Staging, unstaging, discarding, and stashing still required leaving the TUI. File-list navigation also fought the review stream for the same keys, so it was easy to page, stage, or discard the wrong thing.

User impact

In a Git working-tree review, Hunk now lets you inspect and mutate staged vs unstaged work in place:

  • Tab switches the full Unstaged / Staged review stream.
  • Space (or file-row double-click) stages remaining unstaged changes, or unstages a fully staged file. After a code-line click or [ / ], Space stages or unstages only that hunk.
  • d discards the selected file or folder (all changes, or unstaged-only when both sides have work).
  • s stashes only the selected file or folder, preserving its staged/unstaged split and leaving unrelated files alone.
  • e opens $EDITOR at the selected changed line, mapping staged index lines through later unstaged edits.
  • Files-pane folders are selectable. Space, discard, and stash apply to the files shown under that folder.
  • The focused pane is visually emphasized. //j/k move in the files pane when it owns focus; Enter focuses the selected file’s review; Escape returns to the files pane.
  • Sidebar rows show Git-style status colors and keep +/- counts on both tabs.

Keyboard and mouse stay paired for the new actions. Built-in review shortcuts keep their meaning outside an actionable working-tree files pane.

Approach

Keep Pierre as the renderer and the shared review document as the semantic model. Add working-tree mutation as optional VCS provider operations, then drive them from one host-side action layer (useWorkingTreeActions) and a files-pane focus/selection model.

The bundled Git provider implements:

  • exact-file stage / unstage
  • canonical hunk stage / unstage (byte-preserving patches, attestation-checked)
  • scoped discard and stash (including multi-file stashFiles)
  • staged-to-worktree line mapping for the editor

The public extension API is bumped so other adapters can opt in without a parallel protocol:

Version Addition
v20 stageHunk / unstageHunk
v21 discardFile / stashFile
v22 resolveWorkingTreeLine
v23 inventory statusCode
v24 stashFiles
v25 inventory stats (additions / deletions)

Sidebar extensions receive selectedEntryId, selectEntry, and toggleEntry so folder rows are first-class.

Why this belongs in core

Staging, discard, stash, stream tabs, and pane-focus behavior are the default working-tree review, not an opt-in workflow. The host has to own shortcut precedence, confirmation prompts, reload/shutdown serialization, and review-stream geometry. Provider-specific Git writes stay in packages/hunk-git behind the existing hunkdiff/extension contract.

Non-goals

  • Jujutsu and Sapling mutation. The new operations are optional; only the Git adapter implements them here.
  • Browser/session remote commands for staging. These remain host-only TUI actions.
  • Changing the main pane into a single-file view. Sidebar selection still jumps inside the full review stream.
  • Replacing Pierre or the shared review reducer.

Tests

This branch adds provider, command, component, AppHost, and PTY coverage for the new behavior, including:

  • packages/hunk-git/src/{workingTree,hunkStaging,fileActions,editorLine,commands}.test.ts
  • packages/hunk/src/ui/AppHost.working-tree.test.tsx
  • packages/hunk/src/ui/AppHost.interactions.test.tsx
  • test/pty/working-tree-integration.test.ts
  • test/pty/editor-integration.test.ts

This PR submission did not re-run the suite against modem-dev/hunk main.

Suggested checks:

bun run typecheck
bun run test
bun run test:integration

Platforms

  • Developed and rebased on Linux.
  • macOS / Windows not re-verified here. PTY coverage is Unix-only, as elsewhere in the repo.

Visual evidence

None attached yet. The changes are terminal-native (focus chrome, status colors, stream tabs, folder rows, confirm/stash dialogs). Screenshots or a short PTY video can follow if useful for review.

Limitations / follow-up

  • Binary, text-converted, and metadata-only changes keep file-level actions; hunk staging refuses those patches.
  • Unknown editor line-jump syntax is refused rather than opening at file start.
  • Stashing requires an initial commit.
  • d / s only take over discard/stash while the files pane is visible and focused; otherwise they keep half-page scroll and files-pane toggle.
  • Actions wait for Git and a refreshed diff before accepting another mutation.

Commits

  1. feat(review): add status-aware file staging and stream tabs
  2. feat(review): stage and unstage the active diff hunk
  3. feat(review): discard and stash only the selected file
  4. feat(review): open the editor at the selected changed line
  5. feat(ui): show Git-style file status colors
  6. fix(ui): scope file quick actions to the focused sidebar
  7. fix(ui): resolve shortcut ownership across review focus and menus
  8. feat(ui): indicate focused pane and scope keyboard actions to it
  9. feat(ui): make files-pane folders actionable
  10. feat(ui): keep working-tree folder actions and line stats on both tabs
  11. feat(ui): add Enter/escape pane focus commands
  12. fix: reconcile rebased staging and sidebar integrations

Expose both Git status sides through the public VCS and sidebar contracts. Stage or unstage exact files with Space and consecutive mouse double-clicks, preserve unrelated changes, and reconcile writes through reload and graceful shutdown. Add provider, command, component, and PTY coverage plus extension and keybinding documentation.
Apply byte-preserving canonical Git hunks with status and HEAD attestation. Keep unrelated hunks and worktree content intact, refuse text-converted patches, and integrate scoped Space and release-confirmed double-click actions through the provider contract.
Add exact-file confirmation and stash-message prompts with contextual keys and mouse parity. Preserve unrelated live changes and stash trees, partial staging, tracked modes, and recoverable published stashes when cleanup fails.
Track deliberate line selection separately from viewport seeding, fall back to the active hunk's first change, and map staged source addresses through later worktree edits. Guard asynchronous lookups by review generation and refuse unsupported editor line syntax.
Render index and worktree status columns with semantic colors, highlight
selected rows across the full sidebar width, and color fully staged
filenames. Add optional `statusCode` to the v21 extension API, expose
Git status codes, and document and test the new sidebar behavior and
theme contrast.
Hide shadowed key hints from help and menus, keep file quick actions
scoped to the focused sidebar, and fall back to file staging when hunk
staging is unavailable. Add coverage for pointer focus, shortcut
precedence, and working-tree behavior.
Track focus ownership between the files pane and the review stream so
pointer and command toggles move cursor ownership cleanly:
`↑`/`↓`/`j`/`k` now step files when the files pane is focused,
review focus stays in the diff stream, and `Space` stages the file when
a selected hunk is not stageable. Review-stream clicks now drop
files-pane quick-action scope, and focused panes are visually emphasized
with brighter frame and divider styling.

Centralize shortcut labeling for help and menus through first-match
command ownership so a command only advertises keys that are actually
reachable, preventing shadowed aliases from appearing while preserving
visible alternatives on the real owner. Updated command descriptions,
docs, and focused-pane/interaction tests to match the new focus model
and selection behavior.
Add a files-pane selection model that tracks folder rows alongside
files, and thread folder-aware entry IDs through sidebar rendering and
extension working-tree props. Folder and file rows are now
selectable/clickable with updated focus and highlighting, and the
focused entry is kept coherent across tree and compact sidebar modes.

Wire the new model into working-tree actions so `Space`, discard, and
stash now operate on the focused files-pane row, including folders.
Folder actions apply to all nested files in tree view or all files under
a compact group row, with updated prompts/messages and selection
behavior.

Bump extension VCS API version and expose
`selectedEntryId`/`selectEntry`/`toggleEntry`, plus a new provider
operation `stashFiles` so folder actions can stash multiple attested
files in one operation. The Git adapter now performs multi-file stashes
while preserving per-file staged-untracked semantics, with docs and
tests updated for the new behavior.
Add optional `stats` (`additions`/`deletions`) to working-tree file
inventory in API v23 and enrich git status rows from `git diff
--numstat` across both staged and unstaged sides, including
rename/copy-safe parsing and untracked/symlink/large-file count
handling, so sidebar +/- stays visible even when a file is off the
active review stream.

Preserve folder selection semantics by choosing a nested path on the
current tab when available so folder-stage/discard/stash actions do not
unexpectedly jump sides, and update sidebar rendering helpers, selection
tests, and docs/keybinding wording to reflect file-or-folder actions and
stable stats visibility across tabs.
Add `hunk.review.focusDiffPane` and `hunk.review.focusFilesPane` command
entries and App bindings so Enter focuses the selected file’s review
and Escape returns focus to the files pane, with enablement tied to
active pane state and selection kind. Normalize Escape key matching for
`escape`, `esc`, and raw `\u001b`, expose both actions in file
menu/help/keyboard docs, and extend command, menu, and interaction tests
(including mode handoff coverage with overrideable bindings) for the new
focus behavior.
@greptile-apps

greptile-apps Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

PR author is not in the allowed authors list.

@vercel

vercel Bot commented Sep 7, 2026

Copy link
Copy Markdown

@yusing is attempting to deploy a commit to the Modem Team on Vercel.

A member of the Team first needs to authorize it.

@benvinegar

Copy link
Copy Markdown
Member

@yusing This feels like a large UX change, with no screenshots/video etc. Did you consider building this as an extension instead?

(It's unlikely I'm going to merge this because it's not aligned with the project goals. The core is not trying to rebuild lazygit. But if you need more extension points to make that happen, that's worth discussing.)

https://hunk.dev/extensions

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