Improve workmux dev workflow scripts and docs (#8078)

- Add CARGO_FEATURES passthrough: backend pane reads from .env.local,
  wm-cursor supports --features flag on add/open commands
- Fix node_modules copy in worktrees: use cp -a to preserve .bin/
  symlinks that cp -r would dereference (fixes openapi-ts errors)
- Fix EE repo discovery from worktrees: resolve main repo root via
  git-common-dir, search multiple candidate paths
- Add cursor session cleanup to worktree-cleanup (pre_remove hook)
- Use workmux -b flag in wmc add, remove npm install from frontend pane
- Change openBrowserOnce for Cursor port forwarding
- Document cargo features usage and fix stale files.symlink reference
  in README

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hugocasa
2026-02-24 17:34:00 +01:00
committed by GitHub
parent 71acd88f2a
commit c0d136658f
4 changed files with 114 additions and 22 deletions
+2 -2
View File
@@ -57,9 +57,9 @@ panes:
When restarting backend or frontend, make sure to use the ports listed in .env.local.\n
Because we are running backend with cargo watch, to verify your changes, just check the logs in the backend pane. No need for cargo check."
focus: true
- command: 'ROOT="$(git rev-parse --show-toplevel)"; [ -f "$ROOT/.env.local" ] && source "$ROOT/.env.local"; cd "$ROOT/backend" && PORT=${BACKEND_PORT:-8000} cargo watch -x run'
- command: 'ROOT="$(git rev-parse --show-toplevel)"; [ -f "$ROOT/.env.local" ] && source "$ROOT/.env.local"; cd "$ROOT/backend" && PORT=${BACKEND_PORT:-8000} cargo watch -x "run ${CARGO_FEATURES:+--features $CARGO_FEATURES}"'
split: horizontal
- command: 'ROOT="$(git rev-parse --show-toplevel)"; [ -f "$ROOT/.env.local" ] && source "$ROOT/.env.local"; cd "$ROOT/frontend" && npm install && npm run generate-backend-client && REMOTE=${REMOTE:-http://localhost:${BACKEND_PORT:-8000}} npm run dev -- --port ${FRONTEND_PORT:-3000} --host 0.0.0.0'
- command: 'ROOT="$(git rev-parse --show-toplevel)"; [ -f "$ROOT/.env.local" ] && source "$ROOT/.env.local"; cd "$ROOT/frontend" && npm run generate-backend-client && REMOTE=${REMOTE:-http://localhost:${BACKEND_PORT:-8000}} npm run dev -- --port ${FRONTEND_PORT:-3000} --host 0.0.0.0'
split: vertical
files:
+30 -1
View File
@@ -170,7 +170,8 @@ The setup is defined in `.workmux.yaml` at the repo root. Key sections:
- **`post_create`**: Runs `scripts/worktree-env` to generate `.env.local` with port assignments
- **`panes`**: Defines the tmux layout (agent, backend, frontend)
- **`files.copy`**: Copies `backend/.env` and `scripts/` into each worktree
- **`files.symlink`**: Symlinks `node_modules` and `.svelte-kit` to avoid reinstalling per worktree
The `post_create` hook also copies `frontend/node_modules` using `cp -a` (preserves `.bin/` symlinks that `cp -r` would dereference).
## Enterprise (EE) Code Access
@@ -247,6 +248,34 @@ wmc close my-feature
This kills the grouped tmux session and calls `workmux close` to close the tmux window. The worktree and branch are preserved. Grouped sessions are also automatically cleaned up when you `workmux rm` a worktree (via `scripts/worktree-cleanup`).
## Cargo Features
To build the backend with specific Cargo features (e.g., `enterprise`, `parquet`), pass them via `CARGO_FEATURES`. The backend pane reads this from `.env.local` and appends `--features <value>` to the `cargo watch` command.
**With `wm` (workmux):**
Set `CARGO_FEATURES` as an environment variable before creating the worktree:
```bash
CARGO_FEATURES="enterprise,parquet" wm add my-feature
```
This gets written to `.env.local` by the `post_create` hook (`scripts/worktree-env`), and the backend pane picks it up automatically.
**With `wmc` (wm-cursor):**
Use the `--features` flag:
```bash
# Create a new worktree with features
wmc add --features "enterprise,parquet" -A -p "implement feature X"
# Open an existing worktree with different features
wmc open my-feature --features "enterprise,parquet"
```
The `--features` flag exports `CARGO_FEATURES` so the `post_create` hook writes it to `.env.local`. When using `wmc open`, it updates the existing `.env.local` with the new features.
## Login
Default credentials: `admin@windmill.dev` / `changeme`
+56 -11
View File
@@ -81,7 +81,7 @@ setup_grouped_session() {
},
"remote.portsAttributes": {
"'$backend_port'": { "label": "Backend", "onAutoForward": "silent" },
"'$frontend_port'": { "label": "Frontend", "onAutoForward": "openBrowser" }
"'$frontend_port'": { "label": "Frontend", "onAutoForward": "openBrowserOnce" }
}'
fi
fi
@@ -102,18 +102,47 @@ SETTINGS
fi
}
# --- Feature flag parsing ---
# Extracts --features <value> from args, exports CARGO_FEATURES, returns remaining args.
# Usage: parse_features_flag "$@"; set -- "${remaining_args[@]}"
parse_features_flag() {
remaining_args=()
while (( $# )); do
case $1 in
--features)
if (( $# < 2 )); then
print -u2 "Error: --features requires a value"
exit 1
fi
export CARGO_FEATURES=$2
shift 2
;;
--features=*)
export CARGO_FEATURES=${1#--features=}
shift
;;
*)
remaining_args+=("$1")
shift
;;
esac
done
}
# --- Subcommands ---
cmd_add() {
ensure_tmux
check_dev_db
parse_features_flag "$@"
set -- "${remaining_args[@]}"
# Snapshot worktree list before
local -a before=("${(@f)$(git worktree list --porcelain | grep '^worktree ')}")
local prev_window=$(tmux display-message -p '#I')
workmux add "$@"
tmux select-window -t $prev_window
workmux add -b "$@"
# Diff to find the new entry
local -a after=("${(@f)$(git worktree list --porcelain | grep '^worktree ')}")
@@ -140,11 +169,24 @@ cmd_open() {
ensure_tmux
check_dev_db
parse_features_flag "$@"
set -- "${remaining_args[@]}"
# Write CARGO_FEATURES to .env.local if specified
if [[ -n ${CARGO_FEATURES-} ]]; then
local wt_env=$(workmux path $name)/.env.local
if [[ -f $wt_env ]]; then
# Remove existing CARGO_FEATURES line and append new one
sed -i '/^CARGO_FEATURES=/d' $wt_env
echo "CARGO_FEATURES=$CARGO_FEATURES" >> $wt_env
fi
fi
local wt_path=$(workmux path $name)
local prev_window=$(tmux display-message -p '#I')
local prev_target=$(tmux display-message -p '#{session_name}:#{window_index}')
workmux open $name "$@"
tmux select-window -t $prev_window
tmux select-window -t $prev_target
setup_grouped_session $name $wt_path
$cursor_bin -n $wt_path
print "Opened Cursor for ${name}"
@@ -210,7 +252,7 @@ TASKS
},
"remote.portsAttributes": {
"8000": { "label": "Backend", "onAutoForward": "silent" },
"3000": { "label": "Frontend", "onAutoForward": "openBrowser" },
"3000": { "label": "Frontend", "onAutoForward": "openBrowserOnce" },
"5432": { "label": "PostgreSQL", "onAutoForward": "silent" }
}
}'
@@ -257,10 +299,13 @@ case ${1-} in
print -u2 "Usage: wm-cursor <add|open|close|setup> [args...]"
print -u2 ""
print -u2 "Subcommands:"
print -u2 " add [workmux-add-args...] Create worktree + open Cursor"
print -u2 " open <name> Open Cursor for existing worktree"
print -u2 " close <name> Clean up grouped tmux session"
print -u2 " setup <repo-root> Set up .vscode settings, tasks + wmc alias"
print -u2 " add [--features <f>] [workmux-add-args...] Create worktree + open Cursor"
print -u2 " open <name> [--features <f>] Open Cursor for existing worktree"
print -u2 " close <name> Clean up grouped tmux session"
print -u2 " setup <repo-root> Set up .vscode settings, tasks + wmc alias"
print -u2 ""
print -u2 "Options:"
print -u2 " --features <features> Cargo features for the backend (e.g. \"enterprise,parquet\")"
exit 1
;;
esac
+26 -8
View File
@@ -46,8 +46,20 @@ FRONTEND_PORT=$frontend_port
REMOTE=http://localhost:$backend_port
EOF
if [[ -n "${CARGO_FEATURES:-}" ]]; then
echo "CARGO_FEATURES=$CARGO_FEATURES" >> .env.local
fi
echo "Created .env.local with ports: backend=$backend_port, frontend=$frontend_port"
# --- Copy frontend/node_modules preserving symlinks ---
# cp -a preserves .bin/ symlinks that cp -r would dereference, breaking require() paths
main_repo_root="$(cd "$(git rev-parse --git-common-dir 2>/dev/null)/.." && pwd)"
if [[ -n "$main_repo_root" && -d "$main_repo_root/frontend/node_modules" ]]; then
cp -a "$main_repo_root/frontend/node_modules" frontend/
echo "Copied frontend/node_modules (with symlinks preserved)"
fi
# --- Allow direnv so the nix devshell activates in pane commands ---
if command -v direnv &>/dev/null && [ -f .envrc ]; then
direnv allow
@@ -55,14 +67,20 @@ if command -v direnv &>/dev/null && [ -f .envrc ]; then
fi
# --- Create matching windmill-ee-private worktree ---
# Check parent directory first (sibling to worktree root), then fall back to home
parent_dir="$(cd "$(pwd)/.." && pwd)"
if [ -d "${parent_dir}/windmill-ee-private" ]; then
ee_repo="${parent_dir}/windmill-ee-private"
else
ee_repo="${HOME}/windmill-ee-private"
fi
if [ -d "$ee_repo" ]; then
# Find ee repo: sibling to the main worktree (git toplevel of the main checkout),
# then try parent of cwd, then fall back to home
ee_repo=""
for candidate in \
"${main_repo_root:+${main_repo_root}/../windmill-ee-private}" \
"$(pwd)/../windmill-ee-private" \
"${HOME}/windmill-ee-private" \
"${HOME}/projects/windmill-ee-private"; do
if [ -n "$candidate" ] && [ -d "$candidate" ]; then
ee_repo="$(cd "$candidate" && pwd)"
break
fi
done
if [ -n "$ee_repo" ]; then
branch=$(git branch --show-current 2>/dev/null || true)
wt_basename=$(basename "$(pwd)")
ee_worktree_dir="${ee_repo}__worktrees/${wt_basename}"