@nerviq/cli 1.20.1 → 1.21.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/LICENSE +23 -23
- package/README.md +2 -2
- package/package.json +1 -1
- package/src/activity.js +1039 -1039
- package/src/adoption-advisor.js +299 -299
- package/src/aider/config-parser.js +166 -166
- package/src/aider/context.js +4 -1
- package/src/aider/deep-review.js +316 -316
- package/src/aider/domain-packs.js +303 -303
- package/src/aider/freshness.js +93 -93
- package/src/aider/governance.js +253 -253
- package/src/aider/interactive.js +334 -334
- package/src/aider/mcp-packs.js +329 -329
- package/src/aider/patch.js +214 -214
- package/src/aider/plans.js +186 -186
- package/src/aider/premium.js +360 -360
- package/src/aider/setup.js +404 -404
- package/src/aider/techniques.js +312 -67
- package/src/analyze.js +951 -951
- package/src/anti-patterns.js +485 -485
- package/src/audit/instruction-files.js +180 -180
- package/src/audit/recommendations.js +577 -577
- package/src/auto-suggest.js +154 -154
- package/src/badge.js +13 -13
- package/src/behavioral-drift.js +801 -801
- package/src/benchmark.js +67 -67
- package/src/catalog.js +103 -103
- package/src/certification.js +128 -128
- package/src/codex/config-parser.js +183 -183
- package/src/codex/context.js +223 -223
- package/src/codex/deep-review.js +493 -493
- package/src/codex/domain-packs.js +394 -394
- package/src/codex/freshness.js +84 -84
- package/src/codex/governance.js +192 -192
- package/src/codex/interactive.js +618 -618
- package/src/codex/mcp-packs.js +914 -914
- package/src/codex/patch.js +209 -209
- package/src/codex/plans.js +251 -251
- package/src/codex/premium.js +614 -614
- package/src/codex/setup.js +591 -591
- package/src/continuous-ops.js +681 -681
- package/src/copilot/activity.js +309 -309
- package/src/copilot/deep-review.js +346 -346
- package/src/copilot/domain-packs.js +372 -372
- package/src/copilot/freshness.js +57 -57
- package/src/copilot/governance.js +222 -222
- package/src/copilot/interactive.js +406 -406
- package/src/copilot/mcp-packs.js +826 -826
- package/src/copilot/plans.js +253 -253
- package/src/copilot/premium.js +451 -451
- package/src/copilot/setup.js +488 -488
- package/src/cost-tracking.js +61 -61
- package/src/cursor/activity.js +301 -301
- package/src/cursor/config-parser.js +265 -265
- package/src/cursor/context.js +256 -256
- package/src/cursor/deep-review.js +334 -334
- package/src/cursor/domain-packs.js +368 -368
- package/src/cursor/freshness.js +65 -65
- package/src/cursor/governance.js +229 -229
- package/src/cursor/interactive.js +391 -391
- package/src/cursor/mcp-packs.js +828 -828
- package/src/cursor/plans.js +254 -254
- package/src/cursor/premium.js +469 -469
- package/src/cursor/setup.js +488 -488
- package/src/dashboard.js +493 -493
- package/src/deep-review.js +428 -428
- package/src/deprecation.js +98 -98
- package/src/diff-only.js +280 -280
- package/src/doctor.js +119 -119
- package/src/domain-pack-expansion.js +1033 -1033
- package/src/domain-packs.js +387 -387
- package/src/feedback.js +178 -178
- package/src/fix-engine.js +783 -783
- package/src/fix-prompts.js +122 -122
- package/src/formatters/sarif.js +115 -115
- package/src/freshness.js +74 -74
- package/src/gemini/config-parser.js +275 -275
- package/src/gemini/deep-review.js +559 -559
- package/src/gemini/domain-packs.js +393 -393
- package/src/gemini/freshness.js +66 -66
- package/src/gemini/governance.js +201 -201
- package/src/gemini/interactive.js +860 -860
- package/src/gemini/mcp-packs.js +915 -915
- package/src/gemini/plans.js +269 -269
- package/src/gemini/premium.js +760 -760
- package/src/gemini/setup.js +692 -692
- package/src/governance.js +72 -72
- package/src/harmony/add.js +68 -68
- package/src/harmony/advisor.js +333 -333
- package/src/harmony/canon.js +565 -565
- package/src/harmony/cli.js +591 -591
- package/src/harmony/drift.js +401 -401
- package/src/harmony/governance.js +313 -313
- package/src/harmony/memory.js +239 -239
- package/src/harmony/sync.js +475 -475
- package/src/harmony/watch.js +370 -370
- package/src/hook-validation.js +342 -342
- package/src/index.js +271 -271
- package/src/init.js +184 -184
- package/src/instruction-surfaces.js +185 -185
- package/src/integrations.js +144 -144
- package/src/interactive.js +118 -118
- package/src/locales/en.json +1 -1
- package/src/locales/es.json +1 -1
- package/src/mcp-packs.js +830 -830
- package/src/mcp-server.js +726 -726
- package/src/mcp-validation.js +337 -337
- package/src/nerviq-sync.json +7 -7
- package/src/opencode/config-parser.js +109 -109
- package/src/opencode/context.js +247 -247
- package/src/opencode/deep-review.js +313 -313
- package/src/opencode/domain-packs.js +262 -262
- package/src/opencode/freshness.js +66 -66
- package/src/opencode/governance.js +159 -159
- package/src/opencode/interactive.js +392 -392
- package/src/opencode/mcp-packs.js +705 -705
- package/src/opencode/patch.js +184 -184
- package/src/opencode/plans.js +231 -231
- package/src/opencode/premium.js +413 -413
- package/src/opencode/setup.js +449 -449
- package/src/opencode/techniques.js +27 -27
- package/src/operating-profile.js +574 -574
- package/src/org.js +152 -152
- package/src/permission-rules.js +218 -218
- package/src/plans.js +839 -839
- package/src/platform-change-manifest.js +86 -86
- package/src/plugins.js +110 -110
- package/src/policy-layers.js +210 -210
- package/src/profiles.js +124 -124
- package/src/prompt-injection.js +74 -74
- package/src/public-api.js +173 -173
- package/src/recommendation-rules.js +84 -84
- package/src/repo-archetype.js +386 -386
- package/src/secret-patterns.js +39 -39
- package/src/server.js +527 -527
- package/src/setup/analysis.js +607 -607
- package/src/setup/runtime.js +172 -172
- package/src/setup.js +677 -677
- package/src/shared/capabilities.js +194 -194
- package/src/source-urls.js +132 -132
- package/src/stack-checks.js +565 -565
- package/src/supplemental-checks.js +13 -13
- package/src/synergy/adaptive.js +261 -261
- package/src/synergy/compensation.js +137 -137
- package/src/synergy/evidence.js +193 -193
- package/src/synergy/learning.js +199 -199
- package/src/synergy/patterns.js +227 -227
- package/src/synergy/ranking.js +83 -83
- package/src/synergy/report.js +165 -165
- package/src/synergy/routing.js +146 -146
- package/src/techniques/api.js +407 -407
- package/src/techniques/automation.js +316 -316
- package/src/techniques/compliance.js +257 -257
- package/src/techniques/hygiene.js +294 -294
- package/src/techniques/instructions.js +243 -243
- package/src/techniques/observability.js +226 -226
- package/src/techniques/optimization.js +142 -142
- package/src/techniques/quality.js +318 -318
- package/src/techniques/security.js +237 -237
- package/src/techniques/shared.js +443 -443
- package/src/techniques/stacks.js +2294 -2294
- package/src/techniques/tools.js +106 -106
- package/src/techniques/workflow.js +413 -413
- package/src/techniques.js +81 -81
- package/src/terminology.js +73 -73
- package/src/token-estimate.js +35 -35
- package/src/usage-patterns.js +99 -99
- package/src/verification-metadata.js +145 -145
- package/src/watch.js +247 -247
- package/src/windsurf/activity.js +302 -302
- package/src/windsurf/config-parser.js +267 -267
- package/src/windsurf/deep-review.js +337 -337
- package/src/windsurf/domain-packs.js +370 -370
- package/src/windsurf/freshness.js +36 -36
- package/src/windsurf/governance.js +231 -231
- package/src/windsurf/interactive.js +388 -388
- package/src/windsurf/mcp-packs.js +792 -792
- package/src/windsurf/plans.js +247 -247
- package/src/windsurf/premium.js +468 -468
- package/src/windsurf/setup.js +471 -471
- package/src/workspace.js +375 -375
|
@@ -1,294 +1,294 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hygiene technique fragments.
|
|
3
|
-
* Generated mechanically from the legacy techniques.js monolith during HR-09.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const {
|
|
7
|
-
hasFrontendSignals,
|
|
8
|
-
hasProjectFile,
|
|
9
|
-
readProjectFiles,
|
|
10
|
-
isGoProject,
|
|
11
|
-
containsEmbeddedSecret,
|
|
12
|
-
} = require('./shared');
|
|
13
|
-
|
|
14
|
-
module.exports = {
|
|
15
|
-
gitIgnoreClaudeTracked: {
|
|
16
|
-
id: 976,
|
|
17
|
-
name: '.claude/ tracked in git',
|
|
18
|
-
check: (ctx) => {
|
|
19
|
-
if (!ctx.fileContent('.gitignore')) return true; // no gitignore = ok
|
|
20
|
-
const lines = ctx.fileContent('.gitignore')
|
|
21
|
-
.split(/\r?\n/)
|
|
22
|
-
.map(line => line.trim())
|
|
23
|
-
.filter(line => line && !line.startsWith('#'));
|
|
24
|
-
const ignoresClaudeDir = lines.some(line => /^(\/|\*\*\/)?\.claude\/?$/.test(line));
|
|
25
|
-
const unignoresClaudeDir = lines.some(line => /^!(\/)?\.claude(\/|\*\*)?$/.test(line));
|
|
26
|
-
return !ignoresClaudeDir || unignoresClaudeDir;
|
|
27
|
-
},
|
|
28
|
-
impact: 'high',
|
|
29
|
-
rating: 4,
|
|
30
|
-
category: 'git',
|
|
31
|
-
fix: 'Remove .claude/ from .gitignore (keep .claude/settings.local.json ignored).',
|
|
32
|
-
template: null
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
gitIgnoreEnv: {
|
|
36
|
-
id: 917,
|
|
37
|
-
name: '.gitignore blocks .env files',
|
|
38
|
-
check: (ctx) => {
|
|
39
|
-
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
40
|
-
return gitignore.includes('.env');
|
|
41
|
-
},
|
|
42
|
-
impact: 'critical',
|
|
43
|
-
rating: 5,
|
|
44
|
-
category: 'git',
|
|
45
|
-
fix: 'Add .env to .gitignore to prevent leaking secrets.',
|
|
46
|
-
template: null
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
gitIgnoreNodeModules: {
|
|
50
|
-
id: 91701,
|
|
51
|
-
name: '.gitignore blocks node_modules',
|
|
52
|
-
check: (ctx) => {
|
|
53
|
-
const hasNodeSignals = ctx.files.includes('package.json') ||
|
|
54
|
-
ctx.files.includes('tsconfig.json') ||
|
|
55
|
-
ctx.files.some(f => /package-lock\.json|pnpm-lock\.yaml|yarn\.lock|next\.config|vite\.config/i.test(f));
|
|
56
|
-
if (!hasNodeSignals) return null;
|
|
57
|
-
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
58
|
-
return gitignore.includes('node_modules');
|
|
59
|
-
},
|
|
60
|
-
impact: 'high',
|
|
61
|
-
rating: 4,
|
|
62
|
-
category: 'git',
|
|
63
|
-
fix: 'Add node_modules/ to .gitignore.',
|
|
64
|
-
template: null
|
|
65
|
-
},
|
|
66
|
-
|
|
67
|
-
noSecretsInClaude: {
|
|
68
|
-
id: 1039,
|
|
69
|
-
name: 'CLAUDE.md has no embedded secrets',
|
|
70
|
-
check: (ctx) => {
|
|
71
|
-
const md = ctx.claudeMdContent() || '';
|
|
72
|
-
return !containsEmbeddedSecret(md);
|
|
73
|
-
},
|
|
74
|
-
impact: 'critical',
|
|
75
|
-
rating: 5,
|
|
76
|
-
category: 'git',
|
|
77
|
-
fix: 'Remove hardcoded secrets, tokens, private keys, and connection strings from CLAUDE.md. Use environment variables or external secret stores instead.',
|
|
78
|
-
template: null
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
readme: {
|
|
82
|
-
id: 416,
|
|
83
|
-
name: 'Has README.md',
|
|
84
|
-
check: (ctx) => ctx.files.some(f => /^readme\.md$/i.test(f)),
|
|
85
|
-
impact: 'high',
|
|
86
|
-
rating: 4,
|
|
87
|
-
category: 'hygiene',
|
|
88
|
-
fix: 'Add a README.md with project overview, setup instructions, and usage.',
|
|
89
|
-
template: null
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
changelog: {
|
|
93
|
-
id: 417,
|
|
94
|
-
name: 'Has CHANGELOG.md',
|
|
95
|
-
check: (ctx) => ctx.files.some(f => /^(changelog|changes|history|news)\.(md|txt|rst)$/i.test(f) || /^changelog$/i.test(f)),
|
|
96
|
-
impact: 'low',
|
|
97
|
-
rating: 3,
|
|
98
|
-
category: 'hygiene',
|
|
99
|
-
fix: 'Add a CHANGELOG.md (or CHANGES.md, HISTORY.md) to track notable changes across versions.',
|
|
100
|
-
template: null
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
contributing: {
|
|
104
|
-
id: 418,
|
|
105
|
-
name: 'Has CONTRIBUTING.md',
|
|
106
|
-
check: (ctx) => ctx.files.some(f => /^contributing\.md$/i.test(f)),
|
|
107
|
-
impact: 'low',
|
|
108
|
-
rating: 3,
|
|
109
|
-
category: 'hygiene',
|
|
110
|
-
fix: 'Add a CONTRIBUTING.md with contribution guidelines and code standards.',
|
|
111
|
-
template: null
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
license: {
|
|
115
|
-
id: 434,
|
|
116
|
-
name: 'Has LICENSE file',
|
|
117
|
-
check: (ctx) => ctx.files.some(f => /^license/i.test(f)),
|
|
118
|
-
impact: 'low',
|
|
119
|
-
rating: 3,
|
|
120
|
-
category: 'hygiene',
|
|
121
|
-
fix: 'Add a LICENSE file to clarify usage rights.',
|
|
122
|
-
template: null
|
|
123
|
-
},
|
|
124
|
-
|
|
125
|
-
editorconfig: {
|
|
126
|
-
id: 5001,
|
|
127
|
-
name: 'Has .editorconfig',
|
|
128
|
-
check: (ctx) => ctx.files.includes('.editorconfig'),
|
|
129
|
-
impact: 'low',
|
|
130
|
-
rating: 3,
|
|
131
|
-
category: 'hygiene',
|
|
132
|
-
fix: 'Add .editorconfig for consistent formatting across editors and Claude.',
|
|
133
|
-
template: null
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
nvmrc: {
|
|
137
|
-
id: 5002,
|
|
138
|
-
name: 'Node version pinned',
|
|
139
|
-
check: (ctx) => {
|
|
140
|
-
const hasNodeSignals = ctx.files.includes('package.json') ||
|
|
141
|
-
ctx.files.includes('tsconfig.json') ||
|
|
142
|
-
ctx.files.some(f => /package-lock\.json|pnpm-lock\.yaml|yarn\.lock|next\.config|vite\.config/i.test(f));
|
|
143
|
-
if (!hasNodeSignals) return null;
|
|
144
|
-
if (ctx.files.includes('.nvmrc') || ctx.files.includes('.node-version')) return true;
|
|
145
|
-
const pkg = ctx.jsonFile('package.json');
|
|
146
|
-
return !!(pkg && pkg.engines && pkg.engines.node);
|
|
147
|
-
},
|
|
148
|
-
impact: 'low',
|
|
149
|
-
rating: 3,
|
|
150
|
-
category: 'hygiene',
|
|
151
|
-
fix: 'Add .nvmrc, .node-version, or engines.node in package.json to pin Node version.',
|
|
152
|
-
template: null
|
|
153
|
-
},
|
|
154
|
-
|
|
155
|
-
gitAttributionDecision: {
|
|
156
|
-
id: 2015,
|
|
157
|
-
name: 'Git attribution configured',
|
|
158
|
-
check: (ctx) => {
|
|
159
|
-
const shared = ctx.jsonFile('.claude/settings.json') || {};
|
|
160
|
-
const local = ctx.jsonFile('.claude/settings.local.json') || {};
|
|
161
|
-
return shared.attribution !== undefined || local.attribution !== undefined ||
|
|
162
|
-
shared.includeCoAuthoredBy !== undefined || local.includeCoAuthoredBy !== undefined;
|
|
163
|
-
},
|
|
164
|
-
impact: 'low', rating: 3, category: 'git',
|
|
165
|
-
fix: 'Decide on git attribution: set attribution.commit or includeCoAuthoredBy in settings.',
|
|
166
|
-
template: null
|
|
167
|
-
},
|
|
168
|
-
|
|
169
|
-
gitIgnoreClaudeLocal: {
|
|
170
|
-
id: 2028,
|
|
171
|
-
name: '.gitignore excludes settings.local.json',
|
|
172
|
-
check: (ctx) => {
|
|
173
|
-
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
174
|
-
return /settings\.local\.json|settings\.local/i.test(gitignore);
|
|
175
|
-
},
|
|
176
|
-
impact: 'medium', rating: 4, category: 'git',
|
|
177
|
-
fix: 'Add .claude/settings.local.json to .gitignore. Personal overrides should not be committed.',
|
|
178
|
-
template: null
|
|
179
|
-
},
|
|
180
|
-
|
|
181
|
-
envExampleExists: {
|
|
182
|
-
id: 2029,
|
|
183
|
-
name: '.env.example or .env.template exists',
|
|
184
|
-
check: (ctx) => {
|
|
185
|
-
return !!(ctx.fileContent('.env.example') || ctx.fileContent('.env.template') || ctx.fileContent('.env.sample'));
|
|
186
|
-
},
|
|
187
|
-
impact: 'low', rating: 3, category: 'hygiene',
|
|
188
|
-
fix: 'Add .env.example so new developers know which environment variables are needed.',
|
|
189
|
-
template: null
|
|
190
|
-
},
|
|
191
|
-
|
|
192
|
-
packageJsonHasScripts: {
|
|
193
|
-
id: 2030,
|
|
194
|
-
name: 'package.json has dev/test/build scripts',
|
|
195
|
-
check: (ctx) => {
|
|
196
|
-
const pkg = ctx.jsonFile('package.json');
|
|
197
|
-
if (!pkg) return null;
|
|
198
|
-
const scripts = pkg.scripts || {};
|
|
199
|
-
const has = (k) => !!scripts[k];
|
|
200
|
-
return has('test') || has('dev') || has('build') || has('start');
|
|
201
|
-
},
|
|
202
|
-
impact: 'medium', rating: 3, category: 'hygiene',
|
|
203
|
-
fix: 'Add scripts to package.json (test, dev, build). Claude uses these for verification.',
|
|
204
|
-
template: null
|
|
205
|
-
},
|
|
206
|
-
|
|
207
|
-
gitignoreClaudeLocal: {
|
|
208
|
-
id: 2036,
|
|
209
|
-
name: 'CLAUDE.local.md in .gitignore',
|
|
210
|
-
check: (ctx) => {
|
|
211
|
-
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
212
|
-
return /CLAUDE\.local\.md/i.test(gitignore);
|
|
213
|
-
},
|
|
214
|
-
impact: 'medium',
|
|
215
|
-
rating: 3,
|
|
216
|
-
category: 'git',
|
|
217
|
-
fix: 'Add CLAUDE.local.md to .gitignore — it contains personal overrides that should not be committed.',
|
|
218
|
-
template: null
|
|
219
|
-
},
|
|
220
|
-
|
|
221
|
-
readmeQuality: {
|
|
222
|
-
id: 130151,
|
|
223
|
-
name: 'README has installation, usage, and contributing sections',
|
|
224
|
-
check: (ctx) => {
|
|
225
|
-
const readme = ctx.fileContent('README.md') || '';
|
|
226
|
-
if (!readme) return false;
|
|
227
|
-
return /install/i.test(readme) && /usage/i.test(readme) && /contribut/i.test(readme);
|
|
228
|
-
},
|
|
229
|
-
impact: 'medium',
|
|
230
|
-
category: 'docs-quality',
|
|
231
|
-
fix: 'Ensure README.md includes installation, usage, and contributing sections for developer onboarding.',
|
|
232
|
-
confidence: 0.7,
|
|
233
|
-
},
|
|
234
|
-
|
|
235
|
-
contributingGuide: {
|
|
236
|
-
id: 130152,
|
|
237
|
-
name: 'CONTRIBUTING.md exists',
|
|
238
|
-
check: (ctx) => ctx.files.some(f => /^contributing\.md$/i.test(f)),
|
|
239
|
-
impact: 'low',
|
|
240
|
-
category: 'docs-quality',
|
|
241
|
-
fix: 'Add CONTRIBUTING.md with contribution guidelines, code standards, and PR process.',
|
|
242
|
-
confidence: 0.7,
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
apiDocsGenerated: {
|
|
246
|
-
id: 130153,
|
|
247
|
-
name: 'API documentation generator configured',
|
|
248
|
-
check: (ctx) => {
|
|
249
|
-
const pkg = ctx.fileContent('package.json') || '';
|
|
250
|
-
if (/typedoc|jsdoc|apidoc|compodoc/i.test(pkg)) return true;
|
|
251
|
-
const py = readProjectFiles(ctx, /(^|\/)pyproject\.toml$/i) + readProjectFiles(ctx, /(^|\/)requirements[^/]*\.txt$/i);
|
|
252
|
-
if (/sphinx|pdoc|mkdocstrings/i.test(py)) return true;
|
|
253
|
-
if (isGoProject(ctx) && hasProjectFile(ctx, /(^|\/)doc\.go$/i)) return true;
|
|
254
|
-
return false;
|
|
255
|
-
},
|
|
256
|
-
impact: 'low',
|
|
257
|
-
category: 'docs-quality',
|
|
258
|
-
fix: 'Add an API documentation generator (typedoc, jsdoc, sphinx, godoc) for auto-generated docs.',
|
|
259
|
-
confidence: 0.7,
|
|
260
|
-
},
|
|
261
|
-
|
|
262
|
-
storybookConfigured: {
|
|
263
|
-
id: 130154,
|
|
264
|
-
name: 'Storybook configured for component docs',
|
|
265
|
-
check: (ctx) => {
|
|
266
|
-
if (!hasFrontendSignals(ctx)) return null;
|
|
267
|
-
return ctx.hasDir('.storybook') || hasProjectFile(ctx, /(^|\/)\.storybook\//i);
|
|
268
|
-
},
|
|
269
|
-
impact: 'low',
|
|
270
|
-
category: 'docs-quality',
|
|
271
|
-
fix: 'Add Storybook (.storybook/) for interactive component documentation and visual testing.',
|
|
272
|
-
confidence: 0.7,
|
|
273
|
-
},
|
|
274
|
-
|
|
275
|
-
codeOfConduct: {
|
|
276
|
-
id: 130155,
|
|
277
|
-
name: 'CODE_OF_CONDUCT.md exists',
|
|
278
|
-
check: (ctx) => ctx.files.some(f => /^code.of.conduct\.md$/i.test(f)),
|
|
279
|
-
impact: 'low',
|
|
280
|
-
category: 'docs-quality',
|
|
281
|
-
fix: 'Add CODE_OF_CONDUCT.md to set community standards and expectations.',
|
|
282
|
-
confidence: 0.7,
|
|
283
|
-
},
|
|
284
|
-
|
|
285
|
-
licenseDeclared: {
|
|
286
|
-
id: 130156,
|
|
287
|
-
name: 'LICENSE file exists',
|
|
288
|
-
check: (ctx) => ctx.files.some(f => /^license/i.test(f)),
|
|
289
|
-
impact: 'low',
|
|
290
|
-
category: 'docs-quality',
|
|
291
|
-
fix: 'Add a LICENSE file to clarify usage rights and legal terms.',
|
|
292
|
-
confidence: 0.7,
|
|
293
|
-
},
|
|
294
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Hygiene technique fragments.
|
|
3
|
+
* Generated mechanically from the legacy techniques.js monolith during HR-09.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
hasFrontendSignals,
|
|
8
|
+
hasProjectFile,
|
|
9
|
+
readProjectFiles,
|
|
10
|
+
isGoProject,
|
|
11
|
+
containsEmbeddedSecret,
|
|
12
|
+
} = require('./shared');
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
gitIgnoreClaudeTracked: {
|
|
16
|
+
id: 976,
|
|
17
|
+
name: '.claude/ tracked in git',
|
|
18
|
+
check: (ctx) => {
|
|
19
|
+
if (!ctx.fileContent('.gitignore')) return true; // no gitignore = ok
|
|
20
|
+
const lines = ctx.fileContent('.gitignore')
|
|
21
|
+
.split(/\r?\n/)
|
|
22
|
+
.map(line => line.trim())
|
|
23
|
+
.filter(line => line && !line.startsWith('#'));
|
|
24
|
+
const ignoresClaudeDir = lines.some(line => /^(\/|\*\*\/)?\.claude\/?$/.test(line));
|
|
25
|
+
const unignoresClaudeDir = lines.some(line => /^!(\/)?\.claude(\/|\*\*)?$/.test(line));
|
|
26
|
+
return !ignoresClaudeDir || unignoresClaudeDir;
|
|
27
|
+
},
|
|
28
|
+
impact: 'high',
|
|
29
|
+
rating: 4,
|
|
30
|
+
category: 'git',
|
|
31
|
+
fix: 'Remove .claude/ from .gitignore (keep .claude/settings.local.json ignored).',
|
|
32
|
+
template: null
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
gitIgnoreEnv: {
|
|
36
|
+
id: 917,
|
|
37
|
+
name: '.gitignore blocks .env files',
|
|
38
|
+
check: (ctx) => {
|
|
39
|
+
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
40
|
+
return gitignore.includes('.env');
|
|
41
|
+
},
|
|
42
|
+
impact: 'critical',
|
|
43
|
+
rating: 5,
|
|
44
|
+
category: 'git',
|
|
45
|
+
fix: 'Add .env to .gitignore to prevent leaking secrets.',
|
|
46
|
+
template: null
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
gitIgnoreNodeModules: {
|
|
50
|
+
id: 91701,
|
|
51
|
+
name: '.gitignore blocks node_modules',
|
|
52
|
+
check: (ctx) => {
|
|
53
|
+
const hasNodeSignals = ctx.files.includes('package.json') ||
|
|
54
|
+
ctx.files.includes('tsconfig.json') ||
|
|
55
|
+
ctx.files.some(f => /package-lock\.json|pnpm-lock\.yaml|yarn\.lock|next\.config|vite\.config/i.test(f));
|
|
56
|
+
if (!hasNodeSignals) return null;
|
|
57
|
+
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
58
|
+
return gitignore.includes('node_modules');
|
|
59
|
+
},
|
|
60
|
+
impact: 'high',
|
|
61
|
+
rating: 4,
|
|
62
|
+
category: 'git',
|
|
63
|
+
fix: 'Add node_modules/ to .gitignore.',
|
|
64
|
+
template: null
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
noSecretsInClaude: {
|
|
68
|
+
id: 1039,
|
|
69
|
+
name: 'CLAUDE.md has no embedded secrets',
|
|
70
|
+
check: (ctx) => {
|
|
71
|
+
const md = ctx.claudeMdContent() || '';
|
|
72
|
+
return !containsEmbeddedSecret(md);
|
|
73
|
+
},
|
|
74
|
+
impact: 'critical',
|
|
75
|
+
rating: 5,
|
|
76
|
+
category: 'git',
|
|
77
|
+
fix: 'Remove hardcoded secrets, tokens, private keys, and connection strings from CLAUDE.md. Use environment variables or external secret stores instead.',
|
|
78
|
+
template: null
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
readme: {
|
|
82
|
+
id: 416,
|
|
83
|
+
name: 'Has README.md',
|
|
84
|
+
check: (ctx) => ctx.files.some(f => /^readme\.md$/i.test(f)),
|
|
85
|
+
impact: 'high',
|
|
86
|
+
rating: 4,
|
|
87
|
+
category: 'hygiene',
|
|
88
|
+
fix: 'Add a README.md with project overview, setup instructions, and usage.',
|
|
89
|
+
template: null
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
changelog: {
|
|
93
|
+
id: 417,
|
|
94
|
+
name: 'Has CHANGELOG.md',
|
|
95
|
+
check: (ctx) => ctx.files.some(f => /^(changelog|changes|history|news)\.(md|txt|rst)$/i.test(f) || /^changelog$/i.test(f)),
|
|
96
|
+
impact: 'low',
|
|
97
|
+
rating: 3,
|
|
98
|
+
category: 'hygiene',
|
|
99
|
+
fix: 'Add a CHANGELOG.md (or CHANGES.md, HISTORY.md) to track notable changes across versions.',
|
|
100
|
+
template: null
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
contributing: {
|
|
104
|
+
id: 418,
|
|
105
|
+
name: 'Has CONTRIBUTING.md',
|
|
106
|
+
check: (ctx) => ctx.files.some(f => /^contributing\.md$/i.test(f)),
|
|
107
|
+
impact: 'low',
|
|
108
|
+
rating: 3,
|
|
109
|
+
category: 'hygiene',
|
|
110
|
+
fix: 'Add a CONTRIBUTING.md with contribution guidelines and code standards.',
|
|
111
|
+
template: null
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
license: {
|
|
115
|
+
id: 434,
|
|
116
|
+
name: 'Has LICENSE file',
|
|
117
|
+
check: (ctx) => ctx.files.some(f => /^license/i.test(f)),
|
|
118
|
+
impact: 'low',
|
|
119
|
+
rating: 3,
|
|
120
|
+
category: 'hygiene',
|
|
121
|
+
fix: 'Add a LICENSE file to clarify usage rights.',
|
|
122
|
+
template: null
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
editorconfig: {
|
|
126
|
+
id: 5001,
|
|
127
|
+
name: 'Has .editorconfig',
|
|
128
|
+
check: (ctx) => ctx.files.includes('.editorconfig'),
|
|
129
|
+
impact: 'low',
|
|
130
|
+
rating: 3,
|
|
131
|
+
category: 'hygiene',
|
|
132
|
+
fix: 'Add .editorconfig for consistent formatting across editors and Claude.',
|
|
133
|
+
template: null
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
nvmrc: {
|
|
137
|
+
id: 5002,
|
|
138
|
+
name: 'Node version pinned',
|
|
139
|
+
check: (ctx) => {
|
|
140
|
+
const hasNodeSignals = ctx.files.includes('package.json') ||
|
|
141
|
+
ctx.files.includes('tsconfig.json') ||
|
|
142
|
+
ctx.files.some(f => /package-lock\.json|pnpm-lock\.yaml|yarn\.lock|next\.config|vite\.config/i.test(f));
|
|
143
|
+
if (!hasNodeSignals) return null;
|
|
144
|
+
if (ctx.files.includes('.nvmrc') || ctx.files.includes('.node-version')) return true;
|
|
145
|
+
const pkg = ctx.jsonFile('package.json');
|
|
146
|
+
return !!(pkg && pkg.engines && pkg.engines.node);
|
|
147
|
+
},
|
|
148
|
+
impact: 'low',
|
|
149
|
+
rating: 3,
|
|
150
|
+
category: 'hygiene',
|
|
151
|
+
fix: 'Add .nvmrc, .node-version, or engines.node in package.json to pin Node version.',
|
|
152
|
+
template: null
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
gitAttributionDecision: {
|
|
156
|
+
id: 2015,
|
|
157
|
+
name: 'Git attribution configured',
|
|
158
|
+
check: (ctx) => {
|
|
159
|
+
const shared = ctx.jsonFile('.claude/settings.json') || {};
|
|
160
|
+
const local = ctx.jsonFile('.claude/settings.local.json') || {};
|
|
161
|
+
return shared.attribution !== undefined || local.attribution !== undefined ||
|
|
162
|
+
shared.includeCoAuthoredBy !== undefined || local.includeCoAuthoredBy !== undefined;
|
|
163
|
+
},
|
|
164
|
+
impact: 'low', rating: 3, category: 'git',
|
|
165
|
+
fix: 'Decide on git attribution: set attribution.commit or includeCoAuthoredBy in settings.',
|
|
166
|
+
template: null
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
gitIgnoreClaudeLocal: {
|
|
170
|
+
id: 2028,
|
|
171
|
+
name: '.gitignore excludes settings.local.json',
|
|
172
|
+
check: (ctx) => {
|
|
173
|
+
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
174
|
+
return /settings\.local\.json|settings\.local/i.test(gitignore);
|
|
175
|
+
},
|
|
176
|
+
impact: 'medium', rating: 4, category: 'git',
|
|
177
|
+
fix: 'Add .claude/settings.local.json to .gitignore. Personal overrides should not be committed.',
|
|
178
|
+
template: null
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
envExampleExists: {
|
|
182
|
+
id: 2029,
|
|
183
|
+
name: '.env.example or .env.template exists',
|
|
184
|
+
check: (ctx) => {
|
|
185
|
+
return !!(ctx.fileContent('.env.example') || ctx.fileContent('.env.template') || ctx.fileContent('.env.sample'));
|
|
186
|
+
},
|
|
187
|
+
impact: 'low', rating: 3, category: 'hygiene',
|
|
188
|
+
fix: 'Add .env.example so new developers know which environment variables are needed.',
|
|
189
|
+
template: null
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
packageJsonHasScripts: {
|
|
193
|
+
id: 2030,
|
|
194
|
+
name: 'package.json has dev/test/build scripts',
|
|
195
|
+
check: (ctx) => {
|
|
196
|
+
const pkg = ctx.jsonFile('package.json');
|
|
197
|
+
if (!pkg) return null;
|
|
198
|
+
const scripts = pkg.scripts || {};
|
|
199
|
+
const has = (k) => !!scripts[k];
|
|
200
|
+
return has('test') || has('dev') || has('build') || has('start');
|
|
201
|
+
},
|
|
202
|
+
impact: 'medium', rating: 3, category: 'hygiene',
|
|
203
|
+
fix: 'Add scripts to package.json (test, dev, build). Claude uses these for verification.',
|
|
204
|
+
template: null
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
gitignoreClaudeLocal: {
|
|
208
|
+
id: 2036,
|
|
209
|
+
name: 'CLAUDE.local.md in .gitignore',
|
|
210
|
+
check: (ctx) => {
|
|
211
|
+
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
212
|
+
return /CLAUDE\.local\.md/i.test(gitignore);
|
|
213
|
+
},
|
|
214
|
+
impact: 'medium',
|
|
215
|
+
rating: 3,
|
|
216
|
+
category: 'git',
|
|
217
|
+
fix: 'Add CLAUDE.local.md to .gitignore — it contains personal overrides that should not be committed.',
|
|
218
|
+
template: null
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
readmeQuality: {
|
|
222
|
+
id: 130151,
|
|
223
|
+
name: 'README has installation, usage, and contributing sections',
|
|
224
|
+
check: (ctx) => {
|
|
225
|
+
const readme = ctx.fileContent('README.md') || '';
|
|
226
|
+
if (!readme) return false;
|
|
227
|
+
return /install/i.test(readme) && /usage/i.test(readme) && /contribut/i.test(readme);
|
|
228
|
+
},
|
|
229
|
+
impact: 'medium',
|
|
230
|
+
category: 'docs-quality',
|
|
231
|
+
fix: 'Ensure README.md includes installation, usage, and contributing sections for developer onboarding.',
|
|
232
|
+
confidence: 0.7,
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
contributingGuide: {
|
|
236
|
+
id: 130152,
|
|
237
|
+
name: 'CONTRIBUTING.md exists',
|
|
238
|
+
check: (ctx) => ctx.files.some(f => /^contributing\.md$/i.test(f)),
|
|
239
|
+
impact: 'low',
|
|
240
|
+
category: 'docs-quality',
|
|
241
|
+
fix: 'Add CONTRIBUTING.md with contribution guidelines, code standards, and PR process.',
|
|
242
|
+
confidence: 0.7,
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
apiDocsGenerated: {
|
|
246
|
+
id: 130153,
|
|
247
|
+
name: 'API documentation generator configured',
|
|
248
|
+
check: (ctx) => {
|
|
249
|
+
const pkg = ctx.fileContent('package.json') || '';
|
|
250
|
+
if (/typedoc|jsdoc|apidoc|compodoc/i.test(pkg)) return true;
|
|
251
|
+
const py = readProjectFiles(ctx, /(^|\/)pyproject\.toml$/i) + readProjectFiles(ctx, /(^|\/)requirements[^/]*\.txt$/i);
|
|
252
|
+
if (/sphinx|pdoc|mkdocstrings/i.test(py)) return true;
|
|
253
|
+
if (isGoProject(ctx) && hasProjectFile(ctx, /(^|\/)doc\.go$/i)) return true;
|
|
254
|
+
return false;
|
|
255
|
+
},
|
|
256
|
+
impact: 'low',
|
|
257
|
+
category: 'docs-quality',
|
|
258
|
+
fix: 'Add an API documentation generator (typedoc, jsdoc, sphinx, godoc) for auto-generated docs.',
|
|
259
|
+
confidence: 0.7,
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
storybookConfigured: {
|
|
263
|
+
id: 130154,
|
|
264
|
+
name: 'Storybook configured for component docs',
|
|
265
|
+
check: (ctx) => {
|
|
266
|
+
if (!hasFrontendSignals(ctx)) return null;
|
|
267
|
+
return ctx.hasDir('.storybook') || hasProjectFile(ctx, /(^|\/)\.storybook\//i);
|
|
268
|
+
},
|
|
269
|
+
impact: 'low',
|
|
270
|
+
category: 'docs-quality',
|
|
271
|
+
fix: 'Add Storybook (.storybook/) for interactive component documentation and visual testing.',
|
|
272
|
+
confidence: 0.7,
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
codeOfConduct: {
|
|
276
|
+
id: 130155,
|
|
277
|
+
name: 'CODE_OF_CONDUCT.md exists',
|
|
278
|
+
check: (ctx) => ctx.files.some(f => /^code.of.conduct\.md$/i.test(f)),
|
|
279
|
+
impact: 'low',
|
|
280
|
+
category: 'docs-quality',
|
|
281
|
+
fix: 'Add CODE_OF_CONDUCT.md to set community standards and expectations.',
|
|
282
|
+
confidence: 0.7,
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
licenseDeclared: {
|
|
286
|
+
id: 130156,
|
|
287
|
+
name: 'LICENSE file exists',
|
|
288
|
+
check: (ctx) => ctx.files.some(f => /^license/i.test(f)),
|
|
289
|
+
impact: 'low',
|
|
290
|
+
category: 'docs-quality',
|
|
291
|
+
fix: 'Add a LICENSE file to clarify usage rights and legal terms.',
|
|
292
|
+
confidence: 0.7,
|
|
293
|
+
},
|
|
294
|
+
};
|