claudex-setup 0.3.1 → 0.5.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/README.md +39 -5
- package/bin/cli.js +4 -0
- package/package.json +1 -1
- package/src/deep-review.js +278 -0
- package/src/setup.js +15 -4
- package/src/techniques.js +173 -7
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# claudex-setup
|
|
2
2
|
|
|
3
|
-
> Score your project 0-100 for Claude Code. Smart CLAUDE.md,
|
|
3
|
+
> Score your project 0-100 for Claude Code readiness. Smart CLAUDE.md generator, 63 audit checks, interactive wizard, watch mode, CI action. Never overwrites existing config.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/claudex-setup)
|
|
6
6
|
[](https://www.npmjs.com/package/claudex-setup)
|
|
@@ -44,7 +44,7 @@ No install. No config. No dependencies.
|
|
|
44
44
|
design: none (0/2)
|
|
45
45
|
devops: none (0/4)
|
|
46
46
|
|
|
47
|
-
29/
|
|
47
|
+
29/63 checks passing
|
|
48
48
|
Run npx claudex-setup setup to fix
|
|
49
49
|
```
|
|
50
50
|
|
|
@@ -52,12 +52,13 @@ No install. No config. No dependencies.
|
|
|
52
52
|
|
|
53
53
|
| Command | What it does |
|
|
54
54
|
|---------|-------------|
|
|
55
|
-
| `npx claudex-setup` | **Audit** - Score 0-100 against
|
|
55
|
+
| `npx claudex-setup` | **Audit** - Score 0-100 against 63 checks |
|
|
56
56
|
| `npx claudex-setup setup` | **Setup** - Smart CLAUDE.md + hooks + commands + agents |
|
|
57
57
|
| `npx claudex-setup setup --auto` | **Auto-setup** - No prompts, apply all |
|
|
58
58
|
| `npx claudex-setup interactive` | **Wizard** - Step-by-step guided tour |
|
|
59
59
|
| `npx claudex-setup watch` | **Watch** - Live monitoring with score delta |
|
|
60
60
|
| `npx claudex-setup badge` | **Badge** - Generate shields.io badge for README |
|
|
61
|
+
| `npx claudex-setup deep-review` | **Deep Review** - AI-powered config analysis (needs API key) |
|
|
61
62
|
| `npx claudex-setup insights` | **Insights** - View community aggregate stats |
|
|
62
63
|
|
|
63
64
|
### Options
|
|
@@ -79,7 +80,7 @@ Not a generic template. The `setup` command actually analyzes your project:
|
|
|
79
80
|
- **XML constraint blocks** - adds `<constraints>` and `<verification>` with context-aware rules
|
|
80
81
|
- **Verification criteria** - auto-generates checklist from your actual commands
|
|
81
82
|
|
|
82
|
-
##
|
|
83
|
+
## 63 Checks Across 14 Categories
|
|
83
84
|
|
|
84
85
|
| Category | Checks | Key items |
|
|
85
86
|
|----------|-------:|-----------|
|
|
@@ -96,6 +97,7 @@ Not a generic template. The `setup` command actually analyzes your project:
|
|
|
96
97
|
| MCP | 3 | servers, Context7, integrations |
|
|
97
98
|
| Prompting | 3 | constraints, validation, patterns |
|
|
98
99
|
| Features | 2 | /security-review, Channels |
|
|
100
|
+
| **Quality Deep** | **9** | **freshness, contradictions, deprecated patterns, maxTurns, $ARGUMENTS** |
|
|
99
101
|
|
|
100
102
|
## Stack Detection
|
|
101
103
|
|
|
@@ -136,6 +138,36 @@ npx claudex-setup badge
|
|
|
136
138
|
# Output: [](...)
|
|
137
139
|
```
|
|
138
140
|
|
|
141
|
+
## For Veteran Claude Code Users
|
|
142
|
+
|
|
143
|
+
Already have a solid CLAUDE.md and hooks? Two things for you:
|
|
144
|
+
|
|
145
|
+
### Deep Review (AI-powered)
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
ANTHROPIC_API_KEY=sk-ant-... npx claudex-setup deep-review
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Claude reads your actual config and gives specific feedback: what's strong, what has issues, what's missing for your stack. Not pattern matching — real analysis. Your config goes to Anthropic API only, we never see it.
|
|
152
|
+
|
|
153
|
+
### Quality-Deep Checks
|
|
154
|
+
|
|
155
|
+
The v0.4.0 quality-deep checks catch what basic audits miss:
|
|
156
|
+
|
|
157
|
+
| Check | What it catches |
|
|
158
|
+
|-------|----------------|
|
|
159
|
+
| **Freshness** | CLAUDE.md that doesn't mention modern features (hooks, skills, MCP) |
|
|
160
|
+
| **Conciseness** | CLAUDE.md over 200 lines (wastes tokens every session) |
|
|
161
|
+
| **Contradictions** | Conflicting rules ("always X" + "never X") |
|
|
162
|
+
| **Hook specificity** | Hooks without matchers that fire on every tool call |
|
|
163
|
+
| **Permission hygiene** | bypassPermissions still enabled in production |
|
|
164
|
+
| **Command flexibility** | Commands without $ARGUMENTS (static, not reusable) |
|
|
165
|
+
| **Agent limits** | Agents without maxTurns (can run forever) |
|
|
166
|
+
| **Security workflow** | No /security-review in your process |
|
|
167
|
+
| **Deprecated patterns** | Old model names, prefill, deprecated API formats |
|
|
168
|
+
|
|
169
|
+
These checks evaluate **quality**, not just existence. A well-configured project with stale patterns will surface real improvements.
|
|
170
|
+
|
|
139
171
|
## Privacy
|
|
140
172
|
|
|
141
173
|
- **Zero dependencies** - nothing to audit
|
|
@@ -151,7 +183,9 @@ Every check traces to a verified technique from a systematic audit of:
|
|
|
151
183
|
- Anthropic blog posts and benchmark papers
|
|
152
184
|
- 194 hands-on experiments with real evidence
|
|
153
185
|
|
|
154
|
-
1,107 techniques
|
|
186
|
+
The catalog includes 1,107 entries (features, techniques, patterns, tools, stats, and known limitations) — not all are actionable checks. 954 were verified with real evidence. Continuously updated.
|
|
187
|
+
|
|
188
|
+
**Note:** A hand-crafted CLAUDE.md that reflects your real conventions will always be better than a generated one. This tool is most useful for projects starting from zero, or as a checklist for what you might be missing.
|
|
155
189
|
|
|
156
190
|
## Requirements
|
|
157
191
|
|
package/bin/cli.js
CHANGED
|
@@ -18,6 +18,7 @@ const HELP = `
|
|
|
18
18
|
npx claudex-setup audit Same as above
|
|
19
19
|
npx claudex-setup setup Apply recommended configuration
|
|
20
20
|
npx claudex-setup setup --auto Apply all without prompts
|
|
21
|
+
npx claudex-setup deep-review AI-powered config analysis (needs API key)
|
|
21
22
|
npx claudex-setup interactive Step-by-step guided wizard
|
|
22
23
|
npx claudex-setup watch Monitor changes and re-audit live
|
|
23
24
|
npx claudex-setup badge Generate shields.io badge markdown
|
|
@@ -91,6 +92,9 @@ async function main() {
|
|
|
91
92
|
console.log(' Could not reach insights server. Run locally: npx claudex-setup');
|
|
92
93
|
});
|
|
93
94
|
return; // keep process alive for http
|
|
95
|
+
} else if (command === 'deep-review' || command === 'review') {
|
|
96
|
+
const { deepReview } = require('../src/deep-review');
|
|
97
|
+
await deepReview(options);
|
|
94
98
|
} else if (command === 'interactive' || command === 'wizard') {
|
|
95
99
|
const { interactive } = require('../src/interactive');
|
|
96
100
|
await interactive(options);
|
package/package.json
CHANGED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep Review - AI-powered analysis of Claude Code configuration quality.
|
|
3
|
+
* Uses Claude API to read and critique your actual config, not just pattern match.
|
|
4
|
+
*
|
|
5
|
+
* Requires: ANTHROPIC_API_KEY environment variable
|
|
6
|
+
* Usage: npx claudex-setup deep-review
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const https = require('https');
|
|
10
|
+
const { ProjectContext } = require('./context');
|
|
11
|
+
const { STACKS } = require('./techniques');
|
|
12
|
+
|
|
13
|
+
const COLORS = {
|
|
14
|
+
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
15
|
+
red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m',
|
|
16
|
+
blue: '\x1b[36m', magenta: '\x1b[35m',
|
|
17
|
+
};
|
|
18
|
+
const c = (text, color) => `${COLORS[color] || ''}${text}${COLORS.reset}`;
|
|
19
|
+
|
|
20
|
+
function collectProjectConfig(ctx, stacks) {
|
|
21
|
+
const config = {};
|
|
22
|
+
|
|
23
|
+
// CLAUDE.md
|
|
24
|
+
config.claudeMd = ctx.fileContent('CLAUDE.md') || ctx.fileContent('.claude/CLAUDE.md');
|
|
25
|
+
|
|
26
|
+
// Settings
|
|
27
|
+
config.settings = ctx.fileContent('.claude/settings.local.json') || ctx.fileContent('.claude/settings.json');
|
|
28
|
+
|
|
29
|
+
// Commands
|
|
30
|
+
config.commands = {};
|
|
31
|
+
if (ctx.hasDir('.claude/commands')) {
|
|
32
|
+
for (const f of ctx.dirFiles('.claude/commands')) {
|
|
33
|
+
config.commands[f] = ctx.fileContent(`.claude/commands/${f}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Agents
|
|
38
|
+
config.agents = {};
|
|
39
|
+
if (ctx.hasDir('.claude/agents')) {
|
|
40
|
+
for (const f of ctx.dirFiles('.claude/agents')) {
|
|
41
|
+
config.agents[f] = ctx.fileContent(`.claude/agents/${f}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Rules
|
|
46
|
+
config.rules = {};
|
|
47
|
+
if (ctx.hasDir('.claude/rules')) {
|
|
48
|
+
for (const f of ctx.dirFiles('.claude/rules')) {
|
|
49
|
+
config.rules[f] = ctx.fileContent(`.claude/rules/${f}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Hooks (from settings)
|
|
54
|
+
if (ctx.hasDir('.claude/hooks')) {
|
|
55
|
+
config.hookFiles = {};
|
|
56
|
+
for (const f of ctx.dirFiles('.claude/hooks')) {
|
|
57
|
+
config.hookFiles[f] = ctx.fileContent(`.claude/hooks/${f}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Package.json (scripts only)
|
|
62
|
+
const pkg = ctx.jsonFile('package.json');
|
|
63
|
+
if (pkg) {
|
|
64
|
+
config.packageScripts = pkg.scripts || {};
|
|
65
|
+
config.packageName = pkg.name;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
config.stacks = stacks.map(s => s.label);
|
|
69
|
+
|
|
70
|
+
return config;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function buildPrompt(config) {
|
|
74
|
+
const parts = [];
|
|
75
|
+
|
|
76
|
+
parts.push(`You are an expert Claude Code configuration reviewer. Analyze this project's Claude Code setup and provide specific, actionable feedback.
|
|
77
|
+
|
|
78
|
+
The project uses: ${config.stacks.join(', ') || 'unknown stack'}
|
|
79
|
+
${config.packageName ? `Project name: ${config.packageName}` : ''}`);
|
|
80
|
+
|
|
81
|
+
if (config.claudeMd) {
|
|
82
|
+
parts.push(`\n<claude_md>\n${config.claudeMd.slice(0, 4000)}\n</claude_md>`);
|
|
83
|
+
} else {
|
|
84
|
+
parts.push('\nNo CLAUDE.md found.');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (config.settings) {
|
|
88
|
+
parts.push(`\n<settings>\n${config.settings.slice(0, 2000)}\n</settings>`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (Object.keys(config.commands).length > 0) {
|
|
92
|
+
parts.push('\n<commands>');
|
|
93
|
+
for (const [name, content] of Object.entries(config.commands)) {
|
|
94
|
+
parts.push(`--- ${name} ---\n${(content || '').slice(0, 500)}`);
|
|
95
|
+
}
|
|
96
|
+
parts.push('</commands>');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (Object.keys(config.agents).length > 0) {
|
|
100
|
+
parts.push('\n<agents>');
|
|
101
|
+
for (const [name, content] of Object.entries(config.agents)) {
|
|
102
|
+
parts.push(`--- ${name} ---\n${(content || '').slice(0, 500)}`);
|
|
103
|
+
}
|
|
104
|
+
parts.push('</agents>');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (Object.keys(config.rules || {}).length > 0) {
|
|
108
|
+
parts.push('\n<rules>');
|
|
109
|
+
for (const [name, content] of Object.entries(config.rules)) {
|
|
110
|
+
parts.push(`--- ${name} ---\n${(content || '').slice(0, 300)}`);
|
|
111
|
+
}
|
|
112
|
+
parts.push('</rules>');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (config.hookFiles && Object.keys(config.hookFiles).length > 0) {
|
|
116
|
+
parts.push('\n<hooks>');
|
|
117
|
+
for (const [name, content] of Object.entries(config.hookFiles)) {
|
|
118
|
+
parts.push(`--- ${name} ---\n${(content || '').slice(0, 300)}`);
|
|
119
|
+
}
|
|
120
|
+
parts.push('</hooks>');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
parts.push(`
|
|
124
|
+
<task>
|
|
125
|
+
Provide a deep review with these exact sections:
|
|
126
|
+
|
|
127
|
+
## Score: X/10
|
|
128
|
+
|
|
129
|
+
## Strengths (what's done well)
|
|
130
|
+
- List 2-4 specific things this config does right, with WHY they're effective
|
|
131
|
+
|
|
132
|
+
## Issues (what needs fixing)
|
|
133
|
+
- List 3-5 specific issues, each with:
|
|
134
|
+
- What's wrong (be specific, quote from the config)
|
|
135
|
+
- Why it matters
|
|
136
|
+
- Exact fix (show the corrected version or command)
|
|
137
|
+
|
|
138
|
+
## Missing (what's not there but should be)
|
|
139
|
+
- List 2-3 things this project should add based on its stack
|
|
140
|
+
- Be specific to THIS project's stack and size, not generic advice
|
|
141
|
+
|
|
142
|
+
## Quick Wins (fastest improvements)
|
|
143
|
+
- Top 3 changes that take under 2 minutes each
|
|
144
|
+
|
|
145
|
+
Be direct, specific, and honest. Don't pad with generic advice. Reference actual content from the config. If the setup is already excellent, say so and focus on micro-optimizations.
|
|
146
|
+
</task>`);
|
|
147
|
+
|
|
148
|
+
return parts.join('\n');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function callClaude(apiKey, prompt) {
|
|
152
|
+
return new Promise((resolve, reject) => {
|
|
153
|
+
const body = JSON.stringify({
|
|
154
|
+
model: 'claude-sonnet-4-6',
|
|
155
|
+
max_tokens: 2000,
|
|
156
|
+
messages: [{ role: 'user', content: prompt }],
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const req = https.request({
|
|
160
|
+
hostname: 'api.anthropic.com',
|
|
161
|
+
path: '/v1/messages',
|
|
162
|
+
method: 'POST',
|
|
163
|
+
headers: {
|
|
164
|
+
'Content-Type': 'application/json',
|
|
165
|
+
'x-api-key': apiKey,
|
|
166
|
+
'anthropic-version': '2023-06-01',
|
|
167
|
+
'Content-Length': Buffer.byteLength(body),
|
|
168
|
+
},
|
|
169
|
+
}, (res) => {
|
|
170
|
+
let data = '';
|
|
171
|
+
res.on('data', chunk => data += chunk);
|
|
172
|
+
res.on('end', () => {
|
|
173
|
+
try {
|
|
174
|
+
const parsed = JSON.parse(data);
|
|
175
|
+
if (parsed.error) {
|
|
176
|
+
reject(new Error(parsed.error.message));
|
|
177
|
+
} else {
|
|
178
|
+
resolve(parsed.content[0].text);
|
|
179
|
+
}
|
|
180
|
+
} catch (e) {
|
|
181
|
+
reject(new Error(`API response parse error: ${data.slice(0, 200)}`));
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
req.on('error', reject);
|
|
187
|
+
req.write(body);
|
|
188
|
+
req.end();
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async function deepReview(options) {
|
|
193
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
194
|
+
if (!apiKey) {
|
|
195
|
+
console.log('');
|
|
196
|
+
console.log(c(' Deep Review requires an Anthropic API key.', 'bold'));
|
|
197
|
+
console.log('');
|
|
198
|
+
console.log(' Set it with:');
|
|
199
|
+
console.log(c(' export ANTHROPIC_API_KEY=sk-ant-...', 'green'));
|
|
200
|
+
console.log('');
|
|
201
|
+
console.log(c(' Or on Windows:', 'dim'));
|
|
202
|
+
console.log(c(' set ANTHROPIC_API_KEY=sk-ant-...', 'green'));
|
|
203
|
+
console.log('');
|
|
204
|
+
console.log(c(' Your key is sent directly to Anthropic API. We never see or store it.', 'dim'));
|
|
205
|
+
console.log('');
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
console.log('');
|
|
210
|
+
console.log(c(' claudex-setup deep review', 'bold'));
|
|
211
|
+
console.log(c(' ═══════════════════════════════════════', 'dim'));
|
|
212
|
+
|
|
213
|
+
const ctx = new ProjectContext(options.dir);
|
|
214
|
+
const stacks = ctx.detectStacks(STACKS);
|
|
215
|
+
|
|
216
|
+
console.log(c(` Scanning: ${options.dir}`, 'dim'));
|
|
217
|
+
if (stacks.length > 0) {
|
|
218
|
+
console.log(c(` Stack: ${stacks.map(s => s.label).join(', ')}`, 'blue'));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Collect config
|
|
222
|
+
const config = collectProjectConfig(ctx, stacks);
|
|
223
|
+
const fileCount = [
|
|
224
|
+
config.claudeMd ? 1 : 0,
|
|
225
|
+
config.settings ? 1 : 0,
|
|
226
|
+
Object.keys(config.commands).length,
|
|
227
|
+
Object.keys(config.agents).length,
|
|
228
|
+
Object.keys(config.rules || {}).length,
|
|
229
|
+
Object.keys(config.hookFiles || {}).length,
|
|
230
|
+
].reduce((a, b) => a + b, 0);
|
|
231
|
+
|
|
232
|
+
console.log(c(` Found ${fileCount} config files to analyze`, 'dim'));
|
|
233
|
+
console.log('');
|
|
234
|
+
console.log(c(' Sending to Claude for deep analysis...', 'magenta'));
|
|
235
|
+
console.log('');
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
const prompt = buildPrompt(config);
|
|
239
|
+
const review = await callClaude(apiKey, prompt);
|
|
240
|
+
|
|
241
|
+
// Format output
|
|
242
|
+
const lines = review.split('\n');
|
|
243
|
+
for (const line of lines) {
|
|
244
|
+
if (line.startsWith('## Score')) {
|
|
245
|
+
console.log(c(` ${line}`, 'bold'));
|
|
246
|
+
} else if (line.startsWith('## Strengths')) {
|
|
247
|
+
console.log(c(` ${line}`, 'green'));
|
|
248
|
+
} else if (line.startsWith('## Issues')) {
|
|
249
|
+
console.log(c(` ${line}`, 'yellow'));
|
|
250
|
+
} else if (line.startsWith('## Missing')) {
|
|
251
|
+
console.log(c(` ${line}`, 'red'));
|
|
252
|
+
} else if (line.startsWith('## Quick')) {
|
|
253
|
+
console.log(c(` ${line}`, 'magenta'));
|
|
254
|
+
} else if (line.startsWith('- ')) {
|
|
255
|
+
console.log(` ${line}`);
|
|
256
|
+
} else if (line.startsWith('```')) {
|
|
257
|
+
console.log(c(` ${line}`, 'dim'));
|
|
258
|
+
} else if (line.trim()) {
|
|
259
|
+
console.log(` ${line}`);
|
|
260
|
+
} else {
|
|
261
|
+
console.log('');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
console.log('');
|
|
266
|
+
console.log(c(' ─────────────────────────────────────', 'dim'));
|
|
267
|
+
console.log(c(' Reviewed by Claude Sonnet 4.6 via Anthropic API', 'dim'));
|
|
268
|
+
console.log(c(' Your config was sent to api.anthropic.com only. We never see it.', 'dim'));
|
|
269
|
+
console.log('');
|
|
270
|
+
} catch (err) {
|
|
271
|
+
console.log(c(` Error: ${err.message}`, 'red'));
|
|
272
|
+
console.log('');
|
|
273
|
+
console.log(' Check your ANTHROPIC_API_KEY is valid.');
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
module.exports = { deepReview };
|
package/src/setup.js
CHANGED
|
@@ -569,6 +569,7 @@ async function setup(options) {
|
|
|
569
569
|
console.log('');
|
|
570
570
|
|
|
571
571
|
let created = 0;
|
|
572
|
+
let skipped = 0;
|
|
572
573
|
|
|
573
574
|
for (const [key, technique] of Object.entries(TECHNIQUES)) {
|
|
574
575
|
if (technique.passed || technique.check(ctx)) continue;
|
|
@@ -589,6 +590,9 @@ async function setup(options) {
|
|
|
589
590
|
fs.writeFileSync(fullPath, result, 'utf8');
|
|
590
591
|
console.log(` \x1b[32m✅\x1b[0m Created ${filePath}`);
|
|
591
592
|
created++;
|
|
593
|
+
} else {
|
|
594
|
+
console.log(` \x1b[2m⏭️ Skipped ${filePath} (already exists — your version is kept)\x1b[0m`);
|
|
595
|
+
skipped++;
|
|
592
596
|
}
|
|
593
597
|
} else if (typeof result === 'object') {
|
|
594
598
|
// Multiple files template (hooks, commands, etc)
|
|
@@ -616,16 +620,23 @@ async function setup(options) {
|
|
|
616
620
|
fs.writeFileSync(filePath, content, 'utf8');
|
|
617
621
|
console.log(` \x1b[32m✅\x1b[0m Created ${path.relative(options.dir, filePath)}`);
|
|
618
622
|
created++;
|
|
623
|
+
} else {
|
|
624
|
+
skipped++;
|
|
619
625
|
}
|
|
620
626
|
}
|
|
621
627
|
}
|
|
622
628
|
}
|
|
623
629
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
console.log(
|
|
630
|
+
console.log('');
|
|
631
|
+
if (created === 0 && skipped > 0) {
|
|
632
|
+
console.log(' \x1b[32m✅\x1b[0m Your project is already well configured!');
|
|
633
|
+
console.log(` \x1b[2m ${skipped} files already exist and were preserved.\x1b[0m`);
|
|
634
|
+
console.log(' \x1b[2m We never overwrite your existing config — your setup is kept.\x1b[0m');
|
|
635
|
+
} else if (created > 0) {
|
|
628
636
|
console.log(` \x1b[1m${created} files created.\x1b[0m`);
|
|
637
|
+
if (skipped > 0) {
|
|
638
|
+
console.log(` \x1b[2m${skipped} existing files preserved (not overwritten).\x1b[0m`);
|
|
639
|
+
}
|
|
629
640
|
}
|
|
630
641
|
|
|
631
642
|
console.log('');
|
package/src/techniques.js
CHANGED
|
@@ -702,15 +702,18 @@ const TECHNIQUES = {
|
|
|
702
702
|
name: 'XML tags for structured prompts',
|
|
703
703
|
check: (ctx) => {
|
|
704
704
|
const md = ctx.fileContent('CLAUDE.md') || '';
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
md.includes('<validation') || md.includes('<instructions')
|
|
708
|
-
)
|
|
705
|
+
// Give credit for XML tags OR well-structured markdown with clear sections
|
|
706
|
+
const hasXml = md.includes('<constraints') || md.includes('<rules') ||
|
|
707
|
+
md.includes('<validation') || md.includes('<instructions');
|
|
708
|
+
const hasStructuredMd = (md.includes('## Rules') || md.includes('## Constraints') ||
|
|
709
|
+
md.includes('## Do not') || md.includes('## Never') || md.includes('## Important')) &&
|
|
710
|
+
md.split('\n').length > 20;
|
|
711
|
+
return hasXml || hasStructuredMd;
|
|
709
712
|
},
|
|
710
|
-
impact: '
|
|
711
|
-
rating:
|
|
713
|
+
impact: 'medium',
|
|
714
|
+
rating: 4,
|
|
712
715
|
category: 'prompting',
|
|
713
|
-
fix: '
|
|
716
|
+
fix: 'Add clear rules sections to CLAUDE.md. XML tags (<constraints>) are optional but improve clarity.',
|
|
714
717
|
template: null
|
|
715
718
|
},
|
|
716
719
|
|
|
@@ -770,6 +773,169 @@ const TECHNIQUES = {
|
|
|
770
773
|
fix: 'Claude Code Channels (v2.1.80+) lets you control sessions from Telegram/Discord/iMessage.',
|
|
771
774
|
template: null
|
|
772
775
|
},
|
|
776
|
+
|
|
777
|
+
// ============================================================
|
|
778
|
+
// === QUALITY CHECKS FOR VETERANS (category: 'quality-deep')
|
|
779
|
+
// These check HOW GOOD your config is, not just IF it exists.
|
|
780
|
+
// ============================================================
|
|
781
|
+
|
|
782
|
+
claudeMdFreshness: {
|
|
783
|
+
id: 2001,
|
|
784
|
+
name: 'CLAUDE.md mentions current Claude features',
|
|
785
|
+
check: (ctx) => {
|
|
786
|
+
const md = ctx.fileContent('CLAUDE.md') || '';
|
|
787
|
+
if (md.length < 50) return false; // too short to evaluate
|
|
788
|
+
// Check for awareness of features from 2025+
|
|
789
|
+
const modernFeatures = ['hook', 'skill', 'agent', 'subagent', 'mcp', 'compact', '/clear', 'extended thinking', 'tool_use', 'worktree'];
|
|
790
|
+
const found = modernFeatures.filter(f => md.toLowerCase().includes(f));
|
|
791
|
+
return found.length >= 2; // knows at least 2 modern features
|
|
792
|
+
},
|
|
793
|
+
impact: 'medium',
|
|
794
|
+
rating: 4,
|
|
795
|
+
category: 'quality-deep',
|
|
796
|
+
fix: 'Your CLAUDE.md may be outdated. Modern Claude Code supports hooks, skills, agents, MCP, worktrees, and extended thinking. Mention the ones you use.',
|
|
797
|
+
template: null
|
|
798
|
+
},
|
|
799
|
+
|
|
800
|
+
claudeMdNotOverlong: {
|
|
801
|
+
id: 2002,
|
|
802
|
+
name: 'CLAUDE.md is concise (under 200 lines)',
|
|
803
|
+
check: (ctx) => {
|
|
804
|
+
const md = ctx.fileContent('CLAUDE.md') || '';
|
|
805
|
+
return md.split('\n').length <= 200;
|
|
806
|
+
},
|
|
807
|
+
impact: 'medium',
|
|
808
|
+
rating: 4,
|
|
809
|
+
category: 'quality-deep',
|
|
810
|
+
fix: 'CLAUDE.md over 200 lines wastes tokens every session. Move detailed docs to .claude/rules/ or skills. Keep CLAUDE.md lean.',
|
|
811
|
+
template: null
|
|
812
|
+
},
|
|
813
|
+
|
|
814
|
+
claudeMdNoContradictions: {
|
|
815
|
+
id: 2003,
|
|
816
|
+
name: 'CLAUDE.md has no obvious contradictions',
|
|
817
|
+
check: (ctx) => {
|
|
818
|
+
const md = ctx.fileContent('CLAUDE.md') || '';
|
|
819
|
+
// Check for common contradictions
|
|
820
|
+
const hasNever = /never.*always|always.*never/i.test(md);
|
|
821
|
+
const hasBothStyles = /use tabs/i.test(md) && /use spaces/i.test(md);
|
|
822
|
+
return !hasNever && !hasBothStyles;
|
|
823
|
+
},
|
|
824
|
+
impact: 'high',
|
|
825
|
+
rating: 4,
|
|
826
|
+
category: 'quality-deep',
|
|
827
|
+
fix: 'CLAUDE.md may contain contradictory instructions. Review for conflicting rules (e.g., "always X" and "never X" about the same topic).',
|
|
828
|
+
template: null
|
|
829
|
+
},
|
|
830
|
+
|
|
831
|
+
hooksAreSpecific: {
|
|
832
|
+
id: 2004,
|
|
833
|
+
name: 'Hooks use specific matchers (not catch-all)',
|
|
834
|
+
check: (ctx) => {
|
|
835
|
+
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
836
|
+
if (!settings || !settings.hooks) return true; // no hooks = skip
|
|
837
|
+
const hookStr = JSON.stringify(settings.hooks);
|
|
838
|
+
// Check that hooks have matchers, not just catch-all
|
|
839
|
+
return hookStr.includes('matcher');
|
|
840
|
+
},
|
|
841
|
+
impact: 'medium',
|
|
842
|
+
rating: 3,
|
|
843
|
+
category: 'quality-deep',
|
|
844
|
+
fix: 'Hooks without matchers run on every tool call. Use matchers like "Write|Edit" or "Bash" to target specific tools.',
|
|
845
|
+
template: null
|
|
846
|
+
},
|
|
847
|
+
|
|
848
|
+
permissionsNotBypassed: {
|
|
849
|
+
id: 2005,
|
|
850
|
+
name: 'Default mode is not bypassPermissions',
|
|
851
|
+
check: (ctx) => {
|
|
852
|
+
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
853
|
+
if (!settings || !settings.permissions) return true;
|
|
854
|
+
return settings.permissions.defaultMode !== 'bypassPermissions';
|
|
855
|
+
},
|
|
856
|
+
impact: 'high',
|
|
857
|
+
rating: 4,
|
|
858
|
+
category: 'quality-deep',
|
|
859
|
+
fix: 'bypassPermissions skips all safety checks. Use "default" or "auto" mode with targeted allow rules instead.',
|
|
860
|
+
template: null
|
|
861
|
+
},
|
|
862
|
+
|
|
863
|
+
commandsUseArguments: {
|
|
864
|
+
id: 2006,
|
|
865
|
+
name: 'Commands use $ARGUMENTS for flexibility',
|
|
866
|
+
check: (ctx) => {
|
|
867
|
+
if (!ctx.hasDir('.claude/commands')) return true;
|
|
868
|
+
const files = ctx.dirFiles('.claude/commands');
|
|
869
|
+
if (files.length === 0) return true;
|
|
870
|
+
// Check if at least one command uses $ARGUMENTS
|
|
871
|
+
for (const f of files) {
|
|
872
|
+
const content = ctx.fileContent(`.claude/commands/${f}`) || '';
|
|
873
|
+
if (content.includes('$ARGUMENTS') || content.includes('$arguments')) return true;
|
|
874
|
+
}
|
|
875
|
+
return false;
|
|
876
|
+
},
|
|
877
|
+
impact: 'medium',
|
|
878
|
+
rating: 3,
|
|
879
|
+
category: 'quality-deep',
|
|
880
|
+
fix: 'Commands without $ARGUMENTS are static. Use $ARGUMENTS to make them flexible: "Fix the issue: $ARGUMENTS"',
|
|
881
|
+
template: null
|
|
882
|
+
},
|
|
883
|
+
|
|
884
|
+
agentsHaveMaxTurns: {
|
|
885
|
+
id: 2007,
|
|
886
|
+
name: 'Agents have maxTurns limit',
|
|
887
|
+
check: (ctx) => {
|
|
888
|
+
if (!ctx.hasDir('.claude/agents')) return true;
|
|
889
|
+
const files = ctx.dirFiles('.claude/agents');
|
|
890
|
+
if (files.length === 0) return true;
|
|
891
|
+
for (const f of files) {
|
|
892
|
+
const content = ctx.fileContent(`.claude/agents/${f}`) || '';
|
|
893
|
+
if (!content.includes('maxTurns')) return false;
|
|
894
|
+
}
|
|
895
|
+
return true;
|
|
896
|
+
},
|
|
897
|
+
impact: 'medium',
|
|
898
|
+
rating: 3,
|
|
899
|
+
category: 'quality-deep',
|
|
900
|
+
fix: 'Agents without maxTurns can run indefinitely. Add "maxTurns: 50" to agent frontmatter.',
|
|
901
|
+
template: null
|
|
902
|
+
},
|
|
903
|
+
|
|
904
|
+
securityReviewInWorkflow: {
|
|
905
|
+
id: 2008,
|
|
906
|
+
name: '/security-review in workflow',
|
|
907
|
+
check: (ctx) => {
|
|
908
|
+
const md = ctx.fileContent('CLAUDE.md') || '';
|
|
909
|
+
const hasCommand = ctx.hasDir('.claude/commands') &&
|
|
910
|
+
(ctx.dirFiles('.claude/commands') || []).some(f => f.includes('security') || f.includes('review'));
|
|
911
|
+
return md.toLowerCase().includes('security') || hasCommand;
|
|
912
|
+
},
|
|
913
|
+
impact: 'high',
|
|
914
|
+
rating: 4,
|
|
915
|
+
category: 'quality-deep',
|
|
916
|
+
fix: 'Claude Code has built-in /security-review (OWASP Top 10). Add it to your workflow or create a /security command.',
|
|
917
|
+
template: null
|
|
918
|
+
},
|
|
919
|
+
|
|
920
|
+
noDeprecatedPatterns: {
|
|
921
|
+
id: 2009,
|
|
922
|
+
name: 'No deprecated patterns detected',
|
|
923
|
+
check: (ctx) => {
|
|
924
|
+
const md = ctx.fileContent('CLAUDE.md') || '';
|
|
925
|
+
// Check for patterns deprecated in Claude 4.x
|
|
926
|
+
const deprecated = [
|
|
927
|
+
'prefill', // deprecated in 4.6
|
|
928
|
+
'claude-3-opus', 'claude-3-sonnet', 'claude-3-haiku', // old model names
|
|
929
|
+
'human_prompt', 'assistant_prompt', // old API format
|
|
930
|
+
];
|
|
931
|
+
return !deprecated.some(d => md.toLowerCase().includes(d));
|
|
932
|
+
},
|
|
933
|
+
impact: 'medium',
|
|
934
|
+
rating: 3,
|
|
935
|
+
category: 'quality-deep',
|
|
936
|
+
fix: 'CLAUDE.md references deprecated patterns (old model names or API formats). Update to current Claude 4.x conventions.',
|
|
937
|
+
template: null
|
|
938
|
+
},
|
|
773
939
|
};
|
|
774
940
|
|
|
775
941
|
// Stack detection
|