@nerviq/cli 0.0.1 → 0.9.0-beta.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.
Files changed (148) hide show
  1. package/CHANGELOG.md +181 -0
  2. package/LICENSE +21 -0
  3. package/README.md +447 -0
  4. package/bin/cli.js +749 -0
  5. package/content/case-study-template.md +91 -0
  6. package/content/claims-governance.md +37 -0
  7. package/content/claude-code/audit-repo/SKILL.md +20 -0
  8. package/content/claude-native-integration.md +60 -0
  9. package/content/devto-article.json +9 -0
  10. package/content/launch-posts.md +226 -0
  11. package/content/pilot-rollout-kit.md +30 -0
  12. package/content/release-checklist.md +31 -0
  13. package/package.json +53 -4
  14. package/src/activity.js +529 -0
  15. package/src/aider/activity.js +226 -0
  16. package/src/aider/config-parser.js +166 -0
  17. package/src/aider/context.js +158 -0
  18. package/src/aider/deep-review.js +316 -0
  19. package/src/aider/domain-packs.js +278 -0
  20. package/src/aider/freshness.js +168 -0
  21. package/src/aider/governance.js +253 -0
  22. package/src/aider/interactive.js +334 -0
  23. package/src/aider/mcp-packs.js +98 -0
  24. package/src/aider/patch.js +214 -0
  25. package/src/aider/plans.js +186 -0
  26. package/src/aider/premium.js +360 -0
  27. package/src/aider/setup.js +404 -0
  28. package/src/aider/techniques.js +1323 -0
  29. package/src/analyze.js +821 -0
  30. package/src/audit.js +1003 -0
  31. package/src/badge.js +13 -0
  32. package/src/benchmark.js +339 -0
  33. package/src/claudex-sync.json +7 -0
  34. package/src/codex/activity.js +324 -0
  35. package/src/codex/config-parser.js +183 -0
  36. package/src/codex/context.js +221 -0
  37. package/src/codex/deep-review.js +493 -0
  38. package/src/codex/domain-packs.js +372 -0
  39. package/src/codex/freshness.js +167 -0
  40. package/src/codex/governance.js +192 -0
  41. package/src/codex/interactive.js +618 -0
  42. package/src/codex/mcp-packs.js +660 -0
  43. package/src/codex/patch.js +209 -0
  44. package/src/codex/plans.js +251 -0
  45. package/src/codex/premium.js +614 -0
  46. package/src/codex/setup.js +603 -0
  47. package/src/codex/techniques.js +2649 -0
  48. package/src/context.js +272 -0
  49. package/src/copilot/activity.js +309 -0
  50. package/src/copilot/config-parser.js +226 -0
  51. package/src/copilot/context.js +197 -0
  52. package/src/copilot/deep-review.js +346 -0
  53. package/src/copilot/domain-packs.js +350 -0
  54. package/src/copilot/freshness.js +197 -0
  55. package/src/copilot/governance.js +222 -0
  56. package/src/copilot/interactive.js +406 -0
  57. package/src/copilot/mcp-packs.js +572 -0
  58. package/src/copilot/patch.js +238 -0
  59. package/src/copilot/plans.js +253 -0
  60. package/src/copilot/premium.js +450 -0
  61. package/src/copilot/setup.js +488 -0
  62. package/src/copilot/techniques.js +1822 -0
  63. package/src/cursor/activity.js +301 -0
  64. package/src/cursor/config-parser.js +265 -0
  65. package/src/cursor/context.js +236 -0
  66. package/src/cursor/deep-review.js +334 -0
  67. package/src/cursor/domain-packs.js +346 -0
  68. package/src/cursor/freshness.js +214 -0
  69. package/src/cursor/governance.js +229 -0
  70. package/src/cursor/interactive.js +391 -0
  71. package/src/cursor/mcp-packs.js +571 -0
  72. package/src/cursor/patch.js +243 -0
  73. package/src/cursor/plans.js +254 -0
  74. package/src/cursor/premium.js +468 -0
  75. package/src/cursor/setup.js +488 -0
  76. package/src/cursor/techniques.js +1786 -0
  77. package/src/deep-review.js +345 -0
  78. package/src/domain-packs.js +364 -0
  79. package/src/formatters/sarif.js +115 -0
  80. package/src/gemini/activity.js +402 -0
  81. package/src/gemini/config-parser.js +275 -0
  82. package/src/gemini/context.js +221 -0
  83. package/src/gemini/deep-review.js +559 -0
  84. package/src/gemini/domain-packs.js +371 -0
  85. package/src/gemini/freshness.js +204 -0
  86. package/src/gemini/governance.js +201 -0
  87. package/src/gemini/interactive.js +860 -0
  88. package/src/gemini/mcp-packs.js +658 -0
  89. package/src/gemini/patch.js +229 -0
  90. package/src/gemini/plans.js +269 -0
  91. package/src/gemini/premium.js +759 -0
  92. package/src/gemini/setup.js +692 -0
  93. package/src/gemini/techniques.js +2084 -0
  94. package/src/governance.js +523 -0
  95. package/src/harmony/advisor.js +383 -0
  96. package/src/harmony/audit.js +303 -0
  97. package/src/harmony/canon.js +444 -0
  98. package/src/harmony/cli.js +331 -0
  99. package/src/harmony/drift.js +401 -0
  100. package/src/harmony/governance.js +313 -0
  101. package/src/harmony/memory.js +238 -0
  102. package/src/harmony/sync.js +458 -0
  103. package/src/harmony/watch.js +336 -0
  104. package/src/index.js +256 -0
  105. package/src/insights.js +119 -0
  106. package/src/interactive.js +118 -0
  107. package/src/mcp-packs.js +597 -0
  108. package/src/opencode/activity.js +286 -0
  109. package/src/opencode/config-parser.js +109 -0
  110. package/src/opencode/context.js +247 -0
  111. package/src/opencode/deep-review.js +313 -0
  112. package/src/opencode/domain-packs.js +240 -0
  113. package/src/opencode/freshness.js +158 -0
  114. package/src/opencode/governance.js +159 -0
  115. package/src/opencode/interactive.js +392 -0
  116. package/src/opencode/mcp-packs.js +474 -0
  117. package/src/opencode/patch.js +184 -0
  118. package/src/opencode/plans.js +231 -0
  119. package/src/opencode/premium.js +413 -0
  120. package/src/opencode/setup.js +449 -0
  121. package/src/opencode/techniques.js +1713 -0
  122. package/src/plans.js +655 -0
  123. package/src/secret-patterns.js +30 -0
  124. package/src/setup.js +1274 -0
  125. package/src/synergy/adaptive.js +261 -0
  126. package/src/synergy/compensation.js +156 -0
  127. package/src/synergy/evidence.js +193 -0
  128. package/src/synergy/learning.js +184 -0
  129. package/src/synergy/patterns.js +227 -0
  130. package/src/synergy/ranking.js +83 -0
  131. package/src/synergy/report.js +163 -0
  132. package/src/synergy/routing.js +152 -0
  133. package/src/techniques.js +1354 -0
  134. package/src/watch.js +229 -0
  135. package/src/windsurf/activity.js +302 -0
  136. package/src/windsurf/config-parser.js +267 -0
  137. package/src/windsurf/context.js +249 -0
  138. package/src/windsurf/deep-review.js +337 -0
  139. package/src/windsurf/domain-packs.js +348 -0
  140. package/src/windsurf/freshness.js +215 -0
  141. package/src/windsurf/governance.js +231 -0
  142. package/src/windsurf/interactive.js +388 -0
  143. package/src/windsurf/mcp-packs.js +535 -0
  144. package/src/windsurf/patch.js +231 -0
  145. package/src/windsurf/plans.js +247 -0
  146. package/src/windsurf/premium.js +467 -0
  147. package/src/windsurf/setup.js +471 -0
  148. package/src/windsurf/techniques.js +1758 -0
@@ -0,0 +1,1354 @@
1
+ /**
2
+ * CLAUDEX Technique Database
3
+ * Curated from 1107 verified techniques, filtered to actionable setup recommendations.
4
+ * Each technique includes: what to check, how to fix, impact level.
5
+ */
6
+
7
+ function hasFrontendSignals(ctx) {
8
+ const pkg = ctx.fileContent('package.json') || '';
9
+ return /react|vue|angular|next|svelte|tailwind|vite|astro/i.test(pkg) ||
10
+ ctx.files.some(f => /tailwind\.config|vite\.config|next\.config|svelte\.config|nuxt\.config|pages\/|components\/|app\//i.test(f));
11
+ }
12
+
13
+ const { containsEmbeddedSecret } = require('./secret-patterns');
14
+
15
+ const TECHNIQUES = {
16
+ // ============================================================
17
+ // === MEMORY & CONTEXT (category: 'memory') ==================
18
+ // ============================================================
19
+
20
+ claudeMd: {
21
+ id: 1,
22
+ name: 'CLAUDE.md project instructions',
23
+ check: (ctx) => ctx.files.includes('CLAUDE.md') || ctx.files.includes('.claude/CLAUDE.md'),
24
+ impact: 'critical',
25
+ rating: 5,
26
+ category: 'memory',
27
+ fix: 'Create CLAUDE.md with project-specific instructions, build commands, and coding conventions.',
28
+ template: 'claude-md'
29
+ },
30
+
31
+ mermaidArchitecture: {
32
+ id: 51,
33
+ name: 'Mermaid architecture diagram',
34
+ check: (ctx) => {
35
+ const md = ctx.claudeMdContent() || '';
36
+ return md.includes('mermaid') || md.includes('graph ') || md.includes('flowchart ');
37
+ },
38
+ impact: 'high',
39
+ rating: 5,
40
+ category: 'memory',
41
+ fix: 'Add a Mermaid diagram to CLAUDE.md showing project architecture. Saves 73% tokens vs prose.',
42
+ template: 'mermaid'
43
+ },
44
+
45
+ pathRules: {
46
+ id: 3,
47
+ name: 'Path-specific rules',
48
+ check: (ctx) => ctx.hasDir('.claude/rules') && ctx.dirFiles('.claude/rules').length > 0,
49
+ impact: 'medium',
50
+ rating: 4,
51
+ category: 'memory',
52
+ fix: 'Add rules for different file types (frontend vs backend conventions).',
53
+ template: 'rules'
54
+ },
55
+
56
+ importSyntax: {
57
+ id: 763,
58
+ name: 'CLAUDE.md uses @import for modularity',
59
+ check: (ctx) => {
60
+ const md = ctx.claudeMdContent() || '';
61
+ return md.includes('@import');
62
+ },
63
+ impact: 'medium',
64
+ rating: 4,
65
+ category: 'memory',
66
+ fix: 'Use @import in CLAUDE.md to split instructions into focused modules (e.g. @import ./docs/coding-style.md).',
67
+ template: null
68
+ },
69
+
70
+ underlines200: {
71
+ id: 681,
72
+ name: 'CLAUDE.md under 200 lines (concise)',
73
+ check: (ctx) => {
74
+ const md = ctx.claudeMdContent() || '';
75
+ return md.split('\n').length <= 200;
76
+ },
77
+ impact: 'medium',
78
+ rating: 4,
79
+ category: 'memory',
80
+ fix: 'Keep CLAUDE.md under 200 lines. Use @import or .claude/rules/ to split large instructions.',
81
+ template: null
82
+ },
83
+
84
+ // ============================================================
85
+ // === QUALITY & TESTING (category: 'quality') ================
86
+ // ============================================================
87
+
88
+ verificationLoop: {
89
+ id: 93,
90
+ name: 'Verification criteria in CLAUDE.md',
91
+ check: (ctx) => {
92
+ const md = ctx.claudeMdContent() || '';
93
+ return /\b(npm test|yarn test|pnpm test|pytest|go test|make test|npm run lint|yarn lint|npx |ruff |eslint)\b/i.test(md) ||
94
+ /\b(test command|lint command|build command|verify|run tests|run lint)\b/i.test(md);
95
+ },
96
+ impact: 'critical',
97
+ rating: 5,
98
+ category: 'quality',
99
+ fix: 'Add test/lint/build commands to CLAUDE.md so Claude can verify its own work.',
100
+ template: null
101
+ },
102
+
103
+ testCommand: {
104
+ id: 93001,
105
+ name: 'CLAUDE.md contains a test command',
106
+ check: (ctx) => {
107
+ const md = ctx.claudeMdContent() || '';
108
+ return /npm test|pytest|jest|vitest|cargo test|go test|mix test|rspec/.test(md);
109
+ },
110
+ impact: 'high',
111
+ rating: 5,
112
+ category: 'quality',
113
+ fix: 'Add an explicit test command to CLAUDE.md (e.g. "Run `npm test` before committing").',
114
+ template: null
115
+ },
116
+
117
+ lintCommand: {
118
+ id: 93002,
119
+ name: 'CLAUDE.md contains a lint command',
120
+ check: (ctx) => {
121
+ const md = ctx.claudeMdContent() || '';
122
+ return /eslint|prettier|ruff|black|clippy|golangci-lint|rubocop|npm run lint|yarn lint|pnpm lint|bun lint/.test(md);
123
+ },
124
+ impact: 'high',
125
+ rating: 4,
126
+ category: 'quality',
127
+ fix: 'Add a lint command to CLAUDE.md so Claude auto-formats and checks code style.',
128
+ template: null
129
+ },
130
+
131
+ buildCommand: {
132
+ id: 93003,
133
+ name: 'CLAUDE.md contains a build command',
134
+ check: (ctx) => {
135
+ const md = ctx.claudeMdContent() || '';
136
+ return /npm run build|cargo build|go build|make|tsc|gradle build|mvn compile/.test(md);
137
+ },
138
+ impact: 'medium',
139
+ rating: 4,
140
+ category: 'quality',
141
+ fix: 'Add a build command to CLAUDE.md so Claude can verify compilation before committing.',
142
+ template: null
143
+ },
144
+
145
+ // ============================================================
146
+ // === GIT SAFETY (category: 'git') ===========================
147
+ // ============================================================
148
+
149
+ gitIgnoreClaudeTracked: {
150
+ id: 976,
151
+ name: '.claude/ tracked in git',
152
+ check: (ctx) => {
153
+ if (!ctx.fileContent('.gitignore')) return true; // no gitignore = ok
154
+ const lines = ctx.fileContent('.gitignore')
155
+ .split(/\r?\n/)
156
+ .map(line => line.trim())
157
+ .filter(line => line && !line.startsWith('#'));
158
+ const ignoresClaudeDir = lines.some(line => /^(\/|\*\*\/)?\.claude\/?$/.test(line));
159
+ const unignoresClaudeDir = lines.some(line => /^!(\/)?\.claude(\/|\*\*)?$/.test(line));
160
+ return !ignoresClaudeDir || unignoresClaudeDir;
161
+ },
162
+ impact: 'high',
163
+ rating: 4,
164
+ category: 'git',
165
+ fix: 'Remove .claude/ from .gitignore (keep .claude/settings.local.json ignored).',
166
+ template: null
167
+ },
168
+
169
+ gitIgnoreEnv: {
170
+ id: 917,
171
+ name: '.gitignore blocks .env files',
172
+ check: (ctx) => {
173
+ const gitignore = ctx.fileContent('.gitignore') || '';
174
+ return gitignore.includes('.env');
175
+ },
176
+ impact: 'critical',
177
+ rating: 5,
178
+ category: 'git',
179
+ fix: 'Add .env to .gitignore to prevent leaking secrets.',
180
+ template: null
181
+ },
182
+
183
+ gitIgnoreNodeModules: {
184
+ id: 91701,
185
+ name: '.gitignore blocks node_modules',
186
+ check: (ctx) => {
187
+ const hasNodeSignals = ctx.files.includes('package.json') ||
188
+ ctx.files.includes('tsconfig.json') ||
189
+ ctx.files.some(f => /package-lock\.json|pnpm-lock\.yaml|yarn\.lock|next\.config|vite\.config/i.test(f));
190
+ if (!hasNodeSignals) return null;
191
+ const gitignore = ctx.fileContent('.gitignore') || '';
192
+ return gitignore.includes('node_modules');
193
+ },
194
+ impact: 'high',
195
+ rating: 4,
196
+ category: 'git',
197
+ fix: 'Add node_modules/ to .gitignore.',
198
+ template: null
199
+ },
200
+
201
+ noSecretsInClaude: {
202
+ id: 1039,
203
+ name: 'CLAUDE.md has no embedded API keys',
204
+ check: (ctx) => {
205
+ const md = ctx.claudeMdContent() || '';
206
+ return !containsEmbeddedSecret(md);
207
+ },
208
+ impact: 'critical',
209
+ rating: 5,
210
+ category: 'git',
211
+ fix: 'Remove API keys from CLAUDE.md. Use environment variables or .env files instead.',
212
+ template: null
213
+ },
214
+
215
+ // ============================================================
216
+ // === WORKFLOW (category: 'workflow') =========================
217
+ // ============================================================
218
+
219
+ customCommands: {
220
+ id: 20,
221
+ name: 'Custom slash commands',
222
+ check: (ctx) => ctx.hasDir('.claude/commands') && ctx.dirFiles('.claude/commands').length > 0,
223
+ impact: 'high',
224
+ rating: 4,
225
+ category: 'workflow',
226
+ fix: 'Create custom commands for repeated workflows (/test, /deploy, /review).',
227
+ template: 'commands'
228
+ },
229
+
230
+ multipleCommands: {
231
+ id: 20001,
232
+ name: '3+ slash commands for rich workflow',
233
+ check: (ctx) => ctx.hasDir('.claude/commands') && ctx.dirFiles('.claude/commands').length >= 3,
234
+ impact: 'medium',
235
+ rating: 4,
236
+ category: 'workflow',
237
+ fix: 'Add at least 3 slash commands to cover your main workflows (test, deploy, review, etc.).',
238
+ template: 'commands'
239
+ },
240
+
241
+ deployCommand: {
242
+ id: 20002,
243
+ name: 'Has /deploy or /release command',
244
+ check: (ctx) => {
245
+ if (!ctx.hasDir('.claude/commands')) return false;
246
+ const files = ctx.dirFiles('.claude/commands');
247
+ return files.some(f => /deploy|release/i.test(f));
248
+ },
249
+ impact: 'medium',
250
+ rating: 4,
251
+ category: 'workflow',
252
+ fix: 'Create a /deploy or /release command for one-click deployments.',
253
+ template: null
254
+ },
255
+
256
+ reviewCommand: {
257
+ id: 20003,
258
+ name: 'Has /review command',
259
+ check: (ctx) => {
260
+ if (!ctx.hasDir('.claude/commands')) return false;
261
+ const files = ctx.dirFiles('.claude/commands');
262
+ return files.some(f => /review/i.test(f));
263
+ },
264
+ impact: 'medium',
265
+ rating: 4,
266
+ category: 'workflow',
267
+ fix: 'Create a /review command for code review workflows.',
268
+ template: null
269
+ },
270
+
271
+ skills: {
272
+ id: 21,
273
+ name: 'Custom skills',
274
+ check: (ctx) => ctx.hasDir('.claude/skills') && ctx.dirFiles('.claude/skills').length > 0,
275
+ impact: 'medium',
276
+ rating: 4,
277
+ category: 'workflow',
278
+ fix: 'Add skills for domain-specific workflows.',
279
+ template: 'skills'
280
+ },
281
+
282
+ multipleSkills: {
283
+ id: 2101,
284
+ name: '2+ skills for specialization',
285
+ check: (ctx) => ctx.hasDir('.claude/skills') && ctx.dirFiles('.claude/skills').length >= 2,
286
+ impact: 'medium',
287
+ rating: 4,
288
+ category: 'workflow',
289
+ fix: 'Add at least 2 skills to cover different domain areas.',
290
+ template: 'skills'
291
+ },
292
+
293
+ agents: {
294
+ id: 22,
295
+ name: 'Custom agents',
296
+ check: (ctx) => ctx.hasDir('.claude/agents') && ctx.dirFiles('.claude/agents').length > 0,
297
+ impact: 'medium',
298
+ rating: 4,
299
+ category: 'workflow',
300
+ fix: 'Create specialized agents (security-reviewer, test-writer) in .claude/agents/.',
301
+ template: 'agents'
302
+ },
303
+
304
+ multipleAgents: {
305
+ id: 2201,
306
+ name: '2+ agents for delegation',
307
+ check: (ctx) => ctx.hasDir('.claude/agents') && ctx.dirFiles('.claude/agents').length >= 2,
308
+ impact: 'medium',
309
+ rating: 4,
310
+ category: 'workflow',
311
+ fix: 'Add at least 2 agents for specialized tasks (e.g. security-reviewer, test-writer).',
312
+ template: 'agents'
313
+ },
314
+
315
+ multipleRules: {
316
+ id: 301,
317
+ name: '2+ rules files for granular control',
318
+ check: (ctx) => ctx.hasDir('.claude/rules') && ctx.dirFiles('.claude/rules').length >= 2,
319
+ impact: 'medium',
320
+ rating: 4,
321
+ category: 'workflow',
322
+ fix: 'Add path-specific rules for different parts of the codebase (frontend, backend, tests).',
323
+ template: 'rules'
324
+ },
325
+
326
+ // ============================================================
327
+ // === SECURITY (category: 'security') ========================
328
+ // ============================================================
329
+
330
+ settingsPermissions: {
331
+ id: 24,
332
+ name: 'Permission configuration',
333
+ check: (ctx) => {
334
+ // Prefer local (effective config) — any settings file with permissions passes
335
+ const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
336
+ return !!(settings && settings.permissions);
337
+ },
338
+ impact: 'medium',
339
+ rating: 4,
340
+ category: 'security',
341
+ fix: 'Configure allow/deny permission lists for safe tool usage.',
342
+ template: null
343
+ },
344
+
345
+ permissionDeny: {
346
+ id: 2401,
347
+ name: 'Deny rules configured in permissions',
348
+ check: (ctx) => {
349
+ const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
350
+ if (!settings || !settings.permissions) return false;
351
+ const deny = settings.permissions.deny;
352
+ return Array.isArray(deny) && deny.length > 0;
353
+ },
354
+ impact: 'high',
355
+ rating: 5,
356
+ category: 'security',
357
+ fix: 'Add permissions.deny rules to block dangerous operations (e.g. rm -rf, dropping databases).',
358
+ template: null
359
+ },
360
+
361
+ noBypassPermissions: {
362
+ id: 2402,
363
+ name: 'Default mode is not bypassPermissions',
364
+ check: (ctx) => {
365
+ // Check shared settings first (committed to git) — if the shared baseline
366
+ // is safe, a personal settings.local.json override should not fail the audit.
367
+ const shared = ctx.jsonFile('.claude/settings.json');
368
+ if (shared && shared.permissions) {
369
+ return shared.permissions.defaultMode !== 'bypassPermissions';
370
+ }
371
+ const local = ctx.jsonFile('.claude/settings.local.json');
372
+ if (!local || !local.permissions) return null;
373
+ return local.permissions.defaultMode !== 'bypassPermissions';
374
+ },
375
+ impact: 'critical',
376
+ rating: 5,
377
+ category: 'security',
378
+ fix: 'Do not set defaultMode to bypassPermissions. Use explicit allow rules instead.',
379
+ template: null
380
+ },
381
+
382
+ secretsProtection: {
383
+ id: 1096,
384
+ name: 'Secrets protection configured',
385
+ check: (ctx) => {
386
+ // Prefer shared settings.json (committed) over local override
387
+ const settings = ctx.jsonFile('.claude/settings.json') || ctx.jsonFile('.claude/settings.local.json');
388
+ if (!settings || !settings.permissions) return false;
389
+ const deny = JSON.stringify(settings.permissions.deny || []);
390
+ return deny.includes('.env') || deny.includes('secrets');
391
+ },
392
+ impact: 'critical',
393
+ rating: 5,
394
+ category: 'security',
395
+ fix: 'Add permissions.deny rules to block reading .env files and secrets directories.',
396
+ template: null
397
+ },
398
+
399
+ securityReview: {
400
+ id: 1031,
401
+ name: 'Security review command awareness',
402
+ check: (ctx) => {
403
+ const md = ctx.claudeMdContent() || '';
404
+ return md.includes('security') || md.includes('/security-review');
405
+ },
406
+ impact: 'high',
407
+ rating: 5,
408
+ category: 'security',
409
+ fix: 'Add /security-review to your workflow. Claude Code has built-in OWASP Top 10 scanning.',
410
+ template: null
411
+ },
412
+
413
+ // ============================================================
414
+ // === AUTOMATION (category: 'automation') =====================
415
+ // ============================================================
416
+
417
+ hooks: {
418
+ id: 19,
419
+ name: 'Hooks for automation',
420
+ check: (ctx) => {
421
+ if (ctx.hasDir('.claude/hooks') && ctx.dirFiles('.claude/hooks').length > 0) return true;
422
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
423
+ const local = ctx.jsonFile('.claude/settings.local.json') || {};
424
+ return !!(shared.hooks && Object.keys(shared.hooks).length > 0) || !!(local.hooks && Object.keys(local.hooks).length > 0);
425
+ },
426
+ impact: 'high',
427
+ rating: 4,
428
+ category: 'automation',
429
+ fix: 'Add hooks for auto-lint, auto-test, or file change tracking.',
430
+ template: 'hooks'
431
+ },
432
+
433
+ hooksInSettings: {
434
+ id: 8801,
435
+ name: 'Hooks configured in settings',
436
+ check: (ctx) => {
437
+ const shared = ctx.jsonFile('.claude/settings.json');
438
+ const local = ctx.jsonFile('.claude/settings.local.json');
439
+ const hasSharedHooks = shared && shared.hooks && Object.keys(shared.hooks).length > 0;
440
+ const hasLocalHooks = local && local.hooks && Object.keys(local.hooks).length > 0;
441
+ return hasSharedHooks || hasLocalHooks;
442
+ },
443
+ impact: 'high',
444
+ rating: 4,
445
+ category: 'automation',
446
+ fix: 'Add hooks in .claude/settings.json for automated enforcement (lint-on-save, test-on-commit).',
447
+ template: 'hooks'
448
+ },
449
+
450
+ preToolUseHook: {
451
+ id: 8802,
452
+ name: 'PreToolUse hook configured',
453
+ check: (ctx) => {
454
+ const shared = ctx.jsonFile('.claude/settings.json');
455
+ const local = ctx.jsonFile('.claude/settings.local.json');
456
+ return !!(shared?.hooks?.PreToolUse || local?.hooks?.PreToolUse);
457
+ },
458
+ impact: 'high',
459
+ rating: 4,
460
+ category: 'automation',
461
+ fix: 'Add PreToolUse hooks for validation before tool calls (e.g. block writes to protected files).',
462
+ template: null
463
+ },
464
+
465
+ postToolUseHook: {
466
+ id: 8803,
467
+ name: 'PostToolUse hook configured',
468
+ check: (ctx) => {
469
+ const shared = ctx.jsonFile('.claude/settings.json');
470
+ const local = ctx.jsonFile('.claude/settings.local.json');
471
+ return !!(shared?.hooks?.PostToolUse || local?.hooks?.PostToolUse);
472
+ },
473
+ impact: 'high',
474
+ rating: 4,
475
+ category: 'automation',
476
+ fix: 'Add PostToolUse hooks for auto-lint or auto-format after file writes.',
477
+ template: null
478
+ },
479
+
480
+ sessionStartHook: {
481
+ id: 8804,
482
+ name: 'SessionStart hook configured',
483
+ check: (ctx) => {
484
+ const shared = ctx.jsonFile('.claude/settings.json');
485
+ const local = ctx.jsonFile('.claude/settings.local.json');
486
+ if (!(shared?.hooks || local?.hooks)) return false;
487
+ return !!(shared?.hooks?.SessionStart || local?.hooks?.SessionStart);
488
+ },
489
+ impact: 'medium',
490
+ rating: 4,
491
+ category: 'automation',
492
+ fix: 'Add a SessionStart hook for initialization tasks (log rotation, state loading, etc.).',
493
+ template: null
494
+ },
495
+
496
+ // ============================================================
497
+ // === DESIGN (category: 'design') ============================
498
+ // ============================================================
499
+
500
+ frontendDesignSkill: {
501
+ id: 1025,
502
+ name: 'Frontend design skill for anti-AI-slop',
503
+ check: (ctx) => {
504
+ if (!hasFrontendSignals(ctx)) return null;
505
+ const md = ctx.claudeMdContent() || '';
506
+ return md.includes('frontend_aesthetics') || md.includes('anti-AI-slop') || md.includes('frontend-design');
507
+ },
508
+ impact: 'medium',
509
+ rating: 5,
510
+ category: 'design',
511
+ fix: 'Install the official frontend-design skill for better UI output quality.',
512
+ template: null
513
+ },
514
+
515
+ tailwindMention: {
516
+ id: 102501,
517
+ name: 'Tailwind CSS configured',
518
+ check: (ctx) => {
519
+ if (!hasFrontendSignals(ctx)) return null;
520
+ const pkg = ctx.fileContent('package.json') || '';
521
+ return pkg.includes('tailwind') ||
522
+ ctx.files.some(f => /tailwind\.config/.test(f));
523
+ },
524
+ impact: 'low',
525
+ rating: 3,
526
+ category: 'design',
527
+ fix: 'Consider adding Tailwind CSS for rapid, consistent UI styling with Claude.',
528
+ template: null
529
+ },
530
+
531
+ // ============================================================
532
+ // === DEVOPS (category: 'devops') ============================
533
+ // ============================================================
534
+
535
+ dockerfile: {
536
+ id: 399,
537
+ name: 'Has Dockerfile',
538
+ check: (ctx) => ctx.files.some(f => /^Dockerfile/i.test(f)),
539
+ impact: 'medium',
540
+ rating: 3,
541
+ category: 'devops',
542
+ fix: 'Add a Dockerfile for containerized builds and deployments.',
543
+ template: null
544
+ },
545
+
546
+ dockerCompose: {
547
+ id: 39901,
548
+ name: 'Has docker-compose.yml',
549
+ check: (ctx) => ctx.files.some(f => /^docker-compose\.(yml|yaml)$/i.test(f)),
550
+ impact: 'medium',
551
+ rating: 3,
552
+ category: 'devops',
553
+ fix: 'Add docker-compose.yml for multi-service local development.',
554
+ template: null
555
+ },
556
+
557
+ ciPipeline: {
558
+ id: 260,
559
+ name: 'CI pipeline configured',
560
+ check: (ctx) => ctx.hasDir('.github/workflows') || ctx.hasDir('.circleci') ||
561
+ ctx.files.includes('.gitlab-ci.yml') || ctx.files.includes('Jenkinsfile') ||
562
+ ctx.files.includes('.travis.yml') || ctx.files.includes('bitbucket-pipelines.yml'),
563
+ impact: 'high',
564
+ rating: 4,
565
+ category: 'devops',
566
+ fix: 'Add a CI pipeline (GitHub Actions, GitLab CI, CircleCI, etc.) for automated testing and deployment.',
567
+ template: null
568
+ },
569
+
570
+ terraformFiles: {
571
+ id: 397,
572
+ name: 'Infrastructure as Code (Terraform)',
573
+ check: (ctx) => ctx.files.some(f => /\.tf$/.test(f)) || ctx.files.includes('main.tf'),
574
+ impact: 'medium',
575
+ rating: 3,
576
+ category: 'devops',
577
+ fix: 'Add Terraform files for infrastructure-as-code management.',
578
+ template: null
579
+ },
580
+
581
+ // ============================================================
582
+ // === PROJECT HYGIENE (category: 'hygiene') ==================
583
+ // ============================================================
584
+
585
+ readme: {
586
+ id: 416,
587
+ name: 'Has README.md',
588
+ check: (ctx) => ctx.files.some(f => /^readme\.md$/i.test(f)),
589
+ impact: 'high',
590
+ rating: 4,
591
+ category: 'hygiene',
592
+ fix: 'Add a README.md with project overview, setup instructions, and usage.',
593
+ template: null
594
+ },
595
+
596
+ changelog: {
597
+ id: 417,
598
+ name: 'Has CHANGELOG.md',
599
+ check: (ctx) => ctx.files.some(f => /^changelog\.md$/i.test(f)),
600
+ impact: 'low',
601
+ rating: 3,
602
+ category: 'hygiene',
603
+ fix: 'Add a CHANGELOG.md to track notable changes across versions.',
604
+ template: null
605
+ },
606
+
607
+ contributing: {
608
+ id: 418,
609
+ name: 'Has CONTRIBUTING.md',
610
+ check: (ctx) => ctx.files.some(f => /^contributing\.md$/i.test(f)),
611
+ impact: 'low',
612
+ rating: 3,
613
+ category: 'hygiene',
614
+ fix: 'Add a CONTRIBUTING.md with contribution guidelines and code standards.',
615
+ template: null
616
+ },
617
+
618
+ license: {
619
+ id: 434,
620
+ name: 'Has LICENSE file',
621
+ check: (ctx) => ctx.files.some(f => /^license/i.test(f)),
622
+ impact: 'low',
623
+ rating: 3,
624
+ category: 'hygiene',
625
+ fix: 'Add a LICENSE file to clarify usage rights.',
626
+ template: null
627
+ },
628
+
629
+ editorconfig: {
630
+ id: 5001,
631
+ name: 'Has .editorconfig',
632
+ check: (ctx) => ctx.files.includes('.editorconfig'),
633
+ impact: 'low',
634
+ rating: 3,
635
+ category: 'hygiene',
636
+ fix: 'Add .editorconfig for consistent formatting across editors and Claude.',
637
+ template: null
638
+ },
639
+
640
+ nvmrc: {
641
+ id: 5002,
642
+ name: 'Node version pinned',
643
+ check: (ctx) => {
644
+ const hasNodeSignals = ctx.files.includes('package.json') ||
645
+ ctx.files.includes('tsconfig.json') ||
646
+ ctx.files.some(f => /package-lock\.json|pnpm-lock\.yaml|yarn\.lock|next\.config|vite\.config/i.test(f));
647
+ if (!hasNodeSignals) return null;
648
+ if (ctx.files.includes('.nvmrc') || ctx.files.includes('.node-version')) return true;
649
+ const pkg = ctx.jsonFile('package.json');
650
+ return !!(pkg && pkg.engines && pkg.engines.node);
651
+ },
652
+ impact: 'low',
653
+ rating: 3,
654
+ category: 'hygiene',
655
+ fix: 'Add .nvmrc, .node-version, or engines.node in package.json to pin Node version.',
656
+ template: null
657
+ },
658
+
659
+ // ============================================================
660
+ // === PERFORMANCE (category: 'performance') ==================
661
+ // ============================================================
662
+
663
+ compactionAwareness: {
664
+ id: 568,
665
+ name: 'CLAUDE.md mentions /compact or compaction',
666
+ check: (ctx) => {
667
+ const md = ctx.claudeMdContent() || '';
668
+ return /\/compact|compaction|context.*(limit|manage|budget)/i.test(md);
669
+ },
670
+ impact: 'medium',
671
+ rating: 4,
672
+ category: 'performance',
673
+ fix: 'Add compaction guidance to CLAUDE.md (e.g. "Run /compact when context is heavy").',
674
+ template: null
675
+ },
676
+
677
+ contextManagement: {
678
+ id: 45,
679
+ name: 'Context management awareness',
680
+ check: (ctx) => {
681
+ const md = ctx.claudeMdContent() || '';
682
+ return /context.*(manage|window|limit|budget|token)/i.test(md);
683
+ },
684
+ impact: 'medium',
685
+ rating: 4,
686
+ category: 'performance',
687
+ fix: 'Add context management tips to CLAUDE.md to help Claude stay within token limits.',
688
+ template: null
689
+ },
690
+
691
+ // ============================================================
692
+ // === MCP / TOOLS (category: 'tools') ========================
693
+ // ============================================================
694
+
695
+ mcpServers: {
696
+ id: 18,
697
+ name: 'MCP servers configured',
698
+ check: (ctx) => {
699
+ const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
700
+ return !!(settings && settings.mcpServers && Object.keys(settings.mcpServers).length > 0);
701
+ },
702
+ impact: 'medium',
703
+ rating: 3,
704
+ category: 'tools',
705
+ fix: 'Configure MCP servers for external tool integration (database, APIs, etc).',
706
+ template: null
707
+ },
708
+
709
+ multipleMcpServers: {
710
+ id: 1801,
711
+ name: '2+ MCP servers for rich tooling',
712
+ check: (ctx) => {
713
+ let count = 0;
714
+ const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
715
+ if (settings && settings.mcpServers) count += Object.keys(settings.mcpServers).length;
716
+ const mcpJson = ctx.jsonFile('.mcp.json');
717
+ if (mcpJson && mcpJson.mcpServers) count += Object.keys(mcpJson.mcpServers).length;
718
+ return count >= 2;
719
+ },
720
+ impact: 'medium',
721
+ rating: 4,
722
+ category: 'tools',
723
+ fix: 'Add at least 2 MCP servers for broader tool coverage (e.g. database + search).',
724
+ template: null
725
+ },
726
+
727
+ context7Mcp: {
728
+ id: 110,
729
+ name: 'Context7 MCP for real-time docs',
730
+ check: (ctx) => {
731
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
732
+ const local = ctx.jsonFile('.claude/settings.local.json') || {};
733
+ const mcp = ctx.jsonFile('.mcp.json') || {};
734
+ const all = { ...(shared.mcpServers || {}), ...(local.mcpServers || {}), ...(mcp.mcpServers || {}) };
735
+ if (Object.keys(all).length === 0) return false;
736
+ return Object.keys(all).some(k => /context7/i.test(k));
737
+ },
738
+ impact: 'medium',
739
+ rating: 4,
740
+ category: 'tools',
741
+ fix: 'Add Context7 MCP server for real-time documentation lookup (always up-to-date library docs).',
742
+ template: null
743
+ },
744
+
745
+ // ============================================================
746
+ // === PROMPTING (category: 'prompting') ======================
747
+ // ============================================================
748
+
749
+ xmlTags: {
750
+ id: 96,
751
+ name: 'XML tags for structured prompts',
752
+ check: (ctx) => {
753
+ const md = ctx.claudeMdContent() || '';
754
+ // Give credit for XML tags OR well-structured markdown with clear sections
755
+ const hasXml = md.includes('<constraints') || md.includes('<rules') ||
756
+ md.includes('<validation') || md.includes('<instructions');
757
+ const hasStructuredMd = (md.includes('## Rules') || md.includes('## Constraints') ||
758
+ md.includes('## Do not') || md.includes('## Never') || md.includes('## Important')) &&
759
+ md.split('\n').length > 20;
760
+ return hasXml || hasStructuredMd;
761
+ },
762
+ impact: 'medium',
763
+ rating: 4,
764
+ category: 'prompting',
765
+ fix: 'Add clear rules sections to CLAUDE.md. XML tags (<constraints>) are optional but improve clarity.',
766
+ template: null
767
+ },
768
+
769
+ fewShotExamples: {
770
+ id: 9,
771
+ name: 'CLAUDE.md contains code examples',
772
+ check: (ctx) => {
773
+ const md = ctx.claudeMdContent() || '';
774
+ return (md.match(/```/g) || []).length >= 2;
775
+ },
776
+ impact: 'high',
777
+ rating: 5,
778
+ category: 'prompting',
779
+ fix: 'Add code examples (few-shot) in CLAUDE.md to show preferred patterns and conventions.',
780
+ template: null
781
+ },
782
+
783
+ roleDefinition: {
784
+ id: 10,
785
+ name: 'CLAUDE.md defines a role or persona',
786
+ check: (ctx) => {
787
+ const md = ctx.claudeMdContent() || '';
788
+ return /^you are a |^your role is|^act as a |persona:|behave as a /im.test(md);
789
+ },
790
+ impact: 'medium',
791
+ rating: 4,
792
+ category: 'prompting',
793
+ fix: 'Define a role or persona in CLAUDE.md (e.g. "You are a senior backend engineer...").',
794
+ template: null
795
+ },
796
+
797
+ constraintBlocks: {
798
+ id: 9601,
799
+ name: 'XML constraint blocks in CLAUDE.md',
800
+ check: (ctx) => {
801
+ const md = ctx.claudeMdContent() || '';
802
+ return /<constraints|<rules|<requirements|<boundaries/i.test(md);
803
+ },
804
+ impact: 'high',
805
+ rating: 5,
806
+ category: 'prompting',
807
+ fix: 'Wrap critical rules in <constraints> XML blocks for 40% better adherence.',
808
+ template: null
809
+ },
810
+
811
+ // ============================================================
812
+ // === FEATURES (category: 'features') ========================
813
+ // ============================================================
814
+
815
+ channelsAwareness: {
816
+ id: 1102,
817
+ name: 'Claude Code Channels awareness',
818
+ check: (ctx) => {
819
+ const md = ctx.claudeMdContent() || '';
820
+ const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
821
+ const settingsStr = JSON.stringify(settings || {});
822
+ return /\bchannels?\b.*\b(telegram|discord|imessage|slack|bridge)\b|\b(telegram|discord|imessage|slack|bridge)\b.*\bchannels?\b/i.test(md) || settingsStr.includes('channels');
823
+ },
824
+ impact: 'low',
825
+ rating: 3,
826
+ category: 'features',
827
+ fix: 'Claude Code Channels (v2.1.80+) bridges Telegram/Discord/iMessage to your session.',
828
+ template: null
829
+ },
830
+
831
+ // ============================================================
832
+ // === QUALITY CHECKS FOR VETERANS (category: 'quality-deep')
833
+ // These check HOW GOOD your config is, not just IF it exists.
834
+ // ============================================================
835
+
836
+ claudeMdFreshness: {
837
+ id: 2001,
838
+ name: 'CLAUDE.md mentions current Claude features',
839
+ check: (ctx) => {
840
+ const md = ctx.claudeMdContent() || '';
841
+ if (md.length < 50) return false; // too short to evaluate
842
+ // Check for awareness of features from 2025+
843
+ const modernFeatures = ['hook', 'skill', 'agent', 'subagent', 'mcp', 'compact', '/clear', 'extended thinking', 'tool_use', 'worktree'];
844
+ const found = modernFeatures.filter(f => md.toLowerCase().includes(f));
845
+ return found.length >= 2; // knows at least 2 modern features
846
+ },
847
+ impact: 'medium',
848
+ rating: 4,
849
+ category: 'quality-deep',
850
+ fix: 'Your CLAUDE.md may be outdated. Modern Claude Code supports hooks, skills, agents, MCP, worktrees, and extended thinking. Mention the ones you use.',
851
+ template: null
852
+ },
853
+
854
+ // claudeMdNotOverlong removed — duplicate of underlines200 (id 681)
855
+
856
+ claudeMdNotOverlong: {
857
+ id: 2002,
858
+ name: 'CLAUDE.md is concise (under 200 lines)',
859
+ check: (ctx) => {
860
+ // Defer to underlines200 — this check always returns null (skipped)
861
+ return null;
862
+ },
863
+ impact: 'medium',
864
+ rating: 4,
865
+ category: 'quality-deep',
866
+ fix: 'CLAUDE.md over 200 lines wastes tokens every session. Move detailed docs to .claude/rules/ or skills. Keep CLAUDE.md lean.',
867
+ template: null
868
+ },
869
+
870
+ claudeMdNoContradictions: {
871
+ id: 2003,
872
+ name: 'CLAUDE.md has no obvious contradictions',
873
+ check: (ctx) => {
874
+ const md = ctx.claudeMdContent();
875
+ if (!md || md.length < 50) return false; // no CLAUDE.md or too short = not passing
876
+ // Check for common contradictions
877
+ // Check for contradictions on the SAME topic (same line or adjacent sentence)
878
+ const lines = md.split('\n');
879
+ let hasContradiction = false;
880
+ for (const line of lines) {
881
+ if (/\balways\b.*\bnever\b|\bnever\b.*\balways\b/i.test(line)) {
882
+ hasContradiction = true;
883
+ break;
884
+ }
885
+ }
886
+ const hasBothStyles = /\buse tabs\b/i.test(md) && /\buse spaces\b/i.test(md);
887
+ return !hasContradiction && !hasBothStyles;
888
+ },
889
+ impact: 'high',
890
+ rating: 4,
891
+ category: 'quality-deep',
892
+ fix: 'CLAUDE.md may contain contradictory instructions. Review for conflicting rules (e.g., "always X" and "never X" about the same topic).',
893
+ template: null
894
+ },
895
+
896
+ hooksAreSpecific: {
897
+ id: 2004,
898
+ name: 'Hooks use specific matchers (not catch-all)',
899
+ check: (ctx) => {
900
+ const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
901
+ if (!settings || !settings.hooks) return null; // no hooks = not applicable
902
+ const hookStr = JSON.stringify(settings.hooks);
903
+ // Check that hooks have matchers, not just catch-all
904
+ return hookStr.includes('matcher');
905
+ },
906
+ impact: 'medium',
907
+ rating: 3,
908
+ category: 'quality-deep',
909
+ fix: 'Hooks without matchers run on every tool call. Use matchers like "Write|Edit" or "Bash" to target specific tools.',
910
+ template: null
911
+ },
912
+
913
+ // permissionsNotBypassed removed - duplicate of noBypassPermissions (#24)
914
+
915
+ commandsUseArguments: {
916
+ id: 2006,
917
+ name: 'Commands use $ARGUMENTS for flexibility',
918
+ check: (ctx) => {
919
+ if (!ctx.hasDir('.claude/commands')) return null; // not applicable
920
+ const files = ctx.dirFiles('.claude/commands');
921
+ if (files.length === 0) return null;
922
+ // Check if at least one command uses $ARGUMENTS
923
+ for (const f of files) {
924
+ const content = ctx.fileContent(`.claude/commands/${f}`) || '';
925
+ if (content.includes('$ARGUMENTS') || content.includes('$arguments')) return true;
926
+ }
927
+ return false;
928
+ },
929
+ impact: 'medium',
930
+ rating: 3,
931
+ category: 'quality-deep',
932
+ fix: 'Commands without $ARGUMENTS are static. Use $ARGUMENTS to make them flexible: "Fix the issue: $ARGUMENTS"',
933
+ template: null
934
+ },
935
+
936
+ agentsHaveMaxTurns: {
937
+ id: 2007,
938
+ name: 'Agents have maxTurns limit',
939
+ check: (ctx) => {
940
+ if (!ctx.hasDir('.claude/agents')) return null;
941
+ const files = ctx.dirFiles('.claude/agents');
942
+ if (files.length === 0) return null;
943
+ for (const f of files) {
944
+ const content = ctx.fileContent(`.claude/agents/${f}`) || '';
945
+ if (!content.includes('maxTurns')) return false;
946
+ }
947
+ return true;
948
+ },
949
+ impact: 'medium',
950
+ rating: 3,
951
+ category: 'quality-deep',
952
+ fix: 'Agents without maxTurns can run indefinitely. Add "maxTurns: 50" to agent frontmatter.',
953
+ template: null
954
+ },
955
+
956
+ securityReviewInWorkflow: {
957
+ id: 2008,
958
+ name: '/security-review command or workflow',
959
+ check: (ctx) => {
960
+ const hasCommand = ctx.hasDir('.claude/commands') &&
961
+ (ctx.dirFiles('.claude/commands') || []).some(f => f.includes('security') || f.includes('review'));
962
+ const md = ctx.claudeMdContent() || '';
963
+ const hasExplicitRef = /\/security-review|security review command|security workflow/i.test(md);
964
+ return hasCommand || hasExplicitRef;
965
+ },
966
+ impact: 'medium',
967
+ rating: 4,
968
+ category: 'quality-deep',
969
+ fix: 'Claude Code has built-in /security-review (OWASP Top 10). Add it to your workflow or create a /security command.',
970
+ template: null
971
+ },
972
+
973
+ // --- New checks: testing depth ---
974
+ testCoverage: {
975
+ id: 2010,
976
+ name: 'Test coverage or strategy mentioned',
977
+ check: (ctx) => {
978
+ const md = ctx.claudeMdContent() || '';
979
+ return /coverage|test.*strateg|e2e|integration test|unit test/i.test(md);
980
+ },
981
+ impact: 'medium', rating: 3, category: 'quality',
982
+ fix: 'Mention your testing strategy in CLAUDE.md (unit, integration, E2E, coverage targets).',
983
+ template: null
984
+ },
985
+
986
+ // --- New checks: agent depth ---
987
+ agentHasAllowedTools: {
988
+ id: 2011,
989
+ name: 'At least one agent restricts tools',
990
+ check: (ctx) => {
991
+ if (!ctx.hasDir('.claude/agents')) return null;
992
+ const files = ctx.dirFiles('.claude/agents');
993
+ if (files.length === 0) return null;
994
+ for (const f of files) {
995
+ const content = ctx.fileContent(`.claude/agents/${f}`) || '';
996
+ if (/tools:\s*\[/.test(content)) return true;
997
+ }
998
+ return false;
999
+ },
1000
+ impact: 'medium', rating: 3, category: 'workflow',
1001
+ fix: 'Add a tools restriction to agent frontmatter (e.g. tools: [Read, Grep]) for safer delegation.',
1002
+ template: null
1003
+ },
1004
+
1005
+ // --- New checks: memory / auto-memory ---
1006
+ autoMemoryAwareness: {
1007
+ id: 2012,
1008
+ name: 'Auto-memory or memory management mentioned',
1009
+ check: (ctx) => {
1010
+ const md = ctx.claudeMdContent() || '';
1011
+ return /auto.?memory|memory.*manage|remember|persistent.*context/i.test(md);
1012
+ },
1013
+ impact: 'low', rating: 3, category: 'memory',
1014
+ fix: 'Claude Code supports auto-memory for cross-session learning. Mention your memory strategy if relevant.',
1015
+ template: null
1016
+ },
1017
+
1018
+ // --- New checks: sandbox / security depth ---
1019
+ sandboxAwareness: {
1020
+ id: 2013,
1021
+ name: 'Sandbox or isolation mentioned',
1022
+ check: (ctx) => {
1023
+ const md = ctx.claudeMdContent() || '';
1024
+ const settings = ctx.jsonFile('.claude/settings.json') || {};
1025
+ return /sandbox|isolat/i.test(md) || !!settings.sandbox;
1026
+ },
1027
+ impact: 'medium', rating: 3, category: 'security',
1028
+ fix: 'Claude Code supports sandboxed command execution. Consider enabling it for untrusted operations.',
1029
+ template: null
1030
+ },
1031
+
1032
+ denyRulesDepth: {
1033
+ id: 2014,
1034
+ name: 'Deny rules cover 3+ patterns',
1035
+ check: (ctx) => {
1036
+ const shared = ctx.jsonFile('.claude/settings.json');
1037
+ const local = ctx.jsonFile('.claude/settings.local.json');
1038
+ const deny = (shared?.permissions?.deny || []).concat(local?.permissions?.deny || []);
1039
+ return deny.length >= 3;
1040
+ },
1041
+ impact: 'high', rating: 4, category: 'security',
1042
+ fix: 'Add at least 3 deny rules: rm -rf, force-push, and .env reads. More patterns = safer Claude.',
1043
+ template: null
1044
+ },
1045
+
1046
+ // --- New checks: git depth ---
1047
+ gitAttributionDecision: {
1048
+ id: 2015,
1049
+ name: 'Git attribution configured',
1050
+ check: (ctx) => {
1051
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
1052
+ const local = ctx.jsonFile('.claude/settings.local.json') || {};
1053
+ return shared.attribution !== undefined || local.attribution !== undefined ||
1054
+ shared.includeCoAuthoredBy !== undefined || local.includeCoAuthoredBy !== undefined;
1055
+ },
1056
+ impact: 'low', rating: 3, category: 'git',
1057
+ fix: 'Decide on git attribution: set attribution.commit or includeCoAuthoredBy in settings.',
1058
+ template: null
1059
+ },
1060
+
1061
+ // --- New checks: performance ---
1062
+ effortLevelConfigured: {
1063
+ id: 2016,
1064
+ name: 'Effort level or thinking configuration',
1065
+ check: (ctx) => {
1066
+ const md = ctx.claudeMdContent() || '';
1067
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
1068
+ const local = ctx.jsonFile('.claude/settings.local.json') || {};
1069
+ return /effort|thinking/i.test(md) || shared.effortLevel || local.effortLevel ||
1070
+ shared.alwaysThinkingEnabled !== undefined || local.alwaysThinkingEnabled !== undefined;
1071
+ },
1072
+ impact: 'low', rating: 3, category: 'performance',
1073
+ fix: 'Configure effortLevel or mention thinking strategy in CLAUDE.md for task-appropriate reasoning depth.',
1074
+ template: null
1075
+ },
1076
+
1077
+ // --- New checks: workflow depth ---
1078
+ hasSnapshotHistory: {
1079
+ id: 2017,
1080
+ name: 'Audit snapshot history exists',
1081
+ check: (ctx) => {
1082
+ return !!ctx.fileContent('.claude/claudex-setup/snapshots/index.json');
1083
+ },
1084
+ impact: 'low', rating: 3, category: 'workflow',
1085
+ fix: 'Run `npx nerviq --snapshot` to start tracking your setup score over time.',
1086
+ template: null
1087
+ },
1088
+
1089
+ worktreeAwareness: {
1090
+ id: 2018,
1091
+ name: 'Worktree or parallel sessions mentioned',
1092
+ check: (ctx) => {
1093
+ const md = ctx.claudeMdContent() || '';
1094
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
1095
+ return /worktree|parallel.*session/i.test(md) || !!shared.worktree;
1096
+ },
1097
+ impact: 'low', rating: 3, category: 'features',
1098
+ fix: 'Claude Code supports git worktrees for parallel isolated sessions. Mention if relevant.',
1099
+ template: null
1100
+ },
1101
+
1102
+ // --- New checks: prompting depth ---
1103
+ negativeInstructions: {
1104
+ id: 2019,
1105
+ name: 'CLAUDE.md includes "do not" instructions',
1106
+ check: (ctx) => {
1107
+ const md = ctx.claudeMdContent() || '';
1108
+ return /do not|don't|never|avoid|must not/i.test(md);
1109
+ },
1110
+ impact: 'medium', rating: 4, category: 'prompting',
1111
+ fix: 'Add explicit "do not" rules to CLAUDE.md. Negative constraints reduce common mistakes.',
1112
+ template: null
1113
+ },
1114
+
1115
+ outputStyleGuidance: {
1116
+ id: 2020,
1117
+ name: 'CLAUDE.md includes output or style guidance',
1118
+ check: (ctx) => {
1119
+ const md = ctx.claudeMdContent() || '';
1120
+ return /coding style|naming convention|code style|style guide|formatting rules|\bprefer\b.*\b(single|double|tabs|spaces|camel|snake|kebab|named|default|const|let|arrow|function)\b/i.test(md);
1121
+ },
1122
+ impact: 'medium', rating: 3, category: 'prompting',
1123
+ fix: 'Add coding style and naming conventions to CLAUDE.md so Claude matches your project patterns.',
1124
+ template: null
1125
+ },
1126
+
1127
+ // --- New checks: devops depth ---
1128
+ githubActionsOrCI: {
1129
+ id: 2021,
1130
+ name: 'GitHub Actions or CI configured',
1131
+ check: (ctx) => {
1132
+ return ctx.hasDir('.github/workflows') || !!ctx.fileContent('.circleci/config.yml') ||
1133
+ !!ctx.fileContent('.gitlab-ci.yml') || !!ctx.fileContent('Jenkinsfile') ||
1134
+ !!ctx.fileContent('.travis.yml') || !!ctx.fileContent('bitbucket-pipelines.yml');
1135
+ },
1136
+ impact: 'medium', rating: 3, category: 'devops',
1137
+ fix: 'Add CI pipeline for automated testing. Claude Code has a GitHub Action for audit gates.',
1138
+ template: null
1139
+ },
1140
+
1141
+ // --- New checks: depth round 2 ---
1142
+ projectDescriptionInClaudeMd: {
1143
+ id: 2022,
1144
+ name: 'CLAUDE.md describes what the project does',
1145
+ check: (ctx) => {
1146
+ const md = ctx.claudeMdContent() || '';
1147
+ return /what.*does|overview|purpose|about|description|project.*is/i.test(md) && md.length > 100;
1148
+ },
1149
+ impact: 'high', rating: 4, category: 'memory',
1150
+ fix: 'Start CLAUDE.md with a clear project description. Claude needs to know what your project does.',
1151
+ template: null
1152
+ },
1153
+
1154
+ directoryStructureInClaudeMd: {
1155
+ id: 2023,
1156
+ name: 'CLAUDE.md documents directory structure',
1157
+ check: (ctx) => {
1158
+ const md = ctx.claudeMdContent() || '';
1159
+ return /src\/|app\/|lib\/|structure|director|folder/i.test(md);
1160
+ },
1161
+ impact: 'medium', rating: 4, category: 'memory',
1162
+ fix: 'Document your directory structure in CLAUDE.md so Claude navigates your codebase efficiently.',
1163
+ template: null
1164
+ },
1165
+
1166
+ multipleHookTypes: {
1167
+ id: 2024,
1168
+ name: '2+ hook event types configured',
1169
+ check: (ctx) => {
1170
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
1171
+ const local = ctx.jsonFile('.claude/settings.local.json') || {};
1172
+ const hooks = { ...(shared.hooks || {}), ...(local.hooks || {}) };
1173
+ return Object.keys(hooks).length >= 2;
1174
+ },
1175
+ impact: 'medium', rating: 3, category: 'automation',
1176
+ fix: 'Add at least 2 hook types (e.g. PostToolUse for linting + SessionStart for initialization).',
1177
+ template: null
1178
+ },
1179
+
1180
+ stopFailureHook: {
1181
+ id: 2025,
1182
+ name: 'StopFailure or error handling hook',
1183
+ check: (ctx) => {
1184
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
1185
+ const local = ctx.jsonFile('.claude/settings.local.json') || {};
1186
+ return !!(shared.hooks?.StopFailure || shared.hooks?.Stop || local.hooks?.StopFailure || local.hooks?.Stop);
1187
+ },
1188
+ impact: 'low', rating: 3, category: 'automation',
1189
+ fix: 'Add a StopFailure hook to log errors for debugging. Helps track why Claude stops unexpectedly.',
1190
+ template: null
1191
+ },
1192
+
1193
+ skillUsesPaths: {
1194
+ id: 2026,
1195
+ name: 'At least one skill uses paths for scoping',
1196
+ check: (ctx) => {
1197
+ if (!ctx.hasDir('.claude/skills')) return null;
1198
+ const entries = ctx.dirFiles('.claude/skills');
1199
+ if (entries.length === 0) return null;
1200
+ for (const entry of entries) {
1201
+ // Skills can be files or dirs with SKILL.md inside
1202
+ const direct = ctx.fileContent(`.claude/skills/${entry}`) || '';
1203
+ if (/paths:/i.test(direct)) return true;
1204
+ const nested = ctx.fileContent(`.claude/skills/${entry}/SKILL.md`) || '';
1205
+ if (/paths:/i.test(nested)) return true;
1206
+ }
1207
+ return false;
1208
+ },
1209
+ impact: 'low', rating: 3, category: 'workflow',
1210
+ fix: 'Add paths to skill frontmatter to scope when skills activate (e.g. paths: ["src/**/*.ts"]).',
1211
+ template: null
1212
+ },
1213
+
1214
+ mcpHasEnvConfig: {
1215
+ id: 2027,
1216
+ name: 'MCP servers have environment configuration',
1217
+ check: (ctx) => {
1218
+ const shared = ctx.jsonFile('.claude/settings.json') || {};
1219
+ const local = ctx.jsonFile('.claude/settings.local.json') || {};
1220
+ const mcp = ctx.jsonFile('.mcp.json') || {};
1221
+ const allServers = { ...(shared.mcpServers || {}), ...(local.mcpServers || {}), ...(mcp.mcpServers || {}) };
1222
+ if (Object.keys(allServers).length === 0) return null;
1223
+ return Object.values(allServers).some(s => s.env && Object.keys(s.env).length > 0);
1224
+ },
1225
+ impact: 'low', rating: 3, category: 'tools',
1226
+ fix: 'Configure environment variables for MCP servers that need authentication (e.g. GITHUB_TOKEN).',
1227
+ template: null
1228
+ },
1229
+
1230
+ gitIgnoreClaudeLocal: {
1231
+ id: 2028,
1232
+ name: '.gitignore excludes settings.local.json',
1233
+ check: (ctx) => {
1234
+ const gitignore = ctx.fileContent('.gitignore') || '';
1235
+ return /settings\.local\.json|settings\.local/i.test(gitignore);
1236
+ },
1237
+ impact: 'medium', rating: 4, category: 'git',
1238
+ fix: 'Add .claude/settings.local.json to .gitignore. Personal overrides should not be committed.',
1239
+ template: null
1240
+ },
1241
+
1242
+ envExampleExists: {
1243
+ id: 2029,
1244
+ name: '.env.example or .env.template exists',
1245
+ check: (ctx) => {
1246
+ return !!(ctx.fileContent('.env.example') || ctx.fileContent('.env.template') || ctx.fileContent('.env.sample'));
1247
+ },
1248
+ impact: 'low', rating: 3, category: 'hygiene',
1249
+ fix: 'Add .env.example so new developers know which environment variables are needed.',
1250
+ template: null
1251
+ },
1252
+
1253
+ packageJsonHasScripts: {
1254
+ id: 2030,
1255
+ name: 'package.json has dev/test/build scripts',
1256
+ check: (ctx) => {
1257
+ const pkg = ctx.jsonFile('package.json');
1258
+ if (!pkg) return null;
1259
+ const scripts = pkg.scripts || {};
1260
+ const has = (k) => !!scripts[k];
1261
+ return has('test') || has('dev') || has('build') || has('start');
1262
+ },
1263
+ impact: 'medium', rating: 3, category: 'hygiene',
1264
+ fix: 'Add scripts to package.json (test, dev, build). Claude uses these for verification.',
1265
+ template: null
1266
+ },
1267
+
1268
+ typeCheckingConfigured: {
1269
+ id: 2031,
1270
+ name: 'Type checking configured (TypeScript or similar)',
1271
+ check: (ctx) => {
1272
+ return !!(ctx.fileContent('tsconfig.json') || ctx.fileContent('jsconfig.json') ||
1273
+ ctx.fileContent('pyrightconfig.json') || ctx.fileContent('mypy.ini'));
1274
+ },
1275
+ impact: 'medium', rating: 3, category: 'quality',
1276
+ fix: 'Add type checking configuration. Type-safe code produces fewer Claude errors.',
1277
+ template: null
1278
+ },
1279
+
1280
+ noDeprecatedPatterns: {
1281
+ id: 2009,
1282
+ name: 'No deprecated patterns detected',
1283
+ check: (ctx) => {
1284
+ const md = ctx.claudeMdContent();
1285
+ if (!md) return false; // no CLAUDE.md = not passing
1286
+ // Check for patterns deprecated in Claude 4.x
1287
+ const deprecatedPatterns = [
1288
+ /\bprefill\b/i, // deprecated API pattern in 4.6
1289
+ /\bclaude-3-opus\b/i, /\bclaude-3-sonnet\b/i, /\bclaude-3-haiku\b/i, // old model names
1290
+ /\bhuman_prompt\b/i, /\bassistant_prompt\b/i, // old API format
1291
+ ];
1292
+ return !deprecatedPatterns.some(p => p.test(md));
1293
+ },
1294
+ impact: 'medium',
1295
+ rating: 3,
1296
+ category: 'quality-deep',
1297
+ fix: 'CLAUDE.md references deprecated patterns (old model names or API formats). Update to current Claude 4.x conventions.',
1298
+ template: null
1299
+ },
1300
+
1301
+ claudeMdQuality: {
1302
+ id: 102502,
1303
+ name: 'CLAUDE.md has substantive content',
1304
+ check: (ctx) => {
1305
+ const md = ctx.claudeMdContent();
1306
+ if (!md) return null;
1307
+ const lines = md.split('\n').filter(l => l.trim());
1308
+ const sections = (md.match(/^##\s/gm) || []).length;
1309
+ const hasCommand = /\b(npm|yarn|pnpm|pytest|go |make |ruff |cargo |dotnet )\b/i.test(md);
1310
+ return lines.length >= 15 && sections >= 2 && hasCommand;
1311
+ },
1312
+ impact: 'medium',
1313
+ rating: 4,
1314
+ category: 'quality-deep',
1315
+ fix: 'CLAUDE.md exists but lacks substance. Add at least 2 sections (## headings) and include your test/build/lint commands.',
1316
+ template: null
1317
+ },
1318
+ };
1319
+
1320
+ // Stack detection
1321
+ const STACKS = {
1322
+ react: { files: ['package.json'], content: { 'package.json': 'react' }, label: 'React' },
1323
+ vue: { files: ['package.json'], content: { 'package.json': 'vue' }, label: 'Vue' },
1324
+ angular: { files: ['angular.json'], content: {}, label: 'Angular' },
1325
+ nextjs: { files: ['next.config'], content: {}, label: 'Next.js' },
1326
+ python: { files: ['requirements.txt', 'setup.py', 'pyproject.toml', 'Pipfile'], content: {}, label: 'Python' },
1327
+ django: { files: ['manage.py'], content: {}, label: 'Django' },
1328
+ fastapi: { files: ['requirements.txt'], content: { 'requirements.txt': 'fastapi' }, label: 'FastAPI' },
1329
+ node: { files: ['package.json'], content: {}, label: 'Node.js' },
1330
+ typescript: { files: ['tsconfig.json'], content: {}, label: 'TypeScript' },
1331
+ rust: { files: ['Cargo.toml'], content: {}, label: 'Rust' },
1332
+ go: { files: ['go.mod'], content: {}, label: 'Go' },
1333
+ docker: { files: ['Dockerfile', 'docker-compose.yml', 'docker-compose.yaml'], content: {}, label: 'Docker' },
1334
+ svelte: { files: ['svelte.config.js'], content: {}, label: 'Svelte' },
1335
+ flutter: { files: ['pubspec.yaml'], content: {}, label: 'Flutter' },
1336
+ ruby: { files: ['Gemfile'], content: {}, label: 'Ruby' },
1337
+ java: { files: ['pom.xml'], content: {}, label: 'Java' },
1338
+ kotlin: { files: ['build.gradle.kts'], content: {}, label: 'Kotlin' },
1339
+ swift: { files: ['Package.swift'], content: {}, label: 'Swift' },
1340
+ terraform: { files: ['main.tf', 'terraform'], content: {}, label: 'Terraform' },
1341
+ kubernetes: { files: ['k8s', 'kubernetes', 'helm'], content: {}, label: 'Kubernetes' },
1342
+ cpp: { files: ['CMakeLists.txt', 'Makefile', '.clang-format'], content: {}, label: 'C++' },
1343
+ bazel: { files: ['BUILD', 'WORKSPACE', 'BUILD.bazel', 'WORKSPACE.bazel'], content: {}, label: 'Bazel' },
1344
+ deno: { files: ['deno.json', 'deno.jsonc', 'deno.lock'], content: {}, label: 'Deno' },
1345
+ bun: { files: ['bun.lockb', 'bunfig.toml'], content: {}, label: 'Bun' },
1346
+ elixir: { files: ['mix.exs'], content: {}, label: 'Elixir' },
1347
+ astro: { files: ['astro.config.mjs', 'astro.config.ts'], content: {}, label: 'Astro' },
1348
+ remix: { files: ['remix.config.js', 'remix.config.ts'], content: {}, label: 'Remix' },
1349
+ nestjs: { files: ['nest-cli.json'], content: {}, label: 'NestJS' },
1350
+ laravel: { files: ['artisan'], content: {}, label: 'Laravel' },
1351
+ dotnet: { files: ['global.json', 'Directory.Build.props'], content: {}, label: '.NET' },
1352
+ };
1353
+
1354
+ module.exports = { TECHNIQUES, STACKS, containsEmbeddedSecret };