cc-discipline 2.0.0
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/LICENSE +21 -0
- package/README.md +153 -0
- package/README.zh-CN.md +207 -0
- package/bin/cli.sh +96 -0
- package/global/CLAUDE.md +43 -0
- package/init.sh +486 -0
- package/lib/doctor.sh +145 -0
- package/lib/stack-remove.sh +68 -0
- package/lib/status.sh +95 -0
- package/package.json +34 -0
- package/templates/.claude/agents/investigator.md +44 -0
- package/templates/.claude/agents/reviewer.md +46 -0
- package/templates/.claude/hooks/action-counter.sh +28 -0
- package/templates/.claude/hooks/phase-gate.sh +10 -0
- package/templates/.claude/hooks/post-error-remind.sh +109 -0
- package/templates/.claude/hooks/pre-edit-guard.sh +79 -0
- package/templates/.claude/hooks/session-start.sh +43 -0
- package/templates/.claude/hooks/streak-breaker.sh +111 -0
- package/templates/.claude/rules/00-core-principles.md +12 -0
- package/templates/.claude/rules/01-debugging.md +22 -0
- package/templates/.claude/rules/02-before-edit.md +11 -0
- package/templates/.claude/rules/03-context-mgmt.md +19 -0
- package/templates/.claude/rules/04-no-mole-whacking.md +26 -0
- package/templates/.claude/rules/05-phase-discipline.md +13 -0
- package/templates/.claude/rules/06-multi-task.md +11 -0
- package/templates/.claude/rules/07-integrity.md +81 -0
- package/templates/.claude/rules/stacks/embedded.md +24 -0
- package/templates/.claude/rules/stacks/js-ts.md +21 -0
- package/templates/.claude/rules/stacks/mobile.md +16 -0
- package/templates/.claude/rules/stacks/python.md +20 -0
- package/templates/.claude/rules/stacks/rtl.md +24 -0
- package/templates/.claude/settings.json +75 -0
- package/templates/.claude/skills/commit/SKILL.md +40 -0
- package/templates/.claude/skills/evaluate/SKILL.md +57 -0
- package/templates/.claude/skills/self-check/SKILL.md +62 -0
- package/templates/CLAUDE.md +80 -0
- package/templates/docs/debug-log.md +48 -0
- package/templates/docs/progress.md +29 -0
- package/templates/memory/MEMORY.md +23 -0
package/init.sh
ADDED
|
@@ -0,0 +1,486 @@
|
|
|
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
|
+
set -e
|
|
9
|
+
|
|
10
|
+
# ─── Version ───
|
|
11
|
+
VERSION="2.0.0"
|
|
12
|
+
|
|
13
|
+
# ─── Parse CLI arguments ───
|
|
14
|
+
ARG_STACK=""
|
|
15
|
+
ARG_NAME=""
|
|
16
|
+
ARG_GLOBAL=""
|
|
17
|
+
ARG_AUTO=false
|
|
18
|
+
|
|
19
|
+
while [[ $# -gt 0 ]]; do
|
|
20
|
+
case $1 in
|
|
21
|
+
--auto)
|
|
22
|
+
ARG_AUTO=true
|
|
23
|
+
shift
|
|
24
|
+
;;
|
|
25
|
+
--stack)
|
|
26
|
+
ARG_STACK="$2"
|
|
27
|
+
shift 2
|
|
28
|
+
;;
|
|
29
|
+
--name)
|
|
30
|
+
ARG_NAME="$2"
|
|
31
|
+
shift 2
|
|
32
|
+
;;
|
|
33
|
+
--global)
|
|
34
|
+
ARG_GLOBAL="y"
|
|
35
|
+
shift
|
|
36
|
+
;;
|
|
37
|
+
--no-global)
|
|
38
|
+
ARG_GLOBAL="n"
|
|
39
|
+
shift
|
|
40
|
+
;;
|
|
41
|
+
-h|--help)
|
|
42
|
+
echo "Usage: bash init.sh [options]"
|
|
43
|
+
echo ""
|
|
44
|
+
echo "Options:"
|
|
45
|
+
echo " --auto Non-interactive with defaults (stack=7, name=dirname, no global)"
|
|
46
|
+
echo " --stack <choices> Stack selection: 1-7, space-separated (e.g., --stack \"3 4\")"
|
|
47
|
+
echo " --name <name> Project name (default: directory name)"
|
|
48
|
+
echo " --global Install global rules to ~/.claude/CLAUDE.md"
|
|
49
|
+
echo " --no-global Skip global rules install"
|
|
50
|
+
echo " -h, --help Show this help"
|
|
51
|
+
echo ""
|
|
52
|
+
echo "Stacks: 1=RTL 2=Embedded 3=Python 4=JS/TS 5=Mobile 6=Fullstack 7=General"
|
|
53
|
+
exit 0
|
|
54
|
+
;;
|
|
55
|
+
*)
|
|
56
|
+
echo "Unknown option: $1 (use --help for usage)"
|
|
57
|
+
exit 1
|
|
58
|
+
;;
|
|
59
|
+
esac
|
|
60
|
+
done
|
|
61
|
+
|
|
62
|
+
# --auto sets defaults for anything not explicitly provided
|
|
63
|
+
if [ "$ARG_AUTO" = true ]; then
|
|
64
|
+
[ -z "$ARG_STACK" ] && ARG_STACK="7"
|
|
65
|
+
[ -z "$ARG_GLOBAL" ] && ARG_GLOBAL="n"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# ─── Colors ───
|
|
69
|
+
RED='\033[0;31m'
|
|
70
|
+
GREEN='\033[0;32m'
|
|
71
|
+
YELLOW='\033[1;33m'
|
|
72
|
+
BLUE='\033[0;34m'
|
|
73
|
+
CYAN='\033[0;36m'
|
|
74
|
+
NC='\033[0m'
|
|
75
|
+
|
|
76
|
+
# Support both direct execution and npm (via CC_DISCIPLINE_PKG_DIR)
|
|
77
|
+
if [ -n "$CC_DISCIPLINE_PKG_DIR" ]; then
|
|
78
|
+
SCRIPT_DIR="$CC_DISCIPLINE_PKG_DIR"
|
|
79
|
+
else
|
|
80
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
81
|
+
fi
|
|
82
|
+
PROJECT_DIR="$(pwd)"
|
|
83
|
+
|
|
84
|
+
echo -e "${CYAN}╔══════════════════════════════════════════════╗${NC}"
|
|
85
|
+
echo -e "${CYAN}║ Claude Code Discipline Framework — Setup ║${NC}"
|
|
86
|
+
echo -e "${CYAN}╚══════════════════════════════════════════════╝${NC}"
|
|
87
|
+
echo ""
|
|
88
|
+
echo -e "Project directory: ${GREEN}${PROJECT_DIR}${NC}"
|
|
89
|
+
|
|
90
|
+
# ─── Detect install mode ───
|
|
91
|
+
INSTALL_MODE="fresh"
|
|
92
|
+
INSTALLED_VERSION=""
|
|
93
|
+
|
|
94
|
+
if [ -f ".claude/.cc-discipline-version" ]; then
|
|
95
|
+
INSTALL_MODE="upgrade"
|
|
96
|
+
INSTALLED_VERSION=$(cat ".claude/.cc-discipline-version")
|
|
97
|
+
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
|
|
98
|
+
INSTALL_MODE="upgrade"
|
|
99
|
+
INSTALLED_VERSION="<2.0.0"
|
|
100
|
+
elif [ -d ".claude" ] || [ -f "CLAUDE.md" ]; then
|
|
101
|
+
INSTALL_MODE="append"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
case "$INSTALL_MODE" in
|
|
105
|
+
fresh)
|
|
106
|
+
echo -e "Mode: ${GREEN}Fresh install${NC}"
|
|
107
|
+
;;
|
|
108
|
+
upgrade)
|
|
109
|
+
echo -e "Mode: ${YELLOW}Upgrade cc-discipline (${INSTALLED_VERSION} → ${VERSION})${NC}"
|
|
110
|
+
;;
|
|
111
|
+
append)
|
|
112
|
+
echo -e "Mode: ${YELLOW}Adding discipline to existing project${NC}"
|
|
113
|
+
echo -e "${YELLOW}Your existing files will be preserved. cc-discipline files will be added alongside them.${NC}"
|
|
114
|
+
;;
|
|
115
|
+
esac
|
|
116
|
+
echo ""
|
|
117
|
+
|
|
118
|
+
# ─── Backup (upgrade/append) ───
|
|
119
|
+
BACKUP_DIR=""
|
|
120
|
+
if [ "$INSTALL_MODE" != "fresh" ]; then
|
|
121
|
+
BACKUP_DIR=".claude/.backup-$(date +%Y%m%d-%H%M%S)"
|
|
122
|
+
mkdir -p "$BACKUP_DIR"
|
|
123
|
+
[ -f "CLAUDE.md" ] && cp "CLAUDE.md" "$BACKUP_DIR/"
|
|
124
|
+
[ -f ".claude/settings.json" ] && cp ".claude/settings.json" "$BACKUP_DIR/"
|
|
125
|
+
[ -d ".claude/hooks" ] && cp -r ".claude/hooks" "$BACKUP_DIR/"
|
|
126
|
+
[ -d ".claude/rules" ] && cp -r ".claude/rules" "$BACKUP_DIR/"
|
|
127
|
+
[ -d ".claude/agents" ] && cp -r ".claude/agents" "$BACKUP_DIR/"
|
|
128
|
+
[ -d ".claude/skills" ] && cp -r ".claude/skills" "$BACKUP_DIR/"
|
|
129
|
+
echo -e "${GREEN}Backup saved to ${BACKUP_DIR}/${NC}"
|
|
130
|
+
echo ""
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# ─── Detect installed stacks (for upgrade/append) ───
|
|
134
|
+
detect_installed_stacks() {
|
|
135
|
+
INSTALLED_STACKS=""
|
|
136
|
+
[ -f ".claude/rules/stacks/rtl.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}1 "
|
|
137
|
+
[ -f ".claude/rules/stacks/embedded.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}2 "
|
|
138
|
+
[ -f ".claude/rules/stacks/python.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}3 "
|
|
139
|
+
[ -f ".claude/rules/stacks/js-ts.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}4 "
|
|
140
|
+
[ -f ".claude/rules/stacks/mobile.md" ] && INSTALLED_STACKS="${INSTALLED_STACKS}5 "
|
|
141
|
+
return 0
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# ─── Select project type ───
|
|
145
|
+
if [ -n "$ARG_STACK" ]; then
|
|
146
|
+
STACK_CHOICES="$ARG_STACK"
|
|
147
|
+
echo -e "Stack: ${GREEN}${STACK_CHOICES}${NC} (from CLI)"
|
|
148
|
+
elif [ "$INSTALL_MODE" = "fresh" ]; then
|
|
149
|
+
echo -e "${BLUE}What is your project type? (select multiple with spaces)${NC}"
|
|
150
|
+
echo " 1) RTL / IC Design (Verilog, VHDL, SystemVerilog)"
|
|
151
|
+
echo " 2) Embedded (C/C++, bare-metal, RTOS)"
|
|
152
|
+
echo " 3) Python (backend / scripting / ML)"
|
|
153
|
+
echo " 4) JavaScript / TypeScript (Node, Web)"
|
|
154
|
+
echo " 5) Mobile (Swift, Kotlin, React Native, Flutter)"
|
|
155
|
+
echo " 6) Full-stack Web (frontend + backend)"
|
|
156
|
+
echo " 7) Other / General"
|
|
157
|
+
echo ""
|
|
158
|
+
read -p "Choose (e.g.: 1 2 or 3 4 6): " STACK_CHOICES
|
|
159
|
+
else
|
|
160
|
+
detect_installed_stacks
|
|
161
|
+
echo -e "${BLUE}Stack rules (* = already installed):${NC}"
|
|
162
|
+
for i in 1 2 3 4 5; do
|
|
163
|
+
MARKER=""
|
|
164
|
+
echo "$INSTALLED_STACKS" | grep -q "$i" && MARKER=" ${GREEN}*${NC}"
|
|
165
|
+
case $i in
|
|
166
|
+
1) echo -e " 1) RTL / IC Design${MARKER}" ;;
|
|
167
|
+
2) echo -e " 2) Embedded${MARKER}" ;;
|
|
168
|
+
3) echo -e " 3) Python${MARKER}" ;;
|
|
169
|
+
4) echo -e " 4) JavaScript / TypeScript${MARKER}" ;;
|
|
170
|
+
5) echo -e " 5) Mobile${MARKER}" ;;
|
|
171
|
+
esac
|
|
172
|
+
done
|
|
173
|
+
echo " 6) Full-stack Web (JS/TS + Python)"
|
|
174
|
+
echo " 7) Other / General"
|
|
175
|
+
echo ""
|
|
176
|
+
read -p "Add stacks (e.g.: 2 4), or press Enter to keep current: " STACK_CHOICES
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
# Parse choices into array
|
|
180
|
+
IFS=' ' read -ra STACKS <<< "$STACK_CHOICES"
|
|
181
|
+
|
|
182
|
+
# ─── Project name ───
|
|
183
|
+
if [ -n "$ARG_NAME" ]; then
|
|
184
|
+
PROJECT_NAME="$ARG_NAME"
|
|
185
|
+
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (from CLI)"
|
|
186
|
+
elif [ "$INSTALL_MODE" = "fresh" ]; then
|
|
187
|
+
DEFAULT_NAME=$(basename "$PROJECT_DIR")
|
|
188
|
+
if [ "$ARG_AUTO" = true ]; then
|
|
189
|
+
PROJECT_NAME="$DEFAULT_NAME"
|
|
190
|
+
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (auto)"
|
|
191
|
+
else
|
|
192
|
+
read -p "Project name [$DEFAULT_NAME]: " PROJECT_NAME
|
|
193
|
+
PROJECT_NAME=${PROJECT_NAME:-$DEFAULT_NAME}
|
|
194
|
+
fi
|
|
195
|
+
else
|
|
196
|
+
# Try to extract from existing CLAUDE.md: "# MyProject — CLAUDE.md"
|
|
197
|
+
PROJECT_NAME=""
|
|
198
|
+
if [ -f "CLAUDE.md" ]; then
|
|
199
|
+
PROJECT_NAME=$(head -1 CLAUDE.md | sed 's/^# //;s/ — CLAUDE.md$//' 2>/dev/null)
|
|
200
|
+
fi
|
|
201
|
+
if [ -z "$PROJECT_NAME" ] || [ "$PROJECT_NAME" = "[PROJECT_NAME]" ]; then
|
|
202
|
+
DEFAULT_NAME=$(basename "$PROJECT_DIR")
|
|
203
|
+
if [ "$ARG_AUTO" = true ]; then
|
|
204
|
+
PROJECT_NAME="$DEFAULT_NAME"
|
|
205
|
+
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (auto)"
|
|
206
|
+
else
|
|
207
|
+
read -p "Project name [$DEFAULT_NAME]: " PROJECT_NAME
|
|
208
|
+
PROJECT_NAME=${PROJECT_NAME:-$DEFAULT_NAME}
|
|
209
|
+
fi
|
|
210
|
+
else
|
|
211
|
+
echo -e "Project name: ${GREEN}${PROJECT_NAME}${NC} (from CLAUDE.md)"
|
|
212
|
+
fi
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
# ─── Create directory structure ───
|
|
216
|
+
echo ""
|
|
217
|
+
echo -e "${GREEN}Creating directory structure...${NC}"
|
|
218
|
+
mkdir -p .claude/rules/stacks
|
|
219
|
+
mkdir -p .claude/hooks
|
|
220
|
+
mkdir -p .claude/agents
|
|
221
|
+
mkdir -p .claude/skills
|
|
222
|
+
mkdir -p docs
|
|
223
|
+
|
|
224
|
+
# ─── Copy core rules (always applied, always overwrite — these are framework files) ───
|
|
225
|
+
echo -e "${GREEN}Installing core rules...${NC}"
|
|
226
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/00-core-principles.md" .claude/rules/
|
|
227
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/01-debugging.md" .claude/rules/
|
|
228
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/02-before-edit.md" .claude/rules/
|
|
229
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/03-context-mgmt.md" .claude/rules/
|
|
230
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/04-no-mole-whacking.md" .claude/rules/
|
|
231
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/05-phase-discipline.md" .claude/rules/
|
|
232
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/06-multi-task.md" .claude/rules/
|
|
233
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/07-integrity.md" .claude/rules/
|
|
234
|
+
|
|
235
|
+
# ─── Copy stack-specific rules based on selection ───
|
|
236
|
+
if [ ${#STACKS[@]} -gt 0 ] && [ -n "${STACKS[0]}" ]; then
|
|
237
|
+
echo -e "${GREEN}Installing stack rules...${NC}"
|
|
238
|
+
for choice in "${STACKS[@]}"; do
|
|
239
|
+
case $choice in
|
|
240
|
+
1)
|
|
241
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/rtl.md" .claude/rules/stacks/
|
|
242
|
+
echo " ✓ RTL / IC Design rules"
|
|
243
|
+
;;
|
|
244
|
+
2)
|
|
245
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/embedded.md" .claude/rules/stacks/
|
|
246
|
+
echo " ✓ Embedded development rules"
|
|
247
|
+
;;
|
|
248
|
+
3)
|
|
249
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/python.md" .claude/rules/stacks/
|
|
250
|
+
echo " ✓ Python rules"
|
|
251
|
+
;;
|
|
252
|
+
4)
|
|
253
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/js-ts.md" .claude/rules/stacks/
|
|
254
|
+
echo " ✓ JavaScript / TypeScript rules"
|
|
255
|
+
;;
|
|
256
|
+
5)
|
|
257
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/mobile.md" .claude/rules/stacks/
|
|
258
|
+
echo " ✓ Mobile development rules"
|
|
259
|
+
;;
|
|
260
|
+
6)
|
|
261
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/js-ts.md" .claude/rules/stacks/
|
|
262
|
+
cp "$SCRIPT_DIR/templates/.claude/rules/stacks/python.md" .claude/rules/stacks/
|
|
263
|
+
echo " ✓ Full-stack rules (JS/TS + Python)"
|
|
264
|
+
;;
|
|
265
|
+
7)
|
|
266
|
+
echo " ✓ General rules (no additional stack rules)"
|
|
267
|
+
;;
|
|
268
|
+
esac
|
|
269
|
+
done
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
# ─── Install hooks ───
|
|
273
|
+
echo -e "${GREEN}Installing hooks...${NC}"
|
|
274
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/pre-edit-guard.sh" .claude/hooks/
|
|
275
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/post-error-remind.sh" .claude/hooks/
|
|
276
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/streak-breaker.sh" .claude/hooks/
|
|
277
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/session-start.sh" .claude/hooks/
|
|
278
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/phase-gate.sh" .claude/hooks/
|
|
279
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/action-counter.sh" .claude/hooks/
|
|
280
|
+
chmod +x .claude/hooks/*.sh
|
|
281
|
+
|
|
282
|
+
# ─── Check jq availability ───
|
|
283
|
+
HAS_JQ=false
|
|
284
|
+
if command -v jq &>/dev/null; then
|
|
285
|
+
HAS_JQ=true
|
|
286
|
+
else
|
|
287
|
+
echo ""
|
|
288
|
+
echo -e "${YELLOW}Warning: jq not found — Hooks will use grep/sed fallback, but jq is recommended${NC}"
|
|
289
|
+
echo " macOS: brew install jq"
|
|
290
|
+
echo " Ubuntu: sudo apt install jq"
|
|
291
|
+
echo " Arch: sudo pacman -S jq"
|
|
292
|
+
echo ""
|
|
293
|
+
fi
|
|
294
|
+
|
|
295
|
+
# ─── Install/merge settings.json ───
|
|
296
|
+
SETTINGS_TEMPLATE="$SCRIPT_DIR/templates/.claude/settings.json"
|
|
297
|
+
|
|
298
|
+
if [ ! -f ".claude/settings.json" ]; then
|
|
299
|
+
# No existing settings.json — just copy template
|
|
300
|
+
cp "$SETTINGS_TEMPLATE" .claude/settings.json
|
|
301
|
+
echo -e "${GREEN} ✓ settings.json created${NC}"
|
|
302
|
+
elif [ "$INSTALL_MODE" = "fresh" ]; then
|
|
303
|
+
# Fresh mode shouldn't reach here, but just in case
|
|
304
|
+
cp "$SETTINGS_TEMPLATE" .claude/settings.json
|
|
305
|
+
else
|
|
306
|
+
# Merge: preserve user hooks, add/update cc-discipline hooks
|
|
307
|
+
if [ "$HAS_JQ" = true ]; then
|
|
308
|
+
TEMP_SETTINGS=$(mktemp)
|
|
309
|
+
MERGE_OK=false
|
|
310
|
+
|
|
311
|
+
if jq -s '
|
|
312
|
+
.[0] as $e | .[1] as $t |
|
|
313
|
+
def is_cc: .hooks | any(.command | test("pre-edit-guard|streak-breaker|post-error-remind|session-start|phase-gate|action-counter"));
|
|
314
|
+
def merge($ev): (($e.hooks[$ev] // []) | map(select(is_cc | not))) + ($t.hooks[$ev] // []);
|
|
315
|
+
$e * {
|
|
316
|
+
hooks: (($e.hooks // {}) + {
|
|
317
|
+
SessionStart: merge("SessionStart"),
|
|
318
|
+
PreToolUse: merge("PreToolUse"),
|
|
319
|
+
PostToolUse: merge("PostToolUse"),
|
|
320
|
+
PostToolUseFailure: merge("PostToolUseFailure")
|
|
321
|
+
} | with_entries(select(.value | length > 0)))
|
|
322
|
+
}
|
|
323
|
+
' .claude/settings.json "$SETTINGS_TEMPLATE" > "$TEMP_SETTINGS" 2>/dev/null; then
|
|
324
|
+
# Verify the output is valid JSON
|
|
325
|
+
if jq empty "$TEMP_SETTINGS" 2>/dev/null; then
|
|
326
|
+
mv "$TEMP_SETTINGS" .claude/settings.json
|
|
327
|
+
MERGE_OK=true
|
|
328
|
+
echo -e "${GREEN} ✓ settings.json merged (your existing hooks preserved)${NC}"
|
|
329
|
+
fi
|
|
330
|
+
fi
|
|
331
|
+
|
|
332
|
+
if [ "$MERGE_OK" = false ]; then
|
|
333
|
+
rm -f "$TEMP_SETTINGS"
|
|
334
|
+
echo -e "${YELLOW} Warning: settings.json merge failed. Your file was NOT modified.${NC}"
|
|
335
|
+
echo -e "${YELLOW} Backed up to: ${BACKUP_DIR}/settings.json${NC}"
|
|
336
|
+
cp "$SETTINGS_TEMPLATE" .claude/.cc-discipline-settings-template.json
|
|
337
|
+
echo -e "${YELLOW} See .claude/.cc-discipline-settings-template.json for hooks to add manually.${NC}"
|
|
338
|
+
fi
|
|
339
|
+
else
|
|
340
|
+
# No jq — don't touch existing settings.json
|
|
341
|
+
echo -e "${YELLOW} settings.json: cannot merge without jq. Your file was NOT modified.${NC}"
|
|
342
|
+
echo -e "${YELLOW} Backed up to: ${BACKUP_DIR}/settings.json${NC}"
|
|
343
|
+
cp "$SETTINGS_TEMPLATE" .claude/.cc-discipline-settings-template.json
|
|
344
|
+
echo -e "${YELLOW} See .claude/.cc-discipline-settings-template.json for hooks to add manually.${NC}"
|
|
345
|
+
fi
|
|
346
|
+
fi
|
|
347
|
+
|
|
348
|
+
# ─── Install subagents ───
|
|
349
|
+
echo -e "${GREEN}Installing subagents...${NC}"
|
|
350
|
+
cp "$SCRIPT_DIR/templates/.claude/agents/reviewer.md" .claude/agents/
|
|
351
|
+
cp "$SCRIPT_DIR/templates/.claude/agents/investigator.md" .claude/agents/
|
|
352
|
+
|
|
353
|
+
# ─── Install skills ───
|
|
354
|
+
echo -e "${GREEN}Installing skills...${NC}"
|
|
355
|
+
cp -r "$SCRIPT_DIR/templates/.claude/skills/commit" .claude/skills/
|
|
356
|
+
cp -r "$SCRIPT_DIR/templates/.claude/skills/self-check" .claude/skills/
|
|
357
|
+
cp -r "$SCRIPT_DIR/templates/.claude/skills/evaluate" .claude/skills/
|
|
358
|
+
echo " ✓ /commit — smart commit (test → update memory → commit)"
|
|
359
|
+
echo " ✓ /self-check — periodic discipline check (use with /loop 10m /self-check)"
|
|
360
|
+
echo " ✓ /evaluate — evaluate external review/advice against codebase context"
|
|
361
|
+
|
|
362
|
+
# ─── Handle CLAUDE.md ───
|
|
363
|
+
if [ ! -f "CLAUDE.md" ]; then
|
|
364
|
+
# No CLAUDE.md exists — generate from template
|
|
365
|
+
echo -e "${GREEN}Generating CLAUDE.md...${NC}"
|
|
366
|
+
sed "s/\[PROJECT_NAME\]/$PROJECT_NAME/g" "$SCRIPT_DIR/templates/CLAUDE.md" > CLAUDE.md
|
|
367
|
+
else
|
|
368
|
+
if [ "$INSTALL_MODE" = "fresh" ]; then
|
|
369
|
+
# Should not happen (fresh mode means no existing files), but handle gracefully
|
|
370
|
+
sed "s/\[PROJECT_NAME\]/$PROJECT_NAME/g" "$SCRIPT_DIR/templates/CLAUDE.md" > CLAUDE.md
|
|
371
|
+
else
|
|
372
|
+
# Existing CLAUDE.md — NEVER overwrite
|
|
373
|
+
echo -e "${YELLOW} CLAUDE.md already exists — NOT modified (your content is safe)${NC}"
|
|
374
|
+
sed "s/\[PROJECT_NAME\]/$PROJECT_NAME/g" "$SCRIPT_DIR/templates/CLAUDE.md" \
|
|
375
|
+
> .claude/.cc-discipline-claude-md-template
|
|
376
|
+
echo " Discipline template saved to .claude/.cc-discipline-claude-md-template"
|
|
377
|
+
echo " You can reference it to add discipline sections to your CLAUDE.md."
|
|
378
|
+
fi
|
|
379
|
+
fi
|
|
380
|
+
|
|
381
|
+
# ─── Copy docs templates (only if not exist) ───
|
|
382
|
+
if [ ! -f "docs/progress.md" ]; then
|
|
383
|
+
cp "$SCRIPT_DIR/templates/docs/progress.md" docs/
|
|
384
|
+
fi
|
|
385
|
+
if [ ! -f "docs/debug-log.md" ]; then
|
|
386
|
+
cp "$SCRIPT_DIR/templates/docs/debug-log.md" docs/
|
|
387
|
+
fi
|
|
388
|
+
|
|
389
|
+
# ─── Install auto memory ───
|
|
390
|
+
echo -e "${GREEN}Installing auto memory...${NC}"
|
|
391
|
+
MEMORY_PROJECT_KEY=$(echo "$PROJECT_DIR" | sed 's|/|-|g')
|
|
392
|
+
MEMORY_DIR="$HOME/.claude/projects/${MEMORY_PROJECT_KEY}/memory"
|
|
393
|
+
mkdir -p "$MEMORY_DIR"
|
|
394
|
+
if [ ! -f "$MEMORY_DIR/MEMORY.md" ]; then
|
|
395
|
+
cp "$SCRIPT_DIR/templates/memory/MEMORY.md" "$MEMORY_DIR/MEMORY.md"
|
|
396
|
+
echo " ✓ Memory installed to $MEMORY_DIR/MEMORY.md"
|
|
397
|
+
else
|
|
398
|
+
echo -e " ${YELLOW}MEMORY.md already exists, skipping (no overwrite)${NC}"
|
|
399
|
+
fi
|
|
400
|
+
|
|
401
|
+
# ─── Install global rules (optional) ───
|
|
402
|
+
if [ -n "$ARG_GLOBAL" ]; then
|
|
403
|
+
REPLY="$ARG_GLOBAL"
|
|
404
|
+
else
|
|
405
|
+
echo ""
|
|
406
|
+
echo -e "${BLUE}Install global rules to ~/.claude/CLAUDE.md?${NC}"
|
|
407
|
+
echo " (Global rules apply to all projects, only needs to be installed once)"
|
|
408
|
+
read -p "Install global rules? (y/N) " -n 1 -r
|
|
409
|
+
echo
|
|
410
|
+
fi
|
|
411
|
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
412
|
+
mkdir -p ~/.claude
|
|
413
|
+
if [ -f ~/.claude/CLAUDE.md ]; then
|
|
414
|
+
echo -e "${YELLOW} Existing ~/.claude/CLAUDE.md found, backing up to ~/.claude/CLAUDE.md.bak${NC}"
|
|
415
|
+
cp ~/.claude/CLAUDE.md ~/.claude/CLAUDE.md.bak
|
|
416
|
+
fi
|
|
417
|
+
cp "$SCRIPT_DIR/global/CLAUDE.md" ~/.claude/CLAUDE.md
|
|
418
|
+
echo -e "${GREEN} ✓ Global rules installed${NC}"
|
|
419
|
+
fi
|
|
420
|
+
|
|
421
|
+
# ─── Write version marker ───
|
|
422
|
+
echo "$VERSION" > .claude/.cc-discipline-version
|
|
423
|
+
|
|
424
|
+
# ─── Summary ───
|
|
425
|
+
echo ""
|
|
426
|
+
echo -e "${CYAN}╔══════════════════════════════════════════════╗${NC}"
|
|
427
|
+
echo -e "${CYAN}║ Setup complete! ║${NC}"
|
|
428
|
+
echo -e "${CYAN}╚══════════════════════════════════════════════╝${NC}"
|
|
429
|
+
echo ""
|
|
430
|
+
|
|
431
|
+
if [ "$INSTALL_MODE" = "fresh" ]; then
|
|
432
|
+
echo -e "Created files:"
|
|
433
|
+
echo -e " ${GREEN}CLAUDE.md${NC} ← Project rules (fill in [TODO] sections)"
|
|
434
|
+
echo -e " ${GREEN}.claude/rules/${NC} ← Auto-injected rules"
|
|
435
|
+
echo -e " ${GREEN}.claude/hooks/${NC} ← 6 discipline hooks (edit guard, streak breaker, phase gate, action counter, error remind, session start)"
|
|
436
|
+
echo -e " ${GREEN}.claude/agents/${NC} ← Reviewer & investigator subagents"
|
|
437
|
+
echo -e " ${GREEN}.claude/skills/commit/${NC} ← /commit smart commit"
|
|
438
|
+
echo -e " ${GREEN}.claude/skills/self-check/${NC} ← /self-check periodic discipline check"
|
|
439
|
+
echo -e " ${GREEN}.claude/skills/evaluate/${NC} ← /evaluate assess external review advice"
|
|
440
|
+
echo -e " ${GREEN}.claude/settings.json${NC} ← Hooks configuration"
|
|
441
|
+
echo -e " ${GREEN}docs/progress.md${NC} ← Progress log (maintained by Claude)"
|
|
442
|
+
echo -e " ${GREEN}docs/debug-log.md${NC} ← Debug log (maintained by Claude)"
|
|
443
|
+
echo -e " ${GREEN}~/.claude/projects/.../memory/${NC} ← Auto memory (cross-session)"
|
|
444
|
+
echo ""
|
|
445
|
+
echo -e "${YELLOW}Next steps:${NC}"
|
|
446
|
+
echo " 1. Edit CLAUDE.md and fill in the [TODO] sections with project info"
|
|
447
|
+
echo " 2. Review rules in .claude/rules/stacks/ and adjust as needed"
|
|
448
|
+
echo " 3. For complex tasks, use: /loop 10m /self-check"
|
|
449
|
+
echo " 4. Start working with Claude Code!"
|
|
450
|
+
else
|
|
451
|
+
echo -e "What was done:"
|
|
452
|
+
echo -e " ${GREEN}.claude/rules/${NC} ← Discipline rules installed/updated"
|
|
453
|
+
echo -e " ${GREEN}.claude/hooks/${NC} ← Hook scripts installed/updated"
|
|
454
|
+
echo -e " ${GREEN}.claude/agents/${NC} ← Subagents installed/updated"
|
|
455
|
+
echo -e " ${GREEN}.claude/skills/commit/${NC} ← /commit skill installed/updated"
|
|
456
|
+
echo -e " ${GREEN}.claude/skills/self-check/${NC} ← /self-check discipline check installed"
|
|
457
|
+
echo -e " ${GREEN}.claude/skills/evaluate/${NC} ← /evaluate external review assessment"
|
|
458
|
+
if [ ! -f "$BACKUP_DIR/settings.json" ] || [ -f ".claude/.cc-discipline-settings-template.json" ]; then
|
|
459
|
+
echo -e " ${YELLOW}.claude/settings.json${NC} ← See notes above"
|
|
460
|
+
else
|
|
461
|
+
echo -e " ${GREEN}.claude/settings.json${NC} ← Hooks merged"
|
|
462
|
+
fi
|
|
463
|
+
echo ""
|
|
464
|
+
echo -e "What was ${GREEN}NOT${NC} touched:"
|
|
465
|
+
echo -e " CLAUDE.md ← Your project info is safe"
|
|
466
|
+
echo -e " docs/progress.md ← Your progress records are safe"
|
|
467
|
+
echo -e " docs/debug-log.md ← Your debug logs are safe"
|
|
468
|
+
echo -e " Your custom rules/agents ← Untouched (we only add our files)"
|
|
469
|
+
echo ""
|
|
470
|
+
echo -e "${YELLOW}Backup:${NC} ${BACKUP_DIR}/"
|
|
471
|
+
echo " Consider adding .claude/.backup-* to .gitignore"
|
|
472
|
+
echo ""
|
|
473
|
+
if [ -f ".claude/.cc-discipline-claude-md-template" ]; then
|
|
474
|
+
echo -e "${YELLOW}Next steps:${NC}"
|
|
475
|
+
echo " 1. Review .claude/.cc-discipline-claude-md-template"
|
|
476
|
+
echo " Consider adding the docs/ structure and discipline sections to your CLAUDE.md"
|
|
477
|
+
echo " 2. Review rules in .claude/rules/stacks/ and adjust as needed"
|
|
478
|
+
echo " 3. Start working with Claude Code!"
|
|
479
|
+
else
|
|
480
|
+
echo -e "${YELLOW}Next steps:${NC}"
|
|
481
|
+
echo " 1. Review rules in .claude/rules/stacks/ and adjust as needed"
|
|
482
|
+
echo " 2. Start working with Claude Code!"
|
|
483
|
+
fi
|
|
484
|
+
fi
|
|
485
|
+
echo ""
|
|
486
|
+
echo -e "${YELLOW}Tip:${NC} Commit .claude/ and CLAUDE.md to git to share discipline across the team"
|
package/lib/doctor.sh
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# cc-discipline doctor — diagnose installation issues
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
GREEN='\033[0;32m'
|
|
6
|
+
YELLOW='\033[1;33m'
|
|
7
|
+
RED='\033[0;31m'
|
|
8
|
+
NC='\033[0m'
|
|
9
|
+
|
|
10
|
+
ISSUES=0
|
|
11
|
+
WARNINGS=0
|
|
12
|
+
|
|
13
|
+
ok() { echo -e " ${GREEN}✓${NC} $1"; }
|
|
14
|
+
warn() { echo -e " ${YELLOW}!${NC} $1"; WARNINGS=$((WARNINGS + 1)); }
|
|
15
|
+
fail() { echo -e " ${RED}✗${NC} $1"; ISSUES=$((ISSUES + 1)); }
|
|
16
|
+
|
|
17
|
+
echo "cc-discipline doctor"
|
|
18
|
+
echo "──────────────────────"
|
|
19
|
+
echo ""
|
|
20
|
+
|
|
21
|
+
# 1. Version file
|
|
22
|
+
echo "Installation:"
|
|
23
|
+
if [ -f ".claude/.cc-discipline-version" ]; then
|
|
24
|
+
ok "Version file: $(cat .claude/.cc-discipline-version)"
|
|
25
|
+
else
|
|
26
|
+
fail "Not installed (no .claude/.cc-discipline-version)"
|
|
27
|
+
echo ""
|
|
28
|
+
echo "Run 'npx cc-discipline init' to install."
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# 2. Core rules
|
|
33
|
+
echo ""
|
|
34
|
+
echo "Core rules:"
|
|
35
|
+
for i in 00 01 02 03 04 05 06 07; do
|
|
36
|
+
FILE=$(ls .claude/rules/${i}-*.md 2>/dev/null | head -1)
|
|
37
|
+
if [ -n "$FILE" ]; then
|
|
38
|
+
ok "$(basename "$FILE")"
|
|
39
|
+
else
|
|
40
|
+
fail "Missing rule ${i}-*.md"
|
|
41
|
+
fi
|
|
42
|
+
done
|
|
43
|
+
|
|
44
|
+
# 3. Hooks
|
|
45
|
+
echo ""
|
|
46
|
+
echo "Hooks:"
|
|
47
|
+
for hook in pre-edit-guard streak-breaker post-error-remind session-start phase-gate action-counter; do
|
|
48
|
+
if [ -f ".claude/hooks/${hook}.sh" ]; then
|
|
49
|
+
if [ -x ".claude/hooks/${hook}.sh" ]; then
|
|
50
|
+
ok "${hook}.sh"
|
|
51
|
+
else
|
|
52
|
+
warn "${hook}.sh exists but not executable"
|
|
53
|
+
fi
|
|
54
|
+
else
|
|
55
|
+
fail "Missing ${hook}.sh"
|
|
56
|
+
fi
|
|
57
|
+
done
|
|
58
|
+
|
|
59
|
+
# 4. settings.json hook registration
|
|
60
|
+
echo ""
|
|
61
|
+
echo "Hook registration:"
|
|
62
|
+
if [ -f ".claude/settings.json" ]; then
|
|
63
|
+
if command -v jq &>/dev/null; then
|
|
64
|
+
CONTENT=$(cat .claude/settings.json)
|
|
65
|
+
for hook in pre-edit-guard streak-breaker post-error-remind session-start phase-gate action-counter; do
|
|
66
|
+
if echo "$CONTENT" | grep -q "$hook"; then
|
|
67
|
+
ok "${hook} registered"
|
|
68
|
+
else
|
|
69
|
+
fail "${hook} NOT registered in settings.json"
|
|
70
|
+
fi
|
|
71
|
+
done
|
|
72
|
+
else
|
|
73
|
+
warn "jq not installed — cannot verify hook registration details"
|
|
74
|
+
if grep -q "pre-edit-guard" .claude/settings.json 2>/dev/null; then
|
|
75
|
+
ok "settings.json contains hook references"
|
|
76
|
+
else
|
|
77
|
+
fail "settings.json doesn't reference any hooks"
|
|
78
|
+
fi
|
|
79
|
+
fi
|
|
80
|
+
else
|
|
81
|
+
fail "settings.json missing"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# 5. Agents
|
|
85
|
+
echo ""
|
|
86
|
+
echo "Agents:"
|
|
87
|
+
for agent in reviewer investigator; do
|
|
88
|
+
if [ -f ".claude/agents/${agent}.md" ]; then
|
|
89
|
+
ok "${agent}.md"
|
|
90
|
+
else
|
|
91
|
+
warn "Missing ${agent}.md (optional)"
|
|
92
|
+
fi
|
|
93
|
+
done
|
|
94
|
+
|
|
95
|
+
# 6. Skills
|
|
96
|
+
echo ""
|
|
97
|
+
echo "Skills:"
|
|
98
|
+
for skill in commit self-check evaluate; do
|
|
99
|
+
if [ -d ".claude/skills/${skill}" ]; then
|
|
100
|
+
ok "/${skill}"
|
|
101
|
+
else
|
|
102
|
+
warn "Missing /${skill} skill (optional)"
|
|
103
|
+
fi
|
|
104
|
+
done
|
|
105
|
+
|
|
106
|
+
# 7. jq
|
|
107
|
+
echo ""
|
|
108
|
+
echo "Dependencies:"
|
|
109
|
+
if command -v jq &>/dev/null; then
|
|
110
|
+
ok "jq installed ($(jq --version 2>&1))"
|
|
111
|
+
else
|
|
112
|
+
warn "jq not installed — hooks use grep/sed fallback, recommend: brew install jq"
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# 8. CLAUDE.md
|
|
116
|
+
echo ""
|
|
117
|
+
echo "Project files:"
|
|
118
|
+
if [ -f "CLAUDE.md" ]; then
|
|
119
|
+
if grep -q "\[TODO\]" CLAUDE.md 2>/dev/null; then
|
|
120
|
+
warn "CLAUDE.md has unfilled [TODO] sections"
|
|
121
|
+
else
|
|
122
|
+
ok "CLAUDE.md"
|
|
123
|
+
fi
|
|
124
|
+
else
|
|
125
|
+
warn "No CLAUDE.md found"
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
if [ -f "docs/progress.md" ]; then
|
|
129
|
+
ok "docs/progress.md"
|
|
130
|
+
else
|
|
131
|
+
warn "No docs/progress.md"
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# Summary
|
|
135
|
+
echo ""
|
|
136
|
+
echo "──────────────────────"
|
|
137
|
+
if [ "$ISSUES" -eq 0 ] && [ "$WARNINGS" -eq 0 ]; then
|
|
138
|
+
echo -e "${GREEN}All checks passed!${NC}"
|
|
139
|
+
elif [ "$ISSUES" -eq 0 ]; then
|
|
140
|
+
echo -e "${YELLOW}${WARNINGS} warning(s), no critical issues${NC}"
|
|
141
|
+
else
|
|
142
|
+
echo -e "${RED}${ISSUES} issue(s), ${WARNINGS} warning(s)${NC}"
|
|
143
|
+
echo "Run 'npx cc-discipline upgrade' to fix missing files."
|
|
144
|
+
fi
|
|
145
|
+
echo ""
|