-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup.sh
More file actions
executable file
·191 lines (170 loc) · 6.67 KB
/
setup.sh
File metadata and controls
executable file
·191 lines (170 loc) · 6.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/usr/bin/env bash
set -euo pipefail
# Open Elements Claude Base — Setup Script
# Copies claude-project-base into the current project's .claude/ directory
# and merges CLAUDE.md using Claude Code.
#
# Usage (run from your project root):
# curl -sSL https://raw.githubusercontent.com/OpenElementsLabs/claude-base/main/setup.sh | bash
REPO_URL="https://github.com/OpenElementsLabs/claude-base.git"
TMPDIR_BASE="${TMPDIR:-/tmp}"
WORK_DIR="$TMPDIR_BASE/claude-base-setup-$$"
cleanup() {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
# Resolve the latest semver tag (e.g. v2.1.1) from the remote
echo "==> Finding latest release tag..."
LATEST_TAG="$(git ls-remote --tags --sort=-v:refname "$REPO_URL" 'v*' \
| head -n 1 \
| sed 's|.*refs/tags/||')"
if [ -z "$LATEST_TAG" ]; then
echo " WARNING: No version tags found — falling back to main branch"
LATEST_TAG="main"
else
echo " Using tag: $LATEST_TAG"
fi
echo "==> Cloning claude-base ($LATEST_TAG) into temporary directory..."
git clone --depth 1 --branch "$LATEST_TAG" "$REPO_URL" "$WORK_DIR" 2>/dev/null
SRC="$WORK_DIR/claude-project-base"
# --- Sync conventions and hooks into .claude/ ---
# Base items are overwritten to stay up to date.
# Exception: conventions/project-specific/ is never overwritten (project-owned content).
echo "==> Syncing conventions and hooks into .claude/..."
for dir in conventions hooks; do
src_dir="$SRC/$dir"
dest_dir=".claude/$dir"
[ -d "$src_dir" ] || continue
mkdir -p "$dest_dir"
for item in "$src_dir"/*; do
name="$(basename "$item")"
dest="$dest_dir/$name"
# Never overwrite project-specific conventions
if [ "$dir" = "conventions" ] && [ "$name" = "project-specific" ]; then
if [ -e "$dest" ]; then
echo " KEPT: .claude/$dir/$name (project-specific, not overwritten)"
else
cp -R "$item" "$dest"
echo " Copied $dir/$name"
fi
continue
fi
if [ -e "$dest" ]; then
rm -rf "$dest"
echo " Updated $dir/$name"
else
echo " Copied $dir/$name"
fi
cp -R "$item" "$dest"
done
done
# --- Sync skills into .claude/skills/ (flatten categories) ---
# Source layout: claude-project-base/skills/<category>/<skill-name>/SKILL.md
# Target layout: .claude/skills/<skill-name>/SKILL.md
# The categories (information/, tools/, workflows/, coding/, other/) are
# kept in the source repo for navigation but flattened in the target so
# Claude Code's skill discovery (which expects flat skills) works unchanged.
# Convention paths inside SKILL.md files reference `../../../conventions/`
# in the source (skill is three levels deep). After flattening they live
# two levels deep, so we rewrite them to `../../conventions/` on copy.
echo "==> Syncing skills into .claude/skills/ (flattening categories)..."
src_skills="$SRC/skills"
dest_skills=".claude/skills"
if [ -d "$src_skills" ]; then
mkdir -p "$dest_skills"
for category_dir in "$src_skills"/*/; do
[ -d "$category_dir" ] || continue
for skill_dir in "$category_dir"*/; do
[ -d "$skill_dir" ] || continue
skill_name="$(basename "$skill_dir")"
dest="$dest_skills/$skill_name"
if [ -e "$dest" ]; then
rm -rf "$dest"
echo " Updated skills/$skill_name"
else
echo " Copied skills/$skill_name"
fi
cp -R "$skill_dir" "$dest"
# Adjust convention paths: ../../../conventions/ -> ../../conventions/
find "$dest" -name 'SKILL.md' -type f -print0 | while IFS= read -r -d '' f; do
if grep -q '\.\./\.\./\.\./conventions/' "$f"; then
perl -i -pe 's|\.\./\.\./\.\./conventions/|\.\./\.\./conventions/|g' "$f"
fi
done
done
done
fi
# --- Copy settings.local.json into .claude/ ---
if [ -f "$SRC/settings.local.json" ]; then
if [ -f .claude/settings.local.json ]; then
echo " .claude/settings.local.json already exists — skipping (will not overwrite)"
else
cp "$SRC/settings.local.json" .claude/
echo " Copied settings.local.json into .claude/"
fi
fi
# --- Copy automated-spec-implementation-prompt.md into .claude/ ---
if [ -f "$SRC/automated-spec-implementation-prompt.md" ]; then
cp "$SRC/automated-spec-implementation-prompt.md" .claude/
echo " Copied automated-spec-implementation-prompt.md into .claude/"
fi
# --- Copy .mcp.json into .claude/ ---
if [ -f "$SRC/.mcp.json" ]; then
if [ -f .claude/.mcp.json ]; then
echo " .claude/.mcp.json already exists — skipping (will not overwrite)"
else
cp "$SRC/.mcp.json" .claude/.mcp.json
echo " Copied .mcp.json into .claude/"
fi
fi
# --- Append gitignore additions ---
if [ -f "$SRC/PROJECT_GITIGNORE_ADDITITIONS" ]; then
echo "==> Updating .gitignore..."
touch .gitignore
while IFS= read -r line || [ -n "$line" ]; do
if [ -n "$line" ] && ! grep -qxF "$line" .gitignore; then
echo "$line" >> .gitignore
echo " Added '$line' to .gitignore"
fi
done < "$SRC/PROJECT_GITIGNORE_ADDITITIONS"
fi
# --- Merge CLAUDE.md using Claude Code ---
if [ -f "$SRC/PROJECT_CLAUDE.md" ]; then
echo "==> Merging CLAUDE.md..."
if [ -f CLAUDE.md ]; then
# Project already has a CLAUDE.md — use Claude to merge
echo " Existing CLAUDE.md found — merging with base (this may take a moment)..."
cp "$SRC/PROJECT_CLAUDE.md" .claude/_base_claude.md
MERGED="$(claude --print --model sonnet -p "$(cat <<'PROMPT'
Read the files .claude/_base_claude.md and CLAUDE.md.
Merge them into a single Markdown document. Rules:
- Base content (.claude/_base_claude.md) comes first, then project-specific content.
- Do not duplicate rules that appear in both files.
- Keep all project-specific rules, paths, and configurations from CLAUDE.md.
- Keep all base rules from _base_claude.md.
- If rules conflict, the project-specific version wins.
- Output ONLY the merged Markdown content, no explanations or code fences.
PROMPT
)")"
if [ -n "$MERGED" ]; then
echo "$MERGED" > CLAUDE.md
echo " Merged CLAUDE.md (base + project-specific)"
else
echo " WARNING: Claude returned empty result — keeping existing CLAUDE.md unchanged"
echo " You can merge manually: base is at .claude/_base_claude.md"
fi
rm -f .claude/_base_claude.md
else
# No existing CLAUDE.md — just copy the base
cp "$SRC/PROJECT_CLAUDE.md" CLAUDE.md
echo " Created CLAUDE.md from base template"
fi
fi
echo ""
echo "==> Done! Claude base configuration has been applied."
echo ""
echo "Next steps:"
echo " 1. Review CLAUDE.md and remove convention references not needed for your project"
echo " 2. Fill in API keys in .claude/settings.local.json"
echo " 3. Review .mcp.json and remove MCP servers you don't need"
echo " 4. Run 'claude' to start using the configuration"