From 2828616a796f1d4fde9bc0fce9468d6e91ad2eac Mon Sep 17 00:00:00 2001 From: centdix <40307056+centdix@users.noreply.github.com> Date: Mon, 9 Mar 2026 13:58:58 +0100 Subject: [PATCH] chore: webmux config#8279 --- .webmux.yaml | 139 ++++++------------- scripts/post-create.sh | 25 ++++ scripts/pre-remove.sh | 7 + scripts/worktree-cleanup | 73 +--------- scripts/worktree-common.sh | 265 +++++++++++++++++++++++++++++++++++++ scripts/worktree-env | 154 +-------------------- 6 files changed, 343 insertions(+), 320 deletions(-) create mode 100755 scripts/post-create.sh create mode 100755 scripts/pre-remove.sh create mode 100755 scripts/worktree-common.sh diff --git a/.webmux.yaml b/.webmux.yaml index 1a949c94e2..397f96f88f 100644 --- a/.webmux.yaml +++ b/.webmux.yaml @@ -1,113 +1,52 @@ -name: Windmill +# Project display name in the dashboard +name: windmill + +workspace: + mainBranch: main + worktreeRoot: ../__worktrees + defaultAgent: claude startupEnvs: CARGO_FEATURES: "quickjs" WM_CLONE_DB: false USE_RUST_PLUGIN: false +lifecycleHooks: + postCreate: bash ./scripts/post-create.sh + preRemove: bash ./scripts/pre-remove.sh + +# Each service defines a port env var that webmux injects into pane and agent +# process environments when creating a worktree. Ports are auto-assigned: +# base + (slot x step). services: - - name: BE + - name: backend portEnv: BACKEND_PORT - - name: FE + portStart: 8000 + portStep: 10 + - name: frontend portEnv: FRONTEND_PORT + portStart: 3000 + portStep: 10 profiles: default: - name: default + runtime: host + envPassthrough: [] + panes: + - id: agent + kind: agent + focus: true + - id: backend + kind: command + split: right + 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}" + - id: frontend + kind: command + split: bottom + 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 - sandbox: - name: sandbox - image: windmill-sandbox - envPassthrough: - - AWS_ACCESS_KEY_ID - - AWS_SECRET_ACCESS_KEY - - R2_ENDPOINT - - R2_BUCKET - - R2_PUBLIC_URL - extraMounts: - - hostPath: ~/.ssh - guestPath: /root/.ssh - writable: true - - hostPath: ~/.codex - guestPath: /root/.codex - writable: true - - hostPath: ~/windmill-ee-private - writable: true - - hostPath: ~/windmill-ee-private__worktrees - writable: true - systemPrompt: > - You are running inside a sandboxed container with full permissions. - This worktree is configured with the following ports: - - - Backend: port ${BACKEND_PORT}. - Start with: cd backend && PORT=${BACKEND_PORT} - DATABASE_URL=postgres://postgres:changeme@localhost:5432/windmill - cargo watch -x run - - - Frontend: port ${FRONTEND_PORT}. - Start with: cd frontend && REMOTE=http://localhost:${BACKEND_PORT} - npm run dev -- --port ${FRONTEND_PORT} --host 0.0.0.0 - - --- Screenshots --- - You can take screenshots of the frontend UI and upload them to R2 - for use in PR descriptions. - 1) Take a screenshot: - bunx playwright screenshot --browser chromium - http://localhost:${FRONTEND_PORT}/path/to/page /tmp/screenshot.png - 2) Upload to R2: - aws s3 cp /tmp/screenshot.png - "s3://$(printenv R2_BUCKET)/$(git rev-parse --abbrev-ref HEAD)/screenshot.png" - --endpoint-url "$(printenv R2_ENDPOINT)" - 3) The public URL will be: - $(printenv R2_PUBLIC_URL)//screenshot.png - 4) Include in PR descriptions using markdown image syntax. - - --- Terminal Recordings (asciinema) --- - You can record terminal sessions and upload them for sharing. - asciinema is available on PATH. - - 1) Write a shell script with the commands to demo. Add sleep - delays for readable pacing: - - 0.5s after printing a "$ command" line (lets viewer read it) - - 1.5-2s after command output (lets viewer absorb the result) - - Set GIT_PAGER=cat and PAGER=cat to prevent pager hangs - - 2) Record headlessly: - asciinema rec --headless --overwrite \ - -c "bash /tmp/demo.sh" \ - --window-size 120x50 \ - --title "Description of demo" \ - /tmp/demo.cast - - 3) Upload to asciinema.org: - XDG_DATA_HOME=/tmp/.local/share \ - asciinema upload --server-url https://asciinema.org /tmp/demo.cast - - --- Mermaid Diagrams --- - You can render Mermaid diagrams to SVG using the pre-installed mmdc CLI. - The puppeteer config (no-sandbox + Chromium path) is at /root/.puppeteerrc.json. - - 1) Write a .mmd file with your diagram: - cat > /tmp/diagram.mmd << 'EOF' - graph TD - A[Start] --> B[End] - EOF - - 2) Render to SVG (the -p flag is required): - mmdc -i /tmp/diagram.mmd -o /tmp/diagram.svg -p /root/.puppeteerrc.json - - 3) Upload to R2: - aws s3 cp /tmp/diagram.svg - "s3://$(printenv R2_BUCKET)/$(git rev-parse --abbrev-ref HEAD)/diagram.svg" - --endpoint-url "$(printenv R2_ENDPOINT)" - - 4) The public URL will be: - $(printenv R2_PUBLIC_URL)//diagram.svg - - 5) Include in PR descriptions using markdown image syntax. - - IMPORTANT: Read docs/autonomous-mode.md before starting any work. - -linkedRepos: - - repo: windmill-labs/windmill-ee-private - alias: ee +integrations: + github: + linkedRepos: [] + linear: + enabled: true diff --git a/scripts/post-create.sh b/scripts/post-create.sh new file mode 100755 index 0000000000..431e944d74 --- /dev/null +++ b/scripts/post-create.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail + +source "$(dirname "${BASH_SOURCE[0]}")/worktree-common.sh" + +backend_port="${BACKEND_PORT:-}" +frontend_port="${FRONTEND_PORT:-}" + +if [[ -z "$backend_port" || -z "$frontend_port" ]]; then + echo "Missing BACKEND_PORT or FRONTEND_PORT in hook environment" >&2 + exit 1 +fi + +cat > .env.local <> .env.local +fi + +echo "Created .env.local with ports: backend=$backend_port, frontend=$frontend_port" +wm_shared_post_create "$(pwd)" diff --git a/scripts/pre-remove.sh b/scripts/pre-remove.sh new file mode 100755 index 0000000000..a4bac4431e --- /dev/null +++ b/scripts/pre-remove.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail + +source "$(dirname "${BASH_SOURCE[0]}")/worktree-common.sh" + +wm_kill_processes_from_env_file "$(pwd)/.env.local" +wm_shared_pre_remove "$(pwd)" diff --git a/scripts/worktree-cleanup b/scripts/worktree-cleanup index c9a2769a58..f876011235 100755 --- a/scripts/worktree-cleanup +++ b/scripts/worktree-cleanup @@ -1,73 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -# Use WM_WORKTREE_PATH (set by workmux) so this works regardless of cwd +source "$(dirname "${BASH_SOURCE[0]}")/worktree-common.sh" + wt_dir="${WM_WORKTREE_PATH:-.}" -echo "[cleanup] cwd=$(pwd) WM_WORKTREE_PATH=${WM_WORKTREE_PATH:-} wt_dir=$wt_dir" - -# Kill backend/frontend processes using this worktree's ports -if [ -f "$wt_dir/.env.local" ]; then - source "$wt_dir/.env.local" - echo "[cleanup] .env.local found: BACKEND_PORT=${BACKEND_PORT:-} FRONTEND_PORT=${FRONTEND_PORT:-}" - for port in "${BACKEND_PORT:-}" "${FRONTEND_PORT:-}"; do - [ -z "$port" ] && continue - pid=$(lsof -ti "TCP:${port}" -sTCP:LISTEN 2>/dev/null || true) - if [ -n "$pid" ]; then - kill "$pid" 2>/dev/null && echo "[cleanup] Killed process $pid on port $port" \ - || echo "[cleanup] Warning: Could not kill process $pid on port $port" - else - echo "[cleanup] No process listening on port $port" - fi - done -else - echo "[cleanup] No .env.local at $wt_dir/.env.local" -fi - -# Drop per-worktree database -if [ -n "${WM_DB_NAME:-}" ]; then - db_conn="postgres://postgres:changeme@127.0.0.1:5432" - if command -v psql &>/dev/null; then - psql "$db_conn/postgres" -c "DROP DATABASE IF EXISTS ${WM_DB_NAME} WITH (FORCE)" 2>/dev/null \ - && echo "[cleanup] Dropped database $WM_DB_NAME" \ - || echo "[cleanup] Warning: Could not drop database $WM_DB_NAME" - else - echo "[cleanup] psql not found, skipping database cleanup for $WM_DB_NAME" - fi -else - echo "[cleanup] No WM_DB_NAME in .env.local, skipping database cleanup" -fi - -# Remove the matching windmill-ee-private worktree if one exists -wt_basename=$(basename "$wt_dir") - -# Find ee repo using same discovery logic as worktree-env -main_repo_root="$(cd "$(git -C "$wt_dir" rev-parse --git-common-dir 2>/dev/null)/.." && pwd)" -parent_dir="$(cd "$wt_dir/.." && pwd)" -echo "[cleanup] wt_basename=$wt_basename main_repo_root=$main_repo_root parent_dir=$parent_dir" - -ee_repo="" -for candidate in \ - "${main_repo_root:+${main_repo_root}/../windmill-ee-private}" \ - "${parent_dir}/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 [ -z "$ee_repo" ]; then - echo "[cleanup] Could not find windmill-ee-private repo, skipping EE worktree cleanup" -fi - -ee_worktree_dir="${ee_repo:+${ee_repo}__worktrees/${wt_basename}}" -echo "[cleanup] ee_repo=${ee_repo:-} ee_worktree_dir=${ee_worktree_dir:-} exists=$([ -n "$ee_worktree_dir" ] && [ -d "$ee_worktree_dir" ] && echo yes || echo no)" -if [ -n "$ee_worktree_dir" ] && [ -d "$ee_worktree_dir" ]; then - git -C "$ee_repo" worktree remove "$ee_worktree_dir" --force 2>/dev/null \ - && echo "[cleanup] Removed EE worktree at $ee_worktree_dir" \ - || echo "[cleanup] Warning: Could not remove EE worktree at $ee_worktree_dir" -fi - -# Clean up Cursor grouped tmux session -tmux kill-session -t "cursor-${wt_basename}" 2>/dev/null || true +wm_kill_processes_from_env_file "${wt_dir}/.env.local" +wm_shared_pre_remove "$wt_dir" diff --git a/scripts/worktree-common.sh b/scripts/worktree-common.sh new file mode 100755 index 0000000000..0112d271fa --- /dev/null +++ b/scripts/worktree-common.sh @@ -0,0 +1,265 @@ +#!/usr/bin/env bash +set -euo pipefail + +wm_is_true() { + case "${1:-}" in + 1|true|TRUE|yes|YES|on|ON) return 0 ;; + *) return 1 ;; + esac +} + +wm_main_repo_root() { + local repo_root=${1:-.} + cd "$(git -C "$repo_root" rev-parse --git-common-dir 2>/dev/null)/.." && pwd +} + +wm_setup_database() { + local repo_root=$1 + local env_file=$2 + local wt_basename db_name db_conn db_url license_key + + wt_basename="$(basename "$repo_root")" + db_name="windmill_${wt_basename//-/_}" + db_conn="postgres://postgres:changeme@127.0.0.1:5432" + + if ! command -v psql >/dev/null 2>&1; then + echo "WARNING: psql not found, skipping per-worktree database creation" >&2 + return + fi + + if psql "$db_conn/postgres" -tc "SELECT 1 FROM pg_database WHERE datname = '${db_name}'" 2>/dev/null | grep -q 1; then + echo "Database $db_name already exists" + else + if wm_is_true "${WM_CLONE_DB:-}"; then + psql "$db_conn/postgres" -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'windmill' AND pid <> pg_backend_pid();" 2>/dev/null || true + psql "$db_conn/postgres" -c "CREATE DATABASE ${db_name} TEMPLATE windmill" 2>/dev/null \ + && echo "Created database $db_name (template: windmill)" \ + || echo "WARNING: Could not create database $db_name from template windmill" >&2 + else + psql "$db_conn/postgres" -c "CREATE DATABASE ${db_name}" 2>/dev/null \ + && echo "Created database $db_name" \ + || echo "WARNING: Could not create database $db_name (is PostgreSQL running?)" >&2 + fi + fi + + db_url="${db_conn}/${db_name}?sslmode=disable" + DATABASE_URL="$db_url" sqlx migrate run --source "${repo_root}/backend/migrations" \ + && echo "Migrations applied to $db_name" \ + || echo "WARNING: Could not run migrations on $db_name" >&2 + + license_key="$(psql "$db_conn/windmill" -t -A -c "SELECT value FROM global_settings WHERE name = 'license_key'" 2>/dev/null || true)" + if [[ -n "$license_key" ]]; then + psql "$db_url" -c "INSERT INTO global_settings (name, value) VALUES ('license_key', '${license_key}'::jsonb) ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value" 2>/dev/null \ + && echo "Copied license_key to $db_name" \ + || echo "WARNING: Could not copy license_key to $db_name" >&2 + fi + + cat >> "$env_file" <&2 + fi +} + +wm_allow_direnv() { + local repo_root=$1 + if command -v direnv >/dev/null 2>&1 && [[ -f "${repo_root}/.envrc" ]]; then + (cd "$repo_root" && direnv allow) + echo "direnv allowed" + fi +} + +wm_trust_claude() { + local repo_root=$1 + local claude_json="${HOME}/.claude.json" + + if [[ ! -f "$claude_json" ]] || ! command -v python3 >/dev/null 2>&1; then + return + fi + + REPO_ROOT="$repo_root" CLAUDE_JSON="$claude_json" python3 - <<'PY' \ + && echo "Added $repo_root to Claude Code trusted directories" \ + || echo "Warning: Could not update Claude Code trusted directories" +import json +import os + +path = os.environ["REPO_ROOT"] +claude_json = os.environ["CLAUDE_JSON"] +with open(claude_json, "r") as f: + data = json.load(f) +projects = data.setdefault("projects", {}) +proj = projects.setdefault(path, {}) +proj["hasTrustDialogAccepted"] = True +proj["hasCompletedProjectOnboarding"] = True +with open(claude_json, "w") as f: + json.dump(data, f, indent=2) +PY +} + +wm_find_ee_repo() { + local repo_root=$1 + local main_repo_root=$2 + local candidate + + for candidate in \ + "${main_repo_root}/../windmill-ee-private" \ + "${repo_root}/../windmill-ee-private" \ + "${HOME}/windmill-ee-private" \ + "${HOME}/projects/windmill-ee-private"; do + if [[ -d "$candidate" ]]; then + cd "$candidate" && pwd + return 0 + fi + done + + return 1 +} + +wm_setup_ee_worktree() { + local repo_root=$1 + local main_repo_root=$2 + local ee_repo branch wt_basename ee_worktree_dir ee_rel rust_plugin + + if ! ee_repo="$(wm_find_ee_repo "$repo_root" "$main_repo_root")"; then + return + fi + + branch="$(git -C "$repo_root" branch --show-current 2>/dev/null || true)" + wt_basename="$(basename "$repo_root")" + ee_worktree_dir="${ee_repo}__worktrees/${wt_basename}" + + if [[ -n "$branch" && ! -d "$ee_worktree_dir" ]]; then + mkdir -p "$(dirname "$ee_worktree_dir")" + git -C "$ee_repo" fetch --quiet 2>/dev/null || true + + if git -C "$ee_repo" worktree add "$ee_worktree_dir" "$branch" 2>/dev/null; then + echo "Created EE worktree at $ee_worktree_dir (branch: $branch)" + elif git -C "$ee_repo" worktree add -b "$branch" "$ee_worktree_dir" main 2>/dev/null; then + echo "Created EE worktree at $ee_worktree_dir (new branch: $branch from main)" + else + echo "Warning: Could not create EE worktree for branch $branch" + fi + elif [[ -d "$ee_worktree_dir" ]]; then + echo "EE worktree already exists at $ee_worktree_dir" + fi + + if [[ ! -d "$ee_worktree_dir" ]]; then + return + fi + + ee_rel="$(REPO_ROOT="$repo_root" EE_WORKTREE_DIR="$ee_worktree_dir" python3 - <<'PY' 2>/dev/null || echo "$ee_worktree_dir" +import os +print(os.path.relpath(os.environ["EE_WORKTREE_DIR"], os.environ["REPO_ROOT"])) +PY +)" + mkdir -p "${repo_root}/.claude" + rust_plugin="" + if wm_is_true "${USE_RUST_PLUGIN:-}"; then + rust_plugin=', + "enabledPlugins": { + "rust-analyzer-lsp@claude-plugins-official": true + }' + fi + cat > "${repo_root}/.claude/settings.local.json" </dev/null || true)" + if [[ -n "$pid" ]]; then + kill "$pid" 2>/dev/null && echo "Killed process $pid on port $port" \ + || echo "Warning: Could not kill process $pid on port $port" + fi + done +} + +wm_shared_pre_remove() { + local repo_root=$1 + local env_file="${repo_root}/.env.local" + local db_conn wt_basename main_repo_root ee_repo ee_worktree_dir + + if [[ -f "$env_file" ]]; then + # shellcheck disable=SC1090 + source "$env_file" + fi + + if [[ -n "${WM_DB_NAME:-}" ]]; then + db_conn="postgres://postgres:changeme@127.0.0.1:5432" + if command -v psql >/dev/null 2>&1; then + psql "$db_conn/postgres" -c "DROP DATABASE IF EXISTS ${WM_DB_NAME} WITH (FORCE)" 2>/dev/null \ + && echo "Dropped database $WM_DB_NAME" \ + || echo "Warning: Could not drop database $WM_DB_NAME" + else + echo "psql not found, skipping database cleanup for $WM_DB_NAME" + fi + fi + + main_repo_root="$(wm_main_repo_root "$repo_root")" + wt_basename="$(basename "$repo_root")" + if ee_repo="$(wm_find_ee_repo "$repo_root" "$main_repo_root")"; then + ee_worktree_dir="${ee_repo}__worktrees/${wt_basename}" + if [[ -d "$ee_worktree_dir" ]]; then + git -C "$ee_repo" worktree remove "$ee_worktree_dir" --force 2>/dev/null \ + && echo "Removed EE worktree at $ee_worktree_dir" \ + || echo "Warning: Could not remove EE worktree at $ee_worktree_dir" + fi + fi + + tmux kill-session -t "cursor-${wt_basename}" 2>/dev/null || true +} diff --git a/scripts/worktree-env b/scripts/worktree-env index 5fd8490bc2..e45daba75b 100755 --- a/scripts/worktree-env +++ b/scripts/worktree-env @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -euo pipefail +source "$(dirname "${BASH_SOURCE[0]}")/worktree-common.sh" + port_in_use() { lsof -nP -iTCP:"$1" -sTCP:LISTEN &>/dev/null } @@ -51,154 +53,4 @@ if [[ -n "${CARGO_FEATURES:-}" ]]; then fi echo "Created .env.local with ports: backend=$backend_port, frontend=$frontend_port" - -# --- Create per-worktree database --- -wt_basename=$(basename "$(pwd)") -db_name="windmill_${wt_basename//-/_}" -db_conn="postgres://postgres:changeme@127.0.0.1:5432" - -if command -v psql &>/dev/null; then - if psql "$db_conn/postgres" -tc "SELECT 1 FROM pg_database WHERE datname = '${db_name}'" 2>/dev/null | grep -q 1; then - echo "Database $db_name already exists" - else - if [[ "${WM_CLONE_DB:-}" == "1" || "${WM_CLONE_DB:-}" == "true" ]]; then - # Terminate active connections so CREATE DATABASE ... TEMPLATE works - psql "$db_conn/postgres" -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'windmill' AND pid <> pg_backend_pid();" 2>/dev/null || true - psql "$db_conn/postgres" -c "CREATE DATABASE ${db_name} TEMPLATE windmill" 2>/dev/null \ - && echo "Created database $db_name (template: windmill)" \ - || echo "WARNING: Could not create database $db_name from template windmill" >&2 - else - psql "$db_conn/postgres" -c "CREATE DATABASE ${db_name}" 2>/dev/null \ - && echo "Created database $db_name" \ - || echo "WARNING: Could not create database $db_name (is PostgreSQL running?)" >&2 - fi - fi - db_url="${db_conn}/${db_name}?sslmode=disable" - # Run migrations against the new database - DATABASE_URL="$db_url" sqlx migrate run --source backend/migrations \ - && echo "Migrations applied to $db_name" \ - || echo "WARNING: Could not run migrations on $db_name" >&2 - # Copy license_key from the main windmill database to the new database - license_key=$(psql "$db_conn/windmill" -t -A -c "SELECT value FROM global_settings WHERE name = 'license_key'" 2>/dev/null || true) - if [[ -n "$license_key" ]]; then - psql "$db_url" -c "INSERT INTO global_settings (name, value) VALUES ('license_key', '${license_key}'::jsonb) ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value" 2>/dev/null \ - && echo "Copied license_key to $db_name" \ - || echo "WARNING: Could not copy license_key to $db_name" >&2 - fi - # Use export so DATABASE_URL overrides the nix devshell value for child processes - cat >> .env.local <&2 -fi - -# --- 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 - -# --- Install cli deps and generate client --- -if [[ -n "$main_repo_root" && -d "$main_repo_root/cli/node_modules" ]]; then - cp -a "$main_repo_root/cli/node_modules" cli/ - echo "Copied cli/node_modules (with symlinks preserved)" -fi -(cd cli && npm install && npm run gen-client) \ - && echo "CLI deps installed and client generated" \ - || echo "WARNING: CLI setup failed" >&2 - -# --- Allow direnv so the nix devshell activates in pane commands --- -if command -v direnv &>/dev/null && [ -f .envrc ]; then - direnv allow - echo "direnv allowed" -fi - -# --- Trust worktree directory in Claude Code --- -claude_json="$HOME/.claude.json" -if [ -f "$claude_json" ]; then - wt_path="$(pwd)" - python3 -c " -import json, sys -path = '$wt_path' -with open('$claude_json', 'r') as f: - data = json.load(f) -projects = data.setdefault('projects', {}) -proj = projects.setdefault(path, {}) -proj['hasTrustDialogAccepted'] = True -proj['hasCompletedProjectOnboarding'] = True -with open('$claude_json', 'w') as f: - json.dump(data, f, indent=2) -" && echo "Added $wt_path to Claude Code trusted directories" \ - || echo "Warning: Could not update Claude Code trusted directories" -fi - -# --- Create matching windmill-ee-private worktree --- -# 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}" - - if [ -n "$branch" ] && [ ! -d "$ee_worktree_dir" ]; then - mkdir -p "$(dirname "$ee_worktree_dir")" - - # Fetch latest so we can check out remote branches - git -C "$ee_repo" fetch --quiet 2>/dev/null || true - - # Try: existing branch, then new branch from main - if git -C "$ee_repo" worktree add "$ee_worktree_dir" "$branch" 2>/dev/null; then - echo "Created EE worktree at $ee_worktree_dir (branch: $branch)" - elif git -C "$ee_repo" worktree add -b "$branch" "$ee_worktree_dir" main 2>/dev/null; then - echo "Created EE worktree at $ee_worktree_dir (new branch: $branch from main)" - else - echo "Warning: Could not create EE worktree for branch $branch" - fi - elif [ -d "$ee_worktree_dir" ]; then - echo "EE worktree already exists at $ee_worktree_dir" - fi - - # Point Claude Code additionalDirectories at the EE worktree - if [ -d "$ee_worktree_dir" ]; then - ee_rel=$(python3 -c "import os; print(os.path.relpath('$ee_worktree_dir', '$(pwd)'))" 2>/dev/null || echo "$ee_worktree_dir") - mkdir -p .claude - rust_plugin="" - if [[ "${USE_RUST_PLUGIN:-}" == "1" || "${USE_RUST_PLUGIN:-}" == "true" ]]; then - rust_plugin=', - "enabledPlugins": { - "rust-analyzer-lsp@claude-plugins-official": true - }' - fi - cat > .claude/settings.local.json <