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.
Files changed (43) hide show
  1. package/README.md +236 -153
  2. package/README.zh-CN.md +299 -207
  3. package/bin/cli.sh +96 -96
  4. package/global/CLAUDE.md +45 -45
  5. package/init.sh +594 -594
  6. package/lib/doctor.sh +145 -145
  7. package/lib/stack-remove.sh +68 -68
  8. package/lib/status.sh +100 -100
  9. package/package.json +34 -34
  10. package/templates/.claude/agents/investigator.md +44 -44
  11. package/templates/.claude/agents/reviewer.md +46 -46
  12. package/templates/.claude/hooks/action-counter.sh +58 -58
  13. package/templates/.claude/hooks/git-guard.sh +62 -62
  14. package/templates/.claude/hooks/phase-gate.sh +10 -10
  15. package/templates/.claude/hooks/post-error-remind.sh +114 -114
  16. package/templates/.claude/hooks/pre-edit-guard.sh +100 -100
  17. package/templates/.claude/hooks/session-start.sh +44 -44
  18. package/templates/.claude/hooks/streak-breaker.sh +111 -111
  19. package/templates/.claude/rules/00-core-principles.md +16 -16
  20. package/templates/.claude/rules/01-debugging.md +32 -32
  21. package/templates/.claude/rules/02-before-edit.md +22 -22
  22. package/templates/.claude/rules/03-context-mgmt.md +44 -44
  23. package/templates/.claude/rules/04-no-mole-whacking.md +26 -26
  24. package/templates/.claude/rules/05-phase-discipline.md +15 -15
  25. package/templates/.claude/rules/06-multi-task.md +12 -12
  26. package/templates/.claude/rules/07-integrity.md +92 -92
  27. package/templates/.claude/rules/stacks/embedded.md +24 -24
  28. package/templates/.claude/rules/stacks/js-ts.md +21 -21
  29. package/templates/.claude/rules/stacks/mobile.md +16 -16
  30. package/templates/.claude/rules/stacks/python.md +20 -20
  31. package/templates/.claude/rules/stacks/rtl.md +24 -24
  32. package/templates/.claude/settings.json +84 -84
  33. package/templates/.claude/skills/commit/SKILL.md +40 -40
  34. package/templates/.claude/skills/evaluate/SKILL.md +57 -57
  35. package/templates/.claude/skills/investigate/SKILL.md +192 -192
  36. package/templates/.claude/skills/retro/SKILL.md +40 -40
  37. package/templates/.claude/skills/self-check/SKILL.md +112 -87
  38. package/templates/.claude/skills/summary/SKILL.md +48 -48
  39. package/templates/.claude/skills/think/SKILL.md +108 -108
  40. package/templates/CLAUDE.md +96 -96
  41. package/templates/docs/debug-log.md +48 -48
  42. package/templates/docs/progress.md +72 -72
  43. 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"