cc-discipline 2.10.1 → 2.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +236 -153
- package/README.zh-CN.md +299 -207
- package/bin/cli.sh +96 -96
- package/global/CLAUDE.md +45 -45
- package/init.sh +594 -594
- package/lib/doctor.sh +145 -145
- package/lib/stack-remove.sh +68 -68
- package/lib/status.sh +100 -100
- package/package.json +34 -34
- package/templates/.claude/agents/investigator.md +44 -44
- package/templates/.claude/agents/reviewer.md +46 -46
- package/templates/.claude/hooks/action-counter.sh +58 -58
- package/templates/.claude/hooks/git-guard.sh +62 -62
- package/templates/.claude/hooks/phase-gate.sh +10 -10
- package/templates/.claude/hooks/post-error-remind.sh +114 -114
- package/templates/.claude/hooks/pre-edit-guard.sh +100 -100
- package/templates/.claude/hooks/session-start.sh +44 -44
- package/templates/.claude/hooks/streak-breaker.sh +111 -111
- package/templates/.claude/rules/00-core-principles.md +16 -16
- package/templates/.claude/rules/01-debugging.md +32 -32
- package/templates/.claude/rules/02-before-edit.md +22 -22
- package/templates/.claude/rules/03-context-mgmt.md +44 -44
- package/templates/.claude/rules/04-no-mole-whacking.md +26 -26
- package/templates/.claude/rules/05-phase-discipline.md +15 -15
- package/templates/.claude/rules/06-multi-task.md +12 -12
- package/templates/.claude/rules/07-integrity.md +92 -92
- package/templates/.claude/rules/stacks/embedded.md +24 -24
- package/templates/.claude/rules/stacks/js-ts.md +21 -21
- package/templates/.claude/rules/stacks/mobile.md +16 -16
- package/templates/.claude/rules/stacks/python.md +20 -20
- package/templates/.claude/rules/stacks/rtl.md +24 -24
- package/templates/.claude/settings.json +84 -84
- package/templates/.claude/skills/commit/SKILL.md +40 -40
- package/templates/.claude/skills/evaluate/SKILL.md +57 -57
- package/templates/.claude/skills/investigate/SKILL.md +192 -192
- package/templates/.claude/skills/retro/SKILL.md +40 -40
- package/templates/.claude/skills/self-check/SKILL.md +112 -87
- package/templates/.claude/skills/summary/SKILL.md +48 -48
- package/templates/.claude/skills/think/SKILL.md +108 -108
- package/templates/CLAUDE.md +96 -96
- package/templates/docs/debug-log.md +48 -48
- package/templates/docs/progress.md +72 -72
- package/templates/memory/MEMORY.md +23 -23
package/init.sh
CHANGED
|
@@ -1,594 +1,594 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# cc-discipline init script
|
|
3
|
-
# Usage: cd your-project && bash /path/to/init.sh
|
|
4
|
-
# cd your-project && bash /path/to/init.sh --auto # non-interactive, defaults
|
|
5
|
-
# cd your-project && bash /path/to/init.sh --stack "3 4" --name myapp --global
|
|
6
|
-
# Or: curl -sL https://raw.githubusercontent.com/YOU/cc-discipline/main/init.sh | bash
|
|
7
|
-
|
|
8
|
-
# On Windows (Git Bash), set -e causes silent failures due to path/command differences.
|
|
9
|
-
# Use explicit error checking for critical operations instead.
|
|
10
|
-
if [[ "$(uname -s)" != MINGW* ]] && [[ "$(uname -s)" != MSYS* ]]; then
|
|
11
|
-
set -e
|
|
12
|
-
fi
|
|
13
|
-
|
|
14
|
-
# ─── Version ───
|
|
15
|
-
# cli.js sets CC_DISCIPLINE_VERSION on Windows where node paths are tricky
|
|
16
|
-
VERSION="${CC_DISCIPLINE_VERSION:-unknown}"
|
|
17
|
-
if [ "$VERSION" = "unknown" ]; then
|
|
18
|
-
_INIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
19
|
-
if command -v node &>/dev/null && [ -f "$_INIT_DIR/package.json" ]; then
|
|
20
|
-
VERSION=$(node -p "require('$_INIT_DIR/package.json').version" 2>/dev/null) || true
|
|
21
|
-
fi
|
|
22
|
-
fi
|
|
23
|
-
VERSION="${VERSION:-unknown}"
|
|
24
|
-
|
|
25
|
-
# ─── Parse CLI arguments ───
|
|
26
|
-
ARG_STACK=""
|
|
27
|
-
ARG_NAME=""
|
|
28
|
-
ARG_GLOBAL=""
|
|
29
|
-
ARG_AUTO=false
|
|
30
|
-
|
|
31
|
-
while [[ $# -gt 0 ]]; do
|
|
32
|
-
case $1 in
|
|
33
|
-
--auto)
|
|
34
|
-
ARG_AUTO=true
|
|
35
|
-
shift
|
|
36
|
-
;;
|
|
37
|
-
--stack)
|
|
38
|
-
ARG_STACK="$2"
|
|
39
|
-
shift 2
|
|
40
|
-
;;
|
|
41
|
-
--name)
|
|
42
|
-
ARG_NAME="$2"
|
|
43
|
-
shift 2
|
|
44
|
-
;;
|
|
45
|
-
--global)
|
|
46
|
-
ARG_GLOBAL="y"
|
|
47
|
-
shift
|
|
48
|
-
;;
|
|
49
|
-
--no-global)
|
|
50
|
-
ARG_GLOBAL="n"
|
|
51
|
-
shift
|
|
52
|
-
;;
|
|
53
|
-
-h|--help)
|
|
54
|
-
echo "Usage: bash init.sh [options]"
|
|
55
|
-
echo ""
|
|
56
|
-
echo "Options:"
|
|
57
|
-
echo " --auto Non-interactive with defaults (stack=7, name=dirname, no global)"
|
|
58
|
-
echo " --stack <choices> Stack selection: 1-7, space-separated (e.g., --stack \"3 4\")"
|
|
59
|
-
echo " --name <name> Project name (default: directory name)"
|
|
60
|
-
echo " --global Install global rules to ~/.claude/CLAUDE.md"
|
|
61
|
-
echo " --no-global Skip global rules install"
|
|
62
|
-
echo " -h, --help Show this help"
|
|
63
|
-
echo ""
|
|
64
|
-
echo "Stacks: 1=RTL 2=Embedded 3=Python 4=JS/TS 5=Mobile 6=Fullstack 7=General"
|
|
65
|
-
exit 0
|
|
66
|
-
;;
|
|
67
|
-
*)
|
|
68
|
-
echo "Unknown option: $1 (use --help for usage)"
|
|
69
|
-
exit 1
|
|
70
|
-
;;
|
|
71
|
-
esac
|
|
72
|
-
done
|
|
73
|
-
|
|
74
|
-
# --auto sets defaults for anything not explicitly provided
|
|
75
|
-
if [ "$ARG_AUTO" = true ]; then
|
|
76
|
-
[ -z "$ARG_STACK" ] && ARG_STACK="7"
|
|
77
|
-
[ -z "$ARG_GLOBAL" ] && ARG_GLOBAL="n"
|
|
78
|
-
fi
|
|
79
|
-
|
|
80
|
-
# ─── Colors ───
|
|
81
|
-
RED='\033[0;31m'
|
|
82
|
-
GREEN='\033[0;32m'
|
|
83
|
-
YELLOW='\033[1;33m'
|
|
84
|
-
BLUE='\033[0;34m'
|
|
85
|
-
CYAN='\033[0;36m'
|
|
86
|
-
NC='\033[0m'
|
|
87
|
-
|
|
88
|
-
# Support both direct execution and npm (via CC_DISCIPLINE_PKG_DIR)
|
|
89
|
-
if [ -n "$CC_DISCIPLINE_PKG_DIR" ]; then
|
|
90
|
-
SCRIPT_DIR="$CC_DISCIPLINE_PKG_DIR"
|
|
91
|
-
else
|
|
92
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
93
|
-
fi
|
|
94
|
-
PROJECT_DIR="$(pwd)"
|
|
95
|
-
|
|
96
|
-
echo -e "${CYAN}╔══════════════════════════════════════════════╗${NC}"
|
|
97
|
-
echo -e "${CYAN}║ Claude Code Discipline Framework — Setup ║${NC}"
|
|
98
|
-
echo -e "${CYAN}╚══════════════════════════════════════════════╝${NC}"
|
|
99
|
-
echo ""
|
|
100
|
-
echo -e "Project directory: ${GREEN}${PROJECT_DIR}${NC}"
|
|
101
|
-
|
|
102
|
-
# ─── Detect install mode ───
|
|
103
|
-
INSTALL_MODE="fresh"
|
|
104
|
-
INSTALLED_VERSION=""
|
|
105
|
-
|
|
106
|
-
if [ -f ".claude/.cc-discipline-version" ]; then
|
|
107
|
-
INSTALL_MODE="upgrade"
|
|
108
|
-
INSTALLED_VERSION=$(cat ".claude/.cc-discipline-version")
|
|
109
|
-
elif [ -f ".claude/hooks/streak-breaker.sh" ] || [ -f ".claude/hooks/pre-edit-guard.sh" ] || [ -f ".claude/hooks/session-start.sh" ] || [ -f ".claude/hooks/phase-gate.sh" ]; then
|
|
110
|
-
INSTALL_MODE="upgrade"
|
|
111
|
-
INSTALLED_VERSION="<2.0.0"
|
|
112
|
-
elif [ -d ".claude" ] || [ -f "CLAUDE.md" ]; then
|
|
113
|
-
INSTALL_MODE="append"
|
|
114
|
-
fi
|
|
115
|
-
|
|
116
|
-
case "$INSTALL_MODE" in
|
|
117
|
-
fresh)
|
|
118
|
-
echo -e "Mode: ${GREEN}Fresh install${NC}"
|
|
119
|
-
;;
|
|
120
|
-
upgrade)
|
|
121
|
-
echo -e "Mode: ${YELLOW}Upgrade cc-discipline (${INSTALLED_VERSION} → ${VERSION})${NC}"
|
|
122
|
-
;;
|
|
123
|
-
append)
|
|
124
|
-
echo -e "Mode: ${YELLOW}Adding discipline to existing project${NC}"
|
|
125
|
-
echo -e "${YELLOW}Your existing files will be preserved. cc-discipline files will be added alongside them.${NC}"
|
|
126
|
-
;;
|
|
127
|
-
esac
|
|
128
|
-
echo ""
|
|
129
|
-
|
|
130
|
-
# ─── Backup (upgrade/append) ───
|
|
131
|
-
BACKUP_DIR=""
|
|
132
|
-
if [ "$INSTALL_MODE" != "fresh" ]; then
|
|
133
|
-
BACKUP_DIR=".claude/.backup-$(date +%Y%m%d-%H%M%S)"
|
|
134
|
-
mkdir -p "$BACKUP_DIR"
|
|
135
|
-
[ -f "CLAUDE.md" ] && cp "CLAUDE.md" "$BACKUP_DIR/"
|
|
136
|
-
[ -f ".claude/settings.json" ] && cp ".claude/settings.json" "$BACKUP_DIR/"
|
|
137
|
-
[ -d ".claude/hooks" ] && cp -r ".claude/hooks" "$BACKUP_DIR/"
|
|
138
|
-
[ -d ".claude/rules" ] && cp -r ".claude/rules" "$BACKUP_DIR/"
|
|
139
|
-
[ -d ".claude/agents" ] && cp -r ".claude/agents" "$BACKUP_DIR/"
|
|
140
|
-
[ -d ".claude/skills" ] && cp -r ".claude/skills" "$BACKUP_DIR/"
|
|
141
|
-
echo -e "${GREEN}Backup saved to ${BACKUP_DIR}/${NC}"
|
|
142
|
-
echo ""
|
|
143
|
-
fi
|
|
144
|
-
|
|
145
|
-
# ─── Detect installed stacks (for upgrade/append) ───
|
|
146
|
-
detect_installed_stacks() {
|
|
147
|
-
INSTALLED_STACKS=""
|
|
148
|
-
[ -f ".claude/rules/stacks/rtl.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}1 "
|
|
149
|
-
[ -f ".claude/rules/stacks/embedded.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}2 "
|
|
150
|
-
[ -f ".claude/rules/stacks/python.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}3 "
|
|
151
|
-
[ -f ".claude/rules/stacks/js-ts.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}4 "
|
|
152
|
-
[ -f ".claude/rules/stacks/mobile.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}5 "
|
|
153
|
-
return 0
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
# ─── Select project type ───
|
|
157
|
-
if [ -n "$ARG_STACK" ]; then
|
|
158
|
-
STACK_CHOICES="$ARG_STACK"
|
|
159
|
-
echo -e "Stack: ${GREEN}${STACK_CHOICES}${NC} (from CLI)"
|
|
160
|
-
elif [ "$INSTALL_MODE" = "fresh" ]; then
|
|
161
|
-
echo -e "${BLUE}What is your project type? (select multiple with spaces)${NC}"
|
|
162
|
-
echo " 1) RTL / IC Design (Verilog, VHDL, SystemVerilog)"
|
|
163
|
-
echo " 2) Embedded (C/C++, bare-metal, RTOS)"
|
|
164
|
-
echo " 3) Python (backend / scripting / ML)"
|
|
165
|
-
echo " 4) JavaScript / TypeScript (Node, Web)"
|
|
166
|
-
echo " 5) Mobile (Swift, Kotlin, React Native, Flutter)"
|
|
167
|
-
echo " 6) Full-stack Web (frontend + backend)"
|
|
168
|
-
echo " 7) Other / General"
|
|
169
|
-
echo ""
|
|
170
|
-
read -p "Choose (e.g.: 1 2 or 3 4 6): " STACK_CHOICES
|
|
171
|
-
else
|
|
172
|
-
detect_installed_stacks
|
|
173
|
-
echo -e "${BLUE}Stack rules (* = already installed):${NC}"
|
|
174
|
-
for i in 1 2 3 4 5; do
|
|
175
|
-
MARKER=""
|
|
176
|
-
echo "$INSTALLED_STACKS" | grep -q "$i" && MARKER=" ${GREEN}*${NC}"
|
|
177
|
-
case $i in
|
|
178
|
-
1) echo -e " 1) RTL / IC Design${MARKER}" ;;
|
|
179
|
-
2) echo -e " 2) Embedded${MARKER}" ;;
|
|
180
|
-
3) echo -e " 3) Python${MARKER}" ;;
|
|
181
|
-
4) echo -e " 4) JavaScript / TypeScript${MARKER}" ;;
|
|
182
|
-
5) echo -e " 5) Mobile${MARKER}" ;;
|
|
183
|
-
esac
|
|
184
|
-
done
|
|
185
|
-
echo " 6) Full-stack Web (JS/TS + Python)"
|
|
186
|
-
echo " 7) Other / General"
|
|
187
|
-
echo ""
|
|
188
|
-
read -p "Add stacks (e.g.: 2 4), or press Enter to keep current: " STACK_CHOICES
|
|
189
|
-
fi
|
|
190
|
-
|
|
191
|
-
# Parse choices into array
|
|
192
|
-
IFS=' ' read -ra STACKS <<< "$STACK_CHOICES"
|
|
193
|
-
|
|
194
|
-
# ─── Project name ───
|
|
195
|
-
if [ -n "$ARG_NAME" ]; then
|
|
196
|
-
PROJECT_NAME="$ARG_NAME"
|
|
197
|
-
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (from CLI)"
|
|
198
|
-
elif [ "$INSTALL_MODE" = "fresh" ]; then
|
|
199
|
-
DEFAULT_NAME=$(basename "$PROJECT_DIR")
|
|
200
|
-
if [ "$ARG_AUTO" = true ]; then
|
|
201
|
-
PROJECT_NAME="$DEFAULT_NAME"
|
|
202
|
-
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (auto)"
|
|
203
|
-
else
|
|
204
|
-
read -p "Project name [$DEFAULT_NAME]: " PROJECT_NAME
|
|
205
|
-
PROJECT_NAME=${PROJECT_NAME:-$DEFAULT_NAME}
|
|
206
|
-
fi
|
|
207
|
-
else
|
|
208
|
-
# Try to extract from existing CLAUDE.md: "# MyProject — CLAUDE.md"
|
|
209
|
-
PROJECT_NAME=""
|
|
210
|
-
if [ -f "CLAUDE.md" ]; then
|
|
211
|
-
PROJECT_NAME=$(head -1 CLAUDE.md | sed 's/^# //;s/ — CLAUDE.md$//' 2>/dev/null)
|
|
212
|
-
fi
|
|
213
|
-
if [ -z "$PROJECT_NAME" ] || [ "$PROJECT_NAME" = "[PROJECT_NAME]" ]; then
|
|
214
|
-
DEFAULT_NAME=$(basename "$PROJECT_DIR")
|
|
215
|
-
if [ "$ARG_AUTO" = true ]; then
|
|
216
|
-
PROJECT_NAME="$DEFAULT_NAME"
|
|
217
|
-
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (auto)"
|
|
218
|
-
else
|
|
219
|
-
read -p "Project name [$DEFAULT_NAME]: " PROJECT_NAME
|
|
220
|
-
PROJECT_NAME=${PROJECT_NAME:-$DEFAULT_NAME}
|
|
221
|
-
fi
|
|
222
|
-
else
|
|
223
|
-
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (from CLAUDE.md)"
|
|
224
|
-
fi
|
|
225
|
-
fi
|
|
226
|
-
|
|
227
|
-
# ─── Create directory structure ───
|
|
228
|
-
echo ""
|
|
229
|
-
echo -e "${GREEN}Creating directory structure...${NC}"
|
|
230
|
-
mkdir -p .claude/rules/stacks
|
|
231
|
-
mkdir -p .claude/hooks
|
|
232
|
-
mkdir -p .claude/agents
|
|
233
|
-
mkdir -p .claude/skills
|
|
234
|
-
mkdir -p docs
|
|
235
|
-
|
|
236
|
-
# ─── Copy core rules (always applied, always overwrite — these are framework files) ───
|
|
237
|
-
echo -e "${GREEN}Installing core rules...${NC}"
|
|
238
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/00-core-principles.md" .claude/rules/
|
|
239
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/01-debugging.md" .claude/rules/
|
|
240
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/02-before-edit.md" .claude/rules/
|
|
241
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/03-context-mgmt.md" .claude/rules/
|
|
242
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/04-no-mole-whacking.md" .claude/rules/
|
|
243
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/05-phase-discipline.md" .claude/rules/
|
|
244
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/06-multi-task.md" .claude/rules/
|
|
245
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/07-integrity.md" .claude/rules/
|
|
246
|
-
|
|
247
|
-
# ─── Copy stack-specific rules based on selection ───
|
|
248
|
-
if [ ${#STACKS[@]} -gt 0 ] && [ -n "${STACKS[0]}" ]; then
|
|
249
|
-
echo -e "${GREEN}Installing stack rules...${NC}"
|
|
250
|
-
for choice in "${STACKS[@]}"; do
|
|
251
|
-
case $choice in
|
|
252
|
-
1)
|
|
253
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/rtl.md" .claude/rules/stacks/
|
|
254
|
-
echo " ✓ RTL / IC Design rules"
|
|
255
|
-
;;
|
|
256
|
-
2)
|
|
257
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/embedded.md" .claude/rules/stacks/
|
|
258
|
-
echo " ✓ Embedded development rules"
|
|
259
|
-
;;
|
|
260
|
-
3)
|
|
261
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/python.md" .claude/rules/stacks/
|
|
262
|
-
echo " ✓ Python rules"
|
|
263
|
-
;;
|
|
264
|
-
4)
|
|
265
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/js-ts.md" .claude/rules/stacks/
|
|
266
|
-
echo " ✓ JavaScript / TypeScript rules"
|
|
267
|
-
;;
|
|
268
|
-
5)
|
|
269
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/mobile.md" .claude/rules/stacks/
|
|
270
|
-
echo " ✓ Mobile development rules"
|
|
271
|
-
;;
|
|
272
|
-
6)
|
|
273
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/js-ts.md" .claude/rules/stacks/
|
|
274
|
-
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/python.md" .claude/rules/stacks/
|
|
275
|
-
echo " ✓ Full-stack rules (JS/TS + Python)"
|
|
276
|
-
;;
|
|
277
|
-
7)
|
|
278
|
-
echo " ✓ General rules (no additional stack rules)"
|
|
279
|
-
;;
|
|
280
|
-
esac
|
|
281
|
-
done
|
|
282
|
-
fi
|
|
283
|
-
|
|
284
|
-
# ─── Install hooks ───
|
|
285
|
-
echo -e "${GREEN}Installing hooks...${NC}"
|
|
286
|
-
cp "$SCRIPT_DIR/templates/.claude/hooks/pre-edit-guard.sh" .claude/hooks/
|
|
287
|
-
cp "$SCRIPT_DIR/templates/.claude/hooks/post-error-remind.sh" .claude/hooks/
|
|
288
|
-
cp "$SCRIPT_DIR/templates/.claude/hooks/streak-breaker.sh" .claude/hooks/
|
|
289
|
-
cp "$SCRIPT_DIR/templates/.claude/hooks/session-start.sh" .claude/hooks/
|
|
290
|
-
cp "$SCRIPT_DIR/templates/.claude/hooks/phase-gate.sh" .claude/hooks/
|
|
291
|
-
cp "$SCRIPT_DIR/templates/.claude/hooks/git-guard.sh" .claude/hooks/
|
|
292
|
-
cp "$SCRIPT_DIR/templates/.claude/hooks/action-counter.sh" .claude/hooks/
|
|
293
|
-
chmod +x .claude/hooks/*.sh
|
|
294
|
-
|
|
295
|
-
# ─── Check jq availability ───
|
|
296
|
-
HAS_JQ=false
|
|
297
|
-
if command -v jq &>/dev/null; then
|
|
298
|
-
HAS_JQ=true
|
|
299
|
-
else
|
|
300
|
-
echo ""
|
|
301
|
-
echo -e "${YELLOW}Warning: jq not found — Hooks will use grep/sed fallback, but jq is recommended${NC}"
|
|
302
|
-
echo " macOS: brew install jq"
|
|
303
|
-
echo " Ubuntu: sudo apt install jq"
|
|
304
|
-
echo " Arch: sudo pacman -S jq"
|
|
305
|
-
echo ""
|
|
306
|
-
fi
|
|
307
|
-
|
|
308
|
-
# ─── Install/merge settings.json ───
|
|
309
|
-
SETTINGS_TEMPLATE="$SCRIPT_DIR/templates/.claude/settings.json"
|
|
310
|
-
|
|
311
|
-
if [ ! -f ".claude/settings.json" ]; then
|
|
312
|
-
# No existing settings.json — just copy template
|
|
313
|
-
cp "$SETTINGS_TEMPLATE" .claude/settings.json
|
|
314
|
-
echo -e "${GREEN} ✓ settings.json created${NC}"
|
|
315
|
-
elif [ "$INSTALL_MODE" = "fresh" ]; then
|
|
316
|
-
# Fresh mode shouldn't reach here, but just in case
|
|
317
|
-
cp "$SETTINGS_TEMPLATE" .claude/settings.json
|
|
318
|
-
else
|
|
319
|
-
# Merge: preserve user hooks, add/update cc-discipline hooks
|
|
320
|
-
if [ "$HAS_JQ" = true ]; then
|
|
321
|
-
TEMP_SETTINGS=$(mktemp)
|
|
322
|
-
MERGE_OK=false
|
|
323
|
-
|
|
324
|
-
if jq -s '
|
|
325
|
-
.[0] as $e | .[1] as $t |
|
|
326
|
-
def is_cc: .hooks | any(.command | test("pre-edit-guard|streak-breaker|post-error-remind|session-start|phase-gate|action-counter"));
|
|
327
|
-
def merge($ev): (($e.hooks[$ev] // []) | map(select(is_cc | not))) + ($t.hooks[$ev] // []);
|
|
328
|
-
$e * {
|
|
329
|
-
hooks: (($e.hooks // {}) + {
|
|
330
|
-
SessionStart: merge("SessionStart"),
|
|
331
|
-
PreToolUse: merge("PreToolUse"),
|
|
332
|
-
PostToolUse: merge("PostToolUse"),
|
|
333
|
-
PostToolUseFailure: merge("PostToolUseFailure")
|
|
334
|
-
} | with_entries(select(.value | length > 0)))
|
|
335
|
-
}
|
|
336
|
-
' .claude/settings.json "$SETTINGS_TEMPLATE" > "$TEMP_SETTINGS" 2>/dev/null; then
|
|
337
|
-
# Verify the output is valid JSON
|
|
338
|
-
if jq empty "$TEMP_SETTINGS" 2>/dev/null; then
|
|
339
|
-
mv "$TEMP_SETTINGS" .claude/settings.json
|
|
340
|
-
MERGE_OK=true
|
|
341
|
-
echo -e "${GREEN} ✓ settings.json merged (your existing hooks preserved)${NC}"
|
|
342
|
-
fi
|
|
343
|
-
fi
|
|
344
|
-
|
|
345
|
-
if [ "$MERGE_OK" = false ]; then
|
|
346
|
-
rm -f "$TEMP_SETTINGS"
|
|
347
|
-
echo -e "${YELLOW} Warning: settings.json merge failed. Your file was NOT modified.${NC}"
|
|
348
|
-
echo -e "${YELLOW} Backed up to: ${BACKUP_DIR}/settings.json${NC}"
|
|
349
|
-
cp "$SETTINGS_TEMPLATE" .claude/.cc-discipline-settings-template.json
|
|
350
|
-
echo -e "${YELLOW} See .claude/.cc-discipline-settings-template.json for hooks to add manually.${NC}"
|
|
351
|
-
fi
|
|
352
|
-
else
|
|
353
|
-
# No jq — don't touch existing settings.json
|
|
354
|
-
echo -e "${YELLOW} settings.json: cannot merge without jq. Your file was NOT modified.${NC}"
|
|
355
|
-
echo -e "${YELLOW} Backed up to: ${BACKUP_DIR}/settings.json${NC}"
|
|
356
|
-
cp "$SETTINGS_TEMPLATE" .claude/.cc-discipline-settings-template.json
|
|
357
|
-
echo -e "${YELLOW} See .claude/.cc-discipline-settings-template.json for hooks to add manually.${NC}"
|
|
358
|
-
fi
|
|
359
|
-
fi
|
|
360
|
-
|
|
361
|
-
# ─── Install subagents ───
|
|
362
|
-
echo -e "${GREEN}Installing subagents...${NC}"
|
|
363
|
-
cp "$SCRIPT_DIR/templates/.claude/agents/reviewer.md" .claude/agents/
|
|
364
|
-
cp "$SCRIPT_DIR/templates/.claude/agents/investigator.md" .claude/agents/
|
|
365
|
-
|
|
366
|
-
# ─── Install skills ───
|
|
367
|
-
echo -e "${GREEN}Installing skills...${NC}"
|
|
368
|
-
cp -r "$SCRIPT_DIR/templates/.claude/skills/commit" .claude/skills/
|
|
369
|
-
cp -r "$SCRIPT_DIR/templates/.claude/skills/self-check" .claude/skills/
|
|
370
|
-
cp -r "$SCRIPT_DIR/templates/.claude/skills/evaluate" .claude/skills/
|
|
371
|
-
cp -r "$SCRIPT_DIR/templates/.claude/skills/think" .claude/skills/
|
|
372
|
-
cp -r "$SCRIPT_DIR/templates/.claude/skills/retro" .claude/skills/
|
|
373
|
-
cp -r "$SCRIPT_DIR/templates/.claude/skills/summary" .claude/skills/
|
|
374
|
-
cp -r "$SCRIPT_DIR/templates/.claude/skills/investigate" .claude/skills/
|
|
375
|
-
echo " ✓ /commit — smart commit (test → update memory → commit)"
|
|
376
|
-
echo " ✓ /self-check — periodic discipline check (use with /loop 10m /self-check)"
|
|
377
|
-
echo " ✓ /evaluate — evaluate external review/advice against codebase context"
|
|
378
|
-
echo " ✓ /think — stop and think before coding (ask → propose → wait)"
|
|
379
|
-
echo " ✓ /retro — post-task retrospective (project + framework feedback)"
|
|
380
|
-
echo " ✓ /summary — write high-quality compact option before /compact"
|
|
381
|
-
echo " ✓ /investigate — multi-agent cross-investigation and proposal review"
|
|
382
|
-
|
|
383
|
-
# ─── Handle CLAUDE.md ───
|
|
384
|
-
if [ ! -f "CLAUDE.md" ]; then
|
|
385
|
-
# No CLAUDE.md exists — generate from template
|
|
386
|
-
echo -e "${GREEN}Generating CLAUDE.md...${NC}"
|
|
387
|
-
sed "s/\[PROJECT_NAME\]/$PROJECT_NAME/g" "$SCRIPT_DIR/templates/CLAUDE.md" > CLAUDE.md
|
|
388
|
-
else
|
|
389
|
-
if [ "$INSTALL_MODE" = "fresh" ]; then
|
|
390
|
-
# Should not happen (fresh mode means no existing files), but handle gracefully
|
|
391
|
-
sed "s/\[PROJECT_NAME\]/$PROJECT_NAME/g" "$SCRIPT_DIR/templates/CLAUDE.md" > CLAUDE.md
|
|
392
|
-
else
|
|
393
|
-
# Existing CLAUDE.md — NEVER overwrite
|
|
394
|
-
echo -e "${YELLOW} CLAUDE.md already exists — NOT modified (your content is safe)${NC}"
|
|
395
|
-
sed "s/\[PROJECT_NAME\]/$PROJECT_NAME/g" "$SCRIPT_DIR/templates/CLAUDE.md" \
|
|
396
|
-
> .claude/.cc-discipline-claude-md-template
|
|
397
|
-
echo " Discipline template saved to .claude/.cc-discipline-claude-md-template"
|
|
398
|
-
echo " You can reference it to add discipline sections to your CLAUDE.md."
|
|
399
|
-
fi
|
|
400
|
-
fi
|
|
401
|
-
|
|
402
|
-
# ─── Copy docs templates (only if not exist) ───
|
|
403
|
-
if [ ! -f "docs/progress.md" ]; then
|
|
404
|
-
cp "$SCRIPT_DIR/templates/docs/progress.md" docs/
|
|
405
|
-
fi
|
|
406
|
-
if [ ! -f "docs/debug-log.md" ]; then
|
|
407
|
-
cp "$SCRIPT_DIR/templates/docs/debug-log.md" docs/
|
|
408
|
-
fi
|
|
409
|
-
|
|
410
|
-
# ─── Install auto memory (symlink to .claude/memory/) ───
|
|
411
|
-
echo -e "${GREEN}Installing auto memory...${NC}"
|
|
412
|
-
MEMORY_PROJECT_KEY=$(echo "$PROJECT_DIR" | sed 's|/|-|g')
|
|
413
|
-
MEMORY_CLAUDE_DIR="$HOME/.claude/projects/${MEMORY_PROJECT_KEY}"
|
|
414
|
-
MEMORY_LOCAL_DIR="$PROJECT_DIR/.claude/memory"
|
|
415
|
-
|
|
416
|
-
# Ensure local .claude/memory/ exists in repo
|
|
417
|
-
mkdir -p "$MEMORY_LOCAL_DIR"
|
|
418
|
-
|
|
419
|
-
# If MEMORY.md doesn't exist locally, seed from template
|
|
420
|
-
if [ ! -f "$MEMORY_LOCAL_DIR/MEMORY.md" ]; then
|
|
421
|
-
cp "$SCRIPT_DIR/templates/memory/MEMORY.md" "$MEMORY_LOCAL_DIR/MEMORY.md"
|
|
422
|
-
echo " ✓ Memory template installed to .claude/memory/MEMORY.md"
|
|
423
|
-
else
|
|
424
|
-
echo -e " ${YELLOW}.claude/memory/MEMORY.md already exists (preserved)${NC}"
|
|
425
|
-
fi
|
|
426
|
-
|
|
427
|
-
# Create symlink: ~/.claude/projects/<key>/memory → .claude/memory/
|
|
428
|
-
mkdir -p "$MEMORY_CLAUDE_DIR"
|
|
429
|
-
if [ -L "$MEMORY_CLAUDE_DIR/memory" ]; then
|
|
430
|
-
# Symlink already exists — update it
|
|
431
|
-
rm "$MEMORY_CLAUDE_DIR/memory"
|
|
432
|
-
ln -s "$MEMORY_LOCAL_DIR" "$MEMORY_CLAUDE_DIR/memory"
|
|
433
|
-
echo " ✓ Memory symlink updated"
|
|
434
|
-
elif [ -d "$MEMORY_CLAUDE_DIR/memory" ]; then
|
|
435
|
-
# Existing real directory — migrate files then replace with symlink
|
|
436
|
-
for f in "$MEMORY_CLAUDE_DIR/memory/"*; do
|
|
437
|
-
[ -f "$f" ] || continue
|
|
438
|
-
fname=$(basename "$f")
|
|
439
|
-
if [ ! -f "$MEMORY_LOCAL_DIR/$fname" ]; then
|
|
440
|
-
cp "$f" "$MEMORY_LOCAL_DIR/$fname"
|
|
441
|
-
fi
|
|
442
|
-
done
|
|
443
|
-
rm -rf "$MEMORY_CLAUDE_DIR/memory"
|
|
444
|
-
ln -s "$MEMORY_LOCAL_DIR" "$MEMORY_CLAUDE_DIR/memory"
|
|
445
|
-
echo " ✓ Existing memory migrated to .claude/memory/ and symlinked"
|
|
446
|
-
else
|
|
447
|
-
ln -s "$MEMORY_LOCAL_DIR" "$MEMORY_CLAUDE_DIR/memory"
|
|
448
|
-
echo " ✓ Memory symlinked: ~/.claude/projects/.../ → .claude/memory/"
|
|
449
|
-
fi
|
|
450
|
-
|
|
451
|
-
# ─── Install global rules (optional) ───
|
|
452
|
-
if [ -n "$ARG_GLOBAL" ]; then
|
|
453
|
-
REPLY="$ARG_GLOBAL"
|
|
454
|
-
else
|
|
455
|
-
echo ""
|
|
456
|
-
echo -e "${BLUE}Install global rules to ~/.claude/CLAUDE.md?${NC}"
|
|
457
|
-
echo " (Global rules apply to all projects, only needs to be installed once)"
|
|
458
|
-
read -p "Install global rules? (y/N) " -n 1 -r
|
|
459
|
-
echo
|
|
460
|
-
fi
|
|
461
|
-
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
462
|
-
mkdir -p ~/.claude
|
|
463
|
-
if [ -f ~/.claude/CLAUDE.md ]; then
|
|
464
|
-
echo -e "${YELLOW} Existing ~/.claude/CLAUDE.md found, backing up to ~/.claude/CLAUDE.md.bak${NC}"
|
|
465
|
-
cp ~/.claude/CLAUDE.md ~/.claude/CLAUDE.md.bak
|
|
466
|
-
fi
|
|
467
|
-
cp "$SCRIPT_DIR/global/CLAUDE.md" ~/.claude/CLAUDE.md
|
|
468
|
-
echo -e "${GREEN} ✓ Global rules installed${NC}"
|
|
469
|
-
fi
|
|
470
|
-
|
|
471
|
-
# ─── Install status line (optional) ───
|
|
472
|
-
GLOBAL_SETTINGS="$HOME/.claude/settings.json"
|
|
473
|
-
HAS_STATUSLINE=false
|
|
474
|
-
if [ -f "$GLOBAL_SETTINGS" ] && command -v jq &>/dev/null; then
|
|
475
|
-
if jq -e '.statusLine' "$GLOBAL_SETTINGS" &>/dev/null; then
|
|
476
|
-
HAS_STATUSLINE=true
|
|
477
|
-
fi
|
|
478
|
-
elif [ -f "$GLOBAL_SETTINGS" ] && grep -q '"statusLine"' "$GLOBAL_SETTINGS" 2>/dev/null; then
|
|
479
|
-
HAS_STATUSLINE=true
|
|
480
|
-
fi
|
|
481
|
-
|
|
482
|
-
if [ "$HAS_STATUSLINE" = false ]; then
|
|
483
|
-
if [ "$ARG_AUTO" = true ]; then
|
|
484
|
-
# Auto mode: skip statusline (don't install without asking)
|
|
485
|
-
true
|
|
486
|
-
else
|
|
487
|
-
echo ""
|
|
488
|
-
echo -e "${BLUE}Install ccstatusline? (shows model, context %, git branch in terminal)${NC}"
|
|
489
|
-
echo " This adds a status line to all Claude Code sessions via ~/.claude/settings.json"
|
|
490
|
-
read -p "Install status line? (y/N) " -n 1 -r
|
|
491
|
-
echo
|
|
492
|
-
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
493
|
-
mkdir -p ~/.claude
|
|
494
|
-
if [ -f "$GLOBAL_SETTINGS" ]; then
|
|
495
|
-
# Merge statusLine into existing settings
|
|
496
|
-
if command -v jq &>/dev/null; then
|
|
497
|
-
EXISTING=$(cat "$GLOBAL_SETTINGS")
|
|
498
|
-
echo "$EXISTING" | jq '. + {"statusLine": {"type": "command", "command": "npx -y ccstatusline@latest", "padding": 0}}' > "$GLOBAL_SETTINGS"
|
|
499
|
-
else
|
|
500
|
-
# No jq — warn user to add manually
|
|
501
|
-
echo -e "${YELLOW} jq not found — please add statusLine to ~/.claude/settings.json manually:${NC}"
|
|
502
|
-
echo ' "statusLine": {"type": "command", "command": "npx -y ccstatusline@latest", "padding": 0}'
|
|
503
|
-
fi
|
|
504
|
-
else
|
|
505
|
-
# No existing settings — create new
|
|
506
|
-
cat > "$GLOBAL_SETTINGS" <<'SEOF'
|
|
507
|
-
{
|
|
508
|
-
"statusLine": {
|
|
509
|
-
"type": "command",
|
|
510
|
-
"command": "npx -y ccstatusline@latest",
|
|
511
|
-
"padding": 0
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
SEOF
|
|
515
|
-
fi
|
|
516
|
-
echo -e "${GREEN} ✓ Status line installed (run 'npx -y ccstatusline@latest' once to configure widgets)${NC}"
|
|
517
|
-
fi
|
|
518
|
-
fi
|
|
519
|
-
fi
|
|
520
|
-
|
|
521
|
-
# ─── Write version marker ───
|
|
522
|
-
echo "$VERSION" > .claude/.cc-discipline-version
|
|
523
|
-
|
|
524
|
-
# ─── Summary ───
|
|
525
|
-
echo ""
|
|
526
|
-
echo -e "${CYAN}╔══════════════════════════════════════════════╗${NC}"
|
|
527
|
-
echo -e "${CYAN}║ Setup complete! ║${NC}"
|
|
528
|
-
echo -e "${CYAN}╚══════════════════════════════════════════════╝${NC}"
|
|
529
|
-
echo ""
|
|
530
|
-
|
|
531
|
-
if [ "$INSTALL_MODE" = "fresh" ]; then
|
|
532
|
-
echo -e "Created files:"
|
|
533
|
-
echo -e " ${GREEN}CLAUDE.md${NC} ← Project rules (fill in [TODO] sections)"
|
|
534
|
-
echo -e " ${GREEN}.claude/rules/${NC} ← Auto-injected rules"
|
|
535
|
-
echo -e " ${GREEN}.claude/hooks/${NC} ← 7 discipline hooks (edit guard, streak breaker, git guard, phase gate, action counter, error remind, session start)"
|
|
536
|
-
echo -e " ${GREEN}.claude/agents/${NC} ← Reviewer & investigator subagents"
|
|
537
|
-
echo -e " ${GREEN}.claude/skills/commit/${NC} ← /commit smart commit"
|
|
538
|
-
echo -e " ${GREEN}.claude/skills/self-check/${NC} ← /self-check periodic discipline check"
|
|
539
|
-
echo -e " ${GREEN}.claude/skills/evaluate/${NC} ← /evaluate assess external review advice"
|
|
540
|
-
echo -e " ${GREEN}.claude/skills/think/${NC} ← /think stop and think before coding"
|
|
541
|
-
echo -e " ${GREEN}.claude/skills/retro/${NC} ← /retro post-task retrospective"
|
|
542
|
-
echo -e " ${GREEN}.claude/skills/summary/${NC} ← /summary before compacting"
|
|
543
|
-
echo -e " ${GREEN}.claude/skills/investigate/${NC} ← /investigate multi-agent cross-investigation"
|
|
544
|
-
echo -e " ${GREEN}.claude/settings.json${NC} ← Hooks configuration"
|
|
545
|
-
echo -e " ${GREEN}docs/progress.md${NC} ← Progress log (maintained by Claude)"
|
|
546
|
-
echo -e " ${GREEN}docs/debug-log.md${NC} ← Debug log (maintained by Claude)"
|
|
547
|
-
echo -e " ${GREEN}.claude/memory/${NC} ← Auto memory (symlinked, lives in repo)"
|
|
548
|
-
echo ""
|
|
549
|
-
echo -e "${YELLOW}Next steps:${NC}"
|
|
550
|
-
echo " 1. Edit CLAUDE.md and fill in the [TODO] sections with project info"
|
|
551
|
-
echo " 2. Review rules in .claude/rules/stacks/ and adjust as needed"
|
|
552
|
-
echo " 3. For complex tasks, use: /loop 10m /self-check"
|
|
553
|
-
echo " 4. Start working with Claude Code!"
|
|
554
|
-
else
|
|
555
|
-
echo -e "What was done:"
|
|
556
|
-
echo -e " ${GREEN}.claude/rules/${NC} ← Discipline rules installed/updated"
|
|
557
|
-
echo -e " ${GREEN}.claude/hooks/${NC} ← Hook scripts installed/updated"
|
|
558
|
-
echo -e " ${GREEN}.claude/agents/${NC} ← Subagents installed/updated"
|
|
559
|
-
echo -e " ${GREEN}.claude/skills/commit/${NC} ← /commit skill installed/updated"
|
|
560
|
-
echo -e " ${GREEN}.claude/skills/self-check/${NC} ← /self-check discipline check installed"
|
|
561
|
-
echo -e " ${GREEN}.claude/skills/evaluate/${NC} ← /evaluate external review assessment"
|
|
562
|
-
echo -e " ${GREEN}.claude/skills/think/${NC} ← /think stop and think before coding"
|
|
563
|
-
echo -e " ${GREEN}.claude/skills/retro/${NC} ← /retro post-task retrospective"
|
|
564
|
-
echo -e " ${GREEN}.claude/skills/summary/${NC} ← /summary before compacting"
|
|
565
|
-
echo -e " ${GREEN}.claude/skills/investigate/${NC} ← /investigate multi-agent cross-investigation"
|
|
566
|
-
if [ ! -f "$BACKUP_DIR/settings.json" ] || [ -f ".claude/.cc-discipline-settings-template.json" ]; then
|
|
567
|
-
echo -e " ${YELLOW}.claude/settings.json${NC} ← See notes above"
|
|
568
|
-
else
|
|
569
|
-
echo -e " ${GREEN}.claude/settings.json${NC} ← Hooks merged"
|
|
570
|
-
fi
|
|
571
|
-
echo ""
|
|
572
|
-
echo -e "What was ${GREEN}NOT${NC} touched:"
|
|
573
|
-
echo -e " CLAUDE.md ← Your project info is safe"
|
|
574
|
-
echo -e " docs/progress.md ← Your progress records are safe"
|
|
575
|
-
echo -e " docs/debug-log.md ← Your debug logs are safe"
|
|
576
|
-
echo -e " Your custom rules/agents ← Untouched (we only add our files)"
|
|
577
|
-
echo ""
|
|
578
|
-
echo -e "${YELLOW}Backup:${NC} ${BACKUP_DIR}/"
|
|
579
|
-
echo " Consider adding .claude/.backup-* to .gitignore"
|
|
580
|
-
echo ""
|
|
581
|
-
if [ -f ".claude/.cc-discipline-claude-md-template" ]; then
|
|
582
|
-
echo -e "${YELLOW}Next steps:${NC}"
|
|
583
|
-
echo " 1. Review .claude/.cc-discipline-claude-md-template"
|
|
584
|
-
echo " Consider adding the docs/ structure and discipline sections to your CLAUDE.md"
|
|
585
|
-
echo " 2. Review rules in .claude/rules/stacks/ and adjust as needed"
|
|
586
|
-
echo " 3. Start working with Claude Code!"
|
|
587
|
-
else
|
|
588
|
-
echo -e "${YELLOW}Next steps:${NC}"
|
|
589
|
-
echo " 1. Review rules in .claude/rules/stacks/ and adjust as needed"
|
|
590
|
-
echo " 2. Start working with Claude Code!"
|
|
591
|
-
fi
|
|
592
|
-
fi
|
|
593
|
-
echo ""
|
|
594
|
-
echo -e "${YELLOW}Tip:${NC} Commit .claude/ and CLAUDE.md to git to share discipline across the team"
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# cc-discipline init script
|
|
3
|
+
# Usage: cd your-project && bash /path/to/init.sh
|
|
4
|
+
# cd your-project && bash /path/to/init.sh --auto # non-interactive, defaults
|
|
5
|
+
# cd your-project && bash /path/to/init.sh --stack "3 4" --name myapp --global
|
|
6
|
+
# Or: curl -sL https://raw.githubusercontent.com/YOU/cc-discipline/main/init.sh | bash
|
|
7
|
+
|
|
8
|
+
# On Windows (Git Bash), set -e causes silent failures due to path/command differences.
|
|
9
|
+
# Use explicit error checking for critical operations instead.
|
|
10
|
+
if [[ "$(uname -s)" != MINGW* ]] && [[ "$(uname -s)" != MSYS* ]]; then
|
|
11
|
+
set -e
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
# ─── Version ───
|
|
15
|
+
# cli.js sets CC_DISCIPLINE_VERSION on Windows where node paths are tricky
|
|
16
|
+
VERSION="${CC_DISCIPLINE_VERSION:-unknown}"
|
|
17
|
+
if [ "$VERSION" = "unknown" ]; then
|
|
18
|
+
_INIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
19
|
+
if command -v node &>/dev/null && [ -f "$_INIT_DIR/package.json" ]; then
|
|
20
|
+
VERSION=$(node -p "require('$_INIT_DIR/package.json').version" 2>/dev/null) || true
|
|
21
|
+
fi
|
|
22
|
+
fi
|
|
23
|
+
VERSION="${VERSION:-unknown}"
|
|
24
|
+
|
|
25
|
+
# ─── Parse CLI arguments ───
|
|
26
|
+
ARG_STACK=""
|
|
27
|
+
ARG_NAME=""
|
|
28
|
+
ARG_GLOBAL=""
|
|
29
|
+
ARG_AUTO=false
|
|
30
|
+
|
|
31
|
+
while [[ $# -gt 0 ]]; do
|
|
32
|
+
case $1 in
|
|
33
|
+
--auto)
|
|
34
|
+
ARG_AUTO=true
|
|
35
|
+
shift
|
|
36
|
+
;;
|
|
37
|
+
--stack)
|
|
38
|
+
ARG_STACK="$2"
|
|
39
|
+
shift 2
|
|
40
|
+
;;
|
|
41
|
+
--name)
|
|
42
|
+
ARG_NAME="$2"
|
|
43
|
+
shift 2
|
|
44
|
+
;;
|
|
45
|
+
--global)
|
|
46
|
+
ARG_GLOBAL="y"
|
|
47
|
+
shift
|
|
48
|
+
;;
|
|
49
|
+
--no-global)
|
|
50
|
+
ARG_GLOBAL="n"
|
|
51
|
+
shift
|
|
52
|
+
;;
|
|
53
|
+
-h|--help)
|
|
54
|
+
echo "Usage: bash init.sh [options]"
|
|
55
|
+
echo ""
|
|
56
|
+
echo "Options:"
|
|
57
|
+
echo " --auto Non-interactive with defaults (stack=7, name=dirname, no global)"
|
|
58
|
+
echo " --stack <choices> Stack selection: 1-7, space-separated (e.g., --stack \"3 4\")"
|
|
59
|
+
echo " --name <name> Project name (default: directory name)"
|
|
60
|
+
echo " --global Install global rules to ~/.claude/CLAUDE.md"
|
|
61
|
+
echo " --no-global Skip global rules install"
|
|
62
|
+
echo " -h, --help Show this help"
|
|
63
|
+
echo ""
|
|
64
|
+
echo "Stacks: 1=RTL 2=Embedded 3=Python 4=JS/TS 5=Mobile 6=Fullstack 7=General"
|
|
65
|
+
exit 0
|
|
66
|
+
;;
|
|
67
|
+
*)
|
|
68
|
+
echo "Unknown option: $1 (use --help for usage)"
|
|
69
|
+
exit 1
|
|
70
|
+
;;
|
|
71
|
+
esac
|
|
72
|
+
done
|
|
73
|
+
|
|
74
|
+
# --auto sets defaults for anything not explicitly provided
|
|
75
|
+
if [ "$ARG_AUTO" = true ]; then
|
|
76
|
+
[ -z "$ARG_STACK" ] && ARG_STACK="7"
|
|
77
|
+
[ -z "$ARG_GLOBAL" ] && ARG_GLOBAL="n"
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# ─── Colors ───
|
|
81
|
+
RED='\033[0;31m'
|
|
82
|
+
GREEN='\033[0;32m'
|
|
83
|
+
YELLOW='\033[1;33m'
|
|
84
|
+
BLUE='\033[0;34m'
|
|
85
|
+
CYAN='\033[0;36m'
|
|
86
|
+
NC='\033[0m'
|
|
87
|
+
|
|
88
|
+
# Support both direct execution and npm (via CC_DISCIPLINE_PKG_DIR)
|
|
89
|
+
if [ -n "$CC_DISCIPLINE_PKG_DIR" ]; then
|
|
90
|
+
SCRIPT_DIR="$CC_DISCIPLINE_PKG_DIR"
|
|
91
|
+
else
|
|
92
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
93
|
+
fi
|
|
94
|
+
PROJECT_DIR="$(pwd)"
|
|
95
|
+
|
|
96
|
+
echo -e "${CYAN}╔══════════════════════════════════════════════╗${NC}"
|
|
97
|
+
echo -e "${CYAN}║ Claude Code Discipline Framework — Setup ║${NC}"
|
|
98
|
+
echo -e "${CYAN}╚══════════════════════════════════════════════╝${NC}"
|
|
99
|
+
echo ""
|
|
100
|
+
echo -e "Project directory: ${GREEN}${PROJECT_DIR}${NC}"
|
|
101
|
+
|
|
102
|
+
# ─── Detect install mode ───
|
|
103
|
+
INSTALL_MODE="fresh"
|
|
104
|
+
INSTALLED_VERSION=""
|
|
105
|
+
|
|
106
|
+
if [ -f ".claude/.cc-discipline-version" ]; then
|
|
107
|
+
INSTALL_MODE="upgrade"
|
|
108
|
+
INSTALLED_VERSION=$(cat ".claude/.cc-discipline-version")
|
|
109
|
+
elif [ -f ".claude/hooks/streak-breaker.sh" ] || [ -f ".claude/hooks/pre-edit-guard.sh" ] || [ -f ".claude/hooks/session-start.sh" ] || [ -f ".claude/hooks/phase-gate.sh" ]; then
|
|
110
|
+
INSTALL_MODE="upgrade"
|
|
111
|
+
INSTALLED_VERSION="<2.0.0"
|
|
112
|
+
elif [ -d ".claude" ] || [ -f "CLAUDE.md" ]; then
|
|
113
|
+
INSTALL_MODE="append"
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
case "$INSTALL_MODE" in
|
|
117
|
+
fresh)
|
|
118
|
+
echo -e "Mode: ${GREEN}Fresh install${NC}"
|
|
119
|
+
;;
|
|
120
|
+
upgrade)
|
|
121
|
+
echo -e "Mode: ${YELLOW}Upgrade cc-discipline (${INSTALLED_VERSION} → ${VERSION})${NC}"
|
|
122
|
+
;;
|
|
123
|
+
append)
|
|
124
|
+
echo -e "Mode: ${YELLOW}Adding discipline to existing project${NC}"
|
|
125
|
+
echo -e "${YELLOW}Your existing files will be preserved. cc-discipline files will be added alongside them.${NC}"
|
|
126
|
+
;;
|
|
127
|
+
esac
|
|
128
|
+
echo ""
|
|
129
|
+
|
|
130
|
+
# ─── Backup (upgrade/append) ───
|
|
131
|
+
BACKUP_DIR=""
|
|
132
|
+
if [ "$INSTALL_MODE" != "fresh" ]; then
|
|
133
|
+
BACKUP_DIR=".claude/.backup-$(date +%Y%m%d-%H%M%S)"
|
|
134
|
+
mkdir -p "$BACKUP_DIR"
|
|
135
|
+
[ -f "CLAUDE.md" ] && cp "CLAUDE.md" "$BACKUP_DIR/"
|
|
136
|
+
[ -f ".claude/settings.json" ] && cp ".claude/settings.json" "$BACKUP_DIR/"
|
|
137
|
+
[ -d ".claude/hooks" ] && cp -r ".claude/hooks" "$BACKUP_DIR/"
|
|
138
|
+
[ -d ".claude/rules" ] && cp -r ".claude/rules" "$BACKUP_DIR/"
|
|
139
|
+
[ -d ".claude/agents" ] && cp -r ".claude/agents" "$BACKUP_DIR/"
|
|
140
|
+
[ -d ".claude/skills" ] && cp -r ".claude/skills" "$BACKUP_DIR/"
|
|
141
|
+
echo -e "${GREEN}Backup saved to ${BACKUP_DIR}/${NC}"
|
|
142
|
+
echo ""
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
# ─── Detect installed stacks (for upgrade/append) ───
|
|
146
|
+
detect_installed_stacks() {
|
|
147
|
+
INSTALLED_STACKS=""
|
|
148
|
+
[ -f ".claude/rules/stacks/rtl.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}1 "
|
|
149
|
+
[ -f ".claude/rules/stacks/embedded.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}2 "
|
|
150
|
+
[ -f ".claude/rules/stacks/python.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}3 "
|
|
151
|
+
[ -f ".claude/rules/stacks/js-ts.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}4 "
|
|
152
|
+
[ -f ".claude/rules/stacks/mobile.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}5 "
|
|
153
|
+
return 0
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# ─── Select project type ───
|
|
157
|
+
if [ -n "$ARG_STACK" ]; then
|
|
158
|
+
STACK_CHOICES="$ARG_STACK"
|
|
159
|
+
echo -e "Stack: ${GREEN}${STACK_CHOICES}${NC} (from CLI)"
|
|
160
|
+
elif [ "$INSTALL_MODE" = "fresh" ]; then
|
|
161
|
+
echo -e "${BLUE}What is your project type? (select multiple with spaces)${NC}"
|
|
162
|
+
echo " 1) RTL / IC Design (Verilog, VHDL, SystemVerilog)"
|
|
163
|
+
echo " 2) Embedded (C/C++, bare-metal, RTOS)"
|
|
164
|
+
echo " 3) Python (backend / scripting / ML)"
|
|
165
|
+
echo " 4) JavaScript / TypeScript (Node, Web)"
|
|
166
|
+
echo " 5) Mobile (Swift, Kotlin, React Native, Flutter)"
|
|
167
|
+
echo " 6) Full-stack Web (frontend + backend)"
|
|
168
|
+
echo " 7) Other / General"
|
|
169
|
+
echo ""
|
|
170
|
+
read -p "Choose (e.g.: 1 2 or 3 4 6): " STACK_CHOICES
|
|
171
|
+
else
|
|
172
|
+
detect_installed_stacks
|
|
173
|
+
echo -e "${BLUE}Stack rules (* = already installed):${NC}"
|
|
174
|
+
for i in 1 2 3 4 5; do
|
|
175
|
+
MARKER=""
|
|
176
|
+
echo "$INSTALLED_STACKS" | grep -q "$i" && MARKER=" ${GREEN}*${NC}"
|
|
177
|
+
case $i in
|
|
178
|
+
1) echo -e " 1) RTL / IC Design${MARKER}" ;;
|
|
179
|
+
2) echo -e " 2) Embedded${MARKER}" ;;
|
|
180
|
+
3) echo -e " 3) Python${MARKER}" ;;
|
|
181
|
+
4) echo -e " 4) JavaScript / TypeScript${MARKER}" ;;
|
|
182
|
+
5) echo -e " 5) Mobile${MARKER}" ;;
|
|
183
|
+
esac
|
|
184
|
+
done
|
|
185
|
+
echo " 6) Full-stack Web (JS/TS + Python)"
|
|
186
|
+
echo " 7) Other / General"
|
|
187
|
+
echo ""
|
|
188
|
+
read -p "Add stacks (e.g.: 2 4), or press Enter to keep current: " STACK_CHOICES
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
# Parse choices into array
|
|
192
|
+
IFS=' ' read -ra STACKS <<< "$STACK_CHOICES"
|
|
193
|
+
|
|
194
|
+
# ─── Project name ───
|
|
195
|
+
if [ -n "$ARG_NAME" ]; then
|
|
196
|
+
PROJECT_NAME="$ARG_NAME"
|
|
197
|
+
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (from CLI)"
|
|
198
|
+
elif [ "$INSTALL_MODE" = "fresh" ]; then
|
|
199
|
+
DEFAULT_NAME=$(basename "$PROJECT_DIR")
|
|
200
|
+
if [ "$ARG_AUTO" = true ]; then
|
|
201
|
+
PROJECT_NAME="$DEFAULT_NAME"
|
|
202
|
+
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (auto)"
|
|
203
|
+
else
|
|
204
|
+
read -p "Project name [$DEFAULT_NAME]: " PROJECT_NAME
|
|
205
|
+
PROJECT_NAME=${PROJECT_NAME:-$DEFAULT_NAME}
|
|
206
|
+
fi
|
|
207
|
+
else
|
|
208
|
+
# Try to extract from existing CLAUDE.md: "# MyProject — CLAUDE.md"
|
|
209
|
+
PROJECT_NAME=""
|
|
210
|
+
if [ -f "CLAUDE.md" ]; then
|
|
211
|
+
PROJECT_NAME=$(head -1 CLAUDE.md | sed 's/^# //;s/ — CLAUDE.md$//' 2>/dev/null)
|
|
212
|
+
fi
|
|
213
|
+
if [ -z "$PROJECT_NAME" ] || [ "$PROJECT_NAME" = "[PROJECT_NAME]" ]; then
|
|
214
|
+
DEFAULT_NAME=$(basename "$PROJECT_DIR")
|
|
215
|
+
if [ "$ARG_AUTO" = true ]; then
|
|
216
|
+
PROJECT_NAME="$DEFAULT_NAME"
|
|
217
|
+
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (auto)"
|
|
218
|
+
else
|
|
219
|
+
read -p "Project name [$DEFAULT_NAME]: " PROJECT_NAME
|
|
220
|
+
PROJECT_NAME=${PROJECT_NAME:-$DEFAULT_NAME}
|
|
221
|
+
fi
|
|
222
|
+
else
|
|
223
|
+
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (from CLAUDE.md)"
|
|
224
|
+
fi
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
# ─── Create directory structure ───
|
|
228
|
+
echo ""
|
|
229
|
+
echo -e "${GREEN}Creating directory structure...${NC}"
|
|
230
|
+
mkdir -p .claude/rules/stacks
|
|
231
|
+
mkdir -p .claude/hooks
|
|
232
|
+
mkdir -p .claude/agents
|
|
233
|
+
mkdir -p .claude/skills
|
|
234
|
+
mkdir -p docs
|
|
235
|
+
|
|
236
|
+
# ─── Copy core rules (always applied, always overwrite — these are framework files) ───
|
|
237
|
+
echo -e "${GREEN}Installing core rules...${NC}"
|
|
238
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/00-core-principles.md" .claude/rules/
|
|
239
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/01-debugging.md" .claude/rules/
|
|
240
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/02-before-edit.md" .claude/rules/
|
|
241
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/03-context-mgmt.md" .claude/rules/
|
|
242
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/04-no-mole-whacking.md" .claude/rules/
|
|
243
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/05-phase-discipline.md" .claude/rules/
|
|
244
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/06-multi-task.md" .claude/rules/
|
|
245
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/07-integrity.md" .claude/rules/
|
|
246
|
+
|
|
247
|
+
# ─── Copy stack-specific rules based on selection ───
|
|
248
|
+
if [ ${#STACKS[@]} -gt 0 ] && [ -n "${STACKS[0]}" ]; then
|
|
249
|
+
echo -e "${GREEN}Installing stack rules...${NC}"
|
|
250
|
+
for choice in "${STACKS[@]}"; do
|
|
251
|
+
case $choice in
|
|
252
|
+
1)
|
|
253
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/rtl.md" .claude/rules/stacks/
|
|
254
|
+
echo " ✓ RTL / IC Design rules"
|
|
255
|
+
;;
|
|
256
|
+
2)
|
|
257
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/embedded.md" .claude/rules/stacks/
|
|
258
|
+
echo " ✓ Embedded development rules"
|
|
259
|
+
;;
|
|
260
|
+
3)
|
|
261
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/python.md" .claude/rules/stacks/
|
|
262
|
+
echo " ✓ Python rules"
|
|
263
|
+
;;
|
|
264
|
+
4)
|
|
265
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/js-ts.md" .claude/rules/stacks/
|
|
266
|
+
echo " ✓ JavaScript / TypeScript rules"
|
|
267
|
+
;;
|
|
268
|
+
5)
|
|
269
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/mobile.md" .claude/rules/stacks/
|
|
270
|
+
echo " ✓ Mobile development rules"
|
|
271
|
+
;;
|
|
272
|
+
6)
|
|
273
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/js-ts.md" .claude/rules/stacks/
|
|
274
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/python.md" .claude/rules/stacks/
|
|
275
|
+
echo " ✓ Full-stack rules (JS/TS + Python)"
|
|
276
|
+
;;
|
|
277
|
+
7)
|
|
278
|
+
echo " ✓ General rules (no additional stack rules)"
|
|
279
|
+
;;
|
|
280
|
+
esac
|
|
281
|
+
done
|
|
282
|
+
fi
|
|
283
|
+
|
|
284
|
+
# ─── Install hooks ───
|
|
285
|
+
echo -e "${GREEN}Installing hooks...${NC}"
|
|
286
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/pre-edit-guard.sh" .claude/hooks/
|
|
287
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/post-error-remind.sh" .claude/hooks/
|
|
288
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/streak-breaker.sh" .claude/hooks/
|
|
289
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/session-start.sh" .claude/hooks/
|
|
290
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/phase-gate.sh" .claude/hooks/
|
|
291
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/git-guard.sh" .claude/hooks/
|
|
292
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/action-counter.sh" .claude/hooks/
|
|
293
|
+
chmod +x .claude/hooks/*.sh
|
|
294
|
+
|
|
295
|
+
# ─── Check jq availability ───
|
|
296
|
+
HAS_JQ=false
|
|
297
|
+
if command -v jq &>/dev/null; then
|
|
298
|
+
HAS_JQ=true
|
|
299
|
+
else
|
|
300
|
+
echo ""
|
|
301
|
+
echo -e "${YELLOW}Warning: jq not found — Hooks will use grep/sed fallback, but jq is recommended${NC}"
|
|
302
|
+
echo " macOS: brew install jq"
|
|
303
|
+
echo " Ubuntu: sudo apt install jq"
|
|
304
|
+
echo " Arch: sudo pacman -S jq"
|
|
305
|
+
echo ""
|
|
306
|
+
fi
|
|
307
|
+
|
|
308
|
+
# ─── Install/merge settings.json ───
|
|
309
|
+
SETTINGS_TEMPLATE="$SCRIPT_DIR/templates/.claude/settings.json"
|
|
310
|
+
|
|
311
|
+
if [ ! -f ".claude/settings.json" ]; then
|
|
312
|
+
# No existing settings.json — just copy template
|
|
313
|
+
cp "$SETTINGS_TEMPLATE" .claude/settings.json
|
|
314
|
+
echo -e "${GREEN} ✓ settings.json created${NC}"
|
|
315
|
+
elif [ "$INSTALL_MODE" = "fresh" ]; then
|
|
316
|
+
# Fresh mode shouldn't reach here, but just in case
|
|
317
|
+
cp "$SETTINGS_TEMPLATE" .claude/settings.json
|
|
318
|
+
else
|
|
319
|
+
# Merge: preserve user hooks, add/update cc-discipline hooks
|
|
320
|
+
if [ "$HAS_JQ" = true ]; then
|
|
321
|
+
TEMP_SETTINGS=$(mktemp)
|
|
322
|
+
MERGE_OK=false
|
|
323
|
+
|
|
324
|
+
if jq -s '
|
|
325
|
+
.[0] as $e | .[1] as $t |
|
|
326
|
+
def is_cc: .hooks | any(.command | test("pre-edit-guard|streak-breaker|post-error-remind|session-start|phase-gate|action-counter"));
|
|
327
|
+
def merge($ev): (($e.hooks[$ev] // []) | map(select(is_cc | not))) + ($t.hooks[$ev] // []);
|
|
328
|
+
$e * {
|
|
329
|
+
hooks: (($e.hooks // {}) + {
|
|
330
|
+
SessionStart: merge("SessionStart"),
|
|
331
|
+
PreToolUse: merge("PreToolUse"),
|
|
332
|
+
PostToolUse: merge("PostToolUse"),
|
|
333
|
+
PostToolUseFailure: merge("PostToolUseFailure")
|
|
334
|
+
} | with_entries(select(.value | length > 0)))
|
|
335
|
+
}
|
|
336
|
+
' .claude/settings.json "$SETTINGS_TEMPLATE" > "$TEMP_SETTINGS" 2>/dev/null; then
|
|
337
|
+
# Verify the output is valid JSON
|
|
338
|
+
if jq empty "$TEMP_SETTINGS" 2>/dev/null; then
|
|
339
|
+
mv "$TEMP_SETTINGS" .claude/settings.json
|
|
340
|
+
MERGE_OK=true
|
|
341
|
+
echo -e "${GREEN} ✓ settings.json merged (your existing hooks preserved)${NC}"
|
|
342
|
+
fi
|
|
343
|
+
fi
|
|
344
|
+
|
|
345
|
+
if [ "$MERGE_OK" = false ]; then
|
|
346
|
+
rm -f "$TEMP_SETTINGS"
|
|
347
|
+
echo -e "${YELLOW} Warning: settings.json merge failed. Your file was NOT modified.${NC}"
|
|
348
|
+
echo -e "${YELLOW} Backed up to: ${BACKUP_DIR}/settings.json${NC}"
|
|
349
|
+
cp "$SETTINGS_TEMPLATE" .claude/.cc-discipline-settings-template.json
|
|
350
|
+
echo -e "${YELLOW} See .claude/.cc-discipline-settings-template.json for hooks to add manually.${NC}"
|
|
351
|
+
fi
|
|
352
|
+
else
|
|
353
|
+
# No jq — don't touch existing settings.json
|
|
354
|
+
echo -e "${YELLOW} settings.json: cannot merge without jq. Your file was NOT modified.${NC}"
|
|
355
|
+
echo -e "${YELLOW} Backed up to: ${BACKUP_DIR}/settings.json${NC}"
|
|
356
|
+
cp "$SETTINGS_TEMPLATE" .claude/.cc-discipline-settings-template.json
|
|
357
|
+
echo -e "${YELLOW} See .claude/.cc-discipline-settings-template.json for hooks to add manually.${NC}"
|
|
358
|
+
fi
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
# ─── Install subagents ───
|
|
362
|
+
echo -e "${GREEN}Installing subagents...${NC}"
|
|
363
|
+
cp "$SCRIPT_DIR/templates/.claude/agents/reviewer.md" .claude/agents/
|
|
364
|
+
cp "$SCRIPT_DIR/templates/.claude/agents/investigator.md" .claude/agents/
|
|
365
|
+
|
|
366
|
+
# ─── Install skills ───
|
|
367
|
+
echo -e "${GREEN}Installing skills...${NC}"
|
|
368
|
+
cp -r "$SCRIPT_DIR/templates/.claude/skills/commit" .claude/skills/
|
|
369
|
+
cp -r "$SCRIPT_DIR/templates/.claude/skills/self-check" .claude/skills/
|
|
370
|
+
cp -r "$SCRIPT_DIR/templates/.claude/skills/evaluate" .claude/skills/
|
|
371
|
+
cp -r "$SCRIPT_DIR/templates/.claude/skills/think" .claude/skills/
|
|
372
|
+
cp -r "$SCRIPT_DIR/templates/.claude/skills/retro" .claude/skills/
|
|
373
|
+
cp -r "$SCRIPT_DIR/templates/.claude/skills/summary" .claude/skills/
|
|
374
|
+
cp -r "$SCRIPT_DIR/templates/.claude/skills/investigate" .claude/skills/
|
|
375
|
+
echo " ✓ /commit — smart commit (test → update memory → commit)"
|
|
376
|
+
echo " ✓ /self-check — periodic discipline check (use with /loop 10m /self-check)"
|
|
377
|
+
echo " ✓ /evaluate — evaluate external review/advice against codebase context"
|
|
378
|
+
echo " ✓ /think — stop and think before coding (ask → propose → wait)"
|
|
379
|
+
echo " ✓ /retro — post-task retrospective (project + framework feedback)"
|
|
380
|
+
echo " ✓ /summary — write high-quality compact option before /compact"
|
|
381
|
+
echo " ✓ /investigate — multi-agent cross-investigation and proposal review"
|
|
382
|
+
|
|
383
|
+
# ─── Handle CLAUDE.md ───
|
|
384
|
+
if [ ! -f "CLAUDE.md" ]; then
|
|
385
|
+
# No CLAUDE.md exists — generate from template
|
|
386
|
+
echo -e "${GREEN}Generating CLAUDE.md...${NC}"
|
|
387
|
+
sed "s/\[PROJECT_NAME\]/$PROJECT_NAME/g" "$SCRIPT_DIR/templates/CLAUDE.md" > CLAUDE.md
|
|
388
|
+
else
|
|
389
|
+
if [ "$INSTALL_MODE" = "fresh" ]; then
|
|
390
|
+
# Should not happen (fresh mode means no existing files), but handle gracefully
|
|
391
|
+
sed "s/\[PROJECT_NAME\]/$PROJECT_NAME/g" "$SCRIPT_DIR/templates/CLAUDE.md" > CLAUDE.md
|
|
392
|
+
else
|
|
393
|
+
# Existing CLAUDE.md — NEVER overwrite
|
|
394
|
+
echo -e "${YELLOW} CLAUDE.md already exists — NOT modified (your content is safe)${NC}"
|
|
395
|
+
sed "s/\[PROJECT_NAME\]/$PROJECT_NAME/g" "$SCRIPT_DIR/templates/CLAUDE.md" \
|
|
396
|
+
> .claude/.cc-discipline-claude-md-template
|
|
397
|
+
echo " Discipline template saved to .claude/.cc-discipline-claude-md-template"
|
|
398
|
+
echo " You can reference it to add discipline sections to your CLAUDE.md."
|
|
399
|
+
fi
|
|
400
|
+
fi
|
|
401
|
+
|
|
402
|
+
# ─── Copy docs templates (only if not exist) ───
|
|
403
|
+
if [ ! -f "docs/progress.md" ]; then
|
|
404
|
+
cp "$SCRIPT_DIR/templates/docs/progress.md" docs/
|
|
405
|
+
fi
|
|
406
|
+
if [ ! -f "docs/debug-log.md" ]; then
|
|
407
|
+
cp "$SCRIPT_DIR/templates/docs/debug-log.md" docs/
|
|
408
|
+
fi
|
|
409
|
+
|
|
410
|
+
# ─── Install auto memory (symlink to .claude/memory/) ───
|
|
411
|
+
echo -e "${GREEN}Installing auto memory...${NC}"
|
|
412
|
+
MEMORY_PROJECT_KEY=$(echo "$PROJECT_DIR" | sed 's|/|-|g')
|
|
413
|
+
MEMORY_CLAUDE_DIR="$HOME/.claude/projects/${MEMORY_PROJECT_KEY}"
|
|
414
|
+
MEMORY_LOCAL_DIR="$PROJECT_DIR/.claude/memory"
|
|
415
|
+
|
|
416
|
+
# Ensure local .claude/memory/ exists in repo
|
|
417
|
+
mkdir -p "$MEMORY_LOCAL_DIR"
|
|
418
|
+
|
|
419
|
+
# If MEMORY.md doesn't exist locally, seed from template
|
|
420
|
+
if [ ! -f "$MEMORY_LOCAL_DIR/MEMORY.md" ]; then
|
|
421
|
+
cp "$SCRIPT_DIR/templates/memory/MEMORY.md" "$MEMORY_LOCAL_DIR/MEMORY.md"
|
|
422
|
+
echo " ✓ Memory template installed to .claude/memory/MEMORY.md"
|
|
423
|
+
else
|
|
424
|
+
echo -e " ${YELLOW}.claude/memory/MEMORY.md already exists (preserved)${NC}"
|
|
425
|
+
fi
|
|
426
|
+
|
|
427
|
+
# Create symlink: ~/.claude/projects/<key>/memory → .claude/memory/
|
|
428
|
+
mkdir -p "$MEMORY_CLAUDE_DIR"
|
|
429
|
+
if [ -L "$MEMORY_CLAUDE_DIR/memory" ]; then
|
|
430
|
+
# Symlink already exists — update it
|
|
431
|
+
rm "$MEMORY_CLAUDE_DIR/memory"
|
|
432
|
+
ln -s "$MEMORY_LOCAL_DIR" "$MEMORY_CLAUDE_DIR/memory"
|
|
433
|
+
echo " ✓ Memory symlink updated"
|
|
434
|
+
elif [ -d "$MEMORY_CLAUDE_DIR/memory" ]; then
|
|
435
|
+
# Existing real directory — migrate files then replace with symlink
|
|
436
|
+
for f in "$MEMORY_CLAUDE_DIR/memory/"*; do
|
|
437
|
+
[ -f "$f" ] || continue
|
|
438
|
+
fname=$(basename "$f")
|
|
439
|
+
if [ ! -f "$MEMORY_LOCAL_DIR/$fname" ]; then
|
|
440
|
+
cp "$f" "$MEMORY_LOCAL_DIR/$fname"
|
|
441
|
+
fi
|
|
442
|
+
done
|
|
443
|
+
rm -rf "$MEMORY_CLAUDE_DIR/memory"
|
|
444
|
+
ln -s "$MEMORY_LOCAL_DIR" "$MEMORY_CLAUDE_DIR/memory"
|
|
445
|
+
echo " ✓ Existing memory migrated to .claude/memory/ and symlinked"
|
|
446
|
+
else
|
|
447
|
+
ln -s "$MEMORY_LOCAL_DIR" "$MEMORY_CLAUDE_DIR/memory"
|
|
448
|
+
echo " ✓ Memory symlinked: ~/.claude/projects/.../ → .claude/memory/"
|
|
449
|
+
fi
|
|
450
|
+
|
|
451
|
+
# ─── Install global rules (optional) ───
|
|
452
|
+
if [ -n "$ARG_GLOBAL" ]; then
|
|
453
|
+
REPLY="$ARG_GLOBAL"
|
|
454
|
+
else
|
|
455
|
+
echo ""
|
|
456
|
+
echo -e "${BLUE}Install global rules to ~/.claude/CLAUDE.md?${NC}"
|
|
457
|
+
echo " (Global rules apply to all projects, only needs to be installed once)"
|
|
458
|
+
read -p "Install global rules? (y/N) " -n 1 -r
|
|
459
|
+
echo
|
|
460
|
+
fi
|
|
461
|
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
462
|
+
mkdir -p ~/.claude
|
|
463
|
+
if [ -f ~/.claude/CLAUDE.md ]; then
|
|
464
|
+
echo -e "${YELLOW} Existing ~/.claude/CLAUDE.md found, backing up to ~/.claude/CLAUDE.md.bak${NC}"
|
|
465
|
+
cp ~/.claude/CLAUDE.md ~/.claude/CLAUDE.md.bak
|
|
466
|
+
fi
|
|
467
|
+
cp "$SCRIPT_DIR/global/CLAUDE.md" ~/.claude/CLAUDE.md
|
|
468
|
+
echo -e "${GREEN} ✓ Global rules installed${NC}"
|
|
469
|
+
fi
|
|
470
|
+
|
|
471
|
+
# ─── Install status line (optional) ───
|
|
472
|
+
GLOBAL_SETTINGS="$HOME/.claude/settings.json"
|
|
473
|
+
HAS_STATUSLINE=false
|
|
474
|
+
if [ -f "$GLOBAL_SETTINGS" ] && command -v jq &>/dev/null; then
|
|
475
|
+
if jq -e '.statusLine' "$GLOBAL_SETTINGS" &>/dev/null; then
|
|
476
|
+
HAS_STATUSLINE=true
|
|
477
|
+
fi
|
|
478
|
+
elif [ -f "$GLOBAL_SETTINGS" ] && grep -q '"statusLine"' "$GLOBAL_SETTINGS" 2>/dev/null; then
|
|
479
|
+
HAS_STATUSLINE=true
|
|
480
|
+
fi
|
|
481
|
+
|
|
482
|
+
if [ "$HAS_STATUSLINE" = false ]; then
|
|
483
|
+
if [ "$ARG_AUTO" = true ]; then
|
|
484
|
+
# Auto mode: skip statusline (don't install without asking)
|
|
485
|
+
true
|
|
486
|
+
else
|
|
487
|
+
echo ""
|
|
488
|
+
echo -e "${BLUE}Install ccstatusline? (shows model, context %, git branch in terminal)${NC}"
|
|
489
|
+
echo " This adds a status line to all Claude Code sessions via ~/.claude/settings.json"
|
|
490
|
+
read -p "Install status line? (y/N) " -n 1 -r
|
|
491
|
+
echo
|
|
492
|
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
493
|
+
mkdir -p ~/.claude
|
|
494
|
+
if [ -f "$GLOBAL_SETTINGS" ]; then
|
|
495
|
+
# Merge statusLine into existing settings
|
|
496
|
+
if command -v jq &>/dev/null; then
|
|
497
|
+
EXISTING=$(cat "$GLOBAL_SETTINGS")
|
|
498
|
+
echo "$EXISTING" | jq '. + {"statusLine": {"type": "command", "command": "npx -y ccstatusline@latest", "padding": 0}}' > "$GLOBAL_SETTINGS"
|
|
499
|
+
else
|
|
500
|
+
# No jq — warn user to add manually
|
|
501
|
+
echo -e "${YELLOW} jq not found — please add statusLine to ~/.claude/settings.json manually:${NC}"
|
|
502
|
+
echo ' "statusLine": {"type": "command", "command": "npx -y ccstatusline@latest", "padding": 0}'
|
|
503
|
+
fi
|
|
504
|
+
else
|
|
505
|
+
# No existing settings — create new
|
|
506
|
+
cat > "$GLOBAL_SETTINGS" <<'SEOF'
|
|
507
|
+
{
|
|
508
|
+
"statusLine": {
|
|
509
|
+
"type": "command",
|
|
510
|
+
"command": "npx -y ccstatusline@latest",
|
|
511
|
+
"padding": 0
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
SEOF
|
|
515
|
+
fi
|
|
516
|
+
echo -e "${GREEN} ✓ Status line installed (run 'npx -y ccstatusline@latest' once to configure widgets)${NC}"
|
|
517
|
+
fi
|
|
518
|
+
fi
|
|
519
|
+
fi
|
|
520
|
+
|
|
521
|
+
# ─── Write version marker ───
|
|
522
|
+
echo "$VERSION" > .claude/.cc-discipline-version
|
|
523
|
+
|
|
524
|
+
# ─── Summary ───
|
|
525
|
+
echo ""
|
|
526
|
+
echo -e "${CYAN}╔══════════════════════════════════════════════╗${NC}"
|
|
527
|
+
echo -e "${CYAN}║ Setup complete! ║${NC}"
|
|
528
|
+
echo -e "${CYAN}╚══════════════════════════════════════════════╝${NC}"
|
|
529
|
+
echo ""
|
|
530
|
+
|
|
531
|
+
if [ "$INSTALL_MODE" = "fresh" ]; then
|
|
532
|
+
echo -e "Created files:"
|
|
533
|
+
echo -e " ${GREEN}CLAUDE.md${NC} ← Project rules (fill in [TODO] sections)"
|
|
534
|
+
echo -e " ${GREEN}.claude/rules/${NC} ← Auto-injected rules"
|
|
535
|
+
echo -e " ${GREEN}.claude/hooks/${NC} ← 7 discipline hooks (edit guard, streak breaker, git guard, phase gate, action counter, error remind, session start)"
|
|
536
|
+
echo -e " ${GREEN}.claude/agents/${NC} ← Reviewer & investigator subagents"
|
|
537
|
+
echo -e " ${GREEN}.claude/skills/commit/${NC} ← /commit smart commit"
|
|
538
|
+
echo -e " ${GREEN}.claude/skills/self-check/${NC} ← /self-check periodic discipline check"
|
|
539
|
+
echo -e " ${GREEN}.claude/skills/evaluate/${NC} ← /evaluate assess external review advice"
|
|
540
|
+
echo -e " ${GREEN}.claude/skills/think/${NC} ← /think stop and think before coding"
|
|
541
|
+
echo -e " ${GREEN}.claude/skills/retro/${NC} ← /retro post-task retrospective"
|
|
542
|
+
echo -e " ${GREEN}.claude/skills/summary/${NC} ← /summary before compacting"
|
|
543
|
+
echo -e " ${GREEN}.claude/skills/investigate/${NC} ← /investigate multi-agent cross-investigation"
|
|
544
|
+
echo -e " ${GREEN}.claude/settings.json${NC} ← Hooks configuration"
|
|
545
|
+
echo -e " ${GREEN}docs/progress.md${NC} ← Progress log (maintained by Claude)"
|
|
546
|
+
echo -e " ${GREEN}docs/debug-log.md${NC} ← Debug log (maintained by Claude)"
|
|
547
|
+
echo -e " ${GREEN}.claude/memory/${NC} ← Auto memory (symlinked, lives in repo)"
|
|
548
|
+
echo ""
|
|
549
|
+
echo -e "${YELLOW}Next steps:${NC}"
|
|
550
|
+
echo " 1. Edit CLAUDE.md and fill in the [TODO] sections with project info"
|
|
551
|
+
echo " 2. Review rules in .claude/rules/stacks/ and adjust as needed"
|
|
552
|
+
echo " 3. For complex tasks, use: /loop 10m /self-check"
|
|
553
|
+
echo " 4. Start working with Claude Code!"
|
|
554
|
+
else
|
|
555
|
+
echo -e "What was done:"
|
|
556
|
+
echo -e " ${GREEN}.claude/rules/${NC} ← Discipline rules installed/updated"
|
|
557
|
+
echo -e " ${GREEN}.claude/hooks/${NC} ← Hook scripts installed/updated"
|
|
558
|
+
echo -e " ${GREEN}.claude/agents/${NC} ← Subagents installed/updated"
|
|
559
|
+
echo -e " ${GREEN}.claude/skills/commit/${NC} ← /commit skill installed/updated"
|
|
560
|
+
echo -e " ${GREEN}.claude/skills/self-check/${NC} ← /self-check discipline check installed"
|
|
561
|
+
echo -e " ${GREEN}.claude/skills/evaluate/${NC} ← /evaluate external review assessment"
|
|
562
|
+
echo -e " ${GREEN}.claude/skills/think/${NC} ← /think stop and think before coding"
|
|
563
|
+
echo -e " ${GREEN}.claude/skills/retro/${NC} ← /retro post-task retrospective"
|
|
564
|
+
echo -e " ${GREEN}.claude/skills/summary/${NC} ← /summary before compacting"
|
|
565
|
+
echo -e " ${GREEN}.claude/skills/investigate/${NC} ← /investigate multi-agent cross-investigation"
|
|
566
|
+
if [ ! -f "$BACKUP_DIR/settings.json" ] || [ -f ".claude/.cc-discipline-settings-template.json" ]; then
|
|
567
|
+
echo -e " ${YELLOW}.claude/settings.json${NC} ← See notes above"
|
|
568
|
+
else
|
|
569
|
+
echo -e " ${GREEN}.claude/settings.json${NC} ← Hooks merged"
|
|
570
|
+
fi
|
|
571
|
+
echo ""
|
|
572
|
+
echo -e "What was ${GREEN}NOT${NC} touched:"
|
|
573
|
+
echo -e " CLAUDE.md ← Your project info is safe"
|
|
574
|
+
echo -e " docs/progress.md ← Your progress records are safe"
|
|
575
|
+
echo -e " docs/debug-log.md ← Your debug logs are safe"
|
|
576
|
+
echo -e " Your custom rules/agents ← Untouched (we only add our files)"
|
|
577
|
+
echo ""
|
|
578
|
+
echo -e "${YELLOW}Backup:${NC} ${BACKUP_DIR}/"
|
|
579
|
+
echo " Consider adding .claude/.backup-* to .gitignore"
|
|
580
|
+
echo ""
|
|
581
|
+
if [ -f ".claude/.cc-discipline-claude-md-template" ]; then
|
|
582
|
+
echo -e "${YELLOW}Next steps:${NC}"
|
|
583
|
+
echo " 1. Review .claude/.cc-discipline-claude-md-template"
|
|
584
|
+
echo " Consider adding the docs/ structure and discipline sections to your CLAUDE.md"
|
|
585
|
+
echo " 2. Review rules in .claude/rules/stacks/ and adjust as needed"
|
|
586
|
+
echo " 3. Start working with Claude Code!"
|
|
587
|
+
else
|
|
588
|
+
echo -e "${YELLOW}Next steps:${NC}"
|
|
589
|
+
echo " 1. Review rules in .claude/rules/stacks/ and adjust as needed"
|
|
590
|
+
echo " 2. Start working with Claude Code!"
|
|
591
|
+
fi
|
|
592
|
+
fi
|
|
593
|
+
echo ""
|
|
594
|
+
echo -e "${YELLOW}Tip:${NC} Commit .claude/ and CLAUDE.md to git to share discipline across the team"
|