claudex-setup 1.1.0 → 1.2.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/package.json +1 -1
- package/src/audit.js +18 -0
- package/src/setup.js +116 -21
- package/src/techniques.js +22 -22
package/package.json
CHANGED
package/src/audit.js
CHANGED
|
@@ -76,6 +76,21 @@ async function audit(options) {
|
|
|
76
76
|
const earnedScore = passed.reduce((sum, r) => sum + (weights[r.impact] || 5), 0);
|
|
77
77
|
const score = maxScore > 0 ? Math.round((earnedScore / maxScore) * 100) : 0;
|
|
78
78
|
|
|
79
|
+
// Detect scaffolded vs organic: if CLAUDE.md contains our version stamp, some checks
|
|
80
|
+
// are passing because WE generated them, not the user
|
|
81
|
+
const claudeMd = ctx.fileContent('CLAUDE.md') || '';
|
|
82
|
+
const isScaffolded = claudeMd.includes('Generated by claudex-setup') ||
|
|
83
|
+
claudeMd.includes('claudex-setup');
|
|
84
|
+
// Scaffolded checks: things our setup creates (CLAUDE.md, hooks, commands, agents, rules, skills)
|
|
85
|
+
const scaffoldedKeys = new Set(['claudeMd', 'mermaidArchitecture', 'verificationLoop',
|
|
86
|
+
'hooks', 'customCommands', 'multipleCommands', 'agents', 'pathRules', 'multipleRules',
|
|
87
|
+
'skills', 'hooksConfigured', 'preToolUseHook', 'postToolUseHook', 'fewShotExamples',
|
|
88
|
+
'constraintBlocks', 'xmlTags']);
|
|
89
|
+
const organicPassed = passed.filter(r => !scaffoldedKeys.has(r.key));
|
|
90
|
+
const scaffoldedPassed = passed.filter(r => scaffoldedKeys.has(r.key));
|
|
91
|
+
const organicEarned = organicPassed.reduce((sum, r) => sum + (weights[r.impact] || 5), 0);
|
|
92
|
+
const organicScore = maxScore > 0 ? Math.round((organicEarned / maxScore) * 100) : 0;
|
|
93
|
+
|
|
79
94
|
// Silent mode: skip all output, just return result
|
|
80
95
|
if (silent) {
|
|
81
96
|
return { score, passed: passed.length, failed: failed.length, stacks, results };
|
|
@@ -100,6 +115,9 @@ async function audit(options) {
|
|
|
100
115
|
|
|
101
116
|
// Score
|
|
102
117
|
console.log(` ${progressBar(score)} ${colorize(`${score}/100`, 'bold')}`);
|
|
118
|
+
if (isScaffolded && scaffoldedPassed.length > 0) {
|
|
119
|
+
console.log(colorize(` Organic: ${organicScore}/100 (without claudex-setup generated files)`, 'dim'));
|
|
120
|
+
}
|
|
103
121
|
console.log('');
|
|
104
122
|
|
|
105
123
|
// Passed
|
package/src/setup.js
CHANGED
|
@@ -569,38 +569,109 @@ exit 0
|
|
|
569
569
|
`,
|
|
570
570
|
}),
|
|
571
571
|
|
|
572
|
-
'commands': () =>
|
|
573
|
-
|
|
572
|
+
'commands': (stacks) => {
|
|
573
|
+
const stackKeys = stacks.map(s => s.key);
|
|
574
|
+
const isNext = stackKeys.includes('nextjs');
|
|
575
|
+
const isDjango = stackKeys.includes('django');
|
|
576
|
+
const isFastApi = stackKeys.includes('fastapi');
|
|
577
|
+
const isPython = stackKeys.includes('python') || isDjango || isFastApi;
|
|
578
|
+
const hasDocker = stackKeys.includes('docker');
|
|
579
|
+
|
|
580
|
+
const cmds = {};
|
|
581
|
+
|
|
582
|
+
// Test command - stack-specific
|
|
583
|
+
if (isNext) {
|
|
584
|
+
cmds['test.md'] = `Run the test suite for this Next.js project.
|
|
585
|
+
|
|
586
|
+
## Steps:
|
|
587
|
+
1. Run \`npm test\` (or \`npx vitest run\`)
|
|
588
|
+
2. If tests fail, check for missing mocks or async issues
|
|
589
|
+
3. For component tests, ensure React Testing Library patterns are used
|
|
590
|
+
4. For API route tests, check request/response handling
|
|
591
|
+
5. Report: total, passed, failed, coverage if available
|
|
592
|
+
`;
|
|
593
|
+
} else if (isPython) {
|
|
594
|
+
cmds['test.md'] = `Run the test suite for this Python project.
|
|
595
|
+
|
|
596
|
+
## Steps:
|
|
597
|
+
1. Run \`python -m pytest -v\` (or the project's test command)
|
|
598
|
+
2. Check for fixture issues, missing test database, or import errors
|
|
599
|
+
3. If using Django: \`python manage.py test\`
|
|
600
|
+
4. Report: total, passed, failed, and any tracebacks
|
|
601
|
+
`;
|
|
602
|
+
} else {
|
|
603
|
+
cmds['test.md'] = `Run the test suite and report results.
|
|
574
604
|
|
|
575
605
|
## Steps:
|
|
576
606
|
1. Run the project's test command
|
|
577
607
|
2. If tests fail, analyze the failures
|
|
578
608
|
3. Report: total, passed, failed, and any error details
|
|
579
|
-
|
|
580
|
-
|
|
609
|
+
`;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Review - always generic (works well as-is)
|
|
613
|
+
cmds['review.md'] = `Review the current changes for quality and correctness.
|
|
581
614
|
|
|
582
615
|
## Steps:
|
|
583
616
|
1. Run \`git diff\` to see all changes
|
|
584
617
|
2. Check for: bugs, security issues, missing tests, code style
|
|
585
618
|
3. Provide actionable feedback
|
|
586
|
-
|
|
587
|
-
'deploy.md': `Pre-deployment checklist and deployment steps.
|
|
619
|
+
`;
|
|
588
620
|
|
|
589
|
-
|
|
621
|
+
// Deploy - stack-specific
|
|
622
|
+
if (isNext) {
|
|
623
|
+
cmds['deploy.md'] = `Pre-deployment checklist for Next.js.
|
|
624
|
+
|
|
625
|
+
## Pre-deploy:
|
|
626
|
+
1. Run \`git status\` — working tree must be clean
|
|
627
|
+
2. Run \`npm run build\` — must succeed with no errors
|
|
628
|
+
3. Run \`npm test\` — all tests pass
|
|
629
|
+
4. Run \`npm run lint\` — no lint errors
|
|
630
|
+
5. Check for \`console.log\` in production code
|
|
631
|
+
6. Verify environment variables are set in deployment platform
|
|
632
|
+
|
|
633
|
+
## Deploy:
|
|
634
|
+
1. If Vercel: \`git push\` triggers auto-deploy
|
|
635
|
+
2. If self-hosted: \`npm run build && npm start\`
|
|
636
|
+
3. Verify: check /api/health or main page loads
|
|
637
|
+
4. Tag: \`git tag -a vX.Y.Z -m "Release vX.Y.Z"\`
|
|
638
|
+
`;
|
|
639
|
+
} else if (hasDocker) {
|
|
640
|
+
cmds['deploy.md'] = `Pre-deployment checklist with Docker.
|
|
641
|
+
|
|
642
|
+
## Pre-deploy:
|
|
643
|
+
1. Run \`git status\` — working tree must be clean
|
|
644
|
+
2. Run full test suite — all tests pass
|
|
645
|
+
3. Run \`docker build -t app .\` — must succeed
|
|
646
|
+
4. Run \`docker run app\` locally — smoke test
|
|
647
|
+
|
|
648
|
+
## Deploy:
|
|
649
|
+
1. Build: \`docker build -t registry/app:latest .\`
|
|
650
|
+
2. Push: \`docker push registry/app:latest\`
|
|
651
|
+
3. Deploy to target environment
|
|
652
|
+
4. Verify health endpoint responds
|
|
653
|
+
5. Tag: \`git tag -a vX.Y.Z -m "Release vX.Y.Z"\`
|
|
654
|
+
`;
|
|
655
|
+
} else {
|
|
656
|
+
cmds['deploy.md'] = `Pre-deployment checklist.
|
|
657
|
+
|
|
658
|
+
## Pre-deploy:
|
|
590
659
|
1. Run \`git status\` — working tree must be clean
|
|
591
660
|
2. Run full test suite — all tests must pass
|
|
592
|
-
3. Run linter — no errors
|
|
593
|
-
4.
|
|
594
|
-
5.
|
|
595
|
-
|
|
596
|
-
## Deploy
|
|
597
|
-
1. Confirm target environment
|
|
598
|
-
2.
|
|
599
|
-
3.
|
|
600
|
-
4.
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
661
|
+
3. Run linter — no errors
|
|
662
|
+
4. Verify no secrets in staged changes
|
|
663
|
+
5. Review diff since last deploy
|
|
664
|
+
|
|
665
|
+
## Deploy:
|
|
666
|
+
1. Confirm target environment
|
|
667
|
+
2. Run deployment command
|
|
668
|
+
3. Verify deployment (health check)
|
|
669
|
+
4. Tag: \`git tag -a vX.Y.Z -m "Release vX.Y.Z"\`
|
|
670
|
+
`;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Fix - always generic with $ARGUMENTS
|
|
674
|
+
cmds['fix.md'] = `Fix the issue described: $ARGUMENTS
|
|
604
675
|
|
|
605
676
|
## Steps:
|
|
606
677
|
1. Understand the issue — read relevant code and error messages
|
|
@@ -609,8 +680,32 @@ exit 0
|
|
|
609
680
|
4. Write or update tests to cover the fix
|
|
610
681
|
5. Run the full test suite to verify no regressions
|
|
611
682
|
6. Summarize what was wrong and how the fix addresses it
|
|
612
|
-
|
|
613
|
-
|
|
683
|
+
`;
|
|
684
|
+
|
|
685
|
+
// Stack-specific bonus commands
|
|
686
|
+
if (isNext) {
|
|
687
|
+
cmds['check-build.md'] = `Run Next.js build check without deploying.
|
|
688
|
+
|
|
689
|
+
1. Run \`npx next build\`
|
|
690
|
+
2. Check for: TypeScript errors, missing pages, broken imports
|
|
691
|
+
3. Verify no "Dynamic server usage" errors in static pages
|
|
692
|
+
4. Report build output size and any warnings
|
|
693
|
+
`;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (isPython && (isDjango || isFastApi)) {
|
|
697
|
+
cmds['migrate.md'] = `Run database migrations safely.
|
|
698
|
+
|
|
699
|
+
1. Check current migration status${isDjango ? ': `python manage.py showmigrations`' : ''}
|
|
700
|
+
2. Create new migration if schema changed${isDjango ? ': `python manage.py makemigrations`' : ''}
|
|
701
|
+
3. Review the generated migration file
|
|
702
|
+
4. Apply: ${isDjango ? '`python manage.py migrate`' : '`alembic upgrade head`'}
|
|
703
|
+
5. Verify: check that the app starts and queries work
|
|
704
|
+
`;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
return cmds;
|
|
708
|
+
},
|
|
614
709
|
|
|
615
710
|
'skills': () => ({
|
|
616
711
|
'fix-issue/SKILL.md': `---
|
package/src/techniques.js
CHANGED
|
@@ -92,7 +92,7 @@ const TECHNIQUES = {
|
|
|
92
92
|
},
|
|
93
93
|
|
|
94
94
|
testCommand: {
|
|
95
|
-
id:
|
|
95
|
+
id: 93001,
|
|
96
96
|
name: 'CLAUDE.md contains a test command',
|
|
97
97
|
check: (ctx) => {
|
|
98
98
|
const md = ctx.fileContent('CLAUDE.md') || '';
|
|
@@ -106,7 +106,7 @@ const TECHNIQUES = {
|
|
|
106
106
|
},
|
|
107
107
|
|
|
108
108
|
lintCommand: {
|
|
109
|
-
id:
|
|
109
|
+
id: 93002,
|
|
110
110
|
name: 'CLAUDE.md contains a lint command',
|
|
111
111
|
check: (ctx) => {
|
|
112
112
|
const md = ctx.fileContent('CLAUDE.md') || '';
|
|
@@ -120,7 +120,7 @@ const TECHNIQUES = {
|
|
|
120
120
|
},
|
|
121
121
|
|
|
122
122
|
buildCommand: {
|
|
123
|
-
id:
|
|
123
|
+
id: 93003,
|
|
124
124
|
name: 'CLAUDE.md contains a build command',
|
|
125
125
|
check: (ctx) => {
|
|
126
126
|
const md = ctx.fileContent('CLAUDE.md') || '';
|
|
@@ -167,7 +167,7 @@ const TECHNIQUES = {
|
|
|
167
167
|
},
|
|
168
168
|
|
|
169
169
|
gitIgnoreNodeModules: {
|
|
170
|
-
id:
|
|
170
|
+
id: 91701,
|
|
171
171
|
name: '.gitignore blocks node_modules',
|
|
172
172
|
check: (ctx) => {
|
|
173
173
|
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
@@ -210,7 +210,7 @@ const TECHNIQUES = {
|
|
|
210
210
|
},
|
|
211
211
|
|
|
212
212
|
multipleCommands: {
|
|
213
|
-
id:
|
|
213
|
+
id: 20001,
|
|
214
214
|
name: '3+ slash commands for rich workflow',
|
|
215
215
|
check: (ctx) => ctx.hasDir('.claude/commands') && ctx.dirFiles('.claude/commands').length >= 3,
|
|
216
216
|
impact: 'medium',
|
|
@@ -221,7 +221,7 @@ const TECHNIQUES = {
|
|
|
221
221
|
},
|
|
222
222
|
|
|
223
223
|
deployCommand: {
|
|
224
|
-
id:
|
|
224
|
+
id: 20002,
|
|
225
225
|
name: 'Has /deploy or /release command',
|
|
226
226
|
check: (ctx) => {
|
|
227
227
|
if (!ctx.hasDir('.claude/commands')) return false;
|
|
@@ -236,7 +236,7 @@ const TECHNIQUES = {
|
|
|
236
236
|
},
|
|
237
237
|
|
|
238
238
|
reviewCommand: {
|
|
239
|
-
id:
|
|
239
|
+
id: 20003,
|
|
240
240
|
name: 'Has /review command',
|
|
241
241
|
check: (ctx) => {
|
|
242
242
|
if (!ctx.hasDir('.claude/commands')) return false;
|
|
@@ -262,7 +262,7 @@ const TECHNIQUES = {
|
|
|
262
262
|
},
|
|
263
263
|
|
|
264
264
|
multipleSkills: {
|
|
265
|
-
id:
|
|
265
|
+
id: 2101,
|
|
266
266
|
name: '2+ skills for specialization',
|
|
267
267
|
check: (ctx) => ctx.hasDir('.claude/skills') && ctx.dirFiles('.claude/skills').length >= 2,
|
|
268
268
|
impact: 'medium',
|
|
@@ -284,7 +284,7 @@ const TECHNIQUES = {
|
|
|
284
284
|
},
|
|
285
285
|
|
|
286
286
|
multipleAgents: {
|
|
287
|
-
id:
|
|
287
|
+
id: 2201,
|
|
288
288
|
name: '2+ agents for delegation',
|
|
289
289
|
check: (ctx) => ctx.hasDir('.claude/agents') && ctx.dirFiles('.claude/agents').length >= 2,
|
|
290
290
|
impact: 'medium',
|
|
@@ -295,7 +295,7 @@ const TECHNIQUES = {
|
|
|
295
295
|
},
|
|
296
296
|
|
|
297
297
|
multipleRules: {
|
|
298
|
-
id:
|
|
298
|
+
id: 301,
|
|
299
299
|
name: '2+ rules files for granular control',
|
|
300
300
|
check: (ctx) => ctx.hasDir('.claude/rules') && ctx.dirFiles('.claude/rules').length >= 2,
|
|
301
301
|
impact: 'medium',
|
|
@@ -324,7 +324,7 @@ const TECHNIQUES = {
|
|
|
324
324
|
},
|
|
325
325
|
|
|
326
326
|
permissionDeny: {
|
|
327
|
-
id:
|
|
327
|
+
id: 2401,
|
|
328
328
|
name: 'Deny rules configured in permissions',
|
|
329
329
|
check: (ctx) => {
|
|
330
330
|
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
@@ -340,7 +340,7 @@ const TECHNIQUES = {
|
|
|
340
340
|
},
|
|
341
341
|
|
|
342
342
|
noBypassPermissions: {
|
|
343
|
-
id:
|
|
343
|
+
id: 2402,
|
|
344
344
|
name: 'Default mode is not bypassPermissions',
|
|
345
345
|
check: (ctx) => {
|
|
346
346
|
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
@@ -400,7 +400,7 @@ const TECHNIQUES = {
|
|
|
400
400
|
},
|
|
401
401
|
|
|
402
402
|
hooksInSettings: {
|
|
403
|
-
id:
|
|
403
|
+
id: 8801,
|
|
404
404
|
name: 'Hooks configured in settings',
|
|
405
405
|
check: (ctx) => {
|
|
406
406
|
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
@@ -415,7 +415,7 @@ const TECHNIQUES = {
|
|
|
415
415
|
},
|
|
416
416
|
|
|
417
417
|
preToolUseHook: {
|
|
418
|
-
id:
|
|
418
|
+
id: 8802,
|
|
419
419
|
name: 'PreToolUse hook configured',
|
|
420
420
|
check: (ctx) => {
|
|
421
421
|
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
@@ -430,7 +430,7 @@ const TECHNIQUES = {
|
|
|
430
430
|
},
|
|
431
431
|
|
|
432
432
|
postToolUseHook: {
|
|
433
|
-
id:
|
|
433
|
+
id: 8803,
|
|
434
434
|
name: 'PostToolUse hook configured',
|
|
435
435
|
check: (ctx) => {
|
|
436
436
|
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
@@ -445,7 +445,7 @@ const TECHNIQUES = {
|
|
|
445
445
|
},
|
|
446
446
|
|
|
447
447
|
sessionStartHook: {
|
|
448
|
-
id:
|
|
448
|
+
id: 8804,
|
|
449
449
|
name: 'SessionStart hook configured',
|
|
450
450
|
check: (ctx) => {
|
|
451
451
|
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
@@ -478,7 +478,7 @@ const TECHNIQUES = {
|
|
|
478
478
|
},
|
|
479
479
|
|
|
480
480
|
tailwindMention: {
|
|
481
|
-
id:
|
|
481
|
+
id: 102501,
|
|
482
482
|
name: 'Tailwind CSS configured',
|
|
483
483
|
check: (ctx) => {
|
|
484
484
|
const pkg = ctx.fileContent('package.json') || '';
|
|
@@ -508,7 +508,7 @@ const TECHNIQUES = {
|
|
|
508
508
|
},
|
|
509
509
|
|
|
510
510
|
dockerCompose: {
|
|
511
|
-
id:
|
|
511
|
+
id: 39901,
|
|
512
512
|
name: 'Has docker-compose.yml',
|
|
513
513
|
check: (ctx) => ctx.files.some(f => /^docker-compose\.(yml|yaml)$/i.test(f)),
|
|
514
514
|
impact: 'medium',
|
|
@@ -589,7 +589,7 @@ const TECHNIQUES = {
|
|
|
589
589
|
},
|
|
590
590
|
|
|
591
591
|
editorconfig: {
|
|
592
|
-
id:
|
|
592
|
+
id: 5001,
|
|
593
593
|
name: 'Has .editorconfig',
|
|
594
594
|
check: (ctx) => ctx.files.includes('.editorconfig'),
|
|
595
595
|
impact: 'low',
|
|
@@ -600,7 +600,7 @@ const TECHNIQUES = {
|
|
|
600
600
|
},
|
|
601
601
|
|
|
602
602
|
nvmrc: {
|
|
603
|
-
id:
|
|
603
|
+
id: 5002,
|
|
604
604
|
name: 'Node version pinned',
|
|
605
605
|
check: (ctx) => {
|
|
606
606
|
if (ctx.files.includes('.nvmrc') || ctx.files.includes('.node-version')) return true;
|
|
@@ -665,7 +665,7 @@ const TECHNIQUES = {
|
|
|
665
665
|
},
|
|
666
666
|
|
|
667
667
|
multipleMcpServers: {
|
|
668
|
-
id:
|
|
668
|
+
id: 1801,
|
|
669
669
|
name: '2+ MCP servers for rich tooling',
|
|
670
670
|
check: (ctx) => {
|
|
671
671
|
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
@@ -746,7 +746,7 @@ const TECHNIQUES = {
|
|
|
746
746
|
},
|
|
747
747
|
|
|
748
748
|
constraintBlocks: {
|
|
749
|
-
id:
|
|
749
|
+
id: 9601,
|
|
750
750
|
name: 'XML constraint blocks in CLAUDE.md',
|
|
751
751
|
check: (ctx) => {
|
|
752
752
|
const md = ctx.fileContent('CLAUDE.md') || '';
|