Last active
December 7, 2025 21:05
-
-
Save sourman/9ac986f36a23a709ab5da813670b5793 to your computer and use it in GitHub Desktop.
Cursor worktrees fast server spin up
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { defineConfig } from "vite"; | |
| import react from "@vitejs/plugin-react-swc"; | |
| import path from "path"; | |
| import { componentTagger } from "lovable-tagger"; | |
| // https://vitejs.dev/config/ | |
| export default defineConfig(({ mode }) => ({ | |
| server: { | |
| host: "::", | |
| port: 8080, | |
| }, | |
| plugins: [ | |
| react(), | |
| mode === 'development' && | |
| componentTagger(), | |
| // Inject worktree name into HTML title | |
| { | |
| name: 'inject-worktree-title', | |
| transformIndexHtml(html) { | |
| const worktree = process.env.VITE_WORKTREE; | |
| if (worktree) { | |
| return html.replace( | |
| /<title>(.*?)<\/title>/, | |
| `<title>[${worktree}] $1</title>` | |
| ); | |
| } | |
| return html; | |
| }, | |
| }, | |
| ].filter(Boolean), | |
| resolve: { | |
| alias: { | |
| "@": path.resolve(__dirname, "./src"), | |
| }, | |
| }, | |
| })); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # git worktrees spin up script meant for running in conjunction with cursor worktrees | |
| # cursor creates wokrtrees in wsl in ~/.cursor/worktrees/$project/[slug] for each worktree | |
| # The waled function spawns new vite servers in recently created worktrees and can take | |
| # an arg to spevify lookbak window in minutes. e.g. waled 5 will only look at folders | |
| # touched in the last 5 minutes | |
| # mawet cleans up all the pids spawned by waled | |
| # Function 1: Start dev servers for recently created worktree directories | |
| waled() { | |
| local lookback_minutes="${1:-10}" | |
| if ! [[ "$lookback_minutes" =~ ^[0-9]+$ ]]; then | |
| echo "Error: Lookback time must be a positive number (minutes)" | |
| echo "Usage: cdworktree [lookback_minutes]" | |
| return 1 | |
| fi | |
| repo="$(basename "$(pwd)")" | |
| export WORK_TREE_DIR=~/.cursor/worktrees/"${repo}__WSL__ubuntu_"/ | |
| if [ ! -d "$WORK_TREE_DIR" ]; then | |
| echo "Work tree directory not found: $WORK_TREE_DIR" | |
| return 1 | |
| fi | |
| echo "Looking for directories created in the last $lookback_minutes minutes..." | |
| # Find directories created in the last N minutes | |
| recent_dirs=$(find "$WORK_TREE_DIR" -maxdepth 1 -type d -mmin -"$lookback_minutes" ! -path "$WORK_TREE_DIR") | |
| if [ -z "$recent_dirs" ]; then | |
| echo "No recent directories found in $WORK_TREE_DIR (last $lookback_minutes minutes)" | |
| return 0 | |
| fi | |
| # Create PID tracking file | |
| pid_file="/tmp/worktree-pids-${repo}-$$.pid" | |
| map_file="${pid_file%.pid}.map" | |
| touch "$pid_file" | |
| touch "$map_file" | |
| # Spawn bash for each directory | |
| while IFS= read -r dir; do | |
| if [ -n "$dir" ]; then | |
| worktree_name="$(basename "$dir")" | |
| echo "Starting dev server for: $dir (worktree: $worktree_name)" | |
| # Store mapping | |
| echo "$worktree_name:$dir" >> "$map_file" | |
| ( | |
| cd "$dir" && npm i && VITE_WORKTREE="$worktree_name" npm run dev | |
| ) & | |
| pid=$! | |
| echo "$pid" >> "$pid_file" | |
| echo "$pid:$worktree_name" >> "${pid_file%.pid}.details" | |
| echo "Spawned PID $pid for $worktree_name" | |
| fi | |
| done <<< "$recent_dirs" | |
| echo "" | |
| echo "PIDs tracked in: $pid_file" | |
| echo "Worktree mapping in: $map_file" | |
| echo "" | |
| echo "Worktree -> Directory mapping:" | |
| cat "$map_file" | |
| } | |
| # Function 2: Kill all spawned worktree processes | |
| mawet() { | |
| # Find all PID files matching the pattern | |
| pid_files=$(find /tmp -maxdepth 1 -name "worktree-pids-*.pid" -type f 2>/dev/null) | |
| if [ -z "$pid_files" ]; then | |
| echo "No worktree PID files found" | |
| return 0 | |
| fi | |
| # Collect all PIDs and process groups from all files | |
| all_pids=() | |
| all_pgroups=() | |
| while IFS= read -r pid_file; do | |
| if [ -f "$pid_file" ]; then | |
| echo "Reading PIDs from: $pid_file" | |
| while IFS= read -r pid; do | |
| if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then | |
| all_pids+=("$pid") | |
| # Get process group ID | |
| pgid=$(ps -o pgid= -p "$pid" 2>/dev/null | tr -d ' ') | |
| if [ -n "$pgid" ]; then | |
| all_pgroups+=("$pgid") | |
| fi | |
| fi | |
| done < "$pid_file" | |
| # Also show the mapping before killing | |
| map_file="${pid_file%.pid}.map" | |
| if [ -f "$map_file" ]; then | |
| echo "Killing servers:" | |
| cat "$map_file" | while IFS=: read -r name dir; do | |
| echo " - $name" | |
| done | |
| fi | |
| fi | |
| done <<< "$pid_files" | |
| # Kill all process groups (which includes child processes like Vite) | |
| if [ ${#all_pgroups[@]} -eq 0 ]; then | |
| echo "No active process groups found" | |
| else | |
| # Remove duplicates | |
| unique_pgroups=($(printf "%s\n" "${all_pgroups[@]}" | sort -u)) | |
| echo "Killing ${#unique_pgroups[@]} process groups: ${unique_pgroups[*]}" | |
| for pgid in "${unique_pgroups[@]}"; do | |
| # Kill the entire process group | |
| if kill -- "-$pgid" 2>/dev/null; then | |
| echo "Killed process group $pgid" | |
| else | |
| echo "Failed to kill process group $pgid, trying individual PIDs" | |
| fi | |
| done | |
| sleep 2 | |
| # Fallback: kill any remaining individual PIDs | |
| for pid in "${all_pids[@]}"; do | |
| if kill -0 "$pid" 2>/dev/null; then | |
| echo "Force killing remaining PID $pid" | |
| kill -9 "$pid" 2>/dev/null | |
| fi | |
| done | |
| fi | |
| # Clean up PID files | |
| echo "Cleaning up PID files..." | |
| rm -f /tmp/worktree-pids-*.pid | |
| rm -f /tmp/worktree-pids-*.map | |
| rm -f /tmp/worktree-pids-*.details | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The first file defines two functions.
waled()bash function andmawet()waledwill intelligently go into each new worktree created by cursor and it startsnpm run devin each of them so that you can preview the changes made by each agentmawetwhich will find and kill all the spawnednpm run devinstancesDo not forget to update the vite config (or whatever env) so that it auto injects the folder slug into the browser window so it is easy to understand which browser window was created by which agent
https://www.loom.com/share/d0ab6755251b4848b500ab1e3f8a734a