#!/usr/bin/env bash # Set up gstack for local development — test skills from within this repo. # # Creates .claude/skills/gstack → (symlink to repo root) so Claude Code # discovers skills from your working tree. Changes take effect immediately. # # Also copies .env from the main worktree if this is a Conductor workspace # or git worktree (so API keys carry over automatically). # # Usage: bin/dev-setup # set up # bin/dev-teardown # clean up set -e REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" # 1. Copy .env from main worktree (if we're a worktree and don't have one) if [ ! -f "$REPO_ROOT/.env" ]; then MAIN_WORKTREE="$(git -C "$REPO_ROOT" worktree list --porcelain 2>/dev/null | head -1 | sed 's/^worktree //')" if [ -n "$MAIN_WORKTREE" ] && [ "$MAIN_WORKTREE" != "$REPO_ROOT" ] && [ -f "$MAIN_WORKTREE/.env" ]; then cp "$MAIN_WORKTREE/.env" "$REPO_ROOT/.env" echo "Copied .env from main worktree ($MAIN_WORKTREE)" fi fi # 2. Install dependencies if [ ! -d "$REPO_ROOT/node_modules" ]; then echo "Installing dependencies..." (cd "$REPO_ROOT" && bun install) fi # 3. Create .claude/skills/ inside the repo mkdir -p "$REPO_ROOT/.claude/skills" # 4. Symlink .claude/skills/gstack → repo root # This makes setup think it's inside a real .claude/skills/ directory GSTACK_LINK="$REPO_ROOT/.claude/skills/gstack" if [ -L "$GSTACK_LINK" ]; then echo "Updating existing symlink..." rm "$GSTACK_LINK" elif [ -d "$GSTACK_LINK" ]; then echo "Error: .claude/skills/gstack is a real directory, not a symlink." >&2 echo "Remove it manually if you want to use dev mode." >&2 exit 1 fi ln -s "$REPO_ROOT" "$GSTACK_LINK" # 5. Create .agents/skills/gstack → repo root (for Codex/Gemini/Cursor) mkdir -p "$REPO_ROOT/.agents/skills" AGENTS_LINK="$REPO_ROOT/.agents/skills/gstack" if [ -L "$AGENTS_LINK" ]; then rm "$AGENTS_LINK" elif [ -d "$AGENTS_LINK" ]; then echo "Warning: .agents/skills/gstack is a real directory, skipping." >&2 fi if [ ! -e "$AGENTS_LINK" ]; then ln -s "$REPO_ROOT" "$AGENTS_LINK" fi # 6. Run setup via the symlink so it detects .claude/skills/ as its parent. # # Workspace/dev setup MUST be non-interactive: Conductor runs this under a # forwarded pty, so any `read` in setup (skill-prefix prompt, plan-tune hook # consent) would hang the workspace forever. Detaching stdin makes every setup # prompt take its smart non-interactive default (flat skill names, etc.). # # `--plan-tune-hooks=prompt` is load-bearing, not redundant: stdin alone only # suppresses the *prompt* branch. A saved `plan_tune_hooks: yes` or an exported # GSTACK_PLAN_TUNE_HOOKS=yes would still resolve to "install" and rewrite the # user's global ~/.claude/settings.json to point at THIS ephemeral worktree — # which breaks once the workspace is deleted. The flag has highest precedence, # so it pins resolution to "prompt", and closed stdin then makes prompt-mode a # no-op skip (no install, no decline marker). A dev workspace must never mutate # global settings.json. To install the hooks, run `./setup --plan-tune-hooks` # directly (outside dev-setup). Saved prefix/other config preferences still apply. "$GSTACK_LINK/setup" --plan-tune-hooks=prompt