Skip to content

feat: v1.3 polish — agent activity, scrollback UX, graceful TOML, README#40

Merged
sebasv merged 3 commits intomainfrom
feature/v1.3-polish
Apr 25, 2026
Merged

feat: v1.3 polish — agent activity, scrollback UX, graceful TOML, README#40
sebasv merged 3 commits intomainfrom
feature/v1.3-polish

Conversation

@sebasv
Copy link
Copy Markdown
Owner

@sebasv sebasv commented Apr 25, 2026

Summary

A grab-bag of v1.3 polish driven by user feedback in this session:

  • Per-worktree agent indicator! (warn) when a shell in that worktree rang the bell (BEL), (dim) when it wrote output in the last ~2.5s. Aggregated across all terminals; bell clears on activate. Bell is the high-confidence "needs attention" signal that Claude Code, gh, and most readline tools already emit.
  • Scrollback-mode UX — mouse wheel reaching the live edge auto-exits scrollback; any non-navigation keypress in scrollback exits and forwards the key to the PTY (tmux copy-mode parity).
  • Shift+Enter — sends LF (\n) instead of the kitty CSI 13;2u escape, so it reaches Claude Code et al. as a literal newline.
  • Graceful TOML — typos in config.toml no longer refuse to start grove. Falls back to defaults with a sidebar warning and logs the full error.
  • README rewrite — character-aligned example block, full status-badge legend (working tree + PR + CI + agent), v1.3 features documented, Cargo.toml bumped to 1.3.0.

Test plan

  • cargo test (125 passed)
  • cargo clippy --all-targets -- -D warnings clean
  • cargo fmt clean
  • Manual: open a long buffer, scroll up via wheel, scroll back to bottom — mode should auto-exit.
  • Manual: in scrollback, press a — should snap to live edge and send a to the shell.
  • Manual: in a Claude Code session, press Shift+Enter — should produce a newline in the input box.
  • Manual: introduce a typo into config.toml and start grove — should see warning in sidebar and grove still launches with defaults.
  • Manual: with multiple shells per worktree, trigger BEL in one (e.g., a gh prompt) — sidebar row should show !.

🤖 Generated with Claude Code

sebasv and others added 3 commits April 25, 2026 10:25
Sidebar gains a per-worktree agent indicator: '!' (warn) when a shell
rang BEL — Claude Code, gh CLI, and most readline tools ring it on
prompt — and '…' (dim) when the shell wrote output in the last few
seconds. The bell flag clears when the user activates the worktree.
Aggregated across all terminals in a worktree; quiet shells stay silent.

Scrollback-mode UX:
- Mouse-wheel down to the live edge auto-exits scrollback (you're back
  where the shell is writing, so we drop the mode for you).
- Any non-navigation keypress in scrollback (letters, digits, Enter,
  Backspace, Ctrl+anything) snaps to the live edge and reaches the PTY,
  matching tmux copy-mode UX.

Shell input:
- Shift+Enter now sends LF instead of the kitty 'CSI 13;2u' sequence;
  most TUIs (Claude Code included) interpret LF as newline-in-input
  while plain Enter (CR) submits.

Config robustness:
- Config::load_or_default_lossy: malformed TOML falls back to defaults
  with a sidebar warning ('⚠ config.toml: parse error / using defaults;
  see grove.log') instead of refusing to start. The full error goes to
  the log for the user to read.

README:
- Rewritten example block with character-aligned columns.
- Documented every status badge (working tree + PR + CI + agent
  activity), since the meaning was previously oral tradition.
- Documented the new v1.3 surfaces: activity footer, fetch cadence,
  unified worktree modal, theme cycle, base-branch auto-detect.
- Cargo.toml bumped to 1.3.0.

Co-Authored-By: Claude <noreply@anthropic.com>
…stic)

Claude Code and most modern TUI agents announce their state via OSC 0
window-title updates: a braille spinner glyph (U+2800–U+28FF) prefixes
the title while output is streaming, then switches back to a static
'✳' once idle.  This is a far more precise signal than "any PTY byte
in the last 2.5s" — no false positives from background log spam,
spinner ticks unrelated to agent work, or terminal redraws.

Implementation:
- TerminalActivity gains a `title` field, populated by a
  `vt100::Callbacks` impl that pipes set_window_title and audible_bell
  events into the shared activity slot.
- Parser switches from `vt100::Parser` to `vt100::Parser<GroveCallbacks>`
  using `new_with_callbacks`.  Bell-byte scanning in the reader thread
  is removed — the callback handles it.
- `title_is_thinking()` classifies a title by its leading character
  (U+2800–U+28FF braille block).  Tested against real titles captured
  from a Claude Code session ("⠂ Claude Code", "⠐ Run ls command…",
  "✳ Say hi", "✳ Claude Code").
- `WorktreeTerminals::agent_state` uses the title as authoritative when
  set, and falls back to the recent-output heuristic only for shells
  that don't announce themselves.

Discovered via PTY capture of a real Claude Code session — see
/tmp/capture-osc.py + /tmp/drive-claude.py for the harness used.

Co-Authored-By: Claude <noreply@anthropic.com>
Without the kitty keyboard protocol, terminals send the same byte
(\\r) for both Enter and Shift+Enter — crossterm has nothing to
distinguish them, KeyEvent arrives as plain Enter, and our SHIFT
branch is never taken.  That's why the previous fix only sent LF for
Ctrl+J (which terminals encode as raw 0x0A regardless of mode), not
for Shift+Enter.

init_terminal pushes DISAMBIGUATE_ESCAPE_CODES; restore_terminal pops
it.  Both are best-effort: terminals that don't speak the protocol
silently ignore the escapes, so we tolerate the push/pop failing.

With this in place modern terminals (kitty, alacritty, foot, wezterm,
ghostty, recent iTerm2/Apple Terminal, the JetBrains terminals)
deliver Shift+Enter as KeyEvent { code: Enter, modifiers: SHIFT }, our
existing match arm sends LF, and Claude Code treats it as
newline-in-input.

Co-Authored-By: Claude <noreply@anthropic.com>
@sebasv sebasv merged commit 920989e into main Apr 25, 2026
1 check passed
@sebasv sebasv deleted the feature/v1.3-polish branch April 25, 2026 09:09
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