Skip to content

fix: worktree hook race + FocusActiveProject keybinding#86

Merged
neumie merged 3 commits intomainfrom
fix/worktree-hook-race
Mar 27, 2026
Merged

fix: worktree hook race + FocusActiveProject keybinding#86
neumie merged 3 commits intomainfrom
fix/worktree-hook-race

Conversation

@neumie
Copy link
Copy Markdown
Contributor

@neumie neumie commented Mar 27, 2026

Summary

  • Fix race condition where WorktreeSyncWatcher could remove projects while before_worktree_remove hooks were still running — now checks closing_projects and creating_projects guards
  • Add FocusActiveProject toggle keybinding (Cmd+Shift+0 / Ctrl+Shift+0) to zoom into/out of the active terminal's project
  • Center-scroll on the previously-focused project when exiting project zoom (deferred to next layout pass for correct bounds)
  • Merge new default keybindings into existing saved config on load so new actions appear in the UI
  • Revert ShellType::OneShot — all hook terminals go through the session backend

Test plan

  • Open multiple projects, focus a terminal, press Cmd+Shift+0 — zooms into that project
  • Press Cmd+Shift+0 again — zooms out and centers on the project
  • Clear focus via Cmd+0 or status bar ✕ — also centers
  • Verify FocusActiveProject appears in keybindings settings panel
  • Confirm hooks still run through dtach/tmux/screen session backend
  • Create/close worktree projects while hooks are running — no premature removal

🤖 Generated with Claude Code

neumie and others added 2 commits March 27, 2026 17:02
…nning

Two race conditions caused worktrees to be removed before the
before_worktree_remove hook finished:

1. The WorktreeSyncWatcher (30s periodic cleanup) ignored lifecycle state
   and would auto-remove projects whose directories were temporarily missing
   while a hook was running.

2. Hook terminals with keep_alive=false went through the dtach session
   backend, decoupling the hook process from the PTY lifecycle. The dtach
   client could exit independently of the hook command, causing Okena to
   think the hook had finished.

Fix: Add ShellType::OneShot variant that bypasses the session backend for
one-shot hook commands, and guard the sync watcher against projects in
closing/creating/removing state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add Cmd+Shift+0 / Ctrl+Shift+0 to zoom into the project containing the
active terminal (inverse of ClearFocus). When exiting project zoom, the
scroll now centers on the previously-focused project instead of leaving
it at the left edge.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@neumie neumie force-pushed the fix/worktree-hook-race branch from 3b8a6af to 19097a5 Compare March 27, 2026 16:10
Copy link
Copy Markdown
Member

@matej21 matej21 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice root cause analysis on both race conditions. The OneShot shell type is a clean solution for bypassing session backend decoupling. A few things to address:

  1. ShellType::OneShot appears to be missing from to_command_string() in shell_config.rs — this will likely cause a compile error or exhaustiveness panic. Please add the match arm.
  2. The OneShot construction uses -ic flag with $SHELL / /bin/sh fallback. -i is unnecessary for a non-interactive hook command and non-standard with /bin/sh. Consider using just -c.
  3. On Windows, $SHELL is unset and /bin/sh doesn't exist. The existing ShellType::for_command handles this with cmd /COneShot needs similar platform branching.

… centering

- Remove ShellType::OneShot variant — all hook terminals now go through
  the session backend like regular terminals
- Make FocusActiveProject a toggle: pressing again clears focus
- Defer center-scroll to next layout pass so scroll handle has correct
  max_offset after unfocusing
- Merge new default keybindings into existing saved config on load

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@neumie neumie changed the title fix: prevent worktree removal while before_worktree_remove hook runs fix: worktree hook race + FocusActiveProject keybinding Mar 27, 2026
Copy link
Copy Markdown
Contributor Author

@neumie neumie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review! All three points are moot now — we reverted ShellType::OneShot entirely in d4160f3. Hook terminals now use ShellType::for_command() which already handles all platforms correctly. The actual race condition fix (guarding closing_projects/creating_projects in the sync watcher) stands on its own without needing to bypass the session backend.

@neumie neumie merged commit b815de2 into main Mar 27, 2026
8 checks passed
@neumie neumie deleted the fix/worktree-hook-race branch March 27, 2026 16:36
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