Skip to content

feat(overlay): full command display, smart regex proposal, tmux notification passthrough#24

Merged
nnemirovsky merged 5 commits intomainfrom
feat/overlay-smart-proposal
Apr 18, 2026
Merged

feat(overlay): full command display, smart regex proposal, tmux notification passthrough#24
nnemirovsky merged 5 commits intomainfrom
feat/overlay-smart-proposal

Conversation

@nnemirovsky
Copy link
Copy Markdown
Owner

Summary

  • Full command display: overlay wraps long commands to terminal width instead of truncating at 120 chars with "..."
  • Smart regex proposal: when user picks "Yes, always" / "No, always" on a compound Bash command where some segments are already auto-allowed (readonly or existing rule), the suggested regex now targets only the uncovered portion instead of the full command's first word. Example: ls && weird_cmd suggests ^weird_cmd...$, not ^ls...$
  • Tmux notification passthrough: OSC 777 notification now writes to /dev/tty instead of stdout (stdout was being captured as the hook's JSON response and lost). Inside tmux, wraps the OSC in DCS tmux; ... ST passthrough so Ghostty receives the notification through the popup. Requires set -g allow-passthrough on in tmux.conf.

Test plan

  • All 863 bats tests pass (up from 855, +8 new tests)
  • New unit tests for compute_unallowed_segments (5 cases: readonly filter, allow-rule filter, all-readonly, no-coverage, invalid-path)
  • New overlay tests for proposer env var (3 cases: uses segment, first non-empty segment, empty var fallback)
  • Manual: trigger overlay on ls && weird_cmd, verify suggested rule targets weird_cmd
  • Manual: trigger overlay on long command (e.g. echo "very long text...") and verify full text is wrapped, not truncated
  • Manual: trigger overlay inside Ghostty + tmux, verify desktop notification fires (requires allow-passthrough on in tmux)

…ication passthrough

- overlay-dialog: wrap long commands at terminal width instead of truncating with "..."
- propose-rule: when compound command has uncovered segments (via new
  PASSTHRU_OVERLAY_UNALLOWED_SEGMENTS env var), target the first uncovered
  segment's first word instead of the full command's first word
- pre-tool-use: compute uncovered segments via new compute_unallowed_segments
  helper in common.sh (filters out readonly auto-allowed + allow/ask matched)
- notification: write OSC 777 to /dev/tty instead of stdout (stdout is the
  hook's JSON response); wrap in DCS tmux; ... ST passthrough when inside tmux
  so Ghostty can receive the notification through the tmux popup
…atching

`go test ./... | tail -50` with user rule `^go` used to fall through to
overlay because `tail -50` had no allow rule. But tail IS readonly.

Fix: before calling match_all_segments on compound Bash commands,
pre-filter out segments that are readonly-auto-allowed (match readonly
regex + paths inside cwd/allowed_dirs). The filter is gated on
has_redirect=false so `cat file > /tmp/out && ls` still falls through
when has_redirect would have blocked the readonly step.

Also adds regression tests:
- readonly segment covers for compound allow
- filter respects has_redirect guard
- 2>&1 fd duplication does not trigger has_redirect
The overlay queue lock was scoped to $TMPDIR, which on macOS is often a
per-process folder under /var/folders/... - not shared across CC sessions.
Two simultaneous CC sessions could each open their own tmux popup,
breaking the serialization.

Also: when a hook was SIGKILLed (OOM, timeout) the lock directory
persisted forever, blocking every subsequent overlay until manually
cleared.

Fixes:
- Lock lives at $(passthru_user_home)/passthru-overlay.lock.d, guaranteed
  shared across CC sessions of the same user.
- New _OVERLAY_LOCK_STALE_AFTER threshold (default 180s, > overlay
  timeout + margin): if the existing lock's mtime is older than that,
  clear it and retry. Checked every ~2s during wait.
- Default lock timeout raised from 90s to 180s to match typical user
  response time across multiple queued sessions.
…ook ordering

- correct stale 75s hook timeout reference (actual is 300s)
- new "Overlay queue lock (cross-session)" section: user-home lock path,
  macOS TMPDIR caveat, stale-lock recovery
- new "Interaction with CC's native permission system" section: decision
  cascade that explains why "ask" triggers native dialog, and how
  multi-plugin hook ordering causes passthru to see either original or
  wrapped (rtk) commands
- new "Notifications on overlay prompt" section: /dev/tty requirement and
  tmux DCS passthrough wrapping
- document PASSTHRU_OVERLAY_LOCK_TIMEOUT, PASSTHRU_OVERLAY_LOCK_STALE_AFTER,
  and PASSTHRU_OVERLAY_UNALLOWED_SEGMENTS env vars
@nnemirovsky nnemirovsky merged commit ba04f0a into main Apr 18, 2026
2 checks passed
@nnemirovsky nnemirovsky deleted the feat/overlay-smart-proposal branch April 18, 2026 08:52
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