Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .claude/hooks/setup-worktree.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
#
# SessionStart hook: prepare a fresh git worktree so it is ready to run.
#
# Runs `pnpm install` + `pnpm run build` the first time a Claude Code session
# opens inside a linked worktree that has no node_modules yet. It is a no-op in
# the primary checkout and in worktrees that are already set up, so it is safe
# to run on every session start.
#
# The .env files are copied separately by .worktreeinclude (repo root) at
# worktree-creation time; this hook only handles dependency install + build,
# which .worktreeinclude cannot do.
#
# Registered in .claude/settings.json under hooks.SessionStart.

# Anchor to the worktree this session is running in.
toplevel=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
common_dir=$(git rev-parse --git-common-dir 2>/dev/null) || exit 0

# The parent of the shared git common dir is the primary worktree. Normalize to
# an absolute path so the comparison works whether common_dir is "." (primary)
# or an absolute path (linked worktree).
main_worktree=$(cd "$(dirname "$common_dir")" 2>/dev/null && pwd) || exit 0

# Only act inside a linked worktree, never the primary checkout.
[ "$toplevel" = "$main_worktree" ] && exit 0

# Already set up — nothing to do (keeps this cheap on resume/clear/compact).
[ -d "$toplevel/node_modules" ] && exit 0

echo "setup-worktree: fresh worktree at $toplevel — running pnpm install + build…" >&2
cd "$toplevel" || exit 0

# Ensure pnpm is available (the repo manages it via corepack).
if ! command -v pnpm >/dev/null 2>&1; then
corepack enable pnpm >/dev/null 2>&1 || true
fi

# Best-effort: report failures on stderr but never block session startup. If a
# step fails, re-run `pnpm install && pnpm run build` manually in the worktree.
if ! pnpm install >&2; then
echo "setup-worktree: pnpm install failed — run it manually in $toplevel" >&2
exit 0
fi
if ! pnpm run build >&2; then
echo "setup-worktree: pnpm run build failed — run it manually in $toplevel" >&2
exit 0
fi

echo "setup-worktree: worktree ready." >&2
exit 0
16 changes: 16 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume",
"hooks": [
{
"type": "command",
"command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/setup-worktree.sh\"",
"timeout": 600
}
]
}
]
}
}
9 changes: 9 additions & 0 deletions .worktreeinclude
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Files copied into new Claude Code worktrees (--worktree / isolation: "worktree").
# Uses .gitignore glob syntax. Only files that match AND are gitignored are
# copied, so tracked templates like .env.dist / .env.tmpl are left untouched.
#
# Listed as explicit, anchored paths (mirroring .cursor/worktrees.json) rather
# than a bare `.env` glob, so exactly the dev env files are copied and nothing
# else is picked up at unexpected depths.
apps/dev-playground/.env
apps/clean-app/.env
Loading