start-vibing 2.0.44 → 2.0.45
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/package.json
CHANGED
|
@@ -13,6 +13,7 @@ The stop hook validates `/CLAUDE.md` before allowing task completion:
|
|
|
13
13
|
| Character limit | Max 40,000 chars |
|
|
14
14
|
| Required sections | Last Change, 30s Overview, Stack, Architecture |
|
|
15
15
|
| Last Change | Must be updated with session info (branch, date, summary) |
|
|
16
|
+
| Content depth | Relevant rule/flow sections must also be updated |
|
|
16
17
|
| No stacking | Only ONE Last Change section (latest only) |
|
|
17
18
|
| Branch | Must be on main (PR merged) |
|
|
18
19
|
| Git tree | Must be clean (no uncommitted changes) |
|
|
@@ -21,6 +22,25 @@ The stop hook validates `/CLAUDE.md` before allowing task completion:
|
|
|
21
22
|
|
|
22
23
|
**If not on main:** Complete PR workflow (commit, push, PR, merge, checkout main).
|
|
23
24
|
|
|
25
|
+
### Content Depth Rule (CLAUDE_MD_SHALLOW_UPDATE)
|
|
26
|
+
|
|
27
|
+
> **"Last Change" = WHAT was done. Other sections = HOW things work NOW. Both MUST be current.**
|
|
28
|
+
|
|
29
|
+
The stop-validator categorizes changed files and maps them to CLAUDE.md sections:
|
|
30
|
+
|
|
31
|
+
| Changed Files | Must Also Update |
|
|
32
|
+
|---------------|-----------------|
|
|
33
|
+
| API/CRUD routes | Critical Rules, HTTP Requests |
|
|
34
|
+
| UI components | UI Architecture, Component Organization |
|
|
35
|
+
| Pages/layouts | Architecture, Next.js App Router Patterns |
|
|
36
|
+
| Styling/aesthetics | UI Architecture, Design System |
|
|
37
|
+
| Auth/middleware | Critical Rules, Workflow |
|
|
38
|
+
| Database/models | Architecture, Critical Rules |
|
|
39
|
+
| Config files | Stack, Configuration |
|
|
40
|
+
| Hooks/scripts | Workflow, Stop Hook Validations |
|
|
41
|
+
|
|
42
|
+
If ONLY "Last Change" was modified but categorized source files changed, `CLAUDE_MD_SHALLOW_UPDATE` blocks completion.
|
|
43
|
+
|
|
24
44
|
---
|
|
25
45
|
|
|
26
46
|
## System Architecture
|
|
@@ -213,45 +233,139 @@ All implementations MUST:
|
|
|
213
233
|
|
|
214
234
|
---
|
|
215
235
|
|
|
216
|
-
##
|
|
236
|
+
## Claude 4.6 Best Practices
|
|
237
|
+
|
|
238
|
+
> **Source:** [Anthropic Claude 4 Best Practices](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-4-best-practices)
|
|
239
|
+
|
|
240
|
+
### Model Selection
|
|
241
|
+
|
|
242
|
+
| Model | API ID | Cost (In/Out) | Best For |
|
|
243
|
+
|-------|--------|---------------|----------|
|
|
244
|
+
| **Opus 4.6** | `claude-opus-4-6` | $5/$25 MTok | Orchestrators, long-horizon tasks, 128K output |
|
|
245
|
+
| **Sonnet 4.6** | `claude-sonnet-4-6` | $3/$15 MTok | Daily coding, teammates (5x cheaper) |
|
|
246
|
+
| **Haiku 4.5** | `claude-haiku-4-5-20251001` | $1/$5 MTok | Classification, simple tasks |
|
|
217
247
|
|
|
218
248
|
### Effort Levels
|
|
219
249
|
|
|
220
|
-
| Level | Use
|
|
221
|
-
|
|
222
|
-
| `max` |
|
|
223
|
-
| `high` |
|
|
224
|
-
| `medium` |
|
|
225
|
-
| `low` | Subagents, high-volume
|
|
250
|
+
| Level | Behavior | Use Case |
|
|
251
|
+
|-------|----------|----------|
|
|
252
|
+
| `max` | Always thinks, no limits | Complex architecture (**Opus ONLY**) |
|
|
253
|
+
| `high` | Deep thinking (DEFAULT) | Agentic tasks, complex coding |
|
|
254
|
+
| `medium` | Moderate, may skip simple | Most workloads |
|
|
255
|
+
| `low` | Minimal thinking | Subagents, teammates, high-volume |
|
|
226
256
|
|
|
227
|
-
|
|
257
|
+
**CLI:** `/model` then arrow keys to adjust effort.
|
|
228
258
|
|
|
229
|
-
|
|
230
|
-
- **USE**: "Use this tool when it would enhance understanding"
|
|
231
|
-
- Keep prompts minimal - Opus 4.6 overthinks with verbose instructions
|
|
232
|
-
- Explicit instructions work better than implied expectations
|
|
259
|
+
### Adaptive Thinking (Replaces budget_tokens)
|
|
233
260
|
|
|
234
|
-
|
|
261
|
+
```typescript
|
|
262
|
+
// CORRECT for 4.6 models
|
|
263
|
+
thinking: { type: "adaptive" },
|
|
264
|
+
output_config: { effort: "medium" }
|
|
235
265
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
266
|
+
// DEPRECATED (will be removed)
|
|
267
|
+
thinking: { type: "enabled", budget_tokens: 10000 }
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Adaptive thinking enables **interleaved thinking** — Claude reasons BETWEEN tool calls.
|
|
271
|
+
|
|
272
|
+
### Prompting Rules (CRITICAL)
|
|
273
|
+
|
|
274
|
+
**AVOID (causes overtriggering):**
|
|
275
|
+
- "CRITICAL: You MUST use..."
|
|
276
|
+
- "be thorough", "think carefully", "do not be lazy"
|
|
277
|
+
- "use the think tool to plan your approach"
|
|
278
|
+
|
|
279
|
+
**USE INSTEAD:**
|
|
280
|
+
- "Use this tool when..." (softer language)
|
|
281
|
+
- Remove anti-laziness prompts entirely
|
|
282
|
+
- Lower effort level instead of adding constraints
|
|
283
|
+
|
|
284
|
+
**Why:** Opus 4.6 does MORE upfront exploration than older models. Anti-laziness prompts cause runaway thinking.
|
|
285
|
+
|
|
286
|
+
### Tool Use Patterns
|
|
287
|
+
|
|
288
|
+
```text
|
|
289
|
+
# Claude will only SUGGEST:
|
|
290
|
+
"Can you suggest some changes?"
|
|
291
|
+
|
|
292
|
+
# Claude will IMPLEMENT:
|
|
293
|
+
"Change this function to improve performance."
|
|
294
|
+
```
|
|
241
295
|
|
|
242
|
-
|
|
296
|
+
For proactive action by default, add to system prompt:
|
|
297
|
+
```text
|
|
298
|
+
By default, implement changes rather than only suggesting them.
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Subagent Control
|
|
302
|
+
|
|
303
|
+
Opus 4.6 has a **strong predilection for subagents** — may spawn them when direct grep/read is faster.
|
|
304
|
+
|
|
305
|
+
**Use subagents when:** Parallel tasks, isolated context, independent workstreams
|
|
306
|
+
**Work directly when:** Sequential operations, single-file edits, shared state needed
|
|
307
|
+
|
|
308
|
+
```text
|
|
309
|
+
# Add if seeing excessive subagent use:
|
|
310
|
+
For simple tasks, sequential operations, or single-file edits, work directly.
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Avoid Over-Engineering
|
|
314
|
+
|
|
315
|
+
Opus 4.6 tends to create extra files and unnecessary abstractions.
|
|
316
|
+
|
|
317
|
+
```text
|
|
318
|
+
# Add to prompt:
|
|
319
|
+
Avoid over-engineering. Only make changes directly requested.
|
|
320
|
+
Don't add features, docstrings, or error handling beyond what's asked.
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Parallel Tool Calls
|
|
243
324
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
325
|
+
```text
|
|
326
|
+
# Add for maximum efficiency:
|
|
327
|
+
If calling multiple tools with no dependencies, make all calls in parallel.
|
|
328
|
+
```
|
|
248
329
|
|
|
249
330
|
### Cost Control
|
|
250
331
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
332
|
+
| Issue | Solution |
|
|
333
|
+
|-------|----------|
|
|
334
|
+
| Runaway thinking | Lower effort (not prompt constraints) |
|
|
335
|
+
| `stop_reason: "max_tokens"` | Increase `max_tokens` to 64K+ |
|
|
336
|
+
| High costs | Use `low` effort for subagents |
|
|
337
|
+
| Billing confusion | Billed for FULL thinking, not visible summary |
|
|
338
|
+
|
|
339
|
+
### Common Pitfalls
|
|
340
|
+
|
|
341
|
+
| Pitfall | Fix |
|
|
342
|
+
|---------|-----|
|
|
343
|
+
| `max` effort on Sonnet/Haiku | Error — Opus only |
|
|
344
|
+
| Prefilled responses | Deprecated in 4.6 |
|
|
345
|
+
| Multiple agents editing same file | Isolate files per agent |
|
|
346
|
+
| Aggressive prompts from older models | Remove "MUST", "CRITICAL" |
|
|
347
|
+
|
|
348
|
+
### API Examples
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
// Standard agentic call
|
|
352
|
+
await client.messages.create({
|
|
353
|
+
model: "claude-opus-4-6",
|
|
354
|
+
max_tokens: 64000,
|
|
355
|
+
thinking: { type: "adaptive" },
|
|
356
|
+
output_config: { effort: "high" },
|
|
357
|
+
messages: [...]
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// Cost-optimized subagent
|
|
361
|
+
await client.messages.create({
|
|
362
|
+
model: "claude-sonnet-4-6",
|
|
363
|
+
max_tokens: 16000,
|
|
364
|
+
thinking: { type: "adaptive" },
|
|
365
|
+
output_config: { effort: "low" },
|
|
366
|
+
messages: [...]
|
|
367
|
+
});
|
|
368
|
+
```
|
|
255
369
|
|
|
256
370
|
---
|
|
257
371
|
|
|
@@ -54,6 +54,93 @@ const IGNORE_PATTERNS = [
|
|
|
54
54
|
|
|
55
55
|
const DOC_EXTENSIONS = new Set(['.md', '.mdx', '.txt', '.rst']);
|
|
56
56
|
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// FILE CHANGE CATEGORIES → CLAUDE.MD SECTIONS MAPPING
|
|
59
|
+
// ============================================================================
|
|
60
|
+
|
|
61
|
+
interface ChangeCategory {
|
|
62
|
+
name: string;
|
|
63
|
+
claudeMdSections: string[];
|
|
64
|
+
filePatterns: RegExp[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const CHANGE_CATEGORIES: ChangeCategory[] = [
|
|
68
|
+
{
|
|
69
|
+
name: 'API/CRUD',
|
|
70
|
+
claudeMdSections: ['Critical Rules', 'HTTP Requests'],
|
|
71
|
+
filePatterns: [/\/api\//, /\/routers\//, /\/server\//, /\.route\./, /\.controller\./],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'UI Components',
|
|
75
|
+
claudeMdSections: ['UI Architecture', 'Component Organization', 'Design System'],
|
|
76
|
+
filePatterns: [/\/components\//, /\/ui\//],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'Pages/Layouts',
|
|
80
|
+
claudeMdSections: ['Next.js App Router Patterns', 'Architecture'],
|
|
81
|
+
filePatterns: [/\/app\/.*page\.tsx/, /\/app\/.*layout\.tsx/, /\/app\/.*loading\.tsx/],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'Styling/Aesthetics',
|
|
85
|
+
claudeMdSections: ['UI Architecture', 'Design System', 'Design Trends'],
|
|
86
|
+
filePatterns: [/\.css$/, /globals\.css/, /theme/, /tailwind\.config/],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: 'Auth/Middleware',
|
|
90
|
+
claudeMdSections: ['Critical Rules', 'Workflow'],
|
|
91
|
+
filePatterns: [/middleware/, /auth/, /session/],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'Database/Models',
|
|
95
|
+
claudeMdSections: ['Architecture', 'Critical Rules'],
|
|
96
|
+
filePatterns: [/\/models\//, /\.model\./, /\/schema\//, /\.schema\./],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'Configuration',
|
|
100
|
+
claudeMdSections: ['Stack', 'Configuration'],
|
|
101
|
+
filePatterns: [/\.config\./, /next\.config/, /tsconfig/],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'Testing',
|
|
105
|
+
claudeMdSections: ['Quality Gates'],
|
|
106
|
+
filePatterns: [/\.test\./, /\.spec\./, /playwright/, /vitest/],
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'Workflow/Hooks',
|
|
110
|
+
claudeMdSections: ['Workflow', 'Stop Hook Validations'],
|
|
111
|
+
filePatterns: [/\.claude\/hooks\//, /\.claude\/scripts\//, /\.husky\//],
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
function categorizeChangedFiles(
|
|
116
|
+
files: string[]
|
|
117
|
+
): Array<{ category: string; sections: string[]; files: string[] }> {
|
|
118
|
+
const result = new Map<string, { sections: string[]; files: string[] }>();
|
|
119
|
+
|
|
120
|
+
for (const file of files) {
|
|
121
|
+
const normalizedFile = file.replace(/\\/g, '/');
|
|
122
|
+
for (const cat of CHANGE_CATEGORIES) {
|
|
123
|
+
for (const pattern of cat.filePatterns) {
|
|
124
|
+
if (pattern.test(normalizedFile)) {
|
|
125
|
+
if (!result.has(cat.name)) {
|
|
126
|
+
result.set(cat.name, { sections: [...cat.claudeMdSections], files: [] });
|
|
127
|
+
}
|
|
128
|
+
const entry = result.get(cat.name)!;
|
|
129
|
+
if (!entry.files.includes(file)) {
|
|
130
|
+
entry.files.push(file);
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return Array.from(result.entries()).map(([category, data]) => ({
|
|
139
|
+
category,
|
|
140
|
+
...data,
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
|
|
57
144
|
const SOURCE_EXTENSIONS = new Set([
|
|
58
145
|
'.ts',
|
|
59
146
|
'.tsx',
|
|
@@ -603,7 +690,8 @@ IMPORTANT: This section should ONLY contain the LAST change, not a history.
|
|
|
603
690
|
}
|
|
604
691
|
|
|
605
692
|
// Check for multiple Last Change sections (stacking is forbidden)
|
|
606
|
-
|
|
693
|
+
// Use negative lookbehind to avoid matching ### Last Change (H3 subheadings)
|
|
694
|
+
const multipleChanges = content.match(/(?<!#)## Last Change/g);
|
|
607
695
|
if (multipleChanges && multipleChanges.length > 1) {
|
|
608
696
|
return {
|
|
609
697
|
type: 'CLAUDE_MD_STACKED_CHANGES',
|
|
@@ -628,8 +716,10 @@ This keeps the file focused and within the 40k character limit.
|
|
|
628
716
|
return null;
|
|
629
717
|
}
|
|
630
718
|
|
|
631
|
-
|
|
632
|
-
|
|
719
|
+
/**
|
|
720
|
+
* Helper: Get files exempt from CLAUDE.md update requirement
|
|
721
|
+
*/
|
|
722
|
+
function getSignificantFiles(modifiedFiles: string[]): string[] {
|
|
633
723
|
const EXEMPT_PATTERNS = [
|
|
634
724
|
'bun.lockb',
|
|
635
725
|
'package-lock.json',
|
|
@@ -641,13 +731,10 @@ function validateClaudeMdUpdated(modifiedFiles: string[]): ValidationError | nul
|
|
|
641
731
|
/^packages\/start-vibing\/template\//,
|
|
642
732
|
];
|
|
643
733
|
|
|
644
|
-
|
|
645
|
-
const significantFiles = modifiedFiles.filter((f) => {
|
|
646
|
-
// Always exempt CLAUDE.md itself
|
|
734
|
+
return modifiedFiles.filter((f) => {
|
|
647
735
|
if (f === 'CLAUDE.md' || f.endsWith('/CLAUDE.md') || f.endsWith('\\CLAUDE.md')) {
|
|
648
736
|
return false;
|
|
649
737
|
}
|
|
650
|
-
// Check exempt patterns
|
|
651
738
|
for (const pattern of EXEMPT_PATTERNS) {
|
|
652
739
|
if (typeof pattern === 'string') {
|
|
653
740
|
if (f === pattern || f.includes(pattern)) return false;
|
|
@@ -657,17 +744,39 @@ function validateClaudeMdUpdated(modifiedFiles: string[]): ValidationError | nul
|
|
|
657
744
|
}
|
|
658
745
|
return true;
|
|
659
746
|
});
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Helper: Build categorized section guidance for error messages
|
|
751
|
+
*/
|
|
752
|
+
function buildSectionGuidance(significantFiles: string[]): string {
|
|
753
|
+
const categories = categorizeChangedFiles(significantFiles);
|
|
754
|
+
if (categories.length === 0) return '';
|
|
755
|
+
|
|
756
|
+
const lines = categories.map((c) => {
|
|
757
|
+
const uniqueSections = [...new Set(c.sections)];
|
|
758
|
+
return ` - ${c.category} (${c.files.length} file${c.files.length > 1 ? 's' : ''}) → Update sections: ${uniqueSections.join(', ')}`;
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
return `
|
|
762
|
+
DETECTED CHANGE CATEGORIES (update these CLAUDE.md sections):
|
|
660
763
|
|
|
661
|
-
|
|
764
|
+
${lines.join('\n')}
|
|
765
|
+
`;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
function validateClaudeMdUpdated(modifiedFiles: string[]): ValidationError | null {
|
|
769
|
+
const significantFiles = getSignificantFiles(modifiedFiles);
|
|
662
770
|
if (significantFiles.length === 0) return null;
|
|
663
771
|
|
|
664
|
-
// Check if CLAUDE.md is in the modified files
|
|
665
772
|
const claudeMdModified = modifiedFiles.some(
|
|
666
773
|
(f) => f === 'CLAUDE.md' || f.endsWith('/CLAUDE.md') || f.endsWith('\\CLAUDE.md')
|
|
667
774
|
);
|
|
668
775
|
|
|
669
776
|
if (claudeMdModified) return null;
|
|
670
777
|
|
|
778
|
+
const sectionGuidance = buildSectionGuidance(significantFiles);
|
|
779
|
+
|
|
671
780
|
return {
|
|
672
781
|
type: 'CLAUDE_MD_NOT_UPDATED',
|
|
673
782
|
message: `${significantFiles.length} file(s) were modified but CLAUDE.md was not updated.`,
|
|
@@ -683,7 +792,7 @@ ${significantFiles
|
|
|
683
792
|
.slice(0, 10)
|
|
684
793
|
.map((f) => ` - ${f}`)
|
|
685
794
|
.join('\n')}${significantFiles.length > 10 ? '\n ... and more' : ''}
|
|
686
|
-
|
|
795
|
+
${sectionGuidance}
|
|
687
796
|
REQUIRED UPDATES TO CLAUDE.MD:
|
|
688
797
|
|
|
689
798
|
1. Update "## Last Change" section:
|
|
@@ -691,24 +800,193 @@ REQUIRED UPDATES TO CLAUDE.MD:
|
|
|
691
800
|
**Date:** ${new Date().toISOString().split('T')[0]}
|
|
692
801
|
**Summary:** What you implemented/fixed
|
|
693
802
|
|
|
694
|
-
2.
|
|
695
|
-
Update "
|
|
803
|
+
2. UPDATE RELEVANT RULE/FLOW SECTIONS (NOT just Last Change!):
|
|
804
|
+
- Changed API/CRUD logic? → Update "Critical Rules" or "HTTP Requests"
|
|
805
|
+
- Changed UI components? → Update "UI Architecture" or "Component Organization"
|
|
806
|
+
- Changed page structure? → Update "Architecture" or "Next.js App Router Patterns"
|
|
807
|
+
- Changed aesthetic rules? → Update "Design System" or "UI Architecture"
|
|
808
|
+
- Changed auth/middleware? → Update "Critical Rules" or "Workflow"
|
|
809
|
+
- Changed config? → Update "Stack" or "Configuration"
|
|
810
|
+
- Changed testing? → Update "Quality Gates"
|
|
811
|
+
|
|
812
|
+
3. CONTEXT SYNTHESIS:
|
|
813
|
+
Think about what the user asked and what you learned.
|
|
814
|
+
If a rule changed, document the NEW rule in the relevant section.
|
|
815
|
+
If a flow changed, document the NEW flow.
|
|
816
|
+
CLAUDE.md is the single source of truth for ALL project rules.
|
|
817
|
+
|
|
818
|
+
The stop hook will BLOCK until CLAUDE.md is updated with ALL relevant sections.
|
|
819
|
+
================================================================================`,
|
|
820
|
+
};
|
|
821
|
+
}
|
|
696
822
|
|
|
697
|
-
|
|
698
|
-
|
|
823
|
+
/**
|
|
824
|
+
* NEW VALIDATION: Checks if CLAUDE.md was updated but only the "Last Change"
|
|
825
|
+
* section was modified (shallow update). When source files in categorized areas
|
|
826
|
+
* changed, CLAUDE.md sections beyond Last Change should also be updated.
|
|
827
|
+
*
|
|
828
|
+
* This catches the common pattern where Claude updates only "Last Change"
|
|
829
|
+
* but ignores updating the actual rules/flows that changed.
|
|
830
|
+
*/
|
|
831
|
+
function validateClaudeMdContentDepth(modifiedFiles: string[]): ValidationError | null {
|
|
832
|
+
const significantFiles = getSignificantFiles(modifiedFiles);
|
|
833
|
+
if (significantFiles.length === 0) return null;
|
|
699
834
|
|
|
700
|
-
|
|
701
|
-
|
|
835
|
+
// Only run if CLAUDE.md WAS modified (otherwise validateClaudeMdUpdated handles it)
|
|
836
|
+
const claudeMdModified = modifiedFiles.some(
|
|
837
|
+
(f) => f === 'CLAUDE.md' || f.endsWith('/CLAUDE.md') || f.endsWith('\\CLAUDE.md')
|
|
838
|
+
);
|
|
839
|
+
if (!claudeMdModified) return null;
|
|
840
|
+
|
|
841
|
+
// Categorize the source changes
|
|
842
|
+
const categories = categorizeChangedFiles(significantFiles);
|
|
843
|
+
if (categories.length === 0) return null; // No categorizable changes, Last Change is enough
|
|
844
|
+
|
|
845
|
+
// Try to detect if only "Last Change" section was modified in CLAUDE.md
|
|
846
|
+
// Check git diff of CLAUDE.md (staged, unstaged, or last commit)
|
|
847
|
+
let claudeMdDiff = '';
|
|
848
|
+
const diffCommands = [
|
|
849
|
+
'git diff -- CLAUDE.md',
|
|
850
|
+
'git diff --cached -- CLAUDE.md',
|
|
851
|
+
'git diff HEAD~1 HEAD -- CLAUDE.md',
|
|
852
|
+
];
|
|
702
853
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
854
|
+
for (const cmd of diffCommands) {
|
|
855
|
+
try {
|
|
856
|
+
const result = execSync(cmd, {
|
|
857
|
+
cwd: PROJECT_DIR,
|
|
858
|
+
encoding: 'utf8',
|
|
859
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
860
|
+
}).trim();
|
|
861
|
+
if (result) {
|
|
862
|
+
claudeMdDiff = result;
|
|
863
|
+
break;
|
|
864
|
+
}
|
|
865
|
+
} catch {
|
|
866
|
+
continue;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
if (!claudeMdDiff) return null; // Can't determine diff, skip this check
|
|
871
|
+
|
|
872
|
+
// Parse the diff to detect which sections were modified
|
|
873
|
+
const modifiedSections = parseClaudeMdDiffSections(claudeMdDiff);
|
|
874
|
+
|
|
875
|
+
// Check if ONLY "Last Change" was modified
|
|
876
|
+
const onlyLastChange =
|
|
877
|
+
modifiedSections.size > 0 &&
|
|
878
|
+
modifiedSections.size === 1 &&
|
|
879
|
+
modifiedSections.has('Last Change');
|
|
880
|
+
|
|
881
|
+
if (!onlyLastChange) return null; // Other sections were also modified, good
|
|
882
|
+
|
|
883
|
+
// Build specific guidance for what sections need updating
|
|
884
|
+
const sectionGuidance = categories
|
|
885
|
+
.map((c) => {
|
|
886
|
+
const uniqueSections = [...new Set(c.sections)];
|
|
887
|
+
const fileExamples = c.files.slice(0, 3).join(', ');
|
|
888
|
+
return ` - ${c.category}: ${fileExamples}\n → Must review/update: ${uniqueSections.join(', ')}`;
|
|
889
|
+
})
|
|
890
|
+
.join('\n');
|
|
891
|
+
|
|
892
|
+
return {
|
|
893
|
+
type: 'CLAUDE_MD_SHALLOW_UPDATE',
|
|
894
|
+
message: `CLAUDE.md was updated but ONLY "Last Change" was modified. ${categories.length} change category(ies) require updating additional rule/flow sections.`,
|
|
895
|
+
action: `
|
|
896
|
+
================================================================================
|
|
897
|
+
CLAUDE.MD SHALLOW UPDATE DETECTED - MUST UPDATE RELEVANT SECTIONS
|
|
898
|
+
================================================================================
|
|
899
|
+
|
|
900
|
+
You updated CLAUDE.md but ONLY modified the "Last Change" section.
|
|
901
|
+
This is NOT sufficient when source files that affect rules/flows were changed.
|
|
902
|
+
|
|
903
|
+
CHANGES DETECTED THAT REQUIRE SECTION UPDATES:
|
|
904
|
+
|
|
905
|
+
${sectionGuidance}
|
|
906
|
+
|
|
907
|
+
--------------------------------------------------------------------------------
|
|
908
|
+
WHAT TO DO
|
|
909
|
+
--------------------------------------------------------------------------------
|
|
910
|
+
|
|
911
|
+
For EACH category above, review the corresponding CLAUDE.md section and:
|
|
912
|
+
|
|
913
|
+
1. If a RULE changed (e.g., CRUD validation, auth flow):
|
|
914
|
+
→ UPDATE the rule in its section (Critical Rules, Workflow, etc.)
|
|
706
915
|
|
|
707
|
-
|
|
916
|
+
2. If an AESTHETIC/UI pattern changed (e.g., new component style):
|
|
917
|
+
→ UPDATE UI Architecture, Design System, or Component Organization
|
|
918
|
+
|
|
919
|
+
3. If a FLOW changed (e.g., new middleware, data fetching pattern):
|
|
920
|
+
→ UPDATE Workflow, Architecture, or Next.js App Router Patterns
|
|
921
|
+
|
|
922
|
+
4. If NOTHING changed in rules/flows (just implementation):
|
|
923
|
+
→ Add a comment in the relevant section noting the implementation
|
|
924
|
+
|
|
925
|
+
EXAMPLES:
|
|
926
|
+
- Changed how users are fetched? → Update HTTP Requests section
|
|
927
|
+
- Changed button styles? → Update Design System section
|
|
928
|
+
- Added new page? → Update Architecture section
|
|
929
|
+
- Changed form validation? → Update Critical Rules section
|
|
930
|
+
|
|
931
|
+
RULE: "Last Change" documents WHAT was done.
|
|
932
|
+
Other sections document HOW things work NOW.
|
|
933
|
+
Both must be current.
|
|
934
|
+
|
|
935
|
+
The stop hook will BLOCK until relevant sections are also updated.
|
|
708
936
|
================================================================================`,
|
|
709
937
|
};
|
|
710
938
|
}
|
|
711
939
|
|
|
940
|
+
/**
|
|
941
|
+
* Parse a git diff of CLAUDE.md to determine which ## sections were modified.
|
|
942
|
+
* Returns a Set of section names that had actual content changes.
|
|
943
|
+
*/
|
|
944
|
+
function parseClaudeMdDiffSections(diff: string): Set<string> {
|
|
945
|
+
const modifiedSections = new Set<string>();
|
|
946
|
+
const lines = diff.split('\n');
|
|
947
|
+
let currentSection = '';
|
|
948
|
+
|
|
949
|
+
for (const line of lines) {
|
|
950
|
+
// Skip diff metadata
|
|
951
|
+
if (
|
|
952
|
+
line.startsWith('diff ') ||
|
|
953
|
+
line.startsWith('index ') ||
|
|
954
|
+
line.startsWith('--- ') ||
|
|
955
|
+
line.startsWith('+++ ')
|
|
956
|
+
) {
|
|
957
|
+
continue;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// Parse @@ hunk headers - they sometimes contain section context
|
|
961
|
+
const hunkMatch = line.match(/^@@ .+ @@\s*(## .+)?/);
|
|
962
|
+
if (hunkMatch && hunkMatch[1]) {
|
|
963
|
+
currentSection = hunkMatch[1].replace('## ', '').trim();
|
|
964
|
+
continue;
|
|
965
|
+
}
|
|
966
|
+
if (line.startsWith('@@')) continue;
|
|
967
|
+
|
|
968
|
+
// Detect section headers in changed or context lines
|
|
969
|
+
const sectionMatch = line.match(/^[+ -]?## (.+)/);
|
|
970
|
+
if (sectionMatch) {
|
|
971
|
+
currentSection = sectionMatch[1].trim();
|
|
972
|
+
// If the section header itself is a change, count it
|
|
973
|
+
if (line.startsWith('+') || line.startsWith('-')) {
|
|
974
|
+
modifiedSections.add(currentSection);
|
|
975
|
+
}
|
|
976
|
+
continue;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// Track actual content changes (+ or - lines, not context)
|
|
980
|
+
if (line.startsWith('+') || line.startsWith('-')) {
|
|
981
|
+
if (currentSection) {
|
|
982
|
+
modifiedSections.add(currentSection);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
return modifiedSections;
|
|
988
|
+
}
|
|
989
|
+
|
|
712
990
|
function validateDocumentation(sourceFiles: string[]): ValidationError | null {
|
|
713
991
|
if (sourceFiles.length === 0) return null;
|
|
714
992
|
|
|
@@ -996,7 +1274,13 @@ Validate with: wc -m CLAUDE.md (must be < 40000)`,
|
|
|
996
1274
|
},
|
|
997
1275
|
CLAUDE_MD_NOT_UPDATED: {
|
|
998
1276
|
agent: 'documenter',
|
|
999
|
-
prompt:
|
|
1277
|
+
prompt:
|
|
1278
|
+
'Update CLAUDE.md: Last Change section AND all relevant rule/flow sections based on what files were changed (API rules, UI rules, workflow, architecture, etc.)',
|
|
1279
|
+
},
|
|
1280
|
+
CLAUDE_MD_SHALLOW_UPDATE: {
|
|
1281
|
+
agent: 'documenter',
|
|
1282
|
+
prompt:
|
|
1283
|
+
'CLAUDE.md was updated but only Last Change was modified. Review changed source files, categorize them, and update the corresponding CLAUDE.md sections (Critical Rules, UI Architecture, Workflow, etc.) to reflect current rules and flows.',
|
|
1000
1284
|
},
|
|
1001
1285
|
SOURCE_FILES_NOT_DOCUMENTED: {
|
|
1002
1286
|
agent: 'documenter',
|
|
@@ -1087,11 +1371,15 @@ function collectAllErrors(
|
|
|
1087
1371
|
const updatedError = validateClaudeMdUpdated(modifiedFiles);
|
|
1088
1372
|
if (updatedError) errors.push(updatedError);
|
|
1089
1373
|
|
|
1090
|
-
// 9.
|
|
1374
|
+
// 9. CLAUDE.md must have relevant sections updated (not just Last Change)
|
|
1375
|
+
const contentDepthError = validateClaudeMdContentDepth(modifiedFiles);
|
|
1376
|
+
if (contentDepthError) errors.push(contentDepthError);
|
|
1377
|
+
|
|
1378
|
+
// 11. Source files must be documented
|
|
1091
1379
|
const docError = validateDocumentation(sourceFiles);
|
|
1092
1380
|
if (docError) errors.push(docError);
|
|
1093
1381
|
|
|
1094
|
-
//
|
|
1382
|
+
// 12. Domain documentation must be complete
|
|
1095
1383
|
const domainDocError = validateDomainDocumentation(modifiedFiles);
|
|
1096
1384
|
if (domainDocError) errors.push(domainDocError);
|
|
1097
1385
|
|
|
@@ -75,16 +75,21 @@ async function main(): Promise<void> {
|
|
|
75
75
|
|
|
76
76
|
5. COMMIT using conventional commits via commit-manager agent.
|
|
77
77
|
|
|
78
|
-
6. UPDATE CLAUDE.md BEFORE finishing (MANDATORY):
|
|
78
|
+
6. UPDATE CLAUDE.md BEFORE finishing (MANDATORY - NOT JUST "Last Change"!):
|
|
79
79
|
a. "## Last Change" section (date: ${today}, branch, summary). Keep only latest.
|
|
80
|
-
b.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
b. THEN update ALL sections affected by your changes:
|
|
81
|
+
- Changed API/CRUD rules? → Update "Critical Rules" or "HTTP Requests"
|
|
82
|
+
- Changed UI components/aesthetics? → Update "UI Architecture", "Design System", "Component Organization"
|
|
83
|
+
- Changed pages/layouts? → Update "Architecture" or "Next.js App Router Patterns"
|
|
84
|
+
- Changed auth/middleware? → Update "Critical Rules" or "Workflow"
|
|
85
|
+
- Changed config/stack? → Update "Stack" or "Configuration"
|
|
86
|
+
- Changed testing patterns? → Update "Quality Gates"
|
|
87
|
+
- Changed workflow/hooks? → Update "Workflow" or "Stop Hook Validations"
|
|
88
|
+
- New gotchas discovered? → Add to "FORBIDDEN" or "NRY"
|
|
89
|
+
|
|
90
|
+
RULE: "Last Change" = WHAT was done. Other sections = HOW things work NOW.
|
|
91
|
+
If you ONLY update Last Change, the stop-validator will BLOCK with CLAUDE_MD_SHALLOW_UPDATE.
|
|
92
|
+
CLAUDE.md is the SINGLE SOURCE OF TRUTH for ALL project rules and flows.
|
|
88
93
|
|
|
89
94
|
7. RUN stop-validator before finishing: npx tsx .claude/hooks/stop-validator.ts`;
|
|
90
95
|
|