-
-
Save azu/cef84c98aeef832d43dfb640c7e321f5 to your computer and use it in GitHub Desktop.
| #!/bin/bash | |
| # ============================================================================= | |
| # difit-auto-detect.sh | |
| # Automatically detects git state and opens appropriate diff view | |
| # with difit in a cmux browser split pane. | |
| # | |
| # Dependencies: | |
| # - cmux https://cmux.app/ | |
| # - difit https://github.com/yoshiko-pg/difit | |
| # | |
| # Setup: | |
| # 1. Install cmux | |
| # Download from https://cmux.app/ and move to /Applications/ | |
| # 1.1 Change "Socakge Control Mode" to "Automation Mode" | |
| # | |
| # 2. Install difit | |
| # npm install -g difit | |
| # | |
| # 3. Make this script executable and place it somewhere on your PATH | |
| # chmod +x difit-auto-detect.sh | |
| # mv difit-auto-detect.sh /usr/local/bin/difit-cmux | |
| # | |
| # 4. (Optional) Bind to a global shortcut via your preferred launcher | |
| # e.g. Alfred, Karabiner Elements, Raycast, etc. | |
| # | |
| # Usage: | |
| # Run this script while cmux is focused on a git repository pane. | |
| # The script will: | |
| # - Detect the current branch and default branch | |
| # - Show diff against merge-base (for feature branches) | |
| # - Show diff against HEAD (for default branch or detached HEAD) | |
| # - Open the result in a cmux browser split at http://localhost:4966/ | |
| # - Automatically shut down the difit server when the browser pane is closed | |
| # ============================================================================= | |
| CMUX="/Applications/cmux.app/Contents/Resources/bin/cmux" | |
| # Get the working directory of the currently focused cmux pane | |
| targetDir=$("$CMUX" sidebar-state | awk -F= '/^focused_cwd=/{print $2}') | |
| if [[ -z "$targetDir" ]]; then | |
| echo "Error: Could not detect focused_cwd from cmux sidebar-state" >&2 | |
| exit 1 | |
| fi | |
| cd "$targetDir" || exit 1 | |
| # Provide immediate feedback so the user knows the script is running | |
| "$CMUX" notify --title "Difit" --body "Loading diff: $targetDir" | |
| echo "π Detecting git state..." | |
| currentBranch=$(git rev-parse --abbrev-ref HEAD) | |
| # Detect default branch (origin/HEAD β origin/main β origin/master) | |
| defaultBranch=$(git symbolic-ref refs/remotes/origin/HEAD --short 2>/dev/null) | |
| if [[ -z "$defaultBranch" ]]; then | |
| if git rev-parse --verify origin/main >/dev/null 2>&1; then | |
| defaultBranch="origin/main" | |
| elif git rev-parse --verify origin/master >/dev/null 2>&1; then | |
| defaultBranch="origin/master" | |
| fi | |
| fi | |
| # Kill any process using port 4966 | |
| kill_difit() { | |
| lsof -ti:4966 | xargs kill 2>/dev/null | |
| } | |
| trap kill_difit EXIT INT TERM | |
| difitArgs=(--mode unified --no-open --clean --include-untracked --port 4966) | |
| echo "π Starting difit server..." | |
| if [[ -z "$defaultBranch" ]] || [[ "$currentBranch" == "${defaultBranch#origin/}" ]]; then | |
| # On the default branch or no remote β diff working directory against HEAD | |
| difit working "${difitArgs[@]}" & | |
| else | |
| mergeBase=$(git merge-base HEAD "$defaultBranch" 2>/dev/null) | |
| if [[ -z "$mergeBase" ]]; then | |
| # Fallback if merge-base cannot be determined | |
| difit working "${difitArgs[@]}" & | |
| else | |
| echo "π Branch: $currentBranch (base: ${defaultBranch#origin/})" | |
| difit "$mergeBase" . "${difitArgs[@]}" & | |
| fi | |
| fi | |
| # Wait until the difit server is ready | |
| while ! curl -s http://localhost:4966/ > /dev/null 2>&1; do | |
| sleep 0.5 | |
| done | |
| # Open in a cmux browser split and get the surface ID | |
| browserSurface=$("$CMUX" --json browser open-split "http://localhost:4966/" | grep -o '"ref" *: *"surface:[^"]*"' | head -1 | grep -o 'surface:[0-9]*') | |
| if [[ -z "$browserSurface" ]]; then | |
| echo "Warning: Could not get browser surface ID, difit server running in background" >&2 | |
| wait | |
| exit 0 | |
| fi | |
| # Wait until the browser pane is closed, then shut down the server | |
| while "$CMUX" surface-health 2>&1 | grep -q "$browserSurface"; do | |
| sleep 1 | |
| done | |
| kill_difit |
Ah, it was just a typo.
Since it looks at the currently focused tmux window, I think any shortcut key assignment would work.
Thank you for your reply.
I've completed up to step 3 of the setup, but I'm stuck on step 4. For example, when I try to call difit-cmux via Raycast, I get the error "Error: Could not detect focused_cwd from cmux sidebar-state".
The same thing happens when I run difit-cmux in a non-cmux environment, such as Ghostty. It only works as expected when difit-cmux is executed within cmux.
I watched your demo video where you called it from Alfred, and I'm wondering if there's some specific trick to it. Could you please share any insights if you have them?
This script is just being read from Alfred, but cmux may need to be configured to accept input from external processes.
You need to change the Access modes.
https://www.cmux.dev/docs/api
Oh! So there was such a setting. I completely overlooked it.
Thank you very much for the screenshots too. I truly appreciate it.
Thank you. What do "cmux shortcuts" refer to? Is there a way to bind custom commands to shortcuts in cmux?
I've read the cmux documentation, but I couldn't find it.