cc-discipline 2.13.6 → 2.15.1
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 +11 -8
- package/README.zh-CN.md +11 -10
- package/bin/cli.js +6 -1
- package/global/CLAUDE.md +3 -3
- package/init.sh +181 -107
- package/lib/doctor.sh +26 -16
- package/lib/hook-hashes +26 -0
- package/lib/status.sh +5 -0
- package/package.json +1 -1
- package/templates/.claude/hooks/git-guard.sh +662 -117
- package/templates/.claude/hooks/pre-edit-guard.sh +2 -1
- package/templates/.claude/hooks/session-start.sh +192 -14
- package/templates/.claude/rules/00-core-principles.md +0 -5
- package/templates/.claude/rules/03-context-mgmt.md +5 -21
- package/templates/.claude/rules/04-no-mole-whacking.md +1 -10
- package/templates/.claude/rules/06-multi-task.md +5 -6
- package/templates/.claude/rules/07-integrity.md +1 -6
- package/templates/.claude/rules/stacks/embedded.md +8 -0
- package/templates/.claude/rules/stacks/js-ts.md +7 -0
- package/templates/.claude/rules/stacks/mobile.md +7 -0
- package/templates/.claude/rules/stacks/python.md +9 -0
- package/templates/.claude/rules/stacks/rtl.md +6 -0
- package/templates/.claude/skills/commit/SKILL.md +2 -0
- package/templates/.claude/skills/coplan/SKILL.md +4 -2
- package/templates/.claude/skills/self-check/SKILL.md +10 -2
- package/templates/.claude/skills/summary/SKILL.md +2 -2
- package/templates/CLAUDE.md +1 -0
- package/templates/docs/progress.md +2 -1
- package/templates/docs/todo.md +15 -0
- package/templates/.claude/rules/02-before-edit.md +0 -11
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ Without the hook, Claude would keep editing `auth.py` indefinitely — each fix
|
|
|
65
65
|
|
|
66
66
|
---
|
|
67
67
|
|
|
68
|
-
**`pre-edit-guard.sh`** — Before a source edit, checks `docs/debug-log.md` for hypotheses still marked pending, flags unusually large diffs
|
|
68
|
+
**`pre-edit-guard.sh`** — Before a source edit, checks `docs/debug-log.md` for hypotheses still marked pending, and flags unusually large diffs. These are context notes, not blocks.
|
|
69
69
|
|
|
70
70
|
> Downgraded from a hard block on 2026-07-30. Combined with the debugging rules it had become a trap: write three hypotheses into the log as the rules ask, and you were then barred from editing source until three were confirmed — including for unrelated planned work. The hypothesis discipline stays in the rules; only the enforcement was relaxed.
|
|
71
71
|
|
|
@@ -133,7 +133,7 @@ Auto-injected markdown in `.claude/rules/` — Claude sees them when operating o
|
|
|
133
133
|
- Pre-edit checklist: understand the file, know the impact, fix root cause
|
|
134
134
|
- Mole-whacking detection: recognize the pattern, stop, report
|
|
135
135
|
- Phase discipline: stay in research/plan/implement, don't jump ahead
|
|
136
|
-
- Multi-task
|
|
136
|
+
- Multi-task discipline: work in order, report done only when it is done, stop and report on failure
|
|
137
137
|
- Tech stack rules for Python, JS/TS, embedded, RTL, mobile
|
|
138
138
|
|
|
139
139
|
### Subagents (the auditors)
|
|
@@ -163,14 +163,14 @@ The installer is interactive — pick your tech stack, name your project, done.
|
|
|
163
163
|
|
|
164
164
|
```
|
|
165
165
|
.claude/
|
|
166
|
-
├── rules/ #
|
|
166
|
+
├── rules/ # Core rules load every session; stack rules load for matching files
|
|
167
167
|
│ ├── 00-core-principles.md
|
|
168
168
|
│ ├── 01-debugging.md
|
|
169
|
-
│ ├── 02-before-edit.md
|
|
170
169
|
│ ├── 03-context-mgmt.md
|
|
171
170
|
│ ├── 04-no-mole-whacking.md
|
|
172
171
|
│ ├── 05-phase-discipline.md
|
|
173
172
|
│ ├── 06-multi-task.md
|
|
173
|
+
│ ├── 07-integrity.md
|
|
174
174
|
│ └── stacks/ # Picked during install
|
|
175
175
|
├── hooks/ # Shell scripts, exit 2 = block operation
|
|
176
176
|
│ ├── streak-breaker.sh
|
|
@@ -183,11 +183,14 @@ The installer is interactive — pick your tech stack, name your project, done.
|
|
|
183
183
|
│ └── commit/SKILL.md # /commit: test → update docs → commit
|
|
184
184
|
└── settings.json # Hook registration
|
|
185
185
|
docs/
|
|
186
|
-
├── progress.md # Claude maintains
|
|
186
|
+
├── progress.md # What happened — Claude maintains it, read after compact
|
|
187
|
+
├── todo.md # What's still open — Now / Later, edited by you and Claude
|
|
187
188
|
└── debug-log.md # Debug session tracking
|
|
188
189
|
CLAUDE.md # Your project info (you fill this in)
|
|
189
190
|
```
|
|
190
191
|
|
|
192
|
+
**Three record files, three jobs.** `progress.md` records what happened — status, milestones, decisions — and only grows. `todo.md` holds only what is still open: *Now* for the next steps, *Later* for deferred work, each with a condition for when to revisit it; an item is deleted once it's done. `debug-log.md` tracks hypotheses while debugging. At every session start and after each compaction, a hook injects progress.md's Current Status and todo.md's *Now* list, and counts the *Later* items.
|
|
193
|
+
|
|
191
194
|
## Customization
|
|
192
195
|
|
|
193
196
|
**Adjust hook strictness:**
|
|
@@ -204,8 +207,8 @@ STOP_THRESHOLD=10 # Hard block after N edits
|
|
|
204
207
|
```bash
|
|
205
208
|
cat > .claude/rules/my-rule.md << 'EOF'
|
|
206
209
|
---
|
|
207
|
-
|
|
208
|
-
|
|
210
|
+
paths:
|
|
211
|
+
- "src/api/**/*"
|
|
209
212
|
---
|
|
210
213
|
- All API changes must be backwards-compatible
|
|
211
214
|
- New endpoints need OpenAPI spec updates
|
|
@@ -226,7 +229,7 @@ See [Claude Code hooks docs](https://docs.anthropic.com/en/docs/claude-code/hook
|
|
|
226
229
|
No. The hooks are the real enforcement — they're shell scripts that physically block operations. The rules are supplementary structure.
|
|
227
230
|
|
|
228
231
|
**Does it slow things down?**
|
|
229
|
-
|
|
232
|
+
Somewhat. Measured on Windows with Git Bash, the hooks on the edit path add about 150 ms to an edit of a docs or config file and about 650 ms to an edit of a source file. Rules add about 15 KB to context (under 2% of a 200K window), and stack rules load only when Claude reads a matching file.
|
|
230
233
|
|
|
231
234
|
**Should I commit `.claude/` to git?**
|
|
232
235
|
Yes. Team members get the same guardrails. Hook paths use `$CLAUDE_PROJECT_DIR`, so they work across machines.
|
package/README.zh-CN.md
CHANGED
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
│ Layer 1: Rules(自动注入) │
|
|
26
26
|
│ core-principles — 核心原则 │
|
|
27
27
|
│ debugging — 调试纪律 │
|
|
28
|
-
│ before-edit — 修改前检查 │
|
|
29
28
|
│ context-mgmt — 上下文管理 │
|
|
30
29
|
│ no-mole-whacking — 反打地鼠 │
|
|
31
30
|
│ stacks/* — 技术栈特有规则 │
|
|
@@ -73,9 +72,11 @@ your-project/
|
|
|
73
72
|
│ ├── rules/
|
|
74
73
|
│ │ ├── 00-core-principles.md # 核心工作原则
|
|
75
74
|
│ │ ├── 01-debugging.md # 调试纪律
|
|
76
|
-
│ │ ├── 02-before-edit.md # 修改前检查
|
|
77
75
|
│ │ ├── 03-context-mgmt.md # 上下文管理
|
|
78
76
|
│ │ ├── 04-no-mole-whacking.md # 反打地鼠
|
|
77
|
+
│ │ ├── 05-phase-discipline.md # 阶段纪律
|
|
78
|
+
│ │ ├── 06-multi-task.md # 多任务纪律
|
|
79
|
+
│ │ ├── 07-integrity.md # 诚信纪律
|
|
79
80
|
│ │ └── stacks/ # 技术栈特有规则
|
|
80
81
|
│ │ ├── rtl.md # RTL / IC 设计
|
|
81
82
|
│ │ ├── embedded.md # 嵌入式 C/C++
|
|
@@ -92,12 +93,15 @@ your-project/
|
|
|
92
93
|
│ └── skills/
|
|
93
94
|
│ └── commit/SKILL.md # /commit 智能提交
|
|
94
95
|
├── docs/
|
|
95
|
-
│ ├── progress.md #
|
|
96
|
+
│ ├── progress.md # 进度记录:已经发生的事(Claude 维护)
|
|
97
|
+
│ ├── todo.md # 待办:Now / Later(你和 Claude 都可以改)
|
|
96
98
|
│ └── debug-log.md # 调试日志(Claude 维护)
|
|
97
99
|
└── ~/.claude/
|
|
98
100
|
└── CLAUDE.md # 全局通用纪律(可选)
|
|
99
101
|
```
|
|
100
102
|
|
|
103
|
+
**三个记录文件,各管一件事**:`progress.md` 记录已经发生的事(状态、里程碑、决策),只增不减;`todo.md` 只放还没做的事——*Now* 是接下来的具体步骤,*Later* 是推迟的工作,每条都写明什么时候、什么条件下再看,做完就删;`debug-log.md` 记录调试中的假设。每次开会话和每次压缩上下文之后,hook 会注入 progress.md 的 Current Status 和 todo.md 的 *Now* 列表,并报出 *Later* 的条数。
|
|
104
|
+
|
|
101
105
|
## 各层详解
|
|
102
106
|
|
|
103
107
|
### Rules(自动注入)
|
|
@@ -109,10 +113,7 @@ Claude 无法选择性忽略这些规则——它们在操作匹配文件时会
|
|
|
109
113
|
- `00-core-principles.md` — 先理解再动手、不锁定第一解释、连续3次失败必须停下
|
|
110
114
|
- `01-debugging.md` — 四阶段调试流程(收集→假设→验证→修复)
|
|
111
115
|
- `03-context-mgmt.md` — 主动检查点、调研隔离、compact 策略
|
|
112
|
-
- `04-no-mole-whacking.md` —
|
|
113
|
-
|
|
114
|
-
**源码规则**(编辑 src/ 等目录时生效):
|
|
115
|
-
- `02-before-edit.md` — 修改前的 5 项强制检查
|
|
116
|
+
- `04-no-mole-whacking.md` — 打地鼠检测
|
|
116
117
|
|
|
117
118
|
**技术栈规则**(按文件类型触发):
|
|
118
119
|
- `.v/.sv/.vhd` → RTL 规则(时序意识、CDC 检查、综合/仿真区分)
|
|
@@ -251,8 +252,8 @@ Claude: 先别急着改。测试期望 200 但拿到了 401。
|
|
|
251
252
|
# Create a new rule
|
|
252
253
|
cat > .claude/rules/my-rule.md << 'EOF'
|
|
253
254
|
---
|
|
254
|
-
|
|
255
|
-
|
|
255
|
+
paths:
|
|
256
|
+
- "src/api/**/*"
|
|
256
257
|
---
|
|
257
258
|
## API 修改规则
|
|
258
259
|
- 所有 API 变更必须向后兼容
|
|
@@ -289,7 +290,7 @@ EOF
|
|
|
289
290
|
A: CLAUDE.md 在对话开始时读取一次。Rules 是按文件路径匹配自动注入的——当 Claude 操作匹配 glob 的文件时,对应规则会自动出现在它的上下文中。Rules 更可靠,因为它们不依赖 Claude "记得去看"。
|
|
290
291
|
|
|
291
292
|
**Q: Hooks 会影响性能吗?**
|
|
292
|
-
A:
|
|
293
|
+
A: 有一些。在 Windows 的 Git Bash 下实测:编辑文档或配置文件时,每次编辑约增加 150 ms;编辑源码文件约增加 650 ms。规则约占 15 KB 上下文(不到 200K 窗口的 2%),技术栈规则只在读到对应文件时才加载。
|
|
293
294
|
|
|
294
295
|
**Q: 可以把 .claude/ 提交到 git 吗?**
|
|
295
296
|
A: 强烈建议提交。这样团队成员都能共享同一套纪律。注意 `.claude/settings.json` 中的 hooks 路径是相对路径,团队成员不需要额外配置。
|
package/bin/cli.js
CHANGED
|
@@ -144,4 +144,9 @@ const result = spawnSync(bash, [unixScript, ...scriptArgs], {
|
|
|
144
144
|
cwd: process.cwd(),
|
|
145
145
|
});
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
if (result.error) {
|
|
148
|
+
console.error(`cc-discipline: could not start bash (${result.error.code || result.error.message})`);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
// status is null when bash was killed by a signal: a failure, not a success.
|
|
152
|
+
process.exit(result.status === null ? 1 : result.status);
|
package/global/CLAUDE.md
CHANGED
|
@@ -39,7 +39,7 @@ Don't skip the first three steps and jump straight to the fourth.
|
|
|
39
39
|
|
|
40
40
|
## Context Hygiene
|
|
41
41
|
|
|
42
|
-
-
|
|
43
|
-
- Update docs/progress.md after completing each milestone.
|
|
42
|
+
- Delegate to subagents only for sizeable, independent work that would otherwise flood the conversation; do small reads, edits and checks yourself.
|
|
43
|
+
- Update docs/progress.md after completing each milestone; keep open work in docs/todo.md.
|
|
44
44
|
- Don't proactively warn about context running low or suggest compacting. The system auto-compacts at 0% — you cannot see the percentage. Keep progress.md updated instead.
|
|
45
|
-
- First thing after compact: read `docs/progress.md` and `docs/debug-log.md`.
|
|
45
|
+
- First thing after compact: read `docs/progress.md`, `docs/todo.md` and `docs/debug-log.md`.
|
package/init.sh
CHANGED
|
@@ -191,6 +191,18 @@ fi
|
|
|
191
191
|
# Parse choices into array
|
|
192
192
|
IFS=' ' read -ra STACKS <<< "$STACK_CHOICES"
|
|
193
193
|
|
|
194
|
+
# Stack rules are framework files, like the core rules, so anything other than a
|
|
195
|
+
# fresh install refreshes every stack already installed, whatever was chosen
|
|
196
|
+
# above. Without this an `upgrade` (which passes --auto, and --auto defaults the
|
|
197
|
+
# stack to 7, meaning none) or an interactive "Enter to keep current" copied no
|
|
198
|
+
# stack file at all, so changes to stack rules never reached an existing install.
|
|
199
|
+
if [ "$INSTALL_MODE" != "fresh" ]; then
|
|
200
|
+
detect_installed_stacks
|
|
201
|
+
for s in $INSTALLED_STACKS; do
|
|
202
|
+
case " ${STACKS[*]} " in *" $s "*) ;; *) STACKS+=("$s") ;; esac
|
|
203
|
+
done
|
|
204
|
+
fi
|
|
205
|
+
|
|
194
206
|
# ─── Project name ───
|
|
195
207
|
if [ -n "$ARG_NAME" ]; then
|
|
196
208
|
PROJECT_NAME="$ARG_NAME"
|
|
@@ -237,13 +249,24 @@ mkdir -p docs
|
|
|
237
249
|
echo -e "${GREEN}Installing core rules...${NC}"
|
|
238
250
|
cp "$SCRIPT_DIR/templates/.claude/rules/00-core-principles.md" .claude/rules/
|
|
239
251
|
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
252
|
cp "$SCRIPT_DIR/templates/.claude/rules/03-context-mgmt.md" .claude/rules/
|
|
242
253
|
cp "$SCRIPT_DIR/templates/.claude/rules/04-no-mole-whacking.md" .claude/rules/
|
|
243
254
|
cp "$SCRIPT_DIR/templates/.claude/rules/05-phase-discipline.md" .claude/rules/
|
|
244
255
|
cp "$SCRIPT_DIR/templates/.claude/rules/06-multi-task.md" .claude/rules/
|
|
245
256
|
cp "$SCRIPT_DIR/templates/.claude/rules/07-integrity.md" .claude/rules/
|
|
246
257
|
|
|
258
|
+
# Retired core rules. Core rules are framework files that every upgrade overwrites,
|
|
259
|
+
# so a rule dropped from templates/ has to be deleted here as well — otherwise the
|
|
260
|
+
# old copy stays in every existing install indefinitely. The pre-upgrade backup in
|
|
261
|
+
# .claude/.backup-* still holds it.
|
|
262
|
+
# 02-before-edit.md — retired 2026-09-23: every item duplicated another rule or a
|
|
263
|
+
# trained default, and it loaded unconditionally although written as a per-file check.
|
|
264
|
+
# Only in upgrade mode: in append mode the project has never had cc-discipline,
|
|
265
|
+
# so a file by that name is the user's own.
|
|
266
|
+
if [ "$INSTALL_MODE" = "upgrade" ]; then
|
|
267
|
+
rm -f .claude/rules/02-before-edit.md
|
|
268
|
+
fi
|
|
269
|
+
|
|
247
270
|
# ─── Copy stack-specific rules based on selection ───
|
|
248
271
|
if [ ${#STACKS[@]} -gt 0 ] && [ -n "${STACKS[0]}" ]; then
|
|
249
272
|
echo -e "${GREEN}Installing stack rules...${NC}"
|
|
@@ -281,15 +304,138 @@ if [ ${#STACKS[@]} -gt 0 ] && [ -n "${STACKS[0]}" ]; then
|
|
|
281
304
|
done
|
|
282
305
|
fi
|
|
283
306
|
|
|
307
|
+
# ─── Content hashing (skills and hooks) ───
|
|
308
|
+
# Two properties matter here, and both were learned the hard way.
|
|
309
|
+
#
|
|
310
|
+
# 1. Record WHICH algorithm produced a digest. The fallback below resolves
|
|
311
|
+
# differently depending on what is installed, so a manifest holding a bare
|
|
312
|
+
# digest silently mis-compares the moment tool availability changes — every
|
|
313
|
+
# hash mismatches, every retired skill looks user-modified, and the
|
|
314
|
+
# retirement pass does nothing. (fixed 2026-08-28, before 2.13.0 shipped.)
|
|
315
|
+
#
|
|
316
|
+
# 2. Hash line-ending-NORMALIZED content, not raw bytes. Projects that commit
|
|
317
|
+
# .claude/ and run with core.autocrlf=true and no .gitattributes get their
|
|
318
|
+
# SKILL.md rewritten to CRLF by git on checkout. Byte-exact comparison then
|
|
319
|
+
# reports every skill as modified, with the same two consequences as above
|
|
320
|
+
# plus a .new file dropped beside every skill on every upgrade. Measured on
|
|
321
|
+
# one install: the file differed from its manifest entry by exactly 44 bytes
|
|
322
|
+
# across 44 lines, and matched perfectly once normalized. (fixed 2026-08-28)
|
|
323
|
+
#
|
|
324
|
+
# sha256sum and `shasum -a 256` produce identical digests, so both label sha256.
|
|
325
|
+
|
|
326
|
+
_cc_digest_with() { # $1=tool $2=file $3=norm|raw -> bare digest
|
|
327
|
+
if [ "$3" = "norm" ]; then
|
|
328
|
+
case "$1" in
|
|
329
|
+
sha256sum) sed 's/\r$//' "$2" | sha256sum | cut -d' ' -f1 ;;
|
|
330
|
+
shasum) sed 's/\r$//' "$2" | shasum -a 256 | cut -d' ' -f1 ;;
|
|
331
|
+
md5sum) sed 's/\r$//' "$2" | md5sum | cut -d' ' -f1 ;;
|
|
332
|
+
md5) sed 's/\r$//' "$2" | md5 -q ;;
|
|
333
|
+
cksum) sed 's/\r$//' "$2" | cksum | cut -d' ' -f1 ;;
|
|
334
|
+
esac
|
|
335
|
+
else
|
|
336
|
+
case "$1" in
|
|
337
|
+
sha256sum) sha256sum "$2" | cut -d' ' -f1 ;;
|
|
338
|
+
shasum) shasum -a 256 "$2" | cut -d' ' -f1 ;;
|
|
339
|
+
md5sum) md5sum "$2" | cut -d' ' -f1 ;;
|
|
340
|
+
md5) md5 -q "$2" ;;
|
|
341
|
+
cksum) cksum "$2" | cut -d' ' -f1 ;;
|
|
342
|
+
esac
|
|
343
|
+
fi
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
_cc_algo() {
|
|
347
|
+
for _a in sha256sum shasum md5sum md5 cksum; do
|
|
348
|
+
command -v "$_a" >/dev/null 2>&1 && { echo "$_a"; return; }
|
|
349
|
+
done
|
|
350
|
+
echo cksum
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
_cc_label() {
|
|
354
|
+
case "$1" in sha256sum|shasum) echo sha256 ;; md5sum|md5) echo md5 ;; *) echo cksum ;; esac
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
# What gets written into the manifest: normalized, algorithm-labelled.
|
|
358
|
+
_cc_hash() {
|
|
359
|
+
_a=$(_cc_algo)
|
|
360
|
+
echo "$(_cc_label "$_a"):$(_cc_digest_with "$_a" "$1" norm)"
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
# True when manifest entry $2 still describes file $1. Accepts, in order of how
|
|
364
|
+
# the entry was most likely written:
|
|
365
|
+
# - "<algo>:<digest>" from 2.13.1+, normalized
|
|
366
|
+
# - "<algo>:<digest>" from 2.13.0, byte-exact
|
|
367
|
+
# - a bare digest from 2.12.2/2.12.3, algorithm and normalization both unknown
|
|
368
|
+
# Anything that matches under any of those readings counts as pristine. Being
|
|
369
|
+
# permissive here is the safe direction: a false "modified" freezes a skill in
|
|
370
|
+
# place forever and buries the user in .new files, while a false "pristine" can
|
|
371
|
+
# only overwrite a file that is byte-identical to what we would install anyway.
|
|
372
|
+
_cc_hash_matches() {
|
|
373
|
+
_f="$1"; _rec="$2"
|
|
374
|
+
# The manifest itself has no file extension, so .gitattributes rules keyed on
|
|
375
|
+
# *.sh/*.md/*.json never cover it and git may hand it back with CRLF. A
|
|
376
|
+
# trailing CR then rides along in the recorded digest and every comparison
|
|
377
|
+
# fails — the same bug this function exists to fix, one level up. Strip it.
|
|
378
|
+
_rec=${_rec%$'\r'}
|
|
379
|
+
[ -n "$_rec" ] || return 1
|
|
380
|
+
[ -f "$_f" ] || return 1
|
|
381
|
+
case "$_rec" in
|
|
382
|
+
*:*)
|
|
383
|
+
_rl=${_rec%%:*}; _rd=${_rec#*:}
|
|
384
|
+
case "$_rl" in
|
|
385
|
+
sha256) _cands="sha256sum shasum" ;;
|
|
386
|
+
md5) _cands="md5sum md5" ;;
|
|
387
|
+
*) _cands="cksum" ;;
|
|
388
|
+
esac
|
|
389
|
+
for _al in $_cands; do
|
|
390
|
+
command -v "$_al" >/dev/null 2>&1 || continue
|
|
391
|
+
[ "$(_cc_digest_with "$_al" "$_f" norm)" = "$_rd" ] && return 0
|
|
392
|
+
[ "$(_cc_digest_with "$_al" "$_f" raw)" = "$_rd" ] && return 0
|
|
393
|
+
done
|
|
394
|
+
return 1
|
|
395
|
+
;;
|
|
396
|
+
esac
|
|
397
|
+
for _al in sha256sum shasum md5sum md5 cksum; do
|
|
398
|
+
command -v "$_al" >/dev/null 2>&1 || continue
|
|
399
|
+
[ "$(_cc_digest_with "$_al" "$_f" norm)" = "$_rec" ] && return 0
|
|
400
|
+
[ "$(_cc_digest_with "$_al" "$_f" raw)" = "$_rec" ] && return 0
|
|
401
|
+
done
|
|
402
|
+
return 1
|
|
403
|
+
}
|
|
404
|
+
|
|
284
405
|
# ─── Install hooks ───
|
|
406
|
+
# Framework hooks are always replaced. They are enforcement code, and a
|
|
407
|
+
# customized copy left in place would keep whatever holes the new version
|
|
408
|
+
# closes: a stale git-guard keeps every bypass fixed since. But a local change
|
|
409
|
+
# must not vanish silently, as HUB_Rev1_FW's session-start did in the 2.14.0
|
|
410
|
+
# rollout. A hook counts as locally modified when it matches none of: the
|
|
411
|
+
# template being installed, the hash recorded when we last installed it, or any
|
|
412
|
+
# template version shipped up to 2.14.0 (lib/hook-hashes, for installs that
|
|
413
|
+
# predate the hooks manifest). The backup made above keeps the old copy, and
|
|
414
|
+
# the end of this script lists what was replaced.
|
|
285
415
|
echo -e "${GREEN}Installing hooks...${NC}"
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
416
|
+
HOOKS_MANIFEST=".claude/.cc-discipline-hooks.manifest"
|
|
417
|
+
KNOWN_HOOK_HASHES="$SCRIPT_DIR/lib/hook-hashes"
|
|
418
|
+
_cc_hook_pristine() { # $1=installed file $2=template $3=hook file name
|
|
419
|
+
_cc_hash_matches "$1" "$(_cc_hash "$2")" && return 0
|
|
420
|
+
_hrec=$(grep "^$3 " "$HOOKS_MANIFEST" 2>/dev/null | head -1 | cut -d' ' -f2)
|
|
421
|
+
[ -n "$_hrec" ] && _cc_hash_matches "$1" "$_hrec" && return 0
|
|
422
|
+
[ -f "$KNOWN_HOOK_HASHES" ] || return 1
|
|
423
|
+
_ha=$(_cc_algo)
|
|
424
|
+
[ "$(_cc_label "$_ha")" = sha256 ] || return 1
|
|
425
|
+
# CRs stripped first: a CRLF checkout of this list must not flag every hook
|
|
426
|
+
tr -d '\r' < "$KNOWN_HOOK_HASHES" | grep -q "^$3 sha256:$(_cc_digest_with "$_ha" "$1" norm)\$"
|
|
427
|
+
}
|
|
428
|
+
MODIFIED_HOOKS=""
|
|
429
|
+
NEW_HOOKS_MANIFEST=$(mktemp 2>/dev/null || echo ".claude/.hooks-manifest.tmp")
|
|
430
|
+
for hook in pre-edit-guard post-error-remind streak-breaker session-start phase-gate git-guard action-counter; do
|
|
431
|
+
if [ -f ".claude/hooks/$hook.sh" ] && \
|
|
432
|
+
! _cc_hook_pristine ".claude/hooks/$hook.sh" "$SCRIPT_DIR/templates/.claude/hooks/$hook.sh" "$hook.sh"; then
|
|
433
|
+
MODIFIED_HOOKS="$MODIFIED_HOOKS $hook.sh"
|
|
434
|
+
fi
|
|
435
|
+
cp "$SCRIPT_DIR/templates/.claude/hooks/$hook.sh" .claude/hooks/
|
|
436
|
+
echo "$hook.sh $(_cc_hash ".claude/hooks/$hook.sh")" >> "$NEW_HOOKS_MANIFEST"
|
|
437
|
+
done
|
|
438
|
+
mv "$NEW_HOOKS_MANIFEST" "$HOOKS_MANIFEST"
|
|
293
439
|
chmod +x .claude/hooks/*.sh
|
|
294
440
|
|
|
295
441
|
# ─── Check jq availability ───
|
|
@@ -321,9 +467,13 @@ else
|
|
|
321
467
|
TEMP_SETTINGS=$(mktemp)
|
|
322
468
|
MERGE_OK=false
|
|
323
469
|
|
|
470
|
+
# is_cc must name every hook this framework registers. It once omitted
|
|
471
|
+
# git-guard, so each jq upgrade kept the old git-guard entry and appended
|
|
472
|
+
# another; one install had accumulated eleven. With git-guard listed, the
|
|
473
|
+
# next upgrade filters every old entry out and adds exactly one back.
|
|
324
474
|
if jq -s '
|
|
325
475
|
.[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"));
|
|
476
|
+
def is_cc: .hooks | any(.command | test("pre-edit-guard|streak-breaker|post-error-remind|session-start|phase-gate|action-counter|git-guard"));
|
|
327
477
|
def merge($ev): (($e.hooks[$ev] // []) | map(select(is_cc | not))) + ($t.hooks[$ev] // []);
|
|
328
478
|
$e * {
|
|
329
479
|
hooks: (($e.hooks // {}) + {
|
|
@@ -403,104 +553,6 @@ KEPT_RETIRED=""
|
|
|
403
553
|
OLD_MANIFEST=$(mktemp 2>/dev/null || echo ".claude/.skills-manifest.old")
|
|
404
554
|
[ -f "$SKILLS_MANIFEST" ] && cp "$SKILLS_MANIFEST" "$OLD_MANIFEST"
|
|
405
555
|
|
|
406
|
-
# ─── Skill content hashing ───
|
|
407
|
-
# Two properties matter here, and both were learned the hard way.
|
|
408
|
-
#
|
|
409
|
-
# 1. Record WHICH algorithm produced a digest. The fallback below resolves
|
|
410
|
-
# differently depending on what is installed, so a manifest holding a bare
|
|
411
|
-
# digest silently mis-compares the moment tool availability changes — every
|
|
412
|
-
# hash mismatches, every retired skill looks user-modified, and the
|
|
413
|
-
# retirement pass does nothing. (fixed 2026-08-28, before 2.13.0 shipped.)
|
|
414
|
-
#
|
|
415
|
-
# 2. Hash line-ending-NORMALIZED content, not raw bytes. Projects that commit
|
|
416
|
-
# .claude/ and run with core.autocrlf=true and no .gitattributes get their
|
|
417
|
-
# SKILL.md rewritten to CRLF by git on checkout. Byte-exact comparison then
|
|
418
|
-
# reports every skill as modified, with the same two consequences as above
|
|
419
|
-
# plus a .new file dropped beside every skill on every upgrade. Measured on
|
|
420
|
-
# one install: the file differed from its manifest entry by exactly 44 bytes
|
|
421
|
-
# across 44 lines, and matched perfectly once normalized. (fixed 2026-08-28)
|
|
422
|
-
#
|
|
423
|
-
# sha256sum and `shasum -a 256` produce identical digests, so both label sha256.
|
|
424
|
-
|
|
425
|
-
_cc_digest_with() { # $1=tool $2=file $3=norm|raw -> bare digest
|
|
426
|
-
if [ "$3" = "norm" ]; then
|
|
427
|
-
case "$1" in
|
|
428
|
-
sha256sum) sed 's/\r$//' "$2" | sha256sum | cut -d' ' -f1 ;;
|
|
429
|
-
shasum) sed 's/\r$//' "$2" | shasum -a 256 | cut -d' ' -f1 ;;
|
|
430
|
-
md5sum) sed 's/\r$//' "$2" | md5sum | cut -d' ' -f1 ;;
|
|
431
|
-
md5) sed 's/\r$//' "$2" | md5 -q ;;
|
|
432
|
-
cksum) sed 's/\r$//' "$2" | cksum | cut -d' ' -f1 ;;
|
|
433
|
-
esac
|
|
434
|
-
else
|
|
435
|
-
case "$1" in
|
|
436
|
-
sha256sum) sha256sum "$2" | cut -d' ' -f1 ;;
|
|
437
|
-
shasum) shasum -a 256 "$2" | cut -d' ' -f1 ;;
|
|
438
|
-
md5sum) md5sum "$2" | cut -d' ' -f1 ;;
|
|
439
|
-
md5) md5 -q "$2" ;;
|
|
440
|
-
cksum) cksum "$2" | cut -d' ' -f1 ;;
|
|
441
|
-
esac
|
|
442
|
-
fi
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
_cc_algo() {
|
|
446
|
-
for _a in sha256sum shasum md5sum md5 cksum; do
|
|
447
|
-
command -v "$_a" >/dev/null 2>&1 && { echo "$_a"; return; }
|
|
448
|
-
done
|
|
449
|
-
echo cksum
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
_cc_label() {
|
|
453
|
-
case "$1" in sha256sum|shasum) echo sha256 ;; md5sum|md5) echo md5 ;; *) echo cksum ;; esac
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
# What gets written into the manifest: normalized, algorithm-labelled.
|
|
457
|
-
_cc_hash() {
|
|
458
|
-
_a=$(_cc_algo)
|
|
459
|
-
echo "$(_cc_label "$_a"):$(_cc_digest_with "$_a" "$1" norm)"
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
# True when manifest entry $2 still describes file $1. Accepts, in order of how
|
|
463
|
-
# the entry was most likely written:
|
|
464
|
-
# - "<algo>:<digest>" from 2.13.1+, normalized
|
|
465
|
-
# - "<algo>:<digest>" from 2.13.0, byte-exact
|
|
466
|
-
# - a bare digest from 2.12.2/2.12.3, algorithm and normalization both unknown
|
|
467
|
-
# Anything that matches under any of those readings counts as pristine. Being
|
|
468
|
-
# permissive here is the safe direction: a false "modified" freezes a skill in
|
|
469
|
-
# place forever and buries the user in .new files, while a false "pristine" can
|
|
470
|
-
# only overwrite a file that is byte-identical to what we would install anyway.
|
|
471
|
-
_cc_hash_matches() {
|
|
472
|
-
_f="$1"; _rec="$2"
|
|
473
|
-
# The manifest itself has no file extension, so .gitattributes rules keyed on
|
|
474
|
-
# *.sh/*.md/*.json never cover it and git may hand it back with CRLF. A
|
|
475
|
-
# trailing CR then rides along in the recorded digest and every comparison
|
|
476
|
-
# fails — the same bug this function exists to fix, one level up. Strip it.
|
|
477
|
-
_rec=${_rec%$'\r'}
|
|
478
|
-
[ -n "$_rec" ] || return 1
|
|
479
|
-
[ -f "$_f" ] || return 1
|
|
480
|
-
case "$_rec" in
|
|
481
|
-
*:*)
|
|
482
|
-
_rl=${_rec%%:*}; _rd=${_rec#*:}
|
|
483
|
-
case "$_rl" in
|
|
484
|
-
sha256) _cands="sha256sum shasum" ;;
|
|
485
|
-
md5) _cands="md5sum md5" ;;
|
|
486
|
-
*) _cands="cksum" ;;
|
|
487
|
-
esac
|
|
488
|
-
for _al in $_cands; do
|
|
489
|
-
command -v "$_al" >/dev/null 2>&1 || continue
|
|
490
|
-
[ "$(_cc_digest_with "$_al" "$_f" norm)" = "$_rd" ] && return 0
|
|
491
|
-
[ "$(_cc_digest_with "$_al" "$_f" raw)" = "$_rd" ] && return 0
|
|
492
|
-
done
|
|
493
|
-
return 1
|
|
494
|
-
;;
|
|
495
|
-
esac
|
|
496
|
-
for _al in sha256sum shasum md5sum md5 cksum; do
|
|
497
|
-
command -v "$_al" >/dev/null 2>&1 || continue
|
|
498
|
-
[ "$(_cc_digest_with "$_al" "$_f" norm)" = "$_rec" ] && return 0
|
|
499
|
-
[ "$(_cc_digest_with "$_al" "$_f" raw)" = "$_rec" ] && return 0
|
|
500
|
-
done
|
|
501
|
-
return 1
|
|
502
|
-
}
|
|
503
|
-
|
|
504
556
|
for skill_dir in "$SCRIPT_DIR"/templates/.claude/skills/*/; do
|
|
505
557
|
[ -d "$skill_dir" ] || continue
|
|
506
558
|
skill_name=$(basename "$skill_dir")
|
|
@@ -640,6 +692,9 @@ fi
|
|
|
640
692
|
if [ ! -f "docs/debug-log.md" ]; then
|
|
641
693
|
cp "$SCRIPT_DIR/templates/docs/debug-log.md" docs/
|
|
642
694
|
fi
|
|
695
|
+
if [ ! -f "docs/todo.md" ]; then
|
|
696
|
+
cp "$SCRIPT_DIR/templates/docs/todo.md" docs/
|
|
697
|
+
fi
|
|
643
698
|
|
|
644
699
|
# ─── Install auto memory (symlink to .claude/memory/) ───
|
|
645
700
|
echo -e "${GREEN}Installing auto memory...${NC}"
|
|
@@ -762,6 +817,23 @@ echo -e "${CYAN}║ Setup complete! ║${NC}"
|
|
|
762
817
|
echo -e "${CYAN}╚══════════════════════════════════════════════╝${NC}"
|
|
763
818
|
echo ""
|
|
764
819
|
|
|
820
|
+
# Anything the user has to act on goes here, where it cannot scroll past
|
|
821
|
+
# unseen. Rollouts that capture this output must surface these lines too.
|
|
822
|
+
if [ -n "$MODIFIED_HOOKS" ] || [ -n "$PRESERVED_SKILLS" ]; then
|
|
823
|
+
echo -e "${YELLOW}Needs your attention:${NC}"
|
|
824
|
+
if [ -n "$MODIFIED_HOOKS" ]; then
|
|
825
|
+
echo -e " ${YELLOW}Framework hooks with local changes were REPLACED:${NC}$MODIFIED_HOOKS"
|
|
826
|
+
echo " Your versions are in ${BACKUP_DIR}/hooks/"
|
|
827
|
+
echo " Framework hooks are overwritten on every upgrade. Keep project-specific"
|
|
828
|
+
echo " behaviour in a hook of your own: its own file, registered in settings.json."
|
|
829
|
+
fi
|
|
830
|
+
if [ -n "$PRESERVED_SKILLS" ]; then
|
|
831
|
+
echo -e " ${YELLOW}Skills you edited were kept; the new templates wait beside them:${NC}${PRESERVED_SKILLS}"
|
|
832
|
+
echo " Compare: diff .claude/skills/<name>/SKILL.md{,.new}"
|
|
833
|
+
fi
|
|
834
|
+
echo ""
|
|
835
|
+
fi
|
|
836
|
+
|
|
765
837
|
if [ "$INSTALL_MODE" = "fresh" ]; then
|
|
766
838
|
echo -e "Created files:"
|
|
767
839
|
echo -e " ${GREEN}CLAUDE.md${NC} ← Project rules (fill in [TODO] sections)"
|
|
@@ -771,6 +843,7 @@ if [ "$INSTALL_MODE" = "fresh" ]; then
|
|
|
771
843
|
echo -e " ${GREEN}.claude/skills/${NC} ← Skills (run 'npx cc-discipline status' to list)"
|
|
772
844
|
echo -e " ${GREEN}.claude/settings.json${NC} ← Hooks configuration"
|
|
773
845
|
echo -e " ${GREEN}docs/progress.md${NC} ← Progress log (maintained by Claude)"
|
|
846
|
+
echo -e " ${GREEN}docs/todo.md${NC} ← Open work: Now / Later"
|
|
774
847
|
echo -e " ${GREEN}docs/debug-log.md${NC} ← Debug log (maintained by Claude)"
|
|
775
848
|
echo -e " ${GREEN}.claude/memory/${NC} ← Auto memory (symlinked, lives in repo)"
|
|
776
849
|
echo ""
|
|
@@ -794,6 +867,7 @@ else
|
|
|
794
867
|
echo -e "What was ${GREEN}NOT${NC} touched:"
|
|
795
868
|
echo -e " CLAUDE.md ← Your project info is safe"
|
|
796
869
|
echo -e " docs/progress.md ← Your progress records are safe"
|
|
870
|
+
echo -e " docs/todo.md ← Your open items are safe (created only if missing)"
|
|
797
871
|
echo -e " docs/debug-log.md ← Your debug logs are safe"
|
|
798
872
|
echo -e " Your custom rules/agents ← Untouched (we only add our files)"
|
|
799
873
|
echo ""
|
package/lib/doctor.sh
CHANGED
|
@@ -32,7 +32,7 @@ fi
|
|
|
32
32
|
# 2. Core rules
|
|
33
33
|
echo ""
|
|
34
34
|
echo "Core rules:"
|
|
35
|
-
for i in 00 01
|
|
35
|
+
for i in 00 01 03 04 05 06 07; do # 02 retired 2026-09-23
|
|
36
36
|
FILE=$(ls .claude/rules/${i}-*.md 2>/dev/null | head -1)
|
|
37
37
|
if [ -n "$FILE" ]; then
|
|
38
38
|
ok "$(basename "$FILE")"
|
|
@@ -60,23 +60,18 @@ done
|
|
|
60
60
|
echo ""
|
|
61
61
|
echo "Hook registration:"
|
|
62
62
|
if [ -f ".claude/settings.json" ]; then
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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"
|
|
63
|
+
# A text search is all this needs, so it runs the same with or without jq.
|
|
64
|
+
# The old jq-less branch looked only for pre-edit-guard, so an install whose
|
|
65
|
+
# settings.json never registered git-guard (possible after a jq-less upgrade,
|
|
66
|
+
# which leaves settings.json alone) was reported healthy.
|
|
67
|
+
CONTENT=$(cat .claude/settings.json)
|
|
68
|
+
for hook in pre-edit-guard streak-breaker post-error-remind session-start phase-gate action-counter git-guard; do
|
|
69
|
+
if echo "$CONTENT" | grep -q "$hook"; then
|
|
70
|
+
ok "${hook} registered"
|
|
76
71
|
else
|
|
77
|
-
fail "
|
|
72
|
+
fail "${hook} NOT registered in settings.json"
|
|
78
73
|
fi
|
|
79
|
-
|
|
74
|
+
done
|
|
80
75
|
else
|
|
81
76
|
fail "settings.json missing"
|
|
82
77
|
fi
|
|
@@ -102,6 +97,13 @@ for skill_dir in .claude/skills/*/; do
|
|
|
102
97
|
SKILL_FOUND=$((SKILL_FOUND + 1))
|
|
103
98
|
done
|
|
104
99
|
[ "$SKILL_FOUND" -eq 0 ] && warn "No skills installed (optional)"
|
|
100
|
+
# A skill the user edited is kept on upgrade and the new template is written
|
|
101
|
+
# beside it. Nothing else reminds anyone that it is waiting.
|
|
102
|
+
PENDING=""
|
|
103
|
+
for f in .claude/skills/*/SKILL.md.new; do
|
|
104
|
+
[ -f "$f" ] && PENDING="$PENDING $(basename "$(dirname "$f")")"
|
|
105
|
+
done
|
|
106
|
+
[ -n "$PENDING" ] && warn "New skill templates waiting to be merged:$PENDING — diff .claude/skills/<name>/SKILL.md{,.new}"
|
|
105
107
|
|
|
106
108
|
# 7. jq
|
|
107
109
|
echo ""
|
|
@@ -130,6 +132,11 @@ if [ -f "docs/progress.md" ]; then
|
|
|
130
132
|
else
|
|
131
133
|
warn "No docs/progress.md"
|
|
132
134
|
fi
|
|
135
|
+
if [ -f "docs/todo.md" ]; then
|
|
136
|
+
ok "docs/todo.md"
|
|
137
|
+
else
|
|
138
|
+
warn "No docs/todo.md — run upgrade to create it"
|
|
139
|
+
fi
|
|
133
140
|
|
|
134
141
|
# Summary
|
|
135
142
|
echo ""
|
|
@@ -143,3 +150,6 @@ else
|
|
|
143
150
|
echo "Run 'npx cc-discipline upgrade' to fix missing files."
|
|
144
151
|
fi
|
|
145
152
|
echo ""
|
|
153
|
+
|
|
154
|
+
# Non-zero when there are critical issues, so scripts and CI can act on the result.
|
|
155
|
+
[ "$ISSUES" -eq 0 ] || exit 1
|
package/lib/hook-hashes
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# sha256 of every version of each framework hook ever committed to templates/,
|
|
2
|
+
# up to 2.14.0, CRs stripped before hashing. init.sh uses it to tell an older
|
|
3
|
+
# shipped hook from a locally modified one in installs that predate the hooks
|
|
4
|
+
# manifest. Frozen: installs from 2.15.0 on record what they got in
|
|
5
|
+
# .claude/.cc-discipline-hooks.manifest instead. Generated 2026-09-24.
|
|
6
|
+
action-counter.sh sha256:2c3b514017c528771c78997c69db454e2b5dcdbcb813d70f4a18392d4da02f89
|
|
7
|
+
action-counter.sh sha256:6befc0b53a4f245fa4b9cbbadc4fca4c524ea66a8d000cc7e388363a906509a2
|
|
8
|
+
action-counter.sh sha256:9a213ff10ade78193e761f4443c51cc9d8a5242525a6177f0d084d81fa256070
|
|
9
|
+
git-guard.sh sha256:11a210bebccb6c82ce7e42de4a29d8fb10507722cff1d5a2346ebfc1863a5bb0
|
|
10
|
+
git-guard.sh sha256:70fe3e335b6b142bb193912b76735386553d8187ddf2d934f1f49a7e949d424e
|
|
11
|
+
git-guard.sh sha256:c391e51a8c0c20a7278695aeee4c46ed464614dccdb1acc5ca7728221ae0c84c
|
|
12
|
+
git-guard.sh sha256:cb650c0532cd6bb6595ddff375195ad2338df422172663769dccdcbf41b3c354
|
|
13
|
+
git-guard.sh sha256:dc55636e9847cc76f31c1ced71b5b6c7ea2ba9a8380347a8fca5332e162e8e6d
|
|
14
|
+
phase-gate.sh sha256:7cbd2ec05d5ab9d1e2919c327a975a1b082ef27684e5d0effdf664f17efbedff
|
|
15
|
+
post-error-remind.sh sha256:389ab860dfb217cd24253e85d28add3961155158961beffaabb9e2e6fa725c1f
|
|
16
|
+
post-error-remind.sh sha256:83b9cbb836af45889bd06e62feebc71a44c741c0cc8b40d8dff2e6d7bf21c7a6
|
|
17
|
+
pre-edit-guard.sh sha256:07c8a3b9e2c87feff1d11dcb195175cf3d6f421968dea17981e9fc573e9caf24
|
|
18
|
+
pre-edit-guard.sh sha256:3be58e3f0a62842ac44a20581275a9bb3cc597439db2e16602bb87bcf3762fb9
|
|
19
|
+
pre-edit-guard.sh sha256:6daf162b6c9835e80960f873d0f9b514065fe726f70dda7b524dbc9cf3675f52
|
|
20
|
+
pre-edit-guard.sh sha256:ae88735efb05dab465f40a1e6bcf7b808fc8dc14d7695aad0e9f4a273d7b5fb8
|
|
21
|
+
pre-edit-guard.sh sha256:c11aaf1da9fab45501478079ed3937321d2d6213c84d374671e5bd6699d08738
|
|
22
|
+
session-start.sh sha256:5d147dae576fe2443b13410849f97bc7edf0d6c92ad26ddf1fd5b1ef32055890
|
|
23
|
+
session-start.sh sha256:60dc913a7d35f6c119ee465730e00f42deabd057e68c935f96a00511663feaaa
|
|
24
|
+
session-start.sh sha256:7cd80aa4c1873851a4c9c0797369bfa9bc1fbce12672ce830748ba8d469977d3
|
|
25
|
+
streak-breaker.sh sha256:7782280af6c40b9dfd58c99f7c7bcffc58f53e247edfab242d5b5454a56cf79a
|
|
26
|
+
streak-breaker.sh sha256:cb667aee973a72380958241e349359b07ea7711b405abdf68ab626ef5211f1f4
|
package/lib/status.sh
CHANGED
|
@@ -72,6 +72,11 @@ for skill_dir in .claude/skills/*/; do
|
|
|
72
72
|
done
|
|
73
73
|
SKILL_COUNT=$(echo "$SKILLS" | wc -w | tr -d ' ')
|
|
74
74
|
echo -e "${GREEN}${SKILL_COUNT}${NC} (${SKILLS% })"
|
|
75
|
+
PENDING=""
|
|
76
|
+
for f in .claude/skills/*/SKILL.md.new; do
|
|
77
|
+
[ -f "$f" ] && PENDING="$PENDING /$(basename "$(dirname "$f")")"
|
|
78
|
+
done
|
|
79
|
+
[ -n "$PENDING" ] && echo -e " ${YELLOW}New templates waiting to be merged:${NC}${PENDING} (see: npx cc-discipline doctor)"
|
|
75
80
|
|
|
76
81
|
# Settings
|
|
77
82
|
echo -n "Settings: "
|