chore: webmux config#8279

This commit is contained in:
centdix
2026-03-09 13:58:58 +01:00
committed by GitHub
parent 73d27e92dd
commit 2828616a79
6 changed files with 343 additions and 320 deletions

View File

@@ -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)/<branch>/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)/<branch>/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

25
scripts/post-create.sh Executable file
View File

@@ -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 <<EOF
BACKEND_PORT=$backend_port
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"
wm_shared_post_create "$(pwd)"

7
scripts/pre-remove.sh Executable file
View File

@@ -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)"

View File

@@ -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:-<unset>} 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:-<unset>} FRONTEND_PORT=${FRONTEND_PORT:-<unset>}"
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:-<not found>} ee_worktree_dir=${ee_worktree_dir:-<none>} 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"

265
scripts/worktree-common.sh Executable file
View File

@@ -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" <<EOF
export DATABASE_URL=$db_url
WM_DB_NAME=$db_name
EOF
echo "Added DATABASE_URL for database $db_name to .env.local"
}
wm_copy_dependencies() {
local repo_root=$1
local main_repo_root=$2
if [[ -d "${main_repo_root}/frontend/node_modules" ]]; then
cp -a "${main_repo_root}/frontend/node_modules" "${repo_root}/frontend/"
echo "Copied frontend/node_modules (with symlinks preserved)"
fi
if [[ -d "${main_repo_root}/cli/node_modules" ]]; then
cp -a "${main_repo_root}/cli/node_modules" "${repo_root}/cli/"
echo "Copied cli/node_modules (with symlinks preserved)"
fi
if [[ -d "${repo_root}/cli" ]]; then
(cd "${repo_root}/cli" && npm install && npm run gen-client) \
&& echo "CLI deps installed and client generated" \
|| echo "WARNING: CLI setup failed" >&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" <<EOF
{
"permissions": {
"additionalDirectories": [
"$ee_rel"
]
}${rust_plugin}
}
EOF
echo "Created .claude/settings.local.json with EE path: $ee_rel"
if [[ -x "${repo_root}/backend/substitute_ee_code.sh" ]]; then
"${repo_root}/backend/substitute_ee_code.sh" -d "$ee_worktree_dir"
fi
}
wm_shared_post_create() {
local repo_root=$1
local main_repo_root
main_repo_root="$(wm_main_repo_root "$repo_root")"
wm_setup_database "$repo_root" "${repo_root}/.env.local"
wm_copy_dependencies "$repo_root" "$main_repo_root"
wm_allow_direnv "$repo_root"
wm_trust_claude "$repo_root"
wm_setup_ee_worktree "$repo_root" "$main_repo_root"
}
wm_kill_processes_from_env_file() {
local env_file=$1
local pid port
if [[ ! -f "$env_file" ]]; then
return
fi
# shellcheck disable=SC1090
source "$env_file"
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 "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
}

View File

@@ -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 <<EOF
export DATABASE_URL=$db_url
WM_DB_NAME=$db_name
EOF
echo "Added DATABASE_URL for database $db_name to .env.local"
else
echo "WARNING: psql not found, skipping per-worktree database creation" >&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 <<EOFCLAUDE
{
"permissions": {
"additionalDirectories": [
"$ee_rel"
]
}${rust_plugin}
}
EOFCLAUDE
echo "Created .claude/settings.local.json with EE path: $ee_rel"
# Create symlinks from backend crates to the EE worktree
if [ -x "./backend/substitute_ee_code.sh" ]; then
./backend/substitute_ee_code.sh -d "$ee_worktree_dir"
fi
fi
fi
wm_shared_post_create "$(pwd)"